This is both of the scripts that creates the leaderstats:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local BadgeService = game:GetService("BadgeService")
local Players = game:GetService("Players")
--────────────────────────── << MODULES >> ────────────────────────────
-- Empty
--────────────────────────── << VARIABLES >> ──────────────────────────
local module = {}
--────────────────────────── << FUNCTIONS >> ──────────────────────────
-- Check for Badge whenever Kills change
local function setupBadgeListener(player, killsValue, smashesValue)
killsValue.Changed:Connect(function(newVal)
if newVal >= 250 then
local success, hasBadge = pcall(function()
return BadgeService:UserHasBadgeAsync(player.UserId, 2312892374675752)
end)
if success and not hasBadge then
pcall(function()
BadgeService:AwardBadgeAsync(player.UserId, 2312892374675752)
local badgeInfo = BadgeService:GetBadgeInfoAsync(2312892374675752)
local badgeImageId = "rbxassetid://" .. badgeInfo.IconImageId
local BadgeName = badgeInfo.Name
local NotificationRemote = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("Notification")
NotificationRemote:FireClient(player, "Badge", "You got the " .. BadgeName .. " badge!", 15, badgeImageId)
end)
end
end
if newVal >= 500 then
local success, hasBadge = pcall(function()
return BadgeService:UserHasBadgeAsync(player.UserId, 4442479432930128)
end)
if success and not hasBadge then
pcall(function()
BadgeService:AwardBadgeAsync(player.UserId, 4442479432930128)
local badgeInfo = BadgeService:GetBadgeInfoAsync(4442479432930128)
local badgeImageId = "rbxassetid://" .. badgeInfo.IconImageId
local BadgeName = badgeInfo.Name
local NotificationRemote = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("Notification")
NotificationRemote:FireClient(player, "Badge", "You got the " .. BadgeName .. " badge!", 15, badgeImageId)
end)
end
end
if newVal >= 1000 then
local success, hasBadge = pcall(function()
return BadgeService:UserHasBadgeAsync(player.UserId, 425818117264007)
end)
if not success or hasBadge then return end
pcall(function()
BadgeService:AwardBadgeAsync(player.UserId, 425818117264007)
local badgeInfo = BadgeService:GetBadgeInfoAsync(425818117264007)
local badgeImageId = "rbxassetid://" .. badgeInfo.IconImageId
local BadgeName = badgeInfo.Name
local NotificationRemote = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("Notification")
NotificationRemote:FireClient(player, "Badge", "You got the " .. BadgeName .. " badge!", 15, badgeImageId)
end)
end
end)
smashesValue.Changed:Connect(function(newVal)
if newVal >= 1000 then
local success, hasBadge = pcall(function()
return BadgeService:UserHasBadgeAsync(player.UserId, 3435276838241438)
end)
if success and not hasBadge then
pcall(function()
BadgeService:AwardBadgeAsync(player.UserId, 3435276838241438)
local badgeInfo = BadgeService:GetBadgeInfoAsync(3435276838241438)
local badgeImageId = "rbxassetid://" .. badgeInfo.IconImageId
local BadgeName = badgeInfo.Name
local NotificationRemote = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("Notification")
NotificationRemote:FireClient(player, "Badge", "You got the " .. BadgeName .. " badge!", 15, badgeImageId)
end)
end
end
if newVal >= 10000 then
local success, hasBadge = pcall(function()
return BadgeService:UserHasBadgeAsync(player.UserId, 3277737759460434)
end)
if success and not hasBadge then
pcall(function()
BadgeService:AwardBadgeAsync(player.UserId, 3277737759460434)
local badgeInfo = BadgeService:GetBadgeInfoAsync(3277737759460434)
local badgeImageId = "rbxassetid://" .. badgeInfo.IconImageId
local BadgeName = badgeInfo.Name
local NotificationRemote = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("Notification")
NotificationRemote:FireClient(player, "Badge", "You got the " .. BadgeName .. " badge!", 15, badgeImageId)
end)
end
end
if newVal >= 100000 then
local success, hasBadge = pcall(function()
return BadgeService:UserHasBadgeAsync(player.UserId, 3046178914164323)
end)
if success and not hasBadge then
pcall(function()
BadgeService:AwardBadgeAsync(player.UserId, 3046178914164323)
local badgeInfo = BadgeService:GetBadgeInfoAsync(3046178914164323)
local badgeImageId = "rbxassetid://" .. badgeInfo.IconImageId
local BadgeName = badgeInfo.Name
local NotificationRemote = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("Notification")
NotificationRemote:FireClient(player, "Badge", "You got the " .. BadgeName .. " badge!", 15, badgeImageId)
end)
end
end
end)
end
local function createLeaderstats(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
local Smashes = Instance.new("IntValue")
Smashes.Name = "Smashes"
Smashes.Value = 0
Smashes.Parent = leaderstats
local Kills = Instance.new("IntValue")
Kills.Name = "Kills"
Kills.Value = 0
Kills.Parent = leaderstats
local Hammer = Instance.new("StringValue")
Hammer.Name = "Hammer"
Hammer.Value = "Default"
Hammer.Parent = leaderstats
leaderstats.Parent = player
setupBadgeListener(player, Kills, Smashes)
return leaderstats
end
function module:SetStats(Player : Player, NewData : {})
local leaderstats = Player:FindFirstChild("leaderstats")
if not leaderstats then leaderstats = createLeaderstats(Player) end
leaderstats["Smashes"].Value = NewData["Smashes"]
leaderstats.Kills.Value = NewData["Kills"]
leaderstats.Hammer.Value = NewData["Hammer"]
return leaderstats["Smashes"].Value, leaderstats.Hammer.Value, leaderstats.Kills.Value
end
return module
And this is the serverscript that calls that module:
--────────────────────────── << SERVICES >> ───────────────────────────
local ServerScriptService = game:GetService("ServerScriptService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
--────────────────────────── << MODULES >> ────────────────────────────
local ProfileStore = require( ServerScriptService.Utilities.ProfileStore )
local BadgeLoader = require( ServerScriptService.PlayerScripts.BadgeLoader )
local PlayerData = require(ServerStorage.Data.PlayerData )
--────────────────────────── << VARIABLES >> ──────────────────────────
local DATA_STORE_KEY = RunService:IsStudio() and "Development" or "HammerWars_Stats_V1"
local Template = {
Smashes = 0,
Kills = 0,
Hammer = "Default",
Settings = {
["HealthBar"] = true,
["BackgroundMusic"] = true,
["DeathSounds"] = true,
["PlaySFX"] = true,
["EquipRadio"] = false,
["HammerShake"] = false,
["KillstreakMusic"] = true,
},
}
local Profiles = {}
local PlayerStore = ProfileStore.New(DATA_STORE_KEY, Template)
--────────────────────────── << FUNCTIONS >> ──────────────────────────
local function setupLeaderstats(player, data)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
-- Create Smashes
local smashes = Instance.new("IntValue")
smashes.Name = "Smashes"
smashes.Value = data.Smashes
smashes.Parent = leaderstats
-- LIVE SYNC: Update profile data immediately when value changes
smashes.Changed:Connect(function(newVal)
data.Smashes = newVal
end)
-- Create Kills
local kills = Instance.new("IntValue")
kills.Name = "Kills"
kills.Value = data.Kills
kills.Parent = leaderstats
kills.Changed:Connect(function(newVal)
data.Kills = newVal
end)
-- Create Hammer String
local hammer = Instance.new("StringValue")
hammer.Name = "Hammer"
hammer.Value = data.Hammer
hammer.Parent = leaderstats
hammer.Changed:Connect(function(newVal)
data.Hammer = newVal
end)
end
local function onJoin(player)
local profile = PlayerStore:StartSessionAsync(tostring(player.UserId), {
Cancel = function()
return player.Parent ~= Players
end
})
if profile ~= nil then
profile:AddUserId(player.UserId)
profile:Reconcile()
-- Critical: If the session ends unexpectedly (kick/error), clean up
profile.OnSessionEnd:Connect(function()
Profiles[player.UserId] = nil
PlayerData[player.UserId] = nil
player:Kick("Data Session Ended")
end)
if player.Parent == Players then
Profiles[player.UserId] = profile
PlayerData[player.UserId] = profile.Data -- Shared reference
-- Initialize Leaderstats and Badges
setupLeaderstats(player, profile.Data)
BadgeLoader:SetStats(player, profile.Data)
else
profile:EndSession()
end
else
player:Kick("Failed to load data (DataStore Error)")
end
end
local function createInstances(ply : Player)
-- Settings values that aren't in leaderstats but might need to exist
local DeathSounds = Instance.new("BoolValue")
DeathSounds.Name = "DeathSounds"
DeathSounds.Value = PlayerData[ply.UserId] and PlayerData[ply.UserId].Settings.DeathSounds or true
DeathSounds.Parent = ply
local PlaySFX = Instance.new("BoolValue")
PlaySFX.Name = "PlaySFX"
PlaySFX.Value = PlayerData[ply.UserId] and PlayerData[ply.UserId].Settings.PlaySFX or true
PlaySFX.Parent = ply
end
--────────────────────────── << SIGNALS >> ──────────────────────────
Players.PlayerAdded:Connect(function(ply)
onJoin(ply)
createInstances(ply)
end)
Players.PlayerRemoving:Connect(function(ply)
local profile = Profiles[ply.UserId]
if profile then
-- No need to scrape leaderstats here; the .Changed events handled it!
profile:EndSession()
end
end)
-- Early joiner check
for _, player in Players:GetPlayers() do
task.spawn(onJoin, player)
end
--────────────────────────── << SERVER SHUTDOWN >> ──────────────────────────
game:BindToClose(function()
print("Server shutting down, releasing profiles...")
for _, ply in ipairs(Players:GetPlayers()) do
local profile = Profiles[ply.UserId]
if profile then
profile:EndSession()
end
end
task.wait(RunService:IsStudio() and 2 or 5)
end)
When 1 player joins, the smashes is first, the kills are second, and the hammer is last. but when 1 more player joins, then the hammer is first and the smashes are last. why? i need the smashes. first.

