Skip to content

Commit

Permalink
Add chunk unload delay so we can re-use them if we return
Browse files Browse the repository at this point in the history
  • Loading branch information
Johni0702 committed Mar 14, 2021
1 parent 0448e8d commit bcdbb94
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 10 deletions.
14 changes: 13 additions & 1 deletion src/main/java/de/johni0702/minecraft/bobby/BobbyConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,23 @@ public class BobbyConfig {
public static final BobbyConfig DEFAULT = new BobbyConfig();

private boolean enabled = true;
@Comment("Delays the unloading of chunks which are outside your view distance.\nSaves you from having to reload all chunks when leaving the area for a short moment (e.g. cut scenes).\nDoes not work across dimensions.")
private int unloadDelaySecs = 60;
@Comment("Changes the maximum value configurable for Render Distance.\n\nRequires Sodium.")
private int maxRenderDistance = 32;
@Comment("Overwrites the view-distance of the integrated server.\nThis allows Bobby to be useful in Singleplayer.\n\nDisabled when at 0.\nBobby is active in singleplayer only if this is enabled.\nRequires re-log to en-/disable.")
private int viewDistanceOverwrite = 0;

public BobbyConfig() {}

public BobbyConfig(boolean enabled, int maxRenderDistance, int viewDistanceOverwrite) {
public BobbyConfig(
boolean enabled,
int unloadDelaySecs,
int maxRenderDistance,
int viewDistanceOverwrite
) {
this.enabled = enabled;
this.unloadDelaySecs = unloadDelaySecs;
this.maxRenderDistance = maxRenderDistance;
this.viewDistanceOverwrite = viewDistanceOverwrite;
}
Expand All @@ -25,6 +33,10 @@ public boolean isEnabled() {
return enabled;
}

public int getUnloadDelaySecs() {
return unloadDelaySecs;
}

public int getMaxRenderDistance() {
return maxRenderDistance;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ public static Screen createConfigScreen(Screen parent, BobbyConfig config, Consu
.setDefaultValue(defaultConfig.isEnabled())
.build();

IntegerListEntry unloadDelaySecs = entryBuilder
.startIntField(new TranslatableText("option.bobby.unload_delay"), config.getUnloadDelaySecs())
.setTooltip(new TranslatableText("tooltip.option.bobby.unload_delay"))
.setDefaultValue(defaultConfig.getUnloadDelaySecs())
.build();

IntegerListEntry maxRenderDistance = entryBuilder
.startIntField(new TranslatableText("option.bobby.max_render_distance"), config.getMaxRenderDistance())
.setTooltip(new TranslatableText("tooltip.option.bobby.max_render_distance"))
Expand All @@ -41,11 +47,13 @@ public static Screen createConfigScreen(Screen parent, BobbyConfig config, Consu

ConfigCategory general = builder.getOrCreateCategory(new TranslatableText("category.bobby.general"));
general.addEntry(enabled);
general.addEntry(unloadDelaySecs);
general.addEntry(maxRenderDistance);
general.addEntry(viewDistanceOverwrite);

builder.setSavingRunnable(() -> update.accept(new BobbyConfig(
enabled.getValue(),
unloadDelaySecs.getValue(),
maxRenderDistance.getValue(),
viewDistanceOverwrite.getValue()
)));
Expand Down
53 changes: 44 additions & 9 deletions src/main/java/de/johni0702/minecraft/bobby/FakeChunkManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
import de.johni0702.minecraft.bobby.mixin.LightingProviderAccessor;
import de.johni0702.minecraft.bobby.mixin.sodium.SodiumChunkManagerAccessor;
import io.netty.util.concurrent.DefaultThreadFactory;
import it.unimi.dsi.fastutil.longs.Long2LongMap;
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
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.objects.ObjectIterator;
import me.jellysquid.mods.sodium.client.world.ChunkStatusListener;
import me.jellysquid.mods.sodium.client.world.SodiumChunkManager;
Expand Down Expand Up @@ -50,6 +49,8 @@
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
Expand All @@ -70,7 +71,11 @@ public class FakeChunkManager {

private final Long2ObjectMap<WorldChunk> fakeChunks = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
private int centerX, centerZ, viewDistance;
private final LongSet toBeUnloaded = new LongOpenHashSet();
private final Long2LongMap toBeUnloaded = new Long2LongOpenHashMap();
// Contains chunks in order to be unloaded. We keep the chunk and time so we can cross-reference it with
// [toBeUnloaded] to see if the entry has since been removed / the time reset. This way we do not need
// to remove entries from the middle of the queue.
private final Deque<Pair<Long, Long>> unloadQueue = new ArrayDeque<>();

// There unfortunately is only a synchronous api for loading chunks (even though that one just waits on a
// CompletableFuture, annoying but oh well), so we call that blocking api from a separate thread pool.
Expand Down Expand Up @@ -132,6 +137,9 @@ public void update(BooleanSupplier shouldKeepTicking) {
return;
}

BobbyConfig config = Bobby.getInstance().getConfig();
long time = Util.getMeasuringTimeMs();

int oldCenterX = this.centerX;
int oldCenterZ = this.centerZ;
int oldViewDistance = this.viewDistance;
Expand All @@ -146,7 +154,9 @@ public void update(BooleanSupplier shouldKeepTicking) {
boolean zOutsideNew = z < newCenterZ - newViewDistance || z > newCenterZ + newViewDistance;
if (xOutsideNew || zOutsideNew) {
cancelLoad(x, z);
toBeUnloaded.add(ChunkPos.toLong(x, z));
long chunkPos = ChunkPos.toLong(x, z);
toBeUnloaded.put(chunkPos, time);
unloadQueue.add(new Pair<>(chunkPos, time));
}
}
}
Expand All @@ -161,6 +171,7 @@ public void update(BooleanSupplier shouldKeepTicking) {

// We want this chunk, so don't unload it if it's still here
toBeUnloaded.remove(chunkPos);
// Not removing it from [unloadQueue], we check [toBeUnloaded] when we poll it.

// If there already is a chunk loaded, there's nothing to do
if (clientChunkManager.getChunk(x, z, ChunkStatus.FULL, false) != null) {
Expand All @@ -181,10 +192,34 @@ public void update(BooleanSupplier shouldKeepTicking) {
}

// Anything remaining in the set is no longer needed and can now be unloaded
LongIterator unloadingIter = toBeUnloaded.iterator();
while (unloadingIter.hasNext()) {
long chunkPos = unloadingIter.nextLong();
unloadingIter.remove();
long unloadTime = time - config.getUnloadDelaySecs() * 1000L;
while (true) {
Pair<Long, Long> next = unloadQueue.pollFirst();
if (next == null) {
break;
}
long chunkPos = next.getLeft();
long queuedTime = next.getRight();

if (queuedTime > unloadTime) {
// Unload is still being delayed, put the entry back into the queue
// and be done for this update.
unloadQueue.addFirst(next);
break;
}

long actualQueuedTime = toBeUnloaded.remove(chunkPos);
if (actualQueuedTime != queuedTime) {
// The chunk has either been un-queued or re-queued.
if (actualQueuedTime != 0) {
// If it was re-queued, put it back in the map.
toBeUnloaded.put(chunkPos, actualQueuedTime);
}
// Either way, skip it for now and go to the next entry.
continue;
}

// This chunk is due for unloading
unload(ChunkPos.getPackedX(chunkPos), ChunkPos.getPackedZ(chunkPos), false);
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/assets/bobby/lang/en_us.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"title.bobby.config": "Bobby Config",
"option.bobby.enabled": "Enabled",
"option.bobby.unload_delay": "Chunk Unload Delay (Seconds)",
"tooltip.option.bobby.unload_delay": "Delays the unloading of chunks which are outside your view distance.\nSaves you from having to reload all chunks when\nleaving an area for a short moment (e.g. cut scenes).\nDoes not work across dimensions.",
"option.bobby.max_render_distance": "Max Render Distance",
"tooltip.option.bobby.max_render_distance": "Changes the maximum value configurable for Render Distance.\n\nRequires Sodium.",
"option.bobby.view_distance_overwrite": "Singleplayer Server View Distance",
Expand Down

0 comments on commit bcdbb94

Please sign in to comment.