assert(getmetatable(_G)==nil, "_G already has a metatable") setmetatable(_G, { __index = function(t, i) error("attempt to access nil variable "..i, 2) end }) OPT_SAVE_DIR = arg[1] or error("must specify save location") OPT_SAVE_DIR = OPT_SAVE_DIR:gsub("\\", "/") OPT_SAVE_DIR = OPT_SAVE_DIR:gsub("/$", "") print("Save location set to \""..OPT_SAVE_DIR.."\"") local socket = require("socket") local ffi = require("ffi") dofile("iosafe.lua") FFI = ffi dofile("utility.lua") dofile("simulation.lua") dofile("group.lua") dofile("wire.lua") dofile("gatedef.lua") dofile("port.lua") dofile("gate.lua") dofile("save.lua") dofile("compile.lua") FFI = nil OPT_TICK_ENABLED = true OPT_TICK_TIME = 0.032 OPT_TICK_MULT = 1 OPT_FX_UPDATES = true OPT_FX_TIME = 0.032 OPT_TICK_INF = 29 local tickdelay = 0 local ticksperinterval = 0 bool_to_int = {[false] = 0, [true] = 1} local lastticktime = 0 local ticks = 0 local tickrate = 0 local lastmeasuretime = 0 local lastfxtime = 0 local avgticks = {} local totalticks = 0 local sim = Simulation.new(Simulation) GSim = sim local units = { "uHz", "mHz", "Hz", "kHz", "MHz", "GHz", } local function round(x) return math.floor(x+0.5) end local function unitize(v) local unit = 1 v = v*1000000 while v >= 1000 do v = v/1000 unit = unit+1 end local s if v >= 100 then s = "" .. round(v/10)*10 elseif v >= 10 then s = "" .. round(v) elseif v >= 1 then s = "" .. round(v*10)/10 if #s == 1 then s = s .. ".0" end else s = 0 end return s .. " " .. units[unit] end function vectotable(vec) local tbl = {} for comp in string.gmatch(vec, "([^%s]+)") do tbl[#tbl+1] = tonumber(comp) end return tbl end function tabletostring(table) local str = tostring(table[1]) for i = 2, #table do str = str .. " " .. tostring(table[i]) end return str end function toboolean(value) local num = tonumber(value) if num == 1 then return true else return false end end local function acceptclient() client = server:accept() client:settimeout(0) local ip, port = client:getsockname() print("Connection from " .. ip .. ":" .. port) end server = assert(socket.bind("*", 25000)) client = nil local ip, port = server:getsockname() print("Server listening on " .. ip .. ":" .. port) acceptclient() while 1 do local line, err = client:receive() if not err then local data = {} local i = 1 line = line:gsub(";;", "; ;") line = line:gsub(";$", "; ") for str in string.gmatch(line, "([^;]+)") do data[i] = str or "" i = i + 1 end local i = 1 while i <= #data do if data[i] == "W" then local min = vectotable(data[i+3]) local max = vectotable(data[i+4]) local bounds = {min[1], min[2], min[3], max[1], max[2], max[3]} local wire = Wire.new(tonumber(data[i+1]), tonumber(data[i+2]), bounds) Simulation.addwire(sim, wire) i = i + 4 elseif data[i] == "G" then local objref = tonumber(data[i+1]) local definition = Simulation.getdefinitionbyref(sim, tonumber(data[i+2])) assert(definition, "No gate definition for objref "..objref) local position = vectotable(data[i+3]) local rotation = tonumber(data[i+4]) local gate = GateDefinition.constructgate(definition, objref, position, rotation) Simulation.addgate(sim, gate) --print(gate.objref) --Gate.init(gate) --Gate.logic(gate) i = i + 4 elseif data[i] == "RW" then Simulation.removewire(sim, tonumber(data[i+1])) i = i + 1 elseif data[i] == "RG" then Simulation.removegate(sim, tonumber(data[i+1])) i = i + 1 elseif data[i] == "GD" then --print("---------------------------------------[[[[") --print(table.concat(data, "]]]]\n[[[[", i, math.min(#data, i+100))) --print("]]]]---------------------------------------") local objref = tonumber(data[i+1]) local name = data[i+2] local desc = data[i+3] local init = data[i+4] local logic = data[i+5] local input = data[i+6] local global = data[i+7] local numports = tonumber(data[i+8]) local ports = {} for a = i+9, numports*5+i+8, 5 do local portd = { type = tonumber(data[a]), position = vectotable(data[a+1]), direction = tonumber(data[a+2]), causeupdate = toboolean(data[a+3]), name = data[a+4], } ports[#ports+1] = portd if not portd.direction then print(line) end end local definition = GateDefinition.new(objref, name, desc, init, logic, input, global, ports) Simulation.addgatedefinition(sim, definition) i = i + 8 + numports*5 elseif data[i] == "SL" then local wire = Simulation.getwirebyref(sim, tonumber(data[i+1])) if wire ~= nil then Wire.setlayer(wire, tonumber(data[i+2])) end i = i + 2 elseif data[i] == "OPT" then local option = data[i+1] local value = tonumber(data[i+2]) if option == "TICK_ENABLED" then OPT_TICK_ENABLED = toboolean(value) elseif option == "TICK_TIME" then if value < 0 or value > 999999 then value = 0 end if value<=0.001 then value = 0.0001 end OPT_TICK_TIME = value elseif option == "FX_UPDATES" then OPT_FX_UPDATES = toboolean(value) elseif option == "FX_TIME" then if value < 0 or value > 999999 then value = 0 end OPT_FX_TIME = value elseif option=="TICK_MULT" then OPT_TICK_MULT = value end i = i + 2 elseif data[i] == "GINFO" then local userid = data[i+1] local objref = tonumber(data[i+2]) local info = "" local wire = Simulation.getwirebyref(sim, objref) if wire then local group = Wire.getgroup(wire) local numwires = 0; for k, wire2 in pairs(group.wires ) do numwires = numwires +1 end local numportsi = 0; for k, port in pairs(group.in_ports ) do numportsi = numportsi+1 end local numgatesu = #group.gates_update local numportso = 0; local numportson=0; for k, port in pairs(group.out_ports) do numportso = numportso+1 if Port.getstate(port) then numportson = numportson+1 end end info = "\\c5Net " .. tostring(group):match("table: 0x(.+)"):upper() .. "\n" .. (Wire.getgroup(wire).state and "\\c2On" or "\\c0Off") .. "\n" .. "Wires: "..numwires.."\n".. "In Ports: " ..numportsi.."\n".. "Out Ports: "..numportso.."\n".. "Gates Update: "..numgatesu.."\n".. "Out Ports On: "..(group.state_num) ; end local gate = Simulation.getgatebyref(sim, objref) if gate then local def = Gate.getdefinition(gate) info = "\\c5" .. def.name .. "
" for i = 1, #gate.ports do info = info .. (gate.ports[i].state and "\\c2" or "\\c0") .. def.ports[i].name .. (i ~= #gate.ports and " " or "") end end if info ~= "" then client:send("GINFO\t" .. userid .. "\t" .. expandescape(info) .. "\n") end i = i + 2 elseif data[i] == "SINFO" then client:send("SINFO\t" .. data[i+1] .. "\t" .. sim.nwires .. "\t" .. sim.ngates .. "\t" .. sim.ninports .. "\t" .. sim.noutports .. "\n") i = i + 1 elseif data[i] == "TICK" then Simulation.tick(sim) ticks = ticks + 1 elseif data[i] == "IN" then local gate = Simulation.getgatebyref(sim, tonumber(data[i+1])) local argc = tonumber(data[i+2]) local argv = {} for a = i+3, i+3+argc-1 do argv[#argv+1] = collapseescape(data[a]) end if gate then Simulation.queuegateinput(sim, gate, argv) end i = i+2+argc elseif data[i] == "SAVE" then print("saving all data") logicsave() else print("invalid data "..data[i]) end i = i + 1 end elseif err == "closed" then sim = Simulation.new(Simulation) acceptclient() end local time = os.clock() if OPT_TICK_ENABLED then if time-lastticktime >= OPT_TICK_TIME then lastticktime = time if OPT_TICK_TIME==0 then for i = 1, OPT_TICK_INF do Simulation.tick(sim) end ticks = ticks+OPT_TICK_INF else for i = 1, OPT_TICK_MULT do Simulation.tick(sim) ticks = ticks+1 local elapsed = os.clock()-time if elapsed>0.1 then break end end end local sleeptime = time+OPT_TICK_TIME-os.clock()-0.005 if sleeptime>0 then socket.sleep(sleeptime) end end else socket.sleep(0.05) end if time-lastfxtime >= OPT_FX_TIME then if OPT_FX_UPDATES then Simulation.sendfxupdate(sim) end Simulation.sendcallbacks(sim) lastfxtime = time end if time-lastmeasuretime >= 0.1 then if #avgticks >= 10 then totalticks = totalticks - table.remove(avgticks, 1) end table.insert(avgticks, ticks) totalticks = totalticks + ticks ticks = 0 client:send("TPS\t" .. unitize((totalticks/#avgticks)/0.1) .. "\n") lastmeasuretime = os.clock() end end