336 lines
7.5 KiB
Lua
336 lines
7.5 KiB
Lua
|
|
Simulation = {}
|
|
|
|
function Simulation.new(self)
|
|
local o = {
|
|
definitions = {},
|
|
wires = {},
|
|
gates = {},
|
|
|
|
nwires = 0,
|
|
ngates = 0,
|
|
ninports = 0,
|
|
noutports = 0,
|
|
|
|
groupqueue = {},
|
|
groupfxqueue = {},
|
|
gatequeue = {},
|
|
initqueue = {},
|
|
inputqueue = {},
|
|
tickqueue = {},
|
|
|
|
callbacks = {},
|
|
|
|
currenttick = 0
|
|
}
|
|
setmetatable(o, self)
|
|
self.__index = self
|
|
return o
|
|
end
|
|
|
|
function Simulation.addtoworld(self, obj, x, y, z)
|
|
if self[x] == nil then
|
|
self[x] = {}
|
|
end
|
|
|
|
if self[x][y] == nil then
|
|
self[x][y] = {}
|
|
end
|
|
|
|
if self[x][y][z] == nil then
|
|
self[x][y][z] = {}
|
|
end
|
|
|
|
self[x][y][z][obj] = obj
|
|
end
|
|
|
|
function Simulation.getfromworld(self, x, y, z)
|
|
if self[x] == nil or self[x][y] == nil or self[x][y][z] == nil then
|
|
return {}
|
|
else
|
|
return self[x][y][z]
|
|
end
|
|
end
|
|
|
|
function Simulation.getdefinitionbyref(self, objref)
|
|
return self.definitions[objref]
|
|
end
|
|
|
|
function Simulation.getgatebyref(self, objref)
|
|
return self.gates[objref]
|
|
end
|
|
|
|
function Simulation.getwirebyref(self, objref)
|
|
return self.wires[objref]
|
|
end
|
|
|
|
function Simulation.addgatedefinition(self, definition)
|
|
self.definitions[definition.objref] = definition
|
|
end
|
|
|
|
function Simulation.addwire(self, wire)
|
|
self.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(self, wire, x, bounds[2], z)
|
|
Simulation.addtoworld(self, 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(self, wire, bounds[1], y, z)
|
|
Simulation.addtoworld(self, 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(self, wire, x, y, bounds[3])
|
|
Simulation.addtoworld(self, wire, x, y, bounds[6])
|
|
end
|
|
end
|
|
|
|
self.nwires = self.nwires + 1
|
|
Simulation.connectwire(self, wire)
|
|
end
|
|
|
|
function Simulation.addgate(self, gate)
|
|
self.gates[gate.objref] = gate
|
|
|
|
for k, port in pairs(gate.ports) do
|
|
local offset = Port.getconnectionposition(port)
|
|
Simulation.addtoworld(self, port, offset[1], offset[2], offset[3])
|
|
Simulation.connectport(self, port)
|
|
|
|
if Port.gettype(port) == PortTypes.input then
|
|
self.ninports = self.ninports + 1
|
|
elseif Port.gettype(port) == PortTypes.output then
|
|
self.noutports = self.noutports + 1
|
|
end
|
|
end
|
|
|
|
self.ngates = self.ngates + 1
|
|
end
|
|
|
|
function Simulation.removewire(self, objref)
|
|
local wire = self.wires[objref]
|
|
if wire ~= nil then
|
|
self.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
|
|
|
|
self.nwires = self.nwires - 1
|
|
Group.removewire(Wire.getgroup(wire), wire)
|
|
end
|
|
end
|
|
|
|
function Simulation.removegate(self, objref)
|
|
local gate = self.gates[objref]
|
|
if gate ~= nil then
|
|
for k, port in pairs(gate.ports) do
|
|
local pos = Port.getconnectionposition(port)
|
|
self[pos[1]][pos[2]][pos[3]][port] = nil
|
|
Group.removeport(Port.getgroup(port), port)
|
|
|
|
if Port.gettype(port) == PortTypes.input then
|
|
self.ninports = self.ninports - 1
|
|
elseif Port.gettype(port) == PortTypes.output then
|
|
self.noutports = self.noutports - 1
|
|
end
|
|
end
|
|
end
|
|
|
|
self.gates[objref] = nil
|
|
self.ngates = self.ngates - 1
|
|
end
|
|
|
|
function Simulation.connectwireat(self, wire, x, y, z)
|
|
local objs = Simulation.getfromworld(self, x, y, z)
|
|
for k, obj in pairs(objs) do
|
|
if obj ~= wire and obj.group ~= nil then
|
|
if obj.logictype == 0 and Wire.getlayer(obj) == Wire.getlayer(wire) then
|
|
Group.addwire(obj.group, wire)
|
|
elseif obj.logictype == 1 then
|
|
Group.addwire(obj.group, wire)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function Simulation.connectwire(self, 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
|
|
self:connectwireat(wire, x, bounds[2], z)
|
|
self:connectwireat(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
|
|
self:connectwireat(wire, bounds[1], y, z)
|
|
self:connectwireat(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
|
|
self:connectwireat(wire, x, y, bounds[3])
|
|
self:connectwireat(wire, x, y, bounds[6])
|
|
end
|
|
end
|
|
|
|
if Wire.getgroup(wire)==nil then
|
|
Group.addwire(Group.new(Group), wire)
|
|
end
|
|
end
|
|
|
|
function Simulation.connectport(self, port)
|
|
local connpos = Port.getconnectionposition(port)
|
|
local objs = self:getfromworld(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(Group), port)
|
|
end
|
|
end
|
|
|
|
function Simulation.queuegate(self, gate)
|
|
self.gatequeue[gate] = gate
|
|
end
|
|
|
|
function Simulation.queuegatelater(self, gate, delay)
|
|
local tick = self.currenttick + delay
|
|
if self.tickqueue[tick] == nil then
|
|
self.tickqueue[tick] = {}
|
|
end
|
|
table.insert(self.tickqueue[tick], gate)
|
|
end
|
|
|
|
function Simulation.queuegateinput(self, gate, argv)
|
|
self.inputqueue[gate] = self.inputqueue[gate] or {}
|
|
table.insert(self.inputqueue[gate], argv)
|
|
end
|
|
|
|
function Simulation.queuegateinit(self, gate)
|
|
self.initqueue[gate] = gate
|
|
end
|
|
|
|
function Simulation.queuegroup(self, group)
|
|
self.groupqueue[group] = group
|
|
end
|
|
|
|
function Simulation.queuegroupfx(self, group)
|
|
self.groupfxqueue[group] = group
|
|
end
|
|
|
|
function Simulation.queuecallback(self, gate, ...)
|
|
self.callbacks[gate.objref] = {...}
|
|
end
|
|
|
|
function Simulation.tick(self)
|
|
for k, group in pairs(self.groupqueue) do
|
|
local newstate = false
|
|
for j, port in pairs(group.out_ports) do
|
|
newstate = newstate or Port.getstate(port)
|
|
if newstate then
|
|
break
|
|
end
|
|
end
|
|
|
|
Group.setstate(group, newstate)
|
|
end
|
|
self.groupqueue = {}
|
|
|
|
for k, gate in pairs(self.initqueue) do
|
|
gate.definition.init(gate)
|
|
end
|
|
self.initqueue = {}
|
|
|
|
for gate, inputs in pairs(self.inputqueue) do
|
|
for inputidx, argv in ipairs(inputs) do
|
|
gate.definition.input(gate, argv)
|
|
end
|
|
end
|
|
self.inputqueue = {}
|
|
|
|
if self.tickqueue[self.currenttick] ~= nil then
|
|
for i, gate in ipairs(self.tickqueue[self.currenttick]) do
|
|
Simulation.queuegate(self, gate)
|
|
end
|
|
self.tickqueue[self.currenttick] = nil
|
|
end
|
|
|
|
for k, gate in pairs(self.gatequeue) do
|
|
gate.definition.logic(gate)
|
|
end
|
|
self.gatequeue = {}
|
|
|
|
self.currenttick = self.currenttick + 1
|
|
end
|
|
|
|
function Simulation.sendfxupdate(self)
|
|
for k, group in pairs(self.groupfxqueue) do
|
|
if group.state ~= group.fxstate then
|
|
group.fxstate = group.state
|
|
|
|
local data = bool_to_int[group.state]
|
|
|
|
for i, wire in pairs(group.wires) do
|
|
data = data .. "\t" .. Wire.getobjref(wire)
|
|
end
|
|
|
|
client:send("WU\t" .. data .. "\n")
|
|
end
|
|
end
|
|
|
|
self.groupfxqueue = {}
|
|
end
|
|
|
|
function Simulation.sendcallbacks(self)
|
|
if next(self.callbacks) ~= nil then
|
|
local data = "CB"
|
|
|
|
for objref, args in pairs(self.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
|
|
|
|
client:send(data .. "\n")
|
|
self.callbacks = {}
|
|
end
|
|
end
|