Skip to content

Room search: fix volume drift, respect the tick budget, and continue past capped boxes; scan occupants every 5 ticks - #132

Merged
RealAntEngineer merged 6 commits into
RealAntEngineer:1.21.1-releasefrom
dhm-msd:pr/3-room-simulation
Oct 19, 2026
Merged

RealAntEngineer merged 6 commits into
RealAntEngineer:1.21.1-releasefrom
dhm-msd:pr/3-room-simulation

Conversation

@dhm-msd

@dhm-msd dhm-msd commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Three changes (one commit each) that alter how a room is searched and how oxygen is applied. They change behaviour slightly, so I kept them separate from the pure performance PR.

Stacked on the bug-fix PR (pr/1-bug-fixes): these commits edit lines it changes. Until that PR is merged, this one also shows its three commits. I will rebase once it lands.

Changes

  1. Volume drift. searchTopology removes the box containing the start position and searches it again, but the old volume was kept and the re-added volume was added on top, so the total kept growing until the room was wrongly over maxSizePerSealer. The volume of removed boxes is now subtracted first.
  2. Per-box budget and frontier. A single box could grow far past maxBlockPerTick (only its edge length was capped), so one search could take much longer than configured. It now stops growing when it would use more than the tick's remaining budget. Also, when a box stops because of a size cap (edge length 30 or the budget) instead of being blocked on every side, the cells around it were never queued, so a room could be declared sealed with its frontier unexplored. Those cells are now queued. contains() also no longer allocates a Vec3 per box.
  3. Occupant scan every 5 ticks. Each room ran one all-entity query per box every tick. It now runs one LivingEntity query on a cached bounding box every 5 ticks. Oxygen consumption and leaf production are multiplied by 5, so the totals per second are unchanged, but oxygen changes in 5-tick steps.

What to look at

  • Item 2 is the largest logic change. Worth testing a big room, a leaking room, and a room next to the edge of loaded chunks.
  • Item 3: check that tanks and leaf production feel the same.

…ackets

RoomShapeSerializer.copy() returned the same instance, so the set_entity_data packet
kept a reference to the live box list. searchTopology edited that list in place while
the packet was encoded later on a Netty thread, causing a ConcurrentModificationException
-> EncoderException and a disconnect for the tracking player.

A published RoomShape is now never modified: searchTopology builds a new list and a new
shape on every rebuild, so the shape can be shared with packets without a lock or a copy
per sync. The one list copy per rebuild replaces the in-place edit.
inO2() consumes the 'inside an oxygen room' flag, and the suffocation and overheating
checks each called it. The second call always reported 'no oxygen', so entities standing
in a pressurised room took overheating damage. Evaluate it once per check and run the
overheating branch only when there is no oxygen.
The carver instance is shared by all chunk-generation worker threads, but its height
cache was a plain HashMap, which can corrupt or loop under concurrent access. Use a
ConcurrentHashMap.
searchTopology removes the box that contains the start position and searches it again,
but the old shape volume was kept and the re-added volume was added on top, so the
volume grew every time the same area was re-searched until the room was wrongly treated
as over the per-sealer size limit. Subtract the volume of the removed boxes first.
…ast capped boxes

- A single box could grow far past maxBlockPerTick (only the size of the box was capped,
  not the remaining budget), so one search could take much longer than configured.
  A box now stops growing when it would use more than what is left of the tick's budget.
- When a box stops growing because of a size cap (edge length 30 or the budget) rather
  than because every side is blocked, the cells around it were never queued, so a room
  could be declared sealed while its frontier was unexplored. Queue those cells so the
  search continues from them.
- contains() no longer allocates a Vec3 per box per candidate block.
Each room ran one all-entity query per box every tick. It now scans every 5 ticks with
one LivingEntity query on a cached bounding box (filtered against the boxes). Oxygen
consumption and leaf production are multiplied by the interval so the totals per second
stay the same, but oxygen now changes in 5-tick steps.
@CLAassistant

CLAassistant commented Oct 19, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@RealAntEngineer
RealAntEngineer marked this pull request as ready for review October 19, 2026 21:33
@RealAntEngineer
RealAntEngineer merged commit 211ffbb into RealAntEngineer:1.21.1-release Oct 19, 2026
1 check passed
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.

3 participants