fix action being executed 3 times bug

This commit is contained in:
bridge
2026-01-06 23:41:21 +08:00
parent 35c0756e85
commit e4ff312f58
3 changed files with 32 additions and 17 deletions

View File

@@ -141,9 +141,11 @@ class ActionMixin:
for e in result.events:
self.add_event(e)
events, self._pending_events = self._pending_events, []
# 本轮已执行过,清除"新设动作"标记但如果刚刚提交了新动作commit_next_plan会重新设置为True
if self.current_action is None:
# 当前无动作时才清除标记,避免清除新提交动作的标记
# 本轮已执行过,清除"新设动作"标记
# 1. 动作结束 (None)
# 2. 动作继续执行且未发生切换 (is action_instance_before)
# 注意:如果动作发生了切换(如 Escape -> Attack则视为新动作不清除标记以便 Simulator 进行下一轮调度
if self.current_action is None or self.current_action is action_instance_before:
self._new_action_set_this_step = False
return events

View File

@@ -128,26 +128,39 @@ class Simulator:
执行阶段:推进当前动作,支持同月链式抢占即时结算,返回期间产生的事件。
TODO: 为单个角色的 tick_action() 添加 try-except 处理。
当前如果任一角色的动作执行抛出异常,整个 step() 会失败,
导致 month_stamp 不会推进,游戏卡在同一个月份无限循环。
"""
events = []
MAX_LOCAL_ROUNDS = 3
for _ in range(MAX_LOCAL_ROUNDS):
new_action_happened = False
for avatar in self.world.avatar_manager.get_living_avatars():
# 本轮执行前若标记为新设,则清理,执行后由 Avatar 再统一清除
if getattr(avatar, "_new_action_set_this_step", False):
new_action_happened = True
# Round 1: 全员执行一次
avatars_needing_retry = set()
for avatar in self.world.avatar_manager.get_living_avatars():
new_events = await avatar.tick_action()
if new_events:
events.extend(new_events)
# 检查是否有新动作产生(抢占/连招),如果有则加入下一轮
# 注意tick_action 内部已处理标记清除逻辑,仅当动作发生切换时才会保留 True
if getattr(avatar, "_new_action_set_this_step", False):
avatars_needing_retry.add(avatar)
# Round 2+: 仅执行有新动作的角色,避免无辜角色重复执行
round_count = 1
while avatars_needing_retry and round_count < MAX_LOCAL_ROUNDS:
current_avatars = list(avatars_needing_retry)
avatars_needing_retry.clear()
for avatar in current_avatars:
new_events = await avatar.tick_action()
if new_events:
events.extend(new_events)
# 若在本次执行后产生了新的动作(被别人抢占设立),则标志位会在 commit_next_plan 时被置 True
# 再次检查
if getattr(avatar, "_new_action_set_this_step", False):
new_action_happened = True
# 若本轮未检测到新动作产生,则结束本地循环
if not new_action_happened:
break
avatars_needing_retry.add(avatar)
round_count += 1
return events
def _phase_resolve_death(self):

View File

@@ -68,7 +68,7 @@ def execute_gather(
base_quantity = 1
extra_items = int(avatar.effects.get(extra_effect_key, 0) or 0)
total_quantity = max(1, base_quantity + extra_items)
total_quantity = base_quantity + extra_items
avatar.add_item(item, total_quantity)