Skip to content

Fix plant growth quantization drift in save compression#936

Closed
MhaWay wants to merge 1 commit into
rwmt:devfrom
MhaWay:fix/plant-growth-quantization
Closed

Fix plant growth quantization drift in save compression#936
MhaWay wants to merge 1 commit into
rwmt:devfrom
MhaWay:fix/plant-growth-quantization

Conversation

@MhaWay
Copy link
Copy Markdown
Contributor

@MhaWay MhaWay commented May 23, 2026

Summary

This fixes a save compression round-trip issue where plant growth could drift upward after a save/load cycle.

Root cause

I tracked this down while comparing normal hosted saves against the standalone/joinpoint path that goes through SaveAndReload.

With cache re-arming disabled for diagnostics, the payload diff consistently showed plant state changing across a save+reload roundtrip even when session data and queued commands stayed stable. The focused diff showed the same plant entry keeping the same id, HP, age, and flags, but with growthByte increasing by 1 after reload.

This comes from the plant compression format introduced in 2019 in commit e7076df (the save compression change). That commit changed plant growth serialization from a float to a byte using:

  • save: ceil(Growth * 255)
  • load: growthByte / 255f

That encoding is not round-trip stable, so repeated SaveAndReload cycles can ratchet plant growth upward.

Change

Replace the ceil-based quantization with a round-to-nearest quantization that preserves byte -> float -> byte roundtrips.

Validation

  • Checked the history of SaveCompression.cs and confirmed the byte-based plant growth encoding was introduced by the 2019 save compression change.
  • Reproduced the drift by comparing pre/post SaveAndReload payloads.
  • After this change, compressedPlantsDeflate became identical before and after SaveAndReload in the diagnostic runs, removing the growthByte N -> N+1 drift.

Copilot AI review requested due to automatic review settings May 23, 2026 18:06
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR changes how plant growth is quantized into a byte when saving, replacing a direct Math.Ceiling(... * 255) with a dedicated helper that rounds and clamps values.

Changes:

  • Replaced inline plant growth quantization with a new EncodePlantGrowth(float growth) helper.
  • Implemented rounding-to-nearest and explicit clamping to [0, 255] for the encoded growth byte.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +112 to +118
int quantized = (int)(growth * 255f + 0.5f);

if (quantized < 0)
quantized = 0;
else if (quantized > 255)
quantized = 255;


private static byte EncodePlantGrowth(float growth)
{
int quantized = (int)(growth * 255f + 0.5f);
@MhaWay
Copy link
Copy Markdown
Contributor Author

MhaWay commented May 24, 2026

Useless

@MhaWay MhaWay closed this May 24, 2026
Copy link
Copy Markdown
Member

@notfood notfood left a comment

Choose a reason for hiding this comment

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

I wouldn't call it useless, it does fix an issue, even if it ultimately doesn't affect sync.

For clarity, use Math.Clamp with Byte.MaxValue. Since RimWorld code uses the + 0.5f pattern, it's fine to keep that as-is.

Given how short this is, I think it should be simplified into a one-liner.

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