Skip to content

Split conversion process into 3 parts, make converters more standalone#42

Merged
eclipseisoffline merged 13 commits into
GeyserMC:masterfrom
eclipseisoffline:converter-rework
Sep 21, 2025
Merged

Split conversion process into 3 parts, make converters more standalone#42
eclipseisoffline merged 13 commits into
GeyserMC:masterfrom
eclipseisoffline:converter-rework

Conversation

@eclipseisoffline

Copy link
Copy Markdown
Member

This PR refactors the converters of PackConverter. Essentially, the goal is to remove the "Pack" part of PackConverter: converters will be able to act more standalone from each other, allowing library users to manually convert assets loaded with Creative, instead of having PackConverter convert the entire resourcepack at once.

The conversion process has been turned into a pipeline consisting of 3 subprocesses:

  • The extraction of applicable assets to convert, e.g. all models in a resourcepack.
  • The conversion of a single asset to its bedrock counterpart.
  • The merging/combining of all converted bedrock assets, back into the bedrock resourcepack.

This process is much more modular compared to what converters are now (consisting of just a single function doing all of the above at once). This allows library users to use PackConverter however they see fit. On top of this, this could also make it easier to incorporate multithreading into PackConverter.

In the code, this results in the following changes (summarised):

  • The Converter and BaseConverter classes have been removed, and replaced by 3 functional interfaces representing each part of the conversion pipeline: AssetExtractor, AssetConverter, and AssetCombiner.
  • PackConversionContext and ConversionData and its subclasses have been removed. Conversion context/data is now divided between the various process contexts (ExtractionContext, ConversionContext, CombineContext) (only store very generic data) and the data AssetExtractors provide.
  • PackConverter now takes a list of ConverterPipelines, instead of Converters. A ConverterPipeline is a combination of an AssetExtractor, AssetConverter, and AssetCombiner. PackConverter will execute all pipelines upon starting pack conversion.
  • ConverterPipelines are registered in the AssetConverters class, which also contains utility methods to create 3rd-party pipelines.
  • ActionListener has been reworked and expanded with more functionality. It now executes between the various conversion pipeline processes (post extract, post convert, post merge). ActionListeners aren't registered globally at PackConverter anymore, rather, an ActionListener can be attached to a ConverterPipeline.
  • All converters have been refactored to work with the new conversion process. As a small benefit, the language converter now properly handles multiple namespaces containing language files for the same language.
  • The codebase has received a small cleanup that goes along refactors at this scale. BedrockResourcePack#addExtraFile can now take a JsonElement directly, for convenience and to reduce code duplication.

Most of this PR is in a finished state (barring any reviews or requested changes), however, texture conversion does not follow the pipeline accordingly. See the TODOs I have left there for more information.

I have tested this PR and PackConverter is functional with it. However, it could still use some more testing. Things I have tested are basic texture, model, language, splash, icon, and manifest conversion.

@onebeastchris onebeastchris left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! thanks for working on this :)

