mirror of
https://github.com/metrostroi-repo/MetrostroiAddon.git
synced 2026-05-02 00:42:29 +00:00
Removed obsolete content
This commit is contained in:
@@ -1,489 +0,0 @@
|
||||
--------------------------------------------------------------------------------
|
||||
-- Simulation acceleration DLL support
|
||||
--------------------------------------------------------------------------------
|
||||
if Turbostroi and not Turbostroi.SetMTAffinityMask then return end
|
||||
local turbostroiTrains = {}
|
||||
if not TURBOSTROI then
|
||||
local FPS = 33
|
||||
local messageTimeout = 0
|
||||
local messageCounter = 0
|
||||
local dataCache = {{},{}}
|
||||
hook.Add("EntityRemoved","Turbostroi",function(ent)
|
||||
if dataCache[ent] then
|
||||
dataCache[ent] = nil
|
||||
end
|
||||
if turbostroiTrains[ent] then
|
||||
turbostroiTrains[ent] = nil
|
||||
end
|
||||
end)
|
||||
for k,ent in pairs(ents.GetAll()) do
|
||||
if ent.Base == "gmod_subway_base" and not ent.NoTrain and not ent.DontAccelerateSimulation then
|
||||
turbostroiTrains[ent] = true
|
||||
end
|
||||
end
|
||||
hook.Add("OnEntityCreated","Turbostroi",function(ent)
|
||||
timer.Simple(0,function()
|
||||
if IsValid(ent) and ent.Base == "gmod_subway_base" and not ent.NoTrain and not ent.DontAccelerateSimulation then
|
||||
turbostroiTrains[ent] = true
|
||||
end
|
||||
end)
|
||||
end)
|
||||
local inputCache = {}
|
||||
local id,system,name,index,value
|
||||
local _DEBUGPRINT
|
||||
local function updateTrains(trains)
|
||||
--local recvMessage = Turbostroi.RecvMessage
|
||||
-- Get data packets from simulation
|
||||
for train in pairs(trains) do
|
||||
if not dataCache[train] then
|
||||
if not Turbostroi.SendMessage(train,5,"","",0,0) then return end
|
||||
dataCache[train] = {wiresW = {}}
|
||||
|
||||
for sys_name,system in pairs(train.Systems) do
|
||||
if system.OutputsList and system.DontAccelerateSimulation then
|
||||
for _,name in pairs(system.OutputsList) do
|
||||
local value = system[name] or 0
|
||||
if type(value) == "boolean" then value = value and 1 or 0 end
|
||||
if type(value) == "number" then
|
||||
if not dataCache[train][sys_name] then dataCache[train][sys_name] = {} end
|
||||
dataCache[train][sys_name][name] = math.Round(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for i,message in pairs(Turbostroi.RecvMessages(train)) do --NEWTURBOSTROI
|
||||
id,system,name,index,value = unpack(message,0) --NEWTURBOSTROI
|
||||
--while true do --OLDTURBOSTROI
|
||||
--id,system,name,index,value = Turbostroi.RecvMessage(train)
|
||||
if id == 1 then
|
||||
if train.Systems[system] then
|
||||
train.Systems[system][name] = value
|
||||
if train.TriggerTurbostroiInput then train:TriggerTurbostroiInput(system,name,value) end
|
||||
end
|
||||
end
|
||||
if id == 2 then
|
||||
if index == 0 and name ~= "bass" then index = nil end
|
||||
if value == 0 and name ~= "bass" then value = nil end
|
||||
if name == "" then name = nil end
|
||||
--net.WriteString(name)
|
||||
train:PlayOnce(system,name,index,value)
|
||||
end
|
||||
if id == 3 then
|
||||
if name == "on" then
|
||||
--print("[!]Wire "..index.." starts update! Value "..value)
|
||||
dataCache[train]["wiresW"][index] = value
|
||||
--train:WriteTrainWire(index,value)
|
||||
if not train.TrainWireWritersID[index] then train.TrainWireWritersID[index] = true end
|
||||
train.TrainWireTurbostroi[index] = value
|
||||
if train.TriggerTurbostroiInput then train:TriggerTurbostroiInput("TrainWire",index,value) end
|
||||
else
|
||||
--print("[!]Wire "..index.." stop update!")
|
||||
dataCache[train]["wiresW"][index] = nil
|
||||
end
|
||||
end
|
||||
if id == 4 then
|
||||
if train.Systems[system] then
|
||||
train.Systems[system]:TriggerInput(name,value)
|
||||
end
|
||||
end
|
||||
if id == 5 then
|
||||
for twid,value in pairs(dataCache[train]["wiresW"]) do
|
||||
--train:WriteTrainWire(twid,value)
|
||||
end
|
||||
end
|
||||
if id == 6 then
|
||||
if IsValid(Player(index)) then
|
||||
if value==0 then
|
||||
Player(index):PrintMessage( HUD_PRINTCONSOLE, "--START" )
|
||||
print("--START")
|
||||
end
|
||||
Player(index):PrintMessage( HUD_PRINTCONSOLE, system )
|
||||
print(system)
|
||||
end
|
||||
end
|
||||
--print(id,name)
|
||||
|
||||
--if not id then
|
||||
--break--OLDTURBOSTROI
|
||||
--end
|
||||
messageCounter = messageCounter + 1
|
||||
end
|
||||
end
|
||||
-- Send train wire values
|
||||
-- Output all system values
|
||||
for train in pairs(trains) do
|
||||
if train.ReadTrainWire then
|
||||
for i in pairs(train.TrainWires) do
|
||||
if not dataCache[train]["wires"] then dataCache[train]["wires"] = {} end
|
||||
if dataCache[train]["wires"][i] ~= train:ReadTrainWire(i) then
|
||||
if Turbostroi.SendMessage(train,3,"","",i,train:ReadTrainWire(i)) then
|
||||
dataCache[train]["wires"][i] = train:ReadTrainWire(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
for sys_name,system in pairs(train.Systems) do
|
||||
if system.OutputsList and system.DontAccelerateSimulation then
|
||||
for _,name in pairs(system.OutputsList) do
|
||||
local value = system[name] or 0
|
||||
if type(value) == "boolean" then
|
||||
value = value and 1 or 0
|
||||
end
|
||||
if type(value) == "number" then
|
||||
value = math.Round(value)
|
||||
if not dataCache[train][sys_name] then dataCache[train][sys_name] = {} end
|
||||
if dataCache[train][sys_name][name] ~= value then
|
||||
if Turbostroi.SendMessage(train,1,sys_name,name,0,value) then
|
||||
dataCache[train][sys_name][name] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if Turbostroi then
|
||||
concommand.Add("metrostroi_turbostroi_run",function(ply,_,_,cmd)
|
||||
if not IsValid(ply) then return end
|
||||
local train = ply:GetTrain()
|
||||
if IsValid(train) then
|
||||
print(cmd:sub(1,2),cmd:sub(3,4))
|
||||
Turbostroi.SendMessage(train,6,cmd:sub(1,255),cmd:sub(256,511),ply:UserID(),0)
|
||||
end
|
||||
end)
|
||||
function Turbostroi.TriggerInput(train,system,name,value)
|
||||
local v = value or 0
|
||||
if type(value) == "boolean" then v = value and 1 or 0 end
|
||||
Turbostroi.SendMessage(train,4,system,name,0,v)
|
||||
--end
|
||||
end
|
||||
Turbostroi.SetMTAffinityMask(8) -- CPU5 CPU4 on 6 core --NEWTURBOSTROI
|
||||
Turbostroi.SetSTAffinityMask(7) -- 0 - disabled --NEWTURBOSTROI
|
||||
Turbostroi.SetSimulationFPS(FPS)
|
||||
hook.Add("Think", "Turbostroi_Think", function()
|
||||
if not Turbostroi then return end
|
||||
|
||||
-- Proceed with the think loop
|
||||
--Turbostroi.SetTargetTime(CurTime()) //depricated! now using engine
|
||||
--Turbostroi.Think() //depricated! now using engine
|
||||
|
||||
-- Update all types of trains
|
||||
--for k,v in ipairs(turbostroiTrains) do
|
||||
updateTrains(turbostroiTrains)
|
||||
--end
|
||||
-- HACK
|
||||
GLOBAL_SKIP_TRAIN_SYSTEMS = nil
|
||||
|
||||
-- Print stats
|
||||
if ((CurTime() - messageTimeout) > 1.0) then
|
||||
messageTimeout = CurTime()
|
||||
--RunConsoleCommand("say",Format("Metrostroi: %d messages per second (%d per tick)",messageCounter,messageCounter / FPS))
|
||||
messageCounter = 0
|
||||
end
|
||||
end)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Turbostroi scripts
|
||||
--------------------------------------------------------------------------------
|
||||
-- NEW API
|
||||
local ffi = require("ffi")
|
||||
local C = ffi.load("gmsv_turbostroi_win32")
|
||||
ffi.cdef[[
|
||||
bool ThreadSendMessage(void *p, int message, const char* system_name, const char* name, double index, double value);
|
||||
]]
|
||||
|
||||
Metrostroi = {}
|
||||
local dataCache = {wires = {},wiresW = {},wiresL = {}}
|
||||
Metrostroi.BaseSystems = {} -- Systems that can be loaded
|
||||
Metrostroi.Systems = {} -- Constructors for systems
|
||||
|
||||
LoadSystems = {} -- Systems that must be loaded/initialized
|
||||
GlobalTrain = {} -- Train emulator
|
||||
GlobalTrain.Systems = {} -- Train systems
|
||||
GlobalTrain.TrainWires = {}
|
||||
GlobalTrain.WriteTrainWires = {}
|
||||
|
||||
TimeMinus = 0
|
||||
_Time = 0
|
||||
function CurTime()
|
||||
--return CurrentTime-TimeMinus
|
||||
return _Time
|
||||
end
|
||||
--function CurTime() return os.clock() end
|
||||
|
||||
function Metrostroi.DefineSystem(name)
|
||||
TRAIN_SYSTEM = {}
|
||||
Metrostroi.BaseSystems[name] = TRAIN_SYSTEM
|
||||
|
||||
-- Create constructor
|
||||
Metrostroi.Systems[name] = function(train,...)
|
||||
local tbl = { _base = name }
|
||||
local TRAIN_SYSTEM = Metrostroi.BaseSystems[tbl._base]
|
||||
if not TRAIN_SYSTEM then print("No system: "..tbl._base) return end
|
||||
for k,v in pairs(TRAIN_SYSTEM) do
|
||||
if type(v) == "function" then
|
||||
tbl[k] = function(...)
|
||||
if not Metrostroi.BaseSystems[tbl._base][k] then
|
||||
print("ERROR",k,tbl._base)
|
||||
end
|
||||
return Metrostroi.BaseSystems[tbl._base][k](...)
|
||||
end
|
||||
else
|
||||
tbl[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
tbl.Initialize = tbl.Initialize or function() end
|
||||
tbl.Think = tbl.Think or function() end
|
||||
tbl.Inputs = tbl.Inputs or function() return {} end
|
||||
tbl.Outputs = tbl.Outputs or function() return {} end
|
||||
tbl.TriggerInput = tbl.TriggerInput or function() end
|
||||
tbl.TriggerOutput = tbl.TriggerOutput or function() end
|
||||
|
||||
tbl.Train = train
|
||||
tbl:Initialize(...)
|
||||
tbl.OutputsList = tbl:Outputs()
|
||||
tbl.InputsList = tbl:Inputs()
|
||||
tbl.IsInput = {}
|
||||
for k,v in pairs(tbl.InputsList) do tbl.IsInput[v] = true end
|
||||
return tbl
|
||||
end
|
||||
end
|
||||
|
||||
function GlobalTrain.LoadSystem(self,a,b,...)
|
||||
local name
|
||||
local sys_name
|
||||
if b then
|
||||
name = b
|
||||
sys_name = a
|
||||
else
|
||||
name = a
|
||||
sys_name = a
|
||||
end
|
||||
|
||||
if not Metrostroi.Systems[name] then error("No system defined: "..name) end
|
||||
if self.Systems[sys_name] then error("System already defined: "..sys_name) end
|
||||
|
||||
self[sys_name] = Metrostroi.Systems[name](self,...)
|
||||
self[sys_name].Name = sys_name
|
||||
self[sys_name].BaseName = name
|
||||
self.Systems[sys_name] = self[sys_name]
|
||||
|
||||
-- Don't simulate on here
|
||||
local no_acceleration = Metrostroi.BaseSystems[name].DontAccelerateSimulation
|
||||
if no_acceleration then
|
||||
self.Systems[sys_name].Think = function() end
|
||||
self.Systems[sys_name].TriggerInput = function(train,name,value)
|
||||
local v = value or 0
|
||||
if type(value) == "boolean" then v = value and 1 or 0 end
|
||||
C.ThreadSendMessage(_userdata, 4,sys_name,name,0,v)
|
||||
end -- replace with new api
|
||||
|
||||
--Precache values
|
||||
elseif self[sys_name].OutputsList then
|
||||
dataCache[sys_name] = {}
|
||||
for _,name in pairs(self[sys_name].OutputsList) do
|
||||
dataCache[sys_name][name] = 0--self[sys_name][name] or 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function GlobalTrain.PlayOnce(self,soundid,location,range,pitch)
|
||||
C.ThreadSendMessage(_userdata, 2,soundid or "",location or "",range or 0,pitch or 0) -- replace with new api
|
||||
end
|
||||
|
||||
function GlobalTrain.ReadTrainWire(self,n)
|
||||
return self.TrainWires[n] or 0
|
||||
end
|
||||
|
||||
function GlobalTrain.WriteTrainWire(self,n,v)
|
||||
self.WriteTrainWires[n] = v
|
||||
end
|
||||
|
||||
|
||||
GlobalTrain.DeltaTime = 0.33
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Main train code (turbostroi side)
|
||||
--------------------------------------------------------------------------------
|
||||
print("[!] Train initialized!")
|
||||
function Think(skipped)
|
||||
-- This is just blatant copy paste from init.lua of base train entity
|
||||
local self = GlobalTrain
|
||||
|
||||
--[[ if skipped then
|
||||
self.BeSkip = self.BeSkip or CurTime()
|
||||
return
|
||||
else
|
||||
self.PrevTime = self.PrevTime or CurTime()
|
||||
if self.BeSkip then
|
||||
--print(1,(CurTime()-self.BeSkip)-0.03)
|
||||
TimeMinus = TimeMinus + math.max(0,(CurTime()-self.BeSkip)-0.03)
|
||||
--print(2,TimeMinus)
|
||||
self.BeSkip = false
|
||||
end
|
||||
end--]]
|
||||
|
||||
-- Is initialized?
|
||||
if not self.Initialized then
|
||||
Initialize()
|
||||
return
|
||||
end
|
||||
|
||||
self.DeltaTime = (CurrentTime - self.PrevTime)--self.DeltaTime+math.min(0.02,((CurrentTime - self.PrevTime)-self.DeltaTime)*0.1)
|
||||
self.PrevTime = CurrentTime
|
||||
if skipped or self.DeltaTime<=0 then return end
|
||||
_Time = _Time+self.DeltaTime
|
||||
|
||||
-- Perform data exchange
|
||||
DataExchange()
|
||||
|
||||
-- Simulate according to schedule
|
||||
for i,s in ipairs(self.Schedule) do
|
||||
for k,v in ipairs(s) do
|
||||
v:Think(self.DeltaTime / (v.SubIterations or 1),i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Initialize()
|
||||
if not CurrentTime then return end
|
||||
print("[!] Loading systems")
|
||||
local time = os.clock()
|
||||
for k,v in pairs(LoadSystems) do
|
||||
GlobalTrain:LoadSystem(k,v)
|
||||
end
|
||||
print(string.format("[!] -Took %.2fs",os.clock()-time))
|
||||
GlobalTrain.PrevTime = CurrentTime
|
||||
local iterationsCount = 1
|
||||
if (not GlobalTrain.Schedule) or (iterationsCount ~= GlobalTrain.Schedule.IterationsCount) then
|
||||
GlobalTrain.Schedule = { IterationsCount = iterationsCount }
|
||||
local SystemIterations = {}
|
||||
|
||||
-- Find max number of iterations
|
||||
local maxIterations = 0
|
||||
for k,v in pairs(GlobalTrain.Systems) do
|
||||
SystemIterations[k] = (v.SubIterations or 1)
|
||||
maxIterations = math.max(maxIterations,(v.SubIterations or 1))
|
||||
end
|
||||
|
||||
-- Create a schedule of simulation
|
||||
for iteration=1,maxIterations do
|
||||
GlobalTrain.Schedule[iteration] = {}
|
||||
-- Populate schedule
|
||||
for k,v in pairs(GlobalTrain.Systems) do
|
||||
if ((iteration)%(maxIterations/(v.SubIterations or 1))) == 0 then
|
||||
table.insert(GlobalTrain.Schedule[iteration],v)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
GlobalTrain.Initialized = true
|
||||
end
|
||||
|
||||
local id,system,name,index,value
|
||||
function DataExchange()
|
||||
-- Get data packets
|
||||
for i,message in pairs(RecvMessages()) do
|
||||
id,system,name,index,value = unpack(message,0) --NEWTURBOSTROI
|
||||
--while true do
|
||||
--id,system,name,index,value = RecvMessage() --OLDTURBOSTROI
|
||||
if id == 1 then
|
||||
if GlobalTrain.Systems[system] then
|
||||
GlobalTrain.Systems[system][name] = value
|
||||
end
|
||||
end
|
||||
if id == 3 then
|
||||
dataCache["wiresW"][index] = value
|
||||
end
|
||||
if id == 4 then
|
||||
if GlobalTrain.Systems[system] then
|
||||
GlobalTrain.Systems[system]:TriggerInput(name,value)
|
||||
end
|
||||
end
|
||||
if id == 5 then
|
||||
dataCache["wiresL"] = {}
|
||||
end
|
||||
if id == 6 then
|
||||
local scr = [[
|
||||
local _retdata=""
|
||||
local print = function(...)
|
||||
for k,v in ipairs({...}) do _retdata = _retdata..tostring(v).."\t" end
|
||||
_retdata = _retdata.."\n"
|
||||
end
|
||||
]]
|
||||
scr = scr..system..name.."\n"
|
||||
scr = scr.."return _retdata"
|
||||
local data,err = loadstring(scr)
|
||||
if data then
|
||||
local ret = tostring(data()) or "N\\A"
|
||||
for i=0,math.ceil(#ret/63) do
|
||||
C.ThreadSendMessage(_userdata, 6, ret:sub(i*63,(i+1)*63-1), "",index,i)
|
||||
end
|
||||
else
|
||||
print(err)
|
||||
C.ThreadSendMessage(_userdata, 6, tostring(err), "",index,0)
|
||||
end
|
||||
--Turbostroi.SendMessage(train,6,cmd:sub(1,255),cmd:sub(256,511),ply:UserID(),0)
|
||||
end
|
||||
if not id then break end
|
||||
end
|
||||
for twid,value in pairs(dataCache["wiresW"]) do
|
||||
GlobalTrain.TrainWires[twid] = value
|
||||
end
|
||||
|
||||
-- Output all variable values
|
||||
for sys_name,system in pairs(GlobalTrain.Systems) do
|
||||
if system.OutputsList and (not system.DontAccelerateSimulation) then
|
||||
for _,name in pairs(system.OutputsList) do
|
||||
local value = (system[name] or 0)
|
||||
--if type(value) == "boolean" then value = value and 1 or 0 end
|
||||
if not dataCache[sys_name] then print(sys_name) end
|
||||
if dataCache[sys_name][name] ~= value then
|
||||
--print(sys_name,name,value)
|
||||
--if SendMessage(1,sys_name,name,0,tonumber(value) or 0) then -- OLD API
|
||||
if C.ThreadSendMessage(_userdata, 1, sys_name , name, 0, tonumber(value) or 0) then -- NEW API
|
||||
dataCache[sys_name][name] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Output train wire writes
|
||||
for twID,value in pairs(GlobalTrain.WriteTrainWires) do
|
||||
--local value = tonumber(value) or 0
|
||||
if dataCache["wires"][twID] ~= value then
|
||||
dataCache["wires"][twID] = value
|
||||
dataCache["wiresL"][twID] = false
|
||||
end
|
||||
if not dataCache["wiresL"][twID] or dataCache["wiresL"][twID]~=GlobalTrain.PrevTime then
|
||||
--SendMessage(3,"","on",tonumber(twID) or 0,dataCache["wires"][twID]) -- OLD API
|
||||
C.ThreadSendMessage(_userdata, 3, "", "on", tonumber(twID) or 0, dataCache["wires"][twID]) -- NEW API
|
||||
--print("[!]Wire "..twID.." starts update! Value "..dataCache["wires"][twID])
|
||||
end
|
||||
GlobalTrain.WriteTrainWires[twID] = nil
|
||||
dataCache["wiresL"][twID] = CurTime()
|
||||
end
|
||||
for twID,time in pairs(dataCache["wiresL"]) do
|
||||
if time~=CurTime() then
|
||||
C.ThreadSendMessage(_userdata,3, "", "off", tonumber(twID) or 0, 0)
|
||||
--print("[!]Wire "..twID.." stops update!")
|
||||
dataCache["wiresL"][twID] = nil
|
||||
end
|
||||
end
|
||||
--SendMessage(5,"","",0,0) -- OLD API
|
||||
--C.ThreadSendMessage(_userdata, 5,"","",0,0) -- NEW API
|
||||
--print(string.format("%s %s",count,#msgCache))
|
||||
--count = 0
|
||||
|
||||
end
|
||||
@@ -1,125 +0,0 @@
|
||||
Metrostroi.ARMTable = {signal = {},switch = {},trigger = {}}
|
||||
|
||||
if SERVER then
|
||||
util.AddNetworkString "metrostroi-arm"
|
||||
hook.Add("Think","metrostroi_arm_remove",function()
|
||||
for i,v in ipairs(Metrostroi.ARMTable) do
|
||||
if IsValid(v.Controller) and v.Controller.Station ~= i then
|
||||
v.Controller = nil
|
||||
v.net = {}
|
||||
end
|
||||
end
|
||||
end)
|
||||
net.Receive("metrostroi-arm",function(_,ply)
|
||||
local station = net.ReadUInt(16)
|
||||
--print("Player "..tostring(ply).." request full sync."..station)
|
||||
net.Start("metrostroi-arm")
|
||||
net.WriteBool(true)
|
||||
net.WriteInt(station,16)
|
||||
net.WriteTable(Metrostroi.ARMTable[station].net)
|
||||
net.Send(ply)
|
||||
end)
|
||||
function Metrostroi.ARMGet(name,typ)
|
||||
if not name or not Metrostroi.ARMTable[typ] then return end
|
||||
if typ == "signal" then
|
||||
local signal = Metrostroi.ARMTable[typ][name]
|
||||
if not IsValid(signal) then
|
||||
Metrostroi.ARMTable[typ][name] = Metrostroi.GetSignalByName(name)
|
||||
return false
|
||||
end
|
||||
return signal
|
||||
end
|
||||
if typ == "switch" then
|
||||
local switch = Metrostroi.ARMTable[typ][name]
|
||||
if not IsValid(switch) then
|
||||
Metrostroi.ARMTable[typ][name] = Metrostroi.GetSwitchByName(name)
|
||||
return false
|
||||
end
|
||||
return switch
|
||||
end
|
||||
if typ == "trigger" then
|
||||
local trigger = Metrostroi.ARMTable[typ][name]
|
||||
if not IsValid(trigger) then
|
||||
local triggers = ents.FindByName(name)
|
||||
if #triggers == 1 then
|
||||
trigger = triggers[1]
|
||||
Metrostroi.ARMTable[typ][name] = trigger
|
||||
trigger:Fire("AddOutput","OnEndTouchAll !self:ARMEndTouch::0:-1",0)
|
||||
trigger:Fire("AddOutput","OnStartTouchAll !self:ARMStartTouch::0:-1",0)
|
||||
trigger:Fire("AddOutput","OnTouching !self:ARMStartTouch::0:-1",0)
|
||||
trigger:Fire("TouchTest")
|
||||
end
|
||||
return
|
||||
else
|
||||
return trigger
|
||||
end
|
||||
end
|
||||
end
|
||||
function Metrostroi.ARMSync(station,segmid,id,val)
|
||||
local tbl = Metrostroi.ARMTable[station]and Metrostroi.ARMTable[station].net
|
||||
if not tbl then return end
|
||||
if not tbl[segmid] then tbl[segmid] = {} end
|
||||
if val == false then val = nil end
|
||||
if tbl[segmid][id] == val then return end
|
||||
print("Syncing",station,segmid,id,val)
|
||||
net.Start("metrostroi-arm")
|
||||
net.WriteBool(false)
|
||||
net.WriteUInt(station,16)
|
||||
net.WriteUInt(segmid,16)
|
||||
net.WriteString(id)
|
||||
net.WriteType(val)
|
||||
net.Broadcast()
|
||||
tbl[segmid][id] = val
|
||||
end
|
||||
else
|
||||
hook.Add("Think","arm_think",function()
|
||||
for i,station in ipairs(Metrostroi.ARMTable) do
|
||||
if (not station.LastSync or CurTime()-station.LastSync > 15) and (not Metrostroi.ARMTable.LastSyncRequest or CurTime()-Metrostroi.ARMTable.LastSyncRequest > 1) then
|
||||
print(CurTime(),UnPredictedCurTime(),RealTime(),tostring(IsFirstTimePredicted()))
|
||||
net.Start("metrostroi-arm")
|
||||
net.WriteInt(i,16)
|
||||
net.SendToServer()
|
||||
print("Requesting full sync",i)
|
||||
Metrostroi.ARMTable.LastSyncRequest = CurTime()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("metrostroi-arm",function(_,ply)
|
||||
if net.ReadBool() then
|
||||
local station = net.ReadUInt(16)
|
||||
print("We got sync.",station)
|
||||
Metrostroi.ARMTable[station] = net.ReadTable()
|
||||
Metrostroi.ARMTable[station].LastSync = CurTime()
|
||||
else
|
||||
local station = net.ReadUInt(16)
|
||||
local segmid = net.ReadUInt(16)
|
||||
local id = net.ReadString()
|
||||
local val = net.ReadType()
|
||||
print("Received",station,segmid,id,val)
|
||||
if not Metrostroi.ARMTable[station] then Metrostroi.ARMTable[station] = {} end
|
||||
if not Metrostroi.ARMTable[station][segmid] then Metrostroi.ARMTable[station][segmid] = {} end
|
||||
Metrostroi.ARMTable[station][segmid][id] = val
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
function Metrostroi.GetARMInfo(station,segmid,id)
|
||||
local tbl = Metrostroi.ARMTable[station]
|
||||
if not tbl then return end
|
||||
if not tbl[segmid] then return end
|
||||
return tbl[segmid][id]
|
||||
end
|
||||
end
|
||||
if Metrostroi.ARMConfigGenerated then
|
||||
for k,v in ipairs(Metrostroi.ARMConfigGenerated) do
|
||||
Metrostroi.ARMTable[k] = {
|
||||
occChecks = {},
|
||||
net = {},
|
||||
signal = {},
|
||||
switch = {},
|
||||
trigger = {},
|
||||
routes = {},
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -1,315 +0,0 @@
|
||||
|
||||
local function GetOccupation(tbl)
|
||||
if not tbl then return end
|
||||
for sID,signame in ipairs(tbl) do
|
||||
if signame[1] == "@" then
|
||||
local trigger = Metrostroi.ARMGet(signame:sub(2,-1), "trigger")
|
||||
--if not trigger then print(signame) end
|
||||
if not trigger or trigger.ARMTriggered then
|
||||
return true
|
||||
end
|
||||
elseif signame ~= "" then
|
||||
local signal = Metrostroi.ARMGet(signame, "signal")
|
||||
if not signal or signal.OccupiedBy and signal.OccupiedBy ~= signal then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function Metrostroi.CentralisationPrepareRoute(station,route)
|
||||
if not Metrostroi.ARMTable[station].routes then Metrostroi.ARMTable[station].routes = {} end
|
||||
local Routes = Metrostroi.ARMTable[station].routes
|
||||
local stationT = Metrostroi.ARMConfigGenerated[station]
|
||||
if not Routes[route] then
|
||||
local segments = route.route
|
||||
for i,segm in pairs(segments) do
|
||||
if segm.inroute then
|
||||
RunConsoleCommand("say",Format("Station %d. Error building route %s, because there is already another route",station,route))
|
||||
return false
|
||||
end
|
||||
if route.ignores and (not route.ignores or not route.ignores[i]) and segm.occupied then
|
||||
RunConsoleCommand("say",Format("Station %d. Error building route %s. Route occupied!",station,route))
|
||||
return false
|
||||
end
|
||||
end
|
||||
if route.checks then
|
||||
for i,segm in pairs(route.checks) do
|
||||
if segm.inroute then
|
||||
RunConsoleCommand("say",Format("Station %d. Error building route %s, because there is already another route on protective segments",station,route))
|
||||
return false
|
||||
end
|
||||
if route.ignores and (not route.ignores or not route.ignores[i]) and segm.occupied then
|
||||
RunConsoleCommand("say",Format("Station %d. Error building route %s. Protective segments occupied!",station,route))
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _,segm in pairs(segments) do
|
||||
segm.inroute = true
|
||||
end
|
||||
Routes[route] = table.insert(Routes,route)
|
||||
RunConsoleCommand("say",Format("Station %d. Added route %s with ID:%d",station,route,Routes[route]))
|
||||
return true
|
||||
end
|
||||
end
|
||||
local function CentralistationCalculateFreeBS(segm,dir,sigconf,pSeg,rccount)
|
||||
if pSeg then
|
||||
local signal = dir and segm.signal2 or not dir and segm.signal1
|
||||
if signal then
|
||||
local ent = signal.ent
|
||||
if not ent then return 1 end
|
||||
local conf = sigconf[ent.Name]
|
||||
--return (ent.FreeBSARM or ent.FreeBS or 0)+(conf and conf.bs or 1),ent
|
||||
return (ent.FreeBSARM or ent.FreeBS or 0)+rccount,ent
|
||||
end
|
||||
end
|
||||
rccount = (rccount or 0) + 1
|
||||
if not segm or segm.occupied then
|
||||
return rccount
|
||||
end
|
||||
local alt,main = false,true
|
||||
if segm.switch then
|
||||
local switch = Metrostroi.ARMGet(segm.switch, "switch")
|
||||
main = switch and switch.MainTrack and not switch.AlternateTrack
|
||||
alt = switch and not switch.MainTrack and switch.AlternateTrack
|
||||
if not alt and not main then return 0 end
|
||||
end
|
||||
|
||||
if pSeg and segm.next_a and (segm.next_a == pSeg and not alt or segm.next_m == pSeg and not main) then return 0 end
|
||||
local segmM,segmA = segm.next_m,segm.next_a
|
||||
local segmP = segm.prev
|
||||
|
||||
|
||||
local mainM = segmM and (dir and segmM.x > segm.x or not dir and segmM.x < segm.x)
|
||||
local mainP = segmP and (dir and segmP.x > segm.x or not dir and segmP.x < segm.x)
|
||||
if mainM then
|
||||
local next
|
||||
if alt and segmA then next = segmA end
|
||||
if main and segmM then next = segmM end
|
||||
return CentralistationCalculateFreeBS(next,dir,sigconf,segm,rccount)
|
||||
end
|
||||
if segmP and mainP then
|
||||
return CentralistationCalculateFreeBS(segmP,dir,sigconf,segm,rccount)
|
||||
end
|
||||
end
|
||||
local function CentralisationSolveSignalLogic(signal,signalE,signalDir,station,segm)
|
||||
if not signalE then return end
|
||||
if station.signals and station.signals[signal] then
|
||||
local sigconf = station.signals[signal]
|
||||
signalE.ControllerLogic = station
|
||||
local target,codes = "",""
|
||||
local alt = false
|
||||
local occupied = segm.occupied
|
||||
if segm.switch then
|
||||
local switch = Metrostroi.ARMGet(segm.switch, "switch")
|
||||
local main = switch and switch.MainTrack and not switch.AlternateTrack
|
||||
alt = switch and not switch.MainTrack and switch.AlternateTrack
|
||||
if not alt and not main then occupied = true end
|
||||
end
|
||||
if alt then
|
||||
--occupied = occupied or segm.next_a and GetOccupation(segm.next_a)
|
||||
else
|
||||
--occupied = occupied or segm.next_m and GetOccupation(segm.next_m)
|
||||
end
|
||||
|
||||
local route = sigconf.route
|
||||
local free,nextSignal = CentralistationCalculateFreeBS(segm,signalDir,station.signals)
|
||||
--print(free,signalE,signalE.Name)
|
||||
local dir = route and route.dir
|
||||
if route and dir ~= signalDir then
|
||||
print(signalE.Name,dir ,signalDir)
|
||||
route = nil
|
||||
occupied = true
|
||||
end
|
||||
if sigconf.Mode == 1 then
|
||||
if occupied then
|
||||
target = sigconf.R
|
||||
codes = "2"
|
||||
elseif route then
|
||||
if nextSignal then
|
||||
local colors = nextSignal.Colors or ""
|
||||
local segments = route[2]
|
||||
--print(route)
|
||||
local start = false
|
||||
local specialS = sigconf.routes and sigconf.routes[route[1].name]
|
||||
if free < (sigconf.bs or 1) then
|
||||
target = sigconf.RY or sigconf.R
|
||||
elseif route.mode == 3 then
|
||||
target = sigconf.W
|
||||
elseif colors:find("[rR]+") and colors:find("[yY]+") then
|
||||
target = sigconf.Y or sigconf.YG or sigconf.RY or sigconf.R
|
||||
elseif colors:find("[rR]+") then
|
||||
target = sigconf.Y or sigconf.RY or sigconf.R
|
||||
elseif colors:find("[ygYG]+[ygYG]+") or colors:find("[gwGW]+") then
|
||||
target = sigconf.G or sigconf.YG or sigconf.Y or sigconf.RY or sigconf.R
|
||||
elseif colors:find("[yY]+") then
|
||||
target = sigconf.YG or sigconf.G or sigconf.Y or sigconf.RY or sigconf.R
|
||||
else
|
||||
target = sigconf.R
|
||||
end
|
||||
elseif route.mode == 3 then
|
||||
target = sigconf.W
|
||||
else
|
||||
target = sigconf.R
|
||||
end
|
||||
else
|
||||
if free and free < 1 then
|
||||
target = sigconf.R or sigconf.RY or ""
|
||||
else
|
||||
target = sigconf.RY or sigconf.R
|
||||
end
|
||||
codes = "0"
|
||||
end
|
||||
signalE.Red = target==sigconf.R or target==sigconf.RY
|
||||
signalE.AutoEnabled = signalE.AutoEnabled
|
||||
else
|
||||
|
||||
end
|
||||
local sig = ""
|
||||
for i=1,#target do
|
||||
local id = tonumber(target[i])
|
||||
if not id then continue end
|
||||
if #sig < id then sig = sig..string.rep("0",id-#sig) end
|
||||
sig = string.SetChar(sig,tonumber(target[i]),target[i+1]=="b" and "2" or "1")
|
||||
end
|
||||
signalE.Sig = sig
|
||||
signalE.FreeBSARM = occupied and 0 or free
|
||||
signalE.FreeBS = math.ceil(signalE.FreeBSARM or 0)
|
||||
--print(occupied,free,signalE.FreeBS)
|
||||
--print(signalE.Colors,target,signalE.Sig)
|
||||
end
|
||||
end
|
||||
local function CentralisationSolveRoutesLogic(stationID,station)
|
||||
local Routes = Metrostroi.ARMTable[stationID].routes
|
||||
local HasPrepared = true
|
||||
for k,route in ipairs(Routes) do
|
||||
local segments = route.route
|
||||
local directions = route.directions
|
||||
if route.prepared then
|
||||
--HasPrepared = true
|
||||
local done,occupiedN,halfroute = true--,100
|
||||
for segmID,segm in ipairs(segments) do
|
||||
if segm.occupied then
|
||||
if not occupiedN or occupiedN < segmID then occupiedN = segmID end
|
||||
end
|
||||
if segm.route then done = false end
|
||||
if not segm.route then halfroute = true end
|
||||
end
|
||||
if occupiedN then
|
||||
for segmID,segm in ipairs(segments) do
|
||||
if segmID > occupiedN then break end
|
||||
if segm.route == route then
|
||||
segm.route = false
|
||||
segm.inroute = false
|
||||
local signal = route[3] and segm.signal2 or not route[3] and segm.signal1
|
||||
local sig = Metrostroi.ARMGet(signal and signal.name, "signal")
|
||||
end
|
||||
end
|
||||
end
|
||||
if done or halfroute and not occupiedN then
|
||||
for _,segm in ipairs(segments) do
|
||||
segm.inroute = false
|
||||
segm.route = false
|
||||
end
|
||||
for i,signame in pairs(route.signals) do
|
||||
if not station.signals[signame] then continue end
|
||||
station.signals[signame].route = nil
|
||||
end
|
||||
RunConsoleCommand("say",Format("Station %d. Route %s(%d) has destroyed",stationID,route,Routes[route]))
|
||||
table.remove(Routes,Routes[route])
|
||||
Routes[route] = nil
|
||||
for i,v in pairs(Routes) do Routes[v] = i end
|
||||
route.prepared = false
|
||||
end
|
||||
else
|
||||
local Prepared = true
|
||||
--Check for occupation
|
||||
for i,segm in ipairs(segments) do
|
||||
if route.ignores and not route.ignores[i] and segm.occupied then Prepared = false break end
|
||||
if segm.route then Prepared = false break end
|
||||
end
|
||||
--If there is no occupation - check and prepare switches
|
||||
if Prepared then
|
||||
for segmID,segm in ipairs(segments) do
|
||||
if not segm.switch then continue end
|
||||
local switch = Metrostroi.ARMGet(segm.switch, "switch")
|
||||
if not switch then continue end
|
||||
local dir = directions[segmID]
|
||||
|
||||
local main = switch and switch.MainTrack and not switch.AlternateTrack
|
||||
local alt = switch and not switch.MainTrack and switch.AlternateTrack
|
||||
--print(route[3],switch,dir)
|
||||
if dir and main or not dir and alt or (not main and not alt) then
|
||||
switch:SwitchTo(dir and "alt" or "main")
|
||||
Prepared = false
|
||||
print("Move",segmID,segm.switch,switch,dir and "alt" or "main")
|
||||
end
|
||||
if not main and not alt then Prepared = false end
|
||||
end
|
||||
end
|
||||
if Prepared then
|
||||
for k,segm in ipairs(segments) do
|
||||
segm.route = route
|
||||
local signal = route[3] and segm.signal2 or not route[3] and segm.signal1
|
||||
local sig = Metrostroi.ARMGet(signal and signal.name, "signal")
|
||||
end
|
||||
for i,signame in pairs(route.signals) do
|
||||
if not station.signals[signame] then continue end
|
||||
station.signals[signame].route = route
|
||||
end
|
||||
route.prepared = true
|
||||
RunConsoleCommand("say",Format("Station %d. Route %s(%d) has assembled",stationID,route,Routes[route]))
|
||||
end
|
||||
end
|
||||
end
|
||||
return HasPrepared
|
||||
end
|
||||
|
||||
function Metrostroi.Centralisation()
|
||||
if not Metrostroi.ARMConfigGenerated then return end
|
||||
for stationID,station in pairs(Metrostroi.ARMConfigGenerated) do
|
||||
--Route logic
|
||||
local HasPrepared = CentralisationSolveRoutesLogic(stationID,station)
|
||||
|
||||
for name, signal in pairs(station.signals) do
|
||||
if signal.sig then
|
||||
local ent = Metrostroi.ARMGet(name, "signal")
|
||||
signal.sig.ent = ent
|
||||
CentralisationSolveSignalLogic(name,ent,signal.sig.dir,station,signal.segm)
|
||||
end
|
||||
end
|
||||
for segmID, segm in ipairs(station) do
|
||||
segm.occupied = segm._occup or GetOccupation(segm.occup) or GetOccupation(segm.occupAlt)
|
||||
if true then
|
||||
if segm.switch then
|
||||
local switch = Metrostroi.ARMGet(segm.switch, "switch")
|
||||
local main = switch and switch.MainTrack and not switch.AlternateTrack
|
||||
local alt = switch and not switch.MainTrack and switch.AlternateTrack
|
||||
if switch and not segm.route and not segm.inroute and not segm.occupied and (alt or not main and not alt) then
|
||||
switch:SwitchTo("main")
|
||||
print("Reset",segm.switch,switch,segmID,segm.route)
|
||||
end
|
||||
end
|
||||
--[[ if segm.signal1 then
|
||||
local ent = Metrostroi.ARMGet(segm.signal1.name, "signal")
|
||||
segm.signal1.ent = ent
|
||||
CentralisationSolveSignalLogic(segm.signal1.name,ent,false,station,segm)
|
||||
end
|
||||
if segm.signal2 then
|
||||
local ent = Metrostroi.ARMGet(segm.signal2.name, "signal")
|
||||
segm.signal2.ent = ent
|
||||
CentralisationSolveSignalLogic(segm.signal2.name,ent,true,station,segm)
|
||||
end--]]
|
||||
--[[ if segm.route and not HasPrepared then
|
||||
segm.route = false
|
||||
segm.inroute = false
|
||||
end--]]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
timer.Create("metrostroi_centralisation",0.1,0,Metrostroi.Centralisation)
|
||||
@@ -1,77 +0,0 @@
|
||||
require("bromsock")
|
||||
|
||||
if server then server:Close() end
|
||||
server = BromSock()
|
||||
server:SetOption(0xFFFF, 0x0008, 1)
|
||||
server:SetOption(0x6, 0x0001 , 1)
|
||||
|
||||
if (not server:Listen(1337)) then
|
||||
print("[BS:S] Failed to listen!")
|
||||
else
|
||||
print("[BS:S] Server listening...")
|
||||
end
|
||||
server:SetCallbackConnect(function(sockObj, succ, ip, port )
|
||||
print(sockObj, succ, ip, port )
|
||||
end)
|
||||
local opened = {}
|
||||
concommand.Add("test_command_send",function(_,_,args)
|
||||
local sock = opened[tonumber(args[1])]
|
||||
if not sock then return end
|
||||
local packet = BromPacket()
|
||||
packet:WriteStringRaw(args[2])
|
||||
sock:Send(packet,true)
|
||||
end)
|
||||
concommand.Add("test_command_sendtest",function(_,_,args)
|
||||
local sock = opened[tonumber(args[1])]
|
||||
if not sock then return end
|
||||
local packet = BromPacket()
|
||||
packet:WriteByte(0x00)
|
||||
packet:WriteUInt(1234)
|
||||
packet:WriteStringNT("test")
|
||||
sock:Send(packet,true)
|
||||
end)
|
||||
server:SetCallbackAccept(function(serversock, clientsock)
|
||||
print("[BS:S] Accepted:", serversock, clientsock,clientsock:GetPort())
|
||||
opened[clientsock:GetPort()] = clientsock
|
||||
clientsock:SetCallbackReceive(function(sock, packet)
|
||||
print("[BS:S] Received:", sock, packet)
|
||||
|
||||
local typ = packet:ReadByte()
|
||||
print("[BS:S] Type:", typ)
|
||||
if typ == 0x01 then
|
||||
local trains = {}
|
||||
for k,ent in pairs(ents.GetAll()) do
|
||||
if ent.Base == "gmod_subway_base" and not ent.NoTrain then
|
||||
table.insert(trains,ent)
|
||||
end
|
||||
end
|
||||
|
||||
local packet = BromPacket()
|
||||
packet:WriteByte(0x00)
|
||||
packet:WriteUInt(#trains)
|
||||
sock:Send(packet,true)
|
||||
for k,v in ipairs(trains) do
|
||||
print("Send train",v:GetClass())
|
||||
local packet = BromPacket()
|
||||
packet:WriteByte(0x01)
|
||||
packet:WriteUInt(#trains)
|
||||
packet:WriteUInt(v:EntIndex())
|
||||
packet:WriteStringNT(v:GetClass())
|
||||
sock:Send(packet,true)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
clientsock:SetCallbackDisconnect(function(sock)
|
||||
print("[BS:S] Disconnected:", sock)
|
||||
opened[clientsock:GetPort()] = nil
|
||||
end)
|
||||
|
||||
clientsock:SetTimeout(1000)
|
||||
|
||||
clientsock:Receive()
|
||||
|
||||
-- Who's next in line?
|
||||
serversock:Accept()
|
||||
end)
|
||||
server:Accept()
|
||||
Reference in New Issue
Block a user