MMORPG Devlog 2: Networked Player Movement

This post is part of my MMORPG Devlog series.

It’s been a few months since my last entry, as expected. School and some medical things kept me busy for most of that time, but I finally got to work on the game a bit while isolating for the start of the new semester, and have kept at it since. Most of this round of progress happened over a three week span, and I’ll probably keep picking at it until homework levels ramp up again.

The big thing this time is synchronizing player positions and rotations over the network. It’s finally working, so I’m going to go over the major steps in getting this crucial feature up and running.

Sending Client Movement

The first order of business was picking up where I had left off: I had a working player controller, and the server could successfully instruct the client to load a zone and spawn the player prefab. So, the next step was taking the player’s movement and sending it to the server in a stream of packets.

The general plan, as I mentioned in my previous entry, is a fairly simplistic model along the lines of what you see in Minecraft or World of Warcraft. (My past experience making Bukkit plugins for Minecraft probably had an influence on my design decisions, as well as the simplicity.)

  • The client sends a packet, n times per second, containing the new position and rotation

  • The server checks the Euclidean distance between the last location and the new one. If it’s further than expected, it refuses to update the position and sends the client a reset packet that “rubber bands” the player back to the last known good position. Otherwise, the Player model’s position and rotation properties are updated.

  • If the player is stationary, the client only sends the packet once per second.

I’ve tweaked the send rate a little while working on this. Currently, I’ve settled on 5Hz, which seems sufficient for an RPG type game. It’s also fairly easy to adjust later, if necessary.

Eventually, I’ll probably add some additional anti-cheating checks…like ensuring the client doesn’t fudge the vertical component of the position in order to fly.

Broadcasting Positions to All Clients

Now that the server knows where everyone is, it needs to tell the clients.

In Untitled MMO Project, the server considers Players to be children of the Zone they are in. The overall design makes it easy enough to get the Player (or its network client object) from anywhere, but the Player’s Update() method is called from within the Zone’s Update(). This seemed like a sensible design, because it means we get some nice features for free: any player state packets, such as movement, are conveniently isolated to the only place they are relevant. If a player is AFK in a tavern on one side of the world, they don’t need to know what another player is doing in the mines somewhere else. It also means we have a convenient list of everyone in the same locale, which we probably need more often than a list of every player connected to the server.

public void Update() {
    if (Players.Count > 0) {

The actual broadcast method simply iterates all clients in the zone, then sends a packet to each for every other player in the zone. It also does a check to get which server tick we’re on, out of each second, and returns early if it’s not on the list of ones that we want to send packets on. (The goal is 5Hz, not on every single tick.)

Later on, I came back to this and added some additional bandwidth-saving:

  • If a player is stationary, its position will only be broadcast once per second. (To match the client behavior.)

  • If a player is further than a certain (configurable) distance from the client being notified, the position will only be sent once per second. So, the client is notified of movement changes at the full rate when players are nearby, but if they’re far away, fewer packets will be sent. The resolution of the movement is less important at a distance, and it saves a bit of bandwidth.

Spawning Remote Characters

Now our client can tell the server where it is and is kept up to date on where other clients are. The next step is to actually spawn player prefabs in for the other players, and update their position as packets come in. Then we can finally see the whole thing in action.

On the server side, it’s a simple matter of hooking another packet-launching method in where players enter the zone. When a player spawns, all the other clients are notified with a packet indicating that a new player has arrived, with identification and state. The client is where things get more involved.

First, I needed a Unity prefab for the character. I copied my LocalPlayer one, which uses a stock model and animations from Adobe Mixamo, and tweaked it a little before naming it RemotePlayer. The components for turning user input into movement were removed, among other things, and I added a floating TextMesh to be the name plate.

Now I can spawn it programmatically:

var path = "Player/RemotePlayerPrefab";
var obj = Instantiate(Resources.Load<GameObject>(path), loc, rot);

One weird quirk of Unity’s asset management is that you can only use the Instantiate() function on assets that are inside a Resources directory. It won’t work on any others. This has something to do with the way Unity only includes assets that are physically present within a scene, to keep disk usage under control. If an asset is under Resources, it will be included regardless of being present in a scene.

With the object dynamically instantiated, I then set the TextMesh’s value. I also put a reference to the GameObject into a list in a class that deals with scene state. That way, whenever I need to iterate players and update them, I can just hit that list instead of having to traverse scene transforms…which I’m sure is much slower, as well as less convenient.

Bonus: the player’s nameplate really needs to face the camera at all times. Have you ever played a game where you have to walk in a circle around a player to see their name? That would be silly. Fortunately, it’s a simple matter of copying the camera’s rotation to the transform of the TextMesh.

// Make the nameplate face the camera
NamePlate.transform.rotation = Cam.transform.rotation;

This could also be used for a DOOM-style game, where the characters are 2D sprites in a 3D world. You’d just put the flat images onto plane objects, and keep their rotation synchronized with the camera orientation.

With all that done, we’re now at a place where you can connect a second client and see it walk around.

Smoothing Out the Movement

As things stand, we have achieved networked player movement. Unfortunately, the players are just teleporting from place to place as the packets come in. At five packets per second, it’s very noticeable. And with some lag, it gets even worse.

That’s where our friend Linear Interpolation (Lerp) comes in. Getting this right was one of the most time-consuming parts of this batch of work. In principle, we want to take our current position and target position, and smoothly slide from one to the other, over a duration that is roughly in line with the time between the packets. This creates the illusion of continuous movement, and fails somewhat gracefully when the time between successfully delivered packets isn’t optimal.

Initially, I was over-engineering things. I had a queue for the packets and had tried a whole mess of different ways to calculate the t value. Eventually, I came to a much simpler solution that works without all of the mess: store the latest packet and the time (frame count) it was received, as well as the pair from the prior packet.

float duration = thisPacketTime - lastPacketTime;
float t = Mathf.Clamp01((Time.frameCount - packetTime) / duration);
Vector3 pos = Vector3.Lerp(prevPosition, targetPosition, t);

It seems to work nicely so far. With the animations turned on through a couple of calls to the Animator component, it all comes together.

Note that the motion may look a bit choppy due to this being a GIF.

URL Shorteners Set Ad Tracking Cookies

Exploring How Computers Work

Brutalist Web Design

MMORPG Devlog 1: Building an MMORPG in Unity Because I Can

I’ve been fascinated by the idea of developing games since I first started teaching myself to program around the age of ten. Of course, way back in the early 2000s, we didn’t have the wealth of freely-available game engines with fancy rapid prototyping. Big names like Unreal or idtech3 cost a lot of money, and you were almost certainly going to have to be familiar with C++ to hack even simple things together. That’s a tall order for a kid, especially when you’re more familiar with the likes of PHP and JavaScript (yuck). So I didn’t really get into game development back then (though I have played around a little with Unity in recent years), but I did read about the topic quite a bit.

One thing stuck with me, as I read forums or the limited books that I could get my hands on through interlibrary loans: everyone always laid on thick that MMORPGs, which were the hottest genre at the time, were “too complicated” for the hobbyist. Obviously, that wasn’t something you wanted to hear when you were spending too many hours playing RuneScape and frequently read about EverQuest and World of Warcraft.

They did make a reasonable point. An MMORPG is a massive undertaking for a beginner, since it involves a reasonable knowledge of many deep topics, such as networking, concurrency and databases. The thing is…that doesn’t preclude the possibility of a sufficiently knowledgeable hobbyist pulling it off. In fact, Ultima Online was initially produced by a team of 4-5 people and the original incarnation of RuneScape was the work of two brothers.

So, I decided “why not?” I’m on my third year of a Computer Science degree; I can do this. I had some free time while self-isolating before university classes started back up, so I started planning out a hobby MMORPG.

I figured it would be a fun thing to play with over time. Probably a very long time. Maybe it’ll be an actual live game someday, or maybe I’ll get bored and dump the source on GitHub down the line. Either way, it’ll be an interesting project whenever I have some time.

Without further ado, here are some highlights from the first month of development.

Networking Scaffold

The first few days were mostly spent on networking. I immediately rejected any of the high-level tools that involve running Unity on the server, planning from the start to have a custom dedicated server. I fired up a test project and spent some time experimenting with raw C# sockets, until I had the basic concepts down, but ultimately decided to use a lightweight framework to simplify some things.

LiteNetLib, the library I chose, uses UDP but has support for TCP-style reliable/ordered packets and takes the pain out of serialization. You get a lot of features for free, but it just does networking. Nothing fancy or inherently game related. Its NetPacketProcessor class handles routing, so you can easily define methods to invoke when packets come in, and the serialization tools allow you to define packets as plain classes.

Once I had that figured out, I started scaffolding the server out, then created my MMORPG project in Unity and wrote some scripts to connect to the server.


This one is something you won’t see game-related things online talk about, but it’s very important. You need to have a way for users to log in, and you need to do so in a way that does not expose their passwords. Not only do you need to have hashing for the passwords, instead of storing them in plaintext, but you also need encryption while the password is in transit.

For hashing, .NET Core includes functions that do the job. The overall process works the same as any Web application: hash the password and store it in the database when the user registers, then on log in attempts you hash the password submitted and see if it matches.

But that’s not really enough. We don’t want to risk someone sniffing packets and hijacking users' accounts, do we? The contents of sensitive packets, such as the authentication packet, need to be encrypted in flight. Some games encrypt everything, others don’t. LiteNetLib has already made the opinionated decision to not use encryption, which means you have to encrypt the data before building the packet, as opposed to having the socket’s transport taking care of it.

Fortunately, .NET Core also has RSA encryption in its standard library. If you’re not familiar with public-key encryption, not to worry. Unlike hashes, which only work one-way, RSA is symmetric. Each party has two keys, one public and one private. If you have someone’s public key, you can use it in tandem with your private key to produce a message that cannot be read by anyone who lacks the other half of the recipient’s key-pair. So the process the game uses follows this workflow:

  1. When the server starts up, it generates its private and public key.

  2. When a client wants to connect, the client opens a socket connection to the server and sends a packet asking to authenticate.

  3. The server sends back a packet containing its public key.

  4. The client takes the private key it generates and uses it with the server’s public key to encrypt the username and password to be sent.

  5. The server uses its private key to decrypt the incoming message.

  6. The server queries the database for a row matching the username, hashes the password in the login attempt, and checks to see if the two hashes matched. If they do, a success message is sent back…otherwise the client is kicked.


Right around now, I started having that nagging feeling that I had gone far too long without an off-site backup. I had already been using Git locally since the beginning, obviously, but I really needed to be able to push it to a remote repo and make sure I had more than the copy on my laptop.

How to Git with Unity tells you everything you need to know about making Unity play nicely with Git. It gives you some configurations that make sure data is serialized in plain text instead of binary, so your changes can be tracked, as well as LFS details and a .gitignore. Git LFS helps Git deal with the large assets that games may have.

Since GitHub’s LFS offerings cost a bit, and I already have a server, I installed Gitea. It has the core features you’d expect from a GitHub alternative, and you can choose to either store LFS objects locally or to outsource them to Amazon S3. My VPS’s SSD space is bigger than I’m likely to need, but it’s nice to have that option.


With an authentication system working, albeit with a hard-coded test username and password, the next logical step was to create a database that would hold the user account information…and a separate one for the game world. By having them split, it would make it easier to support multiple servers down the line.

Not being terribly familiar with the C# ecosystem, I had to do a bit of searching before settling on a plan for the database. I knew I wanted an ORM of some kind, since I’d eventually have many different sorts of data to persist. I also wanted to, ideally, use SQLite for easier development and be able to later switch over to MySQL or PostgreSQL for production.

I briefly looked at the Dapper micro-ORM, but settled on Microsoft’s own Entity Framework Core, because I wanted migrations and other things it comes with. Whether that decision will work out or not is a question for the future, but so far it seems to work just fine.

The running theme seems to be that the server does a lot of the same things as a large Web application. You model data, shuffle it to and from a database, and talk with clients over an API. The only difference is you’re using an open UDP socket with purpose-built packets instead of something like REST over HTTP.

Login Menu and Character Selection

Now it’s time to do some work on the client. When you start the game, the first Scene loaded by Unity is the Login Menu. Attempting to join the game fires off the packet exchange detailed above in the Authentication section.

Upon successful authentication, the server dispatches a packet with a list of the user’s characters. When it’s received by the client, the menu changes to show a list of characters to choose. Currently there is no way to add a character other than editing the database, since that will probably involve having more of an idea how character customization might work…

When a player is selected, a packet is sent to the server to join the game, and the server responds by sending a player spawn packet. This commands the client to load a Scene by name, including the coordinates and rotation.

Zone Architecture

Zones are a server-side concept that section off parts of the world. Each zone has a Unity Scene associated with it, a list of players in the zone, a list of entities (mobs and NPCs, eventually), and other data. Each zone is defined by a JSON file that contains the relevant information.

Every time the server loop ticks (a fixed number of times per second), it calls each zone’s Update() method, which is responsible for updating all or some of the entities contained within. So it might run mob behaviors near players or do nothing at all if the zone is empty. Every n ticks, player data (e.g. location) will also be persisted to the database.

I developed an editor tool that will automatically generate zone definition files based on input configuration. It’s just the absolute basics right now, but eventually it will be expanded as new features are implemented. For example, exits to other zones may be defined with boundaries in-editor, and the zone definition tool will serialize those as well. NPC spawn points will also be marked in a similar fashion.

The zone tool also has a utility that extracts the vertices and triangles from Unity’s navmesh and writes it out to an OBJ file that can also be copied to the server. This is how mobs and NPCs will be able to pathfind, since that has to be done server-side. It could also be used to check if ranged abilities are obstructed by walls.

The base Zone class is also meant to be inheritable, to support special Zones with procedurally generated content. This factors greatly into the premise I’ve been kicking around for the game.

Player Spawning and Controller

So far, the spawn packet works as expected, using information stored in the database. However, I have not yet fully implemented the logic to handle movement requests from the connected clients. The player can walk around using a basic third person controller, but nothing is sent to the server. I have it planned out on paper, but haven’t finished programming it.

The basic idea for movement is for the client to send updates, multiple times per second, of where the client is moving to. The Euclidean distance between the two points can then be checked to ensure that the player is not moving too far between update intervals. If the delta is greater than the cutoff, the location is reset, and the client will “rubberband” back. This (relatively simple) method is commonly used for games where player movement isn’t a gamebreaking issue, as far as cheating goes. (Minecraft and World of Warcraft operate similarly.)

The method that is increasingly common in fast-faced games, like First Person Shooters, is for the client to send a unit vector of the player’s input to the server, which then calculates the movement update (multiplying the vector by the time difference and legal movement speed) and then commands the client to move the player. Since this is very latency sensitive, they interpolate and predict what the server would do so it looks less stuttery when ping time is reasonably low. (But a little lag still throws it all off.) This is a lot more complicated, and definitely worth it for some games, but overkill for something like this.

With either method, the server is the source of truth and has the final say.

For testing purposes, I’m using a model from Adobe Mixamo with some of the included animations. I’m also using a basic movement controller that allows for jumping, and the Cinemachine package is handling camera movement. This will all replaced/tweaked over time, but I needed something to start with while working on the more interesting parts.


Everything is very iterative, and the project definitely does have a huge scope. It should keep me busy and scratch the recurring itch to make Minecraft server plugins. Why hack together mods for someone else’s game when you can make your own? I have a notebook slowly filling with plans for facets of the system, sketches of zones and a rough premise. It’ll be fun to slowly realize that vision.

I will probably post sporadic updates when I do something new and interesting.

MMORPG Devlog 2: Networked Player Movement

You Don’t Have to be an Expert to Solve Big Problems

Writing a GUI Application with Python and Py2App

To Make Oxygen on Mars, NASA’s Perseverance Rover Needs MOXIE

This is possibly more interesting than the Mars Helicopter on board.

Baking Static Sites with Python and Jinja

As COVID-19 Looms

Friday the Thirteenth…appropriate enough.

It is the last day of classes before Spring Break, though most seem to have been canceled. Cars line the roads near the residence halls as students hastily load their belongings in the rain. Though the weather is warming up and beginning to show signs of the coming season, the mood does not match. The air is thick with dread, confusion, and a weird tension that’s impossible to shake. The proverbial “calm before the storm.”

Just two days before, the World Health Organization upgraded the status of the novel coronavirus outbreak to “pandemic,” and the cascade of emails and news articles began. While the university had previously made the call to keep the dorms open through the break and discourage travel as a precaution, an abrupt change was made. All classes were to immediately move online for the remaining six weeks, a stressful upheaval in itself, and every student would be required to vacate the campus by the end of the break. Labs would likely be hand-waved away, and senior capstone projects would be turned in as-is for grading on partial completion.

Students are saying goodbyes all over campus, and tying up loose ends before leaving. Some may be back in September (if things return to normal), but others will simply have their final year at the university cut short. Inside the Union, the building is packed with over a thousand people in the main thoroughfare, holding an impromptu “Coronamencement” in place of the commencement that would never happen. It’s kind of ironic, holding a major gathering while the semester is being thrown into chaos due to a viral threat…

It’s easy to get caught up in worries about the quality of education inevitably falling off a cliff or the anxiety of being suddenly kicked out of where you live, but it really is a dire situation. The phrase “putting your eggs in one basket” comes to mind, and I suspect that’s the line of thinking going on at an administrative level. In addition to the potential for a disease to spread like wildfire on a college campus, applying the statistics of an epidemic to a hotspot of academics is a terrifying societal risk. Despite the relative isolation of the area, confirmed cases of COVID-19 have made their way to the state.

One day later, I have to go to my job in Retail Land, where I’m floored by the stark contrast in attitudes. Sure, some students and faculty referred to the decision an “overreaction” and favored the idea of merely trying to isolate the campus from the outside world, but that’s nowhere near the brazen stupidity going on in town. The movie theater’s parking lot is as full as it was for the last Avengers film, every restaurant appears busy, and people are out shopping. Frivolous shopping by blasé buyers vocally proclaiming their ignorance and panicked types “stocking up” line up alike. I dare not venture into Wal-Mart or any of the grocery stores after work, but I’m told that there are rows upon rows of aisles that are entirely bare. (The toilet paper and hand sanitizer were long gone, days before, of course.)

I’m, quite frankly, disturbed by what’s going on. You have belligerent ignorance on one end and undirected panic on the other, with little being done to mitigate the impending threat as people create a scenario enabling faster propagation. Meanwhile, medical professionals prepare to do battle, knowing full well that they are ill-equipped. Supply interruptions have caused shortages of everything from masks to commonly used drugs like anticoagulants needed for surgeries. There aren’t enough hospital beds or ventilators in the world for expected numbers of patients, with the WHO’s estimated 20% of infected requiring hospitalization to survive.

People bat around different numbers for mortality rates, but here’s the thing: the number of deaths is a function of the hospitalization rate and hospital capacity. If 10-20% (do you like 1-in-10 odds?) of people who come in contact with a virus known to spread very easily can only survive it with medical attention, that obviously means it’s fatal to not receive that care. Maybe there aren’t enough resources to go around, maybe people avoid seeking medical care due to the costs or lack of insurance. Maybe they have another medical emergency and hospitals are stretched too thin due to the virus. When you have doctors around the world telling you shit’s about to hit the fan…maybe don’t pretend you know more than people who devoted years of their lives to studying their field?

I just read this chilling “open letter letter from Italy to the international scientific community” not too long before I had the urge to sit down and begin writing this.

The next few months will be interesting…

← Newer Page 1 of 8