Abstracting Entity Behavior - #2
6-19-2024 - This is the second update of Mvndicraft’s “dev diary” series
Author: Timo
One of the coolest features that Mvndicraft has had for the longest time (even since the datapack ages) was siege weapons. Siege weapons are a core component of the game, and can be the determining outcome of a siege battle pretty often. One of Mvndi’s old beloved devs, Nappykins, wrote the legacy siege weapon plugin that you are all familiar with.
Problems with the Old Siege Weapons
Poor Interpretation of Object Oriented Programming
Take the tasks in the old siege weapon plugin for example:
These tasks make sense right? We need a task to load a cannon, apply recoil to the cannon, fire a trebuchet, etc… Wrong! What if we wanted to add a catapult siege weapon in the future? Or maybe a gattling gun? What about a battering ram? Every time we would want to add a new siege weapon, we would need to go in the code, and create new animation tasks every time.
As you can imagine, this can get really tedious, and generally in OOP we want to avoid making frequent changes to code.
That’s where I began to think, ‘Hmm…, what are some common functionalities that we can extract from siege weapons? For example, item display entities could potentially be used in some other plugin in the future (i.e. boats).
What if we make a completely seperate library plugin, specifically for handling Mvndi’s unique behavior of entities? Typically, we would want to apply animations to these item displays. Animation classes now become this:
Much better… instead of specifying an animation for each type of siege weapon, we have a few general animations that we can listen to and apply our siege weapon functionality.
Using Collidable Entities as Siege Weapon Hitboxes.
One of the least optimized parts of Minecraft is when multiple entities collide with each other. I’ll spare you the details, but basically all siege weapons used either cows, pigs, or some kind of Minecraft living entity to act as a hitbox.
As you might imagine, this can become very buggy very quickly. We need to listen to each case of Minecraft functionality WITH the mob and remove that functionality (i.e. Cow milking).
I’m not sure if the previous siege weapon dev had a lack of oversight, or just didn’t even know that a specific Minecraft entity exists as of 1.19.4 for listening to interactions.
The new entity system uses these interaction entities instead of living entities to listen for whenever a player interacts with a siege weapon. As a result, the client and server doesn’t have to do additional collision calculations whenever a player runs into a siege weapon.
Lack of Configurability
When making a game, generally game design theory has a consensus that we should make ONE specific type of an object and expand variations to it from there.
Take a Minecraft sword for example. In Minecraft client code, theres only one ItemSword.class
. To add an additional type of sword, we don’t have to make another class, we can just create a new JSON
file, i.e. iron_sword.json
, and apply different final values to our new sword. i.e. damage
, model_id
, reach
etc.
Siege weapons literally didn’t have a single speck of this. For example, if we wanted to add a different ballista with different stats, we would have to create a new class directly in the code.
The new system will solve this. Adding a variant of a siege weapon will finally be possible. This might take a while to implement, but it’s worth it because we are speeding up how fast we can add content to the game.
Performance
John and I did a mini stress test with the new entities plugin:
We spawned over 20,000+ entities (10,000+ of our display entity variant) and ran three different tests on Paper.
The first test we used the very slow Bukkit.getEntity()
. For those of you who don’t know, Bukkit.getEntity()
loops through ALL worlds to find an entity (O(n)
). This test took up a whopping 17ms
of tick time! Not good…
The second test we cached the entities into a map ourselves (O(1)
). Tick time was much better: 9ms
.
Because we cached the entities ourselves and we aren’t directly accessing the location of the entities, we could access our cache on multiple threads. Tick time in this test only took up 3-4ms
! Thats 20,000 loaded entities all animating in one chunk!
The advantage of this is that we could have hundreds of players all operating boats, siege weapons, and other entities with little to no lag. Pretty good if you ask me…
New Siege Weapon Features
Take these with a grain of salt, but this is what I have in mind for the siege weapons.
- Siege weapons will no longer be bought from a shop. Instead, players must craft the parts of a siege weapon and put them together.
- Siege weapons will have durability. If a cannonball hits a ballista for example, the ballista will break. Every time you commit a use on a siege weapon, the durability lowers. Once it breaks, it breaks, you have to craft a new one.
If anyone has any other suggestions, make a ticket on the Discord and I’ll take them into consideration (if they’re good).
Finally, I just want to let everyone know that development is happening. It might not feel like it, but we are a very small team that operates on our free time. Below is a picture of the past commits on our Git org:
As always. Your support is appreciated.