R3EXS 1.0.5 → 1.1.1
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/.yardopts +2 -2
- data/CHANGELOG.md +12 -0
- data/README.md +260 -260
- data/README_EN.md +260 -260
- data/bin/R3EXS +9 -19
- data/ext/R3EXS/R3EXS.c +601 -0
- data/ext/R3EXS/extconf.rb +3 -0
- data/lib/R3EXS/RGSS3.rb +1478 -1456
- data/lib/R3EXS/RGSS3_R3EXS.rb +504 -281
- data/lib/R3EXS/ast.rb +45 -41
- data/lib/R3EXS/error.rb +94 -75
- data/lib/R3EXS/extract_strings.rb +75 -79
- data/lib/R3EXS/inject_strings.rb +36 -44
- data/lib/R3EXS/json_rvdata2.rb +114 -104
- data/lib/R3EXS/rvdata2_json.rb +49 -18
- data/lib/R3EXS/utils.rb +1083 -970
- data/lib/R3EXS/version.rb +1 -1
- data/lib/R3EXS.rb +2 -1
- metadata +13 -14
- data/ext/rgss3a_rvdata2/extconf.rb +0 -3
- data/ext/rgss3a_rvdata2/rgss3a_rvdata2.c +0 -616
data/lib/R3EXS/ast.rb
CHANGED
@@ -7,8 +7,21 @@ module R3EXS
|
|
7
7
|
# 用来提取源码生成的 AST 中的字符串和符号
|
8
8
|
class StringsExtractor < Prism::Visitor
|
9
9
|
|
10
|
+
# 提取后存储的字符串数组
|
11
|
+
#
|
12
|
+
# @return [Array<String>]
|
13
|
+
attr_reader :strings
|
14
|
+
|
15
|
+
# 是否包含脚本中的符号
|
16
|
+
#
|
17
|
+
# @return [Boolean]
|
18
|
+
attr_reader :with_symbol
|
19
|
+
|
20
|
+
# 初始化 StringsExtractor
|
21
|
+
#
|
10
22
|
# @param strings [Array<String>] 存储提取出的字符串的数组
|
11
23
|
# @param with_symbol [Boolean] 是否包含脚本中的符号
|
24
|
+
#
|
12
25
|
# @return [StringsExtractor]
|
13
26
|
def initialize(strings, with_symbol)
|
14
27
|
@strings = strings
|
@@ -18,6 +31,7 @@ module R3EXS
|
|
18
31
|
# 处理类型为 StringNode 的节点
|
19
32
|
#
|
20
33
|
# @param node [Prism::StringNode] AST 节点
|
34
|
+
#
|
21
35
|
# @return [void]
|
22
36
|
def visit_string_node(node)
|
23
37
|
@strings << node.content
|
@@ -27,22 +41,12 @@ module R3EXS
|
|
27
41
|
# 处理类型为 SymbolNode 的节点
|
28
42
|
#
|
29
43
|
# @param node [Prism::SymbolNode] AST 节点
|
44
|
+
#
|
30
45
|
# @return [void]
|
31
46
|
def visit_symbol_node(node)
|
32
47
|
@strings << node.value if @with_symbol
|
33
48
|
super
|
34
49
|
end
|
35
|
-
|
36
|
-
# 提取后存储的字符串数组
|
37
|
-
#
|
38
|
-
# @return [Array<String>]
|
39
|
-
attr_accessor :strings
|
40
|
-
|
41
|
-
# 是否包含脚本中的符号
|
42
|
-
#
|
43
|
-
# @return [Boolean]
|
44
|
-
attr_accessor :with_symbol
|
45
|
-
|
46
50
|
end
|
47
51
|
|
48
52
|
# 用来替换源码里面的字符串和符号
|
@@ -51,18 +55,6 @@ module R3EXS
|
|
51
55
|
# 用来记录字符串的位置
|
52
56
|
class Location
|
53
57
|
|
54
|
-
# @note start_offset 是字符串在二进制下打开时的位置
|
55
|
-
#
|
56
|
-
# @param start_offset [Integer] 字符串在源文件中的起始位置
|
57
|
-
# @param length [Integer] 字符串的长度
|
58
|
-
# @param content [String] 字符串内容
|
59
|
-
# @return [Location]
|
60
|
-
def initialize(start_offset, length, content)
|
61
|
-
@start_offset = start_offset
|
62
|
-
@length = length
|
63
|
-
@content = content
|
64
|
-
end
|
65
|
-
|
66
58
|
# 字符串在二进制源文件中的起始位置
|
67
59
|
#
|
68
60
|
# @return [Integer]
|
@@ -78,9 +70,24 @@ module R3EXS
|
|
78
70
|
# @return [String]
|
79
71
|
attr_reader :content
|
80
72
|
|
73
|
+
# @note start_offset 是字符串在二进制下打开时的位置
|
74
|
+
#
|
75
|
+
# @param start_offset [Integer] 字符串在源文件中的起始位置
|
76
|
+
# @param length [Integer] 字符串的长度
|
77
|
+
# @param content [String] 字符串内容
|
78
|
+
#
|
79
|
+
# @return [Location]
|
80
|
+
def initialize(start_offset, length, content)
|
81
|
+
@start_offset = start_offset
|
82
|
+
@length = length
|
83
|
+
@content = content
|
84
|
+
end
|
81
85
|
end
|
82
86
|
|
87
|
+
# 初始化 StringsInjector
|
88
|
+
#
|
83
89
|
# @param hash [Hash<String, String>] 字符串翻译表
|
90
|
+
#
|
84
91
|
# @return [StringsInjector]
|
85
92
|
def initialize(hash)
|
86
93
|
@strings_hash = hash
|
@@ -91,12 +98,13 @@ module R3EXS
|
|
91
98
|
# 处理类型为 StringNode 的节点
|
92
99
|
#
|
93
100
|
# @param node [Prism::StringNode] AST 节点
|
101
|
+
#
|
94
102
|
# @return [void]
|
95
103
|
def visit_string_node(node)
|
96
104
|
location = node.content_loc
|
97
105
|
value = location.slice
|
98
|
-
if @strings_hash.has_key?(value)
|
99
|
-
@content_loc << Location.new(location.start_offset, location.length,
|
106
|
+
if @strings_hash.has_key?(value) && @strings_hash[value].to_s != ''
|
107
|
+
@content_loc << Location.new(location.start_offset, location.length, value)
|
100
108
|
end
|
101
109
|
super
|
102
110
|
end
|
@@ -104,30 +112,27 @@ module R3EXS
|
|
104
112
|
# 处理类型为 SymbolNode 的节点
|
105
113
|
#
|
106
114
|
# @param node [Prism::SymbolNode] AST 节点
|
115
|
+
#
|
107
116
|
# @return [void]
|
108
117
|
def visit_symbol_node(node)
|
109
118
|
location = node.value_loc
|
110
119
|
# 如果 location 不为 nil,说明这个符号是一个字符串
|
111
120
|
if location
|
112
121
|
value = location.slice
|
113
|
-
if @strings_hash.has_key?(value)
|
114
|
-
@content_loc << Location.new(location.start_offset, location.length,
|
122
|
+
if @strings_hash.has_key?(value) && @strings_hash[value].to_s != ''
|
123
|
+
@content_loc << Location.new(location.start_offset, location.length, value)
|
115
124
|
end
|
116
125
|
end
|
117
126
|
super
|
118
127
|
end
|
119
128
|
|
120
|
-
# 将
|
129
|
+
# 将 script 源码中的字符串替换成 @strings_hash 翻译后的字符串
|
121
130
|
#
|
122
|
-
# @param
|
131
|
+
# @param script [String] Ruby 源码,以二进制编码打开
|
123
132
|
# @param ast_root [Prism::ProgramNode] AST 树根节点
|
133
|
+
#
|
124
134
|
# @return [String]
|
125
|
-
def rewrite(
|
126
|
-
# 读取文件内容
|
127
|
-
# 这里必须使用 rb 模式,因为 Prism 定位的位置是二进制下的位置
|
128
|
-
# 也就是说没有考虑换行符的问题,所以必须使用二进制模式读取文件
|
129
|
-
code = File.read(file_path, mode: 'rb')
|
130
|
-
|
135
|
+
def rewrite(script, ast_root)
|
131
136
|
# 首先遍历一遍,找到所有需要替换的字符串的位置
|
132
137
|
visit(ast_root)
|
133
138
|
|
@@ -138,17 +143,16 @@ module R3EXS
|
|
138
143
|
# 然后将 code 切片,将字符串替换成新的字符串
|
139
144
|
start_offset = 0
|
140
145
|
@content_loc.each do |loc|
|
141
|
-
@code <<
|
142
|
-
@code << loc.content
|
146
|
+
@code << script[start_offset...loc.start_offset]
|
147
|
+
@code << @strings_hash[loc.content]
|
143
148
|
start_offset = loc.start_offset + loc.length
|
144
149
|
end
|
145
|
-
@code <<
|
150
|
+
@code << script[start_offset..-1]
|
146
151
|
|
147
|
-
# 将 @code
|
148
|
-
@code.map! { |str| str.force_encoding('
|
152
|
+
# 将 @code 里面的字符串全部改为二进制编码
|
153
|
+
@code.map! { |str| str.force_encoding('ASCII-8BIT') unless str.nil? }
|
149
154
|
@code.join
|
150
155
|
end
|
151
|
-
|
152
156
|
end
|
153
157
|
|
154
158
|
end
|
data/lib/R3EXS/error.rb
CHANGED
@@ -5,222 +5,241 @@ module R3EXS
|
|
5
5
|
# 用来处理 RPG 模块下的类型错误的异常
|
6
6
|
class RPGTypeError < TypeError
|
7
7
|
|
8
|
+
# 引发异常的类
|
9
|
+
#
|
10
|
+
# @return [Object]
|
11
|
+
attr_reader :obj
|
12
|
+
|
13
|
+
# 初始化 RPGTypeError
|
14
|
+
#
|
8
15
|
# @param msg [String] 异常信息
|
9
16
|
# @param obj [Object] 引发异常的类
|
17
|
+
#
|
10
18
|
# @return [RPGTypeError]
|
11
19
|
def initialize(msg = '', obj)
|
12
20
|
super(msg)
|
13
21
|
@obj = obj
|
14
22
|
end
|
15
|
-
|
16
|
-
# 引发异常的类
|
17
|
-
#
|
18
|
-
# @return [Object]
|
19
|
-
attr_reader :obj
|
20
23
|
end
|
21
24
|
|
22
25
|
# 用来处理 R3EXS 模块下的类型错误的异常
|
23
26
|
class R3EXSTypeError < TypeError
|
24
27
|
|
28
|
+
# 引发异常的类型
|
29
|
+
#
|
30
|
+
# @return [Object]
|
31
|
+
attr_reader :obj
|
32
|
+
|
33
|
+
# 初始化 R3EXSTypeError
|
34
|
+
#
|
25
35
|
# @param msg [String] 异常信息
|
26
36
|
# @param obj [Object] 引发异常的的类型
|
37
|
+
#
|
27
38
|
# @return [R3EXSTypeError]
|
28
39
|
def initialize(msg = '', obj)
|
29
40
|
super(msg)
|
30
41
|
@obj = obj
|
31
42
|
end
|
32
|
-
|
33
|
-
# 引发异常的类型
|
34
|
-
#
|
35
|
-
# @return [Object]
|
36
|
-
attr_reader :obj
|
37
43
|
end
|
38
44
|
|
39
45
|
# 用来处理 Game.rgss3a 文件加密格式不支持的异常
|
40
46
|
class RGSS3AFileError < StandardError
|
41
47
|
|
48
|
+
# 引发异常的 rgss3a 文件路径
|
49
|
+
#
|
50
|
+
# @return [String]
|
51
|
+
attr_reader :rgss3a_path
|
52
|
+
|
53
|
+
# 初始化 RGSS3AFileError
|
54
|
+
#
|
42
55
|
# @param msg [String] 异常信息
|
43
56
|
# @param rgss3a_path [String] 引发异常的 rgss3a 文件路径
|
57
|
+
#
|
44
58
|
# @return [Rvdata2DirError]
|
45
59
|
def initialize(msg = '', rgss3a_path)
|
46
60
|
super(msg)
|
47
61
|
@rgss3a_path = rgss3a_path
|
48
62
|
end
|
49
|
-
|
50
|
-
# 引发异常的 rgss3a 文件路径
|
51
|
-
#
|
52
|
-
# @return [String]
|
53
|
-
attr_reader :rgss3a_path
|
54
63
|
end
|
55
64
|
|
56
65
|
# 用来处理 rvdata2 文件损坏的异常
|
57
66
|
class Rvdata2FileError < StandardError
|
58
67
|
|
68
|
+
# 引发异常的 rvdata2 文件路径
|
69
|
+
#
|
70
|
+
# @return [String]
|
71
|
+
attr_reader :rvdata2_path
|
72
|
+
|
73
|
+
# 初始化 Rvdata2FileError
|
74
|
+
#
|
59
75
|
# @param msg [String] 异常信息
|
60
76
|
# @param rvdata2_path [String] 引发异常的 rvdata2 文件路径
|
77
|
+
#
|
61
78
|
# @return [Rvdata2DirError]
|
62
79
|
def initialize(msg = '', rvdata2_path)
|
63
80
|
super(msg)
|
64
81
|
@rvdata2_path = rvdata2_path
|
65
82
|
end
|
66
|
-
|
67
|
-
# 引发异常的 rvdata2 文件路径
|
68
|
-
#
|
69
|
-
# @return [String]
|
70
|
-
attr_reader :rvdata2_path
|
71
83
|
end
|
72
84
|
|
73
85
|
# 用来处理 RPG 模块下 JSON 文件损坏的异常
|
74
86
|
class RPGJsonFileError < StandardError
|
75
87
|
|
88
|
+
# 引发异常的 json 文件路径
|
89
|
+
#
|
90
|
+
# @return [String]
|
91
|
+
attr_reader :json_path
|
92
|
+
|
93
|
+
# 初始化 RPGJsonFileError
|
94
|
+
#
|
76
95
|
# @param msg [String] 异常信息
|
77
96
|
# @param json_path [String] 引发异常的 json 文件路径
|
97
|
+
#
|
78
98
|
# @return [RPGJsonFileError]
|
79
99
|
def initialize(msg = '', json_path)
|
80
100
|
super(msg)
|
81
101
|
@json_path = json_path
|
82
102
|
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# 用来处理 R3EXS 模块下 JSON 文件损坏的异常
|
106
|
+
class R3EXSJsonFileError < StandardError
|
83
107
|
|
84
108
|
# 引发异常的 json 文件路径
|
85
109
|
#
|
86
110
|
# @return [String]
|
87
111
|
attr_reader :json_path
|
88
|
-
end
|
89
|
-
|
90
|
-
# 用来处理 R3EXS 模块下 JSON 文件损坏的异常
|
91
|
-
class R3EXSJsonFileError < StandardError
|
92
112
|
|
113
|
+
# 初始化 R3EXSJsonFileError
|
114
|
+
#
|
93
115
|
# @param msg [String] 异常信息
|
94
116
|
# @param json_path [String] 引发异常的 json 文件路径
|
117
|
+
#
|
95
118
|
# @return [R3EXSJsonFileError]
|
96
119
|
def initialize(msg = '', json_path)
|
97
120
|
super(msg)
|
98
121
|
@json_path = json_path
|
99
122
|
end
|
100
|
-
|
101
|
-
# 引发异常的 json 文件路径
|
102
|
-
#
|
103
|
-
# @return [String]
|
104
|
-
attr_reader :rvdata2_path
|
105
123
|
end
|
106
124
|
|
107
125
|
# 用来处理模块名错误的异常
|
108
126
|
class ModuleNameError < ArgumentError
|
109
127
|
|
128
|
+
# 引发异常的模块名
|
129
|
+
#
|
130
|
+
# @return [Symbol]
|
131
|
+
attr_reader :module_name
|
132
|
+
|
133
|
+
# 初始化 ModuleNameError
|
134
|
+
#
|
110
135
|
# @param msg [String] 异常信息
|
111
136
|
# @param module_name [Symbol] 引发异常的模块名
|
137
|
+
#
|
112
138
|
# @return [ModuleNameError]
|
113
139
|
def initialize(msg = '', module_name)
|
114
140
|
super(msg)
|
115
141
|
@module_name = module_name
|
116
142
|
end
|
117
|
-
|
118
|
-
# 引发异常的模块名
|
119
|
-
#
|
120
|
-
# @return [Symbol]
|
121
|
-
attr_reader :module_name
|
122
143
|
end
|
123
144
|
|
124
145
|
# 用来处理文件名错误的异常
|
125
146
|
class FileBaseNameError < ArgumentError
|
126
147
|
|
148
|
+
# 引发异常的文件名
|
149
|
+
#
|
150
|
+
# @return [String]
|
151
|
+
attr_reader :filebasename
|
152
|
+
|
153
|
+
# 初始化 FileBaseNameError
|
154
|
+
#
|
127
155
|
# @param msg [String] 异常信息
|
128
156
|
# @param filebasename [String] 引发异常的文件名
|
157
|
+
#
|
129
158
|
# @return [FileBaseNameError]
|
130
159
|
def initialize(msg = '', filebasename)
|
131
160
|
super(msg)
|
132
161
|
@filebasename = filebasename
|
133
162
|
end
|
134
|
-
|
135
|
-
# 引发异常的文件名
|
136
|
-
#
|
137
|
-
# @return [String]
|
138
|
-
attr_reader :filebasename
|
139
163
|
end
|
140
164
|
|
141
165
|
# 用来处理 *.rvdata2 文件目录不存在的异常
|
142
166
|
class Rvdata2DirError < IOError
|
143
167
|
|
168
|
+
# 引发异常的 *.rvdata2 文件目录
|
169
|
+
#
|
170
|
+
# @return [String]
|
171
|
+
attr_reader :rvdata2_dir
|
172
|
+
|
173
|
+
# 初始化 Rvdata2DirError
|
174
|
+
#
|
144
175
|
# @param msg [String] 异常信息
|
145
176
|
# @param rvdata2_dir [String] 引发异常的 *.rvdata2 文件目录
|
177
|
+
#
|
146
178
|
# @return [Rvdata2DirError]
|
147
179
|
def initialize(msg = '', rvdata2_dir)
|
148
180
|
super(msg)
|
149
181
|
@rvdata2_dir = rvdata2_dir
|
150
182
|
end
|
151
|
-
|
152
|
-
# 引发异常的 *.rvdata2 文件目录
|
153
|
-
#
|
154
|
-
# @return [String]
|
155
|
-
attr_reader :rvdata2_dir
|
156
183
|
end
|
157
184
|
|
158
185
|
# 用来处理 *.json 文件目录不存在的异常
|
159
186
|
class JsonDirError < IOError
|
160
187
|
|
161
|
-
# @param msg [String] 异常信息
|
162
|
-
# @param json_dir [String] 引发异常的 *.json 文件目录
|
163
|
-
# @return [JsonDirError]
|
164
|
-
def initialize(msg = '', json_dir)
|
165
|
-
super(msg)
|
166
|
-
@json_dir = json_dir
|
167
|
-
end
|
168
|
-
|
169
188
|
# 引发异常的 *.json 文件目录
|
170
189
|
#
|
171
190
|
# @return [String]
|
172
191
|
attr_reader :json_dir
|
173
|
-
end
|
174
|
-
|
175
|
-
# 用来处理 *.rb 文件目录不存在的异常
|
176
|
-
class ScriptsDirError < IOError
|
177
192
|
|
193
|
+
# 初始化 JsonDirError
|
194
|
+
#
|
178
195
|
# @param msg [String] 异常信息
|
179
|
-
# @param
|
180
|
-
#
|
181
|
-
|
196
|
+
# @param json_dir [String] 引发异常的 *.json 文件目录
|
197
|
+
#
|
198
|
+
# @return [JsonDirError]
|
199
|
+
def initialize(msg = '', json_dir)
|
182
200
|
super(msg)
|
183
|
-
@
|
201
|
+
@json_dir = json_dir
|
184
202
|
end
|
185
|
-
|
186
|
-
# 引发异常的 *.rb 文件目录
|
187
|
-
#
|
188
|
-
# @return [String]
|
189
|
-
attr_reader :scripts_dir
|
190
203
|
end
|
191
204
|
|
192
205
|
# 用来处理 Scripts_info.json 文件不存在的异常
|
193
206
|
class ScriptsInfoPathError < IOError
|
194
207
|
|
208
|
+
# 引发异常的 Scripts_info.json 文件路径
|
209
|
+
#
|
210
|
+
# @return [String]
|
211
|
+
attr_reader :scripts_info_path
|
212
|
+
|
213
|
+
# 初始化 ScriptsInfoPathError
|
214
|
+
#
|
195
215
|
# @param msg [String] 异常信息
|
196
216
|
# @param scripts_info_path [String] 引发异常的 Scripts_info.json 文件路径
|
217
|
+
#
|
197
218
|
# @return [ScriptsInfoPathError]
|
198
219
|
def initialize(msg = '', scripts_info_path)
|
199
220
|
super(msg)
|
200
221
|
@scripts_info_path = scripts_info_path
|
201
222
|
end
|
202
|
-
|
203
|
-
# 引发异常的 Scripts_info.json 文件路径
|
204
|
-
#
|
205
|
-
# @return [String]
|
206
|
-
attr_reader :scripts_info_path
|
207
223
|
end
|
208
224
|
|
209
225
|
# 用来处理 ManualTransFile.json 文件不存在的异常
|
210
226
|
class ManualTransFilePathError < IOError
|
211
227
|
|
228
|
+
# 引发异常的 ManualTransFile.json 文件路径
|
229
|
+
#
|
230
|
+
# @return [String]
|
231
|
+
attr_reader :manualtransfile_path
|
232
|
+
|
233
|
+
# 初始化 ManualTransFilePathError
|
234
|
+
#
|
212
235
|
# @param msg [String] 异常信息
|
213
236
|
# @param manualtransfile_path [String] 引发异常的 ManualTransFile.json 文件路径
|
237
|
+
#
|
214
238
|
# @return [ManualTransFilePathError]
|
215
239
|
def initialize(msg = '', manualtransfile_path)
|
216
240
|
super(msg)
|
217
241
|
@manualtransfile_path = manualtransfile_path
|
218
242
|
end
|
219
|
-
|
220
|
-
# 引发异常的 ManualTransFile.json 文件路径
|
221
|
-
#
|
222
|
-
# @return [String]
|
223
|
-
attr_reader :manualtransfile_path
|
224
243
|
end
|
225
244
|
|
226
245
|
end
|
@@ -1,80 +1,76 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'zlib'
|
4
|
-
require_relative 'ast'
|
5
|
-
require_relative 'utils'
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# @param
|
13
|
-
# @param
|
14
|
-
#
|
15
|
-
# @
|
16
|
-
#
|
17
|
-
# @
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
all_ex_strings.compact!
|
77
|
-
Utils.object_json(all_ex_strings.each_with_object({}) { |item, h| h[item] = item }, File.join(output_dir, "ManualTransFile.json"))
|
78
|
-
end
|
79
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'zlib'
|
4
|
+
require_relative 'ast'
|
5
|
+
require_relative 'utils'
|
6
|
+
|
7
|
+
module R3EXS
|
8
|
+
|
9
|
+
# 将指定目录下的所有已经序列化为 R3EXS 后的 JOSN 文件中的字符串提取出来
|
10
|
+
#
|
11
|
+
# @param target_dir [Pathname] 目标目录
|
12
|
+
# @param output_dir [Pathname] 输出目录
|
13
|
+
# @param with_scripts [Boolean] 是否包含脚本
|
14
|
+
# @param with_symbol [Boolean] 是否包含脚本中的符号
|
15
|
+
# @param with_scripts_separate [Boolean] 是否将脚本提取的字符串单独存放
|
16
|
+
#
|
17
|
+
# @raise [R3EXSJsonFileError] json 文件不是 R3EXS 模块中的对象
|
18
|
+
# @raise [JsonDirError] target_dir 不存在
|
19
|
+
#
|
20
|
+
# @return [void]
|
21
|
+
def R3EXS.ex_strings(target_dir, output_dir, with_scripts, with_symbol, with_scripts_separate)
|
22
|
+
all_ex_strings = []
|
23
|
+
|
24
|
+
# 处理常规的 JSON 文件
|
25
|
+
Utils.all_json_files(target_dir, :R3EXS) do |object, file_basename, parent_relative_dir|
|
26
|
+
file_path = target_dir.join(parent_relative_dir, "#{file_basename}.json")
|
27
|
+
print "#{Utils::ESCAPE}#{Utils::MAGENTA_COLOR}Extracting from #{Utils::RESET_COLOR}#{file_path}...\r" if $global_options[:verbose]
|
28
|
+
if object.is_a?(Array)
|
29
|
+
object.each do |obj|
|
30
|
+
all_ex_strings.concat(obj.ex_strings)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
all_ex_strings.concat(object.ex_strings)
|
34
|
+
end
|
35
|
+
print "#{Utils::ESCAPE}#{Utils::GREEN_COLOR}Extracted #{Utils::RESET_COLOR}#{file_path}\n" if $global_options[:verbose]
|
36
|
+
end
|
37
|
+
|
38
|
+
# 处理 CommonEvent_\d{5}.json 文件
|
39
|
+
Utils.all_commonevent_json_files(target_dir, :R3EXS) do |commonevents, commonevents_basenames, parent_relative_dir|
|
40
|
+
commonevents.zip(commonevents_basenames).each do |commonevent, commonevent_basename|
|
41
|
+
file_path = target_dir.join(parent_relative_dir, "#{commonevent_basename}.json")
|
42
|
+
print "#{Utils::ESCAPE}#{Utils::MAGENTA_COLOR}Extracting from #{Utils::RESET_COLOR}#{file_path}...\r" if $global_options[:verbose]
|
43
|
+
all_ex_strings.concat(commonevent.ex_strings)
|
44
|
+
print "#{Utils::ESCAPE}#{Utils::GREEN_COLOR}Extracted #{Utils::RESET_COLOR}#{file_path}\n" if $global_options[:verbose]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# 处理 \d{5}.rb 文件
|
49
|
+
if with_scripts
|
50
|
+
all_rb_strings = []
|
51
|
+
strings_extractor = StringsExtractor.new(all_rb_strings, with_symbol)
|
52
|
+
|
53
|
+
Utils.all_rb_files(target_dir) do |scripts, scripts_basenames, parent_relative_dir|
|
54
|
+
scripts.zip(scripts_basenames).each do |script, script_basename|
|
55
|
+
file_path = target_dir.join(parent_relative_dir, "#{script_basename}.rb")
|
56
|
+
print "#{Utils::ESCAPE}#{Utils::MAGENTA_COLOR}Extracting from #{Utils::RESET_COLOR}#{file_path}...\r" if $global_options[:verbose]
|
57
|
+
strings_extractor.visit(Prism.parse(script).value)
|
58
|
+
print "#{Utils::ESCAPE}#{Utils::GREEN_COLOR}Extracted #{Utils::RESET_COLOR}#{file_path}\n" if $global_options[:verbose]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
if with_scripts_separate
|
63
|
+
# 去除 nil 元素
|
64
|
+
all_rb_strings.compact!
|
65
|
+
Utils.object_json(all_rb_strings.each_with_object({}) { |item, h| h[item] = item }, output_dir.join('ManualTransFile_scripts.json'))
|
66
|
+
else
|
67
|
+
all_ex_strings.concat(all_rb_strings)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# 去除 nil 元素
|
72
|
+
all_ex_strings.compact!
|
73
|
+
Utils.object_json(all_ex_strings.each_with_object({}) { |item, h| h[item] = item }, output_dir.join('ManualTransFile.json'))
|
74
|
+
end
|
75
|
+
|
80
76
|
end
|