Module: RMXPExtractor

Defined in:
lib/rmxp_extractor.rb,
lib/rmxp_extractor/version.rb,
lib/rmxp_extractor/data_export.rb,
lib/rmxp_extractor/data_import.rb,
lib/rmxp_extractor/script_handler.rb

Constant Summary collapse

FORMATS =
["json", "yaml", "rb", "ron"]
VERSION =
"2.0.0"

Class Method Summary collapse

Class Method Details

.check_format(format) ⇒ Object



39
40
41
42
43
44
45
# File 'lib/rmxp_extractor.rb', line 39

def self.check_format(format)
  format = "json" if format.nil?
  unless FORMATS.include?(format)
    warn "Allowed formats: #{FORMATS.to_s}"
    exit 1
  end
end

.export(format) ⇒ Object



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/rmxp_extractor/data_export.rb', line 2

def self.export(format)
  format ||= "json"
  STDERR.puts "No Data Directory!" unless Dir.exist? "./Data"
  exit 1 unless Dir.exist? "./Data"

  require "json"
  require "yaml"
  require "amazing_print"
  require "ruby-progressbar"
  require "fileutils"
  require "pathname"
  require "readline"
  require_relative "classnames"
  require_relative "script_handler"

  if format == "ron"
    require_relative "ron"
  end

  window_size = 120
  progress_format = "%a /%e |%B| %p%% %c/%C %r files/sec %t, currently processing: "
  progress = ProgressBar.create(
    format: progress_format,
    starting_at: 0,
    total: nil,
    output: $stderr,
    length: window_size,
    title: "exported",
    remainder_mark: "\e[0;30mâ–ˆ\e[0m",
    progress_mark: "â–ˆ",
    unknown_progress_animation_steps: ["==>", ">==", "=>="],
  )
  Dir.mkdir "./Data_#{format.upcase}" unless Dir.exist? "./Data_#{format.upcase}"
  paths = Pathname.glob(("./Data/" + ("*" + ".rxdata")))
  count = paths.size
  progress.total = count
  paths.each_with_index do |path, i|
    content = Hash.new

    name = path.basename(".rxdata")
    begin
      rxdata = Marshal.load(path.read(mode: "rb"))
    rescue TypeError => e # Failed to load
      puts "Failed to load file #{path}.\n"
      next
    end

    progress.format = progress_format + name.to_s
    case name.to_s
    when "xScripts", "Scripts"
      RMXPExtractor.rpgscript("./", "./Scripts", "#{name.to_s}.rxdata", true)
      content["data"] = rxdata.map do |a|
        s = Script.new
        s.id, s.name, s.data = a
        s.data = s.data.bytes
        s
      end.rmxp_serialize
      content["version"] = VERSION
    else
      content["data"] = rxdata.rmxp_serialize
      content["version"] = VERSION
    end

    file = File.open("./Data_#{format.upcase}/" + name.sub_ext(".#{format}").to_s, "wb")
    file.puts case format
              when "yaml"
                content.to_yaml
              when "json"
                JSON.pretty_generate(content)
              when "rb"
                content.ai(index: false, indent: 2, plain: true)
              when "ron"
                content["data"]
              end

    progress.increment
  end
end

.import(format) ⇒ Object



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rmxp_extractor/data_import.rb', line 2

