Skip to content

Commit

Permalink
new: scalable no-tick view distance, allowing usable 300+ render dist…
Browse files Browse the repository at this point in the history
…ances

Squashed commit of the following:

commit b3aecca
Author: ishland <[email protected]>
Date:   Mon Nov 18 19:59:21 2024 +0800

    feat: scalable notickvd
  • Loading branch information
ishland committed Nov 22, 2024
1 parent a689b15 commit 9443136
Show file tree
Hide file tree
Showing 18 changed files with 415 additions and 405 deletions.
12 changes: 12 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,19 @@ configure (allprojects - project(":tests")) {
implementation "org.jctools:jctools-core:${jctools_version}"
implementation annotationProcessor("com.github.bawnorton.mixinsquared:mixinsquared-fabric:${mixinsquared_version}")
api "com.ishland.flowsched:flowsched"

testImplementation platform("org.junit:junit-bom:${junit_version}")
testImplementation 'org.junit.jupiter:junit-jupiter'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
testImplementation "net.fabricmc:fabric-loader-junit:${project.loader_version}"
}

test {
useJUnitPlatform()
workingDir getLayout().buildDirectory
}

jar.dependsOn test
}

subprojects {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import net.minecraft.server.world.ChunkTicket;
import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.util.collection.SortedArraySet;
import net.minecraft.world.SimulationDistanceLevelPropagator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
Expand All @@ -26,4 +27,7 @@ public interface IChunkTicketManager {
@Accessor
ChunkTicketManager.NearbyChunkTicketUpdater getNearbyChunkTicketUpdater();

@Accessor
SimulationDistanceLevelPropagator getSimulationDistanceTracker();

}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import it.unimi.dsi.fastutil.longs.LongSet;

public interface IChunkTicketManager {
public interface ChunkTicketManagerExtension {

LongSet getNoTickOnlyChunks();

int getNoTickPendingTicketUpdates();
long getPendingLoadsCount();

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,7 @@ Requires Fabric API (currently %s)
" This will send chunks twice increasing network load")
.getBoolean(false, true);

public static final long maxViewDistance = new ConfigSystem.ConfigAccessor()
.key("noTickViewDistance.maxViewDistance")
.comment("""
Maximum view distance for no-tick view distance\s
This allows you to specify the maximum view distance that no-tick view distance can support.\s
The maximum supported is 1073741823 and the minimum that make sense is 32,\s
This option is purely to save memory, as it needs to reserve memory for the maximum view distance\s
Note: on the client side, `clientSideConfig.modifyMaxVDConfig.maxViewDistance` should also\s
be increased to actually expose the view distance in video settings\s
""")
.getLong(2048, 2048, ConfigSystem.LongChecks.POSITIVE_VALUES_ONLY);
public static final int maxViewDistance = 1 << 16;

public static void init() {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,61 +1,47 @@
package com.ishland.c2me.notickvd.common;

import com.ishland.c2me.base.common.GlobalExecutors;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.longs.LongSets;
import net.minecraft.server.world.ChunkTicket;
import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.server.world.ServerChunkLoadingManager;
import net.minecraft.util.math.ChunkPos;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;

public class NoTickSystem {

private final PlayerNoTickDistanceMap playerNoTickDistanceMap;
private final NormalTicketDistanceMap normalTicketDistanceMap;
private final ChunkTicketManager chunkTicketManager;

private final PlayerNoTickLoader playerNoTickLoader;
private final ConcurrentLinkedQueue<Runnable> pendingActionsOnScheduler = new ConcurrentLinkedQueue<>();
final ConcurrentLinkedQueue<Runnable> mainBeforeTicketTicks = new ConcurrentLinkedQueue<>();
final ConcurrentLinkedQueue<Runnable> mainAfterTicketTicks = new ConcurrentLinkedQueue<>();

private final AtomicBoolean isTicking = new AtomicBoolean();
final Executor executor = GlobalExecutors.asyncScheduler;
private volatile LongSet noTickOnlyChunksSnapshot = LongSets.EMPTY_SET;
private volatile boolean pendingPurge = false;
private volatile long age = 0;

public NoTickSystem(ChunkTicketManager chunkTicketManager) {
this.chunkTicketManager = chunkTicketManager;
this.playerNoTickDistanceMap = new PlayerNoTickDistanceMap(chunkTicketManager, this);
this.normalTicketDistanceMap = new NormalTicketDistanceMap(chunkTicketManager);
}

public void onTicketAdded(long position, ChunkTicket<?> ticket) {
this.pendingActionsOnScheduler.add(() -> this.normalTicketDistanceMap.addTicket(position, ticket));
}

public void onTicketRemoved(long position, ChunkTicket<?> ticket) {
this.pendingActionsOnScheduler.add(() -> this.normalTicketDistanceMap.removeTicket(position, ticket));
this.playerNoTickLoader = new PlayerNoTickLoader(chunkTicketManager, this);
}

public void addPlayerSource(ChunkPos chunkPos) {
this.pendingActionsOnScheduler.add(() -> this.playerNoTickDistanceMap.addSource(chunkPos));
this.pendingActionsOnScheduler.add(() -> this.playerNoTickLoader.addSource(chunkPos));
}

public void removePlayerSource(ChunkPos chunkPos) {
this.pendingActionsOnScheduler.add(() -> this.playerNoTickDistanceMap.removeSource(chunkPos));
this.pendingActionsOnScheduler.add(() -> this.playerNoTickLoader.removeSource(chunkPos));
}

public void setNoTickViewDistance(int viewDistance) {
this.pendingActionsOnScheduler.add(() -> this.playerNoTickDistanceMap.setViewDistance(viewDistance));
this.pendingActionsOnScheduler.add(() -> this.playerNoTickLoader.setViewDistance(viewDistance));
}

public void beforeTicketTicks() {
Expand All @@ -80,38 +66,20 @@ private void scheduleTick(ServerChunkLoadingManager tacs) {
}
}
executor.execute(() -> {
for (Runnable task : tasks) {
try {
task.run();
} catch (Throwable t) {
t.printStackTrace();
try {
for (Runnable task : tasks) {
try {
task.run();
} catch (Throwable t) {
t.printStackTrace();
}
}
}

boolean hasNoTickTicketUpdates;
if (pendingPurge) {
this.normalTicketDistanceMap.purge(this.age);
hasNoTickTicketUpdates = this.playerNoTickDistanceMap.runPendingTicketUpdates(tacs);
} else {
hasNoTickTicketUpdates = false;
}

final boolean hasNormalTicketUpdates = this.normalTicketDistanceMap.update();
final boolean hasNoTickUpdates = this.playerNoTickDistanceMap.update();
if (hasNormalTicketUpdates || hasNoTickUpdates || hasNoTickTicketUpdates) {
final LongSet noTickChunks = this.playerNoTickDistanceMap.getChunks();
final LongSet normalChunks = this.normalTicketDistanceMap.getChunks();
final LongOpenHashSet longs = new LongOpenHashSet(noTickChunks.size() * 3 / 2);
final LongIterator iterator = noTickChunks.iterator();
while (iterator.hasNext()) {
final long chunk = iterator.nextLong();
if (normalChunks.contains(chunk)) continue;
longs.add(chunk);
}
this.noTickOnlyChunksSnapshot = LongSets.unmodifiable(longs);
this.playerNoTickLoader.tick(tacs);
if (!this.pendingActionsOnScheduler.isEmpty() || !tasks.isEmpty()) scheduleTick(tacs); // run more tasks
} finally {
this.isTicking.set(false);
}
this.isTicking.set(false);
if (hasNormalTicketUpdates || hasNoTickUpdates) scheduleTick(tacs); // run more tasks
});
}
}
Expand All @@ -133,10 +101,10 @@ public void runPurge(long age) {
}

public LongSet getNoTickOnlyChunksSnapshot() {
return this.noTickOnlyChunksSnapshot;
return null;
}

public int getPendingNoTickTicketUpdatesCount() {
return this.playerNoTickDistanceMap.getPendingTicketUpdatesCount();
public long getPendingLoadsCount() {
return this.playerNoTickLoader.getPendingLoadsCount();
}
}

This file was deleted.

Loading

0 comments on commit 9443136

Please sign in to comment.