pyscreeps-arena 0.5.9.0__tar.gz → 0.5.9a0__tar.gz
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.
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/PKG-INFO +1 -1
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/compiler.py +17 -110
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/core/const.py +1 -1
- pyscreeps_arena-0.5.9a0/pyscreeps_arena/project.7z +0 -0
- pyscreeps_arena-0.5.9a0/pyscreeps_arena/ui/project_ui.py +328 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena.egg-info/PKG-INFO +1 -1
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/setup.py +1 -1
- pyscreeps_arena-0.5.9.0/pyscreeps_arena/project.7z +0 -0
- pyscreeps_arena-0.5.9.0/pyscreeps_arena/ui/project_ui.py +0 -948
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/__init__.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/afters/__init__.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/afters/after_config.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/afters/after_custom.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/afters/after_empty.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/afters/after_prefab.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/build.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/core/__init__.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/core/basic.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/core/config.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/core/core.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/core/main.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/core/utils.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/localization.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/P2PY.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/__init__.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/creeplogic_edit.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/map_render.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/mapviewer.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qcreeplogic/__init__.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qcreeplogic/model.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qcreeplogic/qcreeplogic.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapker/__init__.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapker/qmapmarker.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapker/qvariable.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapker/test_compact_variable.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapker/test_qmapmarker.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapker/test_qvariable.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapker/to_code.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapv/__init__.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapv/qcinfo.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapv/qco.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapv/qmapv.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapv/test_array_drag.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapv/test_drag.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapv/test_qcinfo.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapv/test_qco_drag.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapv/test_qmapv.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qmapv/test_simple_array.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qrecipe/__init__.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qrecipe/model.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/qrecipe/qrecipe.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena/ui/rs_icon.py +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena.egg-info/SOURCES.txt +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena.egg-info/dependency_links.txt +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena.egg-info/entry_points.txt +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena.egg-info/requires.txt +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/pyscreeps_arena.egg-info/top_level.txt +0 -0
- {pyscreeps_arena-0.5.9.0 → pyscreeps_arena-0.5.9a0}/setup.cfg +0 -0
|
@@ -8,7 +8,6 @@ import shutil
|
|
|
8
8
|
import chardet
|
|
9
9
|
import subprocess
|
|
10
10
|
import pyperclip
|
|
11
|
-
import datetime
|
|
12
11
|
from colorama import Fore
|
|
13
12
|
from typing import List, Optional, Tuple, Union
|
|
14
13
|
|
|
@@ -53,7 +52,6 @@ def replace_src_prefix(file_list):
|
|
|
53
52
|
# """
|
|
54
53
|
# return PYFILE_PRAGMA_INSERTS + "\n" + content
|
|
55
54
|
class Compiler_Const:
|
|
56
|
-
CALLED_FUNCTIONS = ['behavior', 'sequence', 'selector', 'parallel', 'listen']
|
|
57
55
|
PROTO_DEFINES_DIRS = ["builtin", "library"]
|
|
58
56
|
FILE_STRONG_REPLACE = {
|
|
59
57
|
"std": {
|
|
@@ -110,14 +108,14 @@ export var loop = function () {
|
|
|
110
108
|
if (know.now === 1) {
|
|
111
109
|
std.show_welcome();
|
|
112
110
|
init (know);
|
|
113
|
-
|
|
111
|
+
|
|
114
112
|
}
|
|
115
113
|
step (know);
|
|
116
114
|
timeLine = get.cpu_us();
|
|
117
115
|
if (get._SCH_FLAG) sch.handle();
|
|
118
116
|
stepCost = get.cpu_us() - timeLine;
|
|
119
117
|
std.show_usage ();
|
|
120
|
-
|
|
118
|
+
print("knowCost:", knowCost, "monitorCost:", monitorCost, "stepCost:", stepCost);
|
|
121
119
|
if (know.draw) know.draw();
|
|
122
120
|
};
|
|
123
121
|
"""
|
|
@@ -650,82 +648,6 @@ class Compiler_Utils(Compiler_Const):
|
|
|
650
648
|
|
|
651
649
|
return result
|
|
652
650
|
|
|
653
|
-
@staticmethod
|
|
654
|
-
def stage_called_replace(caller_name: str, content: str) -> str:
|
|
655
|
-
"""
|
|
656
|
-
移除 '@<caller_name>(...)' 装饰器行,并在文末添加对应的 _<caller_name>Login 调用。
|
|
657
|
-
|
|
658
|
-
对于类方法: _<caller_name>Login("ClassName", "method_name", a, b, ...)
|
|
659
|
-
对于普通函数: _<caller_name>Login("", "function_name", a, b, ...)
|
|
660
|
-
"""
|
|
661
|
-
calls_to_add = []
|
|
662
|
-
deletions = []
|
|
663
|
-
|
|
664
|
-
# 1. 收集所有类定义的位置和缩进
|
|
665
|
-
class_pattern = re.compile(r'^(\s*)class\s+(\w+)', re.MULTILINE)
|
|
666
|
-
classes = [(m.start(), len(m.group(1)), m.group(2))
|
|
667
|
-
for m in class_pattern.finditer(content)]
|
|
668
|
-
|
|
669
|
-
# 2. 查找所有 @<caller_name>(...) 装饰器(支持多行参数)
|
|
670
|
-
decorator_pattern = re.compile(
|
|
671
|
-
r'^\s*@\s*' + re.escape(caller_name) + r'\s*\((.*?)\)\s*$\n?',
|
|
672
|
-
re.MULTILINE | re.DOTALL
|
|
673
|
-
)
|
|
674
|
-
|
|
675
|
-
for dec_match in decorator_pattern.finditer(content):
|
|
676
|
-
dec_start = dec_match.start()
|
|
677
|
-
dec_end = dec_match.end()
|
|
678
|
-
# 提取装饰器的参数
|
|
679
|
-
params_str = dec_match.group(1).strip()
|
|
680
|
-
|
|
681
|
-
# 查找接下来的函数定义(跳过可能的空行)
|
|
682
|
-
after_decorator = content[dec_end:]
|
|
683
|
-
func_match = re.search(r'^(\s*)def\s+([^\s\(]+)', after_decorator, re.MULTILINE)
|
|
684
|
-
|
|
685
|
-
if not func_match:
|
|
686
|
-
continue
|
|
687
|
-
|
|
688
|
-
func_indent_len = len(func_match.group(1))
|
|
689
|
-
func_name = func_match.group(2)
|
|
690
|
-
|
|
691
|
-
# 3. 确定类名:查找装饰器前最近的、缩进小于函数缩进的类
|
|
692
|
-
class_name = ""
|
|
693
|
-
for cls_pos, cls_indent_len, cls_name in reversed(classes):
|
|
694
|
-
if cls_pos < dec_match.start() and func_indent_len > cls_indent_len:
|
|
695
|
-
class_name = cls_name
|
|
696
|
-
break
|
|
697
|
-
|
|
698
|
-
# 4. 处理参数,保持参数的格式
|
|
699
|
-
# 移除参数中的换行和多余空格,保持参数列表的格式
|
|
700
|
-
params = []
|
|
701
|
-
if params_str:
|
|
702
|
-
# 简单处理参数,保持引号内的内容不变
|
|
703
|
-
# 这里可以根据需要进行更复杂的参数解析
|
|
704
|
-
params = [p.strip() for p in params_str.split(',') if p.strip()]
|
|
705
|
-
|
|
706
|
-
# 构建参数部分的字符串
|
|
707
|
-
params_part = ""
|
|
708
|
-
if params:
|
|
709
|
-
params_part = ", " + ", ".join(params)
|
|
710
|
-
|
|
711
|
-
# 5. 记录删除位置和调用信息
|
|
712
|
-
deletions.append((dec_start, dec_end))
|
|
713
|
-
calls_to_add.append(f'_{caller_name}Login("{class_name}", "{func_name}"{params_part})')
|
|
714
|
-
|
|
715
|
-
# 6. 应用删除(倒序避免位置偏移)
|
|
716
|
-
if not deletions:
|
|
717
|
-
return content
|
|
718
|
-
|
|
719
|
-
result = content
|
|
720
|
-
for start, end in sorted(deletions, key=lambda x: x[0], reverse=True):
|
|
721
|
-
result = result[:start] + result[end:]
|
|
722
|
-
|
|
723
|
-
# 7. 在文末添加调用
|
|
724
|
-
if calls_to_add:
|
|
725
|
-
result = '\n'.join(calls_to_add) + '\n' + result
|
|
726
|
-
|
|
727
|
-
return result
|
|
728
|
-
|
|
729
651
|
@staticmethod
|
|
730
652
|
def process_mate_code(code):
|
|
731
653
|
# 用于存储匹配到的信息
|
|
@@ -999,8 +921,6 @@ class Compiler(CompilerBase):
|
|
|
999
921
|
|
|
1000
922
|
# 将PYFILE_PRAGMA_INSERTS.replace("\t", "").replace(" ", "")插入到文件开头
|
|
1001
923
|
content = self.auto_read(fpath)
|
|
1002
|
-
# 移除"""$..."""代码块
|
|
1003
|
-
content = re.sub(r'"""\$[\s\S]*?"""', '', content)
|
|
1004
924
|
content = self.PYFILE_PRAGMA_INSERTS.replace("\t", "").replace(" ", "") + content
|
|
1005
925
|
# content = self.remove_long_docstring(content) # 移除长注释 | remove long docstring
|
|
1006
926
|
|
|
@@ -1157,13 +1077,10 @@ class Compiler(CompilerBase):
|
|
|
1157
1077
|
with open(fpath, 'w', encoding='utf-8') as f:
|
|
1158
1078
|
f.write(new_content)
|
|
1159
1079
|
|
|
1160
|
-
# ------------------------------------ 自定义:调用stage_recursive_replace
|
|
1080
|
+
# ------------------------------------ 自定义:调用stage_recursive_replace ------------------------------------ #
|
|
1161
1081
|
for fpath in py_fpath:
|
|
1162
1082
|
content = self.auto_read(fpath)
|
|
1163
1083
|
content = self.stage_recursive_replace(content) # 调用stage_recursive_replace
|
|
1164
|
-
# 调用stage_called_replace处理四个装饰器
|
|
1165
|
-
for caller in self.CALLED_FUNCTIONS:
|
|
1166
|
-
content = self.stage_called_replace(caller, content)
|
|
1167
1084
|
with open(fpath, 'w', encoding='utf-8') as f:
|
|
1168
1085
|
f.write(content)
|
|
1169
1086
|
|
|
@@ -1300,22 +1217,12 @@ class Compiler(CompilerBase):
|
|
|
1300
1217
|
:param min_js_files: list[str] # .min.js文件路径列表
|
|
1301
1218
|
:return: str
|
|
1302
1219
|
"""
|
|
1303
|
-
arena_name = const.ARENA_NAMES.get(config.arena, const.ARENA_NAMES[
|
|
1220
|
+
arena_name = const.ARENA_NAMES.get(config.arena, const.ARENA_NAMES['green']) # like green -> spawn_and_swamp
|
|
1304
1221
|
self.TOTAL_INSERT_AT_HEAD += self.ARENA_IMPORTS_GETTER[arena_name]() # add arena imports
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
timestring = current_time.strftime("%Y-%m-%d %H:%M")
|
|
1308
|
-
|
|
1309
|
-
total_js = f"""const __VERSION__ = '{const.VERSION}';
|
|
1310
|
-
const __PYTHON_VERSION__ = '{python_version_info}';""" + self.TOTAL_INSERT_AT_HEAD + f"""
|
|
1311
|
-
export var LANGUAGE = '{config.language}';
|
|
1312
|
-
"""
|
|
1313
|
-
|
|
1314
|
-
total_js += f"export var TIMESTAMP = {timestamp_ms};\n"
|
|
1315
|
-
total_js += f"export var TIMESTRING = '{timestring}';\n"
|
|
1316
|
-
total_js += f"""const __AUTHOR__ = '{const.AUTHOR}';
|
|
1317
|
-
const __AUTHOR_CN__ = '{const.BILIBILI_NAME}';"""
|
|
1222
|
+
total_js = f"const __VERSION__ = '{const.VERSION}';\nconst __PYTHON_VERSION__ = '{python_version_info}';" + self.TOTAL_INSERT_AT_HEAD + f"\nexport var LANGUAGE = '{config.language}';\n"
|
|
1223
|
+
total_js += f"const __AUTHOR__ = '{const.AUTHOR}';\nconst __AUTHOR_CN__ = '{const.BILIBILI_NAME}';"
|
|
1318
1224
|
|
|
1225
|
+
# 添加.min.js文件的import语句
|
|
1319
1226
|
if min_js_files:
|
|
1320
1227
|
for min_js_path in min_js_files:
|
|
1321
1228
|
min_js_filename = os.path.basename(min_js_path)
|
|
@@ -1435,6 +1342,14 @@ const __AUTHOR_CN__ = '{const.BILIBILI_NAME}';"""
|
|
|
1435
1342
|
dir_path = os.path.dirname(mjs_path)
|
|
1436
1343
|
build_dir_path = os.path.dirname(build_main_mjs)
|
|
1437
1344
|
|
|
1345
|
+
# 复制.min.js文件到目标目录
|
|
1346
|
+
for min_js_path in min_js_files:
|
|
1347
|
+
min_js_filename = os.path.basename(min_js_path)
|
|
1348
|
+
# 复制到build目录
|
|
1349
|
+
shutil.copy(min_js_path, os.path.join(build_dir_path, min_js_filename))
|
|
1350
|
+
# 复制到最终导出目录
|
|
1351
|
+
shutil.copy(min_js_path, os.path.join(dir_path, min_js_filename))
|
|
1352
|
+
|
|
1438
1353
|
# 生成total_js,传入.min.js文件列表
|
|
1439
1354
|
total_js = imports + "\n" + self.generate_total_js(
|
|
1440
1355
|
replace_src_prefix(modules), imps, sorts, self.FILE_STRONG_REPLACE, reps, min_js_files
|
|
@@ -1450,14 +1365,6 @@ const __AUTHOR_CN__ = '{const.BILIBILI_NAME}';"""
|
|
|
1450
1365
|
with open(mjs_path, 'w', encoding='utf-8') as f:
|
|
1451
1366
|
f.write(total_js)
|
|
1452
1367
|
|
|
1453
|
-
# 复制.min.js文件到目标目录
|
|
1454
|
-
for min_js_path in min_js_files:
|
|
1455
|
-
min_js_filename = os.path.basename(min_js_path)
|
|
1456
|
-
# 复制到build目录
|
|
1457
|
-
shutil.copy(min_js_path, os.path.join(build_dir_path, min_js_filename))
|
|
1458
|
-
# 复制到最终导出目录
|
|
1459
|
-
shutil.copy(min_js_path, os.path.join(dir_path, min_js_filename))
|
|
1460
|
-
|
|
1461
1368
|
core.lprint(GREEN.format('[6/6]'), LOC_DONE, " ", LOC_EXPORTING_TOTAL_MAIN_JS_FINISH, sep="", head="\r", ln=config.language)
|
|
1462
1369
|
|
|
1463
1370
|
if mjs_path != build_main_mjs:
|
|
@@ -1515,7 +1422,7 @@ if __name__ == '__main__':
|
|
|
1515
1422
|
# compiler.compile()
|
|
1516
1423
|
# compiler.clean()
|
|
1517
1424
|
test = """
|
|
1518
|
-
|
|
1425
|
+
|
|
1519
1426
|
def patrolling(self, c: Creep):
|
|
1520
1427
|
e = self.center.nearest(k.civilian.enemies, 5)
|
|
1521
1428
|
if e:
|
|
@@ -1525,6 +1432,6 @@ def patrolling(self, c: Creep):
|
|
|
1525
1432
|
):
|
|
1526
1433
|
case True: c.move(e, SWAMP_MOTION)
|
|
1527
1434
|
case False: c.move(self.bpos, SWAMP_MOTION)
|
|
1528
|
-
|
|
1435
|
+
|
|
1529
1436
|
"""
|
|
1530
1437
|
print(f"res=\n{Compiler.convert_match_to_if(test)}")
|
|
Binary file
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
项目创建UI界面
|
|
4
|
+
"""
|
|
5
|
+
import sys
|
|
6
|
+
import os
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
|
|
9
|
+
QHBoxLayout, QLabel, QLineEdit, QPushButton,
|
|
10
|
+
QFileDialog, QMessageBox, QComboBox)
|
|
11
|
+
from PyQt6.QtCore import Qt
|
|
12
|
+
from PyQt6.QtGui import QFont
|
|
13
|
+
from PyQt6.QtGui import QIcon
|
|
14
|
+
from pyscreeps_arena.core import const
|
|
15
|
+
from pyscreeps_arena.ui.rs_icon import get_pixmap
|
|
16
|
+
from pyscreeps_arena.afters import ToConfigAfter, ToEmptyAfter, ToPrefabAfter, ToCustomAfter
|
|
17
|
+
from PyQt6.QtWidgets import QRadioButton, QGroupBox
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ProjectCreatorUI(QMainWindow):
|
|
22
|
+
def __init__(self):
|
|
23
|
+
super().__init__()
|
|
24
|
+
self._proj_name = ""
|
|
25
|
+
self._proj_path = ""
|
|
26
|
+
self._init_ui()
|
|
27
|
+
|
|
28
|
+
def _init_ui(self):
|
|
29
|
+
"""初始化UI界面"""
|
|
30
|
+
self.setWindowTitle("PyScreeps Arena - 项目创建器")
|
|
31
|
+
self.setWindowIcon(QIcon(get_pixmap()))
|
|
32
|
+
self.setFixedSize(500, 580)
|
|
33
|
+
|
|
34
|
+
# 主窗口部件
|
|
35
|
+
central_widget = QWidget()
|
|
36
|
+
self.setCentralWidget(central_widget)
|
|
37
|
+
layout = QVBoxLayout(central_widget)
|
|
38
|
+
layout.setSpacing(15)
|
|
39
|
+
layout.setContentsMargins(30, 30, 30, 30)
|
|
40
|
+
|
|
41
|
+
# 标题
|
|
42
|
+
title = QLabel("PyScreeps Arena")
|
|
43
|
+
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
44
|
+
title_font = QFont()
|
|
45
|
+
title_font.setPointSize(18)
|
|
46
|
+
title_font.setBold(True)
|
|
47
|
+
title.setFont(title_font)
|
|
48
|
+
layout.addWidget(title)
|
|
49
|
+
|
|
50
|
+
# 项目信息
|
|
51
|
+
info_widget = QWidget()
|
|
52
|
+
info_layout = QVBoxLayout(info_widget)
|
|
53
|
+
info_layout.setSpacing(8)
|
|
54
|
+
|
|
55
|
+
# 版本信息
|
|
56
|
+
version_label = QLabel(f"版本: {const.VERSION}")
|
|
57
|
+
version_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
58
|
+
info_layout.addWidget(version_label)
|
|
59
|
+
|
|
60
|
+
# 作者信息
|
|
61
|
+
author_label = QLabel(f"作者: {const.AUTHOR}")
|
|
62
|
+
author_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
63
|
+
info_layout.addWidget(author_label)
|
|
64
|
+
|
|
65
|
+
# GitHub信息
|
|
66
|
+
github_label = QLabel(f"GitHub: {const.GITHUB_NAME}")
|
|
67
|
+
github_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
68
|
+
info_layout.addWidget(github_label)
|
|
69
|
+
|
|
70
|
+
layout.addWidget(info_widget)
|
|
71
|
+
|
|
72
|
+
# 分隔线
|
|
73
|
+
separator = QLabel("─" * 50)
|
|
74
|
+
separator.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
75
|
+
separator.setStyleSheet("color: #ccc;")
|
|
76
|
+
layout.addWidget(separator)
|
|
77
|
+
|
|
78
|
+
# 项目输入区域
|
|
79
|
+
input_widget = QWidget()
|
|
80
|
+
input_layout = QVBoxLayout(input_widget)
|
|
81
|
+
input_layout.setSpacing(12)
|
|
82
|
+
|
|
83
|
+
# 项目名称输入
|
|
84
|
+
name_layout = QHBoxLayout()
|
|
85
|
+
name_label = QLabel("项目名称:")
|
|
86
|
+
name_label.setFixedWidth(80)
|
|
87
|
+
self._name_input = QLineEdit()
|
|
88
|
+
self._name_input.setPlaceholderText("输入项目名称...")
|
|
89
|
+
self._name_input.textChanged.connect(self._on_name_changed)
|
|
90
|
+
self._name_input.returnPressed.connect(self._create_project)
|
|
91
|
+
name_layout.addWidget(name_label)
|
|
92
|
+
name_layout.addWidget(self._name_input)
|
|
93
|
+
input_layout.addLayout(name_layout)
|
|
94
|
+
|
|
95
|
+
# 项目路径输入
|
|
96
|
+
path_layout = QHBoxLayout()
|
|
97
|
+
path_label = QLabel("保存位置:")
|
|
98
|
+
path_label.setFixedWidth(80)
|
|
99
|
+
self._path_input = QLineEdit()
|
|
100
|
+
self._path_input.setPlaceholderText("选择项目保存位置...")
|
|
101
|
+
self._path_input.setReadOnly(True)
|
|
102
|
+
# 默认桌面路径
|
|
103
|
+
desktop_path = os.path.join(os.path.expanduser("~"), "Desktop")
|
|
104
|
+
if os.path.exists(desktop_path):
|
|
105
|
+
self._path_input.setText(desktop_path)
|
|
106
|
+
self._proj_path = desktop_path
|
|
107
|
+
path_layout.addWidget(path_label)
|
|
108
|
+
path_layout.addWidget(self._path_input)
|
|
109
|
+
|
|
110
|
+
# 浏览按钮
|
|
111
|
+
browse_btn = QPushButton("浏览...")
|
|
112
|
+
browse_btn.setFixedWidth(60)
|
|
113
|
+
browse_btn.clicked.connect(self._browse_path)
|
|
114
|
+
path_layout.addWidget(browse_btn)
|
|
115
|
+
|
|
116
|
+
input_layout.addLayout(path_layout)
|
|
117
|
+
layout.addWidget(input_widget)
|
|
118
|
+
|
|
119
|
+
# 分隔线
|
|
120
|
+
separator2 = QLabel("─" * 50)
|
|
121
|
+
separator2.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
122
|
+
separator2.setStyleSheet("color: #ccc;")
|
|
123
|
+
layout.addWidget(separator2)
|
|
124
|
+
|
|
125
|
+
# 配置选项区域(左右布局)
|
|
126
|
+
config_container = QWidget()
|
|
127
|
+
config_container_layout = QHBoxLayout(config_container)
|
|
128
|
+
config_container_layout.setSpacing(20)
|
|
129
|
+
|
|
130
|
+
# 左侧:语言、竞技场、难度配置
|
|
131
|
+
left_config_widget = QWidget()
|
|
132
|
+
left_config_layout = QVBoxLayout(left_config_widget)
|
|
133
|
+
left_config_layout.setSpacing(10)
|
|
134
|
+
|
|
135
|
+
# 语言选择
|
|
136
|
+
lang_layout = QHBoxLayout()
|
|
137
|
+
lang_label = QLabel("语 言:")
|
|
138
|
+
lang_label.setFixedWidth(80)
|
|
139
|
+
self._lang_combo = QComboBox()
|
|
140
|
+
self._lang_combo.addItems(["中文 (cn)", "英文 (en)"])
|
|
141
|
+
self._lang_combo.setCurrentIndex(0)
|
|
142
|
+
lang_layout.addWidget(lang_label)
|
|
143
|
+
lang_layout.addWidget(self._lang_combo)
|
|
144
|
+
left_config_layout.addLayout(lang_layout)
|
|
145
|
+
|
|
146
|
+
# 竞技场选择
|
|
147
|
+
arena_layout = QHBoxLayout()
|
|
148
|
+
arena_label = QLabel("竞技场:")
|
|
149
|
+
arena_label.setFixedWidth(80)
|
|
150
|
+
self._arena_combo = QComboBox()
|
|
151
|
+
self._arena_combo.addItems(["灰色 (gray)", "绿色 (green)", "蓝色 (blue)", "红色 (red)"])
|
|
152
|
+
self._arena_combo.setCurrentIndex(0)
|
|
153
|
+
arena_layout.addWidget(arena_label)
|
|
154
|
+
arena_layout.addWidget(self._arena_combo)
|
|
155
|
+
left_config_layout.addLayout(arena_layout)
|
|
156
|
+
|
|
157
|
+
# 难度级别选择
|
|
158
|
+
level_layout = QHBoxLayout()
|
|
159
|
+
level_label = QLabel("难 度:")
|
|
160
|
+
level_label.setFixedWidth(80)
|
|
161
|
+
self._level_combo = QComboBox()
|
|
162
|
+
self._level_combo.addItems(["基础 (basic)", "高级 (advanced)"])
|
|
163
|
+
self._level_combo.setCurrentIndex(0)
|
|
164
|
+
level_layout.addWidget(level_label)
|
|
165
|
+
level_layout.addWidget(self._level_combo)
|
|
166
|
+
left_config_layout.addLayout(level_layout)
|
|
167
|
+
|
|
168
|
+
config_container_layout.addWidget(left_config_widget)
|
|
169
|
+
|
|
170
|
+
# 右侧:模式选择(单选框)
|
|
171
|
+
right_config_widget = QWidget()
|
|
172
|
+
right_config_layout = QVBoxLayout(right_config_widget)
|
|
173
|
+
right_config_layout.setSpacing(8)
|
|
174
|
+
|
|
175
|
+
# 模式选择标题
|
|
176
|
+
# mode_title = QLabel("模式选择")
|
|
177
|
+
# mode_title.setFont(QFont("Arial", 10, QFont.Weight.Bold))
|
|
178
|
+
# right_config_layout.addWidget(mode_title)
|
|
179
|
+
|
|
180
|
+
# 单选按钮
|
|
181
|
+
self._empty_radio = QRadioButton("空白 (Empty)")
|
|
182
|
+
self._basic_radio = QRadioButton("基础 (Basic)")
|
|
183
|
+
self._prefab_radio = QRadioButton("预设 (Prefab)")
|
|
184
|
+
self._pi_radio = QRadioButton("预设继承 (P&&I)")
|
|
185
|
+
|
|
186
|
+
# 默认选择基础模式
|
|
187
|
+
self._basic_radio.setChecked(True)
|
|
188
|
+
|
|
189
|
+
# 添加到布局
|
|
190
|
+
right_config_layout.addWidget(self._empty_radio)
|
|
191
|
+
right_config_layout.addWidget(self._basic_radio)
|
|
192
|
+
right_config_layout.addWidget(self._prefab_radio)
|
|
193
|
+
right_config_layout.addWidget(self._pi_radio)
|
|
194
|
+
|
|
195
|
+
config_container_layout.addWidget(right_config_widget)
|
|
196
|
+
|
|
197
|
+
layout.addWidget(config_container)
|
|
198
|
+
|
|
199
|
+
# 按钮区域
|
|
200
|
+
button_layout = QHBoxLayout()
|
|
201
|
+
button_layout.addStretch()
|
|
202
|
+
|
|
203
|
+
# 创建按钮
|
|
204
|
+
self._create_btn = QPushButton("创建项目")
|
|
205
|
+
self._create_btn.setFixedSize(100, 35)
|
|
206
|
+
self._create_btn.clicked.connect(self._create_project)
|
|
207
|
+
self._create_btn.setEnabled(False)
|
|
208
|
+
self._create_btn.setDefault(True)
|
|
209
|
+
button_layout.addWidget(self._create_btn)
|
|
210
|
+
|
|
211
|
+
# 取消按钮
|
|
212
|
+
cancel_btn = QPushButton("取消")
|
|
213
|
+
cancel_btn.setFixedSize(80, 35)
|
|
214
|
+
cancel_btn.clicked.connect(self.close)
|
|
215
|
+
button_layout.addWidget(cancel_btn)
|
|
216
|
+
|
|
217
|
+
layout.addLayout(button_layout)
|
|
218
|
+
layout.addStretch()
|
|
219
|
+
|
|
220
|
+
def _on_name_changed(self, text):
|
|
221
|
+
"""项目名称改变时的处理"""
|
|
222
|
+
self._proj_name = text.strip()
|
|
223
|
+
self._create_btn.setEnabled(bool(self._proj_name and self._proj_path))
|
|
224
|
+
|
|
225
|
+
def _browse_path(self):
|
|
226
|
+
"""浏览选择路径"""
|
|
227
|
+
current_path = self._path_input.text() or os.path.expanduser("~")
|
|
228
|
+
path = QFileDialog.getExistingDirectory(
|
|
229
|
+
self, "选择项目保存位置", current_path
|
|
230
|
+
)
|
|
231
|
+
if path:
|
|
232
|
+
self._path_input.setText(path)
|
|
233
|
+
self._proj_path = path
|
|
234
|
+
self._create_btn.setEnabled(bool(self._proj_name and self._proj_path))
|
|
235
|
+
|
|
236
|
+
def _create_project(self):
|
|
237
|
+
"""创建项目"""
|
|
238
|
+
if not self._proj_name or not self._proj_path:
|
|
239
|
+
return
|
|
240
|
+
|
|
241
|
+
# 构建完整路径
|
|
242
|
+
full_path = os.path.join(self._proj_path, self._proj_name)
|
|
243
|
+
|
|
244
|
+
# 检查路径是否已存在
|
|
245
|
+
if os.path.exists(full_path):
|
|
246
|
+
reply = QMessageBox.question(
|
|
247
|
+
self, "路径已存在",
|
|
248
|
+
f"路径 '{full_path}' 已存在。\n是否继续?",
|
|
249
|
+
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
|
250
|
+
)
|
|
251
|
+
if reply != QMessageBox.StandardButton.Yes:
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
# 创建项目
|
|
256
|
+
self._extract_project_template(full_path)
|
|
257
|
+
|
|
258
|
+
QMessageBox.information(
|
|
259
|
+
self, "成功",
|
|
260
|
+
f"项目 '{self._proj_name}' 创建成功!\n路径: {full_path}"
|
|
261
|
+
)
|
|
262
|
+
self.close()
|
|
263
|
+
|
|
264
|
+
except Exception as e:
|
|
265
|
+
QMessageBox.critical(
|
|
266
|
+
self, "错误",
|
|
267
|
+
f"项目创建失败:\n{str(e)}"
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
def _extract_project_template(self, target_path):
|
|
271
|
+
"""提取项目模板"""
|
|
272
|
+
# 获取当前包路径
|
|
273
|
+
this_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
274
|
+
project_7z_path = os.path.join(this_path, 'project.7z')
|
|
275
|
+
|
|
276
|
+
if not os.path.exists(project_7z_path):
|
|
277
|
+
raise FileNotFoundError(f"项目模板文件不存在: {project_7z_path}")
|
|
278
|
+
|
|
279
|
+
# 创建目标目录
|
|
280
|
+
os.makedirs(target_path, exist_ok=True)
|
|
281
|
+
|
|
282
|
+
# 解压项目模板
|
|
283
|
+
import py7zr
|
|
284
|
+
with py7zr.SevenZipFile(project_7z_path, mode='r') as archive:
|
|
285
|
+
archive.extractall(path=target_path)
|
|
286
|
+
|
|
287
|
+
print(f"[DEBUG] 项目模板已解压到: {target_path}") # 调试输出
|
|
288
|
+
|
|
289
|
+
# 获取用户选择的配置
|
|
290
|
+
lang_text = self._lang_combo.currentText()
|
|
291
|
+
lang = lang_text.split('(')[1].strip(')')
|
|
292
|
+
|
|
293
|
+
arena_text = self._arena_combo.currentText()
|
|
294
|
+
arena = arena_text.split('(')[1].strip(')')
|
|
295
|
+
|
|
296
|
+
level_text = self._level_combo.currentText()
|
|
297
|
+
level = level_text.split('(')[1].strip(')')
|
|
298
|
+
|
|
299
|
+
# 调用配置方法
|
|
300
|
+
ToConfigAfter(path=target_path, language=lang, arena=arena, level=level)
|
|
301
|
+
print(f"[DEBUG] 项目配置已更新: language={lang}, arena={arena}, level={level}") # 调试输出
|
|
302
|
+
|
|
303
|
+
# 根据选择的模式执行相应的操作
|
|
304
|
+
if self._empty_radio.isChecked():
|
|
305
|
+
print(f"[DEBUG] 执行空白模式配置")
|
|
306
|
+
ToEmptyAfter(path=target_path)
|
|
307
|
+
elif self._basic_radio.isChecked():
|
|
308
|
+
print(f"[DEBUG] 执行基础模式配置(不操作)")
|
|
309
|
+
# 基础模式不执行任何操作
|
|
310
|
+
elif self._prefab_radio.isChecked():
|
|
311
|
+
print(f"[DEBUG] 执行预设模式配置")
|
|
312
|
+
ToPrefabAfter(path=target_path)
|
|
313
|
+
elif self._pi_radio.isChecked():
|
|
314
|
+
print(f"[DEBUG] 执行预设继承模式配置")
|
|
315
|
+
ToPrefabAfter(path=target_path)
|
|
316
|
+
ToCustomAfter(path=target_path)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def run_project_creator():
|
|
320
|
+
"""运行项目创建器UI"""
|
|
321
|
+
app = QApplication(sys.argv)
|
|
322
|
+
window = ProjectCreatorUI()
|
|
323
|
+
window.show()
|
|
324
|
+
sys.exit(app.exec())
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
if __name__ == '__main__':
|
|
328
|
+
run_project_creator()
|
|
@@ -7,7 +7,7 @@ with open(r"T:\New_PC\Import_Project\uploads\pyscreeps-arena_upload\pyscreeps-ar
|
|
|
7
7
|
long_description = f.read()
|
|
8
8
|
setup(
|
|
9
9
|
name='pyscreeps-arena',
|
|
10
|
-
version='0.5.
|
|
10
|
+
version='0.5.9a0',
|
|
11
11
|
description='Python api|interface to play game: Screeps: Arena.',
|
|
12
12
|
long_description=long_description,
|
|
13
13
|
long_description_content_type='text/markdown',
|
|
Binary file
|