mirror of
https://github.com/maddievision/Celestial.git
synced 2024-08-14 23:55:37 +00:00
Add write bin and JSON read/write
This commit is contained in:
parent
c91b1799cb
commit
664c684b79
1 changed files with 161 additions and 22 deletions
|
@ -1,5 +1,6 @@
|
||||||
require './rom'
|
require './rom'
|
||||||
|
require './binwriter'
|
||||||
|
require 'json'
|
||||||
# Value Types
|
# Value Types
|
||||||
# :boolean, :u8, :s16, :s32, :float, :lookup, :bin, :rle
|
# :boolean, :u8, :s16, :s32, :float, :lookup, :bin, :rle
|
||||||
|
|
||||||
|
@ -63,22 +64,154 @@ class Element
|
||||||
def [] name
|
def [] name
|
||||||
attributes[name.to_s]
|
attributes[name.to_s]
|
||||||
end
|
end
|
||||||
|
def to_h
|
||||||
|
{
|
||||||
|
'name' => name,
|
||||||
|
'package' => package,
|
||||||
|
'attributes' => attributes,
|
||||||
|
'attribute_types' => attributes_value_types,
|
||||||
|
'children' => children.map(&:to_h)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
def strings
|
||||||
|
strs = []
|
||||||
|
strs << name
|
||||||
|
attributes.each do |k, v|
|
||||||
|
strs << k
|
||||||
|
strs << v if attributes_value_types[k].to_sym == :lookup
|
||||||
|
end
|
||||||
|
children.each do |c|
|
||||||
|
strs += c.strings
|
||||||
|
end
|
||||||
|
strs.compact.uniq
|
||||||
|
end
|
||||||
|
def self.from_h obj
|
||||||
|
element = self.new
|
||||||
|
element.name = obj['name']
|
||||||
|
element.package = obj['package']
|
||||||
|
element.attributes = obj['attributes']
|
||||||
|
element.attributes_value_types = obj['attribute_types']
|
||||||
|
element.children = obj['children'].map { |c| from_h c }
|
||||||
|
element
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class CelesteMapReader
|
class CelesteMapReader
|
||||||
attr_accessor :rom, :package, :string_lookup, :root
|
attr_accessor :debug, :rom, :package, :string_lookup, :root, :writer
|
||||||
def initialize fn
|
def initialize fn, fmt: :bin, debug: false
|
||||||
|
@debug = debug
|
||||||
|
case fmt
|
||||||
|
when :bin
|
||||||
@rom = ROM.from_file(fn)
|
@rom = ROM.from_file(fn)
|
||||||
raise "Not a celeste map" unless rom.read_str_varlen == 'CELESTE MAP'
|
raise "Not a celeste map" unless rom.read_str_varlen == 'CELESTE MAP'
|
||||||
@package = rom.read_str_varlen
|
@package = rom.read_str_varlen
|
||||||
@string_lookup = (0...rom.read_u16_le).map { rom.read_str_varlen }
|
@string_lookup = (0...rom.read_u16_le).map { rom.read_str_varlen }
|
||||||
@root = read_element
|
@root = read_element
|
||||||
@root.package = @package
|
@root.package = @package
|
||||||
|
when :json
|
||||||
|
obj = File.open(fn, 'rb') { |f| JSON.parse(f.read) }
|
||||||
|
raise "Not a celeste map" unless obj['type'] == 'CELESTE MAP'
|
||||||
|
@root = Element.from_h(obj['root'])
|
||||||
|
@package = @root.package
|
||||||
|
else
|
||||||
|
raise "unknown fmt #{fmt}"
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def write fn
|
||||||
|
@writer = BinWriter.new(fn)
|
||||||
|
@string_lookup = root.strings
|
||||||
|
writer.write_str_varlen 'CELESTE MAP'
|
||||||
|
writer.write_str_varlen root.package
|
||||||
|
writer.write_u16_le string_lookup.size
|
||||||
|
string_lookup.each do |s|
|
||||||
|
writer.write_str_varlen s
|
||||||
|
end
|
||||||
|
write_element root
|
||||||
|
writer.close
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_json fn
|
||||||
|
File.open(fn, 'wb') do |f|
|
||||||
|
f.write JSON.pretty_generate(
|
||||||
|
obj = {
|
||||||
|
'type' => 'CELESTE MAP',
|
||||||
|
'root' => root.to_h
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_element element
|
||||||
|
writer.write_u16_le string_lookup.index(element.name)
|
||||||
|
writer.write_byte element.attributes.size
|
||||||
|
element.attributes.each do |k, v|
|
||||||
|
writer.write_u16_le string_lookup.index(k)
|
||||||
|
vt = element.attributes_value_types[k]
|
||||||
|
case vt.to_sym
|
||||||
|
when :boolean
|
||||||
|
writer.write_byte 0
|
||||||
|
writer.write_bool v
|
||||||
|
when :u8
|
||||||
|
writer.write_byte 1
|
||||||
|
writer.write_byte v
|
||||||
|
when :s16
|
||||||
|
writer.write_byte 2
|
||||||
|
writer.write_s16_le v
|
||||||
|
when :s32
|
||||||
|
writer.write_byte 3
|
||||||
|
writer.write_s32_le v
|
||||||
|
when :float
|
||||||
|
writer.write_byte 4
|
||||||
|
writer.write_f32_le v
|
||||||
|
when :lookup
|
||||||
|
writer.write_byte 5
|
||||||
|
writer.write_u16_le string_lookup.index(v)
|
||||||
|
when :bin
|
||||||
|
writer.write_byte 6
|
||||||
|
writer.write_varlen_le v.size
|
||||||
|
v.each do |b|
|
||||||
|
writer.write_byte b
|
||||||
|
end
|
||||||
|
when :rle
|
||||||
|
writer.write_byte 7
|
||||||
|
rle = []
|
||||||
|
count = 0
|
||||||
|
lb = -1
|
||||||
|
v.each do |b|
|
||||||
|
if b != lb
|
||||||
|
if lb >= 0
|
||||||
|
rle << count
|
||||||
|
rle << lb
|
||||||
|
end
|
||||||
|
count = 0
|
||||||
|
lb = b
|
||||||
|
end
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
if lb >= 0
|
||||||
|
rle << count
|
||||||
|
rle << lb
|
||||||
|
end
|
||||||
|
writer.write_u16_le rle.size
|
||||||
|
rle.each do |b|
|
||||||
|
writer.write_byte b
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise "unknown value type #{vt} for key #{k} with value #{v}"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
writer.write_u16_le element.children.size
|
||||||
|
element.children.each do |child|
|
||||||
|
write_element child
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def read_element pre=0
|
def read_element pre=0
|
||||||
element = Element.new
|
element = Element.new
|
||||||
element.name = string_lookup[rom.read_u16_le]
|
element.name = string_lookup[rom.read_u16_le]
|
||||||
# puts "#{" " * pre}<#{element.name}"
|
dputs "#{" " * pre}<#{element.name}"
|
||||||
rom.read_byte.times do |i|
|
rom.read_byte.times do |i|
|
||||||
key = string_lookup[rom.read_u16_le]
|
key = string_lookup[rom.read_u16_le]
|
||||||
value_type_enc = rom.read_byte
|
value_type_enc = rom.read_byte
|
||||||
|
@ -88,30 +221,30 @@ class CelesteMapReader
|
||||||
when 0
|
when 0
|
||||||
value = rom.read_bool
|
value = rom.read_bool
|
||||||
if value
|
if value
|
||||||
# puts "#{" " * (pre + 2)}#{key}"
|
dputs "#{" " * (pre + 2)}#{key}"
|
||||||
else
|
else
|
||||||
# puts "#{" " * (pre + 2)}#{key}={#{value}}"
|
dputs "#{" " * (pre + 2)}#{key}={#{value}}"
|
||||||
end
|
end
|
||||||
value_type = :boolean
|
value_type = :boolean
|
||||||
when 1
|
when 1
|
||||||
value = rom.read_byte
|
value = rom.read_byte
|
||||||
# puts "#{" " * (pre + 2)}#{key}={#{value}}"
|
dputs "#{" " * (pre + 2)}#{key}={#{value}}"
|
||||||
value_type = :u8
|
value_type = :u8
|
||||||
when 2
|
when 2
|
||||||
value = rom.read_s16_le
|
value = rom.read_s16_le
|
||||||
# puts "#{" " * (pre + 2)}#{key}={#{value}}"
|
dputs "#{" " * (pre + 2)}#{key}={#{value}}"
|
||||||
value_type = :s16
|
value_type = :s16
|
||||||
when 3
|
when 3
|
||||||
value = rom.read_s32_le
|
value = rom.read_s32_le
|
||||||
# puts "#{" " * (pre + 2)}#{key}={#{value}}"
|
dputs "#{" " * (pre + 2)}#{key}={#{value}}"
|
||||||
value_type = :s32
|
value_type = :s32
|
||||||
when 4
|
when 4
|
||||||
value = rom.read_f32_le
|
value = rom.read_f32_le
|
||||||
# puts "#{" " * (pre + 2)}#{key}={#{value}}"
|
dputs "#{" " * (pre + 2)}#{key}={#{value}}"
|
||||||
value_type = :float
|
value_type = :float
|
||||||
when 5
|
when 5
|
||||||
value = string_lookup[rom.read_u16_le]
|
value = string_lookup[rom.read_u16_le]
|
||||||
# puts "#{" " * (pre + 2)}#{key}=\"#{value}\""
|
dputs "#{" " * (pre + 2)}#{key}=\"#{value}\""
|
||||||
value_type = :lookup
|
value_type = :lookup
|
||||||
when 6
|
when 6
|
||||||
count = rom.read_varlen_le
|
count = rom.read_varlen_le
|
||||||
|
@ -121,8 +254,9 @@ class CelesteMapReader
|
||||||
bin << rom.read_byte
|
bin << rom.read_byte
|
||||||
end
|
end
|
||||||
# value = rom.read_str_varlen
|
# value = rom.read_str_varlen
|
||||||
# # puts "#{" " * (pre + 2)}#{key}=\"#{value}\""
|
dputs "#{" " * (pre + 2)}#{key}=\"#{value}\""
|
||||||
# puts "#{" " * (pre + 2)}#{key}={bin#{bin.inspect}}"
|
dputs "#{" " * (pre + 2)}#{key}={bin#{bin.inspect}}"
|
||||||
|
value = bin
|
||||||
value_type = :bin
|
value_type = :bin
|
||||||
when 7
|
when 7
|
||||||
count = rom.read_u16_le
|
count = rom.read_u16_le
|
||||||
|
@ -134,20 +268,25 @@ class CelesteMapReader
|
||||||
num.times { bin << val }
|
num.times { bin << val }
|
||||||
end
|
end
|
||||||
value = bin
|
value = bin
|
||||||
# puts "#{" " * (pre + 2)}#{key}={rle#{bin.inspect}}"
|
dputs "#{" " * (pre + 2)}#{key}={rle#{bin.inspect}}"
|
||||||
value_type = :rle
|
value_type = :rle
|
||||||
|
else
|
||||||
|
raise "unknown value type byte #{value_type_enc} for key #{key}"
|
||||||
end
|
end
|
||||||
element.attributes[key] = value
|
element.attributes[key] = value
|
||||||
element.attributes_value_types[key] = value_type
|
element.attributes_value_types[key] = value_type
|
||||||
end
|
end
|
||||||
# puts "#{" " * pre}>"
|
dputs "#{" " * pre}>"
|
||||||
rom.read_u16_le.times do |j|
|
rom.read_u16_le.times do |j|
|
||||||
element.children << read_element(pre + 2)
|
element.children << read_element(pre + 2)
|
||||||
end
|
end
|
||||||
# puts "#{" " * pre}</#{element.name}>"
|
dputs "#{" " * pre}</#{element.name}>"
|
||||||
element
|
element
|
||||||
end
|
end
|
||||||
def inspect
|
def inspect
|
||||||
"<Bin #{package} />"
|
"<Bin #{package} />"
|
||||||
end
|
end
|
||||||
|
def dputs s
|
||||||
|
puts s if @debug
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue