Help with my Custom Networking Module for reliable client/server communication

Hi there,

I am currently working on a custom networking system for my game and I need help implementing such a feature.

  1. What do you want to achieve?

I want to create a networking system that eliminates the need for remote events/functions stored in replicated storage. Scripts on both the client and server should be able to both listen to events and also fire events with given arguments and a unique event name. This system should be reliable, such that when a script on the client or server fires an event, the respective listener for it will always receive this signal and process it – which is essential as the server may load before the client or vice versa. So essentially, this proposed system will behave exactly like the common practice of storing remotes in replicated storage, and connecting to and firing these in any scripts, but instead eliminating the need for storing all these remotes in replicated storage objects though using bindable events/functions in this custom networking module.

Let me show you a code example of the whole system: let’s say the server wants to send the client their inventory data and the client will process this and display the players inventory on the screen via a GUI.


-- Server script

local CustomNetworking = require(...)

-- in a game player added event

-- first argument is the event identifier, next the relevant player and the rest is just the arguments for handling the event

CustomNetworking:FireClient('DisplayInventory', player, inventoryData)


-- Client script

local CustomNetworking = require(...)

-- in some sort of constructor

CustomNetworking:Connect('DisplayInventory', function(inventoryData)

-- display the data on gui

end)

With this networking module, the event called from the server should always be received by the client, even if the client has not yet loaded in – such logic I am not sure how to implement. And importantly, I do not need to create a remote event for this as the module will handle these events via bindable events.

  1. What is the issue?
  • The issue, which I just briefly mentioned, is that i’m not sure how to ensure that the events fired or invoked by the client and server will always be processed by the respective script. This is an issue as i know that either the server or client can load in before each other is ready, and so scripts may execute in the wrong order. I need to make sure that if a script uses the module to connect to an event specifier, then any events triggered by other scripts will be processed even if that event specific connection was created after the event was fired.

  • The other main issue is handling remote functions that cannot be processed straight away. This issue is explained in the solution where I tried implementing event buffers which is in the following section, as this is where the issue arises.

  1. What solutions have you tried so far?
  • I know that I can just have a script which contains all the event connections and the scripts that they should use, and then the networking module can just call these connections directly when an event is fired, but I would rather that these connections are not hardcoded in a single file, and instead any script can connect to any event.

  • I have tried using event buffers which hold events and their arguments if the event specifier was not found in the existing ones (a script has not connected to the event yet), and then when the matching event connection is created, it also immediately executes all the ones stored in the buffer for it – this same logic would be implemented on the server side too. However, a problem I found was with remote functions, where if a remote function was added to the buffer, there is no way to return the result back to the original place it was called once the connection is created and the event can be processed. For instance:


-- Client script

local CustomNetworking = require(...)

-- Assume that 'TestingEvent' has not been connected on the server side

local result = CustomNetworking:InvokeServer('TestingEvent')

print(result) -- nil as the module just put the event in the buffer and nothing was returned


-- Custom networking module

function CustomeNetworking:InvokeServer(action, ...)

if self._ServerInitialized then return self._RemoteFunction:InvokeServer(action, ...)

else table.insert(self._ServerOutboundFunctionQueue, {action, ...}) end

end

  • I have also tried implementing a sort of RTS system where a handshake should occur between the client and the server so that once all event connections are made, the client and the server can start firing events and also one’s stored in buffers from before the handshake was made. But this proved difficult as I was not sure what to do in the case that the server or client never gets this signal, meaning the handshake can never occur.

Summary:

Sorry if this post is a bit long-winded or confusing, I found it really hard to explain exactly what the problem was and what I wanted help with. Please let me know if any of the things I have mentioned are not needed or can be changed. Also, If you can help me with this system then please do comment.

Just to let you know I am not asking you to create this whole system for me from scratch, just some guidance and code snippets would be greatly appreciated :slight_smile:

I’m not sure why you won’t use some ready networking library for this, they do the same and have insane traffic optimization.

If you want to make sure that client or server recieves and processes the event, you can use RemoteFunctions, but I feel like its a waste of traffic. The easiest way is to make a boolean variable for each player that client would ask to set true once it fully loads.

Yeah maybe I should just use some networking library, although im not sure which one to use. I just thought that implementing such a networking system should be simple enough and using third party software should not be needed. I remeber trying to use bridge net, but i dont think you can listen to events in other scripts if i remeber correctly.

Not sure what you mean by that, bridge net worked perfectly for me, however it’s kinda outdated and shouldn’t really be used for new projects.

I would recommend taking a look at (my personal top to bottom):

  • Warp - A gem for me, works perfectly and basically identical to vanilla remote events also being faster than most alternatives
  • BridgeNet2 - In my experience it’s not really comfortable to use, but it works great.
  • ByteNet, Zap - The most efficient networking libraries yet being pretty hard to install and use, they should only be used for high traffic usage cases, for example drawing games.

Okay thank you very much, I have not heard of warp but I will try it out. Am I able to use warp with trove or other modules like it?

Never heard about trove. After looking at it’s documentation, I don’t think they would be compatible unless you make your own class for connections. Warp returns a string that is used in disconnect function instead of an object.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.