5
5
6
6
from Python import shared_globals as cfg
7
7
8
-
9
8
progress = 0
10
9
total_progress = 0
10
+
11
+ warnings_file_name = "Warnings.json"
12
+ warnings_path = os .path .join ("ConversionRules" , warnings_file_name )
13
+ warnings_available = os .path .isfile (warnings_path )
14
+
11
15
conversion_rules = {}
16
+ warning_rules = {}
17
+ warnings = []
12
18
13
19
14
20
# TODO: Move to shared_globals.py
@@ -25,20 +31,22 @@ def resource_path(relative_path):
25
31
output_folder = ".." if getattr (sys , 'frozen' , False ) else "Output"
26
32
27
33
28
- def load_conversion_rules ():
34
+ def load_conversion_and_warning_rules ():
29
35
json_parser = JsonComment (json )
30
36
31
37
json_files_found = 0
32
38
try :
33
39
for name in os .listdir ("ConversionRules" ):
34
- if name .endswith (".json" ):
35
- path = os .path .join ("ConversionRules" , name )
36
- with open (path ) as f :
37
- json_files_found += 1
38
- conversion_rules .update (json_parser .load (f ))
40
+ if name .endswith (".json" ) and name != warnings_file_name :
41
+ json_files_found += 1
42
+ with open (os .path .join ("ConversionRules" , name )) as f :
43
+ conversion_rules .update (json_parser .load (f ))
44
+ if warnings_available :
45
+ with open (warnings_path ) as f :
46
+ warning_rules .update (json_parser .load (f ))
39
47
except :
40
48
check_github_button_clicked_and_exit (cfg .sg .Popup ("The 'ConversionRules' folder wasn't found next to this executable. You can get the missing folder from the Legacy Mod Converter GitHub repo." , title = "Missing ConversionRules folder" , custom_text = "Go to GitHub" ))
41
-
49
+
42
50
if json_files_found == 0 :
43
51
check_github_button_clicked_and_exit (cfg .sg .Popup ("The 'ConversionRules' folder didn't contain any JSON files. You can get the JSON files from the Legacy Mod Converter GitHub repo." , title = "Missing JSON files" , custom_text = "Go to GitHub" ))
44
52
@@ -51,147 +59,163 @@ def check_github_button_clicked_and_exit(clicked_github_button):
51
59
52
60
53
61
def convert ():
54
- global progress , total_progress , output_folder
62
+ global progress , total_progress , output_folder , warnings
55
63
56
64
time_start = time .time ()
57
65
58
- input_folder = cfg .sg .user_settings_get_entry ("input_folder" )
66
+ input_folder_path = cfg .sg .user_settings_get_entry ("input_folder" )
67
+ true_input_folder_path = os .path .join (input_folder_path , os .pardir ) # TODO: Better variable name.
59
68
60
- unzip (input_folder )
69
+ unzip (input_folder_path )
61
70
62
- total_progress = get_total_progress (input_folder )
71
+ total_progress = get_total_progress (input_folder_path )
63
72
64
- for input_folder_path , input_subfolders , full_filename_list in os .walk (input_folder ):
65
- mod_subfolder = get_mod_subfolder (input_folder , input_folder_path )
73
+ for input_subfolder_path , input_subfolders , input_subfiles in os .walk (input_folder_path ):
74
+ mod_subfolder = get_mod_subfolder (input_folder_path , input_subfolder_path , true_input_folder_path )
66
75
output_subfolder = os .path .join (output_folder , mod_subfolder )
67
76
68
77
try_print_mod_name (mod_subfolder )
69
- create_folder (input_folder_path , output_subfolder )
70
- process_file (full_filename_list , input_folder_path , output_subfolder )
78
+ create_folder (input_subfolder_path , output_subfolder )
79
+ process_file (input_subfiles , input_subfolder_path , output_subfolder , input_folder_path )
71
80
72
81
if cfg .sg .user_settings_get_entry ("output_zips" ):
73
- create_zips (input_folder , output_folder )
82
+ create_zips (input_folder_path , output_folder )
83
+
84
+ if len (warnings ) > 0 :
85
+ warnings_popup ()
74
86
75
87
progress = 0
76
88
total_progress = 0
89
+ warnings = []
77
90
78
91
elapsed = math .floor (time .time () - time_start )
79
92
if cfg .sg .user_settings_get_entry ("play_finish_sound" ):
80
93
playsound (finishSoundPath )
81
94
print ("Finished in {} {}" .format (elapsed , pluralize ("second" , elapsed )))
82
95
83
96
84
- def unzip (input_folder ):
85
- for f in os .listdir (input_folder ):
86
- zip_path = os .path .join (input_folder , f )
97
+ def unzip (input_folder_path ):
98
+ for f in os .listdir (input_folder_path ):
99
+ zip_path = os .path .join (input_folder_path , f )
87
100
if zipfile .is_zipfile (zip_path ):
88
101
with zipfile .ZipFile (zip_path ) as item :
89
- item .extractall (input_folder )
102
+ item .extractall (input_folder_path )
90
103
os .remove (zip_path )
91
104
92
105
93
- def get_total_progress (input_folder ):
94
- if input_folder .endswith (".rte" ):
106
+ def get_total_progress (input_folder_path ):
107
+ if input_folder_path .endswith (".rte" ):
95
108
mod_count = 1
96
109
else :
97
- mod_count = len ([name for name in os .listdir (input_folder ) if os .path .isdir (os .path .join (input_folder , name ))])
110
+ mod_count = len ([name for name in os .listdir (input_folder_path ) if os .path .isdir (os .path .join (input_folder_path , name ))])
98
111
99
112
return mod_count * 2 if cfg .sg .user_settings_get_entry ("output_zips" ) else mod_count
100
113
101
114
102
- def get_mod_subfolder (input_folder , input_folder_path ):
103
- if input_folder .endswith (".rte" ):
104
- return os .path .relpath (input_folder_path , os . path . join ( input_folder , os . pardir ) )
115
+ def get_mod_subfolder (input_folder_path , input_subfolder_path , true_input_folder_path ):
116
+ if input_folder_path .endswith (".rte" ):
117
+ return os .path .relpath (input_subfolder_path , true_input_folder_path )
105
118
else :
106
- return os .path .relpath (input_folder_path , input_folder )
119
+ return os .path .relpath (input_subfolder_path , input_folder_path )
107
120
108
121
109
122
def try_print_mod_name (mod_subfolder ):
110
- input_folder_path_tuple = pathlib .Path (mod_subfolder ).parts
123
+ input_subfolder_path_tuple = pathlib .Path (mod_subfolder ).parts
111
124
112
- if len (input_folder_path_tuple ) == 1 :
113
- print ("Converting '{}'" .format (input_folder_path_tuple [0 ]))
125
+ if len (input_subfolder_path_tuple ) == 1 :
126
+ print ("Converting '{}'" .format (input_subfolder_path_tuple [0 ]))
114
127
update_progress ()
115
128
116
129
117
130
def update_progress ():
118
- global progress , total_progress
131
+ global progress
119
132
progress += 1
120
133
cfg .progress_bar .UpdateBar (progress % total_progress , total_progress )
121
134
122
135
123
- def create_folder (input_folder_path , output_subfolder ):
124
- # Prevents putting the input_folder itself into the output_subfolder.
125
- # if input_folder_path != cfg.sg.user_settings_get_entry("input_folder"):
126
-
136
+ def create_folder (input_subfolder_path , output_subfolder ):
127
137
try :
128
138
os .makedirs (output_subfolder )
129
139
except FileExistsError :
130
140
pass
131
141
132
142
133
- def process_file (full_filename_list , input_folder_path , output_subfolder ):
134
- for full_filename in full_filename_list :
143
+ def process_file (input_subfiles , input_subfolder_path , output_subfolder , input_folder_path ):
144
+ for full_filename in input_subfiles :
135
145
filename , file_extension = os .path .splitext (full_filename )
136
146
137
147
# The ".empty" file exists so otherwise empty folders can be added to Git.
138
148
if filename == ".empty" :
139
149
continue
140
150
141
- input_file_path = os .path .join (input_folder_path , full_filename )
151
+ input_file_path = os .path .join (input_subfolder_path , full_filename )
142
152
output_file_path = os .path .join (output_subfolder , full_filename )
143
153
144
154
if file_extension in (".ini" , ".lua" ):
145
- create_converted_file (input_file_path , output_file_path )
155
+ create_converted_file (input_file_path , output_file_path , input_folder_path )
146
156
else :
147
157
shutil .copyfile (input_file_path , output_file_path )
148
158
149
159
150
- def create_converted_file (input_file_path , output_file_path ):
160
+ def create_converted_file (input_file_path , output_file_path , input_folder_path ):
151
161
try :
152
162
with open (input_file_path , "r" ) as file_in :
153
163
with open (output_file_path , "w" ) as file_out :
154
- all_lines = regex_replace (file_in .read ())
155
- for old_str , new_str in conversion_rules .items ():
156
- all_lines = all_lines .replace (old_str , new_str )
157
- all_lines = regex_replace_bmps_and_wavs (all_lines )
158
- file_out .write (all_lines )
164
+ all_lines_list = []
165
+ file_path = os .path .relpath (input_file_path , input_folder_path )
166
+
167
+ line_number = 0
168
+ for line in file_in :
169
+ line_number += 1
170
+
171
+ line = regex_replace (line )
172
+ for old_str , new_str in conversion_rules .items ():
173
+ line = line .replace (old_str , new_str )
174
+ all_lines_list .append (line )
175
+
176
+ if warnings_available :
177
+ for old_str , new_str in warning_rules .items ():
178
+ if old_str in line :
179
+ warnings .append ("'{}' line {}: {} -> {}" .format (file_path , line_number , old_str , new_str ))
180
+
181
+ all_lines_str = "" .join (all_lines_list )
182
+ file_out .write (regex_replace_bmps_and_wavs (all_lines_str ))
159
183
except :
160
184
shutil .copyfile (input_file_path , output_file_path )
161
185
162
186
163
- def regex_replace (all_lines ):
164
- all_lines = simple_replace (all_lines , "Framerate = (.*)" , "SpriteAnimMode = 7" )
165
- all_lines = simple_replace (all_lines , "\t PlayerCount = (.*)\n " , "" )
166
- all_lines = simple_replace (all_lines , "\t TeamCount = (.*)\n " , "" )
187
+ def regex_replace (line ):
188
+ line = simple_replace (line , "Framerate = (.*)" , "SpriteAnimMode = 7" )
189
+ line = simple_replace (line , "\t PlayerCount = (.*)\n " , "" )
190
+ line = simple_replace (line , "\t TeamCount = (.*)\n " , "" )
167
191
168
- all_lines = specific_replace (all_lines , regex_replace_particle , False , "ParticleNumberToAdd = (.*)\n \t AddParticles = (.*)\n \t \t CopyOf = (.*)\n " , "AddGib = Gib\n \t \t GibParticle = {}\n \t \t \t CopyOf = {}\n \t \t Count = {}\n " )
169
- all_lines = specific_replace (all_lines , regex_replace_sound_priority , True , " Sound(((?! Sound).)*)Priority" , " Sound{}// Priority" )
170
- all_lines = specific_replace (all_lines , regex_use_capture , False , "FundsOfTeam(.*) =" , "Team{}Funds =" )
171
- # all_lines = specific_replace(all_lines , regex_replace_playsound, False, "", "")
192
+ line = specific_replace (line , regex_replace_particle , False , "ParticleNumberToAdd = (.*)\n \t AddParticles = (.*)\n \t \t CopyOf = (.*)\n " , "AddGib = Gib\n \t \t GibParticle = {}\n \t \t \t CopyOf = {}\n \t \t Count = {}\n " )
193
+ line = specific_replace (line , regex_replace_sound_priority , True , " Sound(((?! Sound).)*)Priority" , " Sound{}// Priority" )
194
+ line = specific_replace (line , regex_use_capture , False , "FundsOfTeam(.*) =" , "Team{}Funds =" )
195
+ # line = specific_replace(line , regex_replace_playsound, False, "", "")
172
196
173
- return all_lines
197
+ return line
174
198
175
199
176
- def simple_replace (all_lines , pattern , replacement ):
177
- matches = re .findall (pattern , all_lines )
200
+ def simple_replace (line , pattern , replacement ):
201
+ matches = re .findall (pattern , line )
178
202
if len (matches ) > 0 :
179
- return re .sub (pattern , replacement , all_lines )
180
- return all_lines
203
+ return re .sub (pattern , replacement , line )
204
+ return line
181
205
182
206
183
- def specific_replace (all_lines , fn , dotall , pattern , replacement ):
184
- # TODO: Refactor so .findall can take dotall as an argument directly.
207
+ def specific_replace (line , fn , dotall , pattern , replacement ):
208
+ # TODO: Refactor so .findall takes re.DOTALL as an argument directly.
185
209
if dotall :
186
- matches = re .findall (pattern , all_lines , re .DOTALL )
210
+ matches = re .findall (pattern , line , re .DOTALL )
187
211
else :
188
- matches = re .findall (pattern , all_lines )
212
+ matches = re .findall (pattern , line )
189
213
if len (matches ) > 0 :
190
- return fn (all_lines , pattern , replacement , matches )
191
- return all_lines
214
+ return fn (line , pattern , replacement , matches )
215
+ return line
192
216
193
217
194
- def regex_replace_particle (all_lines , pattern , replacement , matches ):
218
+ def regex_replace_particle (line , pattern , replacement , matches ):
195
219
# matches == [(4, "foo", "bar"), (2, "baz", "bee")]
196
220
new = [item for tup in matches for item in tup ]
197
221
# new == [4, "foo", "bar", 2, "baz", "bee"]
@@ -201,46 +225,46 @@ def regex_replace_particle(all_lines, pattern, replacement, matches):
201
225
new [1 ::3 ], new [2 ::3 ], new [0 ::3 ]
202
226
203
227
# new == ["foo", "bar", 4, "baz", "bee", 2]
204
- return re .sub (pattern , replacement , all_lines ).format (* new )
228
+ return re .sub (pattern , replacement , line ).format (* new )
205
229
206
230
207
- def regex_replace_sound_priority (all_lines , pattern , replacement , matches ):
231
+ def regex_replace_sound_priority (line , pattern , replacement , matches ):
208
232
# TODO: This pattern returns two items in each tuple, while we only need the first. Create a better pattern.
209
233
# https://stackoverflow.com/a/406408/13279557
210
234
# https://regex101.com/r/NdKaWs/2
211
235
212
236
# matches == [(4, "foo"), (2, "bar")]
213
237
new = [item for tup in matches for item in tup ][::2 ]
214
238
# new == [4, 2]
215
- return re .sub (pattern , replacement , all_lines , flags = re .DOTALL ).format (* new )
239
+ return re .sub (pattern , replacement , line , flags = re .DOTALL ).format (* new )
216
240
217
241
218
- def regex_use_capture (all_lines , pattern , replacement , matches ):
219
- return re .sub (pattern , replacement , all_lines ).format (* matches )
242
+ def regex_use_capture (line , pattern , replacement , matches ):
243
+ return re .sub (pattern , replacement , line ).format (* matches )
220
244
221
245
222
- # def regex_replace_playsound(all_lines , pattern, replacement, matches):
223
- # return all_lines
246
+ # def regex_replace_playsound(line , pattern, replacement, matches):
247
+ # return line
224
248
# # TODO:
225
249
# # AudioMan:PlaySound("ModName.rte/Folder/SoundName.wav", SceneMan:TargetDistanceScalar(self.Pos), false, true, -1)
226
250
# # to
227
251
# # AudioMan:PlaySound("ModName.rte/Folder/SoundName.wav", self.Pos) -- Cut everything and leave the thing inside the brackets after SceneMan:TargetDistanceScalar
228
252
229
253
230
- def regex_replace_bmps_and_wavs (all_lines ):
231
- all_lines = specific_replace (all_lines , regex_use_capture , False , "Base\.rte(.*?)\.bmp" , "Base.rte{}.png" )
232
- all_lines = specific_replace (all_lines , regex_use_capture , False , "base\.rte(.*?)\.bmp" , "Base.rte{}.png" )
233
- all_lines = specific_replace (all_lines , regex_use_capture , False , "Base\.rte(.*?)\.wav" , "Base.rte{}.flac" )
234
- all_lines = specific_replace (all_lines , regex_use_capture , False , "base\.rte(.*?)\.wav" , "Base.rte{}.flac" )
235
- return all_lines
254
+ def regex_replace_bmps_and_wavs (line ):
255
+ line = specific_replace (line , regex_use_capture , False , "Base\.rte(.*?)\.bmp" , "Base.rte{}.png" )
256
+ line = specific_replace (line , regex_use_capture , False , "base\.rte(.*?)\.bmp" , "Base.rte{}.png" )
257
+ line = specific_replace (line , regex_use_capture , False , "Base\.rte(.*?)\.wav" , "Base.rte{}.flac" )
258
+ line = specific_replace (line , regex_use_capture , False , "base\.rte(.*?)\.wav" , "Base.rte{}.flac" )
259
+ return line
236
260
237
261
238
- def create_zips (input_folder , output_folder ):
239
- if input_folder .endswith (".rte" ):
240
- create_single_zip (Path (input_folder ).name , output_folder )
262
+ def create_zips (input_folder_path , output_folder ):
263
+ if input_folder_path .endswith (".rte" ):
264
+ create_single_zip (Path (input_folder_path ).name , output_folder )
241
265
else :
242
266
# TODO: Move check if it's a directory out of this loop.
243
- folder_names = [f for f in os .listdir (cfg . sg . user_settings_get_entry ( "input_folder" ) ) if os .path .isdir (os .path .join (output_folder , f ))]
267
+ folder_names = [f for f in os .listdir (input_folder_path ) if os .path .isdir (os .path .join (output_folder , f ))]
244
268
for mod_name in folder_names :
245
269
create_single_zip (mod_name , output_folder )
246
270
@@ -253,5 +277,12 @@ def create_single_zip(mod_name, output_folder):
253
277
update_progress ()
254
278
255
279
280
+ def warnings_popup ():
281
+ if warnings_available :
282
+ w = max (30 , len (max (warnings , key = len )))
283
+ h = min (50 , len (warnings )) + 1 # + 1 necessary because popup_scrolled adds an extra line
284
+ cfg .sg .popup_scrolled ("\n " .join (warnings ), title = "Lines needing manual replacing" , size = (w , h ), button_color = cfg .sg .theme_button_color (), background_color = cfg .sg .theme_background_color ())
285
+
286
+
256
287
def pluralize (word , count ):
257
288
return word + "s" if count != 1 else word
0 commit comments