pyscreeps-arena 0.3.0__py3-none-any.whl → 0.5.7b0__py3-none-any.whl

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.
@@ -2,11 +2,12 @@ import os
2
2
  import sys
3
3
  import shutil
4
4
  import py7zr
5
-
5
+ from pyscreeps_arena.core import const, config
6
6
  def CMD_NewProject():
7
7
  """
8
8
  cmd:
9
9
  pyscreeps-arena [project_path]
10
+ arena [project_path]
10
11
 
11
12
  * 复制"src" "game" "build.py" 到指定目录
12
13
 
@@ -14,7 +15,7 @@ def CMD_NewProject():
14
15
 
15
16
  """
16
17
  if len(sys.argv) < 2:
17
- print("Usage: pyarena new [project_path]")
18
+ print("Usage: pyarena new [project_path]\n# or\narena new [project_path]")
18
19
  return
19
20
  project_path = sys.argv[1]
20
21
  if not os.path.exists(project_path):
@@ -23,9 +24,33 @@ def CMD_NewProject():
23
24
  extract_7z(os.path.join(this_path, 'project.7z'), project_path)
24
25
  print("Project created at", project_path)
25
26
 
27
+ def CMD_OpenUI():
28
+ """
29
+ cmd:
30
+ psaui
31
+
32
+ * 打开UI界面
33
+
34
+ Returns:
35
+
36
+ """
37
+ try:
38
+ # 检查是否带 -c
39
+ if len(sys.argv) > 1 and sys.argv[1] == '-c':
40
+ from pyscreeps_arena.ui.creeplogic_edit import run_creeplogic_edit
41
+ run_creeplogic_edit()
42
+ else:
43
+ from pyscreeps_arena.ui.project_ui import run_project_creator
44
+ run_project_creator()
45
+ except ImportError as e:
46
+ print(f"错误: 无法导入UI模块 - {e}")
47
+ print("请确保已安装PyQt6: pip install PyQt6")
48
+ except Exception as e:
49
+ print(f"错误: 打开UI界面失败 - {e}")
26
50
 
27
51
  def extract_7z(file_path, output_dir):
28
52
  with py7zr.SevenZipFile(file_path, mode='r') as archive:
29
53
  archive.extractall(path=output_dir)
30
54
 
31
-
55
+ if __name__ == '__main__':
56
+ CMD_OpenUI()
pyscreeps_arena/build.py CHANGED
@@ -1,619 +1,7 @@
1
- import os
2
- import re
3
- import sys
4
- import shutil
5
- import subprocess
6
- import pyperclip
7
- from colorama import Fore
8
-
9
- version_info = sys.version_info
10
- python_version = f"Compiler py-version: {version_info.major}.{version_info.minor}.{version_info.micro}"
11
-
12
- class Compiler:
13
- libs = ["game"]
14
- FILE_STRONG_REPLACE = {
15
- "std": {
16
- "==": "===",
17
- "!=": "!==",
18
- }
19
- }
20
- PYFILE_IGNORE_CHECK_FNAMES = ['game/const.py', 'game/proto.py', 'game/utils.py', 'game/const.py']
21
-
22
- PYFILE_WORD_WARNING_CHECK = {
23
- r"\.\s*get\s*\(": "Please use 'dict.py_get'. (add '# > ignore' same line to ignore it if you sure right).",
24
- r"\.\s*clear\s*\(": "Please use 'container.py_clear'. (add '# > ignore' same line to ignore it if you sure right).",
25
- r"\[\s*-\s*1\s*\]": "Index by '[-1]' may not work in js. (add '# > ignore' same line to ignore it if you sure right).",
26
- }
27
-
28
- PYFILE_EXIST_WARNING_CHECK = {
29
- r"__pragma__\s*\(\s*['\"]noalias['\"]\s*,\s*['\"]undefined['\"]\s*\)": "Strongly suggest to add '__pragma__('noalias', 'undefined')'.",
30
- r"__pragma__\s*\(\s*['\"]noalias['\"]\s*,\s*['\"]Infinity['\"]\s*\)": "Strongly suggest to add '__pragma__('noalias', 'Infinity')'.",
31
- r"__pragma__\s*\(\s*['\"]noalias['\"]\s*,\s*['\"]clear['\"]\s*\)": "Strongly suggest to add '__pragma__('noalias', 'clear')'.",
32
- r"__pragma__\s*\(\s*['\"]noalias['\"]\s*,\s*['\"]get['\"]\s*\)": "Strongly suggest to add '__pragma__('noalias', 'get')'.",
33
- }
34
-
35
- JS_VM = "org.transcrypt.__runtime__.js"
36
-
37
- GAME_UTILS = './game.utils.js'
38
- GAME_PROTO = './game.proto.js'
39
- GAME_CONST = './game.const.js'
40
-
41
- SYSTEM_MODULES_IGNORE = {
42
- GAME_UTILS: ['CircleVisualStyle', 'Color', 'CostMatrix', 'CreateConstructionSiteResult', 'Direction', 'DoesZapCodeSpaceFlag',
43
- 'FindPathOptions', 'Goal', 'HeapInfo',
44
- 'LineStyle', 'LineVisualStyle', 'PolyVisualStyle', 'RectVisualStyle', 'SearchPathOptions', 'SearchPathResult', 'Terrain',
45
- 'TextAlign', 'TextVisualStyle',
46
- 'Visual', 'getAt', 'searchPath'],
47
- GAME_PROTO: ['BodyPartType', 'CreepAttackResult', 'CreepBuildResult', 'CreepDropResult', 'CreepHarvestResult', 'CreepHealResult',
48
- 'CreepMoveResult', 'CreepPickupResult',
49
- 'CreepPullResult', 'CreepRangedAttackResult', 'CreepRangedHealResult', 'CreepRangedMassAttackResult',
50
- 'CreepTransferResult', 'CreepWithdrawResult',
51
- 'ResourceType', 'SpawnCreepResult', 'Store', 'TowerAttackResult', 'TowerHealResult', 'Spawning', 'ScoreController',
52
- 'Flag'],
53
- GAME_CONST: ['RESOURCE_SCORE'],
54
- }
55
- SYSTEM_MODULES_TRANSNAME = {
56
- GAME_UTILS: "game/utils",
57
- GAME_PROTO: "game/prototypes",
58
- GAME_CONST: "game/constants",
59
- }
60
- GENERATE_IGNORE_PYFILES = ['config.py'] # Won't be compiled into the final js code, only for defines.
61
-
62
- JS_IMPORT_PAT = re.compile(r'from\s+[\'\"]([^\']+)[\'\"]')
63
- INSERT_PAT = re.compile(r'#\s*insert\s+([^\n]*)') # 因为被判定的string为单line,所以不需要考虑多行的情况
64
-
65
- TRANSCRYPT_ERROR_REPLACE = {
66
- # 由于transcrypt的问题,导致编译后的js代码中存在一些错误,需要进行替换
67
- r"new\s+set\s*\(": r"set(",
68
- }
69
-
70
- def __init__(self, src_dir, build_dir):
71
- # check
72
- if not os.path.exists(src_dir):
73
- print(Fore.RED + '[Error] ' + Fore.RESET + 'src dir not exists')
74
- sys.exit(1)
75
-
76
- self.src_dir = os.path.abspath(src_dir)
77
- self.build_dir = os.path.abspath(build_dir)
78
- self.target_dir = os.path.join(self.build_dir, '__target__')
79
-
80
- last_output = False
81
- @staticmethod
82
- def auto_read(fpath):
83
- """
84
- 自动用多种编码读取文件
85
-
86
- Args:
87
- fpath:
88
-
89
- Returns:
90
-
91
- """
92
- if not os.path.exists(fpath):
93
- if not Compiler.last_output:
94
- Compiler.last_output = True
95
- print()
96
- print(Fore.YELLOW + '[CriticWarn] ' + Fore.RESET + f"JS file not exists: {fpath}. You can ignore if it's a not used file")
97
- return ""
98
- try:
99
- with open(fpath, 'r', encoding='utf-8') as f:
100
- return f.read()
101
- except UnicodeDecodeError:
102
- with open(fpath, 'r', encoding='gbk') as f:
103
- return f.read()
104
-
105
- def copy_to(self):
106
- # copy to build dir
107
- print(Fore.YELLOW + '>>> ' + Fore.RESET + ' copying to build dir: %s ...' % self.build_dir, end='')
108
- if os.path.exists(self.build_dir):
109
- shutil.rmtree(self.build_dir)
110
- shutil.copytree(self.src_dir, self.build_dir)
111
- # add libs
112
- for lib in self.libs:
113
- shutil.copytree(lib, os.path.join(self.build_dir, lib))
114
-
115
- # overwrite last to [Done]
116
- print(Fore.GREEN + '\r[1/6][Done]' + Fore.RESET + ' copying to build dir: %s' % self.build_dir)
117
-
118
- @property
119
- def target_py(self):
120
- return os.path.join(self.build_dir, 'main.py')
121
-
122
- @property
123
- def target_js(self):
124
- return os.path.join(self.target_dir, 'main.js')
125
-
126
- @staticmethod
127
- def preprocess_if_block(source_code, variables):
128
- lines = source_code.split('\n')
129
- stack = []
130
- result = []
131
-
132
- for i, line in enumerate(lines):
133
- striped = line.strip()
134
- if_match = re.match(r'#\s*>\s*if\s+([^:.]*)$', striped)
135
- elif_match = re.match(r'#\s*>\s*elif\s+([^:.]*)$', striped)
136
- else_match = re.match(r'#\s*>\s*else$', striped)
137
- endif_match = re.match(r'#\s*>\s*endif$', striped)
138
-
139
- if if_match:
140
- condition = if_match.group(1)
141
- stack.append(eval(condition, variables))
142
- elif elif_match and len(stack) > 0:
143
- condition = elif_match.group(1)
144
- stack[-1] = eval(condition, variables)
145
- elif else_match and len(stack) > 0:
146
- stack[-1] = not stack[-1]
147
- elif endif_match:
148
- stack.pop()
149
- else:
150
- if len(stack) == 0 or all(stack):
151
- result.append(line)
152
-
153
- return '\n'.join(result)
154
-
155
- @staticmethod
156
- def pyfile_warn_check(fpath, fname) -> bool:
157
- """
158
- 检查某个py文件内是否有警告
159
-
160
- 如果有的话,输出[Warn][{file_name}/{line_io}]{detail}
161
-
162
- Returns:
163
- bool: 是否有警告
164
- """
165
- # 文件路径检查
166
- if fpath.endswith('__init__.py'):
167
- print(Fore.RED + '\n[Error] ' + Fore.RESET + f'Not support __init__.py! Please remove it(the init file) and use from directory.xxx.py import xxxx instead.')
168
- sys.exit(-1)
169
- if fname in Compiler.PYFILE_IGNORE_CHECK_FNAMES:
170
- return False
171
-
172
- # # 文件内容检查
173
- content = Compiler.auto_read(fpath)
174
- warn_flag = False
175
- # 内容存在性检查
176
- for pat, detail in Compiler.PYFILE_EXIST_WARNING_CHECK.items():
177
- if not re.search(pat, content):
178
- warn_flag = True
179
- print(Fore.YELLOW + f'\n[Warn]' + Fore.RESET + f'[{fname}]: {detail}', end='')
180
- # 内容关键字检查
181
- for pat, detail in Compiler.PYFILE_WORD_WARNING_CHECK.items():
182
- for i, line in enumerate(content.split('\n')):
183
- m = re.search(pat, line)
184
- if m:
185
- # 检查m前面同一行内是否有#,如果有则忽略
186
- comment = re.search(r'#', line[:m.start()])
187
-
188
- # 检查m后面同一行内是否有#\s*ignore;,如果有则忽略
189
- ignore = re.search(r'#\s*>\s*ignore', line[m.end():])
190
-
191
- if not comment and not ignore:
192
- warn_flag = True
193
- print(Fore.YELLOW + f'\n[Warn]' + Fore.RESET + f'[{fname}/line:{i + 1}]: {detail}', end='')
194
- return warn_flag
195
-
196
- def pre_compile(self):
197
- self.copy_to()
198
-
199
- print(Fore.YELLOW + '>>> ' + Fore.RESET + 'preprocessing ...', end='')
200
- py_fpath, py_names, warn_flag = [], [], False
201
- for root, dirs, files in os.walk(self.build_dir):
202
- for file in files:
203
- if file.endswith('.py'):
204
- fpath: str = str(os.path.join(root, file))
205
- # 得到src目录后面的内容
206
- rel_name = os.path.relpath(fpath, self.build_dir).replace('\\', '/')
207
- py_names.append(rel_name.replace('/', '.'))
208
- py_fpath.append(fpath)
209
- warn_flag |= self.pyfile_warn_check(fpath, rel_name)
210
- if warn_flag:
211
- print() # 换行
212
-
213
- _pre_import_, _pre_imp_detail_ = [], {} # import
214
- _pre_sort_ = {} # sort
215
- _pre_define_ = {} # define
216
- _js_replace_, _insert_id_ = {}, 0 # insert
217
-
218
- # ----------------------------------- IMPORT ----------------------------------- #
219
- # 获取所有.py文件中的所有import的内容,并记录下来fname:[imp1, imp2, ...]
220
- for i, fpath in enumerate(py_fpath):
221
- fname = py_names[i][:-3] + '.js'
222
- content = self.auto_read(fpath)
223
- for i, line in enumerate(content.split('\n')):
224
- m = re.search(r'#\s*>\s*import\s+([^\n]+)', line)
225
- if m:
226
- _pre_import_.append('./' + re.sub(r'\s', '', m.group(1)) + '.js')
227
- # 记录文件/lineio信息
228
- _pre_imp_detail_[_pre_import_[-1]] = f'{fname}/line:{i + 1}'
229
-
230
- # ----------------------------------- REMOVE ----------------------------------- #
231
- # 移除所有# > remove所在行的内容
232
- for fpath in py_fpath:
233
- content = self.auto_read(fpath)
234
- new_content = ""
235
- for line in content.split('\n'):
236
- if not re.search(r'#\s*>\s*remove', line):
237
- new_content += line + '\n'
238
-
239
- with open(fpath, 'w', encoding='utf-8') as f:
240
- f.write(new_content)
241
-
242
- # ------------------------------------ SORT ------------------------------------ #
243
- # 获取所有.py文件中的所有# sort的内容,并记录下来(不存在则默认为2^32-1)
244
- for i, fpath in enumerate(py_fpath):
245
- fname = py_names[i][:-3] + '.js'
246
- content = self.auto_read(fpath)
247
- m = re.search(r'#\s*>\s*sort\s+(\d+)', content)
248
- if m:
249
- try:
250
- sort_num = int(m.group(1))
251
- except ValueError:
252
- print(Fore.YELLOW + '[Warn] ' + Fore.RESET + f'sort number error: "{m.group(1)}", use 2^32-1 instead.')
253
- sort_num = 4294967295
254
- _pre_sort_[fname] = sort_num
255
- else:
256
- _pre_sort_[fname] = 4294967295
257
-
258
- # ------------------------------------ DEFINE ------------------------------------ #
259
- # 扫描所有# define的内容,然后在.py中移除这些行,并记录下来
260
- for fpath in py_fpath:
261
- content = self.auto_read(fpath)
262
- new_content = ""
263
- for line in content.split('\n'):
264
- # re.compile(r'#\s*define\s+([^\s]+)\s+([^\n]*)')
265
- m = re.search(r'#\s*>\s*define\s+([^\s]+)\s+([^\n]*)', line)
266
- if m:
267
- _pre_define_[m.group(1)] = m.group(2)
268
- new_content += '\n'
269
- else:
270
- new_content += line + '\n'
271
-
272
- with open(fpath, 'w', encoding='utf-8') as f:
273
- f.write(new_content)
274
-
275
- # 按照keys的顺序,先用前面的key对应的内容去依次替换后面的key对应的value中
276
- _def_keys = list(_pre_define_.keys())
277
- _keys_len = len(_def_keys)
278
- for i in range(_keys_len - 1):
279
- for j in range(i + 1, _keys_len):
280
- _pre_define_[_def_keys[j]] = _pre_define_[_def_keys[j]].replace(_def_keys[i], _pre_define_[_def_keys[i]])
281
-
282
- # ------------------------------------ DEFINE:REPLACE ------------------------------------ #
283
- # 将刚才记录的define替换到.py中(注意优先替换更长的串)(因此先排序)
284
- _def_keys.sort(key=lambda x: len(x), reverse=True)
285
- for fpath in py_fpath:
286
- content = self.auto_read(fpath)
287
-
288
- # std.py PYSCREEPS_ARENA_PYTHON_VERSION replace
289
- if os.path.basename(fpath).lower() == 'std.py':
290
- content = content.replace('PYSCREEPS_ARENA_PYTHON_VERSION', f'\"{python_version}\"')
291
-
292
- for key in _def_keys:
293
- content = re.sub(r'[^_A-Za-z0-9]' + key, self._kfc_wrapper(_pre_define_[key]), content)
294
-
295
- with open(fpath, 'w', encoding='utf-8') as f:
296
- f.write(content)
297
-
298
- # ------------------------------------ IF BLOCK ------------------------------------ #
299
- for fpath in py_fpath:
300
- content = self.auto_read(fpath)
301
-
302
- content = self.preprocess_if_block(content, _pre_define_)
303
-
304
- with open(fpath, 'w', encoding='utf-8') as f:
305
- f.write(content)
306
-
307
- # ------------------------------------ INSERT ------------------------------------ #
308
- # 扫描所有# insert的内容,然后在.py中将整行替换为# __pragma__("js", __JS_INSERT_{id})
309
- for fpath in py_fpath:
310
- content = self.auto_read(fpath)
311
- new_content = ""
312
- for line in content.split('\n'):
313
- # re.compile(r'#\s*insert\s*([^\n]*)')
314
- # '# insert if(obj && obj.body) for(var p of obj.body) if (p.type == MOVE) return true;'
315
- m = re.search(r'#\s*>\s*insert\s+([^\n]*)', line)
316
- if m:
317
- _sign_index_ = line.find('#') # 必然存在
318
- _js_key_ = f"__JS_INSERT_{_insert_id_:08d}"
319
- _js_replace_[_js_key_] = m.group(1)
320
-
321
- new_content += line[:_sign_index_] + f'# __pragma__("js", "{_js_key_}")\n'
322
- _insert_id_ += 1
323
- else:
324
- new_content += line + '\n'
325
-
326
- with open(fpath, 'w', encoding='utf-8') as f:
327
- f.write(new_content)
328
-
329
- print(Fore.GREEN + '\r[2/6][Done] ' + Fore.RESET + 'preprocess finish.')
330
-
331
- return _pre_import_, _pre_imp_detail_, _pre_sort_, _pre_define_, _js_replace_
332
-
333
- def clear_not_generate_pyfile(self):
334
- """
335
- 清空不需要编译的py文件
336
- :return:
337
- """
338
- for root, dirs, files in os.walk(self.build_dir):
339
- for file in files:
340
- if file.endswith('.py') and file in self.GENERATE_IGNORE_PYFILES:
341
- with open(os.path.join(root, file), 'w', encoding='utf-8') as f:
342
- f.write('')
343
-
344
- def transcrypt_cmd(self):
345
- # 执行cmd命令: transcrypt -b -m -n -s -e 6 target
346
- # 并获取cmd得到的输出
347
- cmd = 'transcrypt -b -m -n -s -e 6 %s' % self.target_py
348
- print(Fore.YELLOW + '>>> ' + Fore.RESET + f'"{cmd}" compiling ...', end='')
349
- p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
350
- stdout, stderr = p.communicate()
351
- if 'Error while compiling' in stdout.decode():
352
- print('\r' + stdout.decode())
353
- print(Fore.RED + '[Error] ' + Fore.RESET + 'transcrypt compile error')
354
- sys.exit(1)
355
- print('\r' + Fore.GREEN + '[3/6][Done] ' + Fore.RESET + f'"{cmd}" Ready.')
356
-
357
- @staticmethod
358
- def _keep_lbracket(matched) -> str:
359
- """
360
- 如果第一个字符是{, 则返回'{',否则返回''
361
- :param matched:
362
- :return:
363
- """
364
- return '{' if matched.group(0)[0] == '{' else ''
365
-
366
- @staticmethod
367
- def _keep_first_char(matched) -> str:
368
- """
369
- 保留第一个字符
370
- :param matched:
371
- :return:
372
- """
373
- return matched.group(0)[0]
374
-
375
- @staticmethod
376
- def _kfc_wrapper(replace):
377
- """
378
- 保留第一个字符
379
- :param replace:
380
- :return:
381
- """
382
-
383
- def _kfc(matched) -> str:
384
- return matched.group(0)[0] + replace
385
-
386
- return _kfc
387
-
388
- def analyze_rebuild_main_js(self, defs):
389
- """
390
- 分析main.js中导入的模块名称和先后顺序, 并重新生成main.js
391
- * 主要移除非SYSTEM_MODULES_IGNORE中的模块导入语句
392
- :param defs: dict{define: value}
393
- :return: imports : str, modules (names: str)
394
- """
395
-
396
- # create undefined
397
- imports = ""
398
-
399
- if defs.get('USE_TUTORIAL_FLAG', '0') == '0' and defs.get('USE_ARENA_FLAG', '0') == '0':
400
- imports += 'var Flag = undefined;\n'
401
- if defs.get('USE_SCORE_COLLECTOR', '0') == '0':
402
- imports += 'var ScoreController = undefined;\nvar RESOURCE_SCORE = undefined;\n'
403
- imports += '\n'
404
-
405
- print(Fore.YELLOW + '>>> ' + Fore.RESET + 'analyzing and rebuilding main.js ...', end='')
406
-
407
- content = self.auto_read(self.target_js)
408
- modules, new_content = [], ""
409
- for line in content.split('\n'):
410
- m = re.search(self.JS_IMPORT_PAT, line)
411
- if not m:
412
- new_content += line + '\n'
413
- continue
414
- # remove ignore if in SYSTEM_MODULES_IGNORE
415
- module = m.group(1)
416
- for ignore in self.SYSTEM_MODULES_IGNORE.get(module, []):
417
- line = re.sub(r'[\s{]' + ignore + ',?', self._keep_lbracket, line)
418
-
419
- # do not add in modules if in system_modules_ignores
420
- if module in self.SYSTEM_MODULES_IGNORE:
421
- if module in self.SYSTEM_MODULES_TRANSNAME:
422
- line = line.replace(module, self.SYSTEM_MODULES_TRANSNAME[module]) # 调整为js中的名称
423
- imports += line + '\n'
424
- continue
425
- if module not in modules:
426
- modules.append(module)
427
-
428
- # save raw main.js
429
- with open(self.target_js[:-3] + ".raw.js", 'w', encoding='utf-8') as f:
430
- f.write(content)
431
-
432
- # write rebuild main.js
433
- with open(self.target_js, 'w', encoding='utf-8') as f:
434
- f.write(new_content)
435
-
436
- print(Fore.GREEN + '\r[4/6][Done] ' + Fore.RESET + 'analyze and rebuild main.js successfully.')
437
-
438
- return imports, modules
439
-
440
- @staticmethod
441
- def remove_js_import(raw) -> str:
442
- """
443
- 移除js中的import行
444
- :param raw:
445
- :return:
446
- """
447
- return re.sub(r'import[^\n]*\n', '', raw)
448
-
449
- def generate_total_js(self, usr_modules, t_imps: dict, f_sorts, f_replaces, g_replaces) -> str:
450
- """
451
- 生成总的main.js
452
- 按照如下顺序组合:
453
- ./org.transcrypt.__runtime__.js
454
- ./game.const.js # IGNORE
455
- ./game.proto.js # IGNORE
456
- ./game.utils.js # IGNORE
457
- {usr_modules}
458
- :param usr_modules: list[str] # js vm + 用户自定义模块
459
- :param t_imps: dict{module_name: detail}
460
- :param f_sorts: dict{module_name: sort_priority}
461
- :param f_replaces: dict{module_name: dict{old: new}}
462
- :param g_replaces: dict{old: new}
463
- :return: str
464
- """
465
- total_js = ""
466
-
467
- print(Fore.YELLOW + '>>> ' + Fore.RESET + 'generating total main.js ...', end='')
468
-
469
- # resort modules
470
- f_sorts[self.JS_VM] = -1
471
-
472
- err_flag = False
473
- for i, module in enumerate(usr_modules):
474
- if module[2:] not in f_sorts:
475
- if module[2:6] == 'src.' and module[6:] in f_sorts:
476
- f_sorts[module[2:]] = f_sorts[module[6:]]
477
- # 为了解决这样的问题:
478
- # > import src.creeps.basic
479
- # import src.creeps.basic
480
- else:
481
- print(Fore.RED + '\n[Error] ' + Fore.RESET + f'"{module[2:-3]}.py" is not a user module.')
482
- imp_detail = t_imps.get(module, None)
483
- if imp_detail:
484
- print("\t\t-- May be imported by user in: %s" % imp_detail)
485
- else:
486
- print("\t\t-- Please move this file into the 'src' directory.")
487
- err_flag = True
488
- if err_flag:
489
- sys.exit(1)
490
- for i in range(len(usr_modules)):
491
- for j in range(i + 1, len(usr_modules)):
492
- if f_sorts[usr_modules[i][2:]] > f_sorts[usr_modules[j][2:]]:
493
- usr_modules[i], usr_modules[j] = usr_modules[j], usr_modules[i]
494
-
495
- # write modules
496
- for module in usr_modules:
497
- content = self.auto_read(os.path.join(self.target_dir, module))
498
- content = self.remove_js_import(content)
499
- for old, new in f_replaces.get(module, {}).items():
500
- content = re.sub(old, new, content)
501
- for old, new in self.TRANSCRYPT_ERROR_REPLACE.items():
502
- content = re.sub(old, new, content)
503
- total_js += f"\n// ---------------------------------------- Module:{module} "
504
- total_js += "----------------------------------------\n\n"
505
- total_js += content + '\n'
506
-
507
- # write main.js
508
- content = self.auto_read(self.target_js)
509
- for old, new in self.TRANSCRYPT_ERROR_REPLACE.items():
510
- content = re.sub(old, new, content)
511
- total_js += content
512
-
513
- # global replace
514
- for old, new in g_replaces.items():
515
- total_js = re.sub(old, new, total_js)
516
-
517
- print(Fore.GREEN + '\r[5/6][Done] ' + Fore.RESET + 'generate total main.js successfully.')
518
-
519
- return total_js
520
-
521
- def compile(self, export_to=None, paste=False):
522
- """
523
- 编译
524
- :param export_to: 指定main.mjs的输出路径(/main.mjs)
525
- :param paste: 是否复制到剪贴板
526
- :return:
527
- """
528
- imps, imp_ts, sorts, defs, reps = self.pre_compile()
529
- self.clear_not_generate_pyfile() # 清空不需要编译的py文件(请确保在pre_compile之后)
530
- self.transcrypt_cmd()
531
- imports, modules = self.analyze_rebuild_main_js(defs)
532
- total_js = imports + "\n" + self.generate_total_js(list(set(modules + imps)), imp_ts, sorts, self.FILE_STRONG_REPLACE, reps)
533
-
534
- print(Fore.YELLOW + '>>> ' + Fore.RESET + 'exporting total main.js ...', end='')
535
-
536
- # ensure exported main.mjs path
537
- build_main_mjs = os.path.join(self.build_dir, 'main.mjs')
538
-
539
- if not export_to:
540
- # 尝试读取defs
541
- mjs_path = defs.get('MAIN_JS_PATH', build_main_mjs)
542
- else:
543
- mjs_path = export_to
544
-
545
- if not mjs_path.endswith('js'):
546
- mjs_path = os.path.join(mjs_path, 'main.mjs')
547
-
548
- # write main.mjs
549
- with open(build_main_mjs, 'w', encoding='utf-8') as f:
550
- f.write(total_js)
551
-
552
- # export main.mjs
553
- dir_path = os.path.dirname(mjs_path)
554
- if not os.path.exists(dir_path):
555
- print(Fore.RED + '\n[Error] ' + Fore.RESET + f'export dir path not exists: {dir_path}')
556
- sys.exit(1)
557
- with open(mjs_path, 'w', encoding='utf-8') as f:
558
- f.write(total_js)
559
-
560
- print(Fore.GREEN + '\r[6/6][Done] ' + Fore.RESET + 'export total main.js successfully.')
561
-
562
- if mjs_path != build_main_mjs:
563
- print(Fore.LIGHTBLUE_EX + '[Info] ' + Fore.RESET + f'usr export to {mjs_path}')
564
-
565
- # copy to clipboard
566
- if paste:
567
- pyperclip.copy(total_js)
568
- print(Fore.GREEN + '[Done] ' + Fore.RESET + 'copy to clipboard')
569
-
570
- def clean(self):
571
- """
572
- 清除build目录下除了main.mjs之外的所有文件和目录
573
- * 先复制main.mjs到src目录下,然后删除build目录,再将main.mjs剪切回build目录
574
- :return:
575
- """
576
- print(Fore.YELLOW + '>>> ' + Fore.RESET + 'clean build dir ...', end='')
577
- if not os.path.exists(self.build_dir):
578
- print(Fore.RED + '\r[Error] ' + Fore.RESET + 'build dir not exists')
579
- return
580
-
581
- if not os.path.exists(os.path.join(self.build_dir, 'main.mjs')):
582
- print(Fore.RED + '\r[Error] ' + Fore.RESET + 'main.mjs not exists')
583
- return
584
-
585
- # copy main.mjs to src
586
- shutil.copy(os.path.join(self.build_dir, 'main.mjs'), os.path.join(self.src_dir, 'main.mjs'))
587
-
588
- # remove build dir
589
- shutil.rmtree(self.build_dir)
590
-
591
- # create build dir
592
- os.makedirs(self.build_dir)
593
-
594
- # move main.mjs to build dir
595
- shutil.move(os.path.join(self.src_dir, 'main.mjs'), os.path.join(self.build_dir, 'main.mjs'))
596
-
597
- print(Fore.GREEN + '\r[Done] ' + Fore.RESET + 'clean build dir')
598
-
599
- def clear(self):
600
- """
601
- 清除build目录下所有文件和目录
602
- :return:
603
- """
604
- print(Fore.YELLOW + '>>> ' + Fore.RESET + 'clear build dir ...', end='')
605
- if not os.path.exists(self.build_dir):
606
- print(Fore.RED + '\r[Error] ' + Fore.RESET + 'build dir not exists')
607
- return
608
-
609
- shutil.rmtree(self.build_dir)
610
- os.makedirs(self.build_dir)
611
-
612
- print(Fore.GREEN + '\r[Done] ' + Fore.RESET + 'clear build dir')
613
-
1
+ from pyscreeps_arena.compiler import Compiler
614
2
 
615
3
  if __name__ == '__main__':
616
- compiler = Compiler('src', 'build')
4
+ compiler = Compiler('src', 'library', 'build')
617
5
 
618
6
  compiler.compile()
619
- compiler.clean()
7
+ # compiler.clean()