How Do I Work With Remote Events In Modular OOP?

I’ve been getting into OOP on Roblox lately and have read many tutorials. But there is no one (as far as I can tell) explaining how to properly handle remote events to cross the server-client boundary. I have this basic tool that will be created on the server.

tool = {}
tool.__index = tool

function tool.new(model, name, location)
	local newTool = {}
	setmetatable(newTool, tool)

	newTool.Name = name
	newTool.Model = model
	newTool.Player = {}
	newTool.LocationOnPlayer = location
		
	return newTool
end
return tool

I was looking to make a remote fire from the client when they press ‘E’ and are hovering over the tools model, so does that mean that I should just do this (in a simple example)?

tool = {}
tool.__index = tool

function tool.new(model, name, location)
	local newTool = {}
	setmetatable(newTool, tool)

	newTool.Name = name
	newTool.Model = model
	newTool.Player = {}
	newTool.LocationOnPlayer = location
	remote.OnServerEvent:Connect(function()
		...
	end)

	return newTool
end
return tool

I am also confused about the tool objects on the server vs the client. Do I create two objects, one for the server, and one for the client?

2 Likes

It’s pretty easy once you know how.

First you have to set up like the “Phone line” between the two. I do this in my control script. My object that controls all the core workings of the game. Server side.

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerToClientEvent = Instance.new("RemoteEvent", ReplicatedStorage)
ServerToClientEvent.Name = "ServerToClientEvent"

local ClientToServerEvent = Instance.new("RemoteEvent", ReplicatedStorage)
ClientToServerEvent .Name = "ClientToServerEvent "

So now you have the event in Replicated Storage.

Now you use the phone line.

So a server script like a button will be the object you use to open the gui object of the player. Say a teleport. You stand on it and it triggers code for the player.

The button you stand on has a script and on the touch connect event, you get the player name.

ServerToClientEvent:FireClient(Player, Message1)

That there sends a message to the client, the Player. So you get the player identification and put it into the Player variable. And what ever you want into the Message. Like 1 for portal 1.
The client’s Gui script (localscript) then recives the message:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local ServerToClientEvent = ReplicatedStorage:WaitForChild("ServerToClientEvent")

local ClientToServerEvent = ReplicatedStorage:WaitForChild("ClientToServerEvent")


local function onServerToClientFired(Message1)
	MyMessage = Message1
	--other code here.
end
	

ServerToClientEvent.OnClientEvent:Connect(onServerToClientFired)

Now say there is a button on the gui that is tweened onscreen. You click the button and it will fire the ClientToServerEvent.

ClientToServerEvent:FireServer(Message2)

The server script will then have like:

local function onClientToServerFired(Player, Message2)
	InfoFromPlayer = Message2
	-- insert other code here
end

ClientToServerEvent.OnServerEvent:Connect(onClientToServerFired)

Notice that the server stuff has “OnServerEvent”
And the client stuff has “OnClientEvent”

Notice that the Client auto sends it’s Player ID with the message.
Notice the Server NEEDS the player ID to work out who to send the massage too.

The player doesn’t need to know which player it was sent to so it’s first message is the actual message.

The server needs the player name so that player name is the first message it gets in the event.

It’s pretty easy once you know how.

There are many ways to do it. You can either have each class handle their own connections or have a(n) explicit interface object(s). If each class handles their own communications, the client objects talk to the server object, which may or may not be the exact same class or a subclass with methods / properties specific to the location it is running. The classes that cross the boundary can either inherit communication methods from a base communications class, have a property that is an object they use to communicate, have a connection to use passed into their methods, or use a communicator that exists in the environment like the Roblox instance tree or other globals.

Maybe the “best” way to do it will depend on what game you are making? Often asking ourselves the best way to do something without identifying the use cases leads to overgeneralization and abstractions which are burdonsome and slow.

But in all honesty this is my feeling with OOP, as I’ve posted many times:

4 Likes

That one is a bit tricky. The model will know you are hovering but it won’t know you press E. If it was left click, you could do it all on the server. Just click the model and a click detector registers the click and gets the player name and does all the work.

As for hovering, that’s a bit risky due to lag. So if you say fire the E event, then it takes a second for the server to get the message saying “I pressed E”

If can then check the part and see if you are hovering and then give that tool but if you move to the next tool before the server gets the info, it will see you are hovering over the next tool.

If you have the hovering send a message to the client, then it’s a bit much to have it constantly updating the hover status.

You could use other ways to get the object your are hovering over such as ray tracing but that starts getting a bit crazy.

You can have a Gui pop up when you hover over a tool saying “Press E if you want this tool”

Then you press E and it will do what is in the Gui.

A hover can then send the “OpenDrillGui” message to the client that will then tween out the OpenDrillGui message and set the message2 to “Drill”

Then if you press E, it will fire the “I pressed E” event and send the message2 “Drill” to the server. The server will then do what ever it needs to do.

1 Like

Everything Steve_Speedy advised is great. There are many ways to handle server events. However, I just wanted to explain the hovering thing a bit more for OP.

There are some strategies you can use to actually avoid constant updating and thereby keep server traffic pretty low. Here is one that I thought of that (hopefully) works as intended.

The idea is that you use a “state” system. Once a player hovers some object, you send one event to the server saying that this object is currently being hovered. You can store this data as a bool and maybe some object reference (not sure how you are referencing but whatever system you use should still be able to record it). When the player stops hovering, you send an event to tell the server it is no longer being hovered. This is a lot more efficient than constantly updating the server.

Obviously this is exploitable but really, any input from client-side can be feigned. Always need the server-side checks when you use remote events. Just because they are done on the server doesn’t mean they are fool-proof.

As an aside, I got this idea from chemistry - it’s easier to work with state-dependent systems rather than time-evolving systems. Keep that in mind when you program, computer science is based heavily (not exclusively though) on states.

I think that the state idea is great, but how exactly would I server-side check this? Comparing the positions of the player and model?

The GUI was already planned, and I realize it is tricky. But ,I think it’d be better to stick to one event in this case; However possible.

You can use a ray to identify the base part then.

So the ray will get the part that you are hovering over when you press E.

So E makes like a bullet and shoots the part and says “I hit this part!”

You then use 1 single ClientToServer event and say “I pressed ‘E’ and got this ‘Part’!”

The server will then just work out what tool the part belongs to and do the necessary code.

https://developer.roblox.com/en-us/api-reference/datatype/Ray

ReplicatedStorage:WaitForChild("ServerToClientEvent")

Reminder that you do not have to wait for objects in ReplicatedStorage at game startup. They’re guaranteed to be there before any scripts (with the obvious exception of those in ReplicatedFirst) start running.

4 Likes

Well, assuming that the item being hovered requires some sort of special access, you may need to verify that the player is even allowed to hover it in the first place. If you don’t have this kind of requirement, you don’t really need a check.

But if you do need a check of this sort, just check if the player is actually allowed to hover the object, is in the right place to be able to hover (positions, like you said), and is not doing anything else that might disable the hover (like hovering more than one thing at a time). The last point is really just to prevent exploiters from firing multiple hovers for different objects, i.e. turning all the states on, when only one should be on at a time, or anything else that may interfere with mouse hovering.

Hope this helps