Skip to content

Conversation

@marcus8448
Copy link
Member

@marcus8448 marcus8448 commented Aug 23, 2025

Replaces the old state-inversion based oxygen system with a new "provider-based" system, and updates the oxygen sealer and oxygen bubble distributor implementations to match. This allows for precise point based oxygen checks rather than block position based checks.

Additionally adds the ability for oxygen sealers to quickly update their status based on broken/placed blocks:

  • If a wall block is broken and causes a leak, the seal will break immediately
  • If a wall block is broken and just exposes another sealable space, the seal will update to fill that space immediately
  • If a block is placed in the middle of a sealed space, the seal will be maintained
  • If a block is placed in a way that it blocks off an important/connecting corridor it will destroy the seal in the obstructed room while maintaining the seal on the other side.

Because of this, sealers now only recheck their seals when there is a block broken/placed, rather than on a set interval (the interval is only used for initial seals, to prevent constant rechecking of large unsealable areas).

User facing changes in action: https://www.youtube.com/watch?v=NoDF3qlwULY

General Implementation Notes

Consider "breathable" to be equivalent to "has atmosphere" or "has air" for simplicity, as we don't currently support anything more than that.

AtmosphereProvider: A block entity that has the ability to create breathable spaces. It keeps track of the precise places that it provides air for and can be queried.

A Level still keeps track of whether it has a breathable atmosphere, but now it won't bother checking for positional breathability if it does. This removes the ability to make "vacuums" (non-breathable spaces) on normally breathable planets, but that functionality wasn't in use anyways.

Should a Level not be breathable, then it queries the Chunk at the given x/z-coordinate, which then delegates to the ChunkSection at the given y-coordinate. The section returns a list of positions for AtmosphereProviders which will then be queried (for the block entity). If any provider says that the position is breathable, it's considered breathable.

"Wall" and other solid blocks that are in or surround sealed spaces now are marked breathable.

Unsolved bits

  • Does AtmosphereProvider lookup actually need to have per-block-resolution? No, dropped.
  • I would imagine most bases have only 1-2 sealers, and then maybe a couple bubble distributors?
    • Iterating over all providers in a section (at most maybe 4 items) and then doing a hash lookup for each one doesn't sound too bad in my head.
  • I'm leaning towards dropping it.
  • What should (not) be exposed in the public-facing api. Public api moved to chunk level
  • The section level interface must be used to attach a new AtmosphereProvider to a section
    • Too low level?
  • Chunk-level interface is almost empty (is there a use case?)
    • More complicated as most breathable checks require a world instance (as providers may be outside of the chunk)
  • Multiple sealers can seal the same space Fixed, with interface to identify.
  • Could just add a simple check for other sealers, but no "nice" way to differentiate between bubble distributor (where overlap is ok) and sealer behaviour

The future

There's a few neat things that could come out of this in the future, but aren't implemented here for simplicity:

  • Variable air consumption based on blocks/entities in a bubble/sealed space (rather than flat volume-based rate)
  • Air composition (we'll need to figure out a proper gas api first)

I've also been thinking about sealed spaces unattached to provider blocks (e.g. if a oxygen sealer is broken the air shouldn't just vanish), but that could get more complicated w.r.t block changes, composition/splitting.

@maxryan008
Copy link
Contributor

Not sure if this was a feature already but does copper still oxidize in no atmosphere environments. specifically could you design it so a sealed room will let copper oxidize but in no atmosphere environments it will no longer oxidize

I don't think allowing vacuums is worth it
implemented for the sealer, not yet implemented for the bubble distributor

it's getting even more complicated...
feat. even more cursed custom data structures!
fix text input for target bubble size
clear bubble distribution before removing block entity
also utilize states when tracking subscribers
rationale:
* simplifies implementation - no more funky bitset logic and data growth mechanisms
* in my mind, there shouldn't be more than ~5 sealers/distributors working in a single chunk section in the worst case, so linear time lookup should be fast enough
move chunk oxygen accessor to public api
improve implementation explanations as well
@marcus8448 marcus8448 marked this pull request as ready for review September 10, 2025 03:21

import java.util.Iterator;

public interface LevelOxygenAccessorRO {
Copy link
Contributor

Choose a reason for hiding this comment

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

What does the RO stand for, out of curiosity?

Copy link
Member Author

Choose a reason for hiding this comment

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

It stands for read-only. The interface is split so that LevelReader can implement the read-only parts. It could be renamed to LevelOxygenReader or something if that's easier to understand.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, that makes sense. Don't feel you have to rename it, but a comment saying read-only might be nice.

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like MAX_SEALER_VOLUME is being used as the maximum number of blocks that can be sealed, regardless of how many sealers there are. I feel like this probably shouldn't be the case.

Copy link
Contributor

Choose a reason for hiding this comment

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

It also seems to be the case that covering up an oxygen sealer/subdividing a sealed room does not update the space without a sealer anymore to be non-breathable.

covered_sealer.mp4

@marcus8448 marcus8448 marked this pull request as draft September 20, 2025 19:49
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.

4 participants