Skip to content

Commit

Permalink
fix: Fix save loading
Browse files Browse the repository at this point in the history
World generation progress is now tracked/logged properly and chunks in a tickets' radius with infinite duration are also loaded/unloaded.
  • Loading branch information
Steveplays28 committed Jul 17, 2024
1 parent 003e044 commit 90652b6
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.github.steveplays28.noisiumchunkmanager.mixin.client.gui;

import io.github.steveplays28.noisiumchunkmanager.server.world.chunk.event.ServerChunkEvent;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.WorldGenerationProgressTracker;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.chunk.ChunkStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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;

@Environment(EnvType.CLIENT)
@Mixin(WorldGenerationProgressTracker.class)
public abstract class WorldGenerationProgressTrackerMixin {
@Shadow
public abstract void setChunkStatus(@NotNull ChunkPos chunkPosition, @Nullable ChunkStatus chunkStatus);

@Inject(method = "<init>", at = @At(value = "TAIL"))
private void noisiumchunkmanager$registerEventListeners(@NotNull CallbackInfo ci) {
ServerChunkEvent.WORLD_CHUNK_GENERATED.register(worldChunk -> this.setChunkStatus(worldChunk.getPos(), worldChunk.getStatus()));
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package io.github.steveplays28.noisiumchunkmanager.mixin.server;

import com.llamalad7.mixinextras.sugar.Local;
import io.github.steveplays28.noisiumchunkmanager.extension.world.server.ServerWorldExtension;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.WorldGenerationProgressListener;
import net.minecraft.server.world.ChunkTicketType;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Unit;
import net.minecraft.util.Util;
import net.minecraft.util.math.ChunkPos;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
Expand All @@ -15,24 +22,48 @@

@Mixin(MinecraftServer.class)
public abstract class MinecraftServerMixin<T> {
// @Shadow
// public abstract ServerWorld getOverworld();
//
// @Redirect(method = "prepareStartRegion", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerChunkManager;addTicket(Lnet/minecraft/server/world/ChunkTicketType;Lnet/minecraft/util/math/ChunkPos;ILjava/lang/Object;)V"))
// private void noisiumchunkmanager$prepareStartRegionAddTicketForSpawnChunksToNoisiumServerWorldChunkManager(ServerChunkManager instance, ChunkTicketType<T> ticketType, ChunkPos chunkPos, int radius, T argument) {
// ((NoisiumServerWorldExtension) getOverworld()).noisiumchunkmanager$getServerWorldChunkManager().getChunksInRadius(chunkPos, radius);
// }
//
// @Redirect(method = "prepareStartRegion", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerChunkManager;getTotalChunksLoadedCount()I"))
// private int noisiumchunkmanager$prepareStartRegionRedirectTotalLoadedChunksToNoisiumServerWorldChunkManager(ServerChunkManager instance) {
// // TODO: Make the loadedWorldChunks field private again and remove this whole vanilla Minecraft system
// return ((NoisiumServerWorldExtension) getOverworld()).noisiumchunkmanager$getServerWorldChunkManager().loadedWorldChunks.size();
// }
//
// @ModifyConstant(method = "prepareStartRegion", constant = @Constant(intValue = 441))
// private int noisiumchunkmanager$prepareStartRegionChangeTheAmountOfSpawnChunks(int original) {
// return 484;
// }
@Shadow
@Final
private static Logger LOGGER;
@Shadow
@Final
public static int START_TICKET_CHUNK_RADIUS;

@Shadow
private long timeReference;

@Shadow
protected abstract void updateMobSpawnOptions();

@Shadow
public abstract ServerWorld getOverworld();

@Shadow
protected abstract void runTasksTillTickEnd();

/**
* @author Steveplays28
* @reason Wait for the overworld's spawn chunk to be loaded.
*/
@Overwrite
private void prepareStartRegion(@NotNull WorldGenerationProgressListener worldGenerationProgressListener) {
@NotNull var overworld = this.getOverworld();
LOGGER.info("Preparing start region for dimension {}", overworld.getRegistryKey().getValue());
worldGenerationProgressListener.start();
this.timeReference = Util.getMeasuringTimeMs();

@NotNull var overworldSpawnChunkPosition = new ChunkPos(overworld.getSpawnPos());
overworld.getChunkManager().addTicket(ChunkTicketType.START, overworldSpawnChunkPosition, START_TICKET_CHUNK_RADIUS, Unit.INSTANCE);

@NotNull var noisiumServerWorldChunkManager = ((ServerWorldExtension) overworld).noisiumchunkmanager$getServerWorldChunkManager();
while (!noisiumServerWorldChunkManager.isChunkLoaded(overworldSpawnChunkPosition)) {
this.timeReference = Util.getMeasuringTimeMs() + 10L;
this.runTasksTillTickEnd();
}

worldGenerationProgressListener.stop();
this.updateMobSpawnOptions();
}

@Redirect(method = "shutdown", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;anyMatch(Ljava/util/function/Predicate;)Z"))
private boolean noisiumchunkmanager$shutdownRedirectThreadedAnvilChunkStorageShouldDelayShutdown(@NotNull Stream<ServerWorld> instance, @NotNull Predicate<? super T> predicate) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.github.steveplays28.noisiumchunkmanager.mixin.server;

import io.github.steveplays28.noisiumchunkmanager.server.world.chunk.event.ServerChunkEvent;
import net.minecraft.server.WorldGenerationProgressLogger;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.chunk.ChunkStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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;

@Mixin(WorldGenerationProgressLogger.class)
public abstract class WorldGenerationProgressLoggerMixin {
@Shadow
public abstract void setChunkStatus(@NotNull ChunkPos chunkPosition, @Nullable ChunkStatus chunkStatus);

@Inject(method = "<init>", at = @At(value = "TAIL"))
private void noisiumchunkmanager$registerEventListeners(@NotNull CallbackInfo ci) {
ServerChunkEvent.WORLD_CHUNK_GENERATED.register(worldChunk -> this.setChunkStatus(worldChunk.getPos(), worldChunk.getStatus()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ private void moveToSpawn(@NotNull ServerWorld serverWorld) {
if (serverWorld.isSpaceEmpty(this)) {
break;
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import net.minecraft.registry.RegistryKeys;
import net.minecraft.server.WorldGenerationProgressListener;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ChunkTicketType;
import net.minecraft.server.world.ServerChunkManager;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.server.world.ThreadedAnvilChunkStorage;
Expand Down Expand Up @@ -235,4 +236,23 @@ public abstract class ServerChunkManagerMixin {
private void noisiumchunkmanager$cancelApplyViewAndSimulationDistance(int distance, @NotNull CallbackInfo ci) {
ci.cancel();
}

@Inject(method = "addTicket", at = @At(value = "HEAD"), cancellable = true)
private void noisiumchunkmanager$loadChunksInTicketRadius(@NotNull ChunkTicketType<?> ticketType, @NotNull ChunkPos chunkPosition, int radius, Object argument, @NotNull CallbackInfo ci) {
if (ticketType.getExpiryTicks() != 0L) {
ci.cancel();
return;
}

((ServerWorldExtension) this.getWorld()).noisiumchunkmanager$getServerWorldChunkManager().getChunksInRadiusAsync(
chunkPosition, radius);
ci.cancel();
}

@Inject(method = "removeTicket", at = @At(value = "HEAD"), cancellable = true)
private void noisiumchunkmanager$unloadChunksInTicketRadius(@NotNull ChunkTicketType<?> ticketType, @NotNull ChunkPos chunkPosition, int radius, Object argument, @NotNull CallbackInfo ci) {
// ((ServerWorldExtension) this.getWorld()).noisiumchunkmanager$getServerWorldChunkManager().unloadChunk(
// chunkPosition, radius);
ci.cancel();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.Semaphore;

@Mixin(PalettedContainer.class)
public class PalettedContainerMixin {
Expand All @@ -19,7 +18,7 @@ public class PalettedContainerMixin {
private LockHelper lockHelper;

@Unique
private final Lock noisiumchunkmanager$lock = new ReentrantLock();
private final Semaphore noisiumchunkmanager$lock = new Semaphore(1);

@Inject(
method = {
Expand All @@ -39,7 +38,7 @@ public void removeLockHelper(@NotNull CallbackInfo ci) {
*/
@Overwrite
public void lock() {
noisiumchunkmanager$lock.lock();
noisiumchunkmanager$lock.acquireUninterruptibly();
}

/**
Expand All @@ -48,6 +47,6 @@ public void lock() {
*/
@Overwrite
public void unlock() {
noisiumchunkmanager$lock.unlock();
noisiumchunkmanager$lock.release();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,8 @@ public ServerWorldChunkManager(@NotNull ServerWorld serverWorld, @NotNull ChunkG
* @param radius A square radius of chunks.
* @return All the {@link WorldChunk}s around the specified chunk, using a square radius.
*/
public @NotNull Map<@NotNull ChunkPos, @Nullable CompletableFuture<WorldChunk>> getChunksInRadiusAsync(@NotNull ChunkPos chunkPos, int radius) {
var chunks = new HashMap<@NotNull ChunkPos, @Nullable CompletableFuture<WorldChunk>>();

public @NotNull Map<ChunkPos, CompletableFuture<WorldChunk>> getChunksInRadiusAsync(@NotNull ChunkPos chunkPos, int radius) {
@NotNull var chunks = new HashMap<ChunkPos, CompletableFuture<WorldChunk>>();
for (int chunkPosX = chunkPos.x - radius; chunkPosX < chunkPos.x + radius; chunkPosX++) {
for (int chunkPosZ = chunkPos.z - radius; chunkPosZ < chunkPos.z + radius; chunkPosZ++) {
var chunkPosThatShouldBeLoaded = new ChunkPos(chunkPosX, chunkPosZ);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
"accessor.util.collection.PackedIntegerArrayAccessor",
"accessor.world.gen.chunk.ChunkGeneratorAccessor",
"block.LichenGrowerGrowCheckerMixin",
"client.gui.WorldGenerationProgressTrackerMixin",
"compat.distanthorizons.common.wrappers.world.gen.DHBatchGenerationEnvironmentMixin",
"server.MinecraftServerMixin",
"server.WorldGenerationProgressLoggerMixin",
"server.network.ServerPlayerEntityMixin",
"server.network.SpawnLocatingMixin",
"server.world.ServerChunkManagerMixin",
Expand Down

0 comments on commit 90652b6

Please sign in to comment.