140 lines
3.8 KiB
Python
140 lines
3.8 KiB
Python
"""
|
||
存档功能模块
|
||
"""
|
||
import json
|
||
from pathlib import Path
|
||
from datetime import datetime
|
||
from typing import List, Optional
|
||
|
||
from src.classes.world import World
|
||
from src.sim.simulator import Simulator
|
||
from src.classes.sect import Sect
|
||
from src.utils.config import CONFIG
|
||
|
||
|
||
def save_game(
|
||
world: World,
|
||
simulator: Simulator,
|
||
existed_sects: List[Sect],
|
||
save_path: Optional[Path] = None
|
||
) -> bool:
|
||
"""
|
||
保存游戏状态到文件
|
||
|
||
Args:
|
||
world: 世界对象
|
||
simulator: 模拟器对象
|
||
existed_sects: 本局启用的宗门列表
|
||
save_path: 保存路径,默认为saves/save.json
|
||
|
||
Returns:
|
||
保存是否成功
|
||
"""
|
||
try:
|
||
# 确定保存路径
|
||
if save_path is None:
|
||
saves_dir = CONFIG.paths.saves
|
||
saves_dir.mkdir(parents=True, exist_ok=True)
|
||
save_path = saves_dir / "save.json"
|
||
else:
|
||
save_path = Path(save_path)
|
||
save_path.parent.mkdir(parents=True, exist_ok=True)
|
||
|
||
# 构建元信息
|
||
meta = {
|
||
"version": CONFIG.meta.version,
|
||
"save_time": datetime.now().isoformat(),
|
||
"game_time": f"{world.month_stamp.get_year()}年{world.month_stamp.get_month().value}月"
|
||
}
|
||
|
||
# 构建世界数据
|
||
world_data = {
|
||
"month_stamp": int(world.month_stamp),
|
||
"existed_sect_ids": [sect.id for sect in existed_sects]
|
||
}
|
||
|
||
# 保存所有Avatar(第一阶段:不含relations)
|
||
avatars_data = []
|
||
for avatar in world.avatar_manager.avatars.values():
|
||
avatars_data.append(avatar.to_save_dict())
|
||
|
||
# 保存事件历史(限制数量)
|
||
max_events = CONFIG.save.max_events_to_save
|
||
events_data = []
|
||
recent_events = world.event_manager.get_recent_events(limit=max_events)
|
||
for event in recent_events:
|
||
events_data.append(event.to_dict())
|
||
|
||
# 保存模拟器数据
|
||
simulator_data = {
|
||
"birth_rate": simulator.birth_rate
|
||
}
|
||
|
||
# 组装完整的存档数据
|
||
save_data = {
|
||
"meta": meta,
|
||
"world": world_data,
|
||
"avatars": avatars_data,
|
||
"events": events_data,
|
||
"simulator": simulator_data
|
||
}
|
||
|
||
# 写入文件
|
||
with open(save_path, "w", encoding="utf-8") as f:
|
||
json.dump(save_data, f, ensure_ascii=False, indent=2)
|
||
|
||
print(f"游戏已保存到: {save_path}")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"保存游戏失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
|
||
def get_save_info(save_path: Path) -> Optional[dict]:
|
||
"""
|
||
读取存档文件的元信息(不加载完整数据)
|
||
|
||
Args:
|
||
save_path: 存档路径
|
||
|
||
Returns:
|
||
存档元信息字典,如果读取失败返回None
|
||
"""
|
||
try:
|
||
with open(save_path, "r", encoding="utf-8") as f:
|
||
data = json.load(f)
|
||
return data.get("meta", {})
|
||
except Exception:
|
||
return None
|
||
|
||
|
||
def list_saves(saves_dir: Optional[Path] = None) -> List[tuple[Path, dict]]:
|
||
"""
|
||
列出所有存档文件及其元信息
|
||
|
||
Args:
|
||
saves_dir: 存档目录,默认为config中的saves目录
|
||
|
||
Returns:
|
||
[(存档路径, 元信息字典), ...]
|
||
"""
|
||
if saves_dir is None:
|
||
saves_dir = CONFIG.paths.saves
|
||
|
||
if not saves_dir.exists():
|
||
return []
|
||
|
||
saves = []
|
||
for save_file in saves_dir.glob("*.json"):
|
||
info = get_save_info(save_file)
|
||
if info is not None:
|
||
saves.append((save_file, info))
|
||
|
||
# 按保存时间倒序排列
|
||
saves.sort(key=lambda x: x[1].get("save_time", ""), reverse=True)
|
||
return saves
|
||
|