From 99a450e39573acbaf517e40a28dcf8bb1bd8c008 Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Tue, 17 Jun 2025 19:23:29 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20integrate=20MBP=20=E2=80=93=20Part=20I?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I received permission from the author of MoreBlockPredicates to integrate their mod's functionality into Puzzle. Thanks again :) This is far from ready yet. The MBP codebase is stuck on 1.20.1 and only for Fabric, so I'm basically porting it to 1.21.5 and multiloader at the same time. (There have been LOTS of changes related to block models, too) --- .../java/net/puzzlemc/core/PuzzleCore.java | 24 ++- .../java/net/puzzlemc/core/PuzzleModule.java | 13 ++ .../core/mixin/PuzzleMixinPlugin.java | 50 ++++++ .../main/java/net/puzzlemc/gui/PuzzleApi.java | 10 +- .../main/java/net/puzzlemc/gui/PuzzleGui.java | 20 ++- .../screen/widget/PuzzleOptionListWidget.java | 7 +- .../predicates/BlockStateOverride.java | 14 ++ .../java/net/puzzlemc/predicates/MBPData.java | 29 ++++ .../puzzlemc/predicates/MBPMixinPlugin.java | 68 ++++++++ .../puzzlemc/predicates/PuzzlePredicates.java | 73 ++++++++ .../accessor/BlockRenderManagerAccess.java | 12 ++ .../BlockStateModelManagerAccess.java | 13 ++ .../predicates/common/BlockRendering.java | 36 ++++ .../predicates/common/ContextIdentifiers.java | 16 ++ .../predicates/data/BlockModelPredicate.java | 63 +++++++ .../puzzlemc/predicates/data/DataHelper.java | 33 ++++ .../predicates/data/WorldViewCondition.java | 10 ++ .../data/conditions/AdjacentBlock.java | 50 ++++++ .../data/conditions/CoordinateRange.java | 35 ++++ .../predicates/data/conditions/InBiome.java | 30 ++++ .../data/conditions/IsBlockState.java | 68 ++++++++ .../predicates/data/conditions/IsContext.java | 27 +++ .../data/conditions/LightRange.java | 39 +++++ .../puzzlemc/predicates/data/logic/And.java | 32 ++++ .../puzzlemc/predicates/data/logic/Not.java | 26 +++ .../puzzlemc/predicates/data/logic/Or.java | 39 +++++ .../puzzlemc/predicates/data/logic/When.java | 71 ++++++++ .../mixin/BakedModelManagerMixin.java | 60 +++++++ .../BlockDisplayEntityRendererMixin.java | 24 +++ .../mixin/BlockDustParticleMixin.java | 40 +++++ .../mixin/BlockMarkerParticleMixin.java | 41 +++++ .../mixin/BlockModelRendererMixin.java | 47 +++++ .../mixin/BlockRenderManagerMixin.java | 99 +++++++++++ .../FallingBlockEntityRendererMixin.java | 48 +++++ .../mixin/ItemEntityRendererMixin.java | 21 +++ .../mixin/ItemFrameEntityRendererMixin.java | 22 +++ .../predicates/mixin/ItemRendererMixin.java | 73 ++++++++ .../mixin/PistonBlockEntityRendererMixin.java | 50 ++++++ .../predicates/mixin/StateAccessor.java | 17 ++ .../sodium/ChunkBuilderMeshingTaskMixin.java | 40 +++++ .../resources/MBPModelLoadingPlugin.java | 65 +++++++ .../net/puzzlemc/predicates/util/Utils.java | 50 ++++++ .../splashscreen/PuzzleSplashScreen.java | 164 +++++++++--------- .../resources/puzzle-predicates.mixins.json | 24 +++ .../puzzle-predicates_compat.mixins.json | 11 ++ .../fabric/MBPModelLoadingPlugin.java | 68 ++++++++ .../net/puzzlemc/fabric/PuzzleFabric.java | 5 +- fabric/src/main/resources/fabric.mod.json | 4 +- 48 files changed, 1776 insertions(+), 105 deletions(-) create mode 100644 common/src/main/java/net/puzzlemc/core/PuzzleModule.java create mode 100644 common/src/main/java/net/puzzlemc/core/mixin/PuzzleMixinPlugin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/BlockStateOverride.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/MBPData.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/MBPMixinPlugin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/PuzzlePredicates.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/accessor/BlockRenderManagerAccess.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/accessor/BlockStateModelManagerAccess.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/common/BlockRendering.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/common/ContextIdentifiers.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/BlockModelPredicate.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/DataHelper.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/WorldViewCondition.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/conditions/AdjacentBlock.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/conditions/CoordinateRange.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/conditions/InBiome.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/conditions/IsBlockState.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/conditions/IsContext.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/conditions/LightRange.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/logic/And.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/logic/Not.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/logic/Or.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/data/logic/When.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/BakedModelManagerMixin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/BlockDisplayEntityRendererMixin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/BlockDustParticleMixin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/BlockMarkerParticleMixin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/BlockModelRendererMixin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/BlockRenderManagerMixin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/FallingBlockEntityRendererMixin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/ItemEntityRendererMixin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/ItemFrameEntityRendererMixin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/ItemRendererMixin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/PistonBlockEntityRendererMixin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/StateAccessor.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/mixin/compat/sodium/ChunkBuilderMeshingTaskMixin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/resources/MBPModelLoadingPlugin.java create mode 100644 common/src/main/java/net/puzzlemc/predicates/util/Utils.java create mode 100644 common/src/main/resources/puzzle-predicates.mixins.json create mode 100644 common/src/main/resources/puzzle-predicates_compat.mixins.json create mode 100644 fabric/src/main/java/net/puzzlemc/fabric/MBPModelLoadingPlugin.java diff --git a/common/src/main/java/net/puzzlemc/core/PuzzleCore.java b/common/src/main/java/net/puzzlemc/core/PuzzleCore.java index 0f28063..2ecf0a4 100755 --- a/common/src/main/java/net/puzzlemc/core/PuzzleCore.java +++ b/common/src/main/java/net/puzzlemc/core/PuzzleCore.java @@ -1,18 +1,32 @@ package net.puzzlemc.core; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.SynchronousResourceReloader; import net.puzzlemc.core.config.PuzzleConfig; import net.puzzlemc.gui.PuzzleGui; +import net.puzzlemc.predicates.PuzzlePredicates; import net.puzzlemc.splashscreen.PuzzleSplashScreen; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; public class PuzzleCore { public final static String MOD_ID = "puzzle"; - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + private static final List MODULES = new ArrayList<>(); public static void initModules() { PuzzleConfig.init(MOD_ID, PuzzleConfig.class); - PuzzleGui.init(); - PuzzleSplashScreen.init(); + Collections.addAll(MODULES, PuzzleGui.INSTANCE, PuzzleSplashScreen.INSTANCE, PuzzlePredicates.INSTANCE); + + MODULES.forEach(PuzzleModule::init); + } + + public static class PuzzleResourceManager implements SynchronousResourceReloader { + public static PuzzleResourceManager INSTANCE = new PuzzleResourceManager(); + @Override + public void reload(ResourceManager manager) { + MODULES.forEach(module -> module.reloadResources(manager)); + } } } diff --git a/common/src/main/java/net/puzzlemc/core/PuzzleModule.java b/common/src/main/java/net/puzzlemc/core/PuzzleModule.java new file mode 100644 index 0000000..d5ed0c3 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/core/PuzzleModule.java @@ -0,0 +1,13 @@ +package net.puzzlemc.core; + +import net.minecraft.resource.ResourceManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public interface PuzzleModule { + default void init() {} + default void reloadResources(ResourceManager manager) {} + String getModuleId(); + + default Logger getLogger() {return LoggerFactory.getLogger("puzzle/"+getModuleId());} +} diff --git a/common/src/main/java/net/puzzlemc/core/mixin/PuzzleMixinPlugin.java b/common/src/main/java/net/puzzlemc/core/mixin/PuzzleMixinPlugin.java new file mode 100644 index 0000000..4b04edf --- /dev/null +++ b/common/src/main/java/net/puzzlemc/core/mixin/PuzzleMixinPlugin.java @@ -0,0 +1,50 @@ +package net.puzzlemc.core.mixin; + +import eu.midnightdust.lib.util.PlatformFunctions; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class PuzzleMixinPlugin implements IMixinConfigPlugin { + private String mixinPackage; + + @Override + public void onLoad(String mixinPackage) { + this.mixinPackage = mixinPackage + "."; + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + final String mixinName = mixinClassName.substring(this.mixinPackage.length()); + final String packageName = mixinName.substring(0, mixinName.lastIndexOf('.')); + + if (packageName.startsWith("sodium") && !PlatformFunctions.isModLoaded("sodium")) return false; + + return true; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + } +} diff --git a/common/src/main/java/net/puzzlemc/gui/PuzzleApi.java b/common/src/main/java/net/puzzlemc/gui/PuzzleApi.java index 1391c39..8ae0e4b 100755 --- a/common/src/main/java/net/puzzlemc/gui/PuzzleApi.java +++ b/common/src/main/java/net/puzzlemc/gui/PuzzleApi.java @@ -6,8 +6,6 @@ import net.puzzlemc.gui.screen.widget.PuzzleWidget; import java.util.ArrayList; import java.util.List; -import static net.puzzlemc.core.PuzzleCore.LOGGER; - public class PuzzleApi { public static List GRAPHICS_OPTIONS = new ArrayList<>(); public static List MISC_OPTIONS = new ArrayList<>(); @@ -17,21 +15,21 @@ public class PuzzleApi { public static void addToGraphicsOptions(PuzzleWidget button) { GRAPHICS_OPTIONS.add(button); if (PuzzleConfig.debugMessages) - LOGGER.info("{} -> Graphics Options", button.descriptionText.getContent().toString()); + PuzzleGui.logger().info("{} -> Graphics Options", button.descriptionText.getContent().toString()); } public static void addToMiscOptions(PuzzleWidget button) { MISC_OPTIONS.add(button); if (PuzzleConfig.debugMessages) - LOGGER.info("{} -> Misc Options", button.descriptionText.getContent().toString()); + PuzzleGui.logger().info("{} -> Misc Options", button.descriptionText.getContent().toString()); } public static void addToPerformanceOptions(PuzzleWidget button) { PERFORMANCE_OPTIONS.add(button); if (PuzzleConfig.debugMessages) - LOGGER.info("{}- > Performance Options", button.descriptionText.getContent().toString()); + PuzzleGui.logger().info("{}- > Performance Options", button.descriptionText.getContent().toString()); } public static void addToResourceOptions(PuzzleWidget button) { RESOURCE_OPTIONS.add(button); if (PuzzleConfig.debugMessages) - LOGGER.info("{} -> Resource Options", button.descriptionText.getContent().toString()); + PuzzleGui.logger().info("{} -> Resource Options", button.descriptionText.getContent().toString()); } } diff --git a/common/src/main/java/net/puzzlemc/gui/PuzzleGui.java b/common/src/main/java/net/puzzlemc/gui/PuzzleGui.java index 4c9d409..e8b2056 100755 --- a/common/src/main/java/net/puzzlemc/gui/PuzzleGui.java +++ b/common/src/main/java/net/puzzlemc/gui/PuzzleGui.java @@ -3,6 +3,7 @@ package net.puzzlemc.gui; import eu.midnightdust.core.MidnightLib; import eu.midnightdust.lib.util.PlatformFunctions; import net.minecraft.util.Identifier; +import net.puzzlemc.core.PuzzleModule; import net.puzzlemc.core.config.PuzzleConfig; import net.puzzlemc.gui.compat.*; import net.puzzlemc.gui.screen.widget.PuzzleWidget; @@ -10,16 +11,22 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.puzzlemc.splashscreen.PuzzleSplashScreen; +import org.slf4j.Logger; -import static net.puzzlemc.core.PuzzleCore.LOGGER; - -public class PuzzleGui { +public class PuzzleGui implements PuzzleModule { + public static final PuzzleGui INSTANCE = new PuzzleGui(); public final static String id = "puzzle"; public static final Text YES = Text.translatable("gui.yes").formatted(Formatting.GREEN); public static final Text NO = Text.translatable("gui.no").formatted(Formatting.RED); public static final Identifier PUZZLE_BUTTON = Identifier.of(id, "icon/button"); - public static void init() { + @Override + public String getModuleId() { + return "gui"; + } + + @Override + public void init() { MidnightLib.hiddenMods.add("puzzle"); PuzzleApi.addToMiscOptions(new PuzzleWidget(Text.of("\uD83E\uDDE9 Puzzle"))); PuzzleApi.addToMiscOptions(new PuzzleWidget(Text.translatable("puzzle.midnightconfig.title"), (button) -> button.setMessage(Text.of("OPEN")), (button) -> { @@ -56,7 +63,7 @@ public class PuzzleGui { if (isActive("entity_texture_features")) ETFCompat.init(); if (isActive("entity_model_features")) EMFCompat.init(); } catch (Exception e) { - LOGGER.error("ETF/EMF config structure changed. Again...", e); + INSTANCE.getLogger().error("ETF/EMF config structure changed. Again...", e); } lateInitDone = true; @@ -64,4 +71,7 @@ public class PuzzleGui { public static boolean isActive(String modid) { return PlatformFunctions.isModLoaded(modid) && !PuzzleConfig.disabledIntegrations.contains(modid); } + public static Logger logger() { + return INSTANCE.getLogger(); + } } diff --git a/common/src/main/java/net/puzzlemc/gui/screen/widget/PuzzleOptionListWidget.java b/common/src/main/java/net/puzzlemc/gui/screen/widget/PuzzleOptionListWidget.java index fd5dff4..de37c90 100755 --- a/common/src/main/java/net/puzzlemc/gui/screen/widget/PuzzleOptionListWidget.java +++ b/common/src/main/java/net/puzzlemc/gui/screen/widget/PuzzleOptionListWidget.java @@ -11,14 +11,13 @@ import net.minecraft.client.resource.language.I18n; import net.minecraft.text.Text; import net.minecraft.text.TranslatableTextContent; import net.minecraft.util.Formatting; +import net.puzzlemc.gui.PuzzleGui; import net.puzzlemc.gui.screen.PuzzleOptionsScreen; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; -import static net.puzzlemc.core.PuzzleCore.LOGGER; - @Environment(EnvType.CLIENT) public class PuzzleOptionListWidget extends MidnightConfig.MidnightConfigListWidget { TextRenderer textRenderer; @@ -42,10 +41,10 @@ public class PuzzleOptionListWidget extends MidnightConfig.MidnightConfigListWid else if (button.buttonType == ButtonType.TEXT_FIELD) this.addButton(List.of(new PuzzleTextFieldWidget(textRenderer, buttonX, 0, 150, 20, button.setTextValue, button.changeTextValue)), button.descriptionText); else - LOGGER.warn("Button {} is missing the buttonType variable. This shouldn't happen!", button); + PuzzleGui.logger().warn("Button {} is missing the buttonType variable. This shouldn't happen!", button); } catch (Exception e) { - LOGGER.error("Failed to add button {}. Likely caused by an update of the specific mod.", button.descriptionText); + PuzzleGui.logger().error("Failed to add button {}. Likely caused by an update of the specific mod.", button.descriptionText); } } diff --git a/common/src/main/java/net/puzzlemc/predicates/BlockStateOverride.java b/common/src/main/java/net/puzzlemc/predicates/BlockStateOverride.java new file mode 100644 index 0000000..b037c90 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/BlockStateOverride.java @@ -0,0 +1,14 @@ +package net.puzzlemc.predicates; + +import com.mojang.serialization.MapCodec; +import net.minecraft.block.BlockState; +import net.minecraft.util.Identifier; +import net.puzzlemc.predicates.mixin.StateAccessor; + +public class BlockStateOverride extends BlockState { + public final Identifier overrideId; + public BlockStateOverride(BlockState baseState, Identifier overrideId) { + super(baseState.getBlock(), ((StateAccessor)baseState).getPropertyMap(), (MapCodec) ((StateAccessor)baseState).getCodec()); + this.overrideId = overrideId; + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/MBPData.java b/common/src/main/java/net/puzzlemc/predicates/MBPData.java new file mode 100644 index 0000000..94daf17 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/MBPData.java @@ -0,0 +1,29 @@ +package net.puzzlemc.predicates; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.puzzlemc.predicates.data.logic.When; + +import java.util.HashMap; +import java.util.List; +import java.util.Optional; + +public class MBPData { + public static final HashMap> PREDICATES = new HashMap<>(); + + public static Optional meetsPredicate(BlockView world, BlockPos pos, BlockState state, Identifier renderContext) { + if (PREDICATES.containsKey(state.getBlock())) { + for (When when : PREDICATES.get(state.getBlock())) { + if (when.meetsCondition(world, pos, state, renderContext)) { + long seed = pos.hashCode(); + return Optional.of(new BlockStateOverride(state, when.getModel(seed))); + } + } + } + + return Optional.empty(); + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/MBPMixinPlugin.java b/common/src/main/java/net/puzzlemc/predicates/MBPMixinPlugin.java new file mode 100644 index 0000000..559ecbe --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/MBPMixinPlugin.java @@ -0,0 +1,68 @@ +package net.puzzlemc.predicates; + +import net.fabricmc.loader.api.FabricLoader; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class MBPMixinPlugin implements IMixinConfigPlugin { + public static boolean HAS_SODIUM = false; + public static boolean HAS_WORLDMESHER = false; + + @Override + public void onLoad(String mixinPackage) { + HAS_SODIUM = FabricLoader.getInstance().isModLoaded("sodium"); + HAS_WORLDMESHER = FabricLoader.getInstance().isModLoaded("worldmesher"); + StringBuilder builder = new StringBuilder(); + if (HAS_SODIUM) { + builder.append("sodium, "); + } + if (HAS_WORLDMESHER) { + builder.append("worldmesher, "); + } + String str = "Starting MBP"; + if (builder.length() > 0) { + str = str + " with " + builder.substring(0, builder.length()-2); + } + PuzzlePredicates.logger().debug(str); + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + if (mixinClassName.equals("compat.sodium.ChunkBuilderMeshingTaskMixin")) + return HAS_SODIUM; + //if (mixinClassName.equals("BlockRenderManagerMixin")) + // return !HAS_SODIUM; + //if (mixinClassName.equals("WorldMeshMixin")) + //return HAS_WORLDMESHER; + return true; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return List.of("compat.sodium.ChunkBuilderMeshingTaskMixin"); + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/PuzzlePredicates.java b/common/src/main/java/net/puzzlemc/predicates/PuzzlePredicates.java new file mode 100644 index 0000000..ddd4265 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/PuzzlePredicates.java @@ -0,0 +1,73 @@ +package net.puzzlemc.predicates; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import net.minecraft.block.Block; +import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +import net.puzzlemc.core.PuzzleModule; +import net.puzzlemc.predicates.data.logic.When; +import net.puzzlemc.predicates.util.Utils; +import org.slf4j.Logger; + +import java.util.*; + +public class PuzzlePredicates implements PuzzleModule { + public static final PuzzlePredicates INSTANCE = new PuzzlePredicates(); + public static EntityRenderState currentEntityRenderState; + + @Override + public String getModuleId() { + return "predicates"; + } + + public static Logger logger() { + return INSTANCE.getLogger(); + } + + public static Identifier id(String path) { + return Identifier.of("mbp", path); + } + + @Override + public void init() { + // TODO + //ModelLoadingPluginManager.registerPlugin(new MBPModelLoadingPlugin.ModelIdLoader(), new MBPModelLoadingPlugin()); + } + @Override + public void reloadResources(ResourceManager manager) { + MBPData.PREDICATES.clear(); + + Map map = manager.findResources("mbp", id -> id.getPath().endsWith(".json")); + for (Identifier id : map.keySet()) { + getLogger().info("Loading MBP: " + id); + try { + Identifier blockTarget = Identifier.of(id.toString().substring(0,id.toString().length()-5).replace("mbp/", "")); + JsonObject asset = JsonParser.parseReader(map.get(id).getReader()).getAsJsonObject(); + + Optional block = Utils.getBlock(blockTarget); + + if (block.isPresent()) { + JsonArray overrides = asset.getAsJsonArray("overrides"); + List whenList = new ArrayList<>(); + for(JsonElement overrideEntry : overrides) { + When when = When.parse(overrideEntry); + whenList.add(when); + } + MBPData.PREDICATES.put(block.get(), Collections.unmodifiableList(whenList)); + getLogger().info(MBPData.PREDICATES.toString()); + } else { + getLogger().error("Block entry not found in file %s: %s ".formatted(id, blockTarget)); + } + + } catch (Exception e) { + getLogger().error("Error in file: %s".formatted(id)); + e.printStackTrace(); + } + } + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/accessor/BlockRenderManagerAccess.java b/common/src/main/java/net/puzzlemc/predicates/accessor/BlockRenderManagerAccess.java new file mode 100644 index 0000000..27ffef7 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/accessor/BlockRenderManagerAccess.java @@ -0,0 +1,12 @@ +package net.puzzlemc.predicates.accessor; + +import net.minecraft.client.render.block.BlockRenderManager; +import net.minecraft.client.render.entity.state.BlockDisplayEntityRenderState; + +public interface BlockRenderManagerAccess { + void moreBlockPredicates$setContextEntity(BlockDisplayEntityRenderState renderState); + + static BlockRenderManagerAccess of(BlockRenderManager manager) { + return (BlockRenderManagerAccess) manager; + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/accessor/BlockStateModelManagerAccess.java b/common/src/main/java/net/puzzlemc/predicates/accessor/BlockStateModelManagerAccess.java new file mode 100644 index 0000000..945fcac --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/accessor/BlockStateModelManagerAccess.java @@ -0,0 +1,13 @@ +package net.puzzlemc.predicates.accessor; + +import net.minecraft.client.render.model.BakedModelManager; +import net.minecraft.client.render.model.BlockStateModel; +import net.puzzlemc.predicates.BlockStateOverride; + +public interface BlockStateModelManagerAccess { + BlockStateModel reallyGetModel(BlockStateOverride override); + + static BlockStateModelManagerAccess of(BakedModelManager manager) { + return (BlockStateModelManagerAccess) manager; + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/common/BlockRendering.java b/common/src/main/java/net/puzzlemc/predicates/common/BlockRendering.java new file mode 100644 index 0000000..322a3c9 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/common/BlockRendering.java @@ -0,0 +1,36 @@ +package net.puzzlemc.predicates.common; + +import net.minecraft.block.BlockRenderType; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.block.BlockModels; +import net.minecraft.client.render.model.BlockStateModel; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; +import net.puzzlemc.predicates.BlockStateOverride; +import net.puzzlemc.predicates.MBPData; +import net.puzzlemc.predicates.accessor.BlockStateModelManagerAccess; + +import java.util.Optional; + +public class BlockRendering { + + public static BlockStateModel tryModelOverride(BlockModels models, BlockRenderView world, BlockState state, BlockPos pos, Identifier renderContext) { + BlockRenderType blockRenderType = state.getRenderType(); + if (blockRenderType == BlockRenderType.MODEL) { + Optional override = MBPData.meetsPredicate(world, pos, state, renderContext); + if (override.isPresent()) { + BlockStateModel model; + BlockStateModelManagerAccess manager = ((BlockStateModelManagerAccess) models.getModelManager()); + model = manager.reallyGetModel(override.get()); + if (model == models.getModelManager().getMissingModel()) { + var overId = override.get(); + model = models.getModelManager().getBlockModels().getModel((BlockState) model); + } + return model; + } + } + return null; + } + +} diff --git a/common/src/main/java/net/puzzlemc/predicates/common/ContextIdentifiers.java b/common/src/main/java/net/puzzlemc/predicates/common/ContextIdentifiers.java new file mode 100644 index 0000000..ab3686c --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/common/ContextIdentifiers.java @@ -0,0 +1,16 @@ +package net.puzzlemc.predicates.common; + +import net.minecraft.util.Identifier; + +import static net.puzzlemc.predicates.PuzzlePredicates.id; + +public final class ContextIdentifiers { + public static final Identifier PISTON_PUSHING = id("pushed_by_piston"); + public static final Identifier FALLING_BLOCK = id("falling_block"); + public static final Identifier MARKER_PARTICLE = id("marker_particle"); + public static final Identifier ITEM = id("item"); + public static final Identifier ITEM_HELD = id("item_held"); + public static final Identifier MISC = id("misc"); + public static final Identifier CHUNK_MESH = id("chunk_mesh"); + public static final Identifier ENTITY = id("entity"); +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/BlockModelPredicate.java b/common/src/main/java/net/puzzlemc/predicates/data/BlockModelPredicate.java new file mode 100644 index 0000000..1e7cadc --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/BlockModelPredicate.java @@ -0,0 +1,63 @@ +package net.puzzlemc.predicates.data; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import net.puzzlemc.predicates.PuzzlePredicates; +import net.puzzlemc.predicates.data.conditions.*; +import net.puzzlemc.predicates.data.logic.Not; +import net.puzzlemc.predicates.data.logic.Or; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +public abstract class BlockModelPredicate implements WorldViewCondition { + private static final HashMap> HANDLERS = new HashMap<>() {{ + // Logical operators + put("or", Or::parse); + put("not", Not::parse); + + // Actual conditions + put("adjacent_block", AdjacentBlock::parse); + put("coordinate_range", CoordinateRange::parse); + put("biome", InBiome::parse); + put("state", IsBlockState::parse); + put("light_range", LightRange::parse); + put("is_context", IsContext::parse); + }}; + + public static ArrayList parseFromJson(JsonElement element) { + ArrayList objects = new ArrayList<>(); + if (element.isJsonArray()) { + JsonArray arr = element.getAsJsonArray(); + for (JsonElement obj : arr) { + objects.add(obj.getAsJsonObject()); + } + } else { + objects.add(element.getAsJsonObject()); + } + + ArrayList predicates = new ArrayList<>(); + for(JsonObject curObject : objects) { + for (Map.Entry entries : curObject.entrySet()) { + if (HANDLERS.containsKey(entries.getKey())) { + try { + predicates.add(HANDLERS.get(entries.getKey()).apply(entries.getValue())); + } catch (JsonParseException e) { + PuzzlePredicates.logger().warn(String.format("Failed to load predicate \"%s\"! Reason: %s", entries.getKey(), e.getMessage())); + } + } else { + PuzzlePredicates.logger().warn(String.format("Unhandled predicate \"%s\"!", entries.getKey())); + } + } + } + + return predicates; + } + + + +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/DataHelper.java b/common/src/main/java/net/puzzlemc/predicates/data/DataHelper.java new file mode 100644 index 0000000..602ab8c --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/DataHelper.java @@ -0,0 +1,33 @@ +package net.puzzlemc.predicates.data; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import net.minecraft.predicate.NumberRange; +import net.minecraft.util.math.BlockPos; + +public final class DataHelper { + + public static NumberRange.IntRange parseIntRange(JsonElement arg) { + JsonObject object = arg.getAsJsonObject(); + + boolean hasMin = object.has("min"), hasMax = object.has("max"); + if (hasMin && hasMax) { + return NumberRange.IntRange.between(object.get("min").getAsInt(), object.get("max").getAsInt()); + } else if (hasMin) { + return NumberRange.IntRange.atLeast(object.get("min").getAsInt()); + } else if (hasMax) { + return NumberRange.IntRange.atMost(object.get("max").getAsInt()); + } else { + // none?!?!??!?!?!?!?!?! + throw new JsonParseException("No min or max defined for range!"); + } + } + + public static BlockPos parseBlockPos(JsonObject offset) { + int x = offset.get("x").getAsInt(); + int y = offset.get("y").getAsInt(); + int z = offset.get("z").getAsInt(); + return new BlockPos(x, y, z); + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/WorldViewCondition.java b/common/src/main/java/net/puzzlemc/predicates/data/WorldViewCondition.java new file mode 100644 index 0000000..f3bc999 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/WorldViewCondition.java @@ -0,0 +1,10 @@ +package net.puzzlemc.predicates.data; + +import net.minecraft.block.BlockState; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; + +public interface WorldViewCondition { + boolean meetsCondition(BlockView world, BlockPos pos, BlockState state, Identifier renderContext); +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/conditions/AdjacentBlock.java b/common/src/main/java/net/puzzlemc/predicates/data/conditions/AdjacentBlock.java new file mode 100644 index 0000000..f6c2544 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/conditions/AdjacentBlock.java @@ -0,0 +1,50 @@ +package net.puzzlemc.predicates.data.conditions; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.minecraft.block.BlockState; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.puzzlemc.predicates.data.BlockModelPredicate; +import net.puzzlemc.predicates.data.DataHelper; +import org.jetbrains.annotations.Nullable; + +public class AdjacentBlock extends BlockModelPredicate { + + private final @Nullable IsBlockState stateCondition; + private final BlockPos offset; + private final boolean checkFullCube; + private final boolean checkTransparent; + public AdjacentBlock(@Nullable IsBlockState stateCondition, BlockPos offset, boolean checkFullCube, boolean checkTransparent) { + this.stateCondition = stateCondition; + this.offset = offset; + this.checkFullCube = checkFullCube; + this.checkTransparent = checkTransparent; + } + + @Override + public boolean meetsCondition(BlockView world, BlockPos pos, BlockState state, Identifier renderContext) { + BlockState block = world.getBlockState(pos); + boolean b = true; + if (checkFullCube) b = block.isFullCube(world, pos); + if (checkTransparent) b &= block.isTransparent(); + if (stateCondition != null) b &= stateCondition.meetsCondition(world, pos.add(offset), state, renderContext); + return b; + } + + public static AdjacentBlock parse(JsonElement arg) { + JsonObject obj = arg.getAsJsonObject(); + IsBlockState stateCondition = null; + if (obj.has("state")) { + stateCondition = IsBlockState.parse(obj.get("state")); + } + + boolean checkFullCube = false; + boolean checkTransparent = false; + if (obj.has("is_full_cube")) checkFullCube = obj.get("is_full_cube").getAsBoolean(); + if (obj.has("is_transparent")) checkTransparent = obj.get("is_transparent").getAsBoolean(); + + return new AdjacentBlock(stateCondition, DataHelper.parseBlockPos(obj.getAsJsonObject("offset")), checkFullCube, checkTransparent); + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/conditions/CoordinateRange.java b/common/src/main/java/net/puzzlemc/predicates/data/conditions/CoordinateRange.java new file mode 100644 index 0000000..18078d0 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/conditions/CoordinateRange.java @@ -0,0 +1,35 @@ +package net.puzzlemc.predicates.data.conditions; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.minecraft.block.BlockState; +import net.minecraft.predicate.NumberRange; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockView; +import net.puzzlemc.predicates.data.BlockModelPredicate; +import net.puzzlemc.predicates.data.DataHelper; + +public class CoordinateRange extends BlockModelPredicate { + + public final NumberRange.IntRange range; + public final Direction.Axis axis; + + public CoordinateRange(NumberRange.IntRange range, Direction.Axis axis) { + this.range = range; + this.axis = axis; + } + + @Override + public boolean meetsCondition(BlockView world, BlockPos pos, BlockState state, Identifier renderContext) { + return range.test(pos.getComponentAlongAxis(this.axis)); + } + + public static CoordinateRange parse(JsonElement arg) { + JsonObject object = arg.getAsJsonObject(); + + Direction.Axis axis = Direction.Axis.fromId(object.get("axis").getAsString()); + return new CoordinateRange(DataHelper.parseIntRange(arg), axis); + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/conditions/InBiome.java b/common/src/main/java/net/puzzlemc/predicates/data/conditions/InBiome.java new file mode 100644 index 0000000..ea0381e --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/conditions/InBiome.java @@ -0,0 +1,30 @@ +package net.puzzlemc.predicates.data.conditions; + +import com.google.gson.JsonElement; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; +import net.puzzlemc.predicates.data.BlockModelPredicate; + +public class InBiome extends BlockModelPredicate { + + final Identifier biomeID; + + public InBiome(Identifier biomeID) { + this.biomeID = biomeID; + } + + @Override + public boolean meetsCondition(BlockView world, BlockPos pos, BlockState state, Identifier renderContext) { + World w = MinecraftClient.getInstance().world;; + assert w != null; + return w.getBiome(pos).matchesId(biomeID); + } + + public static InBiome parse(JsonElement arg) { + return new InBiome(Identifier.of(arg.getAsString())); + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/conditions/IsBlockState.java b/common/src/main/java/net/puzzlemc/predicates/data/conditions/IsBlockState.java new file mode 100644 index 0000000..16f972f --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/conditions/IsBlockState.java @@ -0,0 +1,68 @@ +package net.puzzlemc.predicates.data.conditions; + +import com.google.gson.JsonElement; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.block.BlockState; +import net.minecraft.block.pattern.CachedBlockPosition; +import net.minecraft.client.MinecraftClient; +import net.minecraft.command.argument.BlockArgumentParser; +import net.minecraft.command.argument.BlockPredicateArgumentType; +import net.minecraft.registry.Registries; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.puzzlemc.predicates.data.BlockModelPredicate; +import org.jetbrains.annotations.Nullable; + +public class IsBlockState extends BlockModelPredicate { + + final @Nullable BlockPredicateImpl blockStatePredicate; + public IsBlockState(@Nullable BlockPredicateImpl blockStatePredicate) { + this.blockStatePredicate = blockStatePredicate; + } + + @Override + public boolean meetsCondition(BlockView world, BlockPos pos, BlockState state, Identifier renderContext) { + if (blockStatePredicate == null) return true; + return blockStatePredicate.test(new CachedBlockPosition(MinecraftClient.getInstance().world, pos, false)); + } + + public static IsBlockState parse(JsonElement arg) { + try { + String str = arg.getAsString(); + + if (str != null) { + return new IsBlockState(new BlockPredicateImpl(str)); + } + + return null; // explode + } catch (CommandSyntaxException e) { + throw new RuntimeException(e); + } + } + + private static class BlockPredicateImpl implements BlockPredicateArgumentType.BlockPredicate { + final BlockArgumentParser.BlockResult res; + public final String stateString; + public final boolean fuzzy; + + public BlockPredicateImpl(String stateString) throws CommandSyntaxException { + this.stateString = stateString; + fuzzy = !stateString.contains("["); + res = BlockArgumentParser.block(Registries.BLOCK, stateString, false); + } + + @Override + public boolean hasNbt() { + return false; + } + + @Override + public boolean test(CachedBlockPosition cachedBlockPosition) { + if (fuzzy) return cachedBlockPosition.getBlockState().getBlock() == res.blockState().getBlock(); + return cachedBlockPosition.getBlockState().equals(res.blockState()); + } + } + + +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/conditions/IsContext.java b/common/src/main/java/net/puzzlemc/predicates/data/conditions/IsContext.java new file mode 100644 index 0000000..54285c7 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/conditions/IsContext.java @@ -0,0 +1,27 @@ +package net.puzzlemc.predicates.data.conditions; + +import com.google.gson.JsonElement; +import net.minecraft.block.BlockState; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.puzzlemc.predicates.data.BlockModelPredicate; + +public class IsContext extends BlockModelPredicate { + + final Identifier expectedContext; + + public IsContext(Identifier expectedContext) { + this.expectedContext = expectedContext; + } + + @Override + public boolean meetsCondition(BlockView world, BlockPos pos, BlockState state, Identifier renderContext) { + return expectedContext.equals(renderContext); + } + + public static IsContext parse(JsonElement arg) { + return new IsContext(Identifier.of(arg.getAsString())); + } + +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/conditions/LightRange.java b/common/src/main/java/net/puzzlemc/predicates/data/conditions/LightRange.java new file mode 100644 index 0000000..975b972 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/conditions/LightRange.java @@ -0,0 +1,39 @@ +package net.puzzlemc.predicates.data.conditions; + +import com.google.gson.JsonElement; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.predicate.NumberRange; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; +import net.puzzlemc.predicates.data.BlockModelPredicate; +import net.puzzlemc.predicates.data.DataHelper; + +public class LightRange extends BlockModelPredicate { + + public final NumberRange.IntRange range; + + public LightRange(NumberRange.IntRange range) { + this.range = range; + } + + @Override + public boolean meetsCondition(BlockView _unused, BlockPos pos, BlockState state, Identifier renderContext) { + World world = MinecraftClient.getInstance().world; + + // ;-; + return range.test(world.getLightLevel(pos)) + || range.test(world.getLightLevel(pos.up())) + || range.test(world.getLightLevel(pos.down())) + || range.test(world.getLightLevel(pos.north())) + || range.test(world.getLightLevel(pos.south())) + || range.test(world.getLightLevel(pos.east())) + || range.test(world.getLightLevel(pos.west())); + } + + public static LightRange parse(JsonElement arg) { + return new LightRange(DataHelper.parseIntRange(arg)); + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/logic/And.java b/common/src/main/java/net/puzzlemc/predicates/data/logic/And.java new file mode 100644 index 0000000..00284a1 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/logic/And.java @@ -0,0 +1,32 @@ +package net.puzzlemc.predicates.data.logic; + +import com.google.common.collect.ImmutableList; +import com.google.gson.JsonElement; +import net.minecraft.block.BlockState; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.puzzlemc.predicates.data.BlockModelPredicate; + +import java.util.List; + +public class And extends BlockModelPredicate { + + final List predicates; + + public And(List predicates) { + this.predicates = predicates; + } + + @Override + public boolean meetsCondition(BlockView world, BlockPos pos, BlockState state, Identifier renderContext) { + for (BlockModelPredicate action : predicates) { + if (!action.meetsCondition(world, pos, state, renderContext)) return false; + } + return true; + } + + public static And parse(JsonElement arg) { + return new And(ImmutableList.copyOf(BlockModelPredicate.parseFromJson(arg))); + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/logic/Not.java b/common/src/main/java/net/puzzlemc/predicates/data/logic/Not.java new file mode 100644 index 0000000..1dfd03a --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/logic/Not.java @@ -0,0 +1,26 @@ +package net.puzzlemc.predicates.data.logic; + +import com.google.gson.JsonElement; +import net.minecraft.block.BlockState; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.puzzlemc.predicates.data.BlockModelPredicate; + +public class Not extends BlockModelPredicate { + + final And condition; + + public Not(And condition) { + this.condition = condition; + } + + @Override + public boolean meetsCondition(BlockView world, BlockPos pos, BlockState state, Identifier renderContext) { + return !condition.meetsCondition(world, pos, state, renderContext); + } + + public static Not parse(JsonElement arg) { + return new Not(And.parse(arg)); + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/logic/Or.java b/common/src/main/java/net/puzzlemc/predicates/data/logic/Or.java new file mode 100644 index 0000000..2469792 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/logic/Or.java @@ -0,0 +1,39 @@ +package net.puzzlemc.predicates.data.logic; + +import com.google.common.collect.ImmutableList; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import net.minecraft.block.BlockState; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.puzzlemc.predicates.data.BlockModelPredicate; + +import java.util.ArrayList; +import java.util.List; + +public class Or extends BlockModelPredicate { + + final List conditions; + + public Or(List conditions) { + this.conditions = conditions; + } + + @Override + public boolean meetsCondition(BlockView world, BlockPos pos, BlockState state, Identifier renderContext) { + for (And action : conditions) { + if (action.meetsCondition(world, pos, state, renderContext)) return true; + } + return false; + } + + public static Or parse(JsonElement arg) { + ArrayList conditionsList = new ArrayList<>(); + JsonArray entryArray = arg.getAsJsonArray(); + for (JsonElement entry : entryArray) { + conditionsList.add(And.parse(entry)); + } + return new Or(ImmutableList.copyOf(conditionsList)); + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/data/logic/When.java b/common/src/main/java/net/puzzlemc/predicates/data/logic/When.java new file mode 100644 index 0000000..6963744 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/data/logic/When.java @@ -0,0 +1,71 @@ +package net.puzzlemc.predicates.data.logic; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.minecraft.block.BlockState; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.puzzlemc.predicates.data.BlockModelPredicate; +import net.puzzlemc.predicates.data.WorldViewCondition; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class When implements WorldViewCondition { + + final And conditions; + private final List applyModelList; + + public When(And conditions, List applyModelList) { + this.conditions = conditions; + this.applyModelList = Collections.unmodifiableList(applyModelList); + } + + public Identifier getModel(long seed) { + return applyModelList.get((int) (Math.abs(seed) % applyModelList.size())); + } + + public List getModels() { + return applyModelList; + } + + public static When parse(JsonElement arg) { + JsonObject object = arg.getAsJsonObject(); + List conditions = BlockModelPredicate.parseFromJson(object.get("when")); + + List applyModelList; + JsonElement apply = object.get("apply"); + if (apply.isJsonArray()) { + applyModelList = new ArrayList<>(); + for (JsonElement entry : apply.getAsJsonArray()) { + String applyId; + int weight = 1; + if (entry.isJsonObject()) { + JsonObject obj = entry.getAsJsonObject(); + applyId = obj.get("model").getAsString(); + if (obj.has("weight")) weight = obj.get("weight").getAsInt(); + } else { + applyId = entry.getAsString(); + } + + String[] id = applyId.split(":"); + Identifier currentModelID = Identifier.of(id[0], "block/" + id[1]); + for (int i = 0; i < weight; i++) { + applyModelList.add(currentModelID); + } + } + } else { + String[] id = apply.getAsString().split(":"); + applyModelList = List.of(Identifier.of(id[0], "block/" + id[1])); + } + + return new When(new And(conditions), applyModelList); + } + + @Override + public boolean meetsCondition(BlockView world, BlockPos pos, BlockState state, Identifier renderContext) { + return conditions.meetsCondition(world, pos, state, renderContext); + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/BakedModelManagerMixin.java b/common/src/main/java/net/puzzlemc/predicates/mixin/BakedModelManagerMixin.java new file mode 100644 index 0000000..f269e52 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/BakedModelManagerMixin.java @@ -0,0 +1,60 @@ +package net.puzzlemc.predicates.mixin; + +import net.minecraft.client.render.block.BlockModels; +import net.minecraft.client.render.model.BakedModelManager; +import net.minecraft.client.render.model.BlockStateModel; +import net.puzzlemc.predicates.BlockStateOverride; +import net.puzzlemc.predicates.accessor.BlockStateModelManagerAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(BakedModelManager.class) +public abstract class BakedModelManagerMixin implements BlockStateModelManagerAccess { + + //@Shadow private Map models; + + @Shadow public abstract BlockStateModel getMissingModel(); + + @Shadow public abstract BlockModels getBlockModels(); + + @Override @Unique + public BlockStateModel reallyGetModel(BlockStateOverride override) { + return getBlockModels().getModel(override); + //return models.getOrDefault(model, this.getMissingModel()); + } + + + // ITEMS (originally from ItemRendererMixin) + +// @Inject(method = "getModel", at = @At(value = "HEAD")) +// private void getHeldItemModelVariableStealerLol(ItemStack stack, World world, LivingEntity entity, int seed, CallbackInfoReturnable cir) { +// this.world = world; +// this.entity = entity; +// } +// +// @Redirect(method = "getModel", at = @At(value = "INVOKE",target = "Lnet/minecraft/client/render/item/ItemModels;getModel(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/client/render/model/BakedModel;")) +// private BakedModel getHeldItemModelMixin(ItemModels itemModels, ItemStack stack) { +// if (world == null || entity == null) return itemModels.getModel(stack); +// +// BlockPos targetPos = entity.getBlockPos(); +// if (entity instanceof PlayerEntity player) { +// HitResult hit = player.raycast(8, MinecraftClient.getInstance().getTickDelta(), false); +// if (hit instanceof BlockHitResult blockHitResult) { +// targetPos = blockHitResult.getBlockPos().add(blockHitResult.getSide().getVector()); +// } +// } +// +// Optional identifier = MBPData.meetsPredicate(world, targetPos, Block.getBlockFromItem(stack.getItem()).getDefaultState(), ContextIdentifiers.ITEM_HELD); +// +// if (identifier.isPresent()) { +// BlockStateModelManagerAccess access = BlockStateModelManagerAccess.of(itemModels.getModelManager()); +// return access.reallyGetModel(identifier.get()); +// } +// +// world = null; +// entity = null; +// return itemModels.getModel(stack); +// } + +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/BlockDisplayEntityRendererMixin.java b/common/src/main/java/net/puzzlemc/predicates/mixin/BlockDisplayEntityRendererMixin.java new file mode 100644 index 0000000..04ee0ad --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/BlockDisplayEntityRendererMixin.java @@ -0,0 +1,24 @@ +package net.puzzlemc.predicates.mixin; + +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.block.BlockRenderManager; +import net.minecraft.client.render.entity.DisplayEntityRenderer; +import net.minecraft.client.render.entity.state.BlockDisplayEntityRenderState; +import net.minecraft.client.util.math.MatrixStack; +import net.puzzlemc.predicates.accessor.BlockRenderManagerAccess; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(DisplayEntityRenderer.BlockDisplayEntityRenderer.class) +public class BlockDisplayEntityRendererMixin { + @Shadow @Final private BlockRenderManager blockRenderManager; + + @Inject(method = "render(Lnet/minecraft/client/render/entity/state/BlockDisplayEntityRenderState;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IF)V", at = @At("HEAD")) + public void getContext(BlockDisplayEntityRenderState blockDisplayEntityRenderState, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, float f, CallbackInfo ci) { + BlockRenderManagerAccess.of(blockRenderManager).moreBlockPredicates$setContextEntity(blockDisplayEntityRenderState); + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/BlockDustParticleMixin.java b/common/src/main/java/net/puzzlemc/predicates/mixin/BlockDustParticleMixin.java new file mode 100644 index 0000000..db06988 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/BlockDustParticleMixin.java @@ -0,0 +1,40 @@ +package net.puzzlemc.predicates.mixin; + +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.particle.BlockDustParticle; +import net.minecraft.client.particle.SpriteBillboardParticle; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.puzzlemc.predicates.BlockStateOverride; +import net.puzzlemc.predicates.MBPData; +import net.puzzlemc.predicates.accessor.BlockStateModelManagerAccess; +import net.puzzlemc.predicates.common.ContextIdentifiers; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Optional; + +@Mixin(BlockDustParticle.class) +public abstract class BlockDustParticleMixin extends SpriteBillboardParticle { + + protected BlockDustParticleMixin(ClientWorld clientWorld, double d, double e, double f) { + super(clientWorld, d, e, f); + } + + @Inject(at = @At(value = "TAIL"), method = "(Lnet/minecraft/client/world/ClientWorld;DDDDDDLnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;)V") + public void init(ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ, BlockState state, BlockPos blockPos, CallbackInfo ci) { + Optional identifier = MBPData.meetsPredicate(world, blockPos, state, ContextIdentifiers.FALLING_BLOCK); + + MinecraftClient client = MinecraftClient.getInstance(); + if (identifier.isPresent()) { + BlockStateModelManagerAccess access = BlockStateModelManagerAccess.of(client.getBakedModelManager()); + setSprite(access.reallyGetModel(identifier.get()).particleSprite()); + } else { + this.setSprite(client.getBlockRenderManager().getModels().getModelParticleSprite(state)); + } + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/BlockMarkerParticleMixin.java b/common/src/main/java/net/puzzlemc/predicates/mixin/BlockMarkerParticleMixin.java new file mode 100644 index 0000000..723d431 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/BlockMarkerParticleMixin.java @@ -0,0 +1,41 @@ +package net.puzzlemc.predicates.mixin; + +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.particle.BlockMarkerParticle; +import net.minecraft.client.particle.SpriteBillboardParticle; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.puzzlemc.predicates.BlockStateOverride; +import net.puzzlemc.predicates.MBPData; +import net.puzzlemc.predicates.accessor.BlockStateModelManagerAccess; +import net.puzzlemc.predicates.common.ContextIdentifiers; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Optional; + +@Mixin(BlockMarkerParticle.class) +public abstract class BlockMarkerParticleMixin extends SpriteBillboardParticle { + + protected BlockMarkerParticleMixin(ClientWorld clientWorld, double d, double e, double f) { + super(clientWorld, d, e, f); + + } + + @Inject(at = @At(value = "TAIL"), method = "") + public void init(ClientWorld world, double x, double y, double z, BlockState state, CallbackInfo ci) { + Optional identifier = MBPData.meetsPredicate(world, BlockPos.ofFloored(x, y, z), state, ContextIdentifiers.MARKER_PARTICLE); + + MinecraftClient client = MinecraftClient.getInstance(); + if (identifier.isPresent()) { + BlockStateModelManagerAccess access = BlockStateModelManagerAccess.of(client.getBakedModelManager()); + setSprite(access.reallyGetModel(identifier.get()).particleSprite()); + } else { + this.setSprite(client.getBlockRenderManager().getModels().getModelParticleSprite(state)); + } + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/BlockModelRendererMixin.java b/common/src/main/java/net/puzzlemc/predicates/mixin/BlockModelRendererMixin.java new file mode 100644 index 0000000..b2c666d --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/BlockModelRendererMixin.java @@ -0,0 +1,47 @@ +package net.puzzlemc.predicates.mixin; + +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import net.minecraft.block.BlockRenderType; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.block.BlockModelRenderer; +import net.minecraft.client.render.model.BlockModelPart; +import net.minecraft.client.render.model.BlockStateModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; +import net.puzzlemc.predicates.PuzzlePredicates; +import org.spongepowered.asm.mixin.Mixin; + +import java.util.List; + +@Mixin(BlockModelRenderer.class) +public class BlockModelRendererMixin { + + @WrapMethod(method = "render(Lnet/minecraft/world/BlockRenderView;Ljava/util/List;Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;ZI)V") + public void renderBlock(BlockRenderView world, List parts, BlockState state, BlockPos pos, MatrixStack matrices, VertexConsumer vertexConsumer, boolean cull, int overlay, Operation original) { + BlockRenderType blockRenderType = state.getRenderType(); + System.out.println("B"); + if (blockRenderType == BlockRenderType.MODEL) { + if (state.getBlock() == Blocks.SPRUCE_LEAVES) PuzzlePredicates.logger().info(":( Should be activated now"); +// BlockStateModel newModel = BlockRendering.tryModelOverride(BlockModels, world, state, pos, ContextIdentifiers.MISC); +// if (newModel != null) { +// PuzzlePredicates.logger().info(":) Replacing "+state.getBlock().toString()); +// // TODO: Don't create an instance of Random here +// original.call(world, newModel.getParts(Random.create()), state, pos, matrices, vertexConsumer, cull, OverlayTexture.DEFAULT_UV); +// //this.blockModelRenderer.render(world, newModel.getParts(random), state, pos, matrices, vertexConsumer, cull, OverlayTexture.DEFAULT_UV); +// //ci.cancel(); +// return; +// } + } + original.call(world, parts, state, pos, matrices, vertexConsumer, cull, overlay); + } + + @WrapMethod(method = "render(Lnet/minecraft/client/util/math/MatrixStack$Entry;Lnet/minecraft/client/render/VertexConsumer;Lnet/minecraft/client/render/model/BlockStateModel;FFFII)V") + private static void c(MatrixStack.Entry entry, VertexConsumer vertexConsumer, BlockStateModel model, float red, float green, float blue, int light, int overlay, Operation original) { + System.out.println("c"); + original.call(entry, vertexConsumer, model, red, green, blue, light, overlay); + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/BlockRenderManagerMixin.java b/common/src/main/java/net/puzzlemc/predicates/mixin/BlockRenderManagerMixin.java new file mode 100644 index 0000000..bea9dcb --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/BlockRenderManagerMixin.java @@ -0,0 +1,99 @@ +package net.puzzlemc.predicates.mixin; + +import net.minecraft.block.BlockRenderType; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.color.block.BlockColors; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.RenderLayers; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.block.BlockModelRenderer; +import net.minecraft.client.render.block.BlockModels; +import net.minecraft.client.render.block.BlockRenderManager; +import net.minecraft.client.render.entity.state.BlockDisplayEntityRenderState; +import net.minecraft.client.render.model.BlockModelPart; +import net.minecraft.client.render.model.BlockStateModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.BlockRenderView; +import net.puzzlemc.predicates.BlockStateOverride; +import net.puzzlemc.predicates.MBPData; +import net.puzzlemc.predicates.PuzzlePredicates; +import net.puzzlemc.predicates.accessor.BlockStateModelManagerAccess; +import net.puzzlemc.predicates.accessor.BlockRenderManagerAccess; +import net.puzzlemc.predicates.common.BlockRendering; +import net.puzzlemc.predicates.common.ContextIdentifiers; +import net.puzzlemc.predicates.util.Utils; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; +import java.util.Optional; + +@Mixin(value = BlockRenderManager.class, priority = 2000) +public class BlockRenderManagerMixin implements BlockRenderManagerAccess { + + @Shadow @Final private BlockModelRenderer blockModelRenderer; + @Shadow @Final private BlockModels models; + @Shadow @Final private BlockColors blockColors; + @Shadow @Final private Random random; + + @Unique private BlockDisplayEntityRenderState mbp$contextRenderState; + + @Inject(at = @At("HEAD"), method = "renderBlock", cancellable = true) + public void renderBlock(BlockState state, BlockPos pos, BlockRenderView world, MatrixStack matrices, VertexConsumer vertexConsumer, boolean cull, List parts, CallbackInfo ci) { + BlockRenderType blockRenderType = state.getRenderType(); + System.out.println("a"); + if (blockRenderType == BlockRenderType.MODEL) { + if (state.getBlock() == Blocks.SPRUCE_LEAVES) PuzzlePredicates.logger().info(":( Should be activated now"); + BlockStateModel newModel = BlockRendering.tryModelOverride(this.models, world, state, pos, ContextIdentifiers.MISC); + if (newModel != null) { + PuzzlePredicates.logger().info(":) Replacing "+state.getBlock().toString()); + this.blockModelRenderer.render(world, newModel.getParts(random), state, pos, matrices, vertexConsumer, cull, OverlayTexture.DEFAULT_UV); + ci.cancel(); + } + } + } + + @Inject(at = @At("HEAD"), method = "renderBlockAsEntity", cancellable = true) + public void renderBlockAsEntity(BlockState state, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, CallbackInfo ci) { + if (state.getRenderType() == BlockRenderType.MODEL) { + BlockPos pos = mbp$contextRenderState == null ? BlockPos.ORIGIN : Utils.posFromRenderState(mbp$contextRenderState); + mbp$contextRenderState = null; + Optional id = MBPData.meetsPredicate(MinecraftClient.getInstance().world, pos, state, ContextIdentifiers.ENTITY); + if (id.isEmpty()) return; + + BlockStateModel bakedModel = ((BlockStateModelManagerAccess) this.models.getModelManager()).reallyGetModel(id.get()); + int i = this.blockColors.getColor(state, null, null, 0); + float f = (float) (i >> 16 & 0xFF) / 255.0F; + float g = (float) (i >> 8 & 0xFF) / 255.0F; + float h = (float) (i & 0xFF) / 255.0F; + BlockModelRenderer + .render( + matrices.peek(), + vertexConsumers.getBuffer(RenderLayers.getEntityBlockLayer(state)), + bakedModel, + f, + g, + h, + light, + overlay + ); + ci.cancel(); + } + } + + @Override + public void moreBlockPredicates$setContextEntity(BlockDisplayEntityRenderState renderState) { + mbp$contextRenderState = renderState; + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/FallingBlockEntityRendererMixin.java b/common/src/main/java/net/puzzlemc/predicates/mixin/FallingBlockEntityRendererMixin.java new file mode 100644 index 0000000..a1ce84a --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/FallingBlockEntityRendererMixin.java @@ -0,0 +1,48 @@ +package net.puzzlemc.predicates.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.block.BlockRenderManager; +import net.minecraft.client.render.entity.FallingBlockEntityRenderer; +import net.minecraft.client.render.entity.state.FallingBlockEntityRenderState; +import net.minecraft.client.render.model.BlockStateModel; +import net.minecraft.client.util.math.MatrixStack; +import net.puzzlemc.predicates.BlockStateOverride; +import net.puzzlemc.predicates.MBPData; +import net.puzzlemc.predicates.accessor.BlockStateModelManagerAccess; +import net.puzzlemc.predicates.common.ContextIdentifiers; +import net.puzzlemc.predicates.util.Utils; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Optional; + +@Mixin(value = FallingBlockEntityRenderer.class, priority = 1100) +public class FallingBlockEntityRendererMixin { + + @Unique private FallingBlockEntityRenderState mbp$fallingBlockEntityRenderState; + + @Inject(at = @At("HEAD"), method = "render(Lnet/minecraft/client/render/entity/state/FallingBlockEntityRenderState;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V") + public void render(FallingBlockEntityRenderState fallingBlockEntityRenderState, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { + this.mbp$fallingBlockEntityRenderState = fallingBlockEntityRenderState; + } + + @WrapOperation(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockRenderManager;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BlockStateModel;"),method = "render(Lnet/minecraft/client/render/entity/state/FallingBlockEntityRenderState;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V") + public BlockStateModel render(BlockRenderManager instance, BlockState state, Operation original) { + Optional identifier = MBPData.meetsPredicate(mbp$fallingBlockEntityRenderState.world, Utils.posFromRenderState(mbp$fallingBlockEntityRenderState), state, ContextIdentifiers.FALLING_BLOCK); + + MinecraftClient client = MinecraftClient.getInstance(); + if (identifier.isPresent()) { + BlockStateModelManagerAccess access = BlockStateModelManagerAccess.of(client.getBakedModelManager()); + return access.reallyGetModel(identifier.get()); + } else { + return original.call(instance, state); + } + } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/ItemEntityRendererMixin.java b/common/src/main/java/net/puzzlemc/predicates/mixin/ItemEntityRendererMixin.java new file mode 100644 index 0000000..b6ef42a --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/ItemEntityRendererMixin.java @@ -0,0 +1,21 @@ +package net.puzzlemc.predicates.mixin; + +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.ItemEntityRenderer; +import net.minecraft.client.render.entity.state.ItemEntityRenderState; +import net.minecraft.client.util.math.MatrixStack; +import net.puzzlemc.predicates.PuzzlePredicates; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ItemEntityRenderer.class) +public class ItemEntityRendererMixin { + + @Inject(at = @At("HEAD"), method = "render(Lnet/minecraft/client/render/entity/state/ItemEntityRenderState;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V") + private void beforeRender(ItemEntityRenderState itemEntityRenderState, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { + PuzzlePredicates.currentEntityRenderState = itemEntityRenderState; + } + +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/ItemFrameEntityRendererMixin.java b/common/src/main/java/net/puzzlemc/predicates/mixin/ItemFrameEntityRendererMixin.java new file mode 100644 index 0000000..85313a6 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/ItemFrameEntityRendererMixin.java @@ -0,0 +1,22 @@ +package net.puzzlemc.predicates.mixin; + +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.ItemFrameEntityRenderer; +import net.minecraft.client.render.entity.state.ItemFrameEntityRenderState; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.decoration.ItemFrameEntity; +import net.puzzlemc.predicates.PuzzlePredicates; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ItemFrameEntityRenderer.class) +public class ItemFrameEntityRendererMixin { + + @Inject(method = "render(Lnet/minecraft/client/render/entity/state/ItemFrameEntityRenderState;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", at = @At("HEAD")) + public void renderMixin(ItemFrameEntityRenderState itemFrameEntityRenderState, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { + PuzzlePredicates.currentEntityRenderState = itemFrameEntityRenderState; + } + +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/ItemRendererMixin.java b/common/src/main/java/net/puzzlemc/predicates/mixin/ItemRendererMixin.java new file mode 100644 index 0000000..04ae794 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/ItemRendererMixin.java @@ -0,0 +1,73 @@ +package net.puzzlemc.predicates.mixin; + +import net.minecraft.block.Block; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.render.model.BlockStateModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.puzzlemc.predicates.MBPData; +import net.puzzlemc.predicates.PuzzlePredicates; +import net.puzzlemc.predicates.accessor.BlockStateModelManagerAccess; +import net.puzzlemc.predicates.common.ContextIdentifiers; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Optional; + +@Mixin(ItemRenderer.class) +public abstract class ItemRendererMixin { + //@Shadow @Final private ItemModels models; + @Unique private World world; + @Unique private Entity entity; + + + + //@Redirect(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformation$Mode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/ItemRenderer;renderBakedItemModel(Lnet/minecraft/client/render/model/BakedModel;Lnet/minecraft/item/ItemStack;IILnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;)V")) +// @Redirect( +// method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V", +// at = @At( +// value = "INVOKE", +// target = "Lnet/minecraft/client/render/item/ItemRenderer;renderBakedItemModel(Lnet/minecraft/client/render/model/BakedModel;Lnet/minecraft/item/ItemStack;IILnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;)V" +// ) +// ) +// private void renderBakedModelMixin(ItemRenderer instance, BakedModel model, ItemStack stack, int light, int overlay, MatrixStack matrices, VertexConsumer vertices) { +// if (world == null) world = MinecraftClient.getInstance().world; +// if (entity == null) entity = MBPClient.currentEntity; +// if (entity == null) entity = MinecraftClient.getInstance().player; +// +// if (entity != null) { +// BlockPos targetPos = entity.getBlockPos(); +// if (entity instanceof PlayerEntity player) { +// HitResult hit = player.raycast(8, MinecraftClient.getInstance().getTickDelta(), false); +// if (hit instanceof BlockHitResult blockHitResult) { +// targetPos = blockHitResult.getBlockPos().add(blockHitResult.getSide().getVector()); +// } +// } +// +// Optional identifier = MBPData.meetsPredicate(world, targetPos, Block.getBlockFromItem(stack.getItem()).getDefaultState(), ContextIdentifiers.ITEM); +// if (identifier.isPresent()) { +// BlockStateModelManagerAccess access = BlockStateModelManagerAccess.of(models.getModelManager()); +// model = access.reallyGetModel(identifier.get()); +// } +// PuzzlePredicates.currentEntityRenderState = null; +// } +// +// this.renderBakedItemModel(model, stack, light, overlay, matrices, vertices); +// } +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/PistonBlockEntityRendererMixin.java b/common/src/main/java/net/puzzlemc/predicates/mixin/PistonBlockEntityRendererMixin.java new file mode 100644 index 0000000..7acd753 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/PistonBlockEntityRendererMixin.java @@ -0,0 +1,50 @@ +package net.puzzlemc.predicates.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.block.BlockRenderManager; +import net.minecraft.client.render.block.entity.PistonBlockEntityRenderer; +import net.minecraft.client.render.model.BlockStateModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.puzzlemc.predicates.BlockStateOverride; +import net.puzzlemc.predicates.MBPData; +import net.puzzlemc.predicates.accessor.BlockStateModelManagerAccess; +import net.puzzlemc.predicates.common.ContextIdentifiers; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Optional; + +@Mixin(value = PistonBlockEntityRenderer.class, priority = 1100) +public class PistonBlockEntityRendererMixin { + @Unique private BlockPos mbp$tempBlockPos; + @Unique private World mbp$tempWorld; + + @Inject(at = @At("HEAD"), method = "renderModel") + public void renderModel(BlockPos pos, BlockState state, MatrixStack matrices, VertexConsumerProvider vertexConsumers, World world, boolean cull, int overlay, CallbackInfo ci) { + this.mbp$tempBlockPos = pos; + this.mbp$tempWorld = world; + } + + @WrapOperation(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockRenderManager;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BlockStateModel;"), method = "renderModel") + public BlockStateModel renderModel(BlockRenderManager instance, BlockState state, Operation original) { + Optional identifier = MBPData.meetsPredicate(mbp$tempWorld, mbp$tempBlockPos, state, ContextIdentifiers.PISTON_PUSHING); + + MinecraftClient client = MinecraftClient.getInstance(); + if (identifier.isPresent()) { + BlockStateModelManagerAccess access = BlockStateModelManagerAccess.of(client.getBakedModelManager()); + return access.reallyGetModel(identifier.get()); + } else { + return original.call(instance, state); + } + } + +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/StateAccessor.java b/common/src/main/java/net/puzzlemc/predicates/mixin/StateAccessor.java new file mode 100644 index 0000000..84919f1 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/StateAccessor.java @@ -0,0 +1,17 @@ +package net.puzzlemc.predicates.mixin; + +import com.mojang.serialization.MapCodec; +import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; +import net.minecraft.state.State; +import net.minecraft.state.property.Property; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(State.class) +public interface StateAccessor { + @Accessor + Reference2ObjectArrayMap, Comparable> getPropertyMap(); + + @Accessor + MapCodec getCodec(); +} diff --git a/common/src/main/java/net/puzzlemc/predicates/mixin/compat/sodium/ChunkBuilderMeshingTaskMixin.java b/common/src/main/java/net/puzzlemc/predicates/mixin/compat/sodium/ChunkBuilderMeshingTaskMixin.java new file mode 100644 index 0000000..38839ac --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/mixin/compat/sodium/ChunkBuilderMeshingTaskMixin.java @@ -0,0 +1,40 @@ +package net.puzzlemc.predicates.mixin.compat.sodium; + +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.block.BlockModels; +import net.minecraft.client.render.model.BlockStateModel; +import net.minecraft.util.math.BlockPos; +import net.puzzlemc.predicates.common.BlockRendering; +import net.puzzlemc.predicates.common.ContextIdentifiers; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + + +//@Mixin(value = ChunkBuilderMeshingTask.class) +public class ChunkBuilderMeshingTaskMixin { + + @Unique private int x = 0; + @Unique private int y = 0; + @Unique private int z = 0; + +// @Redirect(method = "execute(Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext;Lme/jellysquid/mods/sodium/client/util/task/CancellationToken;)Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput;", at = @At(value = "INVOKE", target = "Lme/jellysquid/mods/sodium/client/world/WorldSlice;getBlockState(III)Lnet/minecraft/block/BlockState;")) +// public BlockState getBlockStateRedirect(WorldSlice worldSlice, int x, int y, int z) { +// this.x = x; +// this.y = y; +// this.z = z; +// return worldSlice.getBlockState(x,y,z); +// } +// +// @Redirect(method = "execute(Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext;Lme/jellysquid/mods/sodium/client/util/task/CancellationToken;)Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput;", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockModels;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BakedModel;")) +// public BlockStateModel getModelRedirect(BlockModels models, BlockState state) { +// BakedModel newModel = BlockRendering.tryModelOverride(models, MinecraftClient.getInstance().world, state, new BlockPos(x, y, z), ContextIdentifiers.CHUNK_MESH); +// if (newModel != null) +// return newModel; +// +// // If failed return original method call +// return models.getModel(state); +// } +} \ No newline at end of file diff --git a/common/src/main/java/net/puzzlemc/predicates/resources/MBPModelLoadingPlugin.java b/common/src/main/java/net/puzzlemc/predicates/resources/MBPModelLoadingPlugin.java new file mode 100644 index 0000000..db0cc08 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/resources/MBPModelLoadingPlugin.java @@ -0,0 +1,65 @@ +package net.puzzlemc.predicates.resources; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import net.minecraft.block.Block; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +import net.puzzlemc.predicates.PuzzlePredicates; +import net.puzzlemc.predicates.data.logic.When; +import net.puzzlemc.predicates.util.Utils; + +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + + +//public class MBPModelLoadingPlugin implements PreparableModelLoadingPlugin> { +// +// +// @Override +// public void onInitializeModelLoader(HashSet data, ModelLoadingPlugin.Context pluginContext) { +// pluginContext.addModels(data); +// } +// +// public static class ModelIdLoader implements PreparableModelLoadingPlugin.DataLoader> { +// @Override +// public CompletableFuture> load(ResourceManager manager, Executor executor) { +// +// return CompletableFuture.supplyAsync(() -> { +// HashSet wantedModels = new HashSet<>(); +// +// Map map = manager.findResources("mbp", id -> id.getPath().endsWith(".json")); +// for (Identifier id : map.keySet()) { +// +// try { +// Identifier blockTarget = Identifier.of(id.toString().substring(0,id.toString().length()-5).replace("mbp/", "")); +// JsonObject asset = JsonParser.parseReader(map.get(id).getReader()).getAsJsonObject(); +// +// Optional block = Utils.getBlock(blockTarget); +// +// if (block.isPresent()) { +// JsonArray overrides = asset.getAsJsonArray("overrides"); +// for(JsonElement overrideEntry : overrides) { +// When when = When.parse(overrideEntry); +// +// wantedModels.addAll(when.getModels()); +// } +// } +// +// } catch (Exception e) { +// PuzzlePredicates.logger().error("Error found in file: " + id, e); +// } +// } +// return wantedModels; +// }, executor); +// +// +// } +// } +//} diff --git a/common/src/main/java/net/puzzlemc/predicates/util/Utils.java b/common/src/main/java/net/puzzlemc/predicates/util/Utils.java new file mode 100644 index 0000000..cf36ca7 --- /dev/null +++ b/common/src/main/java/net/puzzlemc/predicates/util/Utils.java @@ -0,0 +1,50 @@ +package net.puzzlemc.predicates.util; + +import net.minecraft.block.Block; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.biome.Biome; + +import java.util.Optional; +import java.util.function.Supplier; + +public class Utils { + private static DynamicRegistryManager getRegistryManager() { + MinecraftClient instance = MinecraftClient.getInstance(); + return instance != null && instance.world != null ? instance.world.getRegistryManager() : null; + } + + public static final Supplier>> BIOME_REGISTRY = () -> { + DynamicRegistryManager drm = getRegistryManager(); + if (drm != null) return drm.getOptional(RegistryKeys.BIOME); + + return Optional.empty(); + }; + + public static Optional getBiome(Identifier biomeId) { + Optional> registry = BIOME_REGISTRY.get(); + if (registry.isPresent()) { + return registry.get().getOptionalValue(biomeId); + } + return Optional.empty(); + } + + public static Optional getBiome(Biome biome) { + Optional> registry = BIOME_REGISTRY.get(); + return registry.map(biomes -> biomes.getId(biome)); + } + + public static Optional getBlock(Identifier blockId) { + return Registries.BLOCK.getOptionalValue(blockId); + } + + public static BlockPos posFromRenderState(EntityRenderState state) { + return BlockPos.ofFloored(state.x, state.y, state.z); + } +} diff --git a/common/src/main/java/net/puzzlemc/splashscreen/PuzzleSplashScreen.java b/common/src/main/java/net/puzzlemc/splashscreen/PuzzleSplashScreen.java index d972557..429555a 100755 --- a/common/src/main/java/net/puzzlemc/splashscreen/PuzzleSplashScreen.java +++ b/common/src/main/java/net/puzzlemc/splashscreen/PuzzleSplashScreen.java @@ -15,6 +15,7 @@ import net.minecraft.client.texture.TextureContents; import net.minecraft.resource.*; import net.minecraft.util.TriState; import net.minecraft.util.Util; +import net.puzzlemc.core.PuzzleModule; import net.puzzlemc.core.config.PuzzleConfig; import net.minecraft.client.MinecraftClient; import net.minecraft.client.resource.metadata.TextureResourceMetadata; @@ -34,10 +35,10 @@ import java.nio.file.StandardCopyOption; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; -import static net.puzzlemc.core.PuzzleCore.LOGGER; import static net.puzzlemc.core.PuzzleCore.MOD_ID; -public class PuzzleSplashScreen { +public class PuzzleSplashScreen implements PuzzleModule { + public static final PuzzleSplashScreen INSTANCE = new PuzzleSplashScreen(); public static final Identifier LOGO = Identifier.of("textures/gui/title/mojangstudios.png"); public static final Identifier BACKGROUND = Identifier.of("puzzle/splash_background.png"); public static File CONFIG_PATH = new File(String.valueOf(PlatformFunctions.getConfigDirectory().resolve(".puzzle_cache"))); @@ -47,14 +48,17 @@ public class PuzzleSplashScreen { private static boolean keepBackground = false; private static RenderLayer CUSTOM_LOGO_LAYER; - public static void init() { - if (!CONFIG_PATH.exists()) { // Run when config directory is nonexistent // - if (CONFIG_PATH.mkdir()) { // Create our custom config directory // - if (Util.getOperatingSystem().equals(Util.OperatingSystem.WINDOWS)) { - try { Files.setAttribute(CONFIG_PATH.toPath(), "dos:hidden", true); - } catch (IOException ignored) {} - } - } + @Override + public String getModuleId() { + return "splashscreen"; + } + + @Override + public void init() { + // When config directory is nonexistent, create it and set the folder as hidden on Windows systems // + if (!CONFIG_PATH.exists() && CONFIG_PATH.mkdir() && Util.getOperatingSystem().equals(Util.OperatingSystem.WINDOWS)) { + try { Files.setAttribute(CONFIG_PATH.toPath(), "dos:hidden", true); + } catch (IOException ignored) {} } buildRenderLayer(); } @@ -63,7 +67,7 @@ public class PuzzleSplashScreen { return CUSTOM_LOGO_LAYER; } - public static void buildRenderLayer() { + public void buildRenderLayer() { if (PuzzleConfig.resourcepackSplashScreen) { BlendFunction blendFunction = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE); if (PuzzleConfig.disableBlend) blendFunction = null; @@ -75,7 +79,7 @@ public class PuzzleSplashScreen { SourceFactor.valueOf(PuzzleConfig.customBlendFunction.get(2)), DestFactor.valueOf(PuzzleConfig.customBlendFunction.get(3))); } catch (Exception e) { - LOGGER.error("Incorrect blend function defined in color.properties: {}{}", PuzzleConfig.customBlendFunction, e.getMessage()); + getLogger().error("Incorrect blend function defined in color.properties: {}{}", PuzzleConfig.customBlendFunction, e.getMessage()); } } @@ -92,82 +96,78 @@ public class PuzzleSplashScreen { } } - public static class ReloadListener implements SynchronousResourceReloader { - public static final ReloadListener INSTANCE = new ReloadListener(); - private ReloadListener() {} + @Override + public void reloadResources(ResourceManager manager) { + client = MinecraftClient.getInstance(); + if (PuzzleConfig.resourcepackSplashScreen) { + PuzzleSplashScreen.resetColors(); + client.getTextureManager().registerTexture(LOGO, new LogoTexture(LOGO)); + client.getTextureManager().registerTexture(BACKGROUND, new LogoTexture(BACKGROUND)); - @Override - public void reload(ResourceManager manager) { - client = MinecraftClient.getInstance(); - if (PuzzleConfig.resourcepackSplashScreen) { - PuzzleSplashScreen.resetColors(); - client.getTextureManager().registerTexture(LOGO, new LogoTexture(LOGO)); - client.getTextureManager().registerTexture(BACKGROUND, new LogoTexture(BACKGROUND)); + manager.findResources("optifine", path -> path.getPath().contains("color.properties")).forEach((id, resource) -> { + try (InputStream stream = resource.getInputStream()) { + Properties properties = new Properties(); + properties.load(stream); - manager.findResources("optifine", path -> path.getPath().contains("color.properties")).forEach((id, resource) -> { - try (InputStream stream = resource.getInputStream()) { - Properties properties = new Properties(); - properties.load(stream); - - if (properties.get("screen.loading") != null) { - PuzzleConfig.backgroundColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading").toString()).getRGB(); - PuzzleConfig.hasCustomSplashScreen = true; - } - if (properties.get("screen.loading.bar") != null) { - PuzzleConfig.progressBarBackgroundColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading.bar").toString()).getRGB(); - PuzzleConfig.hasCustomSplashScreen = true; - } - if (properties.get("screen.loading.progress") != null) { - PuzzleConfig.progressBarColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading.progress").toString()).getRGB(); - PuzzleConfig.hasCustomSplashScreen = true; - } - if (properties.get("screen.loading.outline") != null) { - PuzzleConfig.progressFrameColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading.outline").toString()).getRGB(); - PuzzleConfig.hasCustomSplashScreen = true; - } - if (properties.get("screen.loading.blend") != null) { - // Recommended blend: SRC_ALPHA ONE_MINUS_SRC_ALPHA ONE ZERO - PuzzleConfig.disableBlend = properties.get("screen.loading.blend").toString().equals("off"); - PuzzleConfig.customBlendFunction = new ArrayList<>(Arrays.stream(properties.get("screen.loading.blend").toString().split(" ")).toList()); - PuzzleConfig.hasCustomSplashScreen = true; - } - - } catch (Exception e) { - LOGGER.error("Error occurred while loading color.properties {}", id.toString(), e); - } - }); - AtomicInteger logoCount = new AtomicInteger(); - manager.findResources("textures", path -> path.getPath().contains("mojangstudios.png")).forEach((id, resource) -> { - try (InputStream stream = resource.getInputStream()) { - Files.copy(stream, LOGO_TEXTURE, StandardCopyOption.REPLACE_EXISTING); - client.getTextureManager().registerTexture(LOGO, new DynamicLogoTexture()); - if (logoCount.get() > 0) PuzzleConfig.hasCustomSplashScreen = true; - logoCount.getAndIncrement(); - } catch (Exception e) { - LOGGER.error("Error occurred while loading custom minecraft logo {}", id.toString(), e); - } - }); - manager.findResources(MOD_ID, path -> path.getPath().contains("splash_background.png")).forEach((id, resource) -> { - try (InputStream stream = resource.getInputStream()) { - Files.copy(stream, BACKGROUND_TEXTURE, StandardCopyOption.REPLACE_EXISTING); - InputStream input = new FileInputStream(String.valueOf(PuzzleSplashScreen.BACKGROUND_TEXTURE)); - client.getTextureManager().registerTexture(BACKGROUND, new NativeImageBackedTexture(() -> "splash_screen_background", NativeImage.read(input))); - keepBackground = true; + if (properties.get("screen.loading") != null) { + PuzzleConfig.backgroundColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading").toString()).getRGB(); PuzzleConfig.hasCustomSplashScreen = true; - } catch (Exception e) { - LOGGER.error("Error occurred while loading custom splash background {}", id.toString(), e); } - }); - if (!keepBackground) { - try { - Files.delete(BACKGROUND_TEXTURE); - } catch (Exception ignored) {} + if (properties.get("screen.loading.bar") != null) { + PuzzleConfig.progressBarBackgroundColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading.bar").toString()).getRGB(); + PuzzleConfig.hasCustomSplashScreen = true; + } + if (properties.get("screen.loading.progress") != null) { + PuzzleConfig.progressBarColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading.progress").toString()).getRGB(); + PuzzleConfig.hasCustomSplashScreen = true; + } + if (properties.get("screen.loading.outline") != null) { + PuzzleConfig.progressFrameColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading.outline").toString()).getRGB(); + PuzzleConfig.hasCustomSplashScreen = true; + } + if (properties.get("screen.loading.blend") != null) { + // Recommended blend: SRC_ALPHA ONE_MINUS_SRC_ALPHA ONE ZERO + PuzzleConfig.disableBlend = properties.get("screen.loading.blend").toString().equals("off"); + PuzzleConfig.customBlendFunction = new ArrayList<>(Arrays.stream(properties.get("screen.loading.blend").toString().split(" ")).toList()); + PuzzleConfig.hasCustomSplashScreen = true; + } + + } catch (Exception e) { + getLogger().error("Error occurred while loading color.properties {}", id.toString(), e); + } + }); + AtomicInteger logoCount = new AtomicInteger(); + manager.findResources("textures", path -> path.getPath().contains("mojangstudios.png")).forEach((id, resource) -> { + try (InputStream stream = resource.getInputStream()) { + Files.copy(stream, LOGO_TEXTURE, StandardCopyOption.REPLACE_EXISTING); + client.getTextureManager().registerTexture(LOGO, new DynamicLogoTexture()); + if (logoCount.get() > 0) PuzzleConfig.hasCustomSplashScreen = true; + logoCount.getAndIncrement(); + } catch (Exception e) { + getLogger().error("Error occurred while loading custom minecraft logo {}", id.toString(), e); + } + }); + manager.findResources(MOD_ID, path -> path.getPath().contains("splash_background.png")).forEach((id, resource) -> { + try (InputStream stream = resource.getInputStream()) { + Files.copy(stream, BACKGROUND_TEXTURE, StandardCopyOption.REPLACE_EXISTING); + InputStream input = new FileInputStream(String.valueOf(PuzzleSplashScreen.BACKGROUND_TEXTURE)); + client.getTextureManager().registerTexture(BACKGROUND, new NativeImageBackedTexture(() -> "splash_screen_background", NativeImage.read(input))); + keepBackground = true; + PuzzleConfig.hasCustomSplashScreen = true; + } catch (Exception e) { + getLogger().error("Error occurred while loading custom splash background {}", id.toString(), e); + } + }); + if (!keepBackground) { + try { + Files.delete(BACKGROUND_TEXTURE); + } catch (Exception ignored) { } - keepBackground = false; - PuzzleConfig.write(MOD_ID); - buildRenderLayer(); } + keepBackground = false; + PuzzleConfig.write(MOD_ID); + buildRenderLayer(); } } @@ -215,7 +215,7 @@ public class PuzzleSplashScreen { InputStream input = new FileInputStream(String.valueOf(PuzzleSplashScreen.LOGO_TEXTURE)); return new TextureContents(NativeImage.read(input), new TextureResourceMetadata(true, true)); } catch (IOException e) { - LOGGER.error("Encountered an error during logo loading: ", e); + INSTANCE.getLogger().error("Encountered an error during logo loading: ", e); try { return TextureContents.load(resourceManager, LOGO); } catch (IOException ex) { diff --git a/common/src/main/resources/puzzle-predicates.mixins.json b/common/src/main/resources/puzzle-predicates.mixins.json new file mode 100644 index 0000000..f9df3da --- /dev/null +++ b/common/src/main/resources/puzzle-predicates.mixins.json @@ -0,0 +1,24 @@ +{ + "required": true, + "package": "net.puzzlemc.predicates.mixin", + "compatibilityLevel": "JAVA_17", + "client": [ + "BakedModelManagerMixin", + "BlockDisplayEntityRendererMixin", + "BlockDustParticleMixin", + "BlockMarkerParticleMixin", + "BlockModelRendererMixin", + "BlockRenderManagerMixin", + "FallingBlockEntityRendererMixin", + "ItemEntityRendererMixin", + "ItemFrameEntityRendererMixin", + "ItemRendererMixin", + "PistonBlockEntityRendererMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "mixins": [ + "StateAccessor" + ] +} diff --git a/common/src/main/resources/puzzle-predicates_compat.mixins.json b/common/src/main/resources/puzzle-predicates_compat.mixins.json new file mode 100644 index 0000000..b1f6840 --- /dev/null +++ b/common/src/main/resources/puzzle-predicates_compat.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "package": "net.puzzlemc.predicates.mixin.compat", + "compatibilityLevel": "JAVA_17", + "plugin": "net.puzzlemc.core.mixin.PuzzleMixinPlugin", + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/fabric/src/main/java/net/puzzlemc/fabric/MBPModelLoadingPlugin.java b/fabric/src/main/java/net/puzzlemc/fabric/MBPModelLoadingPlugin.java new file mode 100644 index 0000000..8c1288b --- /dev/null +++ b/fabric/src/main/java/net/puzzlemc/fabric/MBPModelLoadingPlugin.java @@ -0,0 +1,68 @@ +package net.puzzlemc.fabric; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin; +import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlugin; +import net.minecraft.block.Block; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +import net.puzzlemc.predicates.PuzzlePredicates; +import net.puzzlemc.predicates.data.logic.When; +import net.puzzlemc.predicates.util.Utils; + +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + + +public class MBPModelLoadingPlugin implements PreparableModelLoadingPlugin> { + + + @Override + public void initialize(HashSet data, ModelLoadingPlugin.Context pluginContext) { + //pluginContext.addModels(data); + } + + public static class ModelIdLoader implements DataLoader> { + @Override + public CompletableFuture> load(ResourceManager manager, Executor executor) { + + return CompletableFuture.supplyAsync(() -> { + HashSet wantedModels = new HashSet<>(); + + Map map = manager.findResources("mbp", id -> id.getPath().endsWith(".json")); + for (Identifier id : map.keySet()) { + + try { + Identifier blockTarget = Identifier.of(id.toString().substring(0,id.toString().length()-5).replace("mbp/", "")); + JsonObject asset = JsonParser.parseReader(map.get(id).getReader()).getAsJsonObject(); + + Optional block = Utils.getBlock(blockTarget); + + if (block.isPresent()) { + JsonArray overrides = asset.getAsJsonArray("overrides"); + PuzzlePredicates.logger().info("* Model Loader: "+blockTarget+ " " + overrides); + for(JsonElement overrideEntry : overrides) { + When when = When.parse(overrideEntry); + + wantedModels.addAll(when.getModels()); + } + } + + } catch (Exception e) { + PuzzlePredicates.logger().error("Error found in file: " + id, e); + } + } + return wantedModels; + }, executor); + + + } + } +} diff --git a/fabric/src/main/java/net/puzzlemc/fabric/PuzzleFabric.java b/fabric/src/main/java/net/puzzlemc/fabric/PuzzleFabric.java index 647504e..d436008 100644 --- a/fabric/src/main/java/net/puzzlemc/fabric/PuzzleFabric.java +++ b/fabric/src/main/java/net/puzzlemc/fabric/PuzzleFabric.java @@ -3,16 +3,17 @@ package net.puzzlemc.fabric; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; +import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingPluginManager; import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; import net.puzzlemc.core.PuzzleCore; -import net.puzzlemc.splashscreen.PuzzleSplashScreen; public class PuzzleFabric implements ClientModInitializer { @Override public void onInitializeClient() { PuzzleCore.initModules(); + ModelLoadingPluginManager.registerPlugin(new MBPModelLoadingPlugin.ModelIdLoader(), new MBPModelLoadingPlugin()); ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() { @Override @@ -21,7 +22,7 @@ public class PuzzleFabric implements ClientModInitializer { } @Override public void reload(ResourceManager manager) { - PuzzleSplashScreen.ReloadListener.INSTANCE.reload(manager); + PuzzleCore.PuzzleResourceManager.INSTANCE.reload(manager); } }); } diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 90303f9..a1a16a8 100755 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -32,7 +32,9 @@ "mixins": [ "puzzle-gui.mixins.json", "puzzle-models.mixins.json", - "puzzle-splashscreen.mixins.json" + "puzzle-splashscreen.mixins.json", + "puzzle-predicates.mixins.json", + "puzzle-predicates_compat.mixins.json" ], "depends": {