Notes on ROBLOX Networking and OO Design
On March 4th, I decided it was time to refactor some code in my game. Today, March 30th, I am still at it. A bit of background: the game I am creating is a building game, where you build boats. I have been developing the interactive components for this game. The idea was that I would start writing unit tests on my code to make production faster. Hah. That’s a good one.
Now, about a month later, I am still refactoring my code. Perhaps restructure is the better word, because I have cut around 4,000 lines of code. I also changed the internal structure quite a bit. This is not everything I have accomplished, but I think I cover some of the most interesting design changes.
The pitfall you should avoid when writing code is writing code for both the server and the client. When I had found myself copying and pasting more than I was writing new code, I knew it was time to change things. Of course there’s behavior that only has to happen on the server, but for the most part, a split model is going to end up biting.
This reduced the amount of boilerplate code to add new interactive components. Part of this process was switching from the use of ROBLOX value objects to RemoteEvents and RemoteFunctions. Why? Most convincing was the response of a ROBLOX engineer. I asked him if a CFrameValue or a RemoteEvent was better for the platform. The response was enlightening.
From this research, I can tell you a few interesting insights into ROBLOX’s networking.
First of all, I learned ROBLOX events and functions requests are grouped into packets. I have heard reports that using more than one remote event can be expensive. In search of knowledge, I did what any reasonable ROBLOX developer would do. I asked Arseny Kapoulkin, an engineer at ROBLOX, and he told me that there is minimal overhead from using seperate RemoteEvents to send data. The extra cost comes from sending the global ID of the remote event.
I did some tests, and so far I have yet to see any random disconnects or issues. Using many remote events to replicate has been quite successful. More importantly, my game did not jump around with a foolish grin maniacally disconnecting clients.
I have consolidated my API for the boats. The modeling part comes from an encapsulation of the ROBLOX classes in a “Component.” A subclass of these components is a “HookedComponent” which I designed to make interaction extension easy. Most of these hooks respond to input and change their state, and then trigger other hooks. This represents the behavior I want in my games, where the player does one thing and the world reacts to their action.
An important part of my API design revolves around two key concepts I have learned recently. The first is that the object-graph construction and the logic should be separated. This allowed me to stop differentiating between the server and client model in most cases. The second part was dependency injection. From this concept I have been able to decouple elements a lot more to make my code hypothetically easier to test. It is easier to maintain.
I would not say I wasted my time refactoring. I have learned more than I would have ever expected. Furthermore, my code is easier to change. Still, I have found myself an entire month behind my schedule. It’s Coming Soon™.
In the future, I will always be refactoring, and designing classes that do not instantiate new objects in them. In the end though, I think it is important to always remember that there is more to learn. As long as I am learning from what I am doing, it is all good.