Skip to content

Fixed cover removal not syncing render state to clients#4937

Closed
dalizi2333 wants to merge 1 commit into
GregTechCEu:1.21from
dalizi2333:fix-cover-null-serialization
Closed

Fixed cover removal not syncing render state to clients#4937
dalizi2333 wants to merge 1 commit into
GregTechCEu:1.21from
dalizi2333:fix-cover-null-serialization

Conversation

@dalizi2333

Copy link
Copy Markdown

What

When a cover is removed from a machine or pipe, the cover texture remains visible on the client side until the chunk is reloaded. The root cause is twofold:

  1. SyncDataHolder.serializeField has a condition !field.isSyncManaged && currentValue == null that skips null serialization for ISyncManaged-typed fields. CoverBehavior implements ISyncManaged, so when a cover is removed (up = null), the field is silently skipped instead of being serialized as {"null": true}.
  2. CoverBehaviorTransformer.serializeNBT(null) returns an empty CompoundTag instead of a proper null marker, so even if it were reached, the client would ignore it.

The {"null": true} protocol already exists and is correctly handled by deserializeField on the client side — it was just never being emitted for ISyncManaged fields.

Implementation Details

SyncDataHolder.serializeField — Removed the !field.isSyncManaged condition from the null check at line 108. CoverBehavior is the only ISyncManaged type whose fields can be null in practice. All other ISyncManaged annotated fields (AutoOutputTrait, RecipeLogic, NotifiableItemStackHandler, NotifiableFluidTank, NotifiableEnergyContainer, FilterHandler) are declared public final and initialized in constructors, so they are never null and this change has zero effect on them.

CoverBehaviorTransformer — Defense-in-depth changes: serializeNBT now returns {"null": true} for null values instead of an empty tag, and deserializeNBT handles the {"null": true} tag by returning null early. While the SyncDataHolder fix means these paths are no longer reached with null values, having the transformer itself handle null correctly improves robustness.

AI Usage

  • Yes AI driven tools were used for this pull request.

Agent Used

Trae IDE (DeepSeek-V4-Pro)

Agent Usage Description

Used for codebase analysis: tracing the null serialization path through SyncDataHolder, identifying all ISyncManaged implementations and their field declarations to verify no other types depend on the old behavior, and drafting the PR description. All code changes were manually reviewed and verified.

Outcome

Fixed: Cover removal from machines or pipes now correctly syncs the null state to clients, causing the cover texture to disappear immediately without requiring a chunk reload.

How Was This Tested

Two runClient sessions, one before and one after the fix:

Before fix:

  1. Enter a world, place a machine, install any compatible cover on a side.
  2. Remove the cover via crowbar right-click or the cover GUI.
  3. The cover texture does not update — it remains rendered both inside and outside the GUI.
  4. Interaction logic is already correct (the cover is removed server-side): holding a crowbar and right-clicking the stale face opens the machine GUI instead of removing a cover; holding a cover and right-clicking the stale face installs a new cover, confirming the old one is gone server-side.

After fix:

  1. Same steps — install a cover, then remove it via crowbar or GUI.
  2. The cover texture disappears immediately, both inside and outside the GUI. Render state correctly syncs to the client.

Potential Compatibility Issues

None. The {"null": true} deserialization protocol was already fully implemented. All other ISyncManaged fields in the codebase are final and never null, so the behavioral change in serializeField does not affect them.

- SyncDataHolder.serializeField: removed the !isSyncManaged condition from null check so that nullable ISyncManaged fields (e.g. CoverBehavior) are properly serialized as null instead of being silently skipped, causing client-side render desync when a cover is removed.

- CoverBehaviorTransformer: serializeNBT now returns null tag for null values instead of an empty tag; deserializeNBT now handles null tag as a defensive measure.
@dalizi2333 dalizi2333 requested a review from a team as a code owner June 16, 2026 21:29
@github-actions github-actions Bot added the 1.21 label Jun 16, 2026
@gustovafing

Copy link
Copy Markdown
Member

#4939 fixes this on 1.20.1, and 1.20.1 will be merged into 1.21 in the future

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants