Yes it is … however I’ve never tried to pull data like this from the server side.
FireClient: player argument must be a Player object. Why does it say my argument has to be a player?
That is why I used a table I’d rather make a database for it than using leaderstats. I know it is a lot more complicated but that’s the goal too in a way.
I understand and i get why … I just don’t know how to help you with this. Any call to fire server only goes one way. Clearly this is something I just don’t know yet. Good luck.
And I can’t use the event that goes both ways either because then they would have access I know that it’s really sad : (. I’m pretty sure it is not recommended at all either.
StarterGui is cloned to the PlayerGui whenever a players Character loads.
Using StarterGui to get button clicks and whatnot wont work.
Not to mention, but i dont think the server can get button clicks from PlayerGui either.
Im pretty sure the Player argument isnt passed through when a button is clicked, if it does, roblox has changed something since last time i tried.
Why dont you, instead of using a remove event to update the ui, you instead use
-- This will only work if the player has access to the cash value.
-- Its 100% fine if the cash value is parented to the player, as long as you have server checks to verify the players amount of cash.
local function CashUpdate()
player.PlayerGui.StatGUI.Frame.CashAmount.Text = CashValue.Value..' Cash'
end
CashValue:GetPropertyChangedSignal("Value"):Connect(CashUpdate)
Server sided checks.
Cheaters can only modify the client side of things, so if a cheater sets their money to 1,000,000,000, only they will see that change.
So, using a server-sided script, you can then verify the players money.
- Client script
-- Do not EVER only have client-sided checks for this kind of stuff
if Player.Cash.Value > 1000 then
print('My money is higher than 1 thousand')
ThousandMoneyEvent:FireServer()
end
- Server Script
ThousandMoneyEvent.OnServerEvent:Connect(function(Player)
if Player.Cash.Value > 1000 then
print('Server can verify, this player has over 1 thousand money')
else
print('Player has modified their values client-side')
Player:Kick('Modified money values')
end
end
So, after writing all that, you want the money to ONLY be server sided?
Thats pointless, because well, server-sided checks for the money.
If youre doing that to stop cheaters modifying their values, dont bother. Just change your scripts to use folders, like leaderstats. Youre only making it harder for yourself by attempting to use this almost pointless fully server-sided system.
Anyway, in conclusion, the problem you are having is that the player argument probably isnt sent through when a ui button is clicked, so youre attempting to send a remote event to a nil value, which results in your error.
Do you know of a way I could get the player sent through anyways? You also are not the first one to say this is way harder than it should be and I know that. I just want to make it hard on myself because I could of finished this hours ago :p. It’s better practice for me in the end only reason I am doing this.
Well, you could maybe use a for i, v in pairs
loop to get the players.
I say maybe, because its a really stupid idea.
Every time a player joins, you loop through all players
game.Players.PlayerAdded:Connect(function(Player)
for i, v in pairs(game.Players:GetPlayers()) do
end
end
You then wait until their ui is found, and then wait until the button exists, then you detect when the button is clicked, and then use v
as the player argument.
game.Players.PlayerAdded:Connect(function(Player)
for i, v in pairs(game.Players:GetPlayers()) do
repeat task.wait(1/60) until v:FindFirstChild('PlayerGui'):FindFirstChild('ScreenGuiNameHere'):FindFirstChild('ButtonNameHere')
v.PlayerGui.ScreenGuiNameHere.ButtonNameHere.MouseButton1Click:Connect(function()
event:FireClient(v)
end
end
end
Yeah, that’s not very optimal. It is not better than having people cheat.
So then my other question is what would be the best way to do it with as little access on the client as possible? (what should I use and where no need to make a code for it I will read the documentation for the specific topics).
I would say to just use folders parented to the player, and always have server-sided checks.
Say, youre buying an upgrade, make sure both client and server have checks for the players money.
If you click a ui button to get money, and said button has a cooldown, when the server gets the event to add money, make sure that the player isnt clicking the button too fast.
Adding a limit like that is easy, you have a table that players get added to and removed from when they join/leave.
Whenever the server gets an event, it does some simple math:
local Cooldown = 2 -- 2 second cooldown
local Players_table = {}
-- adding a player
Players_table[Player.Name] = tick()
-- Checking the time difference
local TimeToEvent = (tick() - Players_table[Player.Name])
Players_table[Player.Name] = tick()
if TimeToEvent >= Cooldown then
print('Valid Click')
else
print('Invalid Click, too fast')
end
I love you thanks for the help you’re a mad lad <3
Assuming that you are basically trying to increment a value on the server when the player clicks a TextButton/ImageButton, the general logic should be something along the lines of: track the value on the client and the server, when the player clicks the button, increment the value on the client, then send a request to the server. The server should track whatever value it is for each player and increment its own corresponding version for whichever player sent the request.
It looks like this is for tracking a currency though, so in your case, it’d probably make more sense to use just the server as the source of truth for Cash instead of incrementing them individually. If this is a leaderboard thing, you can use a NumberValue corresponding with Cash to communicate that.
It also looks like you’re trying to make changes to the player’s gui from the server, which is doable, but it introduces a lot of unnecessary complexity in the long-run. It also means that your UI is going to update pretty slowly in comparison, which is frustrating for players. It’s not working for you because you’re trying to access the StarterGui instead of the appropriate player’s unique PlayerGui. Either way, you should pretty much always be handling UI stuff on the client instead.
That being said, here’s a version of your code that is handled entirely on the server:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PlayersList = {}
local function init(Player)
local Data = {
Cash = 0,
Increase = 1,
}
PlayersList[Player] = Data
local Gui = Player.PlayerGui:WaitForChild("ScreenGui")
local TextButton = Gui.CashButton
local TextLabel = Gui.CashAmount
TextButton.MouseButton1Click:Connect(function()
Data.Cash += Data.Increase
TextLabel.Text = Data.Cash .. " Cash"
end)
end
for _, Player in Players:GetPlayers() do
init(Player)
end
game.Players.PlayerAdded:Connect(function(Player)
init(Player)
end)
game.Players.PlayerRemoving:Connect(function(Player)
PlayersList[Player] = nil
end)
And, alternatively, here’s a simple version of what I described:
Server
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CashUpdater = ReplicatedStorage:WaitForChild("CashUpdater")
local PlayersList = {}
local function init(Player)
local Data = {
Cash = 0,
Increase = 1
}
PlayersList[Player] = Data
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
local Cash = Instance.new("NumberValue")
Cash.Name = "Cash"
Cash.Value = 0
Cash.Parent = leaderstats
leaderstats.Parent = Player
end
local function addCash(Player)
local Data = PlayersList[Player]
Data.Cash += Data.Increase
local leaderstats = Player:FindFirstChild("leaderstats")
local CashValue = leaderstats:FindFirstChild("Cash")
CashValue.Value = Data.Cash
end
for _, Player in Players:GetPlayers() do
init(Player)
end
game.Players.PlayerAdded:Connect(function(Player)
init(Player)
end)
game.Players.PlayerRemoving:Connect(function(Player)
PlayersList[Player] = nil
end)
CashUpdater.OnServerEvent:Connect(function(Player)
addCash(Player)
end)
Client
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local CashUpdater = ReplicatedStorage:WaitForChild("CashUpdater")
local Player = Players.LocalPlayer
local Button = script.CashButton
local TextLabel = script.CashAmount
local CashValue = Player:WaitForChild("leaderstats"):WaitForChild("Cash")
Button.MouseButton1Click:Connect(function()
CashUpdater:FireServer()
end)
CashValue:GetPropertyChangedSignal("Value"):Connect(function()
Button.Text = CashValue.Value .. " Cash"
end)
Thank you! I appreciate the time you took to make this <3
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.