Merge commit 'd64a1c760b7cd66393b8cb962501278624f23444' into 1.21.1
This commit is contained in:
commit
935365604d
|
|
@ -1,21 +0,0 @@
|
|||
package org.embeddedt.modernfix;
|
||||
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class FileWalker extends CacheLoader<Pair<Path, Integer>, List<Path>> {
|
||||
public static final FileWalker INSTANCE = new FileWalker();
|
||||
|
||||
@Override
|
||||
public List<Path> load(Pair<Path, Integer> key) throws Exception {
|
||||
try(Stream<Path> stream = Files.walk(key.getLeft(), key.getRight())) {
|
||||
return stream.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
package org.embeddedt.modernfix;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.MemoryReserve;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.embeddedt.modernfix.api.constants.IntegrationConstants;
|
||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||
|
|
@ -98,25 +96,6 @@ public class ModernFixClient {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the IDs match and remap them if not.
|
||||
* @return true if ID remap was needed
|
||||
*/
|
||||
private static boolean compareAndSwitchIds(Class<? extends Entity> eClass, String fieldName, EntityDataAccessor<?> accessor, int newId) {
|
||||
if(accessor.id != newId) {
|
||||
ModernFix.LOGGER.warn("Corrected ID mismatch on {} field {}. Client had {} but server wants {}.",
|
||||
eClass,
|
||||
fieldName,
|
||||
accessor.id,
|
||||
newId);
|
||||
accessor.id = newId;
|
||||
return true;
|
||||
} else {
|
||||
ModernFix.LOGGER.debug("{} {} ID fine: {}", eClass, fieldName, newId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void onServerStarted(MinecraftServer server) {
|
||||
if(!ModernFixMixinPlugin.instance.isOptionEnabled("feature.integrated_server_watchdog.IntegratedWatchdog"))
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||
import org.embeddedt.modernfix.duck.IBlockState;
|
||||
|
||||
public class BlockStateCacheHandler {
|
||||
public static void rebuildParallel(boolean force) {
|
||||
public static void invalidateCache() {
|
||||
synchronized (BlockBehaviour.BlockStateBase.class) {
|
||||
for (BlockState blockState : Block.BLOCK_STATE_REGISTRY) {
|
||||
((IBlockState)blockState).clearCache();
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
package org.embeddedt.modernfix.blockstate;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.StateHolder;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class FerriteCorePostProcess {
|
||||
private static final boolean willPostProcess;
|
||||
|
||||
private static final MethodHandle theTable, toKeyIndex;
|
||||
|
||||
static {
|
||||
boolean success = true;
|
||||
MethodHandle table = null, keyIndex = null;
|
||||
try {
|
||||
Class<?> fastMap = Class.forName("malte0811.ferritecore.fastmap.FastMap");
|
||||
Field field = fastMap.getDeclaredField("toKeyIndex");
|
||||
field.setAccessible(true);
|
||||
keyIndex = MethodHandles.publicLookup().unreflectSetter(field);
|
||||
field = StateHolder.class.getDeclaredField("ferritecore_globalTable");
|
||||
field.setAccessible(true);
|
||||
table = MethodHandles.publicLookup().unreflectGetter(field);
|
||||
} catch(ReflectiveOperationException | RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
success = false;
|
||||
}
|
||||
willPostProcess = success;
|
||||
theTable = table;
|
||||
toKeyIndex = keyIndex;
|
||||
}
|
||||
|
||||
private static final Object2IntMap<?> EMPTY_MAP;
|
||||
|
||||
static {
|
||||
Object2IntArrayMap<?> map = new Object2IntArrayMap<>();
|
||||
map.defaultReturnValue(-1);
|
||||
EMPTY_MAP = Object2IntMaps.unmodifiable(map);
|
||||
}
|
||||
|
||||
public static <O, S extends StateHolder<O, S>> void postProcess(StateDefinition<O, S> state) {
|
||||
if(!willPostProcess)
|
||||
return;
|
||||
try {
|
||||
if(state.getProperties().size() == 0) {
|
||||
for(S holder : state.getPossibleStates()) {
|
||||
// deduplicate Object2IntMap objects from FerriteCore
|
||||
// will probably be fixed upstream at some point, but likely not for older versions
|
||||
Object table = theTable.invoke(holder);
|
||||
toKeyIndex.invoke(table, EMPTY_MAP);
|
||||
}
|
||||
}
|
||||
} catch(Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
package org.embeddedt.modernfix.chunk;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class SafeBlockGetter implements BlockGetter {
|
||||
private final ServerLevel wrapped;
|
||||
private final Thread mainThread;
|
||||
|
||||
public SafeBlockGetter(ServerLevel wrapped) {
|
||||
this.wrapped = wrapped;
|
||||
this.mainThread = Thread.currentThread();
|
||||
}
|
||||
|
||||
public boolean shouldUse() {
|
||||
return Thread.currentThread() != this.mainThread;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BlockGetter getChunkSafe(BlockPos pos) {
|
||||
// can safely call getChunkForLighting off-thread
|
||||
BlockGetter access = this.wrapped.getChunkSource().getChunkForLighting(pos.getX() >> 4, pos.getZ() >> 4);
|
||||
if(!(access instanceof ChunkAccess))
|
||||
return null;
|
||||
ChunkAccess chunk = (ChunkAccess)access;
|
||||
if(!chunk.getPersistedStatus().isOrAfter(ChunkStatus.FULL))
|
||||
return null;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxBuildHeight() {
|
||||
return this.wrapped.getMaxBuildHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxLightLevel() {
|
||||
return this.wrapped.getMaxLightLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinBuildHeight() {
|
||||
return this.wrapped.getMinBuildHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return this.wrapped.getHeight();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(BlockPos pos) {
|
||||
BlockGetter g = getChunkSafe(pos);
|
||||
return g == null ? null : g.getBlockEntity(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
BlockGetter g = getChunkSafe(pos);
|
||||
return g == null ? Blocks.AIR.defaultBlockState() : g.getBlockState(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos) {
|
||||
BlockGetter g = getChunkSafe(pos);
|
||||
return g == null ? Fluids.EMPTY.defaultFluidState() : g.getFluidState(pos);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.bugfix.chunk_deadlock;
|
||||
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import org.embeddedt.modernfix.chunk.SafeBlockGetter;
|
||||
import org.embeddedt.modernfix.duck.ISafeBlockGetter;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
||||
@Mixin(value = BlockBehaviour.BlockStateBase.class, priority = 100)
|
||||
public class BlockStateBaseMixin {
|
||||
@ModifyVariable(method = "getOffset", at = @At("HEAD"), argsOnly = true, index = 1)
|
||||
private BlockGetter useSafeGetter(BlockGetter g) {
|
||||
if(g instanceof ISafeBlockGetter) {
|
||||
SafeBlockGetter replacement = ((ISafeBlockGetter) g).mfix$getSafeBlockGetter();
|
||||
if(replacement.shouldUse())
|
||||
return replacement;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.bugfix.chunk_deadlock;
|
||||
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import org.embeddedt.modernfix.chunk.SafeBlockGetter;
|
||||
import org.embeddedt.modernfix.duck.ISafeBlockGetter;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
@Mixin(ServerLevel.class)
|
||||
public class ServerLevelMixin implements ISafeBlockGetter {
|
||||
@Unique
|
||||
private final SafeBlockGetter mfix$safeBlockGetter = new SafeBlockGetter((ServerLevel)(Object)this);
|
||||
|
||||
@Override
|
||||
public SafeBlockGetter mfix$getSafeBlockGetter() {
|
||||
return mfix$safeBlockGetter;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.bugfix.concurrency;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.thread.BlockableEventLoop;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
@Mixin(Minecraft.class)
|
||||
@ClientOnlyMixin
|
||||
public abstract class MinecraftMixin<R extends Runnable> extends BlockableEventLoop<R> {
|
||||
|
||||
protected MinecraftMixin(String p_i50403_1_) {
|
||||
super(p_i50403_1_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void managedBlock(BooleanSupplier pIsDone) {
|
||||
if(!this.isSameThread()) {
|
||||
ModernFix.LOGGER.warn("A mod is calling Minecraft.managedBlock from the wrong thread. This is most likely related to one of our parallelizations.");
|
||||
ModernFix.LOGGER.warn("ModernFix will work around this, however ideally the issue should be patched in the other mod.");
|
||||
ModernFix.LOGGER.warn("Stacktrace", new IllegalThreadStateException());
|
||||
while(!pIsDone.getAsBoolean()) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch(InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super.managedBlock(pIsDone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.feature.direct_stack_trace;
|
||||
|
||||
import net.minecraft.CrashReport;
|
||||
import net.minecraft.CrashReportCategory;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(CrashReport.class)
|
||||
public class CrashReportMixin {
|
||||
@Shadow @Final private Throwable exception;
|
||||
|
||||
@Inject(method = "addCategory(Ljava/lang/String;I)Lnet/minecraft/CrashReportCategory;", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false))
|
||||
private void dumpStacktrace(String s, int i, CallbackInfoReturnable<CrashReportCategory> cir) {
|
||||
new Exception("ModernFix crash stacktrace").printStackTrace();
|
||||
if(this.exception != null)
|
||||
this.exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.feature.stalled_chunk_load_detection;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.server.level.ChunkResult;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.Biomes;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.EmptyLevelChunk;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
@Mixin(value = ServerChunkCache.class, priority = 1100)
|
||||
public abstract class ServerChunkCacheMixin {
|
||||
@Shadow @Final private Thread mainThread;
|
||||
@Shadow @Final public ServerLevel level;
|
||||
|
||||
@Shadow protected abstract CompletableFuture<ChunkResult<ChunkAccess>> getChunkFutureMainThread(int k, int l, ChunkStatus arg, boolean bl);
|
||||
|
||||
@Shadow @Final private ServerChunkCache.MainThreadExecutor mainThreadProcessor;
|
||||
private final boolean debugDeadServerAccess = Boolean.getBoolean("modernfix.debugBadChunkloading");
|
||||
|
||||
@Inject(method = "getChunk", at = @At("HEAD"), cancellable = true)
|
||||
private void bailIfServerDead(int chunkX, int chunkZ, ChunkStatus requiredStatus, boolean load, CallbackInfoReturnable<ChunkAccess> cir) {
|
||||
if(!this.level.getServer().isRunning() && !this.mainThread.isAlive()) {
|
||||
ModernFix.LOGGER.fatal("A mod is accessing chunks from a stopped server (this will also cause memory leaks)");
|
||||
if(debugDeadServerAccess) {
|
||||
new Exception().printStackTrace();
|
||||
}
|
||||
Holder<Biome> plains = this.level.registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(Biomes.PLAINS);
|
||||
cir.setReturnValue(new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ), plains));
|
||||
} else if(Thread.currentThread() != this.mainThread) {
|
||||
CompletableFuture<ChunkResult<ChunkAccess>> future = CompletableFuture.supplyAsync(() -> this.getChunkFutureMainThread(chunkX, chunkZ, requiredStatus, false), this.mainThreadProcessor).join();
|
||||
if(!future.isDone()) {
|
||||
// Wait at least 500 milliseconds before printing anything
|
||||
ChunkResult<ChunkAccess> resultingChunk = null;
|
||||
try {
|
||||
resultingChunk = future.get(500, TimeUnit.MILLISECONDS);
|
||||
} catch(InterruptedException | ExecutionException | TimeoutException ignored) {
|
||||
}
|
||||
if(resultingChunk != null && resultingChunk.isSuccess()) {
|
||||
cir.setReturnValue(resultingChunk.orElse(null));
|
||||
return;
|
||||
}
|
||||
if(debugDeadServerAccess)
|
||||
ModernFix.LOGGER.warn("Async loading of a chunk was requested, this might not be desirable", new Exception());
|
||||
try {
|
||||
resultingChunk = future.get(10, TimeUnit.SECONDS);
|
||||
if(resultingChunk.isSuccess()) {
|
||||
cir.setReturnValue(resultingChunk.orElse(null));
|
||||
return;
|
||||
}
|
||||
} catch(InterruptedException | ExecutionException | TimeoutException e) {
|
||||
ModernFix.LOGGER.error("Async chunk load took way too long, this needs to be reported to the appropriate mod.", e);
|
||||
}
|
||||
//cir.setReturnValue(new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.cache_model_materials;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.multipart.MultiPart;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@Mixin(MultiPart.class)
|
||||
@ClientOnlyMixin
|
||||
public class MultipartMixin {
|
||||
private Collection<ResourceLocation> dependencyCache = null;
|
||||
@Inject(method = "getDependencies", at = @At("HEAD"), cancellable = true)
|
||||
private void useDependencyCache(CallbackInfoReturnable<Collection<ResourceLocation>> cir) {
|
||||
if(dependencyCache != null)
|
||||
cir.setReturnValue(dependencyCache);
|
||||
}
|
||||
|
||||
@Inject(method = "getDependencies", at = @At("RETURN"))
|
||||
private void storeDependencyCache(CallbackInfoReturnable<Collection<ResourceLocation>> cir) {
|
||||
if(dependencyCache == null)
|
||||
dependencyCache = cir.getReturnValue();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.compact_mojang_registries;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.util.datafix.fixes.BlockStateData;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(value = BlockStateData.class, priority = 2000)
|
||||
public class BlockStateDataMixin {
|
||||
@Unique
|
||||
private static ObjectOpenHashSet<Tag> TAG_INTERNER;
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason Reduce memory use of these constant CompoundTags via aggressive interning.
|
||||
*/
|
||||
@ModifyExpressionValue(method = "parse", at = @At(value = "INVOKE", target = "Lnet/minecraft/nbt/TagParser;parseTag(Ljava/lang/String;)Lnet/minecraft/nbt/CompoundTag;"))
|
||||
private static CompoundTag compactTag(CompoundTag tag) {
|
||||
if (TAG_INTERNER == null) {
|
||||
TAG_INTERNER = new ObjectOpenHashSet<>();
|
||||
}
|
||||
Map.Entry<String, Tag>[] entries = new Map.Entry[tag.size()];
|
||||
int i = 0;
|
||||
for (var key : tag.getAllKeys()) {
|
||||
Tag t = tag.get(key);
|
||||
if (t instanceof CompoundTag ct) {
|
||||
t = compactTag(ct);
|
||||
}
|
||||
t = TAG_INTERNER.addOrGet(t);
|
||||
entries[i++] = Map.entry(key, t);
|
||||
}
|
||||
return new CompoundTag(Map.ofEntries(entries));
|
||||
}
|
||||
|
||||
@Inject(method = "<clinit>", at = @At("RETURN"))
|
||||
private static void clearInterner(CallbackInfo ci) {
|
||||
if (TAG_INTERNER != null) {
|
||||
TAG_INTERNER.clear();
|
||||
TAG_INTERNER.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.deduplicate_climate_parameters;
|
||||
|
||||
import net.minecraft.world.level.biome.Climate;
|
||||
import org.embeddedt.modernfix.dedup.ClimateCache;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin({ Climate.Parameter.class, Climate.ParameterPoint.class })
|
||||
public class ParameterMixin {
|
||||
@Redirect(method = "*", at = @At(value = "NEW", target = "net/minecraft/world/level/biome/Climate$Parameter"), require = 0)
|
||||
private static Climate.Parameter internParameterStatic(long min, long max) {
|
||||
return ClimateCache.MFIX_INTERNER.intern(new Climate.Parameter(min, max));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.deduplicate_location;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.embeddedt.modernfix.dedup.IdentifierCaches;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ResourceLocation.class)
|
||||
public class MixinResourceLocation {
|
||||
@Mutable
|
||||
@Shadow
|
||||
@Final
|
||||
private String namespace;
|
||||
|
||||
@Mutable
|
||||
@Shadow
|
||||
@Final
|
||||
private String path;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void reinit(String string, String string2, CallbackInfo ci) {
|
||||
this.namespace = IdentifierCaches.NAMESPACES.deduplicate(this.namespace);
|
||||
this.path = IdentifierCaches.PATH.deduplicate(this.path);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_entity_renderers;
|
||||
|
||||
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.entity.EntityRendererMap;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(EntityRenderDispatcher.class)
|
||||
@ClientOnlyMixin
|
||||
public class EntityRenderDispatcherMixin {
|
||||
@Shadow private Map<EntityType<?>, EntityRenderer<?>> renderers;
|
||||
|
||||
private EntityRendererMap mfix$dynamicRenderers;
|
||||
|
||||
@Inject(method = "getRenderer", at = @At("RETURN"), cancellable = true)
|
||||
private <T extends Entity> void checkNullness(T entity, CallbackInfoReturnable<EntityRenderer<? super T>> cir) {
|
||||
// apparently some mods yeet the renderers map and cause issues
|
||||
if(cir.getReturnValue() == null)
|
||||
cir.setReturnValue((EntityRenderer<? super T>)mfix$dynamicRenderers.get(entity.getType()));
|
||||
}
|
||||
|
||||
@Redirect(method = "onResourceManagerReload", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/renderer/entity/EntityRenderDispatcher;renderers:Ljava/util/Map;"))
|
||||
private void setRendererField(EntityRenderDispatcher instance, Map<EntityType<?>, EntityRenderer<?>> incomingMap) {
|
||||
this.renderers = incomingMap;
|
||||
this.mfix$dynamicRenderers = (EntityRendererMap)incomingMap;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_entity_renderers;
|
||||
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderers;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.entity.EntityRendererMap;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(EntityRenderers.class)
|
||||
@ClientOnlyMixin
|
||||
public class EntityRenderersMixin {
|
||||
@Shadow @Final private static Map<EntityType<?>, EntityRendererProvider<?>> PROVIDERS;
|
||||
|
||||
@Inject(method = "createEntityRenderers", at = @At("HEAD"), cancellable = true)
|
||||
private static void createDynamicRendererLoader(EntityRendererProvider.Context context, CallbackInfoReturnable<Map<EntityType<?>, EntityRenderer<?>>> cir) {
|
||||
cir.setReturnValue(new EntityRendererMap(PROVIDERS, context));
|
||||
ModernFix.LOGGER.info("Dynamic entity renderer hook setup");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +1,22 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.model_optimizations;
|
||||
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.embeddedt.modernfix.dedup.IdentifierCaches;
|
||||
import org.spongepowered.asm.mixin.*;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
||||
@Mixin(Property.class)
|
||||
public class PropertyMixin {
|
||||
|
||||
@Shadow @Mutable
|
||||
@Final private String name;
|
||||
|
||||
@Shadow private Integer hashCode;
|
||||
@Shadow @Final private String name;
|
||||
|
||||
@Shadow @Final private Class clazz;
|
||||
|
||||
@Redirect(method = "<init>", at = @At(value = "FIELD", target = "Lnet/minecraft/world/level/block/state/properties/Property;name:Ljava/lang/String;"))
|
||||
private void internName(Property instance, String name) {
|
||||
this.name = IdentifierCaches.PROPERTY.deduplicate(name);
|
||||
@ModifyVariable(method = "<init>", at = @At("HEAD"), ordinal = 0, argsOnly = true)
|
||||
private static String internName(String name) {
|
||||
return name.intern();
|
||||
}
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason compare hashcodes if generated, use reference equality for speed
|
||||
|
|
@ -32,7 +29,8 @@ public class PropertyMixin {
|
|||
return false;
|
||||
} else {
|
||||
Property<?> property = (Property)p_equals_1_;
|
||||
/* reference equality is safe here because of deduplication */
|
||||
/* reference equality is safe here because of interning above */
|
||||
//noinspection StringEquality
|
||||
return this.clazz == property.getValueClass() && this.name == property.getName();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.mojang_registry_size;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(ResourceKey.class)
|
||||
public class ResourceKeyMixin<T> {
|
||||
private static final Map<ResourceLocation, Map<ResourceLocation, ResourceKey<?>>> INTERNING_MAP = new Object2ObjectOpenHashMap<>();
|
||||
@Inject(method = "create(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/resources/ResourceKey;", at = @At("HEAD"), cancellable = true)
|
||||
private static <T> void createEfficient(ResourceLocation parent, ResourceLocation location, CallbackInfoReturnable<ResourceKey<T>> cir) {
|
||||
synchronized (ResourceKey.class) {
|
||||
Map<ResourceLocation, ResourceKey<?>> keys = INTERNING_MAP.computeIfAbsent(parent, k -> new Object2ObjectOpenHashMap<>());
|
||||
ResourceKey<?> key = keys.get(location);
|
||||
if(key == null) {
|
||||
key = new ResourceKey<>(parent, location);
|
||||
keys.put(location, key);
|
||||
}
|
||||
cir.setReturnValue((ResourceKey<T>)key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ import java.util.function.Consumer;
|
|||
public class BlocksMixin {
|
||||
@ModifyArg(method = "rebuildCache", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/IdMapper;forEach(Ljava/util/function/Consumer;)V"), index = 0)
|
||||
private static Consumer getEmptyConsumer(Consumer original) {
|
||||
BlockStateCacheHandler.rebuildParallel(true);
|
||||
BlockStateCacheHandler.invalidateCache();
|
||||
return o -> {};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
package org.embeddedt.modernfix.dedup;
|
||||
|
||||
import com.google.common.collect.Interner;
|
||||
import com.google.common.collect.Interners;
|
||||
import net.minecraft.world.level.biome.Climate;
|
||||
|
||||
public class ClimateCache {
|
||||
public static final Interner<Climate.Parameter> MFIX_INTERNER = Interners.newStrongInterner();
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
package org.embeddedt.modernfix.dedup;
|
||||
|
||||
import it.unimi.dsi.fastutil.Hash;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DeduplicationCache<T> {
|
||||
private final ObjectOpenCustomHashSet<T> pool;
|
||||
|
||||
private int attemptedInsertions = 0;
|
||||
private int deduplicated = 0;
|
||||
|
||||
public DeduplicationCache(Hash.Strategy<T> strategy) {
|
||||
this.pool = new ObjectOpenCustomHashSet<>(strategy);
|
||||
}
|
||||
|
||||
public DeduplicationCache() {
|
||||
this.pool = new ObjectOpenCustomHashSet<>(new Hash.Strategy<T>() {
|
||||
@Override
|
||||
public int hashCode(T o) {
|
||||
return Objects.hashCode(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(T a, T b) {
|
||||
return Objects.equals(a, b);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized T deduplicate(T item) {
|
||||
this.attemptedInsertions++;
|
||||
|
||||
T result = this.pool.addOrGet(item);
|
||||
|
||||
if (result != item) {
|
||||
this.deduplicated++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public synchronized void clearCache() {
|
||||
this.attemptedInsertions = 0;
|
||||
this.deduplicated = 0;
|
||||
|
||||
this.pool.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toString() {
|
||||
return String.format("DeduplicationCache ( %d/%d de-duplicated, %d pooled )",
|
||||
this.deduplicated, this.attemptedInsertions, this.pool.size());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package org.embeddedt.modernfix.dedup;
|
||||
|
||||
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
|
||||
public class IdentifierCaches {
|
||||
public static final DeduplicationCache<String> NAMESPACES = new DeduplicationCache<>();
|
||||
public static final DeduplicationCache<String> PATH = new DeduplicationCache<>();
|
||||
public static final DeduplicationCache<String> PROPERTY = new DeduplicationCache<>();
|
||||
|
||||
public static void printDebug() {
|
||||
ModernFix.LOGGER.info("[[[ Identifier de-duplication statistics ]]]");
|
||||
ModernFix.LOGGER.info("Namespace cache: {}", NAMESPACES);
|
||||
ModernFix.LOGGER.info("Path cache: {}", PATH);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
public interface ICachedMaterialsModel {
|
||||
public void clearMaterialsCache();
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
|
||||
public interface ILevelSave {
|
||||
public void runWorldPersistenceHooks(LevelStorageSource format);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import org.embeddedt.modernfix.chunk.SafeBlockGetter;
|
||||
|
||||
public interface ISafeBlockGetter {
|
||||
SafeBlockGetter mfix$getSafeBlockGetter();
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck.reuse_datapacks;
|
||||
|
||||
import net.minecraft.server.ReloadableServerResources;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ICachingResourceClient {
|
||||
void setCachedResources(ReloadableServerResources r);
|
||||
void setCachedDataPackConfig(Collection<String> c);
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
package org.embeddedt.modernfix.dynamicresources;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.BlockFaceUV;
|
||||
|
||||
public class UVController {
|
||||
public static final ThreadLocal<Boolean> useDummyUv = ThreadLocal.withInitial(() -> Boolean.FALSE);
|
||||
public static final BlockFaceUV dummyUv = new BlockFaceUV(new float[4], 0);
|
||||
}
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
package org.embeddedt.modernfix.entity;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.collect.Maps;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderers;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@SuppressWarnings("OptionalAssignedToNull")
|
||||
public class EntityRendererMap implements Map<EntityType<?>, EntityRenderer<?>> {
|
||||
private final Map<EntityType<?>, EntityRendererProvider<?>> rendererProviders;
|
||||
private final LoadingCache<EntityType<?>, Optional<EntityRenderer<?>>> rendererMap;
|
||||
private final EntityRendererProvider.Context context;
|
||||
|
||||
public EntityRendererMap(Map<EntityType<?>, EntityRendererProvider<?>> rendererProviders, EntityRendererProvider.Context context) {
|
||||
this.rendererProviders = rendererProviders;
|
||||
this.context = context;
|
||||
this.rendererMap = CacheBuilder.newBuilder().build(new RenderConstructor());
|
||||
}
|
||||
|
||||
class RenderConstructor extends CacheLoader<EntityType<?>, Optional<EntityRenderer<?>>> {
|
||||
@Override
|
||||
public Optional<EntityRenderer<?>> load(EntityType<?> key) throws Exception {
|
||||
EntityRendererProvider<?> provider = rendererProviders.get(key);
|
||||
if(provider == null)
|
||||
return Optional.empty();
|
||||
synchronized(EntityRenderers.class) {
|
||||
EntityRenderer<?> renderer;
|
||||
try {
|
||||
renderer = provider.create(context);
|
||||
ModernFix.LOGGER.info("Loaded entity {}", BuiltInRegistries.ENTITY_TYPE.getKey(key));
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Failed to create entity model for " + BuiltInRegistries.ENTITY_TYPE.getKey(key) + ":", e);
|
||||
renderer = new ErroredEntityRenderer<>(context);
|
||||
}
|
||||
return Optional.ofNullable(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return rendererProviders.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return rendererProviders.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
return rendererProviders.containsKey(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRenderer<?> get(Object o) {
|
||||
try {
|
||||
Optional<EntityRenderer<?>> renderer = rendererMap.get((EntityType<?>)o);
|
||||
return renderer.orElse(null);
|
||||
} catch (IllegalStateException e) {
|
||||
return null; /* emulate value not being present if recursive load occurs */
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public EntityRenderer<?> put(EntityType<?> entityType, EntityRenderer<?> entityRenderer) {
|
||||
Optional<EntityRenderer<?>> old = rendererMap.getIfPresent(entityType);
|
||||
rendererMap.put(entityType, Optional.ofNullable(entityRenderer));
|
||||
return old != null ? old.orElse(null) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRenderer<?> remove(Object o) {
|
||||
Optional<EntityRenderer<?>> old = rendererMap.getIfPresent(o);
|
||||
rendererMap.invalidate(o);
|
||||
return old != null ? old.orElse(null) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@NotNull Map<? extends EntityType<?>, ? extends EntityRenderer<?>> map) {
|
||||
rendererMap.putAll(Maps.transformValues(map, Optional::ofNullable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
rendererMap.invalidateAll();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<EntityType<?>> keySet() {
|
||||
return rendererProviders.keySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<EntityRenderer<?>> values() {
|
||||
return new AbstractCollection<>() {
|
||||
@Override
|
||||
public Iterator<EntityRenderer<?>> iterator() {
|
||||
return Iterators.transform(Iterators.unmodifiableIterator(rendererProviders.keySet().iterator()), EntityRendererMap.this::get);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return rendererProviders.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class Entry implements Map.Entry<EntityType<?>, EntityRenderer<?>> {
|
||||
private final EntityType<?> key;
|
||||
|
||||
private Entry(EntityType<?> key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType<?> getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRenderer<?> getValue() {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRenderer<?> setValue(EntityRenderer<?> value) {
|
||||
return put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Map.Entry<EntityType<?>, EntityRenderer<?>>> entrySet() {
|
||||
return new AbstractSet<>() {
|
||||
@Override
|
||||
public Iterator<Map.Entry<EntityType<?>, EntityRenderer<?>>> iterator() {
|
||||
return Iterators.transform(Iterators.unmodifiableIterator(rendererProviders.keySet().iterator()), Entry::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (o instanceof Map.Entry<?,?> e) {
|
||||
return rendererProviders.containsKey(e.getKey()) && Objects.equals(get(e.getKey()), e.getValue());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return rendererProviders.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package org.embeddedt.modernfix.entity;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.culling.Frustum;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
public class ErroredEntityRenderer<T extends Entity> extends EntityRenderer<T> {
|
||||
public ErroredEntityRenderer(EntityRendererProvider.Context arg) {
|
||||
super(arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTextureLocation(T entity) {
|
||||
return TextureAtlas.LOCATION_BLOCKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRender(T livingEntity, Frustum camera, double camX, double camY, double camZ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(T entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight) {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package org.embeddedt.modernfix.sound;
|
||||
|
||||
import com.mojang.blaze3d.audio.SoundBuffer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class SoundBufferCache extends LinkedHashMap<ResourceLocation, CompletableFuture<SoundBuffer>> {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<ResourceLocation, CompletableFuture<SoundBuffer>> eldest) {
|
||||
return super.removeEldestEntry(eldest);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
package org.embeddedt.modernfix.tickables;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LoadableTickableObject<T> implements TickableObject {
|
||||
private volatile int ticksInactive = 0;
|
||||
private final int timeout;
|
||||
private final Supplier<T> loader;
|
||||
private final Consumer<T> finalizer;
|
||||
private volatile T theObject = null;
|
||||
|
||||
public LoadableTickableObject(int timeout, Supplier<T> loader, Consumer<T> finalizer) {
|
||||
this(timeout, loader, finalizer, null);
|
||||
}
|
||||
|
||||
public LoadableTickableObject(int timeout, Supplier<T> loader, Consumer<T> finalizer, @Nullable T initialValue) {
|
||||
this.timeout = timeout;
|
||||
this.loader = loader;
|
||||
this.finalizer = finalizer;
|
||||
this.theObject = initialValue;
|
||||
}
|
||||
|
||||
public T get() {
|
||||
synchronized (this) {
|
||||
ticksInactive++;
|
||||
T obj = theObject;
|
||||
if(obj == null) {
|
||||
obj = loader.get();
|
||||
theObject = obj;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public final void tick() {
|
||||
synchronized (this) {
|
||||
ticksInactive++;
|
||||
if(ticksInactive >= this.timeout) {
|
||||
finalizer.accept(theObject);
|
||||
theObject = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package org.embeddedt.modernfix.tickables;
|
||||
|
||||
public interface TickableObject {
|
||||
void tick();
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package org.embeddedt.modernfix.tickables;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public class TickableObjectManager {
|
||||
private static final List<TickableObject> TICKABLE_OBJECT_LIST = new CopyOnWriteArrayList<>();
|
||||
|
||||
public static void register(TickableObject object) {
|
||||
TICKABLE_OBJECT_LIST.add(object);
|
||||
}
|
||||
|
||||
public static void runTick() {
|
||||
for(TickableObject o : TICKABLE_OBJECT_LIST) {
|
||||
o.tick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
package org.embeddedt.modernfix.util;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Interner;
|
||||
import com.google.common.collect.Interners;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Replacement backing map for CompoundTags that interns keys.
|
||||
*/
|
||||
public class CanonizingStringMap<T> extends HashMap<String, T> {
|
||||
private static final Interner<String> KEY_INTERNER = Interners.newWeakInterner();
|
||||
|
||||
private static String intern(String key) {
|
||||
return key != null ? KEY_INTERNER.intern(key) : null;
|
||||
}
|
||||
|
||||
public CanonizingStringMap() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T put(String key, T value) {
|
||||
return super.put(intern(key), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends T> m) {
|
||||
if(m.isEmpty())
|
||||
return;
|
||||
HashMap<String, T> tmp = new HashMap<>();
|
||||
m.forEach((k, v) -> tmp.put(intern(k), v));
|
||||
super.putAll(tmp);
|
||||
}
|
||||
|
||||
private void putAllWithoutInterning(Map<? extends String, ? extends T> m) {
|
||||
super.putAll(m);
|
||||
}
|
||||
|
||||
public static <T> CanonizingStringMap<T> deepCopy(CanonizingStringMap<T> incomingMap, Function<T, T> deepCopier) {
|
||||
CanonizingStringMap<T> newMap = new CanonizingStringMap<>();
|
||||
newMap.putAllWithoutInterning(Maps.transformValues(incomingMap, deepCopier));
|
||||
return newMap;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
package org.embeddedt.modernfix.util;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.level.*;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.world.Difficulty;
|
||||
import net.minecraft.world.level.dimension.end.EndDragonFight;
|
||||
import net.minecraft.world.level.levelgen.WorldOptions;
|
||||
import net.minecraft.world.level.storage.WorldData;
|
||||
import net.minecraft.world.level.storage.ServerLevelData;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public class DummyServerConfiguration implements WorldData {
|
||||
@Override
|
||||
public WorldDataConfiguration getDataConfiguration() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataConfiguration(WorldDataConfiguration arg) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRemovedFeatureFlags() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wasModded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getKnownServerBrands() {
|
||||
return ImmutableSet.of("forge");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModdedInfo(String name, boolean isModded) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getCustomBossEvents() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomBossEvents(CompoundTag nbt) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerLevelData overworldData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelSettings getLevelSettings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag createTag(RegistryAccess registries, CompoundTag hostPlayerNBT) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHardcore() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLevelName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameType getGameType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameType(GameType type) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowCommands() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Difficulty getDifficulty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDifficulty(Difficulty difficulty) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDifficultyLocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDifficultyLocked(boolean locked) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameRules getGameRules() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getLoadedPlayerTag() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EndDragonFight.Data endDragonFightData() {
|
||||
return EndDragonFight.Data.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEndDragonFightData(EndDragonFight.Data data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldOptions worldGenOptions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlatWorld() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugWorld() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lifecycle worldGenSettingsLifecycle() {
|
||||
return Lifecycle.stable();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
package org.embeddedt.modernfix.util;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Simple forwarding map implementation that allows layering multiple maps together.
|
||||
*/
|
||||
public class LayeredForwardingMap<K, V> implements Map<K, V> {
|
||||
private final Map<K, V>[] layers;
|
||||
|
||||
public LayeredForwardingMap(Map<K, V>[] layers) {
|
||||
if(layers.length < 1)
|
||||
throw new IllegalArgumentException();
|
||||
for(Map<K, V> layer : layers) {
|
||||
if(layer == null)
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.layers = layers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for(Map<K, V> map : layers) {
|
||||
if(!map.isEmpty())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
for(Map<K, V> map : layers) {
|
||||
if(map.containsKey(key))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
for(Map<K, V> map : layers) {
|
||||
if(map.containsValue(value))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
for(Map<K, V> map : layers) {
|
||||
V value = map.get(key);
|
||||
if(value != null)
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
if(value == null)
|
||||
throw new IllegalArgumentException();
|
||||
V originalValue = null;
|
||||
for(Map<K, V> map : layers) {
|
||||
V oldVal = map.remove(key);
|
||||
if(originalValue == null)
|
||||
originalValue = oldVal;
|
||||
map.put(key, value);
|
||||
}
|
||||
return originalValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
for(Map<K, V> map : layers) {
|
||||
map.remove(key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@NotNull Map<? extends K, ? extends V> m) {
|
||||
for(V value : m.values()) {
|
||||
if(value == null)
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
for(Map<K, V> map : layers) {
|
||||
map.putAll(m);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
Set<K> keys = new ObjectOpenHashSet<>();
|
||||
for(Map<K, V> map : layers) {
|
||||
keys.addAll(map.keySet());
|
||||
}
|
||||
return Collections.unmodifiableSet(keys);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
Set<K> keys = keySet();
|
||||
List<V> vals = new ArrayList<>();
|
||||
for(K key : keys) {
|
||||
vals.add(get(key));
|
||||
}
|
||||
return vals;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
package org.embeddedt.modernfix.neoforge.classloading;
|
||||
|
||||
/**
|
||||
* Sometimes mods have classes that circularly reference each other. If each of these classes ends up being loaded
|
||||
* from two mods, a deadlock occurs.
|
||||
*
|
||||
* To avoid this problem we maintain a list of classes that should be loaded early and do it via Class.forName.
|
||||
*/
|
||||
public class ClassLoadHack {
|
||||
private static final String[] classesToLoadEarly = new String[] {
|
||||
"team.creative.creativecore.common.config.ConfigTypeConveration",
|
||||
"team.creative.creativecore.common.util.ingredient.CreativeIngredient"
|
||||
};
|
||||
|
||||
public static void loadModClasses() {
|
||||
for(String clzName : classesToLoadEarly) {
|
||||
try {
|
||||
Class.forName(clzName);
|
||||
} catch(Throwable e) {
|
||||
if(!(e instanceof ClassNotFoundException)) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user