Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

NetworkList and NetworkDictionary not working anymore...

Discussion in 'Netcode for GameObjects' started by Altalus06, Jun 4, 2021.

  1. Altalus06

    Altalus06

    Joined:
    Sep 3, 2017
    Posts:
    12
    Hello,

    I encountered some problems using NetworkList and NetworkDictionary in this new experimental MLAPI version (while they were working in previous MLAPI version).
    Server is sending delta correctly, but data received by the client are completely inconsistent.

    Watching to source code, it seems that the problem come from the lack of "RemoteTick" implementation in the method "WriteDelta"...

    I created a new NetworkDictionary class in a test project, duplicating original MLAPI NetworkDictionary source code, then just doing this solved the problem:

    Code (csharp):
    1.  
    2. public void WriteDelta(Stream stream)
    3. {
    4. using (var writer = PooledNetworkWriter.Get(stream))
    5. {
    6. writer.WriteUInt16Packed(NetworkTickSystem.NoTick); // Missing in original MLAPI
    7. NetworkDictionary writer.WriteUInt16Packed((ushort)m_DirtyEvents.Count);
    8.  
    Hope it can help people impacted by this problem
    Cheers
     
    luke-unity likes this.
  2. RobertGrospitch

    RobertGrospitch

    Joined:
    Sep 8, 2020
    Posts:
    7
    Thanks! Where are you getting the original NetworkDictionary source code? Are you creating a entire new class? Do you have to remove the old class? Currently messing around and cannot seem to pinpoint the file you are talking about.

    EDIT:
    I was able to find the WriteDelta in the original NetworkList script and it is as follows
    Code (CSharp):
    1.         public void WriteDelta(Stream stream)
    2.         {
    3.             using (var writer = PooledNetworkWriter.Get(stream))
    4.             {
    5.                 for (int i = 0; i < m_DirtyEvents.Count; i++)
    6.                 {
    7.                     writer.WriteBits((byte)m_DirtyEvents[i].Type, 3);
    8.                     switch (m_DirtyEvents[i].Type)
    9.                     {
    10.                         case NetworkListEvent<T>.EventType.Add:
    11.                         {
    12.                             writer.WriteObjectPacked(m_DirtyEvents[i].Value); //BOX
    13.                         }
    14.                             break;
    15.                         case NetworkListEvent<T>.EventType.Insert:
    16.                         {
    17.                             writer.WriteInt32Packed(m_DirtyEvents[i].Index);
    18.                             writer.WriteObjectPacked(m_DirtyEvents[i].Value); //BOX
    19.                         }
    20.                             break;
    21.                         case NetworkListEvent<T>.EventType.Remove:
    22.                         {
    23.                             writer.WriteObjectPacked(m_DirtyEvents[i].Value); //BOX
    24.                         }
    25.                             break;
    26.                         case NetworkListEvent<T>.EventType.RemoveAt:
    27.                         {
    28.                             writer.WriteInt32Packed(m_DirtyEvents[i].Index);
    29.                         }
    30.                             break;
    31.                         case NetworkListEvent<T>.EventType.Value:
    32.                         {
    33.                             writer.WriteInt32Packed(m_DirtyEvents[i].Index);
    34.                             writer.WriteObjectPacked(m_DirtyEvents[i].Value); //BOX
    35.                         }
    36.                             break;
    37.                         case NetworkListEvent<T>.EventType.Clear:
    38.                         {
    39.                             //Nothing has to be written
    40.                         }
    41.                             break;
    42.                     }
    43.                 }
    44.             }
    45.         }
    Can I add that missing line directly into the Write Delta for it to work? Or do I need to create a brand new class like you were talking about? If I do create this class do I need to delete this one that is already here?

    Thank you!
     
    Last edited: Jun 4, 2021
  3. Altalus06

    Altalus06

    Joined:
    Sep 3, 2017
    Posts:
    12
    The original source code can be found doing a search in project tab, selecting "In Packages" as search option

    upload_2021-6-4_16-44-48.png

    You will the need to create a completly new class from this original class (otherwise, unity will revert any modification done in original class source code).
    Just name you new class with a new name (such as "MLAPINetworkDictionary" for instance)
    And add the missing line in WriteDelta of this new class, at the exact location indicated in my other post

    For me, doing this solved the problem, and the Dictionary was replicated without any problems
     
  4. RobertGrospitch

    RobertGrospitch

    Joined:
    Sep 8, 2020
    Posts:
    7

    Thank you! I have everything working and syncing now properly.

    One other question, when I created the new class there are obviously now multiple classes using the NetworkListevent<> and showing warnings in the inspector. Since I cannot delete the old NetworkList script should I just ignore these by disabling warnings in the console? Or is there a way to not this this warning for this exact conflict?

    upload_2021-6-4_11-31-47.png
     
  5. Altalus06

    Altalus06

    Joined:
    Sep 3, 2017
    Posts:
    12
    Just delete the public struct NetworkDictionaryEvent<TKey, TValue> in your new class, and use the original one instead (the one in MLAPI source code)
     
  6. RobertGrospitch

    RobertGrospitch

    Joined:
    Sep 8, 2020
    Posts:
    7
    Another problem has arisen that I was wondering if you had any incite on. I currently have this script on a netowork object in the scene and am writing data from each player.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using MLAPI;
    5. using MLAPI.Messaging;
    6. using MLAPI.NetworkVariable;
    7. using MLAPI.NetworkVariable.Collections;
    8.  
    9. public class ScoreboardNetworkVariables : NetworkBehaviour
    10. {
    11.  
    12.  
    13.     [SerializeField] public MLAPINetworkList<ulong> PlayerClientID = new MLAPINetworkList<ulong>(new NetworkVariableSettings { WritePermission = NetworkVariablePermission.Everyone, ReadPermission = NetworkVariablePermission.Everyone });
    14.     [SerializeField] public MLAPINetworkList<int> PlayerKills = new MLAPINetworkList<int>(new NetworkVariableSettings { WritePermission = NetworkVariablePermission.Everyone, ReadPermission = NetworkVariablePermission.Everyone });
    15.     [SerializeField] public MLAPINetworkList<int> PlayerDeaths = new MLAPINetworkList<int>(new NetworkVariableSettings { WritePermission = NetworkVariablePermission.Everyone, ReadPermission = NetworkVariablePermission.Everyone });
    16.  
    17.  
    18.     //Current GameObject
    19.     private NetworkObject currentPlayerReading;
    20.  
    21.     //Getting both scripts on current player object
    22.     PlayerKillsDeaths playerKillsDeaths;
    23.     CurrentPlace currentPlace;
    24.  
    25.     private void Start()
    26.     {
    27.  
    28.         if (IsServer)
    29.         {
    30.             //Wait 1 Second then fill all the initial array vales with data
    31.             //This includes Player ID, Kills, Deaths, Username
    32.             StartCoroutine(FillScoreboardValues());
    33.         }
    34.     }
    35.  
    36.  
    37.     public void PopulatePlayerInformation()
    38.     {
    39.         for (int i = 0; NetworkManager.Singleton.ConnectedClientsList.Count > i; i++)
    40.         {
    41.             //Addubg first player ID to the player ID list
    42.             PlayerClientID.Add(NetworkManager.Singleton.ConnectedClientsList[i].ClientId);
    43.             //Gettign the current player that it is reading by the client ID
    44.             currentPlayerReading = NetworkManager.Singleton.ConnectedClients[PlayerClientID[i]].PlayerObject;
    45.             //Gettubg the current kills and deaths scritp from the player that it is reading from
    46.             playerKillsDeaths = currentPlayerReading.GetComponent<PlayerKillsDeaths>();
    47.             //Getting the current place script from the player that it is reading from
    48.             currentPlace = currentPlayerReading.GetComponent<CurrentPlace>();
    49.             //Adding the starting player kills for the current player to this list
    50.             PlayerKills.Add(playerKillsDeaths.playerKills.Value);
    51.             //Adding the starting player deaths for the current player to this list
    52.             PlayerDeaths.Add(playerKillsDeaths.playerDeaths.Value);
    53.             //Printing the current id kills and deaths for the player
    54.             Debug.Log("Client ID: " + PlayerClientID[i] + " " + "Player Kills: " + PlayerKills[i] + " " + "Player Deaths: " + PlayerDeaths[i]);;
    55.         }
    56.     }
    57.  
    58.     IEnumerator FillScoreboardValues()
    59.     {
    60.         yield return new WaitForSeconds(1f);
    61.         PopulatePlayerInformation();
    62.     }
    63.  
    64. }
    65.  
    The code above waits for all players to get into the game pulls the starting data and saves it into an NetworkList. This code is set to only run if we are the server, however, I am now getting an out of bounds error on the client side. It is saying that there is an IndexOutOfRangeException and reffering to the ReadByteMisalinged() ReadDelta in the new script that I had created.

    upload_2021-6-8_10-0-51.png

    I don't see why this would be working on the server absolutely fine but throw an error on the client unless it is trying to sync the LIST Data and getting that error. Would there by anything that I would have to add to the ReadDelta part of the NetworkList class as well?
     
  7. Altalus06

    Altalus06

    Joined:
    Sep 3, 2017
    Posts:
    12
    I haven't got this bug already.
    No real solution to propose :(

    The only other bug I found was when "Add" is called while the array key already exists...so, as the dictionary key is not checked in Readelta and Readfiel in this case, an exception is thrown.
    The easy solution is to modify the code "m_Dictionary.Add(key, value);" in both methods, doing an update instead of add if key exists
     
  8. bindon

    bindon

    Joined:
    May 25, 2017
    Posts:
    20
    Is there a similar fix for NetworkList as there is for NetworkDictionary?
    I don't seem to be able to get it to work.

    I understand that this file has a bug in it, but I don't understand what I need to do to fix it

    https://github.com/Unity-Technologi...me/NetworkVariable/Collections/NetworkList.cs

    I tried adding in
    writer.WriteUInt16Packed(NetworkTickSystem.NoTick);

    like you did with NetworkDictionary but that didn't make it work.

    Please, is there any chance someone could post an entire NetworkList.cs that works?
    That would be really helpful to me.

    UPDATE:
    I managed to get NetworkList to work by using the develop branch of MLAPI github repository as @ 31st July 2021 instead of the release version of MLAPI ie. 0.1.0 ! :)

    ie.
    https://github.com/Unity-Technologi...git?path=/com.unity.multiplayer.mlapi#develop

    instead of
    https://github.com/Unity-Technologi...th=/com.unity.multiplayer.mlapi#release/0.1.0
     
    Last edited: Jul 31, 2021