Przeglądaj źródła

fix(apilot): scheduler 2-arg Schedule + cross-unschedule KeyError

wuzilong 1 miesiąc temu
rodzic
commit
350d25e5cc
2 zmienionych plików z 30 dodań i 2 usunięć
  1. 5 2
      apilot/stubs/scheduler.py
  2. 25 0
      tests/test_scheduler.py

+ 5 - 2
apilot/stubs/scheduler.py

@@ -26,7 +26,10 @@ class Scheduler:
 
     def tick(self, dt: float) -> None:
         for eid in list(self._timers):
-            fn, interval, elapsed, repeat = self._timers[eid]
+            entry = self._timers.get(eid)
+            if entry is None:  # 回调内已 unschedule 本 tick 未遍历的条目
+                continue
+            fn, interval, elapsed, repeat = entry
             elapsed += dt
             if elapsed >= interval:
                 if repeat:
@@ -41,7 +44,7 @@ class Scheduler:
 def install_scheduler(lua, sched: Scheduler) -> None:
     py_sched = sched  # Lupa: Python 对象直接可见
 
-    def lua_schedule(fn, interval: float, loops) -> int:
+    def lua_schedule(fn, interval: float, loops=None) -> int:
         # 游戏里 Schedule(fn, interval, loops) 第三参 nil/缺省=循环, >0=一次性
         if loops is None or loops == 0:
             return py_sched.schedule(fn, float(interval))

+ 25 - 0
tests/test_scheduler.py

@@ -35,6 +35,31 @@ def test_schedule_repeats():
         s.tick(0.05)
     assert rt.eval("n") == 3
 
+def test_schedule_two_arg_repeats():
+    """Schedule 两参调用(第三参缺省)按循环语义注册。"""
+    rt = lj.LuaRuntime()
+    install_scheduler(rt, Scheduler())
+    rt.execute("n = 0; id = Schedule(function() n = n + 1 end, 0.05)")
+    for _ in range(3):
+        s = rt.globals()["SL_getScheduler"]()
+        s.tick(0.05)
+    assert rt.eval("n") == 3
+
+def test_cross_unschedule_within_tick():
+    """A 到期回调里 UnSchedule(B) 不崩, 且 B 不再触发。"""
+    rt = lj.LuaRuntime()
+    s = Scheduler()
+    install_scheduler(rt, s)
+    rt.execute(
+        "hits = 0; "
+        "id_b = Schedule(function() hits = hits + 1 end, 0.05); "
+        "Schedule(function() UnSchedule(id_b) end, 0.05)"
+    )
+    s.tick(0.05)  # A、B 同时到期: A 先注册先遍历, 回调里取消 B
+    s.tick(0.05)
+    s.tick(0.05)
+    assert rt.eval("hits") == 1
+
 def test_unschedule():
     s = Scheduler()
     hits = []