Skip to content

Commit 1a7fa75

Browse files
authored
Lambda timers (#3142)
* init * Add getters + adjust method * deprecate original timers * Remove trailing whitespace from e2lib.lua * Bring back previously removed code lol * Get Vurv's internals implementations * Use ent:Execute instead of UnsafeExtCall * Slight indexing refactor * Update e2descriptions.lua * fix * Return UpdatePerf dep injection in ENT:Execute() * Use args instead of selfTbl.context when provided * Update init.lua
1 parent a67cd48 commit 1a7fa75

File tree

5 files changed

+277
-17
lines changed

5 files changed

+277
-17
lines changed

lua/entities/gmod_wire_expression2/base/compiler.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,8 @@ local CompileVisitors = {
14401440
function(args)
14411441
local s_scopes, s_scope, s_scopeid = state.Scopes, state.Scope, state.ScopeID
14421442

1443+
state.prf = state.prf + 10
1444+
14431445
local scope = { vclk = {} }
14441446
state.Scopes = inherited_scopes
14451447
state.ScopeID = after
@@ -1872,8 +1874,6 @@ local CompileVisitors = {
18721874
end
18731875
end, ret_type
18741876
elseif expr_ty == "f" then
1875-
self.scope.data.ops = self.scope.data.ops + 15 -- Since functions are 10 ops, this is pretty lenient. I will decrease this slightly when functions are made static and cheaper.
1876-
18771877
local nargs = #args
18781878
local sig = table.concat(arg_types)
18791879

lua/entities/gmod_wire_expression2/core/e2lib.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ end
271271
function Function:ExtCall(args, types, ctx)
272272
if self.arg_sig == types then
273273
local success,ret = pcall(self.fn,args)
274-
if success then
274+
if success then
275275
return ret
276276
else
277277
local _,msg,trace = E2Lib.unpackException(ret)
@@ -291,7 +291,7 @@ function Function:Ret()
291291
return self.ret
292292
end
293293

294-
--- If given the correct arguments, returns the inner untyped function you can call.
294+
--- If given the correct arguments, returns the inner untyped function you can then call with ENT:Execute(f).
295295
--- Otherwise, throws an error to the given E2 Context.
296296
---@param arg_sig string
297297
---@param ctx RuntimeContext

lua/entities/gmod_wire_expression2/core/timer.lua

Lines changed: 246 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,79 @@ local function RemoveTimer(self, name)
4646
end
4747
end
4848

49+
-- Lambda timers
50+
51+
local luaTimers = {
52+
/*EXAMPLE:
53+
'[342]e2entity' = {
54+
[342]e2entity_gmod_wire_expression2_luatimer_examplename = {
55+
context = {...} (e2 context),
56+
callback = {...} (e2 callback),
57+
delay = 1,
58+
repetitions = 1
59+
}
60+
}
61+
*/
62+
}
63+
64+
local luaTimerIncrementalKeys = {}
65+
66+
local function luaTimerGetNextIncrementalKey(self)
67+
local key = (luaTimerIncrementalKeys[self.entity:EntIndex()] or 0)+1
68+
luaTimerIncrementalKeys[self.entity:EntIndex()] = key
69+
return key
70+
end
71+
72+
local function luaTimerGetInternalName(entIndex, name)
73+
return entIndex .. '_gmod_wire_expression2_luatimer_' .. name
74+
end
75+
76+
local function luaTimerExists(self, name)
77+
local tbl = luaTimers[self.entity:EntIndex()]
78+
return tbl and tbl[name] and true or false
79+
end
80+
81+
local function luaTimerCreate(self, name, delay, repetitions, callback)
82+
local entIndex = self.entity:EntIndex()
83+
84+
if not luaTimers[entIndex] then
85+
luaTimers[entIndex] = {}
86+
elseif luaTimerExists(self, name) then
87+
return self:throw("Timer with name " .. name .. " already exists", nil)
88+
end
89+
90+
local internalName = luaTimerGetInternalName(self.entity:EntIndex(), name)
91+
local callback, ent = callback:Unwrap("", self), self.entity
92+
93+
luaTimers[entIndex][name] = {
94+
ent = ent,
95+
callback = callback,
96+
delay = delay,
97+
repetitions = repetitions
98+
}
99+
100+
timer.Create(internalName, delay, repetitions, function()
101+
ent:Execute(callback)
102+
103+
if timer.RepsLeft(internalName) == 0 then
104+
luaTimers[name] = nil
105+
end
106+
end)
107+
end
108+
109+
local function luaTimerRemove(self, name)
110+
local entIndex = self.entity:EntIndex()
111+
if not luaTimers[entIndex] then
112+
luaTimers[entIndex] = {}
113+
return self:throw("Timer with name " .. name .. " does not exist", nil)
114+
elseif not luaTimerExists(self, name) then
115+
return self:throw("Timer with name " .. name .. " does not exist", nil)
116+
end
117+
118+
timer.Remove(luaTimerGetInternalName(self.entity:EntIndex(), name))
119+
luaTimers[entIndex][name] = nil
120+
end
121+
49122
/******************************************************************************/
50123

51124
registerCallback("construct", function(self)
@@ -60,39 +133,47 @@ registerCallback("destruct", function(self)
60133
for name,_ in pairs(self.data['timer'].timers) do
61134
RemoveTimer(self, name)
62135
end
136+
137+
local entIndex = self.entity:EntIndex()
138+
for k, _ in pairs(luaTimers[entIndex] or {}) do
139+
timer.Remove(luaTimerGetInternalName(entIndex, k))
140+
end
141+
142+
luaTimers[entIndex] = nil
63143
end)
64144

65145
/******************************************************************************/
66146

67147
__e2setcost(20)
68-
148+
[deprecated = "Use lambda timers instead"]
69149
e2function void interval(rv1)
70150
AddTimer(self, "interval", rv1)
71151
end
72152

153+
[deprecated = "Use lambda timers instead"]
73154
e2function void timer(string rv1, rv2)
74155
AddTimer(self, rv1, rv2)
75156
end
76157

77158
__e2setcost(5)
78-
79159
e2function void stoptimer(string rv1)
80160
RemoveTimer(self, rv1)
161+
pcall(luaTimerRemove, self, rv1)
81162
end
82163

83164
__e2setcost(1)
84165

85-
[nodiscard]
166+
[nodiscard, deprecated = "Use lambda timers instead"]
86167
e2function number clk()
87168
return self.data.timer.runner == "interval" and 1 or 0
88169
end
89170

90-
[nodiscard]
171+
[nodiscard, deprecated = "Use lambda timers instead"]
91172
e2function number clk(string rv1)
92173
return self.data.timer.runner == rv1 and 1 or 0
93174
end
94175

95-
[nodiscard]
176+
[nodiscard, deprecated = "Use lambda timers instead"]
96177
e2function string clkName()
97178
return self.data.timer.runner or ""
98179
end
@@ -104,6 +185,12 @@ e2function array getTimers()
104185
i = i + 1
105186
ret[i] = name
106187
end
188+
189+
for k, _ in pairs( luaTimers[self.entity:EntIndex()] or {} ) do
190+
i = i + 1
191+
ret[i] = k
192+
end
193+
107194
self.prf = self.prf + i * 5
108195
return ret
109196
end
@@ -113,10 +200,164 @@ e2function void stopAllTimers()
113200
self.prf = self.prf + 5
114201
RemoveTimer(self,name)
115202
end
203+
204+
for k, _ in pairs(luaTimers[self.entity:EntIndex()] or {}) do
205+
self.prf = self.prf + 5
206+
luaTimerRemove(self, k)
207+
end
116208
end
117209

118210
/******************************************************************************/
211+
-- Lambda timers
212+
213+
__e2setcost(10)
214+
e2function void timer(string name, number delay, number repetitions, function callback)
215+
luaTimerCreate(self, name, delay, repetitions, callback)
216+
end
217+
218+
e2function string timer(number delay, number repetitions, function callback)
219+
local name = "simpletimer_"..luaTimerGetNextIncrementalKey(self)
220+
luaTimerCreate(self, name, delay, repetitions, callback)
221+
return name
222+
end
223+
224+
e2function string timer(number delay, function callback)
225+
local name = "simpletimer_"..luaTimerGetNextIncrementalKey(self)
226+
luaTimerCreate(self, name, delay, 1, callback)
227+
return name
228+
end
229+
230+
e2function void timer(string name, number delay, function callback)
231+
luaTimerCreate(self, name, delay, 1, callback)
232+
end
233+
234+
__e2setcost(5)
235+
e2function void timerSetDelay(string name, number delay)
236+
if not luaTimerExists(self, name) then
237+
return self:throw("Timer with name " .. name .. " does not exist", nil)
238+
end
239+
240+
local entIndex = self.entity:EntIndex()
241+
luaTimers[entIndex][name].delay = delay
242+
timer.Adjust(luaTimerGetInternalName(entIndex, name), delay, 0)
243+
end
244+
245+
e2function number timerSetReps(string name, number repetitions)
246+
if not luaTimerExists(self, name) then
247+
return self:throw("Timer with name " .. name .. " does not exist", nil)
248+
end
249+
250+
local entIndex = self.entity:EntIndex()
251+
luaTimers[entIndex][name].repetitions = repetitions
252+
timer.Adjust(luaTimerGetInternalName(entIndex, name), luaTimers[entIndex][name].delay, repetitions)
253+
end
254+
255+
e2function void timerAdjust(string name, number delay, number repetitions)
256+
if not luaTimerExists(self, name) then
257+
return self:throw("Timer with name " .. name .. " does not exist", nil)
258+
end
119259

260+
local entIndex = self.entity:EntIndex()
261+
luaTimers[entIndex][name].delay = delay
262+
luaTimers[entIndex][name].repetitions = repetitions
263+
timer.Adjust(luaTimerGetInternalName(entIndex, name), delay, repetitions)
264+
end
265+
266+
267+
__e2setcost(1)
268+
[nodiscard]
269+
e2function number timerGetDelay(string name)
270+
if not luaTimerExists(self, name) then
271+
return self:throw("Timer with name " .. name .. " does not exist", 0)
272+
end
273+
274+
return luaTimers[self.entity:EntIndex()][name].delay
275+
end
276+
277+
[nodiscard]
278+
e2function number timerGetReps(string name)
279+
if not luaTimerExists(self, name) then
280+
return self:throw("Timer with name " .. name .. " does not exist", 0)
281+
end
282+
283+
return luaTimers[self.entity:EntIndex()][name].repetitions
284+
end
285+
286+
[nodiscard]
287+
e2function function timerGetCallback(string name)
288+
if not luaTimerExists(self, name) then
289+
return self:throw("Timer with name " .. name .. " does not exist", "")
290+
end
291+
292+
return luaTimers[self.entity:EntIndex()][name].callback
293+
end
294+
295+
__e2setcost(5)
296+
e2function void timerRestart(string name)
297+
if not luaTimerExists(self, name) then
298+
return self:throw("Timer with name " .. name .. " does not exist", nil)
299+
end
300+
301+
local entIndex = self.entity:EntIndex()
302+
local internalName = luaTimerGetInternalName(entIndex, name)
303+
304+
timer.Adjust(internalName, luaTimers[entIndex][name].delay, luaTimers[entIndex][name].repetitions)
305+
end
306+
307+
__e2setcost(1)
308+
[nodiscard]
309+
e2function number timerExists(string name)
310+
return luaTimerExists(self, name) and 1 or 0
311+
end
312+
313+
e2function void timerPause(string name)
314+
if not luaTimerExists(self, name) then
315+
return self:throw("Timer with name " .. name .. " does not exist", 0)
316+
end
317+
318+
--return timer.Pause(luaTimerGetInternalName(self.entity:EntIndex(), name)) and 1 or 0 -- This is commented due to timer.Pause being broken for some reason. It just does not return anything.
319+
timer.Pause(luaTimerGetInternalName(self.entity:EntIndex(), name))
320+
end
321+
322+
e2function void timerResume(string name)
323+
if not luaTimerExists(self, name) then
324+
return self:throw("Timer with name " .. name .. " does not exist", 0)
325+
end
326+
327+
-- return timer.UnPause(luaTimerGetInternalName(self.entity:EntIndex(), name)) and 1 or 0 -- This is commented due to timer.Pause being broken for some reason. It just does not return anything.
328+
timer.UnPause(luaTimerGetInternalName(self.entity:EntIndex(), name))
329+
end
330+
331+
e2function number timerToggle(string name)
332+
if not luaTimerExists(self, name) then
333+
return self:throw("Timer with name " .. name .. " does not exist", 0)
334+
end
335+
336+
--return timer.Toggle(luaTimerGetInternalName(self.entity:EntIndex(), name)) and 1 or 0 -- This is commented due to timer.Pause being broken for some reason. It just does not return anything.
337+
timer.Toggle(luaTimerGetInternalName(self.entity:EntIndex(), name))
338+
end
339+
340+
__e2setcost(5)
341+
[nodiscard]
342+
e2function number timerRepsLeft(string name)
343+
if not luaTimerExists(self, name) then
344+
return self:throw("Timer with name " .. name .. " does not exist", 0)
345+
end
346+
347+
return timer.RepsLeft(luaTimerGetInternalName(self.entity:EntIndex(), name))
348+
end
349+
350+
[nodiscard]
351+
e2function number timerTimeLeft(string name)
352+
if not luaTimerExists(self, name) then
353+
return self:throw("Timer with name " .. name .. " does not exist", 0)
354+
end
355+
356+
return timer.TimeLeft(luaTimerGetInternalName(self.entity:EntIndex(), name))
357+
end
358+
359+
/******************************************************************************/
360+
__e2setcost(1)
120361
[nodiscard]
121362
e2function number curtime()
122363
return CurTime()

lua/entities/gmod_wire_expression2/init.lua

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,10 @@ function ENT:UpdatePerf(selfTbl)
116116
context.time = 0
117117
end
118118

119-
function ENT:Execute()
119+
function ENT:Execute(script, context)
120120
local selfTbl = self:GetTable()
121-
local context = selfTbl.context
121+
context = context or selfTbl.context
122+
script = script or selfTbl.script
122123
if not context or selfTbl.error or context.resetting then return end
123124

124125
self:PCallHook("preexecute")
@@ -131,7 +132,7 @@ function ENT:Execute()
131132

132133
local bench = SysTime()
133134

134-
local ok, msg = pcall(selfTbl.script, context)
135+
local ok, msg = pcall(script, context)
135136

136137
if not ok then
137138
local _catchable, msg, trace = E2Lib.unpackException(msg)

0 commit comments

Comments
 (0)