Hi everyone! I made this DataStore handler (ModuleScript and ServerScript) a few weeks ago, and now I’d like to use it in another game. And I’m wondering if it’s solid or if there’s anything missing or worth improving.
Let me know what you think. I’d really appreciate any tips or improvements :>
Module Script:
local DATA_STORE_NAME = "PlayerDataStore"
local DSS = game:GetService("DataStoreService")
local PlayerDataStore = DSS:GetDataStore(DATA_STORE_NAME)
local PlayerData = {}
function PlayerData.SavePlayerData(player)
local UserId = player.UserId
local Data = {}
for _,value in ipairs(player:GetDescendants()) do
if value:IsA("NumberValue") or value:IsA("StringValue") or value:IsA("BoolValue") then
Data[value.Name] = value.Value
end
end
local succes, errorMessage = pcall(function()
PlayerDataStore:SetAsync(tostring(UserId), Data)
end)
if not succes then
warn(errorMessage)
end
end
function PlayerData.LoadPlayerData(player, CallBack)
local UserId = player.UserId
local success, result = pcall(function()
return PlayerDataStore:GetAsync(tostring(UserId))
end)
if success and CallBack then
CallBack(result)
elseif not success then
warn("Failed To load Data for" .. player.Name)
end
end
return PlayerData
Server Script:
local Players = game:GetService("Players")
local PlayerDataModule = require(script.Parent)
local Defaults = {
leaderstats = { Coins = 300, Kills = 0, Wins = 0},
Stats = { Level = 1, Exp = 0, Blocks = 0, Gems = 0 },
Settings = { afk = true, Night = false, Music = true },
Wins = { map1 = 0, map2 = 0, map3 = 0, map4 = 0}
}
Players.PlayerAdded:Connect(function(plr)
-- 1. Create folders
local folders = {}
for _, name in ipairs({"leaderstats", "Stats", "Settings", "Wins"}) do
local f = Instance.new("Folder")
f.Name = name
f.Parent = plr
folders[name] = f
end
--
for cat, stats in pairs(Defaults) do
for statName, defaultValue in pairs(stats) do
local className = type(defaultValue) == "boolean" and "BoolValue"
or type(defaultValue) == "string" and "StringValue"
or "NumberValue"
local v = Instance.new(className)
v.Name = statName
v.Value = defaultValue
v.Parent = folders[cat]
end
end
-- 3. Load saved data into those ValueObjects
PlayerDataModule.LoadPlayerData(plr, function(data)
if data then
for _, v in ipairs(plr:GetDescendants()) do
if v:IsA("NumberValue") or v:IsA("BoolValue") or v:IsA("StringValue") then
local newVal = data[v.Name]
if newVal ~= nil then
v.Value = newVal
end
end
end
end
end)
-- This auto saves every 60 seconds
local alive = true
task.spawn(function()
while alive do
task.wait(60)
PlayerDataModule.SavePlayerData(plr)
end
end)
plr.AncestryChanged:Connect(function()
if not plr:IsDescendantOf(game) then
alive = false
end
end)
-- dont mind this :) (its just a hitbox)
plr.CharacterAdded:Connect(function()
local hitbox = Instance.new("Part")
hitbox.Name = "PLRHitbox"
hitbox.Size = Vector3.new(3, 4, 3) -- sized around torso
hitbox.Transparency = 0.67
hitbox.Massless = true
--hitbox.Anchored = true
hitbox.CanCollide = false
hitbox.CanTouch = true
local char = plr.Character or plr.CharacterAdded:Wait()
local hrp = char:WaitForChild("HumanoidRootPart")
hitbox.Position = hrp.Position
hitbox.Parent = char
-- Keep hitbox aligned
local weld = Instance.new("WeldConstraint", hitbox)
weld.Part0 = hitbox
weld.Part1 = hrp
end)
end)
Players.PlayerRemoving:Connect(function(plr)
PlayerDataModule.SavePlayerData(plr)
end)