I have made this script for Gear Shop system, I have worked on doing Equip and UnEquip, but I see that sometimes there are some errors and some item I bought could not be saved.
sometimes some of Item I did buy, it reset like I need to buy the item again.
local DataStoreService = game:GetService("DataStoreService")
local ItemsDataStore = DataStoreService:GetDataStore("ArabV2")
local event = game.ReplicatedStorage.Events.Shop
local allitems = game.ReplicatedStorage["Shop System"]
local Players = game:GetService("Players")
local NotificationEvent = game.ReplicatedStorage.Events:WaitForChild("NotificationEvent")
local UpdateInventoryEvent = game.ReplicatedStorage.Events:WaitForChild("UpdateInventoryEvent")
local saveCooldown = {} -- A table to track player cooldowns
local saveAttempts = {} -- Track failed save attempts to try again later
local function canSave(player)
local currentTime = tick()
if not saveCooldown[player.UserId] or (currentTime - saveCooldown[player.UserId]) > 10 then
saveCooldown[player.UserId] = currentTime
return true
else
return false
end
end
-- Function to send a notification
local function sendNotification(player, message, isError)
NotificationEvent:FireClient(player, message, isError)
end
-- Save item data with activation status
local function saveItemsData(player)
if not canSave(player) then return end
if player:FindFirstChild("ItemInventory") then
local ItemInventory = {}
for _, v in pairs(player.ItemInventory:GetChildren()) do
if typeof(v.Name) == "string" and typeof(v.Value) == "string" then
table.insert(ItemInventory, { Name = v.Name, Status = v.Value })
else
warn("Invalid item data detected: ", v.Name, v.Value)
end
end
local success, err = pcall(function()
ItemsDataStore:SetAsync("player: " .. tostring(player.UserId), ItemInventory)
end)
if not success then
warn("Failed to save item data:", err)
saveAttempts[player.UserId] = saveAttempts[player.UserId] or 0
saveAttempts[player.UserId] = saveAttempts[player.UserId] + 1
-- Retry saving if failed more than 3 times
if saveAttempts[player.UserId] <= 3 then
delay(5, function()
saveItemsData(player)
end)
else
sendNotification(player, "Failed to save your data. Please try again later.", true)
warn("Failed to save your data. Please try again later")
end
end
end
end
local function removeEquippedShopItems(player)
-- Clear from Backpack
if player.Backpack then
for _, item in ipairs(player.Backpack:GetChildren()) do
if allitems:FindFirstChild(item.Name) then -- Only shop items
item:Destroy()
end
end
end
-- Clear from StarterGear
if player.StarterGear then
for _, item in ipairs(player.StarterGear:GetChildren()) do
if allitems:FindFirstChild(item.Name) then -- Only shop items
item:Destroy()
end
end
end
-- Clear from Character model (if equipped)
if player.Character then
for _, item in ipairs(player.Character:GetChildren()) do
if item:IsA("Tool") and allitems:FindFirstChild(item.Name) then -- Only shop items
item:Destroy()
end
end
end
end
-- Load and equip items
local function loadAndEquipItems(player)
local itemInventory = player:FindFirstChild("ItemInventory")
if itemInventory then
itemInventory:ClearAllChildren()
else
itemInventory = Instance.new("Folder")
itemInventory.Name = "ItemInventory"
itemInventory.Parent = player
end
-- Clear only shop items, not other items
removeEquippedShopItems(player)
local success, data = pcall(function()
return ItemsDataStore:GetAsync("player: " .. player.UserId)
end)
if success and data then
for _, itemData in pairs(data) do
if typeof(itemData) == "table" and itemData.Name then
local stringValue = Instance.new("StringValue")
stringValue.Name = itemData.Name
stringValue.Value = itemData.Status or "Unequip"
stringValue.Parent = itemInventory
if itemData.Status == "Equip" then
local itemTemplate = allitems:FindFirstChild(itemData.Name)
if itemTemplate then
local itemClone = itemTemplate:Clone()
itemClone.Parent = player.Backpack
itemClone:Clone().Parent = player.StarterGear
end
end
end
end
end
end
-- Player added event
Players.PlayerAdded:Connect(function(player)
-- Load and equip items when player joins
loadAndEquipItems(player)
-- Create ItemInventory if it doesn't exist
local itemInventory = player:FindFirstChild("ItemInventory") or Instance.new("Folder")
itemInventory.Name = "ItemInventory"
itemInventory.Parent = player
-- Save data when ItemInventory is modified
itemInventory.ChildAdded:Connect(function()
saveItemsData(player)
end)
itemInventory.ChildRemoved:Connect(function()
saveItemsData(player)
end)
-- Manage restoration
player.CharacterAdded:Connect(function()
loadAndEquipItems(player)
end)
end)
-- Helper function to handle item cloning and equipping
local function equipItem(player, itemTemplate)
-- Check if item is already equipped
if not player.Backpack:FindFirstChild(itemTemplate.Name) then
itemTemplate:Clone().Parent = player.Backpack
end
if not player.StarterGear:FindFirstChild(itemTemplate.Name) then
itemTemplate:Clone().Parent = player.StarterGear
end
end
-- Manage item equip/unequip
event.OnServerEvent:Connect(function(player, itemName, action)
if player and allitems:FindFirstChild(itemName) then
local itemTemplate = allitems:FindFirstChild(itemName)
local itemInInventory = player.ItemInventory:FindFirstChild(itemName)
-- Function to remove item from both Backpack and StarterGear
local function removeItemFromGear()
-- Remove from Backpack
if player.Backpack:FindFirstChild(itemName) then
player.Backpack[itemName]:Destroy()
end
-- Remove from StarterGear (even if held)
if player.StarterGear:FindFirstChild(itemName) then
player.StarterGear[itemName]:Destroy()
end
-- Remove from player character if it exists
if player.Character and player.Character:FindFirstChild(itemName) then
player.Character[itemName]:Destroy()
end
end
-- Equip item
if action == "Equip" and itemInInventory then
-- Remove the item if already equipped, even if in StarterGear (held)
removeItemFromGear()
-- Now equip the item
equipItem(player, itemTemplate)
-- Update item status to "Equip"
itemInInventory.Value = "Equip"
-- Unequip item
elseif action == "Unequip" and itemInInventory then
-- Remove the item if already equipped, even if in StarterGear (held)
removeItemFromGear()
-- Update inventory status to "Unequip"
itemInInventory.Value = "Unequip"
end
-- Save changes in ItemsDataStore
saveItemsData(player)
end
end)
-- Manage buying and activating items
event.OnServerEvent:Connect(function(player, itemName, action)
local item = allitems:FindFirstChild(itemName)
if not item then
sendNotification(player, "Item not found: " .. itemName, true)
return
end
local itemInInventory = player.ItemInventory:FindFirstChild(itemName)
-- Helper: Remove items from Backpack, StarterGear, and Character
local function removeItemFromGear()
for _, location in ipairs({player.Backpack, player.StarterGear, player.Character}) do
if location and location:FindFirstChild(itemName) then
location[itemName]:Destroy()
end
end
end
-- **1️⃣ Manage equip**
if action == "Equip" and itemInInventory then
removeItemFromGear() -- Remove duplicate items before adding new
item:Clone().Parent = player.Backpack
item:Clone().Parent = player.StarterGear
itemInInventory.Value = "Equip"
sendNotification(player, "Item equipped: " .. itemName, false)
-- **2️⃣ Manage unequip**
elseif action == "Unequip" and itemInInventory then
removeItemFromGear()
itemInInventory.Value = "Unequip"
sendNotification(player, "Item unequipped: " .. itemName, false)
-- **3️⃣ Manage purchase**
elseif not action then
-- Check the price
local price = (item:FindFirstChild("Handle") and item.Handle:FindFirstChild("PermanentPrice")) and item.Handle.PermanentPrice.Value
or (item:FindFirstChild("PermanentPrice") and item.PermanentPrice.Value)
if not price then
sendNotification(player, "Price not found for item: " .. itemName, true)
return
end
-- Check if player already owns the item
if player.ItemInventory:FindFirstChild(itemName) then
sendNotification(player, "You already own the item: " .. itemName, true)
return
end
-- Purchase logic
if player.leaderstats.Cash.Value >= price then
player.leaderstats.Cash.Value -= price
local saveItem = Instance.new("StringValue")
saveItem.Name = itemName
saveItem.Value = "Equip"
saveItem.Parent = player.ItemInventory
item:Clone().Parent = player.Backpack
item:Clone().Parent = player.StarterGear
sendNotification(player, "Item purchased successfully: " .. itemName, false)
UpdateInventoryEvent:FireClient(player)
else
sendNotification(player, "Not enough money to buy " .. itemName, true)
end
else
sendNotification(player, "Invalid action: " .. tostring(action), true)
end
saveItemsData(player)
end)
Players.PlayerRemoving:Connect(function(player)
saveItemsData(player)
end)