Add transformers
Transformers take raw data from Granblue Fantasy and transforms them into hensei-compatible JSON. Transformers heavily borrow from vazkii/hensei-transfer.
This commit is contained in:
parent
86a16113cc
commit
f83a41bf7c
6 changed files with 437 additions and 0 deletions
91
lib/granblue/transformers/base_deck_transformer.rb
Normal file
91
lib/granblue/transformers/base_deck_transformer.rb
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Granblue
|
||||
module Transformers
|
||||
class BaseDeckTransformer < BaseTransformer
|
||||
def transform
|
||||
Rails.logger.info "[TRANSFORM] Starting BaseDeckTransformer#transform"
|
||||
Rails.logger.info "[TRANSFORM] Data class: #{data.class}"
|
||||
|
||||
# Handle already transformed parameters
|
||||
if data.is_a?(ActionController::Parameters) && data.key?(:name)
|
||||
Rails.logger.info "[TRANSFORM] Found existing parameters, returning as is"
|
||||
return data.to_h.symbolize_keys
|
||||
end
|
||||
|
||||
# Handle raw game data
|
||||
Rails.logger.info "[TRANSFORM] Processing raw game data"
|
||||
input_data = data['import'] if data.is_a?(Hash)
|
||||
unless input_data
|
||||
Rails.logger.error "[TRANSFORM] No import data found"
|
||||
return {}
|
||||
end
|
||||
|
||||
Rails.logger.info "[TRANSFORM] Found import data"
|
||||
deck = input_data['deck']
|
||||
pc = deck['pc'] if deck
|
||||
|
||||
unless deck && pc
|
||||
Rails.logger.error "[TRANSFORM] Missing deck or pc data"
|
||||
Rails.logger.error "[TRANSFORM] deck present: #{!!deck}"
|
||||
Rails.logger.error "[TRANSFORM] pc present: #{!!pc}"
|
||||
return {}
|
||||
end
|
||||
|
||||
Rails.logger.info "[TRANSFORM] Building deck data structure"
|
||||
result = {
|
||||
lang: language,
|
||||
name: deck['name'] || 'Untitled',
|
||||
class: pc.dig('job', 'master', 'name'),
|
||||
extra: pc['isExtraDeck'] || false,
|
||||
subskills: transform_subskills(pc['set_action']),
|
||||
characters: transform_characters(deck['npc']),
|
||||
weapons: transform_weapons(pc['weapons']),
|
||||
summons: transform_summons(pc['summons'], pc['quick_user_summon_id']),
|
||||
sub_summons: transform_summons(pc['sub_summons']),
|
||||
friend_summon: pc.dig('damage_info', 'summon_name')
|
||||
}
|
||||
|
||||
Rails.logger.info "[TRANSFORM] Completed transformation"
|
||||
Rails.logger.debug "[TRANSFORM] Result: #{result}"
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def transform_subskills(set_action)
|
||||
Rails.logger.info "[TRANSFORM] Processing subskills"
|
||||
unless set_action.is_a?(Array) && !set_action.empty?
|
||||
Rails.logger.info "[TRANSFORM] No valid set_action data"
|
||||
return []
|
||||
end
|
||||
|
||||
skills = set_action[0]
|
||||
unless skills.is_a?(Array)
|
||||
Rails.logger.info "[TRANSFORM] Invalid skills array"
|
||||
return []
|
||||
end
|
||||
|
||||
results = skills.map { |skill| skill['name'] if skill.is_a?(Hash) }.compact
|
||||
Rails.logger.info "[TRANSFORM] Found #{results.length} subskills"
|
||||
results
|
||||
end
|
||||
|
||||
def transform_characters(npc_data)
|
||||
Rails.logger.info "[TRANSFORM] Processing characters"
|
||||
CharacterTransformer.new(npc_data, options).transform
|
||||
end
|
||||
|
||||
def transform_weapons(weapons_data)
|
||||
Rails.logger.info "[TRANSFORM] Processing weapons"
|
||||
WeaponTransformer.new(weapons_data, options).transform
|
||||
end
|
||||
|
||||
def transform_summons(summons_data, quick_summon_id = nil)
|
||||
Rails.logger.info "[TRANSFORM] Processing summons"
|
||||
SummonTransformer.new(summons_data, quick_summon_id, options).transform
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
74
lib/granblue/transformers/base_transformer.rb
Normal file
74
lib/granblue/transformers/base_transformer.rb
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Granblue
|
||||
module Transformers
|
||||
class TransformerError < StandardError
|
||||
attr_reader :details
|
||||
|
||||
def initialize(message, details = nil)
|
||||
@details = details
|
||||
super(message)
|
||||
end
|
||||
end
|
||||
|
||||
class BaseTransformer
|
||||
ELEMENT_MAPPING = {
|
||||
0 => nil,
|
||||
1 => 4, # Wind -> Earth
|
||||
2 => 2, # Fire -> Fire
|
||||
3 => 3, # Water -> Water
|
||||
4 => 1, # Earth -> Wind
|
||||
5 => 6, # Dark -> Light
|
||||
6 => 5 # Light -> Dark
|
||||
}.freeze
|
||||
|
||||
def initialize(data, options = {})
|
||||
@data = data
|
||||
@options = options
|
||||
@language = options[:language] || 'en'
|
||||
Rails.logger.info "[TRANSFORM] Initializing #{self.class.name} with data: #{data.class}"
|
||||
validate_data
|
||||
end
|
||||
|
||||
def transform
|
||||
raise NotImplementedError, "#{self.class} must implement #transform"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_reader :data, :options, :language
|
||||
|
||||
def validate_data
|
||||
Rails.logger.info "[TRANSFORM] Validating data: #{data.inspect[0..100]}..."
|
||||
|
||||
if data.nil?
|
||||
Rails.logger.info "[TRANSFORM] Data is nil"
|
||||
return true
|
||||
end
|
||||
|
||||
if data.empty?
|
||||
Rails.logger.info "[TRANSFORM] Data is empty"
|
||||
return true
|
||||
end
|
||||
|
||||
# Data validation successful
|
||||
true
|
||||
end
|
||||
|
||||
def get_master_param(obj)
|
||||
return [nil, nil] unless obj.is_a?(Hash)
|
||||
|
||||
master = obj['master']
|
||||
param = obj['param']
|
||||
Rails.logger.debug "[TRANSFORM] Extracted master: #{!!master}, param: #{!!param}"
|
||||
|
||||
[master, param]
|
||||
end
|
||||
|
||||
def log_debug(message)
|
||||
return unless options[:debug]
|
||||
Rails.logger.debug "[TRANSFORM-DEBUG] #{self.class.name}: #{message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
51
lib/granblue/transformers/character_transformer.rb
Normal file
51
lib/granblue/transformers/character_transformer.rb
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
module Granblue
|
||||
module Transformers
|
||||
class CharacterTransformer < BaseTransformer
|
||||
def transform
|
||||
Rails.logger.info "[TRANSFORM] Starting CharacterTransformer#transform"
|
||||
|
||||
unless data.is_a?(Hash)
|
||||
Rails.logger.error "[TRANSFORM] Invalid character data structure"
|
||||
return []
|
||||
end
|
||||
|
||||
characters = []
|
||||
data.each_value do |char_data|
|
||||
next unless char_data['master'] && char_data['param']
|
||||
|
||||
master = char_data['master']
|
||||
param = char_data['param']
|
||||
|
||||
Rails.logger.debug "[TRANSFORM] Processing character: #{master['name']}"
|
||||
|
||||
character = {
|
||||
name: master['name'],
|
||||
id: master['id'],
|
||||
uncap: param['evolution'].to_i
|
||||
}
|
||||
|
||||
Rails.logger.debug "[TRANSFORM] Base character data: #{character}"
|
||||
|
||||
# Add perpetuity (rings) if present
|
||||
if param['has_npcaugment_constant']
|
||||
character[:ringed] = true
|
||||
Rails.logger.debug "[TRANSFORM] Character is ringed"
|
||||
end
|
||||
|
||||
# Add transcendence if present
|
||||
phase = param['phase'].to_i
|
||||
if phase && phase.positive?
|
||||
character[:transcend] = phase
|
||||
Rails.logger.debug "[TRANSFORM] Character has transcendence: #{phase}"
|
||||
end
|
||||
|
||||
characters << character unless master['id'].nil?
|
||||
Rails.logger.info "[TRANSFORM] Successfully processed character #{character[:name]}"
|
||||
end
|
||||
|
||||
Rails.logger.info "[TRANSFORM] Completed processing #{characters.length} characters"
|
||||
characters
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
73
lib/granblue/transformers/summon_transformer.rb
Normal file
73
lib/granblue/transformers/summon_transformer.rb
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Granblue
|
||||
module Transformers
|
||||
class SummonTransformer < BaseTransformer
|
||||
TRANSCENDENCE_LEVELS = [210, 220, 230, 240].freeze
|
||||
|
||||
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
|
||||
|
||||
def transform
|
||||
Rails.logger.info "[TRANSFORM] Starting SummonTransformer#transform"
|
||||
|
||||
unless data.is_a?(Hash)
|
||||
Rails.logger.error "[TRANSFORM] Invalid summon data structure"
|
||||
Rails.logger.error "[TRANSFORM] Data class: #{data.class}"
|
||||
return []
|
||||
end
|
||||
|
||||
summons = []
|
||||
data.each_value do |summon_data|
|
||||
Rails.logger.debug "[TRANSFORM] Processing summon: #{summon_data['master']['name'] if summon_data['master']}"
|
||||
|
||||
master, param = get_master_param(summon_data)
|
||||
unless master && param
|
||||
Rails.logger.debug "[TRANSFORM] Skipping summon - missing master or param data"
|
||||
next
|
||||
end
|
||||
|
||||
summon = {
|
||||
name: master['name'],
|
||||
id: master['id'],
|
||||
uncap: param['evolution'].to_i
|
||||
}
|
||||
|
||||
Rails.logger.debug "[TRANSFORM] Base summon data: #{summon}"
|
||||
|
||||
# Add transcendence if applicable
|
||||
if summon[:uncap] > 5
|
||||
level = param['level'].to_i
|
||||
trans = calculate_transcendence_level(level)
|
||||
summon[:transcend] = trans
|
||||
Rails.logger.debug "[TRANSFORM] Added transcendence level: #{trans}"
|
||||
end
|
||||
|
||||
# Mark quick summon if applicable
|
||||
if @quick_summon_id && param['id'].to_s == @quick_summon_id.to_s
|
||||
summon[:qs] = true
|
||||
Rails.logger.debug "[TRANSFORM] Marked as quick summon"
|
||||
end
|
||||
|
||||
summons << summon
|
||||
Rails.logger.info "[TRANSFORM] Successfully processed summon #{summon[:name]}"
|
||||
end
|
||||
|
||||
Rails.logger.info "[TRANSFORM] Completed processing #{summons.length} summons"
|
||||
summons
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def calculate_transcendence_level(level)
|
||||
return 1 unless level
|
||||
level = 1 + TRANSCENDENCE_LEVELS.count { |cutoff| level > cutoff }
|
||||
Rails.logger.debug "[TRANSFORM] Calculated transcendence level: #{level}"
|
||||
level
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
12
lib/granblue/transformers/transformer_error.rb
Normal file
12
lib/granblue/transformers/transformer_error.rb
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
module Granblue
|
||||
module Transformers
|
||||
class TransformerError < StandardError
|
||||
attr_reader :details
|
||||
|
||||
def initialize(message, details = nil)
|
||||
@details = details
|
||||
super(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
136
lib/granblue/transformers/weapon_transformer.rb
Normal file
136
lib/granblue/transformers/weapon_transformer.rb
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
module Granblue
|
||||
module Transformers
|
||||
class WeaponTransformer < BaseTransformer
|
||||
UNCAP_LEVELS = [40, 60, 80, 100, 150, 200].freeze
|
||||
TRANSCENDENCE_LEVELS = [210, 220, 230, 240].freeze
|
||||
MULTIELEMENT_SERIES = [13, 17, 19].freeze
|
||||
|
||||
def transform
|
||||
Rails.logger.info "[TRANSFORM] Starting WeaponTransformer#transform"
|
||||
|
||||
unless data.is_a?(Hash)
|
||||
Rails.logger.error "[TRANSFORM] Invalid weapon data structure"
|
||||
return []
|
||||
end
|
||||
|
||||
weapons = []
|
||||
data.each_value do |weapon_data|
|
||||
next unless weapon_data['master'] && weapon_data['param']
|
||||
|
||||
master = weapon_data['master']
|
||||
param = weapon_data['param']
|
||||
|
||||
Rails.logger.debug "[TRANSFORM] Processing weapon: #{master['name']}"
|
||||
|
||||
weapon = transform_base_attributes(master, param)
|
||||
Rails.logger.debug "[TRANSFORM] Base weapon attributes: #{weapon}"
|
||||
|
||||
weapon.merge!(transform_awakening(param))
|
||||
Rails.logger.debug "[TRANSFORM] After awakening: #{weapon[:awakening] if weapon[:awakening]}"
|
||||
|
||||
weapon.merge!(transform_ax_skills(param))
|
||||
Rails.logger.debug "[TRANSFORM] After AX skills: #{weapon[:ax] if weapon[:ax]}"
|
||||
|
||||
weapon.merge!(transform_weapon_keys(weapon_data))
|
||||
Rails.logger.debug "[TRANSFORM] After weapon keys: #{weapon[:keys] if weapon[:keys]}"
|
||||
|
||||
weapons << weapon unless master['id'].nil?
|
||||
Rails.logger.info "[TRANSFORM] Successfully processed weapon #{weapon[:name]}"
|
||||
end
|
||||
|
||||
Rails.logger.info "[TRANSFORM] Completed processing #{weapons.length} weapons"
|
||||
weapons
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def transform_base_attributes(master, param)
|
||||
Rails.logger.debug "[TRANSFORM] Processing base attributes for weapon"
|
||||
|
||||
series = master['series_id'].to_i
|
||||
weapon = {
|
||||
name: master['name'],
|
||||
id: master['id']
|
||||
}
|
||||
|
||||
# Handle multi-element weapons
|
||||
if MULTIELEMENT_SERIES.include?(series)
|
||||
element = master['attribute'].to_i - 1
|
||||
weapon[:attr] = element
|
||||
weapon[:id] = (master['id'].to_i - (element * 100)).to_s
|
||||
Rails.logger.debug "[TRANSFORM] Multi-element weapon adjustments made"
|
||||
end
|
||||
|
||||
# Calculate uncap level
|
||||
level = param['level'].to_i
|
||||
uncap = calculate_uncap_level(level)
|
||||
weapon[:uncap] = uncap
|
||||
Rails.logger.debug "[TRANSFORM] Calculated uncap level: #{uncap}"
|
||||
|
||||
# Add transcendence if applicable
|
||||
if uncap > 5
|
||||
trans = calculate_transcendence_level(level)
|
||||
weapon[:transcend] = trans
|
||||
Rails.logger.debug "[TRANSFORM] Added transcendence level: #{trans}"
|
||||
end
|
||||
|
||||
weapon
|
||||
end
|
||||
|
||||
def transform_awakening(param)
|
||||
return {} unless param['arousal']&.[]('is_arousal_weapon')
|
||||
|
||||
Rails.logger.debug "[TRANSFORM] Processing weapon awakening"
|
||||
{
|
||||
awakening: {
|
||||
type: param['arousal']['form_name'],
|
||||
lvl: param['arousal']['level']
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def transform_ax_skills(param)
|
||||
augments = param['augment_skill_info']
|
||||
return {} unless augments&.first&.any?
|
||||
|
||||
Rails.logger.debug "[TRANSFORM] Processing AX skills"
|
||||
ax = []
|
||||
augments.first.each_value do |augment|
|
||||
ax_skill = {
|
||||
id: augment['skill_id'].to_s,
|
||||
val: augment['show_value']
|
||||
}
|
||||
ax << ax_skill
|
||||
Rails.logger.debug "[TRANSFORM] Added AX skill: #{ax_skill}"
|
||||
end
|
||||
|
||||
{ ax: ax }
|
||||
end
|
||||
|
||||
def transform_weapon_keys(weapon_data)
|
||||
Rails.logger.debug "[TRANSFORM] Processing weapon keys"
|
||||
keys = []
|
||||
|
||||
# Add weapon keys if they exist
|
||||
['skill1', 'skill2', 'skill3'].each do |skill_key|
|
||||
if weapon_data[skill_key]&.[]('id')
|
||||
keys << weapon_data[skill_key]['id']
|
||||
Rails.logger.debug "[TRANSFORM] Added weapon key: #{weapon_data[skill_key]['id']}"
|
||||
end
|
||||
end
|
||||
|
||||
keys.any? ? { keys: keys } : {}
|
||||
end
|
||||
|
||||
def calculate_uncap_level(level)
|
||||
return 0 unless level
|
||||
UNCAP_LEVELS.count { |cutoff| level.to_i > cutoff }
|
||||
end
|
||||
|
||||
def calculate_transcendence_level(level)
|
||||
return 1 unless level
|
||||
1 + TRANSCENDENCE_LEVELS.count { |cutoff| level.to_i > cutoff }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue