For some context:
I am trying to figure out how to call a remote event to tell the server that a player has died, delete that player’s save file. So, it will delete that save file from the player and when they rejoin, all of their items are gone.
Here is the code shown
local folders_to_save = {
-- 'Backpack' is the name of player's folder where items are stored
-- And Items are the folder for where the items are originated
['Backpack'] = game.ReplicatedStorage.Items
}
-- Reload the saved items every time player respawns
local reload_items_on_reset = true
local DataStoreService = game:GetService("DataStoreService")
local ItemStore = DataStoreService:GetDataStore("ItemStore")
-- This is where we store all the loaded data's
local PlayerData = {}
local loseSave = game.ReplicatedStorage:WaitForChild("PlayerWithItemsDied")
local clearPlayer = game.ReplicatedStorage:WaitForChild("ClearPlayerData")
local function LoadItemsFromData(player: Player, data, onReset: boolean)
local folders = {}
for storeFolderName, itemsFolder in pairs(folders_to_save) do
local folder = player:FindFirstChild(storeFolderName)
if not folder then
-- the folder does not exist, so we create it
folder = Instance.new("Folder")
folder.Name = storeFolderName
folder.Parent = player
end
-- keeping track of the folder
folders[storeFolderName] = folder
end
-- now we're going to make a function to add items in data
local function AddItem(item: Instance, folder: Folder, index: number)
-- the data doesn't have the directory for the folder
if not data[folder.Name] then
-- we create it
data[folder.Name] = {}
end
-- if the item wasn't exist in data
if not index then
-- getting the index of next to the very last index
index = #data[folder.Name] + 1
-- inserting the item name to data
table.insert(data[folder.Name], index, item.Name)
end
-- detecting item parent change
item.AncestryChanged:Connect(function(_, newParent)
-- if item is not in the folder anymore
-- and its not because player is resetting
if newParent ~= folder and folder.Parent ~= nil then
data[folder.Name][index] = nil
end
end)
end
-- iterating every item directory of the data
for storeFolderName, savedItems in pairs(data) do
-- if player is respawning, and folder is not Backpack
-- we cancel the iteration
--
-- this is because only Backpack is being resetted
-- after player respawn
--
-- other folder doesnt
-- (btw this script supports not only backpack to save)
-- (it also supports saving other kind of folders)
-- (as long it is inside player)
if onReset == true and storeFolderName ~= 'Backpack' then
continue
end
local itemsFolder: Folder = folders_to_save[storeFolderName]
-- checking if the directory has the items folder
-- (where the items originated)
if itemsFolder then
-- getting the folder from player
local folder = folders[storeFolderName]
for index, itemName in pairs(savedItems) do
-- checking if theres an item in the original items folder
local item = itemsFolder:FindFirstChild(itemName)
if item then
-- cloning the item and put it the player's folder
local playerItem = item:Clone()
playerItem.Parent = folder
-- since the item is exist in data, and has an index
-- we pass that index in the parameter. and we will modify
-- the additem function again
AddItem(playerItem, folder, index)
else
-- if the item is not valid in the items folder
warn(player, 'has unknown item that is said to be in folder', storeFolderName, ":", itemName)
end
end
else
warn(player, 'has unknown directory saved in data:', storeFolderName)
end
end
-- now we loaded saved items to player's folder
-- next is we detect of new items added in player folders
for storeFolderName, folder in pairs(folders) do
-- we dont need to track the folder anymore
folders[storeFolderName] = nil
-- we also need this here
-- so the item added detector dont run twice
if onReset == true and storeFolderName ~= 'Backpack' then
continue
end
folder.ChildAdded:Connect(function(item)
-- we dont have an index, so we leave it empty
-- it means that the item will be added in data
-- if it doesnt have an index
AddItem(item, folder)
end)
end
end
-- a function to load player's data
local function Load(player: Player)
-- if player's data is already loaded, cancel the function
if PlayerData[player] then
return warn(player, 'data is already loaded')
end
-- The key to access player's data
local dataKey = 'key_' .. player.UserId
-- always use pcall for async functions
local loadedData = nil
local success, result = pcall(function()
-- getting the data from ItemStore Datastore
loadedData = ItemStore:GetAsync(dataKey)
end)
-- error occured when loading data, and logging that error in the output
if not success then
error(success)
end
-- if player is new to the game, they dont have a saved data so its nil
if loadedData == nil then
loadedData = {} -- we give it empty data
end
warn(player, 'items have been loaded')
return loadedData
end
local function Save(player: Player)
local dataKey = 'key_' .. player.UserId
-- get the tracked loaded data of the player
local data = PlayerData[player]
local success, result = pcall(function()
ItemStore:SetAsync(dataKey, data, {player.UserId})
end)
-- something wrong/error happened
if not success then
error(result)
end
warn('Successfully saved', player, 'items to Datastore')
end
-- handling joining players
game.Players.PlayerAdded:Connect(function(player: Player)
-- loading the data
local data = Load(player)
-- keep track of the data in PlayerData
PlayerData[player] = data
-- now we use the LoadItemsFromData function here
-- waiting until character is loaded
local character = player.Character or player.CharacterAdded:Wait()
LoadItemsFromData(player, data)
if reload_items_on_reset == true then
player.CharacterAdded:Connect(function(character: Model)
-- we pass true here to tell that the character respawned
-- so we going to modify the LoadItemsFromData function
LoadItemsFromData(player, data, true)
end)
end
end)
game.Players.PlayerRemoving:Connect(function(player: Player)
Save(player)
-- player is leaving, so we dont need their data anymore
-- get rid of it to prevent memory leak
if PlayerData[player] then
table.clear(PlayerData[player])
end
PlayerData[player] = nil
end)
-- at very last
game:BindToClose(function()
-- if the game is closing, we will force save all player data
for _, player in pairs(game.Players:GetPlayers()) do
Save(player)
end
end)`local folders_to_save = {
-- 'Backpack' is the name of player's folder where items are stored
-- And Items are the folder for where the items are originated
['Backpack'] = game.ReplicatedStorage.Items
}
-- Reload the saved items every time player respawns
local reload_items_on_reset = true
local DataStoreService = game:GetService("DataStoreService")
local ItemStore = DataStoreService:GetDataStore("ItemStore")
-- This is where we store all the loaded data's
local PlayerData = {}
local loseSave = game.ReplicatedStorage:WaitForChild("PlayerWithItemsDied")
local clearPlayer = game.ReplicatedStorage:WaitForChild("ClearPlayerData")
local function LoadItemsFromData(player: Player, data, onReset: boolean)
local folders = {}
for storeFolderName, itemsFolder in pairs(folders_to_save) do
local folder = player:FindFirstChild(storeFolderName)
if not folder then
-- the folder does not exist, so we create it
folder = Instance.new("Folder")
folder.Name = storeFolderName
folder.Parent = player
end
-- keeping track of the folder
folders[storeFolderName] = folder
end
-- now we're going to make a function to add items in data
local function AddItem(item: Instance, folder: Folder, index: number)
-- the data doesn't have the directory for the folder
if not data[folder.Name] then
-- we create it
data[folder.Name] = {}
end
-- if the item wasn't exist in data
if not index then
-- getting the index of next to the very last index
index = #data[folder.Name] + 1
-- inserting the item name to data
table.insert(data[folder.Name], index, item.Name)
end
-- detecting item parent change
item.AncestryChanged:Connect(function(_, newParent)
-- if item is not in the folder anymore
-- and its not because player is resetting
if newParent ~= folder and folder.Parent ~= nil then
data[folder.Name][index] = nil
end
end)
end
-- iterating every item directory of the data
for storeFolderName, savedItems in pairs(data) do
-- if player is respawning, and folder is not Backpack
-- we cancel the iteration
--
-- this is because only Backpack is being resetted
-- after player respawn
--
-- other folder doesnt
-- (btw this script supports not only backpack to save)
-- (it also supports saving other kind of folders)
-- (as long it is inside player)
if onReset == true and storeFolderName ~= 'Backpack' then
continue
end
local itemsFolder: Folder = folders_to_save[storeFolderName]
-- checking if the directory has the items folder
-- (where the items originated)
if itemsFolder then
-- getting the folder from player
local folder = folders[storeFolderName]
for index, itemName in pairs(savedItems) do
-- checking if theres an item in the original items folder
local item = itemsFolder:FindFirstChild(itemName)
if item then
-- cloning the item and put it the player's folder
local playerItem = item:Clone()
playerItem.Parent = folder
-- since the item is exist in data, and has an index
-- we pass that index in the parameter. and we will modify
-- the additem function again
AddItem(playerItem, folder, index)
else
-- if the item is not valid in the items folder
warn(player, 'has unknown item that is said to be in folder', storeFolderName, ":", itemName)
end
end
else
warn(player, 'has unknown directory saved in data:', storeFolderName)
end
end
-- now we loaded saved items to player's folder
-- next is we detect of new items added in player folders
for storeFolderName, folder in pairs(folders) do
-- we dont need to track the folder anymore
folders[storeFolderName] = nil
-- we also need this here
-- so the item added detector dont run twice
if onReset == true and storeFolderName ~= 'Backpack' then
continue
end
folder.ChildAdded:Connect(function(item)
-- we dont have an index, so we leave it empty
-- it means that the item will be added in data
-- if it doesnt have an index
AddItem(item, folder)
end)
end
end
-- a function to load player's data
local function Load(player: Player)
-- if player's data is already loaded, cancel the function
if PlayerData[player] then
return warn(player, 'data is already loaded')
end
-- The key to access player's data
local dataKey = 'key_' .. player.UserId
-- always use pcall for async functions
local loadedData = nil
local success, result = pcall(function()
-- getting the data from ItemStore Datastore
loadedData = ItemStore:GetAsync(dataKey)
end)
-- error occured when loading data, and logging that error in the output
if not success then
error(success)
end
-- if player is new to the game, they dont have a saved data so its nil
if loadedData == nil then
loadedData = {} -- we give it empty data
end
warn(player, 'items have been loaded')
return loadedData
end
local function Save(player: Player)
local dataKey = 'key_' .. player.UserId
-- get the tracked loaded data of the player
local data = PlayerData[player]
local success, result = pcall(function()
ItemStore:SetAsync(dataKey, data, {player.UserId})
end)
-- something wrong/error happened
if not success then
error(result)
end
warn('Successfully saved', player, 'items to Datastore')
end
-- handling joining players
game.Players.PlayerAdded:Connect(function(player: Player)
-- loading the data
local data = Load(player)
-- keep track of the data in PlayerData
PlayerData[player] = data
-- now we use the LoadItemsFromData function here
-- waiting until character is loaded
local character = player.Character or player.CharacterAdded:Wait()
LoadItemsFromData(player, data)
if reload_items_on_reset == true then
player.CharacterAdded:Connect(function(character: Model)
-- we pass true here to tell that the character respawned
-- so we going to modify the LoadItemsFromData function
LoadItemsFromData(player, data, true)
end)
end
end)
game.Players.PlayerRemoving:Connect(function(player: Player)
Save(player)
-- player is leaving, so we dont need their data anymore
-- get rid of it to prevent memory leak
if PlayerData[player] then
table.clear(PlayerData[player])
end
PlayerData[player] = nil
end)
-- at very last
game:BindToClose(function()
-- if the game is closing, we will force save all player data
for _, player in pairs(game.Players:GetPlayers()) do
Save(player)
end
end)
Here is the code in StarterPlayer.StarterPlayerScripts
:
local player = game.Players.LocalPlayer
local character = player.Character
local hum = character:FindFirstChild("Humanoid")
local fireLoseSave = game.ReplicatedStorage:WaitForChild("PlayerWithItemsDied")
hum.Died:Connect(function()
end)
I also am trying to fire a remote event to tell the server to delete the player’s save file.
How can I make that happen?