From a344cd37f77279b5e706967b58610fc2410f049b Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sun, 21 Sep 2025 19:43:37 +0000 Subject: [PATCH] Split conversion process into 3 parts, make converters more standalone (#42) * Work on splitting converters * Properly split converting of sound registries and sounds * Testing stuff * Implement splitting of texture conversion, still some things to do * Add bedrock pack back to TransformContext * Transition * AssetCollector -> AssetCombiner * Remove unnecessary interfaces * Re-implement action listeners * Final things * Cleanup * Some Javadocs, fixup copyright * Relocate pipeline classes and rename converter package -> type, create KeyUtil to lessen code warnings --- .../pack/converter/bootstrap/Main.java | 4 +- .../pack/converter/bootstrap/ThunderGUI.java | 4 +- .../pack/converter/PackConversionContext.java | 71 ----- .../pack/converter/PackConverter.java | 80 +---- .../converter/lang/LangConverter.java | 75 ----- .../converter/model/ModelConverter.java | 261 ---------------- .../converter/sound/SoundConverter.java | 92 ------ .../converter/texture/TextureConverter.java | 207 ------------- .../converter/data/BaseConversionData.java | 62 ---- .../converter/data/ModelConversionData.java | 58 ---- .../converter/data/TextureConversionData.java | 61 ---- .../converter/pipeline/ActionListener.java | 78 +++++ .../converter/pipeline/AssetCombiner.java | 37 +++ .../converter/pipeline/AssetConverter.java | 36 +++ .../converter/pipeline/AssetConverters.java | 134 +++++++++ .../AssetExtractor.java} | 19 +- .../converter/pipeline/CombineContext.java | 33 +++ .../converter/pipeline/ConversionContext.java | 33 +++ .../converter/pipeline/ConverterPipeline.java | 113 +++++++ .../ExtractionContext.java} | 37 +-- .../base/PackIconConverter.java | 44 +-- .../base/PackManifestConverter.java | 31 +- .../lang/BedrockLanguage.java} | 9 +- .../converter/type/lang/LangConverter.java | 89 ++++++ .../misc/SplashTextConverter.java | 35 +-- .../model/BedrockModel.java} | 19 +- .../converter/type/model/ModelConverter.java | 278 ++++++++++++++++++ .../model/ModelStitcher.java | 8 +- .../converter/type/sound/SoundConverter.java | 78 +++++ .../type/sound/SoundRegistryConverter.java | 92 ++++++ .../texture/PngToTgaMappings.java | 6 +- .../type/texture/TextureConverter.java | 218 ++++++++++++++ .../texture/TextureMappings.java | 3 +- .../transformer/TextureTransformer.java | 2 +- .../texture/transformer/TransformContext.java | 57 ++-- .../transformer/TransformedTexture.java | 18 +- .../transformer/type/AtlasTransformer.java | 11 +- .../transformer/type/ColorizeTransformer.java | 9 +- .../transformer/type/OverlayTransformer.java | 13 +- .../transformer/type/WeatherTransformer.java | 15 +- .../type/block/BedTransformer.java | 11 +- .../type/block/ChestDoubleTransformer.java | 13 +- .../type/block/ChestFrontTransformer.java | 11 +- .../type/block/ChestNormalTransformer.java | 11 +- .../type/block/ChestSideTransformer.java | 11 +- .../type/block/ConduitTransformer.java | 21 +- .../type/block/LiquidTransformer.java | 11 +- .../type/block/TallSeagrassTransformer.java | 19 +- .../type/entity/ArrowTransformer.java | 11 +- .../type/entity/DolphinTransformer.java | 13 +- .../type/entity/DrownedTransformer.java | 13 +- .../type/entity/PaintingTransformer.java | 21 +- .../type/entity/SheepTransformer.java | 15 +- .../type/entity/VillagerTransformer.java | 11 +- .../type/entity/ZombieTransformer.java | 13 +- .../type/item/BundleTransformer.java | 15 +- .../particle/BaseParticleTransformer.java | 17 +- .../particle/CampfireParticleTransformer.java | 4 +- .../SculkChargeParticleTransformer.java | 4 +- .../SculkChargePopParticleTransformer.java | 4 +- .../SculkSoulParticleTransformer.java | 4 +- .../SonicExplosionParticleTransformer.java | 4 +- .../particle/SoulParticleTransformer.java | 4 +- .../SpritesheetParticleTransformer.java | 11 +- .../transformer/type/ui/FontTransformer.java | 51 ++-- .../type/ui/HotbarTransformer.java | 21 +- .../type/ui/LocatorTransformer.java | 26 +- .../transformer/type/ui/SignTransformer.java | 13 +- .../transformer/type/ui/TitleTransformer.java | 13 +- .../type/ui/UISizeTransformer.java | 23 +- .../BaseConverter.java => util/KeyUtil.java} | 21 +- .../LogListenerHelper.java} | 35 ++- .../converter/util/VanillaPackProvider.java | 15 +- .../bedrock/resource/BedrockResourcePack.java | 23 +- 74 files changed, 1672 insertions(+), 1371 deletions(-) delete mode 100644 converter/src/main/java/org/geysermc/pack/converter/PackConversionContext.java delete mode 100644 converter/src/main/java/org/geysermc/pack/converter/converter/lang/LangConverter.java delete mode 100644 converter/src/main/java/org/geysermc/pack/converter/converter/model/ModelConverter.java delete mode 100644 converter/src/main/java/org/geysermc/pack/converter/converter/sound/SoundConverter.java delete mode 100644 converter/src/main/java/org/geysermc/pack/converter/converter/texture/TextureConverter.java delete mode 100644 converter/src/main/java/org/geysermc/pack/converter/data/BaseConversionData.java delete mode 100644 converter/src/main/java/org/geysermc/pack/converter/data/ModelConversionData.java delete mode 100644 converter/src/main/java/org/geysermc/pack/converter/data/TextureConversionData.java create mode 100644 converter/src/main/java/org/geysermc/pack/converter/pipeline/ActionListener.java create mode 100644 converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetCombiner.java create mode 100644 converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetConverter.java create mode 100644 converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetConverters.java rename converter/src/main/java/org/geysermc/pack/converter/{data/ConversionData.java => pipeline/AssetExtractor.java} (78%) create mode 100644 converter/src/main/java/org/geysermc/pack/converter/pipeline/CombineContext.java create mode 100644 converter/src/main/java/org/geysermc/pack/converter/pipeline/ConversionContext.java create mode 100644 converter/src/main/java/org/geysermc/pack/converter/pipeline/ConverterPipeline.java rename converter/src/main/java/org/geysermc/pack/converter/{converter/Converter.java => pipeline/ExtractionContext.java} (57%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/base/PackIconConverter.java (50%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/base/PackManifestConverter.java (68%) rename converter/src/main/java/org/geysermc/pack/converter/{Constants.java => type/lang/BedrockLanguage.java} (85%) create mode 100644 converter/src/main/java/org/geysermc/pack/converter/type/lang/LangConverter.java rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/misc/SplashTextConverter.java (55%) rename converter/src/main/java/org/geysermc/pack/converter/{converter/ActionListener.java => type/model/BedrockModel.java} (71%) create mode 100644 converter/src/main/java/org/geysermc/pack/converter/type/model/ModelConverter.java rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/model/ModelStitcher.java (95%) create mode 100644 converter/src/main/java/org/geysermc/pack/converter/type/sound/SoundConverter.java create mode 100644 converter/src/main/java/org/geysermc/pack/converter/type/sound/SoundRegistryConverter.java rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/PngToTgaMappings.java (99%) create mode 100644 converter/src/main/java/org/geysermc/pack/converter/type/texture/TextureConverter.java rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/TextureMappings.java (96%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/TextureTransformer.java (96%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/TransformContext.java (78%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/TransformedTexture.java (80%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/AtlasTransformer.java (85%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/ColorizeTransformer.java (99%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/OverlayTransformer.java (94%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/WeatherTransformer.java (83%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/block/BedTransformer.java (90%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/block/ChestDoubleTransformer.java (92%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/block/ChestFrontTransformer.java (86%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/block/ChestNormalTransformer.java (90%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/block/ChestSideTransformer.java (85%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/block/ConduitTransformer.java (75%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/block/LiquidTransformer.java (86%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/block/TallSeagrassTransformer.java (70%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/entity/ArrowTransformer.java (87%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/entity/DolphinTransformer.java (97%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/entity/DrownedTransformer.java (82%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/entity/PaintingTransformer.java (90%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/entity/SheepTransformer.java (87%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/entity/VillagerTransformer.java (87%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/entity/ZombieTransformer.java (84%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/item/BundleTransformer.java (81%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/particle/BaseParticleTransformer.java (91%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/particle/CampfireParticleTransformer.java (91%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/particle/SculkChargeParticleTransformer.java (91%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/particle/SculkChargePopParticleTransformer.java (91%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/particle/SculkSoulParticleTransformer.java (91%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/particle/SonicExplosionParticleTransformer.java (91%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/particle/SoulParticleTransformer.java (91%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/particle/SpritesheetParticleTransformer.java (87%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/ui/FontTransformer.java (92%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/ui/HotbarTransformer.java (79%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/ui/LocatorTransformer.java (79%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/ui/SignTransformer.java (84%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/ui/TitleTransformer.java (81%) rename converter/src/main/java/org/geysermc/pack/converter/{converter => type}/texture/transformer/type/ui/UISizeTransformer.java (77%) rename converter/src/main/java/org/geysermc/pack/converter/{converter/BaseConverter.java => util/KeyUtil.java} (71%) rename converter/src/main/java/org/geysermc/pack/converter/{converter/Converters.java => util/LogListenerHelper.java} (62%) diff --git a/bootstrap/src/main/java/org/geysermc/pack/converter/bootstrap/Main.java b/bootstrap/src/main/java/org/geysermc/pack/converter/bootstrap/Main.java index 09eaef4..98b6865 100644 --- a/bootstrap/src/main/java/org/geysermc/pack/converter/bootstrap/Main.java +++ b/bootstrap/src/main/java/org/geysermc/pack/converter/bootstrap/Main.java @@ -28,7 +28,7 @@ package org.geysermc.pack.converter.bootstrap; import com.formdev.flatlaf.intellijthemes.FlatArcDarkIJTheme; import org.geysermc.pack.converter.PackConverter; -import org.geysermc.pack.converter.converter.Converters; +import org.geysermc.pack.converter.pipeline.AssetConverters; import java.io.*; import java.nio.file.Path; @@ -77,7 +77,7 @@ public class Main { .input(Path.of(inputPath)) .output(Path.of(outputPath)) .packName(packName) - .converters(Converters.defaultConverters(debug)) + .converters(AssetConverters.converters(debug)) .convert() .pack(); } else { diff --git a/bootstrap/src/main/java/org/geysermc/pack/converter/bootstrap/ThunderGUI.java b/bootstrap/src/main/java/org/geysermc/pack/converter/bootstrap/ThunderGUI.java index 34e5a09..0358048 100644 --- a/bootstrap/src/main/java/org/geysermc/pack/converter/bootstrap/ThunderGUI.java +++ b/bootstrap/src/main/java/org/geysermc/pack/converter/bootstrap/ThunderGUI.java @@ -28,7 +28,7 @@ package org.geysermc.pack.converter.bootstrap; import com.twelvemonkeys.image.BufferedImageIcon; import org.geysermc.pack.converter.PackConverter; -import org.geysermc.pack.converter.converter.Converters; +import org.geysermc.pack.converter.pipeline.AssetConverters; import org.geysermc.pack.converter.util.ImageUtil; import org.geysermc.pack.converter.util.ZipUtils; @@ -128,7 +128,7 @@ public class ThunderGUI extends JFrame { .output(outputPath) .packName(packName.getText().isBlank() ? inputPath.getFileName().toString() : packName.getText()) .vanillaPackPath(vanillaPackPath) - .converters(Converters.defaultConverters(this.debugMode.get())) + .converters(AssetConverters.converters(this.debugMode.get())) .logListener(logListener) .convert() .pack(); diff --git a/converter/src/main/java/org/geysermc/pack/converter/PackConversionContext.java b/converter/src/main/java/org/geysermc/pack/converter/PackConversionContext.java deleted file mode 100644 index b92aaaa..0000000 --- a/converter/src/main/java/org/geysermc/pack/converter/PackConversionContext.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/PackConverter - * - */ - -package org.geysermc.pack.converter; - -import org.geysermc.pack.bedrock.resource.BedrockResourcePack; -import org.geysermc.pack.converter.data.ConversionData; -import org.geysermc.pack.converter.util.LogListener; -import org.jetbrains.annotations.NotNull; -import team.unnamed.creative.ResourcePack; - -import java.nio.file.Path; - -public record PackConversionContext( - @NotNull T data, - @NotNull PackConverter packConverter, - @NotNull ResourcePack javaResourcePack, - @NotNull BedrockResourcePack bedrockResourcePack, - @NotNull LogListener logListener) { - - public Path inputDirectory() { - return this.data.inputDirectory(); - } - - public Path outputDirectory() { - return this.data.outputDirectory(); - } - - public void debug(@NotNull String message) { - this.logListener.debug(message); - } - - public void info(@NotNull String message) { - this.logListener.info(message); - } - - public void warn(@NotNull String message) { - this.logListener.warn(message); - } - - public void error(@NotNull String message) { - this.logListener.error(message); - } - - public void error(@NotNull String message, @NotNull Throwable exception) { - this.logListener.error(message, exception); - } -} diff --git a/converter/src/main/java/org/geysermc/pack/converter/PackConverter.java b/converter/src/main/java/org/geysermc/pack/converter/PackConverter.java index 4da4638..f346951 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/PackConverter.java +++ b/converter/src/main/java/org/geysermc/pack/converter/PackConverter.java @@ -28,10 +28,12 @@ package org.geysermc.pack.converter; import org.apache.commons.io.file.PathUtils; import org.geysermc.pack.bedrock.resource.BedrockResourcePack; -import org.geysermc.pack.converter.converter.ActionListener; -import org.geysermc.pack.converter.converter.Converter; -import org.geysermc.pack.converter.data.ConversionData; -import org.geysermc.pack.converter.util.*; +import org.geysermc.pack.converter.pipeline.ConverterPipeline; +import org.geysermc.pack.converter.util.DefaultLogListener; +import org.geysermc.pack.converter.util.LogListener; +import org.geysermc.pack.converter.util.NioDirectoryFileTreeReader; +import org.geysermc.pack.converter.util.VanillaPackProvider; +import org.geysermc.pack.converter.util.ZipUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import team.unnamed.creative.ResourcePack; @@ -43,9 +45,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.IdentityHashMap; import java.util.List; -import java.util.Map; +import java.util.Optional; import java.util.function.BiConsumer; /** @@ -63,11 +64,9 @@ public final class PackConverter { private boolean compressed; private boolean enforcePackCheck = false; - private final Map, List>> actionListeners = new IdentityHashMap<>(); - private BiConsumer postProcessor; - private final List> converters = new ArrayList<>(); + private final List> converters = new ArrayList<>(); private Path tmpDir; @@ -187,7 +186,7 @@ public final class PackConverter { * @param converter the converter to add * @return this instance */ - public PackConverter converter(@NotNull Converter converter) { + public PackConverter converter(@NotNull ConverterPipeline converter) { this.converters.add(converter); return this; } @@ -198,7 +197,7 @@ public final class PackConverter { * @param converters the converters to add * @return this instance */ - public PackConverter converters(@NotNull List> converters) { + public PackConverter converters(@NotNull List> converters) { this.converters.addAll(converters); return this; } @@ -227,42 +226,6 @@ public final class PackConverter { return this; } - /** - * Sets a list of action listeners for a specific conversion data class. - *

- * This is particularly useful for external programs that may rely on - * various bits of information from the pack converter at different - * stages. - * - * @param clazz the conversion data class - * @param actionListeners the action listeners - * @return this instance - * @param the conversion data type - */ - public PackConverter actionListeners(@NotNull Class clazz, @NotNull ActionListener... actionListeners) { - this.actionListeners.put(clazz, List.of(actionListeners)); - return this; - } - - /** - * Sets the action listeners. - *

- * This is particularly useful for external programs that may rely on - * various bits of information from the pack converter at different - * stages. - * - * @param actionListeners the action listeners - * @return this instance - * @param the conversion data type - */ - public PackConverter actionListeners(@NotNull Map, List>> actionListeners) { - for (Map.Entry, List>> entry : actionListeners.entrySet()) { - this.actionListeners.put(entry.getKey(), (List) entry.getValue()); - } - - return this; - } - /** * Sets the post processor for the converted resource pack. *

@@ -320,25 +283,10 @@ public final class PackConverter { ResourcePack vanillaResourcePack = MinecraftResourcePackReader.minecraft().readFromZipFile(vanillaPackPath); BedrockResourcePack bedrockResourcePack = new BedrockResourcePack(this.tmpDir); - final Converter.ConversionDataCreationContext conversionDataCreationContext = new Converter.ConversionDataCreationContext( - this, logListener, input, this.tmpDir, javaResourcePack, vanillaResourcePack - ); - - int errors = 0; - for (Converter converter : this.converters) { - ConversionData data = converter.createConversionData(conversionDataCreationContext); - PackConversionContext context = new PackConversionContext<>(data, this, javaResourcePack, bedrockResourcePack, this.logListener); - - List> actionListeners = this.actionListeners.getOrDefault(data.getClass(), List.of()); - try { - actionListeners.forEach(actionListener -> actionListener.preConvert((PackConversionContext) context)); - converter.convert(context); - actionListeners.forEach(actionListener -> actionListener.postConvert((PackConversionContext) context)); - } catch (Throwable t) { - this.logListener.error("Error converting pack!", t); - errors++; - } - } + int errors = converters.stream() + .mapToInt(converter -> converter.convert(javaResourcePack, Optional.of(vanillaResourcePack), + bedrockResourcePack, packName(), textureSubdirectory, logListener)) + .sum(); if (this.postProcessor != null) { this.postProcessor.accept(javaResourcePack, bedrockResourcePack); diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/lang/LangConverter.java b/converter/src/main/java/org/geysermc/pack/converter/converter/lang/LangConverter.java deleted file mode 100644 index 8f7fc64..0000000 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/lang/LangConverter.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/PackConverter - * - */ - -package org.geysermc.pack.converter.converter.lang; - -import com.google.auto.service.AutoService; -import org.geysermc.pack.converter.PackConversionContext; -import org.geysermc.pack.converter.converter.BaseConverter; -import org.geysermc.pack.converter.converter.Converter; -import org.geysermc.pack.converter.data.BaseConversionData; -import org.jetbrains.annotations.NotNull; -import team.unnamed.creative.lang.Language; - -import java.util.Collection; -import java.util.Map; -import java.util.regex.Pattern; - -@AutoService(Converter.class) -public class LangConverter extends BaseConverter { - private static final String BEDROCK_TEXTS_LOCATION = "texts"; - - private final Pattern positionalStringReplacement = Pattern.compile("%([0-9]+)\\$s"); - - @Override - public void convert(@NotNull PackConversionContext context) throws Exception { - Collection languages = context.javaResourcePack().languages(); - for (Language language : languages) { - Map strings = language.translations(); - - for (Map.Entry entry : strings.entrySet()) { - String value = entry.getValue(); - - // Replace %d with %s - value = value.replace("%d", "%s"); - - // Replace `%x$s` with `%x` - value = positionalStringReplacement.matcher(value).replaceAll("%$1"); - - entry.setValue(value); - } - - String languageKey = language.key().value(); - - // Convert the language key to the Bedrock equivalent - if (languageKey.equals("no_no")) { - languageKey = "nb_no"; - } - - context.bedrockResourcePack().addLanguage(languageKey, strings); - } - } -} diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/model/ModelConverter.java b/converter/src/main/java/org/geysermc/pack/converter/converter/model/ModelConverter.java deleted file mode 100644 index aecc4f0..0000000 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/model/ModelConverter.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/PackConverter - * - */ - -package org.geysermc.pack.converter.converter.model; - -import com.google.auto.service.AutoService; -import net.kyori.adventure.key.Key; -import org.geysermc.pack.bedrock.resource.BedrockResourcePack; -import org.geysermc.pack.bedrock.resource.models.entity.ModelEntity; -import org.geysermc.pack.bedrock.resource.models.entity.modelentity.Geometry; -import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.Bones; -import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.Description; -import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.Cubes; -import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.Uv; -import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.Down; -import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.East; -import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.North; -import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.South; -import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.Up; -import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.West; -import org.geysermc.pack.converter.PackConversionContext; -import org.geysermc.pack.converter.converter.Converter; -import org.geysermc.pack.converter.data.ModelConversionData; -import org.jetbrains.annotations.NotNull; -import team.unnamed.creative.ResourcePack; -import team.unnamed.creative.base.CubeFace; -import team.unnamed.creative.model.Element; -import team.unnamed.creative.model.ElementFace; -import team.unnamed.creative.model.ElementRotation; -import team.unnamed.creative.model.Model; -import team.unnamed.creative.texture.TextureUV; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -@AutoService(Converter.class) -public class ModelConverter implements Converter { - private static final String FORMAT_VERSION = "1.16.0"; - private static final String GEOMETRY_FORMAT = "geometry.%s"; - - private static final float[] ELEMENT_OFFSET = new float[] { 8, 0, 8 }; - - @Override - public void convert(@NotNull PackConversionContext context) throws Exception { - ResourcePack javaPack = context.javaResourcePack(); - BedrockResourcePack bedrockPack = context.bedrockResourcePack(); - Collection models = javaPack.models(); - if (models.isEmpty()) { - return; - } - - ModelStitcher.Provider provider = context.data().getModelProvider(); - for (Model model : models) { - model = new ModelStitcher(provider, model, context.logListener()).stitch(); - - List elements = model.elements(); - if (elements.isEmpty()) { - context.debug("Model " + model.key().key() + " has no elements"); - continue; - } - - String value = model.key().value(); - context.debug("Converting model " + model.key().key() + ":" + value); - - // TODO: Convert item models but save differently? - if (value.startsWith("item/")) { - continue; - } - - ModelEntity modelEntity = new ModelEntity(); - modelEntity.formatVersion(FORMAT_VERSION); - - Geometry geometry = new Geometry(); - - String namespace = model.key().namespace(); - String fileName = value.substring(value.lastIndexOf('/') + 1); - - String geoName = (namespace.equals(Key.MINECRAFT_NAMESPACE) ? "" : namespace + ".") + fileName; - - // 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); - - List bones = new ArrayList<>(); - - // TODO: Should each element be its own bone rather - // than its own cube in the same bone? - int i = 0; - for (Element element : elements) { - float[] from = element.from().toArray(); - float[] to = element.to().toArray(); - - Bones bone = new Bones(); - bone.name("bone_" + i++); - bone.pivot(new float[] { ELEMENT_OFFSET[0], ELEMENT_OFFSET[1], -ELEMENT_OFFSET[2] }); - - Cubes cube = new Cubes(); - cube.origin(new float[] { ELEMENT_OFFSET[0] - to[0], from[1], from[2] - ELEMENT_OFFSET[2] }); - cube.size(new float[] { to[0] - from[0], to[1] - from[1], to[2] - from[2] }); - - ElementRotation elementRotation = element.rotation(); - if (elementRotation != null) { - float[] origin = elementRotation.origin().toArray(); - cube.pivot(new float[] { ELEMENT_OFFSET[0] - origin[0], ELEMENT_OFFSET[1] - origin[1], origin[2] - ELEMENT_OFFSET[2] }); - - float angle = elementRotation.angle(); - float[] rotation = new float[3]; - switch (elementRotation.axis()) { - case X -> rotation[0] = -angle; - case Y -> rotation[1] = -angle; - case Z -> rotation[2] = -angle; - } - - cube.rotation(rotation); - } - - Uv uv = new Uv(); - for (Map.Entry entry : element.faces().entrySet()) { - CubeFace face = entry.getKey(); - ElementFace elementFace = entry.getValue(); - if (elementFace.uv0() == null) { - continue; - } - - // The Java pack lib we use does this weird thing where it - // divides the UV by 16, so we need to multiply it by 16 - - String texture = elementFace.texture().replace("#", ""); - applyUv(uv, face, texture, multiplyUv(elementFace.uv0(), 16f)); - } - - cube.uv(uv); - bone.cubes(List.of(cube)); - - bones.add(bone); - } - - geometry.bones(bones); - - modelEntity.geometry(List.of(geometry)); - - if (model.key().namespace().contains("entity")) { - bedrockPack.addEntityModel(modelEntity, fileName + ".json"); - } else { - // Bedrock only has a concept of entity or block models - bedrockPack.addBlockModel(modelEntity, fileName + ".json"); - } - - context.data().addStitchedModel(model); - } - } - - @Override - public ModelConversionData createConversionData(@NotNull ConversionDataCreationContext context) { - return new ModelConversionData( - context.inputDirectory(), context.outputDirectory(), - ModelStitcher.vanillaProvider(context.javaResourcePack(), context.logListener(), context.vanillaResourcePack()), - context.vanillaResourcePack() - ); - } - - private TextureUV multiplyUv(TextureUV textureUV, float mult) { - return TextureUV.uv(textureUV.from().multiply(mult), textureUV.to().multiply(mult)); - } - - private static void applyUv(Uv uv, CubeFace face, String texture, TextureUV faceUv) { - float[] uvs; - float[] uvSize; - - // These values are flipped for some reason - if (face == CubeFace.DOWN || face == CubeFace.UP) { - uvs = new float[] { faceUv.to().x(), faceUv.to().y() }; - uvSize = new float[] { faceUv.from().x() - faceUv.to().x(), faceUv.from().y() - faceUv.to().y() }; - } else { - uvs = new float[] { faceUv.from().x(), faceUv.from().y() }; - uvSize = new float[] { faceUv.to().x() - faceUv.from().x(), faceUv.to().y() - faceUv.from().y() }; - } - - switch (face) { - case NORTH -> { - North north = new North(); - north.uv(uvs); - north.uvSize(uvSize); - north.materialInstance(texture); - - uv.north(north); - } - case SOUTH -> { - South south = new South(); - south.uv(uvs); - south.uvSize(uvSize); - south.materialInstance(texture); - - uv.south(south); - } - case EAST -> { - East east = new East(); - east.uv(uvs); - east.uvSize(uvSize); - east.materialInstance(texture); - - uv.east(east); - } - case WEST -> { - West west = new West(); - west.uv(uvs); - west.uvSize(uvSize); - west.materialInstance(texture); - - uv.west(west); - } - case UP -> { - Up up = new Up(); - up.uv(uvs); - up.uvSize(uvSize); - up.materialInstance(texture); - - uv.up(up); - } - case DOWN -> { - Down down = new Down(); - down.uv(uvs); - down.uvSize(uvSize); - down.materialInstance(texture); - - uv.down(down); - } - } - } -} diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/sound/SoundConverter.java b/converter/src/main/java/org/geysermc/pack/converter/converter/sound/SoundConverter.java deleted file mode 100644 index ff582a0..0000000 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/sound/SoundConverter.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/PackConverter - * - */ - -package org.geysermc.pack.converter.converter.sound; - -import com.google.auto.service.AutoService; -import org.apache.commons.io.file.PathUtils; -import org.geysermc.pack.bedrock.resource.sounds.sounddefinitions.SoundDefinitions; -import org.geysermc.pack.bedrock.resource.sounds.sounddefinitions.Sounds; -import org.geysermc.pack.converter.Constants; -import org.geysermc.pack.converter.PackConversionContext; -import org.geysermc.pack.converter.converter.BaseConverter; -import org.geysermc.pack.converter.converter.Converter; -import org.geysermc.pack.converter.data.BaseConversionData; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Unmodifiable; -import team.unnamed.creative.sound.SoundEntry; -import team.unnamed.creative.sound.SoundEvent; -import team.unnamed.creative.sound.SoundRegistry; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.Collection; - -@AutoService(Converter.class) -public class SoundConverter extends BaseConverter { - private static final String JAVA_SOUNDS_LOCATION = Constants.JAVA_PACK_LOCATION + "/sounds"; - private static final String BEDROCK_SOUNDS_LOCATION = "sounds"; - - @Override - public void convert(@NotNull PackConversionContext context) throws Exception { - Collection registry = context.javaResourcePack().soundRegistries(); - for (SoundRegistry soundRegistry : registry) { - @Unmodifiable @NotNull Collection sounds = soundRegistry.sounds(); - - for (SoundEvent value : sounds) { - String key = value.key().asString(); - - SoundDefinitions definition = new SoundDefinitions(); - definition.useLegacyMaxDistance(true); // TODO: Needed? - definition.maxDistance(64); // ??? - for (SoundEntry sound : value.sounds()) { - Sounds bedrockSound = new Sounds(); - bedrockSound.name(BEDROCK_SOUNDS_LOCATION + "/" + sound.key().value()); - bedrockSound.stream(sound.stream()); - bedrockSound.loadOnLowMemory(true); - bedrockSound.volume(sound.volume()); - bedrockSound.pitch(sound.pitch()); - bedrockSound.weight(sound.weight()); - - definition.sounds().add(bedrockSound); - } - - context.bedrockResourcePack().addSoundDefinition(key, definition); - } - - // Relocate sound files - Path input = context.inputDirectory().resolve(String.format(JAVA_SOUNDS_LOCATION, soundRegistry.namespace())); - Path output = context.outputDirectory().resolve(BEDROCK_SOUNDS_LOCATION); - - if (Files.notExists(output)) { - Files.createDirectories(output); - } - - PathUtils.copyDirectory(input, output, StandardCopyOption.REPLACE_EXISTING); - } - } -} diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/TextureConverter.java b/converter/src/main/java/org/geysermc/pack/converter/converter/texture/TextureConverter.java deleted file mode 100644 index 17e7332..0000000 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/TextureConverter.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/PackConverter - * - */ - -package org.geysermc.pack.converter.converter.texture; - -import com.google.auto.service.AutoService; -import org.geysermc.pack.converter.PackConversionContext; -import org.geysermc.pack.converter.converter.Converter; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; -import org.geysermc.pack.converter.converter.texture.transformer.TransformedTexture; -import org.geysermc.pack.converter.data.TextureConversionData; -import org.geysermc.pack.converter.util.ImageUtil; -import org.jetbrains.annotations.NotNull; -import team.unnamed.creative.texture.Texture; - -import javax.imageio.ImageIO; -import java.awt.AlphaComposite; -import java.awt.Graphics2D; -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.stream.StreamSupport; - -@AutoService(Converter.class) -public class TextureConverter implements Converter { - public static final String BEDROCK_TEXTURES_LOCATION = "textures"; - - private final List transformers = StreamSupport.stream(ServiceLoader.load(TextureTransformer.class).spliterator(), false) - .sorted(Comparator.comparingInt(TextureTransformer::order)) - .toList(); - - public static final Map DIRECTORY_LOCATIONS = Map.of( - "block", "blocks", - "item", "items", - "gui", "ui" - ); - - @Override - public void convert(@NotNull PackConversionContext context) throws Exception { - TextureMappings mappings = TextureMappings.textureMappings(); - - List textures = new ArrayList<>(context.javaResourcePack().textures()); - - context.info("Transforming textures..."); - TransformContext transformContext = new TransformContext( - context, - mappings, - textures, - context.bedrockResourcePack(), - context.javaResourcePack() - ); - for (TextureTransformer transformer : this.transformers) { - transformer.transform(transformContext); - } - context.info("Transformed textures!"); - - context.info("Writing textures..."); - - for (Texture texture : textures) { - String input = texture.key().value(); - Path texturePath = context.outputDirectory().resolve(BEDROCK_TEXTURES_LOCATION); - Path potentialOutput = texturePath.resolve(input); - String relativePath = texturePath.relativize(potentialOutput).toString().replace(File.separatorChar, '/'); - - if (relativePath.endsWith(".png")) relativePath = relativePath.substring(0, relativePath.length() - 4); - - String rootPath = relativePath.substring(0, relativePath.indexOf('/')); - String bedrockRoot = DIRECTORY_LOCATIONS.getOrDefault(rootPath, rootPath); - - List outputs = new ArrayList<>(); - List outputPaths = new ArrayList<>(); - - Object mappingObject = mappings.textures(relativePath); - - if (mappingObject == null) { - mappingObject = mappings.textures(rootPath); - } - - String fallbackPath = bedrockRoot + "/" + relativePath.substring(relativePath.indexOf('/') + 1) + ".png"; - if (mappingObject instanceof Map keyMappings) { // Handles common subdirectories - String sanitizedName = input.substring(input.indexOf('/') + 1); - if (sanitizedName.endsWith(".png")) sanitizedName = sanitizedName.substring(0, sanitizedName.length() - 4); - - Object bedrockOutput = keyMappings.get(sanitizedName); - if (bedrockOutput instanceof String bedrockPath) { - outputPaths.add(bedrockRoot + "/" + bedrockPath + ".png"); - } else if (bedrockOutput instanceof List paths) { - for (String bedrockPath : (List) paths) { - outputPaths.add(bedrockRoot + "/" + bedrockPath + ".png"); - } - } else { // Fallback - outputPaths.add(fallbackPath); - } - } else if (mappingObject instanceof String str) { // Direct mappings - outputPaths.add(str + ".png"); - } else if (mappingObject instanceof List paths) { // Mappings where duplicate code paths exist - for (String path : (List) paths) { - outputPaths.add(path + ".png"); - } - } else { // Fallback - outputPaths.add(fallbackPath); - } - - String bedrockDirectory = "%s/%s"; - if (context.data().textureSubdirectory() != null) { - bedrockDirectory = "%s/" + context.data().textureSubdirectory() + "/%s"; - } - - for (String outputPath : outputPaths) { - context.debug(String.format("Converted %s to %s, writing texture.", input, outputPath)); - - String root = outputPath.substring(0, outputPath.indexOf('/')); - String value = outputPath.substring(outputPath.indexOf('/') + 1); - - outputs.add(texturePath.resolve(( - bedrockDirectory.formatted(root, value) - ).replace('/', File.separatorChar))); - } - - byte[] bytes = texture.data().toByteArray(); - - BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); - - for (Path output : outputs) { - TransformedTexture transformedTexture = new TransformedTexture(texture, output); - - if (output.getParent() != null && Files.notExists(output.getParent())) { - Files.createDirectories(output.getParent()); - } - - BufferedImage bedrockImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB); - - Graphics2D g = bedrockImage.createGraphics(); - g.setComposite(AlphaComposite.Src); - g.drawImage(image, 0, 0, null); - g.dispose(); - - String pngKey = context.outputDirectory().relativize(output).toString().replace(File.separatorChar, '/'); - PngToTgaMappings.TgaMapping mapping = PngToTgaMappings.mapping(pngKey); - if (mapping != null) { - Path tgaPath = context.outputDirectory().resolve(mapping.value()); - if (Files.notExists(tgaPath.getParent())) { - Files.createDirectories(tgaPath.getParent()); - } - - ImageUtil.writeTGA(tgaPath, bedrockImage); - if (!mapping.keep()) { - Files.deleteIfExists(output); - continue; - } - } - - try (OutputStream stream = Files.newOutputStream(output)) { - ImageIO.write(bedrockImage, "png", stream); - } - - context.data().addTransformedTexture(transformedTexture); - } - } - - context.info("Written textures!"); - - context.info("Texture conversion complete!"); - } - - @Override - public TextureConversionData createConversionData(@NotNull ConversionDataCreationContext context) { - return new TextureConversionData( - context.inputDirectory(), - context.outputDirectory(), - context.converter().textureSubdirectory(), - context.vanillaResourcePack() - ); - } -} diff --git a/converter/src/main/java/org/geysermc/pack/converter/data/BaseConversionData.java b/converter/src/main/java/org/geysermc/pack/converter/data/BaseConversionData.java deleted file mode 100644 index eded19b..0000000 --- a/converter/src/main/java/org/geysermc/pack/converter/data/BaseConversionData.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/PackConverter - * - */ - -package org.geysermc.pack.converter.data; - -import org.jetbrains.annotations.NotNull; -import team.unnamed.creative.ResourcePack; - -import java.nio.file.Path; - -public class BaseConversionData implements ConversionData { - private final Path inputDirectory; - private final Path outputDirectory; - private final ResourcePack vanillaPack; - - public BaseConversionData(@NotNull Path inputDirectory, @NotNull Path outputDirectory, @NotNull ResourcePack vanillaPack) { - this.inputDirectory = inputDirectory; - this.outputDirectory = outputDirectory; - this.vanillaPack = vanillaPack; - } - - @NotNull - @Override - public Path inputDirectory() { - return this.inputDirectory; - } - - @NotNull - @Override - public Path outputDirectory() { - return this.outputDirectory; - } - - @NotNull - @Override - public ResourcePack vanillaPack() { - return this.vanillaPack; - } -} diff --git a/converter/src/main/java/org/geysermc/pack/converter/data/ModelConversionData.java b/converter/src/main/java/org/geysermc/pack/converter/data/ModelConversionData.java deleted file mode 100644 index d2b5ce2..0000000 --- a/converter/src/main/java/org/geysermc/pack/converter/data/ModelConversionData.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/PackConverter - * - */ - -package org.geysermc.pack.converter.data; - -import lombok.Getter; -import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.model.ModelStitcher; -import org.jetbrains.annotations.NotNull; -import team.unnamed.creative.ResourcePack; -import team.unnamed.creative.model.Model; - -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; - -public class ModelConversionData extends BaseConversionData { - private final Map stitchedModels = new HashMap<>(); - @Getter - private final ModelStitcher.Provider modelProvider; - - public ModelConversionData(@NotNull Path inputDirectory, @NotNull Path outputDirectory, ModelStitcher.Provider modelProvider, @NotNull ResourcePack vanillaPack) { - super(inputDirectory, outputDirectory, vanillaPack); - this.modelProvider = modelProvider; - } - - public void addStitchedModel(@NotNull Model model) { - this.stitchedModels.put(model.key(), model); - } - - @NotNull - public Model model(@NotNull Key key) { - return this.stitchedModels.get(key); - } -} diff --git a/converter/src/main/java/org/geysermc/pack/converter/data/TextureConversionData.java b/converter/src/main/java/org/geysermc/pack/converter/data/TextureConversionData.java deleted file mode 100644 index 2ca5482..0000000 --- a/converter/src/main/java/org/geysermc/pack/converter/data/TextureConversionData.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/PackConverter - * - */ - -package org.geysermc.pack.converter.data; - -import org.geysermc.pack.converter.converter.texture.transformer.TransformedTexture; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import team.unnamed.creative.ResourcePack; - -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; - -public class TextureConversionData extends BaseConversionData { - private final List transformedTextures = new ArrayList<>(); - private final String textureSubdirectory; - - public TextureConversionData(@NotNull Path inputDirectory, @NotNull Path outputDirectory, @Nullable String textureSubdirectory, @NotNull ResourcePack vanillaPack) { - super(inputDirectory, outputDirectory, vanillaPack); - - this.textureSubdirectory = textureSubdirectory; - } - - public void addTransformedTexture(@NotNull TransformedTexture transformedTexture) { - this.transformedTextures.add(transformedTexture); - } - - @NotNull - public List transformedTextures() { - return this.transformedTextures; - } - - @Nullable - public String textureSubdirectory() { - return this.textureSubdirectory; - } -} diff --git a/converter/src/main/java/org/geysermc/pack/converter/pipeline/ActionListener.java b/converter/src/main/java/org/geysermc/pack/converter/pipeline/ActionListener.java new file mode 100644 index 0000000..24abf84 --- /dev/null +++ b/converter/src/main/java/org/geysermc/pack/converter/pipeline/ActionListener.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019-2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/PackConverter + * + */ + +package org.geysermc.pack.converter.pipeline; + +import org.geysermc.pack.bedrock.resource.BedrockResourcePack; +import team.unnamed.creative.ResourcePack; + +import java.util.Collection; +import java.util.List; + +/** + * Listeners for actions that occur during execution of a {@link ConverterPipeline}. All implemented listeners should be as pure as possible: + * no side effects should occur, and no modifications should be made to received arguments, unless specifically stated this is allowed. + */ +public interface ActionListener { + + /** + * Executed after a {@link ConverterPipeline} has extracted all applicable {@link JavaAsset}s for conversion of a {@link ResourcePack}. This method + * can be used to add extra {@link JavaAsset}s for conversion by adding them to the {@code extracted} collection, which is mutable. + * + * @param pack the resource pack that is used for extraction of {@link JavaAsset}s + * @param extracted the {@link JavaAsset}s the {@link ConverterPipeline} has extracted from the resource pack + * @param context the {@link ExtractionContext} + */ + default void postExtract(ResourcePack pack, Collection extracted, ExtractionContext context) { + } + + /** + * Executed after a {@link ConverterPipeline} has converted a {@link JavaAsset} to a {@link BedrockAsset}. This method + * can be used to modify the {@link BedrockAsset} after conversion. + * + *

Please note that the {@link BedrockAsset} should be considered immutable, and no modifications should be made to it. Instead, + * return a modified copy.

+ * + * @param asset the {@link JavaAsset} that was converted + * @param bedrockAsset the resulting {@link BedrockAsset} + * @param context the {@link ConversionContext} + * @return the modified {@link BedrockAsset}, or return the original if no modifications were made + */ + default BedrockAsset postConvert(JavaAsset asset, BedrockAsset bedrockAsset, ConversionContext context) { + return bedrockAsset; + } + + /** + * Executed after a {@link ConverterPipeline} has added all converted {@link BedrockAsset}s to the {@link BedrockResourcePack}. This method + * can be used to add additional assets to the output {@code pack}. + * + * @param pack the bedrock resource pack + * @param assets the assets added to the bedrock resource pack (immutable) + * @param context the {@link CombineContext} + */ + default void postInclude(BedrockResourcePack pack, List assets, CombineContext context) { + } +} diff --git a/converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetCombiner.java b/converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetCombiner.java new file mode 100644 index 0000000..9d58217 --- /dev/null +++ b/converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetCombiner.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/PackConverter + * + */ + +package org.geysermc.pack.converter.pipeline; + +import org.geysermc.pack.bedrock.resource.BedrockResourcePack; + +import java.util.List; + +@FunctionalInterface +public interface AssetCombiner { + + void include(BedrockResourcePack pack, List assets, CombineContext context); +} diff --git a/converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetConverter.java b/converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetConverter.java new file mode 100644 index 0000000..ef47879 --- /dev/null +++ b/converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetConverter.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/PackConverter + * + */ + +package org.geysermc.pack.converter.pipeline; + +import org.jetbrains.annotations.Nullable; + +@FunctionalInterface +public interface AssetConverter { + + @Nullable + BedrockAsset convert(JavaAsset asset, ConversionContext context) throws Exception; +} diff --git a/converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetConverters.java b/converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetConverters.java new file mode 100644 index 0000000..a6ed4fd --- /dev/null +++ b/converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetConverters.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/PackConverter + * + */ + +package org.geysermc.pack.converter.pipeline; + +import com.google.gson.JsonElement; +import net.kyori.adventure.key.Keyed; +import org.geysermc.pack.bedrock.resource.BedrockResourcePack; +import org.geysermc.pack.bedrock.resource.Manifest; +import org.geysermc.pack.bedrock.resource.sounds.sounddefinitions.SoundDefinitions; +import org.geysermc.pack.converter.type.base.PackIconConverter; +import org.geysermc.pack.converter.type.base.PackManifestConverter; +import org.geysermc.pack.converter.type.lang.BedrockLanguage; +import org.geysermc.pack.converter.type.lang.LangConverter; +import org.geysermc.pack.converter.type.misc.SplashTextConverter; +import org.geysermc.pack.converter.type.model.BedrockModel; +import org.geysermc.pack.converter.type.model.ModelConverter; +import org.geysermc.pack.converter.type.sound.SoundConverter; +import org.geysermc.pack.converter.type.sound.SoundRegistryConverter; +import org.geysermc.pack.converter.type.texture.TextureConverter; +import org.geysermc.pack.converter.type.texture.transformer.TransformedTexture; +import team.unnamed.creative.ResourcePack; +import team.unnamed.creative.base.Writable; +import team.unnamed.creative.lang.Language; +import team.unnamed.creative.metadata.pack.PackMeta; +import team.unnamed.creative.model.Model; +import team.unnamed.creative.part.ResourcePackPart; +import team.unnamed.creative.serialize.minecraft.ResourceCategory; +import team.unnamed.creative.serialize.minecraft.language.LanguageSerializer; +import team.unnamed.creative.serialize.minecraft.sound.SoundSerializer; +import team.unnamed.creative.sound.Sound; +import team.unnamed.creative.sound.SoundRegistry; +import team.unnamed.creative.texture.Texture; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +@SuppressWarnings({"UnstableApiUsage", "unused"}) +public final class AssetConverters { + private static final List> CONVERTERS = new ArrayList<>(); + private static boolean bootstrapped = false; + + public static final ConverterPipeline MANIFEST = createSingle( + (pack, context) -> pack.packMeta(), + PackManifestConverter.INSTANCE, + BedrockResourcePack::manifest); + public static final ConverterPipeline ICON = createSingle(PackIconConverter::extractIcon, PackIconConverter.INSTANCE, BedrockResourcePack::icon); + public static final ConverterPipeline SPLASH_TEXT = createSingle( + (pack, context) -> pack.unknownFile("assets/minecraft/texts/splashes.txt"), + SplashTextConverter.INSTANCE, + (pack, splashes) -> pack.addExtraFile(splashes, "splashes.json")); + public static final ConverterPipeline LANGUAGE = create(extractor(LanguageSerializer.CATEGORY), LangConverter.INSTANCE); + public static final ConverterPipeline MODEL = create(ModelConverter.INSTANCE); + public static final ConverterPipeline> SOUND_REGISTRY = create( + (pack, context) -> pack.soundRegistries(), SoundRegistryConverter.INSTANCE); + public static final ConverterPipeline SOUND = create(extractor(SoundSerializer.CATEGORY), SoundConverter.INSTANCE); + public static final ConverterPipeline TEXTURE = create(TextureConverter.INSTANCE); + + private static ConverterPipeline createSingle(BiFunction extractor, + AssetConverter converter, + BiConsumer collector) { + return create( + (pack, context) -> Optional.ofNullable(extractor.apply(pack, context)) + .map(List::of) + .orElse(List.of()), + converter, + (pack, assets, context) -> collector.accept(pack, assets.get(0))); + } + + public static + & AssetCombiner> ConverterPipeline create(AssetExtractor extractor, + ConverterCombiner converterCombiner) { + return create(extractor, converterCombiner, converterCombiner); + } + + public static & AssetConverter + & AssetCombiner> ConverterPipeline create(Pipeline pipeline) { + return create(pipeline, pipeline, pipeline); + } + + public static ConverterPipeline create(AssetExtractor extractor, + AssetConverter converter, + AssetCombiner combiner) { + ConverterPipeline pipeline = new ConverterPipeline<>(extractor, converter, combiner, false, Optional.empty()); + if (!bootstrapped) { + CONVERTERS.add(pipeline); + } + return pipeline; + } + + public static List> converters(boolean experimental) { + return List.copyOf(CONVERTERS).stream() + .filter(converter -> experimental || !converter.experimental()) + .toList(); + } + + static { + // This will cause 3rd-party converters made using the utility methods here to not be added to the CONVERTERS array + bootstrapped = true; + } + + private static AssetExtractor extractor(ResourceCategory category) { + return (pack, context) -> category.lister().apply(pack); + } +} diff --git a/converter/src/main/java/org/geysermc/pack/converter/data/ConversionData.java b/converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetExtractor.java similarity index 78% rename from converter/src/main/java/org/geysermc/pack/converter/data/ConversionData.java rename to converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetExtractor.java index c934bd3..4a562f6 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/data/ConversionData.java +++ b/converter/src/main/java/org/geysermc/pack/converter/pipeline/AssetExtractor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,21 +24,14 @@ * */ -package org.geysermc.pack.converter.data; +package org.geysermc.pack.converter.pipeline; -import org.jetbrains.annotations.NotNull; import team.unnamed.creative.ResourcePack; -import java.nio.file.Path; +import java.util.Collection; -public interface ConversionData { +@FunctionalInterface +public interface AssetExtractor { - @NotNull - Path inputDirectory(); - - @NotNull - Path outputDirectory(); - - @NotNull - ResourcePack vanillaPack(); + Collection extract(ResourcePack pack, ExtractionContext context); } diff --git a/converter/src/main/java/org/geysermc/pack/converter/pipeline/CombineContext.java b/converter/src/main/java/org/geysermc/pack/converter/pipeline/CombineContext.java new file mode 100644 index 0000000..ea334f3 --- /dev/null +++ b/converter/src/main/java/org/geysermc/pack/converter/pipeline/CombineContext.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/PackConverter + * + */ + +package org.geysermc.pack.converter.pipeline; + +import org.geysermc.pack.converter.util.LogListener; +import org.geysermc.pack.converter.util.LogListenerHelper; + +public record CombineContext(String textureSubDirectory, LogListener logListener) implements LogListenerHelper { +} diff --git a/converter/src/main/java/org/geysermc/pack/converter/pipeline/ConversionContext.java b/converter/src/main/java/org/geysermc/pack/converter/pipeline/ConversionContext.java new file mode 100644 index 0000000..adbc22b --- /dev/null +++ b/converter/src/main/java/org/geysermc/pack/converter/pipeline/ConversionContext.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/PackConverter + * + */ + +package org.geysermc.pack.converter.pipeline; + +import org.geysermc.pack.converter.util.LogListener; +import org.geysermc.pack.converter.util.LogListenerHelper; + +public record ConversionContext(String packName, LogListener logListener) implements LogListenerHelper { +} diff --git a/converter/src/main/java/org/geysermc/pack/converter/pipeline/ConverterPipeline.java b/converter/src/main/java/org/geysermc/pack/converter/pipeline/ConverterPipeline.java new file mode 100644 index 0000000..a4ba60f --- /dev/null +++ b/converter/src/main/java/org/geysermc/pack/converter/pipeline/ConverterPipeline.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/PackConverter + * + */ + +package org.geysermc.pack.converter.pipeline; + +import org.geysermc.pack.bedrock.resource.BedrockResourcePack; +import org.geysermc.pack.converter.util.LogListener; +import org.jetbrains.annotations.Nullable; +import team.unnamed.creative.ResourcePack; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; + +@SuppressWarnings("ClassCanBeRecord") // We don't want to expose the fields here +public final class ConverterPipeline + implements AssetExtractor, AssetConverter, AssetCombiner { + private final AssetExtractor extractor; + private final AssetConverter converter; + private final AssetCombiner combiner; + private final boolean experimental; + private final Optional> listener; + + public ConverterPipeline(AssetExtractor extractor, + AssetConverter converter, + AssetCombiner combiner, + boolean experimental, + Optional> listener) { + this.extractor = extractor; + this.converter = converter; + this.combiner = combiner; + this.experimental = experimental; + this.listener = listener; + } + + @Override + public Collection extract(ResourcePack pack, ExtractionContext context) { + Collection extracted = extractor.extract(pack, context); + listener.ifPresent(actionListener -> actionListener.postExtract(pack, extracted, context)); + return extracted; + } + + @Override + public @Nullable BedrockAsset convert(JavaAsset asset, ConversionContext context) throws Exception { + BedrockAsset converted = converter.convert(asset, context); + return listener.map(actionListener -> actionListener.postConvert(asset, converted, context)) + .orElse(converted); + } + + @Override + public void include(BedrockResourcePack pack, List assets, CombineContext context) { + combiner.include(pack, assets, context); + listener.ifPresent(actionListener -> actionListener.postInclude(pack, assets, context)); + } + + public int convert(ResourcePack pack, Optional vanillaPack, BedrockResourcePack bedrockPack, String packName, String textureSubDirectory, LogListener logListener) { + ExtractionContext extractionContext = new ExtractionContext(bedrockPack, vanillaPack, logListener); + ConversionContext conversionContext = new ConversionContext(packName, logListener); + CombineContext combineContext = new CombineContext(textureSubDirectory, logListener); + + AtomicInteger errors = new AtomicInteger(0); + List converted = extract(pack, extractionContext).stream() + .map(asset -> { + try { + return convert(asset, conversionContext); + } catch (Exception exception) { + errors.incrementAndGet(); + logListener.error("Failed to convert asset", exception); + } + return null; + }) + .filter(Objects::nonNull) + .toList(); + if (!converted.isEmpty()) { + include(bedrockPack, converted, combineContext); + } + + return errors.get(); + } + + public boolean experimental() { + return experimental; + } + + public ConverterPipeline withActionListener(ActionListener listener) { + return new ConverterPipeline<>(extractor, converter, combiner, experimental, Optional.of(listener)); + } +} diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/Converter.java b/converter/src/main/java/org/geysermc/pack/converter/pipeline/ExtractionContext.java similarity index 57% rename from converter/src/main/java/org/geysermc/pack/converter/converter/Converter.java rename to converter/src/main/java/org/geysermc/pack/converter/pipeline/ExtractionContext.java index 1041b20..ed6068d 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/Converter.java +++ b/converter/src/main/java/org/geysermc/pack/converter/pipeline/ExtractionContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,34 +24,19 @@ * */ -package org.geysermc.pack.converter.converter; +package org.geysermc.pack.converter.pipeline; -import org.geysermc.pack.converter.PackConversionContext; -import org.geysermc.pack.converter.PackConverter; -import org.geysermc.pack.converter.data.ConversionData; +import org.geysermc.pack.bedrock.resource.BedrockResourcePack; import org.geysermc.pack.converter.util.LogListener; -import org.jetbrains.annotations.NotNull; +import org.geysermc.pack.converter.util.LogListenerHelper; import team.unnamed.creative.ResourcePack; -import java.nio.file.Path; +import java.util.Optional; -public interface Converter { - - void convert(@NotNull PackConversionContext context) throws Exception; - - T createConversionData(@NotNull ConversionDataCreationContext context); - - default boolean isExperimental() { - return false; - } - - record ConversionDataCreationContext( - @NotNull PackConverter converter, - @NotNull LogListener logListener, - @NotNull Path inputDirectory, - @NotNull Path outputDirectory, - @NotNull ResourcePack javaResourcePack, - @NotNull ResourcePack vanillaResourcePack - ) { - } +/** + * @param bedrockResourcePack should never be used. The bedrock resource pack should not be written to during extraction, rather only during combination of converted assets. + * The bedrock resource pack is only included here for legacy converters still making use of it, which will be rewritten soon. + */ +public record ExtractionContext(@Deprecated(forRemoval = true) BedrockResourcePack bedrockResourcePack, + Optional vanillaPack, LogListener logListener) implements LogListenerHelper { } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/base/PackIconConverter.java b/converter/src/main/java/org/geysermc/pack/converter/type/base/PackIconConverter.java similarity index 50% rename from converter/src/main/java/org/geysermc/pack/converter/converter/base/PackIconConverter.java rename to converter/src/main/java/org/geysermc/pack/converter/type/base/PackIconConverter.java index c671404..5df90ca 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/base/PackIconConverter.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/base/PackIconConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2025 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,33 +24,41 @@ * */ -package org.geysermc.pack.converter.converter.base; +package org.geysermc.pack.converter.type.base; -import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.PackConversionContext; -import org.geysermc.pack.converter.converter.BaseConverter; -import org.geysermc.pack.converter.converter.Converter; -import org.geysermc.pack.converter.data.BaseConversionData; -import org.jetbrains.annotations.NotNull; +import org.geysermc.pack.converter.pipeline.AssetConverter; +import org.geysermc.pack.converter.pipeline.ConversionContext; +import org.geysermc.pack.converter.pipeline.ExtractionContext; +import org.geysermc.pack.converter.util.KeyUtil; +import team.unnamed.creative.ResourcePack; import team.unnamed.creative.base.Writable; import team.unnamed.creative.texture.Texture; -@AutoService(Converter.class) -public class PackIconConverter extends BaseConverter { - private static final Key UNKNOWN_PACK = Key.key(Key.MINECRAFT_NAMESPACE, "misc/unknown_pack.png"); +import java.util.Optional; - @Override - public void convert(@NotNull PackConversionContext context) throws Exception { - Writable packIcon = context.javaResourcePack().icon(); +public class PackIconConverter implements AssetConverter { + public static final PackIconConverter INSTANCE = new PackIconConverter(); + private static final Key UNKNOWN_PACK = KeyUtil.key(Key.MINECRAFT_NAMESPACE, "misc/unknown_pack.png"); + + public static Writable extractIcon(ResourcePack pack, ExtractionContext context) { + Writable packIcon = pack.icon(); if (packIcon == null) { - if (context.javaResourcePack().texture(UNKNOWN_PACK) != null) { - packIcon = context.javaResourcePack().texture(UNKNOWN_PACK).data(); + Texture unknownPackOverride = pack.texture(UNKNOWN_PACK); + if (unknownPackOverride != null) { + packIcon = unknownPackOverride.data(); } else { - packIcon = context.data().vanillaPack().texture(UNKNOWN_PACK).data(); + packIcon = context.vanillaPack() + .flatMap(vanilla -> Optional.ofNullable(vanilla.texture(UNKNOWN_PACK))) + .map(Texture::data) + .orElse(null); } } + return packIcon; + } - context.bedrockResourcePack().icon(packIcon.toByteArray()); + @Override + public byte[] convert(Writable writable, ConversionContext context) throws Exception { + return writable.toByteArray(); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/base/PackManifestConverter.java b/converter/src/main/java/org/geysermc/pack/converter/type/base/PackManifestConverter.java similarity index 68% rename from converter/src/main/java/org/geysermc/pack/converter/converter/base/PackManifestConverter.java rename to converter/src/main/java/org/geysermc/pack/converter/type/base/PackManifestConverter.java index 65d436e..086615e 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/base/PackManifestConverter.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/base/PackManifestConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2025 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,36 +24,30 @@ * */ -package org.geysermc.pack.converter.converter.base; +package org.geysermc.pack.converter.type.base; -import com.google.auto.service.AutoService; import org.geysermc.pack.bedrock.resource.Manifest; import org.geysermc.pack.bedrock.resource.manifest.Header; import org.geysermc.pack.bedrock.resource.manifest.Modules; -import org.geysermc.pack.converter.PackConversionContext; -import org.geysermc.pack.converter.converter.BaseConverter; -import org.geysermc.pack.converter.converter.Converter; -import org.geysermc.pack.converter.data.BaseConversionData; -import org.jetbrains.annotations.NotNull; -import team.unnamed.creative.ResourcePack; +import org.geysermc.pack.converter.pipeline.AssetConverter; +import org.geysermc.pack.converter.pipeline.ConversionContext; +import team.unnamed.creative.metadata.pack.PackMeta; import java.util.List; import java.util.UUID; -@AutoService(Converter.class) -public class PackManifestConverter extends BaseConverter { +public class PackManifestConverter implements AssetConverter { + public static final PackManifestConverter INSTANCE = new PackManifestConverter(); private static final int FORMAT_VERSION = 2; @Override - public void convert(@NotNull PackConversionContext context) throws Exception { - ResourcePack javaPack = context.javaResourcePack(); - + public Manifest convert(PackMeta packMeta, ConversionContext context) throws Exception { Manifest manifest = new Manifest(); manifest.formatVersion(FORMAT_VERSION); Header header = new Header(); - header.description(javaPack.description()); - header.name(context.packConverter().packName()); + header.description(packMeta.description()); + header.name(context.packName()); header.version(new float[] { 1, 0, 0 }); header.minEngineVersion(new float[] { 1, 16, 0 }); header.uuid(UUID.randomUUID().toString()); @@ -61,12 +55,13 @@ public class PackManifestConverter extends BaseConverter { manifest.header(header); Modules module = new Modules(); - module.description(javaPack.description()); + module.description(packMeta.description()); module.type("resources"); module.uuid(UUID.randomUUID().toString()); module.version(new float[] { 1, 0, 0 }); manifest.modules(List.of(module)); - context.bedrockResourcePack().manifest(manifest); + + return manifest; } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/Constants.java b/converter/src/main/java/org/geysermc/pack/converter/type/lang/BedrockLanguage.java similarity index 85% rename from converter/src/main/java/org/geysermc/pack/converter/Constants.java rename to converter/src/main/java/org/geysermc/pack/converter/type/lang/BedrockLanguage.java index 8f4b342..4a59fb9 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/Constants.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/lang/BedrockLanguage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,8 +24,9 @@ * */ -package org.geysermc.pack.converter; +package org.geysermc.pack.converter.type.lang; -public class Constants { - public static final String JAVA_PACK_LOCATION = "assets/%s"; +import java.util.Map; + +public record BedrockLanguage(String language, Map strings) { } diff --git a/converter/src/main/java/org/geysermc/pack/converter/type/lang/LangConverter.java b/converter/src/main/java/org/geysermc/pack/converter/type/lang/LangConverter.java new file mode 100644 index 0000000..39ef25f --- /dev/null +++ b/converter/src/main/java/org/geysermc/pack/converter/type/lang/LangConverter.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019-2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/PackConverter + * + */ + +package org.geysermc.pack.converter.type.lang; + +import org.geysermc.pack.bedrock.resource.BedrockResourcePack; +import org.geysermc.pack.converter.pipeline.AssetCombiner; +import org.geysermc.pack.converter.pipeline.AssetConverter; +import org.geysermc.pack.converter.pipeline.CombineContext; +import org.geysermc.pack.converter.pipeline.ConversionContext; +import team.unnamed.creative.lang.Language; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +public class LangConverter implements AssetConverter, AssetCombiner { + public static final LangConverter INSTANCE = new LangConverter(); + + private static final Pattern POSITIONAL_STRING_REPLACEMENT = Pattern.compile("%([0-9]+)\\$s"); + + @Override + public BedrockLanguage convert(Language language, ConversionContext context) throws Exception { + Map strings = language.translations(); + + for (Map.Entry entry : strings.entrySet()) { + String value = entry.getValue(); + + // Replace %d with %s + value = value.replace("%d", "%s"); + + // Replace `%x$s` with `%x` + value = POSITIONAL_STRING_REPLACEMENT.matcher(value).replaceAll("%$1"); + + entry.setValue(value); + } + + String languageKey = language.key().value(); + + // Convert the language key to the Bedrock equivalent + if (languageKey.equals("no_no")) { + languageKey = "nb_no"; + } + + return new BedrockLanguage(languageKey, strings); + } + + @Override + public void include(BedrockResourcePack pack, List languages, CombineContext context) { + Map> merged = new HashMap<>(); + + for (BedrockLanguage language : languages) { + Map mergedLanguage = merged.computeIfAbsent(language.language(), name -> new HashMap<>()); + for (Map.Entry entry : language.strings().entrySet()) { + if (mergedLanguage.containsKey(entry.getKey())) { + context.warn("Conflicting language string " + entry.getKey() + "!"); + continue; + } + mergedLanguage.put(entry.getKey(), entry.getValue()); + } + } + + merged.forEach(pack::addLanguage); + } +} diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/misc/SplashTextConverter.java b/converter/src/main/java/org/geysermc/pack/converter/type/misc/SplashTextConverter.java similarity index 55% rename from converter/src/main/java/org/geysermc/pack/converter/converter/misc/SplashTextConverter.java rename to converter/src/main/java/org/geysermc/pack/converter/type/misc/SplashTextConverter.java index 4b8bfc3..3c67a36 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/misc/SplashTextConverter.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/misc/SplashTextConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 GeyserMC. http://geysermc.org + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,38 +24,27 @@ * */ -package org.geysermc.pack.converter.converter.misc; +package org.geysermc.pack.converter.type.misc; -import com.google.auto.service.AutoService; -import com.google.gson.*; -import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.PackConversionContext; -import org.geysermc.pack.converter.converter.BaseConverter; -import org.geysermc.pack.converter.converter.Converter; -import org.geysermc.pack.converter.data.BaseConversionData; -import org.jetbrains.annotations.NotNull; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.geysermc.pack.converter.pipeline.AssetConverter; +import org.geysermc.pack.converter.pipeline.ConversionContext; import team.unnamed.creative.base.Writable; -import java.nio.charset.StandardCharsets; import java.util.Arrays; -@AutoService(Converter.class) -public class SplashTextConverter extends BaseConverter { - private static final Gson GSON = new GsonBuilder() - .setPrettyPrinting() - .create(); +public class SplashTextConverter implements AssetConverter { + public static final SplashTextConverter INSTANCE = new SplashTextConverter(); @Override - public void convert(@NotNull PackConversionContext context) throws Exception { - Writable javaSplashText = context.javaResourcePack().unknownFile("assets/minecraft/texts/splashes.txt"); - if (javaSplashText == null) return; - - String[] splashes = javaSplashText.toUTF8String().split("\n"); + public JsonElement convert(Writable writable, ConversionContext context) throws Exception { + String[] splashes = writable.toUTF8String().split("\n"); JsonArray splashesArray = new JsonArray(); Arrays.stream(splashes).toList().forEach(splashesArray::add); JsonObject object = new JsonObject(); object.add("splashes", splashesArray); - - context.bedrockResourcePack().addExtraFile(GSON.toJson(object).getBytes(StandardCharsets.UTF_8), "splashes.json"); + return object; } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/ActionListener.java b/converter/src/main/java/org/geysermc/pack/converter/type/model/BedrockModel.java similarity index 71% rename from converter/src/main/java/org/geysermc/pack/converter/converter/ActionListener.java rename to converter/src/main/java/org/geysermc/pack/converter/type/model/BedrockModel.java index ce52526..0a2d2fe 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/ActionListener.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/model/BedrockModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,19 +24,14 @@ * */ -package org.geysermc.pack.converter.converter; +package org.geysermc.pack.converter.type.model; -import org.geysermc.pack.converter.PackConversionContext; -import org.geysermc.pack.converter.data.ConversionData; +import org.geysermc.pack.bedrock.resource.models.entity.ModelEntity; -/** - * A listener for actions that occur during pack conversion. - */ -public interface ActionListener { +public record BedrockModel(ModelType type, String fileName, ModelEntity model) { - default void preConvert(PackConversionContext context) { - } - - default void postConvert(PackConversionContext context) { + public enum ModelType { + BLOCK, + ENTITY } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/type/model/ModelConverter.java b/converter/src/main/java/org/geysermc/pack/converter/type/model/ModelConverter.java new file mode 100644 index 0000000..7c3b60b --- /dev/null +++ b/converter/src/main/java/org/geysermc/pack/converter/type/model/ModelConverter.java @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2019-2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/PackConverter + * + */ + +package org.geysermc.pack.converter.type.model; + +import net.kyori.adventure.key.Key; +import org.geysermc.pack.bedrock.resource.BedrockResourcePack; +import org.geysermc.pack.bedrock.resource.models.entity.ModelEntity; +import org.geysermc.pack.bedrock.resource.models.entity.modelentity.Geometry; +import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.Bones; +import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.Description; +import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.Cubes; +import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.Uv; +import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.Down; +import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.East; +import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.North; +import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.South; +import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.Up; +import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.West; +import org.geysermc.pack.converter.pipeline.AssetCombiner; +import org.geysermc.pack.converter.pipeline.AssetConverter; +import org.geysermc.pack.converter.pipeline.AssetExtractor; +import org.geysermc.pack.converter.pipeline.CombineContext; +import org.geysermc.pack.converter.pipeline.ConversionContext; +import org.geysermc.pack.converter.pipeline.ExtractionContext; +import team.unnamed.creative.ResourcePack; +import team.unnamed.creative.base.CubeFace; +import team.unnamed.creative.model.Element; +import team.unnamed.creative.model.ElementFace; +import team.unnamed.creative.model.ElementRotation; +import team.unnamed.creative.model.Model; +import team.unnamed.creative.texture.TextureUV; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public class ModelConverter implements AssetExtractor, AssetConverter, AssetCombiner { + public static final ModelConverter INSTANCE = new ModelConverter(); + + private static final String FORMAT_VERSION = "1.16.0"; + private static final String GEOMETRY_FORMAT = "geometry.%s"; + + private static final float[] ELEMENT_OFFSET = new float[] { 8, 0, 8 }; + + @Override + public Collection extract(ResourcePack pack, ExtractionContext context) { + ModelStitcher.Provider modelProvider = context.vanillaPack() + .map(vanilla -> ModelStitcher.vanillaProvider(pack, vanilla)) + .orElseGet(() -> ModelStitcher.baseProvider(pack)); + // TODO maybe parallel, if model stitching takes a lot of time + return pack.models().stream() + .map(model -> new ModelStitcher(modelProvider, model, context.logListener()).stitch()) + .toList(); + } + + @Override + public BedrockModel convert(Model model, ConversionContext context) throws Exception { + List elements = model.elements(); + if (elements.isEmpty()) { + context.debug("Model " + model.key().key() + " has no elements"); + return null; + } + + String value = model.key().value(); + context.debug("Converting model " + model.key().key() + ":" + value); + + // TODO: Convert item models but save differently? + if (value.startsWith("item/")) { + return null; + } + + ModelEntity modelEntity = new ModelEntity(); + modelEntity.formatVersion(FORMAT_VERSION); + + Geometry geometry = new Geometry(); + + String namespace = model.key().namespace(); + String fileName = value.substring(value.lastIndexOf('/') + 1); + + String geoName = (namespace.equals(Key.MINECRAFT_NAMESPACE) ? "" : namespace + ".") + fileName; + + // 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); + + List bones = new ArrayList<>(); + + // TODO: Should each element be its own bone rather + // than its own cube in the same bone? + int i = 0; + for (Element element : elements) { + float[] from = element.from().toArray(); + float[] to = element.to().toArray(); + + Bones bone = new Bones(); + bone.name("bone_" + i++); + bone.pivot(new float[] { ELEMENT_OFFSET[0], ELEMENT_OFFSET[1], -ELEMENT_OFFSET[2] }); + + Cubes cube = new Cubes(); + cube.origin(new float[] { ELEMENT_OFFSET[0] - to[0], from[1], from[2] - ELEMENT_OFFSET[2] }); + cube.size(new float[] { to[0] - from[0], to[1] - from[1], to[2] - from[2] }); + + ElementRotation elementRotation = element.rotation(); + if (elementRotation != null) { + float[] origin = elementRotation.origin().toArray(); + cube.pivot(new float[] { ELEMENT_OFFSET[0] - origin[0], ELEMENT_OFFSET[1] - origin[1], origin[2] - ELEMENT_OFFSET[2] }); + + float angle = elementRotation.angle(); + float[] rotation = new float[3]; + switch (elementRotation.axis()) { + case X -> rotation[0] = -angle; + case Y -> rotation[1] = -angle; + case Z -> rotation[2] = -angle; + } + + cube.rotation(rotation); + } + + Uv uv = new Uv(); + for (Map.Entry entry : element.faces().entrySet()) { + CubeFace face = entry.getKey(); + ElementFace elementFace = entry.getValue(); + if (elementFace.uv0() == null) { + continue; + } + + // The Java pack lib we use does this weird thing where it + // divides the UV by 16, so we need to multiply it by 16 + + String texture = elementFace.texture().replace("#", ""); + applyUv(uv, face, texture, multiplyUv(elementFace.uv0(), 16f)); + } + + cube.uv(uv); + bone.cubes(List.of(cube)); + + bones.add(bone); + } + + geometry.bones(bones); + + modelEntity.geometry(List.of(geometry)); + + if (model.key().namespace().contains("entity")) { + return new BedrockModel(BedrockModel.ModelType.ENTITY, fileName + ".json", modelEntity); + } else { + // Bedrock only has a concept of entity or block models + return new BedrockModel(BedrockModel.ModelType.BLOCK, fileName + ".json", modelEntity); + } + } + + @Override + public void include(BedrockResourcePack pack, List bedrockModels, CombineContext context) { + List entityModels = new ArrayList<>(); + List blockModels = new ArrayList<>(); + + for (BedrockModel model : bedrockModels) { + switch (model.type()) { + case ENTITY -> { + if (entityModels.contains(model.fileName())) { + context.warn("Conflicting entity model " + model.fileName() + "!"); + continue; + } + entityModels.add(model.fileName()); + pack.addEntityModel(model.model(), model.fileName()); + } + case BLOCK -> { + if (blockModels.contains(model.fileName())) { + context.warn("Conflicting entity model " + model.fileName() + "!"); + continue; + } + blockModels.add(model.fileName()); + pack.addBlockModel(model.model(), model.fileName()); + } + } + } + } + + private TextureUV multiplyUv(TextureUV textureUV, float mult) { + return TextureUV.uv(textureUV.from().multiply(mult), textureUV.to().multiply(mult)); + } + + private static void applyUv(Uv uv, CubeFace face, String texture, TextureUV faceUv) { + float[] uvs; + float[] uvSize; + + // These values are flipped for some reason + if (face == CubeFace.DOWN || face == CubeFace.UP) { + uvs = new float[] { faceUv.to().x(), faceUv.to().y() }; + uvSize = new float[] { faceUv.from().x() - faceUv.to().x(), faceUv.from().y() - faceUv.to().y() }; + } else { + uvs = new float[] { faceUv.from().x(), faceUv.from().y() }; + uvSize = new float[] { faceUv.to().x() - faceUv.from().x(), faceUv.to().y() - faceUv.from().y() }; + } + + switch (face) { + case NORTH -> { + North north = new North(); + north.uv(uvs); + north.uvSize(uvSize); + north.materialInstance(texture); + + uv.north(north); + } + case SOUTH -> { + South south = new South(); + south.uv(uvs); + south.uvSize(uvSize); + south.materialInstance(texture); + + uv.south(south); + } + case EAST -> { + East east = new East(); + east.uv(uvs); + east.uvSize(uvSize); + east.materialInstance(texture); + + uv.east(east); + } + case WEST -> { + West west = new West(); + west.uv(uvs); + west.uvSize(uvSize); + west.materialInstance(texture); + + uv.west(west); + } + case UP -> { + Up up = new Up(); + up.uv(uvs); + up.uvSize(uvSize); + up.materialInstance(texture); + + uv.up(up); + } + case DOWN -> { + Down down = new Down(); + down.uv(uvs); + down.uvSize(uvSize); + down.materialInstance(texture); + + uv.down(down); + } + } + } +} diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/model/ModelStitcher.java b/converter/src/main/java/org/geysermc/pack/converter/type/model/ModelStitcher.java similarity index 95% rename from converter/src/main/java/org/geysermc/pack/converter/converter/model/ModelStitcher.java rename to converter/src/main/java/org/geysermc/pack/converter/type/model/ModelStitcher.java index 71b8403..b5dcbe1 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/model/ModelStitcher.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/model/ModelStitcher.java @@ -24,12 +24,11 @@ * */ -package org.geysermc.pack.converter.converter.model; +package org.geysermc.pack.converter.type.model; import net.kyori.adventure.key.Key; import org.geysermc.pack.converter.util.DefaultLogListener; import org.geysermc.pack.converter.util.LogListener; -import org.geysermc.pack.converter.util.VanillaPackProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import team.unnamed.creative.ResourcePack; @@ -39,10 +38,7 @@ import team.unnamed.creative.model.ItemTransform; import team.unnamed.creative.model.Model; import team.unnamed.creative.model.ModelTexture; import team.unnamed.creative.model.ModelTextures; -import team.unnamed.creative.serialize.minecraft.MinecraftResourcePackReader; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -195,7 +191,7 @@ public class ModelStitcher { return pack::model; } - public static Provider vanillaProvider(@NotNull ResourcePack pack, @NotNull LogListener log, @NotNull ResourcePack vanillaPack) { + public static Provider vanillaProvider(@NotNull ResourcePack pack, @NotNull ResourcePack vanillaPack) { return key -> { Model model = pack.model(key); if (model == null) { diff --git a/converter/src/main/java/org/geysermc/pack/converter/type/sound/SoundConverter.java b/converter/src/main/java/org/geysermc/pack/converter/type/sound/SoundConverter.java new file mode 100644 index 0000000..367cfc3 --- /dev/null +++ b/converter/src/main/java/org/geysermc/pack/converter/type/sound/SoundConverter.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/PackConverter + * + */ + +package org.geysermc.pack.converter.type.sound; + +import org.geysermc.pack.bedrock.resource.BedrockResourcePack; +import org.geysermc.pack.converter.pipeline.AssetCombiner; +import org.geysermc.pack.converter.pipeline.AssetConverter; +import org.geysermc.pack.converter.pipeline.CombineContext; +import org.geysermc.pack.converter.pipeline.ConversionContext; +import org.jetbrains.annotations.Nullable; +import team.unnamed.creative.sound.Sound; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +public class SoundConverter implements AssetConverter, AssetCombiner { + public static final SoundConverter INSTANCE = new SoundConverter(); + + @Override + public @Nullable Sound convert(Sound sound, ConversionContext context) throws Exception { + return sound; + } + + @Override + public void include(BedrockResourcePack pack, List sounds, CombineContext context) { + List exported = new ArrayList<>(); + Path output = pack.directory().resolve(SoundRegistryConverter.BEDROCK_SOUNDS_LOCATION); + + for (Sound sound : sounds) { + String path = sound.key().value(); + if (exported.contains(path)) { + context.warn("Conflicting sound file " + sound.key() + "!"); + continue; + } + Path file = output.resolve(path + ".ogg"); + Path directory = file.getParent(); + try { + Files.createDirectories(directory); + try (OutputStream outputStream = new FileOutputStream(file.toFile())) { + sound.data().write(outputStream); + } + } catch (IOException exception) { + context.error("Failed to write sound file " + sound.key() + "!", exception); + continue; + } + exported.add(path); + } + } +} diff --git a/converter/src/main/java/org/geysermc/pack/converter/type/sound/SoundRegistryConverter.java b/converter/src/main/java/org/geysermc/pack/converter/type/sound/SoundRegistryConverter.java new file mode 100644 index 0000000..c4c4566 --- /dev/null +++ b/converter/src/main/java/org/geysermc/pack/converter/type/sound/SoundRegistryConverter.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/PackConverter + * + */ + +package org.geysermc.pack.converter.type.sound; + +import org.geysermc.pack.bedrock.resource.BedrockResourcePack; +import org.geysermc.pack.bedrock.resource.sounds.sounddefinitions.SoundDefinitions; +import org.geysermc.pack.bedrock.resource.sounds.sounddefinitions.Sounds; +import org.geysermc.pack.converter.pipeline.AssetCombiner; +import org.geysermc.pack.converter.pipeline.AssetConverter; +import org.geysermc.pack.converter.pipeline.CombineContext; +import org.geysermc.pack.converter.pipeline.ConversionContext; +import org.jetbrains.annotations.Nullable; +import team.unnamed.creative.sound.SoundEntry; +import team.unnamed.creative.sound.SoundEvent; +import team.unnamed.creative.sound.SoundRegistry; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SoundRegistryConverter implements AssetConverter>, AssetCombiner> { + public static final SoundRegistryConverter INSTANCE = new SoundRegistryConverter(); + static final String BEDROCK_SOUNDS_LOCATION = "sounds"; + + @Override + public @Nullable Map convert(SoundRegistry soundRegistry, ConversionContext context) throws Exception { + Map definitions = new HashMap<>(); + + for (SoundEvent value : soundRegistry.sounds()) { + String key = value.key().asString(); + + SoundDefinitions definition = new SoundDefinitions(); + definition.useLegacyMaxDistance(true); // TODO: Needed? + definition.maxDistance(64); // ??? + for (SoundEntry sound : value.sounds()) { + Sounds bedrockSound = new Sounds(); + bedrockSound.name(BEDROCK_SOUNDS_LOCATION + "/" + sound.key().value()); + bedrockSound.stream(sound.stream()); + bedrockSound.loadOnLowMemory(true); + bedrockSound.volume(sound.volume()); + bedrockSound.pitch(sound.pitch()); + bedrockSound.weight(sound.weight()); + + definition.sounds().add(bedrockSound); + } + + definitions.put(key, definition); + } + + return definitions; + } + + @Override + public void include(BedrockResourcePack pack, List> maps, CombineContext context) { + List soundEvents = new ArrayList<>(); + + for (Map definitions : maps) { + for (Map.Entry entry : definitions.entrySet()) { + if (soundEvents.contains(entry.getKey())) { + context.warn("Conflicting sound event " + entry.getKey() + "!"); + } + pack.addSoundDefinition(entry.getKey(), entry.getValue()); + soundEvents.add(entry.getKey()); + } + } + } +} diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/PngToTgaMappings.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/PngToTgaMappings.java similarity index 99% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/PngToTgaMappings.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/PngToTgaMappings.java index eefd54d..dfadfc2 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/PngToTgaMappings.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/PngToTgaMappings.java @@ -24,7 +24,7 @@ * */ -package org.geysermc.pack.converter.converter.texture; +package org.geysermc.pack.converter.type.texture; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -189,10 +189,10 @@ public final class PngToTgaMappings { }; @Nullable - public static TgaMapping mapping(@NotNull String key) { + static TgaMapping mapping(@NotNull String key) { return MAPPINGS.get(key); } - + record TgaMapping(String value, boolean keep) { public TgaMapping(String value) { diff --git a/converter/src/main/java/org/geysermc/pack/converter/type/texture/TextureConverter.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/TextureConverter.java new file mode 100644 index 0000000..b6f17be --- /dev/null +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/TextureConverter.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2019-2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/PackConverter + * + */ + +package org.geysermc.pack.converter.type.texture; + +import org.geysermc.pack.bedrock.resource.BedrockResourcePack; +import org.geysermc.pack.converter.pipeline.AssetCombiner; +import org.geysermc.pack.converter.pipeline.AssetConverter; +import org.geysermc.pack.converter.pipeline.AssetExtractor; +import org.geysermc.pack.converter.pipeline.CombineContext; +import org.geysermc.pack.converter.pipeline.ConversionContext; +import org.geysermc.pack.converter.pipeline.ExtractionContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TransformedTexture; +import org.geysermc.pack.converter.util.ImageUtil; +import org.jetbrains.annotations.Nullable; +import team.unnamed.creative.ResourcePack; +import team.unnamed.creative.texture.Texture; + +import javax.imageio.ImageIO; +import java.awt.AlphaComposite; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.stream.StreamSupport; + +public class TextureConverter implements AssetExtractor, AssetConverter, AssetCombiner { + public static final TextureConverter INSTANCE = new TextureConverter(); + public static final String BEDROCK_TEXTURES_LOCATION = "textures"; + + private final List transformers = StreamSupport.stream(ServiceLoader.load(TextureTransformer.class).spliterator(), false) + .sorted(Comparator.comparingInt(TextureTransformer::order)) + .toList(); + + public static final Map DIRECTORY_LOCATIONS = Map.of( + "block", "blocks", + "item", "items", + "gui", "ui" + ); + + @Override + public Collection extract(ResourcePack pack, ExtractionContext context) { + // 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 + TextureMappings mappings = TextureMappings.textureMappings(); + List textures = new ArrayList<>(pack.textures()); + + context.info("Transforming textures..."); + TransformContext transformContext = new TransformContext( + mappings, + textures, + context.bedrockResourcePack(), + pack, + context.vanillaPack(), + context.logListener() + ); + for (TextureTransformer transformer : this.transformers) { + try { + transformer.transform(transformContext); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + context.info("Transformed textures!"); + + return textures; + } + + @Override + public @Nullable TransformedTexture convert(Texture texture, ConversionContext context) throws Exception { + TextureMappings mappings = TextureMappings.textureMappings(); + TransformedTexture transformed = new TransformedTexture(texture); + + String input = texture.key().value(); + String relativePath = input.replaceAll("\\.png$", ""); + + String rootPath = relativePath.substring(0, relativePath.indexOf('/')); + String bedrockRoot = DIRECTORY_LOCATIONS.getOrDefault(rootPath, rootPath); + + Object mappingObject = mappings.textures(relativePath); + + if (mappingObject == null) { + mappingObject = mappings.textures(rootPath); + } + + String fallbackPath = bedrockRoot + "/" + relativePath.substring(relativePath.indexOf('/') + 1) + ".png"; + if (mappingObject instanceof Map keyMappings) { // Handles common subdirectories + String sanitizedName = input.substring(input.indexOf('/') + 1); + if (sanitizedName.endsWith(".png")) sanitizedName = sanitizedName.substring(0, sanitizedName.length() - 4); + + Object bedrockOutput = keyMappings.get(sanitizedName); + if (bedrockOutput instanceof String bedrockPath) { + transformed.output(bedrockRoot + "/" + bedrockPath + ".png"); + } else if (bedrockOutput instanceof List paths) { + for (String bedrockPath : (List) paths) { + transformed.output(bedrockRoot + "/" + bedrockPath + ".png"); + } + } else { // Fallback + transformed.output(fallbackPath); + } + } else if (mappingObject instanceof String str) { // Direct mappings + transformed.output(str + ".png"); + } else if (mappingObject instanceof List paths) { // Mappings where duplicate code paths exist + for (String path : (List) paths) { + transformed.output(path + ".png"); + } + } else { // Fallback + transformed.output(fallbackPath); + } + + return transformed; + } + + @Override + public void include(BedrockResourcePack pack, List transformedTextures, CombineContext context) { + Path texturePath = pack.directory().resolve(BEDROCK_TEXTURES_LOCATION); + List exportedPaths = new ArrayList<>(); + + for (TransformedTexture textureToExport : transformedTextures) { + String bedrockDirectory = "%s/%s"; + if (context.textureSubDirectory() != null) { + bedrockDirectory = "%s/" + context.textureSubDirectory() + "/%s"; + } + + List outputs = new ArrayList<>(); + for (String outputPath : textureToExport.output()) { + if (exportedPaths.contains(outputPath)) { + context.warn("Conflicting texture " + outputPath + "!"); + continue; + } + exportedPaths.add(outputPath); + + String root = outputPath.substring(0, outputPath.indexOf('/')); + String value = outputPath.substring(outputPath.indexOf('/') + 1); + + outputs.add(texturePath.resolve(( + bedrockDirectory.formatted(root, value) + ).replace('/', File.separatorChar))); + } + + try { + byte[] bytes = textureToExport.texture().data().toByteArray(); + + BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); + + for (Path output : outputs) { + if (output.getParent() != null && Files.notExists(output.getParent())) { + Files.createDirectories(output.getParent()); + } + + BufferedImage bedrockImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB); + + Graphics2D g = bedrockImage.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(image, 0, 0, null); + g.dispose(); + + String pngKey = pack.directory().relativize(output).toString().replace(File.separatorChar, '/'); + PngToTgaMappings.TgaMapping mapping = PngToTgaMappings.mapping(pngKey); + if (mapping != null) { + Path tgaPath = pack.directory().resolve(mapping.value()); + if (Files.notExists(tgaPath.getParent())) { + Files.createDirectories(tgaPath.getParent()); + } + + ImageUtil.writeTGA(tgaPath, bedrockImage); + if (!mapping.keep()) { + Files.deleteIfExists(output); + continue; + } + } + + try (OutputStream stream = Files.newOutputStream(output)) { + ImageIO.write(bedrockImage, "png", stream); + } + } + } catch (IOException exception) { + context.error("Failed to write texture " + textureToExport.texture().key() + "!", exception); + } + } + } +} diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/TextureMappings.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/TextureMappings.java similarity index 96% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/TextureMappings.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/TextureMappings.java index f11360e..4ddff9a 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/TextureMappings.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/TextureMappings.java @@ -24,7 +24,7 @@ * */ -package org.geysermc.pack.converter.converter.texture; +package org.geysermc.pack.converter.type.texture; import com.google.gson.Gson; import lombok.ToString; @@ -34,7 +34,6 @@ import org.jetbrains.annotations.Nullable; import java.io.InputStream; import java.io.InputStreamReader; import java.util.LinkedHashMap; -import java.util.Map; @ToString public class TextureMappings extends LinkedHashMap { diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/TextureTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/TextureTransformer.java similarity index 96% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/TextureTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/TextureTransformer.java index 85e02ef..cf5bb01 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/TextureTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/TextureTransformer.java @@ -24,7 +24,7 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer; +package org.geysermc.pack.converter.type.texture.transformer; import org.geysermc.pack.converter.util.ImageUtil; import org.jetbrains.annotations.NotNull; diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/TransformContext.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/TransformContext.java similarity index 78% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/TransformContext.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/TransformContext.java index 883ec98..6397c07 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/TransformContext.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/TransformContext.java @@ -24,14 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer; +package org.geysermc.pack.converter.type.texture.transformer; import net.kyori.adventure.key.Key; import org.geysermc.pack.bedrock.resource.BedrockResourcePack; -import org.geysermc.pack.converter.PackConversionContext; -import org.geysermc.pack.converter.converter.texture.TextureMappings; -import org.geysermc.pack.converter.data.TextureConversionData; +import org.geysermc.pack.converter.type.texture.TextureMappings; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.LogListener; +import org.geysermc.pack.converter.util.LogListenerHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import team.unnamed.creative.ResourcePack; @@ -43,27 +43,33 @@ import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Optional; -public class TransformContext { - private final PackConversionContext conversionContext; +public class TransformContext implements LogListenerHelper { private final TextureMappings mappings; private final Collection textures; + // TODO figure out how to handle this, this is executed in the extraction phase and ideally bedrock pack wouldn't be accessed then + @Deprecated(forRemoval = true) private final BedrockResourcePack bedrockPack; private final ResourcePack javaPack; + private final Optional vanillaPack; + private final LogListener logListener; private final Map byKey = new HashMap<>(); public TransformContext( - PackConversionContext conversionContext, TextureMappings mappings, Collection textures, BedrockResourcePack bedrockPack, - ResourcePack javaPack + ResourcePack javaPack, + Optional vanillaPack, + LogListener logListener ) { - this.conversionContext = conversionContext; this.mappings = mappings; this.textures = textures; this.bedrockPack = bedrockPack; this.javaPack = javaPack; + this.vanillaPack = vanillaPack; + this.logListener = logListener; for (Texture texture : textures) { this.byKey.put(texture.key(), texture); @@ -74,16 +80,17 @@ public class TransformContext { return this.mappings; } + @Deprecated(forRemoval = true) public BedrockResourcePack bedrockResourcePack() { - return this.bedrockPack; + return bedrockPack; } public ResourcePack javaResourcePack() { return this.javaPack; } - public ResourcePack vanillaPack() { - return this.conversionContext.data().vanillaPack(); + public Optional vanillaPack() { + return vanillaPack; } /** @@ -126,8 +133,7 @@ public class TransformContext { public Texture pollOrPeekVanilla(@NotNull Key key) { Texture remove = this.byKey.remove(key); if (remove == null) { - // This *shouldn't* be null, but if a bad key is inputted, it is possible this value is null - return this.conversionContext.data().vanillaPack().texture(key); + return vanillaPack.map(pack -> pack.texture(key)).orElse(null); } this.textures.remove(remove); @@ -146,8 +152,7 @@ public class TransformContext { public Texture peekOrVanilla(@NotNull Key key) { Texture texture = this.byKey.get(key); if (texture == null) { - // This *shouldn't* be null, but if a bad key is inputted, it is possible this value is null - return this.conversionContext.data().vanillaPack().texture(key); + return vanillaPack.map(pack -> pack.texture(key)).orElse(null); } return texture; @@ -186,23 +191,7 @@ public class TransformContext { this.byKey.put(texture.key(), texture); } - public void debug(@NotNull String message) { - this.conversionContext.debug(message); - } - - public void info(@NotNull String message) { - this.conversionContext.info(message); - } - - public void warn(@NotNull String message) { - this.conversionContext.warn(message); - } - - public void error(@NotNull String message) { - this.conversionContext.error(message); - } - - public void error(@NotNull String message, @NotNull Throwable throwable) { - this.conversionContext.error(message, throwable); + public LogListener logListener() { + return logListener; } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/TransformedTexture.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/TransformedTexture.java similarity index 80% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/TransformedTexture.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/TransformedTexture.java index 6949742..5387c5f 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/TransformedTexture.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/TransformedTexture.java @@ -24,20 +24,20 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer; +package org.geysermc.pack.converter.type.texture.transformer; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; -import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; public class TransformedTexture { private final Texture texture; - private Path output; + private final List outputs = new ArrayList<>(); - public TransformedTexture(@NotNull Texture texture, @NotNull Path output) { + public TransformedTexture(@NotNull Texture texture) { this.texture = texture; - this.output = output; } @NotNull @@ -46,11 +46,11 @@ public class TransformedTexture { } @NotNull - public Path output() { - return output; + public List output() { + return outputs; } - public void output(@NotNull Path output) { - this.output = output; + public void output(@NotNull String output) { + outputs.add(output); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/AtlasTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/AtlasTransformer.java similarity index 85% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/AtlasTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/AtlasTransformer.java index 99c3f79..81f5c30 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/AtlasTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/AtlasTransformer.java @@ -24,12 +24,13 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type; +package org.geysermc.pack.converter.type.texture.transformer.type; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -54,7 +55,7 @@ public class AtlasTransformer implements TextureTransformer { BufferedImage atlasImage = null; for (int i = 0; i <= atlasCount; i++) { - Texture texture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, String.format(javaName, String.format("%1$2s", i).replace(" ", "0")))); + Texture texture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, String.format(javaName, String.format("%1$2s", i).replace(" ", "0")))); if (texture == null) { continue; } @@ -69,7 +70,7 @@ public class AtlasTransformer implements TextureTransformer { } if (atlasImage != null) { - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, bedrockName), atlasImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, bedrockName), atlasImage, "png"); context.debug(String.format("Created atlas %s", bedrockName)); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ColorizeTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ColorizeTransformer.java similarity index 99% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ColorizeTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ColorizeTransformer.java index 22f7168..83e91c7 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ColorizeTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ColorizeTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type; +package org.geysermc.pack.converter.type.texture.transformer.type; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.geysermc.pack.converter.util.UnsafeKey; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -272,7 +273,7 @@ public class ColorizeTransformer implements TextureTransformer { Color color = overlay.color(); boolean deleteOverlay = overlay.deleteOverlay(); - Key key = Key.key(Key.MINECRAFT_NAMESPACE, overlayPath); + Key key = KeyUtil.key(Key.MINECRAFT_NAMESPACE, overlayPath); Texture texture = deleteOverlay ? context.poll(key) : context.peek(key); if (texture == null) { context.debug("Missing overlay texture: " + overlayPath); diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/OverlayTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/OverlayTransformer.java similarity index 94% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/OverlayTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/OverlayTransformer.java index f0c4b4c..8331784 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/OverlayTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/OverlayTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type; +package org.geysermc.pack.converter.type.texture.transformer.type; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -102,8 +103,8 @@ public class OverlayTransformer implements TextureTransformer { boolean noReplace = overlay.noReplace(); boolean keep = overlay.keep(); - Key javaKey = Key.key(Key.MINECRAFT_NAMESPACE, javaName); - Key overlayKey = Key.key(Key.MINECRAFT_NAMESPACE, overlayName); + Key javaKey = KeyUtil.key(Key.MINECRAFT_NAMESPACE, javaName); + Key overlayKey = KeyUtil.key(Key.MINECRAFT_NAMESPACE, overlayName); // We don't have either textures, skip this if (!context.isTexturePresent(javaKey) && !context.isTexturePresent(overlayKey)) continue; @@ -149,7 +150,7 @@ public class OverlayTransformer implements TextureTransformer { } } - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, bedrockName), image, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, bedrockName), image, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/WeatherTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/WeatherTransformer.java similarity index 83% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/WeatherTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/WeatherTransformer.java index 52b51df..b723dad 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/WeatherTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/WeatherTransformer.java @@ -24,17 +24,18 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type; +package org.geysermc.pack.converter.type.texture.transformer.type; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; -import java.awt.*; +import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; @@ -46,8 +47,8 @@ public class WeatherTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { - Texture snowTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, SNOW_INPUT)); - Texture rainTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, RAIN_INPUT)); + Texture snowTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, SNOW_INPUT)); + Texture rainTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, RAIN_INPUT)); if (snowTexture == null || rainTexture == null) { return; } @@ -69,6 +70,6 @@ public class WeatherTransformer implements TextureTransformer { // Rain graphics.drawImage(ImageUtil.cover(ImageUtil.crop(rainImage, rainImage.getWidth(), (int) (5 * factor)), weatherImage.getWidth(), (int) (5 * factor)), 0, (int) (5 * factor), null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, WEATHER_OUTPUT), weatherImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, WEATHER_OUTPUT), weatherImage, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/BedTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/BedTransformer.java similarity index 90% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/BedTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/BedTransformer.java index f7c8371..b43b141 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/BedTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/BedTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.block; +package org.geysermc.pack.converter.type.texture.transformer.type.block; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -65,7 +66,7 @@ public class BedTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { for (String bedColor : BED_COLORS) { - Texture texture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, BED_PATH + "/" + bedColor + ".png")); + Texture texture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, BED_PATH + "/" + bedColor + ".png")); if (texture == null) { continue; } @@ -110,7 +111,7 @@ public class BedTransformer implements TextureTransformer { graphics.drawImage(ImageUtil.rotate(ImageUtil.crop(bedImage, ((fromX + 9) * factor), ((fromY + 3) * factor), (3 * factor), (3 * factor)), 180), ((toX + 3) * factor), (toY * factor), null); } - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, BED_PATH + "/" + bedColor + ".png"), newBedImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, BED_PATH + "/" + bedColor + ".png"), newBedImage, "png"); } } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ChestDoubleTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ChestDoubleTransformer.java similarity index 92% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ChestDoubleTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ChestDoubleTransformer.java index ee21afc..b9c6e30 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ChestDoubleTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ChestDoubleTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.block; +package org.geysermc.pack.converter.type.texture.transformer.type.block; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -50,8 +51,8 @@ public class ChestDoubleTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { for (ChestData chest : CHEST_DATA) { - Texture leftTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, chest.javaNameLeft())); - Texture rightTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, chest.javaNameRight())); + Texture leftTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, chest.javaNameLeft())); + Texture rightTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, chest.javaNameRight())); if (leftTexture == null || rightTexture == null) { continue; } @@ -101,7 +102,7 @@ public class ChestDoubleTransformer implements TextureTransformer { graphics.drawImage(ImageUtil.crop(leftImage, 0, 0, (6 * factor), (6 * factor)), 0, 0, null); graphics.drawImage(ImageUtil.crop(rightImage, 0, 0, (6 * factor), (6 * factor)), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, chest.bedrockName()), newImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, chest.bedrockName()), newImage, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ChestFrontTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ChestFrontTransformer.java similarity index 86% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ChestFrontTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ChestFrontTransformer.java index 6ee5c91..3a0f8a7 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ChestFrontTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ChestFrontTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.block; +package org.geysermc.pack.converter.type.texture.transformer.type.block; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -50,7 +51,7 @@ public class ChestFrontTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { for (ChestData chest : CHESTS) { - Texture texture = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, chest.javaName())); + Texture texture = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, chest.javaName())); if (texture == null) { continue; } @@ -68,7 +69,7 @@ public class ChestFrontTransformer implements TextureTransformer { graphics.drawImage(ImageUtil.crop(fromImage, (14 * factor), (34 * factor), (14 * factor), (9 * factor)), 0, (5 * factor), null); graphics.drawImage(ImageUtil.crop(fromImage , factor, factor, (2 * factor), (4 * factor)), (6 * factor), (3 * factor), null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, chest.bedrockName()), newImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, chest.bedrockName()), newImage, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ChestNormalTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ChestNormalTransformer.java similarity index 90% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ChestNormalTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ChestNormalTransformer.java index 8d7ca38..7b9d71d 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ChestNormalTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ChestNormalTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.block; +package org.geysermc.pack.converter.type.texture.transformer.type.block; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -53,7 +54,7 @@ public class ChestNormalTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { for (String variant : VARIANTS) { - Texture texture = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, CHEST_PATH + "/" + variant + ".png")); + Texture texture = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, CHEST_PATH + "/" + variant + ".png")); if (texture == null) { continue; } @@ -86,7 +87,7 @@ public class ChestNormalTransformer implements TextureTransformer { graphics.drawImage(ImageUtil.crop(chestImage, 0, 0, (6 * factor), (6 * factor)), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, CHEST_PATH + "/" + variant + ".png"), newChestImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, CHEST_PATH + "/" + variant + ".png"), newChestImage, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ChestSideTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ChestSideTransformer.java similarity index 85% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ChestSideTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ChestSideTransformer.java index 2e58d0f..fde2e37 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ChestSideTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ChestSideTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.block; +package org.geysermc.pack.converter.type.texture.transformer.type.block; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -49,7 +50,7 @@ public class ChestSideTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { for (ChestData chest : CHESTS) { - Texture texture = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, chest.javaName())); + Texture texture = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, chest.javaName())); if (texture == null) { continue; } @@ -66,7 +67,7 @@ public class ChestSideTransformer implements TextureTransformer { graphics.drawImage(ImageUtil.crop(fromImage, (28 * factor), (14 * factor), (14 * factor), (5 * factor)), 0, 0, null); graphics.drawImage(ImageUtil.crop(fromImage, (28 * factor), (34 * factor), (14 * factor), (9 * factor)), 0, (5 * factor), null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, chest.bedrockName()), newImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, chest.bedrockName()), newImage, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ConduitTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ConduitTransformer.java similarity index 75% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ConduitTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ConduitTransformer.java index f9b07bd..6f4b163 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/ConduitTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/ConduitTransformer.java @@ -24,17 +24,18 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.block; +package org.geysermc.pack.converter.type.texture.transformer.type.block; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; -import java.awt.*; +import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; @@ -42,7 +43,7 @@ import java.io.IOException; public class ConduitTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { - Texture baseTexture = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, "entity/conduit/base.png")); + Texture baseTexture = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "entity/conduit/base.png")); if (baseTexture != null) { BufferedImage baseImage = this.readImage(baseTexture); @@ -53,10 +54,10 @@ public class ConduitTransformer implements TextureTransformer { Graphics g = bedrockBaseImage.getGraphics(); g.drawImage(ImageUtil.crop(baseImage, 0, 0, (int) (24 * scale), (int) (12 * scale)), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "blocks/conduit_base.png"), bedrockBaseImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "blocks/conduit_base.png"), bedrockBaseImage, "png"); } - Texture eyeTexture = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, "entity/conduit/closed_eye.png")); + Texture eyeTexture = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "entity/conduit/closed_eye.png")); if (eyeTexture != null) { BufferedImage image = this.readImage(eyeTexture); @@ -67,10 +68,10 @@ public class ConduitTransformer implements TextureTransformer { Graphics g = bedrockImage.getGraphics(); g.drawImage(ImageUtil.crop(image, 0, 0, (int) (8 * scale), (int) (8 * scale)), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "blocks/conduit_closed.png"), bedrockImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "blocks/conduit_closed.png"), bedrockImage, "png"); } - Texture eyeOpenTexture = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, "entity/conduit/open_eye.png")); + Texture eyeOpenTexture = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "entity/conduit/open_eye.png")); if (eyeOpenTexture != null) { BufferedImage image = this.readImage(eyeOpenTexture); @@ -81,7 +82,7 @@ public class ConduitTransformer implements TextureTransformer { Graphics g = bedrockImage.getGraphics(); g.drawImage(ImageUtil.crop(image, 0, 0, (int) (8 * scale), (int) (8 * scale)), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "blocks/conduit_open.png"), bedrockImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "blocks/conduit_open.png"), bedrockImage, "png"); } } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/LiquidTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/LiquidTransformer.java similarity index 86% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/LiquidTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/LiquidTransformer.java index 63210fd..f6a551b 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/LiquidTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/LiquidTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.block; +package org.geysermc.pack.converter.type.texture.transformer.type.block; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -55,7 +56,7 @@ public class LiquidTransformer implements TextureTransformer { int minWidth = liquid.minWidth(); boolean grayscale = liquid.grayscale(); - Texture texture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, javaName)); + Texture texture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, javaName)); if (texture == null) { continue; } @@ -70,7 +71,7 @@ public class LiquidTransformer implements TextureTransformer { liquidImage = ImageUtil.ensureMinWidth(liquidImage, minWidth); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, bedrockName), liquidImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, bedrockName), liquidImage, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/TallSeagrassTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/TallSeagrassTransformer.java similarity index 70% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/TallSeagrassTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/TallSeagrassTransformer.java index d11d589..fa2f182 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/block/TallSeagrassTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/block/TallSeagrassTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.block; +package org.geysermc.pack.converter.type.texture.transformer.type.block; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -47,22 +48,22 @@ public class TallSeagrassTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { - Texture javaTop = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, JAVA_TOP)); + Texture javaTop = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, JAVA_TOP)); if (javaTop != null) { BufferedImage javaImage = this.readImage(javaTop); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, BEDROCK_TOP.formatted("a")), javaImage, "png"); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, BEDROCK_TOP.formatted("b")), ImageUtil.flip(javaImage, true, false), "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, BEDROCK_TOP.formatted("a")), javaImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, BEDROCK_TOP.formatted("b")), ImageUtil.flip(javaImage, true, false), "png"); } - Texture javaBottom = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, JAVA_BOTTOM)); + Texture javaBottom = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, JAVA_BOTTOM)); if (javaBottom != null) { BufferedImage javaImage = this.readImage(javaBottom); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, BEDROCK_BOTTOM.formatted("a")), javaImage, "png"); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, BEDROCK_BOTTOM.formatted("b")), ImageUtil.flip(javaImage, true, false), "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, BEDROCK_BOTTOM.formatted("a")), javaImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, BEDROCK_BOTTOM.formatted("b")), ImageUtil.flip(javaImage, true, false), "png"); } } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/ArrowTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/ArrowTransformer.java similarity index 87% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/ArrowTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/ArrowTransformer.java index 05a97c4..96ce094 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/ArrowTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/ArrowTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.entity; +package org.geysermc.pack.converter.type.texture.transformer.type.entity; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -46,7 +47,7 @@ public class ArrowTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { - Texture texture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, INPUT)); + Texture texture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, INPUT)); if (texture == null) { return; } @@ -76,6 +77,6 @@ public class ArrowTransformer implements TextureTransformer { graphics.drawImage(fromImage, 0, 10 * factor, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, OUTPUT), newArrowImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, OUTPUT), newArrowImage, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/DolphinTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/DolphinTransformer.java similarity index 97% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/DolphinTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/DolphinTransformer.java index 4cc5237..eb90a0e 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/DolphinTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/DolphinTransformer.java @@ -24,17 +24,18 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.entity; +package org.geysermc.pack.converter.type.texture.transformer.type.entity; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; -import java.awt.*; +import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; @@ -44,7 +45,7 @@ public class DolphinTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { - Texture javaTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, LOCATION)); + Texture javaTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, LOCATION)); if (javaTexture == null) return; BufferedImage javaImage = this.readImage(javaTexture); @@ -590,6 +591,6 @@ public class DolphinTransformer implements TextureTransformer { null ); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, LOCATION), bedrockImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, LOCATION), bedrockImage, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/DrownedTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/DrownedTransformer.java similarity index 82% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/DrownedTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/DrownedTransformer.java index eb85aa9..9283a88 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/DrownedTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/DrownedTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.entity; +package org.geysermc.pack.converter.type.texture.transformer.type.entity; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -47,8 +48,8 @@ public class DrownedTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { - Texture drownedTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, String.format(TEXTURE_PATH, DROWNED_TEXTURE))); - Texture outerLayerTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, String.format(TEXTURE_PATH, DROWNED_OUTER_LAYER_TEXTURE))); + Texture drownedTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, String.format(TEXTURE_PATH, DROWNED_TEXTURE))); + Texture outerLayerTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, String.format(TEXTURE_PATH, DROWNED_OUTER_LAYER_TEXTURE))); if (drownedTexture == null || outerLayerTexture == null) { return; @@ -71,6 +72,6 @@ public class DrownedTransformer implements TextureTransformer { graphics.drawImage(ImageUtil.crop(overlayImage, (int) (16 * factor), (int) (48 * factor), (int) (16 * factor), (int) (16 * factor)), 0, (int) (48 * factor), null); graphics.drawImage(ImageUtil.crop(overlayImage, (int) (32 * factor), (int) (48 * factor), (int) (16 * factor), (int) (16 * factor)), (int) (48 * factor), (int) (48 * factor), null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, String.format(TEXTURE_PATH, DROWNED_TEXTURE)), newImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, String.format(TEXTURE_PATH, DROWNED_TEXTURE)), newImage, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/PaintingTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/PaintingTransformer.java similarity index 90% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/PaintingTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/PaintingTransformer.java index ed3703c..255da41 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/PaintingTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/PaintingTransformer.java @@ -24,22 +24,21 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.entity; +package org.geysermc.pack.converter.type.texture.transformer.type.entity; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; -import java.awt.*; +import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; @AutoService(TextureTransformer.class) @@ -52,11 +51,11 @@ public class PaintingTransformer implements TextureTransformer { public void transform(@NotNull TransformContext context) throws IOException { // Let's check if we actually need to convert anything. boolean isAnyPresent = PAINTING_DATA.keySet().stream().anyMatch(key -> { - return context.isTexturePresent(Key.key(Key.MINECRAFT_NAMESPACE, JAVA_LOCATION.formatted(key))); + return context.isTexturePresent(KeyUtil.key(Key.MINECRAFT_NAMESPACE, JAVA_LOCATION.formatted(key))); }); // We don't map this like the others because bedrock is difficult, so it isn't in PAINTING_DATA. - isAnyPresent = isAnyPresent || context.isTexturePresent(Key.key(Key.MINECRAFT_NAMESPACE, JAVA_LOCATION.formatted("back"))); + isAnyPresent = isAnyPresent || context.isTexturePresent(KeyUtil.key(Key.MINECRAFT_NAMESPACE, JAVA_LOCATION.formatted("back"))); if (!isAnyPresent) return; // we have nothing to convert, skip this @@ -65,7 +64,7 @@ public class PaintingTransformer implements TextureTransformer { Map scales = new HashMap<>(); PAINTING_DATA.forEach((key, value) -> { - Texture javaTexture = context.pollOrPeekVanilla(Key.key(Key.MINECRAFT_NAMESPACE, JAVA_LOCATION.formatted(key))); + Texture javaTexture = context.pollOrPeekVanilla(KeyUtil.key(Key.MINECRAFT_NAMESPACE, JAVA_LOCATION.formatted(key))); if (javaTexture == null) { scales.put(key, 1f); return; @@ -83,7 +82,7 @@ public class PaintingTransformer implements TextureTransformer { }); // Again, bedrock being difficult with back. - Texture backTexture = context.pollOrPeekVanilla(Key.key(Key.MINECRAFT_NAMESPACE, JAVA_LOCATION.formatted("back"))); + Texture backTexture = context.pollOrPeekVanilla(KeyUtil.key(Key.MINECRAFT_NAMESPACE, JAVA_LOCATION.formatted("back"))); if (backTexture != null) { BufferedImage image = this.readImage(backTexture); @@ -128,7 +127,7 @@ public class PaintingTransformer implements TextureTransformer { } } - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "painting/kz.png"), bedrockImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "painting/kz.png"), bedrockImage, "png"); } // BedrockX and BedrockY determine where the image is in kz.png (Bedrock painting atlas) diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/SheepTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/SheepTransformer.java similarity index 87% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/SheepTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/SheepTransformer.java index 9ee5528..124dec2 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/SheepTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/SheepTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.entity; +package org.geysermc.pack.converter.type.texture.transformer.type.entity; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -47,9 +48,9 @@ public class SheepTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { - Key sheepKey = Key.key(Key.MINECRAFT_NAMESPACE, SHEEP); - Key woolKey = Key.key(Key.MINECRAFT_NAMESPACE, SHEEP_WOOL); - Key undercoatKey = Key.key(Key.MINECRAFT_NAMESPACE, SHEEP_UNDERCOAT); + Key sheepKey = KeyUtil.key(Key.MINECRAFT_NAMESPACE, SHEEP); + Key woolKey = KeyUtil.key(Key.MINECRAFT_NAMESPACE, SHEEP_WOOL); + Key undercoatKey = KeyUtil.key(Key.MINECRAFT_NAMESPACE, SHEEP_UNDERCOAT); if ( !context.isTexturePresent(sheepKey) && @@ -93,6 +94,6 @@ public class SheepTransformer implements TextureTransformer { g.drawImage(sheepWoolImage, 0, sheepImage.getHeight(), null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, SHEEP), newImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, SHEEP), newImage, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/VillagerTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/VillagerTransformer.java similarity index 87% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/VillagerTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/VillagerTransformer.java index 2b610c5..bae6a4f 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/VillagerTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/VillagerTransformer.java @@ -24,12 +24,13 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.entity; +package org.geysermc.pack.converter.type.texture.transformer.type.entity; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -69,7 +70,7 @@ public class VillagerTransformer implements TextureTransformer { for (String entity : ENTITIES) { for (String profession : VILLAGER_PROFESSIONS) { String texturePath = String.format(TEXTURE_PATH, entity, profession); - Texture texture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, texturePath)); + Texture texture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, texturePath)); if (texture == null) { continue; } @@ -91,7 +92,7 @@ public class VillagerTransformer implements TextureTransformer { } } - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, texturePath), newImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, texturePath), newImage, "png"); } } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/ZombieTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/ZombieTransformer.java similarity index 84% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/ZombieTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/ZombieTransformer.java index 9e4dba7..d1739ad 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/entity/ZombieTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/entity/ZombieTransformer.java @@ -24,17 +24,18 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.entity; +package org.geysermc.pack.converter.type.texture.transformer.type.entity; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; -import java.awt.*; +import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; @@ -53,7 +54,7 @@ public class ZombieTransformer implements TextureTransformer { public void transform(@NotNull TransformContext context) throws IOException { for (ZombieData zombieData : ZOMBIES) { String zombie = zombieData.name(); - Key path = Key.key(Key.MINECRAFT_NAMESPACE, TEXTURE_PATH.formatted(zombie)); + Key path = KeyUtil.key(Key.MINECRAFT_NAMESPACE, TEXTURE_PATH.formatted(zombie)); Texture texture = context.poll(path); if (texture == null) continue; @@ -70,7 +71,7 @@ public class ZombieTransformer implements TextureTransformer { context.offer(path, bedrockImage, "png"); if (zombieData.mobHead()) { - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, MOB_HEAD_PATH.formatted(zombie)), bedrockImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, MOB_HEAD_PATH.formatted(zombie)), bedrockImage, "png"); } } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/item/BundleTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/item/BundleTransformer.java similarity index 81% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/item/BundleTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/item/BundleTransformer.java index eb9b6de..a890596 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/item/BundleTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/item/BundleTransformer.java @@ -24,16 +24,17 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.item; +package org.geysermc.pack.converter.type.texture.transformer.type.item; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; -import java.awt.*; +import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; @@ -67,8 +68,8 @@ public class BundleTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { for (String color : COLORS) { - Texture backTexture = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, FRONT.formatted(color))); - Texture frontTexture = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, BACK.formatted(color))); + Texture backTexture = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, FRONT.formatted(color))); + Texture frontTexture = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, BACK.formatted(color))); if (backTexture == null || frontTexture == null) continue; // TODO: If one is missing, pull from vanilla pack BufferedImage backImage = this.readImage(backTexture); @@ -81,7 +82,7 @@ public class BundleTransformer implements TextureTransformer { g.drawImage(backImage, 0, 0, null); g.drawImage(frontImage, 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, BEDROCK_OUTPUT.formatted(color)), bedrockImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, BEDROCK_OUTPUT.formatted(color)), bedrockImage, "png"); } } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/BaseParticleTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/BaseParticleTransformer.java similarity index 91% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/BaseParticleTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/BaseParticleTransformer.java index d5bf4c3..d57dc54 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/BaseParticleTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/BaseParticleTransformer.java @@ -24,13 +24,14 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.particle; +package org.geysermc.pack.converter.type.texture.transformer.type.particle; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.geysermc.pack.converter.util.Spritesheet; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -75,10 +76,10 @@ public class BaseParticleTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { // Create a grayscale bubble image - Texture bubbleTexture = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, PATH + "/bubble.png")); + Texture bubbleTexture = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, PATH + "/bubble.png")); if (bubbleTexture != null) { BufferedImage bubble = this.readImage(bubbleTexture); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, PATH + "/bubble_gray.png"), ImageUtil.grayscale(bubble), "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, PATH + "/bubble_gray.png"), ImageUtil.grayscale(bubble), "png"); } this.createSpritesheet(context); @@ -169,7 +170,7 @@ public class BaseParticleTransformer implements TextureTransformer { context.debug(String.format("Creating particle spritesheet %s", OUTPUT)); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, PATH + "/" + OUTPUT), vanillaSprite, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, PATH + "/" + OUTPUT), vanillaSprite, "png"); } interface TextureData { @@ -181,7 +182,7 @@ public class BaseParticleTransformer implements TextureTransformer { @NotNull public Key textureKey(int atlas) { - return Key.key(Key.MINECRAFT_NAMESPACE, PATH + "/" + javaName + "_" + atlas + ".png"); + return KeyUtil.key(Key.MINECRAFT_NAMESPACE, PATH + "/" + javaName + "_" + atlas + ".png"); } @Override @@ -207,7 +208,7 @@ public class BaseParticleTransformer implements TextureTransformer { continue; } - Texture texture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, textureName + ".png")); + Texture texture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, textureName + ".png")); if (texture == null) { continue; } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/CampfireParticleTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/CampfireParticleTransformer.java similarity index 91% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/CampfireParticleTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/CampfireParticleTransformer.java index fd6f7c5..c8a1914 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/CampfireParticleTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/CampfireParticleTransformer.java @@ -24,10 +24,10 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.particle; +package org.geysermc.pack.converter.type.texture.transformer.type.particle; import com.google.auto.service.AutoService; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; @AutoService(TextureTransformer.class) public class CampfireParticleTransformer extends SpritesheetParticleTransformer { diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SculkChargeParticleTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SculkChargeParticleTransformer.java similarity index 91% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SculkChargeParticleTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SculkChargeParticleTransformer.java index 4d36051..e48542a 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SculkChargeParticleTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SculkChargeParticleTransformer.java @@ -24,10 +24,10 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.particle; +package org.geysermc.pack.converter.type.texture.transformer.type.particle; import com.google.auto.service.AutoService; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; @AutoService(TextureTransformer.class) public class SculkChargeParticleTransformer extends SpritesheetParticleTransformer { diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SculkChargePopParticleTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SculkChargePopParticleTransformer.java similarity index 91% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SculkChargePopParticleTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SculkChargePopParticleTransformer.java index 5a66252..a87546a 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SculkChargePopParticleTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SculkChargePopParticleTransformer.java @@ -24,10 +24,10 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.particle; +package org.geysermc.pack.converter.type.texture.transformer.type.particle; import com.google.auto.service.AutoService; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; @AutoService(TextureTransformer.class) public class SculkChargePopParticleTransformer extends SpritesheetParticleTransformer { diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SculkSoulParticleTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SculkSoulParticleTransformer.java similarity index 91% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SculkSoulParticleTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SculkSoulParticleTransformer.java index ed36b81..c1a4e8f 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SculkSoulParticleTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SculkSoulParticleTransformer.java @@ -24,10 +24,10 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.particle; +package org.geysermc.pack.converter.type.texture.transformer.type.particle; import com.google.auto.service.AutoService; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; @AutoService(TextureTransformer.class) public class SculkSoulParticleTransformer extends SpritesheetParticleTransformer { diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SonicExplosionParticleTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SonicExplosionParticleTransformer.java similarity index 91% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SonicExplosionParticleTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SonicExplosionParticleTransformer.java index a6b7ed6..8829660 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SonicExplosionParticleTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SonicExplosionParticleTransformer.java @@ -24,10 +24,10 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.particle; +package org.geysermc.pack.converter.type.texture.transformer.type.particle; import com.google.auto.service.AutoService; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; @AutoService(TextureTransformer.class) public class SonicExplosionParticleTransformer extends SpritesheetParticleTransformer { diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SoulParticleTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SoulParticleTransformer.java similarity index 91% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SoulParticleTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SoulParticleTransformer.java index 3577024..5e98b30 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SoulParticleTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SoulParticleTransformer.java @@ -24,10 +24,10 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.particle; +package org.geysermc.pack.converter.type.texture.transformer.type.particle; import com.google.auto.service.AutoService; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; @AutoService(TextureTransformer.class) public class SoulParticleTransformer extends SpritesheetParticleTransformer { diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SpritesheetParticleTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SpritesheetParticleTransformer.java similarity index 87% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SpritesheetParticleTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SpritesheetParticleTransformer.java index 0fcdb7a..5dd4856 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/particle/SpritesheetParticleTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/particle/SpritesheetParticleTransformer.java @@ -24,12 +24,13 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.particle; +package org.geysermc.pack.converter.type.texture.transformer.type.particle; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.geysermc.pack.converter.util.Spritesheet; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; @@ -59,7 +60,7 @@ public class SpritesheetParticleTransformer implements TextureTransformer { BitSet occupiedSectors = new BitSet(this.atlasCount); Spritesheet spritesheet = new Spritesheet(); for (int i = 0; i < this.atlasCount; i++) { - Texture texture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, String.format(this.javaPath, i))); + Texture texture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, String.format(this.javaPath, i))); if (texture == null) { continue; } @@ -95,6 +96,6 @@ public class SpritesheetParticleTransformer implements TextureTransformer { context.debug(String.format("Creating particle spritesheet %s", this.bedrockPath)); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, this.bedrockPath), vanillaSprite, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, this.bedrockPath), vanillaSprite, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/FontTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/FontTransformer.java similarity index 92% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/FontTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/FontTransformer.java index d0bec3e..d855b0f 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/FontTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/FontTransformer.java @@ -24,26 +24,35 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.ui; +package org.geysermc.pack.converter.type.texture.transformer.type.ui; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; -import team.unnamed.creative.font.*; +import team.unnamed.creative.font.BitMapFontProvider; import team.unnamed.creative.font.Font; +import team.unnamed.creative.font.FontProvider; +import team.unnamed.creative.font.ReferenceFontProvider; +import team.unnamed.creative.font.SpaceFontProvider; +import team.unnamed.creative.font.UnihexFontProvider; import team.unnamed.creative.texture.Texture; import javax.imageio.ImageIO; -import java.awt.*; +import java.awt.Color; +import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HexFormat; import java.util.List; +import java.util.Map; @AutoService(TextureTransformer.class) public class FontTransformer implements TextureTransformer { @@ -69,7 +78,7 @@ public class FontTransformer implements TextureTransformer { // Currently, only the default font is converted, custom fonts are not supported on bedrock for (Font font : context.javaResourcePack().fonts()) { - if (!font.key().equals(Key.key(Key.MINECRAFT_NAMESPACE, "default"))) continue; + if (!font.key().equals(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "default"))) continue; for (FontProvider fontProvider : font.providers()) { unicodeFontData.addAll(handleFont(context, fontProvider)); @@ -77,15 +86,15 @@ public class FontTransformer implements TextureTransformer { } // if we have no data, don't stop yet, we may still want to generate some stuff from vanilla - if (unicodeFontData.isEmpty()) { + if (unicodeFontData.isEmpty() && context.vanillaPack().isPresent()) { if ( - !context.isTexturePresent(Key.key(Key.MINECRAFT_NAMESPACE, "font/ascii.png")) && - !context.isTexturePresent(Key.key(Key.MINECRAFT_NAMESPACE, "font/accented.png")) && - !context.isTexturePresent(Key.key(Key.MINECRAFT_NAMESPACE, "font/nonlatin_european.png")) + !context.isTexturePresent(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "font/ascii.png")) && + !context.isTexturePresent(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "font/accented.png")) && + !context.isTexturePresent(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "font/nonlatin_european.png")) ) return; - for (Font font : context.vanillaPack().fonts()) { - if (!font.key().equals(Key.key(Key.MINECRAFT_NAMESPACE, "default"))) continue; + for (Font font : context.vanillaPack().get().fonts()) { + if (!font.key().equals(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "default"))) continue; for (FontProvider fontProvider : font.providers()) { unicodeFontData.addAll(handleFont(context, fontProvider)); @@ -225,8 +234,8 @@ public class FontTransformer implements TextureTransformer { } else if (fontProvider instanceof ReferenceFontProvider referenceFontProvider) { // Refers to other fonts, so we need to read those Font font = context.javaResourcePack().font(referenceFontProvider.id()); - if (font == null) { // Just maybe, the vanilla files are used - font = context.vanillaPack().font(referenceFontProvider.id()); + if (font == null && context.vanillaPack().isPresent()) { // Just maybe, the vanilla files are used + font = context.vanillaPack().get().font(referenceFontProvider.id()); } if (font == null) { @@ -247,30 +256,30 @@ public class FontTransformer implements TextureTransformer { private void transformDefault8(@NotNull TransformContext context) throws IOException { // Don't attempt to write default8 if we have no data to pull from, otherwise it's vanilla to vanilla if ( - !context.isTexturePresent(Key.key(Key.MINECRAFT_NAMESPACE, "font/ascii.png")) && - !context.isTexturePresent(Key.key(Key.MINECRAFT_NAMESPACE, "font/accented.png")) && - !context.isTexturePresent(Key.key(Key.MINECRAFT_NAMESPACE, "font/nonlatin_european.png")) + !context.isTexturePresent(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "font/ascii.png")) && + !context.isTexturePresent(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "font/accented.png")) && + !context.isTexturePresent(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "font/nonlatin_european.png")) ) return; // Store the java images to prevent constant image reading Map imgs = new HashMap<>(); Map scales = new HashMap<>(); - Texture ascii = context.peekOrVanilla(Key.key(Key.MINECRAFT_NAMESPACE, "font/ascii.png")); + Texture ascii = context.peekOrVanilla(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "font/ascii.png")); if (ascii != null) { BufferedImage image = this.readImage(ascii); imgs.put("ascii", image); scales.put("ascii", image.getWidth() / 128); } - Texture accented = context.peekOrVanilla(Key.key(Key.MINECRAFT_NAMESPACE, "font/accented.png")); + Texture accented = context.peekOrVanilla(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "font/accented.png")); if (accented != null) { BufferedImage image = this.readImage(accented); imgs.put("accented", image); scales.put("accented", image.getWidth() / 144); } - Texture nonlatin_european = context.peekOrVanilla(Key.key(Key.MINECRAFT_NAMESPACE, "font/nonlatin_european.png")); + Texture nonlatin_european = context.peekOrVanilla(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "font/nonlatin_european.png")); if (nonlatin_european != null) { BufferedImage image = this.readImage(nonlatin_european); imgs.put("nonlatin_european", image); diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/HotbarTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/HotbarTransformer.java similarity index 79% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/HotbarTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/HotbarTransformer.java index 0c74db7..141f490 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/HotbarTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/HotbarTransformer.java @@ -24,17 +24,18 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.ui; +package org.geysermc.pack.converter.type.texture.transformer.type.ui; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; -import java.awt.*; +import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; @@ -45,7 +46,7 @@ public class HotbarTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { - Texture javaHotbarTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, HOTBAR)); + Texture javaHotbarTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, HOTBAR)); if (javaHotbarTexture == null) return; BufferedImage javaHotbarImage = readImage(javaHotbarTexture); @@ -61,7 +62,7 @@ public class HotbarTransformer implements TextureTransformer { g.drawImage(ImageUtil.crop(javaHotbarImage, 0, 0, scale, height), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "ui/hotbar_start_cap.png"), bedrockStartHotbar, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "ui/hotbar_start_cap.png"), bedrockStartHotbar, "png"); for (int i = 0; i <= 8; i++) { BufferedImage bedrockHotbarPart = new BufferedImage(scale * 20, height, BufferedImage.TYPE_INT_ARGB); @@ -70,7 +71,7 @@ public class HotbarTransformer implements TextureTransformer { graphics.drawImage(ImageUtil.crop(javaHotbarImage, (i * 20 * scale) + scale, 0, scale * 20, height), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "ui/hotbar_" + i + ".png"), bedrockHotbarPart, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "ui/hotbar_" + i + ".png"), bedrockHotbarPart, "png"); } // The texture is 1 wide, so 1 * scale = scale @@ -80,9 +81,9 @@ public class HotbarTransformer implements TextureTransformer { g.drawImage(ImageUtil.crop(javaHotbarImage, javaHotbarImage.getWidth() - scale, 0, scale, height), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "ui/hotbar_end_cap.png"), bedrockEndHotbar, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "ui/hotbar_end_cap.png"), bedrockEndHotbar, "png"); - Texture javaHotbarSelectionTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, HOTBAR_SELECTION)); + Texture javaHotbarSelectionTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, HOTBAR_SELECTION)); if (javaHotbarSelectionTexture == null) return; BufferedImage javaHotbarSelectionImage = readImage(javaHotbarSelectionTexture); @@ -99,6 +100,6 @@ public class HotbarTransformer implements TextureTransformer { g.drawImage(ImageUtil.flip(ImageUtil.crop(javaHotbarSelectionImage, 0, 0, size, selectionScale), false, true), 0, size - selectionScale, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "ui/selected_hotbar_slot.png"), bedrockHotbarSelection, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "ui/selected_hotbar_slot.png"), bedrockHotbarSelection, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/LocatorTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/LocatorTransformer.java similarity index 79% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/LocatorTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/LocatorTransformer.java index 50b32da..b3e4cbc 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/LocatorTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/LocatorTransformer.java @@ -24,20 +24,20 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.ui; +package org.geysermc.pack.converter.type.texture.transformer.type.ui; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; -import java.awt.*; +import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; -import java.util.List; import java.util.Map; @AutoService(TextureTransformer.class) @@ -52,7 +52,7 @@ public class LocatorTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { for (Map.Entry mapping : DOT_MAPPING.entrySet()) { - Texture dotTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, mapping.getKey())); + Texture dotTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, mapping.getKey())); if (dotTexture == null) continue; BufferedImage dotImage = this.readImage(dotTexture); @@ -71,10 +71,10 @@ public class LocatorTransformer implements TextureTransformer { // Also accounts for the scale a resource pack may offer g.drawImage(ImageUtil.crop(dotImage, scale, scale, bedrockSize, bedrockSize), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, mapping.getValue()), bedrockDotImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, mapping.getValue()), bedrockDotImage, "png"); } - Texture upArrowTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, "gui/sprites/hud/locator_bar_arrow_up.png")); + Texture upArrowTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "gui/sprites/hud/locator_bar_arrow_up.png")); if (upArrowTexture != null) { BufferedImage javaImage = this.readImage(upArrowTexture); @@ -86,10 +86,10 @@ public class LocatorTransformer implements TextureTransformer { g.drawImage(ImageUtil.crop(javaImage, 0, 1, javaImage.getWidth(), scale * 4), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "ui/locator_arrow_up.png"), bedrockImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "ui/locator_arrow_up.png"), bedrockImage, "png"); } - Texture downArrowTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, "gui/sprites/hud/locator_bar_arrow_down.png")); + Texture downArrowTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "gui/sprites/hud/locator_bar_arrow_down.png")); if (downArrowTexture != null) { BufferedImage javaImage = this.readImage(downArrowTexture); @@ -101,10 +101,10 @@ public class LocatorTransformer implements TextureTransformer { g.drawImage(ImageUtil.crop(javaImage, 0, 0, javaImage.getWidth(), scale * 4), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "ui/locator_arrow_down.png"), bedrockImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "ui/locator_arrow_down.png"), bedrockImage, "png"); } - Texture bgTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, "gui/sprites/hud/locator_bar_background.png")); + Texture bgTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "gui/sprites/hud/locator_bar_background.png")); if (bgTexture != null) { BufferedImage javaImage = this.readImage(bgTexture); @@ -122,7 +122,7 @@ public class LocatorTransformer implements TextureTransformer { g.drawImage(ImageUtil.crop(javaImage, javaImage.getWidth() - (scale * 5), 0, scale * 5, javaImage.getHeight()), (scale * 182) - scale * 5, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "ui/locator_bg.png"), bedrockImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "ui/locator_bg.png"), bedrockImage, "png"); } } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/SignTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/SignTransformer.java similarity index 84% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/SignTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/SignTransformer.java index dbe06b3..f1e3a70 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/SignTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/SignTransformer.java @@ -24,17 +24,18 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.ui; +package org.geysermc.pack.converter.type.texture.transformer.type.ui; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; -import java.awt.*; +import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; @@ -62,7 +63,7 @@ public class SignTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { for (SignData signData : SIGNS) { - Texture javaTexture = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, JAVA_LOCATION.formatted(signData.name))); + Texture javaTexture = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, JAVA_LOCATION.formatted(signData.name))); if (javaTexture == null) continue; BufferedImage javaImage = this.readImage(javaTexture); @@ -75,7 +76,7 @@ public class SignTransformer implements TextureTransformer { g.drawImage(ImageUtil.crop(javaImage, (int) (2 * scale), (int) (2 * scale), (int) (scale * 24), (int) (scale * 12)), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, BEDROCK_LOCATION.formatted(signData.bedrockName)), bedrockImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, BEDROCK_LOCATION.formatted(signData.bedrockName)), bedrockImage, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/TitleTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/TitleTransformer.java similarity index 81% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/TitleTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/TitleTransformer.java index db8dde8..d612c08 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/TitleTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/TitleTransformer.java @@ -24,17 +24,18 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.ui; +package org.geysermc.pack.converter.type.texture.transformer.type.ui; import com.google.auto.service.AutoService; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; import org.geysermc.pack.converter.util.ImageUtil; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; -import java.awt.*; +import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; @@ -42,7 +43,7 @@ import java.io.IOException; public class TitleTransformer implements TextureTransformer { @Override public void transform(@NotNull TransformContext context) throws IOException { - Texture javaTexture = context.poll(Key.key(Key.MINECRAFT_NAMESPACE, "gui/title/minecraft.png")); + Texture javaTexture = context.poll(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "gui/title/minecraft.png")); if (javaTexture == null) return; BufferedImage javaImage = this.readImage(javaTexture); @@ -56,6 +57,6 @@ public class TitleTransformer implements TextureTransformer { g.drawImage(ImageUtil.resize(ImageUtil.crop(javaImage, 0, 0, javaImage.getWidth(), javaImage.getHeight() - ((int) (scale * 79))), 1937, 333), 0, 0, null); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "ui/title.png"), bedrockImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "ui/title.png"), bedrockImage, "png"); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/UISizeTransformer.java b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/UISizeTransformer.java similarity index 77% rename from converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/UISizeTransformer.java rename to converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/UISizeTransformer.java index 005b0e9..ad3e5db 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/texture/transformer/type/ui/UISizeTransformer.java +++ b/converter/src/main/java/org/geysermc/pack/converter/type/texture/transformer/type/ui/UISizeTransformer.java @@ -24,22 +24,20 @@ * */ -package org.geysermc.pack.converter.converter.texture.transformer.type.ui; +package org.geysermc.pack.converter.type.texture.transformer.type.ui; import com.google.auto.service.AutoService; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import net.kyori.adventure.key.Key; -import org.geysermc.pack.converter.converter.texture.transformer.TextureTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.TransformContext; +import org.geysermc.pack.converter.type.texture.transformer.TextureTransformer; +import org.geysermc.pack.converter.type.texture.transformer.TransformContext; +import org.geysermc.pack.converter.util.KeyUtil; import org.jetbrains.annotations.NotNull; import team.unnamed.creative.texture.Texture; import java.awt.image.BufferedImage; import java.io.IOException; -import java.nio.charset.StandardCharsets; // This isn't really a "transformer", we just include some files if an certain UI elements are present // in order to get it to appear correctly, the mappings here are still done in textures.json or elsewhere @@ -47,29 +45,26 @@ import java.nio.charset.StandardCharsets; // Credit to Bedrock Tweaks, wouldn't know how to do this without their packs @AutoService(TextureTransformer.class) public class UISizeTransformer implements TextureTransformer { - private static final Gson GSON = new GsonBuilder() - .setPrettyPrinting() - .create(); private static final JsonArray FULLBARSLICE = new JsonArray(); @Override public void transform(@NotNull TransformContext context) throws IOException { - Texture emptyXp = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, "gui/sprites/hud/experience_bar_background.png")); + Texture emptyXp = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "gui/sprites/hud/experience_bar_background.png")); if (emptyXp != null) { writeUiJson(context, this.readImage(emptyXp), "experiencebarempty", FULLBARSLICE); // Since we have the full image, we *don't* want this BufferedImage nubImage = new BufferedImage(11, 5, BufferedImage.TYPE_INT_ARGB); - context.offer(Key.key(Key.MINECRAFT_NAMESPACE, "ui/experiencenub.png"), nubImage, "png"); + context.offer(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "ui/experiencenub.png"), nubImage, "png"); } - Texture fullXp = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, "gui/sprites/hud/experience_bar_progress.png")); + Texture fullXp = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "gui/sprites/hud/experience_bar_progress.png")); if (fullXp != null) { writeUiJson(context, this.readImage(fullXp), "experiencebarfull", FULLBARSLICE); } - Texture locatorBg = context.peek(Key.key(Key.MINECRAFT_NAMESPACE, "gui/sprites/hud/locator_bar_background.png")); + Texture locatorBg = context.peek(KeyUtil.key(Key.MINECRAFT_NAMESPACE, "gui/sprites/hud/locator_bar_background.png")); if (locatorBg != null) { BufferedImage image = this.readImage(locatorBg); @@ -97,7 +92,7 @@ public class UISizeTransformer implements TextureTransformer { baseSize.add(customHeight); rootObject.add("base_size", baseSize); - context.bedrockResourcePack().addExtraFile(GSON.toJson(rootObject).getBytes(StandardCharsets.UTF_8), "textures/ui/%s.json".formatted(jsonName)); + context.bedrockResourcePack().addExtraFile(rootObject, "textures/ui/%s.json".formatted(jsonName)); } static { diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/BaseConverter.java b/converter/src/main/java/org/geysermc/pack/converter/util/KeyUtil.java similarity index 71% rename from converter/src/main/java/org/geysermc/pack/converter/converter/BaseConverter.java rename to converter/src/main/java/org/geysermc/pack/converter/util/KeyUtil.java index e5b0b3b..51ed4d4 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/BaseConverter.java +++ b/converter/src/main/java/org/geysermc/pack/converter/util/KeyUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * Copyright (c) 2025 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,15 +24,22 @@ * */ -package org.geysermc.pack.converter.converter; +package org.geysermc.pack.converter.util; -import org.geysermc.pack.converter.data.BaseConversionData; +import net.kyori.adventure.key.Key; import org.jetbrains.annotations.NotNull; -public abstract class BaseConverter implements Converter { +@SuppressWarnings("PatternValidation") +public final class KeyUtil { - @Override - public BaseConversionData createConversionData(@NotNull ConversionDataCreationContext context) { - return new BaseConversionData(context.inputDirectory(), context.outputDirectory(), context.vanillaResourcePack()); + private KeyUtil() { + } + + public static @NotNull Key key(final @NotNull String string) { + return Key.key(string); + } + + public static @NotNull Key key(final @NotNull String namespace, final @NotNull String value) { + return Key.key(namespace, value); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/converter/Converters.java b/converter/src/main/java/org/geysermc/pack/converter/util/LogListenerHelper.java similarity index 62% rename from converter/src/main/java/org/geysermc/pack/converter/converter/Converters.java rename to converter/src/main/java/org/geysermc/pack/converter/util/LogListenerHelper.java index 69b9eb2..c24fb61 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/converter/Converters.java +++ b/converter/src/main/java/org/geysermc/pack/converter/util/LogListenerHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * Copyright (c) 2025-2025 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,22 +24,31 @@ * */ -package org.geysermc.pack.converter.converter; +package org.geysermc.pack.converter.util; -import java.util.List; -import java.util.ServiceLoader; +import org.jetbrains.annotations.NotNull; -public class Converters { +public interface LogListenerHelper { - public static List> defaultConverters() { - return defaultConverters(false); + LogListener logListener(); + + default void debug(@NotNull String message) { + logListener().debug(message); } - public static List> defaultConverters(boolean experimental) { - return ServiceLoader.load(Converter.class).stream() - .map(ServiceLoader.Provider::get) - .map(c -> (Converter)c) - .filter(converter -> experimental || !converter.isExperimental()) - .toList(); + default void info(@NotNull String message) { + logListener().info(message); + } + + default void warn(@NotNull String message) { + logListener().warn(message); + } + + default void error(@NotNull String message) { + logListener().error(message); + } + + default void error(@NotNull String message, @NotNull Throwable exception) { + logListener().error(message, exception); } } diff --git a/converter/src/main/java/org/geysermc/pack/converter/util/VanillaPackProvider.java b/converter/src/main/java/org/geysermc/pack/converter/util/VanillaPackProvider.java index 0254691..29a48e0 100644 --- a/converter/src/main/java/org/geysermc/pack/converter/util/VanillaPackProvider.java +++ b/converter/src/main/java/org/geysermc/pack/converter/util/VanillaPackProvider.java @@ -26,12 +26,16 @@ package org.geysermc.pack.converter.util; -import com.google.gson.*; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import lombok.Getter; import org.apache.commons.io.IOUtils; import org.apache.commons.io.file.PathUtils; -import org.geysermc.pack.converter.converter.texture.transformer.type.OverlayTransformer; -import org.geysermc.pack.converter.converter.texture.transformer.type.entity.SheepTransformer; +import org.geysermc.pack.converter.type.texture.transformer.type.OverlayTransformer; +import org.geysermc.pack.converter.type.texture.transformer.type.entity.SheepTransformer; import org.jetbrains.annotations.NotNull; import java.io.BufferedReader; @@ -40,7 +44,10 @@ import java.io.InputStream; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Stream; public final class VanillaPackProvider { diff --git a/pack-schema/api/src/main/java/org/geysermc/pack/bedrock/resource/BedrockResourcePack.java b/pack-schema/api/src/main/java/org/geysermc/pack/bedrock/resource/BedrockResourcePack.java index 798f4de..8be34e9 100644 --- a/pack-schema/api/src/main/java/org/geysermc/pack/bedrock/resource/BedrockResourcePack.java +++ b/pack-schema/api/src/main/java/org/geysermc/pack/bedrock/resource/BedrockResourcePack.java @@ -28,6 +28,7 @@ package org.geysermc.pack.bedrock.resource; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; import org.geysermc.pack.bedrock.resource.attachables.Attachables; import org.geysermc.pack.bedrock.resource.models.entity.ModelEntity; import org.geysermc.pack.bedrock.resource.render_controllers.RenderControllers; @@ -44,9 +45,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -91,6 +92,16 @@ public class BedrockResourcePack { this.terrainTexture = terrainTexture; } + /** + * Get the directory of the resource pack. + * + * @return the directory of the resource pack + */ + @NotNull + public Path directory() { + return directory; + } + /** * Get the manifest of the resource pack. * @@ -500,6 +511,16 @@ public class BedrockResourcePack { this.extraFiles.put(location, bytes); } + /** + * Add an extra JSON file to the resource pack. + * + * @param element the contents of the file + * @param location the location of the file + */ + public void addExtraFile(@NotNull JsonElement element, @NotNull String location) { + addExtraFile(GSON.toJson(element).getBytes(StandardCharsets.UTF_8), location); + } + /** * Exports the resource pack to the specified directory. *