Simulation = {} function Simulation.new(sim) local o = { groupqueue = {}, num_groupqueue = 0, gatequeue = {}, num_gatequeue = 0, groupfxqueue = {}, current_tick = 0, definitions = {}, wires = {}, gates = {}, nwires = 0, ngates = 0, ninports = 0, noutports = 0, initqueue = nil, inputqueue = nil, tickqueue = {}, callbacks = nil, } setmetatable(o, sim) sim.__index = sim return o end function Simulation.addtoworld(sim, obj, x, y, z) if sim[x] == nil then sim[x] = {} end if sim[x][y] == nil then sim[x][y] = {} end if sim[x][y][z] == nil then sim[x][y][z] = {} end sim[x][y][z][obj] = obj end function Simulation.getfromworld(sim, x, y, z) if sim[x] == nil or sim[x][y] == nil or sim[x][y][z] == nil then return {} else return sim[x][y][z] end end function Simulation.getdefinitionbyref(sim, objref) return sim.definitions[objref] end function Simulation.getgatebyref(sim, objref) return sim.gates[objref] end function Simulation.getwirebyref(sim, objref) return sim.wires[objref] end function Simulation.addgatedefinition(sim, definition) sim.definitions[definition.objref] = definition end function Simulation.addwire(sim, wire) sim.wires[Wire.getobjref(wire)] = wire local bounds = Wire.getbounds(wire) for x = bounds[1]+1, bounds[4]-1, 2 do for z = bounds[3]+1, bounds[6]-1, 2 do Simulation.addtoworld(sim, wire, x, bounds[2], z) Simulation.addtoworld(sim, wire, x, bounds[5], z) end end for y = bounds[2]+1, bounds[5]-1, 2 do for z = bounds[3]+1, bounds[6]-1, 2 do Simulation.addtoworld(sim, wire, bounds[1], y, z) Simulation.addtoworld(sim, wire, bounds[4], y, z) end end for x = bounds[1]+1, bounds[4]-1, 2 do for y = bounds[2]+1, bounds[5]-1, 2 do Simulation.addtoworld(sim, wire, x, y, bounds[3]) Simulation.addtoworld(sim, wire, x, y, bounds[6]) end end sim.nwires = sim.nwires + 1 Simulation.connectwire(sim, wire) end function Simulation.addgate(sim, gate) sim.gates[gate.objref] = gate for k, port in pairs(gate.ports) do local offset = Port.getconnectionposition(port) Simulation.addtoworld(sim, port, offset[1], offset[2], offset[3]) Simulation.connectport(sim, port) if Port.gettype(port) == PortTypes.input then sim.ninports = sim.ninports + 1 elseif Port.gettype(port) == PortTypes.output then sim.noutports = sim.noutports + 1 end end sim.ngates = sim.ngates + 1 Gate.preinit(gate) Simulation.queuegateinit(sim, gate) Simulation.queuegate_safe(sim, gate) end function Simulation.removewire(sim, objref) local wire = sim.wires[objref] if wire ~= nil then sim.wires[objref] = nil local bounds = Wire.getbounds(wire) for x = bounds[1]+1, bounds[4]-1, 2 do for z = bounds[3]+1, bounds[6]-1, 2 do sim[x][bounds[2]][z][wire] = nil sim[x][bounds[5]][z][wire] = nil end end for y = bounds[2]+1, bounds[5]-1, 2 do for z = bounds[3]+1, bounds[6]-1, 2 do sim[bounds[1]][y][z][wire] = nil sim[bounds[4]][y][z][wire] = nil end end for x = bounds[1]+1, bounds[4]-1, 2 do for y = bounds[2]+1, bounds[5]-1, 2 do sim[x][y][bounds[3]][wire] = nil sim[x][y][bounds[6]][wire] = nil end end sim.nwires = sim.nwires - 1 Group.removewire(Wire.getgroup(wire), wire) end end function Simulation.removegate(sim, objref) local gate = sim.gates[objref] if gate ~= nil then for k, port in pairs(gate.ports) do local pos = Port.getconnectionposition(port) sim[pos[1]][pos[2]][pos[3]][port] = nil Group.removeport(Port.getgroup(port), port) if Port.gettype(port) == PortTypes.input then sim.ninports = sim.ninports - 1 elseif Port.gettype(port) == PortTypes.output then sim.noutports = sim.noutports - 1 end end end Simulation.dequeuegate(sim, gate) sim.gates[objref] = nil sim.ngates = sim.ngates - 1 end local function is_wire(obj) return obj.layer~=nil end function Simulation.connectwireat(sim, wire, x, y, z) local objs = Simulation.getfromworld(sim, x, y, z) for k, obj in pairs(objs) do if obj ~= wire and obj.group ~= nil then if is_wire(obj) then -- wire if Wire.getlayer(obj) == Wire.getlayer(wire) then -- same layer Group.addwire(obj.group, wire) end else -- port Group.addwire(obj.group, wire) end end end end function Simulation.connectwire(sim, wire) local bounds = Wire.getbounds(wire) for x = bounds[1]+1, bounds[4]-1, 2 do for z = bounds[3]+1, bounds[6]-1, 2 do Simulation.connectwireat(sim, wire, x, bounds[2], z) Simulation.connectwireat(sim, wire, x, bounds[5], z) end end for y = bounds[2]+1, bounds[5]-1, 2 do for z = bounds[3]+1, bounds[6]-1, 2 do Simulation.connectwireat(sim, wire, bounds[1], y, z) Simulation.connectwireat(sim, wire, bounds[4], y, z) end end for x = bounds[1]+1, bounds[4]-1, 2 do for y = bounds[2]+1, bounds[5]-1, 2 do Simulation.connectwireat(sim, wire, x, y, bounds[3]) Simulation.connectwireat(sim, wire, x, y, bounds[6]) end end if Wire.getgroup(wire)==nil then Group.addwire(Group.new(), wire) end end function Simulation.connectport(sim, port) local connpos = Port.getconnectionposition(port) local objs = Simulation.getfromworld(sim, connpos[1], connpos[2], connpos[3]) for k, obj in pairs(objs) do if obj ~= port and obj.group ~= nil then Group.addport(obj.group, port) end end if Port.getgroup(port) == nil then Group.addport(Group.new(), port) end end -- Logic Critical function Simulation.queuegate(sim, gate) sim.gatequeue[sim.num_gatequeue+1] = gate sim.num_gatequeue = sim.num_gatequeue + 1 gate.in_queue = 1 end function Simulation.queuegate_safe(sim, gate) if gate.in_queue==0 then Simulation.queuegate(sim, gate) end end function Simulation.queuegatelater(sim, gate, delay) local tick = sim.current_tick + delay if sim.tickqueue[tick] == nil then sim.tickqueue[tick] = {} end sim.tickqueue[tick][gate] = gate end function Simulation.queuegateinput(sim, gate, argv) sim.inputqueue = sim.inputqueue or {} sim.inputqueue[gate] = argv end function Simulation.queuegateinit(sim, gate) sim.initqueue = sim.initqueue or {} sim.initqueue[gate] = gate end -- Logic Critical function Simulation.queuegroup(sim, group) sim.groupqueue[sim.num_groupqueue+1] = group sim.num_groupqueue = sim.num_groupqueue + 1 group.in_queue = 1 end function Simulation.queuegroup_safe(sim, group) if group.in_queue==0 then Simulation.queuegroup(sim, group) end end function Simulation.dequeuegroup(sim, group) if group.in_queue~=0 then array_remove(sim.groupqueue, group, true) sim.num_groupqueue = sim.num_groupqueue - 1 group.in_queue = 0 end sim.groupfxqueue[group] = nil end function Simulation.dequeuegate(sim, gate) if gate.in_queue~=0 then array_remove(sim.gatequeue, gate, true) sim.num_gatequeue = sim.num_gatequeue - 1 gate.in_queue = 0 end if sim.inputqueue~=nil then sim.inputqueue[gate] = nil end if sim.initqueue ~=nil then sim.initqueue [gate] = nil end for tick, tickq in pairs(sim.tickqueue) do tickq[gate] = nil end end function Simulation.queuegroupfx(sim, group) sim.groupfxqueue[group] = group end function Simulation.queuecallback(sim, gate, ...) sim.callbacks = sim.callbacks or {} sim.callbacks[gate.objref] = {...} end -- Logic Critical function Simulation.ticklogic(sim) for i = 1, sim.num_groupqueue do local group = sim.groupqueue[i] Group.update(group) group.in_queue = 0 sim.groupqueue[i] = nil end --sim.groupqueue = {} sim.num_groupqueue = 0 if sim.tickqueue[sim.current_tick] ~= nil then for i, gate in pairs(sim.tickqueue[sim.current_tick]) do if gate.in_queue==0 then Simulation.queuegate(sim, gate) end end sim.tickqueue[sim.current_tick] = nil end for i = 1, sim.num_gatequeue do local gate = sim.gatequeue[i] gate.logic(gate) gate.in_queue = 0 sim.gatequeue[i] = nil end --sim.gatequeue = {} sim.num_gatequeue = 0 sim.current_tick = sim.current_tick + 1 end function Simulation.tickinit(sim) if sim.initqueue ~= nil then for k, gate in pairs(sim.initqueue) do Gate.init(gate) end sim.initqueue = nil end end function Simulation.tickinput(sim) if sim.inputqueue ~= nil then for gate, argv in pairs(sim.inputqueue) do Gate.input(gate, argv) end sim.inputqueue = nil end end function Simulation.sendfxupdate(sim) for k, group in pairs(sim.groupfxqueue) do if group.state ~= group.fxstate then group.fxstate = group.state local data = group.state for i, wire in pairs(group.wires) do data = data .. "\t" .. Wire.getobjref(wire) end network_send("WU\t" .. data .. "\n") end end sim.groupfxqueue = {} end function Simulation.sendcallbacks(sim) if sim.callbacks ~= nil then local data = "CB" for objref, args in pairs(sim.callbacks) do local escargs = {} for argidx, argv in ipairs(args) do table.insert(escargs, expandescape(tostring(argv))) end data = data .. "\t" .. objref .. "\t"..(#escargs)..(#escargs>0 and ("\t"..table.concat(escargs, "\t")) or "") end network_send(data .. "\n") sim.callbacks = nil end end