Development News

Multiplayer Framework

March 4th, 2024

Hello dear TromboSpace readers,


February was a CRAZY month for development, but I did it. Multiplayer is IN. 


Quick notes to get everyone up to date to this point:


Now let's pick it up from that last point: February is done, and so is multiplayer integration!

Current Project: TromboScripts Library

What is TromboScripts?

As a solo game dev, I need to write lots of code in a hurry. TromboScripts is a generic scripting library that will help me code smarter, faster, and performantly, allowing me to focus less on code and more on game design.


Okay but what's in it for me?

Right now, this project is entirely self-serving. When I get back to making games, it will help me offer you semi-casual co-op action games in a number of my favourite genres.

My netcode was adapted from this GameDev.tv course. I highly recommend their stuff! Their courses go on sale often and for great prices.

The Multiplayer Framework


Here is the now-working feature list:

Have you tried my first game, Gaia Snake? Give it a go!

How it Works


This is all pretty theoretical and you'll either love it, or you won't. Let's see how it goes!


First we'll step back a minute into the big picture. I am building a generic, action game development library. To understand the networking side of things, let me boil down the basic library for you into basically 2 parts: I have created entities, and I have created systems.


A system would be something like "animation," "audio," "movement," or similarly general capabilities of the game. Then, an entity would be something that interacts with those systems: A character, an environment, an obstacle, etc. For networking purposes, let me tell you more about my entities framework.


You can think of my entities framework as a collection of general skeleton templates. At the moment, I have seven templates in total: SessionRoot, Presence, SceneRoot, Actor, Prop, Decor, and FX. Each of these templates is the skeleton for a different type of entity, with slightly different requirements and responsibilities from the other types. For now, let's focus on their similarities.


For each of these generic entity templates, I can quickly add on different modular systems in just about any combination, allowing me to rapidly create game-specific entities. This is "Component Oriented Programming" (COP), and for the code nerds among you, you can think of it as a cousin to "Object Oriented Programming" (OOP). I'll explain my entities with an example of COP to show you how my framework lets me do some very cool, very efficient things with my networking (efficient both in terms of network performance, and in terms of how quickly I can develop new games).

The cast of One Wicked Night, currently on hold.

COP vs. OOP


Let's pretend we want to put a cat into our game, and we want to synchronize it over a network. 


In OOP, we would look at the cat as one object. Then, consider that object's behaviours: it should move, meow, eat, maybe scratch some stuff, listen, look, etc. It can probably react to changes in its environment as well. In OOP, all of this behaviour would go on one massive script that tells us everything that makes a cat a cat. You would probably use some sort of inheritance pattern to say that the cat is an "animal" that listens, looks, eats, moves, etc., and so technically your cat script would only say what a cat can do IN ADDITION to what all animals can do. Then, to network your cat, you would go into your cat script (and your animal script, if applicable) and you would write code to hook your cat into your networking systems.


That's all well and good, but what if your game is about a zoo, with dozens (or maybe hundreds!) of different animals? You now need to write behaviours for all of those animals, and make sure that you write networking code for all of that as well. This makes for a lot of work, and a lot of opportunity for error. Which means a lot of debugging. Which means good luck finishing your zoo, let alone the rest of your game.


In COP, things are different. You don't have a "cat" per se. You don't have a master script with dozens of different behaviours and data containers that define a cat. Instead, each of those behaviours is its own script (called a "component."). And if you're a little loopy like me, you make all of the data containers their own components as well. I refer to my components as "Effectors" (logic scripts) and "Blackboards" (data scripts). Together, effectors and blackboards make a system module. My movement system module has one movement blackboard, and a number of optional effectors: an input effector, a collision rebound effector, an AI navigation effector, or just about any other movement-related behaviour I might need. Then, my movement system module, and any other system modules I want for my "cat," can be dragged onto an empty object that I arbitrarily call "cat."


In this way, a cat is just an assembly of particular behaviour modules: Take an empty object and plug on your movement module, your noise module (using a "meow" audio clip but otherwise using generic code), an eating module, a look module, an animation module (with reference to your collection of cat animations), you get the idea. Now if you want to add hundreds, or even thousands of animals to your game, it's much simpler than OOP: Just drag and drop your modules onto an empty object, until that object can do what you want the new animal to do. You don't write any new code unless you need a new system or behaviour, and after you write it, you now have a new module that can also be applied to any other appropriate animal.

Proc-gen for OWN. Networking this is my end-goal.

What about Networking?


I'm glad you asked!


Using COP, I don't need to write a "network cat." I just need to pop a "network module" onto the cat. In reality, it's slightly more complicated than that: there is no "cat," there are only modules that I have arbitrarily put on some empty object named "cat." So what I really need, is an add-on for my system modules. Do I need to synchronize animation? Write a quick synchronization add-on for the animation module. Do my animals have a health module? I should probably synchronize that: write a health- synchronization add-on.


I call each of these add-on scripts a "NetSync," and I find them incredibly powerful. For example, by writing one netsync for my health system, I have now synchronized every health system for every animal in my game. Not only that, but the script is incredibly simple: It simply watches the server and clients for changes to health data (the health blackboard), then announces those changes to the network for other netsyncs to copy.


This also makes it easy to secure that data and prevent cheating: if a client says they gained HP, they will gain that HP locally on their health system. Then, the netsync will push that change to the server. Normally, the server would publish that new HP data to all clients; however, I can easily add a simple validation check before the server publishes. The server can look at the health change, and decide if that change is legal or not. If it finds the change is illegal for some reason, it simply does not publish the change. No other clients ever learn of the change. Then, the server can push back to the "cheater" and forcibly revert their data. All of this behaviour is handled by one clean netsync script, whose only job is to read, communicate, validate, and then publish or revert data. 

Did you know I have a YouTube channel for Project Zomboid? Check it out!

What's Next for TromboSpace?


With networking in place, it's time to start up my first proper multiplayer game. Although I've built this entire system for my procedurally-generated co-op horror survival game One Wicked Night, I'm going to keep that project on pause. First, I want to make a smaller-scale multiplayer game to really put my new library through its paces.


The prep work for the new game is already complete, and I'm creating its new Unity project file in just a couple minutes. However, I won't be talking about that one until I have some finished stuff to show you. Instead, my next blog will probably look at my entity system in more detail and talk about how I've handled (and optimized) my different entity classes for networking.


So that's it for today! Thanks for reading. Subscribe to my emailing list for big announcements, or join the discord if you want to hear about the little things too. I hope to catch you back here in April for my next dev blog.


See you next time,

Trombo


Stay Tune to TromboSpace

Visit the TromboSpace discord for small news updates and community chats about all sorts of games.

I also keep a mailing list now for blog posts and new releases. Subscribe below: