Skip to content

Commit

Permalink
Add relight command
Browse files Browse the repository at this point in the history
This is simply for feature parity with Paper.
  • Loading branch information
Spottedleaf committed Jun 18, 2024
1 parent 240faf5 commit ac971be
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
package ca.spottedleaf.moonrise.mixin.starlight.lightengine;

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.scheduling.ChunkTaskScheduler;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
import ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface;
import ca.spottedleaf.moonrise.patches.starlight.light.StarLightLightingProvider;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkTaskPriorityQueueSorter;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.util.thread.ProcessorHandle;
import net.minecraft.util.thread.ProcessorMailbox;
import net.minecraft.world.level.ChunkPos;
Expand All @@ -24,8 +33,17 @@
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.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
import java.util.function.IntSupplier;
import java.util.function.Supplier;

Expand Down Expand Up @@ -78,6 +96,85 @@ private void queueTaskForSection(final int chunkX, final int chunkY, final int c
});
}

@Override
public final int starlight$serverRelightChunks(final Collection<ChunkPos> chunks0,
final Consumer<ChunkPos> chunkLightCallback,
final IntConsumer onComplete) {
final Set<ChunkPos> chunks = new LinkedHashSet<>(chunks0);
final Map<ChunkPos, Long> ticketIds = new HashMap<>();
final ServerLevel world = (ServerLevel)this.starlight$getLightEngine().getWorld();

for (final Iterator<ChunkPos> iterator = chunks.iterator(); iterator.hasNext();) {
final ChunkPos pos = iterator.next();

final Long id = ChunkTaskScheduler.getNextChunkRelightId();
world.getChunkSource().addRegionTicket(ChunkTaskScheduler.CHUNK_RELIGHT, pos, StarLightInterface.REGION_LIGHT_TICKET_LEVEL, id);
ticketIds.put(pos, id);

final ChunkAccess chunk = (ChunkAccess)world.getChunkSource().getChunkForLighting(pos.x, pos.z);
if (chunk == null || !chunk.isLightCorrect() || !chunk.getPersistedStatus().isOrAfter(ChunkStatus.LIGHT)) {
// cannot relight this chunk
iterator.remove();
ticketIds.remove(pos);
world.getChunkSource().removeRegionTicket(ChunkTaskScheduler.CHUNK_RELIGHT, pos, StarLightInterface.REGION_LIGHT_TICKET_LEVEL, id);
continue;
}
}

((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().radiusAwareScheduler.queueInfiniteRadiusTask(() -> {
ThreadedLevelLightEngineMixin.this.starlight$getLightEngine().relightChunks(
chunks,
(final ChunkPos pos) -> {
if (chunkLightCallback != null) {
chunkLightCallback.accept(pos);
}

((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().scheduleChunkTask(pos.x, pos.z, () -> {
final NewChunkHolder chunkHolder = ((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(
pos.x, pos.z
);

if (chunkHolder == null) {
return;
}

final List<ServerPlayer> players = ((ChunkSystemChunkHolder)chunkHolder.vanillaChunkHolder).moonrise$getPlayers(false);

if (players.isEmpty()) {
return;
}

final Packet<?> relightPacket = new ClientboundLightUpdatePacket(
pos, (ThreadedLevelLightEngine)(Object)ThreadedLevelLightEngineMixin.this,
null, null
);

for (final ServerPlayer player : players) {
final ServerGamePacketListenerImpl conn = player.connection;
if (conn != null) {
conn.send(relightPacket);
}
}
});
},
(final int relight) -> {
if (onComplete != null) {
onComplete.accept(relight);
}

for (final Map.Entry<ChunkPos, Long> entry : ticketIds.entrySet()) {
world.getChunkSource().removeRegionTicket(
ChunkTaskScheduler.CHUNK_RELIGHT, entry.getKey(),
StarLightInterface.REGION_LIGHT_TICKET_LEVEL, entry.getValue()
);
}
}
);
});

return chunks.size();
}

/**
* @reason Destroy old chunk system hook
* @author Spottedleaf
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
import ca.spottedleaf.moonrise.patches.chunk_system.util.ParallelSearchRadiusIteration;
import com.google.gson.JsonObject;
import it.unimi.dsi.fastutil.HashCommon;
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongArrayList;
Expand Down Expand Up @@ -58,7 +59,7 @@ public final class RegionizedPlayerChunkLoader {
public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY);
public static final int TICK_TICKET_LEVEL = ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL;

public static class ViewDistanceHolder {
public static final class ViewDistanceHolder {

private volatile ViewDistances viewDistances;
private static final VarHandle VIEW_DISTANCES_HANDLE = ConcurrentUtil.getVarHandle(ViewDistanceHolder.class, "viewDistances", ViewDistances.class);
Expand Down Expand Up @@ -106,6 +107,10 @@ public void setSendViewDistance(final int distance) {
return param.setTickViewDistance(distance);
});
}

public JsonObject toJson() {
return this.getViewDistances().toJson();
}
}

public static final record ViewDistances(
Expand All @@ -124,6 +129,16 @@ public ViewDistances setLoadViewDistance(final int distance) {
public ViewDistances setSendViewDistance(final int distance) {
return new ViewDistances(this.tickViewDistance, this.loadViewDistance, distance);
}

public JsonObject toJson() {
final JsonObject ret = new JsonObject();

ret.addProperty("tick-view-distance", this.tickViewDistance);
ret.addProperty("load-view-distance", this.loadViewDistance);
ret.addProperty("send-view-distance", this.sendViewDistance);

return ret;
}
}

public static int getAPITickViewDistance(final ServerPlayer player) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1282,7 +1282,6 @@ static List<ChunkProgressionTask> getCurrentTicketUpdateScheduling() {
}

private boolean processTicketUpdates(final boolean processFullUpdates, List<ChunkProgressionTask> scheduledTasks) {
TickThread.ensureTickThread("Cannot process ticket levels off-main");
if (BLOCK_TICKET_UPDATES.get() == Boolean.TRUE) {
throw new IllegalStateException("Cannot update ticket level while unloading chunks or updating entity manager");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ public static Long getNextPoiLoadId() {
return Long.valueOf(POI_LOAD_IDS.getAndIncrement());
}

public static final TicketType<Long> CHUNK_RELIGHT = TicketType.create("starlight:chunk_relight", Long::compareTo);
private static final AtomicLong CHUNK_RELIGHT_IDS = new AtomicLong();

public static Long getNextChunkRelightId() {
return Long.valueOf(CHUNK_RELIGHT_IDS.getAndIncrement());
}


public static int getTicketLevel(final ChunkStatus status) {
return ChunkLevel.byStatus(status);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import java.util.Arrays;
import java.util.Objects;

public class ParallelSearchRadiusIteration {
public final class ParallelSearchRadiusIteration {

// expected that this list returns for a given radius, the set of chunks ordered
// by manhattan distance
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
package ca.spottedleaf.moonrise.patches.command;

import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
import ca.spottedleaf.moonrise.common.util.MoonriseConstants;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
import ca.spottedleaf.moonrise.patches.starlight.light.StarLightLightingProvider;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.context.CommandContext;
import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.contents.PlainTextContents;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ImposterProtoChunk;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.phys.Vec3;
import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

public final class MoonriseCommand {

Expand All @@ -38,6 +51,17 @@ public static void register(final CommandDispatcher<CommandSourceStack> dispatch
.executes((final CommandContext<CommandSourceStack> ctx) -> {
return MoonriseCommand.reload(ctx);
})
).then(
Commands.literal("relight")
.executes((final CommandContext<CommandSourceStack> ctx) -> {
return MoonriseCommand.relight(ctx, 10);
})
.then(
Commands.argument("radius", IntegerArgumentType.integer(0, MoonriseConstants.MAX_VIEW_DISTANCE))
.executes((final CommandContext<CommandSourceStack> ctx) -> {
return MoonriseCommand.relight(ctx, IntegerArgumentType.getInteger(ctx, "radius"));
})
)
)
);
}
Expand Down Expand Up @@ -151,4 +175,67 @@ public static int reload(final CommandContext<CommandSourceStack> ctx) {

return 0;
}

public static int relight(final CommandContext<CommandSourceStack> ctx, final int radius) {
final Vec3 center = ctx.getSource().getPosition();

final int centerChunkX = Mth.floor(center.x) >> 4;
final int centerChunkZ = Mth.floor(center.z) >> 4;

final List<ChunkPos> chunks = new ArrayList<>();

final LongOpenHashSet seen = new LongOpenHashSet();
final LongArrayFIFOQueue queue = new LongArrayFIFOQueue();

final long zero = CoordinateUtils.getChunkKey(0, 0);

seen.add(zero);
queue.enqueue(zero);
chunks.add(new ChunkPos(centerChunkX, centerChunkZ));

final int[][] offsets = new int[][] {
new int[] { -1, 0 },
new int[] { 1, 0 },
new int[] { 0, -1 },
new int[] { 0, 1 }
};

while (!queue.isEmpty()) {
final long chunk = queue.dequeueLong();
final int chunkX = CoordinateUtils.getChunkX(chunk);
final int chunkZ = CoordinateUtils.getChunkZ(chunk);

for (final int[] offset : offsets) {
final int neighbourX = chunkX + offset[0];
final int neighbourZ = chunkZ + offset[1];
final long neighbour = CoordinateUtils.getChunkKey(neighbourX, neighbourZ);

final int dist = Math.max(Math.abs(neighbourX), Math.abs(neighbourZ));

if (dist > radius || !seen.add(neighbour)) {
continue;
}

queue.enqueue(neighbour);
chunks.add(new ChunkPos(neighbourX + centerChunkX, neighbourZ + centerChunkZ));
}
}


final int ret = ((StarLightLightingProvider)ctx.getSource().getLevel().getLightEngine()).starlight$serverRelightChunks(
chunks,
null,
null
);

ctx.getSource().sendSuccess(() -> {
return MutableComponent.create(
new PlainTextContents.LiteralContents(
"Relighting " + ret + " chunks"
)
);
}, true);

return ret;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.chunk.DataLayer;
import net.minecraft.world.level.chunk.LevelChunk;
import java.util.Collection;
import java.util.function.Consumer;
import java.util.function.IntConsumer;

public interface StarLightLightingProvider {

Expand All @@ -17,4 +20,10 @@ public interface StarLightLightingProvider {

public void starlight$clientChunkLoad(final ChunkPos pos, final LevelChunk chunk);

public default int starlight$serverRelightChunks(final Collection<ChunkPos> chunks,
final Consumer<ChunkPos> chunkLightCallback,
final IntConsumer onComplete) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

}

0 comments on commit ac971be

Please sign in to comment.