Comment thread converter/src/main/java/org/geysermc/pack/converter/converter/ActionListener.java Outdated
Comment on lines +35 to +36
public record ExtractionContext(@Deprecated(forRemoval = true) BedrockResourcePack bedrockResourcePack,
Optional<ResourcePack> vanillaPack, LogListener logListener) implements LogListenerHelper {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a deprecation note here would be neat

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this deprecation? All these changes are BC breaking so having a deprecation seems pointless

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deprecation was made because the bedrock resource pack should not be accessible here, as this is the context for the extraction phase. The bedrock pack should only be accessible in the last phase, where all converted bedrock assets are combined into the bedrock pack.

The reason this is still here is because the bedrock pack is written to by the texture transformers, which are executed in the extraction phase at the moment (even though they shouldn't be). I'll leave an explanation with more detail further below in a reply to another comment.

Comment on lines +92 to +95
// TODO: Convert item models but save differently?
if (value.startsWith("item/")) {
return null;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like something where it'd be useful to also check for the target mc version as item models are "new"?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is talking about the actual item models (in assets/<namespace>/models/item, which have existed for a long time), not the item definition assets in the assets/<namespace>/items directory. I should also note this comment wasn't left by me, Git is a bit weird with the blaming here.

Comment on lines +107 to +115
// TODO: Don't hardcode all this
Description description = new Description();
description.identifier(String.format(GEOMETRY_FORMAT, geoName));
description.textureWidth(16);
description.textureHeight(16);
description.visibleBoundsWidth(2);
description.visibleBoundsHeight(2);
description.visibleBoundsOffset(new float[] { 0.0f, 0.25f, 0.0f });
geometry.description(description);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these something the user would need to provide, or could these be automatically extracted?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know these things are the same values Blockbench uses for its Java -> bedrock model conversion, I'm not sure what exactly they affect. I'm also not sure if Blockbench always uses the same values, or if they are dependent on the model. I'd have to look into it.

Comment on lines +78 to +80
// TODO ideally textures should be transformed individually in the convert process, and not together in the extraction process, but this is hard to achieve,
// TODO and will need another big refactor to the texture transformation code
// TODO for now this will work, but for library users it might be nice to be able to properly convert singular textures with transformations

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the meantime: are those transformations done via utility methods? e.g. might be worth considering to add utils that'd allow creating bedrock textures from Java's

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't a user of the library just create their own and make sure the ServiceLoader catches it? Therefor adding it to the transformers list

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main issue the TODO is talking about here is the fact that texture transformations are executed within the extraction phase of the conversion pipeline. On top of this, there are also texture transformers that write to the bedrock pack, which is definitely not something that should happen, given these are executed in the extraction phase.

Ideally, texture transformers would be executed within the conversion phase, as that is essentially what they are doing: transforming/converting a texture from Java's format to bedrock's format. However, there are some texture transformers that take in multiple textures and merge them together, for example the atlas transformer, which takes in multiple Java textures to transform them into a single atlas image for bedrock. This causes some issues when trying to use them in the conversion phase, as that only takes one texture at a time at the moment.

On top of this, the texture transformers are not really built to work this way. TransformContext has poll, peek, and offer methods. Essentially, the way transformers are designed now, all textures are taken from the Java resourcepack, taken through all the transformers (which can poll any of the textures in the resourcepack, and offer a transformed one), and then taken to the mapping process.

Personally, I think it is best to register texture transformers for a "texture group": this limits which textures texture transformers can touch, and allows the extraction phase to simply group all textures in a resourcepack (not-transformed ones would all go in an "untransformed" group). The actual converter can then invoke the transformer of a group, if any exists, and map the resulting textures afterwards, and return them for the combiner to merge into the bedrock pack.

These changes would allow library users to have more control over which textures are transformed and which aren't, along with other benefits, such as having individual textures transformed without having to provide an entire resourcepack. Overall it would follow the design pattern of the conversion pipeline better.

However, these changes would lead to pretty decent refactors to the texture transforming system. I'm fine with including those in this PR, but that would give it a bit of a delay. I could also make them later on, however that'd result in 2 breaking changes shortly after each other.

@rtm516 rtm516 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly nitpics around copyright.
Can we also change the org.geysermc.pack.converter.converter package to be something else, provided we can find something else that makes sense?

Comment on lines +78 to +80
// TODO ideally textures should be transformed individually in the convert process, and not together in the extraction process, but this is hard to achieve,
// TODO and will need another big refactor to the texture transformation code
// TODO for now this will work, but for library users it might be nice to be able to properly convert singular textures with transformations

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't a user of the library just create their own and make sure the ServiceLoader catches it? Therefor adding it to the transformers list

@eclipseisoffline

Copy link
Copy Markdown
Member Author

Will fix the copyright changes with the next commit. I'm not sure what a good alternative name would be for the org.geysermc.pack.converter.converter package though.

@eclipseisoffline eclipseisoffline merged commit a344cd3 into GeyserMC:master Sep 21, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants