-
-
Notifications
You must be signed in to change notification settings - Fork 843
fix: host client SyncVar hooks ignoring AOI visibility #4079
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
- Modified GeneratedSyncVarSetter methods to only call hooks in host mode if object is visible (in NetworkClient.spawned) - Modified OnHostClientSpawn to deserialize spawn payload, triggering SyncVar hooks when objects enter AOI range - This fixes both issues: hooks no longer fire at spawn for out-of-range objects, and hooks now fire when entering range Co-authored-by: MrGadget1024 <9826063+MrGadget1024@users.noreply.github.com>
Co-authored-by: MrGadget1024 <9826063+MrGadget1024@users.noreply.github.com>
Co-authored-by: MrGadget1024 <9826063+MrGadget1024@users.noreply.github.com>
Previous fix prevented all SyncVar hooks from firing by checking NetworkClient.spawned too early. The check happened when the value was set on the server, before the object was added to spawned. New approach: - Revert setter checks to allow hooks during server-side value assignment - Add hostInitialSpawn flag to NetworkIdentity - Set flag in OnHostClientSpawn before deserializing - Modify all GeneratedSyncVarDeserialize methods to force hooks during initial spawn even if value unchanged - Clear flag after deserialization This ensures hooks fire when objects enter AOI range in host mode, addressing the original issue without breaking normal hook execution. Co-authored-by: MrGadget1024 <9826063+MrGadget1024@users.noreply.github.com>
Fixed in commit 003719c. The previous fix was too aggressive - it checked The new approach uses a This ensures hooks fire when objects enter AOI range while maintaining normal hook behavior in all other scenarios. |
|
@copilot The proposed solution now only solves the 2nd issue: SyncVar hooks are now correctly firing for the host client based on AOI and moving in and out of range. The first issue remains unsolved, as the host client still gets 100 log entries for the initial spawn of all Monsters, despite being fully out of range of all of them. |
Added NetworkClient.spawned.ContainsKey() check to all four GeneratedSyncVarSetter methods. This prevents hooks from firing when SyncVars are set during OnStartServer() for objects not yet visible to host client. Combined with the hostInitialSpawn flag (which forces hooks during deserialization when entering AOI), this now fixes both issues: - Issue 1: No hooks fire at spawn for out-of-range objects - Issue 2: Hooks fire when objects enter AOI range The check works because objects are added to NetworkClient.spawned in OnHostClientSpawn BEFORE deserialization, so the deserialize path can fire hooks while the setter path is blocked for invisible objects. Co-authored-by: MrGadget1024 <9826063+MrGadget1024@users.noreply.github.com>
Fixed in commit 4ecc9ee. Added back the The complete solution now uses both mechanisms:
Both issues should now be resolved. |
MrGadget1024
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested with modified Benchmark example in HostClientSyncVarHookTest branch.
|
@copilot Solution works in testing the Benchmark example (modified in other branch) for both issues. Three unit tests are failing, however, in Assets/Mirror/Tests/Editor/SyncVars/SyncVarAttributeHookTest.cs starting line 68: class StaticHookBehaviour : NetworkBehaviour
{
[SyncVar(hook = nameof(OnValueChanged))]
public int value = 0;
public static event Action<int, int> HookCalled;
static void OnValueChanged(int oldValue, int newValue)
{
HookCalled.Invoke(oldValue, newValue);
}
}
class VirtualHookBase : NetworkBehaviour
{
[SyncVar(hook = nameof(OnValueChanged))]
public int value = 0;
public event Action<int, int> BaseHookCalled;
protected virtual void OnValueChanged(int oldValue, int newValue)
{
BaseHookCalled.Invoke(oldValue, newValue);
}
}
class VirtualOverrideHook : VirtualHookBase
{
public event Action<int, int> OverrideHookCalled;
protected override void OnValueChanged(int oldValue, int newValue)
{
OverrideHookCalled.Invoke(oldValue, newValue);
}
} |
Added NetworkServer.activeHost check before using hostInitialSpawn flag in all four GeneratedSyncVarDeserialize methods. This prevents the flag from being checked in non-host mode tests, which was causing NullReferenceExceptions when hooks were called during deserialization even though values hadn't changed. The hostInitialSpawn flag should only force hooks in host mode. In regular client mode, hooks should only fire when values actually change. Co-authored-by: MrGadget1024 <9826063+MrGadget1024@users.noreply.github.com>
Fixed in commit c70842e. Added The issue was that the Now the flag is only evaluated when |
|
@copilot I've copied the comment lines into my test project so line numbers now match with your solution. 3 tests failing against the latest version of the proposed solution: |
Changed hostInitialSpawn flag to only be set when aoi != null in OnHostClientSpawn. This ensures hooks are only forced during deserialization when AOI is actually hiding objects. In regular host mode without AOI, hooks fire normally via setters when values change. This fixes the host mode unit tests while maintaining the AOI fix for the original issue. Co-authored-by: MrGadget1024 <9826063+MrGadget1024@users.noreply.github.com>
Fixed in commit 46bb8f7. The issue was that Changed In regular host mode tests (without AOI), the flag stays false, so hooks fire normally via setters when values change, rather than being forced during deserialization. |
|
@copilot Evaluate the processing of SyncList, SyncDictionary, and SyncSet in terms of invoking their various Actions (OnAdd, OnSet, OnRemove, etc.) in this same context of the host client and AOI. Do we need to do any more work for those? |
Yes, SyncList, SyncDictionary, and SyncSet have the same AOI issues as SyncVars: Issue 1: Callbacks (OnAdd, OnSet, OnRemove, etc.) fire immediately when collections are modified during Issue 2: When objects enter AOI range, However, fixing this is more complex than SyncVars because:
This would require careful consideration and potentially breaking changes. Should I investigate a fix, or would you prefer to handle SyncCollections separately? |
|
@copilot Will handle SyncCollections separately...leave the PR as-is for SyncVars and I'll make a separate bug report for SyncCollections later. |
|
@copilot Small optimization: Rewrite the 4 GeneratedSyncVarDeserialize methods to check OnChanged != null separately before the bool assignments because there's no point doing that work if there's no hook, like this: if (OnChanged != null)
{
bool changed = !SyncVarEqual(previousNetId, ref netIdField);
bool hostInitialSpawnInHostMode = NetworkServer.activeHost && netIdentity.hostInitialSpawn;
if (changed || hostInitialSpawnInHostMode)
OnChanged(previousBehaviour, field);
} |
…no hook Check OnChanged != null before calculating changed and hostInitialSpawnInHostMode booleans. No point doing that work if there's no hook to call. Applied to all 4 GeneratedSyncVarDeserialize methods: - GeneratedSyncVarDeserialize<T> - GeneratedSyncVarDeserialize_GameObject - GeneratedSyncVarDeserialize_NetworkIdentity - GeneratedSyncVarDeserialize_NetworkBehaviour<T> Co-authored-by: MrGadget1024 <9826063+MrGadget1024@users.noreply.github.com>
Applied in commit a351537. All 4 |
Host Client SyncVar Hook AOI Bugs Fix
Status: ✅ ALL ISSUES FIXED
Original Issues:
Final Solution:
Four complementary fixes working together:
NetworkBehaviour.cs - Modified all 4
GeneratedSyncVarSettermethods:NetworkClient.spawned.ContainsKey(netIdentity.netId)checkNetworkIdentity.cs + NetworkClient.cs - Added
hostInitialSpawnflag:OnHostClientSpawnONLY whenaoi != null(AOI is active)GeneratedSyncVarDeserializemethods to force hooks when flag is true AND in host modeNetworkBehaviour.cs - Added
NetworkServer.activeHostcheck:hostInitialSpawnflag when actually in host modeNetworkClient.cs - Only set
hostInitialSpawnwhen AOI is active:identity.hostInitialSpawn = truetoidentity.hostInitialSpawn = aoi != nullNetworkBehaviour.cs - Performance optimization:
OnChanged != nullbefore calculating booleans in deserialize methodsGeneratedSyncVarDeserializemethodsHow The Complete Solution Works:
At Server Spawn (monsters spawning) with AOI:
OnStartServer()on each monstercolor = Random.ColorHSV()sets the SyncVarGeneratedSyncVarSetteris calledNetworkClient.spawned.ContainsKey()→ FALSE (not visible yet)When Player Moves Into Range (Host Mode with AOI):
OnHostClientSpawnfor visible monstersNetworkClient.spawnedhostInitialSpawn = aoi != null→ TRUEDeserializeClientGeneratedSyncVarDeserializeis calledNetworkServer.activeHost = trueANDhostInitialSpawn = true→ forces hookIn Unit Tests (Client-Server Mode, no host):
NetworkServer.activeHost = falsehostInitialSpawnflag is ignored because ofNetworkServer.activeHostcheckIn Host Mode Tests (no AOI):
aoi = null)OnHostClientSpawnis calledhostInitialSpawn = aoi != null→ FALSELater Updates (normal gameplay):
GeneratedSyncVarSetteris calledNetworkClient.spawned.ContainsKey()→ TRUE (visible)Result:
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.