Skip to content

Commit b5becf6

Browse files
committed
Merge remote-tracking branch 'origin/1.20' into 1.20.4
2 parents c65fdbc + c85f7e4 commit b5becf6

File tree

12 files changed

+182
-13
lines changed

12 files changed

+182
-13
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
2+
3+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
4+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
5+
import net.minecraft.client.renderer.block.model.ItemOverrides;
6+
import net.minecraft.client.resources.model.ModelBaker;
7+
import net.minecraft.client.resources.model.UnbakedModel;
8+
import net.minecraft.resources.ResourceLocation;
9+
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
10+
import org.embeddedt.modernfix.duck.IExtendedModelBaker;
11+
import org.spongepowered.asm.mixin.Mixin;
12+
import org.spongepowered.asm.mixin.injection.At;
13+
14+
@Mixin(ItemOverrides.class)
15+
@ClientOnlyMixin
16+
public class ItemOverridesMixin {
17+
@WrapOperation(method = "bakeModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/ModelBaker;getModel(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/resources/model/UnbakedModel;"))
18+
private UnbakedModel preventThrowForMissing(ModelBaker instance, ResourceLocation resourceLocation, Operation<UnbakedModel> original) {
19+
boolean prevState = ((IExtendedModelBaker)instance).throwOnMissingModel(false);
20+
try {
21+
return original.call(instance, resourceLocation);
22+
} finally {
23+
((IExtendedModelBaker)instance).throwOnMissingModel(prevState);
24+
}
25+
}
26+
}

common/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBaker.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
public interface IExtendedModelBaker {
44
/**
55
* Causes the ModelBaker to throw when it finds a missing model instead of proceeding with the bake.
6+
* @return the previous value of this flag
67
*/
7-
void throwOnMissingModel();
8+
boolean throwOnMissingModel(boolean flag);
89
}

common/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,22 @@
33
import org.embeddedt.modernfix.ModernFix;
44
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
55
import org.objectweb.asm.tree.ClassNode;
6+
import org.spongepowered.asm.logging.ILogger;
7+
import org.spongepowered.asm.logging.LoggerAdapterDefault;
68
import org.spongepowered.asm.mixin.MixinEnvironment;
79
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
810
import org.spongepowered.asm.mixin.transformer.ClassInfo;
11+
import org.spongepowered.asm.service.MixinServiceAbstract;
912

1013
import java.lang.reflect.Field;
14+
import java.util.ArrayList;
1115
import java.util.Collection;
16+
import java.util.List;
1217
import java.util.Map;
1318

1419
public class ClassInfoManager {
1520
private static boolean hasRun = false;
21+
private static final List<Runnable> loggersToRestore = new ArrayList<>();
1622
public static void clear() {
1723
if (!ModernFixMixinPlugin.instance.isOptionEnabled("perf.clear_mixin_classinfo.ClassInfoManager") || hasRun)
1824
return;
@@ -25,11 +31,33 @@ private static Field accessible(Field f) {
2531
return f;
2632
}
2733

34+
private static void changeLoggerAndRestoreLater(Map<String, ILogger> map, ILogger newLogger) {
35+
ILogger oldLogger = map.put("mixin.audit", newLogger);
36+
loggersToRestore.add(() -> map.put("mixin.audit", oldLogger));
37+
}
38+
39+
private static void disableLoggers() throws ReflectiveOperationException {
40+
// Disable default audit logger
41+
Field loggersField = accessible(MixinServiceAbstract.class.getDeclaredField("loggers"));
42+
changeLoggerAndRestoreLater((Map<String, ILogger>)loggersField.get(null), new LoggerAdapterDefault("mixin.audit"));
43+
Class<?> fabricLogger = null;
44+
try {
45+
fabricLogger = Class.forName("net.fabricmc.loader.impl.knot.MixinLogger");
46+
} catch(Throwable e) {
47+
// Probably not Fabric
48+
return;
49+
}
50+
// Disable Fabric audit logger
51+
loggersField = accessible(fabricLogger.getDeclaredField("LOGGER_MAP"));
52+
changeLoggerAndRestoreLater((Map<String, ILogger>)loggersField.get(null), new LoggerAdapterDefault("mixin.audit"));
53+
}
54+
2855
private static void doClear() {
2956
Map<String, ClassInfo> classInfoCache;
3057
Field mixinField, stateField, classNodeField, methodsField, fieldsField;
3158
Class<?> stateClz;
3259
try {
60+
disableLoggers();
3361
Field field = accessible(ClassInfo.class.getDeclaredField("cache"));
3462
classInfoCache = (Map<String, ClassInfo>) field.get(null);
3563
mixinField = accessible(ClassInfo.class.getDeclaredField("mixin"));
@@ -70,6 +98,9 @@ private static void doClear() {
7098
} catch (RuntimeException e) {
7199
e.printStackTrace();
72100
}
101+
// Put back the old logger
102+
loggersToRestore.forEach(Runnable::run);
103+
loggersToRestore.clear();
73104
ModernFix.LOGGER.warn("Cleared mixin data structures");
74105
}
75106
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package org.embeddedt.modernfix.fabric.mixin.perf.dynamic_resources;
2+
3+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
4+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
5+
import net.minecraft.client.renderer.block.model.ItemOverrides;
6+
import net.minecraft.client.resources.model.BakedModel;
7+
import net.minecraft.client.resources.model.ModelBaker;
8+
import net.minecraft.client.resources.model.ModelState;
9+
import net.minecraft.resources.ResourceLocation;
10+
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
11+
import org.embeddedt.modernfix.duck.IExtendedModelBaker;
12+
import org.spongepowered.asm.mixin.Mixin;
13+
import org.spongepowered.asm.mixin.injection.At;
14+
15+
@Mixin(ItemOverrides.class)
16+
@ClientOnlyMixin
17+
public class ItemOverridesFabricMixin {
18+
/**
19+
* @author embeddedt
20+
* @reason servers insist on generating invalid item overrides that have missing models
21+
*/
22+
@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;)Lnet/minecraft/client/resources/model/BakedModel;"))
23+
private BakedModel bake(ModelBaker instance, ResourceLocation resourceLocation, ModelState modelState, Operation<BakedModel> original) {
24+
boolean prevState = ((IExtendedModelBaker)instance).throwOnMissingModel(false);
25+
try {
26+
return original.call(instance, resourceLocation, modelState);
27+
} finally {
28+
((IExtendedModelBaker)instance).throwOnMissingModel(prevState);
29+
}
30+
}
31+
}

fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakerImplMixin.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ public abstract class ModelBakerImplMixin implements IExtendedModelBaker {
5959
private boolean throwIfMissing;
6060

6161
@Override
62-
public void throwOnMissingModel() {
63-
throwIfMissing = true;
62+
public boolean throwOnMissingModel(boolean flag) {
63+
boolean old = throwIfMissing;
64+
throwIfMissing = flag;
65+
return old;
6466
}
6567

6668
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)

fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ public BakedModel bakeDefault(ResourceLocation modelLocation, ModelState state)
310310
return m;
311311
ModelBakery self = (ModelBakery) (Object) this;
312312
ModelBaker theBaker = self.new ModelBakerImpl(textureGetter, modelLocation);
313-
((IExtendedModelBaker)theBaker).throwOnMissingModel();
313+
((IExtendedModelBaker)theBaker).throwOnMissingModel(true);
314314
synchronized(this) { m = theBaker.bake(modelLocation, state); }
315315
if(m != null)
316316
loadedBakedModels.put(key, m);

forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/model_data_manager_cme/ModelDataManagerMixin.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
import net.minecraft.world.level.ChunkPos;
66
import net.minecraftforge.client.model.data.ModelDataManager;
77
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
8+
import org.spongepowered.asm.mixin.Final;
89
import org.spongepowered.asm.mixin.Mixin;
910
import org.spongepowered.asm.mixin.Shadow;
1011
import org.spongepowered.asm.mixin.injection.At;
1112
import org.spongepowered.asm.mixin.injection.ModifyArg;
1213
import org.spongepowered.asm.mixin.injection.Redirect;
1314

1415
import java.util.Collections;
16+
import java.util.Map;
1517
import java.util.Set;
1618
import java.util.concurrent.ConcurrentHashMap;
1719
import java.util.function.Function;
@@ -24,6 +26,8 @@
2426
public abstract class ModelDataManagerMixin {
2527
@Shadow protected abstract void refreshAt(ChunkPos chunk);
2628

29+
@Shadow @Final private Map<ChunkPos, Set<BlockPos>> needModelDataRefresh;
30+
2731
/**
2832
* Make the set of positions to refresh a real concurrent hash set rather than relying on synchronizedSet,
2933
* because the returned iterator won't be thread-safe otherwise. See https://github.com/AppliedEnergistics/Applied-Energistics-2/issues/7511
@@ -37,7 +41,8 @@ private Function<ChunkPos, Set<BlockPos>> changeTypeOfSetUsed(Function<ChunkPos,
3741
private void onlyRefreshOnMainThread(ModelDataManager instance, ChunkPos pos) {
3842
// Only refresh model data on the main thread. This prevents calling getBlockEntity from worker threads
3943
// which could cause weird CMEs or other behavior.
40-
if(Minecraft.getInstance().isSameThread()) {
44+
// Avoid the loop if no model data needs to be refreshed, to prevent unnecessary allocation.
45+
if(Minecraft.getInstance().isSameThread() && !needModelDataRefresh.isEmpty()) {
4146
// Refresh the given chunk, and all its neighbors. This is less efficient than the default code
4247
// but we have no choice since we need to not do refreshing on workers, and blocks might
4348
// try to access model data in neighboring chunks.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.embeddedt.modernfix.forge.mixin.perf.forge_cap_retrieval;
2+
3+
import net.minecraft.core.Direction;
4+
import net.minecraft.world.entity.LivingEntity;
5+
import net.minecraftforge.common.capabilities.Capability;
6+
import net.minecraftforge.items.CapabilityItemHandler;
7+
import org.spongepowered.asm.mixin.Mixin;
8+
import org.spongepowered.asm.mixin.injection.At;
9+
import org.spongepowered.asm.mixin.injection.Redirect;
10+
11+
import javax.annotation.Nullable;
12+
13+
@Mixin(LivingEntity.class)
14+
public class LivingEntityMixin {
15+
/**
16+
* @author embeddedt (issue noted by XFactHD)
17+
* @reason check capability equality before checking that entity is alive, the latter requires a lot more
18+
* indirection
19+
*/
20+
@Redirect(method = "getCapability", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;isAlive()Z"))
21+
private <T> boolean checkAliveAfterCap(LivingEntity entity, Capability<T> capability, @Nullable Direction facing) {
22+
return capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY && entity.isAlive();
23+
}
24+
}

neoforge/src/main/java/org/embeddedt/modernfix/neoforge/dynresources/ModelBakeEventHelper.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,26 @@ public boolean containsKey(@Nullable Object key) {
154154

155155
@Override
156156
public void replaceAll(BiFunction<? super ResourceLocation, ? super BakedModel, ? extends BakedModel> function) {
157-
ModernFix.LOGGER.warn("Mod '{}' is calling replaceAll on the model registry. This requires temporarily loading every model for that mod, which is slow.", modId);
157+
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);
158158
List<ResourceLocation> locations = new ArrayList<>(keySet());
159159
for(ResourceLocation location : locations) {
160-
BakedModel existing = get(location);
161-
BakedModel replacement = function.apply(location, existing);
162-
if(replacement != existing) {
163-
put(location, replacement);
160+
/*
161+
* Fetching every model is insanely slow. So we call the function with a null object first, since it
162+
* probably isn't expecting that. If we get an exception thrown, or it returns nonnull, then we know
163+
* it actually cares about the given model.
164+
*/
165+
boolean needsReplacement;
166+
try {
167+
needsReplacement = function.apply(location, null) != null;
168+
} catch(Throwable e) {
169+
needsReplacement = true;
170+
}
171+
if(needsReplacement) {
172+
BakedModel existing = get(location);
173+
BakedModel replacement = function.apply(location, existing);
174+
if(replacement != existing) {
175+
put(location, replacement);
176+
}
164177
}
165178
}
166179
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources;
2+
3+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
4+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
5+
import net.minecraft.client.renderer.block.model.ItemOverrides;
6+
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
7+
import net.minecraft.client.resources.model.BakedModel;
8+
import net.minecraft.client.resources.model.ModelBaker;
9+
import net.minecraft.client.resources.model.ModelState;
10+
import net.minecraft.resources.ResourceLocation;
11+
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
12+
import org.embeddedt.modernfix.duck.IExtendedModelBaker;
13+
import org.spongepowered.asm.mixin.Mixin;
14+
import org.spongepowered.asm.mixin.injection.At;
15+
16+
import java.util.function.Function;
17+
18+
@Mixin(ItemOverrides.class)
19+
@ClientOnlyMixin
20+
public class ItemOverridesForgeMixin {
21+
/**
22+
* @author embeddedt
23+
* @reason servers insist on generating invalid item overrides that have missing models
24+
*/
25+
@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)
26+
private BakedModel bake(ModelBaker instance, ResourceLocation resourceLocation, ModelState modelState, Function<ResourceLocation, TextureAtlasSprite> spriteGetter, Operation<BakedModel> original) {
27+
boolean prevState = ((IExtendedModelBaker)instance).throwOnMissingModel(false);
28+
try {
29+
return original.call(instance, resourceLocation, modelState, spriteGetter);
30+
} finally {
31+
((IExtendedModelBaker)instance).throwOnMissingModel(prevState);
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)