Remove on E hold

Im trying to make an entity get removed after you hold e on it for some time. it works good for when just one entity is spawned on the map but when theres more than 1, it bugs and doesn’t work anymore.

client:


include("shared.lua")

progress = 0
local ply = LocalPlayer()

function ENT:Draw()
    self:DrawModel()
    local tr = ply:GetEyeTrace()

    if tr.Entity.PrintName == "Poop" and input.IsKeyDown(KEY_E) then
        progress = Lerp(FrameTime() * 1, progress, 100)

        print(progress)

        if progress > 97 then
            net.Start("zPoopRemoveEntity")
            net.SendToServer()
        end
    else
        progress = 0
    end
end

server:


AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")
util.AddNetworkString("zPoopRemoveEntity")

function ENT:Initialize()
    self:SetModel("models/poo/poo.mdl")
    self:PhysicsInit(SOLID_VPHYSICS)
    self:SetMoveType(MOVETYPE_VPHYSICS)
    self:SetSolid(SOLID_VPHYSICS)
    self:SetUseType(SIMPLE_USE)
    local phys = self:GetPhysicsObject()
    phys:Wake()

    net.Receive("zPoopRemoveEntity", function()
        if self:IsValid() then
            self:Remove()
        end
    end)
end

What I noticed is that if i spawn more than 1 entity, when you hold e on any of them, it always removes the last spawned entity. Any ideas on what I’m doing wrong?

That would be because network strings (in your case, zPoopRemoveEntity) are unique and overwritten every time you create a new entity. To address this you can add a number like the entity’s EntIndex to the string to make it unique or pass the entity in the net message and remove that instead.

BUT DO NOT DO THIS, THE WAY YOU ARE DOING IS VERY WRONG. You are essentially trusting the client to remove the entity when it’s the server’s role to know if the player held E like expected. Right now I could just send the zPoopRemoveEntity net message anywhere once and the entity will be removed. You should use

ENT:Think in the server to handle the removing part.

I kind of went the hacky way around, not sure if this even works but…


-- Maximum range for deleting an entity
local maxDeleteRange = 1200;

-- Hold time(in seconds) for the entity to be removed
local holdTime = 60;

-- Entities which can not be blacklisted
local entityRemoveBlacklist = {
    "prop_vehicle_jeep",
    -- etc. etc.
}

-- Called when a player presses a key
hook.Add( "KeyPress", "RemoveKeyOnHold", function( ply, key )

    -- Checks if the key is the player's use key(default E)
    if ( key == IN_USE ) then
        local traceEntity = ply:GetEyeTraceNoCursor().Entity
        
        -- Make sure the entity is valid
        if( !IsValid( traceEntity ) ) then return end
        
        -- Check if the entity is not in the blacklist.
        if( entityRemoveBlacklist[ traceEntity:GetClass() ] ) then return end
        
        -- Check if the entity is in range, and create a timer to delete it.
        if( ply:GetPos():Distance( traceEntity:GetPos() ) < maxDeleteRange ) then
            timer.Create( "plyDeleteEntity_" .. ply:SteamID(), holdTime, 1, function()
                -- Remove it!
                print("Ent removed lol")
                traceEntity:Remove()
            end )
        end
    end
    
end )

-- If he lets go, remove his progress!
hook.Add( "KeyRelease", "IsPlayerStillHolding", function( ply, key )
    if ( key == IN_USE ) then
        if( timer.Exists( "plyDeleteEntity_" .. ply:SteamID() ) ) then
            timer.Remove( "plyDeleteEntity_" .. ply:SteamID() )
        end
    end
end )

-- Called every tick, we will check if the player is still removing the entity.
hook.Add( "Think", "CanStillRemoveCheck", function()
    for k, v in pairs( player.GetAll() ) do
        -- If he even is trying to remove an entity
        if( timer.Exists( "plyDeleteEntity_" .. v:SteamID() ) ) then
            -- Check distance and if he is still facing it
            local eyeTraceEntity = v:GetEyeTraceNoCursor().Entity
            
            if( !IsValid( eyeTraceEntity ) or v:GetPos():Distance( eyeTraceEntity:GetPos() ) > maxDeleteRange ) then
                timer.Remove( "plyDeleteEntity_" .. v:SteamID() )
            end
        end
    end
end )

EDIT: just fixed it. I forgot some stuff :frowning:
EDIT again: To make it work in SP I just changed everything from SteamID64 to SteamID, it works just fine :slight_smile:

That is a very expensive call you’re using on Think, to be honest. What about you create a variable inside the entity, and on ENT:Use it decreases a value whilst you’re holding the use key, and make sure the use type of the entity is not SIMPLE_USE. When it hits 0, run SafeRemoveEntity( self ) and voila.

Thanks everyone, I decided to go with the variable that increases while holding the use key all done on the server.