garrysmod
garrysmod copied to clipboard
Add ents/player iterators
This is an attempt to close Facepunch/garrysmod-requests/issues/738. Adds iterators for entities and players which are read-only and cached. The main benefit to this is performance; crossing over from Lua to C and back every function call is slow and creates a new table each call.
Examples of use:
for i, p in player.Iterator() do
print(p)
end
for i, e in ents.Iterator() do
if e:GetClass() == "prop_physics" then e:Remove() end
end
Can be improved by recaching GetAll in hooks not when you call the iterator, this allows to remove if Cache == nil
check entirely
Looks good.
Misc suggestion:
Instead of ipairs
you can get inext beforehand.
local inext = ipairs(EntityCache)
function entity.Iterator()
return inext, EntityCache, 0
end
One thing I don't like with this approach is that it will call ents.GetAll()
whenever an entity is created, which could be hundreds of times on map/server load, map cleanup and maybe server join, basically slowing down loading/freeze times.
One thing I don't like with this approach is that it will call
ents.GetAll()
whenever an entity is created, which could be hundreds of times on map/server load, map cleanup and maybe server join, basically slowing down loading/freeze times.
Maybe it should only set a flag variable to invalidate the cache:
local validCache = false
function player.Iterator()
if validCache then
PlayerCache = player.GetAll()
validCache = true
end
return inext, PlayerCache, 0
end
local function RefreshPlayerCache(ent)
if ent:IsPlayer() then
validCache = false
end
end
One thing I don't like with this approach is that it will call
ents.GetAll()
whenever an entity is created, which could be hundreds of times on map/server load, map cleanup and maybe server join, basically slowing down loading/freeze times.Maybe it should only set a flag variable to invalidate the cache:
local validCache = false function player.Iterator() if validCache then PlayerCache = player.GetAll() validCache = true end return inext, PlayerCache, 0 end local function RefreshPlayerCache(ent) if ent:IsPlayer() then validCache = false end end
if validCache then
should be if not validCache then
.
is there a reason why this isn't merged yet? like 99% of the time when player/ents.GetAll gets used is just to iterate it without ever using the table
with many addons, you have so many copies of the same table constantly getting created to be iterated when they could all just be iterating the same table
why depends on player.GetAll()
?
I would suggest doing it directly, like:
local PlayerCache = {}
hook.Add( "OnEntityCreated", "player.Iterator", function(ent)
if ( ent:IsPlayer() ) then
table.insert(PlayerCache, ent)
end
end )
hook.Add( "EntityRemoved", "player.Iterator", function(ent)
if ( ent:IsPlayer() ) then
for i = 1, #PlayerCache do
if ( PlayerCache[i] == ent ) then
table.remove(PlayerCache, i)
break
end
end
end
end )