feat: integrate MBP – Part I

I received permission from the author of MoreBlockPredicates to integrate their mod's functionality into Puzzle. Thanks again :)

This is far from ready yet. The MBP codebase is stuck on 1.20.1 and only for Fabric, so I'm basically porting it to 1.21.5 and multiloader at the same time. (There have been LOTS of changes related to block models, too)
This commit is contained in:
Martin Prokoph
2025-06-17 19:23:29 +02:00
parent ee274fcefd
commit 99a450e395
48 changed files with 1776 additions and 105 deletions

View File

@@ -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<PuzzleModule> 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));
}
}
}

View File

@@ -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());}
}

View File

@@ -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<String> myTargets, Set<String> otherTargets) {
}
@Override
public List<String> 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) {
}
}

View File

@@ -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<PuzzleWidget> GRAPHICS_OPTIONS = new ArrayList<>();
public static List<PuzzleWidget> 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());
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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<BlockState>) ((StateAccessor<?, ?>)baseState).getCodec());
this.overrideId = overrideId;
}
}

View File

@@ -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<Block, List<When>> PREDICATES = new HashMap<>();
public static Optional<BlockStateOverride> 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();
}
}

View File

@@ -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<String> myTargets, Set<String> otherTargets) {
}
@Override
public List<String> 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) {
}
}

View File

@@ -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<Identifier, Resource> 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> block = Utils.getBlock(blockTarget);
if (block.isPresent()) {
JsonArray overrides = asset.getAsJsonArray("overrides");
List<When> 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();
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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<BlockStateOverride> 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;
}
}

View File

@@ -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");
}

View File

@@ -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<String, Function<JsonElement, BlockModelPredicate>> 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<BlockModelPredicate> parseFromJson(JsonElement element) {
ArrayList<JsonObject> objects = new ArrayList<>();
if (element.isJsonArray()) {
JsonArray arr = element.getAsJsonArray();
for (JsonElement obj : arr) {
objects.add(obj.getAsJsonObject());
}
} else {
objects.add(element.getAsJsonObject());
}
ArrayList<BlockModelPredicate> predicates = new ArrayList<>();
for(JsonObject curObject : objects) {
for (Map.Entry<String, JsonElement> 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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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()));
}
}

View File

@@ -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());
}
}
}

View File

@@ -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()));
}
}

View File

@@ -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));
}
}

View File

@@ -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<BlockModelPredicate> predicates;
public And(List<BlockModelPredicate> 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)));
}
}

View File

@@ -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));
}
}

View File

@@ -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<And> conditions;
public Or(List<And> 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<And> conditionsList = new ArrayList<>();
JsonArray entryArray = arg.getAsJsonArray();
for (JsonElement entry : entryArray) {
conditionsList.add(And.parse(entry));
}
return new Or(ImmutableList.copyOf(conditionsList));
}
}

View File

@@ -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<Identifier> applyModelList;
public When(And conditions, List<Identifier> 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<Identifier> getModels() {
return applyModelList;
}
public static When parse(JsonElement arg) {
JsonObject object = arg.getAsJsonObject();
List<BlockModelPredicate> conditions = BlockModelPredicate.parseFromJson(object.get("when"));
List<Identifier> 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);
}
}

View File

@@ -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<Identifier, BlockStateModel> 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<BakedModel> 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> 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);
// }
}

View File

@@ -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);
}
}

View File

@@ -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 = "<init>(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<BlockStateOverride> 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));
}
}
}

View File

@@ -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 = "<init>")
public void init(ClientWorld world, double x, double y, double z, BlockState state, CallbackInfo ci) {
Optional<BlockStateOverride> 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));
}
}
}

View File

@@ -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<BlockModelPart> parts, BlockState state, BlockPos pos, MatrixStack matrices, VertexConsumer vertexConsumer, boolean cull, int overlay, Operation<Void> 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<Void> original) {
System.out.println("c");
original.call(entry, vertexConsumer, model, red, green, blue, light, overlay);
}
}

View File

@@ -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<BlockModelPart> 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<BlockStateOverride> 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;
}
}

View File

@@ -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<BlockStateModel> original) {
Optional<BlockStateOverride> 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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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<T extends ItemFrameEntity> {
@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;
}
}

View File

@@ -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> 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);
// }
}

View File

@@ -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<BlockStateModel> original) {
Optional<BlockStateOverride> 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);
}
}
}

View File

