Merge remote-tracking branch 'origin/1.19.4' into 1.20
This commit is contained in:
commit
f9cbd8fa61
|
|
@ -25,6 +25,9 @@ dependencies {
|
|||
modCompileOnly("me.shedaniel:RoughlyEnoughItems-fabric:${rei_version}") {
|
||||
transitive = false
|
||||
}
|
||||
|
||||
modCompileOnly("curse.maven:diagonal-fences-458048:${diagonal_fences_version}")
|
||||
|
||||
// compile against the JEI API but do not include it at runtime
|
||||
modCompileOnly("mezz.jei:jei-${jei_minecraft_version}-common:${jei_version}")
|
||||
modCompileOnly("mezz.jei:jei-${jei_minecraft_version}-gui:${jei_version}")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.embeddedt.modernfix;
|
||||
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
|
|
@ -11,6 +12,7 @@ import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
|||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
||||
import org.embeddedt.modernfix.resources.ReloadExecutor;
|
||||
import org.embeddedt.modernfix.util.ClassInfoManager;
|
||||
import org.embeddedt.modernfix.world.IntegratedWatchdog;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
|
@ -23,6 +25,8 @@ public class ModernFix {
|
|||
|
||||
public static final String MODID = "modernfix";
|
||||
|
||||
public static String NAME = "ModernFix";
|
||||
|
||||
public static ModernFix INSTANCE;
|
||||
|
||||
// Used to skip computing the blockstate caches twice
|
||||
|
|
@ -45,7 +49,22 @@ public class ModernFix {
|
|||
|
||||
public ModernFix() {
|
||||
INSTANCE = this;
|
||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.snapshot_easter_egg.NameChange") && !SharedConstants.getCurrentVersion().isStable())
|
||||
NAME = "PreemptiveFix";
|
||||
ModernFixPlatformHooks.onServerCommandRegister(ModernFixCommands::register);
|
||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.spam_thread_dump.ThreadDumper")) {
|
||||
Thread t = new Thread() {
|
||||
public void run() {
|
||||
while(true) {
|
||||
LOGGER.error("------ DEBUG THREAD DUMP (occurs every 60 seconds) ------");
|
||||
LOGGER.error(IntegratedWatchdog.obtainThreadDump());
|
||||
try { Thread.sleep(60000); } catch(InterruptedException e) {}
|
||||
}
|
||||
}
|
||||
};
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void onServerStarted() {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import net.minecraft.network.syncher.SynchedEntityData;
|
|||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.MemoryReserve;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.embeddedt.modernfix.api.constants.IntegrationConstants;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||
import org.embeddedt.modernfix.packet.EntityIDSyncPacket;
|
||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
||||
|
|
@ -22,6 +24,7 @@ import org.embeddedt.modernfix.world.IntegratedWatchdog;
|
|||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public class ModernFixClient {
|
||||
public static long worldLoadStartTime;
|
||||
|
|
@ -33,14 +36,26 @@ public class ModernFixClient {
|
|||
|
||||
public String brandingString = null;
|
||||
|
||||
/**
|
||||
* The list of loaded client integrations.
|
||||
*/
|
||||
public static List<ModernFixClientIntegration> CLIENT_INTEGRATIONS = new CopyOnWriteArrayList<>();
|
||||
|
||||
public ModernFixClient() {
|
||||
// clear reserve as it's not needed
|
||||
MemoryReserve.release();
|
||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.branding.F3Screen")) {
|
||||
brandingString = "ModernFix " + ModernFixPlatformHooks.getVersionString();
|
||||
brandingString = ModernFix.NAME + " " + ModernFixPlatformHooks.getVersionString();
|
||||
}
|
||||
SearchTreeProviderRegistry.register(JEIBackedSearchTree.PROVIDER);
|
||||
SearchTreeProviderRegistry.register(REIBackedSearchTree.PROVIDER);
|
||||
for(String className : ModernFixPlatformHooks.getCustomModOptions().get(IntegrationConstants.CLIENT_INTEGRATION_CLASS)) {
|
||||
try {
|
||||
CLIENT_INTEGRATIONS.add((ModernFixClientIntegration)Class.forName(className).getDeclaredConstructor().newInstance());
|
||||
} catch(ReflectiveOperationException | ClassCastException e) {
|
||||
ModernFix.LOGGER.error("Could not instantiate integration {}", className, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void resetWorldLoadStateMachine() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
package org.embeddedt.modernfix.api.constants;
|
||||
|
||||
public class IntegrationConstants {
|
||||
public static final String INTEGRATIONS_KEY = "modernfix:integration";
|
||||
|
||||
public static final String CLIENT_INTEGRATION_CLASS = "client_entrypoint";
|
||||
public static final String INTEGRATION_CLASS = "entrypoint";
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package org.embeddedt.modernfix.api.entrypoint;
|
||||
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ModelState;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
|
||||
/**
|
||||
* Implement this interface in a mod class and add it to "modernfix:integration_v1" in your mod metadata file
|
||||
* to integrate with ModernFix's features.
|
||||
*/
|
||||
public interface ModernFixClientIntegration {
|
||||
/**
|
||||
* Called when the dynamic resources status has changed during a model reload so mods know whether to run their
|
||||
* normal codepath or the dynamic version.
|
||||
*
|
||||
* @param enabled whether dynamic resources is enabled
|
||||
*/
|
||||
default void onDynamicResourcesStatusChange(boolean enabled) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to allow mods to observe the loading of an unbaked model and either make changes to it or wrap it with their
|
||||
* own instance.
|
||||
* @param location the ResourceLocation of the model (this may be a ModelResourceLocation)
|
||||
* @param originalModel the original model
|
||||
* @param bakery the model bakery - do not touch internal fields as they probably don't behave the way you expect
|
||||
* with dynamic resources on
|
||||
* @return the model which should actually be loaded for this resource location
|
||||
*/
|
||||
default UnbakedModel onUnbakedModelLoad(ResourceLocation location, UnbakedModel originalModel, ModelBakery bakery) {
|
||||
return originalModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to allow mods to observe the use of an unbaked model at bake time and either make changes to it or wrap it with their
|
||||
* own instance.
|
||||
* @param location the ResourceLocation of the model (this may be a ModelResourceLocation)
|
||||
* @param originalModel the original model
|
||||
* @param bakery the model bakery - do not touch internal fields as they probably don't behave the way you expect
|
||||
* with dynamic resources on
|
||||
* @return the model which should actually be loaded for this resource location
|
||||
*/
|
||||
default UnbakedModel onUnbakedModelPreBake(ResourceLocation location, UnbakedModel originalModel, ModelBakery bakery) {
|
||||
return originalModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to allow mods to observe the loading of a baked model and either make changes to it or wrap it with their
|
||||
* own instance.
|
||||
* @param location the ResourceLocation of the model (this may be a ModelResourceLocation)
|
||||
* @param originalModel the original model
|
||||
* @param bakery the model bakery - do not touch internal fields as they probably don't behave the way you expect
|
||||
* with dynamic resources on
|
||||
* @return the model which should actually be loaded for this resource location
|
||||
*/
|
||||
default BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) {
|
||||
return originalModel;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
package org.embeddedt.modernfix.api.helpers;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||
import org.embeddedt.modernfix.dynamicresources.ModelBakeryHelpers;
|
||||
import org.embeddedt.modernfix.util.DynamicMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class ModelHelpers {
|
||||
/**
|
||||
* Allows converting a ModelResourceLocation back into the corresponding BlockState(s). Try to avoid calling this
|
||||
* multiple times if possible.
|
||||
* @param location the location of the model
|
||||
* @return a list of all blockstates related to the model
|
||||
*/
|
||||
public static ImmutableList<BlockState> getBlockStateForLocation(ModelResourceLocation location) {
|
||||
Optional<Block> blockOpt = BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(location.getNamespace(), location.getPath()));
|
||||
if(blockOpt.isPresent())
|
||||
return ModelBakeryHelpers.getBlockStatesForMRL(blockOpt.get().getStateDefinition(), location);
|
||||
else
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows converting a ModelResourceLocation back into the corresponding BlockState(s). Faster version of its
|
||||
* companion function if and only if you know the corresponding Block already for some reason.
|
||||
* @param definition the state definition for the Block
|
||||
* @param location the location of the model
|
||||
* @return a list of all blockstates related to the model
|
||||
*/
|
||||
public static ImmutableList<BlockState> getBlockStateForLocation(StateDefinition<Block, BlockState> definition, ModelResourceLocation location) {
|
||||
return ModelBakeryHelpers.getBlockStatesForMRL(definition, location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compatibility helper for mods to use to get a map-like view of the model bakery.
|
||||
* @param modelGetter the model getter function supplied by the integration class
|
||||
* @return a fake map of the top-level models
|
||||
*/
|
||||
public static Map<ResourceLocation, BakedModel> createFakeTopLevelMap(BiFunction<ResourceLocation, ModelState, BakedModel> modelGetter) {
|
||||
return new DynamicMap<>(location -> modelGetter.apply(location, BlockModelRotation.X0_Y0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a ModelBaker for mods to use.
|
||||
* @param bakery the ModelBakery supplied to your integration
|
||||
* @return an appropriate ModelBaker
|
||||
*/
|
||||
public static ModelBaker adaptBakery(ModelBakery bakery) {
|
||||
return new ModelBaker() {
|
||||
@Override
|
||||
public UnbakedModel getModel(ResourceLocation resourceLocation) {
|
||||
return bakery.getModel(resourceLocation);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BakedModel bake(ResourceLocation resourceLocation, ModelState modelState) {
|
||||
return ((IExtendedModelBakery)bakery).bakeDefault(resourceLocation, modelState);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.bugfix.edge_chunk_not_saved;
|
||||
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/* https://github.com/SuperCoder7979/chunksavingfix-fabric/blob/main/src/main/java/supercoder79/chunksavingfix/mixin/MixinThreadedAnvilChunkStorage.java */
|
||||
@Mixin(ChunkMap.class)
|
||||
public class ChunkManagerMixin {
|
||||
// TODO: hits both at the moment- check and re-evaluate
|
||||
@ModifyArg(method = "saveAllChunks(Z)V", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;filter(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;", ordinal = 0), require = 0)
|
||||
private Predicate<ChunkHolder> alwaysAccessibleFlush(Predicate<ChunkHolder> chunkHolder) {
|
||||
return c -> true;
|
||||
}
|
||||
@ModifyArg(method = "saveAllChunks(Z)V", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;filter(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;", ordinal = 1), require = 0)
|
||||
private Predicate<ChunkAccess> allowProtoChunkFlush(Predicate<ChunkAccess> chunk) {
|
||||
return c -> c instanceof ProtoChunk || c instanceof ImposterProtoChunk || c instanceof LevelChunk;
|
||||
}
|
||||
|
||||
@Redirect(method = "saveChunkIfNeeded", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ChunkHolder;wasAccessibleSinceLastSave()Z"), require = 0)
|
||||
private boolean alwaysAccessible(ChunkHolder chunkHolder) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.bugfix.packet_leak;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.duck.IClientNetHandler;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(ClientPacketListener.class)
|
||||
@ClientOnlyMixin
|
||||
public class ClientPlayNetHandlerMixin {
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason allow the other function to track use of the buffer
|
||||
*/
|
||||
@Redirect(method = "handleCustomPayload", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/protocol/game/ClientboundCustomPayloadPacket;getData()Lnet/minecraft/network/FriendlyByteBuf;"))
|
||||
private FriendlyByteBuf saveCopyForRelease(ClientboundCustomPayloadPacket instance) {
|
||||
return ((IClientNetHandler)instance).getCopiedCustomBuffer();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.blast_search_trees;
|
||||
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.searchtree.SearchRegistry;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
|
@ -8,6 +9,8 @@ import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
||||
import org.embeddedt.modernfix.searchtree.DummySearchTree;
|
||||
import org.embeddedt.modernfix.searchtree.SearchTreeProviderRegistry;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
|
@ -36,6 +39,14 @@ public abstract class MinecraftMixin {
|
|||
this.searchRegistry.register(SearchRegistry.CREATIVE_TAGS, tagSupplier);
|
||||
this.searchRegistry.register(SearchRegistry.RECIPE_COLLECTIONS, list -> new DummySearchTree<>());
|
||||
ModernFixPlatformHooks.registerCreativeSearchTrees(this.searchRegistry, nameSupplier, tagSupplier, this::populateSearchTree);
|
||||
// grab components for all key mappings in order to prevent them from being loaded off-thread later
|
||||
// this populates the LazyLoadedValues
|
||||
// we also need to suppress GLFW errors to prevent crashes if a key is missing
|
||||
GLFWErrorCallback oldCb = GLFW.glfwSetErrorCallback(null);
|
||||
for(KeyMapping mapping : KeyMapping.ALL.values()) {
|
||||
mapping.getTranslatedKeyMessage();
|
||||
}
|
||||
GLFW.glfwSetErrorCallback(oldCb);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
|
|||
import net.minecraft.client.renderer.block.BlockModelShaper;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.dynamicresources.ModelLocationCache;
|
||||
|
|
@ -29,9 +30,14 @@ public class BlockModelShaperMixin {
|
|||
this.modelByStateCache = new DynamicOverridableMap<>(state -> modelManager.getModel(ModelLocationCache.get(state)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason get the model from the dynamic model provider
|
||||
*/
|
||||
@Overwrite
|
||||
public BakedModel getBlockModel(BlockState state) {
|
||||
BakedModel model = modelManager.getModel(ModelLocationCache.get(state));
|
||||
ModelResourceLocation mrl = ModelLocationCache.get(state);
|
||||
BakedModel model = mrl == null ? null : modelManager.getModel(mrl);
|
||||
if (model == null) {
|
||||
model = modelManager.getMissingModel();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources.diagonalfences;
|
||||
|
||||
import fuzs.diagonalfences.api.world.level.block.DiagonalBlock;
|
||||
import fuzs.diagonalfences.client.model.MultipartAppender;
|
||||
import net.minecraft.client.renderer.block.model.multipart.MultiPart;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.FenceBlock;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
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(MultipartAppender.class)
|
||||
@RequiresMod("diagonalfences")
|
||||
public abstract class MultipartAppenderMixin {
|
||||
@Shadow(remap = false)
|
||||
public static void appendDiagonalSelectors(ModelBakery modelBakery, MultiPart multiPart) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
private static boolean handlerInjected = false;
|
||||
|
||||
@Inject(method = "onPrepareModelBaking", at = @At("RETURN"))
|
||||
private static void setupHelper(CallbackInfo ci) {
|
||||
if(handlerInjected)
|
||||
return;
|
||||
handlerInjected = true;
|
||||
ModernFixClient.CLIENT_INTEGRATIONS.add(new ModernFixClientIntegration() {
|
||||
@Override
|
||||
public UnbakedModel onUnbakedModelLoad(ResourceLocation location, UnbakedModel originalModel, ModelBakery bakery) {
|
||||
if(originalModel instanceof MultiPart multipart) {
|
||||
Block block = multipart.definition.getOwner();
|
||||
if(block instanceof FenceBlock && block instanceof DiagonalBlock diagonalBlock && diagonalBlock.hasProperties()) {
|
||||
appendDiagonalSelectors(bakery, multipart);
|
||||
}
|
||||
}
|
||||
return originalModel;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -2,55 +2,33 @@ package org.embeddedt.modernfix.common.mixin.perf.faster_item_rendering;
|
|||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.minecraft.client.color.item.ItemColors;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.SimpleBakedModel;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.embeddedt.modernfix.render.FastItemRenderType;
|
||||
import org.embeddedt.modernfix.render.RenderState;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.embeddedt.modernfix.render.SimpleItemModelView;
|
||||
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.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(ItemRenderer.class)
|
||||
@Mixin(value = ItemRenderer.class, priority = 600)
|
||||
public abstract class ItemRendererMixin {
|
||||
@Shadow @Final private ItemColors itemColors;
|
||||
|
||||
private final RandomSource dummyRandom = RandomSource.createNewThreadLocalInstance();
|
||||
|
||||
private static final float[] COLOR_MULTIPLIER = new float[]{1.0F, 1.0F, 1.0F, 1.0F};
|
||||
|
||||
private ItemDisplayContext transformType;
|
||||
private final SimpleItemModelView modelView = new SimpleItemModelView();
|
||||
|
||||
@Inject(method = "render", at = @At("HEAD"))
|
||||
private void markRenderingType(ItemStack itemStack, ItemDisplayContext transformType, boolean leftHand, PoseStack matrixStack, MultiBufferSource buffer, int combinedLight, int combinedOverlay, BakedModel model, CallbackInfo ci) {
|
||||
this.transformType = transformType;
|
||||
}
|
||||
|
||||
private static final Direction[] ITEM_DIRECTIONS = new Direction[] { Direction.SOUTH };
|
||||
private static final Direction[] BLOCK_DIRECTIONS = new Direction[] { Direction.UP, Direction.EAST, Direction.NORTH };
|
||||
|
||||
private boolean isCorrectDirectionForType(FastItemRenderType type, Direction direction) {
|
||||
if(type == FastItemRenderType.SIMPLE_ITEM)
|
||||
return direction == Direction.SOUTH;
|
||||
else {
|
||||
return direction == Direction.UP || direction == Direction.EAST || direction == Direction.NORTH;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a model
|
||||
* - is a vanilla item model (SimpleBakedModel),
|
||||
|
|
@ -59,8 +37,8 @@ public abstract class ItemRendererMixin {
|
|||
* we do not need to go through the process of rendering every quad. Just render the south ones (the ones facing the
|
||||
* camera).
|
||||
*/
|
||||
@Inject(method = "renderModelLists", at = @At("HEAD"), cancellable = true)
|
||||
private void fasterItemRender(BakedModel model, ItemStack stack, int combinedLight, int combinedOverlay, PoseStack matrixStack, VertexConsumer buffer, CallbackInfo ci) {
|
||||
@ModifyVariable(method = "renderModelLists", at = @At("HEAD"), index = 1, argsOnly = true)
|
||||
private BakedModel useSimpleWrappedItemModel(BakedModel model, BakedModel arg, ItemStack stack, int combinedLight, int combinedOverlay, PoseStack matrixStack, VertexConsumer buffer) {
|
||||
if(!RenderState.IS_RENDERING_LEVEL && !stack.isEmpty() && model.getClass() == SimpleBakedModel.class && transformType == ItemDisplayContext.GUI) {
|
||||
FastItemRenderType type;
|
||||
ItemTransform transform = model.getTransforms().gui;
|
||||
|
|
@ -69,26 +47,12 @@ public abstract class ItemRendererMixin {
|
|||
else if(stack.getItem() instanceof BlockItem && isBlockTransforms(transform))
|
||||
type = FastItemRenderType.SIMPLE_BLOCK;
|
||||
else
|
||||
return;
|
||||
ci.cancel();
|
||||
PoseStack.Pose pose = matrixStack.last();
|
||||
int[] combinedLights = new int[] {combinedLight, combinedLight, combinedLight, combinedLight};
|
||||
Direction[] directions = type == FastItemRenderType.SIMPLE_ITEM ? ITEM_DIRECTIONS : BLOCK_DIRECTIONS;
|
||||
for(Direction direction : directions) {
|
||||
List<BakedQuad> culledFaces = model.getQuads(null, direction, dummyRandom);
|
||||
/* check size to avoid instantiating iterator when the list is empty */
|
||||
if(culledFaces.size() > 0) {
|
||||
for(BakedQuad quad : culledFaces) {
|
||||
render2dItemFace(quad, stack, buffer, pose, combinedLights, combinedOverlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<BakedQuad> unculledFaces = model.getQuads(null, null, dummyRandom);
|
||||
for(BakedQuad quad : unculledFaces) {
|
||||
if(isCorrectDirectionForType(type, quad.getDirection()))
|
||||
render2dItemFace(quad, stack, buffer, pose, combinedLights, combinedOverlay);
|
||||
}
|
||||
}
|
||||
return model;
|
||||
modelView.setItem(model);
|
||||
modelView.setType(type);
|
||||
return modelView;
|
||||
} else
|
||||
return model;
|
||||
}
|
||||
|
||||
private boolean isBlockTransforms(ItemTransform transform) {
|
||||
|
|
@ -96,16 +60,4 @@ public abstract class ItemRendererMixin {
|
|||
&& transform.rotation.y() == 225f
|
||||
&& transform.rotation.z() == 0f;
|
||||
}
|
||||
|
||||
private void render2dItemFace(BakedQuad quad, ItemStack stack, VertexConsumer buffer, PoseStack.Pose pose, int[] combinedLights, int combinedOverlay) {
|
||||
int i = -1;
|
||||
if (quad.isTinted()) {
|
||||
i = this.itemColors.getColor(stack, quad.getTintIndex());
|
||||
}
|
||||
|
||||
float f = (float)(i >> 16 & 255) / 255.0F;
|
||||
float f1 = (float)(i >> 8 & 255) / 255.0F;
|
||||
float f2 = (float)(i & 255) / 255.0F;
|
||||
buffer.putBulkData(pose, quad, COLOR_MULTIPLIER, f, f1, f2, combinedLights, combinedOverlay, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.nbt_memory_usage;
|
||||
|
||||
import net.minecraft.nbt.Tag;
|
||||
import org.embeddedt.modernfix.util.CanonizingStringMap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(targets = "net/minecraft/nbt/CompoundTag$1")
|
||||
public class CompoundTag1Mixin {
|
||||
@ModifyVariable(method = "load(Ljava/io/DataInput;ILnet/minecraft/nbt/NbtAccounter;)Lnet/minecraft/nbt/CompoundTag;", at = @At(value = "INVOKE_ASSIGN", target = "Lcom/google/common/collect/Maps;newHashMap()Ljava/util/HashMap;", remap = false))
|
||||
private Map<String, Tag> modifyMap(Map<String, Tag> map) {
|
||||
CanonizingStringMap<Tag> newMap = new CanonizingStringMap<>();
|
||||
if(map != null)
|
||||
newMap.putAll(map);
|
||||
return newMap;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,27 +6,25 @@ import org.embeddedt.modernfix.util.CanonizingStringMap;
|
|||
import org.spongepowered.asm.mixin.*;
|
||||
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.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(CompoundTag.class)
|
||||
public class CompoundTagMixin {
|
||||
@Shadow @Final @Mutable
|
||||
@Shadow @Final
|
||||
private Map<String, Tag> tags;
|
||||
|
||||
/**
|
||||
* Ensure that the backing map is always a CanonizingStringMap.
|
||||
* Ensure that the default backing map is a CanonizingStringMap.
|
||||
*/
|
||||
@Redirect(method = "<init>(Ljava/util/Map;)V", at = @At(value = "FIELD", target = "Lnet/minecraft/nbt/CompoundTag;tags:Ljava/util/Map;", ordinal = 0))
|
||||
private void replaceTagMap(CompoundTag tag, Map<String, Tag> incomingMap) {
|
||||
if(incomingMap instanceof CanonizingStringMap)
|
||||
this.tags = incomingMap;
|
||||
else {
|
||||
this.tags = new CanonizingStringMap<>();
|
||||
this.tags.putAll(incomingMap);
|
||||
}
|
||||
@ModifyArg(method = "<init>()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/nbt/CompoundTag;<init>(Ljava/util/Map;)V"), index = 0)
|
||||
private static Map<String, Tag> useCanonizingStringMap(Map<String, Tag> incoming) {
|
||||
CanonizingStringMap<Tag> newMap = new CanonizingStringMap<>();
|
||||
if(incoming != null)
|
||||
newMap.putAll(incoming);
|
||||
return newMap;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package org.embeddedt.modernfix.common.mixin.safety;
|
||||
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.layers.RenderLayer;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(LivingEntityRenderer.class)
|
||||
@ClientOnlyMixin
|
||||
public class LivingEntityRendererMixin {
|
||||
@Shadow @Final @Mutable
|
||||
protected List<RenderLayer<?, ?>> layers;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void synchronizeLayerList(CallbackInfo ci) {
|
||||
/* allows buggy mods to call addLayer concurrently, order is not deterministic but can't fix that */
|
||||
this.layers = Collections.synchronizedList(layers);
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,8 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin {
|
|||
public static ModernFixMixinPlugin instance;
|
||||
|
||||
public ModernFixMixinPlugin() {
|
||||
/* invoke early to ensure it gets read on one thread */
|
||||
ModernFixPlatformHooks.getCustomModOptions();
|
||||
boolean firstConfig = instance == null;
|
||||
if(firstConfig) {
|
||||
instance = this;
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ public class ModernFixEarlyConfig {
|
|||
private final Set<String> mixinOptions = new ObjectOpenHashSet<>();
|
||||
private final Map<String, String> mixinsMissingMods = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
public static boolean isFabric = false;
|
||||
|
||||
public Map<String, String> getPermanentlyDisabledMixins() {
|
||||
return mixinsMissingMods;
|
||||
}
|
||||
|
|
@ -71,6 +73,8 @@ public class ModernFixEarlyConfig {
|
|||
if(stream == null)
|
||||
continue;
|
||||
try(Reader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
|
||||
if(configFile.contains("fabric"))
|
||||
isFabric = true;
|
||||
JsonObject configObject = (JsonObject)new JsonParser().parse(reader);
|
||||
JsonArray mixinList = configObject.getAsJsonArray("mixins");
|
||||
String packageName = configObject.get("package").getAsString().replace('.', '/');
|
||||
|
|
@ -143,6 +147,8 @@ public class ModernFixEarlyConfig {
|
|||
.put("mixin.perf.dynamic_entity_renderers", false)
|
||||
.put("mixin.feature.integrated_server_watchdog", true)
|
||||
.put("mixin.perf.faster_item_rendering", false)
|
||||
.put("mixin.feature.spam_thread_dump", false)
|
||||
.put("mixin.feature.snapshot_easter_egg", true)
|
||||
.put("mixin.devenv", isDevEnv)
|
||||
.put("mixin.perf.remove_spawn_chunks", isDevEnv)
|
||||
.build();
|
||||
|
|
@ -177,14 +183,21 @@ public class ModernFixEarlyConfig {
|
|||
disableIfModPresent("mixin.perf.thread_priorities", "smoothboot");
|
||||
disableIfModPresent("mixin.perf.boost_worker_count", "smoothboot");
|
||||
disableIfModPresent("mixin.perf.async_jei", "modernui");
|
||||
disableIfModPresent("mixin.perf.compress_biome_container", "chocolate", "betterendforge");
|
||||
disableIfModPresent("mixin.perf.compress_biome_container", "chocolate", "betterendforge" ,"skyblockbuilder");
|
||||
disableIfModPresent("mixin.bugfix.mc218112", "performant");
|
||||
disableIfModPresent("mixin.bugfix.remove_block_chunkloading", "performant");
|
||||
disableIfModPresent("mixin.bugfix.paper_chunk_patches", "c2me");
|
||||
disableIfModPresent("mixin.perf.nbt_memory_usage", "c2me");
|
||||
// DimThread makes changes to the server chunk manager (understandably), C2ME probably does the same
|
||||
disableIfModPresent("mixin.bugfix.chunk_deadlock", "c2me", "dimthread");
|
||||
disableIfModPresent("mixin.perf.reuse_datapacks", "tac");
|
||||
disableIfModPresent("mixin.launch.class_search_cache", "optifine");
|
||||
disableIfModPresent("mixin.perf.faster_texture_stitching", "optifine");
|
||||
disableIfModPresent("mixin.perf.datapack_reload_exceptions", "cyanide");
|
||||
disableIfModPresent("mixin.perf.faster_texture_loading", "stitch");
|
||||
disableIfModPresent("mixin.perf.faster_texture_loading", "stitch", "optifine", "changed");
|
||||
if(isFabric) {
|
||||
disableIfModPresent("mixin.bugfix.packet_leak", "memoryleakfix");
|
||||
}
|
||||
}
|
||||
|
||||
private void disableIfModPresent(String configName, String... ids) {
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
|
||||
public interface IClientNetHandler {
|
||||
FriendlyByteBuf getCopiedCustomBuffer();
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package org.embeddedt.modernfix.duck;
|
|||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.ModelState;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
|
@ -11,7 +12,7 @@ import net.minecraft.world.level.block.state.StateDefinition;
|
|||
|
||||
public interface IExtendedModelBakery {
|
||||
ImmutableList<BlockState> getBlockStatesForMRL(StateDefinition<Block, BlockState> stateDefinition, ModelResourceLocation location);
|
||||
BakedModel bakeDefault(ResourceLocation modelLocation);
|
||||
BakedModel bakeDefault(ResourceLocation modelLocation, ModelState state);
|
||||
BakedModel getBakedMissingModel();
|
||||
void setBakedMissingModel(BakedModel m);
|
||||
UnbakedModel mfix$getUnbakedMissingModel();
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import net.minecraft.util.RandomSource;
|
|||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
|
@ -109,7 +110,12 @@ public class DynamicBakedModelProvider implements Map<ResourceLocation, BakedMod
|
|||
if(model != SENTINEL)
|
||||
return model;
|
||||
else {
|
||||
model = ((IExtendedModelBakery)bakery).bakeDefault((ResourceLocation)o);
|
||||
try {
|
||||
model = ((IExtendedModelBakery)bakery).bakeDefault((ResourceLocation)o, BlockModelRotation.X0_Y0);
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Exception baking {}: {}", o, e);
|
||||
model = missingModel;
|
||||
}
|
||||
if(model == missingModel) {
|
||||
// to correctly emulate the original map, we return null for missing models
|
||||
permanentOverrides.put((ResourceLocation) o, null);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ public class ModelLocationCache {
|
|||
});
|
||||
|
||||
public static ModelResourceLocation get(BlockState state) {
|
||||
if(state == null)
|
||||
return null;
|
||||
try {
|
||||
return blockLocationCache.get(state);
|
||||
} catch(ExecutionException e) {
|
||||
|
|
@ -39,6 +41,8 @@ public class ModelLocationCache {
|
|||
}
|
||||
|
||||
public static ModelResourceLocation get(Item item) {
|
||||
if(item == null)
|
||||
return null;
|
||||
try {
|
||||
return itemLocationCache.get(item);
|
||||
} catch(ExecutionException e) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
package org.embeddedt.modernfix.platform;
|
||||
|
||||
import dev.architectury.injectables.annotations.ExpectPlatform;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import dev.architectury.injectables.annotations.ExpectPlatform;
|
||||
import net.minecraft.client.searchtree.SearchRegistry;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
|
@ -75,6 +76,11 @@ public class ModernFixPlatformHooks {
|
|||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@ExpectPlatform
|
||||
public static Multimap<String, String> getCustomModOptions() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@ExpectPlatform
|
||||
public static void registerCreativeSearchTrees(SearchRegistry registry, SearchRegistry.TreeBuilderSupplier<ItemStack> nameSupplier, SearchRegistry.TreeBuilderSupplier<ItemStack> tagSupplier, BiConsumer<SearchRegistry.Key<ItemStack>, List<ItemStack>> populator) {
|
||||
throw new AssertionError();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
package org.embeddedt.modernfix.render;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrides;
|
||||
import net.minecraft.client.renderer.block.model.ItemTransforms;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper class that presents a fake view of item models (only showing the simple front-facing quads), rather
|
||||
* than every quad.
|
||||
*/
|
||||
public class SimpleItemModelView implements BakedModel {
|
||||
private BakedModel wrappedItem;
|
||||
private FastItemRenderType type;
|
||||
|
||||
public void setItem(BakedModel model) {
|
||||
this.wrappedItem = model;
|
||||
}
|
||||
|
||||
public void setType(FastItemRenderType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private boolean isCorrectDirectionForType(Direction direction) {
|
||||
if(type == FastItemRenderType.SIMPLE_ITEM)
|
||||
return direction == Direction.SOUTH;
|
||||
else {
|
||||
return direction == Direction.UP || direction == Direction.EAST || direction == Direction.NORTH;
|
||||
}
|
||||
}
|
||||
|
||||
private final List<BakedQuad> nullQuadList = new ObjectArrayList<>();
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand) {
|
||||
if(side != null) {
|
||||
return isCorrectDirectionForType(side) ? wrappedItem.getQuads(state, side, rand) : ImmutableList.of();
|
||||
} else {
|
||||
nullQuadList.clear();
|
||||
List<BakedQuad> realList = wrappedItem.getQuads(state, null, rand);
|
||||
for(int i = 0; i < realList.size(); i++) {
|
||||
BakedQuad quad = realList.get(i);
|
||||
if(isCorrectDirectionForType(quad.getDirection())) {
|
||||
nullQuadList.add(quad);
|
||||
}
|
||||
}
|
||||
return nullQuadList;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAmbientOcclusion() {
|
||||
return wrappedItem.useAmbientOcclusion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d() {
|
||||
return wrappedItem.isGui3d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usesBlockLight() {
|
||||
return wrappedItem.usesBlockLight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCustomRenderer() {
|
||||
return wrappedItem.isCustomRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleIcon() {
|
||||
return wrappedItem.getParticleIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemTransforms getTransforms() {
|
||||
return wrappedItem.getTransforms();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemOverrides getOverrides() {
|
||||
return wrappedItem.getOverrides();
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.PackType;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
||||
import org.embeddedt.modernfix.util.PackTypeHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -163,6 +164,8 @@ public class PackResourcesCacheEngine {
|
|||
}
|
||||
|
||||
public static void invalidate() {
|
||||
if(!ModernFixPlatformHooks.isDevEnv())
|
||||
return;
|
||||
synchronized (cachingPacks) {
|
||||
cachingPacks.keySet().forEach(pack -> {
|
||||
if(pack != null)
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ public class JEIBackedSearchTree extends DummySearchTree<ItemStack> {
|
|||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
return ModernFixPlatformHooks.modPresent("jei") && getIngredientListUncached != null && filterField != null;
|
||||
return ModernFixPlatformHooks.modPresent("jei") && !ModernFixPlatformHooks.modPresent("emi") && getIngredientListUncached != null && filterField != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,22 +1,28 @@
|
|||
package org.embeddedt.modernfix.searchtree;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import me.shedaniel.rei.api.client.registry.entry.EntryRegistry;
|
||||
import me.shedaniel.rei.api.common.entry.EntryStack;
|
||||
import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes;
|
||||
import me.shedaniel.rei.impl.client.search.AsyncSearchManager;
|
||||
import me.shedaniel.rei.impl.common.entry.type.EntryRegistryImpl;
|
||||
import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper;
|
||||
import net.minecraft.client.searchtree.RefreshableSearchTree;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class REIBackedSearchTree extends DummySearchTree<ItemStack> {
|
||||
private final AsyncSearchManager searchManager = new AsyncSearchManager(EntryRegistry.getInstance()::getPreFilteredList, () -> {
|
||||
return stack -> true;
|
||||
}, EntryStack::normalize);
|
||||
private final AsyncSearchManager searchManager = createSearchManager();
|
||||
|
||||
private final boolean filteringByTag;
|
||||
private String lastSearchText = "";
|
||||
|
|
@ -39,14 +45,23 @@ public class REIBackedSearchTree extends DummySearchTree<ItemStack> {
|
|||
if(!pSearchText.equals(lastSearchText)) {
|
||||
listCache.clear();
|
||||
this.searchManager.updateFilter(pSearchText);
|
||||
List<EntryStack<?>> stacks;
|
||||
List stacks;
|
||||
try {
|
||||
stacks = this.searchManager.getNow();
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Couldn't search for '" + pSearchText + "'", e);
|
||||
stacks = Collections.emptyList();
|
||||
}
|
||||
for(EntryStack<?> stack : stacks) {
|
||||
for(Object o : stacks) {
|
||||
EntryStack<?> stack;
|
||||
if(o instanceof EntryStack<?>)
|
||||
stack = (EntryStack<?>)o;
|
||||
else if(o instanceof HashedEntryStackWrapper) {
|
||||
stack = ((HashedEntryStackWrapper)o).unwrap();
|
||||
} else {
|
||||
ModernFix.LOGGER.error("Don't know how to handle {}", o.getClass().getName());
|
||||
continue;
|
||||
}
|
||||
if(stack.getType() == VanillaEntryTypes.ITEM) {
|
||||
listCache.add(stack.cheatsAs().getValue());
|
||||
}
|
||||
|
|
@ -56,6 +71,50 @@ public class REIBackedSearchTree extends DummySearchTree<ItemStack> {
|
|||
return listCache;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private static AsyncSearchManager createSearchManager() {
|
||||
Method m, normalizeMethod;
|
||||
try {
|
||||
try {
|
||||
m = EntryRegistryImpl.class.getDeclaredMethod("getPreFilteredComplexList");
|
||||
m.setAccessible(true);
|
||||
normalizeMethod = HashedEntryStackWrapper.class.getDeclaredMethod("normalize");
|
||||
normalizeMethod.setAccessible(true);
|
||||
} catch(NoSuchMethodException e) {
|
||||
m = EntryRegistryImpl.class.getDeclaredMethod("getPreFilteredList");
|
||||
m.setAccessible(true);
|
||||
normalizeMethod = EntryStack.class.getDeclaredMethod("normalize");
|
||||
normalizeMethod.setAccessible(true);
|
||||
}
|
||||
final MethodHandle getListMethod = MethodHandles.publicLookup().unreflect(m);
|
||||
final MethodHandle normalize = MethodHandles.publicLookup().unreflect(normalizeMethod);
|
||||
final EntryRegistryImpl registry = (EntryRegistryImpl)EntryRegistry.getInstance();
|
||||
Supplier stackListSupplier = () -> {
|
||||
try {
|
||||
return (List)getListMethod.invokeExact(registry);
|
||||
} catch(Throwable e) {
|
||||
if(e instanceof RuntimeException)
|
||||
throw (RuntimeException)e;
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
UnaryOperator normalizeOperator = o -> {
|
||||
try {
|
||||
return normalize.invoke(o);
|
||||
} catch(Throwable e) {
|
||||
if(e instanceof RuntimeException)
|
||||
throw (RuntimeException)e;
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
return new AsyncSearchManager(stackListSupplier, () -> {
|
||||
return Predicates.alwaysTrue();
|
||||
}, normalizeOperator);
|
||||
} catch(ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final SearchTreeProviderRegistry.Provider PROVIDER = new SearchTreeProviderRegistry.Provider() {
|
||||
@Override
|
||||
public RefreshableSearchTree<ItemStack> getSearchTree(boolean tag) {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ public class CachingStructureManager {
|
|||
currentTag.putInt("DataVersion", 500);
|
||||
}
|
||||
int currentDataVersion = currentTag.getInt("DataVersion");
|
||||
if(currentDataVersion < SharedConstants.getCurrentVersion().getDataVersion().getVersion()) {
|
||||
int requiredMinimumDataVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion();
|
||||
if(currentDataVersion < requiredMinimumDataVersion) {
|
||||
/* Needs upgrade, try looking up from cache */
|
||||
MessageDigest hasher = digestThreadLocal.get();
|
||||
hasher.reset();
|
||||
|
|
@ -71,13 +72,13 @@ public class CachingStructureManager {
|
|||
CompoundTag cachedUpgraded = getCachedUpgraded(location, truncateHash(hash));
|
||||
if(cachedUpgraded == null)
|
||||
cachedUpgraded = getCachedUpgraded(location, hash); /* pick up old cache */
|
||||
if(cachedUpgraded != null && cachedUpgraded.getInt("DataVersion") == SharedConstants.getCurrentVersion().getDataVersion().getVersion()) {
|
||||
if(cachedUpgraded != null && cachedUpgraded.getInt("DataVersion") == requiredMinimumDataVersion) {
|
||||
ModernFix.LOGGER.debug("Using cached upgraded version of {}", location);
|
||||
currentTag = cachedUpgraded;
|
||||
} else {
|
||||
synchronized (laggyStructureMods) {
|
||||
if(laggyStructureMods.add(location.getNamespace())) {
|
||||
ModernFix.LOGGER.warn("Mod {} is shipping outdated structure files, which can cause worldgen lag; please report this to them.", location.getNamespace());
|
||||
ModernFix.LOGGER.warn("The namespace {} contains an outdated structure file, which can cause worldgen lag. Please view debug.log for the full filename, determine which mod provides the structure, and report to the mod/datapack author, including the debug log.", location.getNamespace());
|
||||
}
|
||||
}
|
||||
ModernFix.LOGGER.debug("Structure {} is being run through DFU (hash {}), this will cause launch time delays", location, hash);
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ public class CanonizingStringMap<T> implements Map<String, T> {
|
|||
}
|
||||
|
||||
public static <T> CanonizingStringMap<T> deepCopy(CanonizingStringMap<T> inputMap, Function<T, T> deepCopier) {
|
||||
Objects.requireNonNull(deepCopier);
|
||||
Object2ObjectMap<String, T> copiedBackingMap;
|
||||
int size = inputMap.backingMap.size();
|
||||
if(size > GROWTH_THRESHOLD) {
|
||||
|
|
@ -148,7 +149,8 @@ public class CanonizingStringMap<T> implements Map<String, T> {
|
|||
} else
|
||||
copiedBackingMap = new Object2ObjectArrayMap<>(size);
|
||||
inputMap.backingMap.object2ObjectEntrySet().forEach(entry -> {
|
||||
copiedBackingMap.put(entry.getKey(), deepCopier.apply(entry.getValue()));
|
||||
if(entry.getKey() != null && entry.getValue() != null)
|
||||
copiedBackingMap.put(entry.getKey(), deepCopier.apply(entry.getValue()));
|
||||
});
|
||||
return new CanonizingStringMap<>(copiedBackingMap);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,27 @@ public class IntegratedWatchdog extends Thread {
|
|||
this.setName("ModernFix integrated server watchdog");
|
||||
}
|
||||
|
||||
public static String obtainThreadDump() {
|
||||
ThreadMXBean threadmxbean = ManagementFactory.getThreadMXBean();
|
||||
ThreadInfo[] athreadinfo = threadmxbean.dumpAllThreads(true, true);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Thread Dump:\n");
|
||||
for(ThreadInfo threadinfo : athreadinfo) {
|
||||
sb.append(threadinfo);
|
||||
StackTraceElement[] elements = threadinfo.getStackTrace();
|
||||
if(elements.length > 8) {
|
||||
sb.append("extended trace:\n");
|
||||
for(int i = 8; i < elements.length; i++) {
|
||||
sb.append("\tat ");
|
||||
sb.append(elements[i]);
|
||||
sb.append('\n');
|
||||
}
|
||||
}
|
||||
sb.append('\n');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while(true) {
|
||||
MinecraftServer server = this.server.get();
|
||||
|
|
@ -35,24 +56,7 @@ public class IntegratedWatchdog extends Thread {
|
|||
long delta = curTime - nextTick;
|
||||
if(delta > MAX_TICK_DELTA) {
|
||||
LOGGER.error("A single server tick has taken {}, more than {} milliseconds", delta, MAX_TICK_DELTA);
|
||||
ThreadMXBean threadmxbean = ManagementFactory.getThreadMXBean();
|
||||
ThreadInfo[] athreadinfo = threadmxbean.dumpAllThreads(true, true);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Thread Dump:\n");
|
||||
for(ThreadInfo threadinfo : athreadinfo) {
|
||||
sb.append(threadinfo);
|
||||
StackTraceElement[] elements = threadinfo.getStackTrace();
|
||||
if(elements.length > 8) {
|
||||
sb.append("extended trace:\n");
|
||||
for(int i = 8; i < elements.length; i++) {
|
||||
sb.append("\tat ");
|
||||
sb.append(elements[i]);
|
||||
sb.append('\n');
|
||||
}
|
||||
}
|
||||
sb.append('\n');
|
||||
}
|
||||
LOGGER.error(sb.toString());
|
||||
LOGGER.error(obtainThreadDump());
|
||||
nextTick = 0;
|
||||
curTime = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,3 +35,5 @@ accessible class net/minecraft/world/level/chunk/PalettedContainer$Data
|
|||
accessible field net/minecraft/server/MinecraftServer resources Lnet/minecraft/server/MinecraftServer$ReloadableResources;
|
||||
accessible class net/minecraft/server/MinecraftServer$ReloadableResources
|
||||
accessible method net/minecraft/client/gui/screens/Screen addRenderableWidget (Lnet/minecraft/client/gui/components/events/GuiEventListener;)Lnet/minecraft/client/gui/components/events/GuiEventListener;
|
||||
accessible field net/minecraft/client/KeyMapping ALL Ljava/util/Map;
|
||||
accessible field net/minecraft/client/renderer/block/model/multipart/MultiPart definition Lnet/minecraft/world/level/block/state/StateDefinition;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ dependencies {
|
|||
modImplementation(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modImplementation(fabricApi.module("fabric-data-generation-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modCompileOnly("com.terraformersmc:modmenu:${rootProject.modmenu_version}") { transitive false }
|
||||
modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}") { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
// Remove the next line if you don't want to depend on the API
|
||||
// modApi "me.shedaniel:architectury-fabric:${rootProject.architectury_version}"
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import net.minecraft.resources.ResourceLocation;
|
|||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||
import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
|
|
@ -58,39 +60,63 @@ public abstract class ModelBakerImplMixin {
|
|||
}
|
||||
|
||||
private boolean wasMissingModel = false;
|
||||
private ResourceLocation capturedLocation;
|
||||
private UnbakedModel capturedModel;
|
||||
private ModelState capturedState;
|
||||
|
||||
@Inject(method = "bake", at = @At("HEAD"))
|
||||
private void captureState(ResourceLocation rl, ModelState state, CallbackInfoReturnable<BakedModel> cir) {
|
||||
capturedState = state;
|
||||
}
|
||||
|
||||
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
|
||||
private void obtainModel(ResourceLocation arg, CallbackInfoReturnable<UnbakedModel> cir) {
|
||||
capturedLocation = arg;
|
||||
if(debugDynamicModelLoading)
|
||||
ModernFix.LOGGER.info("Baking {}", arg);
|
||||
IExtendedModelBakery extendedBakery = (IExtendedModelBakery)this.field_40571;
|
||||
if(arg instanceof ModelResourceLocation && arg != ModelBakery.MISSING_MODEL_LOCATION) {
|
||||
/* to emulate vanilla model loading, treat as top-level */
|
||||
Optional<Block> blockOpt = Objects.equals(((ModelResourceLocation)arg).getVariant(), "inventory") ? Optional.empty() : BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(arg.getNamespace(), arg.getPath()));
|
||||
if(blockOpt.isPresent()) {
|
||||
/* load via lambda for mods that expect blockstate to get loaded */
|
||||
for(BlockState state : extendedBakery.getBlockStatesForMRL(blockOpt.get().getStateDefinition(), (ModelResourceLocation)arg)) {
|
||||
try {
|
||||
blockStateLoaderHandle.invokeExact(this.field_40571, state);
|
||||
} catch(Throwable e) {
|
||||
ModernFix.LOGGER.error("Error loading model", e);
|
||||
// synchronized because we use topLevelModels
|
||||
synchronized (this.field_40571) {
|
||||
/* to emulate vanilla model loading, treat as top-level */
|
||||
Optional<Block> blockOpt = Objects.equals(((ModelResourceLocation)arg).getVariant(), "inventory") ? Optional.empty() : BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(arg.getNamespace(), arg.getPath()));
|
||||
if(blockOpt.isPresent()) {
|
||||
/* load via lambda for mods that expect blockstate to get loaded */
|
||||
for(BlockState state : extendedBakery.getBlockStatesForMRL(blockOpt.get().getStateDefinition(), (ModelResourceLocation)arg)) {
|
||||
try {
|
||||
blockStateLoaderHandle.invokeExact(this.field_40571, state);
|
||||
} catch(Throwable e) {
|
||||
ModernFix.LOGGER.error("Error loading model", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.field_40571.loadTopLevel((ModelResourceLocation)arg);
|
||||
}
|
||||
} else {
|
||||
this.field_40571.loadTopLevel((ModelResourceLocation)arg);
|
||||
cir.setReturnValue(this.field_40571.topLevelModels.getOrDefault(arg, extendedBakery.mfix$getUnbakedMissingModel()));
|
||||
// avoid leaks
|
||||
this.field_40571.topLevelModels.clear();
|
||||
}
|
||||
cir.setReturnValue(this.field_40571.topLevelModels.getOrDefault(arg, extendedBakery.mfix$getUnbakedMissingModel()));
|
||||
// avoid leaks
|
||||
this.field_40571.topLevelModels.clear();
|
||||
} else
|
||||
cir.setReturnValue(this.field_40571.getModel(arg));
|
||||
UnbakedModel toReplace = cir.getReturnValue();
|
||||
if(!wasMissingModel) {
|
||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
||||
try {
|
||||
toReplace = integration.onUnbakedModelPreBake(arg, toReplace, (ModelBakery)(Object)this);
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Exception firing model pre-bake event for {}", arg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
cir.setReturnValue(toReplace);
|
||||
cir.getReturnValue().resolveParents(this.field_40571::getModel);
|
||||
capturedModel = cir.getReturnValue();
|
||||
if(cir.getReturnValue() == extendedBakery.mfix$getUnbakedMissingModel()) {
|
||||
if(arg != ModelBakery.MISSING_MODEL_LOCATION && debugDynamicModelLoading)
|
||||
ModernFix.LOGGER.warn("Model {} not present", arg);
|
||||
wasMissingModel = true;
|
||||
} else
|
||||
wasMissingModel = false; /* sometimes this runs more than once e.g. for recursive model baking */
|
||||
cir.getReturnValue().resolveParents(this.field_40571::getModel);
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "bake", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/client/resources/model/UnbakedModel;bake(Lnet/minecraft/client/resources/model/ModelBaker;Ljava/util/function/Function;Lnet/minecraft/client/resources/model/ModelState;Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/resources/model/BakedModel;"))
|
||||
|
|
@ -109,6 +135,9 @@ public abstract class ModelBakerImplMixin {
|
|||
}
|
||||
return missing;
|
||||
}
|
||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
||||
model = integration.onBakedModelLoad(capturedLocation, capturedModel, model, capturedState, this.field_40571);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||
import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider;
|
||||
import org.embeddedt.modernfix.dynamicresources.ModelBakeryHelpers;
|
||||
|
|
@ -28,6 +30,7 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.*;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
|
|
@ -107,11 +110,6 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
this.bakedTopLevelModels = new DynamicBakedModelProvider((ModelBakery)(Object)this, bakedCache);
|
||||
}
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void stopIgnore(CallbackInfo ci) {
|
||||
this.ignoreModelLoad = false;
|
||||
}
|
||||
|
||||
private <K, V> void onModelRemoved(RemovalNotification<K, V> notification) {
|
||||
if(!debugDynamicModelLoading)
|
||||
return;
|
||||
|
|
@ -171,6 +169,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
|
||||
@Inject(method = "bakeModels", at = @At("HEAD"))
|
||||
private void captureGetter(BiFunction<ResourceLocation, Material, TextureAtlasSprite> getter, CallbackInfo ci) {
|
||||
this.ignoreModelLoad = false;
|
||||
textureGetter = getter;
|
||||
}
|
||||
|
||||
|
|
@ -189,6 +188,17 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
return unbakedCache.get(rl);
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "cacheAndQueueDependencies", at = @At("HEAD"), argsOnly = true)
|
||||
private UnbakedModel fireUnbakedEvent(UnbakedModel model, ResourceLocation location) {
|
||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
||||
try {
|
||||
model = integration.onUnbakedModelLoad(location, model, (ModelBakery)(Object)this);
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Exception firing model load event for {}", location, e);
|
||||
}
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
|
|
@ -256,14 +266,14 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BakedModel bakeDefault(ResourceLocation modelLocation) {
|
||||
public BakedModel bakeDefault(ResourceLocation modelLocation, ModelState state) {
|
||||
ModelBakery.BakedCacheKey key = new ModelBakery.BakedCacheKey(modelLocation, BlockModelRotation.X0_Y0.getRotation(), BlockModelRotation.X0_Y0.isUvLocked());
|
||||
BakedModel m = loadedBakedModels.getIfPresent(key);
|
||||
if(m != null)
|
||||
return m;
|
||||
ModelBakery self = (ModelBakery) (Object) this;
|
||||
ModelBaker theBaker = self.new ModelBakerImpl(textureGetter, modelLocation);
|
||||
m = theBaker.bake(modelLocation, BlockModelRotation.X0_Y0);
|
||||
m = theBaker.bake(modelLocation, state);
|
||||
if(m != null)
|
||||
loadedBakedModels.put(key, m);
|
||||
return m;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package org.embeddedt.modernfix.fabric.mixin.safety;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
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(DynamicTexture.class)
|
||||
public class DynamicTextureMixin {
|
||||
@Shadow @Nullable private NativeImage pixels;
|
||||
|
||||
private Exception closeTrace;
|
||||
|
||||
@Inject(method = "method_22793", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/texture/DynamicTexture;pixels:Lcom/mojang/blaze3d/platform/NativeImage;", ordinal = 0))
|
||||
private void checkNullPixels(CallbackInfo ci) {
|
||||
if(pixels == null) {
|
||||
ModernFix.LOGGER.error("Attempted to upload null texture! This is not allowed, closed here", closeTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "close", at = @At("HEAD"))
|
||||
private void storeCloseTrace(CallbackInfo ci) {
|
||||
closeTrace = new Exception();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,26 @@
|
|||
package org.embeddedt.modernfix.platform.fabric;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.fabricmc.loader.api.metadata.CustomValue;
|
||||
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||
import net.minecraft.client.searchtree.SearchRegistry;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.embeddedt.modernfix.ModernFixFabric;
|
||||
import org.embeddedt.modernfix.api.constants.IntegrationConstants;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
|
@ -72,6 +78,28 @@ public class ModernFixPlatformHooksImpl {
|
|||
CommandRegistrationCallback.EVENT.register((dispatcher, arg, env) -> handler.accept(dispatcher));
|
||||
}
|
||||
|
||||
private static Multimap<String, String> modOptions;
|
||||
public static Multimap<String, String> getCustomModOptions() {
|
||||
if(modOptions == null) {
|
||||
modOptions = ArrayListMultimap.create();
|
||||
for (ModContainer container : FabricLoader.getInstance().getAllMods()) {
|
||||
ModMetadata meta = container.getMetadata();
|
||||
if (meta.containsCustomValue(IntegrationConstants.INTEGRATIONS_KEY)) {
|
||||
CustomValue integrations = meta.getCustomValue(IntegrationConstants.INTEGRATIONS_KEY);
|
||||
if (integrations.getType() != CustomValue.CvType.OBJECT) {
|
||||
continue;
|
||||
}
|
||||
for (Map.Entry<String, CustomValue> entry : integrations.getAsObject()) {
|
||||
if(entry.getValue().getType() != CustomValue.CvType.STRING)
|
||||
continue;
|
||||
modOptions.put(entry.getKey(), entry.getValue().getAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return modOptions;
|
||||
}
|
||||
|
||||
public static void registerCreativeSearchTrees(SearchRegistry registry, SearchRegistry.TreeBuilderSupplier<ItemStack> nameSupplier, SearchRegistry.TreeBuilderSupplier<ItemStack> tagSupplier, BiConsumer<SearchRegistry.Key<ItemStack>, List<ItemStack>> populator) {
|
||||
/* no-op on Fabric */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
"fabric-screen-api-v1": "*",
|
||||
"fabric-command-api-v2": "*",
|
||||
"fabric-models-v0": "*",
|
||||
"minecraft": ">=1.16.5"
|
||||
"minecraft": ">=1.16.2"
|
||||
},
|
||||
"breaks": {
|
||||
"dashloader": "*"
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ dependencies {
|
|||
modCompileOnly("team.chisel.ctm:CTM:${ctm_version}")
|
||||
|
||||
modCompileOnly("curse.maven:supermartijncore-454372:4455391")
|
||||
modCompileOnly("appeng:appliedenergistics2-forge:12.9.4")
|
||||
modCompileOnly("vazkii.patchouli:Patchouli:1.19.2-77")
|
||||
|
||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
package org.embeddedt.modernfix.forge.dynamicresources;
|
||||
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
|
||||
/**
|
||||
* Fired when a model is baked dynamically. Intended to be used as a replacement for ModelBakeEvent
|
||||
* if mods want to replace a model.
|
||||
* <p></p>
|
||||
* Note that this event can fire many times for the same resource location, as models are unloaded
|
||||
* if unused/under memory pressure.
|
||||
*/
|
||||
public class DynamicModelBakeEvent extends Event {
|
||||
private final ResourceLocation location;
|
||||
private BakedModel model;
|
||||
private final UnbakedModel unbakedModel;
|
||||
private final ModelBaker modelLoader;
|
||||
private final ModelBakery modelBakery;
|
||||
public DynamicModelBakeEvent(ResourceLocation location, UnbakedModel unbakedModel, BakedModel model, ModelBaker loader, ModelBakery bakery) {
|
||||
this.location = location;
|
||||
this.model = model;
|
||||
this.unbakedModel = unbakedModel;
|
||||
this.modelLoader = loader;
|
||||
this.modelBakery = bakery;
|
||||
}
|
||||
|
||||
public ResourceLocation getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
public BakedModel getModel() {
|
||||
return this.model;
|
||||
}
|
||||
|
||||
public UnbakedModel getUnbakedModel() {
|
||||
return this.unbakedModel;
|
||||
}
|
||||
|
||||
public ModelBaker getModelLoader() {
|
||||
return this.modelLoader;
|
||||
}
|
||||
|
||||
public ModelBakery getModelBakery() {
|
||||
return this.modelBakery;
|
||||
}
|
||||
|
||||
public void setModel(BakedModel model) {
|
||||
this.model = model;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,11 +4,11 @@ import net.minecraft.client.renderer.block.model.BlockModel;
|
|||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||
import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider;
|
||||
import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
|
@ -48,6 +48,15 @@ public abstract class ModelBakerImplMixin {
|
|||
ibakedmodel = ModelBakery.ITEM_MODEL_GENERATOR.generateBlockModel(textureGetter, blockmodel).bake((ModelBaker)this, blockmodel, textureGetter, arg2, arg, false);
|
||||
}
|
||||
}
|
||||
if(iunbakedmodel != extendedBakery.mfix$getUnbakedMissingModel()) {
|
||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
||||
try {
|
||||
iunbakedmodel = integration.onUnbakedModelPreBake(arg, iunbakedmodel, (ModelBakery)(Object)this);
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Exception encountered firing bake event for {}", arg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ibakedmodel == null) {
|
||||
if(iunbakedmodel == extendedBakery.mfix$getUnbakedMissingModel()) {
|
||||
// use a shared baked missing model
|
||||
|
|
@ -59,10 +68,11 @@ public abstract class ModelBakerImplMixin {
|
|||
} else
|
||||
ibakedmodel = iunbakedmodel.bake((ModelBaker)this, textureGetter, arg2, arg);
|
||||
}
|
||||
DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, iunbakedmodel, ibakedmodel, (ModelBaker)this, this.field_40571);
|
||||
MinecraftForge.EVENT_BUS.post(event);
|
||||
this.field_40571.bakedCache.put(key, event.getModel());
|
||||
cir.setReturnValue(event.getModel());
|
||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
||||
ibakedmodel = integration.onBakedModelLoad(arg, iunbakedmodel, ibakedmodel, arg2, this.field_40571);
|
||||
}
|
||||
this.field_40571.bakedCache.put(key, ibakedmodel);
|
||||
cir.setReturnValue(ibakedmodel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
|
|
@ -26,6 +28,7 @@ import org.spongepowered.asm.mixin.Mutable;
|
|||
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.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
|
@ -157,6 +160,18 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
return unbakedCache.get(rl);
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "cacheAndQueueDependencies", at = @At("HEAD"), argsOnly = true)
|
||||
private UnbakedModel fireUnbakedEvent(UnbakedModel model, ResourceLocation location) {
|
||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
||||
try {
|
||||
model = integration.onUnbakedModelLoad(location, model, (ModelBakery)(Object)this);
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Exception firing model load event for {}", location, e);
|
||||
}
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
@Inject(method = "cacheAndQueueDependencies", at = @At("RETURN"))
|
||||
private void addToSmallLoadingCache(ResourceLocation location, UnbakedModel model, CallbackInfo ci) {
|
||||
smallLoadingCache.put(location, model);
|
||||
|
|
@ -229,10 +244,10 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BakedModel bakeDefault(ResourceLocation modelLocation) {
|
||||
public BakedModel bakeDefault(ResourceLocation modelLocation, ModelState state) {
|
||||
ModelBakery self = (ModelBakery) (Object) this;
|
||||
ModelBaker theBaker = self.new ModelBakerImpl(textureGetter, modelLocation);
|
||||
return theBaker.bake(modelLocation, BlockModelRotation.X0_Y0);
|
||||
return theBaker.bake(modelLocation, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
package org.embeddedt.modernfix.forge.mixin.perf.dynamic_resources.ae2;
|
||||
|
||||
import appeng.core.AppEng;
|
||||
import appeng.init.client.InitAutoRotatingModel;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent;
|
||||
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;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Mixin(InitAutoRotatingModel.class)
|
||||
@RequiresMod("appliedenergistics2")
|
||||
@ClientOnlyMixin
|
||||
public class RegistrationMixin {
|
||||
@Shadow @Final private static Map<String, Function<BakedModel, BakedModel>> CUSTOMIZERS;
|
||||
@Inject(method = "init", at = @At("TAIL"), remap = false)
|
||||
private static void doRegisterDynBake(CallbackInfo ci) {
|
||||
MinecraftForge.EVENT_BUS.addListener(RegistrationMixin::onDynamicModelBake);
|
||||
}
|
||||
|
||||
private static void onDynamicModelBake(DynamicModelBakeEvent event) {
|
||||
if (!event.getLocation().getNamespace().equals(AppEng.MOD_ID)) {
|
||||
return;
|
||||
}
|
||||
BakedModel missing = event.getModelBakery().getBakedTopLevelModels().get(ModelBakery.MISSING_MODEL_LOCATION);
|
||||
if(event.getModel() == missing)
|
||||
return;
|
||||
Function<BakedModel, BakedModel> customizerFn = CUSTOMIZERS.get(event.getLocation().getPath());
|
||||
if(customizerFn != null)
|
||||
event.setModel(customizerFn.apply(event.getModel()));
|
||||
}
|
||||
}
|
||||
|
|
@ -3,24 +3,20 @@ package org.embeddedt.modernfix.forge.mixin.perf.dynamic_resources.ctm;
|
|||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.client.renderer.ItemBlockRenderTypes;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.MultiPartBakedModel;
|
||||
import net.minecraft.client.resources.model.WeightedBakedModel;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.client.ChunkRenderTypeSet;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||
import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.embeddedt.modernfix.api.helpers.ModelHelpers;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
|
|
@ -38,7 +34,7 @@ import java.util.function.Predicate;
|
|||
@Mixin(CTMPackReloadListener.class)
|
||||
@RequiresMod("ctm")
|
||||
@ClientOnlyMixin
|
||||
public abstract class CTMPackReloadListenerMixin {
|
||||
public abstract class CTMPackReloadListenerMixin implements ModernFixClientIntegration {
|
||||
/* caches the original render checks */
|
||||
@Shadow @Final private static Map<Holder.Reference<Block>, Predicate<RenderType>> blockRenderChecks;
|
||||
|
||||
|
|
@ -52,7 +48,7 @@ public abstract class CTMPackReloadListenerMixin {
|
|||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void onInit(CallbackInfo ci) {
|
||||
MinecraftForge.EVENT_BUS.addListener(EventPriority.LOW, this::onModelBake);
|
||||
ModernFixClient.CLIENT_INTEGRATIONS.add(this);
|
||||
}
|
||||
|
||||
@Overwrite(remap = false)
|
||||
|
|
@ -77,28 +73,32 @@ public abstract class CTMPackReloadListenerMixin {
|
|||
return override.test(type);
|
||||
}
|
||||
|
||||
private void onModelBake(DynamicModelBakeEvent event) {
|
||||
if(!(event.getModel() instanceof AbstractCTMBakedModel || event.getModel() instanceof WeightedBakedModel || event.getModel() instanceof MultiPartBakedModel))
|
||||
return;
|
||||
@Override
|
||||
public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState modelState, ModelBakery bakery) {
|
||||
if(!(location instanceof ModelResourceLocation))
|
||||
return originalModel;
|
||||
if(!(originalModel instanceof AbstractCTMBakedModel || originalModel instanceof WeightedBakedModel || originalModel instanceof MultiPartBakedModel))
|
||||
return originalModel;
|
||||
/* we construct a new ResourceLocation because an MRL is coming in */
|
||||
Block block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(event.getLocation().getNamespace(), event.getLocation().getPath()));
|
||||
Block block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(location.getNamespace(), location.getPath()));
|
||||
Holder.Reference<Block> delegate = block != null ? ForgeRegistries.BLOCKS.getDelegateOrThrow(block) : null;
|
||||
if(block == null || block == Blocks.AIR || renderCheckOverrides.containsKey(delegate))
|
||||
return;
|
||||
return originalModel;
|
||||
/* find all states that match this MRL */
|
||||
ImmutableList<BlockState> allStates;
|
||||
try {
|
||||
allStates = ((IExtendedModelBakery)(Object)event.getModelLoader()).getBlockStatesForMRL(block.getStateDefinition(), (ModelResourceLocation)event.getLocation());
|
||||
allStates = ModelHelpers.getBlockStateForLocation(block.getStateDefinition(), (ModelResourceLocation)location);
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Couldn't get state for MRL " + event.getLocation(), e);
|
||||
return;
|
||||
ModernFix.LOGGER.error("Couldn't get state for MRL " + location, e);
|
||||
return originalModel;
|
||||
}
|
||||
for(BlockState state : allStates) {
|
||||
Predicate<RenderType> newPredicate = this.getLayerCheck(state, event.getModel());
|
||||
Predicate<RenderType> newPredicate = this.getLayerCheck(state, originalModel);
|
||||
if(newPredicate != null) {
|
||||
renderCheckOverrides.put(delegate, newPredicate);
|
||||
return;
|
||||
return originalModel;
|
||||
}
|
||||
}
|
||||
return originalModel;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
package org.embeddedt.modernfix.forge.mixin.perf.dynamic_resources.ctm;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.Material;
|
||||
import net.minecraft.client.resources.model.ModelBaker;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||
import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.embeddedt.modernfix.api.helpers.ModelHelpers;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
|
@ -29,13 +27,13 @@ import java.util.*;
|
|||
@Mixin(TextureMetadataHandler.class)
|
||||
@RequiresMod("ctm")
|
||||
@ClientOnlyMixin
|
||||
public abstract class TextureMetadataHandlerMixin {
|
||||
public abstract class TextureMetadataHandlerMixin implements ModernFixClientIntegration {
|
||||
|
||||
@Shadow @Nonnull protected abstract BakedModel wrap(ResourceLocation loc, UnbakedModel model, BakedModel object, ModelBaker loader) throws IOException;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void subscribeDynamic(CallbackInfo ci) {
|
||||
MinecraftForge.EVENT_BUS.addListener(this::onDynamicModelBake);
|
||||
ModernFixClient.CLIENT_INTEGRATIONS.add(this);
|
||||
}
|
||||
|
||||
@Redirect(method = "onModelBake", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/BakedModel;isCustomRenderer()Z"))
|
||||
|
|
@ -43,10 +41,8 @@ public abstract class TextureMetadataHandlerMixin {
|
|||
return model == null || model.isCustomRenderer();
|
||||
}
|
||||
|
||||
public void onDynamicModelBake(DynamicModelBakeEvent event) {
|
||||
UnbakedModel rootModel = event.getUnbakedModel();
|
||||
BakedModel baked = event.getModel();
|
||||
ResourceLocation rl = event.getLocation();
|
||||
@Override
|
||||
public BakedModel onBakedModelLoad(ResourceLocation rl, UnbakedModel rootModel, BakedModel baked, ModelState state, ModelBakery bakery) {
|
||||
if (!(baked instanceof AbstractCTMBakedModel) && !baked.isCustomRenderer()) {
|
||||
Deque<ResourceLocation> dependencies = new ArrayDeque<>();
|
||||
Set<ResourceLocation> seenModels = new HashSet<>();
|
||||
|
|
@ -59,7 +55,7 @@ public abstract class TextureMetadataHandlerMixin {
|
|||
ResourceLocation dep = dependencies.pop();
|
||||
UnbakedModel model;
|
||||
try {
|
||||
model = dep == rl ? rootModel : event.getModelLoader().getModel(dep);
|
||||
model = dep == rl ? rootModel : bakery.getModel(dep);
|
||||
} catch (Exception e) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -87,12 +83,13 @@ public abstract class TextureMetadataHandlerMixin {
|
|||
}
|
||||
if (shouldWrap) {
|
||||
try {
|
||||
event.setModel(wrap(rl, rootModel, baked, event.getModelLoader()));
|
||||
baked = wrap(rl, rootModel, baked, ModelHelpers.adaptBakery(bakery));
|
||||
dependencies.clear();
|
||||
} catch (IOException e) {
|
||||
CTM.logger.error("Could not wrap model " + rl + ". Aborting...", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return baked;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ package org.embeddedt.modernfix.forge.mixin.perf.dynamic_resources.rs;
|
|||
|
||||
import com.refinedmods.refinedstorage.render.BakedModelOverrideRegistry;
|
||||
import com.refinedmods.refinedstorage.setup.ClientSetup;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||
import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
|
@ -15,20 +15,24 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
|
||||
@Mixin(ClientSetup.class)
|
||||
@RequiresMod("refinedstorage")
|
||||
@ClientOnlyMixin
|
||||
public class ClientSetupMixin {
|
||||
@Shadow @Final private static BakedModelOverrideRegistry BAKED_MODEL_OVERRIDE_REGISTRY;
|
||||
|
||||
@Inject(method = "onClientSetup", at = @At("RETURN"), remap = false)
|
||||
private static void addDynamicListener(CallbackInfo ci) {
|
||||
MinecraftForge.EVENT_BUS.addListener(ClientSetupMixin::onDynamicModelBake);
|
||||
}
|
||||
|
||||
private static void onDynamicModelBake(DynamicModelBakeEvent event) {
|
||||
BakedModelOverrideRegistry.BakedModelOverrideFactory factory = BAKED_MODEL_OVERRIDE_REGISTRY.get(event.getLocation() instanceof ModelResourceLocation ? new ResourceLocation(event.getLocation().getNamespace(), event.getLocation().getPath()) : event.getLocation());
|
||||
if(factory != null)
|
||||
event.setModel(factory.create(event.getModel(), event.getModelBakery().getBakedTopLevelModels()));
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void addDynamicListener(CallbackInfo ci) {
|
||||
ModernFixClient.CLIENT_INTEGRATIONS.add(new ModernFixClientIntegration() {
|
||||
@Override
|
||||
public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) {
|
||||
BakedModelOverrideRegistry.BakedModelOverrideFactory factory = BAKED_MODEL_OVERRIDE_REGISTRY.get(location instanceof ModelResourceLocation ? new ResourceLocation(location.getNamespace(), location.getPath()) : location);
|
||||
if(factory != null)
|
||||
return factory.create(originalModel, bakery.getBakedTopLevelModels());
|
||||
else
|
||||
return originalModel;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,14 @@ import com.supermartijn642.core.registry.ClientRegistrationHandler;
|
|||
import com.supermartijn642.core.util.Pair;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ModelState;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||
import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
|
@ -48,13 +50,15 @@ public class ClientRegistrationHandlerMixin {
|
|||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void registerDynBake(String modid, CallbackInfo ci) {
|
||||
MinecraftForge.EVENT_BUS.addListener(this::onDynamicModelBake);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onDynamicModelBake(DynamicModelBakeEvent event) {
|
||||
Function<BakedModel, BakedModel> replacer = modelOverwritesByLocation.get(event.getLocation());
|
||||
if(replacer != null)
|
||||
event.setModel(replacer.apply(event.getModel()));
|
||||
ModernFixClient.CLIENT_INTEGRATIONS.add(new ModernFixClientIntegration() {
|
||||
@Override
|
||||
public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) {
|
||||
Function<BakedModel, BakedModel> replacer = modelOverwritesByLocation.get(location);
|
||||
if(replacer != null)
|
||||
return replacer.apply(originalModel);
|
||||
else
|
||||
return originalModel;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package org.embeddedt.modernfix.platform.forge;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.minecraft.client.searchtree.SearchRegistry;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
|
@ -15,9 +17,10 @@ import net.minecraftforge.fml.ModLoader;
|
|||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.loading.FMLPaths;
|
||||
import net.minecraftforge.fml.loading.LoadingModList;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ExplodedDirectoryLocator;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
import net.minecraftforge.server.ServerLifecycleHooks;
|
||||
import org.embeddedt.modernfix.api.constants.IntegrationConstants;
|
||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||
import org.embeddedt.modernfix.forge.classloading.FastAccessTransformerList;
|
||||
import org.embeddedt.modernfix.forge.packet.PacketHandler;
|
||||
|
|
@ -55,7 +58,7 @@ public class ModernFixPlatformHooksImpl {
|
|||
}
|
||||
|
||||
public static boolean isDevEnv() {
|
||||
return !FMLLoader.isProduction() && FMLLoader.getLoadingModList().getModFileById("modernfix").getFile().getProvider() instanceof ExplodedDirectoryLocator;
|
||||
return !FMLLoader.isProduction();
|
||||
}
|
||||
|
||||
public static MinecraftServer getCurrentServer() {
|
||||
|
|
@ -100,11 +103,31 @@ public class ModernFixPlatformHooksImpl {
|
|||
});
|
||||
}
|
||||
|
||||
private static Multimap<String, String> modOptions;
|
||||
public static Multimap<String, String> getCustomModOptions() {
|
||||
if(modOptions == null) {
|
||||
modOptions = ArrayListMultimap.create();
|
||||
for (ModInfo meta : LoadingModList.get().getMods()) {
|
||||
meta.getConfigElement(IntegrationConstants.INTEGRATIONS_KEY).ifPresent(optionsObj -> {
|
||||
if(optionsObj instanceof Map) {
|
||||
Map<Object, Object> options = (Map<Object, Object>)optionsObj;
|
||||
options.forEach((key, value) -> {
|
||||
if(key instanceof String && value instanceof String) {
|
||||
modOptions.put((String)key, (String)value);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return modOptions;
|
||||
}
|
||||
|
||||
public static void registerCreativeSearchTrees(SearchRegistry registry, SearchRegistry.TreeBuilderSupplier<ItemStack> nameSupplier, SearchRegistry.TreeBuilderSupplier<ItemStack> tagSupplier, BiConsumer<SearchRegistry.Key<ItemStack>, List<ItemStack>> populator) {
|
||||
for(SearchRegistry.Key<ItemStack> nameKey : CreativeModeTabSearchRegistry.getNameSearchKeys().values()) {
|
||||
for (SearchRegistry.Key<ItemStack> nameKey : CreativeModeTabSearchRegistry.getNameSearchKeys().values()) {
|
||||
registry.register(nameKey, nameSupplier);
|
||||
}
|
||||
for(SearchRegistry.Key<ItemStack> tagKey : CreativeModeTabSearchRegistry.getTagSearchKeys().values()) {
|
||||
for (SearchRegistry.Key<ItemStack> tagKey : CreativeModeTabSearchRegistry.getTagSearchKeys().values()) {
|
||||
registry.register(tagKey, tagSupplier);
|
||||
}
|
||||
Map<CreativeModeTab, SearchRegistry.Key<ItemStack>> tagSearchKeys = CreativeModeTabSearchRegistry.getTagSearchKeys();
|
||||
|
|
|
|||
|
|
@ -19,3 +19,4 @@ fabric_api_version=0.81.2+1.20
|
|||
continuity_version=3.0.0-beta.2+1.19.3
|
||||
|
||||
modmenu_version=7.0.0-beta.2
|
||||
diagonal_fences_version=4545943
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user