From e54eb8eb1304b3c3ef4dfc36cb227a68e8fcab25 Mon Sep 17 00:00:00 2001 From: tomalbrc Date: Sun, 1 Jun 2025 22:32:02 +0200 Subject: [PATCH 1/4] fix: zip file creation when the bedframe config dir doesn't exist --- src/main/java/lol/sylvie/bedframe/util/ZipHelper.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/lol/sylvie/bedframe/util/ZipHelper.java b/src/main/java/lol/sylvie/bedframe/util/ZipHelper.java index 74cdf02..a1cd21e 100644 --- a/src/main/java/lol/sylvie/bedframe/util/ZipHelper.java +++ b/src/main/java/lol/sylvie/bedframe/util/ZipHelper.java @@ -15,6 +15,11 @@ public class ZipHelper { // https://stackoverflow.com/questions/57997257/how-can-i-zip-a-complete-directory-with-all-subfolders-in-java public static void zipFolder(Path source, File destination) { try { + var parent = Path.of(destination.getParent()); + if (!Files.exists(parent)) { + Files.createDirectory(parent); // this is just quickly hacked together, the dir has to exist in order to write the file + } + ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(destination)); Files.walkFileTree(source, new SimpleFileVisitor<>() { @Override From 2b1d183a0ef38d0ed57c4c3ce2bac38d9daa9ff6 Mon Sep 17 00:00:00 2001 From: tomalbrc Date: Sun, 1 Jun 2025 22:34:27 +0200 Subject: [PATCH 2/4] feat: obtain block model values through polymer and fix modelData.parent() comparison --- .../sylvie/bedframe/BedframeInitializer.java | 1 - .../geyser/translator/BlockTranslator.java | 75 ++++++------------- .../mixin/BlockResourceCreatorAccessor.java | 16 ++++ .../PolymerBlockResourceUtilsAccessor.java | 14 ++++ .../lol/sylvie/bedframe/util/JsonHelper.java | 27 +++++++ src/main/resources/bedframe.mixins.json | 2 + 6 files changed, 80 insertions(+), 55 deletions(-) create mode 100644 src/main/java/lol/sylvie/bedframe/mixin/BlockResourceCreatorAccessor.java create mode 100644 src/main/java/lol/sylvie/bedframe/mixin/PolymerBlockResourceUtilsAccessor.java create mode 100644 src/main/java/lol/sylvie/bedframe/util/JsonHelper.java diff --git a/src/main/java/lol/sylvie/bedframe/BedframeInitializer.java b/src/main/java/lol/sylvie/bedframe/BedframeInitializer.java index 7564305..2d75394 100644 --- a/src/main/java/lol/sylvie/bedframe/BedframeInitializer.java +++ b/src/main/java/lol/sylvie/bedframe/BedframeInitializer.java @@ -2,7 +2,6 @@ import lol.sylvie.bedframe.geyser.TranslationManager; import net.fabricmc.api.ModInitializer; - import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.metadata.Person; diff --git a/src/main/java/lol/sylvie/bedframe/geyser/translator/BlockTranslator.java b/src/main/java/lol/sylvie/bedframe/geyser/translator/BlockTranslator.java index c4109fd..f3262c9 100644 --- a/src/main/java/lol/sylvie/bedframe/geyser/translator/BlockTranslator.java +++ b/src/main/java/lol/sylvie/bedframe/geyser/translator/BlockTranslator.java @@ -1,9 +1,13 @@ package lol.sylvie.bedframe.geyser.translator; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import eu.pb4.polymer.blocks.api.BlockResourceCreator; +import eu.pb4.polymer.blocks.api.PolymerBlockModel; import eu.pb4.polymer.blocks.api.PolymerTexturedBlock; import lol.sylvie.bedframe.geyser.Translator; +import lol.sylvie.bedframe.mixin.BlockResourceCreatorAccessor; +import lol.sylvie.bedframe.mixin.PolymerBlockResourceUtilsAccessor; +import lol.sylvie.bedframe.util.JsonHelper; import lol.sylvie.bedframe.util.ResourceHelper; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -122,12 +126,6 @@ private void populateProperties(CustomBlockData.Builder builder, Collection> rotationData = new HashMap<>(); - HashMap models = new HashMap<>(); - - String blockstatesPath = "blockstates/" + identifier.getPath() + ".json"; - try { - JsonObject variants = ResourceHelper.readJsonResource(identifier.getNamespace(), blockstatesPath) - .getAsJsonObject("variants"); - forEachKey(variants, (key, element) -> { - JsonObject object = element.getAsJsonObject(); - - JsonElement potentialX = object.get("x"); - int x = potentialX == null ? 0 : potentialX.getAsInt(); - - JsonElement potentialY = object.get("y"); - int y = potentialY == null ? 0 : potentialY.getAsInt(); - - String modelPath = object.get("model").getAsString(); - JsonObject model = ResourceHelper.readJsonResource(identifier.getNamespace(), "models/" + Identifier.of(modelPath).getPath() + ".json"); - - rotationData.put(key, new Pair<>(x, y)); - models.put(key, ModelData.fromJson(model)); - }); - } catch (NullPointerException e) { - // SHAME! - LOGGER.warn("Missing blockstates for {}", identifier); - JsonObject model = ResourceHelper.readJsonResource(identifier.getNamespace(), "models/block/" + identifier.getPath() + ".json"); - models.put("", ModelData.fromJson(model)); - } - // Block states/permutations List permutations = new ArrayList<>(); for (BlockState state : realBlock.getStateManager().getStates()) { - String stateKey = nonPrefixedBlockState(state, identifier); CustomBlockComponents.Builder stateComponentBuilder = CustomBlockComponents.builder(); + // Obtain model data from polymers internal api + BlockState polymerBlockState = block.getPolymerBlockState(state, PacketContext.get()); + BlockResourceCreator creator = PolymerBlockResourceUtilsAccessor.getCREATOR(); + PolymerBlockModel[] polymerBlockModels = ((BlockResourceCreatorAccessor)(Object)creator).getModels().get(polymerBlockState); + PolymerBlockModel modelEntry = polymerBlockModels[0]; // TODO: java selects one by weight, does bedrock support this? + // Rotation - Pair rotation = rotationData.getOrDefault(stateKey, new Pair<>(0, 0)); - TransformationComponent rotationComponent = new TransformationComponent((360 - rotation.getLeft()) % 360, (360 - rotation.getRight()) % 360, 0); + TransformationComponent rotationComponent = new TransformationComponent((360 - modelEntry.x()) % 360, (360 - modelEntry.y()) % 360, 0); stateComponentBuilder.transformation(rotationComponent); // Geometry // TODO: More geometry types - ModelData modelData = models.getOrDefault(stateKey, models.get("")); - if (modelData == null) { + JsonObject blockModel = ResourceHelper.readJsonResource(modelEntry.model().getNamespace(), "models/" + modelEntry.model().getPath() + ".json"); + if (blockModel == null) { LOGGER.warn("Couldn't load model for blockstate {}", state); continue; } - boolean cross = modelData.parent().equals("minecraft:block/cross"); + + ModelData modelData = ModelData.fromJson(blockModel); + boolean cross = modelData.parent().toString().equals("minecraft:block/cross"); String geometryIdentifier = cross ? "minecraft:geometry.cross" : "minecraft:geometry.full_block"; String renderMethod = cross ? "alpha_test_single_sided" : "opaque"; @@ -227,14 +201,14 @@ public void handle(GeyserDefineCustomBlocksEvent event, Path packRoot) { stateComponentBuilder.geometry(geometryComponent); // Textures - List> faceMap = parentFaceMap.getOrDefault(modelData.parent().replaceFirst("minecraft:", ""), parentFaceMap.get("block/cube_all")); + List> faceMap = parentFaceMap.getOrDefault(modelData.parent().getPath(), parentFaceMap.get("block/cube_all")); for (Pair face : faceMap) { String javaFaceName = face.getLeft(); String bedrockFaceName = face.getRight(); if (!modelData.textures.containsKey(javaFaceName)) continue; String textureName = modelData.textures.get(javaFaceName); - String texturePath = "textures/" + textureName; + String texturePath = "textures/" + Identifier.of(textureName).getPath(); String bedrockPath = ResourceHelper.javaToBedrockTexture(texturePath); JsonObject thisTexture = new JsonObject(); @@ -313,16 +287,9 @@ public void register(EventBus eventBus, Path packRoot) { eventBus.subscribe(this, GeyserDefineCustomBlocksEvent.class, event -> handle(event, packRoot)); } - record ModelData(String parent, Map textures) { + record ModelData(Identifier parent, Map textures) { public static ModelData fromJson(JsonObject object) { - JsonObject texturesObject = object.getAsJsonObject("textures"); - HashMap texturesMap = new HashMap<>(); - texturesObject.entrySet().forEach(e -> { - String texture = e.getValue().getAsString(); - if (texture.contains(":")) texture = Identifier.of(texture).getPath(); - texturesMap.put(e.getKey(), texture); - }); - return new ModelData(object.get("parent").getAsString(), texturesMap); + return JsonHelper.GSON.fromJson(object, ModelData.class); } } } diff --git a/src/main/java/lol/sylvie/bedframe/mixin/BlockResourceCreatorAccessor.java b/src/main/java/lol/sylvie/bedframe/mixin/BlockResourceCreatorAccessor.java new file mode 100644 index 0000000..deb616b --- /dev/null +++ b/src/main/java/lol/sylvie/bedframe/mixin/BlockResourceCreatorAccessor.java @@ -0,0 +1,16 @@ +package lol.sylvie.bedframe.mixin; + +import eu.pb4.polymer.blocks.api.BlockResourceCreator; +import eu.pb4.polymer.blocks.api.PolymerBlockModel; +import net.minecraft.block.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(value = BlockResourceCreator.class, remap = false) +public interface BlockResourceCreatorAccessor { + @Accessor + Map getModels(); +} + \ No newline at end of file diff --git a/src/main/java/lol/sylvie/bedframe/mixin/PolymerBlockResourceUtilsAccessor.java b/src/main/java/lol/sylvie/bedframe/mixin/PolymerBlockResourceUtilsAccessor.java new file mode 100644 index 0000000..c88c010 --- /dev/null +++ b/src/main/java/lol/sylvie/bedframe/mixin/PolymerBlockResourceUtilsAccessor.java @@ -0,0 +1,14 @@ +package lol.sylvie.bedframe.mixin; + +import eu.pb4.polymer.blocks.api.BlockResourceCreator; +import eu.pb4.polymer.blocks.api.PolymerBlockResourceUtils; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(value = PolymerBlockResourceUtils.class, remap = false) +public interface PolymerBlockResourceUtilsAccessor { + @Accessor + static BlockResourceCreator getCREATOR() { + throw new AssertionError(); + } +} \ No newline at end of file diff --git a/src/main/java/lol/sylvie/bedframe/util/JsonHelper.java b/src/main/java/lol/sylvie/bedframe/util/JsonHelper.java new file mode 100644 index 0000000..e61e3fe --- /dev/null +++ b/src/main/java/lol/sylvie/bedframe/util/JsonHelper.java @@ -0,0 +1,27 @@ +package lol.sylvie.bedframe.util; + +import com.google.gson.*; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; +import net.minecraft.util.Identifier; + +import java.lang.reflect.Type; + +public class JsonHelper { + public static final Gson GSON = new GsonBuilder() + .registerTypeAdapter(Identifier.class, new SimpleCodecDeserializer<>(Identifier.CODEC)) + .create(); + + public static class SimpleCodecDeserializer implements JsonDeserializer { + private final Codec codec; + + public SimpleCodecDeserializer(Codec codec) { + this.codec = codec; + } + + @Override + public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + return codec.parse(JsonOps.INSTANCE, json).getOrThrow(error -> new JsonParseException("Failed to deserialize using Codec: " + error)); + } + } +} diff --git a/src/main/resources/bedframe.mixins.json b/src/main/resources/bedframe.mixins.json index 4ddb416..18f4e6f 100644 --- a/src/main/resources/bedframe.mixins.json +++ b/src/main/resources/bedframe.mixins.json @@ -3,7 +3,9 @@ "package": "lol.sylvie.bedframe.mixin", "compatibilityLevel": "JAVA_21", "mixins": [ + "BlockResourceCreatorAccessor", "CustomItemRegistryPopulatorMixin", + "PolymerBlockResourceUtilsAccessor", "PolymerItemMixin", "PolymerItemUtilsMixin" ], From fa865b565836146205a484ab9b901e729414e3f3 Mon Sep 17 00:00:00 2001 From: tomalbrc Date: Sun, 1 Jun 2025 23:00:27 +0200 Subject: [PATCH 3/4] fix: parent check for item/generated --- .../sylvie/bedframe/geyser/translator/ItemTranslator.java | 6 +++--- .../java/lol/sylvie/bedframe/util/BedframeConstants.java | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/lol/sylvie/bedframe/geyser/translator/ItemTranslator.java b/src/main/java/lol/sylvie/bedframe/geyser/translator/ItemTranslator.java index 2280d09..8ff5eac 100644 --- a/src/main/java/lol/sylvie/bedframe/geyser/translator/ItemTranslator.java +++ b/src/main/java/lol/sylvie/bedframe/geyser/translator/ItemTranslator.java @@ -73,7 +73,7 @@ private void handle(GeyserDefineCustomItemsEvent event, Path packRoot) { ItemStack itemStack = item.getPolymerItemStack(realItem.getDefaultStack(), TooltipType.BASIC, PacketContext.get()); Identifier model = itemStack.get(DataComponentTypes.ITEM_MODEL); - if (model == null || model.getNamespace().equals("minecraft")) return; + if (model == null || model.getNamespace().equals("minecraft")) return; // FIXME: some people (cough me cough) store their models in the minecraft namespace CustomItemOptions.Builder itemOptions = CustomItemOptions.builder(); @@ -123,9 +123,9 @@ private void handle(GeyserDefineCustomItemsEvent event, Path packRoot) { Identifier modelId = Identifier.of(itemDescription.get("model").getAsJsonObject().get("model").getAsString()); JsonObject modelObject = ResourceHelper.readJsonResource(modelId.getNamespace(), "models/" + modelId.getPath() + ".json"); - String modelType = modelObject.get("parent").getAsString(); + Identifier modelType = Identifier.of(modelObject.get("parent").getAsString()); - if (modelType.equals("minecraft:item/generated")) { + if (modelType.equals(BedframeConstants.GENERATED_IDENTIFIER)) { Identifier textureId = Identifier.of(modelObject.get("textures").getAsJsonObject().get("layer0").getAsString()); String texturePath = "textures/" + textureId.getPath(); diff --git a/src/main/java/lol/sylvie/bedframe/util/BedframeConstants.java b/src/main/java/lol/sylvie/bedframe/util/BedframeConstants.java index 95e699c..8f4917b 100644 --- a/src/main/java/lol/sylvie/bedframe/util/BedframeConstants.java +++ b/src/main/java/lol/sylvie/bedframe/util/BedframeConstants.java @@ -4,6 +4,7 @@ import com.google.gson.GsonBuilder; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.metadata.ModMetadata; +import net.minecraft.util.Identifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,4 +15,6 @@ public class BedframeConstants { public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); public static final ModMetadata METADATA = FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow().getMetadata(); + + public static final Identifier GENERATED_IDENTIFIER = Identifier.ofVanilla("item/generated"); } From 6ec91cc07529a1ececf52cda44c8937e8ef32cfc Mon Sep 17 00:00:00 2001 From: tomalbrc Date: Sun, 1 Jun 2025 23:03:53 +0200 Subject: [PATCH 4/4] fix: accept item/handheld identifier for texture items --- .../lol/sylvie/bedframe/geyser/translator/ItemTranslator.java | 2 +- src/main/java/lol/sylvie/bedframe/util/BedframeConstants.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/lol/sylvie/bedframe/geyser/translator/ItemTranslator.java b/src/main/java/lol/sylvie/bedframe/geyser/translator/ItemTranslator.java index 8ff5eac..8243c28 100644 --- a/src/main/java/lol/sylvie/bedframe/geyser/translator/ItemTranslator.java +++ b/src/main/java/lol/sylvie/bedframe/geyser/translator/ItemTranslator.java @@ -125,7 +125,7 @@ private void handle(GeyserDefineCustomItemsEvent event, Path packRoot) { JsonObject modelObject = ResourceHelper.readJsonResource(modelId.getNamespace(), "models/" + modelId.getPath() + ".json"); Identifier modelType = Identifier.of(modelObject.get("parent").getAsString()); - if (modelType.equals(BedframeConstants.GENERATED_IDENTIFIER)) { + if (modelType.equals(BedframeConstants.GENERATED_IDENTIFIER) || modelType.equals(BedframeConstants.HANDHELD_IDENTIFIER)) { Identifier textureId = Identifier.of(modelObject.get("textures").getAsJsonObject().get("layer0").getAsString()); String texturePath = "textures/" + textureId.getPath(); diff --git a/src/main/java/lol/sylvie/bedframe/util/BedframeConstants.java b/src/main/java/lol/sylvie/bedframe/util/BedframeConstants.java index 8f4917b..efdd3ba 100644 --- a/src/main/java/lol/sylvie/bedframe/util/BedframeConstants.java +++ b/src/main/java/lol/sylvie/bedframe/util/BedframeConstants.java @@ -17,4 +17,5 @@ public class BedframeConstants { public static final ModMetadata METADATA = FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow().getMetadata(); public static final Identifier GENERATED_IDENTIFIER = Identifier.ofVanilla("item/generated"); + public static final Identifier HANDHELD_IDENTIFIER = Identifier.ofVanilla("item/handheld"); }