Skip to content

Commit

Permalink
Add MixinChunkProviderServer
Browse files Browse the repository at this point in the history
  • Loading branch information
quentin452 committed May 9, 2023
1 parent 956d802 commit 116050b
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 12 deletions.
4 changes: 4 additions & 0 deletions src/main/java/fr/iamacat/multithreading/asm/Mixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ public enum Mixin implements IMixin {
common_core_MixinEntitiesUpdateTimeandLight(Side.COMMON,
m -> MultithreadingandtweaksMultithreadingConfig.enableMixinEntitiesUpdateTimeandLight,
"core.MixinEntitiesUpdateTimeandLight"),

common_core_MixinChunkProviderServer(Side.COMMON,
m -> MultithreadingandtweaksMultithreadingConfig.enableMixinChunkProviderServer,
"core.MixinChunkProviderServer"),
common_core_MixinGodZillaFix(Side.COMMON, m -> MultithreadingandtweaksMultithreadingConfig.enableMixinGodZillaFix,
"core.MixinGodZillaFix"),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ public class MultithreadingandtweaksMultithreadingConfig {
@Config.DefaultBoolean(true)
@Config.RequiresWorldRestart
public static boolean enableMixinEntitiesUpdateTimeandLight;

@Config.Comment("Enable Multithreaded Chunk Provider Server")
@Config.DefaultBoolean(true)
@Config.RequiresWorldRestart
public static boolean enableMixinChunkProviderServer;
@Config.Comment("Fix Godzilla Spam Log from orespawn")
@Config.DefaultBoolean(false)
@Config.RequiresWorldRestart
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
package fr.iamacat.multithreading.mixins.common.core;

import java.util.concurrent.*;

import com.falsepattern.lib.compat.MathHelper;
import fr.iamacat.multithreading.config.MultithreadingandtweaksMultithreadingConfig;
import net.minecraft.crash.CrashReport;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.profiler.Profiler;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.ServerConfigurationManager;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.storage.WorldInfo;

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.callback.CallbackInfo;
import org.spongepowered.libraries.com.google.common.util.concurrent.ThreadFactoryBuilder;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import fr.iamacat.multithreading.config.MultithreadingandtweaksMultithreadingConfig;

@Mixin(value = World.class, priority = 850)
@Mixin(World.class)
public abstract class MixinChunkPopulating {

private final LinkedBlockingQueue<Chunk> chunksToPopulate = new LinkedBlockingQueue<>();
Expand All @@ -42,8 +43,8 @@ public abstract class MixinChunkPopulating {
private void onPopulate(IChunkProvider chunkProvider, IChunkProvider chunkProvider1, CallbackInfo ci) {
if (MultithreadingandtweaksMultithreadingConfig.enableMixinChunkPopulating) {
int maxChunksPerTick = MultithreadingandtweaksMultithreadingConfig.batchsize; // Change this value to limit
// the number of chunks to be
// processed per tick
// the number of chunks to be
// processed per tick
int numChunksProcessed = 0;
Chunk chunk = null;
while (numChunksProcessed < maxChunksPerTick && (chunk = chunksToPopulate.poll()) != null) {
Expand All @@ -52,6 +53,7 @@ private void onPopulate(IChunkProvider chunkProvider, IChunkProvider chunkProvid
finalChunk.isTerrainPopulated = true;
finalChunk.populateChunk(chunkProvider, chunkProvider1, finalChunk.xPosition, finalChunk.zPosition);
});

numChunksProcessed++;
}
}
Expand All @@ -61,13 +63,13 @@ private void onPopulate(IChunkProvider chunkProvider, IChunkProvider chunkProvid
method = "Lnet/minecraft/world/WorldServer;<init>(Lnet/minecraft/server/MinecraftServer;Ljava/util/concurrent/ExecutorService;Lnet/minecraft/world/storage/ISaveHandler;Lnet/minecraft/world/storage/WorldInfo;Lnet/minecraft/world/WorldProvider;Lnet/minecraft/profiler/Profiler;Lnet/minecraft/crash/CrashReport;Lnet/minecraft/util/ReportedException;)V",
at = @At("RETURN"))
private void onInitialize(MinecraftServer server, ExecutorService executorService, ISaveHandler saveHandler,
WorldInfo info, WorldProvider provider, Profiler profiler, CrashReport report, CallbackInfo ci) {
WorldInfo info, WorldProvider provider, Profiler profiler, CrashReport report, CallbackInfo ci) {
ServerConfigurationManager playerList = server.getConfigurationManager();
EntityPlayerMP player = (EntityPlayerMP) playerList.playerEntityList.get(0);
int viewDistance = playerList.getViewDistance() * 16; // Distance in blocks
int playerX = MathHelper.floor_double(player.posX) >> 4;
int playerZ = MathHelper.floor_double(player.posZ) >> 4;
for (int x = playerX - viewDistance; x <= playerX + viewDistance; x++) {
for (int x = playerX - viewDistance; x <= playerX + viewDistance; x++)
for (int z = playerZ - viewDistance; z <= playerZ + viewDistance; z++) {
Chunk chunk = provider.worldObj.getChunkFromChunkCoords(x, z);
if (!chunk.isTerrainPopulated && chunk.isChunkLoaded) {
Expand All @@ -76,4 +78,3 @@ private void onInitialize(MinecraftServer server, ExecutorService executorServic
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package fr.iamacat.multithreading.mixins.common.core;

import fr.iamacat.multithreading.config.MultithreadingandtweaksMultithreadingConfig;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.gen.ChunkProviderServer;
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.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Mixin(ChunkProviderServer.class)
public class MixinChunkProviderServer {
@Shadow
public Chunk loadChunk(int x, int z) {
return null;
}

@Inject(method = "tick", at = @At("HEAD"), cancellable = true)
private void tick(CallbackInfo ci) {
if (MultithreadingandtweaksMultithreadingConfig.enableMixinChunkProviderServer) {
try {
// Number of chunks to process per tick
int batchSize = MultithreadingandtweaksMultithreadingConfig.batchsize;
// Number of threads to use
int numThreads = MultithreadingandtweaksMultithreadingConfig.numberofcpus;

// Create a list of chunks to process
List<Chunk> chunksToProcess = new ArrayList<>();
WorldServer world = MinecraftServer.getServer().worldServers[0];
ChunkProviderServer chunkProvider = (ChunkProviderServer) world.getChunkProvider();

// Use reflection to make the currentChunkSet field accessible
Field currentChunkSetField = ChunkProviderServer.class.getDeclaredField("currentChunkSet");
currentChunkSetField.setAccessible(true);
ChunkCoordIntPair currentChunkSet = (ChunkCoordIntPair) currentChunkSetField.get(chunkProvider);

for (int chunkX = currentChunkSet.chunkXPos - batchSize; chunkX <= currentChunkSet.chunkXPos + batchSize; chunkX++) {
for (int chunkZ = currentChunkSet.chunkZPos - batchSize; chunkZ <= currentChunkSet.chunkZPos + batchSize; chunkZ++) {
Chunk chunk = chunkProvider.loadChunk(chunkX, chunkZ);
if (chunk != null) {
chunksToProcess.add(chunk);
}
}
}

// Process the chunks using a thread pool
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
for (Chunk chunk : chunksToProcess) {
executor.execute(() -> {
ChunkCoordIntPair chunkCoords = new ChunkCoordIntPair(chunk.xPosition, chunk.zPosition);
if (chunk.isModified) {
chunk.isModified = false;
chunkProvider.saveChunks(true, null);
}
});
}
executor.shutdown();

ci.cancel();
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}

0 comments on commit 116050b

Please sign in to comment.