1 Commits

Author SHA1 Message Date
Martin Prokoph
97117ea46a port: Chase the Skies (1.21.6) 2025-06-17 19:44:15 +02:00
50 changed files with 126 additions and 1805 deletions

View File

@@ -1,32 +1,18 @@
package net.puzzlemc.core; package net.puzzlemc.core;
import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.SynchronousResourceReloader;
import net.puzzlemc.core.config.PuzzleConfig; import net.puzzlemc.core.config.PuzzleConfig;
import net.puzzlemc.gui.PuzzleGui; import net.puzzlemc.gui.PuzzleGui;
import net.puzzlemc.predicates.PuzzlePredicates;
import net.puzzlemc.splashscreen.PuzzleSplashScreen; import net.puzzlemc.splashscreen.PuzzleSplashScreen;
import org.slf4j.Logger;
import java.util.ArrayList; import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.List;
public class PuzzleCore { public class PuzzleCore {
public final static String MOD_ID = "puzzle"; public final static String MOD_ID = "puzzle";
private static final List<PuzzleModule> MODULES = new ArrayList<>(); public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
public static void initModules() { public static void initModules() {
PuzzleConfig.init(MOD_ID, PuzzleConfig.class); PuzzleConfig.init(MOD_ID, PuzzleConfig.class);
Collections.addAll(MODULES, PuzzleGui.INSTANCE, PuzzleSplashScreen.INSTANCE, PuzzlePredicates.INSTANCE); PuzzleGui.init();
PuzzleSplashScreen.init();
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

@@ -1,13 +0,0 @@
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

@@ -1,50 +0,0 @@
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,6 +6,8 @@ import net.puzzlemc.gui.screen.widget.PuzzleWidget;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static net.puzzlemc.core.PuzzleCore.LOGGER;
public class PuzzleApi { public class PuzzleApi {
public static List<PuzzleWidget> GRAPHICS_OPTIONS = new ArrayList<>(); public static List<PuzzleWidget> GRAPHICS_OPTIONS = new ArrayList<>();
public static List<PuzzleWidget> MISC_OPTIONS = new ArrayList<>(); public static List<PuzzleWidget> MISC_OPTIONS = new ArrayList<>();
@@ -15,21 +17,21 @@ public class PuzzleApi {
public static void addToGraphicsOptions(PuzzleWidget button) { public static void addToGraphicsOptions(PuzzleWidget button) {
GRAPHICS_OPTIONS.add(button); GRAPHICS_OPTIONS.add(button);
if (PuzzleConfig.debugMessages) if (PuzzleConfig.debugMessages)
PuzzleGui.logger().info("{} -> Graphics Options", button.descriptionText.getContent().toString()); LOGGER.info("{} -> Graphics Options", button.descriptionText.getContent().toString());
} }
public static void addToMiscOptions(PuzzleWidget button) { public static void addToMiscOptions(PuzzleWidget button) {
MISC_OPTIONS.add(button); MISC_OPTIONS.add(button);
if (PuzzleConfig.debugMessages) if (PuzzleConfig.debugMessages)
PuzzleGui.logger().info("{} -> Misc Options", button.descriptionText.getContent().toString()); LOGGER.info("{} -> Misc Options", button.descriptionText.getContent().toString());
} }
public static void addToPerformanceOptions(PuzzleWidget button) { public static void addToPerformanceOptions(PuzzleWidget button) {
PERFORMANCE_OPTIONS.add(button); PERFORMANCE_OPTIONS.add(button);
if (PuzzleConfig.debugMessages) if (PuzzleConfig.debugMessages)
PuzzleGui.logger().info("{}- > Performance Options", button.descriptionText.getContent().toString()); LOGGER.info("{}- > Performance Options", button.descriptionText.getContent().toString());
} }
public static void addToResourceOptions(PuzzleWidget button) { public static void addToResourceOptions(PuzzleWidget button) {
RESOURCE_OPTIONS.add(button); RESOURCE_OPTIONS.add(button);
if (PuzzleConfig.debugMessages) if (PuzzleConfig.debugMessages)
PuzzleGui.logger().info("{} -> Resource Options", button.descriptionText.getContent().toString()); LOGGER.info("{} -> Resource Options", button.descriptionText.getContent().toString());
} }
} }

View File

@@ -3,7 +3,6 @@ package net.puzzlemc.gui;
import eu.midnightdust.core.MidnightLib; import eu.midnightdust.core.MidnightLib;
import eu.midnightdust.lib.util.PlatformFunctions; import eu.midnightdust.lib.util.PlatformFunctions;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.puzzlemc.core.PuzzleModule;
import net.puzzlemc.core.config.PuzzleConfig; import net.puzzlemc.core.config.PuzzleConfig;
import net.puzzlemc.gui.compat.*; import net.puzzlemc.gui.compat.*;
import net.puzzlemc.gui.screen.widget.PuzzleWidget; import net.puzzlemc.gui.screen.widget.PuzzleWidget;
@@ -11,22 +10,16 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import net.puzzlemc.splashscreen.PuzzleSplashScreen; import net.puzzlemc.splashscreen.PuzzleSplashScreen;
import org.slf4j.Logger;
public class PuzzleGui implements PuzzleModule { import static net.puzzlemc.core.PuzzleCore.LOGGER;
public static final PuzzleGui INSTANCE = new PuzzleGui();
public class PuzzleGui {
public final static String id = "puzzle"; public final static String id = "puzzle";
public static final Text YES = Text.translatable("gui.yes").formatted(Formatting.GREEN); 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 Text NO = Text.translatable("gui.no").formatted(Formatting.RED);
public static final Identifier PUZZLE_BUTTON = Identifier.of(id, "icon/button"); public static final Identifier PUZZLE_BUTTON = Identifier.of(id, "icon/button");
@Override public static void init() {
public String getModuleId() {
return "gui";
}
@Override
public void init() {
MidnightLib.hiddenMods.add("puzzle"); MidnightLib.hiddenMods.add("puzzle");
PuzzleApi.addToMiscOptions(new PuzzleWidget(Text.of("\uD83E\uDDE9 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) -> { PuzzleApi.addToMiscOptions(new PuzzleWidget(Text.translatable("puzzle.midnightconfig.title"), (button) -> button.setMessage(Text.of("OPEN")), (button) -> {
@@ -63,7 +56,7 @@ public class PuzzleGui implements PuzzleModule {
if (isActive("entity_texture_features")) ETFCompat.init(); if (isActive("entity_texture_features")) ETFCompat.init();
if (isActive("entity_model_features")) EMFCompat.init(); if (isActive("entity_model_features")) EMFCompat.init();
} catch (Exception e) { } catch (Exception e) {
INSTANCE.getLogger().error("ETF/EMF config structure changed. Again...", e); LOGGER.error("ETF/EMF config structure changed. Again...", e);
} }
lateInitDone = true; lateInitDone = true;
@@ -71,7 +64,4 @@ public class PuzzleGui implements PuzzleModule {
public static boolean isActive(String modid) { public static boolean isActive(String modid) {
return PlatformFunctions.isModLoaded(modid) && !PuzzleConfig.disabledIntegrations.contains(modid); return PlatformFunctions.isModLoaded(modid) && !PuzzleConfig.disabledIntegrations.contains(modid);
} }
public static Logger logger() {
return INSTANCE.getLogger();
}
} }

View File

@@ -11,13 +11,14 @@ import net.minecraft.client.resource.language.I18n;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent; import net.minecraft.text.TranslatableTextContent;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import net.puzzlemc.gui.PuzzleGui;
import net.puzzlemc.gui.screen.PuzzleOptionsScreen; import net.puzzlemc.gui.screen.PuzzleOptionsScreen;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static net.puzzlemc.core.PuzzleCore.LOGGER;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public class PuzzleOptionListWidget extends MidnightConfig.MidnightConfigListWidget { public class PuzzleOptionListWidget extends MidnightConfig.MidnightConfigListWidget {
TextRenderer textRenderer; TextRenderer textRenderer;
@@ -41,10 +42,10 @@ public class PuzzleOptionListWidget extends MidnightConfig.MidnightConfigListWid
else if (button.buttonType == ButtonType.TEXT_FIELD) else if (button.buttonType == ButtonType.TEXT_FIELD)
this.addButton(List.of(new PuzzleTextFieldWidget(textRenderer, buttonX, 0, 150, 20, button.setTextValue, button.changeTextValue)), button.descriptionText); this.addButton(List.of(new PuzzleTextFieldWidget(textRenderer, buttonX, 0, 150, 20, button.setTextValue, button.changeTextValue)), button.descriptionText);
else else
PuzzleGui.logger().warn("Button {} is missing the buttonType variable. This shouldn't happen!", button); LOGGER.warn("Button {} is missing the buttonType variable. This shouldn't happen!", button);
} }
catch (Exception e) { catch (Exception e) {
PuzzleGui.logger().error("Failed to add button {}. Likely caused by an update of the specific mod.", button.descriptionText); LOGGER.error("Failed to add button {}. Likely caused by an update of the specific mod.", button.descriptionText);
} }
} }
@@ -56,6 +57,7 @@ public class PuzzleOptionListWidget extends MidnightConfig.MidnightConfigListWid
public boolean centered() {return true;} public boolean centered() {return true;}
public String category() {return "";} public String category() {return "";}
public String name() {return "";} public String name() {return "";}
public String url() {return "";}
public String requiredMod() {return "";} public String requiredMod() {return "";}
}; };
var entry = new MidnightConfig.ButtonEntry(buttons, text, info); var entry = new MidnightConfig.ButtonEntry(buttons, text, info);

View File

@@ -1,14 +0,0 @@
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

@@ -1,29 +0,0 @@
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

@@ -1,68 +0,0 @@
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

@@ -1,73 +0,0 @@
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

@@ -1,12 +0,0 @@
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

@@ -1,13 +0,0 @@
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

@@ -1,36 +0,0 @@
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

@@ -1,16 +0,0 @@
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

@@ -1,63 +0,0 @@
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

@@ -1,33 +0,0 @@
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

@@ -1,10 +0,0 @@
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

@@ -1,50 +0,0 @@
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

@@ -1,35 +0,0 @@
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

@@ -1,30 +0,0 @@
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

@@ -1,68 +0,0 @@
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

@@ -1,27 +0,0 @@
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

@@ -1,39 +0,0 @@
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

@@ -1,32 +0,0 @@
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

@@ -1,26 +0,0 @@
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

@@ -1,39 +0,0 @@
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

@@ -1,71 +0,0 @@
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

@@ -1,60 +0,0 @@
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

@@ -1,24 +0,0 @@
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

@@ -1,40 +0,0 @@
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

@@ -1,41 +0,0 @@
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

@@ -1,47 +0,0 @@
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

@@ -1,99 +0,0 @@
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

@@ -1,48 +0,0 @@
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

@@ -1,21 +0,0 @@
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

@@ -1,22 +0,0 @@
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

@@ -1,73 +0,0 @@
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

@@ -1,50 +0,0 @@
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

@@ -1,17 +0,0 @@
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

@@ -1,40 +0,0 @@
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

@@ -1,65 +0,0 @@
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

@@ -1,50 +0,0 @@
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

@@ -7,15 +7,10 @@ import com.mojang.blaze3d.platform.DestFactor;
import com.mojang.blaze3d.platform.SourceFactor; import com.mojang.blaze3d.platform.SourceFactor;
import eu.midnightdust.lib.util.MidnightColorUtil; import eu.midnightdust.lib.util.MidnightColorUtil;
import eu.midnightdust.lib.util.PlatformFunctions; import eu.midnightdust.lib.util.PlatformFunctions;
import net.minecraft.client.gui.screen.SplashOverlay;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.RenderPhase;
import net.minecraft.client.texture.NativeImageBackedTexture; import net.minecraft.client.texture.NativeImageBackedTexture;
import net.minecraft.client.texture.TextureContents; import net.minecraft.client.texture.TextureContents;
import net.minecraft.resource.*; import net.minecraft.resource.*;
import net.minecraft.util.TriState;
import net.minecraft.util.Util; import net.minecraft.util.Util;
import net.puzzlemc.core.PuzzleModule;
import net.puzzlemc.core.config.PuzzleConfig; import net.puzzlemc.core.config.PuzzleConfig;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.resource.metadata.TextureResourceMetadata; import net.minecraft.client.resource.metadata.TextureResourceMetadata;
@@ -35,10 +30,10 @@ import java.nio.file.StandardCopyOption;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static net.puzzlemc.core.PuzzleCore.LOGGER;
import static net.puzzlemc.core.PuzzleCore.MOD_ID; import static net.puzzlemc.core.PuzzleCore.MOD_ID;
public class PuzzleSplashScreen implements PuzzleModule { public class PuzzleSplashScreen {
public static final PuzzleSplashScreen INSTANCE = new PuzzleSplashScreen();
public static final Identifier LOGO = Identifier.of("textures/gui/title/mojangstudios.png"); 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 final Identifier BACKGROUND = Identifier.of("puzzle/splash_background.png");
public static File CONFIG_PATH = new File(String.valueOf(PlatformFunctions.getConfigDirectory().resolve(".puzzle_cache"))); public static File CONFIG_PATH = new File(String.valueOf(PlatformFunctions.getConfigDirectory().resolve(".puzzle_cache")));
@@ -46,28 +41,25 @@ public class PuzzleSplashScreen implements PuzzleModule {
public static Path BACKGROUND_TEXTURE = Paths.get(CONFIG_PATH + "/splash_background.png"); public static Path BACKGROUND_TEXTURE = Paths.get(CONFIG_PATH + "/splash_background.png");
private static MinecraftClient client = MinecraftClient.getInstance(); private static MinecraftClient client = MinecraftClient.getInstance();
private static boolean keepBackground = false; private static boolean keepBackground = false;
private static RenderLayer CUSTOM_LOGO_LAYER; private static RenderPipeline CUSTOM_LOGO_PIPELINE;
@Override public static void init() {
public String getModuleId() { if (!CONFIG_PATH.exists()) { // Run when config directory is nonexistent //
return "splashscreen"; if (CONFIG_PATH.mkdir()) { // Create our custom config directory //
} if (Util.getOperatingSystem().equals(Util.OperatingSystem.WINDOWS)) {
@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); try { Files.setAttribute(CONFIG_PATH.toPath(), "dos:hidden", true);
} catch (IOException ignored) {} } catch (IOException ignored) {}
} }
}
}
buildRenderLayer(); buildRenderLayer();
} }
public static RenderLayer getCustomLogoRenderLayer() { public static RenderPipeline getCustomLogoRenderPipeline() {
return CUSTOM_LOGO_LAYER; return CUSTOM_LOGO_PIPELINE;
} }
public void buildRenderLayer() { public static void buildRenderLayer() {
if (PuzzleConfig.resourcepackSplashScreen) { if (PuzzleConfig.resourcepackSplashScreen) {
BlendFunction blendFunction = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE); BlendFunction blendFunction = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE);
if (PuzzleConfig.disableBlend) blendFunction = null; if (PuzzleConfig.disableBlend) blendFunction = null;
@@ -79,7 +71,7 @@ public class PuzzleSplashScreen implements PuzzleModule {
SourceFactor.valueOf(PuzzleConfig.customBlendFunction.get(2)), SourceFactor.valueOf(PuzzleConfig.customBlendFunction.get(2)),
DestFactor.valueOf(PuzzleConfig.customBlendFunction.get(3))); DestFactor.valueOf(PuzzleConfig.customBlendFunction.get(3)));
} catch (Exception e) { } catch (Exception e) {
getLogger().error("Incorrect blend function defined in color.properties: {}{}", PuzzleConfig.customBlendFunction, e.getMessage()); LOGGER.error("Incorrect blend function defined in color.properties: {}{}", PuzzleConfig.customBlendFunction, e.getMessage());
} }
} }
@@ -89,16 +81,17 @@ public class PuzzleSplashScreen implements PuzzleModule {
.withDepthWrite(false); .withDepthWrite(false);
CUSTOM_LOGO_PIPELINE_BUILDER = blendFunction != null ? CUSTOM_LOGO_PIPELINE_BUILDER.withBlend(blendFunction) : CUSTOM_LOGO_PIPELINE_BUILDER.withoutBlend(); CUSTOM_LOGO_PIPELINE_BUILDER = blendFunction != null ? CUSTOM_LOGO_PIPELINE_BUILDER.withBlend(blendFunction) : CUSTOM_LOGO_PIPELINE_BUILDER.withoutBlend();
CUSTOM_LOGO_LAYER = RenderLayer.of("mojang_logo_puzzle", 786432, CUSTOM_LOGO_PIPELINE_BUILDER.build(), CUSTOM_LOGO_PIPELINE = CUSTOM_LOGO_PIPELINE_BUILDER.build();
RenderLayer.MultiPhaseParameters.builder()
.texture(new RenderPhase.Texture(SplashOverlay.LOGO, TriState.DEFAULT, false))
.build(false));
} }
} }
public static class ReloadListener implements SynchronousResourceReloader {
public static final ReloadListener INSTANCE = new ReloadListener();
private ReloadListener() {}
@Override @Override
public void reloadResources(ResourceManager manager) { public void reload(ResourceManager manager) {
client = MinecraftClient.getInstance(); client = MinecraftClient.getInstance();
if (PuzzleConfig.resourcepackSplashScreen) { if (PuzzleConfig.resourcepackSplashScreen) {
PuzzleSplashScreen.resetColors(); PuzzleSplashScreen.resetColors();
@@ -134,7 +127,7 @@ public class PuzzleSplashScreen implements PuzzleModule {
} }
} catch (Exception e) { } catch (Exception e) {
getLogger().error("Error occurred while loading color.properties {}", id.toString(), e); LOGGER.error("Error occurred while loading color.properties {}", id.toString(), e);
} }
}); });
AtomicInteger logoCount = new AtomicInteger(); AtomicInteger logoCount = new AtomicInteger();
@@ -145,7 +138,7 @@ public class PuzzleSplashScreen implements PuzzleModule {
if (logoCount.get() > 0) PuzzleConfig.hasCustomSplashScreen = true; if (logoCount.get() > 0) PuzzleConfig.hasCustomSplashScreen = true;
logoCount.getAndIncrement(); logoCount.getAndIncrement();
} catch (Exception e) { } catch (Exception e) {
getLogger().error("Error occurred while loading custom minecraft logo {}", id.toString(), 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) -> { manager.findResources(MOD_ID, path -> path.getPath().contains("splash_background.png")).forEach((id, resource) -> {
@@ -156,20 +149,20 @@ public class PuzzleSplashScreen implements PuzzleModule {
keepBackground = true; keepBackground = true;
PuzzleConfig.hasCustomSplashScreen = true; PuzzleConfig.hasCustomSplashScreen = true;
} catch (Exception e) { } catch (Exception e) {
getLogger().error("Error occurred while loading custom splash background {}", id.toString(), e); LOGGER.error("Error occurred while loading custom splash background {}", id.toString(), e);
} }
}); });
if (!keepBackground) { if (!keepBackground) {
try { try {
Files.delete(BACKGROUND_TEXTURE); Files.delete(BACKGROUND_TEXTURE);
} catch (Exception ignored) { } catch (Exception ignored) {}
}
} }
keepBackground = false; keepBackground = false;
PuzzleConfig.write(MOD_ID); PuzzleConfig.write(MOD_ID);
buildRenderLayer(); buildRenderLayer();
} }
} }
}
public static void resetColors() { public static void resetColors() {
PuzzleConfig.backgroundColor = 15675965; PuzzleConfig.backgroundColor = 15675965;
@@ -215,7 +208,7 @@ public class PuzzleSplashScreen implements PuzzleModule {
InputStream input = new FileInputStream(String.valueOf(PuzzleSplashScreen.LOGO_TEXTURE)); InputStream input = new FileInputStream(String.valueOf(PuzzleSplashScreen.LOGO_TEXTURE));
return new TextureContents(NativeImage.read(input), new TextureResourceMetadata(true, true)); return new TextureContents(NativeImage.read(input), new TextureResourceMetadata(true, true));
} catch (IOException e) { } catch (IOException e) {
INSTANCE.getLogger().error("Encountered an error during logo loading: ", e); LOGGER.error("Encountered an error during logo loading: ", e);
try { try {
return TextureContents.load(resourceManager, LOGO); return TextureContents.load(resourceManager, LOGO);
} catch (IOException ex) { } catch (IOException ex) {

View File

@@ -2,11 +2,12 @@ package net.puzzlemc.splashscreen.mixin;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.RenderPipelines;
import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Overlay; import net.minecraft.client.gui.screen.Overlay;
import net.minecraft.client.gui.screen.SplashOverlay; import net.minecraft.client.gui.screen.SplashOverlay;
import net.minecraft.client.render.*;
import net.minecraft.client.texture.NativeImage; import net.minecraft.client.texture.NativeImage;
import net.minecraft.client.texture.NativeImageBackedTexture; import net.minecraft.client.texture.NativeImageBackedTexture;
import net.minecraft.client.texture.TextureManager; import net.minecraft.client.texture.TextureManager;
@@ -26,7 +27,6 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.function.Function;
import java.util.function.IntSupplier; import java.util.function.IntSupplier;
import static net.puzzlemc.splashscreen.PuzzleSplashScreen.BACKGROUND; import static net.puzzlemc.splashscreen.PuzzleSplashScreen.BACKGROUND;
@@ -63,11 +63,11 @@ public abstract class MixinSplashScreen extends Overlay {
return (!PuzzleConfig.resourcepackSplashScreen || PuzzleConfig.progressBarBackgroundColor == 15675965) ? instance.getAsInt() : PuzzleConfig.backgroundColor | 255 << 24; return (!PuzzleConfig.resourcepackSplashScreen || PuzzleConfig.progressBarBackgroundColor == 15675965) ? instance.getAsInt() : PuzzleConfig.backgroundColor | 255 << 24;
} }
@WrapOperation(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTexture(Ljava/util/function/Function;Lnet/minecraft/util/Identifier;IIFFIIIIIII)V")) @WrapOperation(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTexture(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/util/Identifier;IIFFIIIIIII)V"))
private void puzzle$modifyRenderLayer(DrawContext instance, Function<Identifier, RenderLayer> renderLayers, Identifier sprite, int x, int y, float u, float v, int width, int height, int regionWidth, int regionHeight, int textureWidth, int textureHeight, int color, Operation<Void> original) { private void puzzle$modifyRenderLayer(DrawContext instance, RenderPipeline pipeline, Identifier sprite, int x, int y, float u, float v, int width, int height, int regionWidth, int regionHeight, int textureWidth, int textureHeight, int color, Operation<Void> original) {
if (PuzzleConfig.resourcepackSplashScreen) if (PuzzleConfig.resourcepackSplashScreen)
instance.drawTexture(id -> PuzzleSplashScreen.getCustomLogoRenderLayer(), sprite, x, y, u, v, width, height, regionWidth, regionHeight, textureWidth, textureHeight, color); instance.drawTexture(PuzzleSplashScreen.getCustomLogoRenderPipeline(), sprite, x, y, u, v, width, height, regionWidth, regionHeight, textureWidth, textureHeight, color);
else instance.drawTexture(renderLayers, sprite, x, y, u, v, width, height, textureWidth, textureHeight, color); else instance.drawTexture(pipeline, sprite, x, y, u, v, width, height, textureWidth, textureHeight, color);
} }
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;getScaledWindowWidth()I", ordinal = 2)) @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;getScaledWindowWidth()I", ordinal = 2))
@@ -82,14 +82,12 @@ public abstract class MixinSplashScreen extends Overlay {
if (f >= 1.0F) s = 1.0F - MathHelper.clamp(f - 1.0F, 0.0F, 1.0F); if (f >= 1.0F) s = 1.0F - MathHelper.clamp(f - 1.0F, 0.0F, 1.0F);
else if (reloading) s = MathHelper.clamp(g, 0.0F, 1.0F); else if (reloading) s = MathHelper.clamp(g, 0.0F, 1.0F);
else s = 1.0F; else s = 1.0F;
context.getMatrices().translate(0, 0, 1f); context.drawTexture(RenderPipelines.GUI_TEXTURED, BACKGROUND, 0, 0, 0, 0, width, height, width, height, ColorHelper.getWhite(s));
context.drawTexture(RenderLayer::getGuiTextured, BACKGROUND, 0, 0, 0, 0, width, height, width, height, ColorHelper.getWhite(s));
} }
} }
@Inject(method = "renderProgressBar", at = @At("HEAD")) @Inject(method = "renderProgressBar", at = @At("HEAD"))
private void puzzle$addProgressBarBackground(DrawContext context, int minX, int minY, int maxX, int maxY, float opacity, CallbackInfo ci) { private void puzzle$addProgressBarBackground(DrawContext context, int minX, int minY, int maxX, int maxY, float opacity, CallbackInfo ci) {
context.getMatrices().translate(0, 0, 1f);
if (!PuzzleConfig.resourcepackSplashScreen || PuzzleConfig.progressBarBackgroundColor == 15675965) return; if (!PuzzleConfig.resourcepackSplashScreen || PuzzleConfig.progressBarBackgroundColor == 15675965) return;
long l = Util.getMeasuringTimeMs(); long l = Util.getMeasuringTimeMs();
float f = this.reloadCompleteTime > -1L ? (float)(l - this.reloadCompleteTime) / 1000.0F : -1.0F; float f = this.reloadCompleteTime > -1L ? (float)(l - this.reloadCompleteTime) / 1000.0F : -1.0F;

View File

@@ -1,24 +0,0 @@
{
"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

@@ -1,11 +0,0 @@
{
"required": true,
"package": "net.puzzlemc.predicates.mixin.compat",
"compatibilityLevel": "JAVA_17",
"plugin": "net.puzzlemc.core.mixin.PuzzleMixinPlugin",
"client": [
],
"injectors": {
"defaultRequire": 1
}
}

View File

@@ -1,68 +0,0 @@
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,17 +3,16 @@ package net.puzzlemc.fabric;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; 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.ResourceManager;
import net.minecraft.resource.ResourceType; import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.puzzlemc.core.PuzzleCore; import net.puzzlemc.core.PuzzleCore;
import net.puzzlemc.splashscreen.PuzzleSplashScreen;
public class PuzzleFabric implements ClientModInitializer { public class PuzzleFabric implements ClientModInitializer {
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
PuzzleCore.initModules(); PuzzleCore.initModules();
ModelLoadingPluginManager.registerPlugin(new MBPModelLoadingPlugin.ModelIdLoader(), new MBPModelLoadingPlugin());
ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() { ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() {
@Override @Override
@@ -22,7 +21,7 @@ public class PuzzleFabric implements ClientModInitializer {
} }
@Override @Override
public void reload(ResourceManager manager) { public void reload(ResourceManager manager) {
PuzzleCore.PuzzleResourceManager.INSTANCE.reload(manager); PuzzleSplashScreen.ReloadListener.INSTANCE.reload(manager);
} }
}); });
} }

View File

@@ -32,9 +32,7 @@
"mixins": [ "mixins": [
"puzzle-gui.mixins.json", "puzzle-gui.mixins.json",
"puzzle-models.mixins.json", "puzzle-models.mixins.json",
"puzzle-splashscreen.mixins.json", "puzzle-splashscreen.mixins.json"
"puzzle-predicates.mixins.json",
"puzzle-predicates_compat.mixins.json"
], ],
"depends": { "depends": {

View File

@@ -1,13 +1,13 @@
# Done to increase the memory available to gradle. # Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx2G org.gradle.jvmargs=-Xmx2G
minecraft_version=1.21.5 minecraft_version=1.21.6
supported_versions= supported_versions=
yarn_mappings=1.21.5+build.1 yarn_mappings=1.21.6+build.1
enabled_platforms=fabric,neoforge enabled_platforms=fabric,neoforge
# Mod Properties # Mod Properties
mod_version = 2.1.0 mod_version = 2.1.1
maven_group = net.puzzlemc maven_group = net.puzzlemc
archives_base_name = puzzle archives_base_name = puzzle
release_type=release release_type=release
@@ -15,15 +15,15 @@ curseforge_id=563977
modrinth_id=3IuO68q1 modrinth_id=3IuO68q1
# Modloaders # Modloaders
fabric_loader_version=0.16.10 fabric_loader_version=0.16.14
fabric_api_version=0.119.5+1.21.5 fabric_api_version=0.127.0+1.21.6
neoforge_version=21.5.3-beta neoforge_version=21.6.0-beta
yarn_mappings_patch_neoforge_version = 1.21+build.4 yarn_mappings_patch_neoforge_version = 1.21+build.4
# Libraries # Libraries
midnightlib_version = 1.7.0+1.21.4 midnightlib_version = 1.7.4+1.21.6
modmenu_version = 13.0.0-beta.1 modmenu_version = 15.0.0-beta.1
# Mod Integrations # Mod Integrations
cull_leaves_version = 3.0.2-fabric cull_leaves_version = 3.0.2-fabric