Skip to content

Supporting multiple versions of Minecraft #99

@avdstaaij

Description

@avdstaaij

The problem

There is a significant limitation (perhaps even design flaw) in GDPC: it cannot support multiple versions of Minecraft simultaneously. Or, differently said, new features in the library cannot be used when writing a generator for an older version of Minecraft, and older versions of the library (and thus old generators) cannot be used with newer versions of Minecraft.

There are two causes of this limitation:

Cause 1: GDPC depends on a minimum version of GDMC-HTTP, which has the same fundamental limitation: Each version of GDMC-HTTP only supports one specific version of Minecraft, with neither backwards nor forwards compatibility.

Cause 2: GDPC interacts with "Minecraft data" (blocks, entities, items) in a few places (see e.g. #98). I attempted to limit this as much as possible, but couldn't fully eliminate it. Currently, I believe these places are:

  • The functions to rotate and flip individual blocks.
  • The utility functions to generate NBT data (signData/placeSign, bookData, etc.).
  • The WorldSlice constructor.

In an ideal world, it would be possible to write a generator using the latest version of GDPC and apply it to any out of a range of supported Minecraft version, and to take an old generator and to apply even to newer Minecraft versions, but the limitations above prevent this.

Why cause 1 must be solved first

I believe that adressing the minecraft data interactions (cause 2) is not useful, or has very limited use, before either GDMC-HTTP becomes backwards compatible with Minecraft versions or GDPC becomes backwards compatible with GDMC-HTTP versions. Abstractly, the reason is as follows: if GDPC inherently supports Minecraft versions X through Y, but requires GDMC-HTTP version >= Z, and GDMC-HTTP version Z requires Minecraft version Y, then by transivitiy, GDPC still only supports Minecraft version Y. There is no use to supporting Minecraft versions that are not supported by the minimum required version of GDMC-HTTP.

For a concrete example, consider issue #98. Issue #98 is about the sign helper functions like placeSign. The NBT data format for signs changed in Minecraft 1.20. If these functions would be updated to the >=1.20 format, they would no longer support <1.20 (cause 2). In #98, it is suggested to change the sign helper functions to check the version of Minecraft that is currently in use (this is not quite trivial, as I will explain under "Solving cause 2", but not impossible), and change their behavior depending on it. In principle, this is a good idea. However, consider the following. GDMC-HTTP 1.4.0 requires Minecraft 1.20.2, and later versions of GDMC-HTTP thus far have only supported later versions of Minecraft. So, if we want to implement features in GDPC that require functionality from GDMC-HTTP 1.4.0 (such as the improved withinBuildArea support), GDPC will have to require GDMC-HTTP 1.4.0, and thus, by transitivity, Minecraft 1.20.2. So the behavior switch in the sign helpers would become useless.

Solving cause 1

Cause 1 can be solved from either the GDMC-HTTP side or the GDPC side.

The GDMC-HTTP side

To solve cause 1 on the GDMC-HTTP side, GDMC-HTTP needs to become backwards compatible with regards to Minecraft. GDPC could then simply depend on the latest version of GDMC-HTTP. One way to do this might be for there to be versions of the mod for a range of Minecraft versions instead of just one: "GDMC-HTTP 1.4.0 for Minecraft 1.20.2", "GDMC-HTTP 1.4.0 for Minecraft 1.19.2", etc. By solving this on the GDMC-HTTP side, everyone who uses GDMC-HTTP would benefit, not just those who use GDPC.

I do not know how possible this is or how much work it would take. @Niels-NTG, I would like to hear your input on this!

The GDPC side

To solve cause 1 on the GDPC side, GDPC needs to become backwards compatible with regards to GDMC-HTTP. It might be possible to do this: we could introduce an abstract class Interface, and add multiple implementations such as GDMC_HTTP_1_3_3_Interface, GDMC_HTTP_1_4_0_Interface, etc. This would even allow things like AmuletInterface, so it may be beneficial regardless. All features that require interface support (such as build area enforcement) would then move to these concrete interface classes, with some classes not supporting all features and perhaps logging warnings when this is the case. However, I am not entirely sure if all interface-dependent features can be so easily grouped together.

Solving cause 2

Once cause 1 is solved, we can consider solving cause 2. To reiterate, I believe the places where GDPC interacts with Minecraft data are:

  • The functions to rotate and flip individual blocks.
  • The utility functions to generate NBT data (signData/placeSign, bookData, etc.).
  • The WorldSlice constructor.

WorldSlice

First of all, WorldSlice. This one might be the most problematic, since it essentially parses Minecraft's entire world format. I think the best way to make this Minecraft version-independent is to completely get rid of the GET /chunks call and instead rely on higher-level GDMC-HTTP calls. GDMC-HTTP now supports getting 3D regions of blocks and biomes, and there is now a /heightmaps endpoint, so this could very well be possible. If we don't switch to higher-level calls, there is no way to get around maintaining multiple implementations of the WorldSlice parser for various versions of Minecraft.

Blocks, entities and items

The other two parts, rotating/flipping blocks and NBT helpers, are fairly similar. They both deal with blocks, entities or items.

In #98, it was suggested to make a NBT helper check the active Minecraft version and switch on it. This approach could in principle be used by all NBT helpers and block transform functions. However, it has a few disadvantages:

  • Currently, these functions do not actually involve GDMC-HTTP at all. I would prefer to keep it that way, since it allows you to use them in situations where there's no Minecraft instance, such as when creating a model/schematic for later use. Making them require GDMC-HTTP access also means that the functions that didn't require an Editor instance now will, which will cause problems with cyclic imports and will certainly cause breaking changes in a lot of places.
  • This approach won't help users who manually specify blocks/entities/items instead of using helper functions like signData.
  • This won't allow us to support future Minecraft versions, though there are few approaches that will.

I think the ideal place to do version-conversions for Minecraft data is right before sending to or after receiving from GDMC-HTTP. This way, you capture all occurences of Minecraft data that needs to be converted, without requiring breaking changes anywhere else.

It seems that Amulet learned from the mistakes of MCEdit, because Amulet Core has a really clever solution to the version-conversion-problem in the form of PyMCTranslate. It uses a "universal format" for blocks (and I believe entities and items as well) which should not be directly used and can therefore be changed without breaking compatibility. When you read or write a block, you specify the Minecraft version you want to work in, and PyMCTranslate translates between that version and the universal format. And while I'm not sure about this, I believe this architecture even enables support for future Minecraft versions, since you could update PyMCTranslate without updating the rest of Amulet Core.

I think it would be possible to utilize PyMCTranslate in GDPC by using it to convert to or from the current Minecraft version right before interacting with GDMC-HTTP. The only problem is that I'm unsure if this is allowed by its license, specificially its non-conpetition restriction. GDPC with GDMC-HTTP might fall under "competition" as described there. But if we could use it, this seems like it would be an ideal solution.

Summary

To support multiple versions of Minecraft with the same version of GDPC, the following is needed:

  1. GDPC must become backwards compatible with regards to GDMC-HTTP, or GDMC-HTTP must become backwards compatible with regards to Minecraft. As long as this is not the case, supporting multiple Minecraft versions internally in GDPC is of little use.
  2. GDPC must internally support multiple versions of Minecraft, which requires fundamental changes in its block rotation/flipping system, its NBT data utility functions and in WorldSlice.

Metadata

Metadata

Assignees

Labels

big changeThis'll take a lot of workenhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions