Hello people of devforum,
I made a script a few months ago for a commission which handles the following things:
- Inventory System
- Item placing
- Item selling
- Item buying
Once I was done with the commission, I was told that my backend code was apparently not secure and needed to undergo some major changes. I personally believe that this code is very secure and does not need any major changes.
I would greatly appreciate if you guys could review and give some feedback on this code:
local ServerScriptService = game:GetService("ServerScriptService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local HttpService = game:GetService("HttpService")
local Remotes = ReplicatedStorage.Remotes
local dataHandler = require(ServerScriptService.DataHandler)
local tableHandler = require(ServerScriptService.TableHandler)
local itemConfig = require(ReplicatedStorage.Modules.ItemConfig)
function UpdateInventory(plr, newData)
plr.Data.Value = HttpService:JSONEncode(newData)
end
function GetPlayerData(plr)
return HttpService:JSONDecode(plr.Data.Value)
end
function AddItemToInventory(plr, itemName)
local plrData = HttpService:JSONDecode(plr.Data.Value)
plrData.Inventory[HttpService:GenerateGUID(false)] = itemName
plr.Data.Value = HttpService:JSONEncode(plrData)
Remotes.UpdateInventoryUI:InvokeClient(plr, plrData)
end
function DoesPlayerHaveItem(plr, itemName, itemId)
for currentItemId, currentItemName in pairs(GetPlayerData(plr).Inventory) do
if itemName == currentItemName and itemId == currentItemId then
return true
end
end
return false
end
function RemoveItemFromInventory(plr, itemId, itemName, isSelling)
local plrData = GetPlayerData(plr)
if plrData.Inventory[itemId] == itemName then
plrData.Inventory[itemId] = nil
if isSelling then
plr.leaderstats.Money.Value += itemConfig[itemName].Cost
end
UpdateInventory(plr, plrData)
end
Remotes.UpdateInventoryUI:InvokeClient(plr, plrData)
end
function IsItemPlaced(plr, itemName, itemId)
local plrTable = workspace.Tables:FindFirstChild(("%sTable"):format(plr.Name))
local decodedData = HttpService:JSONDecode(plrTable.PlacedObjects.Value)
for currentItemId, currentItemName in pairs(decodedData) do
if itemName == currentItemName and currentItemId == itemId then
return true
end
end
return false
end
function SavePlacedItems(plr, itemName, itemId)
local plrTable = workspace.Tables:FindFirstChild(("%sTable"):format(plr.Name))
local decodedData = HttpService:JSONDecode(plrTable.PlacedObjects.Value)
decodedData[itemId] = itemName
plrTable.PlacedObjects.Value = HttpService:JSONEncode(decodedData)
Remotes.UpdatePlacedUI:InvokeClient(plr, decodedData)
RemoveItemFromInventory(plr, itemId, itemName, false)
end
function UnplaceItem(plr, itemName, itemId)
if not IsItemPlaced(plr, itemName, itemId) then return end
local plrTable = workspace.Tables:FindFirstChild(("%sTable"):format(plr.Name))
local decodedData = HttpService:JSONDecode(plrTable.PlacedObjects.Value)
local decodedPlrData = HttpService:JSONDecode(plr.Data.Value)
decodedData[itemId] = nil
plrTable.PlacedObjects.Value = HttpService:JSONEncode(decodedData)
decodedPlrData.Inventory[itemId] = itemName
plr.Data.Value = HttpService:JSONEncode(decodedPlrData)
Remotes.UpdateInventoryUI:InvokeClient(plr, decodedPlrData)
Remotes.UpdatePlacedUI:InvokeClient(plr, decodedData)
for _, v in pairs(plrTable.Placed:GetChildren()) do
if v.Name == itemName and v.ItemId.Value == itemId then
v:Destroy()
end
end
end
function PlaceItem(plr, itemName, itemId)
local plrTable = workspace.Tables:FindFirstChild(("%sTable"):format(plr.Name))
local clonedItem = ReplicatedStorage.Items:FindFirstChild(itemName):Clone()
if not plrTable then return end
if IsItemPlaced(plr, itemName, itemId) then return end
if plrTable.Placed:FindFirstChild(itemName) then return end
clonedItem.CFrame = plrTable.PrimaryPart.CFrame * itemConfig[itemName].Position
clonedItem.ItemId.Value = itemId
clonedItem.Parent = plrTable.Placed
SavePlacedItems(plr, itemName, itemId)
end
game.Players.PlayerAdded:Connect(function(plr)
dataHandler.Load(plr)
tableHandler.AssignTable(plr)
dataHandler.LoadTable(plr)
end)
game.Players.PlayerRemoving:Connect(function(plr)
dataHandler.Save(plr)
dataHandler.SaveTable(plr)
tableHandler.UnassignTable(plr)
end)
Remotes.SellItem.OnServerEvent:Connect(function(plr, itemInfo)
if not DoesPlayerHaveItem(plr, itemInfo.ItemName, itemInfo.ItemId) then return end
if not itemConfig[itemInfo.ItemName] then return end
RemoveItemFromInventory(plr, itemInfo.ItemId, itemInfo.ItemName, true)
end)
Remotes.PlaceItem.OnServerEvent:Connect(function(plr, itemInfo)
if not DoesPlayerHaveItem(plr, itemInfo.ItemName, itemInfo.ItemId) then return end
if not itemConfig[itemInfo.ItemName] then return end
PlaceItem(plr, itemInfo.ItemName, itemInfo.ItemId)
end)
Remotes.UnplaceItem.OnServerEvent:Connect(function(plr, itemInfo)
UnplaceItem(plr, itemInfo.ItemName, itemInfo.ItemId)
end)
game:BindToClose(function()
if RunService:IsStudio() then return end
for _, plr in pairs(game:GetService("Players"):GetChildren()) do
dataHandler.Save(plr)
dataHandler.SaveTable(plr)
tableHandler.UnassignTable(plr)
end
end)
workspace.BuyWood.ClickDetector.MouseClick:Connect(function(plr)
if plr.leaderstats.Money.Value < itemConfig["Wood"].Cost then return end
plr.leaderstats.Money.Value -= itemConfig["Wood"].Cost
AddItemToInventory(plr, "Wood")
end)
workspace.BuyIron.ClickDetector.MouseClick:Connect(function(plr)
if plr.leaderstats.Money.Value < itemConfig["Iron"].Cost then return end
plr.leaderstats.Money.Value -= itemConfig["Iron"].Cost
AddItemToInventory(plr, "Iron")
end)
workspace.BuyGold.ClickDetector.MouseClick:Connect(function(plr)
if plr.leaderstats.Money.Value < itemConfig["Gold"].Cost then return end
plr.leaderstats.Money.Value -= itemConfig["Gold"].Cost
AddItemToInventory(plr, "Gold")
end)
Thank you in advance!