Merge remote-tracking branch 'origin/main' into 1.18
This commit is contained in:
commit
48bec22982
|
|
@ -26,14 +26,11 @@ import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
|
|||
import net.minecraftforge.network.NetworkEvent;
|
||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||
import org.embeddedt.modernfix.core.config.ModernFixConfig;
|
||||
import org.embeddedt.modernfix.load.LoadEvents;
|
||||
import org.embeddedt.modernfix.packet.EntityIDSyncPacket;
|
||||
import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen;
|
||||
import org.embeddedt.modernfix.world.IntegratedWatchdog;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.reflect.Field;
|
||||
import java.sql.Ref;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
|
@ -50,9 +47,6 @@ public class ModernFixClient {
|
|||
public ModernFixClient() {
|
||||
// clear reserve as it's not needed
|
||||
MemoryReserve.release();
|
||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) {
|
||||
MinecraftForge.EVENT_BUS.register(new LoadEvents());
|
||||
}
|
||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.branding.F3Screen")) {
|
||||
Optional<? extends ModContainer> mfContainer = ModList.get().getModContainerById("modernfix");
|
||||
if(mfContainer.isPresent())
|
||||
|
|
@ -92,7 +86,6 @@ public class ModernFixClient {
|
|||
if(event.phase == TickEvent.Phase.END
|
||||
&& recipesUpdated
|
||||
&& tagsUpdated
|
||||
&& !(Minecraft.getInstance().screen instanceof DeferredLevelLoadingScreen)
|
||||
&& worldLoadStartTime != -1
|
||||
&& Minecraft.getInstance().player != null
|
||||
&& numRenderTicks++ >= 10) {
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
package org.embeddedt.modernfix.agent;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.IllegalClassFormatException;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class Agent {
|
||||
public static void agentmain(String args, Instrumentation instrumentation) {
|
||||
instrumentation.addTransformer(new EarlyTransformer());
|
||||
}
|
||||
|
||||
private static class EarlyTransformer implements ClassFileTransformer {
|
||||
|
||||
private static final ImmutableMap<String, Function<ClassNode, ClassNode>> TRANSFORMERS = ImmutableMap.<String, Function<ClassNode, ClassNode>>builder()
|
||||
.put("net/minecraftforge/fml/loading/moddiscovery/Scanner", EarlyTransformer::transformScanner)
|
||||
.build();
|
||||
|
||||
private static ClassNode transformScanner(ClassNode input) {
|
||||
for(MethodNode method : input.methods) {
|
||||
if(method.name.equals("fileVisitor")) {
|
||||
for(int i = 0; i < method.instructions.size(); i++) {
|
||||
AbstractInsnNode ainsn = method.instructions.get(i);
|
||||
if(ainsn.getOpcode() == Opcodes.INVOKEVIRTUAL) {
|
||||
MethodInsnNode minsn = (MethodInsnNode)ainsn;
|
||||
if(minsn.name.equals("accept") && minsn.owner.equals("org/objectweb/asm/ClassReader")) {
|
||||
method.instructions.set(minsn.getPrevious(), new LdcInsnNode(ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES));
|
||||
return input;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(ClassLoader classLoader, String s, Class<?> aClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
|
||||
Function<ClassNode, ClassNode> func = TRANSFORMERS.get(s);
|
||||
if(func != null) {
|
||||
ClassReader reader = new ClassReader(bytes);
|
||||
ClassNode node = new ClassNode(Opcodes.ASM9);
|
||||
reader.accept(node, 0);
|
||||
node = func.apply(node);
|
||||
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
node.accept(writer);
|
||||
return writer.toByteArray();
|
||||
} else
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +60,6 @@ public class ModernFixEarlyConfig {
|
|||
Optional<ModInfo> jeiMod = FMLLoader.getLoadingModList().getMods().stream().filter(mod -> mod.getModId().equals("jei")).findFirst();
|
||||
this.addMixinRule("perf.blast_search_trees", (jeiMod.isPresent() && jeiMod.get().getVersion().getMajorVersion() >= 10) || FMLLoader.getLoadingModList().getModFileById("roughlyenoughitems") != null);
|
||||
this.addMixinRule("safety", true);
|
||||
this.addMixinRule("launch.transformer_cache", false);
|
||||
this.addMixinRule("launch.class_search_cache", true);
|
||||
boolean isDevEnv = !FMLLoader.isProduction() && FMLLoader.getLoadingModList().getModFileById("modernfix").getFile().getLocator() instanceof ExplodedDirectoryLocator;
|
||||
this.addMixinRule("devenv", isDevEnv);
|
||||
|
|
|
|||
|
|
@ -1,113 +0,0 @@
|
|||
package org.embeddedt.modernfix.load;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.LevelLoadingScreen;
|
||||
import net.minecraft.client.gui.screens.ProgressScreen;
|
||||
import net.minecraft.client.server.IntegratedServer;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||
import net.minecraft.util.Unit;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.ForcedChunksSavedData;
|
||||
import net.minecraftforge.client.event.ScreenOpenEvent;
|
||||
import net.minecraftforge.common.world.ForgeChunkManager;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.event.server.ServerAboutToStartEvent;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.server.ServerLifecycleHooks;
|
||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||
import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen;
|
||||
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
/**
|
||||
* Handles deferring the world load screen.
|
||||
* <p></p>
|
||||
* TODO: The vanilla check that at least 441 chunks have been loaded does not check whether they are spawn chunks
|
||||
* or chunks loaded by the player. Consequently it is possible for loading to finish before every spawn chunk has
|
||||
* been loaded. However the chunk system has at least been warmed up by this point so the remaining chunks load
|
||||
* reasonably quickly.
|
||||
*/
|
||||
public class LoadEvents {
|
||||
private boolean hasFirstPlayerJoined = false;
|
||||
|
||||
@SubscribeEvent
|
||||
public void serverWillStart(ServerAboutToStartEvent event) {
|
||||
hasFirstPlayerJoined = false;
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||
public void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) {
|
||||
if(!hasFirstPlayerJoined && ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) {
|
||||
hasFirstPlayerJoined = true;
|
||||
MinecraftServer server = ServerLifecycleHooks.getCurrentServer();
|
||||
if(server instanceof IntegratedServer) {
|
||||
handleInitialChunkLoad();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||
public void onWorldShow(ScreenOpenEvent event) {
|
||||
if(ServerLifecycleHooks.getCurrentServer() instanceof IntegratedServer) {
|
||||
if(event.getScreen() == null && Minecraft.getInstance().level != null && integratedWorldLoadListener != null) {
|
||||
/* this means the world is about to be displayed, check if 441 initialized */
|
||||
ServerChunkCache provider = ServerLifecycleHooks.getCurrentServer().overworld().getChunkSource();
|
||||
BooleanSupplier worldLoadDone = () -> provider.getTickingGenerated() >= 441;
|
||||
if(!worldLoadDone.getAsBoolean()) {
|
||||
DeferredLevelLoadingScreen newScreen = new DeferredLevelLoadingScreen(Minecraft.getInstance().progressListener.get(), worldLoadDone);
|
||||
event.setScreen(newScreen);
|
||||
}
|
||||
} else if(event.getScreen() instanceof LevelLoadingScreen && Minecraft.getInstance().level == null && ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) {
|
||||
ProgressScreen loadscreen = new ProgressScreen(false);
|
||||
loadscreen.progressStartNoAbort(new TranslatableComponent("connect.joining"));
|
||||
event.setScreen(loadscreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ChunkProgressListener integratedWorldLoadListener;
|
||||
|
||||
private void handleInitialChunkLoad() {
|
||||
MinecraftServer server = ServerLifecycleHooks.getCurrentServer();
|
||||
ServerLevel overworld = server.overworld();
|
||||
ServerChunkCache provider = overworld.getChunkSource();
|
||||
provider.getLightEngine().setTaskPerBatch(500);
|
||||
provider.addRegionTicket(TicketType.START, new ChunkPos(overworld.getSharedSpawnPos()), 11, Unit.INSTANCE);
|
||||
while(provider.getTickingGenerated() < 441) {
|
||||
server.runAllTasks();
|
||||
Thread.yield();
|
||||
LockSupport.parkNanos("waiting for world load", 100000L);
|
||||
server.nextTickTime = Util.getMillis() + 10;
|
||||
}
|
||||
for(ServerLevel serverworld1 : server.getAllLevels()) {
|
||||
ForcedChunksSavedData forcedchunkssavedata = serverworld1.getDataStorage().get(ForcedChunksSavedData::load, "chunks");
|
||||
if (forcedchunkssavedata != null) {
|
||||
LongIterator longiterator = forcedchunkssavedata.getChunks().iterator();
|
||||
|
||||
while(longiterator.hasNext()) {
|
||||
long i = longiterator.nextLong();
|
||||
ChunkPos chunkpos = new ChunkPos(i);
|
||||
serverworld1.getChunkSource().updateChunkForced(chunkpos, true);
|
||||
}
|
||||
|
||||
ForgeChunkManager.reinstatePersistentChunks(serverworld1, forcedchunkssavedata);
|
||||
}
|
||||
}
|
||||
server.runAllTasks();
|
||||
server.nextTickTime = Util.getMillis() + 10;
|
||||
provider.getLightEngine().setTaskPerBatch(5);
|
||||
if(integratedWorldLoadListener != null) {
|
||||
integratedWorldLoadListener.stop();
|
||||
integratedWorldLoadListener = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.faster_singleplayer_load;
|
||||
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.server.IntegratedServer;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||
import org.embeddedt.modernfix.ModernFixClient;
|
||||
import org.embeddedt.modernfix.load.LoadEvents;
|
||||
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.CallbackInfo;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public abstract class MinecraftServerMixin {
|
||||
@Shadow protected long nextTickTime;
|
||||
|
||||
@Shadow public abstract ServerLevel overworld();
|
||||
|
||||
@Shadow protected abstract void updateMobSpawningFlags();
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason defer the 441 chunk load until *after* join game packets are sent to the client, in order to allow
|
||||
* mods that process advancements, etc. to work on that at the same time
|
||||
*/
|
||||
@Inject(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;getChunkSource()Lnet/minecraft/server/level/ServerChunkCache;", ordinal = 0), cancellable = true)
|
||||
private void skipInitialChunkLoad(ChunkProgressListener arg, CallbackInfo ci) {
|
||||
if(((Object)this) instanceof IntegratedServer) {
|
||||
ci.cancel();
|
||||
LoadEvents.integratedWorldLoadListener = arg;
|
||||
this.nextTickTime = Util.getMillis();
|
||||
this.overworld().getChunkSource().getLightEngine().setTaskPerBatch(5);
|
||||
this.updateMobSpawningFlags();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.flatten_model_predicates;
|
||||
|
||||
import com.google.common.collect.Streams;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.client.renderer.block.model.multipart.AndCondition;
|
||||
import net.minecraft.client.renderer.block.model.multipart.Condition;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import org.embeddedt.modernfix.predicate.StatePropertyPredicateHelper;
|
||||
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.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(AndCondition.class)
|
||||
public class AndConditionMixin {
|
||||
@Shadow @Final private Iterable<? extends Condition> conditions;
|
||||
|
||||
/**
|
||||
* @author JellySquid
|
||||
* @reason Flatten predicates
|
||||
*/
|
||||
@Overwrite
|
||||
public Predicate<BlockState> getPredicate(StateDefinition<Block, BlockState> stateManager) {
|
||||
return StatePropertyPredicateHelper.allMatch(Streams.stream(this.conditions).map((multipartModelSelector) -> {
|
||||
return multipartModelSelector.getPredicate(stateManager);
|
||||
}).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.flatten_model_predicates;
|
||||
|
||||
import com.google.common.collect.Streams;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.client.renderer.block.model.multipart.Condition;
|
||||
import net.minecraft.client.renderer.block.model.multipart.OrCondition;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import org.embeddedt.modernfix.predicate.StatePropertyPredicateHelper;
|
||||
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.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(OrCondition.class)
|
||||
public class OrConditionMixin {
|
||||
@Shadow @Final private Iterable<? extends Condition> conditions;
|
||||
|
||||
/**
|
||||
* @author JellySquid
|
||||
* @reason Flatten predicates
|
||||
*/
|
||||
@Overwrite
|
||||
public Predicate<BlockState> getPredicate(StateDefinition<Block, BlockState> stateManager) {
|
||||
return StatePropertyPredicateHelper.anyMatch(Streams.stream(this.conditions).map((multipartModelSelector) -> {
|
||||
return multipartModelSelector.getPredicate(stateManager);
|
||||
}).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.flatten_model_predicates;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.client.renderer.block.model.multipart.KeyValueCondition;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import org.embeddedt.modernfix.predicate.single.SingleMatchAny;
|
||||
import org.embeddedt.modernfix.predicate.single.SingleMatchOne;
|
||||
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.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(KeyValueCondition.class)
|
||||
public class PropertyValueConditionMixin {
|
||||
@Shadow @Final private String key;
|
||||
|
||||
@Shadow @Final private String value;
|
||||
|
||||
@Shadow @Final private static Splitter PIPE_SPLITTER;
|
||||
|
||||
/**
|
||||
* @author JellySquid
|
||||
* @reason De-duplication
|
||||
*/
|
||||
@Overwrite
|
||||
public Predicate<BlockState> getPredicate(StateDefinition<Block, BlockState> stateManager) {
|
||||
Property<?> property = stateManager.getProperty(this.key);
|
||||
|
||||
if (property == null) {
|
||||
throw new RuntimeException(String.format("Unknown property '%s' on '%s'", this.key, stateManager.getOwner().toString()));
|
||||
}
|
||||
|
||||
String valueString = this.value;
|
||||
boolean negate = !valueString.isEmpty() && valueString.charAt(0) == '!';
|
||||
|
||||
if (negate) {
|
||||
valueString = valueString.substring(1);
|
||||
}
|
||||
|
||||
List<String> split = PIPE_SPLITTER.splitToList(valueString);
|
||||
|
||||
if (split.isEmpty()) {
|
||||
throw new RuntimeException(String.format("Empty value '%s' for property '%s' on '%s'", this.value, this.key, stateManager.getOwner().toString()));
|
||||
}
|
||||
|
||||
Predicate<BlockState> predicate;
|
||||
|
||||
if (split.size() == 1) {
|
||||
predicate = new SingleMatchOne(property, this.getPropertyValue(stateManager, property, valueString));
|
||||
} else {
|
||||
predicate = SingleMatchAny.create(property, split.stream()
|
||||
.map(str -> this.getPropertyValue(stateManager, property, str))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
return negate ? predicate.negate() : predicate;
|
||||
}
|
||||
|
||||
private Object getPropertyValue(StateDefinition<Block, BlockState> stateFactory, Property<?> property, String valueString) {
|
||||
Object value = property.getValue(valueString)
|
||||
.orElse(null);
|
||||
|
||||
if (value == null) {
|
||||
throw new RuntimeException(String.format("Unknown value '%s' for property '%s' on '%s' in '%s'",
|
||||
valueString, this.key, stateFactory.getOwner().toString(), this.value));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package org.embeddedt.modernfix.predicate;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class AllPredicate<T> implements Predicate<T> {
|
||||
private final Predicate<T>[] predicates;
|
||||
|
||||
public AllPredicate(Predicate<T>[] predicates) {
|
||||
this.predicates = predicates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(T t) {
|
||||
for (Predicate<T> predicate : this.predicates) {
|
||||
if (!predicate.test(t)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package org.embeddedt.modernfix.predicate;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class AnyPredicate<T> implements Predicate<T> {
|
||||
private final Predicate<T>[] predicates;
|
||||
|
||||
public AnyPredicate(Predicate<T>[] predicates) {
|
||||
this.predicates = predicates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(T t) {
|
||||
for (Predicate<T> predicate : this.predicates) {
|
||||
if (predicate.test(t)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package org.embeddedt.modernfix.predicate;
|
||||
|
||||
/**
|
||||
* Calculates the
|
||||
*/
|
||||
public class CachedModelPredicate {
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package org.embeddedt.modernfix.predicate;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.embeddedt.modernfix.predicate.all.AllMatchOneBoolean;
|
||||
import org.embeddedt.modernfix.predicate.all.AllMatchOneObject;
|
||||
import org.embeddedt.modernfix.predicate.any.AllMatchAnyObject;
|
||||
import org.embeddedt.modernfix.predicate.single.SingleMatchAny;
|
||||
import org.embeddedt.modernfix.predicate.single.SingleMatchOne;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class StatePropertyPredicateHelper {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Predicate<BlockState> allMatch(List<Predicate<BlockState>> predicates) {
|
||||
if (SingleMatchOne.areOfType(predicates)) {
|
||||
if (SingleMatchOne.valuesMatchType(predicates, Boolean.class)) {
|
||||
return new AllMatchOneBoolean(predicates);
|
||||
}
|
||||
|
||||
return new AllMatchOneObject(predicates);
|
||||
} else if (SingleMatchAny.areOfType(predicates)) {
|
||||
return new AllMatchAnyObject(predicates);
|
||||
}
|
||||
|
||||
return new AllPredicate<>(predicates.toArray(new Predicate[0]));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Predicate<BlockState> anyMatch(List<Predicate<BlockState>> predicates) {
|
||||
return new AnyPredicate<>(predicates.toArray(new Predicate[0]));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
package org.embeddedt.modernfix.predicate.all;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.embeddedt.modernfix.predicate.single.SingleMatchOne;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class AllMatchOneBoolean implements Predicate<BlockState> {
|
||||
private final Property<?>[] properties;
|
||||
private final boolean[] values;
|
||||
|
||||
public AllMatchOneBoolean(List<Predicate<BlockState>> list) {
|
||||
int size = list.size();
|
||||
|
||||
this.properties = new Property[size];
|
||||
this.values = new boolean[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
SingleMatchOne predicate = (SingleMatchOne) list.get(i);
|
||||
|
||||
this.properties[i] = predicate.property;
|
||||
this.values[i] = (boolean) predicate.value;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean canReplace(List<Predicate<BlockState>> list) {
|
||||
return list.stream()
|
||||
.allMatch(p -> {
|
||||
return p instanceof SingleMatchOne && ((SingleMatchOne) p).value instanceof Boolean;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(BlockState blockState) {
|
||||
for (int i = 0; i < this.properties.length; i++) {
|
||||
Boolean value = (Boolean) blockState.getValue(this.properties[i]);
|
||||
|
||||
if (value != this.values[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package org.embeddedt.modernfix.predicate.all;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.embeddedt.modernfix.predicate.single.SingleMatchOne;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class AllMatchOneObject implements Predicate<BlockState> {
|
||||
private final Property<?>[] properties;
|
||||
private final Object[] values;
|
||||
|
||||
public AllMatchOneObject(List<Predicate<BlockState>> list) {
|
||||
int size = list.size();
|
||||
|
||||
this.properties = new Property[size];
|
||||
this.values = new Object[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
SingleMatchOne predicate = (SingleMatchOne) list.get(i);
|
||||
|
||||
this.properties[i] = predicate.property;
|
||||
this.values[i] = predicate.value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(BlockState blockState) {
|
||||
for (int i = 0; i < this.properties.length; i++) {
|
||||
if (blockState.getValue(this.properties[i]) != this.values[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
package org.embeddedt.modernfix.predicate.any;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.embeddedt.modernfix.predicate.single.SingleMatchAny;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class AllMatchAnyObject implements Predicate<BlockState> {
|
||||
private final Property<?>[] properties;
|
||||
private final Object[][] values;
|
||||
|
||||
public AllMatchAnyObject(List<Predicate<BlockState>> list) {
|
||||
int size = list.size();
|
||||
|
||||
this.properties = new Property[size];
|
||||
this.values = new Object[size][];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
SingleMatchAny predicate = (SingleMatchAny) list.get(i);
|
||||
|
||||
this.properties[i] = predicate.property;
|
||||
this.values[i] = predicate.values;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(BlockState blockState) {
|
||||
for (int i = 0; i < this.properties.length; i++) {
|
||||
if (!ArrayUtils.contains(this.values[i], blockState.getValue(this.properties[i]))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
package org.embeddedt.modernfix.predicate.single;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class SingleMatchAny implements Predicate<BlockState> {
|
||||
public static final ObjectOpenHashSet<SingleMatchAny> PREDICATES = new ObjectOpenHashSet<>();
|
||||
|
||||
public final Property<?> property;
|
||||
public final Object[] values;
|
||||
|
||||
private SingleMatchAny(Property<?> property, List<Object> values) {
|
||||
this.property = property;
|
||||
this.values = values.toArray();
|
||||
}
|
||||
|
||||
public static SingleMatchAny create(Property<?> property, List<Object> values) {
|
||||
return PREDICATES.addOrGet(new SingleMatchAny(property, values));
|
||||
}
|
||||
|
||||
public static boolean areOfType(List<Predicate<BlockState>> predicates) {
|
||||
return predicates.stream()
|
||||
.allMatch(p -> {
|
||||
return p instanceof SingleMatchAny;
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean valuesMatchType(List<Predicate<BlockState>> predicates, Class<?> type) {
|
||||
return predicates.stream()
|
||||
.allMatch(p -> {
|
||||
return p instanceof SingleMatchAny &&
|
||||
Arrays.stream(((SingleMatchAny) p).values).allMatch(t -> type.isInstance(p));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(BlockState blockState) {
|
||||
return ArrayUtils.contains(this.values, blockState.getValue(this.property));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
SingleMatchAny that = (SingleMatchAny) o;
|
||||
return Objects.equals(property, that.property) &&
|
||||
Arrays.equals(values, that.values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(property);
|
||||
result = 31 * result + Arrays.hashCode(values);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package org.embeddedt.modernfix.predicate.single;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class SingleMatchOne implements Predicate<BlockState> {
|
||||
public final Property<?> property;
|
||||
public final Object value;
|
||||
|
||||
public SingleMatchOne(Property<?> property, Object value) {
|
||||
this.property = property;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static boolean areOfType(List<Predicate<BlockState>> predicates) {
|
||||
return predicates.stream()
|
||||
.allMatch(p -> {
|
||||
return p instanceof SingleMatchOne;
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean valuesMatchType(List<Predicate<BlockState>> predicates, Class<?> type) {
|
||||
return predicates.stream()
|
||||
.allMatch(p -> {
|
||||
return p instanceof SingleMatchOne && type.isInstance(((SingleMatchOne) p).value);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(BlockState blockState) {
|
||||
return blockState.getValue(this.property) == this.value;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
package org.embeddedt.modernfix.registry;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.fml.ModWorkManager;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.util.AsyncStopwatch;
|
||||
import org.embeddedt.modernfix.util.CachedSupplier;
|
||||
import org.embeddedt.modernfix.util.OrderedParallelModDispatcher;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class DeferredRegisterBaker {
|
||||
private static final HashMap<ResourceLocation, HashMap<String, List<CachedSupplier<?>>>> supplierMap = new HashMap<>();
|
||||
public static <T> Supplier<T> cacheForComputationLater(ResourceLocation registry, String modid, Supplier<T> supplier) {
|
||||
synchronized (supplierMap) {
|
||||
HashMap<String, List<CachedSupplier<?>>> registrySupplierMap = supplierMap.computeIfAbsent(registry, reg -> new HashMap<>());
|
||||
List<CachedSupplier<?>> modSupplierList = registrySupplierMap.computeIfAbsent(modid, id -> new ArrayList<>());
|
||||
CachedSupplier<T> cacher = new CachedSupplier<>(supplier);
|
||||
modSupplierList.add(cacher);
|
||||
return cacher;
|
||||
}
|
||||
}
|
||||
|
||||
public static void bakeSuppliers(ResourceLocation registry) {
|
||||
synchronized (supplierMap) {
|
||||
Set<String> modErrors = Collections.synchronizedSet(new HashSet<>());
|
||||
HashMap<String, List<CachedSupplier<?>>> registrySupplierMap = supplierMap.get(registry);
|
||||
if(registrySupplierMap == null)
|
||||
return;
|
||||
ModernFix.LOGGER.info("Caching suppliers for " + registry);
|
||||
Stopwatch realtimeStopwatch = Stopwatch.createStarted();
|
||||
AsyncStopwatch cpuStopwatch = new AsyncStopwatch();
|
||||
OrderedParallelModDispatcher.dispatchBlocking(ModWorkManager.parallelExecutor(), modId -> {
|
||||
List<CachedSupplier<?>> suppliersToCompute = registrySupplierMap.get(modId);
|
||||
if (suppliersToCompute == null || suppliersToCompute.size() == 0) {
|
||||
return;
|
||||
}
|
||||
cpuStopwatch.startMeasuringAsync();
|
||||
for (CachedSupplier<?> supplier : suppliersToCompute) {
|
||||
try {
|
||||
supplier.compute();
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.debug("Exception encountered while caching supplier", e);
|
||||
modErrors.add(modId);
|
||||
}
|
||||
}
|
||||
cpuStopwatch.stopMeasuringAsync();
|
||||
});
|
||||
realtimeStopwatch.stop();
|
||||
if(modErrors.size() > 0)
|
||||
ModernFix.LOGGER.warn("The following mods had errors while caching " + registry + " suppliers (this is likely safe): [" + String.join(", ", modErrors) + "]");
|
||||
ModernFix.LOGGER.info("CPU time spent constructing " + registry + " suppliers: " + cpuStopwatch.getCpuTime()/1000f + " seconds");
|
||||
ModernFix.LOGGER.info("Real time spent constructing " + registry + " suppliers: " + realtimeStopwatch.elapsed(TimeUnit.MILLISECONDS)/1000f + " seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package org.embeddedt.modernfix.screen;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.gui.screens.LevelLoadingScreen;
|
||||
import net.minecraft.server.level.progress.StoringChunkProgressListener;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
public class DeferredLevelLoadingScreen extends LevelLoadingScreen {
|
||||
private final BooleanSupplier worldLoadFinished;
|
||||
public DeferredLevelLoadingScreen(StoringChunkProgressListener arg, BooleanSupplier worldLoadFinished) {
|
||||
super(arg);
|
||||
this.worldLoadFinished = worldLoadFinished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
if(this.worldLoadFinished.getAsBoolean())
|
||||
this.onClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderBackground(PoseStack matrixStack, int vOffset) {
|
||||
renderDirtBackground(vOffset);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
package org.embeddedt.modernfix.util;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class AsyncStopwatch {
|
||||
private final AtomicLong cpuTimeMs = new AtomicLong(0);
|
||||
private final ThreadLocal<Stopwatch> threadStopwatch = ThreadLocal.withInitial(Stopwatch::createUnstarted);
|
||||
|
||||
public void startMeasuringAsync() {
|
||||
threadStopwatch.get().start();
|
||||
}
|
||||
|
||||
public void stopMeasuringAsync() {
|
||||
Stopwatch watch = threadStopwatch.get();
|
||||
watch.stop();
|
||||
long elapsed = watch.elapsed(TimeUnit.MILLISECONDS);
|
||||
cpuTimeMs.addAndGet(elapsed);
|
||||
watch.reset();
|
||||
}
|
||||
|
||||
public void ensureStoppedAsync() {
|
||||
Stopwatch watch = threadStopwatch.get();
|
||||
if(watch.isRunning())
|
||||
stopMeasuringAsync();
|
||||
}
|
||||
|
||||
public long getCpuTime() {
|
||||
return cpuTimeMs.get();
|
||||
}
|
||||
|
||||
public static void measureAndLogSerialRunningTime(String label, Runnable runnable) {
|
||||
ModernFix.LOGGER.info(label + "...");
|
||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
try {
|
||||
runnable.run();
|
||||
ModernFix.LOGGER.info(label + " took " + stopwatch.elapsed(TimeUnit.MILLISECONDS)/1000f + " seconds");
|
||||
} finally {
|
||||
stopwatch.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package org.embeddedt.modernfix.util;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* An implementation of Supplier that allows separating the time at which the value is computed from when it is
|
||||
* retrieved.
|
||||
*/
|
||||
public class CachedSupplier<T> implements Supplier<T> {
|
||||
private T value = null;
|
||||
|
||||
private boolean hasBeenComputed;
|
||||
private final Supplier<T> delegate;
|
||||
|
||||
public CachedSupplier(Supplier<T> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public synchronized void compute() {
|
||||
this.value = this.delegate.get();
|
||||
this.hasBeenComputed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized T get() {
|
||||
if(this.hasBeenComputed) {
|
||||
this.hasBeenComputed = false;
|
||||
return this.value;
|
||||
} else {
|
||||
return this.delegate.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
package org.embeddedt.modernfix.util;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.fml.ModLoadingContext;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import org.apache.logging.log4j.Marker;
|
||||
import org.apache.logging.log4j.MarkerManager;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Iterates over all mods in the game, parallelizing where possible while preserving dependency ordering.
|
||||
*
|
||||
* Can also be given a list of mods to skip.
|
||||
*/
|
||||
public class OrderedParallelModDispatcher {
|
||||
private static final Marker DISPATCHER = MarkerManager.getMarker("OrderedParallelModDispatcher");
|
||||
public static void dispatchBlocking(Executor executor, Consumer<String> task, Collection<String> modIDsToFilter) {
|
||||
Set<String> finishedMods = Collections.synchronizedSet(new HashSet<>(modIDsToFilter));
|
||||
HashMap<String, CompletableFuture<?>> submittedFutures = new HashMap<>();
|
||||
Semaphore jobWaitingSemaphore = new Semaphore(0);
|
||||
ArrayList<IModInfo> remainingModList = new ArrayList<>(ModList.get().getMods());
|
||||
while(remainingModList.size() > 0) {
|
||||
remainingModList.removeIf(modInfo -> {
|
||||
if(finishedMods.contains(modInfo.getModId()))
|
||||
return true;
|
||||
List<String> missingDependencies = modInfo.getDependencies().stream()
|
||||
.filter(IModInfo.ModVersion::isMandatory)
|
||||
.map(IModInfo.ModVersion::getModId)
|
||||
.filter(modId -> !finishedMods.contains(modId))
|
||||
.collect(Collectors.toList());
|
||||
if(missingDependencies.size() > 0) {
|
||||
ModernFix.LOGGER.debug(DISPATCHER, "Cannot process " + modInfo.getModId() + ", as it is waiting on mods: [" + String.join(", ", missingDependencies) + "]");
|
||||
return false;
|
||||
}
|
||||
Optional<? extends ModContainer> modContainerOpt = ModList.get().getModContainerById(modInfo.getModId());
|
||||
if(!modContainerOpt.isPresent())
|
||||
throw new IllegalStateException("Can't find mod container");
|
||||
ModContainer container = modContainerOpt.get();
|
||||
ModernFix.LOGGER.debug(DISPATCHER, "Submitting job for " + modInfo.getModId());
|
||||
submittedFutures.put(modInfo.getModId(), CompletableFuture.runAsync(() -> {
|
||||
ModLoadingContext.get().setActiveContainer(container);
|
||||
try {
|
||||
task.accept(modInfo.getModId());
|
||||
} catch(RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
/*
|
||||
* We cannot rely on the main thread to correctly mark us as done, as it might start running
|
||||
* before the future is marked as complete. So we add the mod to the finished set ourselves.
|
||||
*/
|
||||
finishedMods.add(modInfo.getModId());
|
||||
jobWaitingSemaphore.release();
|
||||
//ModLoadingContext.get().setActiveContainer(null, null);
|
||||
}, executor));
|
||||
return true;
|
||||
});
|
||||
Preconditions.checkState(submittedFutures.size() > 0, "The semaphore will block forever!");
|
||||
ModernFix.LOGGER.debug(DISPATCHER, "Waiting for one of [" + String.join(", ", submittedFutures.keySet()) + "] to finish...");
|
||||
try {
|
||||
jobWaitingSemaphore.acquire();
|
||||
} catch(InterruptedException e) {
|
||||
throw new RuntimeException("Unexpected interruption", e);
|
||||
}
|
||||
submittedFutures.entrySet().removeIf(entry -> {
|
||||
if(entry.getValue().isDone()) {
|
||||
ModernFix.LOGGER.debug(DISPATCHER, "Job finished for " + entry.getKey());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
submittedFutures.values().forEach(CompletableFuture::join);
|
||||
}
|
||||
|
||||
public static void dispatchBlocking(Executor executor, Consumer<String> task) {
|
||||
dispatchBlocking(executor, task, Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
|
@ -62,16 +62,12 @@
|
|||
"perf.thread_priorities.IntegratedServerMixin",
|
||||
"safety.BlockColorsMixin",
|
||||
"safety.ItemColorsMixin",
|
||||
"perf.flatten_model_predicates.AndConditionMixin",
|
||||
"perf.flatten_model_predicates.OrConditionMixin",
|
||||
"perf.flatten_model_predicates.PropertyValueConditionMixin",
|
||||
"perf.blast_search_trees.MinecraftMixin",
|
||||
"perf.blast_search_trees.IngredientFilterInvoker",
|
||||
"perf.cache_model_materials.VanillaModelMixin",
|
||||
"perf.cache_model_materials.BlockModelMixin",
|
||||
"perf.cache_model_materials.MultipartMixin",
|
||||
"perf.faster_texture_stitching.StitcherMixin",
|
||||
"perf.faster_singleplayer_load.MinecraftServerMixin",
|
||||
"devenv.MinecraftMixin",
|
||||
"devenv.NarratorMixin"
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user