Skip to content

feat: pack NetworkTransform into one state variable, prevent sync popping (MTT-818)#964

Merged
0xFA11 merged 21 commits intodevelopfrom
feat/mtt-818
Jul 22, 2021
Merged

feat: pack NetworkTransform into one state variable, prevent sync popping (MTT-818)#964
0xFA11 merged 21 commits intodevelopfrom
feat/mtt-818

Conversation

@0xFA11
Copy link
Copy Markdown
Contributor

@0xFA11 0xFA11 commented Jul 17, 2021

we used to have individual NetVars for UseLocal (now InLocalSpace), position, rotation and scale.
with this PR, we're packing all of them under one single NetworkState variable to prevent individual NetVar updates causing incoherent updates (there popping) between ticks.
this PR also updates tests accordingly (very minor) and fixes issues in GrabbableBall script so that it'd rely on NetworkObject parenting rather than trying to do its own reparenting with RPCs.

Authority == NetworkAuthority.Shared;

private void UpdateOneVarPermission<T>(NetworkVariable<T> varToUpdate)
private bool IsNetworkStateDirty
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

note: implementing threshold values would hopefully be easier with this property's body. we could simply ignore too small changes and count them as "not dirty"

}

private Quaternion m_CurrentRotation
private void UpdateNetworkState()
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

note: implementing specific axis for position/rotation/scale would hopefully be easier with this approach because we could simply switch on what we'll serialize/deserialize here (+ an int mask for what's enabled/disabled for sync in NetworkState would make it even fancier to sync between!)

}

private void Awake()
private void ApplyNetworkState(NetworkState netState)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

note: interpolation would potentially be implemented under this function in the future

/// </summary>
[SerializeField]
public bool InterpolateServer = true;
private class NetworkState : INetworkSerializable
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

should be struct

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

class is intentional here as we're modifying its props in UpdateNetworkState() instead of swapping m_NetworkState.Value with a brand-new one

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I still think this should be a struct, also just to get rid of the allocations when deserializing this into a new instance. But we can just go ahead with class that's fine.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since this won't be used by users, only us internally, I'd be with Luke on that one and avoid the allocation vs having something more friendly.
From what I understand, we're creating a new instance each time we deserialize a type.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't think we create new instances everytime we deserialize a type here. why do you think that's the case @LukeStampfli ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Because NetworkVariable ReadDelta is a bit messy.

So it looks like we allocate anyways no matter whether we use a struct or class here 😞

private void OnNetworkStateChanged(NetworkState oldState, NetworkState newState)
{
void SetupVar<T>(NetworkVariable<T> v, T initialValue, ref T oldVal)
if (!NetworkObject.IsSpawned)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This should never happen right? Maybe throw/assert here.

Copy link
Copy Markdown
Contributor Author

@0xFA11 0xFA11 Jul 20, 2021

Choose a reason for hiding this comment

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

yeah, I agree it "should never happen" except it does :)
I'm not sure why (haven't digged into this deeply yet), even though we're not setting m_NetworkState or setting any of its values on Awake or anything.
maybe there's something (in Noel's terms) "order of operations" going on behind the scenes I couldn't grok the details yet.
but hey, it's a little innocent early return here :P (and it only happens once as far as I can tell).
I will comment "should never happen but it does" inline too

m_CurrentScale != m_OldScale
)
{
Debug.LogError($"Trying to update transform's position for object {gameObject.name} with ID {NetworkObjectId} when you're not allowed, please validate your {nameof(NetworkTransform)}'s authority settings. It's also possible you have other systems updating your transform's position, such as a rigid body for example.", gameObject);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd really keep that this error message. It's important to guide users so they don't have silent errors.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

there is no error condition in the new flow. we simply do not care. it's not an error?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

from what I tested with your branch, the transform just doesn't move if it doesn't have the authority. It looks very frustrating. "Why does my code updating that object's transform doesn't do anything??"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

huh, let me try a couple of things there.

@SamuelBellomo
Copy link
Copy Markdown
Contributor

I really like putting everything in a single state, it simplifies a lot of the
"do this for position, do this for rotation, do this for scale" code duplication :)

@0xFA11 0xFA11 enabled auto-merge (squash) July 22, 2021 01:15
@0xFA11 0xFA11 merged commit 34b161a into develop Jul 22, 2021
@0xFA11 0xFA11 deleted the feat/mtt-818 branch July 22, 2021 01:30
SamuelBellomo added a commit that referenced this pull request Jul 23, 2021
…nsform

* develop:
  feat: pack NetworkTransform into one state variable, prevent sync popping (MTT-818) (#964)
  feat!: Network Time (RFC #14) (#845)
  test: small fix to ManualNetworkVariableTest.cs, exposed during anoth… (#968)

# Conflicts:
#	com.unity.multiplayer.mlapi/Prototyping/NetworkTransform.cs
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