diff --git a/src/main/java/carpet/fakes/ThreadedAnvilChunkStorageInterface.java b/src/main/java/carpet/fakes/ThreadedAnvilChunkStorageInterface.java index 32e98484..545c01db 100644 --- a/src/main/java/carpet/fakes/ThreadedAnvilChunkStorageInterface.java +++ b/src/main/java/carpet/fakes/ThreadedAnvilChunkStorageInterface.java @@ -4,5 +4,5 @@ import net.minecraft.util.math.ChunkPos; public interface ThreadedAnvilChunkStorageInterface { - void regenerateChunk(ChunkPos chpos); + void regenerateChunkRegion(ChunkPos from, ChunkPos to); } diff --git a/src/main/java/carpet/mixins/MinecraftServer_tickspeedMixin.java b/src/main/java/carpet/mixins/MinecraftServer_tickspeedMixin.java index 0be8b8ea..fdc08601 100644 --- a/src/main/java/carpet/mixins/MinecraftServer_tickspeedMixin.java +++ b/src/main/java/carpet/mixins/MinecraftServer_tickspeedMixin.java @@ -3,9 +3,11 @@ package carpet.mixins; import carpet.helpers.TickSpeed; import carpet.utils.CarpetProfiler; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.ServerTask; import net.minecraft.util.TickDurationMonitor; import net.minecraft.util.Util; import net.minecraft.util.profiler.Profiler; +import net.minecraft.util.thread.ReentrantThreadExecutor; import org.apache.logging.log4j.Logger; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -18,7 +20,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.function.BooleanSupplier; @Mixin(MinecraftServer.class) -public abstract class MinecraftServer_tickspeedMixin +public abstract class MinecraftServer_tickspeedMixin extends ReentrantThreadExecutor { @Shadow private volatile boolean running; @@ -32,6 +34,11 @@ public abstract class MinecraftServer_tickspeedMixin @Shadow @Final private Profiler profiler; + public MinecraftServer_tickspeedMixin(String name) + { + super(name); + } + @Shadow protected abstract void tick(BooleanSupplier booleanSupplier_1); @Shadow protected abstract boolean shouldKeepTicking(); @@ -116,7 +123,12 @@ public abstract class MinecraftServer_tickspeedMixin this.profiler.swap("nextTickWait"); this.field_19249 = true; this.field_19248 = Math.max(Util.getMeasuringTimeMs() + /*50L*/ msThisTick, this.timeReference); - this.method_16208(); + if (TickSpeed.time_warp_start_time != 0) + { + runTasks(); + runTasks(() -> !hasRunningTasks() ); + } + else { this.method_16208(); } this.profiler.pop(); this.profiler.endTick(); this.loading = true; diff --git a/src/main/java/carpet/mixins/ThreadedAnvilChunkStorage_scarpetChunkCreationMixin.java b/src/main/java/carpet/mixins/ThreadedAnvilChunkStorage_scarpetChunkCreationMixin.java index 357c0444..ec8e10f8 100644 --- a/src/main/java/carpet/mixins/ThreadedAnvilChunkStorage_scarpetChunkCreationMixin.java +++ b/src/main/java/carpet/mixins/ThreadedAnvilChunkStorage_scarpetChunkCreationMixin.java @@ -1,5 +1,6 @@ package carpet.mixins; +import carpet.CarpetSettings; import carpet.fakes.ChunkHolderInterface; import carpet.fakes.ThreadedAnvilChunkStorageInterface; import com.mojang.datafixers.util.Either; @@ -24,6 +25,8 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.util.ArrayList; +import java.util.List; import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -79,9 +82,16 @@ public abstract class ThreadedAnvilChunkStorage_scarpetChunkCreationMixin implem } @Override - public void regenerateChunk(ChunkPos chpos) + public void regenerateChunkRegion(ChunkPos from, ChunkPos to) { - Long id = chpos.toLong(); + List chunksToConvert = new ArrayList<>(); + int xmax = Math.max(from.x, to.x); + int zmax = Math.max(from.z, to.z); + for (int x = Math.min(from.x, to.x); x <= xmax; x++) for (int z = Math.min(from.z, to.z); z <= zmax; z++) + { + chunksToConvert.add(new ChunkPos(x,z)); + } + //flushning all tasks on the thread executor so all futures are ready - we don't want any deadlocks mainThreadExecutor.runTasks(() -> mainThreadExecutor.getTaskCount() == 0); // save all pending chunks @@ -91,52 +101,99 @@ public abstract class ThreadedAnvilChunkStorage_scarpetChunkCreationMixin implem runnable.run(); } - //chunk is currently in memory in some shape or form / loaded / unloaded / queued / cached - ChunkHolder chunkHolder = currentChunkHolders.remove(id); - if (chunkHolder != null) { - //method_20458(id, chunkHolder); // saving chunk // skipping entities etc - Chunk chunk = null; - try + List createdChunks = new ArrayList<>(); + for (ChunkPos chpos : chunksToConvert) + { + Long id = chpos.toLong(); + //chunk is currently in memory in some shape or form / loaded / unloaded / queued / cached + ChunkHolder chunkHolder = currentChunkHolders.remove(id); + if (chunkHolder != null) { - // fingers crossed - chunk = chunkHolder.getFuture().get(); - } - catch (InterruptedException | ExecutionException e) - { } - // if (field_18807.remove(id, chunkHolder) && chunk != null) { - if (chunk != null) { - if (chunk instanceof WorldChunk) { - ((WorldChunk)chunk).setLoadedToWorld(false); + //method_20458(id, chunkHolder); // saving chunk // skipping entities etc + Chunk chunk = null; + try + { + // fingers crossed + chunk = chunkHolder.getFuture().get(); } - save(chunk); - if (this.loadedChunks.remove(id) && chunk instanceof WorldChunk) { - WorldChunk worldChunk = (WorldChunk)chunk; - //apparently that doesn't remove them for the client - this.world.unloadEntities(worldChunk); + catch (InterruptedException | ExecutionException e) + { + } + // if (field_18807.remove(id, chunkHolder) && chunk != null) { + if (chunk != null) + { + if (chunk instanceof WorldChunk) + { + ((WorldChunk) chunk).setLoadedToWorld(false); + } + save(chunk); + if (this.loadedChunks.remove(id) && chunk instanceof WorldChunk) + { + WorldChunk worldChunk = (WorldChunk) chunk; + //apparently that doesn't remove them for the client + this.world.unloadEntities(worldChunk); + } + //this.serverLightingProvider.updateChunkStatus(chunk.getPos()); // we might need that as some point + serverLightingProvider.tick(); + worldGenerationProgressListener.setChunkStatus(chunk.getPos(), (ChunkStatus) null); } - //this.serverLightingProvider.updateChunkStatus(chunk.getPos()); - serverLightingProvider.tick(); - worldGenerationProgressListener.setChunkStatus(chunk.getPos(), (ChunkStatus)null); } + unloadedChunks.remove(id); + loadedChunks.remove(id); + field_18807.remove(id); + ChunkHolder newHolder = new ChunkHolder(chpos, 0,serverLightingProvider, chunkTaskPrioritySystem, (ChunkHolder.PlayersWatchingChunkProvider) this); + this.currentChunkHolders.put(id, newHolder); + //removed holders + field_18807.put(id, newHolder); + //loadedChunks.add(id); + ((ChunkHolderInterface)newHolder).setDefaultProtoChunk(chpos, mainThreadExecutor); + createdChunks.add(newHolder); } //getting rid of all signs this.chunkHolderListDirty = true; - currentChunkHolders.remove(id); - unloadedChunks.remove(id); - loadedChunks.remove(id); - field_18807.remove(id); - - ChunkHolder newHolder = new ChunkHolder(chpos, 0,serverLightingProvider, chunkTaskPrioritySystem, (ChunkHolder.PlayersWatchingChunkProvider) this); - this.currentChunkHolders.put(id, newHolder); - loadedChunks.add(id); - - ((ChunkHolderInterface)newHolder).setDefaultProtoChunk(chpos, mainThreadExecutor); - convertToFullChunk(newHolder); - // running all pending tasks + // not needed right now mainThreadExecutor.runTasks(() -> mainThreadExecutor.getTaskCount() == 0); + //worldgenExecutor. // save all pending chunks / potentially only one max - ours // hopefully that would flush all chunk writes, including current chink - while((runnable = field_19343.poll()) != null) { + while ((runnable = field_19343.poll()) != null) + { + runnable.run(); + } + + for (ChunkStatus status : ChunkStatus.createOrderedList()) + { + CarpetSettings.LOG.error("Creating layer: " + status.getId()); + if (status == ChunkStatus.LIGHT) + { + serverLightingProvider.setTaskBatchSize(chunksToConvert.size() + 20); + } + for (ChunkPos chpos : chunksToConvert) + { + //if (status==ChunkStatus.LIGHT) + //{ + // serverLightingProvider.tick(); + //} + //CarpetSettings.LOG.error("Creating layer: " + status.getId()); + world.getChunk(chpos.x, chpos.z, status); + //CarpetSettings.LOG.error(" .. done"); + //if (status==ChunkStatus.LIGHT) + //{ + // serverLightingProvider.tick(); + //} + } + if (status == ChunkStatus.LIGHT) + { + serverLightingProvider.setTaskBatchSize(5); + } + } + + mainThreadExecutor.runTasks(() -> mainThreadExecutor.getTaskCount() == 0); + //worldgenExecutor. + // save all pending chunks / potentially only one max - ours + // hopefully that would flush all chunk writes, including current chink + while ((runnable = field_19343.poll()) != null) + { runnable.run(); } } diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index f74724a6..930e9114 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -79,7 +79,6 @@ import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ChunkTicket; import net.minecraft.server.world.ServerWorld; -import net.minecraft.server.world.ThreadedAnvilChunkStorage; import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.SoundCategory; import net.minecraft.stat.Stat; @@ -1680,11 +1679,19 @@ public class CarpetExpression CarpetContext cc = (CarpetContext)c; BlockValue.LocatorResult locator = BlockValue.fromParams(cc, lv, 0); + ServerWorld world = cc.s.getWorld(); BlockPos pos = locator.block.getPos(); + BlockPos temp = pos; + if (lv.size() > locator.offset ) + { + BlockValue.LocatorResult locator2 = BlockValue.fromParams(cc, lv, locator.offset); + temp = locator2.block.getPos(); + } + BlockPos toPos = temp; ((CarpetContext)c).s.getMinecraftServer().submitAndJoin( () -> { - ((ThreadedAnvilChunkStorageInterface) world.getChunkManager().threadedAnvilChunkStorage).regenerateChunk(new ChunkPos(pos)); + ((ThreadedAnvilChunkStorageInterface) world.getChunkManager().threadedAnvilChunkStorage).regenerateChunkRegion(new ChunkPos(pos), new ChunkPos(toPos)); world.getChunk(pos); this.forceChunkUpdate(pos, world); });