Track broadcast chunks separately from player ticking chunks
Not all broadcast chunks are ticking in the new chunk system, so we need to track them separately to ensure updates take place in non-simulation range chunks.
This commit is contained in:
@@ -66,6 +66,9 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy
|
||||
@Unique
|
||||
private final ReferenceList<ServerPlayer> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<ServerChunkCache.ChunkAndHolder> instance,
|
||||
final Consumer<ServerChunkCache.ChunkAndHolder> consumer) {
|
||||
final ReferenceList<ChunkHolder> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ServerChunkCache.ChunkAndHolder> loadedChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS);
|
||||
|
||||
@@ -129,6 +135,9 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
||||
@Unique
|
||||
private final ReferenceList<ServerChunkCache.ChunkAndHolder> entityTickingChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS);
|
||||
|
||||
@Unique
|
||||
private final ReferenceList<ChunkHolder> 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<ChunkHolder> 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;
|
||||
|
||||
@@ -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(
|
||||
@@ -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<ServerChunkCache.ChunkAndHolder> instance,
|
||||
final Consumer<ServerChunkCache.ChunkAndHolder> consumer) {
|
||||
final ObjectArrayList<ServerChunkCache.ChunkAndHolder> chunks = (ObjectArrayList<ServerChunkCache.ChunkAndHolder>)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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ServerChunkCache.ChunkAndHolder> moonrise$getTickingChunks();
|
||||
|
||||
public ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getEntityTickingChunks();
|
||||
|
||||
public ReferenceList<ChunkHolder> moonrise$getUnsyncedChunks();
|
||||
|
||||
public void moonrise$addUnsyncedChunk(final ChunkHolder chunkHolder);
|
||||
|
||||
public void moonrise$removeUnsyncedChunk(final ChunkHolder chunkHolder);
|
||||
|
||||
public void moonrise$clearUnsyncedChunks();
|
||||
}
|
||||
|
||||
@@ -23,4 +23,8 @@ public interface ChunkSystemChunkHolder {
|
||||
|
||||
public LevelChunk moonrise$getFullChunk();
|
||||
|
||||
public boolean moonrise$isMarkedDirtyForPlayers();
|
||||
|
||||
public void moonrise$markDirtyForPlayers(final boolean value);
|
||||
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user