You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix silent reconnect-mid-wizard stall in sanjiechuanshuo + catalog new §7.37 class
d/wiz/init.lpc: get_start0() (a reconnect-triggered call_out meant to
auto-resume a stalled gift-selection wizard) called me->command("start")
-- but the real command() efun takes no object argument; this is a
call_other to a method named "command" that is not defined anywhere on
the player object. FluffOS silently no-ops an undefined call_other with
no error anywhere, so a player reconnecting mid-wizard saw nothing at
all after "重新连线完毕。" -- no menu, no error, no hint -- while typing
the undocumented "start" command manually worked fine (confirmed live).
Fixed by replicating the target logic directly with tell_object(me, ...)
instead of write() (write() needs this_player() context, unset inside a
call_out) instead of round-tripping through the broken call. Verified
live: reconnecting to a mid-wizard account now auto-displays the gift
menu within seconds. A fresh uninterrupted registration was independently
confirmed to already work correctly end-to-end.
Cataloged as AGENTS.md §7.37 (new class): calling ob->efun_name(...)
where efun_name matches a real driver efun name, but no method of that
name is defined on ob, silently no-ops with zero error trace anywhere --
distinct from §8.3a's DECL_PRIVATE demotion (there was never a function
to dispatch to here at all).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VyQCUoTo1Z93Py9aVFHQi1
Copy file name to clipboardExpand all lines: AGENTS.md
+50Lines changed: 50 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2160,6 +2160,56 @@ save/quit that same handler exists to guarantee.
2160
2160
2161
2161
---
2162
2162
2163
+
### 7.37 Calling `ob->efun_name(...)` where `efun_name` matches a real driver efun, but no method of that name is actually defined on `ob`, silently no-ops
2164
+
2165
+
Found on `sanjiechuanshuo`'s deep functional test (§10.7): a room's
2166
+
reconnect-triggered `call_out` tried to automatically resume a stalled
2167
+
gift-selection wizard via `me->command("start")` — but the real
2168
+
`command()` efun (`core.spec`: `int command(string)`) takes NO object
2169
+
argument; it always operates on the current command-giver context.
2170
+
`ob->command(str)` is call_other syntax, which requires `ob` to define
2171
+
its OWN function literally named `command`, which nothing in this lib
2172
+
did anywhere (confirmed via a lib-wide grep). This driver raises NO
2173
+
error for a call_other to an undefined function — not to the caller,
2174
+
not to debug.log, nowhere — it just silently returns 0. The result was
2175
+
a completely silent dead end: a player reconnecting mid-wizard saw
2176
+
"重新连线完毕。" and then nothing else, forever, with zero indication
2177
+
anything was wrong, while the SAME verb typed directly by the player
2178
+
(going through the driver's own normal command dispatch, which doesn't
2179
+
depend on this broken call) worked perfectly fine — a discrepancy that
2180
+
made this easy to initially misdiagnose as "the add_action registration
2181
+
must be broken" when in fact it was fine.
2182
+
2183
+
This is a distinct trap from §8.3a (`private`→`DECL_HIDDEN` demotion
2184
+
breaking a real, DEFINED function's dispatch) — here there was never
2185
+
any function to dispatch to in the first place; the bug is confusing
2186
+
"an efun that happens to share this name" with "a method call," a
2187
+
mistake the compiler cannot catch because call_other targets are
2188
+
resolved dynamically at runtime, not statically.
2189
+
2190
+
Detection: whenever you see `ob-><efun_name>(...)` for any of this
2191
+
project's common efuns (`command`, `write`, `tell_object`, `message`,
2192
+
etc. — check the real signature in `core.spec` or the relevant
2193
+
package's `.spec` file), verify the target object actually defines a
2194
+
same-named method (grep the whole lib, not just the obvious base
2195
+
classes) before assuming the call does what its name suggests.
2196
+
Reproduce live by exercising the actual caller path (here: reconnect
2197
+
while mid-wizard, not just fresh registration) and watching for
2198
+
complete silence with no debug.log trace — that combination (call
2199
+
succeeds with no error, but visibly does nothing) is the tell.
2200
+
2201
+
Fix: replace the broken round-trip with a direct call to the underlying
2202
+
logic using the already-available explicit target object, being
2203
+
careful that anything relying on implicit `this_player()` context
2204
+
(`write()`, and similarly `tell_object`-adjacent, ambient-target efuns)
2205
+
gets rewritten to take the explicit target instead — `write()` and
2206
+
friends silently target `this_player()`, which is typically unset
2207
+
inside a `call_out`, so simply removing the broken `ob->command(...)`
2208
+
call without ALSO auditing what it was trying to reach just moves the
2209
+
silent-failure point one level deeper.
2210
+
2211
+
---
2212
+
2163
2213
## 8. Login and registration flow bugs
2164
2214
2165
2215
Registration is where restoration succeeds or fails: it exercises the
0 commit comments