diff --git a/lib/granblue/transformers/base_transformer.rb b/lib/granblue/transformers/base_transformer.rb index e49a3df..581625d 100644 --- a/lib/granblue/transformers/base_transformer.rb +++ b/lib/granblue/transformers/base_transformer.rb @@ -11,7 +11,11 @@ module Granblue end end + # Base class for transforming game data into standardized format + # @abstract class BaseTransformer + # Mapping of game element IDs to internal element IDs + # @return [Hash] ELEMENT_MAPPING = { 0 => nil, 1 => 4, # Wind -> Earth @@ -22,6 +26,12 @@ module Granblue 6 => 5 # Light -> Dark }.freeze + # Initialize a new transformer + # @param data [Object] Raw game data to transform + # @param options [Hash] Optional configuration settings + # @option options [String] :language ('en') Language code for transformations + # @option options [Boolean] :debug (false) Enable debug logging + # @return [void] def initialize(data, options = {}) @data = data @options = options @@ -30,6 +40,9 @@ module Granblue validate_data end + # Transform the raw data into standardized format + # @abstract Subclasses must implement this method + # @return [Object] Transformed data def transform raise NotImplementedError, "#{self.class} must implement #transform" end @@ -38,6 +51,8 @@ module Granblue attr_reader :data, :options, :language + # Validate the input data structure + # @return [Boolean] true if valid, false otherwise def validate_data Rails.logger.info "[TRANSFORM] Validating data: #{data.inspect[0..100]}..." @@ -55,6 +70,9 @@ module Granblue true end + # Extract master and parameter data from an object + # @param obj [Hash] Object containing master/param data + # @return [Array<(Hash?, Hash?)>] Array containing master and param data def get_master_param(obj) return [nil, nil] unless obj.is_a?(Hash) @@ -65,6 +83,9 @@ module Granblue [master, param] end + # Log a debug message if debug mode is enabled + # @param message [String] Message to log + # @return [void] def log_debug(message) return unless options[:debug] Rails.logger.debug "[TRANSFORM-DEBUG] #{self.class.name}: #{message}" diff --git a/lib/granblue/transformers/character_transformer.rb b/lib/granblue/transformers/character_transformer.rb index 210228a..573da04 100644 --- a/lib/granblue/transformers/character_transformer.rb +++ b/lib/granblue/transformers/character_transformer.rb @@ -1,16 +1,41 @@ module Granblue module Transformers + # Transforms raw game character data into standardized format for database import. + # Handles character stats, uncap levels, transcendence, and perpetuity rings. + # + # @example Transforming character data + # data = { "master" => { "name" => "Katalina", "id" => "3040001000" }, + # "param" => { "evolution" => 3, "phase" => 1 } } + # transformer = CharacterTransformer.new(data) + # result = transformer.transform + # # => [{ name: "Katalina", id: "3040001000", uncap: 3, transcend: 1 }] + # + # @note Expects data with "master" and "param" nested objects for each character + # @note Will filter out characters with missing or invalid required attributes + # + # @see BaseTransformer For base transformation functionality class CharacterTransformer < BaseTransformer + # Transforms raw game character data into a standardized format + # @return [Array] Array of character hashes with standardized attributes: + # @option character [String] :name Character's name + # @option character [String] :id Character's ID + # @option character [Integer] :uncap Character's uncap level + # @option character [Boolean] :ringed Whether character has perpetuity rings + # @option character [Integer] :transcend Character's transcendence phase level def transform + # Log start of transformation process Rails.logger.info "[TRANSFORM] Starting CharacterTransformer#transform" + # Validate that the input data is a Hash unless data.is_a?(Hash) Rails.logger.error "[TRANSFORM] Invalid character data structure" return [] end characters = [] + # Iterate through each character data entry data.each_value do |char_data| + # Skip entries missing required master/param data next unless char_data['master'] && char_data['param'] master = char_data['master'] @@ -18,27 +43,29 @@ module Granblue Rails.logger.debug "[TRANSFORM] Processing character: #{master['name']}" + # Build base character hash with required attributes character = { - name: master['name'], - id: master['id'], - uncap: param['evolution'].to_i + name: master['name'], # Character's display name + id: master['id'], # Unique identifier + uncap: param['evolution'].to_i # Current uncap level } Rails.logger.debug "[TRANSFORM] Base character data: #{character}" - # Add perpetuity (rings) if present + # Add perpetuity ring status if present if param['has_npcaugment_constant'] character[:ringed] = true Rails.logger.debug "[TRANSFORM] Character is ringed" end - # Add transcendence if present + # Add transcendence level if present (stored as 'phase' in raw data) phase = param['phase'].to_i - if phase && phase.positive? + if phase&.positive? character[:transcend] = phase Rails.logger.debug "[TRANSFORM] Character has transcendence: #{phase}" end + # Only add characters with valid IDs to result set characters << character unless master['id'].nil? Rails.logger.info "[TRANSFORM] Successfully processed character #{character[:name]}" end diff --git a/lib/granblue/transformers/summon_transformer.rb b/lib/granblue/transformers/summon_transformer.rb index f149c87..eefb380 100644 --- a/lib/granblue/transformers/summon_transformer.rb +++ b/lib/granblue/transformers/summon_transformer.rb @@ -2,18 +2,45 @@ module Granblue module Transformers + # Transforms raw game summon data into standardized format for database import. + # Handles summon stats, uncap levels, transcendence, and quick summon status. + # + # @example Transforming summon data + # data = { + # "master" => { "name" => "Bahamut", "id" => "2040003000" }, + # "param" => { "evolution" => 5, "level" => 200 } + # } + # transformer = SummonTransformer.new(data, "2040003000") + # result = transformer.transform + # # => [{ name: "Bahamut", id: "2040003000", uncap: 5, transcend: 1, qs: true }] + # + # @note Expects data with "master" and "param" nested objects for each summon + # @note Handles quick summon status if ID matches provided quick_summon_id + # + # @see BaseTransformer For base transformation functionality class SummonTransformer < BaseTransformer + # @return [Array] Level thresholds for determining transcendence level TRANSCENDENCE_LEVELS = [210, 220, 230, 240].freeze + # Creates a new summon transformer + # @param data [Object] Raw summon data to transform + # @param quick_summon_id [String, nil] ID of the current quick summon + # @param options [Hash] Additional transformation options + # @option options [String] :language ('en') Language for names + # @option options [Boolean] :debug (false) Enable debug logging + # @return [void] def initialize(data, quick_summon_id = nil, options = {}) super(data, options) @quick_summon_id = quick_summon_id Rails.logger.info "[TRANSFORM] Initializing SummonTransformer with quick_summon_id: #{quick_summon_id}" end + # Transform raw summon data into standardized format + # @return [Array] Array of transformed summon data def transform Rails.logger.info "[TRANSFORM] Starting SummonTransformer#transform" + # Validate that input data is a Hash unless data.is_a?(Hash) Rails.logger.error "[TRANSFORM] Invalid summon data structure" Rails.logger.error "[TRANSFORM] Data class: #{data.class}" @@ -21,24 +48,27 @@ module Granblue end summons = [] + # Process each summon in the data data.each_value do |summon_data| Rails.logger.debug "[TRANSFORM] Processing summon: #{summon_data['master']['name'] if summon_data['master']}" + # Extract master and parameter data master, param = get_master_param(summon_data) unless master && param Rails.logger.debug "[TRANSFORM] Skipping summon - missing master or param data" next end + # Build base summon hash with required attributes summon = { - name: master['name'], - id: master['id'], - uncap: param['evolution'].to_i + name: master['name'], # Summon's display name + id: master['id'], # Unique identifier + uncap: param['evolution'].to_i # Current uncap level } Rails.logger.debug "[TRANSFORM] Base summon data: #{summon}" - # Add transcendence if applicable + # Add transcendence level for highly uncapped summons if summon[:uncap] > 5 level = param['level'].to_i trans = calculate_transcendence_level(level) @@ -46,7 +76,7 @@ module Granblue Rails.logger.debug "[TRANSFORM] Added transcendence level: #{trans}" end - # Mark quick summon if applicable + # Mark quick summon status if this summon matches quick_summon_id if @quick_summon_id && param['id'].to_s == @quick_summon_id.to_s summon[:qs] = true Rails.logger.debug "[TRANSFORM] Marked as quick summon" @@ -62,6 +92,9 @@ module Granblue private + # Calculates transcendence level based on summon level + # @param level [Integer, nil] Current summon level + # @return [Integer] Calculated transcendence level (1-5) def calculate_transcendence_level(level) return 1 unless level level = 1 + TRANSCENDENCE_LEVELS.count { |cutoff| level > cutoff } diff --git a/lib/granblue/transformers/weapon_transformer.rb b/lib/granblue/transformers/weapon_transformer.rb index db5e964..0bb38b0 100644 --- a/lib/granblue/transformers/weapon_transformer.rb +++ b/lib/granblue/transformers/weapon_transformer.rb @@ -1,20 +1,47 @@ module Granblue module Transformers + # Transforms raw game weapon data into standardized format for database import. + # Handles weapon stats, uncap levels, transcendence, awakening, AX skills, and weapon keys. + # + # @example Transforming weapon data + # data = { + # "master" => { "name" => "Luminiera Sword Omega", "id" => "1040007100", "series_id" => 1 }, + # "param" => { "level" => 150, "arousal" => { "is_arousal_weapon" => true } } + # } + # transformer = WeaponTransformer.new(data) + # result = transformer.transform + # # => [{ name: "Luminiera Sword Omega", id: "1040007100", uncap: 4, ... }] + # + # @note Expects data with "master" and "param" nested objects for each weapon + # @note Special handling for multi-element weapons from specific series + # + # @see BaseTransformer For base transformation functionality class WeaponTransformer < BaseTransformer + # @return [Array] Level thresholds for determining uncap level UNCAP_LEVELS = [40, 60, 80, 100, 150, 200].freeze + + # @return [Array] Level thresholds for determining transcendence level TRANSCENDENCE_LEVELS = [210, 220, 230, 240].freeze + + # @return [Array] Weapon series IDs that can have multiple elements MULTIELEMENT_SERIES = [13, 17, 19].freeze + # Transform raw weapon data into standardized format + # @return [Array] Array of transformed weapon data def transform + # Log start of transformation process Rails.logger.info "[TRANSFORM] Starting WeaponTransformer#transform" + # Validate that the input data is a Hash unless data.is_a?(Hash) Rails.logger.error "[TRANSFORM] Invalid weapon data structure" return [] end weapons = [] + # Iterate through each weapon entry in the data data.each_value do |weapon_data| + # Skip entries missing required master/param data next unless weapon_data['master'] && weapon_data['param'] master = weapon_data['master'] @@ -22,18 +49,23 @@ module Granblue Rails.logger.debug "[TRANSFORM] Processing weapon: #{master['name']}" + # Transform base weapon attributes (ID, name, uncap level, etc) weapon = transform_base_attributes(master, param) Rails.logger.debug "[TRANSFORM] Base weapon attributes: #{weapon}" + # Add awakening data if present weapon.merge!(transform_awakening(param)) Rails.logger.debug "[TRANSFORM] After awakening: #{weapon[:awakening] if weapon[:awakening]}" + # Add AX skills if present weapon.merge!(transform_ax_skills(param)) Rails.logger.debug "[TRANSFORM] After AX skills: #{weapon[:ax] if weapon[:ax]}" + # Add weapon keys if present weapon.merge!(transform_weapon_keys(weapon_data)) Rails.logger.debug "[TRANSFORM] After weapon keys: #{weapon[:keys] if weapon[:keys]}" + # Only add weapons with valid IDs weapons << weapon unless master['id'].nil? Rails.logger.info "[TRANSFORM] Successfully processed weapon #{weapon[:name]}" end @@ -44,6 +76,10 @@ module Granblue private + # Transforms the core weapon attributes from master and param data + # @param master [Hash] Master data containing basic weapon information + # @param param [Hash] Parameter data containing weapon's current state + # @return [Hash] Base weapon attributes including ID, name, uncap level, etc def transform_base_attributes(master, param) Rails.logger.debug "[TRANSFORM] Processing base attributes for weapon" @@ -77,6 +113,9 @@ module Granblue weapon end + # Transforms weapon awakening data if present + # @param param [Hash] Parameter data containing awakening information + # @return [Hash] Awakening type and level if weapon is awakened def transform_awakening(param) return {} unless param['arousal']&.[]('is_arousal_weapon') @@ -89,6 +128,9 @@ module Granblue } end + # Transforms AX skill data if present + # @param param [Hash] Parameter data containing AX skill information + # @return [Hash] Array of AX skills with IDs and values def transform_ax_skills(param) augments = param['augment_skill_info'] return {} unless augments&.first&.any? @@ -107,6 +149,9 @@ module Granblue { ax: ax } end + # Transforms weapon key data if present + # @param weapon_data [Hash] Full weapon data containing key information + # @return [Hash] Array of weapon key IDs def transform_weapon_keys(weapon_data) Rails.logger.debug "[TRANSFORM] Processing weapon keys" keys = [] @@ -122,11 +167,17 @@ module Granblue keys.any? ? { keys: keys } : {} end + # Calculates uncap level based on weapon level + # @param level [Integer, nil] Current weapon level + # @return [Integer] Calculated uncap level def calculate_uncap_level(level) return 0 unless level UNCAP_LEVELS.count { |cutoff| level.to_i > cutoff } end + # Calculates transcendence level based on weapon level + # @param level [Integer, nil] Current weapon level + # @return [Integer] Calculated transcendence level def calculate_transcendence_level(level) return 1 unless level 1 + TRANSCENDENCE_LEVELS.count { |cutoff| level.to_i > cutoff } diff --git a/sig/granblue/transformers/base_transformer.rbs b/sig/granblue/transformers/base_transformer.rbs new file mode 100644 index 0000000..6eca1ba --- /dev/null +++ b/sig/granblue/transformers/base_transformer.rbs @@ -0,0 +1,31 @@ +module Granblue + module Transformers + class TransformerError < StandardError + attr_reader details: untyped + + def initialize: (String message, ?untyped details) -> void + end + + class BaseTransformer + ELEMENT_MAPPING: Hash[Integer, Integer?] + + @data: untyped + @options: Hash[Symbol, untyped] + @language: String + + attr_reader data: untyped + attr_reader options: Hash[Symbol, untyped] + attr_reader language: String + + def initialize: (untyped data, ?Hash[Symbol, untyped] options) -> void + + def transform: -> untyped + + def validate_data: -> bool + + def get_master_param: (Hash[String, untyped] obj) -> [Hash[String, untyped]?, Hash[String, untyped]?] + + def log_debug: (String message) -> void + end + end +end diff --git a/sig/granblue/transformers/summon_transformer.rbs b/sig/granblue/transformers/summon_transformer.rbs new file mode 100644 index 0000000..3c0e1bf --- /dev/null +++ b/sig/granblue/transformers/summon_transformer.rbs @@ -0,0 +1,20 @@ +module Granblue + module Transformers + class SummonTransformer < BaseTransformer + # Level thresholds for transcendence calculations + TRANSCENDENCE_LEVELS: Array[Integer] + + # Quick summon ID for the current transformation + @quick_summon_id: String? + + def initialize: (untyped data, ?String? quick_summon_id, ?Hash[Symbol, untyped] options) -> void + + # Implements abstract method from BaseTransformer + def transform: -> Array[Hash[Symbol, untyped]] + + private + + def calculate_transcendence_level: (Integer? level) -> Integer + end + end +end diff --git a/sig/granblue/transformers/weapon_transformer.rbs b/sig/granblue/transformers/weapon_transformer.rbs new file mode 100644 index 0000000..b4402d3 --- /dev/null +++ b/sig/granblue/transformers/weapon_transformer.rbs @@ -0,0 +1,27 @@ +module Granblue + module Transformers + class WeaponTransformer < BaseTransformer + # Constants for level calculations + UNCAP_LEVELS: Array[Integer] + TRANSCENDENCE_LEVELS: Array[Integer] + MULTIELEMENT_SERIES: Array[Integer] + + # Implements abstract method from BaseTransformer + def transform: -> Array[Hash[Symbol, untyped]] + + private + + def transform_base_attributes: (Hash[String, untyped] master, Hash[String, untyped] param) -> Hash[Symbol, untyped] + + def transform_awakening: (Hash[String, untyped] param) -> Hash[Symbol, Hash[Symbol, untyped]] + + def transform_ax_skills: (Hash[String, untyped] param) -> Hash[Symbol, Array[Hash[Symbol, untyped]]] + + def transform_weapon_keys: (Hash[String, untyped] weapon_data) -> Hash[Symbol, Array[String]] + + def calculate_uncap_level: (Integer? level) -> Integer + + def calculate_transcendence_level: (Integer? level) -> Integer + end + end +end