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
refactor!: remove network dictionary & set, use native container in List, add tests #1149
refactor!: remove network dictionary & set, use native container in List, add tests #1149
Conversation
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkDictionary.cs
Outdated
Show resolved
Hide resolved
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkDictionary.cs
Show resolved
Hide resolved
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkDictionary.cs
Show resolved
Hide resolved
@@ -127,33 +109,6 @@ public override void ReadDelta(Stream stream, bool keepDirtyDelta) | |||
} | |||
} | |||
break; | |||
case NetworkDictionaryEvent<TKey, TValue>.EventType.RemovePair: |
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.
I can't see a good reason for RemovePair. This was a holdover from implementing IDictionary. We didn't actually do anything special like deal with if you remove an existing key with a mismatched value, and to me implementing this is unnecessarily complicated, hence out it goes.
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkDictionary.cs
Outdated
Show resolved
Hide resolved
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkDictionary.cs
Show resolved
Hide resolved
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkDictionary.cs
Show resolved
Hide resolved
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkDictionary.cs
Show resolved
Hide resolved
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkDictionary.cs
Outdated
Show resolved
Hide resolved
@@ -79,6 +81,12 @@ public void Awake() | |||
TheDictionary.OnDictionaryChanged += DictionaryChanged; | |||
} | |||
|
|||
public void OnDestroy() |
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.
Horrible, again, I could use some help on how to avoid needing this to avoid leaks (or at least leak warnings!)
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.
since NetworkSet
is still a class, we could use its dtor to dispose underlying data structure there.
but if/when we turn it into a struct, we'll need to call Dispose() on it explicitly.
it's generally a good practice to use MonoBehaviour's Awake/OnDestroy pairs for alloc/free.
I think these look good to me, except I'd alloc TheSet in the Awake method instead of relying on ctor. (future-proofing)
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.
I don't think we can use the dtor here because the Native Collection will complain, this is because dtors only happen when the GC happens which is not always when the object is specifically no longer referenced. So this is the proper location to Dispose the collection.
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.
There is no Awake, NetworkVariableBase is not a monobehaviour. That is why (and this is the part I truly I don't like) this 'OnDestroy()' has to be called in the OnDestroy() method of NetworkVariableTests.
Maybe instead I need to NetworkBehaviour scan and clean up its NetworkVariable instances...
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.
oh, that makes sense.
on the second comment though, whatever creates/registers/initializes NetVar should clean it — in this case, sounds like NetBhv might be a good candidate for that since it registers NetVars and could clean them up in its OnDestroy().
I don't remember the code very well though, if we recreate (therefore down the line realloc) them on connect/spawn, we might pair spawn/despawn, if not, we might dealloc on OnDestroy().
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkSet.cs
Outdated
Show resolved
Hide resolved
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkSet.cs
Show resolved
Hide resolved
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkSet.cs
Show resolved
Hide resolved
Hey @mattwalsh-unity after looking through these changes and after speaking to some people internally, I came to the conclusion that I cannot find use-cases where we would need to replicate a NetworkedSet or a NetworkDictionary? Could perhaps help me understand what is the value that we are putting out there to the users having a NetworkedSet or NetworkDictionary? In 99% of my previous projects, I never needed a replicated set or map, and in the cases that I did needed I found other ways to go around with just a simple NetworkedList or a fixedList. |
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkSet.cs
Outdated
Show resolved
Hide resolved
"version": "2.0.9", | ||
"version": "2.0.8", |
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.
not needed :P
com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkSet.cs
Outdated
Show resolved
Hide resolved
I agree with you Replicated Containers in general are messy and often a case of "Hey I want to shoot myself please give me that loaded gun without safety". I don't see a real use case for map and set (even dynamic size lists are often more buggy than useful) that cannot be better implemented as a List (often fixed-size) of buckets (example inventory). |
I somewhat disagree with this. Users use dictionaries and hashsets in their single player code all the time and it's dead simple. To replicate that kind of state without the prebuilt options, it's a huge PITA. I agree that we shouldn't provide unsafe tools for our users, but I think we shouldn't rule out the use cases for replicating dictionaries and sets without adequate research if our goal is to make multiplayer easy for our users. |
"to make multiplayer easy" we still need to have constraints/limits on I'm leaning not towards any direction, just wanted to reply to that argument :) |
Sadly I will disagree with you on this... I don't know if any engine that supports replication of dictionaries out of the box, and I can't recall a time where I wanted or needed to use one to replicate. To me personally promoting the replication of these kinds of things is just bad practice and what we have there today is just not the right solution. |
(Responding to both Fatih and Andrew's replies, github conversations suck) I can't say that I've had a use case for this either and I'm not so much advocating we keep this specific implementation or even necessarily any implementation if we find that it's not needed. My point is that I think our default stance should be "Provide multiplayer analogs for common single player tools" and then research where we can make exceptions, instead of the other way around. So far the justification for removing these seems to be "no one internally has a use case" which seems like a pretty weak case to me. That said if we feel these implementations shouldn't exist today because we're trying to deliver 1.0 with the smallest stable foundation possible, I have no argument with that. My argument is with justifying its removal from project scope with limited internal discussion. |
I generally agree with you but my main concern is "Provide multiplayer analogs for common single player tools" the issue I have with this is that we allow you to pretty much write any C# you want and that is a rather large API surface to support. I think we should be good about making sure that things that interact with unity things do work as good as their single player parts but I can't think that you would suggest that we just support all C# because that is the API surface for single player games. We don't have the luxury of DOTS or Unreal etc... which have placed restrictions on what you can and cannot do in their eco system and I do think we should be able to look at those same considerations while still wanting folks to have their single player and multiplayer games be similar. |
@@ -824,5 +824,13 @@ protected NetworkObject GetNetworkObject(ulong networkId) | |||
{ | |||
return NetworkManager.SpawnManager.SpawnedObjects.TryGetValue(networkId, out NetworkObject networkObject) ? networkObject : null; | |||
} | |||
|
|||
// public void OnDestroy() |
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.
This is the last issue I need to resolve; I really hoped this would work as it would make cleanup automatic.
// registered here and therefore won't be cleaned up. | ||
// | ||
// we should study to understand the initialization patterns | ||
if (!m_VarInit) |
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.
Again, there is something weird on why - in tests anyway - we instantiate a NB band then ditch it before we ever call InitializeVariables. But regardless, we are now saying that Netvars need a chance to be disposed, and this ensures we don't skip any. There are certainly better ways to register the netvars than the scan in InitializeVariables which we can look at later which might eliminate the need for this
} | ||
} | ||
|
||
public NetworkList(NetworkVariableReadPermission readPerm, NativeList<T> values) : base(readPerm) |
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.
Matt to check if I can pass in INativeList (or read-only collection,etc.) just for the constructor
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.
IEnumerable<T>
it is :)
@@ -118,5 +118,9 @@ public virtual bool CanClientWrite(ulong clientId) | |||
/// <param name="stream">The stream to read the delta from</param> | |||
/// <param name="keepDirtyDelta">Whether or not the delta should be kept as dirty or consumed</param> | |||
public abstract void ReadDelta(Stream stream, bool keepDirtyDelta); | |||
|
|||
public virtual void Dispose() |
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.
Prefer IDisposable
using UnityEngine; | ||
using UnityEngine.TestTools; | ||
using NUnit.Framework; | ||
using Unity.Collections; | ||
|
||
// TODO: guard write operations |
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.
Clean up comment
() => | ||
Assert.IsTrue(m_Player1OnServer.TheList.Count == 3); | ||
|
||
int now = 0; |
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.
change to 'index'
…Unity-Technologies/com.unity.multiplayer.mlapi into refactor/simplify_collection_interfaces
…nsform * develop: feat: NetworkBehaviour.IsSpawned (#1190) feat: added tip to the network manager inspector that directs to install tools (MTT-1211) (#1182) refactor!: remove network dictionary & set, use native container in List, add tests (#1149) fix: Fixed remote disconnects not properly cleaning up (#1184) test: base changes to PR-1114 (#1165) test: verify do not destroy networkobjects on networkmanager shutdown (#1183) chore: removal of EnableNetworkVariable in NetworkConfig. It's always True now (#1179) fix: Fix DontDestroyWithOwner not returning ownership (#1181) test: Giving Android some more room as the connection tests are timing sensitive (#1178) fix: unitytransport connectionmode buttons (#1176) test: added min frames to multi-instance helper (#1170) chore: Add mobile tests to nightly trigger (#1161) feat: snapshot spawn pre-requisite (#1166) feat: Unity Transport + Relay (#887) feat: client scene synchronization mode (#1171) # Conflicts: # testproject/Assets/Scenes/SampleScene.unity
…am/feature/client-network-transform * sam/feature/interpolation-for-network-transform: (22 commits) fixing line issue more formatting fixing formatting issue removing not submitted LiteNetLib from ZooSam feat: Fast buffer reader and fast buffer writer (#1082) restricting public api bumping exec order feat: NetworkBehaviour.IsSpawned (#1190) feat: added tip to the network manager inspector that directs to install tools (MTT-1211) (#1182) refactor!: remove network dictionary & set, use native container in List, add tests (#1149) fix: Fixed remote disconnects not properly cleaning up (#1184) test: base changes to PR-1114 (#1165) test: verify do not destroy networkobjects on networkmanager shutdown (#1183) chore: removal of EnableNetworkVariable in NetworkConfig. It's always True now (#1179) fix: Fix DontDestroyWithOwner not returning ownership (#1181) test: Giving Android some more room as the connection tests are timing sensitive (#1178) fix: unitytransport connectionmode buttons (#1176) test: added min frames to multi-instance helper (#1170) chore: Add mobile tests to nightly trigger (#1161) feat: snapshot spawn pre-requisite (#1166) ... # Conflicts: # com.unity.netcode.gameobjects/Components/NetworkTransform.cs # testproject/Assets/Scenes/SampleScene.unity
I'm working to upgrade my project from 0.1.0 and ran into all my NetworkList and NetworkDictionaries no longer supported due to their removal. Is there a good alternative or best practice for replacing these? Seems like support was dropped without any communication in the docs. https://docs-multiplayer.unity3d.com/docs/migration/upgrade-guide It sounds like they were removed due to the amount of work required to support them, is that right? |
hey @JadenH, |
Is there any alternative to network dictionaries? And I don't want to be told to just use network list. I get that it's "bad practice" but it's really unwarranted to remove a feature like this when the alternative is a deprecated system, and the documentation for the new system is pitiful at best. The link two comments earlier isn't even a year old and it's already broken. |
…ist, add tests (Unity-Technologies#1149) * refactor!: clean up network dictionary, use native containers * added dirty list as native container * remove set & dictionary * list cleanup * more tests * rounded out xtors in NetworkList * improved ienumerable, removed client writability Co-authored-by: Andrew Spiering <andrews@unity3d.com>
This started with a fix observed by @ShadauxCat to avoid boxing in the constructor. I had wanted to (but deferred) simplify the operations that these containers do to be more aligned with what native containers support (mostly, removing the Set operations). It then dawned on me that having them derive from ISet<>, IDictionary<>, etc. wasn't providing any value other than forcing the classes to implement things that in a netcode context aren't always sensible. And when I removed that, it was only a small amount of work to swap in the native containers.