diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ChunkHolderMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ChunkHolderMixin.java index fc99003..3bbeb2a 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ChunkHolderMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ChunkHolderMixin.java @@ -66,6 +66,9 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy @Unique private final ReferenceList playersSentChunkTo = new ReferenceList<>(EMPTY_PLAYER_ARRAY); + @Unique + private boolean isMarkedDirtyForPlayers; + @Unique private ChunkMap getChunkMap() { return (ChunkMap)this.playerProvider; @@ -120,6 +123,16 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy return ret; } + @Override + public final boolean moonrise$isMarkedDirtyForPlayers() { + return this.isMarkedDirtyForPlayers; + } + + @Override + public final void moonrise$markDirtyForPlayers(final boolean value) { + this.isMarkedDirtyForPlayers = value; + } + @Unique private static final ServerPlayer[] EMPTY_PLAYER_ARRAY = new ServerPlayer[0]; @@ -287,7 +300,14 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy // no players to sent to, so don't need to update anything return null; } - return this.getChunkToSend(); + final LevelChunk ret = this.getChunkToSend(); + + if (ret != null) { + ((ChunkSystemServerLevel)this.getChunkMap().level).moonrise$addUnsyncedChunk((ChunkHolder)(Object)this); + return ret; + } + + return ret; } /** @@ -302,7 +322,18 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy ) ) private LevelChunk redirectLightUpdate(final ChunkHolder instance) { - return this.getChunkToSend(); + if (this.playersSentChunkTo.size() == 0) { + // no players to sent to, so don't need to update anything + return null; + } + final LevelChunk ret = this.getChunkToSend(); + + if (ret != null) { + ((ChunkSystemServerLevel)this.getChunkMap().level).moonrise$addUnsyncedChunk((ChunkHolder)(Object)this); + return ret; + } + + return ret; } /** diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerChunkCacheMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerChunkCacheMixin.java index 6b9a76f..c95b09d 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerChunkCacheMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerChunkCacheMixin.java @@ -3,6 +3,7 @@ package ca.spottedleaf.moonrise.mixin.chunk_system; import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable; import ca.spottedleaf.concurrentutil.util.Priority; import ca.spottedleaf.moonrise.common.PlatformHooks; +import ca.spottedleaf.moonrise.common.list.ReferenceList; import ca.spottedleaf.moonrise.common.util.CoordinateUtils; import ca.spottedleaf.moonrise.common.util.TickThread; import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel; @@ -33,6 +34,8 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.io.IOException; +import java.util.List; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -357,4 +360,35 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS private boolean shortShouldTickBlocks(final ServerLevel instance, final long pos) { return true; } + + /** + * @reason Since chunks in non-simulation range are only brought up to FULL status, not TICKING, + * those chunks may not be present in the ticking list and as a result we need to use our own list + * to ensure these chunks broadcast changes + * @author Spottedleaf + */ + @Redirect( + method = "tickChunks", + at = @At( + value = "INVOKE", + target = "Ljava/util/List;forEach(Ljava/util/function/Consumer;)V" + ) + ) + private void fixBroadcastChanges(final List instance, + final Consumer consumer) { + final ReferenceList unsyncedChunks = ((ChunkSystemServerLevel)this.level).moonrise$getUnsyncedChunks(); + final ChunkHolder[] chunkHolders = unsyncedChunks.getRawDataUnchecked(); + final int totalUnsyncedChunks = unsyncedChunks.size(); + + Objects.checkFromToIndex(0, totalUnsyncedChunks, chunkHolders.length); + for (int i = 0; i < totalUnsyncedChunks; ++i) { + final ChunkHolder chunkHolder = chunkHolders[i]; + final LevelChunk chunk = chunkHolder.getChunkToSend(); + if (chunk != null) { + chunkHolder.broadcastChanges(chunk); + } + } + + ((ChunkSystemServerLevel)this.level).moonrise$clearUnsyncedChunks(); + } } diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerLevelMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerLevelMixin.java index 144c510..37d3ba9 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerLevelMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerLevelMixin.java @@ -10,6 +10,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityData import ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.PoiDataController; import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevelReader; import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel; +import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder; import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup; import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader; import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager; @@ -26,6 +27,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.RegistryAccess; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.DistanceManager; import net.minecraft.server.level.ServerChunkCache; @@ -62,6 +64,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.io.Writer; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.UUID; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; @@ -120,6 +123,9 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel, @Unique private static final ServerChunkCache.ChunkAndHolder[] EMPTY_CHUNK_AND_HOLDERS = new ServerChunkCache.ChunkAndHolder[0]; + @Unique + private static final ChunkHolder[] EMPTY_CHUNK_HOLDERS = new ChunkHolder[0]; + @Unique private final ReferenceList loadedChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS); @@ -129,6 +135,9 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel, @Unique private final ReferenceList entityTickingChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS); + @Unique + private final ReferenceList unsyncedChunks = new ReferenceList<>(EMPTY_CHUNK_HOLDERS); + /** * @reason Initialise fields / destroy entity manager state * @author Spottedleaf @@ -345,6 +354,45 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel, return this.entityTickingChunks; } + @Override + public final ReferenceList moonrise$getUnsyncedChunks() { + return this.unsyncedChunks; + } + + @Override + public final void moonrise$addUnsyncedChunk(final ChunkHolder chunkHolder) { + if (((ChunkSystemChunkHolder)chunkHolder).moonrise$isMarkedDirtyForPlayers()) { + return; + } + + ((ChunkSystemChunkHolder)chunkHolder).moonrise$markDirtyForPlayers(true); + this.unsyncedChunks.add(chunkHolder); + } + + @Override + public final void moonrise$removeUnsyncedChunk(final ChunkHolder chunkHolder) { + if (!((ChunkSystemChunkHolder)chunkHolder).moonrise$isMarkedDirtyForPlayers()) { + return; + } + + ((ChunkSystemChunkHolder)chunkHolder).moonrise$markDirtyForPlayers(false); + this.unsyncedChunks.remove(chunkHolder); + } + + @Override + public final void moonrise$clearUnsyncedChunks() { + final ChunkHolder[] chunkHolders = this.unsyncedChunks.getRawDataUnchecked(); + final int totalUnsyncedChunks = this.unsyncedChunks.size(); + + Objects.checkFromToIndex(0, totalUnsyncedChunks, chunkHolders.length); + for (int i = 0; i < totalUnsyncedChunks; ++i) { + final ChunkHolder chunkHolder = chunkHolders[i]; + + ((ChunkSystemChunkHolder)chunkHolder).moonrise$markDirtyForPlayers(false); + } + this.unsyncedChunks.clear(); + } + @Override public final boolean moonrise$areChunksLoaded(final int fromX, final int fromZ, final int toX, final int toZ) { final ServerChunkCache chunkSource = this.chunkSource; diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_tick_iteration/ServerChunkCacheMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_tick_iteration/ServerChunkCacheMixin.java index db34375..3ff75d1 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_tick_iteration/ServerChunkCacheMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_tick_iteration/ServerChunkCacheMixin.java @@ -24,9 +24,12 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Objects; @@ -42,6 +45,9 @@ abstract class ServerChunkCacheMixin extends ChunkSource { @Unique private ServerChunkCache.ChunkAndHolder[] iterationCopy; + @Unique + private int iterationCopyLen; + @Unique private final SimpleRandom shuffleRandom = new SimpleRandom(0L); @@ -83,6 +89,7 @@ abstract class ServerChunkCacheMixin extends ChunkSource { if (this.iterationCopy == null || this.iterationCopy.length < size) { this.iterationCopy = new ServerChunkCache.ChunkAndHolder[raw.length]; } + this.iterationCopyLen = size; System.arraycopy(raw, 0, this.iterationCopy, 0, size); return ObjectArrayList.wrap( @@ -135,7 +142,7 @@ abstract class ServerChunkCacheMixin extends ChunkSource { ) ) private boolean useNearbyCache(final ChunkMap instance, final ChunkPos chunkPos, - @Local(ordinal = 0, argsOnly = false) final LevelChunk levelChunk) { + @Local(ordinal = 0, argsOnly = false) final LevelChunk levelChunk) { final ChunkData chunkData = ((ChunkSystemChunkHolder)((ChunkSystemLevelChunk)levelChunk).moonrise$getChunkAndHolder().holder()) .moonrise$getRealChunkHolder().holderData; @@ -164,29 +171,19 @@ abstract class ServerChunkCacheMixin extends ChunkSource { } /** - * @reason Clear the iteration array, and at the same time broadcast chunk changes. + * @reason Clear the iteration array after the list is done being used. * @author Spottedleaf */ - @Redirect( + @Inject( method = "tickChunks", at = @At( value = "INVOKE", target = "Ljava/util/List;forEach(Ljava/util/function/Consumer;)V", - ordinal = 0 + ordinal = 0, + shift = At.Shift.AFTER ) ) - private void broadcastChanges(final List instance, - final Consumer consumer) { - final ObjectArrayList chunks = (ObjectArrayList)instance; - final ServerChunkCache.ChunkAndHolder[] raw = chunks.elements(); - final int size = chunks.size(); - - Objects.checkFromToIndex(0, size, raw.length); - for (int i = 0; i < size; ++i) { - final ServerChunkCache.ChunkAndHolder holder = raw[i]; - raw[i] = null; - - holder.holder().broadcastChanges(holder.chunk()); - } + private void broadcastChanges(final CallbackInfo ci) { + Arrays.fill(this.iterationCopy, 0, this.iterationCopyLen, null); } } diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemServerLevel.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemServerLevel.java index 39a2755..0fb7377 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemServerLevel.java +++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemServerLevel.java @@ -7,6 +7,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader; import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler; import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.status.ChunkStatus; @@ -60,4 +61,12 @@ public interface ChunkSystemServerLevel extends ChunkSystemLevel { public ReferenceList moonrise$getTickingChunks(); public ReferenceList moonrise$getEntityTickingChunks(); + + public ReferenceList moonrise$getUnsyncedChunks(); + + public void moonrise$addUnsyncedChunk(final ChunkHolder chunkHolder); + + public void moonrise$removeUnsyncedChunk(final ChunkHolder chunkHolder); + + public void moonrise$clearUnsyncedChunks(); } diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/chunk/ChunkSystemChunkHolder.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/chunk/ChunkSystemChunkHolder.java index 7d049d7..ba9111f 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/chunk/ChunkSystemChunkHolder.java +++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/chunk/ChunkSystemChunkHolder.java @@ -23,4 +23,8 @@ public interface ChunkSystemChunkHolder { public LevelChunk moonrise$getFullChunk(); + public boolean moonrise$isMarkedDirtyForPlayers(); + + public void moonrise$markDirtyForPlayers(final boolean value); + } diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java index b74ec68..1cacbf4 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java +++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java @@ -760,6 +760,7 @@ public final class NewChunkHolder { void onUnload() { this.unloaded = true; + ((ChunkSystemServerLevel)this.world).moonrise$removeUnsyncedChunk(this.vanillaChunkHolder); ((ChunkSystemLevel)this.world).moonrise$releaseChunkData(CoordinateUtils.getChunkKey(this.chunkX, this.chunkZ)); }