Skip to content

Commit

Permalink
fix: Fix various issues with world generation
Browse files Browse the repository at this point in the history
  • Loading branch information
Steveplays28 committed Jun 23, 2024
1 parent 5c857c0 commit 1fad880
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import net.minecraft.util.math.ChunkSectionPos;
import net.minecraft.world.LightType;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkStatus;
import net.minecraft.world.chunk.WorldChunk;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
Expand Down Expand Up @@ -42,6 +44,14 @@ public abstract class ServerChunkManagerMixin {
ci.cancel();
}

// TODO: Fix infinite loop
@Inject(method = "getChunk(IILnet/minecraft/world/chunk/ChunkStatus;Z)Lnet/minecraft/world/chunk/Chunk;", at = @At(value = "HEAD"), cancellable = true)
private void noisium$getChunkFromNoisiumServerWorldChunkManager(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create, CallbackInfoReturnable<Chunk> cir) {
((NoisiumServerWorldExtension) this.getWorld()).noisium$getServerWorldChunkManager().getChunkAsync(
new ChunkPos(chunkX, chunkZ)
).whenComplete((worldChunk, throwable) -> cir.setReturnValue(worldChunk));
}

@Inject(method = "getWorldChunk", at = @At(value = "HEAD"), cancellable = true)
private void noisium$getWorldChunkFromNoisiumServerWorldChunkManager(int chunkX, int chunkZ, CallbackInfoReturnable<WorldChunk> cir) {
((NoisiumServerWorldExtension) this.getWorld()).noisium$getServerWorldChunkManager().getChunkAsync(
Expand Down Expand Up @@ -112,4 +122,15 @@ public abstract class ServerChunkManagerMixin {
NoisiumServerChunkEvent.LIGHT_UPDATE.invoker().onLightUpdate(lightType, chunkSectionPos);
ci.cancel();
}

@Inject(method = "save", at = @At(value = "HEAD"), cancellable = true)
private void noisium$cancelSave(boolean flush, CallbackInfo ci) {
ci.cancel();
}

@Inject(method = "isChunkLoaded", at = @At(value = "HEAD"), cancellable = true)
private void noisium$isChunkLoadedInNoisiumServerChunkManager(int chunkX, int chunkZ, CallbackInfoReturnable<Boolean> cir) {
cir.setReturnValue(((NoisiumServerWorldExtension) this.getWorld()).noisium$getServerWorldChunkManager().isChunkLoaded(
new ChunkPos(chunkX, chunkZ)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

// TODO: Disable vanilla's ServerEntityManager's save method
@Mixin(value = ServerEntityManager.class, priority = 500)
public class ServerEntityManagerMixin<T extends EntityLike> {
@Inject(method = "stopTracking", at = @At(value = "HEAD"), cancellable = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
import io.github.steveplays28.noisium.server.world.chunk.event.NoisiumServerChunkEvent;
import io.github.steveplays28.noisium.server.world.entity.NoisiumServerWorldEntityTracker;
import io.github.steveplays28.noisium.util.world.chunk.networking.packet.PacketUtil;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.WorldGenerationProgressListener;
import net.minecraft.server.world.ChunkLevelType;
import net.minecraft.server.world.ServerEntityManager;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.RandomSequencesState;
import net.minecraft.util.profiler.Profiler;
import net.minecraft.world.World;
Expand Down Expand Up @@ -59,7 +61,13 @@ public abstract class ServerWorldMixin implements NoisiumServerWorldExtension {

// TODO: Redo the server entity manager entirely, in an event-based way
// Also remove this line when that's done, since this doesn't belong here
PlayerEvent.PLAYER_JOIN.register(player -> this.entityManager.addEntity(player));
PlayerEvent.PLAYER_JOIN.register(player -> {
if (!player.getWorld().equals(serverWorld)) {
return;
}

this.entityManager.addEntity(player);
});

// TODO: Move this event listener registration to ServerEntityManagerMixin
// or (when it's finished and able to completely replace the vanilla class) to NoisiumServerWorldEntityTracker
Expand All @@ -79,6 +87,12 @@ public abstract class ServerWorldMixin implements NoisiumServerWorldExtension {
return this.entityManager.shouldTick(entity.getChunkPos());
}

@Inject(method = "onBlockChanged", at = @At(value = "HEAD"), cancellable = true)
private void noisium$redirectOnBlockChangedToNoisiumServerWorldChunkManager(BlockPos blockPos, BlockState oldBlockState, BlockState newBlockState, CallbackInfo ci) {
NoisiumServerChunkEvent.BLOCK_CHANGE.invoker().onBlockChange(blockPos, oldBlockState, newBlockState);
ci.cancel();
}

@Override
public NoisiumServerWorldChunkManager noisium$getServerWorldChunkManager() {
return noisium$serverWorldChunkManager;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package io.github.steveplays28.noisium.mixin.world.gen.chunk;

import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.server.network.DebugInfoSender;
import net.minecraft.structure.StructureStart;
import net.minecraft.util.crash.CrashException;
import net.minecraft.util.crash.CrashReport;
import net.minecraft.util.crash.CrashReportSection;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.ChunkSectionPos;
import net.minecraft.world.StructureWorldAccess;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkSection;
import net.minecraft.world.gen.StructureAccessor;
import net.minecraft.world.gen.chunk.ChunkGenerator;
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 java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Stream;

@Mixin(ChunkGenerator.class)
public class ChunkGeneratorMixin {
@WrapWithCondition(method = "generateFeatures", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;forEach(Ljava/util/function/Consumer;)V"))
private static boolean noisium$cancelChunkPosStreamToFixAnInfiniteLoop(Stream<ChunkPos> stream, Consumer<?> consumer) {
return false;
}

@Inject(method = "generateFeatures", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/ChunkPos;stream(Lnet/minecraft/util/math/ChunkPos;I)Ljava/util/stream/Stream;", shift = At.Shift.BEFORE))
private void noisium$addChunkSectionBiomeContainersToSet(StructureWorldAccess world, Chunk chunk, StructureAccessor structureAccessor, CallbackInfo ci, @Local Set<RegistryEntry<Biome>> set) {
for (ChunkSection chunkSection : chunk.getSectionArray()) {
chunkSection.getBiomeContainer().forEachValue(set::add);
}
}

/**
* Replaces {@link ChunkGenerator#addStructureReferences} with a simpler one, that only checks the center chunk, instead of iterating outwards.
* This fixes an infinite loop with {@link io.github.steveplays28.noisium.server.world.NoisiumServerWorldChunkManager}.
*/
@Inject(method = "addStructureReferences", at = @At(value = "HEAD"), cancellable = true)
public void noisium$replaceAddStructureReferencesToFixAnInfiniteLoop(StructureWorldAccess world, StructureAccessor structureAccessor, Chunk chunk, CallbackInfo ci) {
var chunkPos = chunk.getPos();
int chunkPosStartX = chunkPos.getStartX();
int chunkPosStartZ = chunkPos.getStartZ();
var chunkSectionPos = ChunkSectionPos.from(chunk);
var chunkPosLong = chunkPos.toLong();

for (StructureStart structureStart : chunk.getStructureStarts().values()) {
try {
if (structureStart.hasChildren() && structureStart.getBoundingBox().intersectsXZ(
chunkPosStartX, chunkPosStartZ, chunkPosStartX + 15, chunkPosStartZ + 15)
) {
structureAccessor.addStructureReference(chunkSectionPos, structureStart.getStructure(), chunkPosLong, chunk);
DebugInfoSender.sendStructureStart(world, structureStart);
}
} catch (Exception e) {
CrashReport crashReport = CrashReport.create(e, "Generating structure reference");
CrashReportSection crashReportSection = crashReport.addElement("Structure");
crashReportSection.add(
"Id",
() -> world.getRegistryManager().getOptional(RegistryKeys.STRUCTURE).map(
structureTypeRegistry -> {
var structureId = structureTypeRegistry.getId(structureStart.getStructure());
if (structureId == null) {
return "UNKNOWN";
}

return structureId.toString();
}
).orElse("UNKNOWN")
);
crashReportSection.add(
"Name",
() -> {
var structureTypeId = Registries.STRUCTURE_TYPE.getId(structureStart.getStructure().getType());
if (structureTypeId == null) {
return "UNKNOWN";
}

return structureTypeId.toString();
}
);
crashReportSection.add("Class", () -> structureStart.getStructure().getClass().getCanonicalName());
throw new CrashException(crashReport);
}
}

ci.cancel();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.github.steveplays28.noisium.mixin.world.gen.chunk;

import net.minecraft.world.gen.chunk.NoiseChunkGenerator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;

@Mixin(NoiseChunkGenerator.class)
public class NoiseChunkGeneratorMixin {
@ModifyConstant(method = "carve", constant = @Constant(intValue = 8))
private int noisium$modifyCarvingChunkRadiusPositiveToFixAnInfiniteLoop(int chunkRadius) {
return 0;
}

@ModifyConstant(method = "carve", constant = @Constant(intValue = -8))
private int noisium$modifyCarvingChunkRadiusNegativeToFixAnInfiniteLoop(int chunkRadius) {
return 0;
}
}
Loading

0 comments on commit 1fad880

Please sign in to comment.