Terra Palus

by Lukah

A hybrid planet combining features of Nauvis and Gleba. Brave the dangerous swamp moon of Terra Palus; mine Palusium ore and use UV light to freeze those that would see you destroyed.

Content
8 hours ago
2.0
15.8K
Factorio: Space Age Icon Space Age Mod
Planets Combat Environment Mining Fluids Power

b Desynch Bug.

10 hours ago

Hellow.

We run your planet on our server, and regretfully have to report that it causes desync.

Our inhouse programmer has found it to be the code block bellonging to the function "needs_first_tick_rescan"

When the line is quoted out the desync issues disapear.

8 hours ago

Hi SkunkMaster, thanks for letting me know! I've not seen Terra Palus on a server before, so I'm very happy to get your feedback and bug reports for any issues in multiplayer. I've just taken a look and done some refactoring - v0.2.8 has been released with some fixes for needs_first_tick_rescan. Could you give it a try and let me know how you go? Thanks!

4 hours ago

Hi, I was the person who debugged the desync to this mod. The code of v0.2.8 and initial testing (using heavy mode, without running a actual server) seems fine.

That said, in our case, the desync wasn't caused by the act of creating stickers; it was caused by the act of rescanning somehow caused the storage to diverge between server and client (I'm actually not confident on how sensitive factorio is to changes in the storage). I checked in our save and the tables storage.frozen_entities, storage.spotlight_frozen, and storage.thawing_entities were all empty at the time of desync. Since storage.pending_sticker_refresh is effectively a no-op in our save (since the tables are empty) in v0.2.8, I wouldn't say my testing is conclusive.

Though I wonder, is there a reason why the stickers has to be re-applied on load? Do stickers not persist on save/reload? I initially thought the block for needs_first_tick_rescan was... to rescan and rebuild the cache in storage in case of mod updates, but it would be so unnecessary because the same logic also happens at script.on_configuration_changed, which already catches that. So my current workaround was simply removing the needs_first_tick_rescan block.

3 hours ago

Hi zhuyifei1999!
You're spot on, the desync was caused by rescan_all_lamps() and rebuild_frozen_entity_keys() modifying storage unsynchronized - specifically:

  • surface.find_entities_filtered() potentially returning entities in different orders
  • Resetting indices like storage.lamp_index = 1 on one client but not another
  • Rebuilding arrays with table.insert() creating ordering divergence

The core fix in v0.2.8 is exactly your workaround - removing the needs_first_tick_rescan block entirely. You're also correct that it was redundant with on_configuration_changed. The on_player_joined_game sticker refresh I added is probably unnecessary - I initially found in my testing in single player that stickers didn't persist through save/load, but maybe that doesn't happen anymore. Stickers are now saved entities and should persist. The original sticker reapplication logic may have been cargo-culted in without being needed.

The sticker refresh code should be (?) harmless (it's a no-op when tables are empty, and when they're not it just reapplies visuals), but hopefully 0.2.8 continues to be performant for you.

Thanks for the detailed investigation - your diagnosis was correct! :D

2 hours ago
(updated 2 hours ago)

The sticker refresh code should be (?) harmless

I haven't looked too deeply in the code, but is it possible for stickers to be applied multiple times to the same entity? It's not super obvious how the tracking works

(Just a side question; this is not relevant to the desync)

2 hours ago

Yes, stickers can be applied multiple times - there's no deduplication. The functions just call surface.create_entity without checking for existing stickers:

  local function apply_frozen_sticker(entity)
      if entity and entity.valid then
          entity.surface.create_entity{
              name = "frozen-sticker",
              target = entity,
              position = entity.position
          }
      end
  end

The tracking tables (frozen_entities, spotlight_frozen, thawing_entities) prevent the same entity from being re-frozen multiple times in normal gameplay, but the sticker refresh paths (on_configuration_changed, on_player_joined_game) will blindly reapply stickers.

In practice, Factorio generally handles this gracefully - applying the same sticker type to an entity that already has one typically refreshes/extends the duration rather than creating visual duplicates. But you're right that there's no explicit check. If you wanted to be defensive, you could check entity.stickers before applying:

  local function has_sticker(entity, sticker_name)
      if entity.stickers then
          for _, sticker in pairs(entity.stickers) do
              if sticker.valid and sticker.name == sticker_name then
                  return true
              end
          end
      end
      return false
  end

But given Factorio's behavior, it's probably not necessary (at least for now! might change in a future Factorio update)

New response