Skip to content

Commit c28b4eb

Browse files
authored
Fix isElementStreamedIn returning false for localPlayer (multitheftauto#4836)
#### Summary Fixes isElementStreamedIn(localPlayer) returning false on the client in some contexts. The local player is, by definition, always streamed in from its own client's perspective returning false here is a contract break. Fix is scoped to the Lua binding (CLuaElementDefs::IsElementStreamedIn): when the queried element is the local player, return true directly. Internal C++ uses of IsStreamedIn() are untouched, so no engine-side behavior change. ``` if (IS_PLAYER(pEntity) && static_cast<CClientPlayer*>(pEntity)->IsLocalPlayer()) { lua_pushboolean(luaVM, true); return 1; } ``` #### Motivation This worked in 1.6 and broke in 1.7. The local player is created through a dedicated path (_CreateLocalModel) that doesn't go through the regular streamer's stream-in flow, so its internal m_bStreamedIn flag stays false by default. In 1.6 the old streamer happened to flip it on as a side effect of how it sorted/picked elements every frame; after the streamer refactor that side effect is gone. The bug doesn't always reproduce, in normal gameplay the streamer keeps pulling the local player back in often enough that the flag ends up true and nothing looks broken. But in less typical setups (custom interior/dimension, camera framed away from the ped, idle ped, basically any in-game UI that takes over the camera and parks the player aside, like a garage), the streamer doesn't reach the local player and the flag stays false permanently. The visible impact is that this very common pattern silently stops working in those contexts: ``` setElementData(localPlayer, "mykey", data) addEventHandler("onClientElementDataChange", root, function(dataName) if dataName == "mykey" and isElementStreamedIn(source) then -- update something end end) ``` The event still fires, but the isElementStreamedIn(source) guard now drops every update because source is localPlayer. We hit it on multiple unrelated systems in our resource (garage body parts preview, window tints preview), everything works in the open world, breaks the moment the player enters our garage. #### Test plan Reproducer: Reproducing the actual bug requires a specific in-game UI context (custom dimension/interior + camera moved off the player), which isn't easy to share as a minimal snippet. The behavioral check itself is simple in any context where you can call it from the local client: isElementStreamedIn(localPlayer) Before the fix: can return false depending on context. After the fix: always returns true for the local player. #### Checklist * [X] Your code should follow the [coding guidelines](https://wiki.multitheftauto.com/index.php?title=Coding_guidelines). * [X] Smaller pull requests are easier to review. If your pull request is beefy, your pull request should be reviewable commit-by-commit.
1 parent d446b9c commit c28b4eb

1 file changed

Lines changed: 10 additions & 0 deletions

File tree

Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,6 +1592,16 @@ int CLuaElementDefs::IsElementStreamedIn(lua_State* luaVM)
15921592
// Is this a streaming compatible class?
15931593
if (pEntity->IsStreamingCompatibleClass())
15941594
{
1595+
// Local player is always streamed in from its own perspective.
1596+
// Its entity is created via _CreateLocalModel() which doesn't go through
1597+
// InternalStreamIn(), so m_bStreamedIn can stay false even though the player
1598+
// is fully active — breaking scripts that filter handlers with isElementStreamedIn(source).
1599+
if (IS_PLAYER(pEntity) && static_cast<CClientPlayer*>(pEntity)->IsLocalPlayer())
1600+
{
1601+
lua_pushboolean(luaVM, true);
1602+
return 1;
1603+
}
1604+
15951605
CClientStreamElement* pStreamElement = static_cast<CClientStreamElement*>(pEntity);
15961606

15971607
// Return whether or not this class is streamed in

0 commit comments

Comments
 (0)