fix a bug

This commit is contained in:
bridge
2026-01-06 20:42:53 +08:00
parent fa909e5a2a
commit 3f980d4593
7 changed files with 91 additions and 28 deletions

View File

@@ -1,6 +1,7 @@
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Dict, List, TYPE_CHECKING
from typing import Dict, List, TYPE_CHECKING, Iterable
import itertools
if TYPE_CHECKING:
from src.classes.avatar import Avatar
@@ -9,22 +10,39 @@ from src.classes.observe import get_observable_avatars
@dataclass
class AvatarManager:
# 仅存储存活的角色,用于主循环遍历
avatars: Dict[str, "Avatar"] = field(default_factory=dict)
# 存储已死亡的角色(归档)
dead_avatars: Dict[str, "Avatar"] = field(default_factory=dict)
def get_avatar(self, avatar_id: str) -> "Avatar | None":
"""
根据 ID 获取角色对象
根据 ID 获取角色对象,优先查找活人,再查找死者
"""
return self.avatars.get(str(avatar_id))
aid = str(avatar_id)
return self.avatars.get(aid) or self.dead_avatars.get(aid)
def handle_death(self, avatar_id: str) -> None:
"""
处理角色死亡:将角色从活跃列表移动到墓地
"""
aid = str(avatar_id)
if aid in self.avatars:
avatar = self.avatars.pop(aid)
self.dead_avatars[aid] = avatar
# 断开地图连接,确保不出现在地图网格上
if hasattr(avatar, "tile"):
avatar.tile = None
def get_avatars_in_same_region(self, avatar: "Avatar") -> List["Avatar"]:
"""
返回与给定 avatar 处于同一区域的其他角色列表(不含自己)。
返回与给定 avatar 处于同一区域的其他【存活】角色列表(不含自己)。
"""
if avatar is None or getattr(avatar, "tile", None) is None or avatar.tile.region is None:
return []
region = avatar.tile.region
same_region: list["Avatar"] = []
# 只遍历活人
for other in self.avatars.values():
if other is avatar or getattr(other, "tile", None) is None:
continue
@@ -35,35 +53,46 @@ class AvatarManager:
def get_living_avatars(self) -> List["Avatar"]:
"""
返回所有存活的角色列表。
由于 avatars 现在只存活人,直接返回 values 即可。
"""
return [avatar for avatar in self.avatars.values() if not avatar.is_dead]
return list(self.avatars.values())
def get_observable_avatars(self, avatar: "Avatar") -> List["Avatar"]:
"""
返回处于 avatar 交互范围内的其他角色列表(不含自己)。
基于曼哈顿距离与境界映射的感知半径过滤。
返回处于 avatar 交互范围内的其他【存活】角色列表(不含自己)。
"""
return get_observable_avatars(avatar, self.avatars.values())
def _iter_all_avatars(self) -> Iterable["Avatar"]:
"""辅助方法:遍历所有角色(活人+死者)"""
return itertools.chain(self.avatars.values(), self.dead_avatars.values())
def remove_avatar(self, avatar_id: str) -> None:
"""
从管理器中删除一个 avatar并清理所有与其相关的双向关系。
从管理器中彻底删除一个 avatar(无论是死是活),并清理所有与其相关的双向关系。
此操作不可逆。
"""
avatar = self.avatars.get(avatar_id)
aid = str(avatar_id)
avatar = self.get_avatar(aid)
if avatar is None:
return
# 先清理与其直接记录的关系(会保持对称)
# 1. 清理与其直接记录的关系
related = list(getattr(avatar, "relations", {}).keys())
for other in related:
avatar.clear_relation(other)
# 再次扫一遍所有 avatar确保不存在残留引用
for other in list(self.avatars.values()):
# 2. 扫一遍所有角色(含死者),确保清除反向引用
for other in self._iter_all_avatars():
if other is avatar:
continue
if getattr(other, "relations", None) is not None and avatar in other.relations:
other.clear_relation(avatar)
# 最后移除自身
self.avatars.pop(avatar_id, None)
# 3. 移除自身
self.avatars.pop(aid, None)
self.dead_avatars.pop(aid, None)
def remove_avatars(self, avatar_ids: List[str]) -> None:
"""
@@ -71,5 +100,3 @@ class AvatarManager:
"""
for aid in list(avatar_ids):
self.remove_avatar(aid)