Files
VnUtest/garrysmod/gamemodes/militaryrp/plugins/personal_storage/sv_plugin.lua
2026-03-31 10:27:04 +03:00

181 lines
5.4 KiB
Lua

local PLUGIN = PLUGIN
util.AddNetworkString("ixStorageOpen")
util.AddNetworkString("ixStorageDeposit")
util.AddNetworkString("ixStorageWithdraw")
util.AddNetworkString("ixStorageSync")
-- Robust and STABLE data retrieval: ensures we ALWAYS return a sequential numeric array
-- handled in a stable order based on original keys.
function PLUGIN:GetStorage(char)
local data = char:GetData("personal_storage", {})
if (!istable(data)) then return {} end
local fixedData = {}
local keys = {}
for k, _ in pairs(data) do
local n = tonumber(k)
if (n) then table.insert(keys, n) end
end
table.sort(keys) -- Ensure key stability (1 before 2, etc)
for _, k in ipairs(keys) do
local v = data[k] or data[tostring(k)]
if (istable(v) and v.type) then
table.insert(fixedData, v)
end
end
return fixedData
end
function PLUGIN:SaveStorage(char, data)
-- We save it as a clean array. Helix will JSON-encode it.
char:SetData("personal_storage", data)
end
net.Receive("ixStorageDeposit", function(len, ply)
local char = ply:GetCharacter()
if (!char) then return end
local type = net.ReadString()
local id = net.ReadString()
local storage = PLUGIN:GetStorage(char)
local entry = {type = type}
if (type == "weapon") then
local weapon = ply:GetWeapon(id)
if (!IsValid(weapon)) then
net.Start("ixStorageSync")
net.WriteTable(storage)
net.Send(ply)
return
end
local blacklist = {["weapon_physgun"] = true, ["gmod_tool"] = true, ["gmod_camera"] = true}
if (blacklist[id]) then
net.Start("ixStorageSync")
net.WriteTable(storage)
net.Send(ply)
return
end
entry.class = id
entry.name = weapon:GetPrintName() or id
entry.clip1 = weapon:Clip1()
entry.clip2 = weapon:Clip2()
ply:StripWeapon(id)
table.insert(storage, entry)
PLUGIN:SaveStorage(char, storage)
net.Start("ixStorageSync")
net.WriteTable(storage)
net.Send(ply)
elseif (type == "item") then
local inv = char:GetInventory()
local itemID = tonumber(id)
local item = inv:GetItemByID(itemID)
if (!item) then
net.Start("ixStorageSync")
net.WriteTable(storage)
net.Send(ply)
return
end
entry.uniqueID = item.uniqueID
entry.data = item.data or {}
entry.name = item:GetName() or item.name
item:Remove():next(function()
-- Add to storage only after successful removal from inventory
local currentStorage = PLUGIN:GetStorage(char)
table.insert(currentStorage, entry)
PLUGIN:SaveStorage(char, currentStorage)
net.Start("ixStorageSync")
net.WriteTable(currentStorage)
net.Send(ply)
end):catch(function(err)
net.Start("ixStorageSync")
net.WriteTable(PLUGIN:GetStorage(char))
net.Send(ply)
ply:Notify("Ошибка удаления: " .. (err or "неизвестно"))
end)
end
end)
net.Receive("ixStorageWithdraw", function(len, ply)
local char = ply:GetCharacter()
if (!char) then return end
local index = net.ReadUInt(8)
local storage = PLUGIN:GetStorage(char)
local entry = storage[index]
if (!entry) then
net.Start("ixStorageSync")
net.WriteTable(storage)
net.Send(ply)
return
end
-- PRE-EMPTIVE REMOVAL to prevent duplication exploit/bug
table.remove(storage, index)
PLUGIN:SaveStorage(char, storage)
if (entry.type == "weapon") then
local weapon = ply:Give(entry.class)
if (IsValid(weapon)) then
weapon:SetClip1(entry.clip1 or 0)
weapon:SetClip2(entry.clip2 or 0)
-- Already removed from storage, just sync
net.Start("ixStorageSync")
net.WriteTable(storage)
net.Send(ply)
else
-- FAIL: Put back
local currentStorage = PLUGIN:GetStorage(char)
table.insert(currentStorage, entry)
PLUGIN:SaveStorage(char, currentStorage)
net.Start("ixStorageSync")
net.WriteTable(currentStorage)
net.Send(ply)
end
else
local inv = char:GetInventory()
inv:Add(entry.uniqueID, 1, entry.data):next(function(res)
-- Already removed from storage, just sync to confirm removal
net.Start("ixStorageSync")
net.WriteTable(PLUGIN:GetStorage(char))
net.Send(ply)
end):catch(function(err)
-- FAIL: Put back
local currentStorage = PLUGIN:GetStorage(char)
table.insert(currentStorage, entry)
PLUGIN:SaveStorage(char, currentStorage)
net.Start("ixStorageSync")
net.WriteTable(currentStorage)
net.Send(ply)
ply:Notify("Нет места в инвентаре! Предмет возвращен в шкаф.")
end)
end
end)
function PLUGIN:OpenStorage(ply)
local char = ply:GetCharacter()
if (!char) then return end
local data = self:GetStorage(char)
net.Start("ixStorageSync")
net.WriteTable(data)
net.Send(ply)
end