rvpacker 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|