pgtools 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +25 -0
  3. data/bin/bxm_decoder +2 -0
  4. data/bin/bxm_encoder +2 -0
  5. data/bin/clh_convert +2 -0
  6. data/bin/clp_convert +2 -0
  7. data/bin/clw_convert +2 -0
  8. data/bin/dat_creator +2 -0
  9. data/bin/dat_extractor +2 -0
  10. data/bin/dat_ls +2 -0
  11. data/bin/eff_idd_creator +2 -0
  12. data/bin/eff_idd_extractor +2 -0
  13. data/bin/exp_convert_wiiu_pc +2 -0
  14. data/bin/exp_tool +2 -0
  15. data/bin/mot_convert_wiiu_pc +2 -0
  16. data/bin/mot_tool +2 -0
  17. data/bin/pkz_extractor +2 -0
  18. data/bin/scr_creator +2 -0
  19. data/bin/scr_extractor +2 -0
  20. data/bin/wmb_cleanup +2 -0
  21. data/bin/wmb_common_bones +2 -0
  22. data/bin/wmb_convert_pc_switch +2 -0
  23. data/bin/wmb_convert_wiiu_pc +2 -0
  24. data/bin/wmb_export_assimp +2 -0
  25. data/bin/wmb_get_bone_map +2 -0
  26. data/bin/wmb_import_assimp +2 -0
  27. data/bin/wmb_import_nier +2 -0
  28. data/bin/wmb_import_wiiu +2 -0
  29. data/bin/wtb_convert_wiiu_pc +2 -0
  30. data/bin/wtx_creator +2 -0
  31. data/bin/wtx_extractor +2 -0
  32. data/lib/bayonetta/alignment.rb +14 -0
  33. data/lib/bayonetta/bone.rb +55 -0
  34. data/lib/bayonetta/bxm.rb +180 -0
  35. data/lib/bayonetta/clh.rb +159 -0
  36. data/lib/bayonetta/clp.rb +212 -0
  37. data/lib/bayonetta/clw.rb +166 -0
  38. data/lib/bayonetta/dat.rb +261 -0
  39. data/lib/bayonetta/eff.rb +314 -0
  40. data/lib/bayonetta/endianness.rb +53 -0
  41. data/lib/bayonetta/exp.rb +768 -0
  42. data/lib/bayonetta/linalg.rb +416 -0
  43. data/lib/bayonetta/material_database.yaml +2581 -0
  44. data/lib/bayonetta/mot.rb +763 -0
  45. data/lib/bayonetta/pkz.rb +63 -0
  46. data/lib/bayonetta/scr.rb +393 -0
  47. data/lib/bayonetta/tools/bxm_decoder.rb +23 -0
  48. data/lib/bayonetta/tools/bxm_encoder.rb +37 -0
  49. data/lib/bayonetta/tools/clh_convert.rb +60 -0
  50. data/lib/bayonetta/tools/clp_convert.rb +70 -0
  51. data/lib/bayonetta/tools/clw_convert.rb +60 -0
  52. data/lib/bayonetta/tools/dat_creator.rb +57 -0
  53. data/lib/bayonetta/tools/dat_extractor.rb +94 -0
  54. data/lib/bayonetta/tools/dat_ls.rb +106 -0
  55. data/lib/bayonetta/tools/eff_idd_creator.rb +66 -0
  56. data/lib/bayonetta/tools/eff_idd_extractor.rb +73 -0
  57. data/lib/bayonetta/tools/exp_convert_wiiu_pc.rb +33 -0
  58. data/lib/bayonetta/tools/exp_tool.rb +48 -0
  59. data/lib/bayonetta/tools/mot_convert_wiiu_pc.rb +33 -0
  60. data/lib/bayonetta/tools/mot_tool.rb +60 -0
  61. data/lib/bayonetta/tools/pkz_extractor.rb +75 -0
  62. data/lib/bayonetta/tools/scr_creator.rb +63 -0
  63. data/lib/bayonetta/tools/scr_extractor.rb +78 -0
  64. data/lib/bayonetta/tools/wmb_cleanup.rb +250 -0
  65. data/lib/bayonetta/tools/wmb_common_bones.rb +45 -0
  66. data/lib/bayonetta/tools/wmb_convert_pc_switch.rb +35 -0
  67. data/lib/bayonetta/tools/wmb_convert_wiiu_pc.rb +33 -0
  68. data/lib/bayonetta/tools/wmb_export_assimp.rb +479 -0
  69. data/lib/bayonetta/tools/wmb_get_bone_map.rb +50 -0
  70. data/lib/bayonetta/tools/wmb_import_assimp.rb +735 -0
  71. data/lib/bayonetta/tools/wmb_import_geometry_wiiu_pc.rb +472 -0
  72. data/lib/bayonetta/tools/wmb_import_nier.rb +309 -0
  73. data/lib/bayonetta/tools/wtb_convert_wiiu_pc.rb +95 -0
  74. data/lib/bayonetta/tools/wtb_import_textures.rb +103 -0
  75. data/lib/bayonetta/tools/wtx_creator.rb +69 -0
  76. data/lib/bayonetta/tools/wtx_extractor.rb +85 -0
  77. data/lib/bayonetta/vertex_types.yaml +213 -0
  78. data/lib/bayonetta/vertex_types2.yaml +164 -0
  79. data/lib/bayonetta/vertex_types_nier.yaml +145 -0
  80. data/lib/bayonetta/wmb.rb +2443 -0
  81. data/lib/bayonetta/wmb3.rb +759 -0
  82. data/lib/bayonetta/wtb.rb +481 -0
  83. data/lib/bayonetta.rb +60 -0
  84. metadata +254 -0
