You can write your topic however you want, but you need to answer these questions:
-
What do you want to achieve? Keep it simple and clear!
im making a gacha system -
What is the issue? Include screenshots / videos if possible!
this error
14:22:24.225 Stack Begin - Studio
14:22:24.225 Script 'ServerScriptService.Leaderstats', Line 21 - Studio - Leaderstats:21
14:22:24.226 Stack End - Studio
14:22:24.226 superman978705 joined with 0 Tokens and 70 Stardust - Server - Leaderstats:40
14:22:25.877 Animation Spoofer cannot run while game is running - Server
14:22:26.559 Animation Spoofer cannot run while game is running - Client
14:22:32.969 0_1410575 - Server
14:22:33.321 Players.superman978705.PlayerScripts.GachaClient:297: attempt to concatenate nil with string - Client - GachaClient:297
14:22:33.321 Stack Begin - Studio
14:22:33.321 Script 'Players.superman978705.PlayerScripts.GachaClient', Line 297 - function updateCurrencyDisplays - Studio - GachaClient:297
14:22:33.321 Script 'Players.superman978705.PlayerScripts.GachaClient', Line 304 - function RefreshPlayerData - Studio - GachaClient:304
14:22:33.322 Script 'Players.superman978705.PlayerScripts.GachaClient', Line 500 - Studio - GachaClient:500
14:22:33.322 Stack End - Studio
14:22:33.411 0_1447505 - Client
- What solutions have you tried so far? Did you look for solutions on the Creator Hub?
ive tried ai, devforum, documentation, etc.
After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!
leaderstats script
local Players = game:GetService("Players")
local PlayerDataManager = require(script.Parent.PlayerDataManager)
Players.PlayerAdded:Connect(function(player)
-- Load player data first
local data = PlayerDataManager.LoadData(player)
-- Create leaderstats folder
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
-- Create Tokens value (loaded from data)
local tokens = Instance.new("IntValue")
tokens.Name = "Tokens"
tokens.Value = data.Tokens
tokens.Parent = leaderstats
-- Create Stardust value (loaded from data)
local stardust = Instance.new("IntValue")
stardust.Name = "Stardust"
stardust.Value = data.Stardust
stardust.Parent = leaderstats
-- Sync Tokens changes to DataStore
tokens.Changed:Connect(function(newValue)
PlayerDataManager.SetTokens(player, newValue)
end)
-- Sync Stardust changes to DataStore
stardust.Changed:Connect(function(newValue)
PlayerDataManager.SetStardust(player, newValue)
end)
print(player.Name.." joined with "..tokens.Value.." Tokens and "..stardust.Value.." Stardust")
end)
Players.PlayerRemoving:Connect(function(player)
-- Save data when player leaves
PlayerDataManager.SaveData(player)
end)
GachaClient
-- GachaClient.lua
-- Place in StarterPlayer > StarterPlayerScripts
-- Handles UI interactions
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
-- Wait for modules to load
local Modules = ReplicatedStorage:WaitForChild("Modules")
local GachaModule = require(Modules:WaitForChild("GachaModule"))
local BannerConfig = require(Modules:WaitForChild("BannerConfig"))
local player = Players.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui")
local gachaGui = playerGui:WaitForChild("GachaGui")
-- UI Elements (with error checking)
local mainFrame = gachaGui:WaitForChild("MainFrame", 10)
if not mainFrame then
warn("MainFrame not found in GachaGui! Please create the UI first.")
return
end
local bannerDisplay = mainFrame:WaitForChild("BannerDisplay", 5)
local pullButton1 = mainFrame:WaitForChild("Pull1Button", 5)
local pullButton10 = mainFrame:WaitForChild("Pull10Button", 5)
local stardustLabel = mainFrame:WaitForChild("StardustLabel", 5)
local tokensLabel = mainFrame:WaitForChild("TokensLabel", 5)
local bannerButtonsFrame = mainFrame:WaitForChild("BannerButtons", 5)
local shopButton = mainFrame:WaitForChild("ShopButton", 5)
local closeButton = mainFrame:WaitForChild("CloseButton", 5)
local shopFrame = gachaGui:WaitForChild("ShopFrame", 5)
local shopCloseButton = shopFrame and shopFrame:WaitForChild("CloseButton", 5)
local shopItemsFrame = shopFrame and shopFrame:WaitForChild("ItemsFrame", 5)
local shopStardustLabel = shopFrame and shopFrame:WaitForChild("StardustLabel", 5)
local resultsFrame = gachaGui:WaitForChild("ResultsFrame", 5)
local resultsContainer = resultsFrame and resultsFrame:WaitForChild("ResultsContainer", 5)
local resultsCloseButton = resultsFrame and resultsFrame:WaitForChild("CloseButton", 5)
-- Check if critical UI elements exist
if not pullButton1 or not pullButton10 then
warn("Critical UI elements missing! Please check the UI structure.")
return
end
-- Set button text with costs
if pullButton1 then
pullButton1.Text = "Pull x1\n(100 Tokens)"
end
if pullButton10 then
pullButton10.Text = "Pull x10\n(900 Tokens)"
end
-- Remotes
local GachaRemotes = ReplicatedStorage:WaitForChild("GachaRemotes", 10)
if not GachaRemotes then
warn("GachaRemotes folder not found! Please run SetupRemotes.lua")
return
end
local PullRemote = GachaRemotes:WaitForChild("PullRemote", 5)
local PurchaseFromShopRemote = GachaRemotes:WaitForChild("PurchaseFromShopRemote", 5)
local GetPlayerDataRemote = GachaRemotes:WaitForChild("GetPlayerDataRemote", 5)
if not PullRemote or not PurchaseFromShopRemote or not GetPlayerDataRemote then
warn("One or more remotes are missing! Please run SetupRemotes.lua")
return
end
-- State
local currentBanner = "Standard"
local playerData = nil
local isPulling = false
local currentBackgroundClone = nil
local originalCameraCFrame = nil
local originalCameraType = nil
local originalSkybox = {}
local backgroundsFolder = nil
local isGachaOpen = false
-- Wait for backgrounds folder
local function GetBackgroundsFolder()
if not backgroundsFolder then
backgroundsFolder = ReplicatedStorage:WaitForChild("GachaBackgrounds", 5)
if not backgroundsFolder then
warn("GachaBackgrounds folder not found in ReplicatedStorage!")
end
end
return backgroundsFolder
end
-- Save original skybox
local function SaveOriginalSkybox()
local lighting = game:GetService("Lighting")
originalSkybox = {
SkyboxBk = lighting:FindFirstChild("SkyboxBk") and lighting.SkyboxBk:Clone(),
SkyboxDn = lighting:FindFirstChild("SkyboxDn") and lighting.SkyboxDn:Clone(),
SkyboxFt = lighting:FindFirstChild("SkyboxFt") and lighting.SkyboxFt:Clone(),
SkyboxLf = lighting:FindFirstChild("SkyboxLf") and lighting.SkyboxLf:Clone(),
SkyboxRt = lighting:FindFirstChild("SkyboxRt") and lighting.SkyboxRt:Clone(),
SkyboxUp = lighting:FindFirstChild("SkyboxUp") and lighting.SkyboxUp:Clone()
}
end
-- Apply skybox from background model
local function ApplySkybox(backgroundModel)
local lighting = game:GetService("Lighting")
-- Remove existing skybox
for _, child in ipairs(lighting:GetChildren()) do
if child:IsA("Sky") or child.Name:match("^Skybox") then
child:Destroy()
end
end
-- Check if background has a Sky object
local skyObject = backgroundModel:FindFirstChildOfClass("Sky")
if skyObject then
local newSky = skyObject:Clone()
newSky.Parent = lighting
return
end
-- Check for individual skybox faces
local skyboxFaces = {"SkyboxBk", "SkyboxDn", "SkyboxFt", "SkyboxLf", "SkyboxRt", "SkyboxUp"}
local hasSkybox = false
for _, faceName in ipairs(skyboxFaces) do
local face = backgroundModel:FindFirstChild(faceName)
if face then
hasSkybox = true
local newFace = face:Clone()
newFace.Parent = lighting
end
end
if not hasSkybox then
-- No custom skybox, could set a default dark sky
local sky = Instance.new("Sky")
sky.SkyboxBk = "rbxasset://textures/sky/night.jpg"
sky.SkyboxDn = "rbxasset://textures/sky/night.jpg"
sky.SkyboxFt = "rbxasset://textures/sky/night.jpg"
sky.SkyboxLf = "rbxasset://textures/sky/night.jpg"
sky.SkyboxRt = "rbxasset://textures/sky/night.jpg"
sky.SkyboxUp = "rbxasset://textures/sky/night.jpg"
sky.Parent = lighting
end
end
-- Restore original skybox
local function RestoreSkybox()
local lighting = game:GetService("Lighting")
-- Remove gacha skybox
for _, child in ipairs(lighting:GetChildren()) do
if child:IsA("Sky") or child.Name:match("^Skybox") then
child:Destroy()
end
end
-- Restore original
for name, skyboxPart in pairs(originalSkybox) do
if skyboxPart then
local restored = skyboxPart:Clone()
restored.Parent = lighting
end
end
end
-- Load and position background model (CLIENT-SIDE)
local function LoadBackgroundModel(bannerName)
local bannerData = BannerConfig.Banners[bannerName]
if not bannerData or not bannerData.BackgroundModel then
warn("No background model specified for banner: "..bannerName)
return
end
-- Remove old background if it exists
if currentBackgroundClone then
currentBackgroundClone:Destroy()
currentBackgroundClone = nil
end
-- Get backgrounds folder
local bgFolder = GetBackgroundsFolder()
if not bgFolder then return end
-- Find the background model template
local backgroundTemplate = bgFolder:FindFirstChild(bannerData.BackgroundModel)
if not backgroundTemplate then
warn("Background model not found: "..bannerData.BackgroundModel.." in ReplicatedStorage.GachaBackgrounds")
return
end
-- Clone the background model to the camera
-- This keeps it client-side only
currentBackgroundClone = backgroundTemplate:Clone()
-- Parent to CurrentCamera so it's only visible to this client
currentBackgroundClone.Parent = workspace.CurrentCamera
-- Apply skybox if gacha is open
if isGachaOpen then
ApplySkybox(currentBackgroundClone)
end
-- Find the camera part in the model
local cameraPart = currentBackgroundClone:FindFirstChild("Camera")
if not cameraPart then
warn("Camera part not found in background model: "..bannerData.BackgroundModel)
currentBackgroundClone:Destroy()
currentBackgroundClone = nil
return
end
-- Set camera to the background camera position (only if gacha is open)
if isGachaOpen then
local camera = workspace.CurrentCamera
-- Save original camera settings (only first time)
if not originalCameraCFrame then
originalCameraCFrame = camera.CFrame
originalCameraType = camera.CameraType
end
-- Switch to scriptable camera at the background position
camera.CameraType = Enum.CameraType.Scriptable
camera.CFrame = cameraPart.CFrame
end
-- Make the Camera part invisible (just in case)
if cameraPart:IsA("BasePart") then
cameraPart.Transparency = 1
cameraPart.CanCollide = false
end
end
-- Restore original camera (CLIENT-SIDE)
local function RestoreCamera()
local camera = workspace.CurrentCamera
if originalCameraType then
camera.CameraType = originalCameraType
end
-- Reset values
originalCameraCFrame = nil
originalCameraType = nil
-- Remove background model clone
if currentBackgroundClone then
currentBackgroundClone:Destroy()
currentBackgroundClone = nil
end
-- Restore skybox
RestoreSkybox()
end
-- Open gacha (with camera and skybox)
local function OpenGachaUI()
if isGachaOpen then return end
isGachaOpen = true
-- Save current skybox before opening
SaveOriginalSkybox()
-- Show UI
mainFrame.Visible = true
gachaGui.Enabled = true
-- Load background with camera and skybox
LoadBackgroundModel(currentBanner)
end
-- Close gacha (restore camera and skybox)
local function CloseGachaUI()
if not isGachaOpen then return end
isGachaOpen = false
-- Hide UI
mainFrame.Visible = false
gachaGui.Enabled = false
-- Restore everything
RestoreCamera()
end
-- Update stardust display
local function updateCurrencyDisplays()
if playerData then
stardustLabel.Text = "⭐ "..playerData.Stardust
shopStardustLabel.Text = "⭐ "..playerData.Stardust
tokensLabel.Text = playerData.Tokens.." Tokens."
end
end
-- Refresh player data
local function RefreshPlayerData()
playerData = GetPlayerDataRemote:InvokeServer()
updateCurrencyDisplays()
end
-- Update banner display
local function UpdateBannerDisplay()
local bannerData = BannerConfig.Banners[currentBanner]
if bannerDisplay then
bannerDisplay.Image = bannerData.imageId
if bannerDisplay:FindFirstChild("Title") then
bannerDisplay.Title.Text = bannerData.name
end
end
-- Load the background model and switch camera (only if gacha is open)
if isGachaOpen then
LoadBackgroundModel(currentBanner)
end
end
-- Create banner selection buttons
local function CreateBannerButtons()
for bannerName, bannerData in pairs(BannerConfig.Banners) do
local button = Instance.new("TextButton")
button.Size = UDim2.new(0, 150, 0, 40)
button.Text = bannerData.name
button.Parent = bannerButtonsFrame
button.MouseButton1Click:Connect(function()
currentBanner = bannerName
UpdateBannerDisplay()
end)
end
end
-- Show pull results
local function ShowResults(results)
-- Clear previous results
for _, child in ipairs(resultsContainer:GetChildren()) do
if child:IsA("Frame") then
child:Destroy()
end
end
-- Create result cards
for i, result in ipairs(results) do
local card = Instance.new("Frame")
card.Size = UDim2.new(0, 150, 0, 200)
card.BackgroundColor3 = GachaModule.RarityConfig[result.rarity].color
card.Parent = resultsContainer
local nameLabel = Instance.new("TextLabel")
nameLabel.Size = UDim2.new(1, 0, 0, 30)
nameLabel.Position = UDim2.new(0, 0, 0, 0)
nameLabel.Text = result.name
nameLabel.TextScaled = true
nameLabel.Parent = card
local rarityLabel = Instance.new("TextLabel")
rarityLabel.Size = UDim2.new(1, 0, 0, 25)
rarityLabel.Position = UDim2.new(0, 0, 0, 35)
rarityLabel.Text = result.rarity
rarityLabel.TextScaled = true
rarityLabel.Parent = card
if result.isDuplicate then
local dupLabel = Instance.new("TextLabel")
dupLabel.Size = UDim2.new(1, 0, 0, 30)
dupLabel.Position = UDim2.new(0, 0, 1, -30)
dupLabel.Text = "DUPLICATE\n+"..result.stardustGained.." ⭐"
dupLabel.TextScaled = true
dupLabel.TextColor3 = Color3.new(1, 1, 0)
dupLabel.Parent = card
else
local newLabel = Instance.new("TextLabel")
newLabel.Size = UDim2.new(1, 0, 0, 30)
newLabel.Position = UDim2.new(0, 0, 1, -30)
newLabel.Text = "NEW!"
newLabel.TextScaled = true
newLabel.TextColor3 = Color3.new(0, 1, 0)
newLabel.Parent = card
end
-- Animate card appearance
card.BackgroundTransparency = 1
TweenService:Create(card, TweenInfo.new(0.3), {BackgroundTransparency = 0}):Play()
end
resultsFrame.Visible = true
end
-- Handle pulls
local function DoPull(count)
if isPulling then return end
isPulling = true
if pullButton1 then
pullButton1.Text = "Rolling..."
end
if pullButton10 then
pullButton10.Text = "Rolling..."
end
local response = PullRemote:InvokeServer(currentBanner, count)
if response.success then
UpdateCurrencyDisplays() -- Update both currencies from leaderstats
ShowResults(response.results)
else
warn("Pull failed: "..response.message)
-- Show error to player
if pullButton1 then
pullButton1.Text = response.message
wait(2)
end
end
if pullButton1 then
pullButton1.Text = "Pull x1\n(100 Tokens)"
end
if pullButton10 then
pullButton10.Text = "Pull x10\n(900 Tokens)"
end
isPulling = false
end
-- Create shop items
local function PopulateShop()
for _, child in ipairs(shopItemsFrame:GetChildren()) do
if child:IsA("Frame") then
child:Destroy()
end
end
for index, shopItem in ipairs(BannerConfig.StardustShop) do
local itemFrame = Instance.new("Frame")
itemFrame.Size = UDim2.new(0, 200, 0, 100)
itemFrame.BackgroundColor3 = GachaModule.RarityConfig[shopItem.rarity].color
itemFrame.Parent = shopItemsFrame
local nameLabel = Instance.new("TextLabel")
nameLabel.Size = UDim2.new(1, 0, 0.4, 0)
nameLabel.Text = shopItem.name
nameLabel.TextScaled = true
nameLabel.Parent = itemFrame
local buyButton = Instance.new("TextButton")
buyButton.Size = UDim2.new(0.8, 0, 0.4, 0)
buyButton.Position = UDim2.new(0.1, 0, 0.5, 0)
buyButton.Text = "Buy ("..shopItem.cost.." ⭐)"
buyButton.Parent = itemFrame
buyButton.MouseButton1Click:Connect(function()
local response = PurchaseFromShopRemote:InvokeServer(index)
if response.success then
playerData.Stardust = response.newStardustTotal
UpdateStardustDisplay()
-- Could show a success message here
else
warn(response.message)
end
end)
end
end
-- Button connections
pullButton1.MouseButton1Click:Connect(function()
DoPull(1)
end)
pullButton10.MouseButton1Click:Connect(function()
DoPull(10)
end)
shopButton.MouseButton1Click:Connect(function()
if shopFrame then
shopFrame.Visible = true
PopulateShop()
end
end)
shopCloseButton.MouseButton1Click:Connect(function()
if shopFrame then
shopFrame.Visible = false
end
end)
closeButton.MouseButton1Click:Connect(function()
CloseGachaUI() -- Use the new close function that restores camera and skybox
end)
resultsCloseButton.MouseButton1Click:Connect(function()
resultsFrame.Visible = false
end)
-- Initialize
CreateBannerButtons()
RefreshPlayerData()
UpdateBannerDisplay()
if shopFrame then shopFrame.Visible = false end
if resultsFrame then resultsFrame.Visible = false end
-- Keep gacha closed initially
gachaGui.Enabled = false
mainFrame.Visible = false
-- Monitor leaderstats changes for live updates
if player:FindFirstChild("leaderstats") then
if player.leaderstats:FindFirstChild("Tokens") then
player.leaderstats.Tokens.Changed:Connect(function()
UpdateCurrencyDisplays()
end)
end
if player.leaderstats:FindFirstChild("Stardust") then
player.leaderstats.Stardust.Changed:Connect(function()
UpdateCurrencyDisplays()
end)
end
end
-- Monitor GachaGui.Enabled changes
gachaGui:GetPropertyChangedSignal("Enabled"):Connect(function()
if gachaGui.Enabled then
OpenGachaUI()
else
CloseGachaUI()
end
end)
-- Example: Open gacha with G key (optional, remove if you have your own method)
local UserInputService = game:GetService("UserInputService")
UserInputService.InputBegan:Connect(function(input, gameProcessed)
if gameProcessed then return end
if input.KeyCode == Enum.KeyCode.G then
if gachaGui.Enabled then
gachaGui.Enabled = false
else
gachaGui.Enabled = true
end
end
end)
Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category.