@@ -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<O, S> {
@Accessor
Reference2ObjectArrayMap<Property<?>, Comparable<?>> getPropertyMap();
@Accessor
MapCodec<S> getCodec();
}

View File

@@ -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);
// }
}

View File

@@ -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<HashSet<Identifier>> {
//
//
// @Override
// public void onInitializeModelLoader(HashSet<Identifier> data, ModelLoadingPlugin.Context pluginContext) {
// pluginContext.addModels(data);
// }
//
// public static class ModelIdLoader implements PreparableModelLoadingPlugin.DataLoader<HashSet<Identifier>> {
// @Override
// public CompletableFuture<HashSet<Identifier>> load(ResourceManager manager, Executor executor) {
//
// return CompletableFuture.supplyAsync(() -> {
// HashSet<Identifier> wantedModels = new HashSet<>();
//
// Map<Identifier, Resource> 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> 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);
//
//
// }
// }
//}

View File

@@ -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<Optional<Registry<Biome>>> BIOME_REGISTRY = () -> {
DynamicRegistryManager drm = getRegistryManager();
if (drm != null) return drm.getOptional(RegistryKeys.BIOME);
return Optional.empty();
};
public static Optional<Biome> getBiome(Identifier biomeId) {
Optional<Registry<Biome>> registry = BIOME_REGISTRY.get();
if (registry.isPresent()) {
return registry.get().getOptionalValue(biomeId);
}
return Optional.empty();
}
public static Optional<Identifier> getBiome(Biome biome) {
Optional<Registry<Biome>> registry = BIOME_REGISTRY.get();
return registry.map(biomes -> biomes.getId(biome));
}
public static Optional<Block> getBlock(Identifier blockId) {
return Registries.BLOCK.getOptionalValue(blockId);
}
public static BlockPos posFromRenderState(EntityRenderState state) {
return BlockPos.ofFloored(state.x, state.y, state.z);
}
}

View File

@@ -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,15 +48,18 @@ 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)) {
@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,13 +96,9 @@ public class PuzzleSplashScreen {
}
}
public static class ReloadListener implements SynchronousResourceReloader {
public static final ReloadListener INSTANCE = new ReloadListener();
private ReloadListener() {}
@Override
public void reload(ResourceManager manager) {
public void reloadResources(ResourceManager manager) {
client = MinecraftClient.getInstance();
if (PuzzleConfig.resourcepackSplashScreen) {
PuzzleSplashScreen.resetColors();
@@ -134,7 +134,7 @@ public class PuzzleSplashScreen {
}
} catch (Exception e) {
LOGGER.error("Error occurred while loading color.properties {}", id.toString(), e);
getLogger().error("Error occurred while loading color.properties {}", id.toString(), e);
}
});
AtomicInteger logoCount = new AtomicInteger();
@@ -145,7 +145,7 @@ public class PuzzleSplashScreen {
if (logoCount.get() > 0) PuzzleConfig.hasCustomSplashScreen = true;
logoCount.getAndIncrement();
} catch (Exception e) {
LOGGER.error("Error occurred while loading custom minecraft logo {}", id.toString(), 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) -> {
@@ -156,20 +156,20 @@ public class PuzzleSplashScreen {
keepBackground = true;
PuzzleConfig.hasCustomSplashScreen = true;
} catch (Exception e) {
LOGGER.error("Error occurred while loading custom splash background {}", id.toString(), e);
getLogger().error("Error occurred while loading custom splash background {}", id.toString(), e);
}
});
if (!keepBackground) {
try {
Files.delete(BACKGROUND_TEXTURE);
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
}
keepBackground = false;
PuzzleConfig.write(MOD_ID);
buildRenderLayer();
}
}
}
public static void resetColors() {
PuzzleConfig.backgroundColor = 15675965;
@@ -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) {

View File

@@ -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"
]
}

View File

@@ -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
}
}

View File

@@ -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<HashSet<Identifier>> {
@Override
public void initialize(HashSet<Identifier> data, ModelLoadingPlugin.Context pluginContext) {
//pluginContext.addModels(data);
}
public static class ModelIdLoader implements DataLoader<HashSet<Identifier>> {
@Override
public CompletableFuture<HashSet<Identifier>> load(ResourceManager manager, Executor executor) {
return CompletableFuture.supplyAsync(() -> {
HashSet<Identifier> wantedModels = new HashSet<>();
Map<Identifier, Resource> 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> 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);
}
}
}

View File

@@ -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);
}
});
}

View File

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