Jump to content

.sleepstatepending boolean gets cleared late, making it unreliable to check through some events


hoxi
  • Pending
function OnEntitySleep(guid)
    local inst = Ents[guid]
    if inst then
        inst:PushEvent("entitysleep")

        if inst.OnEntitySleep then
            inst:OnEntitySleep()
        end

		inst:_DisableBrain_Internal()

        if inst.sg then
            SGManager:Hibernate(inst.sg)
        end

		inst.sleepstatepending = nil

        if inst.emitter then
            EmitterManager:Hibernate(inst.emitter)
        end

        for k,v in pairs(inst.components) do
            if v.OnEntitySleep then
                v:OnEntitySleep()
            end
        end
    end
end

Same applies to OnEntityWake.

 

The way it's done right now results in OnEntitySleep and OnEntityWake functions on an entity instance, as well as "entitysleep" and "entitywake" event listeners, to not be able to check for it properly. This can mainly be an issue with making common functions or common functionality shared across a few functions.

 

Here's an example:

Spoiler
local function InitLocalSoundEmitter(proxy, from_wake)
	-- shouldn't be needed but just in case
	if proxy.local_sound_emitter ~= nil and proxy.local_sound_emitter:IsValid() then
		proxy.local_sound_emitter:Remove()
		proxy.local_sound_emitter = nil -- to account for the mastersim checks below stopping things there
	end

	-- need to handle this this way for now
	-- .sleepstatepending check is not reliable for "entitysleep" or "entitywake" events for now
	if TheWorld.ismastersim then
		if from_wake then
			if proxy:IsInLimbo() then
				return
			end
		elseif proxy.sleepstatepending or proxy:IsAsleep() then
			return
		end
	end

	-- non-networked entity creation stuff here
end

local function RemoveLocalSoundEmitter(inst)
	if inst.local_sound_emitter ~= nil and inst.local_sound_emitter:IsValid() then
		inst.local_sound_emitter:Remove()
	end

	inst.local_sound_emitter = nil
end

-- for context, clients spawn the sound emitter whenever the relevant entity spawns for them (after 1 tick)
-- the server instead does the following:

local function OnEntityWake(inst)
	InitLocalSoundEmitter(inst, true) -- this is the only outlier due to the .sleepstatepending issue
end

-- in prefab postinit
inst:ListenForEvent("entitysleep", RemoveLocalSoundEmitter)
inst:ListenForEvent("entitywake", OnEntityWake)

inst:ListenForEvent("enterlimbo", RemoveLocalSoundEmitter)
inst:ListenForEvent("exitlimbo", InitLocalSoundEmitter)

 

 

 

On a related note..

function EntityScript:IsAsleep()
    return not self.entity:IsAwake()
end

Is there a reason this function doesn't check for .sleepstatepending?

If something checks for entity sleep, then you don't want it to go through during entity construction either (where entity:IsAwake() returns true as a false positive, but the entity is basically sleep and at 0, 0, 0), and there's plenty of cases like that that do it anyway.

Mostly, what's done because of it gets immediately undone right after on receiving sleep status, so it's just a waste of performance, but it could be worse and result in unintended behavior.

 

You can try logging if inst:IsAsleep() is called when .sleepstatepending is still true, and you'll see what I mean.

Keep in mind that there are some weird edge cases where entity:IsAwake() is checked instead of inst:IsAsleep(). Those should be updated to use the latter instead.


Steps to Reproduce

Self-explanatory.

  • Like 1



User Feedback


There are no comments to display.



Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
  • Create New...