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