Fixed cover removal not syncing render state to clients#4937
Closed
dalizi2333 wants to merge 1 commit into
Closed
Conversation
- 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.
gustovafing
approved these changes
Jun 17, 2026
Member
|
#4939 fixes this on 1.20.1, and 1.20.1 will be merged into 1.21 in the future |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
SyncDataHolder.serializeFieldhas a condition!field.isSyncManaged && currentValue == nullthat skips null serialization forISyncManaged-typed fields.CoverBehaviorimplementsISyncManaged, so when a cover is removed (up = null), the field is silently skipped instead of being serialized as{"null": true}.CoverBehaviorTransformer.serializeNBT(null)returns an emptyCompoundTaginstead 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 bydeserializeFieldon the client side — it was just never being emitted forISyncManagedfields.Implementation Details
SyncDataHolder.serializeField — Removed the
!field.isSyncManagedcondition from the null check at line 108.CoverBehavioris the onlyISyncManagedtype whose fields can be null in practice. All otherISyncManagedannotated fields (AutoOutputTrait,RecipeLogic,NotifiableItemStackHandler,NotifiableFluidTank,NotifiableEnergyContainer,FilterHandler) are declaredpublic finaland initialized in constructors, so they are never null and this change has zero effect on them.CoverBehaviorTransformer — Defense-in-depth changes:
serializeNBTnow returns{"null": true}for null values instead of an empty tag, anddeserializeNBThandles the{"null": true}tag by returning null early. While theSyncDataHolderfix means these paths are no longer reached with null values, having the transformer itself handle null correctly improves robustness.AI Usage
Agent Used
Trae IDE (DeepSeek-V4-Pro)
Agent Usage Description
Used for codebase analysis: tracing the null serialization path through
SyncDataHolder, identifying allISyncManagedimplementations 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
runClientsessions, one before and one after the fix:Before fix:
After fix:
Potential Compatibility Issues
None. The
{"null": true}deserialization protocol was already fully implemented. All otherISyncManagedfields in the codebase arefinaland never null, so the behavioral change inserializeFielddoes not affect them.