fix pngs
This commit is contained in:
@@ -29,6 +29,26 @@ class Auxiliary:
|
||||
# 特殊属性(用于存储实例特定数据)
|
||||
special_data: dict = field(default_factory=dict)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
"""
|
||||
自定义深拷贝:
|
||||
Sect 对象必须保持单例引用,不能深拷贝,否则会复制整个宗门及其所有成员,
|
||||
导致内存浪费和潜在的无限递归/哈希错误。
|
||||
"""
|
||||
import copy
|
||||
cls = self.__class__
|
||||
result = cls.__new__(cls)
|
||||
memo[id(self)] = result
|
||||
|
||||
for k, v in self.__dict__.items():
|
||||
if k == 'sect':
|
||||
# 浅拷贝引用
|
||||
setattr(result, k, v)
|
||||
else:
|
||||
# 深拷贝其他属性
|
||||
setattr(result, k, copy.deepcopy(v, memo))
|
||||
return result
|
||||
|
||||
def get_info(self) -> str:
|
||||
"""获取简略信息"""
|
||||
return f"{self.name}"
|
||||
|
||||
@@ -32,6 +32,26 @@ class Weapon:
|
||||
# 特殊属性(如万魂幡的吞噬魂魄计数)
|
||||
special_data: dict = field(default_factory=dict)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
"""
|
||||
自定义深拷贝:
|
||||
Sect 对象必须保持单例引用,不能深拷贝,否则会复制整个宗门及其所有成员,
|
||||
导致内存浪费和潜在的无限递归/哈希错误。
|
||||
"""
|
||||
import copy
|
||||
cls = self.__class__
|
||||
result = cls.__new__(cls)
|
||||
memo[id(self)] = result
|
||||
|
||||
for k, v in self.__dict__.items():
|
||||
if k == 'sect':
|
||||
# 浅拷贝引用
|
||||
setattr(result, k, v)
|
||||
else:
|
||||
# 深拷贝其他属性
|
||||
setattr(result, k, copy.deepcopy(v, memo))
|
||||
return result
|
||||
|
||||
def get_info(self) -> str:
|
||||
"""获取简略信息"""
|
||||
suffix = ""
|
||||
|
||||
@@ -67,7 +67,7 @@ def load_game(save_path: Optional[Path] = None) -> Tuple["World", "Simulator", L
|
||||
from src.classes.avatar import Avatar
|
||||
from src.classes.sect import sects_by_id
|
||||
from src.sim.simulator import Simulator
|
||||
from src.run.create_map import create_cultivation_world_map, add_sect_headquarters
|
||||
from src.run.load_map import load_cultivation_world_map
|
||||
|
||||
# 读取存档文件
|
||||
with open(save_path, "r", encoding="utf-8") as f:
|
||||
@@ -79,7 +79,7 @@ def load_game(save_path: Optional[Path] = None) -> Tuple["World", "Simulator", L
|
||||
f"游戏时间: {meta.get('game_time', 'unknown')})")
|
||||
|
||||
# 重建地图(地图本身不变,只需重建宗门总部位置)
|
||||
game_map = create_cultivation_world_map()
|
||||
game_map = load_cultivation_world_map()
|
||||
|
||||
# 读取世界数据
|
||||
world_data = save_data.get("world", {})
|
||||
@@ -99,9 +99,6 @@ def load_game(save_path: Optional[Path] = None) -> Tuple["World", "Simulator", L
|
||||
existed_sect_ids = world_data.get("existed_sect_ids", [])
|
||||
existed_sects = [sects_by_id[sid] for sid in existed_sect_ids if sid in sects_by_id]
|
||||
|
||||
# 在地图上添加宗门总部
|
||||
add_sect_headquarters(game_map, existed_sects)
|
||||
|
||||
# 第一阶段:重建所有Avatar(不含relations)
|
||||
avatars_data = save_data.get("avatars", [])
|
||||
all_avatars = {}
|
||||
|
||||
@@ -31,7 +31,7 @@ avatar:
|
||||
# all 引入所有主角不引入随机角色
|
||||
# random,正常随机角色,但是有一定概率出主角
|
||||
# none, 不引入主角(默认选项)
|
||||
protagonist: "all"
|
||||
protagonist: "random"
|
||||
|
||||
social:
|
||||
major_event_context_num: 10 # 大事(长期记忆)展示数量
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 将项目根目录加入 Python 路径,确保可以导入 `src` 包
|
||||
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||
if PROJECT_ROOT not in sys.path:
|
||||
sys.path.insert(0, PROJECT_ROOT)
|
||||
|
||||
|
||||
55
tests/test_deepcopy_fix.py
Normal file
55
tests/test_deepcopy_fix.py
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
import pytest
|
||||
import copy
|
||||
from src.classes.weapon import Weapon, WeaponType
|
||||
from src.classes.equipment_grade import EquipmentGrade
|
||||
from src.classes.sect import Sect, SectHeadQuarter
|
||||
from src.classes.alignment import Alignment
|
||||
from pathlib import Path
|
||||
|
||||
def test_weapon_deepcopy_does_not_copy_sect():
|
||||
# 1. 创建模拟的 Sect
|
||||
hq = SectHeadQuarter("HQ", "Desc", Path("img.png"))
|
||||
sect = Sect(
|
||||
id=1, name="TestSect", desc="Desc", member_act_style="Style",
|
||||
alignment=Alignment.Righteous, headquarter=hq, technique_names=[]
|
||||
)
|
||||
|
||||
# 向 Sect 中添加一些可能导致问题的成员(虽然这里只是简单测试引用)
|
||||
# 在真实场景中,Sect.members 可能包含复杂的 Avatar 对象
|
||||
sect.members["dummy"] = "DummyAvatar"
|
||||
|
||||
# 2. 创建 Weapon 并关联 Sect
|
||||
weapon = Weapon(
|
||||
id=101, name="TestWeapon", weapon_type=WeaponType.SWORD,
|
||||
grade=EquipmentGrade.COMMON, sect_id=1, desc="Desc", sect=sect
|
||||
)
|
||||
|
||||
# 3. 深拷贝 Weapon
|
||||
weapon_copy = copy.deepcopy(weapon)
|
||||
|
||||
# 4. 验证 Weapon 被复制了
|
||||
assert weapon_copy is not weapon
|
||||
assert weapon_copy.id == weapon.id
|
||||
|
||||
# 5. 关键验证:Sect 应该是同一个对象(浅拷贝)
|
||||
assert weapon_copy.sect is sect
|
||||
assert weapon_copy.sect is weapon.sect
|
||||
|
||||
# 验证 Sect 的成员没有被复制
|
||||
assert weapon_copy.sect.members is sect.members
|
||||
|
||||
def test_weapon_special_data_is_copied():
|
||||
# 验证 special_data 是否被正确深拷贝
|
||||
weapon = Weapon(
|
||||
id=101, name="TestWeapon", weapon_type=WeaponType.SWORD,
|
||||
grade=EquipmentGrade.COMMON, sect_id=None, desc="Desc"
|
||||
)
|
||||
weapon.special_data = {"souls": 10, "nested": {"a": 1}}
|
||||
|
||||
weapon_copy = copy.deepcopy(weapon)
|
||||
|
||||
assert weapon_copy.special_data == weapon.special_data
|
||||
assert weapon_copy.special_data is not weapon.special_data
|
||||
assert weapon_copy.special_data["nested"] is not weapon.special_data["nested"]
|
||||
|
||||
0
tests/test_save_load.py
Normal file
0
tests/test_save_load.py
Normal file
@@ -50,8 +50,8 @@ def test_auto_promote():
|
||||
|
||||
def test_avatar_sect_rank_assignment():
|
||||
"""测试avatar创建时宗门职位分配"""
|
||||
from src.run.create_map import create_cultivation_world_map
|
||||
game_map = create_cultivation_world_map()
|
||||
from src.run.load_map import load_cultivation_world_map
|
||||
game_map = load_cultivation_world_map()
|
||||
world = World(
|
||||
map=game_map,
|
||||
month_stamp=MonthStamp(100 * 12),
|
||||
@@ -77,8 +77,8 @@ def test_avatar_sect_rank_assignment():
|
||||
|
||||
def test_patriarch_uniqueness():
|
||||
"""测试每个宗门只有一个掌门"""
|
||||
from src.run.create_map import create_cultivation_world_map
|
||||
game_map = create_cultivation_world_map()
|
||||
from src.run.load_map import load_cultivation_world_map
|
||||
game_map = load_cultivation_world_map()
|
||||
world = World(
|
||||
map=game_map,
|
||||
month_stamp=MonthStamp(100 * 12),
|
||||
@@ -104,8 +104,8 @@ def test_patriarch_uniqueness():
|
||||
|
||||
def test_sect_str_display():
|
||||
"""测试宗门信息显示"""
|
||||
from src.run.create_map import create_cultivation_world_map
|
||||
game_map = create_cultivation_world_map()
|
||||
from src.run.load_map import load_cultivation_world_map
|
||||
game_map = load_cultivation_world_map()
|
||||
world = World(
|
||||
map=game_map,
|
||||
month_stamp=MonthStamp(100 * 12),
|
||||
@@ -129,8 +129,8 @@ def test_sect_str_display():
|
||||
|
||||
def test_cultivation_breakthrough_promotion():
|
||||
"""测试突破境界后自动晋升"""
|
||||
from src.run.create_map import create_cultivation_world_map
|
||||
game_map = create_cultivation_world_map()
|
||||
from src.run.load_map import load_cultivation_world_map
|
||||
game_map = load_cultivation_world_map()
|
||||
world = World(
|
||||
map=game_map,
|
||||
month_stamp=MonthStamp(100 * 12),
|
||||
|
||||
@@ -53,15 +53,8 @@ export function useTextures() {
|
||||
'SEA': '/assets/tiles/sea.png',
|
||||
'WATER_FULL': '/assets/tiles/water_full.jpg',
|
||||
'SEA_FULL': '/assets/tiles/sea_full.jpg',
|
||||
'MOUNTAIN': '/assets/tiles/mountain.png',
|
||||
'FOREST': '/assets/tiles/forest.png',
|
||||
'CITY': '/assets/tiles/city.png',
|
||||
'DESERT': '/assets/tiles/desert.png',
|
||||
'RAINFOREST': '/assets/tiles/rainforest.png',
|
||||
'GLACIER': '/assets/tiles/glacier.png',
|
||||
'SNOW_MOUNTAIN': '/assets/tiles/snow_mountain.png',
|
||||
'VOLCANO': '/assets/tiles/volcano.png',
|
||||
'GRASSLAND': '/assets/tiles/grassland.png',
|
||||
'SWAMP': '/assets/tiles/swamp.png',
|
||||
'FARM': '/assets/tiles/farm.png',
|
||||
'ISLAND': '/assets/tiles/island.png',
|
||||
@@ -134,6 +127,13 @@ export function useTextures() {
|
||||
|
||||
await Promise.all([...tilePromises, ...variantPromises, ...avatarPromises, ...cloudPromises])
|
||||
|
||||
// 为没有基础纹理的变体类型设置默认纹理(使用第0个变体作为默认值)
|
||||
Object.keys(TILE_VARIANTS).forEach(key => {
|
||||
if (!textures.value[key] && textures.value[`${key}_0`]) {
|
||||
textures.value[key] = textures.value[`${key}_0`]
|
||||
}
|
||||
})
|
||||
|
||||
isLoaded.value = true
|
||||
console.log('Base textures loaded')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user