diff --git a/build.gradle b/build.gradle index 3e33ea67..03597527 100644 --- a/build.gradle +++ b/build.gradle @@ -121,11 +121,6 @@ repositories { includeGroup "curse.maven" } } - maven { - // location of the maven that hosts JEI files - name = "Progwml6 maven" - url = "https://dvs1.progwml6.com/files/maven/" - } } dependencies { @@ -150,6 +145,8 @@ dependencies { runtimeOnly fg.deobf("mezz.jei:jei-${minecraft_version}:${jei_version}") runtimeOnly fg.deobf("curse.maven:spark-361579:3767277") + + compileOnly fg.deobf("curse.maven:refinedstorage-243076:3807951") } // Example for how to get properties into the manifest for reading at runtime. diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index 23d47671..cd861db2 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -21,14 +21,17 @@ import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent; +import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.fml.network.FMLNetworkConstants; import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.core.config.ModernFixConfig; +import java.lang.management.ManagementFactory; import java.util.stream.Collectors; // The value here should match an entry in the META-INF/mods.toml file @@ -54,4 +57,12 @@ public class ModernFix { ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG); } + + @SubscribeEvent + public void onServerStarted(FMLServerStartedEvent event) { + if(FMLLoader.getDist() == Dist.DEDICATED_SERVER) { + float gameStartTime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000f; + ModernFix.LOGGER.warn("Dedicated server took " + gameStartTime + " seconds to load"); + } + } } diff --git a/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java b/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java index bccb787c..2ec1cdaf 100644 --- a/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java +++ b/src/main/java/org/embeddedt/modernfix/blockstate/BlockStateCacheHandler.java @@ -1,23 +1,30 @@ package org.embeddedt.modernfix.blockstate; import com.google.common.base.Stopwatch; +import com.google.common.collect.ImmutableSet; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.util.Util; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.shapes.ISelectionContext; +import net.minecraft.world.EmptyBlockReader; import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.duck.IBlockState; -import org.embeddedt.modernfix.util.AsyncStopwatch; import org.embeddedt.modernfix.util.BakeReason; -import org.embeddedt.modernfix.util.OrderedParallelModDispatcher; -import java.util.ArrayList; -import java.util.Map; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import java.util.stream.Stream; import java.util.stream.StreamSupport; public class BlockStateCacheHandler { + private static final Set PRECACHED_COLLISION_SHAPES = ImmutableSet.builder() + .add("refinedstorage") + .add("cabletiers") + .add("extrastorage") + .build(); public static void handleStateCache(BlockState state) { if(BakeReason.currentBakeReason == BakeReason.FREEZE || BakeReason.currentBakeReason == BakeReason.REMOTE_SNAPSHOT_INJECT @@ -34,42 +41,20 @@ public class BlockStateCacheHandler { handleStateCache(state); } public static void rebuildParallel(boolean force) { - Map> statesByModId = StreamSupport.stream(Block.BLOCK_STATE_REGISTRY.spliterator(), false) - .collect(Collectors.groupingBy(state -> state.getBlock().getRegistryName().getNamespace(), Collectors.toCollection(ArrayList::new))); + /* Run some special sauce for Refined Storage since it has very slow collision shapes */ Stopwatch realtimeStopwatch = Stopwatch.createStarted(); - AsyncStopwatch cpuStopwatch = new AsyncStopwatch(); - /* For safety, do built-in blocks first */ - cpuStopwatch.startMeasuringAsync(); - ArrayList initialStates = statesByModId.remove("minecraft"); - for(BlockState state : initialStates) { - handleStateCacheParallel(state, force); - } - cpuStopwatch.stopMeasuringAsync(); - OrderedParallelModDispatcher.dispatchBlocking(Util.backgroundExecutor(), modId -> { - ArrayList states = statesByModId.get(modId); - if(states == null) - return; - cpuStopwatch.startMeasuringAsync(); - states.removeIf(state -> { - try { - handleStateCacheParallel(state, force); - return true; - } catch(RuntimeException e) { - ModernFix.LOGGER.error("Error computing state cache for " + state + ": ", e); - return false; - } - }); - cpuStopwatch.stopMeasuringAsync(); - }); - cpuStopwatch.startMeasuringAsync(); - for(ArrayList remainingStates : statesByModId.values()) { - for(BlockState state : remainingStates) { - handleStateCacheParallel(state, force); - } - } - cpuStopwatch.stopMeasuringAsync(); + List specialStates = StreamSupport.stream(Block.BLOCK_STATE_REGISTRY.spliterator(), false) + .filter(state -> PRECACHED_COLLISION_SHAPES.contains(state.getBlock().getRegistryName().getNamespace())).collect(Collectors.toList()); + CompletableFuture.runAsync(() -> { + specialStates.parallelStream() + .forEach(state -> { + /* Force these blocks to compute their shapes ahead of time on worker threads */ + state.getBlock().getCollisionShape(state, EmptyBlockReader.INSTANCE, BlockPos.ZERO, ISelectionContext.empty()); + state.getBlock().getOcclusionShape(state, EmptyBlockReader.INSTANCE, BlockPos.ZERO); + }); + }, Util.backgroundExecutor()).join(); + Block.BLOCK_STATE_REGISTRY.forEach(state -> handleStateCacheParallel(state, force)); realtimeStopwatch.stop(); - ModernFix.LOGGER.info("CPU time spent rebuilding blockstate cache: " + cpuStopwatch.getCpuTime()/1000f + " seconds"); ModernFix.LOGGER.info("Real time spent rebuilding blockstate cache: " + realtimeStopwatch.elapsed(TimeUnit.MILLISECONDS)/1000f + " seconds"); } } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallel_potentially_unsafe/parallel_blockstate_cache_rebuild/ShapeCacheMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallel_potentially_unsafe/parallel_blockstate_cache_rebuild/ShapeCacheMixin.java new file mode 100644 index 00000000..54898be1 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallel_potentially_unsafe/parallel_blockstate_cache_rebuild/ShapeCacheMixin.java @@ -0,0 +1,26 @@ +package org.embeddedt.modernfix.mixin.perf.parallel_potentially_unsafe.parallel_blockstate_cache_rebuild; + +import com.refinedmods.refinedstorage.block.shape.ShapeCache; +import net.minecraft.block.BlockState; +import net.minecraft.util.math.shapes.VoxelShape; +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.CallbackInfo; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Mixin(ShapeCache.class) +public class ShapeCacheMixin { + @Shadow private static Map CACHE; + + @Inject(method = "", at = @At("TAIL")) + private static void useConcurrentMap(CallbackInfo ci) { + CACHE = new ConcurrentHashMap<>(); + ModernFix.LOGGER.info("Successfully replaced ShapeCache with concurrent map"); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/registry/DeferredRegisterBaker.java b/src/main/java/org/embeddedt/modernfix/registry/DeferredRegisterBaker.java index 70ecd880..79f7fefa 100644 --- a/src/main/java/org/embeddedt/modernfix/registry/DeferredRegisterBaker.java +++ b/src/main/java/org/embeddedt/modernfix/registry/DeferredRegisterBaker.java @@ -2,24 +2,14 @@ package org.embeddedt.modernfix.registry; import com.google.common.base.Stopwatch; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.ModContainer; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.ModWorkManager; -import net.minecraftforge.fml.common.ObfuscationReflectionHelper; -import net.minecraftforge.fml.loading.moddiscovery.ModInfo; -import net.minecraftforge.forgespi.language.IModInfo; 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.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; import java.util.function.Supplier; public class DeferredRegisterBaker { @@ -36,6 +26,7 @@ public class DeferredRegisterBaker { public static void bakeSuppliers(ResourceLocation registry) { synchronized (supplierMap) { + Set modErrors = Collections.synchronizedSet(new HashSet<>()); HashMap>> registrySupplierMap = supplierMap.get(registry); if(registrySupplierMap == null) return; @@ -51,12 +42,15 @@ public class DeferredRegisterBaker { try { supplier.compute(); } catch(RuntimeException e) { - e.printStackTrace(); + 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 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"); } diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index eb5d2321..b77edf3b 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -20,7 +20,10 @@ "perf.thread_priorities.UtilMixin", "perf.preload_block_classes.GameDataMixin", "perf.parallel_potentially_unsafe.parallel_deferred_suppliers.DeferredRegisterMixin", - "perf.parallel_potentially_unsafe.parallel_deferred_suppliers.GameDataMixin" + "perf.parallel_potentially_unsafe.parallel_deferred_suppliers.GameDataMixin", + "perf.parallel_potentially_unsafe.parallel_blockstate_cache_rebuild.BlocksMixin", + "perf.parallel_potentially_unsafe.parallel_blockstate_cache_rebuild.BlockCallbacksMixin", + "perf.parallel_potentially_unsafe.parallel_blockstate_cache_rebuild.ShapeCacheMixin" ], "client": [ "perf.skip_first_datapack_reload.MinecraftMixin",