Merge remote-tracking branch 'origin/1.18' into 1.19.2

This commit is contained in:
embeddedt 2023-04-24 16:59:12 -04:00
commit ec31b0361e
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
23 changed files with 0 additions and 927 deletions

View File

@ -27,14 +27,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;
@ -51,9 +48,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())
@ -93,7 +87,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) {

View File

@ -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;
}
}
}

View File

@ -59,7 +59,6 @@ public class ModernFixEarlyConfig {
/* Keep this off if JEI/REI isn't installed to prevent breaking vanilla gameplay */
this.addMixinRule("perf.blast_search_trees", FMLLoader.getLoadingModList().getModFileById("jei") != null || 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().getProvider() instanceof ExplodedDirectoryLocator;
this.addMixinRule("devenv", isDevEnv);

View File

@ -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.Component;
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.ScreenEvent;
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(ScreenEvent.Opening event) {
if(ServerLifecycleHooks.getCurrentServer() instanceof IntegratedServer) {
if(event.getNewScreen() == 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.setNewScreen(newScreen);
}
} else if(event.getNewScreen() instanceof LevelLoadingScreen && Minecraft.getInstance().level == null && ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) {
ProgressScreen loadscreen = new ProgressScreen(false);
loadscreen.progressStartNoAbort(Component.translatable("connect.joining"));
event.setNewScreen(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;
}
}
}

View File

@ -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();
}
}
}

View File

@ -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()));
}
}

View File

@ -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()));
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -1,7 +0,0 @@
package org.embeddedt.modernfix.predicate;
/**
* Calculates the
*/
public class CachedModelPredicate {
}

View File

@ -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]));
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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");
}
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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());
}
}

View File

@ -64,9 +64,6 @@
"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",
@ -74,7 +71,6 @@
"perf.cache_model_materials.MultipartMixin",
"perf.faster_texture_stitching.StitcherMixin",
"perf.skip_first_datapack_reload.CreateWorldScreenMixin",
"perf.faster_singleplayer_load.MinecraftServerMixin",
"devenv.MinecraftMixin",
"devenv.NarratorMixin"
],