#!/usr/bin/env ruby # frozen_string_literal: true require 'mikunyan' require 'fileutils' begin require 'usamin' require 'usamin/overwrite' rescue LoadError require 'json' end 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 else arg ||= ARGV[i] end i += 1 end unless arg warn('Input file is not specified') exit(1) end unless File.file?(arg) warn("File not found: #{arg}") exit(1) end if opts[:as_asset] assets = [Mikunyan::Asset.file(arg)] else bundle = Mikunyan::AssetBundle.file(arg) assets = bundle.assets end outdir = opts[:outputdir] || File.basename(arg, '.*') FileUtils.mkpath(outdir) if opts[:sprite] textures = {} textures_meta = {} assets.each do |asset| json = {} asset.each_object do |obj| next unless obj.type == 'Sprite' next unless obj.klass obj = obj.parse next unless obj&.m_RD&.texture file_id = obj.m_RD.texture.m_FileID.value texture_asset = file_id == 0 ? asset : bundle && bundle[asset.references[file_id - 1].file_path] texture_id = obj.m_RD.texture.m_PathID.value next unless texture_asset && texture_id unless textures.dig(texture_asset, texture_id) texture_obj = texture_asset.parse_object(texture_id) if texture_obj.is_a?(Mikunyan::CustomTypes::Texture2D) textures[texture_asset] ||= {} textures[texture_asset][texture_id] = texture_obj.generate_png textures_meta[texture_asset] ||= {} textures_meta[texture_asset][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, asset: texture_asset.name, path_id: texture_id } end end next unless textures_meta[texture_asset][texture_id] unless json.key?([file_id, texture_id]) json[[file_id, texture_id]] = textures_meta[texture_asset][texture_id].dup json[[file_id, texture_id]][:sprites] = [] 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[[file_id, texture_id]][:sprites] << { name: obj.object_name, x: x, y: y, width: width, height: height, path_id: obj.path_id } texture = textures[texture_asset][texture_id] next unless texture && x && y && width && height texture.crop(x.round, (texture.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) end else assets.each do |asset| json = [] asset.each_object do |obj| next unless obj.type == 'Texture2D' next unless obj.klass 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