wolftrans 0.0.2 → 0.1.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.
- checksums.yaml +4 -4
- data/Rakefile +22 -2
- data/bin/wolftrans +2 -1
- data/lib/wolfrpg.rb +6 -60
- data/lib/wolfrpg/command.rb +30 -30
- data/lib/wolfrpg/common_events.rb +69 -71
- data/lib/wolfrpg/database.rb +89 -91
- data/lib/wolfrpg/debug.rb +60 -0
- data/lib/wolfrpg/filecoder.rb +114 -0
- data/lib/wolfrpg/game_dat.rb +93 -31
- data/lib/wolfrpg/map.rb +81 -85
- data/lib/wolfrpg/route.rb +10 -10
- data/lib/wolftrans.rb +4 -64
- data/lib/wolftrans/context.rb +3 -3
- data/lib/wolftrans/debug.rb +35 -0
- data/lib/wolftrans/patch_data.rb +10 -8
- data/lib/wolftrans/patch_text.rb +2 -2
- data/lib/wolftrans/util.rb +29 -0
- data/lib/wolftrans/version.rb +3 -0
- data/test/test_wolftrans.rb +2 -1
- data/wolftrans.gemspec +6 -4
- metadata +8 -4
- data/lib/wolfrpg/io.rb +0 -63
data/lib/wolftrans.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
require 'wolftrans/util.rb'
|
2
|
+
|
1
3
|
require 'wolftrans/patch_text'
|
2
4
|
require 'wolftrans/patch_data'
|
3
|
-
|
5
|
+
|
6
|
+
require 'wolftrans/debug.rb'
|
4
7
|
|
5
8
|
module WolfTrans
|
6
9
|
class Patch
|
@@ -101,69 +104,6 @@ module WolfTrans
|
|
101
104
|
end
|
102
105
|
end
|
103
106
|
|
104
|
-
#####################
|
105
|
-
# Utility functions #
|
106
|
-
|
107
|
-
# Sanitize a path; i.e., standardize path separators remove trailing separator
|
108
|
-
def self.sanitize_path(path)
|
109
|
-
if File::ALT_SEPARATOR
|
110
|
-
path = path.gsub(File::ALT_SEPARATOR, '/')
|
111
|
-
end
|
112
|
-
path.sub(/\/$/, '')
|
113
|
-
end
|
114
|
-
|
115
|
-
# Get the name of a path case-insensitively
|
116
|
-
def self.join_path_nocase(parent, child)
|
117
|
-
child_case = Dir.entries(parent).select { |e| e.downcase == child }.first
|
118
|
-
return nil unless child_case
|
119
|
-
return "#{parent}/#{child_case}"
|
120
|
-
end
|
121
|
-
|
122
|
-
# Strip all leading/trailing whitespace, including fullwidth spaces
|
123
|
-
def self.full_strip(str)
|
124
|
-
str.strip.sub(/^\u{3000}*/, '').sub(/\u{3000}*$/, '')
|
125
|
-
end
|
126
|
-
|
127
|
-
# Escape a string for use as a path on the filesystem
|
128
|
-
# https://stackoverflow.com/questions/2270635/invalid-chars-filter-for-file-folder-name-ruby
|
129
|
-
def self.escape_path(path)
|
130
|
-
full_strip(path).gsub(/[\x00\/\\:\*\?\"<>\|]/, '_')
|
131
|
-
end
|
132
|
-
|
133
|
-
###################
|
134
|
-
# Debug functions #
|
135
|
-
def self.grep(dir, needle)
|
136
|
-
Find.find(dir) do |path|
|
137
|
-
next if FileTest.directory? path
|
138
|
-
|
139
|
-
basename = File.basename(path)
|
140
|
-
basename_downcase = basename.downcase
|
141
|
-
basename_noext = File.basename(basename_downcase, '.*')
|
142
|
-
parent_path = File.dirname(path)
|
143
|
-
ext = File.extname(basename_downcase)
|
144
|
-
|
145
|
-
if ext.downcase == '.mps'
|
146
|
-
WolfRpg::Map.new(path).grep(needle)
|
147
|
-
elsif ext.downcase == '.project'
|
148
|
-
next if basename_downcase == 'sysdatabasebasic.project'
|
149
|
-
dat_filename = WolfTrans.join_path_nocase(parent_path, "#{basename_noext}.dat")
|
150
|
-
next if dat_filename == nil
|
151
|
-
WolfRpg::Database.new(path, dat_filename).grep(needle)
|
152
|
-
elsif basename_downcase == 'commonevent.dat'
|
153
|
-
WolfRpg::CommonEvents.new(path).grep(needle)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
def self.grep_cid(dir, cid)
|
159
|
-
Find.find(dir) do |path|
|
160
|
-
next if FileTest.directory? path
|
161
|
-
if File.extname(path).downcase == '.mps'
|
162
|
-
WolfRpg::Map.new(path).grep_cid(cid)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
107
|
# Latest patch version format that can be read
|
168
108
|
TXT_VERSION = Version.new(major: 1, minor: 0)
|
169
109
|
end
|
data/lib/wolftrans/context.rb
CHANGED
@@ -146,11 +146,11 @@ module WolfTrans
|
|
146
146
|
def initialize(db_name, type_index, type_name, datum_index, datum_name, field_index, field_name)
|
147
147
|
@db_name = db_name
|
148
148
|
@type_index = type_index
|
149
|
-
@type_name =
|
149
|
+
@type_name = Util.full_strip(type_name)
|
150
150
|
@datum_index = datum_index
|
151
|
-
@datum_name =
|
151
|
+
@datum_name = Util.full_strip(datum_name)
|
152
152
|
@field_index = field_index
|
153
|
-
@field_name =
|
153
|
+
@field_name = Util.full_strip(field_name)
|
154
154
|
end
|
155
155
|
|
156
156
|
def eql?(other)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module WolfTrans
|
2
|
+
module Debug
|
3
|
+
def self.grep(dir, needle)
|
4
|
+
Find.find(dir) do |path|
|
5
|
+
next if FileTest.directory? path
|
6
|
+
|
7
|
+
basename = File.basename(path)
|
8
|
+
basename_downcase = basename.downcase
|
9
|
+
basename_noext = File.basename(basename_downcase, '.*')
|
10
|
+
parent_path = File.dirname(path)
|
11
|
+
ext = File.extname(basename_downcase)
|
12
|
+
|
13
|
+
if ext.downcase == '.mps'
|
14
|
+
WolfRpg::Map.new(path).grep(needle)
|
15
|
+
elsif ext.downcase == '.project'
|
16
|
+
next if basename_downcase == 'sysdatabasebasic.project'
|
17
|
+
dat_filename = WolfTrans.join_path_nocase(parent_path, "#{basename_noext}.dat")
|
18
|
+
next if dat_filename == nil
|
19
|
+
WolfRpg::Database.new(path, dat_filename).grep(needle)
|
20
|
+
elsif basename_downcase == 'commonevent.dat'
|
21
|
+
WolfRpg::CommonEvents.new(path).grep(needle)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.grep_cid(dir, cid)
|
27
|
+
Find.find(dir) do |path|
|
28
|
+
next if FileTest.directory? path
|
29
|
+
if File.extname(path).downcase == '.mps'
|
30
|
+
WolfRpg::Map.new(path).grep_cid(cid)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/wolftrans/patch_data.rb
CHANGED
@@ -9,11 +9,11 @@ require 'find'
|
|
9
9
|
module WolfTrans
|
10
10
|
class Patch
|
11
11
|
def load_data(game_dir)
|
12
|
-
@game_dir =
|
12
|
+
@game_dir = Util.sanitize_path(game_dir)
|
13
13
|
unless Dir.exist? @game_dir
|
14
14
|
raise "could not find game folder '#{@game_dir}'"
|
15
15
|
end
|
16
|
-
@game_data_dir =
|
16
|
+
@game_data_dir = Util.join_path_nocase(@game_dir, 'data')
|
17
17
|
if @game_data_dir == nil
|
18
18
|
raise "could not find data folder in '#{@game_dir}'"
|
19
19
|
end
|
@@ -39,7 +39,7 @@ module WolfTrans
|
|
39
39
|
load_game_dat(filename)
|
40
40
|
elsif extension == '.project'
|
41
41
|
next if basename_downcase == 'sysdatabasebasic.project'
|
42
|
-
dat_filename =
|
42
|
+
dat_filename = Util.join_path_nocase(parent_path, "#{basename_noext}.dat")
|
43
43
|
next if dat_filename == nil
|
44
44
|
load_game_database(filename, dat_filename)
|
45
45
|
elsif basename_downcase == 'commonevent.dat'
|
@@ -53,7 +53,7 @@ module WolfTrans
|
|
53
53
|
# Apply the patch to the files in the game path and write them to the
|
54
54
|
# output directory
|
55
55
|
def apply(out_dir)
|
56
|
-
out_dir =
|
56
|
+
out_dir = Util.sanitize_path(out_dir)
|
57
57
|
out_data_dir = "#{out_dir}/Data"
|
58
58
|
|
59
59
|
# Clear out directory
|
@@ -116,6 +116,7 @@ module WolfTrans
|
|
116
116
|
'MapChip',
|
117
117
|
'Picture',
|
118
118
|
'SystemFile',
|
119
|
+
'SystemGraphic',
|
119
120
|
].each do |dirname|
|
120
121
|
copy_data_files(out_data_dir, dirname, ['png','jpg','jpeg','bmp'])
|
121
122
|
end
|
@@ -182,24 +183,25 @@ module WolfTrans
|
|
182
183
|
end
|
183
184
|
|
184
185
|
def load_game_database(project_filename, dat_filename)
|
186
|
+
db_name = File.basename(project_filename, '.*')
|
185
187
|
db = WolfRpg::Database.new(project_filename, dat_filename)
|
186
188
|
db.types.each_with_index do |type, type_index|
|
187
189
|
next if type.name.empty?
|
188
|
-
patch_filename = "dump/db/#{
|
190
|
+
patch_filename = "dump/db/#{db_name}/#{Util.escape_path(type.name)}.txt"
|
189
191
|
type.data.each_with_index do |datum, datum_index|
|
190
192
|
datum.each_translatable do |str, field|
|
191
|
-
context = Context::Database.from_data(
|
193
|
+
context = Context::Database.from_data(db_name, type_index, type, datum_index, datum, field)
|
192
194
|
@strings[str][context] ||= Translation.new(patch_filename)
|
193
195
|
end
|
194
196
|
end
|
195
197
|
end
|
196
|
-
@databases[
|
198
|
+
@databases[db_name] = db
|
197
199
|
end
|
198
200
|
|
199
201
|
def load_common_events(filename)
|
200
202
|
@common_events = WolfRpg::CommonEvents.new(filename)
|
201
203
|
@common_events.events.each do |event|
|
202
|
-
patch_filename = "dump/common/#{'%03d' % event.id}_#{
|
204
|
+
patch_filename = "dump/common/#{'%03d' % event.id}_#{Util.escape_path(event.name)}.txt"
|
203
205
|
event.commands.each_with_index do |command, cmd_index|
|
204
206
|
strings_of_command(command) do |string|
|
205
207
|
@strings[string][Context::CommonEvent.from_data(event, cmd_index, command)] ||=
|
data/lib/wolftrans/patch_text.rb
CHANGED
@@ -9,7 +9,7 @@ module WolfTrans
|
|
9
9
|
######################
|
10
10
|
# Loading Patch data #
|
11
11
|
def load_patch(patch_dir)
|
12
|
-
@patch_dir =
|
12
|
+
@patch_dir = Util.sanitize_path(patch_dir)
|
13
13
|
@patch_assets_dir = "#{@patch_dir}/Assets"
|
14
14
|
@patch_strings_dir = "#{@patch_dir}/Patch"
|
15
15
|
|
@@ -19,7 +19,7 @@ module WolfTrans
|
|
19
19
|
end
|
20
20
|
|
21
21
|
# Find data dir
|
22
|
-
@patch_data_dir =
|
22
|
+
@patch_data_dir = Util.join_path_nocase(@patch_assets_dir, 'data')
|
23
23
|
|
24
24
|
# Load blacklist
|
25
25
|
@file_blacklist = []
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module WolfTrans
|
2
|
+
module Util
|
3
|
+
# Sanitize a path; i.e., standardize path separators remove trailing separator
|
4
|
+
def self.sanitize_path(path)
|
5
|
+
if File::ALT_SEPARATOR
|
6
|
+
path = path.gsub(File::ALT_SEPARATOR, '/')
|
7
|
+
end
|
8
|
+
path.sub(/\/$/, '')
|
9
|
+
end
|
10
|
+
|
11
|
+
# Get the name of a path case-insensitively
|
12
|
+
def self.join_path_nocase(parent, child)
|
13
|
+
child_case = Dir.entries(parent).select { |e| e.downcase == child }.first
|
14
|
+
return nil unless child_case
|
15
|
+
return "#{parent}/#{child_case}"
|
16
|
+
end
|
17
|
+
|
18
|
+
# Strip all leading/trailing whitespace, including fullwidth spaces
|
19
|
+
def self.full_strip(str)
|
20
|
+
str.strip.sub(/^\u{3000}*/, '').sub(/\u{3000}*$/, '')
|
21
|
+
end
|
22
|
+
|
23
|
+
# Escape a string for use as a path on the filesystem
|
24
|
+
# https://stackoverflow.com/questions/2270635/invalid-chars-filter-for-file-folder-name-ruby
|
25
|
+
def self.escape_path(path)
|
26
|
+
full_strip(path).gsub(/[\x00\/\\:\*\?\"<>\|]/, '_')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/test/test_wolftrans.rb
CHANGED
@@ -27,8 +27,9 @@ Dir.entries(TEST_DIR).sort.each do |entry|
|
|
27
27
|
Dir.mktmpdir do |tmpdir|
|
28
28
|
patch_dir = "#{tmpdir}/patch"
|
29
29
|
out_dir = "#{tmpdir}/out"
|
30
|
-
puts "==
|
30
|
+
puts "==Patching '#{entry}'"
|
31
31
|
WolfTrans::Patch.new(path, patch_dir).apply(out_dir)
|
32
|
+
puts "==Running '#{entry}'"
|
32
33
|
run_exe("#{out_dir}/Game.exe")
|
33
34
|
end
|
34
35
|
end
|
data/wolftrans.gemspec
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
|
1
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'wolftrans/version'
|
4
|
+
|
2
5
|
Gem::Specification.new do |s|
|
3
6
|
s.name = 'wolftrans'
|
4
|
-
s.version =
|
5
|
-
s.date = '2015-09-14'
|
7
|
+
s.version = WolfTrans::VERSION
|
6
8
|
s.summary = 'A utility to translate Wolf RPG Editor games'
|
7
9
|
s.description = s.summary
|
8
10
|
s.authors = ['Mathew Velasquez']
|
9
11
|
s.email = 'mathewvq@gmail.com'
|
10
12
|
s.files = `git ls-files -z`.split("\x0")
|
11
13
|
s.executables << 'wolftrans'
|
12
|
-
s.homepage = '
|
14
|
+
s.homepage = 'https://github.com/mathewv/wolftrans'
|
13
15
|
s.license = 'MPL'
|
14
16
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wolftrans
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mathew Velasquez
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A utility to translate Wolf RPG Editor games
|
14
14
|
email: mathewvq@gmail.com
|
@@ -25,17 +25,21 @@ files:
|
|
25
25
|
- lib/wolfrpg/command.rb
|
26
26
|
- lib/wolfrpg/common_events.rb
|
27
27
|
- lib/wolfrpg/database.rb
|
28
|
+
- lib/wolfrpg/debug.rb
|
29
|
+
- lib/wolfrpg/filecoder.rb
|
28
30
|
- lib/wolfrpg/game_dat.rb
|
29
|
-
- lib/wolfrpg/io.rb
|
30
31
|
- lib/wolfrpg/map.rb
|
31
32
|
- lib/wolfrpg/route.rb
|
32
33
|
- lib/wolftrans.rb
|
33
34
|
- lib/wolftrans/context.rb
|
35
|
+
- lib/wolftrans/debug.rb
|
34
36
|
- lib/wolftrans/patch_data.rb
|
35
37
|
- lib/wolftrans/patch_text.rb
|
38
|
+
- lib/wolftrans/util.rb
|
39
|
+
- lib/wolftrans/version.rb
|
36
40
|
- test/test_wolftrans.rb
|
37
41
|
- wolftrans.gemspec
|
38
|
-
homepage:
|
42
|
+
homepage: https://github.com/mathewv/wolftrans
|
39
43
|
licenses:
|
40
44
|
- MPL
|
41
45
|
metadata: {}
|
data/lib/wolfrpg/io.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
module WolfRpg
|
2
|
-
module IO
|
3
|
-
########
|
4
|
-
# Read #
|
5
|
-
def self.read(io, size)
|
6
|
-
io.readpartial(size)
|
7
|
-
end
|
8
|
-
def self.read_byte(io)
|
9
|
-
io.readpartial(1).unpack('C').first
|
10
|
-
end
|
11
|
-
def self.read_int(io)
|
12
|
-
io.readpartial(4).unpack('l<').first
|
13
|
-
end
|
14
|
-
def self.read_string(io)
|
15
|
-
size = read_int(io)
|
16
|
-
return '' if size == 0
|
17
|
-
str = io.readpartial(size - 1).encode(Encoding::UTF_8, Encoding::WINDOWS_31J)
|
18
|
-
raise "string not null-terminated" unless read_byte(io) == 0
|
19
|
-
return str
|
20
|
-
end
|
21
|
-
def self.verify(io, data)
|
22
|
-
got = io.readpartial(data.length)
|
23
|
-
if got != data
|
24
|
-
raise "could not verify magic data (expecting #{data.unpack('C*')}, got #{got.unpack('C*')})"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
def self.dump(io, length)
|
28
|
-
length.times do |i|
|
29
|
-
print " %02x" % read_byte(io)
|
30
|
-
end
|
31
|
-
print "\n"
|
32
|
-
end
|
33
|
-
def self.dump_until(pattern)
|
34
|
-
escaped_pattern = Regexp.escape(pattern)
|
35
|
-
str = ''.force_encoding('BINARY')
|
36
|
-
until str =~ /#{escaped_pattern}\z/nm
|
37
|
-
str << io.readpartial(1)
|
38
|
-
end
|
39
|
-
str.gsub(/#{escaped_pattern}\z/nm, '').each_byte do |byte|
|
40
|
-
print " %02x" % byte
|
41
|
-
end
|
42
|
-
print "\n"
|
43
|
-
end
|
44
|
-
|
45
|
-
#########
|
46
|
-
# Write #
|
47
|
-
def self.write(io, data)
|
48
|
-
io.write(data)
|
49
|
-
end
|
50
|
-
def self.write_byte(io, data)
|
51
|
-
io.write(data.chr)
|
52
|
-
end
|
53
|
-
def self.write_int(io, data)
|
54
|
-
io.write([data].pack('l<'))
|
55
|
-
end
|
56
|
-
def self.write_string(io, data)
|
57
|
-
new_data = data.encode(Encoding::WINDOWS_31J, Encoding::UTF_8)
|
58
|
-
write_int(io, new_data.bytesize + 1)
|
59
|
-
io.write(new_data)
|
60
|
-
write_byte(io, 0)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|