mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-08 13:44:59 +00:00
Created animation PBS file compiler and writer
This commit is contained in:
182
Data/Scripts/902_Anim compiler/anim pbs compiler.rb
Normal file
182
Data/Scripts/902_Anim compiler/anim pbs compiler.rb
Normal file
@@ -0,0 +1,182 @@
|
||||
module Compiler
|
||||
module_function
|
||||
|
||||
def compile_battle_animations(*paths)
|
||||
GameData::Animation::DATA.clear
|
||||
schema = GameData::Animation.schema
|
||||
sub_schema = GameData::Animation.sub_schema
|
||||
idx = 0
|
||||
# Read from PBS file(s)
|
||||
paths.each do |path|
|
||||
compile_pbs_file_message_start(path)
|
||||
file_name = path.gsub(/^PBS\/Animations\//, "").gsub(/.txt$/, "")
|
||||
data_hash = nil
|
||||
current_particle = nil
|
||||
section_name = nil
|
||||
section_line = nil
|
||||
# Read each line of the animation PBS file at a time and compile it as an
|
||||
# animation property
|
||||
pbCompilerEachPreppedLine(path) do |line, line_no|
|
||||
echo "." if idx % 100 == 0
|
||||
idx += 1
|
||||
Graphics.update if idx % 500 == 0
|
||||
FileLineData.setSection(section_name, nil, section_line)
|
||||
if line[/^\s*\[\s*(.+)\s*\]\s*$/]
|
||||
# New section [anim_type, name]
|
||||
section_name = $~[1]
|
||||
section_line = line
|
||||
if data_hash
|
||||
validate_compiled_animation(data_hash)
|
||||
GameData::Animation.register(data_hash)
|
||||
end
|
||||
FileLineData.setSection(section_name, nil, section_line)
|
||||
# Construct data hash
|
||||
data_hash = {
|
||||
:pbs_path => file_name
|
||||
}
|
||||
data_hash[schema["SectionName"][0]] = get_csv_record(section_name.clone, schema["SectionName"])
|
||||
data_hash[schema["Particle"][0]] = []
|
||||
current_particle = nil
|
||||
elsif line[/^\s*<\s*(.+)\s*>\s*$/]
|
||||
# New subsection [particle_name]
|
||||
value = get_csv_record($~[1], schema["Particle"])
|
||||
current_particle = {
|
||||
# TODO: If "Particle" is changed to be more than just a single
|
||||
# string, add more properties accordingly.
|
||||
:name => value
|
||||
}
|
||||
data_hash[schema["Particle"][0]].push(current_particle)
|
||||
elsif line[/^\s*(\w+)\s*=\s*(.*)$/]
|
||||
# XXX=YYY lines
|
||||
if !data_hash
|
||||
raise _INTL("Expected a section at the beginning of the file.\n{1}", FileLineData.linereport)
|
||||
end
|
||||
key = $~[1]
|
||||
if schema[key] # Property of the animation
|
||||
value = get_csv_record($~[2], schema[key])
|
||||
if schema[key][1][0] == "^"
|
||||
value = nil if value.is_a?(Array) && value.empty?
|
||||
data_hash[schema[key][0]] ||= []
|
||||
data_hash[schema[key][0]].push(value) if value
|
||||
else
|
||||
value = nil if value.is_a?(Array) && value.empty?
|
||||
data_hash[schema[key][0]] = value
|
||||
end
|
||||
elsif sub_schema[key] # Property of a particle
|
||||
if !current_particle
|
||||
raise _INTL("Particle hasn't been defined yet!\n{1}", FileLineData.linereport)
|
||||
end
|
||||
value = get_csv_record($~[2], sub_schema[key])
|
||||
if sub_schema[key][1][0] == "^"
|
||||
value = nil if value.is_a?(Array) && value.empty?
|
||||
current_particle[sub_schema[key][0]] ||= []
|
||||
current_particle[sub_schema[key][0]].push(value) if value
|
||||
else
|
||||
value = nil if value.is_a?(Array) && value.empty?
|
||||
current_particle[sub_schema[key][0]] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
# Add last animation's data to records
|
||||
if data_hash
|
||||
FileLineData.setSection(section_name, nil, section_line)
|
||||
validate_compiled_animation(data_hash)
|
||||
GameData::Animation.register(data_hash)
|
||||
end
|
||||
process_pbs_file_message_end
|
||||
end
|
||||
validate_all_compiled_animations
|
||||
# Save all data
|
||||
GameData::Animation.save
|
||||
end
|
||||
|
||||
def validate_compiled_animation(hash)
|
||||
# Split anim_type, move/common_name, version into their own values
|
||||
hash[:type] = hash[:id][0]
|
||||
hash[:move] = hash[:id][1]
|
||||
hash[:version] = hash[:id][2] || 0
|
||||
# Go through each particle in turn
|
||||
hash[:particles].each do |particle|
|
||||
# Convert all "SetXYZ" particle commands to "MoveXYZ" by giving them a
|
||||
# duration of 0
|
||||
[:frame, :x, :y, :zoom_x, :zoom_y, :angle, :opacity].each do |prop|
|
||||
next if !particle[prop]
|
||||
particle[prop].each do |cmd|
|
||||
cmd.insert(1, 0) if cmd.length == 2
|
||||
end
|
||||
end
|
||||
# Sort each particle's commands by their keyframe and duration
|
||||
particle.keys.each do |key|
|
||||
next if !particle[key].is_a?(Array)
|
||||
particle[key].sort! { |a, b| a[0] == b[0] ? a[1] == b[1] ? 0 : a[1] <=> b[1] : a[0] <=> b[0] }
|
||||
# TODO: Find any overlapping particle commands and raise an error.
|
||||
end
|
||||
# Ensure valid values for "SetBlending" commands
|
||||
if particle[:blending]
|
||||
particle[:blending].each do |blend|
|
||||
next if blend[1] <= 2
|
||||
raise _INTL("Invalid blend value: {1} (must be 0, 1 or 2).\n{2}",
|
||||
blend[1], FileLineData.linereport)
|
||||
end
|
||||
end
|
||||
# TODO: Ensure "Play", "PlayUserCry", "PlayTargetCry" are exclusively used
|
||||
# by the particle "SE", and that the "SE" particle can only use
|
||||
# those commands. Raise if problems found.
|
||||
|
||||
# Ensure all particles have a default focus if not given
|
||||
if !particle[:focus]
|
||||
if particle[:name] == "User"
|
||||
particle[:focus] = :user
|
||||
elsif particle[:name] == "Target"
|
||||
particle[:focus] = :target
|
||||
elsif particle[:name] != "SE"
|
||||
particle[:focus] = :screen
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Depending on hash[:target], ensure all particles have an
|
||||
# appropriate focus (i.e. can't be :user_and_target if hash[:target]
|
||||
# doesn't include a target). Raise if problems found.
|
||||
end
|
||||
end
|
||||
|
||||
def validate_all_compiled_animations; end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Hook into the regular Compiler to also compile animation PBS files.
|
||||
#===============================================================================
|
||||
module Compiler
|
||||
module_function
|
||||
|
||||
def get_animation_pbs_files_to_compile
|
||||
ret = []
|
||||
if FileTest.directory?("PBS/Animations")
|
||||
Dir.all("PBS/Animations", "**/**.txt").each { |file| ret.push(file) }
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
class << self
|
||||
if !method_defined?(:__new_anims__get_all_pbs_files_to_compile)
|
||||
alias_method :__new_anims__get_all_pbs_files_to_compile, :get_all_pbs_files_to_compile
|
||||
end
|
||||
if !method_defined?(:__new_anims__compile_pbs_files)
|
||||
alias_method :__new_anims__compile_pbs_files, :compile_pbs_files
|
||||
end
|
||||
end
|
||||
|
||||
def get_all_pbs_files_to_compile
|
||||
ret = __new_anims__get_all_pbs_files_to_compile
|
||||
extra = get_animation_pbs_files_to_compile
|
||||
ret[:Animation] = [nil, extra]
|
||||
return ret
|
||||
end
|
||||
|
||||
def compile_pbs_files
|
||||
__new_anims__compile_pbs_files
|
||||
text_files = get_animation_pbs_files_to_compile
|
||||
compile_battle_animations(*text_files)
|
||||
end
|
||||
end
|
||||
122
Data/Scripts/902_Anim compiler/anim pbs writer.rb
Normal file
122
Data/Scripts/902_Anim compiler/anim pbs writer.rb
Normal file
@@ -0,0 +1,122 @@
|
||||
module Compiler
|
||||
module_function
|
||||
|
||||
def write_all_battle_animations
|
||||
# Delete all existing .txt files in the PBS/Animations/ folder
|
||||
files_to_delete = get_animation_pbs_files_to_compile
|
||||
files_to_delete.each { |path| File.delete(path) }
|
||||
# Get all files that need writing
|
||||
paths = []
|
||||
GameData::Animation.each { |anim| paths.push(anim.pbs_path) if !paths.include?(anim.pbs_path) }
|
||||
idx = 0
|
||||
# Write each file in turn
|
||||
paths.each do |path|
|
||||
Graphics.update if idx % 500 == 0
|
||||
idx += 1
|
||||
write_battle_animation_file(path)
|
||||
end
|
||||
end
|
||||
|
||||
def write_battle_animation_file(path)
|
||||
schema = GameData::Animation.schema
|
||||
sub_schema = GameData::Animation.sub_schema
|
||||
write_pbs_file_message_start(path)
|
||||
# Create all subfolders needed
|
||||
dirs = ("PBS/Animations/" + path).split("/")
|
||||
dirs.pop # Remove the filename
|
||||
dirs.length.times do |i|
|
||||
dir_string = dirs[0..i].join("/")
|
||||
if !FileTest.directory?(dir_string)
|
||||
Dir.mkdir(dir_string) rescue nil
|
||||
end
|
||||
end
|
||||
# Write file
|
||||
File.open("PBS/Animations/" + path + ".txt", "wb") do |f|
|
||||
add_PBS_header_to_file(f)
|
||||
# Write each element in turn
|
||||
GameData::Animation.each do |element|
|
||||
next if element.pbs_path != path
|
||||
f.write("\#-------------------------------\r\n")
|
||||
if schema["SectionName"]
|
||||
f.write("[")
|
||||
pbWriteCsvRecord(element.get_property_for_PBS("SectionName"), f, schema["SectionName"])
|
||||
f.write("]\r\n")
|
||||
else
|
||||
f.write("[#{element.id}]\r\n")
|
||||
end
|
||||
# Write each animation property
|
||||
schema.each_key do |key|
|
||||
next if ["SectionName", "Particle"].include?(key)
|
||||
val = element.get_property_for_PBS(key)
|
||||
next if val.nil?
|
||||
f.write(sprintf("%s = ", key))
|
||||
pbWriteCsvRecord(val, f, schema[key])
|
||||
f.write("\r\n")
|
||||
end
|
||||
# Write each particle in turn
|
||||
element.particles.sort! do |a, b|
|
||||
a_val = 0
|
||||
a_val = -2 if a[:name] == "User"
|
||||
a_val = -1 if a[:name] == "Target"
|
||||
a_val = 1 if a[:name] == "SE"
|
||||
b_val = 0
|
||||
b_val = -2 if b[:name] == "User"
|
||||
b_val = -1 if b[:name] == "Target"
|
||||
b_val = 1 if b[:name] == "SE"
|
||||
next a_val <=> b_val
|
||||
end
|
||||
element.particles.each_with_index do |particle, i|
|
||||
# Write header
|
||||
f.write("<" + particle[:name] + ">")
|
||||
f.write("\r\n")
|
||||
# Write one-off particle properties
|
||||
sub_schema.each_pair do |key, val|
|
||||
next if val[1][0] == "^"
|
||||
val = element.get_particle_property_for_PBS(key, i)
|
||||
next if val.nil?
|
||||
f.write(sprintf(" %s = ", key))
|
||||
pbWriteCsvRecord(val, f, sub_schema[key])
|
||||
f.write("\r\n")
|
||||
end
|
||||
# Write particle commands (in keyframe order)
|
||||
cmds = element.get_particle_property_for_PBS("AllCommands", i)
|
||||
cmds.each do |cmd|
|
||||
if cmd[2] == 0 # Duration of 0
|
||||
f.write(sprintf(" %s = ", cmd[0]))
|
||||
new_cmd = cmd[1..-1]
|
||||
new_cmd.delete_at(1)
|
||||
pbWriteCsvRecord(new_cmd, f, sub_schema[cmd[0]])
|
||||
f.write("\r\n")
|
||||
else # Has a duration
|
||||
f.write(sprintf(" %s = ", cmd[0]))
|
||||
pbWriteCsvRecord(cmd[1..-1], f, sub_schema[cmd[0]])
|
||||
f.write("\r\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
process_pbs_file_message_end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Hook into the regular Compiler to also write all animation PBS files.
|
||||
#===============================================================================
|
||||
module Compiler
|
||||
module_function
|
||||
|
||||
class << self
|
||||
if !method_defined?(:__new_anims__write_all)
|
||||
alias_method :__new_anims__write_all, :write_all
|
||||
end
|
||||
end
|
||||
|
||||
def write_all
|
||||
__new_anims__write_all
|
||||
Console.echo_h1(_INTL("Writing all animation PBS files"))
|
||||
write_all_battle_animations
|
||||
echoln ""
|
||||
Console.echo_h2(_INTL("Successfully rewrote all animation PBS files"), text: :green)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user