Enable NeoForge project
This commit is contained in:
parent
9d584d13d2
commit
6e9dfaf0c6
|
|
@ -1,12 +1,5 @@
|
|||
package org.embeddedt.modernfix.api.entrypoint;
|
||||
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
|
@ -20,58 +13,4 @@ public interface ModernFixClientIntegration {
|
|||
*/
|
||||
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
|
||||
*/
|
||||
@Deprecated
|
||||
default BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, 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
|
||||
* @param textureGetter function to retrieve textures for this model
|
||||
* @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, Function<Material, TextureAtlasSprite> textureGetter) {
|
||||
return onBakedModelLoad(location, baseModel, originalModel, state, bakery);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import org.embeddedt.modernfix.searchtree.RecipeBookSearchTree;
|
|||
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;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
|
@ -28,6 +29,8 @@ import java.util.concurrent.CompletableFuture;
|
|||
public abstract class SessionSearchTreesMixin {
|
||||
@Shadow private CompletableFuture<SearchTree<RecipeCollection>> recipeSearch;
|
||||
@Shadow private CompletableFuture<SearchTree<ItemStack>> creativeByNameSearch;
|
||||
@Shadow @Final private static SessionSearchTrees.Key CREATIVE_NAMES;
|
||||
@Shadow @Final private static SessionSearchTrees.Key CREATIVE_TAGS;
|
||||
private SearchTreeProviderRegistry.Provider mfix$provider;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
|
|
@ -63,11 +66,12 @@ public abstract class SessionSearchTreesMixin {
|
|||
}
|
||||
}
|
||||
|
||||
@ModifyArg(method = "updateCreativeTooltips", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/SessionSearchTrees;register(Lnet/minecraft/client/multiplayer/SessionSearchTrees$Key;Ljava/lang/Runnable;)V"), index = 1)
|
||||
private Runnable useSearchModItems(Runnable r) {
|
||||
@ModifyArg(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/SessionSearchTrees;register(Lnet/minecraft/client/multiplayer/SessionSearchTrees$Key;Ljava/lang/Runnable;)V"), index = 1)
|
||||
private Runnable useOverridenSearchTreeLogic(SessionSearchTrees.Key key, Runnable r) {
|
||||
if(mfix$provider == null) {
|
||||
return r;
|
||||
} else {
|
||||
}
|
||||
if(key == CREATIVE_NAMES) {
|
||||
return () -> {
|
||||
CompletableFuture<?> old = this.creativeByNameSearch;
|
||||
this.creativeByNameSearch = CompletableFuture.supplyAsync(() -> {
|
||||
|
|
@ -76,13 +80,7 @@ public abstract class SessionSearchTreesMixin {
|
|||
old.cancel(true);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyArg(method = "updateCreativeTags", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/SessionSearchTrees;register(Lnet/minecraft/client/multiplayer/SessionSearchTrees$Key;Ljava/lang/Runnable;)V"), index = 1)
|
||||
private Runnable useSearchModTags(Runnable r) {
|
||||
if(mfix$provider == null) {
|
||||
return r;
|
||||
} else {
|
||||
if(key == CREATIVE_TAGS) {
|
||||
return () -> {
|
||||
CompletableFuture<?> old = this.creativeByNameSearch;
|
||||
this.creativeByNameSearch = CompletableFuture.supplyAsync(() -> {
|
||||
|
|
@ -91,5 +89,6 @@ public abstract class SessionSearchTreesMixin {
|
|||
old.cancel(true);
|
||||
};
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,13 @@ package org.embeddedt.modernfix.dynamicresources;
|
|||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
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 net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class ModelBakeryHelpers {
|
||||
/**
|
||||
|
|
@ -108,13 +104,4 @@ public class ModelBakeryHelpers {
|
|||
}
|
||||
return ImmutableList.copyOf(finalList);
|
||||
}
|
||||
|
||||
public static ModernFixClientIntegration bakedModelWrapper(BiFunction<ResourceLocation, Pair<UnbakedModel, BakedModel>, BakedModel> consumer) {
|
||||
return new ModernFixClientIntegration() {
|
||||
@Override
|
||||
public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) {
|
||||
return consumer.apply(location, Pair.of(baseModel, originalModel));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,4 +38,5 @@ accessible field net/minecraft/client/renderer/block/model/multipart/MultiPart d
|
|||
accessible field net/minecraft/client/renderer/block/model/ItemOverrides$BakedOverride model Lnet/minecraft/client/resources/model/BakedModel;
|
||||
mutable field net/minecraft/client/renderer/block/model/ItemOverrides$BakedOverride model Lnet/minecraft/client/resources/model/BakedModel;
|
||||
accessible field net/minecraft/client/renderer/entity/EnderDragonRenderer$DragonModel entity Lnet/minecraft/world/entity/boss/enderdragon/EnderDragon;
|
||||
accessible method net/minecraft/world/level/block/state/StateDefinition appendPropertyCodec (Lcom/mojang/serialization/MapCodec;Ljava/util/function/Supplier;Ljava/lang/String;Lnet/minecraft/world/level/block/state/properties/Property;)Lcom/mojang/serialization/MapCodec;
|
||||
accessible method net/minecraft/world/level/block/state/StateDefinition appendPropertyCodec (Lcom/mojang/serialization/MapCodec;Ljava/util/function/Supplier;Ljava/lang/String;Lnet/minecraft/world/level/block/state/properties/Property;)Lcom/mojang/serialization/MapCodec;
|
||||
accessible class net/minecraft/client/multiplayer/SessionSearchTrees$Key
|
||||
|
|
@ -5,9 +5,10 @@ junit_version=5.10.0-M1
|
|||
mixinextras_version=0.3.2
|
||||
|
||||
mod_id=modernfix
|
||||
minecraft_version=1.21-pre3
|
||||
enabled_platforms=fabric
|
||||
forge_version=20.6.100-beta
|
||||
minecraft_version=1.21-pre4
|
||||
enabled_platforms=fabric,neoforge
|
||||
forge_version=21.0.0-alpha.1.21-pre4.20240609.000029
|
||||
neoforge_pr=1076
|
||||
# parchment_version=2023.07.09
|
||||
refined_storage_version=4392788
|
||||
jei_version=16.0.0.28
|
||||
|
|
@ -15,7 +16,7 @@ rei_version=13.0.678
|
|||
ctm_version=1.20.1-1.1.8+4
|
||||
kubejs_version=1902.6.0-build.142
|
||||
rhino_version=1902.2.2-build.268
|
||||
supported_minecraft_versions=1.21-pre3
|
||||
supported_minecraft_versions=1.21-pre4
|
||||
|
||||
fabric_loader_version=0.15.11
|
||||
fabric_api_version=0.100.0+1.21
|
||||
|
|
|
|||
|
|
@ -31,6 +31,15 @@ repositories {
|
|||
}
|
||||
}
|
||||
maven { url "https://maven.neoforged.net" }
|
||||
if(rootProject.hasProperty("neoforge_pr")) {
|
||||
maven {
|
||||
url 'https://prmaven.neoforged.net/NeoForge/pr' + rootProject.neoforge_pr
|
||||
content {
|
||||
includeModule('net.neoforged', 'neoforge')
|
||||
includeModule('net.neoforged', 'testframework')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class ModernFixConfig {
|
|||
|
||||
public static Set<ResourceLocation> getJeiPluginBlacklist() {
|
||||
if(jeiPluginBlacklist == null) {
|
||||
jeiPluginBlacklist = BLACKLIST_ASYNC_JEI_PLUGINS.get().stream().map(ResourceLocation::new).collect(Collectors.toSet());
|
||||
jeiPluginBlacklist = BLACKLIST_ASYNC_JEI_PLUGINS.get().stream().map(ResourceLocation::parse).collect(Collectors.toSet());
|
||||
}
|
||||
return jeiPluginBlacklist;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,10 +34,10 @@ public class ModelBakeEventHelper {
|
|||
"vampirism",
|
||||
"elevatorid",
|
||||
"embers");
|
||||
private final Map<ResourceLocation, BakedModel> modelRegistry;
|
||||
private final Set<ResourceLocation> topLevelModelLocations;
|
||||
private final Map<ModelResourceLocation, BakedModel> modelRegistry;
|
||||
private final Set<ModelResourceLocation> topLevelModelLocations;
|
||||
private final MutableGraph<String> dependencyGraph;
|
||||
public ModelBakeEventHelper(Map<ResourceLocation, BakedModel> modelRegistry) {
|
||||
public ModelBakeEventHelper(Map<ModelResourceLocation, BakedModel> modelRegistry) {
|
||||
this.modelRegistry = modelRegistry;
|
||||
this.topLevelModelLocations = new HashSet<>(modelRegistry.keySet());
|
||||
// Skip going through ModelLocationCache because most of the accesses will be misses
|
||||
|
|
@ -74,10 +74,10 @@ public class ModelBakeEventHelper {
|
|||
* @param modId the mod that the event is being fired for
|
||||
* @return a wrapper around the model registry
|
||||
*/
|
||||
private Map<ResourceLocation, BakedModel> createWarningRegistry(String modId) {
|
||||
return new ForwardingInclDefaultsMap<ResourceLocation, BakedModel>() {
|
||||
private Map<ModelResourceLocation, BakedModel> createWarningRegistry(String modId) {
|
||||
return new ForwardingInclDefaultsMap<ModelResourceLocation, BakedModel>() {
|
||||
@Override
|
||||
protected Map<ResourceLocation, BakedModel> delegate() {
|
||||
protected Map<ModelResourceLocation, BakedModel> delegate() {
|
||||
return modelRegistry;
|
||||
}
|
||||
|
||||
|
|
@ -89,13 +89,13 @@ public class ModelBakeEventHelper {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceLocation> keySet() {
|
||||
public Set<ModelResourceLocation> keySet() {
|
||||
logWarning();
|
||||
return super.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<ResourceLocation, BakedModel>> entrySet() {
|
||||
public Set<Entry<ModelResourceLocation, BakedModel>> entrySet() {
|
||||
logWarning();
|
||||
return super.entrySet();
|
||||
}
|
||||
|
|
@ -107,14 +107,14 @@ public class ModelBakeEventHelper {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void replaceAll(BiFunction<? super ResourceLocation, ? super BakedModel, ? extends BakedModel> function) {
|
||||
public void replaceAll(BiFunction<? super ModelResourceLocation, ? super BakedModel, ? extends BakedModel> function) {
|
||||
logWarning();
|
||||
super.replaceAll(function);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Map<ResourceLocation, BakedModel> wrapRegistry(String modId) {
|
||||
public Map<ModelResourceLocation, BakedModel> wrapRegistry(String modId) {
|
||||
final Set<String> modIdsToInclude = new HashSet<>();
|
||||
modIdsToInclude.add(modId);
|
||||
try {
|
||||
|
|
@ -123,11 +123,11 @@ public class ModelBakeEventHelper {
|
|||
modIdsToInclude.remove("minecraft");
|
||||
if(modIdsToInclude.stream().noneMatch(INCOMPATIBLE_MODS::contains))
|
||||
return createWarningRegistry(modId);
|
||||
Set<ResourceLocation> ourModelLocations = Sets.filter(this.topLevelModelLocations, loc -> modIdsToInclude.contains(loc.getNamespace()));
|
||||
Set<ModelResourceLocation> ourModelLocations = Sets.filter(this.topLevelModelLocations, loc -> modIdsToInclude.contains(loc.id().getNamespace()));
|
||||
BakedModel missingModel = modelRegistry.get(ModelBakery.MISSING_MODEL_LOCATION);
|
||||
return new ForwardingMap<ResourceLocation, BakedModel>() {
|
||||
return new ForwardingMap<ModelResourceLocation, BakedModel>() {
|
||||
@Override
|
||||
protected Map<ResourceLocation, BakedModel> delegate() {
|
||||
protected Map<ModelResourceLocation, BakedModel> delegate() {
|
||||
return modelRegistry;
|
||||
}
|
||||
|
||||
|
|
@ -142,7 +142,7 @@ public class ModelBakeEventHelper {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceLocation> keySet() {
|
||||
public Set<ModelResourceLocation> keySet() {
|
||||
return ourModelLocations;
|
||||
}
|
||||
|
||||
|
|
@ -152,10 +152,10 @@ public class ModelBakeEventHelper {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void replaceAll(BiFunction<? super ResourceLocation, ? super BakedModel, ? extends BakedModel> function) {
|
||||
public void replaceAll(BiFunction<? super ModelResourceLocation, ? super BakedModel, ? extends BakedModel> function) {
|
||||
ModernFix.LOGGER.warn("Mod '{}' is calling replaceAll on the model registry. Some hacks will be used to keep this fast, but they may not be 100% compatible.", modId);
|
||||
List<ResourceLocation> locations = new ArrayList<>(keySet());
|
||||
for(ResourceLocation location : locations) {
|
||||
List<ModelResourceLocation> locations = new ArrayList<>(keySet());
|
||||
for(ModelResourceLocation location : locations) {
|
||||
/*
|
||||
* Fetching every model is insanely slow. So we call the function with a null object first, since it
|
||||
* probably isn't expecting that. If we get an exception thrown, or it returns nonnull, then we know
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ public class ModernFixForge {
|
|||
event.register(Registries.ITEM, helper -> {
|
||||
Item.Properties props = new Item.Properties();
|
||||
for(int i = 0; i < 1000000; i++) {
|
||||
helper.register(new ResourceLocation("modernfix", "item_" + i), new Item(props));
|
||||
helper.register(ResourceLocation.fromNamespaceAndPath("modernfix", "item_" + i), new Item(props));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package org.embeddedt.modernfix.neoforge.mixin.bugfix.chunk_deadlock;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.neoforged.fml.util.ObfuscationReflectionHelper;
|
||||
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 java.lang.reflect.Field;
|
||||
|
||||
@Mixin(ChunkMap.class)
|
||||
public abstract class ChunkMapLoadMixin {
|
||||
@Shadow @Nullable protected abstract ChunkHolder getVisibleChunkIfPresent(long l);
|
||||
|
||||
private static final Field currentlyLoadingField = ObfuscationReflectionHelper.findField(ChunkHolder.class, "currentlyLoading");
|
||||
|
||||
private static void setCurrentlyLoading(ChunkHolder holder, LevelChunk value) {
|
||||
try {
|
||||
currentlyLoadingField.set(holder, value);
|
||||
} catch(ReflectiveOperationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set currentlyLoading before calling runPostLoad and restore its old value afterwards. We track the old value
|
||||
* to avoid conflicting with Forge if/when this feature is added.
|
||||
*/
|
||||
@WrapOperation(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;runPostLoad()V"))
|
||||
private void setCurrentLoadingThenPostLoad(LevelChunk chunk, Operation<Void> operation) {
|
||||
ChunkHolder holder = this.getVisibleChunkIfPresent(chunk.getPos().toLong());
|
||||
if(holder != null) {
|
||||
LevelChunk prevLoading = null;
|
||||
try {
|
||||
prevLoading = (LevelChunk)currentlyLoadingField.get(holder);
|
||||
} catch(ReflectiveOperationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
setCurrentlyLoading(holder, chunk);
|
||||
operation.call(chunk);
|
||||
} finally {
|
||||
setCurrentlyLoading(holder, prevLoading);
|
||||
}
|
||||
} else {
|
||||
ModernFix.LOGGER.warn("Unable to find chunk holder for loading chunk");
|
||||
operation.call(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources;
|
|||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.neoforged.bus.api.Event;
|
||||
import net.neoforged.fml.ModContainer;
|
||||
import net.neoforged.fml.ModList;
|
||||
|
|
@ -33,7 +33,7 @@ public class ForgeHooksClientMixin {
|
|||
ModelBakeEventHelper helper = new ModelBakeEventHelper(bakeEvent.getModels());
|
||||
Method acceptEv = ObfuscationReflectionHelper.findMethod(ModContainer.class, "acceptEvent", Event.class);
|
||||
ModList.get().forEachModContainer((id, mc) -> {
|
||||
Map<ResourceLocation, BakedModel> newRegistry = helper.wrapRegistry(id);
|
||||
Map<ModelResourceLocation, BakedModel> newRegistry = helper.wrapRegistry(id);
|
||||
ModelEvent.ModifyBakingResult postedEvent = new ModelEvent.ModifyBakingResult(newRegistry, bakeEvent.getTextureGetter(), bakeEvent.getModelBakery());
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public abstract class ItemModelMesherForgeMixin extends ItemModelShaper {
|
|||
super(arg);
|
||||
}
|
||||
|
||||
private static final ModelResourceLocation SENTINEL = new ModelResourceLocation(new ResourceLocation("modernfix", "sentinel"), "sentinel");
|
||||
private static final ModelResourceLocation SENTINEL = new ModelResourceLocation(ResourceLocation.fromNamespaceAndPath("modernfix", "sentinel"), "sentinel");
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void replaceLocationMap(CallbackInfo ci) {
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrides;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelBaker;
|
||||
import net.minecraft.client.resources.model.ModelState;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelBaker;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@Mixin(ItemOverrides.class)
|
||||
@ClientOnlyMixin
|
||||
public class ItemOverridesForgeMixin {
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason servers insist on generating invalid item overrides that have missing models
|
||||
*/
|
||||
@WrapOperation(method = "bakeModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/ModelBaker;bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;Ljava/util/function/Function;)Lnet/minecraft/client/resources/model/BakedModel;"), remap = false)
|
||||
private BakedModel bake(ModelBaker instance, ResourceLocation resourceLocation, ModelState modelState, Function<ResourceLocation, TextureAtlasSprite> spriteGetter, Operation<BakedModel> original) {
|
||||
boolean prevState = ((IExtendedModelBaker)instance).throwOnMissingModel(false);
|
||||
try {
|
||||
return original.call(instance, resourceLocation, modelState, spriteGetter);
|
||||
} finally {
|
||||
((IExtendedModelBaker)instance).throwOnMissingModel(prevState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
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.IExtendedModelBaker;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||
import org.embeddedt.modernfix.dynamicresources.ModelMissingException;
|
||||
import org.embeddedt.modernfix.neoforge.dynresources.IModelBakerImpl;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@Mixin(value = ModelBakery.ModelBakerImpl.class, priority = 600)
|
||||
@ClientOnlyMixin
|
||||
public abstract class ModelBakerImplMixin implements IModelBakerImpl, IExtendedModelBaker {
|
||||
private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading");
|
||||
@Shadow @Final private ModelBakery field_40571;
|
||||
|
||||
private boolean mfix$ignoreCache = false;
|
||||
|
||||
@Shadow @Final private Function<Material, TextureAtlasSprite> modelTextureGetter;
|
||||
|
||||
@Override
|
||||
public void mfix$ignoreCache() {
|
||||
mfix$ignoreCache = true;
|
||||
}
|
||||
|
||||
private boolean throwIfMissing;
|
||||
|
||||
@Override
|
||||
public boolean throwOnMissingModel(boolean flag) {
|
||||
boolean old = throwIfMissing;
|
||||
throwIfMissing = flag;
|
||||
return old;
|
||||
}
|
||||
|
||||
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
|
||||
private void obtainModel(ResourceLocation arg, CallbackInfoReturnable<UnbakedModel> cir) {
|
||||
if(debugDynamicModelLoading)
|
||||
ModernFix.LOGGER.info("Baking {}", arg);
|
||||
IExtendedModelBakery extendedBakery = (IExtendedModelBakery)this.field_40571;
|
||||
if(arg instanceof ModelResourceLocation && arg != ModelBakery.MISSING_MODEL_LOCATION) {
|
||||
// synchronized because we use topLevelModels
|
||||
synchronized (this.field_40571) {
|
||||
this.field_40571.loadTopLevel((ModelResourceLocation)arg);
|
||||
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(true) {
|
||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
||||
try {
|
||||
toReplace = integration.onUnbakedModelPreBake(arg, toReplace, this.field_40571);
|
||||
} 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);
|
||||
if(cir.getReturnValue() == extendedBakery.mfix$getUnbakedMissingModel()) {
|
||||
if(arg != ModelBakery.MISSING_MODEL_LOCATION) {
|
||||
if(debugDynamicModelLoading)
|
||||
ModernFix.LOGGER.warn("Model {} not present", arg);
|
||||
if(throwIfMissing)
|
||||
throw new ModelMissingException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyExpressionValue(method = "bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;Ljava/util/function/Function;)Lnet/minecraft/client/resources/model/BakedModel;", at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;", ordinal = 0), remap = false)
|
||||
private Object ignoreCacheIfRequested(Object o) {
|
||||
return mfix$ignoreCache ? null : o;
|
||||
}
|
||||
|
||||
@WrapOperation(method = "bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;Ljava/util/function/Function;)Lnet/minecraft/client/resources/model/BakedModel;", at = @At(value = "INVOKE", 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;"))
|
||||
private BakedModel callBakedModelIntegration(UnbakedModel unbakedModel, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState state, ResourceLocation location, Operation<BakedModel> operation) {
|
||||
BakedModel model = operation.call(unbakedModel, baker, spriteGetter, state, location);
|
||||
|
||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
||||
model = integration.onBakedModelLoad(location, unbakedModel, model, state, this.field_40571, spriteGetter);
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,344 +0,0 @@
|
|||
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.RemovalNotification;
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
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.minecraft.world.level.block.Block;
|
||||
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.duck.IExtendedModelBaker;
|
||||
import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider;
|
||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.dynamicresources.ModelBakeryHelpers;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.slf4j.Logger;
|
||||
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.*;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/* low priority so that our injectors are added after other mods' */
|
||||
@Mixin(value = ModelBakery.class, priority = 1100)
|
||||
@ClientOnlyMixin
|
||||
public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
||||
|
||||
private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading");
|
||||
|
||||
@Shadow @Final @Mutable public Map<ResourceLocation, UnbakedModel> unbakedCache;
|
||||
|
||||
@Shadow @Final public static ModelResourceLocation MISSING_MODEL_LOCATION;
|
||||
|
||||
@Shadow protected abstract BlockModel loadBlockModel(ResourceLocation location) throws IOException;
|
||||
|
||||
@Shadow @Final private Set<ResourceLocation> loadingStack;
|
||||
|
||||
@Shadow protected abstract void loadModel(ResourceLocation blockstateLocation) throws Exception;
|
||||
|
||||
@Shadow @Final @Mutable
|
||||
private Map<ResourceLocation, BakedModel> bakedTopLevelModels;
|
||||
|
||||
@Shadow @Final @Mutable private Map<ModelBakery.BakedCacheKey, BakedModel> bakedCache;
|
||||
|
||||
@Shadow @Final @Mutable private BlockColors blockColors;
|
||||
|
||||
@Shadow @Final private static Logger LOGGER;
|
||||
|
||||
@Shadow
|
||||
public abstract void loadTopLevel(ModelResourceLocation modelResourceLocation);
|
||||
|
||||
@Shadow public abstract UnbakedModel getModel(ResourceLocation resourceLocation);
|
||||
|
||||
private Cache<ModelBakery.BakedCacheKey, BakedModel> loadedBakedModels;
|
||||
|
||||
private Cache<ResourceLocation, UnbakedModel> loadedModels;
|
||||
|
||||
private HashMap<ResourceLocation, UnbakedModel> smallLoadingCache = new HashMap<>();
|
||||
|
||||
private boolean ignoreModelLoad;
|
||||
|
||||
// disable fabric recursion
|
||||
@SuppressWarnings("unused")
|
||||
private boolean fabric_enableGetOrLoadModelGuard;
|
||||
|
||||
|
||||
@Redirect(method = "<init>", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/resources/model/ModelBakery;blockColors:Lnet/minecraft/client/color/block/BlockColors;"))
|
||||
private void replaceTopLevelBakedModels(ModelBakery bakery, BlockColors val) {
|
||||
fabric_enableGetOrLoadModelGuard = false;
|
||||
this.blockColors = val;
|
||||
this.loadedBakedModels = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(ModelBakeryHelpers.MAX_MODEL_LIFETIME_SECS, TimeUnit.SECONDS)
|
||||
.maximumSize(ModelBakeryHelpers.MAX_BAKED_MODEL_COUNT)
|
||||
.concurrencyLevel(8)
|
||||
.removalListener(this::onModelRemoved)
|
||||
.softValues()
|
||||
.build();
|
||||
this.loadedModels = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(ModelBakeryHelpers.MAX_MODEL_LIFETIME_SECS, TimeUnit.SECONDS)
|
||||
.maximumSize(ModelBakeryHelpers.MAX_UNBAKED_MODEL_COUNT)
|
||||
.concurrencyLevel(8)
|
||||
.removalListener(this::onModelRemoved)
|
||||
.softValues()
|
||||
.build();
|
||||
this.bakedCache = loadedBakedModels.asMap();
|
||||
ConcurrentMap<ResourceLocation, UnbakedModel> unbakedCacheBackingMap = loadedModels.asMap();
|
||||
this.unbakedCache = new ForwardingMap<ResourceLocation, UnbakedModel>() {
|
||||
@Override
|
||||
protected Map<ResourceLocation, UnbakedModel> delegate() {
|
||||
return unbakedCacheBackingMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbakedModel put(ResourceLocation key, UnbakedModel value) {
|
||||
smallLoadingCache.put(key, value);
|
||||
return super.put(key, value);
|
||||
}
|
||||
};
|
||||
this.bakedTopLevelModels = new DynamicBakedModelProvider((ModelBakery)(Object)this, bakedCache);
|
||||
}
|
||||
|
||||
@ModifyArg(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush(Ljava/lang/String;)V", ordinal = 0), index = 0)
|
||||
private String ignoreFutureModelLoads(String name) {
|
||||
this.ignoreModelLoad = true;
|
||||
return name;
|
||||
}
|
||||
|
||||
private <K, V> void onModelRemoved(RemovalNotification<K, V> notification) {
|
||||
if(!debugDynamicModelLoading)
|
||||
return;
|
||||
Object k = notification.getKey();
|
||||
if(k == null)
|
||||
return;
|
||||
ResourceLocation rl;
|
||||
boolean baked = false;
|
||||
if(k instanceof ResourceLocation) {
|
||||
rl = (ResourceLocation)k;
|
||||
} else {
|
||||
rl = ((ModelBakery.BakedCacheKey)k).id();
|
||||
baked = true;
|
||||
}
|
||||
/* can fire when a model is replaced */
|
||||
if(!baked && this.loadedModels.getIfPresent(rl) != null)
|
||||
return;
|
||||
ModernFix.LOGGER.warn("Evicted {} model {}", baked ? "baked" : "unbaked", rl);
|
||||
}
|
||||
|
||||
private UnbakedModel missingModel;
|
||||
|
||||
private Set<ResourceLocation> blockStateFiles;
|
||||
private Set<ResourceLocation> modelFiles;
|
||||
|
||||
@ModifyArg(method = "<init>", at = @At(value = "INVOKE", target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", ordinal = 0), index = 1)
|
||||
private Object captureMissingModel(Object model) {
|
||||
this.missingModel = (UnbakedModel)model;
|
||||
this.blockStateFiles = new HashSet<>();
|
||||
this.modelFiles = new HashSet<>();
|
||||
return this.missingModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason don't actually load most models
|
||||
*/
|
||||
@Redirect(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/ModelBakery;loadTopLevel(Lnet/minecraft/client/resources/model/ModelResourceLocation;)V"))
|
||||
private void addTopLevelFile(ModelBakery bakery, ModelResourceLocation location) {
|
||||
if(location == MISSING_MODEL_LOCATION || !this.ignoreModelLoad) {
|
||||
loadTopLevel(location);
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Ljava/util/Map;forEach(Ljava/util/function/BiConsumer;)V", ordinal = 0))
|
||||
private void fetchStaticDefinitions(Map<ResourceLocation, StateDefinition<Block, BlockState>> map, BiConsumer<ResourceLocation, StateDefinition<Block, BlockState>> func) {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/StateDefinition;getPossibleStates()Lcom/google/common/collect/ImmutableList;", ordinal = 0))
|
||||
private ImmutableList<BlockState> fetchBlocks(StateDefinition<Block, BlockState> def) {
|
||||
/* no-op */
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a copy of the top-level model list to avoid CME if more models get loaded here.
|
||||
*/
|
||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Ljava/util/Map;values()Ljava/util/Collection;", ordinal = 0))
|
||||
private Collection<?> copyTopLevelModelList(Map<?, ?> map) {
|
||||
return new ArrayList<>(map.values());
|
||||
}
|
||||
|
||||
private BiFunction<ResourceLocation, Material, TextureAtlasSprite> textureGetter;
|
||||
|
||||
@Inject(method = "bakeModels", at = @At("HEAD"))
|
||||
private void captureGetter(BiFunction<ResourceLocation, Material, TextureAtlasSprite> getter, CallbackInfo ci) {
|
||||
this.ignoreModelLoad = false;
|
||||
textureGetter = getter;
|
||||
DynamicBakedModelProvider.currentInstance = (DynamicBakedModelProvider)this.bakedTopLevelModels;
|
||||
}
|
||||
|
||||
@Redirect(method = "bakeModels", at = @At(value = "INVOKE", target = "Ljava/util/Map;keySet()Ljava/util/Set;"))
|
||||
private Set<ResourceLocation> skipBake(Map<ResourceLocation, UnbakedModel> instance) {
|
||||
Set<ResourceLocation> modelSet = new HashSet<>(instance.keySet());
|
||||
if(modelSet.size() > 0)
|
||||
ModernFix.LOGGER.info("Early baking {} models", modelSet.size());
|
||||
return modelSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the already loaded missing model instead of the cache entry (which will probably get evicted).
|
||||
*/
|
||||
@Redirect(method = "loadModel", at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;", ordinal = 1))
|
||||
private Object getMissingModel(Map map, Object rl) {
|
||||
if(rl == MISSING_MODEL_LOCATION && map == unbakedCache)
|
||||
return missingModel;
|
||||
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);
|
||||
}
|
||||
|
||||
private int mfix$nestedLoads = 0;
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason synchronize
|
||||
*/
|
||||
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
|
||||
public void getOrLoadModelDynamic(ResourceLocation modelLocation, CallbackInfoReturnable<UnbakedModel> cir) {
|
||||
if(modelLocation.equals(MISSING_MODEL_LOCATION)) {
|
||||
cir.setReturnValue(missingModel);
|
||||
return;
|
||||
}
|
||||
UnbakedModel existing = this.unbakedCache.get(modelLocation);
|
||||
if (existing != null) {
|
||||
cir.setReturnValue(existing);
|
||||
} else {
|
||||
synchronized(this) {
|
||||
if (this.loadingStack.contains(modelLocation)) {
|
||||
throw new IllegalStateException("Circular reference while loading " + modelLocation);
|
||||
} else {
|
||||
this.loadingStack.add(modelLocation);
|
||||
UnbakedModel iunbakedmodel = missingModel;
|
||||
|
||||
while(!this.loadingStack.isEmpty()) {
|
||||
ResourceLocation resourcelocation = this.loadingStack.iterator().next();
|
||||
|
||||
mfix$nestedLoads++;
|
||||
try {
|
||||
existing = this.unbakedCache.get(resourcelocation);
|
||||
if (existing == null) {
|
||||
if(debugDynamicModelLoading)
|
||||
LOGGER.info("Loading {}", resourcelocation);
|
||||
this.loadModel(resourcelocation);
|
||||
} else
|
||||
smallLoadingCache.put(resourcelocation, existing);
|
||||
} catch (ModelBakery.BlockStateDefinitionException var9) {
|
||||
LOGGER.warn(var9.getMessage());
|
||||
this.unbakedCache.put(resourcelocation, iunbakedmodel);
|
||||
smallLoadingCache.put(resourcelocation, iunbakedmodel);
|
||||
} catch (Exception var10) {
|
||||
LOGGER.warn("Unable to load model: '{}' referenced from: {}: {}", resourcelocation, modelLocation, var10);
|
||||
this.unbakedCache.put(resourcelocation, iunbakedmodel);
|
||||
smallLoadingCache.put(resourcelocation, iunbakedmodel);
|
||||
} finally {
|
||||
mfix$nestedLoads--;
|
||||
this.loadingStack.remove(resourcelocation);
|
||||
}
|
||||
}
|
||||
|
||||
// We have to get the result from the temporary cache used for a model load
|
||||
// As in pathological cases (e.g. Pedestals on 1.19) unbakedCache can lose
|
||||
// the model immediately
|
||||
UnbakedModel result = smallLoadingCache.getOrDefault(modelLocation, iunbakedmodel);
|
||||
try {
|
||||
// required as some mods (e.g. EBE) call bake directly on the returned model, without resolving parents themselves
|
||||
result.resolveParents(this::getModel);
|
||||
} catch(RuntimeException ignored) {}
|
||||
// We are done with loading, so clear this cache to allow GC of any unneeded models
|
||||
if(mfix$nestedLoads == 0)
|
||||
smallLoadingCache.clear();
|
||||
cir.setReturnValue(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Comparable<T>, V extends T> BlockState setPropertyGeneric(BlockState state, Property<T> prop, Object o) {
|
||||
return state.setValue(prop, (V)o);
|
||||
}
|
||||
@Redirect(method = "loadModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/StateDefinition;getPossibleStates()Lcom/google/common/collect/ImmutableList;"))
|
||||
private ImmutableList<BlockState> loadOnlyRelevantBlockState(StateDefinition<Block, BlockState> stateDefinition, ResourceLocation location) {
|
||||
if(!(location instanceof ModelResourceLocation) || Minecraft.getInstance().level == null)
|
||||
return stateDefinition.getPossibleStates();
|
||||
return ModelBakeryHelpers.getBlockStatesForMRL(stateDefinition, (ModelResourceLocation)location);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
((IExtendedModelBaker)theBaker).throwOnMissingModel(true);
|
||||
synchronized(this) { m = theBaker.bake(modelLocation, state, theBaker.getModelTextureGetter()); }
|
||||
if(m != null)
|
||||
loadedBakedModels.put(key, m);
|
||||
return m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<BlockState> getBlockStatesForMRL(StateDefinition<Block, BlockState> stateDefinition, ModelResourceLocation location) {
|
||||
return loadOnlyRelevantBlockState(stateDefinition, location);
|
||||
}
|
||||
|
||||
private BakedModel bakedMissingModel = null;
|
||||
|
||||
public void setBakedMissingModel(BakedModel m) {
|
||||
bakedMissingModel = m;
|
||||
}
|
||||
|
||||
public BakedModel getBakedMissingModel() {
|
||||
return bakedMissingModel;
|
||||
}
|
||||
|
||||
public UnbakedModel mfix$getUnbakedMissingModel() {
|
||||
return missingModel;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources.ctm;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.embeddedt.modernfix.neoforge.dynresources.IModelBakerImpl;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import team.chisel.ctm.CTM;
|
||||
import team.chisel.ctm.api.model.IModelCTM;
|
||||
import team.chisel.ctm.client.model.AbstractCTMBakedModel;
|
||||
import team.chisel.ctm.client.model.ModelCTM;
|
||||
import team.chisel.ctm.client.texture.IMetadataSectionCTM;
|
||||
import team.chisel.ctm.client.util.ResourceUtil;
|
||||
import team.chisel.ctm.client.util.TextureMetadataHandler;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Mixin(TextureMetadataHandler.class)
|
||||
@RequiresMod("ctm")
|
||||
@ClientOnlyMixin
|
||||
public abstract class TextureMetadataHandlerMixin implements ModernFixClientIntegration {
|
||||
|
||||
@Shadow(remap = false) @Nonnull protected abstract BakedModel wrap(UnbakedModel model, BakedModel object) throws IOException;
|
||||
|
||||
@Shadow @Final private Multimap<ResourceLocation, Material> scrapedTextures;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void subscribeDynamic(CallbackInfo ci) {
|
||||
ModernFixClient.CLIENT_INTEGRATIONS.add(this);
|
||||
}
|
||||
|
||||
@Inject(method = { "onModelBake(Lnet/neoforged/neoforge/client/event/ModelEvent$ModifyBakingResult;)V", "onModelBake(Lnet/neoforged/neoforge/client/event/ModelEvent$BakingCompleted;)V" }, at = @At("HEAD"), cancellable = true, remap = false)
|
||||
private void noIteration(CallbackInfo ci) {
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BakedModel onBakedModelLoad(ResourceLocation rl, UnbakedModel rootModel, BakedModel baked, ModelState state, ModelBakery bakery) {
|
||||
if (rl instanceof ModelResourceLocation && !(baked instanceof AbstractCTMBakedModel) && !baked.isCustomRenderer()) {
|
||||
Deque<ResourceLocation> dependencies = new ArrayDeque<>();
|
||||
Set<ResourceLocation> seenModels = new HashSet<>();
|
||||
dependencies.push(rl);
|
||||
seenModels.add(rl);
|
||||
boolean shouldWrap = false;
|
||||
Set<Pair<String, String>> errors = new HashSet<>();
|
||||
// Breadth-first loop through dependencies, exiting as soon as a CTM texture is found, and skipping duplicates/cycles
|
||||
while (!shouldWrap && !dependencies.isEmpty()) {
|
||||
ResourceLocation dep = dependencies.pop();
|
||||
UnbakedModel model;
|
||||
try {
|
||||
model = dep == rl ? rootModel : bakery.getModel(dep);
|
||||
} catch (Exception e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Collection<Material> textures = Sets.newHashSet(scrapedTextures.get(dep));
|
||||
Collection<ResourceLocation> newDependencies = model.getDependencies();
|
||||
for (Material tex : textures) {
|
||||
IMetadataSectionCTM meta = null;
|
||||
// Cache all dependent texture metadata
|
||||
try {
|
||||
meta = ResourceUtil.getMetadata(ResourceUtil.spriteToAbsolute(tex.texture())).orElse(null); // TODO, lazy
|
||||
} catch (IOException e) {} // Fallthrough
|
||||
if (meta != null) {
|
||||
// At least one texture has CTM metadata, so we should wrap this model
|
||||
shouldWrap = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (ResourceLocation newDep : newDependencies) {
|
||||
if (seenModels.add(newDep)) {
|
||||
dependencies.push(newDep);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldWrap) {
|
||||
try {
|
||||
baked = wrap(rootModel, baked);
|
||||
handleInit(rl, baked, bakery);
|
||||
dependencies.clear();
|
||||
} catch (IOException e) {
|
||||
CTM.logger.error("Could not wrap model " + rl + ". Aborting...", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return baked;
|
||||
}
|
||||
|
||||
private void handleInit(ResourceLocation key, BakedModel wrappedModel, ModelBakery bakery) {
|
||||
if(wrappedModel instanceof AbstractCTMBakedModel baked) {
|
||||
IModelCTM var10 = baked.getModel();
|
||||
if (var10 instanceof ModelCTM ctmModel) {
|
||||
if (!ctmModel.isInitialized()) {
|
||||
Function<Material, TextureAtlasSprite> spriteGetter = (m) -> {
|
||||
return Minecraft.getInstance().getModelManager().getAtlas(m.atlasLocation()).getSprite(m.texture());
|
||||
};
|
||||
ModelBakery.ModelBakerImpl baker = bakery.new ModelBakerImpl((rl, m) -> {
|
||||
return m.sprite();
|
||||
}, key);
|
||||
// bypass bakedCache so that dependent models get re-baked and thus retrieve their sprites again
|
||||
((IModelBakerImpl)baker).mfix$ignoreCache();
|
||||
ctmModel.bake(baker, spriteGetter, BlockModelRotation.X0_Y0, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources.rs;
|
||||
|
||||
import com.refinedmods.refinedstorage.render.BakedModelOverrideRegistry;
|
||||
import com.refinedmods.refinedstorage.setup.ClientSetup;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||
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;
|
||||
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(remap = false) @Final private static BakedModelOverrideRegistry BAKED_MODEL_OVERRIDE_REGISTRY;
|
||||
|
||||
@Inject(method = "registerBakedModelOverrides", at = @At("RETURN"), remap = false)
|
||||
private static 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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources.supermartijncore;
|
||||
|
||||
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 org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||
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;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Mixin(ClientRegistrationHandler.class)
|
||||
@RequiresMod("supermartijn642corelib")
|
||||
@ClientOnlyMixin
|
||||
public class ClientRegistrationHandlerMixin {
|
||||
@Shadow(remap = false) @Final private List<Pair<Supplier<Stream<ResourceLocation>>, Function<BakedModel, BakedModel>>> modelOverwrites;
|
||||
|
||||
private Map<ResourceLocation, Function<BakedModel, BakedModel>> modelOverwritesByLocation = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
@Redirect(method = "handleModelBakeEvent", at = @At(value = "FIELD", target = "Lcom/supermartijn642/core/registry/ClientRegistrationHandler;modelOverwrites:Ljava/util/List;"), remap = false)
|
||||
private List<?> skipModelOverwrites(ClientRegistrationHandler h) {
|
||||
modelOverwritesByLocation.clear();
|
||||
for(Pair<Supplier<Stream<ResourceLocation>>, Function<BakedModel, BakedModel>> pair : this.modelOverwrites) {
|
||||
Stream<ResourceLocation> locationStream = pair.left().get();
|
||||
Function<BakedModel, BakedModel> swapper = pair.right();
|
||||
locationStream.forEach(l -> {
|
||||
modelOverwritesByLocation.put(l, swapper);
|
||||
});
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void registerDynBake(String modid, CallbackInfo ci) {
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -3,13 +3,10 @@ package org.embeddedt.modernfix.platform.neoforge;
|
|||
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;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.fml.ModLoader;
|
||||
import net.neoforged.fml.ModLoadingIssue;
|
||||
|
|
@ -17,7 +14,6 @@ import net.neoforged.fml.loading.FMLLoader;
|
|||
import net.neoforged.fml.loading.FMLPaths;
|
||||
import net.neoforged.fml.loading.LoadingModList;
|
||||
import net.neoforged.fml.loading.moddiscovery.ModInfo;
|
||||
import net.neoforged.neoforge.client.CreativeModeTabSearchRegistry;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.event.RegisterCommandsEvent;
|
||||
import net.neoforged.neoforge.network.PacketDistributor;
|
||||
|
|
@ -145,23 +141,6 @@ public class ModernFixPlatformHooksImpl implements ModernFixPlatformHooks {
|
|||
return modOptions;
|
||||
}
|
||||
|
||||
public 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()) {
|
||||
registry.register(nameKey, nameSupplier);
|
||||
}
|
||||
for (SearchRegistry.Key<ItemStack> tagKey : CreativeModeTabSearchRegistry.getTagSearchKeys().values()) {
|
||||
registry.register(tagKey, tagSupplier);
|
||||
}
|
||||
Map<CreativeModeTab, SearchRegistry.Key<ItemStack>> tagSearchKeys = CreativeModeTabSearchRegistry.getTagSearchKeys();
|
||||
CreativeModeTabSearchRegistry.getNameSearchKeys().forEach((tab, nameSearchKey) -> {
|
||||
SearchRegistry.Key<ItemStack> tagSearchKey = tagSearchKeys.get(tab);
|
||||
tab.setSearchTreeBuilder((contents) -> {
|
||||
populator.accept(nameSearchKey, contents);
|
||||
populator.accept(tagSearchKey, contents);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void onLaunchComplete() {
|
||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.spark_profile_launch.OnForge")) {
|
||||
CommonModUtil.runWithoutCrash(() -> SparkLaunchProfiler.stop("launch"), "Failed to stop profiler");
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ modId = "neoforge" #mandatory
|
|||
# Does this dependency have to exist - if not, ordering below must be specified
|
||||
type = "required" #mandatory
|
||||
# The version range of the dependency
|
||||
versionRange = "[20.6.100-beta,)" #mandatory
|
||||
versionRange = "[21.0.0-alpha,)" #mandatory
|
||||
# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
|
||||
ordering = "NONE"
|
||||
# Side this dependency is applied on - BOTH, CLIENT or SERVER
|
||||
|
|
@ -57,7 +57,7 @@ side = "BOTH"
|
|||
modId = "minecraft"
|
||||
type = "required"
|
||||
# This version range declares a minimum of the current minecraft version up to but not including the next major version
|
||||
versionRange = "[1.20, 1.21)"
|
||||
versionRange = "[1.21, 1.22)"
|
||||
ordering = "NONE"
|
||||
side = "BOTH"
|
||||
[[dependencies.modernfix]]
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user