mirror of
https://github.com/metrostroi-repo/MetrostroiAddon.git
synced 2026-05-02 00:42:29 +00:00
1011 lines
41 KiB
Lua
1011 lines
41 KiB
Lua
--------------------------------------------------------------------------------
|
||
-- Add all required clientside files
|
||
--------------------------------------------------------------------------------
|
||
local function resource_AddDir(dir)
|
||
local files,dirs = file.Find(dir.."/*","GAME")
|
||
for _, fdir in pairs(dirs) do
|
||
resource_AddDir(dir.."/"..fdir)
|
||
end
|
||
|
||
for _,v in pairs(files) do
|
||
resource.AddFile(dir.."/"..v)
|
||
end
|
||
end
|
||
if SERVER then
|
||
util.AddNetworkString("metrostroi-mouse-move")
|
||
util.AddNetworkString("metrostroi-cabin-button")
|
||
util.AddNetworkString("metrostroi-cabin-reset")
|
||
util.AddNetworkString("metrostroi-panel-touch")
|
||
|
||
util.PrecacheModel("models/metrostroi_train/reversor/reversor_classic.mdl")
|
||
util.PrecacheModel("models/metrostroi_train/reversor/reversor_gold.mdl")
|
||
|
||
--[[resource_AddDir("materials/metrostroi/props")
|
||
resource_AddDir("materials/models/metrostroi_signs")
|
||
resource_AddDir("materials/models/metrostroi_train")
|
||
resource_AddDir("materials/models/metrostroi_passengers")
|
||
resource_AddDir("materials/models/metrostroi_signals")
|
||
|
||
resource_AddDir("models/metrostroi/signs")
|
||
resource_AddDir("models/metrostroi/81-717")
|
||
resource_AddDir("models/metrostroi/e")
|
||
resource_AddDir("models/metrostroi/81")
|
||
resource_AddDir("models/metrostroi/81-703")
|
||
resource_AddDir("models/metrostroi/81-508")
|
||
resource_AddDir("models/metrostroi/metro")
|
||
resource_AddDir("models/metrostroi/passengers")
|
||
resource_AddDir("models/metrostroi/signals")
|
||
resource_AddDir("models/metrostroi/tatra_t3")
|
||
|
||
resource_AddDir("sound/subway_trains")
|
||
resource_AddDir("sound/subway_announcer")
|
||
resource_AddDir("sound/subway_stations_test1")
|
||
resource_AddDir("sound/subway_trains/new")]]
|
||
end
|
||
|
||
|
||
------ --------------------------------------------------------------------------
|
||
-- Create metrostroi global library
|
||
--------------------------------------------------------------------------------
|
||
if not Metrostroi then
|
||
-- Global library
|
||
Metrostroi = {}
|
||
|
||
-- Supported train classes
|
||
Metrostroi.TrainClasses = {}
|
||
Metrostroi.IsTrainClass = {}
|
||
-- Supported train classes
|
||
Metrostroi.TrainSpawnerClasses = {}
|
||
timer.Simple(0.05, function()
|
||
for name in pairs(scripted_ents.GetList()) do
|
||
local prefix = "gmod_subway_"
|
||
if string.sub(name,1,#prefix) == prefix and scripted_ents.Get(name).Base == "gmod_subway_base" then
|
||
table.insert(Metrostroi.TrainClasses,name)
|
||
Metrostroi.IsTrainClass[name] = true
|
||
end
|
||
end
|
||
end)
|
||
|
||
-- List of all systems
|
||
Metrostroi.Systems = {}
|
||
Metrostroi.BaseSystems = {}
|
||
end
|
||
|
||
--List of spawned trains
|
||
Metrostroi.SpawnedTrains = {}
|
||
for k,ent in pairs(ents.GetAll()) do
|
||
if ent.Base == "gmod_subway_base" or ent:GetClass() == "gmod_subway_base" then
|
||
Metrostroi.SpawnedTrains[ent] = true
|
||
end
|
||
end
|
||
|
||
hook.Add("EntityRemoved","MetrostroiTrains",function(ent)
|
||
if Metrostroi.SpawnedTrains[ent] then
|
||
Metrostroi.SpawnedTrains[ent] = nil
|
||
end
|
||
end)
|
||
if SERVER then
|
||
hook.Add("OnEntityCreated","MetrostroiTrains",function(ent)
|
||
if ent.Base == "gmod_subway_base" or ent:GetClass() == "gmod_subway_base" then
|
||
Metrostroi.SpawnedTrains[ent] = true
|
||
end
|
||
end)
|
||
else
|
||
hook.Add("OnEntityCreated","MetrostroiTrains",function(ent)
|
||
if ent:GetClass() == "gmod_subway_base" or scripted_ents.IsBasedOn(ent:GetClass(), "gmod_subway_base") then
|
||
Metrostroi.SpawnedTrains[ent] = true
|
||
end
|
||
end)
|
||
end
|
||
|
||
------------------------
|
||
-- Metrostroi version --
|
||
------------------------
|
||
Metrostroi.Version = 1623941696
|
||
Metrostroi.Loaded = false
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Add skins function
|
||
-- category - a skin category(pass, cab, train)
|
||
-- name - name of skin(must be unique) or skin table(table must have a name)
|
||
-- tbl - skin table
|
||
-- Skin table:
|
||
-- {
|
||
-- typ = "81-717_lvz", (it's a gmod_subway_*(gmod_subway_81-717_lvz))
|
||
-- name = "NAME",(or you can send name to function)
|
||
-- textures = {
|
||
-- texture_name = "path_to_texture",
|
||
-- b01a = "myskin/mycoolskin",
|
||
-- }
|
||
-- }
|
||
-- List of trains and manufacturers:
|
||
-- 81-717_mvm
|
||
-- 81-717_lvz
|
||
-- Ezh3
|
||
-- Em
|
||
-- E
|
||
--------------------------------------------------------------------------------
|
||
function Metrostroi.AddSkin(category,name,tbl)
|
||
if type(name) == "table" then
|
||
local Table = name
|
||
name = Table.name
|
||
Table.name = nil
|
||
tbl = Table
|
||
end
|
||
if CLIENT and tbl.textures then
|
||
local find
|
||
for k,v in pairs(tbl.textures) do
|
||
if not file.Exists("materials/"..v..".vmt","GAME") then
|
||
find = true
|
||
ErrorNoHalt(Format("Metrostroi: %s texture: %s, not found. Check folder and addons!\n",category,v))
|
||
end
|
||
end
|
||
if find then return end
|
||
end
|
||
if not Metrostroi.Skins[category] then
|
||
print(Format("Metrostroi: Added a %s skin category",category))
|
||
Metrostroi.Skins[category] = {}
|
||
end
|
||
if not tbl.typ then ErrorNoHalt(Format("Metrostroi:Skin error: %s wont have a typ direvtive!\n",tbl.name or name)) return end
|
||
Metrostroi.Skins[category][name] = tbl
|
||
Metrostroi.Skins.GetTable = function(id,name,tbl,typ)
|
||
local SkinsType = ENT and ENT.SkinsType
|
||
return {id,name,"List",function()
|
||
if SkinsType then
|
||
tbl = {}
|
||
for k,v in pairs(Metrostroi.Skins[typ]) do
|
||
if v.typ == SkinsType and not hook.Run("MetrostroiSkinsCheck",SkinsType,typ,v.name or k,k) then tbl[k] = v.name or k end
|
||
end
|
||
return tbl
|
||
end
|
||
end,nil,function(ent,val)
|
||
if not Metrostroi.Skins or not Metrostroi.Skins[typ] then return end
|
||
local texture = Metrostroi.Skins[typ][val]
|
||
if not texture or hook.Run("MetrostroiSkinsCheck",texture.typ,typ,texture.name or val,val) then return end
|
||
ent:SetNW2String(id,val)
|
||
--[[ if texture.textures then
|
||
ent:SetNW2String(id,texture.func and texture.func(ent) or val)
|
||
elseif texture.func then
|
||
ent:SetNW2String(id,texture.func(ent))
|
||
end--]]
|
||
end,function(List,VGUI)
|
||
if not Metrostroi.Skins or not Metrostroi.Skins[typ] then return end
|
||
local texture = Metrostroi.Skins[typ][List:GetOptionData(List:GetSelectedID())]
|
||
if not texture or not texture.defaults then return end
|
||
for k,v in pairs(texture.defaults) do
|
||
local id = VGUI[k].ID
|
||
print(List:GetOptionData(List:GetSelectedID()),id,VGUI[id],v)
|
||
if id and VGUI[id] then
|
||
VGUI[id](v,true)
|
||
end
|
||
end
|
||
end}
|
||
end
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Function for announcer adding
|
||
--------------------------------------------------------------------------------
|
||
Metrostroi.AnnouncementsASNP = {}
|
||
Metrostroi.ASNPSetup = {}
|
||
function Metrostroi.AddANSPAnnouncer(name,soundtable,datatable)
|
||
if not soundtable or not datatable then return end
|
||
for k,v in pairs(Metrostroi.AnnouncementsASNP) do
|
||
if v.name == name then
|
||
Metrostroi.AnnouncementsASNP[k] = soundtable
|
||
Metrostroi.AnnouncementsASNP[k].name = name
|
||
Metrostroi.ASNPSetup[k] = datatable
|
||
Metrostroi.ASNPSetup[k].name = name
|
||
print("Metrostroi: Changed \""..name.."\" ASNP announcer.")
|
||
return
|
||
end
|
||
end
|
||
local id = table.insert(Metrostroi.AnnouncementsASNP,soundtable)
|
||
Metrostroi.AnnouncementsASNP[id].name = name
|
||
|
||
local id = table.insert(Metrostroi.ASNPSetup,datatable)
|
||
Metrostroi.ASNPSetup[id].name = name
|
||
print("Metrostroi: Added \""..name.."\" ASNP announcer.")
|
||
end
|
||
|
||
Metrostroi.AnnouncementsSarmatUPO = {}
|
||
Metrostroi.SarmatUPOSetup = {}
|
||
function Metrostroi.AddSarmatUPOAnnouncer(name,soundtable,datatable)
|
||
if not soundtable or not datatable then return end
|
||
for k,v in pairs(Metrostroi.AnnouncementsSarmatUPO) do
|
||
if v.name == name then
|
||
Metrostroi.AnnouncementsSarmatUPO[k] = soundtable
|
||
Metrostroi.AnnouncementsSarmatUPO[k].name = name
|
||
Metrostroi.SarmatUPOSetup[k] = datatable
|
||
Metrostroi.SarmatUPOSetup[k].name = name
|
||
print("Metrostroi: Changed \""..name.."\" Sarmat UPO(UPO2) announcer.")
|
||
return
|
||
end
|
||
end
|
||
local id = table.insert(Metrostroi.AnnouncementsSarmatUPO,soundtable)
|
||
Metrostroi.AnnouncementsSarmatUPO[id].name = name
|
||
|
||
local id = table.insert(Metrostroi.SarmatUPOSetup,datatable)
|
||
Metrostroi.SarmatUPOSetup[id].name = name
|
||
|
||
print("Metrostroi: Added \""..name.."\" Sarmat UPO(UPO2) announcer.")
|
||
end
|
||
|
||
Metrostroi.AnnouncementsUPO = {}
|
||
Metrostroi.UPOSetup = {}
|
||
function Metrostroi.SetUPOAnnouncer(soundtable,datatable)
|
||
if not soundtable or not datatable then return end
|
||
Metrostroi.AnnouncementsUPO = {soundtable}
|
||
Metrostroi.UPOSetup = datatable
|
||
--Generating noise
|
||
for k,v in pairs(Metrostroi.UPOSetup or {}) do
|
||
if v.noises and v.noiserandom < math.random() then
|
||
v.noise = table.Random(v.noises)
|
||
end
|
||
end
|
||
|
||
print("Metrostroi: Set UPO announcer and generated nosies.")
|
||
end
|
||
Metrostroi.AnnouncementsRRI = {}
|
||
Metrostroi.RRISetup = {}
|
||
function Metrostroi.SetRRIAnnouncer(soundtable,datatable)
|
||
if not soundtable or not datatable then return end
|
||
Metrostroi.AnnouncementsRRI = {soundtable}
|
||
Metrostroi.RRISetup = datatable
|
||
|
||
print("Metrostroi: Set RRI announcer.")
|
||
end
|
||
|
||
function Metrostroi.AddPassSchemeTex(id,name,schTbl)
|
||
id = id.."_schemes"
|
||
if not Metrostroi.Skins[id] then
|
||
Metrostroi.Skins[id] = {}
|
||
end
|
||
local tbl = Metrostroi.Skins[id]
|
||
for k,v in ipairs(tbl) do
|
||
if name == v.name then
|
||
tbl[k] = schTbl
|
||
tbl[k].name = name
|
||
return
|
||
end
|
||
end
|
||
tbl[table.insert(tbl,schTbl)].name = name
|
||
end
|
||
|
||
local defaults = {
|
||
["702_routes"] = {
|
||
"models/metrostroi_schemes/destination_table_black/label_cross",
|
||
"models/metrostroi_schemes/destination_table_black/label_dev",
|
||
"models/metrostroi_schemes/destination_table_black/label_freight",
|
||
},
|
||
["710_routes"] = {
|
||
"models/metrostroi_train/81-710/route_empty",
|
||
"models/metrostroi_schemes/destination_table_white/label_cross",
|
||
"models/metrostroi_schemes/destination_table_white/label_dev",
|
||
"models/metrostroi_schemes/destination_table_white/label_freight",
|
||
},
|
||
["717_routes"] = {
|
||
"models/metrostroi_schemes/destination_table_white/label_cross",
|
||
"models/metrostroi_schemes/destination_table_white/label_dev",
|
||
"models/metrostroi_schemes/destination_table_white/label_freight",
|
||
},
|
||
["720_routes"] = {
|
||
"models/metrostroi_train/81-720/labels/label_empty",
|
||
"models/metrostroi_schemes/destination_table_white/label_cross",
|
||
"models/metrostroi_schemes/destination_table_white/label_freight",
|
||
}
|
||
}
|
||
function Metrostroi.AddLastStationTex(id,stIndex,texture)
|
||
id = id.."_routes"
|
||
if not Metrostroi.Skins[id] then
|
||
Metrostroi.Skins[id] = {}
|
||
if defaults[id] then
|
||
if type(defaults[id]) == "table" then
|
||
Metrostroi.Skins[id].default = defaults[id][1]
|
||
for i=2,#defaults[id] do
|
||
Metrostroi.AddLastStationTex(id:sub(1,-8),1000+(i-1),defaults[id][i])
|
||
end
|
||
else
|
||
Metrostroi.Skins[id].default = defaults[id]
|
||
end
|
||
end
|
||
end
|
||
local tbl = Metrostroi.Skins[id]
|
||
for k,v in pairs(tbl) do
|
||
if k == index then
|
||
tbl[v] = texture
|
||
return
|
||
end
|
||
end
|
||
tbl[stIndex] = table.insert(tbl,texture)
|
||
end
|
||
--------------------------------------------------------------------------------
|
||
-- Load core files and skins
|
||
--------------------------------------------------------------------------------
|
||
if SERVER then
|
||
local OSes = {
|
||
Windows = "win32",
|
||
Linux = "linux",
|
||
BSD = "linux",
|
||
POSIX = "linux",
|
||
OSX = "osx",
|
||
}
|
||
DISABLE_TURBOSTROI = false
|
||
if not DISABLE_TURBOSTROI then
|
||
print(Format("Metrostroi: Trying to load simulation acceleration DLL for %s %s...",jit.os,jit.arch))
|
||
--TODO: OS specific check
|
||
if jit.arch == "x86" and OSes[jit.os] and file.Exists(Format("lua/bin/gmsv_turbostroi_%s.dll",OSes[jit.os]), "GAME") then
|
||
if not pcall(require,"turbostroi") then
|
||
if system.IsWindows() then
|
||
ErrorNoHalt("======================================================\nMetrostroi: Turbostroi library can't be loaded because of missing libraries!\nCheck, that you have Microsoft visual c++ 2010 and 2017 redistributable(x86) installed\nYou can download it from:\n")
|
||
MsgC(Color(255,0,0),"https://www.microsoft.com/en-us/download/details.aspx?id=5555\nhttps://aka.ms/vs/15/release/vc_redist.x86.exe\n")
|
||
ErrorNoHalt("======================================================\n")
|
||
else
|
||
ErrorNoHalt("Metrostroi: Turbostroi library can't be loaded!\n")
|
||
end
|
||
else
|
||
print("Metrostroi: Turbostroi library loaded successfuly.")
|
||
end
|
||
elseif jit.arch ~= "x86" then
|
||
ErrorNoHalt("Metrostroi: Unsupported architecture "..jit.arch..".\nTurbostroi works only on x86(32 bit) version of server\n")
|
||
elseif system.IsWindows() then
|
||
ErrorNoHalt("======================================================\nMetrostroi: Turbostroi DLL not found.\nYou can found turbostroi for Windows at \n")
|
||
MsgC(Color(255,0,0),"https://metrostroi.net/turbostroi\n")
|
||
ErrorNoHalt("Just place this .dll to garrysmod/lua/bin folder.\nIf bin folder doesn't exists - create it.\nDon't forget to install Microsoft visual c++ 2010 and 2017 redistributable(x86)\nYou can download it from:\n")
|
||
MsgC(Color(255,0,0),"https://www.microsoft.com/en-us/download/details.aspx?id=5555\nhttps://aka.ms/vs/15/release/vc_redist.x86.exe\n")
|
||
ErrorNoHalt("======================================================\n")
|
||
else
|
||
ErrorNoHalt("Metrostroi: Turbostroi DLL not found.\n")
|
||
end
|
||
else
|
||
Turbostroi = nil
|
||
end
|
||
|
||
if Turbostroi
|
||
then print("Metrostroi: Simulation acceleration ENABLED!")
|
||
else print("Metrostroi: Simulation acceleration DISABLED")
|
||
end
|
||
|
||
-- Load all lua translations
|
||
local files = file.Find("metrostroi_data/languages/*.lua","LUA")
|
||
for _,filename in pairs(files) do
|
||
AddCSLuaFile("metrostroi_data/languages/"..filename)
|
||
end
|
||
-- Loadall serverside lua files
|
||
files = file.Find("metrostroi/sv_*.lua","LUA")
|
||
for _,filename in pairs(files) do include("metrostroi/"..filename) end
|
||
-- Load all shared files serverside
|
||
|
||
include("metrostroi/convars.lua")
|
||
files = file.Find("metrostroi/sh_*.lua","LUA")
|
||
for _,filename in pairs(files) do include("metrostroi/"..filename) end
|
||
|
||
files = file.Find("metrostroi/cl_*.lua","LUA")
|
||
for _,filename in pairs(files) do AddCSLuaFile("metrostroi/"..filename) end
|
||
-- Add all shared files
|
||
AddCSLuaFile("metrostroi/convars.lua")
|
||
files = file.Find("metrostroi/sh_*.lua","LUA")
|
||
for _,filename in pairs(files) do AddCSLuaFile("metrostroi/"..filename) end
|
||
-- Add all system files
|
||
files = file.Find("metrostroi/systems/sys_*.lua","LUA")
|
||
for _,filename in pairs(files) do AddCSLuaFile("metrostroi/systems/"..filename) end
|
||
-- Add skin
|
||
Metrostroi.Skins = {["717_schemes"]={p={},m={}}}
|
||
files = file.Find("metrostroi/skins/*.lua","LUA")
|
||
for _,filename in pairs(files) do
|
||
AddCSLuaFile("metrostroi/skins/"..filename)
|
||
include("metrostroi/skins/"..filename)
|
||
end
|
||
|
||
files = file.Find("metrostroi/maps/*.lua","LUA")
|
||
for _,filename in pairs(files) do
|
||
AddCSLuaFile("metrostroi/maps/"..filename)
|
||
include("metrostroi/maps/"..filename)
|
||
end
|
||
else
|
||
--[[
|
||
concommand.Add( "metrostroi_reload_spawnmenu", function()
|
||
if IsValid( g_SpawnMenu ) then
|
||
g_SpawnMenu:Remove()
|
||
g_SpawnMenu = nil
|
||
end
|
||
hook.Call("OnGamemodeLoaded")
|
||
end)]]
|
||
include("metrostroi/convars.lua")
|
||
-- Load all clientside files
|
||
local files = file.Find("metrostroi/cl_*.lua","LUA")
|
||
for _,filename in pairs(files) do include("metrostroi/"..filename) end
|
||
-- Load all shared files
|
||
files = file.Find("metrostroi/sh_*.lua","LUA")
|
||
for _,filename in pairs(files) do include("metrostroi/"..filename) end
|
||
|
||
-- Add skins
|
||
Metrostroi.Skins = {["717_schemes"]={p={},m={}}}
|
||
files = file.Find("metrostroi/skins/*.lua","LUA")
|
||
for _,filename in pairs(files) do include("metrostroi/skins/"..filename) end
|
||
--Include map scripts
|
||
files = file.Find("metrostroi/maps/*.lua","LUA")
|
||
for _,filename in pairs(files) do include("metrostroi/maps/"..filename) end
|
||
end
|
||
Metrostroi.AddLastStationTex("710","obkatka","metrostroi_skins/81-710_names/route_obkatka")
|
||
Metrostroi.AddLastStationTex("720","obkatka","metrostroi_skins/81-720_names/label_obkatka")
|
||
--------------------------------------------------------------------------------
|
||
-- Load systems
|
||
--------------------------------------------------------------------------------
|
||
if not Metrostroi.TurbostroiRegistered then
|
||
Metrostroi.TurbostroiRegistered = {}
|
||
end
|
||
|
||
function Metrostroi.DefineSystem(name)
|
||
if not Metrostroi.BaseSystems[name] then
|
||
Metrostroi.BaseSystems[name] = {}
|
||
end
|
||
TRAIN_SYSTEM = Metrostroi.BaseSystems[name]
|
||
TRAIN_SYSTEM_NAME = name
|
||
end
|
||
|
||
local function loadSystem(filename)
|
||
-- Get the Lua code
|
||
include(filename)
|
||
|
||
-- Load train systems
|
||
if TRAIN_SYSTEM then TRAIN_SYSTEM.FileName = filename end
|
||
local name = TRAIN_SYSTEM_NAME or "UndefinedSystem"
|
||
TRAIN_SYSTEM_NAME = nil
|
||
|
||
-- Register system with turbostroi
|
||
if Turbostroi and (not Metrostroi.TurbostroiRegistered[name]) then
|
||
Turbostroi.RegisterSystem(name,filename)
|
||
Metrostroi.TurbostroiRegistered[name] = true
|
||
end
|
||
|
||
-- Load up the system
|
||
Metrostroi.Systems["_"..name] = TRAIN_SYSTEM
|
||
Metrostroi.BaseSystems[name] = TRAIN_SYSTEM
|
||
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.ClientInitialize = tbl.ClientInitialize or function() end
|
||
tbl.Think = tbl.Think or function() end
|
||
tbl.ClientThink = tbl.ClientThink or function() end
|
||
tbl.ClientDraw = tbl.ClientDraw or function() end
|
||
tbl.Inputs = tbl.Inputs or function() return {} end
|
||
tbl.Outputs = tbl.Outputs or function() return {} end
|
||
tbl.TriggerOutput = tbl.TriggerOutput or function() end
|
||
tbl.TriggerInput = tbl.TriggerInput or function() end
|
||
|
||
tbl.Train = train
|
||
if SERVER then
|
||
tbl:Initialize(...)
|
||
else
|
||
tbl:ClientInitialize(...)
|
||
end
|
||
tbl.OutputsList = tbl:Outputs()
|
||
tbl.InputsList = tbl:Inputs()
|
||
tbl.IsInput = {}
|
||
for _,v in pairs(tbl.InputsList) do tbl.IsInput[v] = true end
|
||
return tbl
|
||
end
|
||
end
|
||
|
||
-- Load all systems
|
||
local files = file.Find("metrostroi/systems/sys_*.lua","LUA")
|
||
for _,short_filename in pairs(files) do
|
||
local filename = "metrostroi/systems/"..short_filename
|
||
|
||
-- Load the file
|
||
if SERVER
|
||
then loadSystem(filename)
|
||
else timer.Simple(0.05, function() loadSystem(filename) end)
|
||
end
|
||
end
|
||
local function loadAnn ()
|
||
if Metrostroi.WorkingStations then
|
||
for k, v in pairs(Metrostroi.WorkingStations) do
|
||
for k1, v1 in pairs(v) do
|
||
Metrostroi.WorkingStations[k][v1] = k1
|
||
end
|
||
end
|
||
end
|
||
|
||
if Metrostroi.EndStations then
|
||
for k, v in pairs(Metrostroi.EndStations) do
|
||
for k1, v1 in pairs(v) do
|
||
Metrostroi.EndStations[k][v1] = k1
|
||
end
|
||
end
|
||
end
|
||
end
|
||
if SERVER
|
||
then loadAnn()
|
||
else timer.Simple(0.1, loadAnn)
|
||
end
|
||
if SERVER then
|
||
util.AddNetworkString "MetrostroiMessages"
|
||
local function CheckErr(ply)
|
||
if not Turbostroi and IsValid(ply) and (ply:IsSuperAdmin() or not game.IsDedicated()) then
|
||
net.Start "MetrostroiMessages"
|
||
net.WriteString("Turbostroi is not installed!\nTurbostroi is accelerating train calculations by using multiple\ncores. Check "..(game.IsDedicated() and "server" or "game").." logs for more information.\nYou can download it at:\nhttps://metrostroi.net/turbostroi")
|
||
net.WriteString("https://metrostroi.net/turbostroi")
|
||
net.Send(ply)
|
||
end
|
||
if not game.IsDedicated() then
|
||
net.Start "MetrostroiMessages"
|
||
net.WriteString("For comfort and smooth experience, you need to\njoin to server or host a dedicated server.\nIt's required because Garry's mod using only\n1 core, and now it using it for client and server code.\nWhen you join or host server you can separate server\nand client processes to different cores.\nInformation about how to host server:\nhttp://wiki.garrysmod.com/page/Hosting_A_Dedicated_Server")
|
||
net.WriteString("http://wiki.garrysmod.com/page/Hosting_A_Dedicated_Server")
|
||
net.Send(ply)
|
||
end
|
||
end
|
||
local m_adm = {}
|
||
for _,v in pairs(player.GetHumans()) do
|
||
if IsValid(v) and v:IsAdmin() then
|
||
table.insert(m_adm,v)
|
||
end
|
||
end
|
||
CheckErr(m_adm)
|
||
hook.Add("PlayerInitialSpawn","MetrostroiWarnMessage",CheckErr)
|
||
else
|
||
local function err(msg, url)
|
||
local count = #msg:gsub("[^\n]+","")
|
||
local size = 83+count*18
|
||
local warn = vgui.Create("DFrame")
|
||
warn:SetDeleteOnClose(true)
|
||
warn:SetTitle("Warning")
|
||
warn:SetSize(380, size)
|
||
warn:SetDraggable(false)
|
||
warn:SetSizable(false)
|
||
warn:Center()
|
||
warn:MakePopup()
|
||
local wrn = warn.Paint
|
||
warn.Paint = function(self, w, h)
|
||
wrn(self, w, h)
|
||
draw.DrawText(msg, "Trebuchet18", w/2, 30, color_white, 1)
|
||
end
|
||
|
||
local Close = vgui.Create("DButton", warn)
|
||
Close:SetText("I understand")
|
||
Close:SetPos(290, size-30)
|
||
Close:SetSize(80, 25)
|
||
Close.DoClick = function()
|
||
warn:Close()
|
||
end
|
||
|
||
local Open = vgui.Create("DButton", warn)
|
||
Open:SetText("Open link")
|
||
Open:SetPos(15, size-30)
|
||
Open:SetSize(80, 25)
|
||
Open.DoClick = function()
|
||
Close:SetText("Close window")
|
||
gui.OpenURL(url)
|
||
end
|
||
|
||
local Copy = vgui.Create("DButton", warn)
|
||
Copy:SetText("Copy link")
|
||
Copy:SetPos(100, size-30)
|
||
Copy:SetSize(80, 25)
|
||
Copy.DoClick = function()
|
||
Close:SetText("Close window")
|
||
SetClipboardText(url)
|
||
end
|
||
end
|
||
net.Receive("MetrostroiMessages", function()
|
||
err(net.ReadString(),net.ReadString())
|
||
end)
|
||
end
|
||
hook.Run("MetrostroiLoaded")
|
||
Metrostroi.Loaded = true
|
||
|
||
if SERVER then
|
||
---------------------------------------------------
|
||
-- Metrostroi reverser ID get --
|
||
--===============================================--
|
||
-- If you read this, please, don't try to spam --
|
||
-- metrostroi.net site with requests --
|
||
-- Thanks for understanding --
|
||
--===============================================--
|
||
-- Если ты читаешь это, пожалуйта, не пытайся --
|
||
-- спамить запросами на сайт metrostroi.net --
|
||
-- Спасибо за понимание --
|
||
---------------------------------------------------
|
||
--Cvars
|
||
local R_Disabled = CreateConVar("metrostroi_reverser_local",0, FCVAR_ARCHIVE,"Switch reverser IDs to local mode")
|
||
|
||
Metrostroi.ReverserIDs = Metrostroi.ReverserIDs or {SS = {},SG = {}}
|
||
Metrostroi.ReverserID = Metrostroi.ReverserID or 0
|
||
local function claimID(ply,id,typ,isLocal)
|
||
if not id then return end
|
||
if typ then
|
||
Metrostroi.ReverserIDs.SG[ply] = id
|
||
else
|
||
Metrostroi.ReverserIDs.SS[id] = not isLocal
|
||
Metrostroi.ReverserIDs.SS[ply] = id
|
||
end
|
||
end
|
||
|
||
local function isNotLocal(id)
|
||
if not id then return end
|
||
return Metrostroi.ReverserIDs.SS[id]
|
||
end
|
||
|
||
local function getLocalID(ply)
|
||
if Metrostroi.ReverserIDs.SS[ply] then return Metrostroi.ReverserIDs.SS[ply] end
|
||
|
||
repeat
|
||
Metrostroi.ReverserID = Metrostroi.ReverserID + 1
|
||
until Metrostroi.ReverserIDs.SS[Metrostroi.ReverserID]==nil
|
||
|
||
claimID(ply,Metrostroi.ReverserID,false,true)
|
||
return Metrostroi.ReverserID
|
||
end
|
||
|
||
local function removeGolden(ply)
|
||
if Metrostroi.ReverserIDs.SG[ply] then Metrostroi.ReverserIDs.SG[ply] = nil end
|
||
end
|
||
|
||
function Metrostroi.GetReverserID(ply,callback,typ)
|
||
|
||
if not IsValid(ply) or ply:IsBot() then return end
|
||
if callback == true then return Metrostroi.ReverserIDs.SG[ply] end
|
||
if game.SinglePlayer() then callback(1) return end
|
||
if not typ then
|
||
local ID = hook.Run("MetrostroiGetReverserID",ply)
|
||
if ID and type(ID)=="number" then callback(ID) return end
|
||
if R_Disabled:GetBool() then callback(getLocalID(ply)) return end
|
||
if isNotLocal(Metrostroi.ReverserIDs.SS[ply]) then callback(Metrostroi.ReverserIDs.SS[ply]) return end
|
||
end
|
||
|
||
http.Post("https://api.metrostroi.net/get_info",{[typ and "SG" or "SS"]=ply:SteamID()},function(result,_,_,statusCode)
|
||
if not IsValid(ply) then return end
|
||
local ID = statusCode == 200 and tonumber(result)
|
||
|
||
claimID(ply,ID,typ)
|
||
callback(ID or not typ and getLocalID(ply))
|
||
|
||
if typ and not ID then removeGolden(ply) end
|
||
end,function()
|
||
if not IsValid(ply) then return end
|
||
|
||
callback(not typ and getLocalID(ply))
|
||
|
||
if typ then removeGolden(ply) end
|
||
end)
|
||
end
|
||
|
||
---------------------------------------------------
|
||
-- Metrostroi servers monitoring --
|
||
--===============================================--
|
||
-- If you read this, please, don't try to break --
|
||
-- monitoring by sending wrong data to --
|
||
-- metrostroi.net. Monitoring not created for --
|
||
-- break it. Thanks for understanding --
|
||
--===============================================--
|
||
-- Если ты читаешь это, пожалуйта, не пытайся --
|
||
-- сломать мониторинг отправкой не достоверных --
|
||
-- данных на сайт metrostroi.net. Мониторинг --
|
||
-- создан не для того, чтобы его пытались --
|
||
-- сломать. Спасибо за понимание --
|
||
---------------------------------------------------
|
||
--Cvars
|
||
local CV_Enabled = CreateConVar("metrostroi_monitoring_allow",1, FCVAR_ARCHIVE,"Enables metrostroi servers monitoring for this server. Send only basic info(map,ip,port,hostname) for metrostroi servers list")
|
||
local CV_Key = CreateConVar("metrostroi_monitoring_key","", FCVAR_ARCHIVE,"Unique key for metrostroi servers monitoring. Used for server identification for servers with dynamic IP")
|
||
local CV_Pass = GetConVar("sv_password")
|
||
local State,LastSend,LastRec,LastSucc = 0
|
||
local LastErr
|
||
|
||
local metrostroiMonitoring
|
||
local function monitoringStarted() return timer.Exists("MetrostroiMonitoring") or timer.Exists("MetrostroiMonitoringPass") end
|
||
|
||
local function adjustTimer(time,force)
|
||
if not force and not timer.Exists("MetrostroiMonitoring") then return end
|
||
timer.Create("MetrostroiMonitoring",time,0,metrostroiMonitoring)
|
||
--MsgC(Color(255,0,255),"MetrostroiMon: ",Color(255,255,255),"Timer ",time,"\n")
|
||
end
|
||
local function destroy()
|
||
hook.Remove("PlayerInitialSpawn","MetrostroiMonitoring")
|
||
hook.Remove("PlayerDisconnected","MetrostroiMonitoring")
|
||
timer.Remove("MetrostroiMonitoring")
|
||
timer.Remove("MetrostroiMonitoringPass")
|
||
--cvars.RemoveChangeCallback("metrostroi_monitoring_allow", "metrostroiMonitoring")
|
||
|
||
--MsgC(Color(255,0,255),"MetrostroiMon: ",Color(255,255,255),"Destroy\n")
|
||
|
||
State = 0
|
||
end
|
||
local oldPass = CV_Pass:GetString()
|
||
local function init()
|
||
if monitoringStarted() then destroy() end
|
||
if not CV_Enabled:GetBool() then return end
|
||
adjustTimer(10,true)
|
||
--Post, if new player joined
|
||
hook.Add("PlayerInitialSpawn","MetrostroiMonitoring",function(ply) if not ply:IsBot() then metrostroiMonitoring(1,ply) end end)
|
||
hook.Add("PlayerDisconnected","MetrostroiMonitoring",function(ply) if not ply:IsBot() then metrostroiMonitoring(0,ply) end end)
|
||
--MsgC(Color(255,0,255),"MetrostroiMon: ",Color(255,255,255),"Init\n")
|
||
|
||
State = 1
|
||
LastErr = false
|
||
end
|
||
|
||
local codes = {
|
||
[402] = "No SourceQuery answer",
|
||
[403] = "IP rejected",
|
||
[404] = "Wrong parameters",
|
||
}
|
||
|
||
local function metrostroiMonitoringSucc(responseText, _, _, statusCode)
|
||
--if not monitoringStarted() then return end
|
||
if statusCode == 401 then return end
|
||
LastRec = CurTime()
|
||
if monitoringStarted() and State==1 then State=2 end
|
||
if codes[statusCode] then
|
||
RunConsoleCommand("metrostroi_monitoring_stop")
|
||
LastErr = codes[statusCode]
|
||
elseif statusCode == 500 then --Error in site
|
||
adjustTimer(30)
|
||
LastErr = "Internal server error (500). "..responseText
|
||
elseif statusCode==200 then
|
||
if #responseText==0 then
|
||
adjustTimer(60)
|
||
LastErr = false
|
||
LastSucc = CurTime()
|
||
else
|
||
local code = responseText:sub(1,2)
|
||
local response = responseText:sub(3,-1)
|
||
if code == "01" then
|
||
CV_Key:SetString(response)
|
||
adjustTimer(30)
|
||
elseif code=="02" then
|
||
if LastErr ~= "Server requested update (203)" then
|
||
LastErr = "Server requested update (203)"
|
||
metrostroiMonitoring()
|
||
end
|
||
adjustTimer(30)
|
||
elseif code == "03" then
|
||
MsgC(Color(255,255,255),"Your code: ",Color(255,0,255),response:sub(1,6),"\n")
|
||
MsgC(Color(255,255,255),"Your ServerID: ",Color(255,0,255),response:sub(7,-1),"\n")
|
||
MsgC(Color(255,255,255),"Do not show this code and ServerID to third parties!\n")
|
||
elseif code == "04"then
|
||
MsgC(Color(255,0,0),"This server is already confirmed\n")
|
||
MsgC(Color(255,0,0),"If you didn't do it, write to\n")
|
||
MsgC(Color(255,0,255),"https://metrostroi.net/tickets",Color(255,0,0)," about it.\n")
|
||
end
|
||
LastErr = code=="02" and LastErr or false
|
||
LastSucc = CurTime()
|
||
end
|
||
--[[ elseif 200 <= statusCode and statusCode <= 202 then
|
||
if statusCode == 201 and not responseText:find("SourceQuery") then
|
||
CV_Key:SetString(responseText)
|
||
adjustTimer(30)
|
||
elseif statusCode == 200 then
|
||
adjustTimer(60)
|
||
end
|
||
LastSucc = CurTime()
|
||
LastErr = false
|
||
elseif statusCode == 203 then
|
||
if LastErr ~= "Server requested update (203)" then
|
||
LastErr = "Server requested update (203)"
|
||
metrostroiMonitoring()
|
||
end
|
||
adjustTimer(30)
|
||
elseif statusCode == 204 then
|
||
MsgC(Color(255,255,255),"Your code: ",Color(255,0,255),responseText,"\n")
|
||
MsgC(Color(255,255,255),"Do not show this code to third parties!\n")
|
||
elseif statusCode == 205 then
|
||
MsgC(Color(255,0,0),"This server is already confirmed\n")
|
||
MsgC(Color(255,0,0),"If you didn't do it, write to\n")
|
||
MsgC(Color(255,0,255),"https://metrostroi.net/tickets",Color(255,0,0)," about it.\n")]]
|
||
else --Unhandled error in site
|
||
adjustTimer(30)
|
||
LastErr = Format("Unhandled status code (%d)!\n%s",statusCode,responseText)
|
||
RunConsoleCommand("metrostroi_monitoring_status")
|
||
end
|
||
--[[
|
||
MsgC(Color(255,0,255),"MetrostroiMon:")
|
||
MsgC(Color(255,255,255),"\n\tResponse : ",Color(255,255,0),responseText)
|
||
MsgC(Color(255,255,255),"\n\tStatusCode: ",Color(255,255,0),statusCode)
|
||
Msg("\n")--]]
|
||
end
|
||
|
||
local function metrostroiMonitoringFail(errorMessage)
|
||
--MsgC(Color(255,0,255),"MetrostroiMon: ",Color(255,0,0),"Failed\n")
|
||
adjustTimer(20)
|
||
LastErr = "Data send error! "..errorMessage
|
||
end
|
||
|
||
local function post(params)
|
||
--PrintTable(params)
|
||
--MsgC(Color(255,0,255),"MetrostroiMon: ",Color(255,255,255),"Post\n")
|
||
http.Post("https://api.metrostroi.net/server_info",params,metrostroiMonitoringSucc,metrostroiMonitoringFail)
|
||
LastSend = CurTime()
|
||
end
|
||
local function shutdown()
|
||
if not monitoringStarted() then return end
|
||
local key = CV_Key:GetString("metrostroi_monitoring_key")
|
||
if #key ~= 128 then key = "" end
|
||
post{
|
||
status = "2",
|
||
uid = key,
|
||
}
|
||
destroy()
|
||
end
|
||
|
||
metrostroiMonitoring = function(typ,ply)
|
||
if not monitoringStarted() then return end
|
||
if game.SinglePlayer() or not CV_Enabled:GetBool() or not Metrostroi.CurrentMap then
|
||
destroy()
|
||
return
|
||
end
|
||
local ip,port = string.match(game.GetIPAddress(),"([%d.]+):([%d]+)")
|
||
local key = CV_Key:GetString("metrostroi_monitoring_key")
|
||
if #key ~= 128 then key = "" end
|
||
if CV_Pass:GetString("sv_password") ~= "" then
|
||
--if key ~= "" then
|
||
post{
|
||
--[[ ip = ip,
|
||
port = port,
|
||
hostname = "",
|
||
map = "",
|
||
maxplayers = "0",
|
||
players = "0",
|
||
version = "0",--]]
|
||
|
||
status = "1",
|
||
uid = key,
|
||
}
|
||
--end
|
||
destroy()
|
||
--Detect sv_password changes for monitoring status change
|
||
timer.Create("MetrostroiMonitoringPass",1,0,function()
|
||
local value = CV_Pass:GetString()
|
||
if oldPass ~= value and value == "" then
|
||
init()
|
||
timer.Remove("MetrostroiMonitoringPass")
|
||
end
|
||
oldPass = value
|
||
end)
|
||
State = -1
|
||
elseif typ==2 then
|
||
post{
|
||
uid = key,
|
||
owner = ply,
|
||
status = "0",
|
||
}
|
||
else
|
||
local players
|
||
if LastErr == "Server requested update (203)" then
|
||
players = {}
|
||
for _,v in pairs(player.GetHumans()) do
|
||
if v:IsBot() then continue end
|
||
table.insert(players,v:SteamID())
|
||
end
|
||
end
|
||
post{
|
||
ip = ip,
|
||
port = port,
|
||
hostname = GetHostName(),
|
||
map = game.GetMap(),
|
||
maxplayers = tostring(game.MaxPlayers()),
|
||
players = tostring(typ==0 and player.GetCount()-1 or player.GetCount()),
|
||
version = tostring(Metrostroi.Version),
|
||
status = "0",
|
||
uid = key,
|
||
connect = ply and tostring(typ),
|
||
SID = ply and ply:SteamID(),
|
||
players_list = players and util.TableToJSON(players),
|
||
}
|
||
end
|
||
end
|
||
|
||
init()
|
||
concommand.Add("metrostroi_monitoring_start",function(ply)
|
||
if IsValid(ply) then return end
|
||
|
||
if not monitoringStarted() and CV_Enabled:GetBool() then
|
||
init()
|
||
MsgC(Color(255,0,255),"MetrostroiMon: ",Color(0,255,0),"Started.\n")
|
||
elseif CV_Enabled:GetBool() then
|
||
MsgC(Color(255,0,255),"MetrostroiMon: ",Color(255,255,0),"Already started.\n")
|
||
else
|
||
MsgC(Color(255,0,255),"MetrostroiMon: ",Color(255,0,0),"Start blocked.",
|
||
Color(255,255,0),"\n\tIf you want send monitoring data, type\n\t",Color(255,0,255),"metrostroi_monitoring_allow 1",Color(255,255,0)," to console\n")
|
||
end
|
||
end,nil,"Try to start monitoring")
|
||
concommand.Add("metrostroi_monitoring_stop",function(ply)
|
||
if IsValid(ply) then return end
|
||
|
||
if monitoringStarted() then
|
||
shutdown()
|
||
MsgC(Color(255,0,255),"MetrostroiMon: ",Color(0,255,0),"Stopped.\n")
|
||
else
|
||
MsgC(Color(255,0,255),"MetrostroiMon: ",Color(255,255,0),"Already stopped.\n")
|
||
end
|
||
end,nil,"Try to stop monitoring")
|
||
|
||
local function printTime(time)
|
||
if not time then MsgC(Color(255,255,0),"N/A\n") return end
|
||
local elapsed = CurTime()-time
|
||
MsgC(
|
||
Color(elapsed > 120 and 255 or 0,elapsed < 180 and 255 or 0,0),
|
||
string.NiceTime(elapsed),"\n"
|
||
)
|
||
end
|
||
concommand.Add("metrostroi_monitoring_status",function(ply)
|
||
if IsValid(ply) then return end
|
||
|
||
if State>0 then
|
||
MsgC(Color(255,0,255),"MetrostroiMon:\t\t",Color(0,255,0),"Watchdog working\n")
|
||
MsgC(Color(255,255,255),"\tStatus:\t\t")
|
||
if State == 1 then
|
||
MsgC(Color(255,255,0),"Initialization...\n")
|
||
elseif State == 2 then
|
||
MsgC(Color(0,255,0),"Working")
|
||
if LastErr then MsgC(Color(255,0,0)," Errored") end
|
||
MsgC("\n")
|
||
end
|
||
MsgC(Color(255,255,255),"\tNext send:\t",string.NiceTime(timer.TimeLeft("MetrostroiMonitoring")),"\n")
|
||
MsgC(Color(255,255,255),"\tLast send:\t")
|
||
printTime(LastSend)
|
||
MsgC(Color(255,255,255),"\tLast receive:\t")
|
||
printTime(LastRec)
|
||
MsgC(Color(255,255,255),"\tLast success:\t")
|
||
printTime(LastSucc)
|
||
if LastErr then MsgC(Color(255,0,0),"\tLast error:\t",LastErr,"\n") end
|
||
elseif State == -1 then
|
||
MsgC(Color(255,0,255),"MetrostroiMon:\t\t",Color(255,255,0),"Suspended by sv_password\n")
|
||
if LastErr then MsgC(Color(255,0,0),"\tLast error:\t",LastErr,"\n") end
|
||
elseif CV_Enabled:GetBool() then
|
||
MsgC(Color(255,0,255),"MetrostroiMon:\t\t",Color(0,255,0),"Watchdog stopped\n")
|
||
if LastErr then MsgC(Color(255,0,0),"\tCaused by:\t",LastErr,"\n") end
|
||
else
|
||
MsgC(Color(255,0,255),"MetrostroiMon: ",Color(255,0,0),"Watchdog blocked.",
|
||
Color(255,255,0),"\n\tIf you want send monitoring data,enter\n\t",Color(255,0,255),"metrostroi_monitoring_allow 1",Color(255,255,0)," to console\n")
|
||
if LastErr then MsgC(Color(255,0,0),"\tLast error:\t",LastErr,"\n") end
|
||
end
|
||
end,nil,"Monitoring status")
|
||
--Restart monitoring, if we want to start it
|
||
concommand.Add("metrostroi_monitoring_restart",function(ply)
|
||
if IsValid(ply) then return end
|
||
|
||
RunConsoleCommand("metrostroi_monitoring_stop")
|
||
RunConsoleCommand("metrostroi_monitoring_start")
|
||
end,nil,"Restart monitoring")
|
||
|
||
concommand.Add("metrostroi_monitoring_confirm",function(ply,_,_,str)
|
||
if IsValid(ply) then return end
|
||
|
||
if not monitoringStarted() or State<=1 then
|
||
print("Monitoring is not started. It can be disabled or have a error.")
|
||
print("You can check monitoring status by metrostroi_monitoring_status console command.")
|
||
elseif #str==0 then
|
||
print("Usage of the command:metrostroi_monitoring_confirm SteamID")
|
||
elseif not str:match("^STEAM_[0-5]:[0-2]:[%d]+$") then
|
||
print("Invalid argument. First argument must be valid SteamID.")
|
||
else
|
||
metrostroiMonitoring(2,str)
|
||
end
|
||
end,nil,"Confirm validity of server and set the owner of the server.")
|
||
|
||
|
||
cvars.AddChangeCallback("metrostroi_monitoring_allow", function(cvar, old, value)
|
||
if not monitoringStarted() and CV_Enabled:GetBool() then
|
||
RunConsoleCommand("metrostroi_monitoring_start")
|
||
elseif monitoringStarted() and not CV_Enabled:GetBool() then
|
||
RunConsoleCommand("metrostroi_monitoring_stop")
|
||
end
|
||
end, "metrostroiMonitoring")
|
||
hook.Add("ShutDown","MetrostroiMonitoring",shutdown)
|
||
end |