Revert "Use copy-on-write map for permanent overrides"

This solution is also not good enough. It causes catastrophic
time complexity with mods that call get and put in rapid
succession (i.e. every Forge mod using ModelBakeEvent)
This commit is contained in:
embeddedt 2023-10-29 21:14:51 -04:00
parent 621ecf6b3e
commit ced7f866d8
No known key found for this signature in database
GPG Key ID: A69433EC199B5613

View File

@ -2,7 +2,6 @@ package org.embeddedt.modernfix.dynamicresources;
import com.google.common.collect.ImmutableSet;
import com.mojang.math.Transformation;
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemOverrides;
@ -39,8 +38,7 @@ public class DynamicBakedModelProvider implements Map<ResourceLocation, BakedMod
public static DynamicBakedModelProvider currentInstance = null;
private final ModelBakery bakery;
private final Map<Triple<ResourceLocation, Transformation, Boolean>, BakedModel> bakedCache;
private volatile Map<ResourceLocation, BakedModel> permanentOverridesView = null;
private final Map<ResourceLocation, BakedModel> permanentOverridesMutable;
private final Map<ResourceLocation, BakedModel> permanentOverrides;
private BakedModel missingModel;
private static final BakedModel SENTINEL = new BakedModel() {
@Override
@ -87,7 +85,7 @@ public class DynamicBakedModelProvider implements Map<ResourceLocation, BakedMod
public DynamicBakedModelProvider(ModelBakery bakery, Map<Triple<ResourceLocation, Transformation, Boolean>, BakedModel> cache) {
this.bakery = bakery;
this.bakedCache = cache;
this.permanentOverridesMutable = new Object2ObjectOpenHashMap<>();
this.permanentOverrides = Collections.synchronizedMap(new Object2ObjectOpenHashMap<>());
if(currentInstance == null)
currentInstance = this;
}
@ -109,27 +107,14 @@ public class DynamicBakedModelProvider implements Map<ResourceLocation, BakedMod
return bakedCache.isEmpty();
}
private Map<ResourceLocation, BakedModel> getPermanentOverrides() {
Map<ResourceLocation, BakedModel> map = permanentOverridesView;
if(map == null) {
synchronized (this) {
map = permanentOverridesView;
if(map == null) {
permanentOverridesView = map = Object2ObjectMaps.unmodifiable(new Object2ObjectOpenHashMap<>(permanentOverridesMutable));
}
}
}
return map;
}
@Override
public boolean containsKey(Object o) {
return getPermanentOverrides().getOrDefault(o, SENTINEL) != null;
return permanentOverrides.getOrDefault(o, SENTINEL) != null;
}
@Override
public boolean containsValue(Object o) {
return getPermanentOverrides().containsValue(o) || bakedCache.containsValue(o);
return permanentOverrides.containsValue(o) || bakedCache.containsValue(o);
}
private static boolean isVanillaTopLevelModel(ResourceLocation location) {
@ -155,7 +140,7 @@ public class DynamicBakedModelProvider implements Map<ResourceLocation, BakedMod
@Override
public BakedModel get(Object o) {
BakedModel model = getPermanentOverrides().getOrDefault(o, SENTINEL);
BakedModel model = permanentOverrides.getOrDefault(o, SENTINEL);
if(model != SENTINEL)
return model;
else {
@ -171,7 +156,7 @@ public class DynamicBakedModelProvider implements Map<ResourceLocation, BakedMod
if(model == missingModel) {
// to correctly emulate the original map, we return null for missing models, unless they are top-level
model = isVanillaTopLevelModel((ResourceLocation)o) ? model : null;
this.put((ResourceLocation) o, model);
permanentOverrides.put((ResourceLocation) o, model);
}
return model;
}
@ -179,11 +164,7 @@ public class DynamicBakedModelProvider implements Map<ResourceLocation, BakedMod
@Override
public BakedModel put(ResourceLocation resourceLocation, BakedModel bakedModel) {
BakedModel m;
synchronized (this) {
m = permanentOverridesMutable.put(resourceLocation, bakedModel);
permanentOverridesView = null;
}
BakedModel m = permanentOverrides.put(resourceLocation, bakedModel);
if(m != null)
return m;
else
@ -192,11 +173,7 @@ public class DynamicBakedModelProvider implements Map<ResourceLocation, BakedMod
@Override
public BakedModel remove(Object o) {
BakedModel m;
synchronized (this) {
m = permanentOverridesMutable.remove(o);
permanentOverridesView = null;
}
BakedModel m = permanentOverrides.remove(o);
if(m != null)
return m;
return bakedCache.remove(vanillaKey(o));
@ -204,10 +181,7 @@ public class DynamicBakedModelProvider implements Map<ResourceLocation, BakedMod
@Override
public void putAll(@NotNull Map<? extends ResourceLocation, ? extends BakedModel> map) {
synchronized (this) {
permanentOverridesMutable.putAll(map);
permanentOverridesView = null;
}
permanentOverrides.putAll(map);
}
@Override
@ -236,27 +210,23 @@ public class DynamicBakedModelProvider implements Map<ResourceLocation, BakedMod
@Nullable
@Override
public BakedModel replace(ResourceLocation key, BakedModel value) {
synchronized (this) {
BakedModel existingOverride = permanentOverridesMutable.get(key);
// as long as no valid override was put in (null can mean unable to load model, so we treat as invalid), replace
// the model
if(existingOverride == null)
return this.put(key, value);
else
return existingOverride;
}
BakedModel existingOverride = permanentOverrides.get(key);
// as long as no valid override was put in (null can mean unable to load model, so we treat as invalid), replace
// the model
if(existingOverride == null)
return this.put(key, value);
else
return existingOverride;
}
@Override
public void replaceAll(BiFunction<? super ResourceLocation, ? super BakedModel, ? extends BakedModel> function) {
synchronized (this) {
permanentOverridesMutable.replaceAll(function);
permanentOverridesView = null;
}
Set<ResourceLocation> overridenLocations = permanentOverrides.keySet();
permanentOverrides.replaceAll(function);
boolean uvLock = BlockModelRotation.X0_Y0.isUvLocked();
Transformation rotation = BlockModelRotation.X0_Y0.getRotation();
bakedCache.replaceAll((loc, oldModel) -> {
if(loc.getMiddle() != rotation || loc.getRight() != uvLock || getPermanentOverrides().containsKey(loc.getLeft()))
if(loc.getMiddle() != rotation || loc.getRight() != uvLock || overridenLocations.contains(loc.getLeft()))
return oldModel;
else
return function.apply(loc.getLeft(), oldModel);