-- src/ServerScriptService/PlayerSetupManager.server.lua local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local GameConfig = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("GameConfig")) local EconomyConfig = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("EconomyConfig")) local ShopConfig = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("ShopConfig")) local NotificationEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("NotificationEvent") -- Player data cache for this session local playerData = {} local function createLeaderstats(player) local leaderstats = Instance.new("Folder") leaderstats.Name = "leaderstats" leaderstats.Parent = player local cash = Instance.new("IntValue") cash.Name = GameConfig.Stats.Cash cash.Value = EconomyConfig.StarterCash cash.Parent = leaderstats local woodChopped = Instance.new("IntValue") woodChopped.Name = GameConfig.Stats.WoodChopped woodChopped.Value = 0 woodChopped.Parent = leaderstats end local function initializeInventory(player) -- Start with empty inventory -- players must craft their tools local defaultInventory = { Tools = {}, Machines = {}, Vehicles = {}, Automation = {}, } -- Store in player data cache playerData[player.UserId] = { Inventory = defaultInventory, EquippedAxe = "", -- empty = fists QuestProgress = {}, Achievements = {}, BiomesVisited = {}, Resources = { Wood = 0, Stone = 0, GoldOre = 0, Diamond = 0 }, TotalEarned = 0, TotalWoodSold = 0, TotalBuilt = 0, } -- Empty string means fists -- client will default to fist stats player:SetAttribute("EquippedAxe", "") end local function onPlayerAdded(player) createLeaderstats(player) initializeInventory(player) -- Wait for character to load then set attributes player.CharacterAdded:Connect(function(character) character:SetAttribute("EquippedAxe", playerData[player.UserId].EquippedAxe) end) -- Welcome notification task.delay(3, function() if player.Parent then NotificationEvent:FireClient(player, "Welcome", "Welcome to Timberbound Expeditions! Punch trees to gather wood, then press C to craft your first axe!") end end) end local function onPlayerRemoving(player) playerData[player.UserId] = nil end -- Expose playerData globally for other server scripts _G.GetPlayerData = function(player) return playerData[player.UserId] end _G.SetPlayerData = function(player, key, value) if playerData[player.UserId] then playerData[player.UserId][key] = value end end _G.AddToInventory = function(player, category, itemId) local data = playerData[player.UserId] if data and data.Inventory[category] then table.insert(data.Inventory[category], itemId) return true end return false end _G.HasInInventory = function(player, category, itemId) local data = playerData[player.UserId] if data and data.Inventory[category] then for _, id in ipairs(data.Inventory[category]) do if id == itemId then return true end end end return false end _G.IncrementStat = function(player, statName, amount) local data = playerData[player.UserId] if not data then return end if statName == "WoodChopped" then local leaderstats = player:FindFirstChild("leaderstats") if leaderstats then local stat = leaderstats:FindFirstChild(statName) if stat then stat.Value = stat.Value + amount end end elseif statName == "TotalEarned" then data.TotalEarned = (data.TotalEarned or 0) + amount elseif statName == "TotalWoodSold" then data.TotalWoodSold = (data.TotalWoodSold or 0) + amount elseif statName == "TotalBuilt" then data.TotalBuilt = (data.TotalBuilt or 0) + amount end end Players.PlayerAdded:Connect(onPlayerAdded) Players.PlayerRemoving:Connect(onPlayerRemoving) -- Handle players who joined before this script loaded for _, player in ipairs(Players:GetPlayers()) do task.spawn(function() onPlayerAdded(player) end) end