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;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import net.minecraft.core.MappedRegistry;
|
||||
import net.minecraft.core.RegistrationInfo;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.embeddedt.modernfix.annotation.IgnoreOutsideDev;
|
||||
import org.embeddedt.modernfix.registry.LifecycleMap;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
|
|
@ -25,17 +23,8 @@ public abstract class MappedRegistryMixin<T> {
|
|||
@Mutable
|
||||
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>(Lnet/minecraft/resources/ResourceKey;Lcom/mojang/serialization/Lifecycle;Z)V", at = @At("RETURN"))
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void replaceStorage(CallbackInfo ci) {
|
||||
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;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ReferenceLinkedOpenHashMap;
|
||||
import net.minecraft.client.renderer.block.BlockModelShaper;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.dynamicresources.DynamicModelCache;
|
||||
import org.embeddedt.modernfix.dynamicresources.ModelLocationCache;
|
||||
import org.embeddedt.modernfix.util.DynamicOverridableMap;
|
||||
import org.spongepowered.asm.mixin.*;
|
||||
|
|
@ -24,14 +24,13 @@ public class BlockModelShaperMixin {
|
|||
@Shadow
|
||||
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"))
|
||||
private void replaceModelMap(CallbackInfo ci) {
|
||||
// replace the backing map for mods which will access it
|
||||
this.modelByStateCache = new DynamicOverridableMap<>(state -> modelManager.getModel(ModelLocationCache.get(state)));
|
||||
if(this.mfix$modelCache != null)
|
||||
this.mfix$modelCache.clear();
|
||||
this.mfix$modelCache = ThreadLocal.withInitial(Reference2ReferenceLinkedOpenHashMap::new);
|
||||
}
|
||||
|
||||
private BakedModel cacheBlockModel(BlockState state) {
|
||||
|
|
@ -51,6 +50,18 @@ public class BlockModelShaperMixin {
|
|||
*/
|
||||
@Overwrite
|
||||
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()
|
||||
.put("mixin.perf.dynamic_resources", false)
|
||||
.put("mixin.perf.dynamic_block_codecs", 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.deduplicate_climate_parameters", false)
|
||||
.put("mixin.bugfix.packet_leak", false)
|
||||
|
|
@ -228,6 +226,7 @@ public class ModernFixEarlyConfig {
|
|||
disableIfModPresent("mixin.perf.reuse_datapacks", "tac");
|
||||
disableIfModPresent("mixin.launch.class_search_cache", "optifine");
|
||||
disableIfModPresent("mixin.perf.faster_texture_stitching", "optifine");
|
||||
disableIfModPresent("mixin.bugfix.entity_pose_stack", "optifine");
|
||||
disableIfModPresent("mixin.perf.datapack_reload_exceptions", "cyanide");
|
||||
disableIfModPresent("mixin.bugfix.buffer_builder_leak", "isometric-renders");
|
||||
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
|
||||
minecraft_version=24w09a
|
||||
enabled_platforms=fabric
|
||||
forge_version=20.4.132-beta
|
||||
forge_version=20.4.190
|
||||
# parchment_version=2023.07.09
|
||||
refined_storage_version=4392788
|
||||
jei_version=16.0.0.28
|
||||
|
|
|
|||
|
|
@ -50,8 +50,6 @@ dependencies {
|
|||
modCompileOnly("curse.maven:supermartijncore-454372:4455391")
|
||||
modCompileOnly("vazkii.patchouli:Patchouli:1.19.2-77")
|
||||
|
||||
modCompileOnly("curse.maven:blueprint-382216:3991478")
|
||||
|
||||
// runtime remapping at home
|
||||
for (extraModJar in fileTree(dir: extraModsDir, include: '*.jar')) {
|
||||
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 net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraftforge.client.event.RenderLivingEvent;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.neoforged.neoforge.client.event.RenderLivingEvent;
|
||||
import net.neoforged.bus.api.Event;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
|
@ -13,18 +13,17 @@ import org.spongepowered.asm.mixin.injection.Redirect;
|
|||
@Mixin(LivingEntityRenderer.class)
|
||||
@ClientOnlyMixin
|
||||
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))
|
||||
private boolean fireCheckingPoseStack(IEventBus instance, Event event) {
|
||||
@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 Event fireCheckingPoseStack(IEventBus instance, Event event) {
|
||||
PoseStack stack = ((RenderLivingEvent)event).getPoseStack();
|
||||
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
|
||||
while (((PoseStackAccessor)stack).getPoseStack().size() > size) {
|
||||
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 net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||
import net.minecraftforge.client.event.RenderPlayerEvent;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.neoforged.bus.api.Event;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.client.event.RenderPlayerEvent;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
|
@ -13,18 +13,17 @@ import org.spongepowered.asm.mixin.injection.Redirect;
|
|||
@Mixin(PlayerRenderer.class)
|
||||
@ClientOnlyMixin
|
||||
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))
|
||||
private boolean fireCheckingPoseStack(IEventBus instance, Event event) {
|
||||
@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 Event fireCheckingPoseStack(IEventBus instance, Event event) {
|
||||
PoseStack stack = ((RenderPlayerEvent)event).getPoseStack();
|
||||
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
|
||||
while (((PoseStackAccessor)stack).getPoseStack().size() > size) {
|
||||
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 org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
Loading…
Reference in New Issue
Block a user