mirror of
https://github.com/metrostroi-repo/MetrostroiAddon.git
synced 2026-05-02 00:42:29 +00:00
933 lines
37 KiB
Lua
933 lines
37 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")
|
||
|
||
--[[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
|
||
------------------------
|
||
-- Metrostroi version --
|
||
------------------------
|
||
Metrostroi.Version = 1537278077
|
||
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 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!",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 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 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 _,v in ipairs(VGUI) do v(nil,nil,true) end
|
||
for k,v in pairs(texture.defaults) do
|
||
local id = VGUI[k].ID
|
||
if 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 pairs(tbl) do
|
||
if name == v.name then
|
||
tbl[id] = schTbl
|
||
v.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
|
||
DISABLE_TURBOSTROI = false
|
||
if not DISABLE_TURBOSTROI then
|
||
print("Metrostroi: Trying to load simulation acceleration DLL...")
|
||
--TODO: OS specific check
|
||
if file.Exists("lua/bin/gmsv_turbostroi_"..(system.IsWindows() and "win32" or system.IsLinux() and "linux" or "osx")..".dll", "GAME") then
|
||
print("Metrostroi: Founded. System: "..(system.IsWindows() and "Windows" or system.IsLinux() and "Linux" or "OSX"))
|
||
if not pcall(require,"turbostroi") then
|
||
if system.IsWindows() then
|
||
ErrorNoHalt("Metrostroi: Turbostroi DLL can't be loaded!\nCheck, that you have Microsoft visual c++ 2010 redistributable(x86)\nYou can find it here:https://www.microsoft.com/en-us/download/details.aspx?id=5555\n")
|
||
else
|
||
ErrorNoHalt("Metrostroi: Turbostroi library can't be loaded!\n")
|
||
end
|
||
else
|
||
print("Metrostroi: Turbostroi DLL be loaded successfuly.")
|
||
end
|
||
else
|
||
print("Metrostroi: Turbostroi DLL not not found")
|
||
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 then
|
||
net.Start "MetrostroiMessages"
|
||
net.WriteString("Turbostroi is not installed! Performance will be low!\nDownload 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("You playing in listenserver. For comfortable playing, you need host a dedicated 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.GetAll()) 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 warn = vgui.Create("DFrame")
|
||
warn:SetDeleteOnClose(true)
|
||
warn:SetTitle("Warning")
|
||
warn:SetSize(380, 120)
|
||
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 Open = vgui.Create("DButton", warn)
|
||
Open:SetText("Open link")
|
||
Open:SetPos(15, 85)
|
||
Open:SetSize(80, 25)
|
||
Open.DoClick = function()
|
||
gui.OpenURL(url)
|
||
end
|
||
|
||
local Close = vgui.Create("DButton", warn)
|
||
Close:SetText("Close")
|
||
Close:SetPos(290, 85)
|
||
Close:SetSize(80, 25)
|
||
Close.DoClick = function()
|
||
warn:Close()
|
||
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.GetAll()) 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()
|
||
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()
|
||
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()
|
||
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()
|
||
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 |