rvpacker 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.
- data/.gitignore +34 -0
- data/Gemfile +4 -0
- data/LICENSE +17 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/bin/rvpacker +34 -0
- data/lib/RGSS.rb +320 -0
- data/lib/RGSS/BasicCoder.rb +49 -0
- data/lib/RGSS/psych_mods.rb +129 -0
- data/lib/RGSS/serialize.rb +371 -0
- data/lib/RPG.rb +57 -0
- data/lib/rvpacker/version.rb +3 -0
- data/rvpacker.gemspec +25 -0
- metadata +141 -0
data/.gitignore
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/lib/bundler/man/
|
26
|
+
|
27
|
+
# for a library or gem, you might want to ignore these files since the code is
|
28
|
+
# intended to run in multiple environments; otherwise, check them in:
|
29
|
+
# Gemfile.lock
|
30
|
+
# .ruby-version
|
31
|
+
# .ruby-gemset
|
32
|
+
|
33
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
34
|
+
.rvmrc
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Copyright (c) 2013 Howard Jeng
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
4
|
+
software and associated documentation files (the "Software"), to deal in the Software
|
5
|
+
without restriction, including without limitation the rights to use, copy, modify, merge,
|
6
|
+
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
7
|
+
to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
+
|
9
|
+
The above copyright notice and this permission notice shall be included in all copies or
|
10
|
+
substantial portions of the Software.
|
11
|
+
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
13
|
+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
14
|
+
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
15
|
+
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
16
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
17
|
+
DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Rvpacker
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'rvpacker'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install rvpacker
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it ( https://github.com/[my-github-username]/rvpacker/fork )
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/rvpacker
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'trollop'
|
5
|
+
require 'RGSS'
|
6
|
+
|
7
|
+
opts = Trollop::options do
|
8
|
+
opt :action, "Action to perform on project (unpack|pack)", :short => "a", :type => String
|
9
|
+
opt :project, "RPG Maker Project directory", :short => "d", :type => String
|
10
|
+
opt :force, "Update target even when source is older than target", :short => "f"
|
11
|
+
opt :project_type, "Project type (vx|ace|xp)", :short => "t", :type => String
|
12
|
+
opt :verbose, "Print verbose information while processing", :short => "V"
|
13
|
+
end
|
14
|
+
|
15
|
+
directions = {
|
16
|
+
"unpack" => :all_bin_to_text,
|
17
|
+
"pack" => :all_text_to_bin
|
18
|
+
}
|
19
|
+
projecttypes = {
|
20
|
+
"vx" => :vx,
|
21
|
+
"ace" => :ace,
|
22
|
+
"xp" => :xp
|
23
|
+
}
|
24
|
+
$VERBOSE=opts[:verbose]
|
25
|
+
|
26
|
+
RGSS.serialize(projecttypes[opts[:project_type]],
|
27
|
+
directions[opts[:action]],
|
28
|
+
opts[:project],
|
29
|
+
{ :force => (opts[:force] ? true : false),
|
30
|
+
:line_width => -1,
|
31
|
+
:table_width => -1
|
32
|
+
}
|
33
|
+
)
|
34
|
+
|
data/lib/RGSS.rb
ADDED
@@ -0,0 +1,320 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright (c) 2013 Howard Jeng
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
5
|
+
software and associated documentation files (the "Software"), to deal in the Software
|
6
|
+
without restriction, including without limitation the rights to use, copy, modify, merge,
|
7
|
+
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
8
|
+
to whom the Software is furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all copies or
|
11
|
+
substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
14
|
+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
15
|
+
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
16
|
+
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
17
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
18
|
+
DEALINGS IN THE SOFTWARE.
|
19
|
+
=end
|
20
|
+
|
21
|
+
require 'scanf'
|
22
|
+
|
23
|
+
class Table
|
24
|
+
def initialize(bytes)
|
25
|
+
@dim, @x, @y, @z, items, *@data = bytes.unpack('L5 S*')
|
26
|
+
raise "Size mismatch loading Table from data" unless items == @data.length
|
27
|
+
raise "Size mismatch loading Table from data" unless @x * @y * @z == items
|
28
|
+
end
|
29
|
+
|
30
|
+
MAX_ROW_LENGTH = 20
|
31
|
+
|
32
|
+
def encode_with(coder)
|
33
|
+
coder.style = Psych::Nodes::Mapping::BLOCK
|
34
|
+
|
35
|
+
coder['dim'] = @dim
|
36
|
+
coder['x'] = @x
|
37
|
+
coder['y'] = @y
|
38
|
+
coder['z'] = @z
|
39
|
+
|
40
|
+
if @x * @y * @z > 0
|
41
|
+
stride = @x < 2 ? (@y < 2 ? @z : @y) : @x
|
42
|
+
rows = @data.each_slice(stride).to_a
|
43
|
+
if MAX_ROW_LENGTH != -1 && stride > MAX_ROW_LENGTH
|
44
|
+
block_length = (stride + MAX_ROW_LENGTH - 1) / MAX_ROW_LENGTH
|
45
|
+
row_length = (stride + block_length - 1) / block_length
|
46
|
+
rows = rows.collect{|x| x.each_slice(row_length).to_a}.flatten(1)
|
47
|
+
end
|
48
|
+
rows = rows.collect{|x| x.collect{|y| "%04x" % y}.join(" ")}
|
49
|
+
coder['data'] = rows
|
50
|
+
else
|
51
|
+
coder['data'] = []
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def init_with(coder)
|
56
|
+
@dim = coder['dim']
|
57
|
+
@x = coder['x']
|
58
|
+
@y = coder['y']
|
59
|
+
@z = coder['z']
|
60
|
+
@data = coder['data'].collect{|x| x.split(" ").collect{|y| y.hex}}.flatten
|
61
|
+
items = @x * @y * @z
|
62
|
+
raise "Size mismatch loading Table from YAML" unless items == @data.length
|
63
|
+
end
|
64
|
+
|
65
|
+
def _dump(*ignored)
|
66
|
+
return [@dim, @x, @y, @z, @x * @y * @z, *@data].pack('L5 S*')
|
67
|
+
end
|
68
|
+
|
69
|
+
def self._load(bytes)
|
70
|
+
Table.new(bytes)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Color
|
75
|
+
def initialize(bytes)
|
76
|
+
@r, @g, @b, @a = *bytes.unpack('D4')
|
77
|
+
end
|
78
|
+
|
79
|
+
def _dump(*ignored)
|
80
|
+
return [@r, @g, @b, @a].pack('D4')
|
81
|
+
end
|
82
|
+
|
83
|
+
def self._load(bytes)
|
84
|
+
Color.new(bytes)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Tone
|
89
|
+
def initialize(bytes)
|
90
|
+
@r, @g, @b, @a = *bytes.unpack('D4')
|
91
|
+
end
|
92
|
+
|
93
|
+
def _dump(*ignored)
|
94
|
+
return [@r, @g, @b, @a].pack('D4')
|
95
|
+
end
|
96
|
+
|
97
|
+
def self._load(bytes)
|
98
|
+
Tone.new(bytes)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Rect
|
103
|
+
def initialize(bytes)
|
104
|
+
@x, @y, @width, @height = *bytes.unpack('i4')
|
105
|
+
end
|
106
|
+
|
107
|
+
def _dump(*ignored)
|
108
|
+
return [@x, @y, @width, @height].pack('i4')
|
109
|
+
end
|
110
|
+
|
111
|
+
def self._load(bytes)
|
112
|
+
Rect.new(bytes)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
module RGSS
|
117
|
+
def self.remove_defined_method(scope, name)
|
118
|
+
scope.send(:remove_method, name) if scope.instance_methods(false).include?(name)
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.reset_method(scope, name, method)
|
122
|
+
remove_defined_method(scope, name)
|
123
|
+
scope.send(:define_method, name, method)
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.reset_const(scope, sym, value)
|
127
|
+
scope.send(:remove_const, sym) if scope.const_defined?(sym)
|
128
|
+
scope.send(:const_set, sym, value)
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.array_to_hash(arr, &block)
|
132
|
+
h = {}
|
133
|
+
arr.each_with_index do |val, index|
|
134
|
+
r = block_given? ? block.call(val) : val
|
135
|
+
h[index] = r unless r.nil?
|
136
|
+
end
|
137
|
+
if arr.length > 0
|
138
|
+
last = arr.length - 1
|
139
|
+
h[last] = nil unless h.has_key?(last)
|
140
|
+
end
|
141
|
+
return h
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.hash_to_array(hash)
|
145
|
+
arr = []
|
146
|
+
hash.each do |k, v|
|
147
|
+
arr[k] = v
|
148
|
+
end
|
149
|
+
return arr
|
150
|
+
end
|
151
|
+
|
152
|
+
require 'RGSS/BasicCoder'
|
153
|
+
require 'RPG'
|
154
|
+
|
155
|
+
# creates an empty class in a potentially nested scope
|
156
|
+
def self.process(root, name, *args)
|
157
|
+
if args.length > 0
|
158
|
+
process(root.const_get(name), *args)
|
159
|
+
else
|
160
|
+
root.const_set(name, Class.new) unless root.const_defined?(name, false)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# other classes that don't need definitions
|
165
|
+
[ # RGSS data structures
|
166
|
+
[:RPG, :Actor], [:RPG, :Animation], [:RPG, :Animation, :Frame],
|
167
|
+
[:RPG, :Animation, :Timing], [:RPG, :Area], [:RPG, :Armor], [:RPG, :AudioFile],
|
168
|
+
[:RPG, :BaseItem], [:RPG, :BaseItem, :Feature], [:RPG, :BGM], [:RPG, :BGS],
|
169
|
+
[:RPG, :Class], [:RPG, :Class, :Learning], [:RPG, :CommonEvent], [:RPG, :Enemy],
|
170
|
+
[:RPG, :Enemy, :Action], [:RPG, :Enemy, :DropItem], [:RPG, :EquipItem],
|
171
|
+
[:RPG, :Event], [:RPG, :Event, :Page], [:RPG, :Event, :Page, :Condition],
|
172
|
+
[:RPG, :Event, :Page, :Graphic], [:RPG, :Item], [:RPG, :Map],
|
173
|
+
[:RPG, :Map, :Encounter], [:RPG, :MapInfo], [:RPG, :ME], [:RPG, :MoveCommand],
|
174
|
+
[:RPG, :MoveRoute], [:RPG, :SE], [:RPG, :Skill], [:RPG, :State],
|
175
|
+
[:RPG, :System, :Terms], [:RPG, :System, :TestBattler], [:RPG, :System, :Vehicle],
|
176
|
+
[:RPG, :System, :Words], [:RPG, :Tileset], [:RPG, :Troop], [:RPG, :Troop, :Member],
|
177
|
+
[:RPG, :Troop, :Page], [:RPG, :Troop, :Page, :Condition], [:RPG, :UsableItem],
|
178
|
+
[:RPG, :UsableItem, :Damage], [:RPG, :UsableItem, :Effect], [:RPG, :Weapon],
|
179
|
+
# Script classes serialized in save game files
|
180
|
+
[:Game_ActionResult], [:Game_Actor], [:Game_Actors], [:Game_BaseItem],
|
181
|
+
[:Game_BattleAction], [:Game_CommonEvent], [:Game_Enemy], [:Game_Event],
|
182
|
+
[:Game_Follower], [:Game_Followers], [:Game_Interpreter], [:Game_Map],
|
183
|
+
[:Game_Message], [:Game_Party], [:Game_Picture], [:Game_Pictures], [:Game_Player],
|
184
|
+
[:Game_System], [:Game_Timer], [:Game_Troop], [:Game_Screen], [:Game_Vehicle],
|
185
|
+
[:Interpreter]
|
186
|
+
].each {|x| process(Object, *x)}
|
187
|
+
|
188
|
+
def self.setup_system(version, options)
|
189
|
+
# convert variable and switch name arrays to a hash when serialized
|
190
|
+
# if round_trip isn't set change version_id to fixed number
|
191
|
+
if options[:round_trip]
|
192
|
+
iso = ->(val) { return val }
|
193
|
+
reset_method(RPG::System, :reduce_string, iso)
|
194
|
+
reset_method(RPG::System, :map_version, iso)
|
195
|
+
reset_method(Game_System, :map_version, iso)
|
196
|
+
else
|
197
|
+
reset_method(RPG::System, :reduce_string, ->(str) {
|
198
|
+
return nil if str.nil?
|
199
|
+
stripped = str.strip
|
200
|
+
return stripped.empty? ? nil : stripped
|
201
|
+
})
|
202
|
+
# These magic numbers should be different. If they are the same, the saved version
|
203
|
+
# of the map in save files will be used instead of any updated version of the map
|
204
|
+
reset_method(RPG::System, :map_version, ->(ignored) { return 12345678 })
|
205
|
+
reset_method(Game_System, :map_version, ->(ignored) { return 87654321 })
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def self.setup_interpreter(version)
|
210
|
+
# Game_Interpreter is marshalled differently in VX Ace
|
211
|
+
if version == :ace
|
212
|
+
reset_method(Game_Interpreter, :marshal_dump, ->{
|
213
|
+
return @data
|
214
|
+
})
|
215
|
+
reset_method(Game_Interpreter, :marshal_load, ->(obj) {
|
216
|
+
@data = obj
|
217
|
+
})
|
218
|
+
else
|
219
|
+
remove_defined_method(Game_Interpreter, :marshal_dump)
|
220
|
+
remove_defined_method(Game_Interpreter, :marshal_load)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def self.setup_event_command(version, options)
|
225
|
+
# format event commands to flow style for the event codes that aren't move commands
|
226
|
+
if options[:round_trip]
|
227
|
+
reset_method(RPG::EventCommand, :clean, ->{})
|
228
|
+
else
|
229
|
+
reset_method(RPG::EventCommand, :clean, ->{
|
230
|
+
@parameters[0].rstrip! if @code == 401
|
231
|
+
})
|
232
|
+
end
|
233
|
+
reset_const(RPG::EventCommand, :MOVE_LIST_CODE, version == :xp ? 209 : 205)
|
234
|
+
end
|
235
|
+
|
236
|
+
def self.setup_classes(version, options)
|
237
|
+
setup_system(version, options)
|
238
|
+
setup_interpreter(version)
|
239
|
+
setup_event_command(version, options)
|
240
|
+
BasicCoder.set_ivars_methods(version)
|
241
|
+
end
|
242
|
+
|
243
|
+
FLOW_CLASSES = [Color, Tone, RPG::BGM, RPG::BGS, RPG::MoveCommand, RPG::SE]
|
244
|
+
|
245
|
+
SCRIPTS_BASE = 'Scripts'
|
246
|
+
|
247
|
+
ACE_DATA_EXT = '.rvdata2'
|
248
|
+
VX_DATA_EXT = '.rvdata'
|
249
|
+
XP_DATA_EXT = '.rxdata'
|
250
|
+
YAML_EXT = '.yaml'
|
251
|
+
RUBY_EXT = '.rb'
|
252
|
+
|
253
|
+
def self.get_data_directory(base)
|
254
|
+
return File.join(base, 'Data')
|
255
|
+
end
|
256
|
+
|
257
|
+
def self.get_yaml_directory(base)
|
258
|
+
return File.join(base, 'YAML')
|
259
|
+
end
|
260
|
+
|
261
|
+
def self.get_script_directory(base)
|
262
|
+
return File.join(base, 'Scripts')
|
263
|
+
end
|
264
|
+
|
265
|
+
class Game_Switches
|
266
|
+
include RGSS::BasicCoder
|
267
|
+
|
268
|
+
def encode(name, value)
|
269
|
+
return array_to_hash(value)
|
270
|
+
end
|
271
|
+
|
272
|
+
def decode(name, value)
|
273
|
+
return hash_to_array(value)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
class Game_Variables
|
278
|
+
include RGSS::BasicCoder
|
279
|
+
|
280
|
+
def encode(name, value)
|
281
|
+
return array_to_hash(value)
|
282
|
+
end
|
283
|
+
|
284
|
+
def decode(name, value)
|
285
|
+
return hash_to_array(value)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
class Game_SelfSwitches
|
290
|
+
include RGSS::BasicCoder
|
291
|
+
|
292
|
+
def encode(name, value)
|
293
|
+
return Hash[value.collect {|pair|
|
294
|
+
key, value = pair
|
295
|
+
next ["%03d %03d %s" % key, value]
|
296
|
+
}]
|
297
|
+
end
|
298
|
+
|
299
|
+
def decode(name, value)
|
300
|
+
return Hash[value.collect {|pair|
|
301
|
+
key, value = pair
|
302
|
+
next [key.scanf("%d %d %s"), value]
|
303
|
+
}]
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
class Game_System
|
308
|
+
include RGSS::BasicCoder
|
309
|
+
|
310
|
+
def encode(name, value)
|
311
|
+
if name == 'version_id'
|
312
|
+
return map_version(value)
|
313
|
+
else
|
314
|
+
return value
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
require 'RGSS/serialize'
|
320
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module RGSS
|
2
|
+
module BasicCoder
|
3
|
+
def encode_with(coder)
|
4
|
+
ivars.each do |var|
|
5
|
+
name = var.to_s.sub(/^@/, '')
|
6
|
+
value = instance_variable_get(var)
|
7
|
+
coder[name] = encode(name, value)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def encode(name, value)
|
12
|
+
return value
|
13
|
+
end
|
14
|
+
|
15
|
+
def init_with(coder)
|
16
|
+
coder.map.each do |key, value|
|
17
|
+
sym = "@#{key}".to_sym
|
18
|
+
instance_variable_set(sym, decode(key, value))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def decode(name, value)
|
23
|
+
return value
|
24
|
+
end
|
25
|
+
|
26
|
+
def ivars
|
27
|
+
return instance_variables
|
28
|
+
end
|
29
|
+
|
30
|
+
INCLUDED_CLASSES = []
|
31
|
+
def self.included(mod)
|
32
|
+
INCLUDED_CLASSES.push(mod)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.set_ivars_methods(version)
|
36
|
+
INCLUDED_CLASSES.each do |c|
|
37
|
+
if version == :ace
|
38
|
+
RGSS::reset_method(c, :ivars, ->{
|
39
|
+
return instance_variables
|
40
|
+
})
|
41
|
+
else
|
42
|
+
RGSS::reset_method(c, :ivars, ->{
|
43
|
+
return instance_variables.sort
|
44
|
+
})
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
=begin
|
2
|
+
This file contains significant portions of Psych 2.0.0 to modify behavior and to fix
|
3
|
+
bugs. The license follows:
|
4
|
+
|
5
|
+
Copyright 2009 Aaron Patterson, et al.
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
8
|
+
software and associated documentation files (the 'Software'), to deal in the Software
|
9
|
+
without restriction, including without limitation the rights to use, copy, modify, merge,
|
10
|
+
publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
11
|
+
persons to whom the Software is furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all copies or
|
14
|
+
substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
17
|
+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
18
|
+
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
19
|
+
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
20
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
21
|
+
DEALINGS IN THE SOFTWARE.
|
22
|
+
=end
|
23
|
+
|
24
|
+
gem 'psych', '2.0.0'
|
25
|
+
require 'psych'
|
26
|
+
|
27
|
+
if Psych::VERSION == '2.0.0'
|
28
|
+
# Psych bugs:
|
29
|
+
#
|
30
|
+
# 1) Psych has a bug where it stores an anchor to the YAML for an object, but indexes
|
31
|
+
# the reference by object_id. This doesn't keep the object alive, so if it gets garbage
|
32
|
+
# collected, Ruby might generate an object with the same object_id and try to generate a
|
33
|
+
# reference to the stored anchor. This monkey-patches the Registrar to keep the object
|
34
|
+
# alive so incorrect references aren't generated. The bug is also present in Psych 1.3.4
|
35
|
+
# but there isn't a convenient way to patch that.
|
36
|
+
#
|
37
|
+
# 2) Psych also doesn't create references and anchors for classes that implement
|
38
|
+
# encode_with. This modifies dump_coder to handle that situation.
|
39
|
+
#
|
40
|
+
# Added two options:
|
41
|
+
# :sort - sort hashes and instance variables for objects
|
42
|
+
# :flow_classes - array of class types that will automatically emit with flow style
|
43
|
+
# rather than block style
|
44
|
+
module Psych
|
45
|
+
module Visitors
|
46
|
+
class YAMLTree < Psych::Visitors::Visitor
|
47
|
+
class Registrar
|
48
|
+
old_initialize = self.instance_method(:initialize)
|
49
|
+
define_method(:initialize) do
|
50
|
+
old_initialize.bind(self).call
|
51
|
+
@obj_to_obj = {}
|
52
|
+
end
|
53
|
+
|
54
|
+
old_register = self.instance_method(:register)
|
55
|
+
define_method(:register) do |target, node|
|
56
|
+
old_register.bind(self).call(target, node)
|
57
|
+
@obj_to_obj[target.object_id] = target
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
remove_method(:visit_Hash)
|
62
|
+
def visit_Hash o
|
63
|
+
tag = o.class == ::Hash ? nil : "!ruby/hash:#{o.class}"
|
64
|
+
implicit = !tag
|
65
|
+
|
66
|
+
register(o, @emitter.start_mapping(nil, tag, implicit, Nodes::Mapping::BLOCK))
|
67
|
+
|
68
|
+
keys = o.keys
|
69
|
+
keys = keys.sort if @options[:sort]
|
70
|
+
keys.each do |k|
|
71
|
+
accept k
|
72
|
+
accept o[k]
|
73
|
+
end
|
74
|
+
|
75
|
+
@emitter.end_mapping
|
76
|
+
end
|
77
|
+
|
78
|
+
remove_method(:visit_Object)
|
79
|
+
def visit_Object o
|
80
|
+
tag = Psych.dump_tags[o.class]
|
81
|
+
unless tag
|
82
|
+
klass = o.class == Object ? nil : o.class.name
|
83
|
+
tag = ['!ruby/object', klass].compact.join(':')
|
84
|
+
end
|
85
|
+
|
86
|
+
if @options[:flow_classes] && @options[:flow_classes].include?(o.class)
|
87
|
+
style = Nodes::Mapping::FLOW
|
88
|
+
else
|
89
|
+
style = Nodes::Mapping::BLOCK
|
90
|
+
end
|
91
|
+
|
92
|
+
map = @emitter.start_mapping(nil, tag, false, style)
|
93
|
+
register(o, map)
|
94
|
+
|
95
|
+
dump_ivars o
|
96
|
+
@emitter.end_mapping
|
97
|
+
end
|
98
|
+
|
99
|
+
remove_method(:dump_coder)
|
100
|
+
def dump_coder o
|
101
|
+
@coders << o
|
102
|
+
tag = Psych.dump_tags[o.class]
|
103
|
+
unless tag
|
104
|
+
klass = o.class == Object ? nil : o.class.name
|
105
|
+
tag = ['!ruby/object', klass].compact.join(':')
|
106
|
+
end
|
107
|
+
|
108
|
+
c = Psych::Coder.new(tag)
|
109
|
+
o.encode_with(c)
|
110
|
+
register o, emit_coder(c)
|
111
|
+
end
|
112
|
+
|
113
|
+
remove_method(:dump_ivars)
|
114
|
+
def dump_ivars target
|
115
|
+
ivars = find_ivars target
|
116
|
+
ivars = ivars.sort() if @options[:sort]
|
117
|
+
|
118
|
+
ivars.each do |iv|
|
119
|
+
@emitter.scalar("#{iv.to_s.sub(/^@/, '')}", nil, nil, true, false, Nodes::Scalar::ANY)
|
120
|
+
accept target.instance_variable_get(iv)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
else
|
128
|
+
warn "Warning: Psych 2.0.0 not detected" if $VERBOSE
|
129
|
+
end
|
@@ -0,0 +1,371 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright (c) 2013 Howard Jeng
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
5
|
+
software and associated documentation files (the "Software"), to deal in the Software
|
6
|
+
without restriction, including without limitation the rights to use, copy, modify, merge,
|
7
|
+
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
8
|
+
to whom the Software is furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all copies or
|
11
|
+
substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
14
|
+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
15
|
+
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
16
|
+
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
17
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
18
|
+
DEALINGS IN THE SOFTWARE.
|
19
|
+
=end
|
20
|
+
|
21
|
+
require 'RGSS/psych_mods'
|
22
|
+
require 'fileutils'
|
23
|
+
require 'zlib'
|
24
|
+
require 'pp'
|
25
|
+
require 'formatador'
|
26
|
+
|
27
|
+
module RGSS
|
28
|
+
def self.change_extension(file, new_ext)
|
29
|
+
return File.basename(file, '.*') + new_ext
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.sanitize_filename(filename)
|
33
|
+
return filename.gsub(/[^0-9A-Za-z]+/, '_')
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.files_with_extension(directory, extension)
|
37
|
+
return Dir.entries(directory).select{|file| File.extname(file) == extension}
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.inflate(str)
|
41
|
+
text = Zlib::Inflate.inflate(str)
|
42
|
+
return text.force_encoding("UTF-8")
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.deflate(str)
|
46
|
+
return Zlib::Deflate.deflate(str, Zlib::BEST_COMPRESSION)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def self.dump_data_file(file, data, time, options)
|
51
|
+
File.open(file, "wb") do |f|
|
52
|
+
Marshal.dump(data, f)
|
53
|
+
end
|
54
|
+
File.utime(time, time, file)
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.dump_yaml_file(file, data, time, options)
|
58
|
+
File.open(file, "wb") do |f|
|
59
|
+
Psych::dump(data, f, options)
|
60
|
+
end
|
61
|
+
File.utime(time, time, file)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.dump_save(file, data, time, options)
|
65
|
+
File.open(file, "wb") do |f|
|
66
|
+
data.each do |chunk|
|
67
|
+
Marshal.dump(chunk, f)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
File.utime(time, time, file)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.dump_raw_file(file, data, time, options)
|
74
|
+
File.open(file, "wb") do |f|
|
75
|
+
f.write(data)
|
76
|
+
end
|
77
|
+
File.utime(time, time, file)
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.dump(dumper, file, data, time, options)
|
81
|
+
self.method(dumper).call(file, data, time, options)
|
82
|
+
rescue
|
83
|
+
warn "Exception dumping #{file}"
|
84
|
+
raise
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
def self.load_data_file(file)
|
89
|
+
File.open(file, "rb") do |f|
|
90
|
+
return Marshal.load(f)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.load_yaml_file(file)
|
95
|
+
formatador = Formatador.new
|
96
|
+
obj = nil
|
97
|
+
File.open(file, "rb") do |f|
|
98
|
+
obj = Psych::load(f)
|
99
|
+
end
|
100
|
+
max = 0
|
101
|
+
return obj unless obj.kind_of?(Array)
|
102
|
+
seen = {}
|
103
|
+
idx =
|
104
|
+
obj.each do |elem|
|
105
|
+
next if elem.nil?
|
106
|
+
if elem.instance_variable_defined?("@id")
|
107
|
+
id = elem.instance_variable_get("@id")
|
108
|
+
else
|
109
|
+
id = nil
|
110
|
+
elem.instance_variable_set("@id", nil)
|
111
|
+
end
|
112
|
+
next if id.nil?
|
113
|
+
|
114
|
+
if seen.has_key?(id)
|
115
|
+
formatador.display_line("[red]#{file}: Duplicate ID #{id}[/]")
|
116
|
+
formatador.indent {
|
117
|
+
formatador.indent {
|
118
|
+
elem.pretty_inspect.split(/\n/).each do |line|
|
119
|
+
formatador.display_line("[red]#{line}[/]")
|
120
|
+
end
|
121
|
+
}
|
122
|
+
formatador.display_line
|
123
|
+
formatador.display_line("[red]Last seen at:\n[/]")
|
124
|
+
formatador.indent {
|
125
|
+
elem.pretty_inspect.split(/\n/).each do |line|
|
126
|
+
formatador.display_line("[red]#{line}[/]")
|
127
|
+
end
|
128
|
+
}
|
129
|
+
}
|
130
|
+
exit
|
131
|
+
end
|
132
|
+
seen[id] = elem
|
133
|
+
max = ((id + 1) unless id < max)
|
134
|
+
end
|
135
|
+
obj.each do |elem|
|
136
|
+
next if elem.nil?
|
137
|
+
id = elem.instance_variable_get("@id")
|
138
|
+
if id.nil?
|
139
|
+
elem.instance_variable_set("@id", max)
|
140
|
+
max += 1
|
141
|
+
end
|
142
|
+
end
|
143
|
+
return obj
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.load_raw_file(file)
|
147
|
+
File.open(file, "rb") do |f|
|
148
|
+
return f.read
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.load_save(file)
|
153
|
+
File.open(file, "rb") do |f|
|
154
|
+
data = []
|
155
|
+
while not f.eof?
|
156
|
+
o = Marshal.load(f)
|
157
|
+
data.push(o)
|
158
|
+
end
|
159
|
+
return data
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.load(loader, file)
|
164
|
+
return self.method(loader).call(file)
|
165
|
+
rescue
|
166
|
+
warn "Exception loading #{file}"
|
167
|
+
raise
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
def self.scripts_to_text(dirs, src, dest, options)
|
172
|
+
formatador = Formatador.new
|
173
|
+
src_file = File.join(dirs[:data], src)
|
174
|
+
dest_file = File.join(dirs[:yaml], dest)
|
175
|
+
raise "Missing #{src}" unless File.exists?(src_file)
|
176
|
+
|
177
|
+
script_entries = load(:load_data_file, src_file)
|
178
|
+
check_time = !options[:force] && File.exists?(dest_file)
|
179
|
+
oldest_time = File.mtime(dest_file) if check_time
|
180
|
+
|
181
|
+
file_map, script_index, script_code = Hash.new(-1), [], {}
|
182
|
+
|
183
|
+
idx=0
|
184
|
+
script_entries.each do |script|
|
185
|
+
idx += 1
|
186
|
+
magic_number, script_name, code = idx, script[1], inflate(script[2])
|
187
|
+
script_name.force_encoding("UTF-8")
|
188
|
+
|
189
|
+
if code.length > 0
|
190
|
+
filename = script_name.empty? ? 'blank' : sanitize_filename(script_name)
|
191
|
+
key = filename.upcase
|
192
|
+
value = (file_map[key] += 1)
|
193
|
+
actual_filename = filename + (value == 0 ? "" : ".#{value}") + RUBY_EXT
|
194
|
+
script_index.push([magic_number, script_name, actual_filename])
|
195
|
+
full_filename = File.join(dirs[:script], actual_filename)
|
196
|
+
script_code[full_filename] = code
|
197
|
+
check_time = false unless File.exists?(full_filename)
|
198
|
+
oldest_time = [File.mtime(full_filename), oldest_time].min if check_time
|
199
|
+
else
|
200
|
+
script_index.push([magic_number, script_name, nil])
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
src_time = File.mtime(src_file)
|
205
|
+
if check_time && (src_time - 1) < oldest_time
|
206
|
+
formatador.display_line("[yellow]Skipping scripts to text[/]") if $VERBOSE
|
207
|
+
else
|
208
|
+
formatador.display_line("[green]Converting scripts to text[/]") if $VERBOSE
|
209
|
+
dump(:dump_yaml_file, dest_file, script_index, src_time, options)
|
210
|
+
script_code.each {|file, code| dump(:dump_raw_file, file, code, src_time, options)}
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def self.scripts_to_binary(dirs, src, dest, options)
|
215
|
+
formatador = Formatador.new
|
216
|
+
src_file = File.join(dirs[:yaml], src)
|
217
|
+
dest_file = File.join(dirs[:data], dest)
|
218
|
+
raise "Missing #{src}" unless File.exists?(src_file)
|
219
|
+
check_time = !options[:force] && File.exists?(dest_file)
|
220
|
+
newest_time = File.mtime(src_file) if check_time
|
221
|
+
|
222
|
+
index = load(:load_yaml_file, src_file)
|
223
|
+
script_entries = []
|
224
|
+
index.each do |entry|
|
225
|
+
magic_number, script_name, filename = entry
|
226
|
+
code = ''
|
227
|
+
if filename
|
228
|
+
full_filename = File.join(dirs[:script], filename)
|
229
|
+
raise "Missing script file #{filename}" unless File.exists?(full_filename)
|
230
|
+
newest_time = [File.mtime(full_filename), newest_time].max if check_time
|
231
|
+
code = load(:load_raw_file, full_filename)
|
232
|
+
end
|
233
|
+
script_entries.push([magic_number, script_name, deflate(code)])
|
234
|
+
end
|
235
|
+
if check_time && (newest_time - 1) < File.mtime(dest_file)
|
236
|
+
formatador.display_line("[yellow]Skipping scripts to binary[/]") if $VERBOSE
|
237
|
+
else
|
238
|
+
formatador.display_line("[green]Converting scripts to binary[/]") if $VERBOSE
|
239
|
+
dump(:dump_data_file, dest_file, script_entries, newest_time, options)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def self.process_file(file, src_file, dest_file, dest_ext, loader, dumper, options)
|
244
|
+
formatador = Formatador.new
|
245
|
+
src_time = File.mtime(src_file)
|
246
|
+
if !options[:force] && File.exists?(dest_file) && (src_time - 1) < File.mtime(dest_file)
|
247
|
+
formatador.display_line("[yellow]Skipping #{file}[/]") if $VERBOSE
|
248
|
+
else
|
249
|
+
formatador.display_line("[green]Converting #{file} to #{dest_ext}[/]") if $VERBOSE
|
250
|
+
data = load(loader, src_file)
|
251
|
+
dump(dumper, dest_file, data, src_time, options)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def self.convert(src, dest, options)
|
256
|
+
files = files_with_extension(src[:directory], src[:ext])
|
257
|
+
files -= src[:exclude]
|
258
|
+
|
259
|
+
files.each do |file|
|
260
|
+
src_file = File.join(src[:directory], file)
|
261
|
+
dest_file = File.join(dest[:directory], change_extension(file, dest[:ext]))
|
262
|
+
|
263
|
+
process_file(file, src_file, dest_file, dest[:ext], src[:load_file],
|
264
|
+
dest[:dump_file], options)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def self.convert_saves(base, src, dest, options)
|
269
|
+
save_files = files_with_extension(base, src[:ext])
|
270
|
+
save_files.each do |file|
|
271
|
+
src_file = File.join(base, file)
|
272
|
+
dest_file = File.join(base, change_extension(file, dest[:ext]))
|
273
|
+
|
274
|
+
process_file(file, src_file, dest_file, dest[:ext], src[:load_save],
|
275
|
+
dest[:dump_save], options)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# [version] one of :ace, :vx, :xp
|
280
|
+
# [direction] one of :data_bin_to_text, :data_text_to_bin, :save_bin_to_text,
|
281
|
+
# :save_text_to_bin, :scripts_bin_to_text, :scripts_text_to_bin,
|
282
|
+
# :all_text_to_bin, :all_bin_to_text
|
283
|
+
# [directory] directory that project file is in
|
284
|
+
# [options] :force - ignores file dates when converting (default false)
|
285
|
+
# :round_trip - create yaml data that matches original marshalled data skips
|
286
|
+
# data cleanup operations (default false)
|
287
|
+
# :line_width - line width form YAML files, -1 for no line width limit
|
288
|
+
# (default 130)
|
289
|
+
# :table_width - maximum number of entries per row for table data, -1 for no
|
290
|
+
# table row limit (default 20)
|
291
|
+
def self.serialize(version, direction, directory, options = {})
|
292
|
+
raise "#{directory} not found" unless File.exist?(directory)
|
293
|
+
|
294
|
+
setup_classes(version, options)
|
295
|
+
options = options.clone()
|
296
|
+
options[:sort] = true if [:vx, :xp].include?(version)
|
297
|
+
options[:flow_classes] = FLOW_CLASSES
|
298
|
+
options[:line_width] ||= 130
|
299
|
+
|
300
|
+
table_width = options[:table_width]
|
301
|
+
RGSS::reset_const(Table, :MAX_ROW_LENGTH, table_width ? table_width : 20)
|
302
|
+
|
303
|
+
base = File.realpath(directory)
|
304
|
+
|
305
|
+
dirs = {
|
306
|
+
:base => base,
|
307
|
+
:data => get_data_directory(base),
|
308
|
+
:yaml => get_yaml_directory(base),
|
309
|
+
:script => get_script_directory(base)
|
310
|
+
}
|
311
|
+
|
312
|
+
dirs.values.each do |d|
|
313
|
+
FileUtils.mkdir(d) unless File.exists?(d)
|
314
|
+
end
|
315
|
+
|
316
|
+
exts = {
|
317
|
+
:ace => ACE_DATA_EXT,
|
318
|
+
:vx => VX_DATA_EXT,
|
319
|
+
:xp => XP_DATA_EXT
|
320
|
+
}
|
321
|
+
|
322
|
+
yaml_scripts = SCRIPTS_BASE + YAML_EXT
|
323
|
+
yaml = {
|
324
|
+
:directory => dirs[:yaml],
|
325
|
+
:exclude => [yaml_scripts],
|
326
|
+
:ext => YAML_EXT,
|
327
|
+
:load_file => :load_yaml_file,
|
328
|
+
:dump_file => :dump_yaml_file,
|
329
|
+
:load_save => :load_yaml_file,
|
330
|
+
:dump_save => :dump_yaml_file
|
331
|
+
}
|
332
|
+
|
333
|
+
scripts = SCRIPTS_BASE + exts[version]
|
334
|
+
data = {
|
335
|
+
:directory => dirs[:data],
|
336
|
+
:exclude => [scripts],
|
337
|
+
:ext => exts[version],
|
338
|
+
:load_file => :load_data_file,
|
339
|
+
:dump_file => :dump_data_file,
|
340
|
+
:load_save => :load_save,
|
341
|
+
:dump_save => :dump_save
|
342
|
+
}
|
343
|
+
|
344
|
+
case direction
|
345
|
+
when :data_bin_to_text
|
346
|
+
convert(data, yaml, options)
|
347
|
+
scripts_to_text(dirs, scripts, yaml_scripts, options)
|
348
|
+
when :data_text_to_bin
|
349
|
+
convert(yaml, data, options)
|
350
|
+
scripts_to_binary(dirs, yaml_scripts, scripts, options)
|
351
|
+
when :save_bin_to_text
|
352
|
+
convert_saves(base, data, yaml, options)
|
353
|
+
when :save_text_to_bin
|
354
|
+
convert_saves(base, yaml, data, options)
|
355
|
+
when :scripts_bin_to_text
|
356
|
+
scripts_to_text(dirs, scripts, yaml_scripts, options)
|
357
|
+
when :scripts_text_to_bin
|
358
|
+
scripts_to_binary(dirs, yaml_scripts, scripts, options)
|
359
|
+
when :all_bin_to_text
|
360
|
+
convert(data, yaml, options)
|
361
|
+
scripts_to_text(dirs, scripts, yaml_scripts, options)
|
362
|
+
convert_saves(base, data, yaml, options)
|
363
|
+
when :all_text_to_bin
|
364
|
+
convert(yaml, data, options)
|
365
|
+
scripts_to_binary(dirs, yaml_scripts, scripts, options)
|
366
|
+
convert_saves(base, yaml, data, options)
|
367
|
+
else
|
368
|
+
raise "Unrecognized direction :#{direction}"
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
data/lib/RPG.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'RGSS'
|
2
|
+
module RPG
|
3
|
+
class System
|
4
|
+
include RGSS::BasicCoder
|
5
|
+
HASHED_VARS = ['variables', 'switches']
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.array_to_hash(arr, &block)
|
9
|
+
h = {}
|
10
|
+
arr.each_with_index do |val, index|
|
11
|
+
r = block_given? ? block.call(val) : val
|
12
|
+
h[index] = r unless r.nil?
|
13
|
+
end
|
14
|
+
if arr.length > 0
|
15
|
+
last = arr.length - 1
|
16
|
+
h[last] = nil unless h.has_key?(last)
|
17
|
+
end
|
18
|
+
return h
|
19
|
+
end
|
20
|
+
|
21
|
+
def encode(name, value)
|
22
|
+
if HASHED_VARS.include?(name)
|
23
|
+
return array_to_hash(value) {|val| reduce_string(val)}
|
24
|
+
elsif name == 'version_id'
|
25
|
+
return map_version(value)
|
26
|
+
else
|
27
|
+
return value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def decode(name, value)
|
32
|
+
if HASHED_VARS.include?(name)
|
33
|
+
return hash_to_array(value)
|
34
|
+
else
|
35
|
+
return value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class EventCommand
|
40
|
+
def encode_with(coder)
|
41
|
+
raise 'Unexpected number of instance variables' if instance_variables.length != 3
|
42
|
+
clean
|
43
|
+
|
44
|
+
case @code
|
45
|
+
when MOVE_LIST_CODE # move list
|
46
|
+
coder.style = Psych::Nodes::Mapping::BLOCK
|
47
|
+
else
|
48
|
+
coder.style = Psych::Nodes::Mapping::FLOW
|
49
|
+
end
|
50
|
+
coder['i'], coder['c'], coder['p'] = @indent, @code, @parameters
|
51
|
+
end
|
52
|
+
|
53
|
+
def init_with(coder)
|
54
|
+
@indent, @code, @parameters = coder['i'], coder['c'], coder['p']
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/rvpacker.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rvpacker/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rvpacker"
|
8
|
+
spec.version = Rvpacker::VERSION
|
9
|
+
spec.authors = ["Howard Jeng", "Andrew Kesterson"]
|
10
|
+
spec.email = ["andrew@aklabs.net"]
|
11
|
+
spec.summary = %q{Pack and unpack RPG Maker data files}
|
12
|
+
spec.homepage = "https://github.com/akesterson/rvpacker"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
spec.add_dependency "trollop"
|
23
|
+
spec.add_dependency "psych", "2.0.0"
|
24
|
+
spec.add_dependency "formatador"
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rvpacker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Howard Jeng
|
9
|
+
- Andrew Kesterson
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2014-04-20 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: bundler
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '1.6'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '1.6'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: rake
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: trollop
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: psych
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - '='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 2.0.0
|
71
|
+
type: :runtime
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - '='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 2.0.0
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: formatador
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
type: :runtime
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
description:
|
96
|
+
email:
|
97
|
+
- andrew@aklabs.net
|
98
|
+
executables:
|
99
|
+
- rvpacker
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files: []
|
102
|
+
files:
|
103
|
+
- .gitignore
|
104
|
+
- Gemfile
|
105
|
+
- LICENSE
|
106
|
+
- README.md
|
107
|
+
- Rakefile
|
108
|
+
- bin/rvpacker
|
109
|
+
- lib/RGSS.rb
|
110
|
+
- lib/RGSS/BasicCoder.rb
|
111
|
+
- lib/RGSS/psych_mods.rb
|
112
|
+
- lib/RGSS/serialize.rb
|
113
|
+
- lib/RPG.rb
|
114
|
+
- lib/rvpacker/version.rb
|
115
|
+
- rvpacker.gemspec
|
116
|
+
homepage: https://github.com/akesterson/rvpacker
|
117
|
+
licenses:
|
118
|
+
- MIT
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
124
|
+
none: false
|
125
|
+
requirements:
|
126
|
+
- - ! '>='
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
requirements: []
|
136
|
+
rubyforge_project:
|
137
|
+
rubygems_version: 1.8.23
|
138
|
+
signing_key:
|
139
|
+
specification_version: 3
|
140
|
+
summary: Pack and unpack RPG Maker data files
|
141
|
+
test_files: []
|