181 lines
5.4 KiB
Lua
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
|