Skip to content

Fix wind turbine desync#594

Merged
notfood merged 1 commit intorwmt:devfrom
Tick-git:Fix-Wind-Turbine-Desync
Jul 21, 2025
Merged

Fix wind turbine desync#594
notfood merged 1 commit intorwmt:devfrom
Tick-git:Fix-Wind-Turbine-Desync

Conversation

@Tick-git
Copy link
Copy Markdown
Contributor

Label: 1.6, Desync

Tested only on dev.

Issue:

Reported by two people on discord:

In RimWorld 1.6 desyncs occur whenever electrical devices - like ACs connected directly to wind turbines - lose power or regain power. The power state change seems to consistently trigger desyncs during multiplayer.

Fix:

Changes wind speed calculation to be equal on all clients.

This patch replaces object.GetHashCode() with a deterministic hash based on map.Tile when in multiplayer.

In version 1.5, this.map.Tile was used instead of this.map.GetHashCode().

In version 1.6, map.Tile is no longer an int, but a PlanetTile object. However, it can still be implicitly converted to an int.

Using GetHashCode() in 1.6 introduces wind speed randomness across game loads. This patch ensures consistency between all clients in multiplayer, but it removes the randomness.

Tested

  • Wind turbine output is equal across all clients.
  • Connected many consumers to a wind turbine, causing them to lose and regain power intermittently.
  • Created a new settlement in the session to test whether the new wind manager calculates wind speed deterministically across clients as well.

Method in 1.6

private float BaseWindSpeedAt(int ticksAbs)
{
    if (this.windNoise == null)
    {
        int seed = Gen.HashCombineInt(this.map.GetHashCode(), 122049541) ^ Find.World.info.Seed;
        this.windNoise = new Perlin(3.9999998989515007E-05, 2.0, 0.5, 4, seed, QualityMode.Medium);
        this.windNoise = new ScaleBias(1.5, 0.5, this.windNoise);
        this.windNoise = new Clamp((double)WindManager.WindSpeedRange.min, (double)WindManager.WindSpeedRange.max, this.windNoise);
    }
    return (float)this.windNoise.GetValue((double)ticksAbs, 0.0, 0.0);
}

Method in 1.5

private float BaseWindSpeedAt(int ticksAbs)
{
    if (this.windNoise == null)
    {
        int seed = Gen.HashCombineInt(this.map.Tile, 122049541) ^ Find.World.info.Seed;
        this.windNoise = new Perlin(3.9999998989515007E-05, 2.0, 0.5, 4, seed, QualityMode.Medium);
        this.windNoise = new ScaleBias(1.5, 0.5, this.windNoise);
        this.windNoise = new Clamp((double)WindManager.WindSpeedRange.min, (double)WindManager.WindSpeedRange.max, this.windNoise);
    }
    return (float)this.windNoise.GetValue((double)ticksAbs, 0.0, 0.0);
}

Changes wind speed calculation to be equal on all clients.

This patch replaces `object.GetHashCode()` with a deterministic hash based on `map.Tile` when in multiplayer.

In version 1.5, `this.map.Tile` was used instead of `this.map.GetHashCode()`.

In version 1.6, `map.Tile` is no longer an `int`, but a `PlanetTile` object. However, it can still be implicitly converted to an `int`.

Using `GetHashCode()`in 1.6 introduces wind speed randomness across game loads.
This patch ensures consistency between all clients in multiplayer, but it removes the randomness.
@notfood notfood added fix Fixes for a bug or desync. desync Bug that specifically causes a desynced state. 1.6 Fixes or bugs relating to 1.6 (Not Odyssey). labels Jul 21, 2025
@notfood notfood moved this to In review in 1.6 and Odyssey Jul 21, 2025
@notfood
Copy link
Copy Markdown
Member

notfood commented Jul 21, 2025

This is a bug that could be reported to Ludeon, feels like a mistake on their part.

@notfood notfood merged commit 9f41fb2 into rwmt:dev Jul 21, 2025
1 check passed
@github-project-automation github-project-automation bot moved this from In review to Done in 1.6 and Odyssey Jul 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1.6 Fixes or bugs relating to 1.6 (Not Odyssey). desync Bug that specifically causes a desynced state. fix Fixes for a bug or desync.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants