📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

Remote Events (One-Way Communication) - Roblox Advanced Scripting #5

BrawlDev32:09

Transcription

Hey, thanks for stopping by. We're going to be creating a bunch of stuff that correlates to server and client communication so that we can create systems that allow us to have more security with our Roblox games and also more robust systems with the things that we decide to create inside of our Roblox games.

And in this episode, I'm going to be introducing two of them, which are called remote events and remote functions. And with them, we're able to create things like this. So I made a text label that says, "Would you like to buy this?" and I have a button down here that we can press called "Buy Button." And this costs 50 coins. And up here, you can see in my leader stats, we have 50 coins to be able to buy this. So let's see what happens when I actually press it.

So essentially, when I press this button, it communicated to the server to check whether I had 50 coins or not. And if it did, then it would subtract 50 coins from my leader stats and it would tell us the message that the purchase has been successful by updating this text label. If we press it again now that we can't afford it, it will check again, but this time we can't afford it. So the server will tell the client that the purchase has failed.

I want you to understand what goes on behind the scenes when we're communicating with the server and client, and why this matters a lot when we're dealing with security and exploitation and all those other sorts of things. But before we start implementing, let me show you something else.

All right, let's think about this for a minute. So if you saw one of my previous episodes, you might find this diagram to be familiar. And yes, this is the server and client model found on the Roblox Developer Hub. That's because in this episode, I feel like this really ties back into what we're going to be doing inside of this episode. So if you remember, the game consists of two sides. You have the server and the client. The server up here is basically the perspective of the game that has access to everything inside of the server and also in the client. But if you're one of these clients attached to the server, also known as the players, so we have Player One down here, and then we have Player Two, and then Player Three, all within their own perspectives of the game, do not have access to whatever information is in the server. The server is the powerhouse of all its valuable information that the client cannot simply access freely.

That's why there has to be communication between the server and the client. Whether that would be from this player, so let's call this Player One, if it wanted to send information to the server, then we will use a remote event to be able to tell the server we wanted to do something, and it'll do it for us. Or if we have information to a specific player from the server, we will go from the server and we will send information to a specific player, let's say Player Two, to tell them that they got a notification or something. Or if we're playing a round-based game, then we will have the server replicate to all the players inside of the game that if this is a round-based game, that the game is over and it's going to reset everything to wait for the next game to happen.

So there's so many use cases where we would have to communicate with the client and the server to get stuff done, to make systems robust, to make it very secure from hackers, because that's one of the main important things we need to know about here. Is that even if it's not for security, there's a lot of things you can't do unless you know how to communicate with the server and client. So that's why it's very important to understand how this stuff works, when to use it, and why you should use them. And I hope this gave you a little more insight as to what we're going to be doing in this episode.

Now that we understand it, let's make some stuff that effectively communicates between the server and client. So first thing we will do is create a leader stats script to give ourselves some coins. So we're going to go to the Server Script Service and we're going to make a script and we're going to rename the script to "leaderstats." I'm not going to write all this out. I'll just like quickly copy and paste the code that I've already had from a previous episode. Yeah, so just to save us a bit of time, I created a player added event where we created a leader stats folder and we created a coins int value with a default value of 50, so that we have some coins to work with. But we're going to basically, but basically what we're going to do first is create a remote event. And how we can communicate from the client to the server, we're basically going to create a button here that says "Give Currency." And when the player presses that button, it's going to send a message to the server to give our player currency. And I mentioned that this is going to be a remote event. So you might ask, where do we create this remote event? For the most part, I would say create it inside of ReplicatedStorage. I'd say this is the best place to access information that we want to know about from the server and also the client. Because as you know, there are specific folders inside of the game that can only be accessed by either the server or the client. For instance, ServerScriptService and ServerStorage, these can only be accessed on the server. But things like StarterGui, StarterPack, StarterPlayer, these things can be accessed on the client. But we want a folder that can be accessed from both the server and the client, which is usually ReplicatedStorage and ReplicatedFirst. But we're going to put it inside of ReplicatedStorage.

So we're going to hit the plus sign and let's insert a remote event. This is what it should look like. And let's rename this remote event to "GiveCurrency." So this is what we're going to use to tell the server that we want to give the player currency whenever we press a button.

Now let's actually create the button. So let's go to StarterGui, hit the plus sign, we're going to create a ScreenGui. We're going to then hit the plus sign here and create a TextButton. So here's our TextButton. Let's just drag this alongside here. So let's change TextScaled to true and we'll name this text "Give Currency." And now let's create a local script inside of the ScreenGui. So we'll make a local script. Let's first make a reference to the ScreenGui, which is going to be local GUI = script.Parent. And then we'll first make a reference to the TextButton, but let's actually rename this TextButton to "GiveCurrency." So local giveButton = GUI.GiveCurrency. And finally, we'll make a reference to our GiveCurrency remote event, which is located inside of ReplicatedStorage. So down here, we're going to say local giveCurrency = game.ReplicatedStorage.GiveCurrency.

So now that we have our references, let's create the MouseButton1Click event when we press the button. So we'll say giveButton.MouseButton1Click:Connect(function() ... end). And then drop a line down here. We want to fire the event so that when we go back to the server, we can catch that event when it's being activated. And the way we activate this event is by saying giveCurrency, which is our remote event, :FireServer(). So when we press the button, we're going to fire this remote event to the server, and we're going to have the server take this function call, which I will show you in a little bit. There are multiple arguments we can put in here, but just for right now, we're going to leave this empty.

So now let's catch this inside of the server. We're going to copy this reference right here. So we're going to highlight this and copy, and we're going to go to our leader stats script. So down here, let's drop two lines and let's just Ctrl+V to paste our copied code. And now what we'll do is we will catch this fired event. We'll say giveCurrency.OnServerEvent:Connect(function(player) ... end). And here's what's really important about this. So whenever we call FireServer, we don't pass anything here, but indirectly, it's automatically going to pass in the player object that called this event. So it's going to be our player in the game that called this event when we pressed the button. So we're going to pass in the player argument, and this is required. You have to have the first argument be the player, and anything after that is basically just going to be whatever arguments we put inside of our function call. But for right now, it's just going to be player.

So now that we understand that, let's locate our coins int value inside of our leader stats. So we're going to say local leaderStats = player.leaderStats. And then we will make reference to the coins. We will say local coins = leaderStats.Coins. Now let's add coins to the int value. So we'll say coins.Value += 50.

All right, so essentially what we've done is that we created a text button that says "Give Currency." When we press it, it's going to send a message to the server, and it's going to catch it onto the server that we want to give the player that called this remote event to give them 50 coins. And I will explain to you why this is important, but let's test this out first. So we're going to go to the game, hit test, and hit play, and see the new button that we just created.

All right, so I've spawned into the game. Our coins by default is 50. But if I press "Give Currency," then it should effectively give 100 coins to the player. So if we keep pressing it, then we should constantly be getting 50 coins every time we press the button. So that should be working as expected.

But now you might ask, why do we need this server and client communication when we're, let's say, giving currency to a player? So in order for me to explain that, let me go back into the game. And like I mentioned with the server and client model, there's, you can go between the server and client window by going to Test and then hitting this button here, by telling you whether you're on the server side or if you're on the client side. Right now, I'm on the server side. But if I press it again, I'm back to the client side. So let's see what our coins value actually looks like when we're on both sides of the game.

So we're going to go to Players, BrawlBattle, LeaderStats, Coins. So as you can see, my coins int value is 50, like expected. Let's see what happens if I change the value in the client. So if I just change this value to 200, then it'll show that my coins have been updated to 200, and my coins int value has also been updated to 200. But what's the problem here? It looks like it's working as expected. If we go into the server side, so if I click our server window and we do the same thing where we go to Players, we go to BrawlBattle, the LeaderStats, and Coins, we can see that our value is still 50, despite us changing the value inside of our local client.

This is why I must reiterate that the communication between the server and client is very important because what you see inside of the client is not going to be replicated to the server for all the other players. It's not going to be the same thing. So if I had a shop system, this actually is not 200 coins, but in reality, the game says that my player has 50 coins instead of 200. That's why when we're updating, or in this case, giving currency, we need to tell the server to give us 50 coins, not the client. That's why we have to do this whole server and client model with creating a remote event, firing the server, and then making the server catch this event to then update our coins value. Because we could have just simply done this inside of our local script, but this wouldn't have actually given the player the coins that we want to give the player. This would have made us think in the client that we would have that we gave ourselves coins, but in reality, the game says we did not do anything. Because this is very easily exploitable for any hacker or exploiter inside of a Roblox game to give themselves a huge ridiculous amount of coins inside of the game so that they can buy everything inside of the game. That's why we rely on the server to do all this for us, not the client. So I hope this gives you a better explanation and a better understanding of why we do these things.

All right, so I mentioned extra parameters being extra arguments or parameters being a thing for remote events, and that's what I'm going to show you really quickly here. So when we have a remote event, it doesn't matter how many arguments we throw into here because we can have as many as we want. This is usually to pass in information to the server using this remote event if we want it to do anything specific. It gives us more power to be able to say exactly what we want to do with arguments that we pass into to this event call. So in this case, we have "GiveCurrency," which gives us 50, which gives us a fixed amount of coins every single time we press the button. But what if we wanted to specify it on the client? We would do that by creating parameters and passing in arguments to our function calls.

So we're going to create another parameter here after player by putting in a comma, and this is going to be the coins amount. And we're going to take this coins amount and we're going to replace it with our fixed 50 currency that's over here. So now what we're going to do is we're going to go to our fire, we're going to go to our local script, and inside of this FireServer, remember that player is implicitly passed into our function call, so we actually don't need to pass in player, but rather we're going to pass in our coins amount. So in this case, it's going to be 50. So what's going to happen here is that when we call FireServer, we're going to pass in our coins amount, and over here, it's going to implicitly pass in the player argument, and then our coins amount. So it's very important to understand that we're not passing in player first. This is actually our second argument, which is our coins amount. But over here, we're going to pass in player first thing, and then all the arguments afterwards that we provided inside of these parameters. So if we go back and test it, it should essentially do the exact same thing. So if you press it, then it should do what we needed to do. So that works out wonders. And like I mentioned, you can have as many arguments as you want, as long as you have this player parameter, you can have as many arguments as you want here. You can pass in as much information, and the script will not complain about it.

So what we just did was we communicated from the client to the server. But now, what if we wanted to do it the other way around? What if we wanted to communicate from the server to the client? Like, for instance, if the player has joined the game, then we will tell the server to send a message to the client to give them like a special greeting through text or something. So that's what we're going to do with this example. This can also be done by using a remote event.

So for this example, we're going to create another remote event. So like I said, it's going to be inside of ReplicatedStorage, because that's the folder I recommend putting all your remote events in. So we'll hit the plus sign and we're going to create another remote event, and we're going to rename this "GreetPlayer." And let's go back to our leader stats script. So in our leader stats script, let's make room for our reference to the GreetPlayer remote event. So we'll say local greetPlayer = game.ReplicatedStorage.GreetPlayer. And so, and now what we'll do is we'll drop two lines after we create the coins leader stat by saying greetPlayer. And you remember how we communicated from the client to the server? So we took the remote event and we called FireServer. But this time, what we're going to do is we're going to do the opposite. We're going to say :FireClient(). So it basically does the opposite of FireServer. It just says FireClient instead. But here, but here's the very important thing. We are required, much like our OnServerEvent, we're required to pass in the specific player we want to send this message to. So in this case, it's going to be our player, which we labeled right here in our player variable. So we're just going to simply pass in player. So this is the basic syntax for our FireClient event. Like, like I mentioned before, you can pass in other parameters if you really want to, but that is totally optional. What is required is specifying which player we're trying to send this message to.

And like with our OnServerEvent, we need to catch this call onto the client instead. So in our local script, we're actually going to copy our GreetPlayer reference and then we're going to paste it down here. And then what we'll do is instead of OnServerEvent, we're going to say OnClientEvent. And it's going to look like this: we're going to say greetPlayer.OnClientEvent:Connect(function() ... end). And we'll hit enter. Now you might notice we're not required to pass in a player argument because we already know which player we're trying to send the message to. So this does require a little bit of practice to understand like the different parameters, what is required, what's not required. But as long as you understand it, I think it'll make sense.

So in this case, let's actually pass in an argument. We're going to create one argument here that's basically going to be the message. So we'll say "message" as our second parameter to our FireClient call. So the first argument is going to be player, and then we'll space it out with a comma, and we're going to pass in a message. We will say "Hello new player." That's going to be our message that we're going to pass into the client. And so it's going to be passed into here. So now what we'll do is we're going to create a text label that we will use to greet the player. So let's click the plus sign and let's add in a text label. And we're going to call this label "Greeting." And let's move this over here. Let's scale this up a little bit and center it down here. Let's autoscale the text with TextScaled. And let's go back to the local script and let's first make reference to our greetings text label by dropping a line. And we'll say local greetingLabel = GUI.Greeting. And now what we'll do here is we're going to say greetingLabel.Text = message.

All right, so now this should work. As soon as we join the game, then this text label should be updated to the message that we specified. So as you can see, the text label has been updated to "Hello new player" because when the player joined the game, we called FireClient to that specific player and we gave it a message. Here, we passed it into here as an argument, and we changed the greeting label's text to whatever the message was. And in this case, the message was "Hello new player."

We could be even more specific by concatenating this message with the player's name. So we will say "Hello new player," but instead of an exclamation point, we will put in a colon, and we will use string concatenation to add in the player's name to create a customized message. And the way combining strings work is by putting in the two dots here, and then we're going to put in player.Name. We're going to get the name of the player and pass it into this string. So it's going to say "Hello new player: " and then the player's name, which in this case it's BrawlBattle. So let's go into the game and hit play again.

So now it says "Hello new player BrawlBattle" because BrawlBattle is my name. So it's going to give out a customized message for each individual player whenever they join the game for the first time.

All right, and the final event we will talk about with remote events is called FireAllClients. And this is useful if we want to go, if we want the server to send a message to every single player inside of the game. So this is very useful for, let's say, round-based Roblox games where it's like if we had a status bar up here that says there's a current game in progress, or we're about to be teleporting all the players to the new map. Like, you kind of get what I mean, right? Murder Mystery 2 and a bunch of other round-based games do this where they have a status label that tells us the status of the current game, and it notifies and it updates for every single player. So that's similar to what we're going to do with FireAllClients. We're going to make a global announcement that will show up for every single player up here.

And we will do that first by creating another text label. So let's duplicate our "Greeting" text label by hitting Ctrl+D, and we will move this up here, all the way at the top, and let's rename this to "Announcement." And let's change the text label to "Global Announcement." And what we'll do is we're going to hide this for now by clicking on, by unchecking Visible. So whenever the server fires to all the clients, we're going to make this announcement label visible.

So now let's create another remote event over here in ReplicatedStorage. So let's just create a remote event. Let's rename this to "Announcement." Or no, actually, let's make it more specific. Let's say "GiveAnnouncement." So now what we'll do is we're going to go to our leader stats and let's make reference to our GiveAnnouncement remote event. So we'll say local giveAnnouncement = game.ReplicatedStorage.GiveAnnouncement. We're going to wait about 20 seconds before a global announcement will be sent to all the players that are inside of the game. So we're going to put in a task.wait() function here with about 20 seconds. And then what we'll do is we're going to fire the GiveAnnouncement remote event to every single client. And it's structured like this: we'll say giveAnnouncement:FireAllClients(). And you might have noticed that we don't need a player argument here because we know that for this, we're going to pass it to every single player in the game. So we don't need to specify which player. But we can still add in more arguments into here, like usual.

So now what we'll do is we're going to catch this down here into our local script. And what's really interesting here is that the syntax is exactly the same for if we're just communicating from the server to one player, because this works the same way if it's being sent to each individual player. So it's essentially the same thing here. Let's first go back to our script, let's copy our announcement and let's paste it down here. And then we will say giveAnnouncement.OnClientEvent:Connect(function() ... end). And then we have no arguments here, so we'll just, we'll just drop to the next line. And then what we'll do is we're going to make our announcement text label visible so that all the players can see this. So what we'll do is we're going to say GUI.Announcement.Visible = true. So this one line will make this announcement text label visible to every single player inside of the game.

