more and more update

This commit is contained in:
Ishotihadus
2019-12-09 00:44:21 +09:00
parent 629e82353a
commit e1ac05e540
1066 changed files with 1797 additions and 1384 deletions
+2
View File
@@ -15,3 +15,5 @@
*.bundle
.DS_Store
.idea/
*.iml
+72 -71
View File
@@ -1,101 +1,102 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'mikunyan'
require 'mikunyan/decoders'
require 'fileutils'
begin
require 'usamin'
require 'usamin/overwrite'
require 'usamin'
require 'usamin/overwrite'
rescue LoadError
require 'json'
require 'json'
end
opts = {:as_asset => false, :outputdir => nil, :sprite => false, :pretty => false}
opts = { as_asset: false, outputdir: nil, sprite: false, pretty: false }
arg = nil
i = 0
while i < ARGV.count
if ARGV[i].start_with?('-')
case ARGV[i]
when '--as-asset', '-a'
opts[:as_asset] = true
when '--outputdir', '-o'
i += 1
opts[:outputdir] = ARGV[i]
when '--sprite', '-s'
opts[:sprite] = true
when '--pretty', '-p'
opts[:pretty] = true
else
warn("Unknown option: #{ARGV[i]}")
end
if ARGV[i].start_with?('-')
case ARGV[i]
when '--as-asset', '-a'
opts[:as_asset] = true
when '--outputdir', '-o'
i += 1
opts[:outputdir] = ARGV[i]
when '--sprite', '-s'
opts[:sprite] = true
when '--pretty', '-p'
opts[:pretty] = true
else
arg = ARGV[i] unless arg
warn("Unknown option: #{ARGV[i]}")
end
i += 1
else
arg ||= ARGV[i]
end
i += 1
end
unless arg
warn("Input file is not specified")
exit(1)
warn('Input file is not specified')
exit(1)
end
unless File.file?(arg)
warn("File not found: #{arg}")
exit(1)
warn("File not found: #{arg}")
exit(1)
end
assets = []
if opts[:as_asset]
assets = [Mikunyan::Asset.file(arg, File.basename(arg, '.*'))]
else
assets = Mikunyan::AssetBundle.file(arg).assets
end
assets = opts[:as_asset] ? [Mikunyan::Asset.file(arg)] : Mikunyan::AssetBundle.file(arg).assets
outdir = opts[:outputdir] || File.basename(arg, '.*')
FileUtils.mkpath(outdir)
assets.each do |asset|
if opts[:sprite]
json = {}
textures = {}
if opts[:sprite]
json = {}
textures = {}
asset.objects.select{|o| asset.object_type(o) == 'Sprite'}.each do |o|
obj = asset.parse_object(o)
next unless obj
name = obj.m_Name.value
tex_id = obj.m_RD.texture.m_PathID.value
asset.each_object do |obj|
next unless obj.type == 'Sprite'
obj = obj.parse
next unless obj
texture_id = obj.m_RD&.texture&.m_PathID&.value
next unless texture_id
unless textures[tex_id]
tex_obj = asset.parse_object(tex_id)
if tex_obj
textures[tex_id] = Mikunyan::ImageDecoder.decode_object(tex_obj)
json[tex_id] = {:name => tex_obj.m_Name.value, :width => textures[tex_id].width, :height => textures[tex_id].height, :path_id => tex_id, :sprites => []} if textures[tex_id]
end
end
if textures[tex_id]
x = obj.m_Rect.x.value
y = obj.m_Rect.y.value
width = obj.m_Rect.width.value
height = obj.m_Rect.height.value
json[tex_id][:sprites] << {:name => name, :x => x, :y => y, :width => width, :height => height, :path_id => o.path_id}
textures[tex_id].crop(x.round, (textures[tex_id].height - height - y).round, width.round, height.round).save("#{outdir}/#{name}.png")
end
unless textures.key?(texture_id)
texture_obj = asset.parse_object(texture_id)
if texture_obj.is_a?(Mikunyan::CustomTypes::Texture2D)
textures[texture_id] = texture_obj.generate_png
json[texture_id] = {
name: texture_obj.m_Name&.value, width: texture_obj.m_Width&.value, height: texture_obj.m_Height&.value,
format: texture_obj.m_TextureFormat&.value, path_id: texture_id, sprites: []
}
end
puts opts[:pretty] ? JSON.pretty_generate(json.values) : JSON.generate(json.values)
else
json = []
asset.objects.select{|o| asset.object_type(o) == 'Texture2D'}.each do |o|
obj = asset.parse_object(o)
next unless obj
name = obj.m_Name.value
image = Mikunyan::ImageDecoder.decode_object(obj)
if image
json << {:name => name, :width => image.width, :height => image.height, :path_id => o.path_id}
image.save("#{outdir}/#{name}.png")
end
end
puts opts[:pretty] ? JSON.pretty_generate(json) : JSON.generate(json)
end
x = obj.m_Rect&.x&.value
y = obj.m_Rect&.y&.value
width = obj.m_Rect&.width&.value
height = obj.m_Rect&.height&.value
json[texture_id][:sprites] << { name: obj.object_name, x: x, y: y, width: width, height: height, path_id: obj.path_id }
next unless textures[texture_id] && x && y && width && height
textures[texture_id].crop(
x.round, (textures[texture_id].height - height - y).round, width.round, height.round
).save("#{outdir}/#{obj.object_name}.png")
end
puts opts[:pretty] ? JSON.pretty_generate(json.values) : JSON.generate(json.values)
else
json = []
asset.each_object do |obj|
next unless obj.type == 'Texture2D'
obj = obj.parse
next unless obj.is_a?(Mikunyan::CustomTypes::Texture2D)
json << {
name: obj.object_name, width: obj.width, height: obj.height,
format: obj.texture_format, path_id: obj.path_id
}
obj.generate_png&.save("#{outdir}/#{obj.object_name}.png")
end
puts opts[:pretty] ? JSON.pretty_generate(json) : JSON.generate(json)
end
end
+46 -65
View File
@@ -1,89 +1,70 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'mikunyan'
require 'base64'
def obj64(obj)
if obj.class == Hash
obj.map{|k, v| [k, obj64(v)]}.to_h
elsif obj.class == Array
obj.map{|e| obj64(e)}
elsif obj.class == String
if obj.encoding == Encoding::UTF_8
obj
else
Base64::strict_encode64(obj)
end
if obj.is_a?(Hash)
obj.map{|k, v| [k, obj64(v)]}.to_h
elsif obj.is_a?(Array)
obj.map{|e| obj64(e)}
elsif obj.is_a?(String)
if obj.encoding == Encoding::UTF_8
obj
else
obj
Base64.strict_encode64(obj)
end
else
obj
end
end
opts = {:as_asset => false, :pretty => false, :yaml => false}
opts = { as_asset: false, pretty: false, yaml: false }
arg = nil
i = 0
while i < ARGV.count
if ARGV[i].start_with?('-')
case ARGV[i]
when '--as-asset', '-a'
opts[:as_asset] = true
when '--pretty', '-p'
opts[:pretty] = true
when '--yaml', '-y'
opts[:yaml] = true
else
warn("Unknown option: #{ARGV[i]}")
end
if ARGV[i].start_with?('-')
case ARGV[i]
when '--as-asset', '-a'
opts[:as_asset] = true
when '--pretty', '-p'
opts[:pretty] = true
when '--yaml', '-y'
opts[:yaml] = true
else
arg = ARGV[i] unless arg
warn("Unknown option: #{ARGV[i]}")
end
i += 1
else
arg ||= ARGV[i]
end
i += 1
end
if opts[:pretty] && opts[:yaml]
warn("Option --pretty is ignored if --yaml is specified.")
end
warn('Option --pretty is ignored if --yaml is specified.') if opts[:pretty] && opts[:yaml]
unless File.file?(arg)
warn("File not found: #{arg}")
exit(1)
warn("File not found: #{arg}")
exit(1)
end
assets = {}
if opts[:as_asset]
asset = Mikunyan::Asset.file(arg, arg.match(/([^\/]*?)(\.[^.]*)?\z/)[1])
objs = []
asset.path_ids.each do |e|
obj = asset.parse_object_simple(e)
objs << obj
end
assets[asset.name] = objs
else
bundle = Mikunyan::AssetBundle.file(arg)
bundle.assets.each do |asset|
objs = []
asset.path_ids.each do |e|
obj = asset.parse_object_simple(e)
objs << obj
end
assets[asset.name] = objs
end
end
assets = opts[:as_asset] ? [Mikunyan::Asset.file(arg)] : Mikunyan::AssetBundle.file(arg).assets
assets = assets.map{|asset| [asset.name, asset.each_object.map(&:parse_simple)]}.to_h
if opts[:yaml]
require 'yaml'
puts YAML.dump(assets)
require 'yaml'
puts YAML.dump(assets)
else
begin
require 'usamin'
require 'usamin/overwrite'
rescue LoadError
require 'json'
end
assets = assets.map{|k, v| [k, obj64(v)]}.to_h
if opts[:pretty]
puts JSON.pretty_generate(assets)
else
puts JSON.generate(assets)
end
begin
require 'usamin'
require 'usamin/overwrite'
rescue LoadError
require 'json'
end
assets = assets.map{|k, v| [k, obj64(v)]}.to_h
if opts[:pretty]
puts JSON.pretty_generate(assets)
else
puts JSON.generate(assets)
end
end
-6
View File
@@ -1,13 +1,7 @@
# frozen_string_literal: true
require 'mikunyan/version'
require 'mikunyan/asset_bundle'
require 'mikunyan/asset'
require 'mikunyan/binary_reader'
require 'mikunyan/object_value'
require 'mikunyan/type_tree'
require 'mikunyan/constants'
# Module for deserializing Unity Assets and AssetBundles
module Mikunyan
+190 -221
View File
@@ -1,5 +1,10 @@
# frozen_string_literal: true
require 'mikunyan/type_tree'
require 'mikunyan/constants'
require 'mikunyan/object_value'
require 'mikunyan/base_object'
module Mikunyan
# Class for representing Unity Asset
# @attr_reader [String] name Asset name
@@ -8,18 +13,19 @@ module Mikunyan
# @attr_reader [Integer] target_platform target platform number
# @attr_reader [Symbol] endian data endianness (:little or :big)
# @attr_reader [Array<Mikunyan::Asset::Klass>] klasses defined classes
# @attr_reader [Array<Mikunyan::Asset::ObjectData>] objects included objects
# @attr_reader [Array<Integer>] add_ids ?
# @attr_reader [Array<Mikunyan::Asset::ObjectEntry>] objects contained objects
# @attr_reader [Array<Mikunyan::Asset::LocalObjectEntry>] add_ids ?
# @attr_reader [Array<Mikunyan::Asset::Reference>] references reference data
class Asset
attr_reader :name, :format, :generator_version, :target_platform, :endian, :klasses, :objects, :add_ids, :references, :res_s
attr_reader :name, :format, :generator_version, :target_platform, :endian, :klasses, :objects, :add_ids, :references
# Struct for representing Asset class definition
# @attr [Integer] class_id class ID
# @attr [Boolean] stripped?
# @attr [Integer,nil] script_id script ID
# @attr [String] hash hash value (16 or 32 bytes)
# @attr [Mikunyan::TypeTree, nil] type_tree given TypeTree
Klass = Struct.new(:class_id, :script_id, :hash, :type_tree)
Klass = Struct.new(:class_id, :stripped?, :script_id, :hash, :type_tree)
# Struct for representing Asset object information
# @attr [Integer] path_id path ID
@@ -30,7 +36,29 @@ module Mikunyan
# @attr [Integer,nil] class_idx class definition index
# @attr [Boolean] destroyed? destroyed or not
# @attr [String] data binary data of object
ObjectData = Struct.new(:path_id, :offset, :size, :type_id, :class_id, :class_idx, :destroyed?, :data)
# @attr [Mikunyan::Asset] parent_asset
# @attr [Klass] klass
ObjectEntry = Struct.new(
:path_id, :offset, :size, :type_id, :class_id, :class_idx, :destroyed?, :stripped?,
:data, :parent_asset, :klass,
keyword_init: true
) do
def parse
parent_asset.parse_object(self)
end
def parse_simple
parent_asset.parse_object_simple(self)
end
# Returns object type name string
# @return [String,nil] type name
def type
klass&.type_tree&.tree&.type || Mikunyan::Constants::CLASS_ID2NAME[class_id]
end
end
LocalObjectEntry = Struct.new(:file_id, :local_id)
# Struct for representing Asset reference information
# @attr [String] path path
@@ -39,13 +67,20 @@ module Mikunyan
# @attr [String] file_path Asset name
Reference = Struct.new(:path, :guid, :type, :file_path)
# Strcut for container information
# @attr [String] name
# @attr [Integer] preload_index
# @attr [Integer] path_id
ContainerInfo = Struct.new(:name, :preload_index, :preload_size, :file_id, :path_id)
# Load Asset from binary string
# @param [String] bin binary data
# @param [String,IO] bin binary data
# @param [String] name Asset name
# @param [String] resource resource data
# @param [String] res_s resS data
# @return [Mikunyan::Asset] deserialized Asset object
def self.load(bin, name, res_s = nil)
r = Asset.new(name, res_s)
def self.load(bin, name, resource = nil, res_s = nil)
r = Asset.new(name, resource, res_s)
r.send(:load, bin)
r
end
@@ -56,7 +91,15 @@ module Mikunyan
# @return [Mikunyan::Asset] deserialized Asset object
def self.file(file, name = nil)
name ||= File.basename(name, '.*')
Asset.load(File.binread(file), name)
File.open(file, 'rb') do |io|
Asset.load(io, name)
end
end
# Same as objects.each
# @return [Enumerator<Mikunyan::Asset::ObjectEntry>,Array<Mikunyan::Asset::ObjectEntry>]
def each_object(&block)
@objects.each(&block)
end
# Returns list of all path IDs
@@ -68,273 +111,199 @@ module Mikunyan
# Returns list of containers
# @return [Array<Hash>,nil] list of all containers
def containers
obj = parse_object(1)
return nil unless obj&.m_Container && obj.m_Container.array?
obj.m_Container.value.map do |e|
{ name: e.first.value, preload_index: e.second.preloadIndex.value, path_id: e.second.asset.m_PathID.value }
obj = @path_id_table[1]
return nil unless obj.klass&.type_tree&.tree&.type == 'AssetBundle'
parse_object(obj).m_Container.value.map do |e|
ContainerInfo.new(e.first.value, e.second.preloadIndex.value, e.second.preloadSize.value, e.second.asset.m_FileID.value, e.second.asset.m_PathID.value)
end
end
# Parse object of given path ID
# @param [Integer,ObjectData] path_id path ID or object
# @return [Mikunyan::ObjectValue,nil] parsed object
def parse_object(path_id)
if path_id.class == Integer
obj = @objects.find{|e| e.path_id == path_id}
return nil unless obj
elsif path_id.class == ObjectData
obj = path_id
else
return nil
end
klass = (obj.class_idx ? @klasses[obj.class_idx] : @klasses.find{|e| e.class_id == obj.class_id} || @klasses.find{|e| e.class_id == obj.type_id})
type_tree = Asset.parse_type_tree(klass)
return nil unless type_tree
parse_object_private(BinaryReader.new(obj.data, @endian), type_tree)
# @param [Integer,ObjectEntry] obj path ID or object
# @return [Mikunyan::BaseObject,nil] parsed object
def parse_object(obj)
obj = @path_id_table[obj] if obj.class == Integer
return nil unless obj.klass&.type_tree
value_klass = Mikunyan::CustomTypes.get_custom_type(obj.klass.type_tree.tree.type, obj.class_id)
ret = parse_object_private(BinaryReader.new(obj.data, @endian), obj.klass.type_tree.tree, value_klass)
ret.object_entry = obj
ret
end
# Parse object of given path ID and simplify it
# @param [Integer,ObjectData] path_id path ID or object
# @param [Integer,ObjectEntry] obj path ID or object
# @return [Hash,nil] parsed object
def parse_object_simple(path_id)
Asset.object_simplify(parse_object(path_id))
def parse_object_simple(obj)
parse_object(obj)&.simplify
end
# Returns object type name string
# @param [Integer,ObjectData] path_id path ID or object
# @param [Integer,ObjectEntry] obj path ID or object
# @return [String,nil] type name
def object_type(path_id)
if path_id.class == Integer
obj = @objects.find{|e| e.path_id == path_id}
return nil unless obj
elsif path_id.class == ObjectData
obj = path_id
else
return nil
end
klass = (obj.class_idx ? @klasses[obj.class_idx] : @klasses.find{|e| e.class_id == obj.class_id} || @klasses.find{|e| e.class_id == obj.type_id})
if klass&.type_tree && klass.type_tree.nodes[0]
klass.type_tree.nodes[0].type
elsif klass
Mikunyan::CLASS_ID[klass.class_id]
end
def object_type(obj)
obj = @path_id_table[obj] if obj.class == Integer
obj&.type
end
def self.object_simplify(obj)
obj.is_a?(ObjectValue) ? obj.simplify : obj
end
private
def initialize(name, res_s = nil)
def initialize(name, resource = nil, res_s = nil)
@name = name
@endian = :big
@resource = resource
@res_s = res_s
end
def load(bin)
br = BinaryReader.new(bin)
metadata_size = br.i32u
size = br.i32u
meta_size = br.i32u
file_size = br.i32u
@format = br.i32u
data_offset = br.i32u
if @format >= 9
@endian = :little if br.i32 == 0
br.endian = @endian
end
@generator_version = br.cstr
@target_platform = br.i32
@klasses = []
if @format >= 17
has_type_trees = (br.i8 != 0)
type_tree_count = br.i32u
type_tree_count.times do
class_id = br.i32
br.adv(1)
script_id = br.i16
hash = if class_id < 0 || class_id == 114
br.read(32)
else
br.read(16)
end
@klasses << Klass.new(class_id, script_id, hash, has_type_trees ? TypeTree.load(br) : TypeTree.load_default(hash))
end
elsif @format >= 13
has_type_trees = (br.i8 != 0)
type_tree_count = br.i32u
type_tree_count.times do
class_id = br.i32
hash = if class_id < 0
br.read(32)
else
br.read(16)
end
@klasses << Klass.new(class_id, nil, hash, has_type_trees ? TypeTree.load(br) : TypeTree.load_default(hash))
end
@endian = br.bool ? :big : :little
br.adv(3)
else
@type_trees = {}
type_tree_count = br.i32u
type_tree_count.times do
class_id = br.i32
@klasses << Klass.new(class_id, nil, nil, @format == 10 || @format == 12 ? TypeTree.load(br) : TypeTree.load_legacy(br))
br.pos = file_size - meta_size
@endian = br.bool ? :big : :little
end
br.endian = @endian
@generator_version = br.cstr if @format >= 7
@target_platform = br.i32 if @format >= 8
has_type_trees = @format >= 13 ? br.bool : true
type_count = br.i32u
@klasses = Array.new(type_count) do
class_id = br.i32s
stripped = br.bool if @format >= 16
script_id = br.i16 if @format >= 17
hash = br.read(@format < 16 && class_id < 0 || @format >= 16 && class_id == 114 ? 32 : 16) if @format >= 13
type_tree = has_type_trees ? TypeTree.load(br, @format) : TypeTree.load_default(class_id, hash)
Klass.new(class_id, stripped, script_id, hash, type_tree)
end
wide_path_id = @format >= 14 || @format >= 7 && br.i32 != 0
object_count = br.i32u
@objects = Array.new(object_count) do
br.align(4) if @format >= 14
if @format >= 16
ObjectEntry.new(
path_id: wide_path_id ? br.i64s : br.i32s, offset: br.i32u, size: br.i32u,
class_idx: br.i32u, stripped?: @format == 16 ? br.bool : nil,
parent_asset: self
)
else
ObjectEntry.new(
path_id: wide_path_id ? br.i64s : br.i32s, offset: br.i32u, size: br.i32u,
type_id: br.i32, class_id: br.i16, destroyed?: br.i16 == 1, stripped?: @format == 15 ? br.bool : nil,
parent_asset: self
)
end
end
long_object_ids = (@format >= 14 || (7 <= @format && @format <= 13 && br.i32 != 0))
@objects = []
object_count = br.i32u
object_count.times do
br.align(4) if @format >= 14
path_id = long_object_ids ? br.i64 : br.i32
offset = br.i32u
size = br.i32u
@objects << if @format >= 17
ObjectData.new(path_id, offset, size, nil, nil, br.i32u, @format <= 10 && br.i16 != 0)
else
ObjectData.new(path_id, offset, size, br.i32, br.i16, nil, @format <= 10 && br.i16 != 0)
end
br.adv(2) if 11 <= @format && @format <= 16
br.adv(1) if 15 <= @format && @format <= 16
end
@path_id_table = @objects.map{|e| [e.path_id, e]}.to_h
if @format >= 11
@add_ids = []
add_id_count = br.i32u
add_id_count.times do
@add_ids = Array.new(add_id_count) do
br.align(4) if @format >= 14
@add_ids << [(long_object_ids ? br.i64 : br.i32), br.i32]
LocalObjectEntry.new(br.i32u, wide_path_id ? br.i64s : br.i32s)
end
end
if @format >= 6
@references = []
reference_count = br.i32u
reference_count.times do
@references << Reference.new(br.cstr, br.read(16), br.i32, br.cstr)
end
reference_count = br.i32u
@references = Array.new(reference_count) do
Reference.new(@format >= 6 ? br.cstr : nil, @format >= 5 ? br.read(16) : nil, @format >= 5 ? br.i32s : nil, br.cstr)
end
@comment = br.cstr if @format >= 5
@objects.each do |e|
br.jmp(data_offset + e.offset)
e.data = br.read(e.size)
e.klass = e.class_idx ? @klasses[e.class_idx] : @klasses.find{|e2| e2.class_id == e.class_id} || @klasses.find{|e2| e2.class_id == e.type_id}
end
end
def parse_object_private(br, type_tree)
r = nil
node = type_tree[:node]
children = type_tree[:children]
# @param [Mikunyan::BinaryReader] br
# @param [Mikunyan::TypeTree::Node] node
def parse_object_private(br, node, klass = ObjectValue)
ret = klass.new(node.name, node.type, br.endian)
children = node.children
if node.array?
data = nil
size = parse_object_private(br, children.find{|e| e[:name] == 'size'}).value
data_type_tree = children.find{|e| e[:name] == 'data'}
data = if node.type == 'TypelessData'
br.read(size * data_type_tree[:node].size)
else
size.times.map{parse_object_private(br, data_type_tree)}
end
r = ObjectValue.new(node.name, node.type, br.endian, data)
elsif node.size == -1
r = ObjectValue.new(node.name, node.type, br.endian)
if children.size == 1 && children[0][:name] == 'Array' && children[0][:node].type == 'Array' && children[0][:node].array?
if node.type == 'string'
size = parse_object_private(br, children[0][:children].find{|e| e[:name] == 'size'}).value
r.value = br.read(size * children[0][:children].find{|e| e[:name] == 'data'}[:node].size).force_encoding('utf-8')
br.align(4) if children[0][:node].flags & 0x4000 != 0
if children.empty?
pos = br.pos
ret.value =
case node.type
when 'bool'
br.bool
when 'SInt8'
br.i8s
when 'UInt8'
br.i8u
when 'SInt16', 'short'
br.i16s
when 'UInt16', 'unsigned short'
br.i16u
when 'SInt32', 'int'
br.i32s
when 'UInt32', 'unsigned int', 'Type*'
br.i32u
when 'SInt64', 'long long'
br.i64s
when 'UInt64', 'unsigned long long'
br.i64u
when 'float'
br.float
when 'double'
br.double
else
r.value = parse_object_private(br, children[0]).value
br.read(node.size)
end
elsif node.type == 'StreamingInfo'
children.each{|child| r[child[:name]] = parse_object_private(br, child)}
r.value = @res_s.byteslice(r['offset'].value, r['size'].value) if r['path'].value == "archive:/#{name}/#{name}.resS"
else
children.each do |child|
r[child[:name]] = parse_object_private(br, child)
end
end
elsif !children.empty?
pos = br.pos
r = ObjectValue.new(node.name, node.type, br.endian)
r.is_struct = true
br.jmp(pos + node.size) if node.size >= 0
elsif node.array?
children.each do |child|
r[child[:name]] = parse_object_private(br, child)
next ret[child.name] = parse_object_private(br, child) unless child.name == 'data'
size = ret['size']&.value || raise('`size` node must appear before `data` node in array node')
ret.value =
if child.children.empty? && (!child.need_align? || br.pos % 4 == 0 && child.size % 4 == 0)
if node.type == 'TypelessData'
br.read(size * child.size)
elsif child.type == 'char'
# string
br.read(size * child.size).force_encoding('utf-8')
end
end
ret.value ||= Array.new(size){parse_object_private(br, child)}
ret['data'] = ret.value
end
elsif children.size == 1 && children[0].array? && children[0].type == 'Array' && children[0].name == 'Array'
ret = parse_object_private(br, children[0])
ret.name = node.name
ret.type = node.type
else
pos = br.pos
value = nil
case node.type
when 'bool'
value = (br.i8 != 0)
when 'SInt8'
value = br.i8s
when 'UInt8', 'char'
value = br.i8u
when 'SInt16', 'short'
value = br.i16s
when 'UInt16', 'unsigned short'
value = br.i16u
when 'SInt32', 'int'
value = br.i32s
when 'UInt32', 'unsigned int'
value = br.i32u
when 'SInt64', 'long long'
value = br.i64s
when 'UInt64', 'unsigned long long'
value = br.i64u
when 'float'
value = br.float
when 'double'
value = br.double
when 'ColorRGBA'
value = [br.i8u, br.i8u, br.i8u, br.i8u]
ret.attr = children.map{|c| [c.name, parse_object_private(br, c)]}.to_h
if node.type == 'StreamingInfo'
ret.value =
if ret['path'].value == "archive:/#{name}/#{name}.resource"
@resource&.byteslice(ret['offset'].value, ret['size'].value)
elsif ret['path'].value == "archive:/#{name}/#{name}.resS"
@res_s&.byteslice(ret['offset'].value, ret['size'].value)
end
else
value = br.read(node.size)
ret.is_struct = true
end
br.jmp(pos + node.size)
r = ObjectValue.new(node.name, node.type, br.endian, value)
end
br.align(4) if node.flags & 0x4000 != 0
r
end
def self.object_simplify(obj)
if obj.class != ObjectValue
obj
elsif obj.type == 'pair'
[object_simplify(obj['first']), object_simplify(obj['second'])]
elsif obj.type == 'map' && obj.array?
obj.value.map{|e| [object_simplify(e['first']), object_simplify(e['second'])]}.to_h
elsif obj.value?
object_simplify(obj.value)
elsif obj.array?
obj.value.map{|e| object_simplify(e)}
else
hash = {}
obj.keys.each do |key|
hash[key] = object_simplify(obj[key])
end
hash
end
end
def self.parse_type_tree(klass)
return nil unless klass.type_tree
nodes = klass.type_tree.nodes
tree = {}
stack = []
nodes.each do |node|
this = { name: node.name, node: node, children: [] }
if node.depth == 0
tree = this
else
stack[node.depth - 1][:children] << this
end
stack[node.depth] = this
end
tree
br.align(4) if node.need_align?
ret
end
end
end
+86 -63
View File
@@ -2,19 +2,36 @@
require 'extlz4'
require 'extlzma'
require 'mikunyan/asset'
require 'mikunyan/binary_reader'
module Mikunyan
# Class for representing Unity AssetBundle
# @attr_reader [String] signature file signature (UnityRaw or UnityFS)
# @attr_reader [Integer] format file format number
# @attr_reader [String] unity_version version string of Unity to use this AssetBundle
# @attr_reader [String] unity_version version string of Unity for this AssetBundle
# @attr_reader [String] generator_version version string of generator
# @attr_reader [Array<Mikunyan::Asset>] assets included Assets
# @attr_reader [String] guid unique identifier (can be zero)
# @attr_reader [Array<Mikunyan::Asset>] assets contained Assets
class AssetBundle
attr_reader :signature, :format, :unity_version, :generator_version, :assets
attr_reader :signature, :format, :unity_version, :generator_version, :guid, :assets, :blobs
# Load AssetBundle from binary string
# @param [String] bin binary data
AssetEntry = Struct.new(:name, :data, :blob?, :status, keyword_init: true)
# @param [String,Integer] index
# @return [Mikunyan::Asset,nil]
def [](index)
index.is_a?(String) ? @assets.find{|e| e.name == index} : @assets[index]
end
# Same as assets.each
# @return [Enumerator<Mikunyan::Asset>,Array<Mikunyan::Asset>]
def each_asset(&block)
@assets.each(&block)
end
# Loads AssetBundle from binary string
# @param [String,IO] bin binary data
# @return [Mikunyan::AssetBundle] deserialized AssetBundle object
def self.load(bin)
r = AssetBundle.new
@@ -22,11 +39,13 @@ module Mikunyan
r
end
# Load AssetBundle from file
# Loads AssetBundle from file
# @param [String] file file name
# @return [Mikunyan::AssetBundle] deserialized AssetBundle object
def self.file(file)
AssetBundle.load(File.binread(file))
File.open(file, 'rb') do |io|
AssetBundle.load(io)
end
end
private
@@ -34,84 +53,71 @@ module Mikunyan
def load(bin)
br = BinaryReader.new(bin)
@signature = br.cstr
raise("Invalid signature: #{@signature}") unless @signature.start_with?('Unity')
@format = br.i32
@unity_version = br.cstr
@generator_version = br.cstr
case @signature
when 'UnityRaw'
load_unity_raw(br, false)
when 'UnityFS'
load_unity_fs(br)
when 'UnityWeb'
if @format <= 3
load_unity_raw(br, true)
else
load_unity_fs(br)
end
else
raise("Unknown signature: #{@signature}")
end
@format < 6 ? load_unity_raw(br) : load_unity_fs(br)
end
def load_unity_raw(br, compressed)
# @param [Mikunyan::BinaryReader] br
def load_unity_raw(br)
@assets = []
file_size = br.i32u
_file_size = br.i32u
header_size = br.i32u
if compressed
br.adv(4)
block_count = br.i32u
blocks = block_count.times.map{{ c: br.i32u, u: br.i32u }}
br.jmp(header_size)
data = ''
blocks.each{|b| data << LZMA.decode(br.read(b[:c]))}
br = BinaryReader.new(data)
else
br.jmp(header_size)
end
br.pos = header_size
# この部分全然わからん(ファイルの最後まで読まないとダメらしい?)
block = br.read(nil)
data = @signature == 'UnityRaw' ? block : uncompress_lzma(block, true)
br = BinaryReader.new(data)
asset_count = br.i32u
asset_count.times do
asset_pos = br.pos
asset_name = br.cstr
asset_header_size = br.i32u
asset_size = br.i32u
br.jmp(asset_pos + asset_header_size - 4)
asset_data = br.read(asset_size)
asset = Asset.load(asset_data, asset_name)
@assets << asset
asset_entries = Array.new(asset_count) do
name = br.cstr
offset = br.i32u
size = br.i32u
is_asset = ['', '.assets'].include?(split_name(name)[1]) && size > 16
AssetEntry.new(name: name, data: br.read_abs(size, offset), blob?: !is_asset)
end
process_asset_entries(asset_entries)
end
# @param [Mikunyan::BinaryReader] br
def load_unity_fs(br)
@assets = []
file_size = br.i64u
ci_block_size = br.i32u
ui_block_size = br.i32u
flags = br.i32u
head = BinaryReader.new(uncompress(flags & 0x80 == 0 ? br.read(ci_block_size) : br.read_abs(ci_block_size, file_size - ci_block_size), ui_block_size, flags))
guid = head.read(16)
@guid = head.read(16)
blocks = []
block_count = head.i32u
block_count.times{blocks << { u: head.i32u, c: head.i32u, f: head.i16u }}
raw_data = Array.new(block_count) do
u_size = head.i32u
c_size = head.i32u
flags = head.i16u
uncompress(br.read(c_size), u_size, flags)
end.join
asset_blocks = []
asset_count = head.i32u
asset_count.times{asset_blocks << { offset: head.i64u, size: head.i64u, status: head.i32, name: head.cstr }}
asset_entries = Array.new(asset_count) do
offset = head.i64u
size = head.i64u
status = head.i32
AssetEntry.new(name: head.cstr, data: raw_data.byteslice(offset, size), blob?: status != 4, status: status)
end
process_asset_entries(asset_entries)
end
raw_data = ''
blocks.each{|b| raw_data << uncompress(br.read(b[:c]), b[:u], b[:f])}
asset_blocks.each do |b|
next if b[:name].end_with?('.resS')
res_s = asset_blocks.find{|e| e[:name] == "#{b[:name]}.resS"}
asset = Asset.load(raw_data.byteslice(b[:offset], b[:size]), b[:name], res_s && raw_data.byteslice(res_s[:offset], res_s[:size]))
@assets << asset
def process_asset_entries(asset_entries)
@blobs = asset_entries.select(&:blob?).map{|e| [e.name, e.data]}.to_h
@assets = asset_entries.reject(&:blob?).map do |e|
basename = split_name(e.name)[0]
Asset.load(e.data, e.name, @blobs["#{basename}.resource"], @blobs["#{basename}.resS"])
end
end
@@ -119,16 +125,33 @@ module Mikunyan
case flags & 0x3f
when 0
block
# when 1
# LZMA
when 1
uncompress_lzma(block)
when 2, 3
LZ4.raw_decode(block, max_dest_size)
LZ4.block_decode(block, max_dest_size)
# when 4
# LZHMA
else
warn("Unknown compression flag: #{@flags}")
warn("Unknown compression flag: #{flags}")
block
end
end
def uncompress_lzma(block, with_max_len = false)
prop = block.ord
filter = LZMA.lzma1(dictsize: block.unpack1('@1V'), lc: prop % 9, lp: (prop / 9) % 5, pb: prop / 45)
max_len = block.unpack1('@5V') | block.unpack1('@9V') << 32 if with_max_len
StringIO.open(block) do |io|
io.seek(with_max_len ? 13 : 5)
LZMA.raw_decode(io, filter) do |lzma|
lzma.read(max_len)
end
end
end
def split_name(str)
m = str.match(/\A(.*?)(\.[^.]*)?\z/)
[m[1], m[2] || '']
end
end
end
+34
View File
@@ -0,0 +1,34 @@
# frozen_string_literal: true
require 'mikunyan/object_value'
module Mikunyan
# Class for representing decoded base object
class BaseObject < Mikunyan::ObjectValue
attr_accessor :object_entry
def path_id
@object_entry&.path_id
end
def object_name
@attr['m_Name']&.value
end
end
module CustomTypes
def self.get_custom_type(name, class_id = nil)
class_id ||= Mikunyan::Constants::CLASS_NAME2ID[name]
@custom_types&.[]([class_id, name]) || Mikunyan::BaseObject
end
def self.set_custom_type(klass, name, class_id = nil)
class_id ||= Mikunyan::Constants::CLASS_NAME2ID[name]
@custom_types ||= {}
@custom_types[[class_id, name].freeze] = klass
end
end
end
require 'mikunyan/types/text_asset'
require 'mikunyan/types/texture2d'
+63 -85
View File
@@ -5,18 +5,16 @@ require 'bin_utils'
module Mikunyan
# Class for manipulating binary string
# @attr [Symbol] endian endianness
# @attr [Integer] pos position
# @attr [Integer] length data size
class BinaryReader
attr_accessor :endian, :pos, :length
attr_accessor :endian
# Constructor
# @param [String] data binary string
# @param [IO,String] io binary String or IO
# @param [Symbol] endian endianness
def initialize(data, endian = :big)
@data = data
@pos = 0
@length = data.bytesize
def initialize(io, endian = :big)
@io = io.is_a?(String) ? StringIO.new(io, 'r') : io.dup
@io.binmode
@base_pos = @io.pos
@endian = endian
end
@@ -26,137 +24,117 @@ module Mikunyan
@endian == :little
end
# Jump to given position
# @param [Integer] pos position
def jmp(pos = 0)
@pos = pos
# Tells current potision
# @return [Integer]
def pos
@io.pos - @base_pos
end
# Advance position given size
# Jumps to given position
# @param [Integer] pos position
def jmp(jmp_pos = 0)
@io.pos = jmp_pos + @base_pos
end
alias pos= jmp
# Advances position given size
# @param [Integer] size size
def adv(size = 0)
@pos += size
@io.seek(size, IO::SEEK_CUR)
end
# Round up position to multiple of given size
# Rounds up position to multiple of given size
# @param [Integer] size size
def align(size)
@pos = (@pos + size - 1) / size * size
rem = pos % size
adv(size - rem) if rem > 0
end
# Read given size of binary string and seek
# Reads given size of binary string and seek
# @param [Integer] size size
# @return [String] data
def read(size)
data = @data.byteslice(@pos, size)
@pos += size
data
ret = @io.read(size)
raise EOFError if ret.nil? || size && ret.bytesize < size
ret
end
# Read given size of binary string from specified position. This method does not seek.
# Reads given size of binary string from specified position. This method does not seek.
# @param [Integer] size size
# @param [Integer] pos position
# @return [String] data
def read_abs(size, pos)
@data.byteslice(pos, size)
def read_abs(size, jmp_pos)
orig_pos = pos
jmp(jmp_pos)
ret = read(size)
jmp(orig_pos)
ret
end
# Read string until null character
# Reads string until null character
# @return [String] string
def cstr
r = @data.unpack1("@#{pos}Z*")
@pos += r.bytesize + 1
r
raise EOFError if @io.eof?
@io.each_byte.take_while(&:nonzero?).pack('C*')
end
# Read 8bit signed integer
def i8
i8s
# Reads an 8bit bool value
def bool
i8u != 0
end
# Read 8bit signed integer
# Reads an 8bit signed integer value
def i8s
r = BinUtils.get_sint8(@data, @pos)
@pos += 1
r
BinUtils.get_sint8(read(1))
end
alias i8 i8s
# Read 8bit unsigned integer
# Reads an 8bit unsigned integer value
def i8u
r = BinUtils.get_int8(@data, @pos)
@pos += 1
r
@io.getbyte
end
# Read 16bit signed integer
def i16
i16s
end
# Read 16bit signed integer
# Reads a 16bit signed integer value
def i16s
r = little? ? BinUtils.get_sint16_le(@data, @pos) : BinUtils.get_sint16_be(@data, @pos)
@pos += 2
r
little? ? BinUtils.get_sint16_le(read(2)) : BinUtils.get_sint16_be(read(2))
end
alias i16 i16s
# Read 16bit unsigned integer
# Reads a 16bit unsigned integer value
def i16u
r = little? ? BinUtils.get_int16_le(@data, @pos) : BinUtils.get_int16_be(@data, @pos)
@pos += 2
r
little? ? BinUtils.get_int16_le(read(2)) : BinUtils.get_int16_be(read(2))
end
# Read 32bit signed integer
def i32
i32s
end
# Read 32bit signed integer
# Reads a 32bit signed integer value
def i32s
r = little? ? BinUtils.get_sint32_le(@data, @pos) : BinUtils.get_sint32_be(@data, @pos)
@pos += 4
r
little? ? BinUtils.get_sint32_le(read(4)) : BinUtils.get_sint32_be(read(4))
end
alias i32 i32s
# Read 32bit unsigned integer
# Reads a 32bit unsigned integer value
def i32u
r = little? ? BinUtils.get_int32_le(@data, @pos) : BinUtils.get_int32_be(@data, @pos)
@pos += 4
r
little? ? BinUtils.get_int32_le(read(4)) : BinUtils.get_int32_be(read(4))
end
# Read 64bit signed integer
def i64
i64s
end
# Read 64bit signed integer
# Reads a 64bit signed integer value
def i64s
r = little? ? BinUtils.get_sint64_le(@data, @pos) : BinUtils.get_sint64_be(@data, @pos)
@pos += 8
r
little? ? BinUtils.get_sint64_le(read(8)) : BinUtils.get_sint64_be(read(8))
end
alias i64 i64s
# Read 64bit unsigned integer
# Reads a 64bit unsigned integer value
def i64u
r = little? ? BinUtils.get_int64_le(@data, @pos) : BinUtils.get_int64_be(@data, @pos)
@pos += 8
r
little? ? BinUtils.get_int64_le(read(8)) : BinUtils.get_int64_be(read(8))
end
# Read 32bit floating point value
# Reads a 32bit floating point value
def float
r = little? ? @data.byteslice(@pos, 4).unpack1('e') : @data.byteslice(@pos, 4).unpack1('g')
@pos += 4
r
little? ? read(4).unpack1('e') : read(4).unpack1('g')
end
# Read 64bit floating point value
# Reads a 64bit floating point value
def double
r = little? ? @data.byteslice(@pos, 8).unpack1('E') : @data.byteslice(@pos, 8).unpack1('G')
@pos += 8
r
little? ? read(8).unpack1('E') : read(8).unpack1('G')
end
end
end
+504 -341
View File
@@ -1,347 +1,510 @@
# frozen_string_literal: true
module Mikunyan
private
# Module for defining and uzing constants
module Constants
# @param [Integer] pos position value
# @param [String] buffer string buffer
# @return [String,nil]
def self.get_string_or_default(pos, buffer)
pos & 0x80000000 == 0 ? buffer.unpack1("@#{pos}Z*") : STRING_TABLE[pos & 0x7fffffff]
end
STRING_TABLE = {
0 => 'AABB',
5 => 'AnimationClip',
19 => 'AnimationCurve',
34 => 'AnimationState',
49 => 'Array',
55 => 'Base',
60 => 'BitField',
69 => 'bitset',
76 => 'bool',
81 => 'char',
86 => 'ColorRGBA',
96 => 'Component',
106 => 'data',
111 => 'deque',
117 => 'double',
124 => 'dynamic_array',
138 => 'FastPropertyName',
155 => 'first',
161 => 'float',
167 => 'Font',
172 => 'GameObject',
183 => 'Generic Mono',
196 => 'GradientNEW',
208 => 'GUID',
213 => 'GUIStyle',
222 => 'int',
226 => 'list',
231 => 'long long',
241 => 'map',
245 => 'Matrix4x4f',
256 => 'MdFour',
263 => 'MonoBehaviour',
277 => 'MonoScript',
288 => 'm_ByteSize',
299 => 'm_Curve',
307 => 'm_EditorClassIdentifier',
331 => 'm_EditorHideFlags',
349 => 'm_Enabled',
359 => 'm_ExtensionPtr',
374 => 'm_GameObject',
387 => 'm_Index',
395 => 'm_IsArray',
405 => 'm_IsStatic',
416 => 'm_MetaFlag',
427 => 'm_Name',
434 => 'm_ObjectHideFlags',
452 => 'm_PrefabInternal',
469 => 'm_PrefabParentObject',
490 => 'm_Script',
499 => 'm_StaticEditorFlags',
519 => 'm_Type',
526 => 'm_Version',
536 => 'Object',
543 => 'pair',
548 => 'PPtr<Component>',
564 => 'PPtr<GameObject>',
581 => 'PPtr<Material>',
596 => 'PPtr<MonoBehaviour>',
616 => 'PPtr<MonoScript>',
633 => 'PPtr<Object>',
646 => 'PPtr<Prefab>',
659 => 'PPtr<Sprite>',
672 => 'PPtr<TextAsset>',
688 => 'PPtr<Texture>',
702 => 'PPtr<Texture2D>',
718 => 'PPtr<Transform>',
734 => 'Prefab',
741 => 'Quaternionf',
753 => 'Rectf',
759 => 'RectInt',
767 => 'RectOffset',
778 => 'second',
785 => 'set',
789 => 'short',
795 => 'size',
800 => 'SInt16',
807 => 'SInt32',
814 => 'SInt64',
821 => 'SInt8',
827 => 'staticvector',
840 => 'string',
847 => 'TextAsset',
857 => 'TextMesh',
866 => 'Texture',
874 => 'Texture2D',
884 => 'Transform',
894 => 'TypelessData',
907 => 'UInt16',
914 => 'UInt32',
921 => 'UInt64',
928 => 'UInt8',
934 => 'unsigned int',
947 => 'unsigned long long',
966 => 'unsigned short',
981 => 'vector',
988 => 'Vector2f',
997 => 'Vector3f',
1006 => 'Vector4f',
1015 => 'm_ScriptingClassIdentifier',
1042 => 'Gradient'
}.freeze
STRING_TABLE = {
0 => 'AABB',
5 => 'AnimationClip',
19 => 'AnimationCurve',
34 => 'AnimationState',
49 => 'Array',
55 => 'Base',
60 => 'BitField',
69 => 'bitset',
76 => 'bool',
81 => 'char',
86 => 'ColorRGBA',
96 => 'Component',
106 => 'data',
111 => 'deque',
117 => 'double',
124 => 'dynamic_array',
138 => 'FastPropertyName',
155 => 'first',
161 => 'float',
167 => 'Font',
172 => 'GameObject',
183 => 'Generic Mono',
196 => 'GradientNEW',
208 => 'GUID',
213 => 'GUIStyle',
222 => 'int',
226 => 'list',
231 => 'long long',
241 => 'map',
245 => 'Matrix4x4f',
256 => 'MdFour',
263 => 'MonoBehaviour',
277 => 'MonoScript',
288 => 'm_ByteSize',
299 => 'm_Curve',
307 => 'm_EditorClassIdentifier',
331 => 'm_EditorHideFlags',
349 => 'm_Enabled',
359 => 'm_ExtensionPtr',
374 => 'm_GameObject',
387 => 'm_Index',
395 => 'm_IsArray',
405 => 'm_IsStatic',
416 => 'm_MetaFlag',
427 => 'm_Name',
434 => 'm_ObjectHideFlags',
452 => 'm_PrefabInternal',
469 => 'm_PrefabParentObject',
490 => 'm_Script',
499 => 'm_StaticEditorFlags',
519 => 'm_Type',
526 => 'm_Version',
536 => 'Object',
543 => 'pair',
548 => 'PPtr<Component>',
564 => 'PPtr<GameObject>',
581 => 'PPtr<Material>',
596 => 'PPtr<MonoBehaviour>',
616 => 'PPtr<MonoScript>',
633 => 'PPtr<Object>',
646 => 'PPtr<Prefab>',
659 => 'PPtr<Sprite>',
672 => 'PPtr<TextAsset>',
688 => 'PPtr<Texture>',
702 => 'PPtr<Texture2D>',
718 => 'PPtr<Transform>',
734 => 'Prefab',
741 => 'Quaternionf',
753 => 'Rectf',
759 => 'RectInt',
767 => 'RectOffset',
778 => 'second',
785 => 'set',
789 => 'short',
795 => 'size',
800 => 'SInt16',
807 => 'SInt32',
814 => 'SInt64',
821 => 'SInt8',
827 => 'staticvector',
840 => 'string',
847 => 'TextAsset',
857 => 'TextMesh',
866 => 'Texture',
874 => 'Texture2D',
884 => 'Transform',
894 => 'TypelessData',
907 => 'UInt16',
914 => 'UInt32',
921 => 'UInt64',
928 => 'UInt8',
934 => 'unsigned int',
947 => 'unsigned long long',
966 => 'unsigned short',
981 => 'vector',
988 => 'Vector2f',
997 => 'Vector3f',
1006 => 'Vector4f',
1015 => 'm_ScriptingClassIdentifier',
1042 => 'Gradient',
1051 => 'Type*',
1057 => 'int2_storage',
1070 => 'int3_storage',
1083 => 'BoundsInt',
1093 => 'm_CorrespondingSourceObject',
1121 => 'm_PrefabInstance',
1138 => 'm_PrefabAsset'
}.freeze
CLASS_ID = {
1 => 'GameObject',
2 => 'Component',
3 => 'LevelGameManager',
4 => 'Transform',
5 => 'TimeManager',
6 => 'GlobalGameManager',
8 => 'Behaviour',
9 => 'GameManager',
11 => 'AudioManager',
12 => 'ParticleAnimator',
13 => 'InputManager',
15 => 'EllipsoidParticleEmitter',
17 => 'Pipeline',
18 => 'EditorExtension',
19 => 'Physics2DSettings',
20 => 'Camera',
21 => 'Material',
23 => 'MeshRenderer',
25 => 'Renderer',
26 => 'ParticleRenderer',
27 => 'Texture',
28 => 'Texture2D',
29 => 'SceneSettings',
30 => 'GraphicsSettings',
33 => 'MeshFilter',
41 => 'OcclusionPortal',
43 => 'Mesh',
45 => 'Skybox',
47 => 'QualitySettings',
48 => 'Shader',
49 => 'TextAsset',
50 => 'Rigidbody2D',
51 => 'Physics2DManager',
53 => 'Collider2D',
54 => 'Rigidbody',
55 => 'PhysicsManager',
56 => 'Collider',
57 => 'Joint',
58 => 'CircleCollider2D',
59 => 'HingeJoint',
60 => 'PolygonCollider2D',
61 => 'BoxCollider2D',
62 => 'PhysicsMaterial2D',
64 => 'MeshCollider',
65 => 'BoxCollider',
66 => 'SpriteCollider2D',
68 => 'EdgeCollider2D',
72 => 'ComputeShader',
74 => 'AnimationClip',
75 => 'ConstantForce',
76 => 'WorldParticleCollider',
78 => 'TagManager',
81 => 'AudioListener',
82 => 'AudioSource',
83 => 'AudioClip',
84 => 'RenderTexture',
87 => 'MeshParticleEmitter',
88 => 'ParticleEmitter',
89 => 'Cubemap',
90 => 'Avatar',
91 => 'AnimatorController',
92 => 'GUILayer',
93 => 'RuntimeAnimatorController',
94 => 'ScriptMapper',
95 => 'Animator',
96 => 'TrailRenderer',
98 => 'DelayedCallManager',
102 => 'TextMesh',
104 => 'RenderSettings',
108 => 'Light',
109 => 'CGProgram',
110 => 'BaseAnimationTrack',
111 => 'Animation',
114 => 'MonoBehaviour',
115 => 'MonoScript',
116 => 'MonoManager',
117 => 'Texture3D',
118 => 'NewAnimationTrack',
119 => 'Projector',
120 => 'LineRenderer',
121 => 'Flare',
122 => 'Halo',
123 => 'LensFlare',
124 => 'FlareLayer',
125 => 'HaloLayer',
126 => 'NavMeshAreas',
127 => 'HaloManager',
128 => 'Font',
129 => 'PlayerSettings',
130 => 'NamedObject',
131 => 'GUITexture',
132 => 'GUIText',
133 => 'GUIElement',
134 => 'PhysicMaterial',
135 => 'SphereCollider',
136 => 'CapsuleCollider',
137 => 'SkinnedMeshRenderer',
138 => 'FixedJoint',
140 => 'RaycastCollider',
141 => 'BuildSettings',
142 => 'AssetBundle',
143 => 'CharacterController',
144 => 'CharacterJoint',
145 => 'SpringJoint',
146 => 'WheelCollider',
147 => 'ResourceManager',
148 => 'NetworkView',
149 => 'NetworkManager',
150 => 'PreloadData',
152 => 'MovieTexture',
153 => 'ConfigurableJoint',
154 => 'TerrainCollider',
155 => 'MasterServerInterface',
156 => 'TerrainData',
157 => 'LightmapSettings',
158 => 'WebCamTexture',
159 => 'EditorSettings',
160 => 'InteractiveCloth',
161 => 'ClothRenderer',
162 => 'EditorUserSettings',
163 => 'SkinnedCloth',
164 => 'AudioReverbFilter',
165 => 'AudioHighPassFilter',
166 => 'AudioChorusFilter',
167 => 'AudioReverbZone',
168 => 'AudioEchoFilter',
169 => 'AudioLowPassFilter',
170 => 'AudioDistortionFilter',
171 => 'SparseTexture',
180 => 'AudioBehaviour',
181 => 'AudioFilter',
182 => 'WindZone',
183 => 'Cloth',
184 => 'SubstanceArchive',
185 => 'ProceduralMaterial',
186 => 'ProceduralTexture',
191 => 'OffMeshLink',
192 => 'OcclusionArea',
193 => 'Tree',
194 => 'NavMeshObsolete',
195 => 'NavMeshAgent',
196 => 'NavMeshSettings',
197 => 'LightProbesLegacy',
198 => 'ParticleSystem',
199 => 'ParticleSystemRenderer',
200 => 'ShaderVariantCollection',
205 => 'LODGroup',
206 => 'BlendTree',
207 => 'Motion',
208 => 'NavMeshObstacle',
210 => 'TerrainInstance',
212 => 'SpriteRenderer',
213 => 'Sprite',
214 => 'CachedSpriteAtlas',
215 => 'ReflectionProbe',
216 => 'ReflectionProbes',
218 => 'Terrain',
220 => 'LightProbeGroup',
221 => 'AnimatorOverrideController',
222 => 'CanvasRenderer',
223 => 'Canvas',
224 => 'RectTransform',
225 => 'CanvasGroup',
226 => 'BillboardAsset',
227 => 'BillboardRenderer',
228 => 'SpeedTreeWindAsset',
229 => 'AnchoredJoint2D',
230 => 'Joint2D',
231 => 'SpringJoint2D',
232 => 'DistanceJoint2D',
233 => 'HingeJoint2D',
234 => 'SliderJoint2D',
235 => 'WheelJoint2D',
238 => 'NavMeshData',
240 => 'AudioMixer',
241 => 'AudioMixerController',
243 => 'AudioMixerGroupController',
244 => 'AudioMixerEffectController',
245 => 'AudioMixerSnapshotController',
246 => 'PhysicsUpdateBehaviour2D',
247 => 'ConstantForce2D',
248 => 'Effector2D',
249 => 'AreaEffector2D',
250 => 'PointEffector2D',
251 => 'PlatformEffector2D',
252 => 'SurfaceEffector2D',
258 => 'LightProbes',
271 => 'SampleClip',
272 => 'AudioMixerSnapshot',
273 => 'AudioMixerGroup',
290 => 'AssetBundleManifest',
1001 => 'Prefab',
1002 => 'EditorExtensionImpl',
1003 => 'AssetImporter',
1004 => 'AssetDatabase',
1005 => 'Mesh3DSImporter',
1006 => 'TextureImporter',
1007 => 'ShaderImporter',
1008 => 'ComputeShaderImporter',
1011 => 'AvatarMask',
1020 => 'AudioImporter',
1026 => 'HierarchyState',
1027 => 'GUIDSerializer',
1028 => 'AssetMetaData',
1029 => 'DefaultAsset',
1030 => 'DefaultImporter',
1031 => 'TextScriptImporter',
1032 => 'SceneAsset',
1034 => 'NativeFormatImporter',
1035 => 'MonoImporter',
1037 => 'AssetServerCache',
1038 => 'LibraryAssetImporter',
1040 => 'ModelImporter',
1041 => 'FBXImporter',
1042 => 'TrueTypeFontImporter',
1044 => 'MovieImporter',
1045 => 'EditorBuildSettings',
1046 => 'DDSImporter',
1048 => 'InspectorExpandedState',
1049 => 'AnnotationManager',
1050 => 'PluginImporter',
1051 => 'EditorUserBuildSettings',
1052 => 'PVRImporter',
1053 => 'ASTCImporter',
1054 => 'KTXImporter',
1101 => 'AnimatorStateTransition',
1102 => 'AnimatorState',
1105 => 'HumanTemplate',
1107 => 'AnimatorStateMachine',
1108 => 'PreviewAssetType',
1109 => 'AnimatorTransition',
1110 => 'SpeedTreeImporter',
1111 => 'AnimatorTransitionBase',
1112 => 'SubstanceImporter',
1113 => 'LightmapParameters',
1120 => 'LightmapSnapshot'
}.freeze
CLASS_ID_TABLE = [
[0, 'Object'],
[1, 'GameObject'],
[2, 'Component'],
[3, 'LevelGameManager'],
[4, 'Transform'],
[5, 'TimeManager'],
[6, 'GlobalGameManager'],
[8, 'Behaviour'],
[9, 'GameManager'],
[11, 'AudioManager'],
[12, 'ParticleAnimator'],
[13, 'InputManager'],
[15, 'EllipsoidParticleEmitter'],
[17, 'Pipeline'],
[18, 'EditorExtension'],
[19, 'Physics2DSettings'],
[20, 'Camera'],
[21, 'Material'],
[23, 'MeshRenderer'],
[25, 'Renderer'],
[26, 'ParticleRenderer'],
[27, 'Texture'],
[28, 'Texture2D'],
[29, 'Scene'],
[29, 'SceneSettings'],
[29, 'OcclusionCullingSettings'],
[30, 'RenderManager'],
[30, 'GraphicsSettings'],
[33, 'MeshFilter'],
[41, 'OcclusionPortal'],
[43, 'Mesh'],
[45, 'Skybox'],
[47, 'QualitySettings'],
[48, 'Shader'],
[49, 'TextAsset'],
[50, 'Rigidbody2D'],
[51, 'Physics2DManager'],
[52, 'NotificationManager'],
[53, 'Collider2D'],
[54, 'Rigidbody'],
[55, 'PhysicsManager'],
[56, 'Collider'],
[57, 'Joint'],
[58, 'CircleCollider2D'],
[59, 'HingeJoint'],
[60, 'PolygonCollider2D'],
[61, 'BoxCollider2D'],
[62, 'PhysicsMaterial2D'],
[64, 'MeshCollider'],
[65, 'BoxCollider'],
[66, 'SpriteCollider2D'],
[66, 'CompositeCollider2D'],
[68, 'EdgeCollider2D'],
[70, 'CapsuleCollider2D'],
[71, 'AnimationManager'],
[72, 'ComputeShader'],
[74, 'AnimationClip'],
[75, 'ConstantForce'],
[76, 'WorldParticleCollider'],
[78, 'TagManager'],
[81, 'AudioListener'],
[82, 'AudioSource'],
[83, 'AudioClip'],
[84, 'RenderTexture'],
[86, 'CustomRenderTexture'],
[87, 'MeshParticleEmitter'],
[88, 'ParticleEmitter'],
[89, 'Cubemap'],
[90, 'Avatar'],
[91, 'AnimatorController'],
[92, 'GUILayer'],
[93, 'RuntimeAnimatorController'],
[94, 'ScriptMapper'],
[95, 'Animator'],
[96, 'TrailRenderer'],
[98, 'DelayedCallManager'],
[102, 'TextMesh'],
[104, 'RenderSettings'],
[108, 'Light'],
[109, 'CGProgram'],
[110, 'BaseAnimationTrack'],
[111, 'Animation'],
[114, 'MonoBehaviour'],
[115, 'MonoScript'],
[116, 'MonoManager'],
[117, 'Texture3D'],
[118, 'NewAnimationTrack'],
[119, 'Projector'],
[120, 'LineRenderer'],
[121, 'Flare'],
[122, 'Halo'],
[123, 'LensFlare'],
[124, 'FlareLayer'],
[125, 'HaloLayer'],
[126, 'NavMeshLayers'],
[126, 'NavMeshAreas'],
[126, 'NavMeshProjectSettings'],
[127, 'HaloManager'],
[128, 'Font'],
[129, 'PlayerSettings'],
[130, 'NamedObject'],
[131, 'GUITexture'],
[132, 'GUIText'],
[133, 'GUIElement'],
[134, 'PhysicMaterial'],
[135, 'SphereCollider'],
[136, 'CapsuleCollider'],
[137, 'SkinnedMeshRenderer'],
[138, 'FixedJoint'],
[140, 'RaycastCollider'],
[141, 'BuildSettings'],
[142, 'AssetBundle'],
[143, 'CharacterController'],
[144, 'CharacterJoint'],
[145, 'SpringJoint'],
[146, 'WheelCollider'],
[147, 'ResourceManager'],
[148, 'NetworkView'],
[149, 'NetworkManager'],
[150, 'PreloadData'],
[152, 'MovieTexture'],
[153, 'ConfigurableJoint'],
[154, 'TerrainCollider'],
[155, 'MasterServerInterface'],
[156, 'TerrainData'],
[157, 'LightmapSettings'],
[158, 'WebCamTexture'],
[159, 'EditorSettings'],
[160, 'InteractiveCloth'],
[161, 'ClothRenderer'],
[162, 'EditorUserSettings'],
[163, 'SkinnedCloth'],
[164, 'AudioReverbFilter'],
[165, 'AudioHighPassFilter'],
[166, 'AudioChorusFilter'],
[167, 'AudioReverbZone'],
[168, 'AudioEchoFilter'],
[169, 'AudioLowPassFilter'],
[170, 'AudioDistortionFilter'],
[171, 'SparseTexture'],
[180, 'AudioBehaviour'],
[181, 'AudioFilter'],
[182, 'WindZone'],
[183, 'Cloth'],
[184, 'SubstanceArchive'],
[185, 'ProceduralMaterial'],
[186, 'ProceduralTexture'],
[187, 'Texture2DArray'],
[188, 'CubemapArray'],
[191, 'OffMeshLink'],
[192, 'OcclusionArea'],
[193, 'Tree'],
[194, 'NavMesh'],
[194, 'NavMeshObsolete'],
[195, 'NavMeshAgent'],
[196, 'NavMeshSettings'],
[197, 'LightProbeCloud'],
[197, 'LightProbesLegacy'],
[198, 'ParticleSystem'],
[199, 'ParticleSystemRenderer'],
[200, 'ShaderVariantCollection'],
[205, 'LODGroup'],
[206, 'BlendTree'],
[207, 'Motion'],
[208, 'NavMeshObstacle'],
[210, 'TerrainInstance'],
[210, 'SortingGroup'],
[212, 'SpriteRenderer'],
[213, 'Sprite'],
[214, 'CachedSpriteAtlas'],
[215, 'ReflectionProbe'],
[216, 'ReflectionProbes'],
[218, 'Terrain'],
[220, 'LightProbeGroup'],
[221, 'AnimatorOverrideController'],
[222, 'CanvasRenderer'],
[223, 'Canvas'],
[224, 'RectTransform'],
[225, 'CanvasGroup'],
[226, 'BillboardAsset'],
[227, 'BillboardRenderer'],
[228, 'SpeedTreeWindAsset'],
[229, 'AnchoredJoint2D'],
[230, 'Joint2D'],
[231, 'SpringJoint2D'],
[232, 'DistanceJoint2D'],
[233, 'HingeJoint2D'],
[234, 'SliderJoint2D'],
[235, 'WheelJoint2D'],
[236, 'ClusterInputManager'],
[237, 'BaseVideoTexture'],
[238, 'NavMeshData'],
[240, 'AudioMixer'],
[241, 'AudioMixerController'],
[243, 'AudioMixerGroupController'],
[244, 'AudioMixerEffectController'],
[245, 'AudioMixerSnapshotController'],
[246, 'PhysicsUpdateBehaviour2D'],
[247, 'ConstantForce2D'],
[248, 'Effector2D'],
[249, 'AreaEffector2D'],
[250, 'PointEffector2D'],
[251, 'PlatformEffector2D'],
[252, 'SurfaceEffector2D'],
[253, 'BuoyancyEffector2D'],
[254, 'RelativeJoint2D'],
[255, 'FixedJoint2D'],
[256, 'FrictionJoint2D'],
[257, 'TargetJoint2D'],
[258, 'LightProbes'],
[259, 'LightProbeProxyVolume'],
[271, 'SampleClip'],
[272, 'AudioMixerSnapshot'],
[273, 'AudioMixerGroup'],
[280, 'NScreenBridge'],
[290, 'AssetBundleManifest'],
[292, 'UnityAdsSettings'],
[292, 'UnityAdsManager'],
[300, 'RuntimeInitializeOnLoadManager'],
[301, 'CloudWebServicesManager'],
[303, 'UnityAnalyticsManager'],
[304, 'CrashReportManager'],
[305, 'PerformanceReportingManager'],
[310, 'UnityConnectSettings'],
[319, 'AvatarMask'],
[320, 'PlayableDirector'],
[328, 'VideoPlayer'],
[329, 'VideoClip'],
[330, 'ParticleSystemForceField'],
[331, 'SpriteMask'],
[362, 'WorldAnchor'],
[363, 'OcclusionCullingData'],
[1000, 'SmallestEditorClassID'],
[1001, 'Prefab'], # 1001480554
[1001, 'PrefabInstance'],
[1002, 'EditorExtensionImpl'],
[1003, 'AssetImporter'],
[1004, 'AssetDatabase'],
[1004, 'AssetDatabaseV1'],
[1005, 'Mesh3DSImporter'],
[1006, 'TextureImporter'],
[1007, 'ShaderImporter'],
[1008, 'ComputeShaderImporter'],
[1011, 'AvatarMask'],
[1020, 'AudioImporter'],
[1026, 'HierarchyState'],
[1027, 'GUIDSerializer'],
[1028, 'AssetMetaData'],
[1029, 'DefaultAsset'],
[1030, 'DefaultImporter'],
[1031, 'TextScriptImporter'],
[1032, 'SceneAsset'],
[1034, 'NativeFormatImporter'],
[1035, 'MonoImporter'],
[1037, 'AssetServerCache'],
[1038, 'LibraryAssetImporter'],
[1040, 'ModelImporter'],
[1041, 'FBXImporter'],
[1042, 'TrueTypeFontImporter'],
[1044, 'MovieImporter'],
[1045, 'EditorBuildSettings'],
[1046, 'DDSImporter'],
[1048, 'InspectorExpandedState'],
[1049, 'AnnotationManager'],
[1050, 'MonoAssemblyImporter'],
[1050, 'PluginImporter'],
[1051, 'EditorUserBuildSettings'],
[1052, 'PVRImporter'],
[1053, 'ASTCImporter'],
[1054, 'KTXImporter'],
[1055, 'IHVImageFormatImporter'],
[1101, 'Transition'],
[1101, 'AnimatorStateTransition'],
[1102, 'State'],
[1102, 'AnimatorState'],
[1105, 'HumanTemplate'],
[1107, 'StateMachine'],
[1107, 'AnimatorStateMachine'],
[1108, 'PreviewAssetType'],
[1108, 'PreviewAnimationClip'],
[1109, 'AnimatorTransition'],
[1110, 'SpeedTreeImporter'],
[1111, 'AnimatorTransitionBase'],
[1112, 'SubstanceImporter'],
[1113, 'LightmapParameters'],
[1120, 'LightmapSnapshot'],
[1120, 'LightingDataAsset'],
[1121, 'GISRaster'],
[1122, 'GISRasterImporter'],
[1123, 'CadImporter'],
[1124, 'SketchUpImporter'],
[1125, 'BuildReport'],
[1126, 'PackedAssets'],
[1127, 'VideoClipImporter'],
[2000, 'ActivationLogComponent'],
[100000, 'int'],
[100001, 'bool'],
[100002, 'float'],
[100003, 'MonoObject'],
[100004, 'Collision'],
[100005, 'Vector3f'],
[100006, 'RootMotionData'],
[100007, 'Collision2D'],
[100008, 'AudioMixerLiveUpdateFloat'],
[100009, 'AudioMixerLiveUpdateBool'],
[100010, 'Polygon2D'],
[100011, 'void'],
[19719996, 'TilemapCollider2D'],
[41386430, 'AssetImporterLog'],
[73398921, 'VFXRenderer'],
[76251197, 'SerializableManagedRefTestClass'],
[156049354, 'Grid'],
[181963792, 'Preset'],
[277625683, 'EmptyObject'],
[285090594, 'IConstraint'],
[293259124, 'TestObjectWithSpecialLayoutOne'],
[294290339, 'AssemblyDefinitionReferenceImporter'],
[334799969, 'SiblingDerived'],
[342846651, 'TestObjectWithSerializedMapStringNonAlignedStruct'],
[367388927, 'SubDerived'],
[369655926, 'AssetImportInProgressProxy'],
[382020655, 'PluginBuildInfo'],
[426301858, 'EditorProjectAccess'],
[468431735, 'PrefabImporter'],
[478637458, 'TestObjectWithSerializedArray'],
[478637459, 'TestObjectWithSerializedAnimationCurve'],
[483693784, 'TilemapRenderer'],
[638013454, 'SpriteAtlasDatabase'],
[641289076, 'AudioBuildInfo'],
[644342135, 'CachedSpriteAtlasRuntimeData'],
[646504946, 'RendererFake'],
[662584278, 'AssemblyDefinitionReferenceAsset'],
[668709126, 'BuiltAssetBundleInfoSet'],
[687078895, 'SpriteAtlas'],
[877146078, 'PlatformModuleSetup'],
[895512359, 'AimConstraint'],
[937362698, 'VFXManager'],
[994735392, 'VisualEffectSubgraph'],
[994735403, 'VisualEffectSubgraphOperator'],
[994735404, 'VisualEffectSubgraphBlock'],
[1001480554, 'Prefab'],
[1027052791, 'LocalizationImporter'],
[1091556383, 'Derived'],
[1111377672, 'PropertyModificationsTargetTestObject'],
[1114811875, 'ReferencesArtifactGenerator'],
[1152215463, 'AssemblyDefinitionAsset'],
[1154873562, 'SceneVisibilityState'],
[1183024399, 'LookAtConstraint'],
[1223240404, 'MultiArtifactTestImporter'],
[1268269756, 'GameObjectRecorder'],
[1325145578, 'LightingDataAssetParent'],
[1386491679, 'PresetManager'],
[1392443030, 'TestObjectWithSpecialLayoutTwo'],
[1403656975, 'StreamingManager'],
[1480428607, 'LowerResBlitTexture'],
[1542919678, 'StreamingController'],
[1571458007, 'RenderPassAttachment'],
[1628831178, 'TestObjectVectorPairStringBool'],
[1742807556, 'GridLayout'],
[1766753193, 'AssemblyDefinitionImporter'],
[1773428102, 'ParentConstraint'],
[1803986026, 'FakeComponent'],
[1818360608, 'PositionConstraint'],
[1818360609, 'RotationConstraint'],
[1818360610, 'ScaleConstraint'],
[1839735485, 'Tilemap'],
[1896753125, 'PackageManifest'],
[1896753126, 'PackageManifestImporter'],
[1953259897, 'TerrainLayer'],
[1971053207, 'SpriteShapeRenderer'],
[1977754360, 'NativeObjectType'],
[1981279845, 'TestObjectWithSerializedMapStringBool'],
[1995898324, 'SerializableManagedHost'],
[2058629509, 'VisualEffectAsset'],
[2058629510, 'VisualEffectImporter'],
[2058629511, 'VisualEffectResource'],
[2059678085, 'VisualEffectObject'],
[2083052967, 'VisualEffect'],
[2083778819, 'LocalizationAsset'],
[2089858483, 'ScriptedImporter']
]
CLASS_ID2NAME = CLASS_ID_TABLE.to_h.freeze
CLASS_ID = CLASS_ID2NAME # compatibility
CLASS_NAME2ID = CLASS_ID_TABLE.map(&:reverse).to_h.freeze
end
end
+2
View File
@@ -1,5 +1,7 @@
# frozen_string_literal: true
warn 'Warning: `mikunyan/decoders` is deprecated and will be removed at a future release.'
require 'mikunyan/decoders/image_decoder'
module Mikunyan
+483 -462
View File
@@ -9,475 +9,496 @@ require 'bin_utils'
require 'mikunyan/decoders/native'
module Mikunyan
# Class for image decoding tools
class ImageDecoder
# Decode image from Mikunyan::ObjectValue
# @param [Mikunyan::ObjectValue] object object to decode
# @return [ChunkyPNG::Image,nil] decoded image
def self.decode_object(object)
return nil unless object.class == ObjectValue
module Decoder
# Class for image decoding tools
class ImageDecoder
# Decode image from Mikunyan::ObjectValue
# @param [Mikunyan::ObjectValue] object object to decode
# @return [ChunkyPNG::Image,nil] decoded image
def self.decode_object(object)
return nil unless object.is_a?(ObjectValue)
endian = object.endian
width = object['m_Width']
height = object['m_Height']
bin = object['image data']
fmt = object['m_TextureFormat']
return nil unless width && height && bin && fmt
endian = object.endian
width = object['m_Width']&.value
height = object['m_Height']&.value
bin = object['image data']&.value
fmt = object['m_TextureFormat']&.value
return nil unless width && height && bin && fmt
width = width.value
height = height.value
bin = bin.value
fmt = fmt.value
if bin.empty? && object['m_StreamData']
bin = object['m_StreamData'].value
bin = object['m_StreamData']&.value if bin.empty?
return nil unless bin
end
case fmt
when 1
decode_a8(width, height, bin)
when 2
decode_argb4444(width, height, bin, endian)
when 3
decode_rgb24(width, height, bin)
when 4
decode_rgba32(width, height, bin)
when 5
decode_argb32(width, height, bin)
when 7
decode_rgb565(width, height, bin, endian)
when 9
decode_r16(width, height, bin)
when 10
decode_dxt1(width, height, bin)
when 12
decode_dxt5(width, height, bin)
when 13
decode_rgba4444(width, height, bin, endian)
when 14
decode_bgra32(width, height, bin)
when 15
decode_rhalf(width, height, bin, endian)
when 16
decode_rghalf(width, height, bin, endian)
when 17
decode_rgbahalf(width, height, bin, endian)
when 18
decode_rfloat(width, height, bin, endian)
when 19
decode_rgfloat(width, height, bin, endian)
when 20
decode_rgbafloat(width, height, bin, endian)
when 22
decode_rgb9e5float(width, height, bin, endian)
when 34
decode_etc1(width, height, bin)
when 45
decode_etc2rgb(width, height, bin)
when 46
decode_etc2rgba1(width, height, bin)
when 47
decode_etc2rgba8(width, height, bin)
when 48, 54
decode_astc(width, height, 4, bin)
when 49, 55
decode_astc(width, height, 5, bin)
when 50, 56
decode_astc(width, height, 6, bin)
when 51, 57
decode_astc(width, height, 8, bin)
when 52, 58
decode_astc(width, height, 10, bin)
when 53, 59
decode_astc(width, height, 12, bin)
when 62
decode_rg16(width, height, bin)
when 63
decode_r8(width, height, bin)
end
end
# Decode image from RGBA4444 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgba4444(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 4)
(width * height).times do |i|
c = endian == :little ? BinUtils.get_int16_le(bin, i * 2) : BinUtils.get_int16_be(bin, i * 2)
c = ((c & 0xf000) << 12) | ((c & 0x0f00) << 8) | ((c & 0x00f0) << 4) | (c & 0x000f)
BinUtils.append_int32_be!(mem, c << 4 | c)
end
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
end
# Decode image from ARGB4444 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_argb4444(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 4)
(width * height).times do |i|
c = endian == :little ? BinUtils.get_int16_le(bin, i * 2) : BinUtils.get_int16_be(bin, i * 2)
c = ((c & 0x0f00) << 16) | ((c & 0x00f0) << 12) | ((c & 0x000f) << 8) | ((c & 0xf000) >> 12)
BinUtils.append_int32_be!(mem, c << 4 | c)
end
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
end
# Decode image from RGB565 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgb565(width, height, bin, endian = :big)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_rgb565(bin, width * height, endian == :big)).flip
end
# Decode image from A8 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_a8(width, height, bin)
mem = String.new(capacity: width * height * 3)
(width * height).times do |i|
c = BinUtils.get_int8(bin, i)
BinUtils.append_int8!(mem, c, c, c)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from R8 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_r8(width, height, bin)
decode_a8(width, height, bin)
end
# Decode image from RG16 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_rg16(width, height, bin)
mem = String.new(capacity: width * height * 3)
(width * height).times do |i|
BinUtils.append_int16_int8_be!(mem, BinUtils.get_int16_be(bin, i * 2), 0)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from RGB24 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgb24(width, height, bin)
ChunkyPNG::Image.from_rgb_stream(width, height, bin).flip
end
# Decode image from RGBA32 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgba32(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, bin).flip
end
# Decode image from ARGB32 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_argb32(width, height, bin)
mem = String.new(capacity: width * height * 4)
(width * height).times do |i|
c = BinUtils.get_int32_be(bin, i * 4)
BinUtils.append_int32_be!(mem, ((c & 0x00ffffff) << 8) | ((c & 0xff000000) >> 24))
end
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
end
# Decode image from BGRA32 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_bgra32(width, height, bin)
mem = String.new(capacity: width * height * 4)
(width * height).times do |i|
c = BinUtils.get_int32_le(bin, i * 4)
BinUtils.append_int32_be!(mem, ((c & 0x00ffffff) << 8) | ((c & 0xff000000) >> 24))
end
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
end
# Decode image from R16 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_r16(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 3)
(width * height).times do |i|
c = endian == :little ? BinUtils.get_int16_le(bin, i * 2) : BinUtils.get_int16_be(bin, i * 2)
c = f2i(r / 65535.0)
BinUtils.append_int8!(mem, c, c, c)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from RGB9e5 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgb9e5float(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 3)
(width * height).times do |i|
n = endian == :little ? BinUtils.get_int32_le(bin, i * 4) : BinUtils.get_int32_be(bin, i * 4)
e = (n & 0xf8000000) >> 27
r = (n & 0x7fc0000) >> 9
g = (n & 0x3fe00) >> 9
b = n & 0x1ff
r = (r / 512r + 1) * (2**(e - 15))
g = (g / 512r + 1) * (2**(e - 15))
b = (b / 512r + 1) * (2**(e - 15))
BinUtils.append_int8!(mem, f2i(r), f2i(g), f2i(b))
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from R Half-float binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rhalf(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 3)
(width * height).times do |i|
c = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 2) : BinUtils.get_int16_be(bin, i * 2)))
BinUtils.append_int8!(mem, c, c, c)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from RG Half-float binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rghalf(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 3)
(width * height).times do |i|
r = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 4) : BinUtils.get_int16_be(bin, i * 4)))
g = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 4 + 2) : BinUtils.get_int16_be(bin, i * 4 + 2)))
BinUtils.append_int8!(mem, r, g, 0)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from RGBA Half-float binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgbahalf(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 4)
(width * height).times do |i|
r = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 8) : BinUtils.get_int16_be(bin, i * 8)))
g = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 8 + 2) : BinUtils.get_int16_be(bin, i * 8 + 2)))
b = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 8 + 4) : BinUtils.get_int16_be(bin, i * 8 + 4)))
a = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 8 + 6) : BinUtils.get_int16_be(bin, i * 8 + 6)))
BinUtils.append_int8!(mem, r, g, b, a)
end
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
end
# Decode image from R float binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rfloat(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 3)
unpackstr = endian == :little ? 'e' : 'g'
(width * height).times do |i|
c = f2i(bin.byteslice(i * 4, 4).unpack1(unpackstr))
BinUtils.append_int8!(mem, c, c, c)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from RG float binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgfloat(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 3)
unpackstr = endian == :little ? 'e2' : 'g2'
(width * height).times do |i|
r, g = bin.byteslice(i * 8, 8).unpack(unpackstr)
BinUtils.append_int8!(mem, f2i(r), f2i(g), 0)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from RGBA float binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgbafloat(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 4)
unpackstr = endian == :little ? 'e4' : 'g4'
(width * height).times do |i|
r, g, b, a = bin.byteslice(i * 16, 16).unpack(unpackstr)
BinUtils.append_int8!(mem, f2i(r), f2i(g), f2i(b), f2i(a))
end
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
end
# Decode image from DXT1 compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_dxt1(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_dxt1(bin, width, height))
end
# Decode image from DXT5 compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_dxt5(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_dxt5(bin, width, height))
end
# Decode image from ETC1 compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_etc1(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_etc1(bin, width, height))
end
# Decode image from ETC2 compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_etc2rgb(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_etc2(bin, width, height))
end
# Decode image from ETC2 Alpha1 compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_etc2rgba1(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_etc2a1(bin, width, height))
end
# Decode image from ETC2 Alpha8 compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_etc2rgba8(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_etc2a8(bin, width, height))
end
# Decode image from ASTC compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [Integer] blocksize block size
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_astc(width, height, blocksize, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_astc(bin, width, height, blocksize, blocksize))
end
# Create ASTC file data from ObjectValue
# @param [Mikunyan::ObjectValue,Hash] object target object
# @return [String,nil] created file
def self.create_astc_file(object)
astc_list = {
48 => 4, 49 => 5, 50 => 6, 51 => 8, 52 => 10, 53 => 12,
54 => 4, 55 => 5, 56 => 6, 57 => 8, 58 => 10, 59 => 12
}
width = object['m_Width']
height = object['m_Height']
fmt = object['m_TextureFormat']
bin = object['image data']
width = width.value if width.class == ObjectValue
height = height.value if height.class == ObjectValue
fmt = fmt.value if fmt.class == ObjectValue
bin = bin.value if bin.class == ObjectValue
if width && height && fmt && astc_list[fmt]
header = "\x13\xAB\xA1\x5C".force_encoding('ascii-8bit')
header << [astc_list[fmt], astc_list[fmt], 1].pack('C*')
header << [width].pack('V').byteslice(0, 3)
header << [height].pack('V').byteslice(0, 3)
header << "\x01\x00\x00"
header + bin
end
end
private
# convert 16bit float
def self.n2f(n)
case n
when 0x0000
0.0
when 0x8000
-0.0
when 0x7c00
Float::INFINITY
when 0xfc00
-Float::INFINITY
else
s = n & 0x8000 != 0
e = n & 0x7c00
f = n & 0x03ff
case e
when 0x7c00
Float::NAN
when 0
(s ? -f : f) * 2.0**-24
else
(s ? -1 : 1) * (f / 1024.0 + 1) * (2.0**((e >> 10) - 15))
case fmt
when 1 # Alpha8
decode_a8(width, height, bin)
when 2 # ARGB4444
decode_argb4444(width, height, bin, endian)
when 3 # RGB24
decode_rgb24(width, height, bin)
when 4 # RGBA32
decode_rgba32(width, height, bin)
when 5 # ARGB32
decode_argb32(width, height, bin)
when 7 # RGB565
decode_rgb565(width, height, bin, endian)
when 9 # R16
decode_r16(width, height, bin)
when 10 # DXT1
decode_dxt1(width, height, bin)
when 12 # DXT5
decode_dxt5(width, height, bin)
when 13 # RGBA4444
decode_rgba4444(width, height, bin, endian)
when 14 # BGRA32
decode_bgra32(width, height, bin)
when 15 # RHalf
decode_rhalf(width, height, bin, endian)
when 16 # RGHalf
decode_rghalf(width, height, bin, endian)
when 17 # RGBAHalf
decode_rgbahalf(width, height, bin, endian)
when 18 # RFloat
decode_rfloat(width, height, bin, endian)
when 19 # RGFloat
decode_rgfloat(width, height, bin, endian)
when 20 # RGBAFloat
decode_rgbafloat(width, height, bin, endian)
# when 21 # YUY2
when 22 # RGB9e5Float
decode_rgb9e5float(width, height, bin, endian)
# when 24 # BC6H
# when 25 # BC7
# when 26 # BC4
# when 27 # BC5
# when 28 # DXT1Crunched
# when 29 # DXT5Crunched
# when 30 # PVRTC_RGB2
# when 31, -127 # PVRTC_RGBA2, PVRTC_2BPP_RGBA
# when 32 # PVRTC_RGB4
# when 33 # PVRTC_RGBA4
when 34 # ETC_RGB4
decode_etc1(width, height, bin)
# when 41 # EAC_R
# when 42 # EAC_R_SIGNED
# when 43 # EAC_RG
# when 44 # EAC_RG_SIGNED
when 45 # ETC2_RGB
decode_etc2rgb(width, height, bin)
when 46 # ETC2_RGBA1
decode_etc2rgba1(width, height, bin)
when 47 # ETC2_RGBA8
decode_etc2rgba8(width, height, bin)
when 48, 54, 66 # ASTC_RGB_4x4, ASTC_RGBA_4x4, ASTC_HDR_4x4
decode_astc(width, height, 4, bin)
when 49, 55, 67 # ASTC_RGB_5x5, ASTC_RGBA_5x5, ASTC_HDR_5x5
decode_astc(width, height, 5, bin)
when 50, 56, 68 # ASTC_RGB_6x6, ASTC_RGBA_6x6, ASTC_HDR_6x6
decode_astc(width, height, 6, bin)
when 51, 57, 69 # ASTC_RGB_8x8, ASTC_RGBA_8x8, ASTC_HDR_8x8
decode_astc(width, height, 8, bin)
when 52, 58, 70 # ASTC_10x10, ASTC_RGBA_10x10, ASTC_HDR_10x10
decode_astc(width, height, 10, bin)
when 53, 59, 71 # ASTC_RGB_12x12, ASTC_RGBA_12x12, ASTC_HDR_12x12
decode_astc(width, height, 12, bin)
# when 60 # ETC_RGB4_3DS
# when 61 # ETC_RGBA8_3DS
when 62 # RG16
decode_rg16(width, height, bin)
when 63 # R8
decode_r8(width, height, bin)
# when 64 # ETC_RGB4Crunched
# when 65 # ETC2_RGBA8Crunched
end
end
end
# [0.0,1.0] -> [0,255]
def self.f2i(d)
(d * 255).round.clamp(0, 255)
# Decode image from RGBA4444 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgba4444(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 4)
(width * height).times do |i|
c = endian == :little ? BinUtils.get_int16_le(bin, i * 2) : BinUtils.get_int16_be(bin, i * 2)
c = ((c & 0xf000) << 12) | ((c & 0x0f00) << 8) | ((c & 0x00f0) << 4) | (c & 0x000f)
BinUtils.append_int32_be!(mem, c << 4 | c)
end
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
end
# Decode image from ARGB4444 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_argb4444(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 4)
(width * height).times do |i|
c = endian == :little ? BinUtils.get_int16_le(bin, i * 2) : BinUtils.get_int16_be(bin, i * 2)
c = ((c & 0x0f00) << 16) | ((c & 0x00f0) << 12) | ((c & 0x000f) << 8) | ((c & 0xf000) >> 12)
BinUtils.append_int32_be!(mem, c << 4 | c)
end
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
end
# Decode image from RGB565 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgb565(width, height, bin, endian = :big)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_rgb565(bin, width * height, endian == :big)).flip
end
# Decode image from A8 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_a8(width, height, bin)
mem = String.new(capacity: width * height * 3)
(width * height).times do |i|
c = BinUtils.get_int8(bin, i)
BinUtils.append_int8!(mem, c, c, c)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from R8 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_r8(width, height, bin)
decode_a8(width, height, bin)
end
# Decode image from RG16 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_rg16(width, height, bin)
mem = String.new(capacity: width * height * 3)
(width * height).times do |i|
BinUtils.append_int16_int8_be!(mem, BinUtils.get_int16_be(bin, i * 2), 0)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from RGB24 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgb24(width, height, bin)
ChunkyPNG::Image.from_rgb_stream(width, height, bin).flip
end
# Decode image from RGBA32 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgba32(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, bin).flip
end
# Decode image from ARGB32 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_argb32(width, height, bin)
mem = String.new(capacity: width * height * 4)
(width * height).times do |i|
c = BinUtils.get_int32_be(bin, i * 4)
BinUtils.append_int32_be!(mem, ((c & 0x00ffffff) << 8) | ((c & 0xff000000) >> 24))
end
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
end
# Decode image from BGRA32 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_bgra32(width, height, bin)
mem = String.new(capacity: width * height * 4)
(width * height).times do |i|
c = BinUtils.get_int32_le(bin, i * 4)
BinUtils.append_int32_be!(mem, ((c & 0x00ffffff) << 8) | ((c & 0xff000000) >> 24))
end
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
end
# Decode image from R16 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_r16(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 3)
(width * height).times do |i|
c = endian == :little ? BinUtils.get_int16_le(bin, i * 2) : BinUtils.get_int16_be(bin, i * 2)
c = f2i(r / 65535.0)
BinUtils.append_int8!(mem, c, c, c)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from RGB9e5 binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgb9e5float(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 3)
(width * height).times do |i|
n = endian == :little ? BinUtils.get_int32_le(bin, i * 4) : BinUtils.get_int32_be(bin, i * 4)
e = (n & 0xf8000000) >> 27
r = (n & 0x7fc0000) >> 9
g = (n & 0x3fe00) >> 9
b = n & 0x1ff
r = (r / 512r + 1) * (2**(e - 15))
g = (g / 512r + 1) * (2**(e - 15))
b = (b / 512r + 1) * (2**(e - 15))
BinUtils.append_int8!(mem, f2i(r), f2i(g), f2i(b))
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from R Half-float binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rhalf(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 3)
(width * height).times do |i|
c = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 2) : BinUtils.get_int16_be(bin, i * 2)))
BinUtils.append_int8!(mem, c, c, c)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from RG Half-float binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rghalf(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 3)
(width * height).times do |i|
r = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 4) : BinUtils.get_int16_be(bin, i * 4)))
g = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 4 + 2) : BinUtils.get_int16_be(bin, i * 4 + 2)))
BinUtils.append_int8!(mem, r, g, 0)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from RGBA Half-float binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgbahalf(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 4)
(width * height).times do |i|
r = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 8) : BinUtils.get_int16_be(bin, i * 8)))
g = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 8 + 2) : BinUtils.get_int16_be(bin, i * 8 + 2)))
b = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 8 + 4) : BinUtils.get_int16_be(bin, i * 8 + 4)))
a = f2i(n2f(endian == :little ? BinUtils.get_int16_le(bin, i * 8 + 6) : BinUtils.get_int16_be(bin, i * 8 + 6)))
BinUtils.append_int8!(mem, r, g, b, a)
end
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
end
# Decode image from R float binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rfloat(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 3)
unpackstr = endian == :little ? 'e' : 'g'
(width * height).times do |i|
c = f2i(bin.byteslice(i * 4, 4).unpack1(unpackstr))
BinUtils.append_int8!(mem, c, c, c)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from RG float binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgfloat(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 3)
unpackstr = endian == :little ? 'e2' : 'g2'
(width * height).times do |i|
r, g = bin.byteslice(i * 8, 8).unpack(unpackstr)
BinUtils.append_int8!(mem, f2i(r), f2i(g), 0)
end
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
end
# Decode image from RGBA float binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @param [Symbol] endian endianness of binary
# @return [ChunkyPNG::Image] decoded image
def self.decode_rgbafloat(width, height, bin, endian = :big)
mem = String.new(capacity: width * height * 4)
unpackstr = endian == :little ? 'e4' : 'g4'
(width * height).times do |i|
r, g, b, a = bin.byteslice(i * 16, 16).unpack(unpackstr)
BinUtils.append_int8!(mem, f2i(r), f2i(g), f2i(b), f2i(a))
end
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
end
# Decode image from DXT1 compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_dxt1(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_dxt1(bin, width, height))
end
# Decode image from DXT5 compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_dxt5(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_dxt5(bin, width, height))
end
# Decode image from ETC1 compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_etc1(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_etc1(bin, width, height))
end
# Decode image from ETC2 compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_etc2rgb(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_etc2(bin, width, height))
end
# Decode image from ETC2 Alpha1 compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_etc2rgba1(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_etc2a1(bin, width, height))
end
# Decode image from ETC2 Alpha8 compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_etc2rgba8(width, height, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_etc2a8(bin, width, height))
end
# Decode image from ASTC compressed binary
# @param [Integer] width image width
# @param [Integer] height image height
# @param [Integer] blocksize block size
# @param [String] bin binary to decode
# @return [ChunkyPNG::Image] decoded image
def self.decode_astc(width, height, blocksize, bin)
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_astc(bin, width, height, blocksize, blocksize))
end
# Create ASTC file data from ObjectValue
# @param [Mikunyan::ObjectValue,Hash] object target object
# @return [String,nil] created file
def self.create_astc_file(object)
astc_list = {
48 => 4, 49 => 5, 50 => 6, 51 => 8, 52 => 10, 53 => 12,
54 => 4, 55 => 5, 56 => 6, 57 => 8, 58 => 10, 59 => 12
}
width = object['m_Width']
height = object['m_Height']
fmt = object['m_TextureFormat']
bin = object['image data']
width = width.value if width.class == ObjectValue
height = height.value if height.class == ObjectValue
fmt = fmt.value if fmt.class == ObjectValue
bin = bin.value if bin.class == ObjectValue
if width && height && fmt && astc_list[fmt]
header = "\x13\xAB\xA1\x5C".force_encoding('ascii-8bit')
header << [astc_list[fmt], astc_list[fmt], 1].pack('C*')
header << [width].pack('V').byteslice(0, 3)
header << [height].pack('V').byteslice(0, 3)
header << "\x01\x00\x00"
header + bin
end
end
# convert 16bit float
def self.n2f(n)
case n
when 0x0000
0.0
when 0x8000
-0.0
when 0x7c00
Float::INFINITY
when 0xfc00
-Float::INFINITY
else
s = n & 0x8000 != 0
e = n & 0x7c00
f = n & 0x03ff
case e
when 0x7c00
Float::NAN
when 0
(s ? -f : f) * 2.0**-24
else
(s ? -1 : 1) * (f / 1024.0 + 1) * (2.0**((e >> 10) - 15))
end
end
end
# [0.0,1.0] -> [0,255]
def self.f2i(d)
(d * 255).round.clamp(0, 255)
end
end
end
class ImageDecoder
def self.decode_object(object)
warn 'Warning: Mikunyan::ImageDecoder.decode_object is deprecated and will be removed at a future release. ' \
'Use Mikunyan::Decoder::ImageDecoder.decode_object or' \
'Mikunyan::CustomTypes::Texture2D::generate_png instead.'
Mikunyan::Decoder::ImageDecoder.decode_object(object)
end
end
end
+31 -16
View File
@@ -4,11 +4,12 @@ module Mikunyan
# Class for representing decoded object
# @attr [String] name object name
# @attr [String] type object type name
# @attr [Hash<String,Mikunyan::ObjectValue>] attr
# @attr [Object] value object
# @attr [Symbol] endian endianness
# @attr [Boolean] is_struct
class ObjectValue
attr_accessor :name, :type, :value, :endian, :is_struct
attr_accessor :name, :type, :attr, :value, :endian, :is_struct
# Constructor
# @param [String] name object name
@@ -27,13 +28,13 @@ module Mikunyan
# Return whether object is array or not
# @return [Boolean]
def array?
value && value.class == Array
value&.is_a?(Array)
end
# Return whether object is value or not
# @return [Boolean]
def value?
value && value.class != Array
value && !value.is_a?(Array)
end
# Return whether object is struct or not
@@ -55,20 +56,16 @@ module Mikunyan
@attr.key?(key)
end
# Return value
# @return [Object] value
def []
@value
end
# Return value of selected index or key
# @param [Integer,String] i index or key
# @param [Integer,String] key index or key
# @return [Object] value
def [](i)
if array? && i.class == Integer
@value[i]
def [](key = nil)
if key.nil?
@value
elsif array? && key.is_a?(Integer)
@value[key]
else
@attr[i]
@attr[key]
end
end
@@ -83,13 +80,31 @@ module Mikunyan
# Return value of called key
# @param [String] name key
# @return [Object] value
def method_missing(name, *_args)
@attr[name.to_s]
def method_missing(name, *args)
n = name.to_s
@attr.key?(n) ? @attr[n] : super
end
# Implementation of respond_to_missing?
def respond_to_missing?(symbol, _include_private)
@attr.key?(symbol.to_s)
end
# Simplifies self, or serializes self with ruby primitive types
def simplify
if @type == 'pair'
[@attr['first'].simplify, @attr['second'].simplify]
elsif @type == 'map' && @value.is_a?(Array)
@value.map{|e| [e['first'].simplify, e['second'].simplify]}.to_h
elsif is_struct
@attr.map{|key, val| [key, val.simplify]}.to_h
elsif @value.is_a?(Array)
@value.map{|e| e.is_a?(ObjectValue) ? e.simplify : e}
elsif @value.is_a?(ObjectValue)
@value.simplify
else
@value
end
end
end
end
+121 -54
View File
@@ -1,5 +1,8 @@
# frozen_string_literal: true
require 'json'
require 'mikunyan/binary_reader'
module Mikunyan
# Class for representing TypeTree
# @attr [Array<Mikunyan::TypeTree::Node>] nodes list of all nodes
@@ -8,77 +11,141 @@ module Mikunyan
# Struct for representing Node in TypeTree
# @attr [String] version version string
# @attr [Integer] depth depth of node (>= 0)
# @attr [Integer] level level of node (>= 0)
# @attr [Boolean] array? array node or not
# @attr [String] type type name
# @attr [String] name node (attribute) name
# @attr [Integer] index index in node list
# @attr [Integer] flags flags of node
Node = Struct.new(:version, :depth, :array?, :type, :name, :size, :index, :flags)
# Create TypeTree from binary string (new version)
# @param [Mikunyan::BinaryReader] br
# @return [Mikunyan::TypeTree] created TypeTree
def self.load(br)
nodes = []
node_count = br.i32u
buffer_size = br.i32u
node_count.times do
node = Node.new(br.i16u, br.i8u, br.i8u != 0, br.i32, br.i32, br.i32, br.i32u, br.i32u)
nodes << node
# @attr [Integer,nil] v18meta
# @attr [Mikunyan::TypeTree::Node,nil] parent ̑
# @attr [Array<Mikunyan::TypeTree::Node>] children
Node = Struct.new(:version, :level, :array?, :type, :name, :size, :index, :flags, :v18meta, :parent, :children, keyword_init: true) do
def need_align?
flags & 0x4000 != 0
end
buffer = br.read(buffer_size)
nodes.each do |n|
n.type = if n.type >= 0
buffer.unpack1("@#{n.type}Z*")
else
Mikunyan::STRING_TABLE[n.type + 2**31]
end
n.name = if n.name >= 0
buffer.unpack1("@#{n.name}Z*")
else
Mikunyan::STRING_TABLE[n.name + 2**31]
end
end
r = TypeTree.new
r.nodes = nodes
r
end
# Create TypeTree from binary string (legacy version)
# Returns the root node of the typetree
# @return [Mikunyan::TypeTree::Node,nil]
def tree
nodes&.[](0)
end
# Generates JSON-compatible serialized representation of typetree information
def serialize
{
'nodes' =>
nodes.map do |e|
{
'version' => e.version,
'level' => e.level,
'is_array' => e.array?,
'type' => e.type,
'name' => e.name,
'size' => e.size,
'flags' => e.flags,
'v18meta' => e.v18meta
}
end
}
end
# Creates TypeTree from binary string
# @param [Mikunyan::BinaryReader] br
# @param [Integer] version asset format version
# @return [Mikunyan::TypeTree] created TypeTree
def self.load_legacy(br)
nodes = []
stack = [0]
until stack.empty?
depth = stack.pop
type = br.cstr
name = br.cstr
size = br.i32
index = br.i32u
is_array = (br.i32 != 0)
version = br.i32u
flags = br.i32u
child_count = br.i32u
child_count.times{stack << depth + 1}
nodes << Node.new(version, depth, is_array, type, name, size, index, flags)
def self.load(br, version)
if version == 10 || version >= 12
node_count = br.i32u
buffer_size = br.i32u
nodes = Array.new(node_count) do
Node.new(
version: br.i16u,
level: br.i8u,
array?: br.bool,
type: br.i32u,
name: br.i32u,
size: br.i32s,
index: br.i32u,
flags: br.i32u,
v18meta: version >= 18 ? br.i64u : nil,
children: []
)
end
buffer = br.read(buffer_size)
stack = []
nodes.each do |n|
n.type = Mikunyan::Constants.get_string_or_default(n.type, buffer)
n.name = Mikunyan::Constants.get_string_or_default(n.name, buffer)
if n.level > 0
n.parent = stack[n.level - 1]
n.parent.children << n
end
stack[n.level] = n
end
else
nodes = []
stack = []
until stack.empty? && !nodes.empty?
parent = stack.pop
node = Node.new(
type: br.cstr,
name: br.cstr,
size: br.i32s,
index: br.i32u,
array?: br.i32 != 0,
version: br.i32u,
flags: br.i32u,
level: parent ? parent.level + 1 : 0,
parent: parent,
children: []
)
nodes << node
parent.children << node if parent
stack += Array.new(br.i32u, node)
end
end
r = TypeTree.new
r.nodes = nodes
r
ret = TypeTree.new
ret.nodes = nodes
ret
end
# Create default TypeTree from hash string (if exists)
# @param [Integer] class_id
# @param [String] hash
# @return [Mikunyan::TypeTree,nil] created TypeTree
def self.load_default(hash)
hash_str = hash.unpack1('H*')
file = File.expand_path("../typetrees/#{hash_str}.dat", __FILE__)
def self.load_default(class_id, hash)
file = File.expand_path("../typetrees/#{class_id}/#{hash.unpack1('H*')}.json", __FILE__)
return nil unless File.file?(file)
r = TypeTree.new
r.nodes = Marshal.load(File.binread(file))
r
TypeTree.deserialize(JSON.parse(File.read(file)))
end
# Creates TypeTree from serialized object
# @param [Hash] obj
def self.deserialize(obj)
stack = []
ret = TypeTree.new
ret.nodes = obj['nodes'].map.with_index do |e, index|
level = e['level'] || e['depth']
parent = level > 0 ? stack[level - 1] : nil
n = Node.new(
version: e['version'],
level: level,
array?: e['is_array'],
type: e['type'],
name: e['name'],
size: e['size'],
index: index,
flags: e['flags'],
v18meta: e['v18meta'],
parent: parent,
children: []
)
parent.children << n if parent
stack[level] = n
end
ret
end
end
end
+19
View File
@@ -0,0 +1,19 @@
# frozen_string_literal: true
require 'mikunyan/base_object'
module Mikunyan
module CustomTypes
class TextAsset < Mikunyan::BaseObject
Mikunyan::CustomTypes.set_custom_type(self, 'TextAsset')
def text
@attr['m_Script']&.value
end
def bytes
@attr['m_Script']&.value.dup.force_encoding('ASCII-8BIT')
end
end
end
end
+32
View File
@@ -0,0 +1,32 @@
# frozen_string_literal: true
require 'mikunyan/base_object'
require 'mikunyan/decoders/image_decoder'
module Mikunyan
module CustomTypes
class Texture2D < Mikunyan::BaseObject
Mikunyan::CustomTypes.set_custom_type(self, 'Texture2D')
def generate_png
Mikunyan::Decoder::ImageDecoder.decode_object(self)
end
def width
@attr['m_Width']&.value
end
def height
@attr['m_Height']&.value
end
def texture_format
@attr['m_TextureFormat']&.value
end
def mipmap_count
@attr['m_MipCount']&.value
end
end
end
end
@@ -0,0 +1 @@
{"nodes":[{"version":5,"level":0,"is_array":false,"type":"GameObject","name":"Base","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"vector","name":"m_Component","size":-1,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":65,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":65,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"ComponentPair","name":"data","size":12,"flags":65,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"PPtr<Component>","name":"component","size":12,"flags":65,"v18meta":null},{"version":1,"level":5,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":65,"v18meta":null},{"version":1,"level":5,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":65,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"unsigned int","name":"m_Layer","size":4,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_Name","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16385,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":1,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":1,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"UInt16","name":"m_Tag","size":2,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_IsActive","size":1,"flags":0,"v18meta":null}]}
@@ -0,0 +1 @@
{"nodes":[{"version":6,"level":0,"is_array":false,"type":"GameObject","name":"Base","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"vector","name":"m_Component","size":-1,"flags":32833,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16449,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":65,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"ComponentPair","name":"data","size":12,"flags":65,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"PPtr<Component>","name":"component","size":12,"flags":65,"v18meta":null},{"version":1,"level":5,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":65,"v18meta":null},{"version":1,"level":5,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":65,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"unsigned int","name":"m_Layer","size":4,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_Name","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16385,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":1,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":1,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"UInt16","name":"m_Tag","size":2,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_IsActive","size":1,"flags":0,"v18meta":null}]}
@@ -0,0 +1 @@
{"nodes":[{"version":5,"level":0,"is_array":false,"type":"GameObject","name":"Base","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"vector","name":"m_Component","size":-1,"flags":32833,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16449,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":65,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"ComponentPair","name":"data","size":12,"flags":65,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"PPtr<Component>","name":"component","size":12,"flags":65,"v18meta":null},{"version":1,"level":5,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":65,"v18meta":null},{"version":1,"level":5,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":65,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"unsigned int","name":"m_Layer","size":4,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_Name","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16385,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":1,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":1,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"UInt16","name":"m_Tag","size":2,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_IsActive","size":1,"flags":0,"v18meta":null}]}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"nodes":[{"version":1,"level":0,"is_array":false,"type":"TextAsset","name":"Base","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_Name","size":-1,"flags":32769,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16385,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":1,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":1,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_Script","size":-1,"flags":67141633,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":67125249,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":67108865,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":67108865,"v18meta":null}]}
@@ -0,0 +1 @@
{"nodes":[{"version":3,"level":0,"is_array":false,"type":"Animation","name":"Base","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"PPtr<GameObject>","name":"m_GameObject","size":12,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":65,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"UInt8","name":"m_Enabled","size":1,"flags":16641,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"PPtr<AnimationClip>","name":"m_Animation","size":12,"flags":0,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":8388609,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":8388609,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"vector","name":"m_Animations","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16384,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":0,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"PPtr<AnimationClip>","name":"data","size":12,"flags":0,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":8388609,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":8388609,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"int","name":"m_WrapMode","size":4,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_PlayAutomatically","size":1,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_AnimatePhysics","size":1,"flags":16384,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"int","name":"m_CullingType","size":4,"flags":0,"v18meta":null}]}
@@ -0,0 +1 @@
{"nodes":[{"version":3,"level":0,"is_array":false,"type":"Animation","name":"Base","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"PPtr<GameObject>","name":"m_GameObject","size":12,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":65,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"UInt8","name":"m_Enabled","size":1,"flags":16641,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"PPtr<AnimationClip>","name":"m_Animation","size":12,"flags":0,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":1,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":1,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"vector","name":"m_Animations","size":-1,"flags":0,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":0,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":0,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"PPtr<AnimationClip>","name":"data","size":12,"flags":0,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":1,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":1,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"int","name":"m_WrapMode","size":4,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_PlayAutomatically","size":1,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_AnimatePhysics","size":1,"flags":16384,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"int","name":"m_CullingType","size":4,"flags":0,"v18meta":null}]}
@@ -0,0 +1 @@
{"nodes":[{"version":4,"level":0,"is_array":false,"type":"MonoScript","name":"Base","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_Name","size":-1,"flags":32769,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16385,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":1,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":1,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"int","name":"m_ExecutionOrder","size":4,"flags":16,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"Hash128","name":"m_PropertiesHash","size":16,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[0]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[1]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[2]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[3]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[4]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[5]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[6]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[7]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[8]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[9]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[10]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[11]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[12]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[13]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[14]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[15]","size":1,"flags":16,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_ClassName","size":-1,"flags":32784,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16401,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":17,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":17,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_Namespace","size":-1,"flags":32784,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16401,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":17,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":17,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_AssemblyName","size":-1,"flags":32784,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16401,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":17,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":17,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_IsEditorScript","size":1,"flags":1,"v18meta":null}]}
@@ -0,0 +1 @@
{"nodes":[{"version":5,"level":0,"is_array":false,"type":"MonoScript","name":"Base","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_Name","size":-1,"flags":557057,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":540673,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":524289,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":524289,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"int","name":"m_ExecutionOrder","size":4,"flags":16,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"Hash128","name":"m_PropertiesHash","size":16,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[0]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[1]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[2]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[3]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[4]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[5]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[6]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[7]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[8]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[9]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[10]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[11]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[12]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[13]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[14]","size":1,"flags":16,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"UInt8","name":"bytes[15]","size":1,"flags":16,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_ClassName","size":-1,"flags":32784,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16401,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":17,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":17,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_Namespace","size":-1,"flags":32784,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16401,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":17,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":17,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_AssemblyName","size":-1,"flags":32784,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16401,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":17,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":17,"v18meta":null}]}
@@ -0,0 +1 @@
{"nodes":[{"version":1,"level":0,"is_array":false,"type":"Flare","name":"Base","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"string","name":"m_Name","size":-1,"flags":32769,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16385,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":1,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"char","name":"data","size":1,"flags":1,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"PPtr<Texture>","name":"m_FlareTexture","size":12,"flags":0,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":8388609,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":8388609,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"int","name":"m_TextureLayout","size":4,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"vector","name":"m_Elements","size":-1,"flags":32768,"v18meta":null},{"version":1,"level":2,"is_array":true,"type":"Array","name":"Array","size":-1,"flags":16384,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"int","name":"size","size":4,"flags":0,"v18meta":null},{"version":1,"level":3,"is_array":false,"type":"FlareElement","name":"data","size":32,"flags":0,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"unsigned int","name":"m_ImageIndex","size":4,"flags":0,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"float","name":"m_Position","size":4,"flags":0,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"float","name":"m_Size","size":4,"flags":0,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"ColorRGBA","name":"m_Color","size":16,"flags":2097152,"v18meta":null},{"version":1,"level":5,"is_array":false,"type":"float","name":"r","size":4,"flags":2097153,"v18meta":null},{"version":1,"level":5,"is_array":false,"type":"float","name":"g","size":4,"flags":2097153,"v18meta":null},{"version":1,"level":5,"is_array":false,"type":"float","name":"b","size":4,"flags":2097153,"v18meta":null},{"version":1,"level":5,"is_array":false,"type":"float","name":"a","size":4,"flags":2097153,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"bool","name":"m_UseLightColor","size":1,"flags":0,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"bool","name":"m_Rotate","size":1,"flags":0,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"bool","name":"m_Zoom","size":1,"flags":0,"v18meta":null},{"version":1,"level":4,"is_array":false,"type":"bool","name":"m_Fade","size":1,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_UseFog","size":1,"flags":0,"v18meta":null}]}
@@ -0,0 +1 @@
{"nodes":[{"version":1,"level":0,"is_array":false,"type":"LensFlare","name":"Base","size":54,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"PPtr<GameObject>","name":"m_GameObject","size":12,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":65,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"UInt8","name":"m_Enabled","size":1,"flags":16641,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"PPtr<Flare>","name":"m_Flare","size":12,"flags":0,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":8388609,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":8388609,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"ColorRGBA","name":"m_Color","size":16,"flags":2097152,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"float","name":"r","size":4,"flags":2097153,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"float","name":"g","size":4,"flags":2097153,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"float","name":"b","size":4,"flags":2097153,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"float","name":"a","size":4,"flags":2097153,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"float","name":"m_Brightness","size":4,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"float","name":"m_FadeSpeed","size":4,"flags":0,"v18meta":null},{"version":2,"level":1,"is_array":false,"type":"BitField","name":"m_IgnoreLayers","size":4,"flags":0,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"unsigned int","name":"m_Bits","size":4,"flags":4194305,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_Directional","size":1,"flags":0,"v18meta":null}]}
@@ -0,0 +1 @@
{"nodes":[{"version":1,"level":0,"is_array":false,"type":"Behaviour","name":"Base","size":13,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"PPtr<GameObject>","name":"m_GameObject","size":12,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":65,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"UInt8","name":"m_Enabled","size":1,"flags":16641,"v18meta":null}]}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"nodes":[{"version":2,"level":0,"is_array":false,"type":"SphereCollider","name":"Base","size":42,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"PPtr<GameObject>","name":"m_GameObject","size":12,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":65,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"PPtr<PhysicMaterial>","name":"m_Material","size":12,"flags":0,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":8388609,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":8388609,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_IsTrigger","size":1,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_Enabled","size":1,"flags":16641,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"float","name":"m_Radius","size":4,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"Vector3f","name":"m_Center","size":12,"flags":2097152,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"float","name":"x","size":4,"flags":2097152,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"float","name":"y","size":4,"flags":2097152,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"float","name":"z","size":4,"flags":2097152,"v18meta":null}]}
@@ -0,0 +1 @@
{"nodes":[{"version":1,"level":0,"is_array":false,"type":"CapsuleCollider","name":"Base","size":50,"flags":32768,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"PPtr<GameObject>","name":"m_GameObject","size":12,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":65,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":65,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"PPtr<PhysicMaterial>","name":"m_Material","size":12,"flags":0,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"int","name":"m_FileID","size":4,"flags":8388609,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"SInt64","name":"m_PathID","size":8,"flags":8388609,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_IsTrigger","size":1,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"bool","name":"m_Enabled","size":1,"flags":16641,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"float","name":"m_Radius","size":4,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"float","name":"m_Height","size":4,"flags":0,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"int","name":"m_Direction","size":4,"flags":8388608,"v18meta":null},{"version":1,"level":1,"is_array":false,"type":"Vector3f","name":"m_Center","size":12,"flags":2097152,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"float","name":"x","size":4,"flags":2097152,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"float","name":"y","size":4,"flags":2097152,"v18meta":null},{"version":1,"level":2,"is_array":false,"type":"float","name":"z","size":4,"flags":2097152,"v18meta":null}]}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More