I have one month to make an MMO: Day 18

Yuan Gao (Meseta)
Meseta’s MMO experiment
6 min readSep 14, 2019

I spent a lot of time refactoring the item storage. It’s sad to see that the results of most of a day’s hard work is just to be able to see this potato on the floor.

This image represents 6 hours of solid dev work.

Refactoring

I needed to have the server be able to store all of the loose items in a chunk, however as it turns out, this required quite a bit of refactoring. The reason for this is chunks now have to store several different kinds of “thing”, and it was cleaner to make tho code treat these separately:

Entities

Entities are only loosely tied to a chunk. Entities are NPCs, and other player-characters; they’re things that can move around the world and are controlled by either an entity node, or a player node.

Entities exist in the TMX maps when I create the world, but they only exist as a marker for me to define what entities should be spawned in the world, and where they start. Entities are free to move around the world, though NPCs tend to not have any movement logic so they stay in the same spot, and mobs may have some logic in their behaviours to have them return to their starting locations if not chasing a player.

What it looks like on Tiled when I define a bunch of entities (and one static object)

When the map is processed, these entity markers are stripped out of the map data and cease to be part of the chunk data that goes into the database, but are inserted into a different part of the database as their own thing.

The player client doesn’t know about the existence of the entity until the entity is near enough to the player that they start receiving position updates for that entity. At that point the player client can start displaying the entity to the player.

Static Objects

As introduced in a previous post, static objects exist at fixed positions on a chunk. They never move, and exist only to provide interactivity on the map. These tend to be things like signposts, and occasionally containers or other triggers. Static objects stay in the chunk data, and get loaded and unloaded with the chunk. They are static for the lifetime of the game.

(While the static object itself may never change, they can point to dialogues which could have some scripted behaviours in them. So a static object might give each player an item, but remember that they’ve already handed out an object, and so won’t give the player more than one item)

Loose Items

This is the one I had troubles with. Loose Items are different from both entities and static objects.

They are somewhat similar to Static Objects because they exist as part of a chunk, and so should be loaded/unloaded with the chunk, and they certainly don’t publish any kind of position update (loose items don’t just run around on their own).

But unlike Static Objects (and more similar to Entities), Loose Items can change. New loose items are created in a chunk if a player drops an item. Loose items may be removed from a chunk if a player picks them up.

In the end, I needed to refactor the chunk storage to store loose items as sort of a half-way between a Static Object and an Entity. Long story short, this refactoring took quite a lot of time to do.

Picking up loose items

With the refactoring done, I was able to quickly add an ability to pick up loose items off the environment.

In this example, I pick up a potato.

Though this action may be simple, the process that was required to achieve this was quiet extensive. The sequence of actions goes as follows:

  1. In order to place that potato there in the first place, I needed a new Loose Item marker in Tiled.
  2. The Tiled parser needed to recognise this, and insert relevant entries into the database to create a Loose Item
  3. When the player is moving around the map, the player node sends the player clients chunk data. This data must include all of the loose items on that chunk.
  4. The player client needs to be able to receive this loose items list, and pawn the item loader objects
  5. Item loader objects then have to request what kind of object they are from the server. I don’t store all of the item’s information inside the chunk, only which items are in the chunk, the loader has to go fetch the rest of the information from the database.
  6. Player node needs to be able to look up an item in the Loose Items part of the database and return what type and what sprite this item is. This system works the same as how Entity data is loaded.
  7. Player client must be able to receive this information and then draw the actual item.
  8. When the player tries to pick up the item, the player client must send this pick up request to the player node for validation.
  9. The player node must check if that item still exists (in case two players try to grab the same item at the same time), and disallow the pickup if it’s already gone.
  10. If the item pickup is allowed, the player node must then check if there’s enough space in the player’s inventory to pick up the item. If there isn’t disallow the pickup.
  11. The player node must also check if there’s an existing item of the same type and quality, and stack them. If there isn’t an existing item, the item goes into an empty slot instead.
  12. The player node must then notify all other player nodes that this item has no been removed from the chunk, so that the player clients can stop showing this item to the player.
  13. The player node must then notify the player of their new changed inventory.

The simple act of being able to pick up a potato involved quite complex sequence of events that took me much more time than I anticipated.

But, now that it’s done, a lot of the code and architecture needed to do it supports other item-related features, like mobs dropping items, or NPCs giving items.

Checksums in the Tiled uploader

With the larger map, it now takes several seconds to process the map and upload the data. Several hundred database entries are generated covering all the chunks, entities, and loose items in the world.

Since a lot of the existing content doesn’t change, I’ve added a checksum system so that data that hasn’t change between map uploads don’t have to be uploaded.

Showing most chunks being skipped except for two that were changed

Day 18 task Summary

Due to the above refactoring task, I only accomplished one task today, which was allowing the environment to give items.

But, this has given me insight into how the item system needs to work, and so I have a better understanding of what work is left for tasks like the Item RPC and Item Dropping. So, while I’ve only completed 1 task today, I don’t feel significantly behind.

Tomorrow I’ll work on NPCs giving and taking items. This may take a while as it requires new features to be added into the dialogue system.

--

--

Yuan Gao (Meseta)
Meseta’s MMO experiment

🤖 Build robots, code in python. Former Electrical Engineer 👨‍💻 Programmer, Chief Technology Officer 🏆 Forbes 30 Under 30 in Enterprise Technology