So now you might ask, how do we know if this works inside of Studio if we're trying to test out FireAllClients? Because we need to know if this works for at least two players. Roblox has actually provided us a great way to test our Roblox game with multiple players if we need more than one player to test the game. Because what we've been doing is we've just been simulating playing solo inside of a Roblox game. But what if we wanted to create our own server, our own local server to test multiple players at once? We can actually do that with a feature Roblox has provided for us by going over here to Test and there should be a little section here inside of Clients and Servers where we can create a local server with however many players we want. But in this case, we're going to use two players. And essentially what we'll do is we'll press the Start button. And what will happen is that Roblox will give us three windows. One is the server, and the other two are each of the players. So let's hit Start and see what happens.

So what we should see is one window that represents the server, and there's two more windows that are showing up. So one of them is Player One, and the other one is Player Two, because we made a local server to play test as two players. So now that we're in the game, we can see that we have Player Two over here, and we have Player One over here. So this is how we're able to play test a game with multiple players by creating our own server to be able to do that. And as you saw, I don't know if you actually did see it, but around the 22nd mark, the global announcement was sent to all the players. So both of our players at the exact same time. I don't know if you did catch that, you can like rewind it for like about 10 seconds, but it is what happened. The server, after about 20 seconds, has sent the global announcement message to every single player that was inside of the game to tell them to make this text label visible, and we were able to successfully do it at the exact same time. So that's just another very useful function to use whenever you want to send a message to all the players inside of the game.

And so if you want to stop this playtest session with all of these different windows, you can just go to Test and then hit Cleanup to get rid of all of the windows that are on screen. And sometimes it doesn't get rid of all of them, so you just have to manually X out of them, which I don't think should be a problem.

Now you might ask, can't we just get a table full of all the players and just manually use FireClient for every single player? Yes, you can do it that way, but why would you want to put up with the struggles of having to do all that when you can just do it all in one line? I think Roblox has realized that this is a very common use case, which is why they made this into a separate event rather than having you constantly fetch a table full of all the players inside of the game and then just manually putting and just manually using FireClient for every single player. So that's why we could just do it all inside of one line with FireAllClients rather than having to do it individually.

To finish off, let's review what we just learned with remote events. And again, this can be found inside of the Roblox Dev Hub, so I'll leave a link to that in the description if you want to take a closer deep dive into it. There's three ways of communicating from the server and client with remote events. The first one is from the client to the server. And basically, how it works is that we have a local script that uses the FireServer function, and you can pass in whatever arguments you want inside of this. And then the server will catch this call by using the remote event OnServerEvent. And the first argument has to be the player that calls this function, no matter what. It implicitly calls it. And then afterwards, it's whatever arguments you put inside of this FireServer function call.

The second way of communication is the opposite. So it's from the server to the client. And this is basically completely flipped. So from the server, it calls FireClient, and the first argument has to be the player that we're specifically trying to send this call to. And then anything after that is going to be the arguments after the player. And then it's the client's job to use OnClientEvent to take this function call and do whatever it wants to do with the arguments that we provided into here. And like I mentioned, you don't need to have arguments. Arguments are optional, but where it says that we need to pass in players, that is required. And so server to client is basically the opposite of client to server, as expected.

And then finally, we have a special use case, which is server to all the clients. And this is basically the same thing as server to client, except this is for every single client or player inside of the game. So the only thing different here, as you noticed, client here is the same thing as the client here for server and client. The only thing different is the server instead of using FireClient and specifying the player parameter, all we need to do is just say FireAllClients, and we can pass in whatever optional parameters we need. So that's the basic rundown of all three functions that you can use to communicate from the server to the client with one-way communication.

This episode is a bit too long, so that's why I'm going to continue this in the next episode when we talk about remote functions and how we can further expand upon our communication with the server and the client. Because remote events essentially act as a one-way communication from either client to server, server to client, or server to all clients. But in the next episode, we're going to do two-way communication. So it's going to take the extra step to further our knowledge on the server and client field. So that's pretty much going to be it for this episode. Join my Discord, the link is in the description, and I will see you in the next episode. Take care.