Merge remote-tracking branch 'origin/1.20.4' into 1.20.5
This commit is contained in:
commit
b65a63896b
|
|
@ -1,57 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.bugfix.buffer_builder_leak;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.embeddedt.modernfix.render.UnsafeBufferHelper;
|
|
||||||
import org.spongepowered.asm.mixin.Dynamic;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
@Mixin(value = BufferBuilder.class, priority = 1500)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class BufferBuilderMixin {
|
|
||||||
@Shadow private ByteBuffer buffer;
|
|
||||||
@Shadow private boolean closed;
|
|
||||||
|
|
||||||
private static boolean leakReported = false;
|
|
||||||
|
|
||||||
private boolean mfix$shouldFree = true;
|
|
||||||
|
|
||||||
@Dynamic
|
|
||||||
@Inject(method = "flywheel$injectForRender", at = @At("RETURN"), remap = false, require = 0)
|
|
||||||
private void preventFree(CallbackInfo ci) {
|
|
||||||
mfix$shouldFree = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure UnsafeBufferHelper is classloaded early, to avoid Forge's event transformer showing an error in the log.
|
|
||||||
*/
|
|
||||||
@Inject(method = "<clinit>", at = @At(value = "RETURN"))
|
|
||||||
private static void initUnsafeBufferHelper(CallbackInfo ci) {
|
|
||||||
UnsafeBufferHelper.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void finalize() throws Throwable {
|
|
||||||
try {
|
|
||||||
ByteBuffer buf = buffer;
|
|
||||||
// can be null if a mod already tried to free the buffer
|
|
||||||
if(!this.closed && buf != null && mfix$shouldFree) {
|
|
||||||
if(!leakReported) {
|
|
||||||
leakReported = true;
|
|
||||||
ModernFix.LOGGER.warn("One or more BufferBuilders have been leaked, ModernFix will attempt to correct this.");
|
|
||||||
}
|
|
||||||
UnsafeBufferHelper.free(buf);
|
|
||||||
buffer = null;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
super.finalize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.compact_mojang_registries;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.item.Item;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import org.embeddedt.modernfix.annotation.IgnoreOutsideDev;
|
|
||||||
import org.embeddedt.modernfix.registry.DirectStorageRegistryObject;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
|
|
||||||
@Mixin({ Block.class, Item.class })
|
|
||||||
@IgnoreOutsideDev
|
|
||||||
public class DirectObjectMixin implements DirectStorageRegistryObject {
|
|
||||||
private ResourceLocation mfix$resourceKey;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResourceLocation mfix$getResourceKey() {
|
|
||||||
return mfix$resourceKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mfix$setResourceKey(ResourceLocation key) {
|
|
||||||
mfix$resourceKey = key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.compact_mojang_registries;
|
package org.embeddedt.modernfix.common.mixin.perf.compact_mojang_registries;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import net.minecraft.core.MappedRegistry;
|
import net.minecraft.core.MappedRegistry;
|
||||||
import net.minecraft.core.RegistrationInfo;
|
import net.minecraft.core.RegistrationInfo;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.embeddedt.modernfix.annotation.IgnoreOutsideDev;
|
import org.embeddedt.modernfix.annotation.IgnoreOutsideDev;
|
||||||
import org.embeddedt.modernfix.registry.LifecycleMap;
|
import org.embeddedt.modernfix.registry.LifecycleMap;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
|
@ -25,17 +23,8 @@ public abstract class MappedRegistryMixin<T> {
|
||||||
@Mutable
|
@Mutable
|
||||||
private Map<ResourceKey<T>, RegistrationInfo> registrationInfos;
|
private Map<ResourceKey<T>, RegistrationInfo> registrationInfos;
|
||||||
|
|
||||||
private static final ImmutableSet<ResourceLocation> MFIX$NEW_STORAGE_KEYS = ImmutableSet.of(new ResourceLocation("block"), new ResourceLocation("item"));
|
@Inject(method = "<init>", at = @At("RETURN"))
|
||||||
|
|
||||||
@Inject(method = "<init>(Lnet/minecraft/resources/ResourceKey;Lcom/mojang/serialization/Lifecycle;Z)V", at = @At("RETURN"))
|
|
||||||
private void replaceStorage(CallbackInfo ci) {
|
private void replaceStorage(CallbackInfo ci) {
|
||||||
this.registrationInfos = new LifecycleMap<>();
|
this.registrationInfos = new LifecycleMap<>();
|
||||||
/*
|
|
||||||
if(MFIX$NEW_STORAGE_KEYS.contains(this.key().location())) {
|
|
||||||
ModernFixMixinPlugin.instance.logger.info("Using experimental registry storage for {}", this.key());
|
|
||||||
this.storage = (BiMap<ResourceLocation, T>) RegistryStorage.createStorage();
|
|
||||||
this.keyStorage = (BiMap<ResourceKey<T>, T>)RegistryStorage.createKeyStorage(this.key(), (BiMap<ResourceLocation, DirectStorageRegistryObject>)this.storage);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_block_codecs;
|
|
||||||
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.state.StateDefinition;
|
|
||||||
import net.minecraft.world.level.block.state.StateHolder;
|
|
||||||
import net.minecraft.world.level.block.state.properties.Property;
|
|
||||||
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.ModifyVariable;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
@Mixin(StateDefinition.class)
|
|
||||||
public class StateDefinitionMixin<O, S extends StateHolder<O, S>> {
|
|
||||||
@Shadow @Final private O owner;
|
|
||||||
|
|
||||||
@ModifyVariable(method = "<init>", at = @At("HEAD"), ordinal = 0, argsOnly = true)
|
|
||||||
private static <O, S extends StateHolder<O, S>> StateDefinition.Factory<O, S> replaceMapCodec(StateDefinition.Factory<O, S> factory, Function<O, S> function, O object, StateDefinition.Factory<O, S> factory2, Map<String, Property<?>> map) {
|
|
||||||
if(object instanceof Block)
|
|
||||||
return (o, m, c) -> factory.create(o, m, null);
|
|
||||||
return factory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_block_codecs;
|
|
||||||
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
|
||||||
import com.google.common.cache.CacheLoader;
|
|
||||||
import com.google.common.cache.LoadingCache;
|
|
||||||
import com.mojang.serialization.Codec;
|
|
||||||
import com.mojang.serialization.Decoder;
|
|
||||||
import com.mojang.serialization.Encoder;
|
|
||||||
import com.mojang.serialization.MapCodec;
|
|
||||||
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.StateHolder;
|
|
||||||
import net.minecraft.world.level.block.state.properties.Property;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
@Mixin(StateHolder.class)
|
|
||||||
public class StateHolderMixin {
|
|
||||||
private static final LoadingCache<Block, MapCodec<BlockState>> MODERNFIX_CODEC_CACHE = CacheBuilder.newBuilder()
|
|
||||||
.maximumSize(100000)
|
|
||||||
.build(new CacheLoader<Block, MapCodec<BlockState>>() {
|
|
||||||
@Override
|
|
||||||
public MapCodec<BlockState> load(Block block) throws Exception {
|
|
||||||
Supplier<BlockState> stateSupplier = block::defaultBlockState;
|
|
||||||
MapCodec<BlockState> mapCodec = MapCodec.of(Encoder.empty(), Decoder.unit(stateSupplier));
|
|
||||||
for(Property<?> property : block.getStateDefinition().getProperties()) {
|
|
||||||
mapCodec = StateDefinition.appendPropertyCodec(mapCodec, stateSupplier, property.getName(), property);
|
|
||||||
}
|
|
||||||
return mapCodec;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
@Redirect(method = "codec", at = @At(value = "INVOKE", target = "Lcom/mojang/serialization/Codec;dispatch(Ljava/lang/String;Ljava/util/function/Function;Ljava/util/function/Function;)Lcom/mojang/serialization/Codec;", remap = false))
|
|
||||||
private static <O, S extends StateHolder<O, S>> Codec<S> obtainCodec(Codec<O> codec, String typeKey, Function<S, O> type, Function<O, ? extends Codec<S>> codecFn, Codec<O> codecMethodArg, Function<O, S> stateSupplier) {
|
|
||||||
return codec.dispatch(typeKey, type, block -> {
|
|
||||||
if(block instanceof Block) {
|
|
||||||
S state = stateSupplier.apply(block);
|
|
||||||
if(state.getValues().isEmpty())
|
|
||||||
return Codec.unit(state);
|
|
||||||
MapCodec<S> mapCodec;
|
|
||||||
try {
|
|
||||||
mapCodec = (MapCodec<S>)MODERNFIX_CODEC_CACHE.get((Block)block);
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
return mapCodec.fieldOf("Properties").codec();
|
|
||||||
} else {
|
|
||||||
return codecFn.apply(block);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
|
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Reference2ReferenceLinkedOpenHashMap;
|
||||||
import net.minecraft.client.renderer.block.BlockModelShaper;
|
import net.minecraft.client.renderer.block.BlockModelShaper;
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
import net.minecraft.client.resources.model.BakedModel;
|
||||||
import net.minecraft.client.resources.model.ModelManager;
|
import net.minecraft.client.resources.model.ModelManager;
|
||||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
import org.embeddedt.modernfix.dynamicresources.DynamicModelCache;
|
|
||||||
import org.embeddedt.modernfix.dynamicresources.ModelLocationCache;
|
import org.embeddedt.modernfix.dynamicresources.ModelLocationCache;
|
||||||
import org.embeddedt.modernfix.util.DynamicOverridableMap;
|
import org.embeddedt.modernfix.util.DynamicOverridableMap;
|
||||||
import org.spongepowered.asm.mixin.*;
|
import org.spongepowered.asm.mixin.*;
|
||||||
|
|
@ -24,14 +24,13 @@ public class BlockModelShaperMixin {
|
||||||
@Shadow
|
@Shadow
|
||||||
private Map<BlockState, BakedModel> modelByStateCache;
|
private Map<BlockState, BakedModel> modelByStateCache;
|
||||||
|
|
||||||
private final DynamicModelCache<BlockState> mfix$modelCache = new DynamicModelCache<>(k -> this.cacheBlockModel((BlockState)k), false);
|
private ThreadLocal<Reference2ReferenceLinkedOpenHashMap<BlockState, BakedModel>> mfix$modelCache = ThreadLocal.withInitial(Reference2ReferenceLinkedOpenHashMap::new);
|
||||||
|
|
||||||
@Inject(method = { "<init>", "replaceCache" }, at = @At("RETURN"))
|
@Inject(method = { "<init>", "replaceCache" }, at = @At("RETURN"))
|
||||||
private void replaceModelMap(CallbackInfo ci) {
|
private void replaceModelMap(CallbackInfo ci) {
|
||||||
// replace the backing map for mods which will access it
|
// replace the backing map for mods which will access it
|
||||||
this.modelByStateCache = new DynamicOverridableMap<>(state -> modelManager.getModel(ModelLocationCache.get(state)));
|
this.modelByStateCache = new DynamicOverridableMap<>(state -> modelManager.getModel(ModelLocationCache.get(state)));
|
||||||
if(this.mfix$modelCache != null)
|
this.mfix$modelCache = ThreadLocal.withInitial(Reference2ReferenceLinkedOpenHashMap::new);
|
||||||
this.mfix$modelCache.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BakedModel cacheBlockModel(BlockState state) {
|
private BakedModel cacheBlockModel(BlockState state) {
|
||||||
|
|
@ -51,6 +50,18 @@ public class BlockModelShaperMixin {
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public BakedModel getBlockModel(BlockState state) {
|
public BakedModel getBlockModel(BlockState state) {
|
||||||
return this.mfix$modelCache.get(state);
|
Reference2ReferenceLinkedOpenHashMap<BlockState, BakedModel> map = this.mfix$modelCache.get();
|
||||||
|
BakedModel model = map.get(state);
|
||||||
|
|
||||||
|
if(model != null) {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
model = this.cacheBlockModel(state);
|
||||||
|
map.putAndMoveToFirst(state, model);
|
||||||
|
if(map.size() > 500) {
|
||||||
|
map.removeLast();
|
||||||
|
}
|
||||||
|
return model;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -162,9 +162,7 @@ public class ModernFixEarlyConfig {
|
||||||
|
|
||||||
private static final ImmutableMap<String, Boolean> DEFAULT_SETTING_OVERRIDES = new DefaultSettingMapBuilder()
|
private static final ImmutableMap<String, Boolean> DEFAULT_SETTING_OVERRIDES = new DefaultSettingMapBuilder()
|
||||||
.put("mixin.perf.dynamic_resources", false)
|
.put("mixin.perf.dynamic_resources", false)
|
||||||
.put("mixin.perf.dynamic_block_codecs", false)
|
|
||||||
.put("mixin.feature.direct_stack_trace", false)
|
.put("mixin.feature.direct_stack_trace", false)
|
||||||
.putConditionally(ModernFixPlatformHooks.INSTANCE::isDevEnv, "mixin.perf.rewrite_registry", false)
|
|
||||||
.put("mixin.perf.clear_mixin_classinfo", false)
|
.put("mixin.perf.clear_mixin_classinfo", false)
|
||||||
.put("mixin.perf.deduplicate_climate_parameters", false)
|
.put("mixin.perf.deduplicate_climate_parameters", false)
|
||||||
.put("mixin.bugfix.packet_leak", false)
|
.put("mixin.bugfix.packet_leak", false)
|
||||||
|
|
@ -228,6 +226,7 @@ public class ModernFixEarlyConfig {
|
||||||
disableIfModPresent("mixin.perf.reuse_datapacks", "tac");
|
disableIfModPresent("mixin.perf.reuse_datapacks", "tac");
|
||||||
disableIfModPresent("mixin.launch.class_search_cache", "optifine");
|
disableIfModPresent("mixin.launch.class_search_cache", "optifine");
|
||||||
disableIfModPresent("mixin.perf.faster_texture_stitching", "optifine");
|
disableIfModPresent("mixin.perf.faster_texture_stitching", "optifine");
|
||||||
|
disableIfModPresent("mixin.bugfix.entity_pose_stack", "optifine");
|
||||||
disableIfModPresent("mixin.perf.datapack_reload_exceptions", "cyanide");
|
disableIfModPresent("mixin.perf.datapack_reload_exceptions", "cyanide");
|
||||||
disableIfModPresent("mixin.bugfix.buffer_builder_leak", "isometric-renders");
|
disableIfModPresent("mixin.bugfix.buffer_builder_leak", "isometric-renders");
|
||||||
disableIfModPresent("mixin.feature.remove_chat_signing", "nochatreports");
|
disableIfModPresent("mixin.feature.remove_chat_signing", "nochatreports");
|
||||||
|
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
||||||
package org.embeddedt.modernfix.registry;
|
|
||||||
|
|
||||||
import com.google.common.collect.BiMap;
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public class DirectStorageBiMap<K, V> implements BiMap<K, V> {
|
|
||||||
private final Function<V, K> keyGetter;
|
|
||||||
private final BiConsumer<V, K> keySetter;
|
|
||||||
private final Map<K, V> forwardMap;
|
|
||||||
|
|
||||||
public DirectStorageBiMap(Function<V, K> keyGetter, BiConsumer<V, K> keySetter) {
|
|
||||||
Objects.requireNonNull(keyGetter);
|
|
||||||
Objects.requireNonNull(keySetter);
|
|
||||||
this.keyGetter = keyGetter;
|
|
||||||
this.keySetter = keySetter;
|
|
||||||
this.forwardMap = new Object2ObjectOpenHashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return this.forwardMap.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return this.forwardMap.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsKey(Object o) {
|
|
||||||
return this.forwardMap.containsKey(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsValue(Object o) {
|
|
||||||
return o != null && keyGetter.apply((V)o) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public V get(Object o) {
|
|
||||||
return this.forwardMap.get(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public V put(K key, V value) {
|
|
||||||
if(this.forwardMap.containsKey(key) || (value != null && keyGetter.apply(value) != null))
|
|
||||||
throw new IllegalArgumentException("Already have mapping for " + key);
|
|
||||||
return forcePut(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public V remove(Object o) {
|
|
||||||
return put((K)o, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public V forcePut(K key, V value) {
|
|
||||||
V previousValue = this.forwardMap.put(key, value);
|
|
||||||
if(previousValue != null)
|
|
||||||
keySetter.accept(previousValue, null);
|
|
||||||
if(value != null)
|
|
||||||
keySetter.accept(value, key);
|
|
||||||
return previousValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putAll(Map<? extends K, ? extends V> map) {
|
|
||||||
map.forEach(this::put);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
for(V value : this.forwardMap.values()) {
|
|
||||||
if(value != null)
|
|
||||||
keySetter.accept(value, null);
|
|
||||||
}
|
|
||||||
this.forwardMap.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Set<K> keySet() {
|
|
||||||
return this.forwardMap.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<V> values() {
|
|
||||||
return new HashSet<>(this.forwardMap.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Set<Entry<K, V>> entrySet() {
|
|
||||||
return this.forwardMap.entrySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BiMap<V, K> inverse() {
|
|
||||||
return new Reverse();
|
|
||||||
}
|
|
||||||
|
|
||||||
class Reverse implements BiMap<V, K> {
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return DirectStorageBiMap.this.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return DirectStorageBiMap.this.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsKey(Object o) {
|
|
||||||
return DirectStorageBiMap.this.containsValue(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsValue(Object o) {
|
|
||||||
return DirectStorageBiMap.this.containsKey(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public K get(Object o) {
|
|
||||||
return o == null ? null : keyGetter.apply((V)o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public K put(V key, K value) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public K remove(Object o) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public K forcePut(V key, K value) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putAll(Map<? extends V, ? extends K> map) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Set<V> keySet() {
|
|
||||||
return DirectStorageBiMap.this.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<K> values() {
|
|
||||||
return DirectStorageBiMap.this.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Set<Entry<V, K>> entrySet() {
|
|
||||||
return DirectStorageBiMap.this.entrySet().stream()
|
|
||||||
.map(entry -> new AbstractMap.SimpleImmutableEntry<>(entry.getValue(), entry.getKey()))
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BiMap<K, V> inverse() {
|
|
||||||
return DirectStorageBiMap.this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package org.embeddedt.modernfix.registry;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
|
|
||||||
public interface DirectStorageRegistryObject {
|
|
||||||
ResourceLocation mfix$getResourceKey();
|
|
||||||
void mfix$setResourceKey(ResourceLocation key);
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
package org.embeddedt.modernfix.registry;
|
|
||||||
|
|
||||||
import com.google.common.collect.BiMap;
|
|
||||||
import net.minecraft.core.Registry;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public class RegistryStorage {
|
|
||||||
public static BiMap<ResourceLocation, DirectStorageRegistryObject> createStorage() {
|
|
||||||
return new DirectStorageBiMap<>(DirectStorageRegistryObject::mfix$getResourceKey, DirectStorageRegistryObject::mfix$setResourceKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> BiMap<ResourceKey<T>, DirectStorageRegistryObject> createKeyStorage(ResourceKey<? extends Registry<T>> registryKey, BiMap<ResourceLocation, DirectStorageRegistryObject> storage) {
|
|
||||||
if(storage instanceof DirectStorageBiMap) {
|
|
||||||
// silently ignore put/putAll calls on this map
|
|
||||||
return new TransformingBiMap<ResourceLocation, DirectStorageRegistryObject, ResourceKey<T>, DirectStorageRegistryObject>(storage, loc -> ResourceKey.create(registryKey, loc), ResourceKey::location, Function.identity(), Function.identity()) {
|
|
||||||
@Override
|
|
||||||
public DirectStorageRegistryObject put(ResourceKey<T> key, DirectStorageRegistryObject value) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putAll(Map<? extends ResourceKey<T>, ? extends DirectStorageRegistryObject> map) {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,224 +0,0 @@
|
||||||
package org.embeddedt.modernfix.registry;
|
|
||||||
|
|
||||||
import com.google.common.collect.BiMap;
|
|
||||||
import com.google.common.collect.Collections2;
|
|
||||||
import com.google.common.collect.Iterators;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public class TransformingBiMap<KFrom, VFrom, KTo, VTo> implements BiMap<KTo, VTo> {
|
|
||||||
private final BiMap<KFrom, VFrom> delegate;
|
|
||||||
private final Function<KFrom, KTo> keyFwd;
|
|
||||||
private final Function<KTo, KFrom> keyBack;
|
|
||||||
private final Function<VFrom, VTo> valueFwd;
|
|
||||||
private final Function<VTo, VFrom> valueBack;
|
|
||||||
|
|
||||||
public TransformingBiMap(BiMap<KFrom, VFrom> map, Function<KFrom, KTo> keyFwd, Function<KTo, KFrom> keyBack, Function<VFrom, VTo> valueFwd, Function<VTo, VFrom> valueBack) {
|
|
||||||
this.delegate = map;
|
|
||||||
this.keyFwd = keyFwd;
|
|
||||||
this.keyBack = keyBack;
|
|
||||||
this.valueFwd = valueFwd;
|
|
||||||
this.valueBack = valueBack;
|
|
||||||
}
|
|
||||||
|
|
||||||
private KFrom keyBack(KTo key) {
|
|
||||||
return key == null ? null : this.keyBack.apply(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private KTo keyFwd(KFrom key) {
|
|
||||||
return key == null ? null : this.keyFwd.apply(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private VFrom valueBack(VTo value) {
|
|
||||||
return value == null ? null : this.valueBack.apply(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private VTo valueFwd(VFrom value) {
|
|
||||||
return value == null ? null : this.valueFwd.apply(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return this.delegate.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return this.delegate.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsKey(Object o) {
|
|
||||||
return this.delegate.containsKey(keyBack((KTo)o));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsValue(Object o) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VTo get(Object o) {
|
|
||||||
return valueFwd(this.delegate.get(keyBack((KTo)o)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VTo put(KTo key, VTo value) {
|
|
||||||
return valueFwd(this.delegate.put(keyBack(key), valueBack(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VTo remove(Object o) {
|
|
||||||
return valueFwd(this.delegate.remove(keyBack((KTo)o)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VTo forcePut(KTo key, VTo value) {
|
|
||||||
return valueFwd(this.delegate.forcePut(keyBack(key), valueBack(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putAll(Map<? extends KTo, ? extends VTo> map) {
|
|
||||||
map.forEach((key, value) -> {
|
|
||||||
this.delegate.put(keyBack(key), valueBack(value));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
this.delegate.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Set<KTo> keySet() {
|
|
||||||
return new TransformingSet<>(this.delegate.keySet(), this.keyFwd, this.keyBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<VTo> values() {
|
|
||||||
return new TransformingSet<>(this.delegate.values(), this.valueFwd, this.valueBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Set<Entry<KTo, VTo>> entrySet() {
|
|
||||||
return new TransformingSet<>(this.delegate.entrySet(), entry -> {
|
|
||||||
return new AbstractMap.SimpleImmutableEntry<>(keyFwd(entry.getKey()), valueFwd(entry.getValue()));
|
|
||||||
}, entry -> {
|
|
||||||
return new AbstractMap.SimpleImmutableEntry<>(keyBack(entry.getKey()), valueBack(entry.getValue()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BiMap<VTo, KTo> inverse() {
|
|
||||||
return new TransformingBiMap<>(this.delegate.inverse(), this.valueFwd, this.valueBack, this.keyFwd, this.keyBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TransformingSet<TypeFrom, TypeTo> implements Set<TypeTo> {
|
|
||||||
private final Set<TypeFrom> delegate;
|
|
||||||
private final Function<TypeFrom, TypeTo> forward;
|
|
||||||
private final Function<TypeTo, TypeFrom> reverse;
|
|
||||||
|
|
||||||
public TransformingSet(Set<TypeFrom> set, Function<TypeFrom, TypeTo> forward, Function<TypeTo, TypeFrom> reverse) {
|
|
||||||
this.delegate = set;
|
|
||||||
this.forward = forward;
|
|
||||||
this.reverse = reverse;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeTo forward(TypeFrom t) {
|
|
||||||
return t == null ? null : this.forward.apply(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeFrom reverse(TypeTo t) {
|
|
||||||
return t == null ? null : this.reverse.apply(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return this.delegate.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return this.delegate.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean contains(Object o) {
|
|
||||||
return this.delegate.contains(reverse((TypeTo)o));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Iterator<TypeTo> iterator() {
|
|
||||||
return Iterators.transform(this.delegate.iterator(), this::forward);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Object[] toArray() {
|
|
||||||
Object[] array = this.delegate.toArray();
|
|
||||||
for(int i = 0; i < array.length; i++) {
|
|
||||||
array[i] = this.forward((TypeFrom)array[i]);
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public <T> T[] toArray(@NotNull T[] ts) {
|
|
||||||
if(ts.length >= this.delegate.size()) {
|
|
||||||
Object[] setContents = toArray();
|
|
||||||
System.arraycopy(setContents, 0, ts, 0, Math.min(setContents.length, ts.length));
|
|
||||||
if(ts.length > setContents.length)
|
|
||||||
ts[setContents.length] = null;
|
|
||||||
return ts;
|
|
||||||
} else {
|
|
||||||
T[] realArray = Arrays.copyOf(ts, this.delegate.size());
|
|
||||||
Iterator<TypeTo> iterator = this.iterator();
|
|
||||||
int i = 0;
|
|
||||||
while(iterator.hasNext())
|
|
||||||
realArray[i++] = (T)iterator.next();
|
|
||||||
return realArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(TypeTo typeFrom) {
|
|
||||||
return this.delegate.add(reverse(typeFrom));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object o) {
|
|
||||||
return this.delegate.remove(reverse((TypeTo)o));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsAll(@NotNull Collection<?> collection) {
|
|
||||||
return this.delegate.containsAll(Collections2.transform(collection, obj -> reverse((TypeTo)obj)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean addAll(@NotNull Collection<? extends TypeTo> collection) {
|
|
||||||
return this.delegate.addAll(Collections2.transform(collection, this::reverse));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean retainAll(@NotNull Collection<?> collection) {
|
|
||||||
return this.delegate.retainAll(Collections2.transform(collection, obj -> reverse((TypeTo)obj)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean removeAll(@NotNull Collection<?> collection) {
|
|
||||||
return this.delegate.removeAll(Collections2.transform(collection, obj -> reverse((TypeTo)obj)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
this.delegate.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
package org.embeddedt.modernfix.render;
|
|
||||||
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.lwjgl.system.MemoryUtil;
|
|
||||||
import sun.misc.Unsafe;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper that frees ByteBuffers allocated by BufferBuilders, and nulls out the address pointer
|
|
||||||
* to prevent double frees.
|
|
||||||
*
|
|
||||||
* @author Moulberry
|
|
||||||
*/
|
|
||||||
public class UnsafeBufferHelper {
|
|
||||||
private static final MemoryUtil.MemoryAllocator ALLOCATOR = MemoryUtil.getAllocator(false);
|
|
||||||
|
|
||||||
private static sun.misc.Unsafe UNSAFE = null;
|
|
||||||
private static long ADDRESS = -1;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
|
|
||||||
theUnsafe.setAccessible(true);
|
|
||||||
UNSAFE = (Unsafe)theUnsafe.get(null);
|
|
||||||
|
|
||||||
final Field addressField = MemoryUtil.class.getDeclaredField("ADDRESS");
|
|
||||||
addressField.setAccessible(true);
|
|
||||||
ADDRESS = addressField.getLong(null);
|
|
||||||
} catch(Throwable t) {
|
|
||||||
ModernFix.LOGGER.error("Could load unsafe/buffer address", t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void init() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void free(ByteBuffer buf) {
|
|
||||||
if(UNSAFE != null && ADDRESS >= 0) {
|
|
||||||
// set the address to 0 to prevent double free
|
|
||||||
long address = UNSAFE.getAndSetLong(buf, ADDRESS, 0);
|
|
||||||
if(address != 0) {
|
|
||||||
ALLOCATOR.free(address);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ALLOCATOR.free(MemoryUtil.memAddress0(buf));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
package org.embeddedt.modernfix.forge.mixin.bugfix.model_data_manager_cme;
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
|
||||||
import net.minecraftforge.client.model.data.ModelDataManager;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
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.ModifyArg;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fix several concurrency issues in the default ModelDataManager.
|
|
||||||
*/
|
|
||||||
@Mixin(ModelDataManager.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public abstract class ModelDataManagerMixin {
|
|
||||||
@Shadow protected abstract void refreshAt(ChunkPos chunk);
|
|
||||||
|
|
||||||
@Shadow @Final private Map<ChunkPos, Set<BlockPos>> needModelDataRefresh;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make the set of positions to refresh a real concurrent hash set rather than relying on synchronizedSet,
|
|
||||||
* because the returned iterator won't be thread-safe otherwise. See https://github.com/AppliedEnergistics/Applied-Energistics-2/issues/7511
|
|
||||||
*/
|
|
||||||
@ModifyArg(method = "requestRefresh", at = @At(value = "INVOKE", target = "Ljava/util/Map;computeIfAbsent(Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;", ordinal = 0), index = 1, remap = false)
|
|
||||||
private Function<ChunkPos, Set<BlockPos>> changeTypeOfSetUsed(Function<ChunkPos, Set<BlockPos>> mappingFunction) {
|
|
||||||
return pos -> Collections.newSetFromMap(new ConcurrentHashMap<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "getAt(Lnet/minecraft/world/level/ChunkPos;)Ljava/util/Map;", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/client/model/data/ModelDataManager;refreshAt(Lnet/minecraft/world/level/ChunkPos;)V"), remap = false)
|
|
||||||
private void onlyRefreshOnMainThread(ModelDataManager instance, ChunkPos pos) {
|
|
||||||
// Only refresh model data on the main thread. This prevents calling getBlockEntity from worker threads
|
|
||||||
// which could cause weird CMEs or other behavior.
|
|
||||||
// Avoid the loop if no model data needs to be refreshed, to prevent unnecessary allocation.
|
|
||||||
if(Minecraft.getInstance().isSameThread() && !needModelDataRefresh.isEmpty()) {
|
|
||||||
// Refresh the given chunk, and all its neighbors. This is less efficient than the default code
|
|
||||||
// but we have no choice since we need to not do refreshing on workers, and blocks might
|
|
||||||
// try to access model data in neighboring chunks.
|
|
||||||
for(int x = -1; x <= 1; x++) {
|
|
||||||
for(int z = -1; z <= 1; z++) {
|
|
||||||
refreshAt(new ChunkPos(pos.x + x, pos.z + z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
package org.embeddedt.modernfix.forge.mixin.perf.forge_cap_retrieval;
|
|
||||||
|
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
|
||||||
import net.minecraftforge.common.capabilities.Capability;
|
|
||||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
@Mixin(LivingEntity.class)
|
|
||||||
public class LivingEntityMixin {
|
|
||||||
/**
|
|
||||||
* @author embeddedt (issue noted by XFactHD)
|
|
||||||
* @reason check capability equality before checking that entity is alive, the latter requires a lot more
|
|
||||||
* indirection
|
|
||||||
*/
|
|
||||||
@Redirect(method = "getCapability", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;isAlive()Z"))
|
|
||||||
private <T> boolean checkAliveAfterCap(LivingEntity entity, Capability<T> capability, @Nullable Direction facing) {
|
|
||||||
return capability == ForgeCapabilities.ITEM_HANDLER && entity.isAlive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
package org.embeddedt.modernfix.forge.mixin.perf.forge_registry_alloc;
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
|
||||||
import net.minecraft.core.Holder;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraftforge.registries.ForgeRegistry;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Mixin(value = ForgeRegistry.class, remap = false)
|
|
||||||
public abstract class ForgeRegistryMixin<V> {
|
|
||||||
// Replace the backing maps with fastutil maps for a bit more speed, since value->holder lookups in particular
|
|
||||||
// are a bottleneck in many areas (e.g. render type lookup)
|
|
||||||
@Shadow @Final private Map<ResourceLocation, Holder.Reference<V>> delegatesByName = new Object2ObjectOpenHashMap<>();
|
|
||||||
|
|
||||||
@Shadow @Final private Map<V, Holder.Reference<V>> delegatesByValue = new Object2ObjectOpenHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason stop allocating so many unneeded objects. stop.
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public Holder.Reference<V> getDelegateOrThrow(ResourceLocation location) {
|
|
||||||
Holder.Reference<V> holder = delegatesByName.get(location);
|
|
||||||
|
|
||||||
if (holder == null) {
|
|
||||||
throw new IllegalArgumentException(String.format(Locale.ENGLISH, "No delegate exists for location %s", location));
|
|
||||||
}
|
|
||||||
|
|
||||||
return holder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason see above
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public Holder.Reference<V> getDelegateOrThrow(ResourceKey<V> rkey) {
|
|
||||||
Holder.Reference<V> holder = delegatesByName.get(rkey.location());
|
|
||||||
|
|
||||||
if (holder == null) {
|
|
||||||
throw new IllegalArgumentException(String.format(Locale.ENGLISH, "No delegate exists for key %s", rkey));
|
|
||||||
}
|
|
||||||
|
|
||||||
return holder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason see above
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public Holder.Reference<V> getDelegateOrThrow(V value) {
|
|
||||||
Holder.Reference<V> holder = delegatesByValue.get(value);
|
|
||||||
|
|
||||||
if (holder == null) {
|
|
||||||
throw new IllegalArgumentException(String.format(Locale.ENGLISH, "No delegate exists for value %s", value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return holder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,7 @@ mixinextras_version=0.3.2
|
||||||
mod_id=modernfix
|
mod_id=modernfix
|
||||||
minecraft_version=24w09a
|
minecraft_version=24w09a
|
||||||
enabled_platforms=fabric
|
enabled_platforms=fabric
|
||||||
forge_version=20.4.132-beta
|
forge_version=20.4.190
|
||||||
# parchment_version=2023.07.09
|
# parchment_version=2023.07.09
|
||||||
refined_storage_version=4392788
|
refined_storage_version=4392788
|
||||||
jei_version=16.0.0.28
|
jei_version=16.0.0.28
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,6 @@ dependencies {
|
||||||
modCompileOnly("curse.maven:supermartijncore-454372:4455391")
|
modCompileOnly("curse.maven:supermartijncore-454372:4455391")
|
||||||
modCompileOnly("vazkii.patchouli:Patchouli:1.19.2-77")
|
modCompileOnly("vazkii.patchouli:Patchouli:1.19.2-77")
|
||||||
|
|
||||||
modCompileOnly("curse.maven:blueprint-382216:3991478")
|
|
||||||
|
|
||||||
// runtime remapping at home
|
// runtime remapping at home
|
||||||
for (extraModJar in fileTree(dir: extraModsDir, include: '*.jar')) {
|
for (extraModJar in fileTree(dir: extraModsDir, include: '*.jar')) {
|
||||||
def basename = extraModJar.name.substring(0, extraModJar.name.length() - ".jar".length())
|
def basename = extraModJar.name.substring(0, extraModJar.name.length() - ".jar".length())
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package org.embeddedt.modernfix.neoforge.mixin.bugfix.blueprint_modif_memory_leak;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.teamabnormals.blueprint.core.util.modification.ObjectModificationManager;
|
|
||||||
import com.teamabnormals.blueprint.core.util.modification.selection.SelectionSpace;
|
|
||||||
import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
|
|
||||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
|
||||||
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(ObjectModificationManager.class)
|
|
||||||
@RequiresMod("blueprint")
|
|
||||||
public abstract class ObjectModificationManagerMixin extends SimpleJsonResourceReloadListener {
|
|
||||||
@Shadow(remap = false) protected SelectionSpace selectionSpace;
|
|
||||||
|
|
||||||
public ObjectModificationManagerMixin(Gson gson, String string) {
|
|
||||||
super(gson, string);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "apply(Ljava/util/Map;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", at = @At("RETURN"), remap = false)
|
|
||||||
private void clearSelectionSpace(CallbackInfo ci) {
|
|
||||||
this.selectionSpace = consumer -> {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package org.embeddedt.modernfix.forge.mixin.bugfix.entity_pose_stack;
|
package org.embeddedt.modernfix.neoforge.mixin.bugfix.entity_pose_stack;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||||
import net.minecraftforge.client.event.RenderLivingEvent;
|
import net.neoforged.neoforge.client.event.RenderLivingEvent;
|
||||||
import net.minecraftforge.eventbus.api.Event;
|
import net.neoforged.bus.api.Event;
|
||||||
import net.minecraftforge.eventbus.api.IEventBus;
|
import net.neoforged.bus.api.IEventBus;
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
@ -13,18 +13,17 @@ import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
@Mixin(LivingEntityRenderer.class)
|
@Mixin(LivingEntityRenderer.class)
|
||||||
@ClientOnlyMixin
|
@ClientOnlyMixin
|
||||||
public class LivingEntityRendererMixin {
|
public class LivingEntityRendererMixin {
|
||||||
@Redirect(method = "render(Lnet/minecraft/world/entity/LivingEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/eventbus/api/IEventBus;post(Lnet/minecraftforge/eventbus/api/Event;)Z", ordinal = 0))
|
@Redirect(method = "render(Lnet/minecraft/world/entity/LivingEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "INVOKE", target = "Lnet/neoforged/bus/api/IEventBus;post(Lnet/neoforged/bus/api/Event;)Lnet/neoforged/bus/api/Event;", ordinal = 0))
|
||||||
private boolean fireCheckingPoseStack(IEventBus instance, Event event) {
|
private Event fireCheckingPoseStack(IEventBus instance, Event event) {
|
||||||
PoseStack stack = ((RenderLivingEvent)event).getPoseStack();
|
PoseStack stack = ((RenderLivingEvent)event).getPoseStack();
|
||||||
int size = ((PoseStackAccessor)stack).getPoseStack().size();
|
int size = ((PoseStackAccessor)stack).getPoseStack().size();
|
||||||
if (instance.post(event)) {
|
instance.post(event);
|
||||||
|
if (((RenderLivingEvent.Pre)event).isCanceled()) {
|
||||||
// Pop the stack if someone pushed it in the event
|
// Pop the stack if someone pushed it in the event
|
||||||
while (((PoseStackAccessor)stack).getPoseStack().size() > size) {
|
while (((PoseStackAccessor)stack).getPoseStack().size() > size) {
|
||||||
stack.popPose();
|
stack.popPose();
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package org.embeddedt.modernfix.forge.mixin.bugfix.entity_pose_stack;
|
package org.embeddedt.modernfix.neoforge.mixin.bugfix.entity_pose_stack;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||||
import net.minecraftforge.client.event.RenderPlayerEvent;
|
import net.neoforged.bus.api.Event;
|
||||||
import net.minecraftforge.eventbus.api.Event;
|
import net.neoforged.bus.api.IEventBus;
|
||||||
import net.minecraftforge.eventbus.api.IEventBus;
|
import net.neoforged.neoforge.client.event.RenderPlayerEvent;
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
@ -13,18 +13,17 @@ import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
@Mixin(PlayerRenderer.class)
|
@Mixin(PlayerRenderer.class)
|
||||||
@ClientOnlyMixin
|
@ClientOnlyMixin
|
||||||
public class PlayerRendererMixin {
|
public class PlayerRendererMixin {
|
||||||
@Redirect(method = "render(Lnet/minecraft/client/player/AbstractClientPlayer;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/eventbus/api/IEventBus;post(Lnet/minecraftforge/eventbus/api/Event;)Z", ordinal = 0))
|
@Redirect(method = "render(Lnet/minecraft/client/player/AbstractClientPlayer;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "INVOKE", target = "Lnet/neoforged/bus/api/IEventBus;post(Lnet/neoforged/bus/api/Event;)Lnet/neoforged/bus/api/Event;", ordinal = 0))
|
||||||
private boolean fireCheckingPoseStack(IEventBus instance, Event event) {
|
private Event fireCheckingPoseStack(IEventBus instance, Event event) {
|
||||||
PoseStack stack = ((RenderPlayerEvent)event).getPoseStack();
|
PoseStack stack = ((RenderPlayerEvent)event).getPoseStack();
|
||||||
int size = ((PoseStackAccessor)stack).getPoseStack().size();
|
int size = ((PoseStackAccessor)stack).getPoseStack().size();
|
||||||
if (instance.post(event)) {
|
instance.post(event);
|
||||||
|
if (((RenderPlayerEvent.Pre)event).isCanceled()) {
|
||||||
// Pop the stack if someone pushed it in the event
|
// Pop the stack if someone pushed it in the event
|
||||||
while (((PoseStackAccessor)stack).getPoseStack().size() > size) {
|
while (((PoseStackAccessor)stack).getPoseStack().size() > size) {
|
||||||
stack.popPose();
|
stack.popPose();
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package org.embeddedt.modernfix.forge.mixin.bugfix.entity_pose_stack;
|
package org.embeddedt.modernfix.neoforge.mixin.bugfix.entity_pose_stack;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
Loading…
Reference in New Issue
Block a user