Skip to content

feat(perf): Unload non ticking chunks - #14

Open
remminiscent wants to merge 3 commits into
altayofficial:devfrom
remminiscent:unload-non-ticking-chunks
Open

feat(perf): Unload non ticking chunks#14
remminiscent wants to merge 3 commits into
altayofficial:devfrom
remminiscent:unload-non-ticking-chunks

Conversation

@remminiscent

Copy link
Copy Markdown
Contributor

Related issues & PRs

Behavioural changes

Great ram usage decrease in servers that have large open worlds, and high render distances

Tests

Tested in game, works.
Loaded chunks at view-distance 16:

  • Unfixed: 856
  • Fixed: 64

Loaded chunks at view-distance 24:

  • Unfixed: 1884
  • Fixed: 64, while client sees farther

In both tests, the ticking chunks remained at 36 (chunk radius: 3)

@xRookieFight

Copy link
Copy Markdown
Contributor

@remminiscent Ready?

@remminiscent

Copy link
Copy Markdown
Contributor Author

@remminiscent Ready?

currently, it works. however it needs proper testing for different scenarios. will do later tonight

@xRookieFight
xRookieFight marked this pull request as ready for review August 8, 2026 22:55

@xRookieFight xRookieFight left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some nits.

Comment thread src/player/Player.php
}

public function onChunkUnloaded(int $chunkX, int $chunkZ, Chunk $chunk) : void{
$hash = World::chunkHash($chunkX, $chunkZ);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The early return can't tell a deliberate unload from a forced one. A plugin calling $world->unloadChunk gets swallowed: chunk stays SENT, orderChunks never re-queues it, client keeps stale terrain forever. Needs an explicit flag on the deliberate path, not inference from ticking state.

Comment thread src/player/Player.php
}

return false;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Full scan of usedChunks on every orderChunks(), with a getChunkEntities() per entry. That's the set this PR makes large. updateTickingChunkRegistrations() above works so this should too afaik

Comment thread src/player/Player.php
@@ -988,6 +992,35 @@ public function doFirstSpawn() : void{
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a 1-chunk margin? Presumably edge ticking needs loaded neighbours. Put it in a comment.

Comment thread src/player/Player.php
$this->loadQueue = $newOrder;

$this->updateTickingChunkRegistrations($this->tickingChunks, $tickingChunks);
$oldTickingChunks = $this->tickingChunks;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$oldTickingChunks used once as an arg. Drop it.

Comment on lines 106 to +111
){}

public function retain(int $chunkX, int $chunkZ) : void{
$chunkHash = World::chunkHash($chunkX, $chunkZ);
$this->usageCounts[$chunkHash] = ($this->usageCounts[$chunkHash] ?? 0) + 1;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document those functions please

return;
}
$worldId = $world->getId();
$chunkHash = World::chunkHash($chunkX, $chunkZ);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On world change this calls getInstance($oldWorld, ...). If the old world is already unloaded it reconstructs an instance and registers an addOnUnloadCallback that never fires, leaking self::$instances. Probably unreachable since Server::unloadWorld() evacuates first, but don't depend on that ordering.

@xRookieFight xRookieFight changed the title Unload non ticking chunks feat(perf): Unload non ticking chunks Aug 8, 2026
@xRookieFight

Copy link
Copy Markdown
Contributor

We should merge this into "dev" branch

@xRookieFight
xRookieFight changed the base branch from master to dev August 13, 2026 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Don't keep non-ticking chunks in memory on the server

2 participants