feat(avatar): implement region ownership management in AvatarManager and Avatar classes
- Added `owned_regions` attribute to the Avatar class to track regions owned by avatars. - Introduced `occupy_region` and `release_region` methods for managing region ownership and ensuring proper relationship handling. - Updated AvatarManager to clear relationships when an avatar is released, ensuring no lingering references. - Refactored region ownership logic in the Occupy action and Simulator to utilize the new methods for better clarity and maintainability. - Enhanced game loading process to establish ownership relationships correctly during game state restoration.
This commit is contained in:
@@ -11,6 +11,7 @@ from typing import Optional, List, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.classes.sect_ranks import SectRank
|
||||
from src.classes.region import CultivateRegion
|
||||
|
||||
from src.classes.calendar import MonthStamp
|
||||
from src.classes.world import World
|
||||
@@ -133,6 +134,39 @@ class Avatar(
|
||||
# 关系交互计数器: key=target_id, value={"count": 0, "checked_times": 0}
|
||||
relation_interaction_states: dict[str, dict[str, int]] = field(default_factory=lambda: defaultdict(lambda: {"count": 0, "checked_times": 0}))
|
||||
|
||||
# 拥有的洞府列表(不参与序列化,通过 load_game 重建)
|
||||
owned_regions: List["CultivateRegion"] = field(default_factory=list, init=False)
|
||||
|
||||
def occupy_region(self, region: "CultivateRegion") -> None:
|
||||
"""
|
||||
占据一个洞府,处理双向绑定和旧主清理。
|
||||
"""
|
||||
# 如果已经是我的,无需操作
|
||||
if region.host_avatar == self:
|
||||
if region not in self.owned_regions:
|
||||
self.owned_regions.append(region)
|
||||
return
|
||||
|
||||
# 如果有旧主,先让旧主释放
|
||||
if region.host_avatar is not None:
|
||||
region.host_avatar.release_region(region)
|
||||
|
||||
# 建立新关系
|
||||
region.host_avatar = self
|
||||
if region not in self.owned_regions:
|
||||
self.owned_regions.append(region)
|
||||
|
||||
def release_region(self, region: "CultivateRegion") -> None:
|
||||
"""
|
||||
放弃一个洞府的所有权。
|
||||
"""
|
||||
if region in self.owned_regions:
|
||||
self.owned_regions.remove(region)
|
||||
|
||||
# 只有当 region 的主人确实是自己时才置空(防止误伤新主人)
|
||||
if region.host_avatar == self:
|
||||
region.host_avatar = None
|
||||
|
||||
def add_breakthrough_rate(self, rate: float, duration: int = 1) -> None:
|
||||
"""
|
||||
增加突破成功率(临时效果)
|
||||
@@ -259,6 +293,11 @@ class Avatar(
|
||||
self.thinking = ""
|
||||
self.short_term_objective = ""
|
||||
|
||||
# 释放所有拥有的洞府
|
||||
# 复制列表进行遍历,因为 release_region 会修改列表
|
||||
for region in list(self.owned_regions):
|
||||
self.release_region(region)
|
||||
|
||||
if self.sect:
|
||||
self.sect.remove_member(self)
|
||||
|
||||
|
||||
@@ -114,10 +114,12 @@ class AvatarManager:
|
||||
avatar.clear_relation(other)
|
||||
|
||||
# 2. 清理占据的洞府
|
||||
if getattr(avatar, "world", None) and hasattr(avatar.world, "map"):
|
||||
for region in avatar.world.map.regions.values():
|
||||
if getattr(region, "host_avatar", None) == avatar:
|
||||
if hasattr(avatar, "owned_regions") and avatar.owned_regions:
|
||||
for region in list(avatar.owned_regions):
|
||||
# 仅解除关系,不触发其他逻辑
|
||||
if region.host_avatar == avatar:
|
||||
region.host_avatar = None
|
||||
avatar.owned_regions.clear()
|
||||
|
||||
# 3. 扫一遍所有角色(含死者),确保清除反向引用
|
||||
for other in self._iter_all_avatars():
|
||||
|
||||
@@ -106,7 +106,7 @@ class Occupy(MutualAction):
|
||||
if feedback_name == "Yield":
|
||||
# 对方让步:直接转移所有权
|
||||
if region:
|
||||
region.host_avatar = self.avatar
|
||||
self.avatar.occupy_region(region)
|
||||
|
||||
# 共用一个事件
|
||||
event_text = t("{initiator} forced {target} to yield {region}",
|
||||
@@ -131,7 +131,7 @@ class Occupy(MutualAction):
|
||||
# 进攻方胜利则洞府易主
|
||||
attacker_won = winner == self.avatar
|
||||
if attacker_won and region:
|
||||
region.host_avatar = self.avatar
|
||||
self.avatar.occupy_region(region)
|
||||
|
||||
self._last_result = (winner, loser, loser_dmg, winner_dmg, region_name, attacker_won)
|
||||
|
||||
|
||||
@@ -261,7 +261,9 @@ def load_game(save_path: Optional[Path] = None) -> Tuple["World", "Simulator", L
|
||||
if rid in game_map.regions:
|
||||
region = game_map.regions[rid]
|
||||
if isinstance(region, CultivateRegion) and avatar_id in all_avatars:
|
||||
region.host_avatar = all_avatars[avatar_id]
|
||||
avatar = all_avatars[avatar_id]
|
||||
# 使用 occupy_region 建立双向绑定
|
||||
avatar.occupy_region(region)
|
||||
|
||||
# 重建宗门成员关系与功法列表
|
||||
from src.classes.technique import techniques_by_name
|
||||
|
||||
@@ -82,7 +82,7 @@ class Simulator:
|
||||
if region.host_avatar is None:
|
||||
if avatar.id not in avatars_with_home:
|
||||
# 占据
|
||||
region.host_avatar = avatar
|
||||
avatar.occupy_region(region)
|
||||
avatars_with_home.add(avatar.id)
|
||||
# 记录事件
|
||||
event = Event(
|
||||
|
||||
Reference in New Issue
Block a user