add sborka
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
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
|
||||
Reference in New Issue
Block a user