forked from OpenNeo/impress
core of pet loading, still needs get image hash, download assets
This commit is contained in:
parent
8b7b40019d
commit
bb233359d8
13 changed files with 361 additions and 13 deletions
13
Gemfile
13
Gemfile
|
@ -1,22 +1,19 @@
|
||||||
source 'http://rubygems.org'
|
source 'http://rubygems.org'
|
||||||
|
|
||||||
gem 'rails', '3.0.0'
|
gem 'rails', '3.0.0'
|
||||||
|
|
||||||
gem 'sqlite3-ruby', :require => 'sqlite3'
|
gem 'sqlite3-ruby', :require => 'sqlite3'
|
||||||
|
|
||||||
gem 'haml', '~> 3.0.18'
|
|
||||||
|
|
||||||
gem 'will_paginate', '~> 3.0.pre2'
|
|
||||||
|
|
||||||
gem 'rdiscount', '~> 1.6.5'
|
|
||||||
|
|
||||||
gem 'compass', '~> 0.10.1'
|
gem 'compass', '~> 0.10.1'
|
||||||
|
gem 'haml', '~> 3.0.18'
|
||||||
|
gem 'rdiscount', '~> 1.6.5'
|
||||||
|
gem 'RocketAMF', '~> 0.2.1'
|
||||||
|
gem 'will_paginate', '~> 3.0.pre2'
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
gem 'mysql'
|
gem 'mysql'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem 'rspec-rails', '~> 2.0.0.beta.22'
|
|
||||||
gem 'factory_girl_rails', '~> 1.0'
|
gem 'factory_girl_rails', '~> 1.0'
|
||||||
|
gem 'rspec-rails', '~> 2.0.0.beta.22'
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
GEM
|
GEM
|
||||||
remote: http://rubygems.org/
|
remote: http://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
|
RocketAMF (0.2.1)
|
||||||
abstract (1.0.0)
|
abstract (1.0.0)
|
||||||
actionmailer (3.0.0)
|
actionmailer (3.0.0)
|
||||||
actionpack (= 3.0.0)
|
actionpack (= 3.0.0)
|
||||||
|
@ -92,6 +93,7 @@ PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
|
RocketAMF (~> 0.2.1)
|
||||||
compass (~> 0.10.1)
|
compass (~> 0.10.1)
|
||||||
factory_girl_rails (~> 1.0)
|
factory_girl_rails (~> 1.0)
|
||||||
haml (~> 3.0.18)
|
haml (~> 3.0.18)
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
class Item < ActiveRecord::Base
|
class Item < ActiveRecord::Base
|
||||||
include SwfAssetParent
|
|
||||||
|
|
||||||
SwfAssetType = 'object'
|
SwfAssetType = 'object'
|
||||||
|
|
||||||
|
has_many :parent_swf_asset_relationships, :foreign_key => 'parent_id',
|
||||||
|
:conditions => {:swf_asset_type => SwfAssetType}
|
||||||
|
has_many :swf_assets, :through => :parent_swf_asset_relationships
|
||||||
|
|
||||||
NCRarities = [0, 500]
|
NCRarities = [0, 500]
|
||||||
PaintbrushSetDescription = 'This item is part of a deluxe paint brush set!'
|
PaintbrushSetDescription = 'This item is part of a deluxe paint brush set!'
|
||||||
|
|
||||||
|
@ -102,6 +104,89 @@ class Item < ActiveRecord::Base
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def before_save
|
||||||
|
sold_in_mall = false
|
||||||
|
end
|
||||||
|
|
||||||
|
def origin_registry_info=(info)
|
||||||
|
# bear in mind that numbers from registries are floats
|
||||||
|
self.species_support_ids = info[:species_support].map(&:to_i)
|
||||||
|
attribute_names.each do |attribute|
|
||||||
|
value = info[attribute.to_sym]
|
||||||
|
if value
|
||||||
|
value = value.to_i if value.is_a? Float
|
||||||
|
self[attribute] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.collection_from_pet_type_and_registries(pet_type, info_registry, asset_registry)
|
||||||
|
# bear in mind that registries are arrays with many nil elements,
|
||||||
|
# due to how the parser works
|
||||||
|
items = {}
|
||||||
|
item_ids = []
|
||||||
|
info_registry.each do |info|
|
||||||
|
if info
|
||||||
|
item_ids << info[:obj_info_id].to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
existing_relationships_by_item_id_and_swf_asset_id = {}
|
||||||
|
existing_items = Item.find_all_by_id(item_ids, :include => :parent_swf_asset_relationships)
|
||||||
|
existing_items.each do |item|
|
||||||
|
items[item.id] = item
|
||||||
|
relationships_by_swf_asset_id = {}
|
||||||
|
item.parent_swf_asset_relationships.each do |relationship|
|
||||||
|
relationships_by_swf_asset_id[relationship.swf_asset_id] = relationship
|
||||||
|
end
|
||||||
|
existing_relationships_by_item_id_and_swf_asset_id[item.id] =
|
||||||
|
relationships_by_swf_asset_id
|
||||||
|
end
|
||||||
|
swf_asset_ids = []
|
||||||
|
asset_registry.each_with_index do |asset_data, index|
|
||||||
|
swf_asset_ids << index if asset_data
|
||||||
|
end
|
||||||
|
existing_swf_assets = SwfAsset.find_all_by_id(swf_asset_ids)
|
||||||
|
existing_swf_assets_by_id = {}
|
||||||
|
existing_swf_assets.each do |swf_asset|
|
||||||
|
existing_swf_assets_by_id[swf_asset.id] = swf_asset
|
||||||
|
end
|
||||||
|
relationships_by_item_id = {}
|
||||||
|
asset_registry.each do |asset_data|
|
||||||
|
if asset_data
|
||||||
|
item_id = asset_data[:obj_info_id].to_i
|
||||||
|
item = items[item_id]
|
||||||
|
unless item
|
||||||
|
item = Item.new
|
||||||
|
item.id = item_id
|
||||||
|
items[item_id] = item
|
||||||
|
end
|
||||||
|
item.origin_registry_info = info_registry[item.id]
|
||||||
|
swf_asset_id = asset_data[:asset_id].to_i
|
||||||
|
swf_asset = existing_swf_assets[swf_asset_id]
|
||||||
|
unless swf_asset
|
||||||
|
swf_asset = SwfAsset.new
|
||||||
|
swf_asset.id = swf_asset_id
|
||||||
|
end
|
||||||
|
swf_asset.origin_object_data = asset_data
|
||||||
|
swf_asset.origin_pet_type = pet_type
|
||||||
|
relationship = existing_relationships_by_item_id_and_swf_asset_id[item.id][swf_asset_id] rescue nil
|
||||||
|
unless relationship
|
||||||
|
relationship = ParentSwfAssetRelationship.new
|
||||||
|
relationship.parent_id = item.id
|
||||||
|
relationship.swf_asset_type = SwfAssetType
|
||||||
|
relationship.swf_asset_id = swf_asset.id
|
||||||
|
end
|
||||||
|
relationship.swf_asset = swf_asset
|
||||||
|
relationships_by_item_id[item_id] ||= []
|
||||||
|
relationships_by_item_id[item_id] << relationship
|
||||||
|
end
|
||||||
|
end
|
||||||
|
relationships_by_item_id.each do |item_id, relationships|
|
||||||
|
items[item_id].parent_swf_asset_relationships = relationships
|
||||||
|
end
|
||||||
|
items.values
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
SearchFilterScopes = []
|
SearchFilterScopes = []
|
||||||
|
|
55
app/models/pet.rb
Normal file
55
app/models/pet.rb
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
class Pet < ActiveRecord::Base
|
||||||
|
GATEWAY_URL = 'http://www.neopets.com/amfphp/gateway.php'
|
||||||
|
AMF_SERVICE_NAME = 'CustomPetService'
|
||||||
|
PET_VIEWER_METHOD = 'getViewerData'
|
||||||
|
PET_NOT_FOUND_REMOTE_ERROR = 'PHP: Unable to retrieve records from the database.'
|
||||||
|
|
||||||
|
belongs_to :pet_type
|
||||||
|
|
||||||
|
attr_reader :items
|
||||||
|
|
||||||
|
def load!
|
||||||
|
require 'ostruct'
|
||||||
|
begin
|
||||||
|
envelope = Pet.amf_service.fetch(PET_VIEWER_METHOD, name, nil)
|
||||||
|
rescue RocketAMF::RemoteGateway::AMFError => e
|
||||||
|
if e.message == PET_NOT_FOUND_REMOTE_ERROR
|
||||||
|
raise PetNotFound, "Pet #{name.inspect} does not exist"
|
||||||
|
end
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
contents = OpenStruct.new(envelope.messages[0].data.body)
|
||||||
|
pet_data = OpenStruct.new(contents.custom_pet)
|
||||||
|
self.pet_type = PetType.find_or_initialize_by_species_id_and_color_id(
|
||||||
|
pet_data.species_id.to_i,
|
||||||
|
pet_data.color_id.to_i
|
||||||
|
)
|
||||||
|
self.pet_type.body_id = pet_data.body_id
|
||||||
|
@pet_state = self.pet_type.add_pet_state_from_biology! pet_data.biology_by_zone
|
||||||
|
@items = Item.collection_from_pet_type_and_registries(self.pet_type,
|
||||||
|
contents.object_info_registry, contents.object_asset_registry)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.load(name)
|
||||||
|
pet = Pet.find_or_initialize_by_name(name)
|
||||||
|
pet.load!
|
||||||
|
pet
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def self.amf_service
|
||||||
|
@amf_service ||= gateway.service AMF_SERVICE_NAME
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.gateway
|
||||||
|
unless @gateway
|
||||||
|
require 'rocketamf/remote_gateway'
|
||||||
|
@gateway = RocketAMF::RemoteGateway.new(GATEWAY_URL)
|
||||||
|
end
|
||||||
|
@gateway
|
||||||
|
end
|
||||||
|
|
||||||
|
class PetNotFound < Exception;end
|
||||||
|
end
|
|
@ -1,4 +1,73 @@
|
||||||
class PetState < ActiveRecord::Base
|
class PetState < ActiveRecord::Base
|
||||||
include SwfAssetParent
|
|
||||||
SwfAssetType = 'biology'
|
SwfAssetType = 'biology'
|
||||||
|
|
||||||
|
has_many :parent_swf_asset_relationships, :foreign_key => 'parent_id',
|
||||||
|
:conditions => {:swf_asset_type => SwfAssetType}
|
||||||
|
has_many :swf_assets, :through => :parent_swf_asset_relationships
|
||||||
|
|
||||||
|
belongs_to :pet_type
|
||||||
|
|
||||||
|
alias_method :swf_asset_ids_from_association, :swf_asset_ids
|
||||||
|
|
||||||
|
def swf_asset_ids
|
||||||
|
self['swf_asset_ids']
|
||||||
|
end
|
||||||
|
|
||||||
|
def swf_asset_ids=(ids)
|
||||||
|
self['swf_asset_ids'] = ids
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_pet_type_and_biology_info(pet_type, info)
|
||||||
|
swf_asset_ids = []
|
||||||
|
info.each do |asset_info|
|
||||||
|
if asset_info
|
||||||
|
swf_asset_ids << asset_info[:part_id].to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
swf_asset_ids_str = swf_asset_ids.join(',')
|
||||||
|
if pet_type.new_record?
|
||||||
|
pet_state = self.new :swf_asset_ids => swf_asset_ids_str
|
||||||
|
else
|
||||||
|
pet_state = self.find_or_initialize_by_pet_type_id_and_swf_asset_ids(
|
||||||
|
pet_type.id,
|
||||||
|
swf_asset_ids_str
|
||||||
|
)
|
||||||
|
end
|
||||||
|
existing_swf_assets = SwfAsset.find_all_by_id(swf_asset_ids)
|
||||||
|
existing_swf_assets_by_id = {}
|
||||||
|
existing_swf_assets.each do |swf_asset|
|
||||||
|
existing_swf_assets_by_id[swf_asset.id] = swf_asset
|
||||||
|
end
|
||||||
|
existing_relationships_by_swf_asset_id = {}
|
||||||
|
unless pet_state.new_record?
|
||||||
|
pet_state.parent_swf_asset_relationships.each do |relationship|
|
||||||
|
existing_relationships_by_swf_asset_id[relationship.swf_asset_id] = relationship
|
||||||
|
end
|
||||||
|
end
|
||||||
|
pet_state.pet_type = pet_type # save the second case from having to look it up by ID
|
||||||
|
relationships = []
|
||||||
|
info.each do |asset_info|
|
||||||
|
if asset_info
|
||||||
|
swf_asset_id = asset_info[:part_id].to_i
|
||||||
|
swf_asset = existing_swf_assets_by_id[swf_asset_id]
|
||||||
|
unless swf_asset
|
||||||
|
swf_asset = SwfAsset.new
|
||||||
|
swf_asset.id = swf_asset_id
|
||||||
|
end
|
||||||
|
swf_asset.origin_biology_data = asset_info
|
||||||
|
swf_asset.origin_pet_type = pet_type
|
||||||
|
relationship = existing_relationships_by_swf_asset_id[swf_asset_id]
|
||||||
|
unless relationship
|
||||||
|
relationship ||= ParentSwfAssetRelationship.new
|
||||||
|
relationship.parent_id = pet_state.id
|
||||||
|
relationship.swf_asset_type = SwfAssetType
|
||||||
|
relationship.swf_asset_id = swf_asset.id
|
||||||
|
end
|
||||||
|
relationship.swf_asset = swf_asset
|
||||||
|
relationships << relationship
|
||||||
|
end
|
||||||
|
end
|
||||||
|
pet_state.parent_swf_asset_relationships = relationships
|
||||||
|
pet_state
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,6 @@ class PetType < ActiveRecord::Base
|
||||||
|
|
||||||
BasicHashes = YAML::load_file(Rails.root.join('config', 'basic_type_hashes.yml'))
|
BasicHashes = YAML::load_file(Rails.root.join('config', 'basic_type_hashes.yml'))
|
||||||
|
|
||||||
|
|
||||||
StandardBodyIds = PetType.select(arel_table[:body_id]).
|
StandardBodyIds = PetType.select(arel_table[:body_id]).
|
||||||
where(arel_table[:color_id].in(Color::BasicIds)).
|
where(arel_table[:color_id].in(Color::BasicIds)).
|
||||||
group(arel_table[:species_id]).map(&:body_id)
|
group(arel_table[:species_id]).map(&:body_id)
|
||||||
|
@ -55,4 +54,10 @@ class PetType < ActiveRecord::Base
|
||||||
def image_hash
|
def image_hash
|
||||||
BasicHashes[species.name][color.name]
|
BasicHashes[species.name][color.name]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def add_pet_state_from_biology!(biology)
|
||||||
|
pet_state = PetState.from_pet_type_and_biology_info(self, biology)
|
||||||
|
self.pet_states << pet_state
|
||||||
|
pet_state
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,4 +33,21 @@ class SwfAsset < ActiveRecord::Base
|
||||||
def zone
|
def zone
|
||||||
@zone ||= Zone.find(zone_id)
|
@zone ||= Zone.find(zone_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def origin_pet_type=(pet_type)
|
||||||
|
self.body_id = pet_type.body_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def origin_biology_data=(data)
|
||||||
|
self.type = 'biology'
|
||||||
|
self.zone_id = data[:zone_id].to_i
|
||||||
|
self.url = data[:asset_url]
|
||||||
|
self.zones_restrict = data[:zones_restrict]
|
||||||
|
end
|
||||||
|
|
||||||
|
def origin_object_data=(data)
|
||||||
|
self.type = 'object'
|
||||||
|
self.zone_id = data[:zone_id].to_i
|
||||||
|
self.url = data[:asset_url]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
10
lib/deferred_attributes.rb
Normal file
10
lib/deferred_attributes.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
module DeferredAttributes
|
||||||
|
def attr_deferred(name, &block)
|
||||||
|
instance_variable_name = "@#{name}"
|
||||||
|
define_method name do
|
||||||
|
value = instance_variable_get(instance_variable_name)
|
||||||
|
return value if value
|
||||||
|
instance_variable_set(instance_variable_name, self.instance_eval(&block))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
18
lib/rocketamf/remote_gateway.rb
Normal file
18
lib/rocketamf/remote_gateway.rb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
require 'net/http'
|
||||||
|
require 'rocketamf'
|
||||||
|
require_relative 'remote_gateway/service'
|
||||||
|
require_relative 'remote_gateway/request'
|
||||||
|
|
||||||
|
module RocketAMF
|
||||||
|
class RemoteGateway
|
||||||
|
attr_reader :uri
|
||||||
|
|
||||||
|
def initialize(url)
|
||||||
|
@uri = URI.parse url
|
||||||
|
end
|
||||||
|
|
||||||
|
def service(name)
|
||||||
|
Service.new(self, name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
74
lib/rocketamf/remote_gateway/request.rb
Normal file
74
lib/rocketamf/remote_gateway/request.rb
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
module RocketAMF
|
||||||
|
class RemoteGateway
|
||||||
|
class Request
|
||||||
|
ERROR_CODE = 'AMFPHP_RUNTIME_ERROR'
|
||||||
|
|
||||||
|
def initialize(service, method, *params)
|
||||||
|
@service = service
|
||||||
|
@method = method
|
||||||
|
@params = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch
|
||||||
|
uri = @service.gateway.uri
|
||||||
|
data = envelope.serialize
|
||||||
|
|
||||||
|
req = Net::HTTP::Post.new(uri.path)
|
||||||
|
req.body = data
|
||||||
|
res = Net::HTTP.new(uri.host, uri.port).start { |http| http.request(req) }
|
||||||
|
case res
|
||||||
|
when Net::HTTPSuccess, Net::HTTPRedirection
|
||||||
|
result = RocketAMF::Envelope.new.populate_from_stream(res.body)
|
||||||
|
first_message_data = result.messages[0].data
|
||||||
|
if first_message_data.respond_to?(:[]) && first_message_data[:code] == ERROR_CODE
|
||||||
|
raise AMFError.new(first_message_data)
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
else
|
||||||
|
error = nil
|
||||||
|
begin
|
||||||
|
res.error!
|
||||||
|
rescue Exception => scoped_error
|
||||||
|
error = scoped_error
|
||||||
|
end
|
||||||
|
raise ConnectionError, "Error connecting to gateway: #{error}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def envelope
|
||||||
|
output = Envelope.new
|
||||||
|
output.messages << wrapper_message
|
||||||
|
output
|
||||||
|
end
|
||||||
|
|
||||||
|
def wrapper_message
|
||||||
|
message = Message.new 'null', '/1', [remoting_message]
|
||||||
|
end
|
||||||
|
|
||||||
|
def remoting_message
|
||||||
|
message = Values::RemotingMessage.new
|
||||||
|
message.source = @service.name
|
||||||
|
message.operation = @method
|
||||||
|
message.body = @params
|
||||||
|
message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ConnectionError < RuntimeError;end
|
||||||
|
class AMFError < RuntimeError
|
||||||
|
DATA_KEYS = [:details, :line, :code]
|
||||||
|
attr_reader *DATA_KEYS
|
||||||
|
attr_reader :message
|
||||||
|
|
||||||
|
def initialize(data)
|
||||||
|
DATA_KEYS.each do |key|
|
||||||
|
instance_variable_set "@#{key}", data[key]
|
||||||
|
end
|
||||||
|
|
||||||
|
@message = data[:description]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
16
lib/rocketamf/remote_gateway/service.rb
Normal file
16
lib/rocketamf/remote_gateway/service.rb
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
module RocketAMF
|
||||||
|
class RemoteGateway
|
||||||
|
class Service
|
||||||
|
attr_reader :gateway, :name
|
||||||
|
|
||||||
|
def initialize(gateway, name)
|
||||||
|
@gateway = gateway
|
||||||
|
@name = name
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch(method, *params)
|
||||||
|
Request.new(self, method, *params).fetch
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,4 +1,4 @@
|
||||||
Factory.define :pet_state do |ps|
|
Factory.define :pet_state do |ps|
|
||||||
ps.pet_type_id 1
|
ps.pet_type_id 1
|
||||||
ps.swf_asset_ids '1,2,3'
|
ps.swf_asset_ids_cache '1,2,3'
|
||||||
end
|
end
|
||||||
|
|
BIN
vendor/cache/RocketAMF-0.2.1.gem
vendored
Normal file
BIN
vendor/cache/RocketAMF-0.2.1.gem
vendored
Normal file
Binary file not shown.
Loading…
Reference in a new issue