Skip to content

Commit 2261282

Browse files
authored
Add 5s cache for successful prop perm checks. Also introduces overrides (#2210)
* Add 5s cache for successful prop perm checks. Also introduces overrides * Make it just a single cache * Small cleanup
1 parent c05c87b commit 2261282

File tree

1 file changed

+164
-120
lines changed

1 file changed

+164
-120
lines changed

lua/starfall/permissions/providers_sh/entity.lua

Lines changed: 164 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -4,125 +4,89 @@ local owneraccess
44
if SERVER then
55
owneraccess = CreateConVar("sf_permissions_entity_owneraccess", "0", { FCVAR_ARCHIVE }, "Allows starfall chip's owner to access their player entity")
66
end
7-
8-
local P = {}
9-
P.id = "entities"
10-
P.name = "Entity Permissions"
11-
P.settingsoptions = { "Owner Only", "Can Tool", "Can Physgun", "Anything" }
12-
P.defaultsetting = 2
13-
local truefunc = function() return true end
14-
P.checks = {truefunc, truefunc, truefunc, truefunc}
15-
SF.Permissions.registerProvider(P)
7+
local cacheLifetime = CreateConVar("sf_permissions_entity_cachelife", "5", {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "How long to store successful prop permission checks before checking again")
168

179
local ENT_META,PLY_META = FindMetaTable("Entity"),FindMetaTable("Player")
1810
local Ent_GetNWEntity,Ent_GetTable,Ent_IsValid,Ent_SetNWEntity = ENT_META.GetNWEntity,ENT_META.GetTable,ENT_META.IsValid,ENT_META.SetNWEntity
1911
local Ply_IsSuperAdmin,Ply_SteamID64 = PLY_META.IsSuperAdmin,PLY_META.SteamID64
2012

13+
local checkOwner, checkCanTool, checkCanPhysgun
14+
2115
if CPPI then
2216
function SF.Permissions.getOwner(ent)
2317
return ent:CPPIGetOwner()
2418
end
2519

2620
if SERVER then
27-
P.checks = {
28-
function(instance, target)
29-
if not Ent_IsValid(target) then return false, "Entity is invalid" end
30-
if target == instance.player and owneraccess:GetBool() or
31-
Ply_IsSuperAdmin(instance.player) or
32-
target:CPPIGetOwner()==instance.player then return true end
33-
34-
return false, "You're not the owner of this prop"
35-
end,
36-
function(instance, target)
37-
if not Ent_IsValid(target) then return false, "Entity is invalid" end
38-
if target == instance.player and owneraccess:GetBool() or
39-
target:CPPICanTool(instance.player, "starfall_ent_lib") then return true end
40-
41-
return false, "You can't toolgun this entity"
42-
end,
43-
function(instance, target)
44-
if not Ent_IsValid(target) then return false, "Entity is invalid" end
45-
if target == instance.player and owneraccess:GetBool() or
46-
target:CPPICanPhysgun(instance.player) then return true end
47-
48-
return false, "You can't physgun this entity"
49-
end,
50-
"allow"
51-
}
21+
function checkOwner(instance, ent)
22+
if ent == instance.player and owneraccess:GetBool() then return true end
23+
if ent:CPPIGetOwner()==instance.player then return true end
24+
return false, "You're not the owner of this prop"
25+
end
26+
function checkCanTool(instance, ent)
27+
if ent == instance.player and owneraccess:GetBool() then return true end
28+
if ent:CPPICanTool(instance.player, "starfall_ent_lib") then return true end
29+
return false, "You can't toolgun this entity"
30+
end
31+
function checkCanPhysgun(instance, ent)
32+
if ent == instance.player and owneraccess:GetBool() then return true end
33+
if ent:CPPICanPhysgun(instance.player) then return true end
34+
return false, "You can't physgun this entity"
35+
end
5236
else
53-
P.checks = {
54-
function(instance, target)
55-
if not Ent_IsValid(target) then return false, "Entity is invalid" end
56-
if target==instance.player or
57-
LocalPlayer()==instance.player or
58-
Ply_IsSuperAdmin(instance.player) or
59-
target:CPPIGetOwner()==instance.player then return true end
60-
61-
return false, "You're not the owner of this prop"
62-
end,
63-
function(instance, target)
64-
if not Ent_IsValid(target) then return false, "Entity is invalid" end
65-
if target==instance.player or
66-
LocalPlayer()==instance.player or
67-
Ply_IsSuperAdmin(instance.player) or
68-
target:CPPICanTool(instance.player, "starfall_ent_lib") then return true end
69-
70-
return false, "You can't toolgun this entity"
71-
end,
72-
function(instance, target)
73-
if not Ent_IsValid(target) then return false, "Entity is invalid" end
74-
if target==instance.player or
75-
LocalPlayer()==instance.player or
76-
Ply_IsSuperAdmin(instance.player) or
77-
target:CPPICanPhysgun(instance.player) then return true end
78-
79-
return false, "You can't physgun this entity"
80-
end,
81-
"allow"
82-
}
83-
if not ENT_META.CPPICanTool then P.checks[2] = P.checks[1] end
84-
if not ENT_META.CPPICanPhysgun then P.checks[3] = P.checks[1] end
37+
function checkOwner(instance, ent)
38+
if ent==instance.player or LocalPlayer()==instance.player then return true end
39+
if ent:CPPIGetOwner()==instance.player then return true end
40+
return false, "You're not the owner of this prop"
41+
end
42+
function checkCanTool(instance, ent)
43+
if ent==instance.player or LocalPlayer()==instance.player then return true end
44+
if ent:CPPICanTool(instance.player, "starfall_ent_lib") then return true end
45+
return false, "You can't toolgun this entity"
46+
end
47+
function checkCanPhysgun(instance, ent)
48+
if ent==instance.player or LocalPlayer()==instance.player then return true end
49+
if ent:CPPICanPhysgun(instance.player) then return true end
50+
return false, "You can't physgun this entity"
51+
end
52+
if not ENT_META.CPPICanTool then checkCanTool = checkOwner end
53+
if not ENT_META.CPPICanPhysgun then checkCanPhysgun = checkOwner end
8554
end
8655
else
8756
if SERVER then
88-
P.checks = {
89-
function(instance, target)
90-
if not Ent_IsValid(target) then return false, "Entity is invalid" end
91-
if target == instance.player and owneraccess:GetBool() or
92-
Ply_IsSuperAdmin(instance.player) or
93-
P.props[target]==instance.player then return true end
94-
95-
return false, "You're not the owner of this prop"
96-
end,
97-
function(instance, target)
98-
if not Ent_IsValid(target) then return false, "Entity is invalid" end
99-
if target == instance.player and owneraccess:GetBool() or
100-
hook.Run("CanTool", instance.player, SF.dumbTrace(target), "starfall_ent_lib") ~= false then return true end
101-
102-
return false, "Target doesn't have toolgun access"
103-
end,
104-
function(instance, target)
105-
if not Ent_IsValid(target) then return false, "Entity is invalid" end
106-
if target == instance.player and owneraccess:GetBool() then return true end
107-
108-
if hook.Run("PhysgunPickup", instance.player, target) ~= false then
109-
-- Some mods expect a release when there's a pickup involved.
110-
hook.Run("PhysgunDrop", instance.player, target)
111-
return true
112-
end
57+
local PropOwners = SF.EntityTable("PropProtection")
58+
local PropOwnersDisconnected = SF.EntityTable("PropProtectionReconnect")
59+
SF.PropOwners = PropOwners
11360

114-
return false, "Target doesn't have physgun access"
115-
end,
116-
"allow"
117-
}
118-
119-
P.props = SF.EntityTable("PropProtection")
12061
function SF.Permissions.getOwner(ent)
121-
return P.props[ent] or NULL
62+
return PropOwners[ent] or NULL
63+
end
64+
65+
function checkOwner(instance, ent)
66+
if ent == instance.player and owneraccess:GetBool() then return true end
67+
if PropOwners[ent]==instance.player then return true end
68+
return false, "You're not the owner of this prop"
12269
end
70+
function checkCanTool(instance, ent)
71+
if ent == instance.player and owneraccess:GetBool() then return true end
72+
if hook.Run("CanTool", instance.player, SF.dumbTrace(ent), "starfall_ent_lib") ~= false then return true end
73+
return false, "You can't toolgun this entity"
74+
end
75+
function checkCanPhysgun(instance, ent)
76+
if ent == instance.player and owneraccess:GetBool() then return true end
77+
78+
if hook.Run("PhysgunPickup", instance.player, ent) ~= false then
79+
-- Some mods expect a release when there's a pickup involved.
80+
hook.Run("PhysgunDrop", instance.player, ent)
81+
return true
82+
end
83+
84+
return false, "You can't physgun this entity"
85+
end
86+
12387

12488
local function PropOwn(ply,ent)
125-
P.props[ent] = ply
89+
PropOwners[ent] = ply
12690
Ent_SetNWEntity(ent, "SFPP", ply)
12791
end
12892

@@ -148,42 +112,122 @@ else
148112
hook.Add("PlayerSpawnedSWEP", "SFPP.PlayerSpawnedSWEP", PropOwn)
149113
hook.Add("PlayerInitialSpawn","SFPP.PlayerInitialSpawn", function(ply)
150114
local steamid = Ply_SteamID64(ply)
151-
for k, v in pairs(P.props) do
115+
for k, v in pairs(PropOwnersDisconnected) do
152116
if v==steamid then
153117
PropOwn(ply,k)
154118
end
155119
end
156120
end)
157121
hook.Add("PlayerDisconnected","SFPP.PlayerDisconnected", function(ply)
158122
local steamid = Ply_SteamID64(ply)
159-
for k, v in pairs(P.props) do
123+
for k, v in pairs(PropOwners) do
160124
if v==ply then
161-
P.props[k] = steamid
125+
PropOwnersDisconnected[k] = steamid
126+
PropOwners[k] = nil
162127
end
163128
end
164129
end)
165130

166131
else
167-
P.checks = {
168-
function(instance, target)
169-
if not Ent_IsValid(target) then return false, "Entity is invalid" end
170-
if target==instance.player or
171-
LocalPlayer()==instance.player or
172-
Ply_IsSuperAdmin(instance.player) or
173-
Ent_GetNWEntity(target, "SFPP")==instance.player or
174-
target.SFHoloOwner==instance.player then return true end
175-
176-
return false, "You're not the owner of this prop"
177-
end,
178-
nil,
179-
nil,
180-
"allow"
181-
}
182-
P.checks[2] = P.checks[1]
183-
P.checks[3] = P.checks[1]
184-
185132
function SF.Permissions.getOwner(ent)
186133
return Ent_GetTable(ent).SFHoloOwner or Ent_GetNWEntity(ent, "SFPP")
187134
end
135+
136+
function checkOwner(instance, ent)
137+
if ent==instance.player or LocalPlayer()==instance.player then return true end
138+
if Ent_GetNWEntity(ent, "SFPP")==instance.player or Ent_GetTable(ent).SFHoloOwner==instance.player then return true end
139+
return false, "You're not the owner of this prop"
140+
end
141+
checkCanTool = checkOwner
142+
checkCanPhysgun = checkOwner
188143
end
189144
end
145+
146+
local overridesMeta = {__mode = "k"}
147+
148+
local EntityPermissionCache = {
149+
__index = {
150+
checkNormal = function(self, instance, ent, checkfunc)
151+
local t = CurTime()
152+
if t < self.timeout then return true end
153+
154+
local result, reason = checkfunc(instance, ent)
155+
if result then self.timeout = t + cacheLifetime:GetFloat() end
156+
return result, reason
157+
end,
158+
checkOverrides = function(self, instance, ent, checkfunc)
159+
local t = CurTime()
160+
if t < self.timeout then return true end
161+
162+
if table.IsEmpty(self.overrides) then
163+
self.check = self.checkNormal
164+
return self:check(instance, ent, checkfunc)
165+
end
166+
local result, reason
167+
for overrideInst in pairs(self.overrides) do
168+
result, reason = checkfunc(overrideInst, ent)
169+
if result then self.timeout = t + cacheLifetime:GetFloat() return true end
170+
self.overrides[overrideInst] = nil
171+
end
172+
return result, reason
173+
end,
174+
addOverride = function(self, instance)
175+
self.overrides[instance] = true
176+
self.check = self.checkOverrides
177+
end,
178+
removeOverride = function(self, instance)
179+
self.overrides[instance] = nil
180+
if table.IsEmpty(self.overrides) then
181+
self.check = self.checkNormal
182+
end
183+
end
184+
},
185+
__call = function(t)
186+
local ret = setmetatable({
187+
timeout = 0,
188+
overrides = setmetatable({}, overridesMeta)
189+
}, t)
190+
ret.check = ret.checkNormal
191+
return ret
192+
end
193+
}
194+
setmetatable(EntityPermissionCache, EntityPermissionCache)
195+
196+
local cacheMeta = {__mode="k", __index = function(t,k) local r=EntityPermissionCache() t[k]=r return r end}
197+
198+
local function getEntPermCache(ent_tbl, instance)
199+
local cache = ent_tbl.SF_EntPermCache
200+
if not cache then
201+
cache = setmetatable({}, cacheMeta)
202+
ent_tbl.SF_EntPermCache = cache
203+
end
204+
return cache[instance]
205+
end
206+
SF.GetEntPermCache = getEntPermCache
207+
208+
local function check(instance, ent, checkfunc)
209+
local ent_tbl = Ent_GetTable(ent)
210+
if not ent_tbl then return false, "Entity is invalid" end
211+
if Ply_IsSuperAdmin(instance.player) then return true end
212+
return getEntPermCache(ent_tbl, instance):check(instance, ent, checkfunc)
213+
end
214+
215+
SF.Permissions.registerProvider({
216+
id = "entities",
217+
name = "Entity Permissions",
218+
settingsoptions = { "Owner Only", "Can Tool", "Can Physgun", "Anything" },
219+
defaultsetting = 2,
220+
checks = {
221+
function(instance, ent)
222+
return check(instance, ent, checkOwner)
223+
end,
224+
function(instance, ent)
225+
return check(instance, ent, checkCanTool)
226+
end,
227+
function(instance, ent)
228+
return check(instance, ent, checkCanPhysgun)
229+
end,
230+
"allow"
231+
}
232+
})
233+

0 commit comments

Comments
 (0)