diff --git a/assets/splash.png b/assets/splash.png new file mode 100644 index 0000000..782cec8 Binary files /dev/null and b/assets/splash.png differ diff --git a/src/server/main.py b/src/server/main.py index f601ada..11a15a2 100644 --- a/src/server/main.py +++ b/src/server/main.py @@ -4,7 +4,10 @@ import asyncio import webbrowser import subprocess import time +import threading +import signal from contextlib import asynccontextmanager + from typing import List, Optional from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException, Query from fastapi.middleware.cors import CORSMiddleware @@ -883,6 +886,18 @@ def get_map(): } +@app.post("/api/control/reset") +def reset_game(): + """重置游戏到 Idle 状态(回到主菜单)""" + game_instance["world"] = None + game_instance["sim"] = None + game_instance["is_paused"] = True + game_instance["init_status"] = "idle" + game_instance["init_phase"] = 0 + game_instance["init_progress"] = 0 + game_instance["init_error"] = None + return {"status": "ok", "message": "Game reset to idle"} + @app.post("/api/control/pause") def pause_game(): """暂停游戏循环""" @@ -895,6 +910,17 @@ def resume_game(): game_instance["is_paused"] = False return {"status": "ok", "message": "Game resumed"} +@app.post("/api/control/shutdown") +async def shutdown_server(): + def _shutdown(): + time.sleep(1) # 给前端一点时间接收 200 OK 响应 + # 这种方式适用于 uvicorn 运行环境,或者直接杀进程 + os.kill(os.getpid(), signal.SIGINT) + + # 异步执行关闭,确保先返回响应 + threading.Thread(target=_shutdown).start() + return {"status": "shutting_down", "message": "Server is shutting down..."} + # --- 初始化状态 API --- @@ -1551,6 +1577,11 @@ async def api_load_game(req: LoadGameRequest): game_instance["init_start_time"] = time.time() game_instance["init_error"] = None game_instance["init_phase"] = 0 + + # 0. 扫描资源 (修复读取存档不加载头像的问题) + game_instance["init_phase_name"] = "scanning_assets" + await asyncio.to_thread(scan_avatar_assets) + game_instance["init_phase_name"] = "loading_save" game_instance["init_progress"] = 10 diff --git a/tests/conftest.py b/tests/conftest.py index b185278..830041c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -61,6 +61,8 @@ def dummy_avatar(base_world): # 强制清空特质(因为 __post_init__ 会在 personas 为空时自动随机生成) av.personas = [] + # 强制清空功法,防止随机出的功法带有移动步长加成(如逍遥游) + av.technique = None av.recalc_effects() return av diff --git a/web/src/App.vue b/web/src/App.vue index 4e580c1..236bf20 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -1,9 +1,11 @@ + + + + + + + 修仙模拟器 + Cultivation World Simulator + + + + + + + {{ opt.label }} + {{ opt.subLabel }} + + + + + + + + + diff --git a/web/src/components/SystemMenu.vue b/web/src/components/SystemMenu.vue index dcc4d6a..48284c7 100644 --- a/web/src/components/SystemMenu.vue +++ b/web/src/components/SystemMenu.vue @@ -1,5 +1,6 @@
Cultivation World Simulator