Facepunch / garrysmod-issues

Garry's Mod issue tracker
141 stars 56 forks source link

Parented Clientside Models FUBAR on loss of PVS #861

Open trptmx opened 10 years ago

trptmx commented 10 years ago

When leaving the PVS of a SENT (all that I've tested with) any parented clientside models will permanently lose their parenting and float detached from the entity. It'll still say it's parented when running GetParent making it difficult to detect.

I've gotten around it using

function ENT:UpdateTransmitState()
return TRANSMIT_ALWAYS end

robotboy655 commented 10 years ago

This seems to be the same with weapons when you enter a vehicle and get out of it. The bonemerged clientside models will detach when you leave the vehicle.

Python1320 commented 8 years ago

This is not really a bug. When entities go out of PVS they become dormant or rather half-removed. If a "fullupdate" happens they actually become removed as far as the client is concerned, until you see the entity again that is. Hook NetworkEntityCreated to see when entities reappear and for when entities become dormant hook for example NotifyShouldTransmit and remove/hide your clientside model.

LeQuackers commented 3 years ago

I think I found part of the issue. When normal entities are removed because of a full update or from becoming dormant C_BaseEntity::UnlinkFromHierarchy is called (fullupdate, dormant), which causes their children to be unlinked as well. Normally this would be fine because the parenting is fixed here using m_hNetworkMoveParent after an update; however, because clientside entities aren't affected by full updates or pvs C_BaseEntity::PostDataUpdate is never called.

test code for cl_fullupdate fix:

hook.Add("NotifyShouldTransmit", "test", function(ent, transmit)
    if ent == LocalPlayer() then
        local tbl = ents.GetAll()
        for i=1, #tbl do
            local v = tbl[i]
            if v:EntIndex() == -1 then
                v:SetParent(v:GetInternalVariable("m_hNetworkMoveParent"))
            end
        end
    end
end)
LeQuackers commented 3 years ago

test code for cl_fullupdate + pvs fix:

local parentLookup = {}
local function cacheParents()
    parentLookup = {}
    local tbl = ents.GetAll()
    for i=1, #tbl do
        local v = tbl[i]
        if v:EntIndex() == -1 then
            local parent = v:GetInternalVariable("m_hNetworkMoveParent")
            local children = parentLookup[parent]
            if not children then children = {}; parentLookup[parent] = children end
            children[#children + 1] = v
        end
    end
end

local function fixChildren(parent, transmit)
    local tbl = parentLookup[parent]
    if tbl then
        for i=1, #tbl do
            local child = tbl[i]
            if transmit then
                print("parented " .. tostring(child) .. " to " .. tostring(parent))
                child:SetNoDraw(false)
                child:SetParent(parent)
                fixChildren(child, transmit)
            else
                print("parent " .. tostring(parent) .. " is dorment. hiding " .. tostring(child))
                child:SetNoDraw(true)
                fixChildren(child, transmit)
            end
        end
    end
end

local lastTime = 0
hook.Add("NotifyShouldTransmit", "test", function(ent, transmit)
    local time = RealTime()
    if lastTime < time then
        cacheParents()
        lastTime = time
    end

    fixChildren(ent, transmit)
end)