Skip to content

fix delegates lifetime: unsubscribe stale handlers on network despawn#14

Merged
Lordfirespeed merged 1 commit intolc-sigurd:mainfrom
ratijas:work/ratijas/delegates
Mar 31, 2026
Merged

fix delegates lifetime: unsubscribe stale handlers on network despawn#14
Lordfirespeed merged 1 commit intolc-sigurd:mainfrom
ratijas:work/ratijas/delegates

Conversation

@ratijas
Copy link
Copy Markdown

@ratijas ratijas commented Aug 8, 2025

CSync leaves stale change handlers after quitting the hosted game.

When the host quits the game back to the main menu, ConfigSyncBehaviour despawns and gets destroyed by Unity (not by .NET GC), but any delegates connected to events in OnNetworkSpawn method remain and go stale.

So next time a player hosts a lobby without shutting down and re-launching the game completely, when any of subscribed config files or config entries change, stale delegates execute and try to assign to a dead NetworkList _deltas[index]. Of course it results in an exception being logged to the console by BepInEx (which wraps event handler invocation in a try-catch).

To fix this, store subscribed delegates, and properly unsubscribe them during despawn.

Note that NetworkList and _syncEnabled variable can not be cleared/reset due to Unity issue which only got resolved in the most recent version.

References:

Fixes #13

@ratijas
Copy link
Copy Markdown
Author

ratijas commented Aug 8, 2025

I could combine two lists of delegates into one with a huge signature or an internal struct, but it doesn't matter too much.

@ratijas
Copy link
Copy Markdown
Author

ratijas commented Aug 12, 2025

Polite ping?

Comment thread CSync/CSync/Lib/ConfigSyncBehaviour.cs
Comment thread CSync/CSync/Lib/ConfigSyncBehaviour.cs Outdated
Comment thread CSync/CSync/Lib/ConfigSyncBehaviour.cs Outdated
Comment thread CSync/CSync/Lib/ConfigSyncBehaviour.cs Outdated
Comment thread CSync/CSync/Lib/ConfigSyncBehaviour.cs Outdated
Comment thread CSync/CSync/Lib/ConfigSyncBehaviour.cs
@ratijas ratijas force-pushed the work/ratijas/delegates branch from a4f9c8d to 1c7cb9b Compare September 16, 2025 16:10
@ratijas ratijas force-pushed the work/ratijas/delegates branch from 1c7cb9b to a9b09fe Compare March 30, 2026 12:36
@ratijas
Copy link
Copy Markdown
Author

ratijas commented Mar 30, 2026

just squashed for now

@ratijas ratijas force-pushed the work/ratijas/delegates branch from a9b09fe to 1552fd8 Compare March 30, 2026 13:29
@ratijas
Copy link
Copy Markdown
Author

ratijas commented Mar 30, 2026

Reverted _deltas initialization to Awake, removed unused import

@ratijas ratijas force-pushed the work/ratijas/delegates branch 2 times, most recently from 0fc402a to aab7f5e Compare March 31, 2026 00:25
@ratijas
Copy link
Copy Markdown
Author

ratijas commented Mar 31, 2026

The latest patch includes a helper class which handles event registration and clean-up.

I tested it with a modified ExamplePlugin mod and 2-players LAN setup, switching host/client roles at runtime multiple times. It worked fine. No duplicate clean-up (I removed the one in OnDestroy), no exceptions, changes do propagate and synchronize as usual.

CSync leaves stale change handlers after quitting the hosted game.

When the host quits the game back to the main menu, ConfigSyncBehaviour
despawns and gets destroyed by Unity (not by .NET GC), but any delegates
connected to events in OnNetworkSpawn method remain and go stale.

So next time a player hosts a lobby without shutting down and
re-launching the game completely, when any of subscribed config files
or config entries change, stale delegates execute and try to assign to
a dead NetworkList _deltas[index]. Of course it results in an exception
being logged to the console by BepInEx (which wraps event handler
invocation in a try-catch).

To fix this, store subscribed delegates, and properly unsubscribe them
during despawn.

Note that NetworkList and _syncEnabled variable can not be cleared/reset
due to Unity issue which only got resolved in the most recent version.
Lethal Company v73 updated Unity Netcode for GameObjects (NGO) to
1.12.0, but the fix is available for NGO 1.14.0+ only.

References:
- https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/using-delegates
- Unity-Technologies/com.unity.netcode.gameobjects#3502

Fixes lc-sigurd#13
@ratijas ratijas force-pushed the work/ratijas/delegates branch from aab7f5e to 7fb4f03 Compare March 31, 2026 00:42
@Lordfirespeed Lordfirespeed merged commit 84c745a into lc-sigurd:main Mar 31, 2026
1 check passed
@ratijas ratijas deleted the work/ratijas/delegates branch March 31, 2026 00:50
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.

CSync leaves stale change handlers after quitting the hosted game

2 participants