hensei-api/app/services/processors/character_processor.rb
Justin Edmund 3cdd925162
Fix filters and add processors (#181)
* Update test csvs

* Fix count filters and refactor apply_filters

* Update party_querying_concern.rb

* +tests/-debug logs

* Make party association optional in Job

* Updates for weapon series

- Change to new series numbers
- Add static method for querying whether the weapon's element is changeable
- Add a new method to return a text slug for the weapon's series

* Add and update test data

- Updates canonical.rb for loading multiple types of data with multiple types of associations
- Adds test data for Guidebooks, Job Accessories, Job Skills, and Jobs
- Updates test data for Weapons and Summons

* Migrations

- Adds series of migrations for changing the weapon's series to the values used by Cygames
- Shuffled around some foreign keys

* Implement BaseProcessor

Processors are in charge of processing deck data straight from Granblue.

* Implement CharacterProcessor

Process character data from deck

* Implement WeaponProcessor

Process weapon data from deck

* Implement JobProcessor

Process job, job skill, and job accessory data from deck

* Implement SummonProcessor

Process summon data from deck

* Update SummonProcessor to work like the others

* ImportController should use processors

* Process element for changeable weapons
2025-02-17 23:51:50 -08:00

89 lines
2.7 KiB
Ruby

# frozen_string_literal: true
module Processors
##
# CharacterProcessor processes an array of character data and creates GridCharacter records.
#
# @example
# processor = Processors::CharacterProcessor.new(party, transformed_characters_array)
# processor.process
class CharacterProcessor < BaseProcessor
def initialize(party, data, type = :normal, options = {})
super(party, data, options)
@party = party
@data = data
end
##
# Processes character data.
#
# Iterates over each character hash in +data+ and creates a new GridCharacter record.
# Expects each character hash to include keys such as :id, :position, :uncap, etc.
#
# @return [void]
def process
unless @data.is_a?(Hash)
Rails.logger.error "[CHARACTER] Invalid data format: expected a Hash, got #{@data.class}"
return
end
unless @data.key?('deck') && @data['deck'].key?('npc')
Rails.logger.error '[CHARACTER] Missing npc data in deck JSON'
return
end
@data = @data.with_indifferent_access
characters_data = @data.dig('deck', 'npc')
grid_characters = process_characters(characters_data)
grid_characters.each do |grid_character|
begin
grid_character.save!
rescue ActiveRecord::RecordInvalid => e
Rails.logger.error "[CHARACTER] Failed to create GridCharacter: #{e.record.errors.full_messages.join(', ')}"
end
end
rescue StandardError => e
raise e
end
private
def process_characters(characters_data)
characters_data.map do |key, raw_character|
next if raw_character.nil? || raw_character['param'].nil? || raw_character['master'].nil?
position = key.to_i - 1
# Find the Character record by its granblue_id.
character_id = raw_character.dig('master', 'id')
character = Character.find_by(granblue_id: character_id)
unless character
Rails.logger.error "[CHARACTER] Character not found with id #{character_id}"
next
end
# The deck doesn't have Awakening data, so use the default
awakening = Awakening.where(slug: 'character-balanced').first
grid_character = GridCharacter.create(
party_id: @party.id,
character_id: character.id,
uncap_level: raw_character.dig('param', 'evolution').to_i,
transcendence_step: raw_character.dig('param', 'phase').to_i,
position: position,
perpetuity: raw_character.dig('param', 'has_npcaugment_constant'),
awakening: awakening
)
grid_character
end.compact
end
# Converts a value to a boolean.
def parse_boolean(val)
val.to_s.downcase == 'true'
end
end
end