This commit is contained in:
bridge
2025-12-20 21:16:09 +08:00
parent 8fb81c3473
commit 57c669be47
5 changed files with 59 additions and 25 deletions

View File

@@ -137,7 +137,7 @@ class ActionMixin:
# 合并动作返回的事件(通常为空)
if result.events:
for e in result.events:
self._pending_events.append(e)
self.add_event(e)
events, self._pending_events = self._pending_events, []
# 本轮已执行过,清除"新设动作"标记但如果刚刚提交了新动作commit_next_plan会重新设置为True
if self.current_action is None:

View File

@@ -11,6 +11,12 @@ from src.classes.observe import get_observable_avatars
class AvatarManager:
avatars: Dict[str, "Avatar"] = field(default_factory=dict)
def get_avatar(self, avatar_id: str) -> "Avatar | None":
"""
根据 ID 获取角色对象
"""
return self.avatars.get(str(avatar_id))
def get_avatars_in_same_region(self, avatar: "Avatar") -> List["Avatar"]:
"""
返回与给定 avatar 处于同一区域的其他角色列表(不含自己)。

View File

@@ -1,5 +1,5 @@
from __future__ import annotations
from typing import TYPE_CHECKING, List, Tuple
from typing import TYPE_CHECKING, List, Tuple, Optional
from src.classes.relation import (
Relation,
@@ -12,7 +12,6 @@ from src.classes.relations import (
)
from src.classes.calendar import get_date_str
from src.classes.event import Event
from src.classes.action.event_helper import EventHelper
from src.utils.llm import call_llm_with_template, LLMMode
from src.utils.config import CONFIG
@@ -50,8 +49,9 @@ class RelationResolver:
return {
"relation_rules_desc": get_relation_rules_desc(),
"avatar_a_info": str(avatar_a.get_info(detailed=True)),
"avatar_a_name": avatar_a.name,
"avatar_a_info": str(avatar_a.get_info(detailed=True)),
"avatar_b_name": avatar_b.name,
"avatar_b_info": str(avatar_b.get_info(detailed=True)),
"current_relations": f"目前关系:{rel_desc}",
"recent_events_text": recent_events_text,
@@ -59,9 +59,9 @@ class RelationResolver:
}
@staticmethod
async def resolve_pair(avatar_a: "Avatar", avatar_b: "Avatar") -> None:
async def resolve_pair(avatar_a: "Avatar", avatar_b: "Avatar") -> Optional[Event]:
"""
处理一对角色的关系变化
处理一对角色的关系变化,返回产生的事件
"""
infos = RelationResolver._build_prompt_data(avatar_a, avatar_b)
@@ -69,7 +69,7 @@ class RelationResolver:
changed = result.get("changed", False)
if not changed:
return
return None
month_stamp = avatar_a.world.month_stamp
@@ -78,15 +78,16 @@ class RelationResolver:
reason = result.get("reason", "")
if not rel_name:
return
return None
# 解析关系枚举
try:
rel = Relation[rel_name]
except KeyError:
return
return None
display_name = relation_display_names.get(rel, rel_name)
event = None
if c_type == "ADD":
# 检查是否已有
@@ -106,31 +107,55 @@ class RelationResolver:
current_rel = avatar_b.get_relation(avatar_a)
if current_rel == rel:
return
return None
set_relation(avatar_b, avatar_a, rel)
event_text = f"【关系新增】{reason}{avatar_a.name}{avatar_b.name}{display_name}"
event_text = f"{avatar_a.name}{avatar_b.name}因为{reason}{display_name}"
event = Event(month_stamp, event_text, related_avatars=[avatar_a.id, avatar_b.id], is_major=True)
EventHelper.push_pair(event, initiator=avatar_a, target=avatar_b, to_sidebar_once=True)
elif c_type == "REMOVE":
# 同样反转调用
success = cancel_relation(avatar_b, avatar_a, rel)
if success:
event_text = f"【关系断绝】{reason}{avatar_a.name}{avatar_b.name} 不再是{display_name}"
event_text = f"{avatar_a.name}{avatar_b.name} 因为{reason}不再是{display_name}"
event = Event(month_stamp, event_text, related_avatars=[avatar_a.id, avatar_b.id], is_major=True)
EventHelper.push_pair(event, initiator=avatar_a, target=avatar_b, to_sidebar_once=True)
if event:
# 手动调用 add_event(to_sidebar=False) 来更新统计数据,但不加入 pending_events
# 因为事件将由 Simulator 统一处理
avatar_a.add_event(event, to_sidebar=False)
avatar_b.add_event(event, to_sidebar=False)
return event
return None
@staticmethod
async def run_batch(pairs: List[Tuple["Avatar", "Avatar"]]) -> None:
async def run_batch(pairs: List[Tuple["Avatar", "Avatar"]]) -> List[Event]:
"""
批量并发处理
批量并发处理,返回产生的所有事件
"""
if not pairs:
return
return []
async with AITaskBatch() as batch:
for a, b in pairs:
batch.add(RelationResolver.resolve_pair(a, b))
events = []
# 使用 asyncio.gather 而不是 AITaskBatch.gather因为 AITaskBatch 没有 gather 方法
import asyncio
tasks = []
for a, b in pairs:
# 创建协程任务但不立即 await
tasks.append(RelationResolver.resolve_pair(a, b))
if not tasks:
return []
# 并发执行所有任务
results = await asyncio.gather(*tasks)
# 收集结果
for res in results:
if res and isinstance(res, Event):
events.append(res)
return events

View File

@@ -350,11 +350,14 @@ class Simulator:
t_state["count"] = 0
t_state["checked_times"] += 1
events = []
if pairs_to_resolve:
# 批量并发处理
await RelationResolver.run_batch(pairs_to_resolve)
# 批量并发处理,并直接收集返回的事件
relation_events = await RelationResolver.run_batch(pairs_to_resolve)
if relation_events:
events.extend(relation_events)
return []
return events
async def step(self):
"""

View File

@@ -29,5 +29,5 @@
"changed": true | false, // 是否发生关系变更。如无必要,请填 false
"change_type": "ADD" | "REMOVE", // 变更类型。changed为false时可忽略
"relation": "LOVERS" | "FRIEND" | "ENEMY" | "MASTER" ... (必须是大写枚举名), // 涉及的关系。changed为false时可忽略。注意是{avatar_a_name}相对于{avatar_b_name}的身份。如输出MASTER即A变为B的师傅。
"reason": "..." // 用于生成事件日志如“经过多次生死与共A与B结为道侣”。changed为false时可忽略
"reason": "..." // 简述原因,名词,类似“意气相投”。changed为false时可忽略
}}