Skip to content

Commit

Permalink
Threaded Feature Generation
Browse files Browse the repository at this point in the history
  • Loading branch information
ishland committed Mar 6, 2021
1 parent c35c681 commit e4e8052
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 22 deletions.
1 change: 1 addition & 0 deletions src/main/java/org/yatopiamc/c2me/C2MEMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public void onInitialize() {
final Metrics metrics = new Metrics(10514);
metrics.addCustomChart(new Metrics.SimplePie("environmentType", () -> FabricLoader.getInstance().getEnvironmentType().name().toLowerCase(Locale.ENGLISH)));
metrics.addCustomChart(new Metrics.SimplePie("useThreadedWorldGeneration", () -> String.valueOf(C2MEConfig.threadedWorldGenConfig.enabled)));
metrics.addCustomChart(new Metrics.SimplePie("useThreadedWorldFeatureGeneration", () -> String.valueOf(C2MEConfig.threadedWorldGenConfig.allowThreadedFeatures)));
metrics.addCustomChart(new Metrics.DrilldownPie("detailedMinecraftVersion", () -> ImmutableMap.of(MinecraftVersion.field_25319.getReleaseTarget(), ImmutableMap.of(MinecraftVersion.field_25319.getName(), 1))));
}
}
14 changes: 12 additions & 2 deletions src/main/java/org/yatopiamc/c2me/common/config/C2MEConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ public class C2MEConfig {
.sync()
.build();
config.load();
@SuppressWarnings("unused")
CommentedConfig globalConfig = config.get("global"); // Unused for now

asyncIoConfig = new AsyncIoConfig(config.get("asyncIO"));
threadedWorldGenConfig = new ThreadedWorldGenConfig(config.get("threadedWorldGen"));
config.save();
config.close();
}

Expand Down Expand Up @@ -54,16 +54,26 @@ public AsyncIoConfig(CommentedConfig config) {
public static class ThreadedWorldGenConfig {
public final boolean enabled;
public final int parallelism;
public final boolean allowThreadedFeatures;

public ThreadedWorldGenConfig(CommentedConfig config) {
Preconditions.checkNotNull(config, "threadedWorldGen config is not present");
upgrade(config);
enabled = config.getOrElse("enabled", false);
int configuredParallelism = config.getIntOrElse("parallelism", -1);
Preconditions.checkArgument(configuredParallelism >= -1 && configuredParallelism != 0 && configuredParallelism <= 0x7fff, "Invalid parallelism");
if (configuredParallelism == -1)
parallelism = Math.min(6, Runtime.getRuntime().availableProcessors());
else
parallelism = configuredParallelism;
allowThreadedFeatures = config.getOrElse("allowThreadedFeatures", false);
}

private void upgrade(CommentedConfig config) {
if (!config.contains("allowThreadedFeatures")) {
config.set("allowThreadedFeatures", false);
config.setComment("allowThreadedFeatures", " Whether to allow feature generation (world decorations like trees, ores and etc.) run in parallel");
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.ibm.asyncutil.locks.AsyncNamedLock;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.chunk.ChunkStatus;
import org.yatopiamc.c2me.common.config.C2MEConfig;
import org.yatopiamc.c2me.common.threading.GlobalExecutors;
import org.yatopiamc.c2me.common.util.AsyncCombinedLock;
import org.yatopiamc.c2me.common.util.AsyncNamedLockDelegateAsyncLock;
Expand All @@ -14,25 +15,28 @@
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;

import static org.yatopiamc.c2me.common.threading.worldgen.ChunkStatusThreadingType.AS_IS;
import static org.yatopiamc.c2me.common.threading.worldgen.ChunkStatusThreadingType.PARALLELIZED;
import static org.yatopiamc.c2me.common.threading.worldgen.ChunkStatusThreadingType.SINGLE_THREADED;

public class ChunkStatusUtils {

public static ChunkStatusThreadingType getThreadingType(final ChunkStatus status) {
switch (status.getId()) {
case "structure_starts":
case "structure_references":
case "biomes":
case "noise":
case "surface":
case "carvers":
case "liquid_carvers":
case "heightmaps":
return ChunkStatusThreadingType.PARALLELIZED;
case "spawn":
case "features":
return ChunkStatusThreadingType.SINGLE_THREADED;
default:
return ChunkStatusThreadingType.AS_IS;
if (status.equals(ChunkStatus.STRUCTURE_STARTS)
|| status.equals(ChunkStatus.STRUCTURE_REFERENCES)
|| status.equals(ChunkStatus.BIOMES)
|| status.equals(ChunkStatus.NOISE)
|| status.equals(ChunkStatus.SURFACE)
|| status.equals(ChunkStatus.CARVERS)
|| status.equals(ChunkStatus.LIQUID_CARVERS)
|| status.equals(ChunkStatus.HEIGHTMAPS)) {
return PARALLELIZED;
} else if (status.equals(ChunkStatus.SPAWN)) {
return SINGLE_THREADED;
} else if (status.equals(ChunkStatus.FEATURES)) {
return C2MEConfig.threadedWorldGenConfig.allowThreadedFeatures ? PARALLELIZED : SINGLE_THREADED;
}
return AS_IS;
}

public static <T> CompletableFuture<T> runChunkGenWithLock(ChunkPos target, int radius, AsyncNamedLock<ChunkPos> chunkLock, Supplier<CompletableFuture<T>> action) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.yatopiamc.c2me.mixin.threading.chunkio;

import net.minecraft.server.world.ServerChunkManager;
import net.minecraft.util.thread.ThreadExecutor;
import org.spongepowered.asm.mixin.Dynamic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(ServerChunkManager.MainThreadExecutor.class)
public abstract class MixinServerChunkManagerMainThreadExecutor extends ThreadExecutor<Runnable> {

protected MixinServerChunkManagerMainThreadExecutor(String name) {
super(name);
}

@Inject(method = "runTask", at = @At("RETURN"))
private void onPostRunTask(CallbackInfoReturnable<Boolean> cir) {
super.runTask();
}

}
2 changes: 2 additions & 0 deletions src/main/resources/c2me.accesswidener
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ accessible class net/minecraft/world/chunk/ChunkStatus$SimpleGenerationTas
accessible class net/minecraft/world/chunk/ChunkStatus$LoadTask
accessible class net/minecraft/world/chunk/ChunkStatus$GenerationTask
accessible class net/minecraft/world/storage/StorageIoWorker$Result
accessible class net/minecraft/server/world/ServerChunkManager$MainThreadExecutor

accessible method net/minecraft/world/storage/RegionBasedStorage <init> (Ljava/io/File;Z)V
accessible method net/minecraft/world/storage/RegionBasedStorage getRegionFile (Lnet/minecraft/util/math/ChunkPos;)Lnet/minecraft/world/storage/RegionFile;
accessible method net/minecraft/world/storage/RegionBasedStorage write (Lnet/minecraft/util/math/ChunkPos;Lnet/minecraft/nbt/CompoundTag;)V
accessible method net/minecraft/util/collection/WeightedList <init> (Ljava/util/List;)V
accessible method net/minecraft/server/world/ServerChunkManager tick ()Z

accessible field net/minecraft/world/storage/StorageIoWorker$Result nbt Lnet/minecraft/nbt/CompoundTag;
accessible field net/minecraft/world/storage/StorageIoWorker$Result future Ljava/util/concurrent/CompletableFuture;
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/c2me.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"threading.chunkio.MixinLightingProvider",
"threading.chunkio.MixinScheduledTick",
"threading.chunkio.MixinSerializingRegionBasedStorage",
"threading.chunkio.MixinServerChunkManagerMainThreadExecutor",
"threading.chunkio.MixinServerTickScheduler",
"threading.chunkio.MixinSimpleTickScheduler",
"threading.chunkio.MixinStorageIoWorker",
Expand Down
10 changes: 5 additions & 5 deletions src/main/resources/default-c2me.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Global settings
[global]

# Configuration for async io system
[asyncIO]
# Serializer executor parallelism
serializerParallelism = -1
# IO worker executor parallelism
ioWorkerParallelism = -1
# Serializer executor parallelism
serializerParallelism = -1

# Configuration for threaded world generation
[threadedWorldGen]
# Whether to enable this feature
enabled = true
# World generation worker executor parallelism
parallelism = -1
# Whether to allow feature generation (world decorations like trees, ores and etc.) run in parallel
allowThreadedFeatures = false

0 comments on commit e4e8052

Please sign in to comment.