Hello CubeCrafters!
Welcome back to Behind the Cube! We've been on hiatus for a while and been busy cracking out other updates over the last few years, but today I want to step back a couple years to our 1.19 server update. This was our biggest, most ambitious update we've ever performed on the network. This has allowed us to deliver far more feature-complete updates across both networks simultaneously, and completely transformed our developer experience.
This edition will dive deep into the internals our server update to 1.19, some the challenges that we encountered during our migration, and some
spicy
changes we’ve made on the tech side that have greatly improved our updating process. This is a juicy one, so grab a bowl of popcorn
and let’s dive right in!
As many of you may be aware, we initially communicated our goals of updating the network to 1.19 waaaaay back in September of 2022, however in actuality, work began far earlier, prior to 1.19 even being released. Updating nearly 10 Minecraft versions was no easy feat, and required a lot of background planning and backend work.
Previously, our server platform was running on a 1.9.2 Spigot jar we updated to 1.12 and modded Bedrock support into back in 2021. Some of you may recall our Translator system we discussed in our [Feelin’ Lucky] Behind the Cube which sat on top of our BungeeCords. This system allowed us to support Bedrock Edition users on our existing Java infrastructure.
As we grew throughout 2020 and 2021, it became a major technical challenge for us to maintain as we started implementing native Bedrock features that are now integral to our server, such as resource packs, custom entities and custom items / blocks. We decided to go the route of removing the Translator, and turning our Java server into a full-on Bedrock server.
Moving away from our Translator proved to have a large number of benefits, including reducing player latency by 50ms - 100ms across the board. However, this came with the downside of maintaining a significant amount of code in our server software.
Rather than going the route of updating our 1.9-but-really-it-was-actually-1.12-server jar to 1.18, we decided to start fresh by forking Paper 1.18. The first commits to our new CubeTap project (internally known as CubeTap Junior) were in March of 2022.
The first few months of work primarily revolved around getting our new CubeTap version up to speed with our 1.12 version. We also took the opportunity to redesign core parts of our Bedrock support, such as moving to Bedrock’s server-authoritative inventory system, implementing chunk caching, and adding proper custom blocks. We also added new APIs to integrate nicely with these systems.
First look at chunks rendering for Bedrock Edition on our new software.
Much of the work to update the CubeCraft codebase began in July of 2023. For those of you who have worked with Spigot or Paper before may know that in 1.13, there were massive, backwards-compatible breaking changes in the Bukkit API. The internal NMS code also saw major changes, going from being heavily obfuscated to fully deobfuscated using Mojang’s code mappings. Additionally, from 1.13 - 1.18, huge amounts of the server code was rewritten.
While most of these changes were positive, essentially most anything using NMS was going to break (and boooyyy did we use a lot!) and most all 1.13+ Bukkit plugins were going to no longer be functional.
After some time, the first project we completed updating was GameFramework, which is one of our core frameworks that all our games are built on top of.
First look at a simple TNT Run game running on a local server using GameFramework.
Getting GameFramework to work was a massive milestone and meant that within a short period of time, we could actually start testing CubeCraft code on 1.19!
Within just a few weeks from this point, we had many of our other core libraries updated, such as Loot, Armoury, Play Again, etc. and by early August, had a version of Survival Games running for Java Edition
As bug free as you get…
At the speed things were going, it looked as if we were going to have 1.19 out by December, just in time for our 10th anniversary! Right? Right..? Well, we’ll see… let’s not get too ahead of ourselves
As work continued to get all our code updated to 1.19, a question arose: what did we want to get out of this update?
I think the obvious answer everyone arrived to was: offer new features and to build potential for future content. While these are and have always been at the root of any content update at CubeCraft, we were starting to see major technical debt problems arise on our existing network.
At the time, our codebases for both Java and Bedrock were very disjointed. We maintained four separate Git branches for each project:
This ultimately meant that if a bug fix was found in team handling for instance that was present on both Java and Bedrock, that would mean a commit fixing the issue would need to be pushed to eight branches (╯°□°)╯︵ ┻━┻
Also at the time, our update process typically involved us writing the code for Java Edition first, testing it, and then merging it into our Bedrock branches, often encountering multiple merge conflicts, then updating or removing any features not relevant to Bedrock, and testing again. This is also the reason that in times past, we often released all major content updates for Java first (or even exclusively in some cases), then later Bedrock. This made any major update incredibly cumbersome and often led to very "Java-first" updates that disregarded features on Bedrock.
Since we were already making major technical changes, we decided now would be the best time to reconsider how we conducted our updates on a technical side.
Shortly after getting Survival Games functional on our Java Edition development network, @ rubik_cube_man, @ Alemiz, @ Austin Mayes and I sat down and discussed plans on how we wanted to approach this problem. We decided that modularising the code was the best approach, creating a common module for all common code, then separate java and bedrock modules for features that vary for each platform. Rather than maintaining 4 branches, we would only need 2: one for production code and one for development code.
We then pitched the idea to the rest of the dev team and decided on a course of action.
Modularising all our Bedrock and Java code together essentially meant that all updates we did would only ever need to be written once, rather than one time for Java, then tested, then updated in bits and places for Bedrock (or in some cases like MinerWare, substantially), then tested again, then finally released. We could instead streamline the process and do simultaneous testing on both platforms, allowing greater flexibility between updates and the ability to offer much more content. These changes also meant that general bug fixes in the game logic only needed to be written once, rather than individually for each platform.
SkyWars project layout today.
While the results of this modularisation have been incredibly beneficial for us today, it took us a long time to get there. There was a large amount of scope creep, unexpected challenges and many, many delays.
As we began to modularise our codebase and integrate everything together, we began to realize that many of our core libraries needed massive rewrites to cooperate well with both Java and Bedrock, or needed to be rewritten from the ground up. Systems such as our menu library, game voting system, loot, and other similar systems needed massive overhauls.
Here is a quick look at how we now create menus on our network now using the UI library we wrote as part of this migration:
The code used to render the Loot home menu in the Bedrock module.
The code used to render the Loot home menu in the Java module.
And in our common module, we can have a common open method, even if it is rendered differently on both platforms...
Welcome back to Behind the Cube! We've been on hiatus for a while and been busy cracking out other updates over the last few years, but today I want to step back a couple years to our 1.19 server update. This was our biggest, most ambitious update we've ever performed on the network. This has allowed us to deliver far more feature-complete updates across both networks simultaneously, and completely transformed our developer experience.
This edition will dive deep into the internals our server update to 1.19, some the challenges that we encountered during our migration, and some
spicy
changes we’ve made on the tech side that have greatly improved our updating process. This is a juicy one, so grab a bowl of popcorn
and let’s dive right in!
The 1.19 1.18 update…?
The As many of you may be aware, we initially communicated our goals of updating the network to 1.19 waaaaay back in September of 2022, however in actuality, work began far earlier, prior to 1.19 even being released. Updating nearly 10 Minecraft versions was no easy feat, and required a lot of background planning and backend work.
For a bit of background…
Previously, our server platform was running on a 1.9.2 Spigot jar we updated to 1.12 and modded Bedrock support into back in 2021. Some of you may recall our Translator system we discussed in our [Feelin’ Lucky] Behind the Cube which sat on top of our BungeeCords. This system allowed us to support Bedrock Edition users on our existing Java infrastructure.
As we grew throughout 2020 and 2021, it became a major technical challenge for us to maintain as we started implementing native Bedrock features that are now integral to our server, such as resource packs, custom entities and custom items / blocks. We decided to go the route of removing the Translator, and turning our Java server into a full-on Bedrock server.
Moving away from our Translator proved to have a large number of benefits, including reducing player latency by 50ms - 100ms across the board. However, this came with the downside of maintaining a significant amount of code in our server software.
Updating to 1.18…
Rather than going the route of updating our 1.9-but-really-it-was-actually-1.12-server jar to 1.18, we decided to start fresh by forking Paper 1.18. The first commits to our new CubeTap project (internally known as CubeTap Junior) were in March of 2022.
The first few months of work primarily revolved around getting our new CubeTap version up to speed with our 1.12 version. We also took the opportunity to redesign core parts of our Bedrock support, such as moving to Bedrock’s server-authoritative inventory system, implementing chunk caching, and adding proper custom blocks. We also added new APIs to integrate nicely with these systems.
If you want to hear more about how we added Bedrock support into our server, implemented custom items, entities and blocks on both Java and Bedrock, let us know!
First look at chunks rendering for Bedrock Edition on our new software.
Updating CubeCraft!
Updating CubeCraft!Much of the work to update the CubeCraft codebase began in July of 2023. For those of you who have worked with Spigot or Paper before may know that in 1.13, there were massive, backwards-compatible breaking changes in the Bukkit API. The internal NMS code also saw major changes, going from being heavily obfuscated to fully deobfuscated using Mojang’s code mappings. Additionally, from 1.13 - 1.18, huge amounts of the server code was rewritten.
While most of these changes were positive, essentially most anything using NMS was going to break (and boooyyy did we use a lot!) and most all 1.13+ Bukkit plugins were going to no longer be functional.
After some time, the first project we completed updating was GameFramework, which is one of our core frameworks that all our games are built on top of.
First look at a simple TNT Run game running on a local server using GameFramework.
Getting GameFramework to work was a massive milestone and meant that within a short period of time, we could actually start testing CubeCraft code on 1.19!

