Initial commit
This commit is contained in:
		
							
								
								
									
										4
									
								
								StartBackend.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								StartBackend.bat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | @echo off | ||||||
|  | cd "sim" | ||||||
|  | luajit "main.lua" | ||||||
|  | pause | ||||||
							
								
								
									
										53
									
								
								sim/gate.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								sim/gate.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | Gate = {} | ||||||
|  |  | ||||||
|  | function Gate:new(objref, definition) | ||||||
|  | 	local o = { | ||||||
|  | 		objref = objref, | ||||||
|  | 		definition = definition, | ||||||
|  | 		ports = {} | ||||||
|  | 	} | ||||||
|  | 	setmetatable(o, self) | ||||||
|  | 	self.__index = self | ||||||
|  | 	return o | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Gate:addport(port) | ||||||
|  | 	self.ports[#self.ports+1] = port | ||||||
|  | 	port.gate = self | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Gate:setportstate(index, state) | ||||||
|  | 	self.ports[index]:setstate(state) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- function Gate:cb(...) | ||||||
|  | -- 	local args = {...} | ||||||
|  | -- 	local str = tostring(#args) | ||||||
|  |  | ||||||
|  | -- 	for i, v in ipairs(args) do | ||||||
|  | -- 		v = bool_to_int[v] or tostring(v) | ||||||
|  | -- 		str = str .. "\t" .. tostring(v) | ||||||
|  | -- 	end | ||||||
|  |  | ||||||
|  | -- 	sim:queuecallback(self, str) | ||||||
|  | -- end | ||||||
|  |  | ||||||
|  | function Gate:cb(str) | ||||||
|  | 	sim:queuecallback(self, str) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Gate:queue(delay) | ||||||
|  | 	sim:queuegatelater(self, delay) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Gate:testlogic(n) | ||||||
|  | 	local time = os.clock() | ||||||
|  | 	for i = 1, n do | ||||||
|  | 		self.definition.logic(self) | ||||||
|  | 	end | ||||||
|  | 	client:send("TEST\t" .. (os.clock()-time) .. "\n") | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Gate:gettick() | ||||||
|  | 	return sim.currenttick | ||||||
|  | end | ||||||
							
								
								
									
										87
									
								
								sim/gatedef.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								sim/gatedef.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | |||||||
|  |  | ||||||
|  | require "utility" | ||||||
|  |  | ||||||
|  | GateDefinition = { | ||||||
|  | 	ports = {}, | ||||||
|  | 	logic = function(gate) end, | ||||||
|  | 	input = function(gate, argv) end | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function GateDefinition:new(objref, name, description, init, logic, input, global, ports) | ||||||
|  | 	local o = { | ||||||
|  | 		objref = objref, | ||||||
|  | 		name = name, | ||||||
|  | 		description = description, | ||||||
|  | 		ports = ports or {} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	init  = collapseescape(init) | ||||||
|  | 	logic = collapseescape(logic) | ||||||
|  | 	input = collapseescape(input) | ||||||
|  | 	global = collapseescape(global) | ||||||
|  | 	 | ||||||
|  | 	local initfunc = loadstring(tostring(init)) | ||||||
|  | 	if initfunc~=nil then | ||||||
|  | 		o.init = initfunc() or function()end | ||||||
|  | 	else | ||||||
|  | 		print("Error loading init func for ".. (name or "")) | ||||||
|  | 	end | ||||||
|  | 	 | ||||||
|  | 	local logicfunc = loadstring(tostring(logic)) | ||||||
|  | 	if logicfunc ~= nil then | ||||||
|  | 		o.logic = logicfunc() or function()end | ||||||
|  | 	else | ||||||
|  | 		print("Error loading logic function for " .. (name or "")) | ||||||
|  | 		print(logic) | ||||||
|  | 	end | ||||||
|  | 	 | ||||||
|  | 	local inputfunc = loadstring(tostring(input)) | ||||||
|  | 	if inputfunc ~= nil then | ||||||
|  | 		o.input = inputfunc() or function()end | ||||||
|  | 	else | ||||||
|  | 		print("Error loading input function for " .. (name or "")) | ||||||
|  | 	end | ||||||
|  | 	 | ||||||
|  | 	local globalfunc = loadstring(tostring(global)) | ||||||
|  | 	if globalfunc~=nil then | ||||||
|  | 		globalfunc() | ||||||
|  | 	else | ||||||
|  | 		print("Error loading global function for ".. (name or "")) | ||||||
|  | 	end | ||||||
|  | 	 | ||||||
|  | 	setmetatable(o, self) | ||||||
|  | 	self.__index = self | ||||||
|  | 	return o | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function GateDefinition:constructgate(objref, position, rotation) | ||||||
|  | 	local gate = Gate:new(objref, self) | ||||||
|  |  | ||||||
|  | 	for i = 1, #self.ports do | ||||||
|  | 		local port = self.ports[i] | ||||||
|  | 		local type = port.type | ||||||
|  | 		local pos = {port.position[1], port.position[2], port.position[3]} | ||||||
|  | 		local dir = port.direction | ||||||
|  |  | ||||||
|  | 		if dir < 4 then | ||||||
|  | 			dir = (dir + rotation) % 4 | ||||||
|  | 		end | ||||||
|  |  | ||||||
|  | 		local x = pos[1] | ||||||
|  |  | ||||||
|  | 		if rotation == 1 then | ||||||
|  | 			pos[1] = pos[2] | ||||||
|  | 			pos[2] = -x | ||||||
|  | 		elseif rotation == 2 then | ||||||
|  | 			pos[1] = -pos[1] | ||||||
|  | 			pos[2] = -pos[2] | ||||||
|  | 		elseif rotation == 3 then | ||||||
|  | 			pos[1] = -pos[2] | ||||||
|  | 			pos[2] = x | ||||||
|  | 		end | ||||||
|  |  | ||||||
|  | 		gate:addport(Port:new(type, dir, {position[1]+pos[1], position[2]+pos[2], position[3]+pos[3]}, port.causeupdate)) | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	return gate | ||||||
|  | end | ||||||
							
								
								
									
										147
									
								
								sim/group.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								sim/group.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | |||||||
|  | Group = {} | ||||||
|  |  | ||||||
|  | function Group:new() | ||||||
|  | 	local o = { | ||||||
|  | 		state = false, | ||||||
|  | 		fxstate = false, | ||||||
|  | 		updatetick = 0, | ||||||
|  | 		wires = {}, | ||||||
|  | 		out_ports = {}, | ||||||
|  | 		in_ports = {}, | ||||||
|  | 	 | ||||||
|  | 		nwires = 0, | ||||||
|  | 		nout_ports = 0, | ||||||
|  | 		nin_ports = 0 | ||||||
|  | 	} | ||||||
|  | 	setmetatable(o, self) | ||||||
|  | 	self.__index = self | ||||||
|  | 	return o | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Group:getsize() | ||||||
|  | 	return self.nwires + self.nout_ports + self.nin_ports | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Group:addwire(wire) | ||||||
|  | 	if wire.group ~= self then | ||||||
|  | 		if wire.group ~= nil then | ||||||
|  | 			self:mergewith(wire.group) | ||||||
|  | 		else | ||||||
|  | 			self.wires[wire] = wire | ||||||
|  | 			self.nwires = self.nwires + 1 | ||||||
|  | 			 | ||||||
|  | 			wire.group = self | ||||||
|  | 			wire:update() | ||||||
|  | 			sim:queuegroup(self) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Group:removewire(wire) | ||||||
|  | 	wire.group = nil | ||||||
|  | 	self.wires[wire] = nil | ||||||
|  |  | ||||||
|  | 	for k, wire in pairs(self.wires) do | ||||||
|  | 		wire.group = nil | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	for k, port in pairs(self.out_ports) do | ||||||
|  | 		port.group = nil | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	for k, port in pairs(self.in_ports) do | ||||||
|  | 		port.group = nil | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	for k, wire in pairs(self.wires) do | ||||||
|  | 		sim:connectwire(wire) | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	for k, port in pairs(self.out_ports) do | ||||||
|  | 		sim:connectport(port) | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	for k, port in pairs(self.in_ports) do | ||||||
|  | 		sim:connectport(port) | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	self.wires = {} | ||||||
|  | 	self.out_ports = {} | ||||||
|  | 	self.in_ports = {} | ||||||
|  |  | ||||||
|  | 	self.nwires = 0 | ||||||
|  | 	self.nout_ports = 0 | ||||||
|  | 	self.nin_ports = 0 | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Group:addport(port) | ||||||
|  | 	port.group = self | ||||||
|  |  | ||||||
|  | 	if port.type == PortTypes.output then | ||||||
|  | 		self.out_ports[port] = port | ||||||
|  | 		self.nout_ports = self.nout_ports + 1 | ||||||
|  | 		sim:queuegroup(self) | ||||||
|  | 	elseif port.type == PortTypes.input then | ||||||
|  | 		self.in_ports[port] = port | ||||||
|  | 		self.nin_ports = self.nin_ports + 1 | ||||||
|  | 		port:setinputstate(self.state) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Group:removeport(port) | ||||||
|  | 	if port.type == PortTypes.output then | ||||||
|  | 		self.out_ports[port] = nil | ||||||
|  | 		self.nout_ports = self.nout_ports - 1 | ||||||
|  | 	elseif port.type == PortTypes.input then | ||||||
|  | 		self.in_ports[port] = nil | ||||||
|  | 		self.nin_ports = self.nin_ports - 1 | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	sim:queuegroup(self) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Group:mergewith(group) | ||||||
|  | 	if self:getsize() >= group:getsize() then | ||||||
|  | 		group:mergeinto(self) | ||||||
|  | 		return self | ||||||
|  | 	else | ||||||
|  | 		self:mergeinto(group) | ||||||
|  | 		return group | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Group:mergeinto(group) | ||||||
|  | 	for k, wire in pairs(self.wires) do | ||||||
|  | 		wire.group = nil | ||||||
|  | 		group:addwire(wire) | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	for k, port in pairs(self.out_ports) do | ||||||
|  | 		group:addport(port) | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	for k, port in pairs(self.in_ports) do | ||||||
|  | 		group:addport(port) | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	self.wires = {} | ||||||
|  | 	self.out_ports = {} | ||||||
|  | 	self.in_ports = {} | ||||||
|  |  | ||||||
|  | 	self.nwires = 0 | ||||||
|  | 	self.nout_ports = 0 | ||||||
|  | 	self.nin_ports = 0 | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Group:setstate(state) | ||||||
|  | 	if state ~= self.state then | ||||||
|  | 		self.state = state | ||||||
|  | 		self.updatetick = sim.currenttick | ||||||
|  |  | ||||||
|  | 		for k, port in pairs(self.in_ports) do | ||||||
|  | 			port:setinputstate(state) | ||||||
|  | 		end | ||||||
|  |  | ||||||
|  | 		sim:queuegroupfx(self) | ||||||
|  | 	end | ||||||
|  | end | ||||||
							
								
								
									
										312
									
								
								sim/main.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										312
									
								
								sim/main.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,312 @@ | |||||||
|  | dofile("simulation.lua") | ||||||
|  | dofile("group.lua") | ||||||
|  | dofile("wire.lua") | ||||||
|  | dofile("gatedef.lua") | ||||||
|  | dofile("gate.lua") | ||||||
|  | dofile("port.lua") | ||||||
|  |  | ||||||
|  | OPT_TICK_ENABLED = true | ||||||
|  | OPT_TICK_TIME = 0 | ||||||
|  | OPT_FX_UPDATES = true | ||||||
|  | OPT_FX_TIME = 0.03 | ||||||
|  |  | ||||||
|  | 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 | ||||||
|  |  | ||||||
|  | sim = Simulation:new() | ||||||
|  |  | ||||||
|  | local units = { | ||||||
|  | 	"uTz", | ||||||
|  | 	"mTz", | ||||||
|  | 	"Tz", | ||||||
|  | 	"kTz", | ||||||
|  | 	"MTz", | ||||||
|  | 	"GTz", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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 | ||||||
|  |  | ||||||
|  | local socket = require("socket") | ||||||
|  | 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(";;", "; ;") | ||||||
|  | 		for str in string.gmatch(line, "([^;]+)") do | ||||||
|  | 			data[i] = str | ||||||
|  | 			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) | ||||||
|  | 				sim:addwire(wire) | ||||||
|  |  | ||||||
|  | 				i = i + 4 | ||||||
|  | 			elseif data[i] == "G" then | ||||||
|  | 				local objref = tonumber(data[i+1]) | ||||||
|  | 				local definition = sim:getdefinitionbyref(tonumber(data[i+2])) or GateDefinition | ||||||
|  | 				local position = vectotable(data[i+3]) | ||||||
|  | 				local rotation = tonumber(data[i+4]) | ||||||
|  | 				local gate = definition:constructgate(objref, position, rotation) | ||||||
|  |  | ||||||
|  | 				sim:addgate(gate) | ||||||
|  | 				--print(gate.objref) | ||||||
|  | 				gate.definition.init(gate) | ||||||
|  | 				gate.definition.logic(gate) | ||||||
|  |  | ||||||
|  | 				i = i + 4 | ||||||
|  | 			elseif data[i] == "RW" then | ||||||
|  | 				sim:removewire(tonumber(data[i+1])) | ||||||
|  | 				i = i + 1 | ||||||
|  | 			elseif data[i] == "RG" then | ||||||
|  | 				sim:removegate(tonumber(data[i+1])) | ||||||
|  | 				i = i + 1 | ||||||
|  | 			elseif data[i] == "GD" then | ||||||
|  | 				--print(table.concat(data, "\n", i, math.min(#data, i+100))) | ||||||
|  | 				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 port = { | ||||||
|  | 						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] = port | ||||||
|  |  | ||||||
|  | 					if not port.direction then print(line) end | ||||||
|  | 				end | ||||||
|  |  | ||||||
|  | 				local definition = GateDefinition:new(objref, name, desc, init, logic, input, global, ports) | ||||||
|  | 				sim:addgatedefinition(definition) | ||||||
|  |  | ||||||
|  | 				i = i + 8 + numports*5 | ||||||
|  | 			elseif data[i] == "SL" then | ||||||
|  | 				local wire = sim:getwirebyref(tonumber(data[i+1])) | ||||||
|  | 				if wire ~= nil then | ||||||
|  | 					wire:setlayer(tonumber(data[i+2])) | ||||||
|  | 				end | ||||||
|  |  | ||||||
|  | 				i = i + 2 | ||||||
|  | 			elseif data[i] == "SP" then | ||||||
|  | 				local gate = sim:getgatebyref(tonumber(data[i+1])) | ||||||
|  | 				if gate ~= nil then | ||||||
|  | 					gate.ports[tonumber(data[i+2])]:setstate(toboolean(data[i+3])) | ||||||
|  | 				end | ||||||
|  |  | ||||||
|  | 				i = i + 3 | ||||||
|  | 			elseif data[i] == "SG" then | ||||||
|  | 				local wire = sim:getwirebyref(tonumber(data[i+1])) | ||||||
|  | 				if wire ~= nil then | ||||||
|  | 					wire.group:setstate(toboolean(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 | ||||||
|  | 					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 | ||||||
|  | 				end | ||||||
|  |  | ||||||
|  | 				i = i + 2 | ||||||
|  | 			elseif data[i] == "GINFO" then | ||||||
|  | 				local userid = data[i+1] | ||||||
|  | 				local objref = tonumber(data[i+2]) | ||||||
|  |  | ||||||
|  | 				local obj = sim:getwirebyref(objref) or sim:getgatebyref(objref) | ||||||
|  |  | ||||||
|  | 				if obj ~= nil then | ||||||
|  | 					local info = "" | ||||||
|  |  | ||||||
|  | 					if obj.logictype == 0 then | ||||||
|  | 						local numportsi = 0; for k, wire in pairs(obj.group.in_ports ) do numportsi = numportsi+1 end | ||||||
|  | 						local numportso = 0; for k, wire in pairs(obj.group.out_ports) do numportso = numportso+1 end | ||||||
|  |  | ||||||
|  | 						info = "\\c5WIRE<br>" .. (obj.group.state and "\\c2ON" or "\\c0OFF") .. "\n" .. | ||||||
|  | 							"IN PORTS: " ..numportsi.."\n".. | ||||||
|  | 							"OUT PORTS: "..numportso | ||||||
|  | 						; | ||||||
|  | 					else | ||||||
|  | 						info = "\\c5" .. obj.definition.name .. "<br>" | ||||||
|  | 						for i = 1, #obj.ports do | ||||||
|  | 							info = info .. (obj.ports[i].state and "\\c2" or "\\c0") .. obj.definition.ports[i].name .. (i ~= #obj.ports and " " or "") | ||||||
|  | 						end | ||||||
|  | 					end | ||||||
|  |  | ||||||
|  | 					if info ~= "" then | ||||||
|  | 						client:send("GINFO\t" .. userid .. "\t" .. expandescape(info) .. "\n") | ||||||
|  | 					end | ||||||
|  | 				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 | ||||||
|  | 				sim:tick() | ||||||
|  | 				ticks = ticks + 1 | ||||||
|  | 			elseif data[i] == "TEST" then | ||||||
|  | 				local gate = sim:getgatebyref(tonumber(data[i+1])) | ||||||
|  | 				gate:testlogic(tonumber(data[i+2])) | ||||||
|  | 				i = i + 2 | ||||||
|  | 			elseif data[i] == "IN" then | ||||||
|  | 				local gate = sim:getgatebyref(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 | ||||||
|  | 				sim:queuegateinput(gate, argv) | ||||||
|  |  | ||||||
|  | 				i = i+2+argc | ||||||
|  | 			end | ||||||
|  |  | ||||||
|  | 			i = i + 1 | ||||||
|  | 		end | ||||||
|  | 	elseif err == "closed" then | ||||||
|  | 		sim = Simulation:new() | ||||||
|  | 		acceptclient() | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	local time = os.clock() | ||||||
|  |  | ||||||
|  | 	if OPT_TICK_ENABLED then | ||||||
|  | 		if time - lastticktime >= OPT_TICK_TIME then | ||||||
|  | 			sim:tick() | ||||||
|  | 			ticks = ticks + 1 | ||||||
|  | 			lastticktime = time | ||||||
|  |  | ||||||
|  | 			local timetonext = time+OPT_TICK_TIME-os.clock() | ||||||
|  |  | ||||||
|  | 			local sleeptime = timetonext*0.9 | ||||||
|  | 			if sleeptime>0 then socket.sleep(sleeptime) end | ||||||
|  | 		end | ||||||
|  | 	else | ||||||
|  | 		socket.sleep(0.1) | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	if time-lastfxtime >= OPT_FX_TIME then | ||||||
|  | 		sim:sendfxupdate() | ||||||
|  | 		sim:sendcallbacks() | ||||||
|  | 		lastfxtime = time | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	if time-lastmeasuretime >= 0.1 then | ||||||
|  | 		if #avgticks >= 20 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 | ||||||
							
								
								
									
										67
									
								
								sim/port.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								sim/port.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | PortTypes = { | ||||||
|  | 	output = 0, | ||||||
|  | 	input = 1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | PortDirections = { | ||||||
|  | 	[0] = {-1, 0, 0}, | ||||||
|  | 	[1] = {0, 1, 0}, | ||||||
|  | 	[2] = {1, 0, 0}, | ||||||
|  | 	[3] = {0, -1, 0}, | ||||||
|  | 	[4] = {0, 0, 1}, | ||||||
|  | 	[5] = {0, 0, -1} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Port = { | ||||||
|  | 	logictype = 1, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function Port:new(type, direction, position, causeupdate) | ||||||
|  | 	local o = { | ||||||
|  | 		type = type, | ||||||
|  | 		direction = direction, | ||||||
|  | 		position = position, | ||||||
|  | 		causeupdate = causeupdate, | ||||||
|  | 		state = false, | ||||||
|  | 		gate = nil, | ||||||
|  | 		group = nil, | ||||||
|  | 	} | ||||||
|  | 	setmetatable(o, self) | ||||||
|  | 	self.__index = self | ||||||
|  | 	return o | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Port:setstate(state) | ||||||
|  | 	if state ~= self.state then | ||||||
|  | 		self.state = state | ||||||
|  | 		sim:queuegroup(self.group) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Port:setinputstate(state) | ||||||
|  | 	if state ~= self.state then | ||||||
|  | 		self.state = state | ||||||
|  | 		if self.causeupdate then | ||||||
|  | 			sim:queuegate(self.gate) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Port:getconnectionposition() | ||||||
|  | 	local offset = PortDirections[self.direction] | ||||||
|  | 	return {self.position[1]+offset[1], self.position[2]+offset[2], self.position[3]+offset[3]} | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Port:isrising() | ||||||
|  | 	if self.group == nil then | ||||||
|  | 		return false | ||||||
|  | 	end | ||||||
|  | 	return self.group.state and (self.group.updatetick == sim.currenttick) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Port:isfalling() | ||||||
|  | 	if self.group == nil then | ||||||
|  | 		return false | ||||||
|  | 	end | ||||||
|  | 	return self.group.state == false and (self.group.updatetick == sim.currenttick) | ||||||
|  | end | ||||||
							
								
								
									
										343
									
								
								sim/simulation.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								sim/simulation.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,343 @@ | |||||||
|  |  | ||||||
|  | require "utility" | ||||||
|  |  | ||||||
|  | Simulation = {} | ||||||
|  |  | ||||||
|  | function Simulation:new() | ||||||
|  | 	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(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(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(objref) | ||||||
|  | 	return self.definitions[objref] | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:getgatebyref(objref) | ||||||
|  | 	return self.gates[objref] | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:getwirebyref(objref) | ||||||
|  | 	return self.wires[objref] | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:addgatedefinition(definition) | ||||||
|  | 	self.definitions[definition.objref] = definition | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:addwire(wire) | ||||||
|  | 	self.wires[wire.objref] = wire | ||||||
|  |  | ||||||
|  | 	for x = wire.bounds[1]+1, wire.bounds[4]-1, 2 do | ||||||
|  | 		for z = wire.bounds[3]+1, wire.bounds[6]-1, 2 do | ||||||
|  | 			self:addtoworld(wire, x, wire.bounds[2], z) | ||||||
|  | 			self:addtoworld(wire, x, wire.bounds[5], z) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	for y = wire.bounds[2]+1, wire.bounds[5]-1, 2 do | ||||||
|  | 		for z = wire.bounds[3]+1, wire.bounds[6]-1, 2 do | ||||||
|  | 			self:addtoworld(wire, wire.bounds[1], y, z) | ||||||
|  | 			self:addtoworld(wire, wire.bounds[4], y, z) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	for x = wire.bounds[1]+1, wire.bounds[4]-1, 2 do | ||||||
|  | 		for y = wire.bounds[2]+1, wire.bounds[5]-1, 2 do | ||||||
|  | 			self:addtoworld(wire, x, y, wire.bounds[3]) | ||||||
|  | 			self:addtoworld(wire, x, y, wire.bounds[6]) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	self.nwires = self.nwires + 1 | ||||||
|  | 	self:connectwire(wire) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:addgate(gate) | ||||||
|  | 	self.gates[gate.objref] = gate | ||||||
|  |  | ||||||
|  | 	for k, port in pairs(gate.ports) do | ||||||
|  | 		local offset = port:getconnectionposition() | ||||||
|  | 		self:addtoworld(port, offset[1], offset[2], offset[3]) | ||||||
|  | 		self:connectport(port) | ||||||
|  |  | ||||||
|  | 		if port.type == PortTypes.input then | ||||||
|  | 			self.ninports = self.ninports + 1 | ||||||
|  | 		elseif port.type == PortTypes.output then | ||||||
|  | 			self.noutports = self.noutports + 1 | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	self.ngates = self.ngates + 1 | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:removewire(objref) | ||||||
|  | 	local wire = self.wires[objref] | ||||||
|  | 	if wire ~= nil then | ||||||
|  | 		self.wires[objref] = nil | ||||||
|  |  | ||||||
|  | 		for x = wire.bounds[1]+1, wire.bounds[4]-1, 2 do | ||||||
|  | 			for z = wire.bounds[3]+1, wire.bounds[6]-1, 2 do | ||||||
|  | 				sim[x][wire.bounds[2]][z][wire] = nil | ||||||
|  | 				sim[x][wire.bounds[5]][z][wire] = nil | ||||||
|  | 			end | ||||||
|  | 		end | ||||||
|  | 	 | ||||||
|  | 		for y = wire.bounds[2]+1, wire.bounds[5]-1, 2 do | ||||||
|  | 			for z = wire.bounds[3]+1, wire.bounds[6]-1, 2 do | ||||||
|  | 				sim[wire.bounds[1]][y][z][wire] = nil | ||||||
|  | 				sim[wire.bounds[4]][y][z][wire] = nil | ||||||
|  | 			end | ||||||
|  | 		end | ||||||
|  | 	 | ||||||
|  | 		for x = wire.bounds[1]+1, wire.bounds[4]-1, 2 do | ||||||
|  | 			for y = wire.bounds[2]+1, wire.bounds[5]-1, 2 do | ||||||
|  | 				sim[x][y][wire.bounds[3]][wire] = nil | ||||||
|  | 				sim[x][y][wire.bounds[6]][wire] = nil | ||||||
|  | 			end | ||||||
|  | 		end | ||||||
|  |  | ||||||
|  | 		self.nwires = self.nwires - 1 | ||||||
|  | 		wire.group:removewire(wire) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:removegate(objref) | ||||||
|  | 	local gate = self.gates[objref] | ||||||
|  | 	if gate ~= nil then | ||||||
|  | 		for k, port in pairs(gate.ports) do | ||||||
|  | 			local pos = port:getconnectionposition() | ||||||
|  | 			self[pos[1]][pos[2]][pos[3]][port] = nil | ||||||
|  | 			port.group:removeport(port) | ||||||
|  |  | ||||||
|  | 			if port.type == PortTypes.input then | ||||||
|  | 				self.ninports = self.ninports - 1 | ||||||
|  | 			elseif port.type == PortTypes.output then | ||||||
|  | 				self.noutports = self.noutports - 1 | ||||||
|  | 			end | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	self.gates[objref] = nil | ||||||
|  | 	self.ngates = self.ngates - 1 | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:connectwireat(wire, x, y, z) | ||||||
|  | 	local objs = self:getfromworld(x, y, z) | ||||||
|  | 	for k, obj in pairs(objs) do | ||||||
|  | 		if obj ~= wire and obj.group ~= nil then | ||||||
|  | 			if obj.logictype == 0 and obj.layer == wire.layer then | ||||||
|  | 				if obj.layer == wire.layer then | ||||||
|  | 					obj.group:addwire(wire) | ||||||
|  | 				end | ||||||
|  | 			elseif obj.logictype == 1 then | ||||||
|  | 				obj.group:addwire(wire) | ||||||
|  | 			end | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:connectwire(wire) | ||||||
|  | 	for x = wire.bounds[1]+1, wire.bounds[4]-1, 2 do | ||||||
|  | 		for z = wire.bounds[3]+1, wire.bounds[6]-1, 2 do | ||||||
|  | 			self:connectwireat(wire, x, wire.bounds[2], z) | ||||||
|  | 			self:connectwireat(wire, x, wire.bounds[5], z) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	for y = wire.bounds[2]+1, wire.bounds[5]-1, 2 do | ||||||
|  | 		for z = wire.bounds[3]+1, wire.bounds[6]-1, 2 do | ||||||
|  | 			self:connectwireat(wire, wire.bounds[1], y, z) | ||||||
|  | 			self:connectwireat(wire, wire.bounds[4], y, z) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	for x = wire.bounds[1]+1, wire.bounds[4]-1, 2 do | ||||||
|  | 		for y = wire.bounds[2]+1, wire.bounds[5]-1, 2 do | ||||||
|  | 			self:connectwireat(wire, x, y, wire.bounds[3]) | ||||||
|  | 			self:connectwireat(wire, x, y, wire.bounds[6]) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  | 	 | ||||||
|  | 	if wire.group == nil then | ||||||
|  | 		Group:new():addwire(wire) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:connectport(port) | ||||||
|  | 	local connpos = port:getconnectionposition() | ||||||
|  | 	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 | ||||||
|  | 			obj.group:addport(port) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	if port.group == nil then | ||||||
|  | 		Group:new():addport(port) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:queuegate(gate) | ||||||
|  | 	self.gatequeue[gate] = gate | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:queuegatelater(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(gate, argv) | ||||||
|  | 	self.inputqueue[gate] = self.inputqueue[gate] or {} | ||||||
|  | 	table.insert(self.inputqueue[gate], argv) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:queuegateinit(gate) | ||||||
|  | 	self.initqueue[gate] = gate | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:queuegroup(group) | ||||||
|  | 	self.groupqueue[group] = group | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:queuegroupfx(group) | ||||||
|  | 	self.groupfxqueue[group] = group | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:queuecallback(gate, ...) | ||||||
|  | 	self.callbacks[gate.objref] = {...} | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:tick() | ||||||
|  | 	for k, group in pairs(self.groupqueue) do | ||||||
|  | 		local newstate = false | ||||||
|  | 		for j, port in pairs(group.out_ports) do | ||||||
|  | 			newstate = newstate or port.state | ||||||
|  | 			if newstate then | ||||||
|  | 				break | ||||||
|  | 			end | ||||||
|  | 		end | ||||||
|  | 		 | ||||||
|  | 		group:setstate(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 | ||||||
|  | 			self:queuegate(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() | ||||||
|  | 	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] | ||||||
|  |  | ||||||
|  | 			if OPT_FX_UPDATES then | ||||||
|  | 				for i, wire in pairs(group.wires) do | ||||||
|  | 					data = data .. "\t" .. wire.objref | ||||||
|  | 				end | ||||||
|  | 			else | ||||||
|  | 				for i, wire in pairs(group.wires) do | ||||||
|  | 					if wire.isvisual then | ||||||
|  | 						data = data .. "\t" .. wire.objref | ||||||
|  | 					end | ||||||
|  | 				end | ||||||
|  | 			end | ||||||
|  |  | ||||||
|  | 			client:send("WU\t" .. data .. "\n") | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	self.groupfxqueue = {} | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Simulation:sendcallbacks() | ||||||
|  | 	if next(self.callbacks) ~= nil then | ||||||
|  | 		local data = "CB" | ||||||
|  | 		 | ||||||
|  | 		for objref, args in pairs(self.callbacks) do | ||||||
|  | 			local argc = 0 | ||||||
|  | 			local escargs = {} | ||||||
|  | 			for argidx, argv in ipairs(args) do | ||||||
|  | 				table.insert(escargs, expandescape(tostring(argv))) | ||||||
|  | 				argc = argc+1 | ||||||
|  | 			end | ||||||
|  | 			data = data .. "\t" .. objref .. "\t"..argc..(#escargs>0 and ("\t"..table.concat(escargs, "\t")) or "") | ||||||
|  | 		end | ||||||
|  | 		 | ||||||
|  | 		client:send(data .. "\n") | ||||||
|  | 		self.callbacks = {} | ||||||
|  | 	end | ||||||
|  | end | ||||||
							
								
								
									
										53
									
								
								sim/utility.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								sim/utility.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  |  | ||||||
|  | local escapes = { | ||||||
|  | 	{"\\", "b"}, | ||||||
|  | 	{"\t", "t"}, | ||||||
|  | 	{"\n", "n"}, | ||||||
|  | 	{"\r", "r"}, | ||||||
|  | 	{"\'", "a"}, | ||||||
|  | 	{"\"", "q"}, | ||||||
|  | 	{";" , "s"}, | ||||||
|  | 	{":" , "c"}, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function expandescape(str) | ||||||
|  | 	local ostrt = {} | ||||||
|  | 	 | ||||||
|  | 	local len = #str | ||||||
|  | 	for i=1, len do | ||||||
|  | 		local ci = str:sub(i, i) | ||||||
|  | 		 | ||||||
|  | 		local co = ci | ||||||
|  | 		for escidx, esc in ipairs(escapes) do | ||||||
|  | 			if ci==esc[1] then co = "\\"..esc[2] end | ||||||
|  | 		end | ||||||
|  | 		 | ||||||
|  | 		table.insert(ostrt, co) | ||||||
|  | 	end | ||||||
|  | 	 | ||||||
|  | 	return table.concat(ostrt) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function collapseescape(str) | ||||||
|  | 	local ostrt = {} | ||||||
|  | 	 | ||||||
|  | 	local i = 1 | ||||||
|  | 	local len = #str | ||||||
|  | 	while i<=len do | ||||||
|  | 		local ci = str:sub(i, i) | ||||||
|  | 		 | ||||||
|  | 		local co = ci | ||||||
|  | 		if ci=="\\" and i<len then | ||||||
|  | 			i = i+1 | ||||||
|  | 			ci = str:sub(i, i) | ||||||
|  | 			for escidx, esc in ipairs(escapes) do | ||||||
|  | 				if ci==esc[2] then co = esc[1] end | ||||||
|  | 			end | ||||||
|  | 		end | ||||||
|  | 		 | ||||||
|  | 		table.insert(ostrt, co) | ||||||
|  | 		i = i+1 | ||||||
|  | 	end | ||||||
|  | 	 | ||||||
|  | 	return table.concat(ostrt) | ||||||
|  | end | ||||||
							
								
								
									
										27
									
								
								sim/wire.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								sim/wire.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | Wire = { | ||||||
|  | 	logictype = 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function Wire:new(objref, layer, bounds) | ||||||
|  | 	local o = { | ||||||
|  | 		objref = objref, | ||||||
|  | 		layer = layer, | ||||||
|  | 		group = nil, | ||||||
|  | 		bounds = bounds | ||||||
|  | 	} | ||||||
|  | 	setmetatable(o, self) | ||||||
|  | 	self.__index = self | ||||||
|  | 	return o | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Wire:setlayer(layer) | ||||||
|  | 	if self.group ~= nil then | ||||||
|  | 		self.group:removewire(self) | ||||||
|  | 	end | ||||||
|  | 	self.layer = layer | ||||||
|  | 	sim:connectwire(self) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function Wire:update() | ||||||
|  | 	client:send("WU\t" .. bool_to_int[self.group.state] .. "\t" .. self.objref .. "\n") | ||||||
|  | end | ||||||
		Reference in New Issue
	
	Block a user
	 Eagle517
					Eagle517