409 lines
10 KiB
Lua
409 lines
10 KiB
Lua
TFA.Attachments = TFA.Attachments or {}
|
|
TFA.Attachments.Atts = {}
|
|
|
|
TFA.Attachments.Colors = {
|
|
["active"] = Color(252, 151, 50, 255),
|
|
["error"] = Color(225, 0, 0, 255),
|
|
["error_attached"] = Color(140, 80, 30, 255),
|
|
["background"] = Color(15, 15, 15, 64),
|
|
["primary"] = Color(245, 245, 245, 255),
|
|
["secondary"] = Color(153, 253, 220, 255),
|
|
["+"] = Color(128, 255, 128, 255),
|
|
["-"] = Color(255, 128, 128, 255),
|
|
["="] = Color(192, 192, 192, 255)
|
|
}
|
|
|
|
TFA.Attachments.UIPadding = 2
|
|
TFA.Attachments.IconSize = 64
|
|
TFA.Attachments.CategorySpacing = 128
|
|
|
|
if SERVER then
|
|
util.AddNetworkString("TFA_Attachment_Set")
|
|
util.AddNetworkString("TFA_Attachment_SetStatus")
|
|
util.AddNetworkString("TFA_Attachment_Reload")
|
|
util.AddNetworkString("TFA_Attachment_Request")
|
|
|
|
local function UpdateWeapon(wep, ply)
|
|
for category, data in pairs(wep.Attachments or {}) do
|
|
if type(category) ~= "string" then
|
|
net.Start("TFA_Attachment_Set")
|
|
net.WriteEntity(wep)
|
|
|
|
net.WriteUInt(category, 8)
|
|
if data.atts and data.atts[data.sel] then
|
|
net.WriteString(data.atts[data.sel])
|
|
else
|
|
net.WriteString("")
|
|
end
|
|
|
|
net.Send(ply)
|
|
end
|
|
end
|
|
end
|
|
|
|
net.Receive("TFA_Attachment_Request", function(len, ply)
|
|
if not IsValid(ply) then return end
|
|
local wep = net.ReadEntity()
|
|
if not IsValid(wep) or not wep.IsTFAWeapon or not wep.HasInitAttachments or wep.AttachmentCount < 1 then return end
|
|
local ctime = SysTime()
|
|
|
|
local currentScheduleRequest = ply.__TFA_Base_Next_Attachment_Request or ctime
|
|
local nextScheduleRequest = math.max(ctime + 0.2, currentScheduleRequest + 0.2)
|
|
ply.__TFA_Base_Next_Attachment_Request = nextScheduleRequest
|
|
|
|
if currentScheduleRequest <= ctime then
|
|
UpdateWeapon(wep, ply)
|
|
-- elseif currentScheduleRequest - ctime >= 10 then
|
|
-- ply:Kick("TFA_Attachment_Request spam")
|
|
else
|
|
timer.Simple(nextScheduleRequest - ctime, function()
|
|
if IsValid(ply) and IsValid(wep) then
|
|
UpdateWeapon(wep, ply)
|
|
end
|
|
end)
|
|
end
|
|
end)
|
|
|
|
net.Receive("TFA_Attachment_Set", function(len, ply)
|
|
local wep = ply:GetWeapon(net.ReadString())
|
|
if not IsValid(wep) or not wep.IsTFAWeapon then return end
|
|
|
|
local cat = net.ReadUInt(8)
|
|
local ind = net.ReadString()
|
|
local status = wep:SetTFAAttachment(cat, ind, ply)
|
|
|
|
net.Start("TFA_Attachment_SetStatus")
|
|
net.WriteEntity(wep)
|
|
net.WriteBool(status)
|
|
|
|
if not status then
|
|
if wep.Attachments and wep.Attachments[cat] then
|
|
local data = wep.Attachments[cat]
|
|
net.WriteUInt(cat, 8)
|
|
|
|
if data.atts and data.atts[data.sel] then
|
|
net.WriteString(data.atts[data.sel])
|
|
else
|
|
net.WriteString("")
|
|
end
|
|
end
|
|
end
|
|
|
|
net.Send(ply)
|
|
end)
|
|
else
|
|
sql.Query([[
|
|
CREATE TABLE IF NOT EXISTS tfa_savedattachments (
|
|
class VARCHAR(80) NOT NULL,
|
|
atts TEXT NOT NULL,
|
|
PRIMARY KEY (class)
|
|
)
|
|
]])
|
|
|
|
net.Receive("TFA_Attachment_Set", function(len)
|
|
local wep = net.ReadEntity()
|
|
|
|
local cat = net.ReadUInt(8)
|
|
local ind = net.ReadString()
|
|
|
|
if IsValid(wep) and wep.SetTFAAttachment then
|
|
wep:SetTFAAttachment(cat, ind, false)
|
|
end
|
|
end)
|
|
|
|
net.Receive("TFA_Attachment_Reload", function(len)
|
|
TFAUpdateAttachments()
|
|
end)
|
|
|
|
net.Receive("TFA_Attachment_SetStatus", function(len)
|
|
local weapon = net.ReadEntity()
|
|
if not IsValid(weapon) then return end
|
|
local status = net.ReadBool()
|
|
|
|
if status then
|
|
weapon:SaveAttachments()
|
|
return
|
|
end
|
|
surface.PlaySound("buttons/button2.wav")
|
|
|
|
local cat = net.ReadUInt(8)
|
|
local ind = net.ReadString()
|
|
weapon:SetTFAAttachment(cat, ind, false)
|
|
end)
|
|
|
|
local function request(self)
|
|
if self._TFA_Attachment_Request then return end
|
|
if not self.HasInitAttachments or self.AttachmentCount < 1 then return end
|
|
net.Start("TFA_Attachment_Request")
|
|
net.WriteEntity(self)
|
|
net.SendToServer()
|
|
self._TFA_Attachment_Request = true
|
|
end
|
|
|
|
hook.Add("NotifyShouldTransmit", "TFA_AttachmentsRequest", function(self, notDormant)
|
|
if not self.IsTFAWeapon or not notDormant then return end
|
|
request(self)
|
|
end)
|
|
|
|
hook.Add("NetworkEntityCreated", "TFA_AttachmentsRequest", function(self)
|
|
timer.Simple(0, function()
|
|
if not IsValid(self) or not self.IsTFAWeapon then return end
|
|
request(self)
|
|
end)
|
|
end)
|
|
|
|
hook.Add("OnEntityCreated", "TFA_AttachmentsRequest", function(self)
|
|
timer.Simple(0, function()
|
|
if not IsValid(self) or not self.IsTFAWeapon then return end
|
|
request(self)
|
|
end)
|
|
end)
|
|
|
|
local LoadQuery = [[SELECT atts FROM tfa_savedattachments WHERE class = '%s']]
|
|
function TFA.GetSavedAttachments(Weapon)
|
|
if not IsValid(Weapon) or not Weapon.IsTFAWeapon then return end
|
|
|
|
local data = sql.QueryRow(string.format(LoadQuery, sql.SQLStr(Weapon:GetClass(), true)))
|
|
|
|
if data and data.atts then
|
|
return util.JSONToTable(data.atts)
|
|
end
|
|
end
|
|
|
|
local SaveQuery = [[REPLACE INTO tfa_savedattachments (class, atts) VALUES ('%s', '%s');]]
|
|
function TFA.SetSavedAttachments(Weapon)
|
|
if not IsValid(Weapon) or not Weapon.IsTFAWeapon or not next(Weapon.Attachments or {}) then return end
|
|
|
|
local seltbl = {}
|
|
for cat, catTbl in pairs(Weapon.Attachments or {}) do
|
|
if cat ~= "BaseClass" and catTbl.atts then
|
|
seltbl[cat] = catTbl.atts[catTbl.sel or -1] or ""
|
|
end
|
|
end
|
|
|
|
return sql.Query(string.format(SaveQuery, sql.SQLStr(Weapon:GetClass(), true), sql.SQLStr(util.TableToJSON(seltbl), true)))
|
|
end
|
|
end
|
|
|
|
local function basefunc(t, k)
|
|
if k == "Base" then return end
|
|
|
|
if t.Base then
|
|
local bt = TFA.Attachments.Atts[t.Base]
|
|
if bt then return bt[k] end
|
|
end
|
|
end
|
|
|
|
function TFA.Attachments.SetupBaseTable(id, path)
|
|
local ATTACHMENT = {}
|
|
|
|
setmetatable(ATTACHMENT, {
|
|
__index = basefunc
|
|
})
|
|
|
|
ATTACHMENT.ID = id
|
|
|
|
ProtectedCall(function()
|
|
hook.Run("TFABase_PreBuildAttachment", id, path, ATTACHMENT)
|
|
end)
|
|
|
|
return ATTACHMENT
|
|
end
|
|
|
|
function TFA.Attachments.Register(id, ATTACHMENT, path)
|
|
if istable(id) then
|
|
ATTACHMENT = id
|
|
id = ATTACHMENT.ID
|
|
end
|
|
|
|
assert(istable(ATTACHMENT), "Invalid attachment argument provided")
|
|
assert(isstring(id), "Invalid attachment ID provided")
|
|
local size = table.Count(ATTACHMENT)
|
|
|
|
if size == 0 or size == 1 and ATTACHMENT.ID ~= nil then
|
|
local id2 = id or ATTACHMENT.ID
|
|
|
|
if id2 then
|
|
ErrorNoHalt("[TFA Base] Attempt to register an empty attachment " .. id2 .. "\n")
|
|
else
|
|
ErrorNoHalt("[TFA Base] Attempt to register an empty attachment\n")
|
|
end
|
|
|
|
ErrorNoHalt(debug.traceback() .. "\n")
|
|
MsgC("\n")
|
|
return
|
|
end
|
|
|
|
ProtectedCall(function()
|
|
hook.Run("TFABase_BuildAttachment", id, path, ATTACHMENT)
|
|
end)
|
|
|
|
ATTACHMENT.ID = ATTACHMENT.ID or id
|
|
|
|
if ATTACHMENT.ID and ATTACHMENT.ID ~= "base" then
|
|
ATTACHMENT.Base = ATTACHMENT.Base or "base"
|
|
end
|
|
|
|
--[[if not TFA_ATTACHMENT_ISUPDATING and istable(ATTACHMENT.WeaponTable) then
|
|
TFA.MigrateStructure(ATTACHMENT, ATTACHMENT.WeaponTable, id or "<attachment>", false)
|
|
end]]
|
|
|
|
ProtectedCall(function()
|
|
hook.Run("TFABase_RegisterAttachment", id, ATTACHMENT)
|
|
end)
|
|
|
|
TFA.Attachments.Atts[ATTACHMENT.ID or ATTACHMENT.Name] = ATTACHMENT
|
|
end
|
|
|
|
function TFA.Attachments.RegisterFromTable(id, tbl, path)
|
|
local status
|
|
|
|
ProtectedCall(function()
|
|
status = hook.Run("TFABase_ShouldLoadAttachment", id, path)
|
|
end)
|
|
|
|
if status == false then return end
|
|
|
|
local ATTACHMENT = TFA.Attachments.SetupBaseTable(id)
|
|
|
|
for k, v in pairs(tbl) do
|
|
ATTACHMENT[k] = v
|
|
end
|
|
|
|
TFA.Attachments.Register(id, ATTACHMENT)
|
|
end
|
|
|
|
TFARegisterAttachment = TFA.Attachments.Register
|
|
TFA.Attachments.Path = "tfa/att/"
|
|
TFA.Attachments.Path_Batch = "tfa/attbatch/"
|
|
TFA_ATTACHMENT_ISUPDATING = false
|
|
|
|
local inheritanceCached = {}
|
|
local missingBaseWarningShown = {}
|
|
|
|
local function patchInheritance(t, basetbl)
|
|
if t.Base and t.Base ~= "base" and not TFA.Attachments.Atts[t.Base] then
|
|
if t.ID and not missingBaseWarningShown[t.ID] then
|
|
missingBaseWarningShown[t.ID] = true
|
|
|
|
print("[TFA Base] [!] Attachment '" .. t.ID .. "' depends on unknown attachment '" .. t.Base .. "'!")
|
|
end
|
|
|
|
t.Base = "base"
|
|
end
|
|
|
|
if not basetbl and t.Base then
|
|
basetbl = TFA.Attachments.Atts[t.Base]
|
|
|
|
if basetbl and istable(basetbl) and basetbl.ID and not inheritanceCached[basetbl.ID] then
|
|
inheritanceCached[basetbl.ID] = true
|
|
patchInheritance(basetbl)
|
|
end
|
|
end
|
|
|
|
if not (basetbl and istable(basetbl)) then return end
|
|
|
|
for k, v in pairs(t) do
|
|
local baseT = basetbl[k]
|
|
|
|
if istable(v) and baseT then
|
|
patchInheritance(v, baseT)
|
|
end
|
|
end
|
|
|
|
for k, v in pairs(basetbl) do
|
|
if rawget(t, k) == nil then
|
|
t[k] = v
|
|
end
|
|
end
|
|
end
|
|
|
|
function TFAUpdateAttachments(network)
|
|
if SERVER and network ~= false then
|
|
net.Start("TFA_Attachment_Reload")
|
|
net.Broadcast()
|
|
end
|
|
|
|
TFA.AttachmentColors = TFA.Attachments.Colors --for compatibility
|
|
TFA.Attachments.Atts = {}
|
|
TFA_ATTACHMENT_ISUPDATING = true
|
|
local tbl = file.Find(TFA.Attachments.Path .. "*base*", "LUA")
|
|
local addtbl = file.Find(TFA.Attachments.Path .. "*", "LUA")
|
|
|
|
for _, v in ipairs(addtbl) do
|
|
if not string.find(v, "base") then
|
|
table.insert(tbl, #tbl + 1, v)
|
|
end
|
|
end
|
|
|
|
table.sort(tbl)
|
|
|
|
for _, fname in ipairs(tbl) do
|
|
local path = TFA.Attachments.Path .. fname
|
|
local id = fname:lower():Replace(".lua", "")
|
|
|
|
local status
|
|
|
|
ProtectedCall(function()
|
|
status = hook.Run("TFABase_ShouldLoadAttachment", id, path)
|
|
end)
|
|
|
|
if status ~= false then
|
|
ATTACHMENT = TFA.Attachments.SetupBaseTable(id, path)
|
|
|
|
if SERVER then
|
|
AddCSLuaFile(path)
|
|
include(path)
|
|
else
|
|
include(path)
|
|
end
|
|
|
|
TFA.Attachments.Register(id, ATTACHMENT, path)
|
|
ATTACHMENT = nil
|
|
end
|
|
end
|
|
|
|
local tbl2 = file.Find(TFA.Attachments.Path_Batch .. "*", "LUA")
|
|
|
|
for _, fname in ipairs(tbl2) do
|
|
local path = TFA.Attachments.Path_Batch .. fname
|
|
|
|
if SERVER then
|
|
AddCSLuaFile(path)
|
|
include(path)
|
|
else
|
|
include(path)
|
|
end
|
|
end
|
|
|
|
ProtectedCall(function()
|
|
hook.Run("TFAAttachmentsLoaded")
|
|
end)
|
|
|
|
for _, v in pairs(TFA.Attachments.Atts) do
|
|
patchInheritance(v)
|
|
|
|
--[[if istable(v.WeaponTable) then
|
|
TFA.MigrateStructure(v, v.WeaponTable, v.ID or "<attachment>", false)
|
|
end]]
|
|
end
|
|
|
|
ProtectedCall(function()
|
|
hook.Run("TFAAttachmentsInitialized")
|
|
end)
|
|
|
|
TFA_ATTACHMENT_ISUPDATING = false
|
|
|
|
TFA.ATTACHMENTS_LOADED = true
|
|
end
|
|
|
|
if not VLL2_FILEDEF and TFA.ATTACHMENTS_LOADED then
|
|
TFAUpdateAttachments(false)
|
|
end
|
|
|
|
concommand.Add("sv_tfa_attachments_reload", function(ply, cmd, args, argStr)
|
|
if SERVER and (not IsValid(ply) or ply:IsAdmin()) then
|
|
TFAUpdateAttachments()
|
|
end
|
|
end, function() end, "Reloads all TFA Attachments", {FCVAR_SERVER_CAN_EXECUTE})
|