Within just a few weeks from this point, we had many of our other core libraries updated, such as Loot, Armoury, Play Again, etc. and by early August, had a version of Survival Games running for Java Edition

As bug free as you get…
At the speed things were going, it looked as if we were going to have 1.19 out by December, just in time for our 10th anniversary! Right? Right..? Well, we’ll see… let’s not get too ahead of ourselves
What did we want out of this update?
What did we want out of this update?As work continued to get all our code updated to 1.19, a question arose: what did we want to get out of this update?
I think the obvious answer everyone arrived to was: offer new features and to build potential for future content. While these are and have always been at the root of any content update at CubeCraft, we were starting to see major technical debt problems arise on our existing network.
At the time, our codebases for both Java and Bedrock were very disjointed. We maintained four separate Git branches for each project:
- production - Contains all code live on our Java Edition server
- production-mco - Contains all code live on our Bedrock Edition server
- master - Contains all code live on our Java Edition development server
- master-mco - Contains all code live on our Bedrock Edition development server
This ultimately meant that if a bug fix was found in team handling for instance that was present on both Java and Bedrock, that would mean a commit fixing the issue would need to be pushed to eight branches (╯°□°)╯︵ ┻━┻
Also at the time, our update process typically involved us writing the code for Java Edition first, testing it, and then merging it into our Bedrock branches, often encountering multiple merge conflicts, then updating or removing any features not relevant to Bedrock, and testing again. This is also the reason that in times past, we often released all major content updates for Java first (or even exclusively in some cases), then later Bedrock. This made any major update incredibly cumbersome and often led to very "Java-first" updates that disregarded features on Bedrock.
Since we were already making major technical changes, we decided now would be the best time to reconsider how we conducted our updates on a technical side.
Modularising the code
Modularising the codeShortly after getting Survival Games functional on our Java Edition development network, @ rubik_cube_man, @ Alemiz, @ Austin Mayes and I sat down and discussed plans on how we wanted to approach this problem. We decided that modularising the code was the best approach, creating a common module for all common code, then separate java and bedrock modules for features that vary for each platform. Rather than maintaining 4 branches, we would only need 2: one for production code and one for development code.
We then pitched the idea to the rest of the dev team and decided on a course of action.
Initial slide from our pitch deck in August of 2022
Modularising all our Bedrock and Java code together essentially meant that all updates we did would only ever need to be written once, rather than one time for Java, then tested, then updated in bits and places for Bedrock (or in some cases like MinerWare, substantially), then tested again, then finally released. We could instead streamline the process and do simultaneous testing on both platforms, allowing greater flexibility between updates and the ability to offer much more content. These changes also meant that general bug fixes in the game logic only needed to be written once, rather than individually for each platform.
SkyWars project layout today.
While the results of this modularisation have been incredibly beneficial for us today, it took us a long time to get there. There was a large amount of scope creep, unexpected challenges and many, many delays.
Delays and challenges…
Delays and challenges…As we began to modularise our codebase and integrate everything together, we began to realize that many of our core libraries needed massive rewrites to cooperate well with both Java and Bedrock, or needed to be rewritten from the ground up. Systems such as our menu library, game voting system, loot, and other similar systems needed massive overhauls.
Here is a quick look at how we now create menus on our network now using the UI library we wrote as part of this migration:
The code used to render the Loot home menu in the Bedrock module.
The code used to render the Loot home menu in the Java module.
And in our common module, we can have a common open method, even if it is rendered differently on both platforms...
Halloween Hub & Hunt
New Halloween Maps + Returning
BlockWars Giga - Domination & New Maps!
- Solo SkyWars is the only gamemode that shares the same pool of maps between networks. This means you'll see previously Java-exclusive maps available on Bedrock in Private Game map selection, technically making them "new" to Bedrock. You'll see 14 new Solo EggWars maps, and 33 new Solo SkyWars, plus more in other games!
Private Games Out Now in Beta!
CubeCraft Gold & Subscription Management!
- Learn more below!
Warden Bundle!