def self.import(format)
  STDERR.puts "No Data_JSON Directory!" unless Dir.exist? "./Data_#{format.upcase}"
  exit 1 unless Dir.exist? "./Data_#{format.upcase}"

  require "oj"
  require "yaml"
  require "ruby-progressbar"
  require "fileutils"
  require "pathname"
  require "readline"
  require_relative "classnames"
  require_relative "script_handler"

  if format == "ron"
    puts "RON not supported for importing yet"
    exit 1
  end

  window_size = 120
  progress_format = "%a /%e |%B| %p%% %c/%C %r files/sec %t, currently processing: "
  progress = ProgressBar.create(
    format: progress_format,
    starting_at: 0,
    total: nil,
    output: $stderr,
    length: window_size,
    title: "imported",
    remainder_mark: "\e[0;30mâ–ˆ\e[0m",
    progress_mark: "â–ˆ",
    unknown_progress_animation_steps: ["==>", ">==", "=>="],
  )
  Dir.mkdir "./Data" unless Dir.exist? "./Data"
  paths = Pathname.glob(("./Data_#{format.upcase}/" + ("*" + ".#{format}")))
  count = paths.size
  progress.total = count
  paths.each_with_index do |path, i|
    name = path.basename(".#{format}")
    progress.format = progress_format + name.to_s
    file_contents = path.read(mode: "rb")
    hash = case format
      when "json"
        Oj.load file_contents
      when "yaml"
        YAML.load file_contents
      when "rb"
        eval file_contents # Yes, this SHOULD work. Is it bad? Yes.
      end

    warn "\n\e[33;1mWARNING: Incompatible version format in #{name.to_s}!\e[0m\n" if hash["version"] != VERSION

    case name.to_s
    when "xScripts", "Scripts"
      RMXPExtractor.rpgscript("./", "./Scripts", "#{name.to_s}")
      progress.increment
      return
    else
      content = create_from_rmxp_serialize(hash["data"])
    end

    begin
      dump = Marshal.dump(content)

      rxdata = File.open("./Data/" + name.sub_ext(".rxdata").to_s, "wb")
      rxdata.puts dump
    rescue TypeError => e
      puts "Failed to dump file #{path}.\n"
      next
    end

    progress.increment
  end
end

.process(type) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/rmxp_extractor.rb', line 14

def self.process(type)
  RMXPExtractor.usage if type.length < 1

  case type[0]
  when "-v", "--version"
    puts VERSION
  when "import"
    check_format(type[1])
    import(type[1])
  when "export"
    check_format(type[1])
    export(type[1])
  when "scripts"
    if type.length < 4 || type.length > 5
      STDERR.puts "usage: rmxp_extractor scripts game_dir scripts_dir scripts_name  [x]"
      exit 1
    else
      puts type.to_s
      RMXPExtractor.rpgscript(type[1], type[2], type[3], type[4] == "x")
    end
  else
    RMXPExtractor.usage
  end
end

.rpgscript(game_dir, scripts_dir, script_name, extract = false) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/rmxp_extractor/script_handler.rb', line 5

def self.rpgscript(game_dir, scripts_dir, script_name, extract = false)
  # Determine version of game engine
  game_data_dir = File.join(game_dir, "Data")
  unless Dir.exist? game_data_dir
    STDERR.puts "error: #{game_dir} does not have a Data subdirectory"
    exit 1
  end

  target_path = File.join(game_data_dir, script_name)

  # Generate path of script list
  list_path = File.join(scripts_dir, "_scripts.txt")

  if extract
    # Make sure the script directory exists
    Dir.mkdir(scripts_dir) unless Dir.exist? scripts_dir

    # Keep track of names of scripts extracted so we can warn about duplicates
    names = Hash.new(0)

    # Read scripts
    File.open(target_path, "rb") do |fin|
      File.open(list_path, "w") do |flist|
        Marshal.load(fin).each_with_index do |script, index|
          name = script[1].strip
          data = Zlib::Inflate.inflate(script[2]).rstrip
            .gsub(/[ \t]*(?:$|\r\n?)/, "\n")

          # Make sure this file doesn't already exist
          if name.empty?
            if data.empty? || data == "\n"
              flist.puts
              next
            else
              name = "UNTITLED"
            end
          end

          names[name] += 1
          if names[name] > 1
            name << " (#{names[name]})"
          end

          if data.empty? || data == "\n"
            # Treat this like a comment
            flist.puts("# " + name)
          else
            # Write to file order list
            flist.puts(name)

            # Write script file
            File.open(File.join(scripts_dir, name + ".rb"), "wb") do |fout|
              fout.write(data)
            end
          end
        end
      end
    end
    #puts "#{target_path} extracted."
  else
    # Write scripts
    scripts = []

    IO.foreach(list_path) do |name|
      name.strip!
      next if name.empty? || name.start_with?("#")

      data = File.read(File.join(scripts_dir, name + ".rb")).rstrip.gsub("\n", "\r\n")

      script = Array.new(3)
      script[0] = 0
      script[1] = name
      script[2] = Zlib.deflate(data)
      scripts << script
    end

    File.open(target_path, "wb") { |f| f.write(Marshal.dump(scripts)) }
    #puts "#{target_path} written."
  end
end

.usageObject



9
10
11
12
# File 'lib/rmxp_extractor.rb', line 9

def self.usage
  STDERR.puts "usage: rmxp_extractor < -v/--version > import/export <type = json> | scripts"
  exit 1
end