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": {