Replace Forge dynamic model bake event with modloader-independent custom solution
This commit is contained in:
parent
45d308c6a4
commit
b4ffe68adb
|
|
@ -10,6 +10,8 @@ import net.minecraft.network.syncher.EntityDataAccessor;
|
|||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
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;
|
||||
|
|
@ -29,12 +31,24 @@ public class ModernFixClient {
|
|||
|
||||
public String brandingString = null;
|
||||
|
||||
/**
|
||||
* The list of loaded client integrations.
|
||||
*/
|
||||
public static List<ModernFixClientIntegration> CLIENT_INTEGRATIONS = new ArrayList<>();
|
||||
|
||||
public ModernFixClient() {
|
||||
// clear reserve as it's not needed
|
||||
Minecraft.reserve = new byte[0];
|
||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.branding.F3Screen")) {
|
||||
brandingString = "ModernFix " + ModernFixPlatformHooks.getVersionString();
|
||||
}
|
||||
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,49 @@
|
|||
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 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,55 @@
|
|||
package org.embeddedt.modernfix.api.helpers;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.ModelState;
|
||||
import net.minecraft.core.Registry;
|
||||
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.dynamicresources.ModelBakeryHelpers;
|
||||
import org.embeddedt.modernfix.util.DynamicMap;
|
||||
|
||||
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 = Registry.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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.embeddedt.modernfix.platform;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import dev.architectury.injectables.annotations.ExpectPlatform;
|
||||
|
|
@ -85,4 +86,9 @@ public class ModernFixPlatformHooks {
|
|||
public static void onServerCommandRegister(Consumer<CommandDispatcher<CommandSourceStack>> handler) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@ExpectPlatform
|
||||
public static Multimap<String, String> getCustomModOptions() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
package org.embeddedt.modernfix.platform.fabric;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.fabric.api.command.v1.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.renderer.texture.TextureAtlas;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
|
@ -14,6 +18,7 @@ import net.minecraft.server.level.ServerPlayer;
|
|||
import net.minecraft.server.packs.resources.Resource;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import org.embeddedt.modernfix.ModernFixFabric;
|
||||
import org.embeddedt.modernfix.api.constants.IntegrationConstants;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
|
@ -82,4 +87,26 @@ public class ModernFixPlatformHooksImpl {
|
|||
public static void onServerCommandRegister(Consumer<CommandDispatcher<CommandSourceStack>> handler) {
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, arg) -> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
package org.embeddedt.modernfix.forge.dynamicresources;
|
||||
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
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 ModelLoader modelLoader;
|
||||
public DynamicModelBakeEvent(ResourceLocation location, UnbakedModel unbakedModel, BakedModel model, ModelLoader loader) {
|
||||
this.location = location;
|
||||
this.model = model;
|
||||
this.unbakedModel = unbakedModel;
|
||||
this.modelLoader = loader;
|
||||
}
|
||||
|
||||
public ResourceLocation getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
public BakedModel getModel() {
|
||||
return this.model;
|
||||
}
|
||||
|
||||
public UnbakedModel getUnbakedModel() {
|
||||
return this.unbakedModel;
|
||||
}
|
||||
|
||||
public ModelLoader getModelLoader() {
|
||||
return this.modelLoader;
|
||||
}
|
||||
|
||||
public void setModel(BakedModel model) {
|
||||
this.model = model;
|
||||
}
|
||||
}
|
||||
|
|
@ -26,26 +26,23 @@ 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 net.minecraftforge.client.ForgeHooksClient;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.fml.packs.DelegatingResourcePack;
|
||||
import net.minecraftforge.fml.packs.ModFileResourcePack;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
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.forge.dynamicresources.DynamicModelBakeEvent;
|
||||
import org.embeddedt.modernfix.dynamicresources.ModelBakeryHelpers;
|
||||
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.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.*;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
|
|
@ -90,6 +87,8 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
|
||||
@Shadow @Nullable public abstract BakedModel getBakedModel(ResourceLocation arg, ModelState arg2, Function<Material, TextureAtlasSprite> textureGetter);
|
||||
|
||||
@Shadow @org.jetbrains.annotations.Nullable public abstract BakedModel bake(ResourceLocation location, ModelState transform);
|
||||
|
||||
private Cache<Triple<ResourceLocation, Transformation, Boolean>, BakedModel> loadedBakedModels;
|
||||
private Cache<ResourceLocation, UnbakedModel> loadedModels;
|
||||
|
||||
|
|
@ -217,6 +216,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);
|
||||
|
|
@ -329,10 +340,15 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
} else
|
||||
ibakedmodel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg);
|
||||
}
|
||||
DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, iunbakedmodel, ibakedmodel, (ModelLoader)(Object)this);
|
||||
MinecraftForge.EVENT_BUS.post(event);
|
||||
this.bakedCache.put(triple, event.getModel());
|
||||
cir.setReturnValue(event.getModel());
|
||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
||||
try {
|
||||
ibakedmodel = integration.onBakedModelLoad(arg, iunbakedmodel, ibakedmodel, arg2, (ModelBakery)(Object)this);
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Exception encountered firing bake event for {}", arg, e);
|
||||
}
|
||||
}
|
||||
this.bakedCache.put(triple, ibakedmodel);
|
||||
cir.setReturnValue(ibakedmodel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,21 +4,21 @@ import appeng.bootstrap.components.IModelBakeComponent;
|
|||
import appeng.bootstrap.components.ModelOverrideComponent;
|
||||
import appeng.core.Api;
|
||||
import appeng.core.AppEng;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
|
||||
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.forge.dynamicresources.DynamicModelBakeEvent;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
|
|
@ -29,34 +29,33 @@ public class RegistrationMixin {
|
|||
private static Field customizerField;
|
||||
@Inject(method = "registerClientEvents", at = @At("TAIL"), remap = false)
|
||||
private void doRegisterDynBake(CallbackInfo ci) {
|
||||
MinecraftForge.EVENT_BUS.addListener(this::onDynamicModelBake);
|
||||
customizerField = ObfuscationReflectionHelper.findField(ModelOverrideComponent.class, "customizer");
|
||||
}
|
||||
|
||||
private void onDynamicModelBake(DynamicModelBakeEvent event) {
|
||||
if (!event.getLocation().getNamespace().equals(AppEng.MOD_ID)) {
|
||||
return;
|
||||
}
|
||||
BakedModel missing = event.getModelLoader().getBakedTopLevelModels().get(ModelBakery.MISSING_MODEL_LOCATION);
|
||||
if(event.getModel() == missing)
|
||||
return;
|
||||
Api.INSTANCE.definitions().getRegistry().getBootstrapComponents(IModelBakeComponent.class).forEachRemaining(c -> {
|
||||
if(c instanceof ModelOverrideComponent)
|
||||
handleModelOverride((ModelOverrideComponent)c, event);
|
||||
ModernFixClient.CLIENT_INTEGRATIONS.add(new ModernFixClientIntegration() {
|
||||
@Override
|
||||
public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) {
|
||||
if(location.getNamespace().equals(AppEng.MOD_ID)) {
|
||||
BakedModel m = bakery.bake(ModelBakery.MISSING_MODEL_LOCATION, BlockModelRotation.X0_Y0);
|
||||
if(originalModel == m)
|
||||
return originalModel;
|
||||
Iterator<IModelBakeComponent> components = Api.INSTANCE.definitions().getRegistry().getBootstrapComponents(IModelBakeComponent.class);
|
||||
while(components.hasNext()) {
|
||||
IModelBakeComponent c = components.next();
|
||||
if(c instanceof ModelOverrideComponent) {
|
||||
Map<String, BiFunction<ResourceLocation, BakedModel, BakedModel>> customizer;
|
||||
try {
|
||||
customizer = (Map<String, BiFunction<ResourceLocation, BakedModel, BakedModel>>)customizerField.get(c);
|
||||
} catch(ReflectiveOperationException e) {
|
||||
ModernFix.LOGGER.error("Can't replace model", e);
|
||||
continue;
|
||||
}
|
||||
BiFunction<ResourceLocation, BakedModel, BakedModel> fn = customizer.get(location.getPath());
|
||||
if(fn != null)
|
||||
originalModel = fn.apply(location, originalModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
return originalModel;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleModelOverride(ModelOverrideComponent c, DynamicModelBakeEvent event) {
|
||||
Map<String, BiFunction<ResourceLocation, BakedModel, BakedModel>> customizer;
|
||||
try {
|
||||
customizer = (Map<String, BiFunction<ResourceLocation, BakedModel, BakedModel>>)customizerField.get(c);
|
||||
} catch(ReflectiveOperationException e) {
|
||||
ModernFix.LOGGER.error("Can't replace model", e);
|
||||
return;
|
||||
}
|
||||
BiFunction<ResourceLocation, BakedModel, BakedModel> fn = customizer.get(event.getLocation().getPath());
|
||||
if(fn != null) {
|
||||
event.setModel(fn.apply(event.getLocation(), event.getModel()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,23 +3,19 @@ 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.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.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.IRegistryDelegate;
|
||||
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;
|
||||
|
|
@ -37,7 +33,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<IRegistryDelegate<Block>, Predicate<RenderType>> blockRenderChecks;
|
||||
|
||||
|
|
@ -51,7 +47,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)
|
||||
|
|
@ -75,27 +71,31 @@ 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()));
|
||||
if(block == null || block == Blocks.AIR || renderCheckOverrides.containsKey(block.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(block.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.UnbakedModel;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
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.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, ModelLoader 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,12 +55,12 @@ 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;
|
||||
}
|
||||
|
||||
Collection<Material> textures = model.getMaterials(event.getModelLoader()::getModel, errors);
|
||||
Collection<Material> textures = model.getMaterials(bakery::getModel, errors);
|
||||
Collection<ResourceLocation> newDependencies = model.getDependencies();
|
||||
for (Material tex : textures) {
|
||||
IMetadataSectionCTM meta = null;
|
||||
|
|
@ -86,12 +82,13 @@ public abstract class TextureMetadataHandlerMixin {
|
|||
}
|
||||
if (shouldWrap) {
|
||||
try {
|
||||
event.setModel(wrap(rl, rootModel, baked, event.getModelLoader()));
|
||||
baked = wrap(rl, rootModel, baked, (ModelLoader)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,6 +15,7 @@ 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
|
||||
|
|
@ -23,12 +24,15 @@ public class ClientSetupMixin {
|
|||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void addDynamicListener(CallbackInfo ci) {
|
||||
MinecraftForge.EVENT_BUS.addListener(this::onDynamicModelBake);
|
||||
}
|
||||
|
||||
private void onDynamicModelBake(DynamicModelBakeEvent event) {
|
||||
BakedModelOverrideRegistry.BakedModelOverrideFactory factory = bakedModelOverrideRegistry.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.getModelLoader().getBakedTopLevelModels()));
|
||||
ModernFixClient.CLIENT_INTEGRATIONS.add(new ModernFixClientIntegration() {
|
||||
@Override
|
||||
public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) {
|
||||
BakedModelOverrideRegistry.BakedModelOverrideFactory factory = bakedModelOverrideRegistry.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.google.common.io.Resources;
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
|
|
@ -23,8 +25,10 @@ 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.fml.network.PacketDistributor;
|
||||
import net.minecraftforge.fml.server.ServerLifecycleHooks;
|
||||
import org.embeddedt.modernfix.api.constants.IntegrationConstants;
|
||||
import org.embeddedt.modernfix.forge.classloading.FastAccessTransformerList;
|
||||
import org.embeddedt.modernfix.forge.classloading.ModernFixResourceFinder;
|
||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||
|
|
@ -255,4 +259,24 @@ public class ModernFixPlatformHooksImpl {
|
|||
handler.accept(event.getDispatcher());
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user