Move mod dispatching logic into its own class
This commit is contained in:
parent
5c0d23b2f0
commit
2525a64313
|
|
@ -11,6 +11,7 @@ import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||||
import net.minecraftforge.forgespi.language.IModInfo;
|
import net.minecraftforge.forgespi.language.IModInfo;
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
import org.embeddedt.modernfix.util.CachedSupplier;
|
import org.embeddedt.modernfix.util.CachedSupplier;
|
||||||
|
import org.embeddedt.modernfix.util.OrderedParallelModDispatcher;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
@ -37,64 +38,20 @@ public class DeferredRegisterBaker {
|
||||||
HashMap<String, List<CachedSupplier<?>>> registrySupplierMap = supplierMap.get(registry);
|
HashMap<String, List<CachedSupplier<?>>> registrySupplierMap = supplierMap.get(registry);
|
||||||
if(registrySupplierMap == null)
|
if(registrySupplierMap == null)
|
||||||
return;
|
return;
|
||||||
HashSet<String> finishedMods = new HashSet<>();
|
|
||||||
finishedMods.add("minecraft");
|
|
||||||
finishedMods.add("forge");
|
|
||||||
HashMap<String, CompletableFuture<?>> submittedFutures = new HashMap<>();
|
|
||||||
int numMods = ModList.get().getMods().size();
|
|
||||||
Semaphore jobWaitingSemaphore = new Semaphore(0);
|
|
||||||
ArrayList<ModInfo> remainingModList = new ArrayList<>(ModList.get().getMods());
|
|
||||||
Stopwatch realtimeStopwatch = Stopwatch.createStarted();
|
Stopwatch realtimeStopwatch = Stopwatch.createStarted();
|
||||||
AtomicLong cpuLong = new AtomicLong(0);
|
AtomicLong cpuLong = new AtomicLong(0);
|
||||||
while(finishedMods.size() < numMods) {
|
OrderedParallelModDispatcher.dispatchBlocking(modId -> {
|
||||||
remainingModList.removeIf(modInfo -> {
|
List<CachedSupplier<?>> suppliersToCompute = registrySupplierMap.get(modId);
|
||||||
if(finishedMods.contains(modInfo.getModId()))
|
if (suppliersToCompute == null || suppliersToCompute.size() == 0) {
|
||||||
return true;
|
return;
|
||||||
boolean allDependenciesLoaded = true;
|
|
||||||
for(IModInfo.ModVersion dep : modInfo.getDependencies()) {
|
|
||||||
if(dep.isMandatory() && !finishedMods.contains(dep.getModId())) {
|
|
||||||
allDependenciesLoaded = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!allDependenciesLoaded)
|
|
||||||
return false;
|
|
||||||
/* Submit job */
|
|
||||||
List<CachedSupplier<?>> suppliersToCompute = registrySupplierMap.get(modInfo.getModId());
|
|
||||||
if (suppliersToCompute == null || suppliersToCompute.size() == 0) {
|
|
||||||
finishedMods.add(modInfo.getModId());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Optional<? extends ModContainer> modContainerOpt = ModList.get().getModContainerById(modInfo.getModId());
|
|
||||||
if(!modContainerOpt.isPresent())
|
|
||||||
throw new IllegalStateException("Can't find mod container");
|
|
||||||
ModContainer container = modContainerOpt.get();
|
|
||||||
submittedFutures.put(modInfo.getModId(), CompletableFuture.runAsync(() -> {
|
|
||||||
Supplier<?> contextExtension = ObfuscationReflectionHelper.getPrivateValue(ModContainer.class, container, "contextExtension");
|
|
||||||
ModLoadingContext.get().setActiveContainer(container, contextExtension.get());
|
|
||||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
|
||||||
for (CachedSupplier<?> supplier : suppliersToCompute) {
|
|
||||||
supplier.compute();
|
|
||||||
}
|
|
||||||
stopwatch.stop();
|
|
||||||
cpuLong.addAndGet(stopwatch.elapsed(TimeUnit.MILLISECONDS));
|
|
||||||
jobWaitingSemaphore.release();
|
|
||||||
}, ModWorkManager.parallelExecutor()));
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
jobWaitingSemaphore.acquire();
|
|
||||||
} catch(InterruptedException e) {
|
|
||||||
throw new RuntimeException("Unexpected interruption", e);
|
|
||||||
}
|
}
|
||||||
submittedFutures.entrySet().removeIf(entry -> {
|
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||||
if(entry.getValue().isDone()) {
|
for (CachedSupplier<?> supplier : suppliersToCompute) {
|
||||||
finishedMods.add(entry.getKey());
|
supplier.compute();
|
||||||
return true;
|
}
|
||||||
}
|
stopwatch.stop();
|
||||||
return false;
|
cpuLong.addAndGet(stopwatch.elapsed(TimeUnit.MILLISECONDS));
|
||||||
});
|
});
|
||||||
}
|
|
||||||
realtimeStopwatch.stop();
|
realtimeStopwatch.stop();
|
||||||
ModernFix.LOGGER.info("CPU time spent constructing " + registry + " suppliers: " + cpuLong.get()/1000f + " seconds");
|
ModernFix.LOGGER.info("CPU time spent constructing " + registry + " suppliers: " + cpuLong.get()/1000f + " seconds");
|
||||||
ModernFix.LOGGER.info("Real time spent constructing " + registry + " suppliers: " + realtimeStopwatch.elapsed(TimeUnit.MILLISECONDS)/1000f + " seconds");
|
ModernFix.LOGGER.info("Real time spent constructing " + registry + " suppliers: " + realtimeStopwatch.elapsed(TimeUnit.MILLISECONDS)/1000f + " seconds");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
package org.embeddedt.modernfix.util;
|
||||||
|
|
||||||
|
import com.google.common.base.Stopwatch;
|
||||||
|
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 java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
public static void dispatchBlocking(Consumer<String> task, Collection<String> modIDsToFilter) {
|
||||||
|
HashSet<String> finishedMods = new HashSet<>(modIDsToFilter);
|
||||||
|
HashMap<String, CompletableFuture<?>> submittedFutures = new HashMap<>();
|
||||||
|
int numMods = ModList.get().getMods().size();
|
||||||
|
Semaphore jobWaitingSemaphore = new Semaphore(0);
|
||||||
|
ArrayList<ModInfo> remainingModList = new ArrayList<>(ModList.get().getMods());
|
||||||
|
while(finishedMods.size() < numMods) {
|
||||||
|
remainingModList.removeIf(modInfo -> {
|
||||||
|
if(finishedMods.contains(modInfo.getModId()))
|
||||||
|
return true;
|
||||||
|
boolean allDependenciesLoaded = true;
|
||||||
|
for(IModInfo.ModVersion dep : modInfo.getDependencies()) {
|
||||||
|
if(dep.isMandatory() && !finishedMods.contains(dep.getModId())) {
|
||||||
|
allDependenciesLoaded = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!allDependenciesLoaded)
|
||||||
|
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();
|
||||||
|
submittedFutures.put(modInfo.getModId(), CompletableFuture.runAsync(() -> {
|
||||||
|
Supplier<?> contextExtension = ObfuscationReflectionHelper.getPrivateValue(ModContainer.class, container, "contextExtension");
|
||||||
|
ModLoadingContext.get().setActiveContainer(container, contextExtension.get());
|
||||||
|
task.accept(modInfo.getModId());
|
||||||
|
jobWaitingSemaphore.release();
|
||||||
|
}, ModWorkManager.parallelExecutor()));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
jobWaitingSemaphore.acquire();
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
throw new RuntimeException("Unexpected interruption", e);
|
||||||
|
}
|
||||||
|
submittedFutures.entrySet().removeIf(entry -> {
|
||||||
|
if(entry.getValue().isDone()) {
|
||||||
|
finishedMods.add(entry.getKey());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void dispatchBlocking(Consumer<String> task) {
|
||||||
|
dispatchBlocking(task, Collections.emptyList());
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user