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 *.bundle
.DS_Store .DS_Store
.idea/
*.iml
+38 -37
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# frozen_string_literal: true
require 'mikunyan' require 'mikunyan'
require 'mikunyan/decoders'
require 'fileutils' require 'fileutils'
begin begin
require 'usamin' require 'usamin'
@@ -9,7 +10,7 @@ rescue LoadError
require 'json' require 'json'
end end
opts = {:as_asset => false, :outputdir => nil, :sprite => false, :pretty => false} opts = { as_asset: false, outputdir: nil, sprite: false, pretty: false }
arg = nil arg = nil
i = 0 i = 0
while i < ARGV.count while i < ARGV.count
@@ -28,13 +29,13 @@ while i < ARGV.count
warn("Unknown option: #{ARGV[i]}") warn("Unknown option: #{ARGV[i]}")
end end
else else
arg = ARGV[i] unless arg arg ||= ARGV[i]
end end
i += 1 i += 1
end end
unless arg unless arg
warn("Input file is not specified") warn('Input file is not specified')
exit(1) exit(1)
end end
@@ -43,13 +44,7 @@ unless File.file?(arg)
exit(1) exit(1)
end end
assets = [] assets = opts[:as_asset] ? [Mikunyan::Asset.file(arg)] : Mikunyan::AssetBundle.file(arg).assets
if opts[:as_asset]
assets = [Mikunyan::Asset.file(arg, File.basename(arg, '.*'))]
else
assets = Mikunyan::AssetBundle.file(arg).assets
end
outdir = opts[:outputdir] || File.basename(arg, '.*') outdir = opts[:outputdir] || File.basename(arg, '.*')
FileUtils.mkpath(outdir) FileUtils.mkpath(outdir)
@@ -59,42 +54,48 @@ assets.each do |asset|
json = {} json = {}
textures = {} textures = {}
asset.objects.select{|o| asset.object_type(o) == 'Sprite'}.each do |o| asset.each_object do |obj|
obj = asset.parse_object(o) next unless obj.type == 'Sprite'
obj = obj.parse
next unless obj next unless obj
name = obj.m_Name.value texture_id = obj.m_RD&.texture&.m_PathID&.value
tex_id = obj.m_RD.texture.m_PathID.value next unless texture_id
unless textures[tex_id] unless textures.key?(texture_id)
tex_obj = asset.parse_object(tex_id) texture_obj = asset.parse_object(texture_id)
if tex_obj if texture_obj.is_a?(Mikunyan::CustomTypes::Texture2D)
textures[tex_id] = Mikunyan::ImageDecoder.decode_object(tex_obj) textures[texture_id] = texture_obj.generate_png
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] 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 end
end end
if textures[tex_id] x = obj.m_Rect&.x&.value
x = obj.m_Rect.x.value y = obj.m_Rect&.y&.value
y = obj.m_Rect.y.value width = obj.m_Rect&.width&.value
width = obj.m_Rect.width.value height = obj.m_Rect&.height&.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} json[texture_id][:sprites] << { name: obj.object_name, x: x, y: y, width: width, height: height, path_id: obj.path_id }
textures[tex_id].crop(x.round, (textures[tex_id].height - height - y).round, width.round, height.round).save("#{outdir}/#{name}.png")
end 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 end
puts opts[:pretty] ? JSON.pretty_generate(json.values) : JSON.generate(json.values) puts opts[:pretty] ? JSON.pretty_generate(json.values) : JSON.generate(json.values)
else else
json = [] json = []
asset.objects.select{|o| asset.object_type(o) == 'Texture2D'}.each do |o| asset.each_object do |obj|
obj = asset.parse_object(o) next unless obj.type == 'Texture2D'
next unless obj obj = obj.parse
name = obj.m_Name.value next unless obj.is_a?(Mikunyan::CustomTypes::Texture2D)
image = Mikunyan::ImageDecoder.decode_object(obj) json << {
if image name: obj.object_name, width: obj.width, height: obj.height,
json << {:name => name, :width => image.width, :height => image.height, :path_id => o.path_id} format: obj.texture_format, path_id: obj.path_id
image.save("#{outdir}/#{name}.png") }
end obj.generate_png&.save("#{outdir}/#{obj.object_name}.png")
end end
puts opts[:pretty] ? JSON.pretty_generate(json) : JSON.generate(json) puts opts[:pretty] ? JSON.pretty_generate(json) : JSON.generate(json)
end end
+11 -30
View File
@@ -1,24 +1,26 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# frozen_string_literal: true
require 'mikunyan' require 'mikunyan'
require 'base64' require 'base64'
def obj64(obj) def obj64(obj)
if obj.class == Hash if obj.is_a?(Hash)
obj.map{|k, v| [k, obj64(v)]}.to_h obj.map{|k, v| [k, obj64(v)]}.to_h
elsif obj.class == Array elsif obj.is_a?(Array)
obj.map{|e| obj64(e)} obj.map{|e| obj64(e)}
elsif obj.class == String elsif obj.is_a?(String)
if obj.encoding == Encoding::UTF_8 if obj.encoding == Encoding::UTF_8
obj obj
else else
Base64::strict_encode64(obj) Base64.strict_encode64(obj)
end end
else else
obj obj
end end
end end
opts = {:as_asset => false, :pretty => false, :yaml => false} opts = { as_asset: false, pretty: false, yaml: false }
arg = nil arg = nil
i = 0 i = 0
while i < ARGV.count while i < ARGV.count
@@ -34,41 +36,20 @@ while i < ARGV.count
warn("Unknown option: #{ARGV[i]}") warn("Unknown option: #{ARGV[i]}")
end end
else else
arg = ARGV[i] unless arg arg ||= ARGV[i]
end end
i += 1 i += 1
end end
if opts[:pretty] && opts[:yaml] warn('Option --pretty is ignored if --yaml is specified.') if opts[:pretty] && opts[:yaml]
warn("Option --pretty is ignored if --yaml is specified.")
end
unless File.file?(arg) unless File.file?(arg)
warn("File not found: #{arg}") warn("File not found: #{arg}")
exit(1) exit(1)
end end
assets = {} 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[: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
if opts[:yaml] if opts[:yaml]
require 'yaml' require 'yaml'
-6
View File
@@ -1,13 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'mikunyan/version' require 'mikunyan/version'
require 'mikunyan/asset_bundle' 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 for deserializing Unity Assets and AssetBundles
module Mikunyan module Mikunyan
+171 -202
View File
@@ -1,5 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'mikunyan/type_tree'
require 'mikunyan/constants'
require 'mikunyan/object_value'
require 'mikunyan/base_object'
module Mikunyan module Mikunyan
# Class for representing Unity Asset # Class for representing Unity Asset
# @attr_reader [String] name Asset name # @attr_reader [String] name Asset name
@@ -8,18 +13,19 @@ module Mikunyan
# @attr_reader [Integer] target_platform target platform number # @attr_reader [Integer] target_platform target platform number
# @attr_reader [Symbol] endian data endianness (:little or :big) # @attr_reader [Symbol] endian data endianness (:little or :big)
# @attr_reader [Array<Mikunyan::Asset::Klass>] klasses defined classes # @attr_reader [Array<Mikunyan::Asset::Klass>] klasses defined classes
# @attr_reader [Array<Mikunyan::Asset::ObjectData>] objects included objects # @attr_reader [Array<Mikunyan::Asset::ObjectEntry>] objects contained objects
# @attr_reader [Array<Integer>] add_ids ? # @attr_reader [Array<Mikunyan::Asset::LocalObjectEntry>] add_ids ?
# @attr_reader [Array<Mikunyan::Asset::Reference>] references reference data # @attr_reader [Array<Mikunyan::Asset::Reference>] references reference data
class Asset 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 # Struct for representing Asset class definition
# @attr [Integer] class_id class ID # @attr [Integer] class_id class ID
# @attr [Boolean] stripped?
# @attr [Integer,nil] script_id script ID # @attr [Integer,nil] script_id script ID
# @attr [String] hash hash value (16 or 32 bytes) # @attr [String] hash hash value (16 or 32 bytes)
# @attr [Mikunyan::TypeTree, nil] type_tree given TypeTree # @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 # Struct for representing Asset object information
# @attr [Integer] path_id path ID # @attr [Integer] path_id path ID
@@ -30,7 +36,29 @@ module Mikunyan
# @attr [Integer,nil] class_idx class definition index # @attr [Integer,nil] class_idx class definition index
# @attr [Boolean] destroyed? destroyed or not # @attr [Boolean] destroyed? destroyed or not
# @attr [String] data binary data of object # @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 # Struct for representing Asset reference information
# @attr [String] path path # @attr [String] path path
@@ -39,13 +67,20 @@ module Mikunyan
# @attr [String] file_path Asset name # @attr [String] file_path Asset name
Reference = Struct.new(:path, :guid, :type, :file_path) 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 # Load Asset from binary string
# @param [String] bin binary data # @param [String,IO] bin binary data
# @param [String] name Asset name # @param [String] name Asset name
# @param [String] resource resource data
# @param [String] res_s resS data # @param [String] res_s resS data
# @return [Mikunyan::Asset] deserialized Asset object # @return [Mikunyan::Asset] deserialized Asset object
def self.load(bin, name, res_s = nil) def self.load(bin, name, resource = nil, res_s = nil)
r = Asset.new(name, res_s) r = Asset.new(name, resource, res_s)
r.send(:load, bin) r.send(:load, bin)
r r
end end
@@ -56,7 +91,15 @@ module Mikunyan
# @return [Mikunyan::Asset] deserialized Asset object # @return [Mikunyan::Asset] deserialized Asset object
def self.file(file, name = nil) def self.file(file, name = nil)
name ||= File.basename(name, '.*') 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 end
# Returns list of all path IDs # Returns list of all path IDs
@@ -68,273 +111,199 @@ module Mikunyan
# Returns list of containers # Returns list of containers
# @return [Array<Hash>,nil] list of all containers # @return [Array<Hash>,nil] list of all containers
def containers def containers
obj = parse_object(1) obj = @path_id_table[1]
return nil unless obj&.m_Container && obj.m_Container.array? return nil unless obj.klass&.type_tree&.tree&.type == 'AssetBundle'
obj.m_Container.value.map do |e| parse_object(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 } 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
end end
# Parse object of given path ID # Parse object of given path ID
# @param [Integer,ObjectData] path_id path ID or object # @param [Integer,ObjectEntry] obj path ID or object
# @return [Mikunyan::ObjectValue,nil] parsed object # @return [Mikunyan::BaseObject,nil] parsed object
def parse_object(path_id) def parse_object(obj)
if path_id.class == Integer obj = @path_id_table[obj] if obj.class == Integer
obj = @objects.find{|e| e.path_id == path_id} return nil unless obj.klass&.type_tree
return nil unless obj value_klass = Mikunyan::CustomTypes.get_custom_type(obj.klass.type_tree.tree.type, obj.class_id)
elsif path_id.class == ObjectData ret = parse_object_private(BinaryReader.new(obj.data, @endian), obj.klass.type_tree.tree, value_klass)
obj = path_id ret.object_entry = obj
else ret
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)
end end
# Parse object of given path ID and simplify it # 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 # @return [Hash,nil] parsed object
def parse_object_simple(path_id) def parse_object_simple(obj)
Asset.object_simplify(parse_object(path_id)) parse_object(obj)&.simplify
end end
# Returns object type name string # 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 # @return [String,nil] type name
def object_type(path_id) def object_type(obj)
if path_id.class == Integer obj = @path_id_table[obj] if obj.class == Integer
obj = @objects.find{|e| e.path_id == path_id} obj&.type
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 end
def self.object_simplify(obj)
obj.is_a?(ObjectValue) ? obj.simplify : obj
end end
private private
def initialize(name, res_s = nil) def initialize(name, resource = nil, res_s = nil)
@name = name @name = name
@endian = :big @endian = :big
@resource = resource
@res_s = res_s @res_s = res_s
end end
def load(bin) def load(bin)
br = BinaryReader.new(bin) br = BinaryReader.new(bin)
metadata_size = br.i32u
size = br.i32u meta_size = br.i32u
file_size = br.i32u
@format = br.i32u @format = br.i32u
data_offset = br.i32u data_offset = br.i32u
if @format >= 9 if @format >= 9
@endian = :little if br.i32 == 0 @endian = br.bool ? :big : :little
br.adv(3)
else
br.pos = file_size - meta_size
@endian = br.bool ? :big : :little
end
br.endian = @endian 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 end
@generator_version = br.cstr wide_path_id = @format >= 14 || @format >= 7 && br.i32 != 0
@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
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))
end
end
long_object_ids = (@format >= 14 || (7 <= @format && @format <= 13 && br.i32 != 0))
@objects = []
object_count = br.i32u object_count = br.i32u
object_count.times do @objects = Array.new(object_count) do
br.align(4) if @format >= 14 br.align(4) if @format >= 14
path_id = long_object_ids ? br.i64 : br.i32 if @format >= 16
offset = br.i32u ObjectEntry.new(
size = br.i32u path_id: wide_path_id ? br.i64s : br.i32s, offset: br.i32u, size: br.i32u,
@objects << if @format >= 17 class_idx: br.i32u, stripped?: @format == 16 ? br.bool : nil,
ObjectData.new(path_id, offset, size, nil, nil, br.i32u, @format <= 10 && br.i16 != 0) parent_asset: self
)
else else
ObjectData.new(path_id, offset, size, br.i32, br.i16, nil, @format <= 10 && br.i16 != 0) 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
br.adv(2) if 11 <= @format && @format <= 16
br.adv(1) if 15 <= @format && @format <= 16
end end
@path_id_table = @objects.map{|e| [e.path_id, e]}.to_h
if @format >= 11 if @format >= 11
@add_ids = []
add_id_count = br.i32u add_id_count = br.i32u
add_id_count.times do @add_ids = Array.new(add_id_count) do
br.align(4) if @format >= 14 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
end end
if @format >= 6
@references = []
reference_count = br.i32u reference_count = br.i32u
reference_count.times do @references = Array.new(reference_count) do
@references << Reference.new(br.cstr, br.read(16), br.i32, br.cstr) Reference.new(@format >= 6 ? br.cstr : nil, @format >= 5 ? br.read(16) : nil, @format >= 5 ? br.i32s : nil, br.cstr)
end
end end
@comment = br.cstr if @format >= 5
@objects.each do |e| @objects.each do |e|
br.jmp(data_offset + e.offset) br.jmp(data_offset + e.offset)
e.data = br.read(e.size) 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
end end
def parse_object_private(br, type_tree) # @param [Mikunyan::BinaryReader] br
r = nil # @param [Mikunyan::TypeTree::Node] node
node = type_tree[:node] def parse_object_private(br, node, klass = ObjectValue)
children = type_tree[:children] ret = klass.new(node.name, node.type, br.endian)
children = node.children
if node.array? if children.empty?
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
else
r.value = parse_object_private(br, children[0]).value
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 pos = br.pos
r = ObjectValue.new(node.name, node.type, br.endian) ret.value =
r.is_struct = true
children.each do |child|
r[child[:name]] = parse_object_private(br, child)
end
else
pos = br.pos
value = nil
case node.type case node.type
when 'bool' when 'bool'
value = (br.i8 != 0) br.bool
when 'SInt8' when 'SInt8'
value = br.i8s br.i8s
when 'UInt8', 'char' when 'UInt8'
value = br.i8u br.i8u
when 'SInt16', 'short' when 'SInt16', 'short'
value = br.i16s br.i16s
when 'UInt16', 'unsigned short' when 'UInt16', 'unsigned short'
value = br.i16u br.i16u
when 'SInt32', 'int' when 'SInt32', 'int'
value = br.i32s br.i32s
when 'UInt32', 'unsigned int' when 'UInt32', 'unsigned int', 'Type*'
value = br.i32u br.i32u
when 'SInt64', 'long long' when 'SInt64', 'long long'
value = br.i64s br.i64s
when 'UInt64', 'unsigned long long' when 'UInt64', 'unsigned long long'
value = br.i64u br.i64u
when 'float' when 'float'
value = br.float br.float
when 'double' when 'double'
value = br.double br.double
when 'ColorRGBA'
value = [br.i8u, br.i8u, br.i8u, br.i8u]
else else
value = br.read(node.size) br.read(node.size)
end end
br.jmp(pos + node.size) br.jmp(pos + node.size) if node.size >= 0
r = ObjectValue.new(node.name, node.type, br.endian, value) elsif node.array?
children.each do |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
br.align(4) if node.flags & 0x4000 != 0
r
end end
ret.value ||= Array.new(size){parse_object_private(br, child)}
def self.object_simplify(obj) ret['data'] = ret.value
if obj.class != ObjectValue end
obj elsif children.size == 1 && children[0].array? && children[0].type == 'Array' && children[0].name == 'Array'
elsif obj.type == 'pair' ret = parse_object_private(br, children[0])
[object_simplify(obj['first']), object_simplify(obj['second'])] ret.name = node.name
elsif obj.type == 'map' && obj.array? ret.type = node.type
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 else
hash = {} ret.attr = children.map{|c| [c.name, parse_object_private(br, c)]}.to_h
obj.keys.each do |key| if node.type == 'StreamingInfo'
hash[key] = object_simplify(obj[key]) 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 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 else
stack[node.depth - 1][:children] << this ret.is_struct = true
end end
stack[node.depth] = this
end end
tree br.align(4) if node.need_align?
ret
end end
end end
end end
+85 -62
View File
@@ -2,19 +2,36 @@
require 'extlz4' require 'extlz4'
require 'extlzma' require 'extlzma'
require 'mikunyan/asset'
require 'mikunyan/binary_reader'
module Mikunyan module Mikunyan
# Class for representing Unity AssetBundle # Class for representing Unity AssetBundle
# @attr_reader [String] signature file signature (UnityRaw or UnityFS) # @attr_reader [String] signature file signature (UnityRaw or UnityFS)
# @attr_reader [Integer] format file format number # @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 [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 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 AssetEntry = Struct.new(:name, :data, :blob?, :status, keyword_init: true)
# @param [String] bin binary data
# @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 # @return [Mikunyan::AssetBundle] deserialized AssetBundle object
def self.load(bin) def self.load(bin)
r = AssetBundle.new r = AssetBundle.new
@@ -22,11 +39,13 @@ module Mikunyan
r r
end end
# Load AssetBundle from file # Loads AssetBundle from file
# @param [String] file file name # @param [String] file file name
# @return [Mikunyan::AssetBundle] deserialized AssetBundle object # @return [Mikunyan::AssetBundle] deserialized AssetBundle object
def self.file(file) def self.file(file)
AssetBundle.load(File.binread(file)) File.open(file, 'rb') do |io|
AssetBundle.load(io)
end
end end
private private
@@ -34,84 +53,71 @@ module Mikunyan
def load(bin) def load(bin)
br = BinaryReader.new(bin) br = BinaryReader.new(bin)
@signature = br.cstr @signature = br.cstr
raise("Invalid signature: #{@signature}") unless @signature.start_with?('Unity')
@format = br.i32 @format = br.i32
@unity_version = br.cstr @unity_version = br.cstr
@generator_version = br.cstr @generator_version = br.cstr
case @signature @format < 6 ? load_unity_raw(br) : load_unity_fs(br)
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
end end
def load_unity_raw(br, compressed) # @param [Mikunyan::BinaryReader] br
def load_unity_raw(br)
@assets = [] @assets = []
file_size = br.i32u _file_size = br.i32u
header_size = br.i32u header_size = br.i32u
br.pos = header_size
if compressed # この部分全然わからん(ファイルの最後まで読まないとダメらしい?)
br.adv(4) block = br.read(nil)
block_count = br.i32u data = @signature == 'UnityRaw' ? block : uncompress_lzma(block, true)
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) br = BinaryReader.new(data)
else
br.jmp(header_size)
end
asset_count = br.i32u asset_count = br.i32u
asset_count.times do asset_entries = Array.new(asset_count) do
asset_pos = br.pos name = br.cstr
asset_name = br.cstr offset = br.i32u
asset_header_size = br.i32u size = br.i32u
asset_size = br.i32u is_asset = ['', '.assets'].include?(split_name(name)[1]) && size > 16
br.jmp(asset_pos + asset_header_size - 4) AssetEntry.new(name: name, data: br.read_abs(size, offset), blob?: !is_asset)
asset_data = br.read(asset_size)
asset = Asset.load(asset_data, asset_name)
@assets << asset
end end
process_asset_entries(asset_entries)
end end
# @param [Mikunyan::BinaryReader] br
def load_unity_fs(br) def load_unity_fs(br)
@assets = []
file_size = br.i64u file_size = br.i64u
ci_block_size = br.i32u ci_block_size = br.i32u
ui_block_size = br.i32u ui_block_size = br.i32u
flags = 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)) 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 = 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 = 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 = '' def process_asset_entries(asset_entries)
blocks.each{|b| raw_data << uncompress(br.read(b[:c]), b[:u], b[:f])} @blobs = asset_entries.select(&:blob?).map{|e| [e.name, e.data]}.to_h
@assets = asset_entries.reject(&:blob?).map do |e|
asset_blocks.each do |b| basename = split_name(e.name)[0]
next if b[:name].end_with?('.resS') Asset.load(e.data, e.name, @blobs["#{basename}.resource"], @blobs["#{basename}.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
end end
end end
@@ -119,16 +125,33 @@ module Mikunyan
case flags & 0x3f case flags & 0x3f
when 0 when 0
block block
# when 1 when 1
# LZMA uncompress_lzma(block)
when 2, 3 when 2, 3
LZ4.raw_decode(block, max_dest_size) LZ4.block_decode(block, max_dest_size)
# when 4 # when 4
# LZHMA # LZHMA
else else
warn("Unknown compression flag: #{@flags}") warn("Unknown compression flag: #{flags}")
block block
end end
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
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 module Mikunyan
# Class for manipulating binary string # Class for manipulating binary string
# @attr [Symbol] endian endianness # @attr [Symbol] endian endianness
# @attr [Integer] pos position
# @attr [Integer] length data size
class BinaryReader class BinaryReader
attr_accessor :endian, :pos, :length attr_accessor :endian
# Constructor # Constructor
# @param [String] data binary string # @param [IO,String] io binary String or IO
# @param [Symbol] endian endianness # @param [Symbol] endian endianness
def initialize(data, endian = :big) def initialize(io, endian = :big)
@data = data @io = io.is_a?(String) ? StringIO.new(io, 'r') : io.dup
@pos = 0 @io.binmode
@length = data.bytesize @base_pos = @io.pos
@endian = endian @endian = endian
end end
@@ -26,137 +24,117 @@ module Mikunyan
@endian == :little @endian == :little
end end
# Jump to given position # Tells current potision
# @param [Integer] pos position # @return [Integer]
def jmp(pos = 0) def pos
@pos = pos @io.pos - @base_pos
end 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 # @param [Integer] size size
def adv(size = 0) def adv(size = 0)
@pos += size @io.seek(size, IO::SEEK_CUR)
end end
# Round up position to multiple of given size # Rounds up position to multiple of given size
# @param [Integer] size size # @param [Integer] size size
def align(size) def align(size)
@pos = (@pos + size - 1) / size * size rem = pos % size
adv(size - rem) if rem > 0
end end
# Read given size of binary string and seek # Reads given size of binary string and seek
# @param [Integer] size size # @param [Integer] size size
# @return [String] data # @return [String] data
def read(size) def read(size)
data = @data.byteslice(@pos, size) ret = @io.read(size)
@pos += size raise EOFError if ret.nil? || size && ret.bytesize < size
data ret
end 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] size size
# @param [Integer] pos position # @param [Integer] pos position
# @return [String] data # @return [String] data
def read_abs(size, pos) def read_abs(size, jmp_pos)
@data.byteslice(pos, size) orig_pos = pos
jmp(jmp_pos)
ret = read(size)
jmp(orig_pos)
ret
end end
# Read string until null character # Reads string until null character
# @return [String] string # @return [String] string
def cstr def cstr
r = @data.unpack1("@#{pos}Z*") raise EOFError if @io.eof?
@pos += r.bytesize + 1 @io.each_byte.take_while(&:nonzero?).pack('C*')
r
end end
# Read 8bit signed integer # Reads an 8bit bool value
def i8 def bool
i8s i8u != 0
end end
# Read 8bit signed integer # Reads an 8bit signed integer value
def i8s def i8s
r = BinUtils.get_sint8(@data, @pos) BinUtils.get_sint8(read(1))
@pos += 1
r
end end
alias i8 i8s
# Read 8bit unsigned integer # Reads an 8bit unsigned integer value
def i8u def i8u
r = BinUtils.get_int8(@data, @pos) @io.getbyte
@pos += 1
r
end end
# Read 16bit signed integer # Reads a 16bit signed integer value
def i16
i16s
end
# Read 16bit signed integer
def i16s def i16s
r = little? ? BinUtils.get_sint16_le(@data, @pos) : BinUtils.get_sint16_be(@data, @pos) little? ? BinUtils.get_sint16_le(read(2)) : BinUtils.get_sint16_be(read(2))
@pos += 2
r
end end
alias i16 i16s
# Read 16bit unsigned integer # Reads a 16bit unsigned integer value
def i16u def i16u
r = little? ? BinUtils.get_int16_le(@data, @pos) : BinUtils.get_int16_be(@data, @pos) little? ? BinUtils.get_int16_le(read(2)) : BinUtils.get_int16_be(read(2))
@pos += 2
r
end end
# Read 32bit signed integer # Reads a 32bit signed integer value
def i32
i32s
end
# Read 32bit signed integer
def i32s def i32s
r = little? ? BinUtils.get_sint32_le(@data, @pos) : BinUtils.get_sint32_be(@data, @pos) little? ? BinUtils.get_sint32_le(read(4)) : BinUtils.get_sint32_be(read(4))
@pos += 4
r
end end
alias i32 i32s
# Read 32bit unsigned integer # Reads a 32bit unsigned integer value
def i32u def i32u
r = little? ? BinUtils.get_int32_le(@data, @pos) : BinUtils.get_int32_be(@data, @pos) little? ? BinUtils.get_int32_le(read(4)) : BinUtils.get_int32_be(read(4))
@pos += 4
r
end end
# Read 64bit signed integer # Reads a 64bit signed integer value
def i64
i64s
end
# Read 64bit signed integer
def i64s def i64s
r = little? ? BinUtils.get_sint64_le(@data, @pos) : BinUtils.get_sint64_be(@data, @pos) little? ? BinUtils.get_sint64_le(read(8)) : BinUtils.get_sint64_be(read(8))
@pos += 8
r
end end
alias i64 i64s
# Read 64bit unsigned integer # Reads a 64bit unsigned integer value
def i64u def i64u
r = little? ? BinUtils.get_int64_le(@data, @pos) : BinUtils.get_int64_be(@data, @pos) little? ? BinUtils.get_int64_le(read(8)) : BinUtils.get_int64_be(read(8))
@pos += 8
r
end end
# Read 32bit floating point value # Reads a 32bit floating point value
def float def float
r = little? ? @data.byteslice(@pos, 4).unpack1('e') : @data.byteslice(@pos, 4).unpack1('g') little? ? read(4).unpack1('e') : read(4).unpack1('g')
@pos += 4
r
end end
# Read 64bit floating point value # Reads a 64bit floating point value
def double def double
r = little? ? @data.byteslice(@pos, 8).unpack1('E') : @data.byteslice(@pos, 8).unpack1('G') little? ? read(8).unpack1('E') : read(8).unpack1('G')
@pos += 8
r
end end
end end
end end
+403 -240
View File
@@ -1,7 +1,14 @@
# frozen_string_literal: true # frozen_string_literal: true
module Mikunyan 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 = { STRING_TABLE = {
0 => 'AABB', 0 => 'AABB',
@@ -103,245 +110,401 @@ module Mikunyan
997 => 'Vector3f', 997 => 'Vector3f',
1006 => 'Vector4f', 1006 => 'Vector4f',
1015 => 'm_ScriptingClassIdentifier', 1015 => 'm_ScriptingClassIdentifier',
1042 => 'Gradient' 1042 => 'Gradient',
1051 => 'Type*',
1057 => 'int2_storage',
1070 => 'int3_storage',
1083 => 'BoundsInt',
1093 => 'm_CorrespondingSourceObject',
1121 => 'm_PrefabInstance',
1138 => 'm_PrefabAsset'
}.freeze }.freeze
CLASS_ID = { CLASS_ID_TABLE = [
1 => 'GameObject', [0, 'Object'],
2 => 'Component', [1, 'GameObject'],
3 => 'LevelGameManager', [2, 'Component'],
4 => 'Transform', [3, 'LevelGameManager'],
5 => 'TimeManager', [4, 'Transform'],
6 => 'GlobalGameManager', [5, 'TimeManager'],
8 => 'Behaviour', [6, 'GlobalGameManager'],
9 => 'GameManager', [8, 'Behaviour'],
11 => 'AudioManager', [9, 'GameManager'],
12 => 'ParticleAnimator', [11, 'AudioManager'],
13 => 'InputManager', [12, 'ParticleAnimator'],
15 => 'EllipsoidParticleEmitter', [13, 'InputManager'],
17 => 'Pipeline', [15, 'EllipsoidParticleEmitter'],
18 => 'EditorExtension', [17, 'Pipeline'],
19 => 'Physics2DSettings', [18, 'EditorExtension'],
20 => 'Camera', [19, 'Physics2DSettings'],
21 => 'Material', [20, 'Camera'],
23 => 'MeshRenderer', [21, 'Material'],
25 => 'Renderer', [23, 'MeshRenderer'],
26 => 'ParticleRenderer', [25, 'Renderer'],
27 => 'Texture', [26, 'ParticleRenderer'],
28 => 'Texture2D', [27, 'Texture'],
29 => 'SceneSettings', [28, 'Texture2D'],
30 => 'GraphicsSettings', [29, 'Scene'],
33 => 'MeshFilter', [29, 'SceneSettings'],
41 => 'OcclusionPortal', [29, 'OcclusionCullingSettings'],
43 => 'Mesh', [30, 'RenderManager'],
45 => 'Skybox', [30, 'GraphicsSettings'],
47 => 'QualitySettings', [33, 'MeshFilter'],
48 => 'Shader', [41, 'OcclusionPortal'],
49 => 'TextAsset', [43, 'Mesh'],
50 => 'Rigidbody2D', [45, 'Skybox'],
51 => 'Physics2DManager', [47, 'QualitySettings'],
53 => 'Collider2D', [48, 'Shader'],
54 => 'Rigidbody', [49, 'TextAsset'],
55 => 'PhysicsManager', [50, 'Rigidbody2D'],
56 => 'Collider', [51, 'Physics2DManager'],
57 => 'Joint', [52, 'NotificationManager'],
58 => 'CircleCollider2D', [53, 'Collider2D'],
59 => 'HingeJoint', [54, 'Rigidbody'],
60 => 'PolygonCollider2D', [55, 'PhysicsManager'],
61 => 'BoxCollider2D', [56, 'Collider'],
62 => 'PhysicsMaterial2D', [57, 'Joint'],
64 => 'MeshCollider', [58, 'CircleCollider2D'],
65 => 'BoxCollider', [59, 'HingeJoint'],
66 => 'SpriteCollider2D', [60, 'PolygonCollider2D'],
68 => 'EdgeCollider2D', [61, 'BoxCollider2D'],
72 => 'ComputeShader', [62, 'PhysicsMaterial2D'],
74 => 'AnimationClip', [64, 'MeshCollider'],
75 => 'ConstantForce', [65, 'BoxCollider'],
76 => 'WorldParticleCollider', [66, 'SpriteCollider2D'],
78 => 'TagManager', [66, 'CompositeCollider2D'],
81 => 'AudioListener', [68, 'EdgeCollider2D'],
82 => 'AudioSource', [70, 'CapsuleCollider2D'],
83 => 'AudioClip', [71, 'AnimationManager'],
84 => 'RenderTexture', [72, 'ComputeShader'],
87 => 'MeshParticleEmitter', [74, 'AnimationClip'],
88 => 'ParticleEmitter', [75, 'ConstantForce'],
89 => 'Cubemap', [76, 'WorldParticleCollider'],
90 => 'Avatar', [78, 'TagManager'],
91 => 'AnimatorController', [81, 'AudioListener'],
92 => 'GUILayer', [82, 'AudioSource'],
93 => 'RuntimeAnimatorController', [83, 'AudioClip'],
94 => 'ScriptMapper', [84, 'RenderTexture'],
95 => 'Animator', [86, 'CustomRenderTexture'],
96 => 'TrailRenderer', [87, 'MeshParticleEmitter'],
98 => 'DelayedCallManager', [88, 'ParticleEmitter'],
102 => 'TextMesh', [89, 'Cubemap'],
104 => 'RenderSettings', [90, 'Avatar'],
108 => 'Light', [91, 'AnimatorController'],
109 => 'CGProgram', [92, 'GUILayer'],
110 => 'BaseAnimationTrack', [93, 'RuntimeAnimatorController'],
111 => 'Animation', [94, 'ScriptMapper'],
114 => 'MonoBehaviour', [95, 'Animator'],
115 => 'MonoScript', [96, 'TrailRenderer'],
116 => 'MonoManager', [98, 'DelayedCallManager'],
117 => 'Texture3D', [102, 'TextMesh'],
118 => 'NewAnimationTrack', [104, 'RenderSettings'],
119 => 'Projector', [108, 'Light'],
120 => 'LineRenderer', [109, 'CGProgram'],
121 => 'Flare', [110, 'BaseAnimationTrack'],
122 => 'Halo', [111, 'Animation'],
123 => 'LensFlare', [114, 'MonoBehaviour'],
124 => 'FlareLayer', [115, 'MonoScript'],
125 => 'HaloLayer', [116, 'MonoManager'],
126 => 'NavMeshAreas', [117, 'Texture3D'],
127 => 'HaloManager', [118, 'NewAnimationTrack'],
128 => 'Font', [119, 'Projector'],
129 => 'PlayerSettings', [120, 'LineRenderer'],
130 => 'NamedObject', [121, 'Flare'],
131 => 'GUITexture', [122, 'Halo'],
132 => 'GUIText', [123, 'LensFlare'],
133 => 'GUIElement', [124, 'FlareLayer'],
134 => 'PhysicMaterial', [125, 'HaloLayer'],
135 => 'SphereCollider', [126, 'NavMeshLayers'],
136 => 'CapsuleCollider', [126, 'NavMeshAreas'],
137 => 'SkinnedMeshRenderer', [126, 'NavMeshProjectSettings'],
138 => 'FixedJoint', [127, 'HaloManager'],
140 => 'RaycastCollider', [128, 'Font'],
141 => 'BuildSettings', [129, 'PlayerSettings'],
142 => 'AssetBundle', [130, 'NamedObject'],
143 => 'CharacterController', [131, 'GUITexture'],
144 => 'CharacterJoint', [132, 'GUIText'],
145 => 'SpringJoint', [133, 'GUIElement'],
146 => 'WheelCollider', [134, 'PhysicMaterial'],
147 => 'ResourceManager', [135, 'SphereCollider'],
148 => 'NetworkView', [136, 'CapsuleCollider'],
149 => 'NetworkManager', [137, 'SkinnedMeshRenderer'],
150 => 'PreloadData', [138, 'FixedJoint'],
152 => 'MovieTexture', [140, 'RaycastCollider'],
153 => 'ConfigurableJoint', [141, 'BuildSettings'],
154 => 'TerrainCollider', [142, 'AssetBundle'],
155 => 'MasterServerInterface', [143, 'CharacterController'],
156 => 'TerrainData', [144, 'CharacterJoint'],
157 => 'LightmapSettings', [145, 'SpringJoint'],
158 => 'WebCamTexture', [146, 'WheelCollider'],
159 => 'EditorSettings', [147, 'ResourceManager'],
160 => 'InteractiveCloth', [148, 'NetworkView'],
161 => 'ClothRenderer', [149, 'NetworkManager'],
162 => 'EditorUserSettings', [150, 'PreloadData'],
163 => 'SkinnedCloth', [152, 'MovieTexture'],
164 => 'AudioReverbFilter', [153, 'ConfigurableJoint'],
165 => 'AudioHighPassFilter', [154, 'TerrainCollider'],
166 => 'AudioChorusFilter', [155, 'MasterServerInterface'],
167 => 'AudioReverbZone', [156, 'TerrainData'],
168 => 'AudioEchoFilter', [157, 'LightmapSettings'],
169 => 'AudioLowPassFilter', [158, 'WebCamTexture'],
170 => 'AudioDistortionFilter', [159, 'EditorSettings'],
171 => 'SparseTexture', [160, 'InteractiveCloth'],
180 => 'AudioBehaviour', [161, 'ClothRenderer'],
181 => 'AudioFilter', [162, 'EditorUserSettings'],
182 => 'WindZone', [163, 'SkinnedCloth'],
183 => 'Cloth', [164, 'AudioReverbFilter'],
184 => 'SubstanceArchive', [165, 'AudioHighPassFilter'],
185 => 'ProceduralMaterial', [166, 'AudioChorusFilter'],
186 => 'ProceduralTexture', [167, 'AudioReverbZone'],
191 => 'OffMeshLink', [168, 'AudioEchoFilter'],
192 => 'OcclusionArea', [169, 'AudioLowPassFilter'],
193 => 'Tree', [170, 'AudioDistortionFilter'],
194 => 'NavMeshObsolete', [171, 'SparseTexture'],
195 => 'NavMeshAgent', [180, 'AudioBehaviour'],
196 => 'NavMeshSettings', [181, 'AudioFilter'],
197 => 'LightProbesLegacy', [182, 'WindZone'],
198 => 'ParticleSystem', [183, 'Cloth'],
199 => 'ParticleSystemRenderer', [184, 'SubstanceArchive'],
200 => 'ShaderVariantCollection', [185, 'ProceduralMaterial'],
205 => 'LODGroup', [186, 'ProceduralTexture'],
206 => 'BlendTree', [187, 'Texture2DArray'],
207 => 'Motion', [188, 'CubemapArray'],
208 => 'NavMeshObstacle', [191, 'OffMeshLink'],
210 => 'TerrainInstance', [192, 'OcclusionArea'],
212 => 'SpriteRenderer', [193, 'Tree'],
213 => 'Sprite', [194, 'NavMesh'],
214 => 'CachedSpriteAtlas', [194, 'NavMeshObsolete'],
215 => 'ReflectionProbe', [195, 'NavMeshAgent'],
216 => 'ReflectionProbes', [196, 'NavMeshSettings'],
218 => 'Terrain', [197, 'LightProbeCloud'],
220 => 'LightProbeGroup', [197, 'LightProbesLegacy'],
221 => 'AnimatorOverrideController', [198, 'ParticleSystem'],
222 => 'CanvasRenderer', [199, 'ParticleSystemRenderer'],
223 => 'Canvas', [200, 'ShaderVariantCollection'],
224 => 'RectTransform', [205, 'LODGroup'],
225 => 'CanvasGroup', [206, 'BlendTree'],
226 => 'BillboardAsset', [207, 'Motion'],
227 => 'BillboardRenderer', [208, 'NavMeshObstacle'],
228 => 'SpeedTreeWindAsset', [210, 'TerrainInstance'],
229 => 'AnchoredJoint2D', [210, 'SortingGroup'],
230 => 'Joint2D', [212, 'SpriteRenderer'],
231 => 'SpringJoint2D', [213, 'Sprite'],
232 => 'DistanceJoint2D', [214, 'CachedSpriteAtlas'],
233 => 'HingeJoint2D', [215, 'ReflectionProbe'],
234 => 'SliderJoint2D', [216, 'ReflectionProbes'],
235 => 'WheelJoint2D', [218, 'Terrain'],
238 => 'NavMeshData', [220, 'LightProbeGroup'],
240 => 'AudioMixer', [221, 'AnimatorOverrideController'],
241 => 'AudioMixerController', [222, 'CanvasRenderer'],
243 => 'AudioMixerGroupController', [223, 'Canvas'],
244 => 'AudioMixerEffectController', [224, 'RectTransform'],
245 => 'AudioMixerSnapshotController', [225, 'CanvasGroup'],
246 => 'PhysicsUpdateBehaviour2D', [226, 'BillboardAsset'],
247 => 'ConstantForce2D', [227, 'BillboardRenderer'],
248 => 'Effector2D', [228, 'SpeedTreeWindAsset'],
249 => 'AreaEffector2D', [229, 'AnchoredJoint2D'],
250 => 'PointEffector2D', [230, 'Joint2D'],
251 => 'PlatformEffector2D', [231, 'SpringJoint2D'],
252 => 'SurfaceEffector2D', [232, 'DistanceJoint2D'],
258 => 'LightProbes', [233, 'HingeJoint2D'],
271 => 'SampleClip', [234, 'SliderJoint2D'],
272 => 'AudioMixerSnapshot', [235, 'WheelJoint2D'],
273 => 'AudioMixerGroup', [236, 'ClusterInputManager'],
290 => 'AssetBundleManifest', [237, 'BaseVideoTexture'],
1001 => 'Prefab', [238, 'NavMeshData'],
1002 => 'EditorExtensionImpl', [240, 'AudioMixer'],
1003 => 'AssetImporter', [241, 'AudioMixerController'],
1004 => 'AssetDatabase', [243, 'AudioMixerGroupController'],
1005 => 'Mesh3DSImporter', [244, 'AudioMixerEffectController'],
1006 => 'TextureImporter', [245, 'AudioMixerSnapshotController'],
1007 => 'ShaderImporter', [246, 'PhysicsUpdateBehaviour2D'],
1008 => 'ComputeShaderImporter', [247, 'ConstantForce2D'],
1011 => 'AvatarMask', [248, 'Effector2D'],
1020 => 'AudioImporter', [249, 'AreaEffector2D'],
1026 => 'HierarchyState', [250, 'PointEffector2D'],
1027 => 'GUIDSerializer', [251, 'PlatformEffector2D'],
1028 => 'AssetMetaData', [252, 'SurfaceEffector2D'],
1029 => 'DefaultAsset', [253, 'BuoyancyEffector2D'],
1030 => 'DefaultImporter', [254, 'RelativeJoint2D'],
1031 => 'TextScriptImporter', [255, 'FixedJoint2D'],
1032 => 'SceneAsset', [256, 'FrictionJoint2D'],
1034 => 'NativeFormatImporter', [257, 'TargetJoint2D'],
1035 => 'MonoImporter', [258, 'LightProbes'],
1037 => 'AssetServerCache', [259, 'LightProbeProxyVolume'],
1038 => 'LibraryAssetImporter', [271, 'SampleClip'],
1040 => 'ModelImporter', [272, 'AudioMixerSnapshot'],
1041 => 'FBXImporter', [273, 'AudioMixerGroup'],
1042 => 'TrueTypeFontImporter', [280, 'NScreenBridge'],
1044 => 'MovieImporter', [290, 'AssetBundleManifest'],
1045 => 'EditorBuildSettings', [292, 'UnityAdsSettings'],
1046 => 'DDSImporter', [292, 'UnityAdsManager'],
1048 => 'InspectorExpandedState', [300, 'RuntimeInitializeOnLoadManager'],
1049 => 'AnnotationManager', [301, 'CloudWebServicesManager'],
1050 => 'PluginImporter', [303, 'UnityAnalyticsManager'],
1051 => 'EditorUserBuildSettings', [304, 'CrashReportManager'],
1052 => 'PVRImporter', [305, 'PerformanceReportingManager'],
1053 => 'ASTCImporter', [310, 'UnityConnectSettings'],
1054 => 'KTXImporter', [319, 'AvatarMask'],
1101 => 'AnimatorStateTransition', [320, 'PlayableDirector'],
1102 => 'AnimatorState', [328, 'VideoPlayer'],
1105 => 'HumanTemplate', [329, 'VideoClip'],
1107 => 'AnimatorStateMachine', [330, 'ParticleSystemForceField'],
1108 => 'PreviewAssetType', [331, 'SpriteMask'],
1109 => 'AnimatorTransition', [362, 'WorldAnchor'],
1110 => 'SpeedTreeImporter', [363, 'OcclusionCullingData'],
1111 => 'AnimatorTransitionBase', [1000, 'SmallestEditorClassID'],
1112 => 'SubstanceImporter', [1001, 'Prefab'], # 1001480554
1113 => 'LightmapParameters', [1001, 'PrefabInstance'],
1120 => 'LightmapSnapshot' [1002, 'EditorExtensionImpl'],
}.freeze [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 end
+2
View File
@@ -1,5 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
warn 'Warning: `mikunyan/decoders` is deprecated and will be removed at a future release.'
require 'mikunyan/decoders/image_decoder' require 'mikunyan/decoders/image_decoder'
module Mikunyan module Mikunyan
+66 -45
View File
@@ -9,92 +9,105 @@ require 'bin_utils'
require 'mikunyan/decoders/native' require 'mikunyan/decoders/native'
module Mikunyan module Mikunyan
module Decoder
# Class for image decoding tools # Class for image decoding tools
class ImageDecoder class ImageDecoder
# Decode image from Mikunyan::ObjectValue # Decode image from Mikunyan::ObjectValue
# @param [Mikunyan::ObjectValue] object object to decode # @param [Mikunyan::ObjectValue] object object to decode
# @return [ChunkyPNG::Image,nil] decoded image # @return [ChunkyPNG::Image,nil] decoded image
def self.decode_object(object) def self.decode_object(object)
return nil unless object.class == ObjectValue return nil unless object.is_a?(ObjectValue)
endian = object.endian endian = object.endian
width = object['m_Width'] width = object['m_Width']&.value
height = object['m_Height'] height = object['m_Height']&.value
bin = object['image data'] bin = object['image data']&.value
fmt = object['m_TextureFormat'] fmt = object['m_TextureFormat']&.value
return nil unless width && height && bin && fmt return nil unless width && height && bin && fmt
width = width.value bin = object['m_StreamData']&.value if bin.empty?
height = height.value
bin = bin.value
fmt = fmt.value
if bin.empty? && object['m_StreamData']
bin = object['m_StreamData'].value
return nil unless bin return nil unless bin
end
case fmt case fmt
when 1 when 1 # Alpha8
decode_a8(width, height, bin) decode_a8(width, height, bin)
when 2 when 2 # ARGB4444
decode_argb4444(width, height, bin, endian) decode_argb4444(width, height, bin, endian)
when 3 when 3 # RGB24
decode_rgb24(width, height, bin) decode_rgb24(width, height, bin)
when 4 when 4 # RGBA32
decode_rgba32(width, height, bin) decode_rgba32(width, height, bin)
when 5 when 5 # ARGB32
decode_argb32(width, height, bin) decode_argb32(width, height, bin)
when 7 when 7 # RGB565
decode_rgb565(width, height, bin, endian) decode_rgb565(width, height, bin, endian)
when 9 when 9 # R16
decode_r16(width, height, bin) decode_r16(width, height, bin)
when 10 when 10 # DXT1
decode_dxt1(width, height, bin) decode_dxt1(width, height, bin)
when 12 when 12 # DXT5
decode_dxt5(width, height, bin) decode_dxt5(width, height, bin)
when 13 when 13 # RGBA4444
decode_rgba4444(width, height, bin, endian) decode_rgba4444(width, height, bin, endian)
when 14 when 14 # BGRA32
decode_bgra32(width, height, bin) decode_bgra32(width, height, bin)
when 15 when 15 # RHalf
decode_rhalf(width, height, bin, endian) decode_rhalf(width, height, bin, endian)
when 16 when 16 # RGHalf
decode_rghalf(width, height, bin, endian) decode_rghalf(width, height, bin, endian)
when 17 when 17 # RGBAHalf
decode_rgbahalf(width, height, bin, endian) decode_rgbahalf(width, height, bin, endian)
when 18 when 18 # RFloat
decode_rfloat(width, height, bin, endian) decode_rfloat(width, height, bin, endian)
when 19 when 19 # RGFloat
decode_rgfloat(width, height, bin, endian) decode_rgfloat(width, height, bin, endian)
when 20 when 20 # RGBAFloat
decode_rgbafloat(width, height, bin, endian) decode_rgbafloat(width, height, bin, endian)
when 22 # when 21 # YUY2
when 22 # RGB9e5Float
decode_rgb9e5float(width, height, bin, endian) decode_rgb9e5float(width, height, bin, endian)
when 34 # 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) decode_etc1(width, height, bin)
when 45 # 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) decode_etc2rgb(width, height, bin)
when 46 when 46 # ETC2_RGBA1
decode_etc2rgba1(width, height, bin) decode_etc2rgba1(width, height, bin)
when 47 when 47 # ETC2_RGBA8
decode_etc2rgba8(width, height, bin) decode_etc2rgba8(width, height, bin)
when 48, 54 when 48, 54, 66 # ASTC_RGB_4x4, ASTC_RGBA_4x4, ASTC_HDR_4x4
decode_astc(width, height, 4, bin) decode_astc(width, height, 4, bin)
when 49, 55 when 49, 55, 67 # ASTC_RGB_5x5, ASTC_RGBA_5x5, ASTC_HDR_5x5
decode_astc(width, height, 5, bin) decode_astc(width, height, 5, bin)
when 50, 56 when 50, 56, 68 # ASTC_RGB_6x6, ASTC_RGBA_6x6, ASTC_HDR_6x6
decode_astc(width, height, 6, bin) decode_astc(width, height, 6, bin)
when 51, 57 when 51, 57, 69 # ASTC_RGB_8x8, ASTC_RGBA_8x8, ASTC_HDR_8x8
decode_astc(width, height, 8, bin) decode_astc(width, height, 8, bin)
when 52, 58 when 52, 58, 70 # ASTC_10x10, ASTC_RGBA_10x10, ASTC_HDR_10x10
decode_astc(width, height, 10, bin) decode_astc(width, height, 10, bin)
when 53, 59 when 53, 59, 71 # ASTC_RGB_12x12, ASTC_RGBA_12x12, ASTC_HDR_12x12
decode_astc(width, height, 12, bin) decode_astc(width, height, 12, bin)
when 62 # when 60 # ETC_RGB4_3DS
# when 61 # ETC_RGBA8_3DS
when 62 # RG16
decode_rg16(width, height, bin) decode_rg16(width, height, bin)
when 63 when 63 # R8
decode_r8(width, height, bin) decode_r8(width, height, bin)
# when 64 # ETC_RGB4Crunched
# when 65 # ETC2_RGBA8Crunched
end end
end end
@@ -447,8 +460,6 @@ module Mikunyan
end end
end end
private
# convert 16bit float # convert 16bit float
def self.n2f(n) def self.n2f(n)
case n case n
@@ -481,3 +492,13 @@ module Mikunyan
end end
end 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 # Class for representing decoded object
# @attr [String] name object name # @attr [String] name object name
# @attr [String] type object type name # @attr [String] type object type name
# @attr [Hash<String,Mikunyan::ObjectValue>] attr
# @attr [Object] value object # @attr [Object] value object
# @attr [Symbol] endian endianness # @attr [Symbol] endian endianness
# @attr [Boolean] is_struct # @attr [Boolean] is_struct
class ObjectValue class ObjectValue
attr_accessor :name, :type, :value, :endian, :is_struct attr_accessor :name, :type, :attr, :value, :endian, :is_struct
# Constructor # Constructor
# @param [String] name object name # @param [String] name object name
@@ -27,13 +28,13 @@ module Mikunyan
# Return whether object is array or not # Return whether object is array or not
# @return [Boolean] # @return [Boolean]
def array? def array?
value && value.class == Array value&.is_a?(Array)
end end
# Return whether object is value or not # Return whether object is value or not
# @return [Boolean] # @return [Boolean]
def value? def value?
value && value.class != Array value && !value.is_a?(Array)
end end
# Return whether object is struct or not # Return whether object is struct or not
@@ -55,20 +56,16 @@ module Mikunyan
@attr.key?(key) @attr.key?(key)
end end
# Return value
# @return [Object] value
def []
@value
end
# Return value of selected index or key # Return value of selected index or key
# @param [Integer,String] i index or key # @param [Integer,String] key index or key
# @return [Object] value # @return [Object] value
def [](i) def [](key = nil)
if array? && i.class == Integer if key.nil?
@value[i] @value
elsif array? && key.is_a?(Integer)
@value[key]
else else
@attr[i] @attr[key]
end end
end end
@@ -83,13 +80,31 @@ module Mikunyan
# Return value of called key # Return value of called key
# @param [String] name key # @param [String] name key
# @return [Object] value # @return [Object] value
def method_missing(name, *_args) def method_missing(name, *args)
@attr[name.to_s] n = name.to_s
@attr.key?(n) ? @attr[n] : super
end end
# Implementation of respond_to_missing? # Implementation of respond_to_missing?
def respond_to_missing?(symbol, _include_private) def respond_to_missing?(symbol, _include_private)
@attr.key?(symbol.to_s) @attr.key?(symbol.to_s)
end 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
end end
+116 -49
View File
@@ -1,5 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'json'
require 'mikunyan/binary_reader'
module Mikunyan module Mikunyan
# Class for representing TypeTree # Class for representing TypeTree
# @attr [Array<Mikunyan::TypeTree::Node>] nodes list of all nodes # @attr [Array<Mikunyan::TypeTree::Node>] nodes list of all nodes
@@ -8,77 +11,141 @@ module Mikunyan
# Struct for representing Node in TypeTree # Struct for representing Node in TypeTree
# @attr [String] version version string # @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 [Boolean] array? array node or not
# @attr [String] type type name # @attr [String] type type name
# @attr [String] name node (attribute) name # @attr [String] name node (attribute) name
# @attr [Integer] index index in node list # @attr [Integer] index index in node list
# @attr [Integer] flags flags of node # @attr [Integer] flags flags of node
Node = Struct.new(:version, :depth, :array?, :type, :name, :size, :index, :flags) # @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
end
# Create TypeTree from binary string (new 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 [Mikunyan::BinaryReader] br
# @param [Integer] version asset format version
# @return [Mikunyan::TypeTree] created TypeTree # @return [Mikunyan::TypeTree] created TypeTree
def self.load(br) def self.load(br, version)
nodes = [] if version == 10 || version >= 12
node_count = br.i32u node_count = br.i32u
buffer_size = br.i32u buffer_size = br.i32u
node_count.times do nodes = Array.new(node_count) do
node = Node.new(br.i16u, br.i8u, br.i8u != 0, br.i32, br.i32, br.i32, br.i32u, br.i32u) Node.new(
nodes << node 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 end
buffer = br.read(buffer_size) buffer = br.read(buffer_size)
stack = []
nodes.each do |n| nodes.each do |n|
n.type = if n.type >= 0 n.type = Mikunyan::Constants.get_string_or_default(n.type, buffer)
buffer.unpack1("@#{n.type}Z*") 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 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)
# @param [Mikunyan::BinaryReader] br
# @return [Mikunyan::TypeTree] created TypeTree
def self.load_legacy(br)
nodes = [] nodes = []
stack = [0] stack = []
until stack.empty? until stack.empty? && !nodes.empty?
depth = stack.pop parent = stack.pop
type = br.cstr node = Node.new(
name = br.cstr type: br.cstr,
size = br.i32 name: br.cstr,
index = br.i32u size: br.i32s,
is_array = (br.i32 != 0) index: br.i32u,
version = br.i32u array?: br.i32 != 0,
flags = br.i32u version: br.i32u,
child_count = br.i32u flags: br.i32u,
child_count.times{stack << depth + 1} level: parent ? parent.level + 1 : 0,
nodes << Node.new(version, depth, is_array, type, name, size, index, flags) parent: parent,
children: []
)
nodes << node
parent.children << node if parent
stack += Array.new(br.i32u, node)
end end
r = TypeTree.new end
r.nodes = nodes ret = TypeTree.new
r ret.nodes = nodes
ret
end end
# Create default TypeTree from hash string (if exists) # Create default TypeTree from hash string (if exists)
# @param [Integer] class_id
# @param [String] hash # @param [String] hash
# @return [Mikunyan::TypeTree,nil] created TypeTree # @return [Mikunyan::TypeTree,nil] created TypeTree
def self.load_default(hash) def self.load_default(class_id, hash)
hash_str = hash.unpack1('H*') file = File.expand_path("../typetrees/#{class_id}/#{hash.unpack1('H*')}.json", __FILE__)
file = File.expand_path("../typetrees/#{hash_str}.dat", __FILE__)
return nil unless File.file?(file) return nil unless File.file?(file)
r = TypeTree.new TypeTree.deserialize(JSON.parse(File.read(file)))
r.nodes = Marshal.load(File.binread(file)) end
r
# 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 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