@@ -0,0 +1,57 @@
1
+ require 'optparse'
2
+ require 'yaml'
3
+ require_relative '../../bayonetta'
4
+
5
+ $options = {
6
+ output: nil
7
+ }
8
+ OptionParser.new do |opts|
9
+ opts.banner = <<EOF
10
+ Usage: dat_creator target_directory
11
+ EOF
12
+ opts.on("-h", "--help", "Prints this help") do
13
+ puts opts
14
+ exit
15
+ end
16
+
17
+ opts.on("-o", "--output=filename", "file to output result") do |name|
18
+ $options[:output] = name
19
+ end
20
+
21
+ end.parse!
22
+
23
+
24
+ input_dir = ARGV[0]
25
+
26
+ raise "Not a directory: #{input_dir}!" unless input_dir && File.directory?(input_dir)
27
+
28
+ pwd = Dir.pwd
29
+ Dir.chdir(input_dir)
30
+ Dir.mkdir("dat_output") unless $options[:output] || Dir.exist?("dat_output")
31
+
32
+ big = YAML::load_file(".metadata/big.yaml")
33
+
34
+ d = Bayonetta::DATFile::new(big)
35
+
36
+ layout = YAML::load_file(".metadata/layout.yaml")
37
+
38
+ layout.each { |fname|
39
+ File::open(fname, "rb") { |f|
40
+ d.push(fname, StringIO.new(f.read,"rb") )
41
+ }
42
+ }
43
+
44
+ if File::exist?(".metadata/hash_map.yaml")
45
+ d.set_hash_map YAML::load_file(".metadata/hash_map.yaml")
46
+ end
47
+
48
+ output_file = $options[:output]
49
+ if !output_file
50
+ extension = YAML::load_file(".metadata/extension.yaml")
51
+ suffix = extension.gsub(".", "_")
52
+ output_file = "dat_output/#{File.basename(input_dir).gsub(suffix, "")}#{extension}"
53
+ else
54
+ Dir.chdir(pwd)
55
+ end
56
+
57
+ d.dump(output_file)
@@ -0,0 +1,94 @@
1
+ require 'fileutils'
2
+ require 'optparse'
3
+ require 'yaml'
4
+ require_relative '../../bayonetta'
5
+
6
+ $options = {
7
+ output: nil
8
+ }
9
+
10
+ OptionParser.new do |opts|
11
+ opts.banner = <<EOF
12
+ Usage: dat_extractor [dat_file [dat_file2 ...]]
13
+ EOF
14
+ opts.on("-h", "--help", "Prints this help") do
15
+ puts opts
16
+ exit
17
+ end
18
+
19
+ opts.on("-o", "--output=dirname", "directory to output result") do |name|
20
+ $options[:output] = name
21
+ end
22
+
23
+ end.parse!
24
+
25
+ save_pwd = Dir.pwd
26
+
27
+ raise "Invalid output directory #{$options[:output]}" if $options[:output] && !Dir.exist?($options[:output])
28
+
29
+ ARGV.each { |filename|
30
+ raise "Invalid file: #{filename}!" unless File.exist?(filename)
31
+ directory = File.dirname(filename)
32
+ name = File.basename(filename)
33
+ ext_name = File.extname(name)
34
+
35
+ raise "Invalid file: #{filename}!" unless ext_name == ".dat" || ext_name == ".evn" || ext_name == ".eff" || ext_name == ".dtt"
36
+
37
+ next unless File::size?(filename)
38
+ f = File::open(filename, "rb")
39
+
40
+ if $options[:output]
41
+ Dir.chdir(save_pwd)
42
+ Dir.chdir($options[:output])
43
+ else
44
+ Dir.chdir(directory)
45
+ end
46
+ dir_name = File.basename(name, ext_name) + "#{ext_name.gsub(".","_")}"
47
+ Dir.mkdir(dir_name) unless Dir.exist?(dir_name)
48
+ Dir.chdir(dir_name)
49
+
50
+ dat = Bayonetta::DATFile::load(f)
51
+
52
+ duplicates = dat.each.each_with_object(Hash.new(0)) { |f, counts|
53
+ name, _ = f
54
+ counts[name] += 1
55
+ }
56
+ duplicates.select! { |name, count| count > 1 }
57
+
58
+ if duplicates.size > 0
59
+ puts "Duplicate files found:"
60
+ duplicates.each { |name, count|
61
+ files = dat.each.to_a
62
+ puts "#{name} : #{(idx = files.each_index.select{ |i| files[i][0] == name }).inspect}"
63
+ puts "\t sizes: #{idx.collect { |i| files[i][1].size }.inspect}"
64
+ }
65
+ end
66
+
67
+ dat.each { |name, f|
68
+ d = File::dirname(name)
69
+ if d != "."
70
+ FileUtils.mkdir_p(d)
71
+ end
72
+ File::open(name, "wb") { |f2|
73
+ f2.write(f.read)
74
+ }
75
+ }
76
+ Dir.mkdir(".metadata") unless Dir.exist?(".metadata")
77
+ Dir.chdir(".metadata")
78
+ File::open("layout.yaml", "w") { |fl|
79
+ fl.print YAML::dump( dat.layout )
80
+ }
81
+ File::open("extension.yaml", "w") { |fl|
82
+ fl.print YAML::dump( ext_name )
83
+ }
84
+ File::open("big.yaml","w") { |fl|
85
+ fl.print YAML::dump( dat.big )
86
+ }
87
+ if dat.hash_map
88
+ File::open("hash_map.yaml", "w") { |fl|
89
+ fl.print YAML::dump( dat.hash_map.get )
90
+ }
91
+ end
92
+ # clean up
93
+ Dir.chdir(save_pwd)
94
+ }
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env ruby
2
+ require 'yaml'
3
+ require 'optparse'
4
+ require_relative '../../bayonetta'
5
+
6
+ class WTBFilePartial < LibBin::Structure
7
+ uint32 :id
8
+ uint32 :unknown
9
+ uint32 :num_textures
10
+ uint32 :offset_texture_offsets
11
+ uint32 :offset_texture_sizes
12
+ uint32 :offset_texture_flags
13
+ uint32 :offset_texture_ids
14
+ uint32 :offset_texture_infos
15
+ uint32 :texture_ids, count: 'num_textures', offset: 'offset_texture_ids'
16
+ end
17
+
18
+ $options = {
19
+ windows: false,
20
+ yaml: false
21
+ }
22
+
23
+ OptionParser.new do |opts|
24
+ opts.banner = <<EOF
25
+ Usage: dat_ls [target_directory] [target_dat_file]
26
+ EOF
27
+
28
+ opts.on("-w", "--[no-]windows", "Output Windows path") do |windows|
29
+ $options[:windows] = windows
30
+ end
31
+
32
+ opts.on("-y", "--[no-]yaml", "Ouput YAML database") do |yaml|
33
+ $options[:yaml] = yaml
34
+ end
35
+
36
+ opts.on("-h", "--help", "Prints this help") do
37
+ puts opts
38
+ exit
39
+ end
40
+
41
+ end.parse!
42
+
43
+ yaml_dat_block = lambda { |path, fh=nil|
44
+ h = []
45
+ begin
46
+ d = Bayonetta::DATFile::load(fh ? fh : path)
47
+ d.each.select { |name, f|
48
+ File.extname(name) == ".dat" || File.extname(name) == ".dtt"
49
+ }.collect { |name, f|
50
+ res = yaml_dat_block.call("", f)
51
+ h.push = [name, res] if res.size > 0
52
+ }
53
+ d.each { |name, _|
54
+ h.push name
55
+ }
56
+ h
57
+ rescue
58
+ h
59
+ end
60
+ }
61
+
62
+ dat_block = lambda { |path, fh=nil|
63
+ begin
64
+ d = Bayonetta::DATFile::load(fh ? fh : path)
65
+ path = path.gsub("/", "\\") if $options[:windows]
66
+ d.each.select { |name, f|
67
+ File.extname(name) == ".dat" || File.extname(name) == ".dtt"
68
+ }.each { |name, f|
69
+ dat_block.call(path + ":" + name, f)
70
+ }
71
+ d.each { |name, _|
72
+ puts "#{path}:#{name}"
73
+ }
74
+ rescue
75
+ next
76
+ end
77
+ }
78
+
79
+ path = ARGV[0]
80
+ h = []
81
+ if path && File::directory?(path)
82
+ Dir.chdir(path)
83
+ dats = Dir.glob("./**/*.d[at]t")
84
+ dats.each { |path|
85
+ if $options[:yaml]
86
+ res = yaml_dat_block.call(path)
87
+ path = path.gsub(ARGV[0],"")
88
+ path = path.gsub("/", "\\") if $options[:windows]
89
+ h.push [path, res] if res.size > 0
90
+ else
91
+ dat_block.call(path)
92
+ end
93
+ }
94
+ elsif path && File::exist?(path)
95
+ if $options[:yaml]
96
+ res = yaml_dat_block.call(path)
97
+ path = path.gsub("/", "\\") if $options[:windows]
98
+ h.push [path, res] if res.size > 0
99
+ else
100
+ dat_block.call(path)
101
+ end
102
+ else
103
+ raise "Invalid file or directory: #{ARGV[0]}!"
104
+ end
105
+
106
+ puts YAML::dump(h) if $options[:yaml]
@@ -0,0 +1,66 @@
1
+ require 'optparse'
2
+ require 'yaml'
3
+ require_relative '../../bayonetta'
4
+
5
+ $options = {
6
+ output: nil
7
+ }
8
+ OptionParser.new do |opts|
9
+ opts.banner = <<EOF
10
+ Usage: eff_idd_creator target_directory
11
+ EOF
12
+ opts.on("-h", "--help", "Prints this help") do
13
+ puts opts
14
+ exit
15
+ end
16
+
17
+ opts.on("-o", "--output=filename", "file to output result") do |name|
18
+ $options[:output] = name
19
+ end
20
+
21
+ end.parse!
22
+
23
+ input_dir = ARGV[0]
24
+
25
+ raise "Not a directory: #{input_dir}!" unless input_dir && File.directory?(input_dir)
26
+
27
+ pwd = Dir.pwd
28
+ Dir.chdir(input_dir)
29
+ pwd_basedir = Dir.pwd
30
+
31
+ id = YAML::load_file(".metadata/id.yaml")
32
+ big = YAML::load_file(".metadata/big.yaml")
33
+ extension = YAML::load_file(".metadata/extension.yaml")
34
+ suffix = extension.gsub(".", "_")
35
+
36
+ file_name = File.basename(input_dir).gsub(suffix, "")
37
+
38
+ eff = Bayonetta::EFFFile::new(nil, big, id)
39
+
40
+ eff.layout = YAML::load_file(".metadata/layout.yaml")
41
+
42
+ eff.layout.each { |id, dname|
43
+ d = Bayonetta::EFFFile::Directory::new(nil, big)
44
+ d.name = dname
45
+ fnames = Dir.entries("#{dname}")
46
+ Dir.chdir(dname)
47
+ fnames.select! { |f| File.file?(f) }
48
+ fnames.sort!
49
+ fnames.each { |fname|
50
+ d.push( File::basename(fname, File::extname(fname)).to_i, File::new(fname, "rb"))
51
+ }
52
+ eff.push(id, d)
53
+ Dir.chdir(pwd_basedir)
54
+ }
55
+
56
+ output_file = $options[:output]
57
+ if !output_file
58
+ Dir.mkdir("eff_output") unless Dir.exist?("eff_output")
59
+ Dir.chdir("eff_output")
60
+ output_file = file_name+extension
61
+ else
62
+ Dir.chdir(pwd)
63
+ end
64
+ File::open(output_file, "wb") { |f|
65
+ f.write eff.to_stringio.read
66
+ }
@@ -0,0 +1,73 @@
1
+ require 'optparse'
2
+ require 'yaml'
3
+ require_relative '../../bayonetta'
4
+
5
+ $options = {
6
+ output: nil
7
+ }
8
+
9
+ OptionParser.new do |opts|
10
+ opts.banner = <<EOF
11
+ Usage: eff_idd_extractor file
12
+ EOF
13
+ opts.on("-h", "--help", "Prints this help") do
14
+ puts opts
15
+ exit
16
+ end
17
+
18
+ opts.on("-o", "--output=dirname", "directory to output result") do |name|
19
+ $options[:output] = name
20
+ end
21
+
22
+ end.parse!
23
+
24
+ save_pwd = Dir.pwd
25
+
26
+ raise "Invalid output directory #{$options[:output]}" if $options[:output] && !Dir.exist?($options[:output])
27
+
28
+ filename = ARGV[0]
29
+ raise "Invalid file: #{filename}!" unless filename && File.exist?(filename)
30
+ directory = File.dirname(filename)
31
+ name = File.basename(filename)
32
+ ext_name = File.extname(name)
33
+
34
+ raise "Invalid file: #{filename}!" unless ext_name == ".eff" || ext_name == ".idd"
35
+
36
+ f = File::open(filename, "rb")
37
+
38
+ if $options[:output]
39
+ Dir.chdir(save_pwd)
40
+ Dir.chdir($options[:output])
41
+ else
42
+ Dir.chdir(directory)
43
+ end
44
+ dir_name = File.basename(name, ext_name) + "#{ext_name.gsub(".","_")}"
45
+ Dir.mkdir(dir_name) unless Dir.exist?(dir_name)
46
+ Dir.chdir(dir_name)
47
+
48
+ eff = Bayonetta::EFFFile::new(f)
49
+
50
+ eff.each_directory { |id, dir|
51
+ Dir.mkdir(dir.name) unless Dir.exist?(dir.name)
52
+ dir.each { |fname, f2|
53
+ File::open("#{dir.name}/#{fname}", "wb") { |f3|
54
+ f2.rewind
55
+ f3.write(f2.read)
56
+ }
57
+ }
58
+ }
59
+
60
+ Dir.mkdir(".metadata") unless Dir.exist?(".metadata")
61
+ Dir.chdir(".metadata")
62
+ File::open("id.yaml", "w") { |fl|
63
+ fl.print YAML::dump( eff.id )
64
+ }
65
+ File::open("layout.yaml", "w") { |fl|
66
+ fl.print YAML::dump( eff.layout )
67
+ }
68
+ File::open("extension.yaml", "w") { |fl|
69
+ fl.print YAML::dump( ext_name )
70
+ }
71
+ File::open("big.yaml","w") { |fl|
72
+ fl.print YAML::dump( eff.big )
73
+ }
@@ -0,0 +1,33 @@
1
+ require 'optparse'
2
+ require_relative '../../bayonetta'
3
+ include Bayonetta
4
+
5
+ $options = {
6
+ output: nil
7
+ }
8
+
9
+ OptionParser.new do |opts|
10
+ opts.banner = <<EOF
11
+ Usage: exp_convert_wiiu_pc target_file
12
+ EOF
13
+ opts.on("-h", "--help", "Prints this help") do
14
+ puts opts
15
+ exit
16
+ end
17
+
18
+ opts.on("-o", "--output=filename", "file to output result") do |name|
19
+ $options[:output] = name
20
+ end
21
+
22
+ end.parse!
23
+
24
+ input_file = ARGV[0]
25
+
26
+ raise "Invalid file #{input_file}" unless input_file && File::file?(input_file)
27
+
28
+ output_file = $options[:output]
29
+ if !output_file
30
+ Dir.mkdir("exp_output") unless Dir.exist?("exp_output")
31
+ output_file = File.join("exp_output", File.basename(input_file))
32
+ end
33
+ EXPFile::convert(input_file, output_file)
@@ -0,0 +1,48 @@
1
+ require 'optparse'
2
+ require 'yaml'
3
+ require_relative '../../bayonetta.rb'
4
+ include Bayonetta
5
+
6
+ $options = {
7
+ :add => false,
8
+ :overwrite => false,
9
+ :swap => false
10
+ }
11
+
12
+ OptionParser.new do |opts|
13
+ opts.banner = "Usage: exp_tool.rb target_file [options]"
14
+
15
+ opts.on("-a", "--add=HASH", "Add entries for the give type example: --add={2=>1, 3=>2} 1 type 2 entry and 2 type 3") { |add|
16
+ $options[:add] = eval(add).to_h
17
+ }
18
+
19
+ opts.on("--overwrite", "Overwrite input file") do |overwrite|
20
+ $options[:overwrite] = overwrite
21
+ end
22
+
23
+ opts.on("-e", "--swap-endianness", "Swap endianness") do |swap|
24
+ $options[:swap] = swap
25
+ end
26
+
27
+ opts.on("-h", "--help", "Prints this help") do
28
+ puts opts
29
+ exit
30
+ end
31
+
32
+ end.parse!
33
+
34
+ Dir.mkdir("exp_output") unless Dir.exist?("exp_output")
35
+ input_file = ARGV[0]
36
+ raise "Invalid file #{input_file}" unless File::file?(input_file)
37
+
38
+ exp = EXPFile::load(input_file)
39
+
40
+ exp.add_entries($options[:add]) if $options[:add]
41
+
42
+ exp.recompute_layout
43
+
44
+ if $options[:overwrite]
45
+ exp.dump(input_file, $options[:swap] ? !exp.was_big? : exp.was_big? )
46
+ else
47
+ exp.dump("exp_output/"+File.basename(input_file), $options[:swap] ? !exp.was_big? : exp.was_big? )
48
+ end
@@ -0,0 +1,33 @@
1
+ require 'optparse'
2
+ require_relative '../../bayonetta'
3
+ include Bayonetta
4
+
5
+ $options = {
6
+ output: nil
7
+ }
8
+
9
+ OptionParser.new do |opts|
10
+ opts.banner = <<EOF
11
+ Usage: mot_convert_wiiu_pc target_file
12
+ EOF
13
+ opts.on("-h", "--help", "Prints this help") do
14
+ puts opts
15
+ exit
16
+ end
17
+
18
+ opts.on("-o", "--output=filename", "file to output result") do |name|
19
+ $options[:output] = name
20
+ end
21
+
22
+ end.parse!
23
+
24
+ input_file = ARGV[0]
25
+
26
+ raise "Invalid file #{input_file}" unless input_file && File::file?(input_file)
27
+
28
+ output_file = $options[:output]
29
+ if !output_file
30
+ Dir.mkdir("mot_output") unless Dir.exist?("mot_output")
31
+ output_file = File.join("mot_output", File.basename(input_file))
32
+ end
33
+ MOTFile::convert(input_file, output_file)
@@ -0,0 +1,60 @@
1
+ require 'optparse'
2
+ require 'yaml'
3
+ require_relative '../../bayonetta'
4
+ include Bayonetta
5
+
6
+ $options = {
7
+ decode: false,
8
+ decode_frame: nil,
9
+ swap: false
10
+ }
11
+
12
+ OptionParser.new do |opts|
13
+ opts.banner = "Usage: mot_tool.rb target_file [options]"
14
+
15
+ opts.on("--remap-bones=HASH", "Remap bones in the motion file") { |remap_bones|
16
+ $options[:remap_bones] = YAML::load_file(remap_bones)
17
+ }
18
+
19
+ opts.on("--[no-]decode", "Decode motion file") { |decode|
20
+ $options[:decode] = decode
21
+ }
22
+
23
+ opts.on("--decode-frame=FRAME_INDEX", "Decode a motion frame") { |decode_frame|
24
+ $options[:decode_frame] = decode_frame.to_i
25
+ }
26
+
27
+ opts.on("--[no-]overwrite", "Overwrite source file") { |overwrite|
28
+ $options[:overwrite] = overwrite
29
+ }
30
+
31
+ opts.on("-e", "--swap-endianness", "Swap endianness") do |swap|
32
+ $options[:swap] = swap
33
+ end
34
+
35
+ opts.on("-h", "--help", "Prints this help") do
36
+ puts opts
37
+ exit
38
+ end
39
+
40
+ end.parse!
41
+
42
+ Dir.mkdir("mot_output") unless Dir.exist?("mot_output")
43
+ input_file = ARGV[0]
44
+ raise "Invalid file #{input_file}" unless File::file?(input_file)
45
+
46
+ mot = MOTFile::load(input_file)
47
+
48
+ mot.remap_bones($options[:remap_bones]) if $options[:remap_bones]
49
+
50
+ if $options[:decode] || $options[:decode_frame]
51
+ puts YAML::dump(mot.decode) if $options[:decode]
52
+ puts YAML::dump(mot.decode_frame($options[:decode_frame])) if $options[:decode_frame]
53
+ exit
54
+ end
55
+
56
+ if $options[:overwrite]
57
+ mot.dump(input_file, $options[:swap] ? !mot.was_big? : mot.was_big?)
58
+ else
59
+ mot.dump("mot_output/"+File.basename(input_file), $options[:swap] ? !mot.was_big? : mot.was_big?)
60
+ end
@@ -0,0 +1,75 @@
1
+ require 'optparse'
2
+ require 'fileutils'
3
+ require 'zstd-ruby'
4
+ require 'oodle-kraken-ruby'
5
+ require_relative '../../bayonetta'
6
+
7
+ $options = {
8
+ output: nil
9
+ }
10
+
11
+ OptionParser.new do |opts|
12
+ opts.banner = <<EOF
13
+ Usage: pkz_extractor [pkz_file [pkz_file2 ...]]
14
+ EOF
15
+ opts.on("-h", "--help", "Prints this help") do
16
+ puts opts
17
+ exit
18
+ end
19
+
20
+ opts.on("-o", "--output=dirname", "directory to output result") do |name|
21
+ $options[:output] = name
22
+ end
23
+
24
+ end.parse!
25
+
26
+ save_pwd = Dir.pwd
27
+
28
+ raise "Invalid output directory #{$options[:output]}" if $options[:output] && !Dir.exist?($options[:output])
29
+
30
+ ARGV.each { |filename|
31
+ raise "Invalid file: #{filename}!" unless File.exist?(filename)
32
+ directory = File.dirname(filename)
33
+ name = File.basename(filename)
34
+ ext_name = File.extname(name)
35
+ raise "Invalid file (#{name})!" unless ext_name == ".pkz"
36
+
37
+ f = File::open(filename, "rb")
38
+
39
+ if $options[:output]
40
+ Dir.chdir(save_pwd)
41
+ Dir.chdir($options[:output])
42
+ else
43
+ Dir.chdir(directory)
44
+ end
45
+ pkz = Bayonetta::PKZFile::load(f)
46
+
47
+ pkz.file_descriptors.each { |d|
48
+ f.seek(d.offset)
49
+ fname = d.name[0..-2]
50
+ compression = d.compression[0..-2]
51
+ dirname = File.dirname(fname)
52
+ unless File.directory?(dirname)
53
+ FileUtils.mkdir_p(dirname)
54
+ end
55
+ case compression
56
+ when "ZStandard"
57
+ File::open(fname, "wb") { |nf|
58
+ nf.write Zstd.decompress(f.read(d.compressed_size))
59
+ raise "Decompression error!" if nf.size != d.size
60
+ }
61
+ when "OodleKraken"
62
+ File::open(fname, "wb") { |nf|
63
+ nf.write OodleKraken.decompress(f.read(d.compressed_size), d.size)
64
+ }
65
+ when "None"
66
+ File::open(fname, "wb") { |nf|
67
+ nf.write f.read(d.compressed_size)
68
+ }
69
+ else
70
+ warn "Unsupported compression format for #{fname}: #{compression}!"
71
+ end
72
+ }
73
+ Dir.chdir(save_pwd)
74
+ f.close
75
+ }