Advertisement
g14ndev

DataManager

Mar 15th, 2025
402
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 12.14 KB | Gaming | 0 0
  1. local ProfileService = require(game.ServerScriptService.ProfileService)
  2.  
  3. -----------------------------------------------------------
  4. -- DataStore Configuration
  5. -----------------------------------------------------------
  6. local DataStoreName = "PlayerData_1" -- Change this name to reset all data
  7.  
  8. -- Default data template for new players.
  9. -- If a player joins for the first time, their data will be initialized using these values.
  10. local DataTemplate = {
  11.     Coins = 0,                   -- Integer: Total coins the player has
  12.     Loot = {},                   -- Dictionary: key = loot name, value = quantity
  13.     Weapons = {"Bow"},           -- Array: List of weapon names the player owns (default: "Bow")
  14.     Kills = 0,                   -- Integer: Total number of kills
  15.     Equipped_Weapon = "Bow"      -- String: The weapon currently equipped (default: "Bow")
  16. }
  17.  
  18. -----------------------------------------------------------
  19. -- Global Variables
  20. -----------------------------------------------------------
  21. local Profiles = {} -- Table to store each player's loaded profile during gameplay
  22.  
  23. -- Create the ProfileStore using ProfileService.
  24. -- This connects to the DataStore using the DataTemplate.
  25. local ProfileStore = ProfileService.GetProfileStore(DataStoreName, DataTemplate)
  26.  
  27. -----------------------------------------------------------
  28. -- Remote Setup for Live Data Updates
  29. -----------------------------------------------------------
  30. local ReplicatedStorage = game:GetService("ReplicatedStorage")
  31. -- Get (or create) the Remotes folder in ReplicatedStorage.
  32. local Remotes = ReplicatedStorage:FindFirstChild("Remotes") or Instance.new("Folder")
  33. Remotes.Name = "Remotes"
  34. Remotes.Parent = ReplicatedStorage
  35.  
  36. -- RemoteEvent to push live data updates to the client.
  37. local UpdateEvent = Remotes:FindFirstChild("UpdatePlayerData") or Instance.new("RemoteEvent")
  38. UpdateEvent.Name = "UpdatePlayerData"
  39. UpdateEvent.Parent = Remotes
  40.  
  41. -- RemoteFunction to allow clients to fetch their data on startup.
  42. local GetDataFunction = Remotes:FindFirstChild("GetPlayerData") or Instance.new("RemoteFunction")
  43. GetDataFunction.Name = "GetPlayerData"
  44. GetDataFunction.Parent = Remotes
  45.  
  46. -----------------------------------------------------------
  47. -- DataManager Table
  48. -----------------------------------------------------------
  49. local DataManager = {}
  50.  
  51. -----------------------------------------------------------
  52. -- Function: DataManager.SendUpdate
  53. -- Description: Sends the current profile data to the specified player's client.
  54. -- Parameters: player (Player) – the player whose data to update.
  55. -----------------------------------------------------------
  56. function DataManager.SendUpdate(player)
  57.     local profile = Profiles[player]
  58.     if profile then
  59.         -- Fire the remote event with the player's current data table.
  60.         UpdateEvent:FireClient(player, profile.Data)
  61.     end
  62. end
  63.  
  64. -----------------------------------------------------------
  65. -- Function: DataManager.LoadData
  66. -- Description: Loads a player's data using ProfileService when they join.
  67. -- If the player has no previous data, it initializes with DataTemplate.
  68. -- It also sets up a listener to kick the player if the profile is released.
  69. -- Finally, if the player is still in-game, it stores their profile and sends an initial update.
  70. -----------------------------------------------------------
  71. function DataManager.LoadData(player)
  72.     -- Attempt to load the player's profile from the DataStore using their UserId.
  73.     local profile = ProfileStore:LoadProfileAsync("Player_" .. player.UserId)
  74.  
  75.     if profile then
  76.         -- Link the profile to the player's UserId.
  77.         profile:AddUserId(player.UserId)
  78.         -- Reconcile the profile so any missing fields are filled using DataTemplate.
  79.         profile:Reconcile()
  80.         -- Listen for profile release (e.g. data error) and kick the player if it happens.
  81.         profile:ListenToRelease(function()
  82.             Profiles[player] = nil
  83.             player:Kick("Data Error: Please rejoin!")
  84.         end)
  85.  
  86.         -- Ensure every field defined in DataTemplate exists in profile.Data.
  87.         for key, defaultValue in pairs(DataTemplate) do
  88.             if profile.Data[key] == nil then
  89.                 profile.Data[key] = defaultValue
  90.             end
  91.         end
  92.  
  93.         --print("Data loaded for", player.Name, profile.Data)
  94.  
  95.         -- Only store the profile if the player is still in the game.
  96.         if player:IsDescendantOf(game.Players) then
  97.             Profiles[player] = profile
  98.             -- Send the initial data update to the player's client.
  99.             DataManager.SendUpdate(player)
  100.  
  101.             -- Immediately equip the weapon if the player's character already exists.
  102.             if player.Character then
  103.                 -- Wait a short moment to ensure the Backpack is ready.
  104.                 local backpack = player:FindFirstChild("Backpack") or player:WaitForChild("Backpack")
  105.                 task.wait(0.5)
  106.                 DataManager.EquipWeapon(player, profile.Data.Equipped_Weapon)
  107.             end
  108.  
  109.             -- Also listen for CharacterAdded to equip weapon on respawn.
  110.             player.CharacterAdded:Connect(function(character)
  111.                 local backpack = player:FindFirstChild("Backpack") or player:WaitForChild("Backpack")
  112.                 task.wait(0.5) -- Small delay for smooth loading
  113.                 DataManager.EquipWeapon(player, profile.Data.Equipped_Weapon)
  114.             end)
  115.         else
  116.             profile:Release()
  117.         end
  118.     else
  119.         -- If profile fails to load, kick the player.
  120.         player:Kick("Data failed to load. Try rejoining.")
  121.     end
  122. end
  123.  
  124. -----------------------------------------------------------
  125. -- Function: DataManager.EquipWeapon
  126. -- Description: Equips a weapon for the player by cloning the weapon tool from ReplicatedStorage.
  127. -- It removes any existing weapon from the player's Backpack, then equips the new weapon.
  128. -- Also updates the player's profile with the newly equipped weapon and sends a UI update.
  129. -- Parameters:
  130. --   player (Player): The player to equip the weapon.
  131. --   weaponName (string): The name of the weapon to equip.
  132. -----------------------------------------------------------
  133. function DataManager.EquipWeapon(player, weaponName)
  134.     -- Get the Weapons folder from ReplicatedStorage.
  135.     local Weapons = ReplicatedStorage:FindFirstChild("Weapons")
  136.     local profile = Profiles[player]
  137.     if not Weapons then
  138.         warn("Weapons folder missing in ReplicatedStorage!")
  139.         return
  140.     end
  141.  
  142.     -- Find the weapon tool by name.
  143.     local clonedWeapon = Weapons:FindFirstChild(weaponName)
  144.     -- Wait for the player's Backpack.
  145.     local Backpack = player:WaitForChild("Backpack")
  146.     local StarterGear = player:WaitForChild("StarterGear")
  147.     if clonedWeapon and Backpack then
  148.         -- Remove any existing weapon tools from the Backpack.
  149.         for _, tool in ipairs(Backpack:GetChildren()) do
  150.             if tool:IsA("Tool") then
  151.                 tool:Destroy()
  152.             end
  153.         end
  154.  
  155.         -- Also clear StarterGear to ensure consistency.
  156.         for _, tool in ipairs(StarterGear:GetChildren()) do
  157.             if tool:IsA("Tool") then
  158.                 tool:Destroy()
  159.             end
  160.         end
  161.  
  162.         -- Clone the weapon tool and parent it to the Backpack.
  163.         local newWeapon = clonedWeapon:Clone()
  164.         newWeapon.Parent = Backpack
  165.  
  166.         -- Clone for StarterGear as well.
  167.         local starterGearWeapon = clonedWeapon:Clone()
  168.         starterGearWeapon.Parent = StarterGear
  169.  
  170.         -- Update the player's profile with the newly equipped weapon.
  171.         profile.Data.Equipped_Weapon = weaponName
  172.  
  173.         -- Send a live update to the client.
  174.         DataManager.SendUpdate(player)
  175.         -- Debug (optional): print("Equipped", weaponName, "to", player.Name)
  176.     else
  177.         warn("Could not equip weapon for", player.Name)
  178.     end
  179. end
  180.  
  181. -----------------------------------------------------------
  182. -- RemoteFunction: GetDataFunction.OnServerInvoke
  183. -- Description: When the client requests their data, this function waits until the player's profile is loaded
  184. -- (with a maximum wait time) and then returns the stored data. If data isn’t available, it returns the default template.
  185. -----------------------------------------------------------
  186. function GetDataFunction.OnServerInvoke(player)
  187.     local totalWait = 0
  188.     while not Profiles[player] and totalWait < 5 do
  189.         task.wait(0.2)
  190.         totalWait = totalWait + 0.2
  191.     end
  192.     if not Profiles[player] then
  193.         return DataTemplate
  194.     end
  195.     return Profiles[player].Data
  196. end
  197.  
  198. -----------------------------------------------------------
  199. -- Function: DataManager.SaveData
  200. -- Description: Called when a player leaves. It releases their profile, which saves the data.
  201. -----------------------------------------------------------
  202. function DataManager.SaveData(player)
  203.     local profile = Profiles[player]
  204.     if profile then
  205.         profile:Release()
  206.     end
  207. end
  208.  
  209. -----------------------------------------------------------
  210. -- Update Methods for Player Data
  211. -----------------------------------------------------------
  212.  
  213. -- Function: DataManager.UpdateStat
  214. -- Updates a specific stat in the player's data, then sends a live update.
  215. function DataManager.UpdateStat(player, stat, value)
  216.     local profile = Profiles[player]
  217.     if profile and profile.Data[stat] ~= nil then
  218.         profile.Data[stat] = value
  219.         DataManager.SendUpdate(player)
  220.     end
  221. end
  222.  
  223. -- Function: DataManager.AddLoot
  224. -- Adds a specified amount of loot to the player's data if it is obtainable,
  225. -- updates the player's profile, sends a live update, and triggers a GUI popup.
  226. function DataManager.AddLoot(player, lootName, amount)
  227.     local obtainableLoot = require(game.ServerScriptService.LootManager).GetObtainableLoot()
  228.     local profile = Profiles[player]
  229.     -- Only add loot if it's marked as obtainable.
  230.     if profile and obtainableLoot[lootName] then
  231.         profile.Data.Loot[lootName] = (profile.Data.Loot[lootName] or 0) + amount
  232.         DataManager.SendUpdate(player)
  233.  
  234.         -- Trigger the loot popup GUI on the client.
  235.         local ReplicatedStorage = game:GetService("ReplicatedStorage")
  236.         local Remotes = ReplicatedStorage:WaitForChild("Remotes")
  237.         local LootPopupEvent = Remotes:FindFirstChild("LootPopupEvent")
  238.         if LootPopupEvent then
  239.             LootPopupEvent:FireClient(player, lootName, amount)
  240.         end
  241.     end
  242. end
  243.  
  244. -- Function: DataManager.RemoveLoot
  245. -- Removes a specified amount of loot from the player's data if they have enough.
  246. -- Returns true if successful; false otherwise.
  247. function DataManager.RemoveLoot(player, lootName, amount)
  248.     local profile = Profiles[player]
  249.     if profile and profile.Data.Loot[lootName] and profile.Data.Loot[lootName] >= amount then
  250.         profile.Data.Loot[lootName] = profile.Data.Loot[lootName] - amount
  251.         if profile.Data.Loot[lootName] <= 0 then
  252.             profile.Data.Loot[lootName] = nil
  253.         end
  254.         DataManager.SendUpdate(player)
  255.         return true
  256.     end
  257.     return false
  258. end
  259.  
  260. -- Function: DataManager.AddWeapon
  261. -- Adds a weapon to the player's owned list (if they don't already own it) and sends an update.
  262. function DataManager.AddWeapon(player, weaponName)
  263.     local profile = Profiles[player]
  264.     if profile and not table.find(profile.Data.Weapons, weaponName) then
  265.         table.insert(profile.Data.Weapons, weaponName)
  266.         DataManager.SendUpdate(player)
  267.     end
  268. end
  269.  
  270. -- Function: DataManager.AddCoins
  271. -- Increments the player's coins by the given amount and sends an update.
  272. function DataManager.AddCoins(player, amount)
  273.     local profile = Profiles[player]
  274.     if profile then
  275.         profile.Data.Coins = profile.Data.Coins + amount
  276.         DataManager.SendUpdate(player)
  277.     end
  278. end
  279.  
  280. -- Function: DataManager.RemoveCoins
  281. -- Deducts coins from the player's data if they have enough.
  282. -- Returns true if successful; false otherwise.
  283. function DataManager.RemoveCoins(player, amount)
  284.     local profile = Profiles[player]
  285.     if profile and profile.Data.Coins >= amount then
  286.         profile.Data.Coins = profile.Data.Coins - amount
  287.         DataManager.SendUpdate(player)
  288.         return true
  289.     end
  290.     return false
  291. end
  292.  
  293. -- Function: DataManager.AddKill
  294. -- Increments the player's kill count by one and sends an update.
  295. function DataManager.AddKill(player)
  296.     local profile = Profiles[player]
  297.     if profile then
  298.         profile.Data.Kills = profile.Data.Kills + 1
  299.         DataManager.SendUpdate(player)
  300.     end
  301. end
  302.  
  303. -----------------------------------------------------------
  304. -- Connect Player Events
  305. -----------------------------------------------------------
  306. game.Players.PlayerAdded:Connect(DataManager.LoadData)      -- Load data when a player joins
  307. game.Players.PlayerRemoving:Connect(DataManager.SaveData)   -- Save data when a player leaves
  308.  
  309. -----------------------------------------------------------
  310. -- Return the DataManager module
  311. -----------------------------------------------------------
  312. return DataManager
  313.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement