there is 1 ServerScript in the game, which is the one I posted in the beginning.
Add another script and just put a print(âThis script is runningâ)
that works ofc. you understand that the serverscript is working right?
Then whats wrong with your giving data to multiple player script. When a player is added, that plr
becomes the player that was added
Yes⌠but as I said the LocalScripts trigger on both players for some reason.
Hey there, I would be glad to help, but it appears that the issue you are having does not originate from the code snippet you have provided, but rather the part of the game that modifies these values.
You mention that the players can play on behalf of the player that joined first?
Could you show us the code that does this?
Show your local scripts FULLY
This is the first type. I duplicated and edited it (yes I know that the variables should be x,y,z so I can edit the duplicates faster/easier)
grass = script.Parent.Parent:WaitForChild("vals").Grass
local soul = script.Parent.Parent:WaitForChild("leaderstats").Soul
local dirtBtn = game.Workspace.dirtButton
local soulGui = game.Players.LocalPlayer.PlayerGui:WaitForChild("currency").currencyHolder.Soul.amount
local dirt = script.Parent.Parent:WaitForChild("vals").Dirt
local dirtGui = game.Players.LocalPlayer.PlayerGui:WaitForChild("currency").currencyHolder.Dirt.amount
local holder = dirtBtn.GUI.text
local holder2 = dirtBtn.GUI2.text
local req1 = script.Parent.Parent:WaitForChild("reqs").req1
local giv1 = script.Parent.Parent:WaitForChild("givs").giv1
local sfx = game.SoundService.buttonSound
req1.Value = 5
giv1.Value = 1 * (grass.Value+1)
holder.Text = "Cost: "..req1.Value.." Soul"
holder2.Text = "Gives: "..giv1.Value.." Dirt"
local ready = true
dirtBtn.Touched:Connect(function()
if soul.Value >= req1.Value then
sfx:Play()
soul.Value -= req1.Value
giv1.Value = 1 * (grass.Value+1)
dirt.Value += giv1.Value
req1.Value = 5 + (dirt.Value * 2)
if ready == true then
ready = false
ready = true
wait(0.3)
end
end
end)
This is the second type
local x = script.Parent.Parent:WaitForChild("givs").giv1
local abbreviations = {
"K", -- 4 digits
"M", -- 7 digits
"B", -- 10 digits
"T", -- 13 digits
"QD", -- 16 digits
"QT", -- 19 digits
"SXT", -- 22 digits
"SEPT", -- 25 digits
"OCT", -- 28 digits
"NON", -- 31 digits
"DEA", -- 34 digits
"DEB", -- 37 digits
"DEC", -- 40 digits
}
local function Abbreviate(x, decimals)
local x = script.Parent.Parent:WaitForChild("givs").giv1
if decimals == nil then decimals = 0 end
local visible = nil
local suffix = nil
if x.Value < 1000 then
visible = x.Value * math.pow(10, decimals)
suffix = ""
else
local digits = math.floor(math.log10(x.Value)) + 1
local index = math.min(#abbreviations, math.floor((digits - 1) / 3))
visible = x.Value / math.pow(10, index * 3 - decimals)
suffix = abbreviations[index] .. "+"
end
local front = visible / math.pow(10, decimals)
local back = visible % math.pow(10, decimals)
if decimals > 0 then
return string.format("%i.%0." .. tostring(decimals) .. "i%s", front, back, suffix)
else
return string.format("%i%s", front, suffix)
end
end
x.Changed:Connect(function()
local holder = game.Workspace.dirtButton.GUI2.text
if x.Value > 1000 then
holder.Text = "Gives: "..Abbreviate(69420, 1).." Dirt"
else
holder.Text = "Gives: "..x.Value.." Dirt"
end
end)
The third, fourth and fifth script types seems to work (music and colour changes locally)
local soul = script.Parent.Parent:WaitForChild("leaderstats").Soul
local dirt = script.Parent.Parent:WaitForChild("vals").Dirt
local req1 = script.Parent.Parent:WaitForChild("reqs").req1
local dirtBtn = game.Workspace.dirtButton
local holder = dirtBtn.GUI.text
soul.Changed:Connect(function()
if soul.Value >= req1.Value then
dirtBtn.Color = Color3.fromRGB(255, 134, 21)
dirtBtn.Transparency = 0.3
holder.TextColor3 = Color3.fromRGB(38, 255, 0)
else
holder.TextColor3 = Color3.fromRGB(255, 0, 0)
dirtBtn.Color = Color3.fromRGB(106, 57, 9)
dirtBtn.Transparency = 0
end
end)
local onGui = script.Parent.Parent.PlayerGui:WaitForChild("sound").musicHolder.on
local offGui = script.Parent.Parent.PlayerGui:WaitForChild("sound").musicHolder.off
local hitbox = script.Parent.Parent.PlayerGui:WaitForChild("sound").musicHolder.TextButton
local song1 = game.SoundService.song1
local song2 = game.SoundService.song2
local song3 = game.SoundService.song3
local song4 = game.SoundService.song4
hitbox.Activated:Connect(function()
if onGui.Visible == true then
onGui.Visible = false
offGui.Visible = true
song1.Volume = 0
song2.Volume = 0
song3.Volume = 0
song4.Volume = 0
else
offGui.Visible = false
onGui.Visible = true
song1.Volume = 0.55
song2.Volume = 0.4
song3.Volume = 0.5
song4.Volume = 0.5
end
end)
local song1 = game.SoundService.song1
local song2 = game.SoundService.song2
local song3 = game.SoundService.song3
local song4 = game.SoundService.song4
while true do
song1:Play()
wait(301.583)
song2:Play()
wait(143.666)
song3:Play()
wait(30.377)
song4:Play()
wait(165.041)
end```
Alright, I seem to understand what the issue is. Since these are all local scripts, they run once individually on all clients, however, on your event connections, such as dirtBtn.Touched:Connect(function()
in the first script, you donât check to make sure that the person who touched the part is the local player, this means that each playerâs button is pressed, whenever anyone steps on the button, regardless of who it was.
This isnât really a hard fix, but I strongly recommend you rework this entire system. When you change variables on the client like this, not only does it not replicate across the server, so other players cannot see the change that are made to your progress, but it may also pose a security risk later in development, as exploiters will be able to cheat through the entire game.
What you can do instead, is create the variables on the server like you do in the original script your provided in this thread, then also on the server, connect the events as you already are.
The thing about events is that they can pass variables, the .Touched
event that you are using also passes variables. This specific event passes the part that has touched whatever you bind the event to, in this case the button, so if a player steps on the button, you can expect the passed variables to be the playerâs leg. This means that you can do something like this:
local sfx = game.SoundService.buttonSound
local dirtBtn = game.Workspace.dirtButton
dirtBtn.Touched:Connect(function(Part)
local Player = game.Players:GetPlayerFromCharacter(Part.Parent) -- Here you find the player object from the character, as you know that any part of the player's character will be a direct child of the character model.
if Player then
-- Here you wanna check if the player actually exists before continuing
-- This is incase a part that isn't a player touches the button
-- You would then proceed to adjust all the variables you want here.
-- Keep in mind that since this is on the server, you have to find the location of the values in here, so that you ensure you always find the values specific to the player that hit the button.
-- Since you have the player object, this can be done by doing something like:
local soul = Player:WaitForChild("leaderstats").Soul
local req1 = Player:WaitForChild("reqs").req1
local giv1 = Player:WaitForChild("givs").giv1
local dirt = Player:WaitForChild("vals").Dirt
if soul.Value >= req1.Value then
sfx:Play()
soul.Value -= req1.Value
giv1.Value = 1 * (grass.Value+1)
dirt.Value += giv1.Value
req1.Value = 5 + (dirt.Value * 2)
if ready == true then
ready = false
task.wait(0.3) -- I recommend you in general use task.wait() instead of wait() as it is more accurate
ready = true
end
end
end
end)
It looks to me like you are taking on a project a bit too hard for your current level. I recommend you experiment around a bit more, since it looks like you have a bit to go, although you are not far off from being able to make a great game.
I hope this helps.
This whole game is for practice (so I donât mind if itâs unplayble in the end).
But the things I wanted to do were: Datastore, RemoteEvents, functioning general system.
Unfortunately reworking the system seems like a lot of work (for me), but on the other hand if I went ahead and made RemoteEvents / datastore in the current system, it probably wonât be the same methods as if I did it on the reworked (and better) system.
What do you think: Should I rework it, or do RemoteEvents/Datastore instantly?
If you do RemoteEvents and Datastore now, there are 2 possible outcomes.
- The game doesnât work
- The game is so exploitable that exploiters have full control over their own stats
Neither of these are desirable, so I strongly recommend you rework it now.
Thank you for the help. Should I message you about potential problems with creating the new system? Considering you would have better context.
Feel free to message me if you need help, although I canât promise I will answer immediately.
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.