Skip to content

player:SetEventStatus(...) Lua binding is a no-op — scripted trigger enable/disable silently does nothing #187

Description

@pretema

Summary

map-server/src/lua/userdata.rs:2884:

methods.add_method("SetEventStatus", |_, _this, _status: Value| Ok(()));

The status argument is discarded and the method returns immediately —
nothing is pushed onto the script's CommandQueue, so a Lua-level call to
player:SetEventStatus(...) never produces a LuaCommand, never reaches
apply_*, and never emits a 0x0136 SetEventStatusPacket to the client.

This is a different code path from the system-level SetEventStatus
emission in world_manager.rs (build_set_event_status, used at spawn/init
to enable a director's or NPC's event conditions — that path is real and
already correctly wired, with detailed packet-capture-diffed comments
explaining exactly why it's needed). The bug is specifically in the
script-callable binding — when content Lua calls player:SetEventStatus(...)
directly (as opposed to the engine emitting it automatically at spawn), the
call is silently swallowed.

Where it's actually called

6 call sites across the man0l0 (Limsa)/man0u0 (Ul'dah) opening-tutorial
scripts, all toggling a push-trigger's enabled state in response to a quest
flag:

scripts/lua/unique/wil0Battle01/PopulaceStandard/ascilia.lua:17,27
scripts/lua/unique/wil0Battle01/PopulaceStandard/exit_trigger.lua:9
scripts/lua/unique/ocn0Battle02/PopulaceStandard/rostnsthal.lua
scripts/lua/unique/ocn0Battle02/PopulaceStandard/exit_door.lua
scripts/lua/unique/fst0Battle03/PopulaceStandard/yda.lua
scripts/lua/directors/OpeningDirector.lua:39,55

Example (exit_trigger.lua:9): once all three mini-tutorial flags are set,
the script calls player:SetEventStatus(npc, "pushDefault", true, 0x2) to
enable the exit door's push trigger so the player can walk out of the
tutorial area. With the binding a no-op, that enable never reaches the
client — the trigger's initial (disabled, or whatever world_manager.rs
set at spawn) state just... stays put. ascilia.lua uses the same call to
disable a trigger once its own step is done.

Given how much work has already gone into man0u0/man0l0 SEQ_000 softlock
fixes (e.g. PR #39 "fix(#25): Limsa Man0l0 SEQ_000 softlock"), this seemed
worth flagging directly — a script-level enable/disable that silently does
nothing is a plausible contributor to exactly this class of bug if any
remaining tutorial-progression softlocks trace back to one of these 6 call
sites.

Lineage note

The same conceptual bug exists in the original C# reference implementation:
Player.cs::SetEventStatus builds a SetEventStatusPacket but never calls
QueuePacket() on it (every sibling method — KickEventSpecial,
RunEventFunction, EndEvent — does). So this isn't something the Rust
port introduced; it looks like a faithful (if accidental) port of an
upstream gap. Filing here rather than (or in addition to) Bitbucket since
this port's implementation is directly reproducible and actively
maintained.

Suggested fix shape

Push a LuaCommand (something like SetEventStatus { player_id, actor_id, condition_name, enabled, kind }) from the binding, mirroring the existing
build_set_event_status packet builder in packets/send/actor.rs, and add
an apply_set_event_status in the runtime applier. I haven't attempted the
fix myself — didn't want to guess at the CommandQueue/applier plumbing
without being able to build and boot-test this repo locally — but wanted to
report it with the exact file/line and call sites since they were
straightforward to pin down.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Garlemald ServerFor work units related to Garlemald Server.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions