Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b2b1cce

Browse files
author
Jeija
committedNov 25, 2014
Merge branch 'improve-luacontroller'
However, without the print_count limiting functionality Conflicts: mesecons_luacontroller/init.lua
2 parents f69caba + 085b4d8 commit b2b1cce

File tree

2 files changed

+425
-371
lines changed

2 files changed

+425
-371
lines changed
 

‎mesecons/legacy.lua

+30-29
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
1-
-- Ugly hack to prevent breaking compatibility with other mods
2-
-- Just remove the following two functions to delete the hack, to be done when other mods have updated
3-
function mesecon.receptor_on(self, pos, rules)
4-
if (self.receptor_on) then
5-
print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_on.")
6-
print("[Mesecons] If you are the programmer of this mod, please update it ")
7-
print("[Mesecons] to use mesecon.receptor_on instead. mesecon:* is deprecated")
8-
print("[Mesecons] Otherwise, please make sure you're running the latest version")
9-
print("[Mesecons] of that mod and inform the mod creator.")
10-
else
11-
rules = pos
12-
pos = self
13-
end
14-
mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
15-
end
16-
17-
function mesecon.receptor_off(self, pos, rules)
18-
if (self.receptor_off) then
19-
print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_off.")
20-
print("[Mesecons] If you are the programmer of this mod, please update it ")
21-
print("[Mesecons] to use mesecon.receptor_off instead. mesecon:* is deprecated")
22-
print("[Mesecons] Otherwise, please make sure you're running the latest version")
23-
print("[Mesecons] of that mod and inform the mod creator.")
24-
else
25-
rules = pos
26-
pos = self
27-
end
28-
mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
29-
end
1+
-- Ugly hack to prevent breaking compatibility with other mods
2+
-- Just remove the following two functions to delete the hack, to be done when other mods have updated
3+
function mesecon.receptor_on(self, pos, rules)
4+
if (self.receptor_on) then
5+
print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_on.")
6+
print("[Mesecons] If you are the programmer of this mod, please update it ")
7+
print("[Mesecons] to use mesecon.receptor_on instead. mesecon:* is deprecated")
8+
print("[Mesecons] Otherwise, please make sure you're running the latest version")
9+
print("[Mesecons] of that mod and inform the mod creator.")
10+
else
11+
rules = pos
12+
pos = self
13+
end
14+
mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
15+
end
16+
17+
function mesecon.receptor_off(self, pos, rules)
18+
if (self.receptor_off) then
19+
print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_off.")
20+
print("[Mesecons] If you are the programmer of this mod, please update it ")
21+
print("[Mesecons] to use mesecon.receptor_off instead. mesecon:* is deprecated")
22+
print("[Mesecons] Otherwise, please make sure you're running the latest version")
23+
print("[Mesecons] of that mod and inform the mod creator.")
24+
else
25+
rules = pos
26+
pos = self
27+
end
28+
mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
29+
end
30+

‎mesecons_luacontroller/init.lua

+395-342
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1+
-- ______
2+
-- |
3+
-- |
4+
-- | __ ___ _ __ _ _
5+
-- | | | | | |\ | | |_| | | | | |_ |_|
6+
-- |___| |______ |__| | \| | | \ |__| |_ |_ |_ |\
7+
-- |
8+
-- |
9+
--
10+
111
-- Reference
2-
-- ports = get_real_portstates(pos): gets if inputs are powered from outside
3-
-- newport = merge_portstates(state1, state2): just does result = state1 or state2 for every port
4-
-- action_setports(pos, rule, state): activates/deactivates the mesecons according to the portstates (helper for action)
5-
-- action(pos, ports): Applies new portstates to a luacontroller at pos
6-
-- lc_update(pos): updates the controller at pos by executing the code
7-
-- reset_meta (pos, code, errmsg): performs a software-reset, installs new code and prints error messages
8-
-- reset (pos): performs a hardware reset, turns off all ports
12+
-- ports = get_real_port_states(pos): gets if inputs are powered from outside
13+
-- newport = merge_port_states(state1, state2): just does result = state1 or state2 for every port
14+
-- set_port(pos, rule, state): activates/deactivates the mesecons according to the port states
15+
-- set_port_states(pos, ports): Applies new port states to a LuaController at pos
16+
-- run(pos): runs the code in the controller at pos
17+
-- reset_meta(pos, code, errmsg): performs a software-reset, installs new code and prints error messages
18+
-- resetn(pos): performs a hardware reset, turns off all ports
919
--
1020
-- The Sandbox
1121
-- The whole code of the controller runs in a sandbox,
@@ -20,311 +30,375 @@
2030

2131
local BASENAME = "mesecons_luacontroller:luacontroller"
2232

23-
local rules = {}
24-
rules.a = {x = -1, y = 0, z = 0, name="A"}
25-
rules.b = {x = 0, y = 0, z = 1, name="B"}
26-
rules.c = {x = 1, y = 0, z = 0, name="C"}
27-
rules.d = {x = 0, y = 0, z = -1, name="D"}
33+
local rules = {
34+
a = {x = -1, y = 0, z = 0, name="A"},
35+
b = {x = 0, y = 0, z = 1, name="B"},
36+
c = {x = 1, y = 0, z = 0, name="C"},
37+
d = {x = 0, y = 0, z = -1, name="D"},
38+
}
39+
2840

2941
------------------
3042
-- Action stuff --
3143
------------------
32-
-- These helpers are required to set the portstates of the luacontroller
44+
-- These helpers are required to set the port states of the luacontroller
3345

34-
function lc_update_real_portstates(pos, rulename, newstate)
46+
local function update_real_port_states(pos, rule_name, new_state)
3547
local meta = minetest.get_meta(pos)
36-
if rulename == nil then
48+
if rule_name == nil then
3749
meta:set_int("real_portstates", 1)
3850
return
3951
end
4052
local n = meta:get_int("real_portstates") - 1
4153
local L = {}
4254
for i = 1, 4 do
43-
L[i] = n%2
44-
n = math.floor(n/2)
55+
L[i] = n % 2
56+
n = math.floor(n / 2)
4557
end
46-
if rulename.x == nil then
47-
for _, rname in ipairs(rulename) do
48-
local port = ({4, 1, nil, 3, 2})[rname.x+2*rname.z+3]
58+
-- (0,-1) (-1,0) (1,0) (0,1)
59+
local pos_to_side = { 4, 1, nil, 3, 2 }
60+
if rule_name.x == nil then
61+
for _, rname in ipairs(rule_name) do
62+
local port = pos_to_side[rname.x + (2 * rname.z) + 3]
4963
L[port] = (newstate == "on") and 1 or 0
5064
end
5165
else
52-
local port = ({4, 1, nil, 3, 2})[rulename.x+2*rulename.z+3]
53-
L[port] = (newstate == "on") and 1 or 0
66+
local port = pos_to_side[rule_name.x + (2 * rule_name.z) + 3]
67+
L[port] = (new_state == "on") and 1 or 0
5468
end
55-
meta:set_int("real_portstates", 1 + L[1] + 2*L[2] + 4*L[3] + 8*L[4])
69+
meta:set_int("real_portstates",
70+
1 +
71+
1 * L[1] +
72+
2 * L[2] +
73+
4 * L[3] +
74+
8 * L[4])
5675
end
5776

58-
local get_real_portstates = function(pos) -- determine if ports are powered (by itself or from outside)
77+
78+
local port_names = {"a", "b", "c", "d"}
79+
80+
local function get_real_port_states(pos)
81+
-- Determine if ports are powered (by itself or from outside)
5982
local meta = minetest.get_meta(pos)
6083
local L = {}
6184
local n = meta:get_int("real_portstates") - 1
62-
for _, index in ipairs({"a", "b", "c", "d"}) do
63-
L[index] = ((n%2) == 1)
64-
n = math.floor(n/2)
85+
for _, name in ipairs(port_names) do
86+
L[name] = ((n % 2) == 1)
87+
n = math.floor(n / 2)
6588
end
6689
return L
6790
end
6891

69-
local merge_portstates = function (ports, vports)
70-
local npo = {a=false, b=false, c=false, d=false}
71-
npo.a = vports.a or ports.a
72-
npo.b = vports.b or ports.b
73-
npo.c = vports.c or ports.c
74-
npo.d = vports.d or ports.d
75-
return npo
92+
93+
local function merge_port_states(ports, vports)
94+
return {
95+
a = ports.a or vports.a,
96+
b = ports.b or vports.b,
97+
c = ports.c or vports.c,
98+
d = ports.d or vports.d,
99+
}
76100
end
77101

78-
local generate_name = function (ports)
102+
local function generate_name(ports)
79103
local d = ports.d and 1 or 0
80104
local c = ports.c and 1 or 0
81105
local b = ports.b and 1 or 0
82106
local a = ports.a and 1 or 0
83107
return BASENAME..d..c..b..a
84108
end
85109

86-
local setport = function (pos, rule, state)
110+
111+
local function set_port(pos, rule, state)
87112
if state then
88113
mesecon.receptor_on(pos, {rule})
89114
else
90115
mesecon.receptor_off(pos, {rule})
91116
end
92117
end
93118

94-
local action = function (pos, ports)
119+
120+
local function clean_port_states(ports)
121+
ports.a = ports.a and true or false
122+
ports.b = ports.b and true or false
123+
ports.c = ports.c and true or false
124+
ports.d = ports.d and true or false
125+
end
126+
127+
128+
local function set_port_states(pos, ports)
95129
local node = minetest.get_node(pos)
96130
local name = node.name
131+
clean_port_states(ports)
97132
local vports = minetest.registered_nodes[name].virtual_portstates
98-
local newname = generate_name(ports)
99-
100-
if name ~= newname and vports then
101-
local rules_on = {}
102-
local rules_off = {}
133+
local new_name = generate_name(ports)
103134

104-
minetest.swap_node(pos, {name = newname, param2 = node.param2})
135+
if name ~= new_name and vports then
136+
minetest.swap_node(pos, {name = new_name, param2 = node.param2})
105137

106-
if ports.a ~= vports.a then setport(pos, rules.a, ports.a) end
107-
if ports.b ~= vports.b then setport(pos, rules.b, ports.b) end
108-
if ports.c ~= vports.c then setport(pos, rules.c, ports.c) end
109-
if ports.d ~= vports.d then setport(pos, rules.d, ports.d) end
138+
if ports.a ~= vports.a then set_port(pos, rules.a, ports.a) end
139+
if ports.b ~= vports.b then set_port(pos, rules.b, ports.b) end
140+
if ports.c ~= vports.c then set_port(pos, rules.c, ports.c) end
141+
if ports.d ~= vports.d then set_port(pos, rules.d, ports.d) end
110142
end
111143
end
112144

113-
--------------------
114-
-- Overheat stuff --
115-
--------------------
116145

117-
local overheat_off = function(pos)
146+
-----------------
147+
-- Overheating --
148+
-----------------
149+
150+
local function overheat_off(pos)
118151
mesecon.receptor_off(pos, mesecon.rules.flat)
119152
end
120153

121-
-------------------
122-
-- Parsing stuff --
123-
-------------------
124154

125-
local code_prohibited = function(code)
126-
-- Clean code
127-
local prohibited = {"while", "for", "repeat", "until", "function", "goto"}
128-
for _, p in ipairs(prohibited) do
129-
if string.find(code, p) then
130-
return "Prohibited command: "..p
131-
end
155+
local function overheat(pos, meta)
156+
if mesecon.do_overheat(pos) then -- If too hot
157+
local node = minetest.get_node(pos)
158+
node.name = BASENAME.."_burnt"
159+
minetest.swap_node(pos, node)
160+
-- Wait for pending operations
161+
minetest.after(0.2, overheat_off, pos)
162+
return true
132163
end
133164
end
134165

135-
local safe_print = function(param)
166+
167+
-------------------------
168+
-- Parsing and running --
169+
-------------------------
170+
171+
local function safe_print(param)
136172
print(dump(param))
137173
end
138174

139-
deep_copy = function(original, visited) --deep copy that removes functions
140-
visited = visited or {}
141-
if visited[original] ~= nil then --already visited this node
142-
return visited[original]
143-
end
144-
if type(original) == 'table' then --nested table
145-
local copy = {}
146-
visited[original] = copy
147-
for key, value in next, original, nil do
148-
copy[deep_copy(key, visited)] = deep_copy(value, visited)
175+
minetest.register_globalstep(function(dtime)
176+
print_count = print_count - dtime
177+
end)
178+
179+
180+
local function remove_functions(x)
181+
local tp = type(x)
182+
if tp == "table" then
183+
for key, value in pairs(x) do
184+
local key_t, val_t = type(key), type(value)
185+
if key_t == "function" or val_t == "function" then
186+
x[key] = nil
187+
else
188+
if key_t == "table" then
189+
remove_functions(key)
190+
end
191+
if val_t == "table" then
192+
remove_functions(value)
193+
end
194+
end
149195
end
150-
setmetatable(copy, deep_copy(getmetatable(original), visited))
151-
return copy
152-
elseif type(original) == 'function' then --ignore functions
196+
elseif tp == "function" then
153197
return nil
154-
else --by-value type
155-
return original
156198
end
199+
return x
157200
end
158201

159-
local safe_serialize = function(value)
160-
return minetest.serialize(deep_copy(value))
161-
end
162-
163-
mesecon.queue:add_function("lc_interrupt", function (pos, luac_id, iid)
164-
-- There is no luacontroller anymore / it has been reprogrammed / replaced
165-
if (minetest.get_meta(pos):get_int("luac_id") ~= luac_id) then return end
166-
lc_update(pos, {type="interrupt", iid = iid})
167-
end)
168-
169-
local getinterrupt = function(pos)
170-
local interrupt = function (time, iid) -- iid = interrupt id
202+
local function get_interrupt(pos)
203+
-- iid = interrupt id
204+
local function interrupt(time, iid)
171205
if type(time) ~= "number" then return end
172206
local luac_id = minetest.get_meta(pos):get_int("luac_id")
173207
mesecon.queue:add_action(pos, "lc_interrupt", {luac_id, iid}, time, iid, 1)
174208
end
175209
return interrupt
176210
end
177211

178-
local getdigiline_send = function(pos)
212+
213+
local function get_digiline_send(pos)
179214
if not digiline then return end
180-
-- Send messages on next serverstep
181215
return function(channel, msg)
182216
minetest.after(0, function()
183217
digiline:receptor_send(pos, digiline.rules.default, channel, msg)
184218
end)
185219
end
186220
end
187221

188-
local create_environment = function(pos, mem, event)
222+
223+
local safe_globals = {
224+
"assert", "error", "ipairs", "next", "pairs", "pcall", "select",
225+
"tonumber", "tostring", "type", "unpack", "_VERSION", "xpcall",
226+
}
227+
local function create_environment(pos, mem, event)
189228
-- Gather variables for the environment
190229
local vports = minetest.registered_nodes[minetest.get_node(pos).name].virtual_portstates
191-
vports = {a = vports.a, b = vports.b, c = vports.c, d = vports.d}
192-
local rports = get_real_portstates(pos)
193-
194-
return {
195-
print = safe_print,
196-
pin = merge_portstates(vports, rports),
197-
port = vports,
198-
interrupt = getinterrupt(pos),
199-
digiline_send = getdigiline_send(pos),
200-
mem = mem,
201-
tostring = tostring,
202-
tonumber = tonumber,
203-
heat = minetest.get_meta(pos):get_int("heat"),
204-
-- overheat_max Unit: actions per second, checks are every 1 second
205-
heat_max = mesecon.setting("overheat_max", 20),
206-
string = {
207-
byte = string.byte,
208-
char = string.char,
209-
find = string.find,
210-
format = string.format,
211-
gmatch = string.gmatch,
212-
gsub = string.gsub,
213-
len = string.len,
214-
lower = string.lower,
215-
upper = string.upper,
216-
match = string.match,
217-
rep = string.rep,
218-
reverse = string.reverse,
219-
sub = string.sub,
220-
},
221-
math = {
222-
abs = math.abs,
223-
acos = math.acos,
224-
asin = math.asin,
225-
atan = math.atan,
226-
atan2 = math.atan2,
227-
ceil = math.ceil,
228-
cos = math.cos,
229-
cosh = math.cosh,
230-
deg = math.deg,
231-
exp = math.exp,
232-
floor = math.floor,
233-
fmod = math.fmod,
234-
frexp = math.frexp,
235-
huge = math.huge,
236-
ldexp = math.ldexp,
237-
log = math.log,
238-
log10 = math.log10,
239-
max = math.max,
240-
min = math.min,
241-
modf = math.modf,
242-
pi = math.pi,
243-
pow = math.pow,
244-
rad = math.rad,
245-
random = math.random,
246-
sin = math.sin,
247-
sinh = math.sinh,
248-
sqrt = math.sqrt,
249-
tan = math.tan,
250-
tanh = math.tanh,
251-
},
252-
table = {
253-
insert = table.insert,
254-
maxn = table.maxn,
255-
remove = table.remove,
256-
sort = table.sort
257-
},
258-
event = event,
230+
local vports_copy = {}
231+
for k, v in pairs(vports) do vports_copy[k] = v end
232+
local rports = get_real_port_states(pos)
233+
234+
-- Create new library tables on each call to prevent one LuaController
235+
-- from breaking a library and messing up other LuaControllers.
236+
local env = {
237+
pin = merge_port_states(vports, rports),
238+
port = vports_copy,
239+
event = event,
240+
mem = mem,
241+
heat = minetest.get_meta(pos):get_int("heat"),
242+
heat_max = mesecon.setting("overheat_max", 20),
243+
print = safe_print,
244+
interrupt = get_interrupt(pos),
245+
digiline_send = get_digiline_send(pos),
246+
string = {
247+
byte = string.byte,
248+
char = string.char,
249+
format = string.format,
250+
gsub = string.gsub,
251+
len = string.len,
252+
lower = string.lower,
253+
upper = string.upper,
254+
rep = string.rep,
255+
reverse = string.reverse,
256+
sub = string.sub,
257+
},
258+
math = {
259+
abs = math.abs,
260+
acos = math.acos,
261+
asin = math.asin,
262+
atan = math.atan,
263+
atan2 = math.atan2,
264+
ceil = math.ceil,
265+
cos = math.cos,
266+
cosh = math.cosh,
267+
deg = math.deg,
268+
exp = math.exp,
269+
floor = math.floor,
270+
fmod = math.fmod,
271+
frexp = math.frexp,
272+
huge = math.huge,
273+
ldexp = math.ldexp,
274+
log = math.log,
275+
log10 = math.log10,
276+
max = math.max,
277+
min = math.min,
278+
modf = math.modf,
279+
pi = math.pi,
280+
pow = math.pow,
281+
rad = math.rad,
282+
random = math.random,
283+
sin = math.sin,
284+
sinh = math.sinh,
285+
sqrt = math.sqrt,
286+
tan = math.tan,
287+
tanh = math.tanh,
288+
},
289+
table = {
290+
concat = table.concat,
291+
insert = table.insert,
292+
maxn = table.maxn,
293+
remove = table.remove,
294+
sort = table.sort,
295+
},
296+
os = {
297+
clock = os.clock,
298+
difftime = os.difftime,
299+
time = os.time,
300+
},
259301
}
302+
env._G = env
303+
304+
for _, name in pairs(safe_globals) do
305+
env[name] = _G[name]
306+
end
307+
308+
return env
260309
end
261310

262-
local create_sandbox = function (code, env)
263-
-- Create Sandbox
311+
312+
local function timeout()
313+
debug.sethook() -- Clear hook
314+
error("Code timed out!")
315+
end
316+
317+
318+
local function code_prohibited(code)
319+
-- LuaJIT doesn't increment the instruction counter when running
320+
-- loops, so we have to sanitize inputs if we're using LuaJIT.
321+
if not jit then
322+
return false
323+
end
324+
local prohibited = {"while", "for", "do", "repeat", "until", "goto"}
325+
code = " "..code.." "
326+
for _, p in ipairs(prohibited) do
327+
if string.find(code, "[^%w_]"..p.."[^%w_]") then
328+
return "Prohibited command: "..p
329+
end
330+
end
331+
end
332+
333+
334+
local function create_sandbox(code, env)
264335
if code:byte(1) == 27 then
265-
return _, "You Hacker You! Don't use binary code!"
336+
return nil, "Binary code prohibited."
266337
end
267338
local f, msg = loadstring(code)
268-
if not f then return _, msg end
339+
if not f then return nil, msg end
269340
setfenv(f, env)
270-
return f
271-
end
272341

273-
local lc_overheat = function (pos, meta)
274-
if mesecon.do_overheat(pos) then -- if too hot
275-
local node = minetest.get_node(pos)
276-
minetest.swap_node(pos, {name = BASENAME.."_burnt", param2 = node.param2})
277-
minetest.after(0.2, overheat_off, pos) -- wait for pending operations
278-
return true
342+
return function(...)
343+
debug.sethook(timeout, "", 10000)
344+
local ok, ret = pcall(f, ...)
345+
debug.sethook() -- Clear hook
346+
if not ok then error(ret) end
347+
return ret
279348
end
280349
end
281350

282-
local load_memory = function(meta)
351+
352+
local function load_memory(meta)
283353
return minetest.deserialize(meta:get_string("lc_memory")) or {}
284354
end
285355

286-
local save_memory = function(meta, mem)
287-
meta:set_string("lc_memory", safe_serialize(mem))
288-
end
289356

290-
local ports_invalid = function (var)
291-
if type(var) == "table" then
292-
return false
293-
end
294-
return "The ports you set are invalid"
357+
local function save_memory(meta, mem)
358+
meta:set_string("lc_memory",
359+
minetest.serialize(
360+
remove_functions(mem)
361+
)
362+
)
295363
end
296364

297-
----------------------
298-
-- Parsing function --
299-
----------------------
300365

301-
lc_update = function (pos, event)
366+
local function run(pos, event)
302367
local meta = minetest.get_meta(pos)
303-
if lc_overheat(pos) then return end
368+
if overheat(pos) then return end
304369

305-
-- load code & mem from memory
370+
-- Load code & mem from meta
306371
local mem = load_memory(meta)
307372
local code = meta:get_string("code")
308373

309-
-- make sure code is ok and create environment
310-
local prohibited = code_prohibited(code)
311-
if prohibited then return prohibited end
374+
local err = code_prohibited(code)
375+
if err then return err end
376+
377+
-- Create environment
312378
local env = create_environment(pos, mem, event)
313379

314-
-- create the sandbox and execute code
315-
local chunk, msg = create_sandbox (code, env)
316-
if not chunk then return msg end
317-
local success, msg = pcall(chunk)
380+
-- Create the sandbox and execute code
381+
local f, msg = create_sandbox(code, env)
382+
if not f then return msg end
383+
local success, msg = pcall(f)
318384
if not success then return msg end
319-
if ports_invalid(env.port) then return ports_invalid(env.port) end
385+
if type(env.port) ~= "table" then
386+
return "Ports set are invalid."
387+
end
320388

321-
save_memory(meta, mem)
389+
save_memory(meta, env.mem)
322390

323391
-- Actually set the ports
324-
action(pos, env.port)
392+
set_port_states(pos, env.port)
325393
end
326394

327-
local reset_meta = function(pos, code, errmsg)
395+
mesecon.queue:add_function("lc_interrupt", function (pos, luac_id, iid)
396+
-- There is no luacontroller anymore / it has been reprogrammed / replaced
397+
if (minetest.get_meta(pos):get_int("luac_id") ~= luac_id) then return end
398+
run(pos, {type="interrupt", iid = iid})
399+
end)
400+
401+
local function reset_meta(pos, code, errmsg)
328402
local meta = minetest.get_meta(pos)
329403
meta:set_string("code", code)
330404
code = minetest.formspec_escape(code or "")
@@ -336,172 +410,155 @@ local reset_meta = function(pos, code, errmsg)
336410
"image_button_exit[9.72,-0.25;0.425,0.4;jeija_close_window.png;exit;]"..
337411
"label[0.1,5;"..errmsg.."]")
338412
meta:set_int("heat", 0)
339-
meta:set_int("luac_id", math.random(1, 1000000))
413+
meta:set_int("luac_id", math.random(1, 65535))
340414
end
341415

342-
local reset = function (pos)
343-
action(pos, {a=false, b=false, c=false, d=false})
416+
local function reset(pos)
417+
set_port_states(pos, {a=false, b=false, c=false, d=false})
344418
end
345419

346-
-- ______
347-
-- |
348-
-- |
349-
-- | __ ___ _ __ _ _
350-
-- | | | | | |\ | | |_| | | | | |_ |_|
351-
-- |___| |______ |__| | \| | | \ |__| |_ |_ |_ |\
352-
-- |
353-
-- |
354-
--
355420

356421
-----------------------
357422
-- Node Registration --
358423
-----------------------
359424

360-
local output_rules={}
361-
local input_rules={}
425+
local output_rules = {}
426+
local input_rules = {}
362427

363-
local nodebox = {
364-
type = "fixed",
365-
fixed = {
366-
{ -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab
367-
{ -5/16, -7/16, -5/16, 5/16, -6/16, 5/16 }, -- circuit board
368-
{ -3/16, -6/16, -3/16, 3/16, -5/16, 3/16 }, -- IC
369-
}
428+
local node_box = {
429+
type = "fixed",
430+
fixed = {
431+
{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16}, -- Bottom slab
432+
{-5/16, -7/16, -5/16, 5/16, -6/16, 5/16}, -- Circuit board
433+
{-3/16, -6/16, -3/16, 3/16, -5/16, 3/16}, -- IC
370434
}
435+
}
371436

372-
local selectionbox = {
373-
type = "fixed",
374-
fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 },
375-
}
437+
local selection_box = {
438+
type = "fixed",
439+
fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 },
440+
}
376441

377442
local digiline = {
378443
receptor = {},
379444
effector = {
380-
action = function (pos, node, channel, msg)
381-
lc_update (pos, {type = "digiline", channel = channel, msg = msg})
445+
action = function(pos, node, channel, msg)
446+
run(pos, {type = "digiline", channel = channel, msg = msg})
382447
end
383448
}
384449
}
450+
local function on_receive_fields(pos, form_name, fields)
451+
if not fields.program then
452+
return
453+
end
454+
reset(pos)
455+
reset_meta(pos, fields.code)
456+
local err = run(pos, {type="program"})
457+
if err then
458+
print(err)
459+
reset_meta(pos, fields.code, err)
460+
end
461+
end
385462

386-
for a = 0, 1 do -- 0 = off; 1 = on
463+
for a = 0, 1 do -- 0 = off 1 = on
387464
for b = 0, 1 do
388465
for c = 0, 1 do
389466
for d = 0, 1 do
467+
local cid = tostring(d)..tostring(c)..tostring(b)..tostring(a)
468+
local node_name = BASENAME..cid
469+
local top = "jeija_luacontroller_top.png"
470+
if a == 1 then
471+
top = top.."^jeija_luacontroller_LED_A.png"
472+
end
473+
if b == 1 then
474+
top = top.."^jeija_luacontroller_LED_B.png"
475+
end
476+
if c == 1 then
477+
top = top.."^jeija_luacontroller_LED_C.png"
478+
end
479+
if d == 1 then
480+
top = top.."^jeija_luacontroller_LED_D.png"
481+
end
390482

391-
local cid = tostring(d)..tostring(c)..tostring(b)..tostring(a)
392-
local nodename = BASENAME..cid
393-
local top = "jeija_luacontroller_top.png"
394-
if a == 1 then
395-
top = top.."^jeija_luacontroller_LED_A.png"
396-
end
397-
if b == 1 then
398-
top = top.."^jeija_luacontroller_LED_B.png"
399-
end
400-
if c == 1 then
401-
top = top.."^jeija_luacontroller_LED_C.png"
402-
end
403-
if d == 1 then
404-
top = top.."^jeija_luacontroller_LED_D.png"
405-
end
406-
407-
if a + b + c + d ~= 0 then
408-
groups = {dig_immediate=2, not_in_creative_inventory=1, overheat = 1}
409-
else
410-
groups = {dig_immediate=2, overheat = 1}
411-
end
483+
local groups
484+
if a + b + c + d ~= 0 then
485+
groups = {dig_immediate=2, not_in_creative_inventory=1, overheat = 1}
486+
else
487+
groups = {dig_immediate=2, overheat = 1}
488+
end
412489

413-
output_rules[cid] = {}
414-
input_rules[cid] = {}
415-
if (a == 1) then table.insert(output_rules[cid], rules.a) end
416-
if (b == 1) then table.insert(output_rules[cid], rules.b) end
417-
if (c == 1) then table.insert(output_rules[cid], rules.c) end
418-
if (d == 1) then table.insert(output_rules[cid], rules.d) end
419-
420-
if (a == 0) then table.insert(input_rules[cid], rules.a) end
421-
if (b == 0) then table.insert(input_rules[cid], rules.b) end
422-
if (c == 0) then table.insert(input_rules[cid], rules.c) end
423-
if (d == 0) then table.insert(input_rules[cid], rules.d) end
424-
425-
local mesecons = {
426-
effector =
427-
{
428-
rules = input_rules[cid],
429-
action_change = function (pos, _, rulename, newstate)
430-
lc_update_real_portstates(pos, rulename, newstate)
431-
lc_update(pos, {type=newstate, pin=rulename})
432-
end,
433-
},
434-
receptor =
435-
{
436-
state = mesecon.state.on,
437-
rules = output_rules[cid]
490+
output_rules[cid] = {}
491+
input_rules[cid] = {}
492+
if a == 1 then table.insert(output_rules[cid], rules.a) end
493+
if b == 1 then table.insert(output_rules[cid], rules.b) end
494+
if c == 1 then table.insert(output_rules[cid], rules.c) end
495+
if d == 1 then table.insert(output_rules[cid], rules.d) end
496+
497+
if a == 0 then table.insert( input_rules[cid], rules.a) end
498+
if b == 0 then table.insert( input_rules[cid], rules.b) end
499+
if c == 0 then table.insert( input_rules[cid], rules.c) end
500+
if d == 0 then table.insert( input_rules[cid], rules.d) end
501+
502+
local mesecons = {
503+
effector = {
504+
rules = input_rules[cid],
505+
action_change = function (pos, _, rule_name, new_state)
506+
update_real_port_states(pos, rule_name, new_state)
507+
run(pos, {type=new_state, pin=rule_name})
508+
end,
509+
},
510+
receptor = {
511+
state = mesecon.state.on,
512+
rules = output_rules[cid]
513+
}
438514
}
439-
}
440515

441-
minetest.register_node(nodename, {
442-
description = "Luacontroller",
443-
drawtype = "nodebox",
444-
tiles = {
445-
top,
446-
"jeija_microcontroller_bottom.png",
447-
"jeija_microcontroller_sides.png",
448-
"jeija_microcontroller_sides.png",
449-
"jeija_microcontroller_sides.png",
450-
"jeija_microcontroller_sides.png"
516+
minetest.register_node(node_name, {
517+
description = "LuaController",
518+
drawtype = "nodebox",
519+
tiles = {
520+
top,
521+
"jeija_microcontroller_bottom.png",
522+
"jeija_microcontroller_sides.png",
523+
"jeija_microcontroller_sides.png",
524+
"jeija_microcontroller_sides.png",
525+
"jeija_microcontroller_sides.png"
451526
},
452-
453-
inventory_image = top,
454-
paramtype = "light",
455-
groups = groups,
456-
drop = BASENAME.."0000",
457-
sunlight_propagates = true,
458-
selection_box = selectionbox,
459-
node_box = nodebox,
460-
on_construct = reset_meta,
461-
on_receive_fields = function(pos, formname, fields)
462-
if not fields.program then
463-
return
464-
end
465-
reset(pos)
466-
reset_meta(pos, fields.code)
467-
local err = lc_update(pos, {type="program"})
468-
if err then
469-
print(err)
470-
reset_meta(pos, fields.code, err)
471-
end
472-
end,
473-
sounds = default.node_sound_stone_defaults(),
474-
mesecons = mesecons,
475-
digiline = digiline,
476-
virtual_portstates = { a = a == 1, -- virtual portstates are
477-
b = b == 1, -- the ports the the
478-
c = c == 1, -- controller powers itself
479-
d = d == 1},-- so those that light up
480-
after_dig_node = function (pos, node)
481-
mesecon.receptor_off(pos, output_rules)
482-
end,
483-
is_luacontroller = true,
484-
})
527+
inventory_image = top,
528+
paramtype = "light",
529+
groups = groups,
530+
drop = BASENAME.."0000",
531+
sunlight_propagates = true,
532+
selection_box = selection_box,
533+
node_box = node_box,
534+
on_construct = reset_meta,
535+
on_receive_fields = on_receive_fields,
536+
on_timer = handle_timer,
537+
sounds = default.node_sound_stone_defaults(),
538+
mesecons = mesecons,
539+
digiline = digiline,
540+
-- Virtual portstates are the ports that
541+
-- the node shows as powered up (light up).
542+
virtual_portstates = {
543+
a = a == 1,
544+
b = b == 1,
545+
c = c == 1,
546+
d = d == 1,
547+
},
548+
after_dig_node = function (pos, node)
549+
mesecon.receptor_off(pos, output_rules)
550+
end,
551+
is_luacontroller = true,
552+
})
485553
end
486554
end
487555
end
488556
end
489557

490558
------------------------------
491-
-- overheated luacontroller --
559+
-- Overheated LuaController --
492560
------------------------------
493561

494-
local mesecons_burnt = {
495-
effector =
496-
{
497-
rules = mesecon.rules.flat,
498-
action_change = function (pos, _, rulename, newstate)
499-
-- only update portstates when changes are triggered
500-
lc_update_real_portstates(pos, rulename, newstate)
501-
end
502-
}
503-
}
504-
505562
minetest.register_node(BASENAME .. "_burnt", {
506563
drawtype = "nodebox",
507564
tiles = {
@@ -518,23 +575,19 @@ minetest.register_node(BASENAME .. "_burnt", {
518575
drop = BASENAME.."0000",
519576
sunlight_propagates = true,
520577
selection_box = selectionbox,
521-
node_box = nodebox,
578+
node_box = node_box,
522579
on_construct = reset_meta,
523-
on_receive_fields = function(pos, formname, fields)
524-
if fields.quit then
525-
return
526-
end
527-
reset(pos)
528-
reset_meta(pos, fields.code)
529-
local err = lc_update(pos, {type="program"})
530-
if err then
531-
print(err)
532-
reset_meta(pos, fields.code, err)
533-
end
534-
end,
580+
on_receive_fields = on_receive_fields,
535581
sounds = default.node_sound_stone_defaults(),
536582
virtual_portstates = {a = false, b = false, c = false, d = false},
537-
mesecons = mesecons_burnt,
583+
mesecons = {
584+
effector = {
585+
rules = mesecon.rules.flat,
586+
action_change = function(pos, _, rule_name, new_state)
587+
update_real_port_states(pos, rule_name, new_state)
588+
end,
589+
},
590+
},
538591
})
539592

540593
------------------------

0 commit comments

Comments
 (0)
Please sign in to comment.