Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local ProfileService = require(game.ServerScriptService.ProfileService)
- -----------------------------------------------------------
- -- DataStore Configuration
- -----------------------------------------------------------
- local DataStoreName = "PlayerData_1" -- Change this name to reset all data
- -- Default data template for new players.
- -- If a player joins for the first time, their data will be initialized using these values.
- local DataTemplate = {
- Coins = 0, -- Integer: Total coins the player has
- Loot = {}, -- Dictionary: key = loot name, value = quantity
- Weapons = {"Bow"}, -- Array: List of weapon names the player owns (default: "Bow")
- Kills = 0, -- Integer: Total number of kills
- Equipped_Weapon = "Bow" -- String: The weapon currently equipped (default: "Bow")
- }
- -----------------------------------------------------------
- -- Global Variables
- -----------------------------------------------------------
- local Profiles = {} -- Table to store each player's loaded profile during gameplay
- -- Create the ProfileStore using ProfileService.
- -- This connects to the DataStore using the DataTemplate.
- local ProfileStore = ProfileService.GetProfileStore(DataStoreName, DataTemplate)
- -----------------------------------------------------------
- -- Remote Setup for Live Data Updates
- -----------------------------------------------------------
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
- -- Get (or create) the Remotes folder in ReplicatedStorage.
- local Remotes = ReplicatedStorage:FindFirstChild("Remotes") or Instance.new("Folder")
- Remotes.Name = "Remotes"
- Remotes.Parent = ReplicatedStorage
- -- RemoteEvent to push live data updates to the client.
- local UpdateEvent = Remotes:FindFirstChild("UpdatePlayerData") or Instance.new("RemoteEvent")
- UpdateEvent.Name = "UpdatePlayerData"
- UpdateEvent.Parent = Remotes
- -- RemoteFunction to allow clients to fetch their data on startup.
- local GetDataFunction = Remotes:FindFirstChild("GetPlayerData") or Instance.new("RemoteFunction")
- GetDataFunction.Name = "GetPlayerData"
- GetDataFunction.Parent = Remotes
- -----------------------------------------------------------
- -- DataManager Table
- -----------------------------------------------------------
- local DataManager = {}
- -----------------------------------------------------------
- -- Function: DataManager.SendUpdate
- -- Description: Sends the current profile data to the specified player's client.
- -- Parameters: player (Player) – the player whose data to update.
- -----------------------------------------------------------
- function DataManager.SendUpdate(player)
- local profile = Profiles[player]
- if profile then
- -- Fire the remote event with the player's current data table.
- UpdateEvent:FireClient(player, profile.Data)
- end
- end
- -----------------------------------------------------------
- -- Function: DataManager.LoadData
- -- Description: Loads a player's data using ProfileService when they join.
- -- If the player has no previous data, it initializes with DataTemplate.
- -- It also sets up a listener to kick the player if the profile is released.
- -- Finally, if the player is still in-game, it stores their profile and sends an initial update.
- -----------------------------------------------------------
- function DataManager.LoadData(player)
- -- Attempt to load the player's profile from the DataStore using their UserId.
- local profile = ProfileStore:LoadProfileAsync("Player_" .. player.UserId)
- if profile then
- -- Link the profile to the player's UserId.
- profile:AddUserId(player.UserId)
- -- Reconcile the profile so any missing fields are filled using DataTemplate.
- profile:Reconcile()
- -- Listen for profile release (e.g. data error) and kick the player if it happens.
- profile:ListenToRelease(function()
- Profiles[player] = nil
- player:Kick("Data Error: Please rejoin!")
- end)
- -- Ensure every field defined in DataTemplate exists in profile.Data.
- for key, defaultValue in pairs(DataTemplate) do
- if profile.Data[key] == nil then
- profile.Data[key] = defaultValue
- end
- end
- --print("Data loaded for", player.Name, profile.Data)
- -- Only store the profile if the player is still in the game.
- if player:IsDescendantOf(game.Players) then
- Profiles[player] = profile
- -- Send the initial data update to the player's client.
- DataManager.SendUpdate(player)
- -- Immediately equip the weapon if the player's character already exists.
- if player.Character then
- -- Wait a short moment to ensure the Backpack is ready.
- local backpack = player:FindFirstChild("Backpack") or player:WaitForChild("Backpack")
- task.wait(0.5)
- DataManager.EquipWeapon(player, profile.Data.Equipped_Weapon)
- end
- -- Also listen for CharacterAdded to equip weapon on respawn.
- player.CharacterAdded:Connect(function(character)
- local backpack = player:FindFirstChild("Backpack") or player:WaitForChild("Backpack")
- task.wait(0.5) -- Small delay for smooth loading
- DataManager.EquipWeapon(player, profile.Data.Equipped_Weapon)
- end)
- else
- profile:Release()
- end
- else
- -- If profile fails to load, kick the player.
- player:Kick("Data failed to load. Try rejoining.")
- end
- end
- -----------------------------------------------------------
- -- Function: DataManager.EquipWeapon
- -- Description: Equips a weapon for the player by cloning the weapon tool from ReplicatedStorage.
- -- It removes any existing weapon from the player's Backpack, then equips the new weapon.
- -- Also updates the player's profile with the newly equipped weapon and sends a UI update.
- -- Parameters:
- -- player (Player): The player to equip the weapon.
- -- weaponName (string): The name of the weapon to equip.
- -----------------------------------------------------------
- function DataManager.EquipWeapon(player, weaponName)
- -- Get the Weapons folder from ReplicatedStorage.
- local Weapons = ReplicatedStorage:FindFirstChild("Weapons")
- local profile = Profiles[player]
- if not Weapons then
- warn("Weapons folder missing in ReplicatedStorage!")
- return
- end
- -- Find the weapon tool by name.
- local clonedWeapon = Weapons:FindFirstChild(weaponName)
- -- Wait for the player's Backpack.
- local Backpack = player:WaitForChild("Backpack")
- local StarterGear = player:WaitForChild("StarterGear")
- if clonedWeapon and Backpack then
- -- Remove any existing weapon tools from the Backpack.
- for _, tool in ipairs(Backpack:GetChildren()) do
- if tool:IsA("Tool") then
- tool:Destroy()
- end
- end
- -- Also clear StarterGear to ensure consistency.
- for _, tool in ipairs(StarterGear:GetChildren()) do
- if tool:IsA("Tool") then
- tool:Destroy()
- end
- end
- -- Clone the weapon tool and parent it to the Backpack.
- local newWeapon = clonedWeapon:Clone()
- newWeapon.Parent = Backpack
- -- Clone for StarterGear as well.
- local starterGearWeapon = clonedWeapon:Clone()
- starterGearWeapon.Parent = StarterGear
- -- Update the player's profile with the newly equipped weapon.
- profile.Data.Equipped_Weapon = weaponName
- -- Send a live update to the client.
- DataManager.SendUpdate(player)
- -- Debug (optional): print("Equipped", weaponName, "to", player.Name)
- else
- warn("Could not equip weapon for", player.Name)
- end
- end
- -----------------------------------------------------------
- -- RemoteFunction: GetDataFunction.OnServerInvoke
- -- Description: When the client requests their data, this function waits until the player's profile is loaded
- -- (with a maximum wait time) and then returns the stored data. If data isn’t available, it returns the default template.
- -----------------------------------------------------------
- function GetDataFunction.OnServerInvoke(player)
- local totalWait = 0
- while not Profiles[player] and totalWait < 5 do
- task.wait(0.2)
- totalWait = totalWait + 0.2
- end
- if not Profiles[player] then
- return DataTemplate
- end
- return Profiles[player].Data
- end
- -----------------------------------------------------------
- -- Function: DataManager.SaveData
- -- Description: Called when a player leaves. It releases their profile, which saves the data.
- -----------------------------------------------------------
- function DataManager.SaveData(player)
- local profile = Profiles[player]
- if profile then
- profile:Release()
- end
- end
- -----------------------------------------------------------
- -- Update Methods for Player Data
- -----------------------------------------------------------
- -- Function: DataManager.UpdateStat
- -- Updates a specific stat in the player's data, then sends a live update.
- function DataManager.UpdateStat(player, stat, value)
- local profile = Profiles[player]
- if profile and profile.Data[stat] ~= nil then
- profile.Data[stat] = value
- DataManager.SendUpdate(player)
- end
- end
- -- Function: DataManager.AddLoot
- -- Adds a specified amount of loot to the player's data if it is obtainable,
- -- updates the player's profile, sends a live update, and triggers a GUI popup.
- function DataManager.AddLoot(player, lootName, amount)
- local obtainableLoot = require(game.ServerScriptService.LootManager).GetObtainableLoot()
- local profile = Profiles[player]
- -- Only add loot if it's marked as obtainable.
- if profile and obtainableLoot[lootName] then
- profile.Data.Loot[lootName] = (profile.Data.Loot[lootName] or 0) + amount
- DataManager.SendUpdate(player)
- -- Trigger the loot popup GUI on the client.
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
- local Remotes = ReplicatedStorage:WaitForChild("Remotes")
- local LootPopupEvent = Remotes:FindFirstChild("LootPopupEvent")
- if LootPopupEvent then
- LootPopupEvent:FireClient(player, lootName, amount)
- end
- end
- end
- -- Function: DataManager.RemoveLoot
- -- Removes a specified amount of loot from the player's data if they have enough.
- -- Returns true if successful; false otherwise.
- function DataManager.RemoveLoot(player, lootName, amount)
- local profile = Profiles[player]
- if profile and profile.Data.Loot[lootName] and profile.Data.Loot[lootName] >= amount then
- profile.Data.Loot[lootName] = profile.Data.Loot[lootName] - amount
- if profile.Data.Loot[lootName] <= 0 then
- profile.Data.Loot[lootName] = nil
- end
- DataManager.SendUpdate(player)
- return true
- end
- return false
- end
- -- Function: DataManager.AddWeapon
- -- Adds a weapon to the player's owned list (if they don't already own it) and sends an update.
- function DataManager.AddWeapon(player, weaponName)
- local profile = Profiles[player]
- if profile and not table.find(profile.Data.Weapons, weaponName) then
- table.insert(profile.Data.Weapons, weaponName)
- DataManager.SendUpdate(player)
- end
- end
- -- Function: DataManager.AddCoins
- -- Increments the player's coins by the given amount and sends an update.
- function DataManager.AddCoins(player, amount)
- local profile = Profiles[player]
- if profile then
- profile.Data.Coins = profile.Data.Coins + amount
- DataManager.SendUpdate(player)
- end
- end
- -- Function: DataManager.RemoveCoins
- -- Deducts coins from the player's data if they have enough.
- -- Returns true if successful; false otherwise.
- function DataManager.RemoveCoins(player, amount)
- local profile = Profiles[player]
- if profile and profile.Data.Coins >= amount then
- profile.Data.Coins = profile.Data.Coins - amount
- DataManager.SendUpdate(player)
- return true
- end
- return false
- end
- -- Function: DataManager.AddKill
- -- Increments the player's kill count by one and sends an update.
- function DataManager.AddKill(player)
- local profile = Profiles[player]
- if profile then
- profile.Data.Kills = profile.Data.Kills + 1
- DataManager.SendUpdate(player)
- end
- end
- -----------------------------------------------------------
- -- Connect Player Events
- -----------------------------------------------------------
- game.Players.PlayerAdded:Connect(DataManager.LoadData) -- Load data when a player joins
- game.Players.PlayerRemoving:Connect(DataManager.SaveData) -- Save data when a player leaves
- -----------------------------------------------------------
- -- Return the DataManager module
- -----------------------------------------------------------
- return DataManager
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement