Search Unity

SyncList not initialized

Discussion in 'Multiplayer' started by Kesarium, Jul 21, 2017.

  1. Kesarium

    Kesarium

    Joined:
    Dec 3, 2014
    Posts:
    56
    I'm facing a problem with my multiplayer game. I'm using a SyncListStruct for each treasure chest, which holds all the items inside the chest, and these items are shared between all players. The code seems to work fine when you're playing the game but when script debugging is enabled or you look in the logs you can see 6 'SyncList not initialized' errors. These are from the inactive treasure chests in the scene, and by inactive I mean their collision and renderer are inactive, all of their scripts and their game objects are still active.

    Now here's the weird part. When I run either the host or the client in the editor and connect the other with the .exe these errors show up in the host and client logs. When I run both the host and client from the .exe the errors only show on the client.

    I stumbled upon these errors in the log when trying to figure out why the client is always getting disconnected from the host after approximately 25 minutes of playing the game. I've been looking at forum posts of similar issues and anything from those posts that I try just doesn't solve the problem.

    Here is the error in the client's log that occurs 6 times when both the host and client are run from an .exe:

    SyncList not initialized
    0x00007FF6E34C1A24 (Quest)
    0x00007FF6E34C5122 (Quest)
    0x00007FF6E37F56A1 (Quest)
    0x00007FF6E3B2B274 (Quest)
    0x00007FF6E3B2B70C (Quest)
    0x00007FF6E4044718 (Quest)
    0x0000000006D97E33 (Mono JIT Code) (wrapper managed-to-native) UnityEngine.DebugLogHandler:Internal_Log (UnityEngine.LogType,string,UnityEngine.Object)
    0x0000000006D97C94 (Mono JIT Code) [DebugLogHandler.cs:9] UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])
    0x0000000006D97595 (Mono JIT Code) [Logger.cs:47] UnityEngine.Logger:Log (UnityEngine.LogType,object)
    0x000000004F74B8B3 (Mono JIT Code) [DebugBindings.gen.cs:124] UnityEngine.Debug:LogError (object)
    0x000000004F74AE44 (Mono JIT Code) [SyncList.cs:295] UnityEngine.Networking.SyncList`1<LootShared/SharedItem>:SendMsg (UnityEngine.Networking.SyncList`1/Operation<LootShared/SharedItem>,int,LootShared/SharedItem)
    0x000000004F74AC79 (Mono JIT Code) [SyncList.cs:338] UnityEngine.Networking.SyncList`1<LootShared/SharedItem>:SendMsg (UnityEngine.Networking.SyncList`1/Operation<LootShared/SharedItem>,int)
    0x000000004F74A99C (Mono JIT Code) [SyncList.cs:395] UnityEngine.Networking.SyncList`1<LootShared/SharedItem>:Clear ()
    0x000000004F74A6F9 (Mono JIT Code) Unity.GeneratedNetworkCode:_ReadStructSyncListSharedItem_LootShared (UnityEngine.Networking.NetworkReader,LootShared/SyncListSharedItem)
    0x000000004F74A265 (Mono JIT Code) LootShared:OnDeserialize (UnityEngine.Networking.NetworkReader,bool)
    0x000000004F743C60 (Mono JIT Code) [NetworkIdentity.cs:750] UnityEngine.Networking.NetworkIdentity:OnUpdateVars (UnityEngine.Networking.NetworkReader,bool)
    0x000000004F74375F (Mono JIT Code) [ClientScene.cs:491] UnityEngine.Networking.ClientScene:ApplySpawnPayload (UnityEngine.Networking.NetworkIdentity,UnityEngine.Vector3,byte[],UnityEngine.Networking.NetworkInstanceId,UnityEngine.GameObject)
    0x000000004F740568 (Mono JIT Code) [ClientScene.cs:608] UnityEngine.Networking.ClientScene:OnObjectSpawnScene (UnityEngine.Networking.NetworkMessage)
    0x000000004F7372CC (Mono JIT Code) [NetworkConnection.cs:469] UnityEngine.Networking.NetworkConnection:HandleReader (UnityEngine.Networking.NetworkReader,int,int)
    0x000000004F73689B (Mono JIT Code) [NetworkConnection.cs:425] UnityEngine.Networking.NetworkConnection:HandleBytes (byte[],int,int)
    0x000000004F73673F (Mono JIT Code) [NetworkConnection.cs:576] UnityEngine.Networking.NetworkConnection:TransportReceive (byte[],int,int)
    0x000000002D62A13F (Mono JIT Code) [NetworkClient.cs:753] UnityEngine.Networking.NetworkClient:Update ()
    0x000000002D6293DD (Mono JIT Code) [NetworkClient.cs:965] UnityEngine.Networking.NetworkClient:UpdateClients ()
    0x000000002D628FB4 (Mono JIT Code) [NetworkIdentity.cs:1091] UnityEngine.Networking.NetworkIdentity:UNetStaticUpdate ()
    0x0000000006D00ADE (Mono JIT Code) (wrapper runtime-invoke) object:runtime_invoke_void (object,intptr,intptr,intptr)
    0x00007FFDFFCC5B63 (mono) mono_set_defaults
    0x00007FFDFFC1872D (mono) mono_runtime_invoke
    0x00007FF6E3DAB3F4 (Quest)
    0x00007FF6E3DA6101 (Quest)
    0x00007FF6E3C2FD60 (Quest)
    0x00007FF6E3BA90A1 (Quest)
    0x00007FF6E34EBCF0 (Quest)
    0x00007FF6E34EBE9A (Quest)
    0x00007FF6E34FA454 (Quest)
    0x00007FF6E48907D0 (Quest)
    0x00007FFE37DC2774 (KERNEL32) BaseThreadInitThunk
    0x00007FFE386C0D51 (ntdll) RtlUserThreadStart
    (Filename: C:/buildslave/unity/build/artifacts/generated/common/runtime/DebugBindings.gen.cpp Line: 51)

    I'm using Unity 2017.1.0f3 and building for Windows x86_64. The computer I'm using has Windows 10 (64-bit) on it. I've been working on this project since 2015 and have been upgrading it alongside Unity version updates as they come out. I'm just curious if this might be a bug with Unity or if its something on my end. Its a big project but I can try to provide more information if needed.
     
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    I think you're trying to use SyncLists from somewhere when it's not yet ready. E.g. Start or Awake, or something in that scope.

    Since SyncLists cannot be used before server/client is ready you're receiving this message;
    On the disconnect topic - make sure you're not running into 4kb/s Unet cap, that there isn't memory leak somewhere, and message don't get stuck in queue.
     
  3. Kesarium

    Kesarium

    Joined:
    Dec 3, 2014
    Posts:
    56
    My code for the client doesn't do anything with the SyncListStruct if it is null, nor does the client try to read the variable further after the null reference check if its null. The client never tries to modify the SyncListStruct either, it only sends a command if the client wants to take an item out of the chest, which it doesn't right at the joining of the client and server.

    The server will populate that sharedItems SyncListStruct only when the network is set up and the host player has spawned in the game. The client never tries to add anything to that list and it never tries to clear it.
     
  4. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    You could, and should remove those checks, since in theory it's never null. If you're initializing it properly.
     
  5. Kesarium

    Kesarium

    Joined:
    Dec 3, 2014
    Posts:
    56
    This is the code from the LootShared.cs file, which is where I declare the Struct and initialize and use the SyncListStruct. The declaration has been moved around and modified different ways when working from some other forum search results but none of the proposed solutions solved this. The whole file might not be necessary but here it is anyway.

    Code (csharp):
    1.  
    2. public class LootShared : NetworkBehaviour
    3. {
    4.     public struct SharedItem
    5.     {
    6.         public int ID;
    7.         public string Title;
    8.         public string Type;
    9.         public string SubType;
    10.         public string MaterialType;
    11.         public int MaterialAmount;
    12.         public int DurabilityMax;
    13.         public int Durability;
    14.         public int Value;
    15.         public int ShopValue;
    16.         public int Damage;
    17.         public float AttackSpeed;
    18.         public int Armor;
    19.         public int Vitality;
    20.         public int Stamina;
    21.         public int Wisdom;
    22.         public int Strength;
    23.         public int Dexterity;
    24.         public int Intelligence;
    25.         public int HealthRegen;
    26.         public int EnergyRegen;
    27.         public int ManaRegen;
    28.         public string Description;
    29.         public string[] Special;
    30.         public bool Stackable;
    31.         public bool Consumable;
    32.         public int Rarity;
    33.         public bool RandomQuality;
    34.         public string Slug;
    35.         public int Quantity;
    36.     };
    37.  
    38.  
    39.  
    40.     public class SyncListSharedItem : SyncListStruct<SharedItem> {}
    41.  
    42.     public SyncListSharedItem sharedItems = new SyncListSharedItem ();
    43.  
    44.  
    45.  
    46.     [SyncVar] public bool decaying;
    47.     [SyncVar] public float decayTime;
    48.     [SyncVar] public float decayTimer;
    49.  
    50.  
    51.  
    52.     public NetworkIdentity myNetworkIdentity;
    53.  
    54.  
    55.  
    56.     void Start()
    57.     {
    58.         if (this.transform.GetComponent<Enemy>() != null)
    59.         {
    60.             StartCoroutine(Countdown_Decay(1f));
    61.         }
    62.         else
    63.         {
    64.             if (this.transform.GetComponent<StaticChestHolder>() == null)
    65.             {
    66.                 StartCoroutine (Countdown_Decay (decayTime));
    67.             }
    68.         }
    69.     }
    70.  
    71.  
    72.  
    73.     IEnumerator Countdown_Decay(float DELAY)
    74.     {
    75.         yield return new WaitForSeconds(DELAY);
    76.  
    77.         if(this.transform.GetComponent<Enemy>() != null)
    78.         {
    79.             if(this.transform.GetComponent<Enemy>().isDead())
    80.             {
    81.                 Decay();
    82.             }
    83.             else
    84.             {
    85.                 StartCoroutine(Countdown_Decay(1f));
    86.             }
    87.         }
    88.         else
    89.         {
    90.             Decay();
    91.         }
    92.     }
    93.  
    94.  
    95.  
    96.     public void Decay()
    97.     {
    98.         if (this != null)
    99.         {
    100.             if (this.gameObject.GetComponent<Enemy>() != null)
    101.             {
    102.                 if (ClickToMove.myInventory.lootWindow.lootGameObject != null &&
    103.                     ClickToMove.myInventory.lootWindow.lootGameObject.GetInstanceID() == this.gameObject.GetInstanceID())
    104.                 {
    105.                     ClickToMove.myInventory.lootWindow.Close();
    106.                 }
    107.  
    108.                 if (isServer)
    109.                 {
    110.                     decaying = false;
    111.                     decayTimer = 0f;
    112.  
    113.                     if (sharedItems != null && sharedItems.Count > 0)
    114.                     {
    115.                         sharedItems.Clear ();
    116.                     }
    117.                 }
    118.             }
    119.             else if (this.gameObject.GetComponent<StaticResource>() != null)
    120.             {
    121.  
    122.             }
    123.             else
    124.             {
    125.                 if (ClickToMove.myInventory.lootWindow.lootGameObject != null &&
    126.                     ClickToMove.myInventory.lootWindow.lootGameObject.GetInstanceID() == this.gameObject.GetInstanceID())
    127.                 {
    128.                     ClickToMove.myInventory.lootWindow.Close();
    129.                 }
    130.  
    131.                 if (isServer)
    132.                 {
    133.                     NetworkServer.Destroy(this.gameObject);
    134.                     //Destroy(this.gameObject);
    135.                 }
    136.             }
    137.         }
    138.     }
    139.  
    140.  
    141.  
    142.     void OnMouseOver()
    143.     {
    144.         if (Input.GetMouseButtonDown(1))
    145.         {
    146.             if (decaying)
    147.             {
    148.                 if (this.gameObject.GetComponent<StaticResource>() == null && this.gameObject.GetComponent<Enemy>() == null)
    149.                 {
    150.                     if (!ClickToMove.mouseOverInventory && !ClickToMove.mouseOverEquipment && !ClickToMove.mouseOverStats && !ClickToMove.mouseOverSkills && !ClickToMove.mouseOverAbilities &&
    151.                         !ClickToMove.mouseOverInstructions && !ClickToMove.mouseOverTalents && !ClickToMove.mouseOverLoot && !ClickToMove.mouseOverShop &&
    152.                         !ClickToMove.mouseOverInventoryBar && !ClickToMove.mouseOverEquipmentBar && !ClickToMove.mouseOverStatsBar && !ClickToMove.mouseOverSkillsBar && !ClickToMove.mouseOverAbilitiesBar &&
    153.                         !ClickToMove.mouseOverInstructionsBar && !ClickToMove.mouseOverTalentsBar && !ClickToMove.mouseOverLootBar && !ClickToMove.mouseOverShopBar && !ClickToMove.openLoot && !ClickToMove.openShop)
    154.                     {
    155.                         Open_Loot_Window();
    156.                     }
    157.                 }
    158.             }
    159.         }
    160.     }
    161.  
    162.     public void Open_Loot_Window()
    163.     {
    164.         if (!ClickToMove.myPlayer.isDead())
    165.         {
    166.             if(sharedItems != null && sharedItems.Count > 0)
    167.             {
    168.                 if (Vector3.Distance(this.transform.position, ClickToMove.myPlayerGameObject.transform.position) <= 2f)
    169.                 {
    170.                     if (!ClickToMove.openLoot)
    171.                     {
    172.                         ClickToMove.myInventory.lootWindow.OpenWindow(this.gameObject);
    173.                         ClickToMove.mouseRightClickedLootSack = true;
    174.                     }
    175.                 }
    176.             }
    177.         }
    178.     }
    179.  
    180.  
    181.  
    182.     public bool LootSelected(int index)
    183.     {
    184.         if(sharedItems != null && sharedItems.Count > 0)
    185.         {
    186.             if (ClickToMove.myInventory.AddNewItem(sharedItems[index]))
    187.             {
    188.                 ClickToMove.myLootTextManager.Gain_Text_Item("PICKED UP:  ", sharedItems[index].Slug, sharedItems[index].Quantity, sharedItems[index].Title, sharedItems[index].Rarity);
    189.  
    190.                 sharedItems.RemoveAt(index);
    191.  
    192.  
    193.  
    194.                 if (sharedItems.Count == 0)
    195.                 {
    196.                     ClickToMove.myPlayer.DestroyDroppedItem(myNetworkIdentity.netId);
    197.                 }
    198.  
    199.  
    200.  
    201.                 return true;
    202.             }
    203.         }
    204.  
    205.  
    206.  
    207.         return false;
    208.     }
    209.  
    210.     public void LootAll()
    211.     {
    212.         ClickToMove.myPlayer.DestroyDroppedItem(myNetworkIdentity.netId);
    213.     }
    214.  
    215.  
    216.  
    217.     public bool Looted()
    218.     {
    219.         if (sharedItems != null && sharedItems.Count > 0)
    220.         {
    221.             if (Vector3.Distance(this.transform.position, ClickToMove.myPlayerGameObject.transform.position) <= 1.5f)
    222.             {
    223.                 if (!ClickToMove.openLoot)
    224.                 {
    225.                     ClickToMove.myInventory.lootWindow.OpenWindow(this.gameObject);
    226.  
    227.                     return true;
    228.                 }
    229.             }
    230.         }
    231.  
    232.         return false;
    233.     }
    234.  
    235.  
    236.  
    237.     public void Create_Item(Item ITEM)
    238.     {
    239.         SharedItem newItem = new SharedItem();
    240.  
    241.         newItem.ID = ITEM.ID;
    242.         newItem.Title = ITEM.Title;
    243.         newItem.Type = ITEM.Type;
    244.         newItem.SubType = ITEM.SubType;
    245.         newItem.MaterialType = ITEM.MaterialType;
    246.         newItem.MaterialAmount = ITEM.MaterialAmount;
    247.         newItem.DurabilityMax = ITEM.DurabilityMax;
    248.         newItem.Durability = ITEM.Durability;
    249.         newItem.Value = ITEM.Value;
    250.         newItem.ShopValue = ITEM.ShopValue;
    251.         newItem.Damage = ITEM.Damage;
    252.         newItem.AttackSpeed = ITEM.AttackSpeed;
    253.         newItem.Armor = ITEM.Armor;
    254.         newItem.Vitality = ITEM.Vitality;
    255.         newItem.Stamina = ITEM.Stamina;
    256.         newItem.Wisdom = ITEM.Wisdom;
    257.         newItem.Strength = ITEM.Strength;
    258.         newItem.Dexterity = ITEM.Dexterity;
    259.         newItem.Intelligence = ITEM.Intelligence;
    260.         newItem.HealthRegen = ITEM.HealthRegen;
    261.         newItem.EnergyRegen = ITEM.EnergyRegen;
    262.         newItem.ManaRegen = ITEM.ManaRegen;
    263.         newItem.Description = ITEM.Description;
    264.         newItem.Special = ITEM.Special;
    265.         newItem.Stackable = ITEM.Stackable;
    266.         newItem.Consumable = ITEM.Consumable;
    267.         newItem.Rarity = ITEM.Rarity;
    268.         newItem.RandomQuality = ITEM.RandomQuality;
    269.         newItem.Slug = ITEM.Slug;
    270.         newItem.Quantity = ITEM.Quantity;
    271.  
    272.         sharedItems.Add (newItem);
    273.     }
    274.  
    275.     public void Create_Item(ItemDrop ITEM)
    276.     {
    277.         SharedItem newItem = new SharedItem();
    278.  
    279.         newItem.ID = ITEM.ID;
    280.         newItem.Title = ITEM.Title;
    281.         newItem.Type = ITEM.Type;
    282.         newItem.SubType = ITEM.SubType;
    283.         newItem.MaterialType = ITEM.MaterialType;
    284.         newItem.MaterialAmount = ITEM.MaterialAmount;
    285.         newItem.DurabilityMax = ITEM.DurabilityMax;
    286.         newItem.Durability = ITEM.Durability;
    287.         newItem.Value = ITEM.Value;
    288.         newItem.ShopValue = ITEM.ShopValue;
    289.         newItem.Damage = ITEM.Damage;
    290.         newItem.AttackSpeed = ITEM.AttackSpeed;
    291.         newItem.Armor = ITEM.Armor;
    292.         newItem.Vitality = ITEM.Vitality;
    293.         newItem.Stamina = ITEM.Stamina;
    294.         newItem.Wisdom = ITEM.Wisdom;
    295.         newItem.Strength = ITEM.Strength;
    296.         newItem.Dexterity = ITEM.Dexterity;
    297.         newItem.Intelligence = ITEM.Intelligence;
    298.         newItem.HealthRegen = ITEM.HealthRegen;
    299.         newItem.EnergyRegen = ITEM.EnergyRegen;
    300.         newItem.ManaRegen = ITEM.ManaRegen;
    301.         newItem.Description = ITEM.Description;
    302.         newItem.Special = ITEM.Special;
    303.         newItem.Stackable = ITEM.Stackable;
    304.         newItem.Consumable = ITEM.Consumable;
    305.         newItem.Rarity = ITEM.Rarity;
    306.         newItem.RandomQuality = ITEM.RandomQuality;
    307.         newItem.Slug = ITEM.Slug;
    308.         newItem.Quantity = ITEM.Quantity;
    309.  
    310.         sharedItems.Add (newItem);
    311.     }
    312.  
    313.     public void Create_Item(SharedItem ITEM)
    314.     {
    315.         SharedItem newItem = new SharedItem();
    316.  
    317.         newItem.ID = ITEM.ID;
    318.         newItem.Title = ITEM.Title;
    319.         newItem.Type = ITEM.Type;
    320.         newItem.SubType = ITEM.SubType;
    321.         newItem.MaterialType = ITEM.MaterialType;
    322.         newItem.MaterialAmount = ITEM.MaterialAmount;
    323.         newItem.DurabilityMax = ITEM.DurabilityMax;
    324.         newItem.Durability = ITEM.Durability;
    325.         newItem.Value = ITEM.Value;
    326.         newItem.ShopValue = ITEM.ShopValue;
    327.         newItem.Damage = ITEM.Damage;
    328.         newItem.AttackSpeed = ITEM.AttackSpeed;
    329.         newItem.Armor = ITEM.Armor;
    330.         newItem.Vitality = ITEM.Vitality;
    331.         newItem.Stamina = ITEM.Stamina;
    332.         newItem.Wisdom = ITEM.Wisdom;
    333.         newItem.Strength = ITEM.Strength;
    334.         newItem.Dexterity = ITEM.Dexterity;
    335.         newItem.Intelligence = ITEM.Intelligence;
    336.         newItem.HealthRegen = ITEM.HealthRegen;
    337.         newItem.EnergyRegen = ITEM.EnergyRegen;
    338.         newItem.ManaRegen = ITEM.ManaRegen;
    339.         newItem.Description = ITEM.Description;
    340.         newItem.Special = ITEM.Special;
    341.         newItem.Stackable = ITEM.Stackable;
    342.         newItem.Consumable = ITEM.Consumable;
    343.         newItem.Rarity = ITEM.Rarity;
    344.         newItem.RandomQuality = ITEM.RandomQuality;
    345.         newItem.Slug = ITEM.Slug;
    346.         newItem.Quantity = ITEM.Quantity;
    347.  
    348.         sharedItems.Add (newItem);
    349.     }
    350.  


    Here is the code for another related .cs file, the 'Spawner' for the treasure chests, its really just the manager of the treasure chests. In here is where the treasure chests are 'initialized' and synchronized. The chests aren't spawned over the network because I couldn't get a custom OnSpawn method to get called when something was spawned. So I just use RPCs to enable or disable a chest from a pool of chests for clients.

    Code (csharp):
    1.  
    2. public class StaticChestSpawner : NetworkBehaviour
    3. {
    4.     public GameObject[] pool;
    5.     public StaticChestHolder[] pool_StaticChestHolders;
    6.  
    7.     public float[] pool_Timers;
    8.  
    9.     public int spawnPoints;
    10.  
    11.     private bool readyToInitialize;
    12.     private bool initialized = false;
    13.     private bool initializedPool = false;
    14.  
    15.     public NetworkIdentity myNetworkIdentity;
    16.  
    17.  
    18.  
    19.     public void Initialize()
    20.     {
    21.         if (!readyToInitialize)
    22.         {
    23.             if (ClickToMove.myPlayer != null)
    24.             {
    25.                 readyToInitialize = true;
    26.             }
    27.         }
    28.  
    29.         if (!initialized && readyToInitialize)
    30.         {
    31.             pool_StaticChestHolders = new StaticChestHolder[pool.Length];
    32.             for (int a = 0; a < pool.Length; a++)
    33.             {
    34.                 pool_StaticChestHolders[a] = pool[a].GetComponent<StaticChestHolder>();
    35.                 pool_StaticChestHolders[a].myBoxCollider = pool_StaticChestHolders[a].myStaticChestGameObject.transform.GetComponent<BoxCollider> ();
    36.             }
    37.  
    38.            
    39.  
    40.             if (isServer)
    41.             {
    42.                 pool_Timers = new float[pool.Length];
    43.                 for (int a = 0; a < pool_Timers.Length; a++)
    44.                 {
    45.                     pool_Timers[a] = 0f;
    46.                 }
    47.  
    48.  
    49.  
    50.                 for (int a = 0; a < pool.Length; a++)
    51.                 {
    52.                     pool_StaticChestHolders[a].myStaticChestScript.spawnPoolID = a;
    53.  
    54.                     if (spawnPoints >= pool_StaticChestHolders[a].myStaticChestScript.spawnPoints && Random.Range(0, 100) <= pool_StaticChestHolders[a].myStaticChestScript.spawnChance)
    55.                     {
    56.                         spawnPoints -= pool_StaticChestHolders[a].myStaticChestScript.spawnPoints;
    57.  
    58.                         pool_StaticChestHolders[a].Spawn();
    59.                         pool_StaticChestHolders[a].chestEnabled = true;
    60.                         pool_StaticChestHolders[a].myMeshRendererBox.enabled = true;
    61.                         pool_StaticChestHolders[a].myMeshRendererLid.enabled = true;
    62.                         pool_StaticChestHolders[a].myNavMeshObstacle.enabled = true;
    63.                         pool_StaticChestHolders[a].myBoxCollider.enabled = true;
    64.                         CmdEnableChest(pool_StaticChestHolders[a].myStaticChestScript.spawnPoolID);
    65.                     }
    66.                     else
    67.                     {
    68.                         //pool_StaticChestHolders[a].Spawn();
    69.                         pool_StaticChestHolders[a].chestEnabled = false;
    70.                         pool_StaticChestHolders[a].myMeshRendererBox.enabled = false;
    71.                         pool_StaticChestHolders[a].myMeshRendererLid.enabled = false;
    72.                         pool_StaticChestHolders[a].myNavMeshObstacle.enabled = false;
    73.                         pool_StaticChestHolders[a].myBoxCollider.enabled = false;
    74.                         CmdDisableChest(pool_StaticChestHolders[a].myStaticChestScript.spawnPoolID);
    75.                     }
    76.                 }
    77.                
    78.  
    79.  
    80.                 initialized = true;
    81.                 initializedPool = true;
    82.             }
    83.             else
    84.             {
    85.                 pool_Timers = new float[pool.Length];
    86.                 for (int a = 0; a < pool_Timers.Length; a++)
    87.                 {
    88.                     pool_Timers[a] = 0f;
    89.                 }
    90.  
    91.                 for (int a = 0; a < pool.Length; a++)
    92.                 {
    93.                     pool_StaticChestHolders[a].myStaticChestScript.spawnPoolID = a;
    94.                     pool_StaticChestHolders[a].myNavMeshObstacle.enabled = false;
    95.                 }
    96.  
    97.                 initialized = true;
    98.                 initializedPool = true;
    99.  
    100.                 GetPoolFromServer();
    101.             }
    102.         }
    103.  
    104.         if (!initialized)
    105.         {
    106.             StartCoroutine(Countdown_Loop_Initialize(1f));
    107.         }
    108.         else
    109.         {
    110.             if (isServer)
    111.             {
    112.                 StartCoroutine(Countdown_Loop_UpdateSpawner(1f));
    113.             }
    114.         }
    115.     }
    116.  
    117.  
    118.  
    119.     IEnumerator Countdown_Loop_Initialize(float DELAY)
    120.     {
    121.         yield return new WaitForSeconds(DELAY);
    122.  
    123.         Initialize();
    124.  
    125.         if (!initialized)
    126.         {
    127.             StartCoroutine(Countdown_Loop_UpdateSpawner(1f));
    128.         }
    129.     }
    130.  
    131.     IEnumerator Countdown_Loop_UpdateSpawner(float DELAY)
    132.     {
    133.         yield return new WaitForSeconds(DELAY);
    134.  
    135.         UpdateSpawner();
    136.  
    137.         StartCoroutine(Countdown_Loop_UpdateSpawner(1f));
    138.     }
    139.  
    140.  
    141.  
    142.     private void UpdateSpawner ()
    143.     {
    144.         if(initialized)
    145.         {
    146.             for (int a = 0; a < pool.Length; a++)
    147.             {
    148.                 if (pool_StaticChestHolders[a].chestEnabled)
    149.                 {
    150.                     if (pool_StaticChestHolders[a].myStaticChestScript.lootings <= 0 &&
    151.                         pool_StaticChestHolders[a].myStaticChestScript.fcMain.m_Lid.m_LidStatus == FCLid.eState.Close &&
    152.                         !pool_StaticChestHolders[a].myStaticChestScript.fcMain.m_Lid.m_ChangingState)
    153.                     {
    154.                         spawnPoints += pool_StaticChestHolders[a].myStaticChestScript.spawnPoints;
    155.                         pool_Timers[pool_StaticChestHolders[a].myStaticChestScript.spawnPoolID] = 0f;
    156.  
    157.                         CmdDisableChest(pool_StaticChestHolders[a].myStaticChestScript.spawnPoolID);
    158.                         pool_StaticChestHolders[a].chestEnabled = false;
    159.                         pool_StaticChestHolders[a].myMeshRendererBox.enabled = false;
    160.                         pool_StaticChestHolders[a].myMeshRendererLid.enabled = false;
    161.                         pool_StaticChestHolders[a].myNavMeshObstacle.enabled = false;
    162.                         pool_StaticChestHolders[a].myBoxCollider.enabled = false;
    163.                     }
    164.                 }
    165.             }
    166.  
    167.  
    168.  
    169.             for (int a = 0; a < pool_Timers.Length; a++)
    170.             {
    171.                 if (!pool_StaticChestHolders[a].chestEnabled)
    172.                 {
    173.                     pool_Timers[a] += 1f;
    174.                 }
    175.             }
    176.  
    177.  
    178.  
    179.             if (spawnPoints > 0)
    180.             {
    181.                 for (int a = 0; a < spawnPoints; a++)
    182.                 {
    183.                     for (int b = 0; b < pool.Length; b++)
    184.                     {
    185.                         if (!pool_StaticChestHolders[b].chestEnabled)
    186.                         {
    187.                             if (pool_Timers[b] >= pool_StaticChestHolders[b].myStaticChestScript.respawnTime)
    188.                             {
    189.                                 if (spawnPoints >= pool_StaticChestHolders[b].myStaticChestScript.spawnPoints)
    190.                                 {
    191.                                     if (Random.Range(0, 100) <= pool_StaticChestHolders[b].myStaticChestScript.spawnChance)
    192.                                     {
    193.                                         spawnPoints -= pool_StaticChestHolders[b].myStaticChestScript.spawnPoints;
    194.                                         pool_StaticChestHolders[b].chestEnabled = true;
    195.                                         pool_StaticChestHolders[b].myMeshRendererBox.enabled = true;
    196.                                         pool_StaticChestHolders[b].myMeshRendererLid.enabled = true;
    197.                                         pool_StaticChestHolders[b].myNavMeshObstacle.enabled = true;
    198.                                         pool_StaticChestHolders[b].myBoxCollider.enabled = true;
    199.                                         pool_StaticChestHolders[b].myStaticChestScript.Reset_Chest();
    200.                                         CmdResetChest(pool_StaticChestHolders[b].myStaticChestScript.spawnPoolID);
    201.                                         CmdEnableChest(pool_StaticChestHolders[b].myStaticChestScript.spawnPoolID);
    202.                                         pool_Timers[b] = 0f;
    203.                                         pool_StaticChestHolders[b].Respawn();
    204.                                     }
    205.                                     else
    206.                                     {
    207.                                         pool_Timers[b] = 0f;
    208.                                     }
    209.                                 }
    210.                                 else
    211.                                 {
    212.                                     pool_Timers[b] = 0f;
    213.                                 }
    214.                             }
    215.                         }
    216.                     }
    217.                 }
    218.             }
    219.         }
    220.     }
    221.  
    222.  
    223.  
    224.     void GetPoolFromServer()
    225.     {
    226.         ClickToMove.myPlayer.ClientRequestInitialStaticChestPool(myNetworkIdentity.netId, ClickToMove.myPlayer.myNetworkIdentity.netId);
    227.     }
    228.  
    229.     public void SendPoolToClients()
    230.     {
    231.         for (int a = 0; a < pool.Length; a++)
    232.         {
    233.             if(pool_StaticChestHolders[a].chestEnabled)
    234.             {
    235.                 //CmdEnableChest(pool[a].GetComponent<StaticChest>().spawnPoolID);
    236.                 Cmd_UpdateChest_Locked(pool_StaticChestHolders[a].myStaticChestScript.spawnPoolID, pool_StaticChestHolders[a].myStaticChestScript.locked);
    237.  
    238.                 if(pool_StaticChestHolders[a].myStaticChestScript.fcMain.m_Lid.m_LidStatus == FCLid.eState.Open)
    239.                 {
    240.                     Cmd_UpdateChest_Opened(pool_StaticChestHolders[a].myStaticChestScript.spawnPoolID, true);
    241.                 }
    242.             }
    243.             else
    244.             {
    245.                 CmdDisableChest(pool_StaticChestHolders[a].myStaticChestScript.spawnPoolID);
    246.             }
    247.         }
    248.     }
    249.  
    250.     [Command]
    251.     public void CmdEnableChest(int INDEX)
    252.     {
    253.         RpcEnableChest(INDEX);
    254.     }
    255.  
    256.     [Command]
    257.     public void CmdDisableChest(int INDEX)
    258.     {
    259.         RpcDisableChest(INDEX);
    260.     }
    261.  
    262.     [ClientRpc]
    263.     void RpcEnableChest(int INDEX)
    264.     {
    265.         if (!isServer)
    266.         {
    267.             if (INDEX < pool.Length)
    268.             {
    269.                 if(pool_StaticChestHolders[INDEX].myBoxCollider == null)
    270.                 {
    271.                     pool_StaticChestHolders[INDEX].myBoxCollider = pool_StaticChestHolders[INDEX].myStaticChestGameObject.transform.GetComponent<BoxCollider> ();
    272.                 }
    273.  
    274.                 pool_StaticChestHolders[INDEX].chestEnabled = true;
    275.                 pool_StaticChestHolders[INDEX].myMeshRendererBox.enabled = true;
    276.                 pool_StaticChestHolders[INDEX].myMeshRendererLid.enabled = true;
    277.                 pool_StaticChestHolders[INDEX].myBoxCollider.enabled = true;
    278.             }
    279.             else
    280.             {
    281.                 //Debug.Log("enable pool index: " + INDEX + " is out of bounds for pool: " + transform.name + "(" + pool.Length + ")");
    282.             }
    283.         }
    284.     }
    285.  
    286.     [ClientRpc]
    287.     void RpcDisableChest(int INDEX)
    288.     {
    289.         if (!isServer)
    290.         {
    291.             if (INDEX < pool.Length)
    292.             {
    293.                 if(pool_StaticChestHolders[INDEX].myBoxCollider == null)
    294.                 {
    295.                     pool_StaticChestHolders[INDEX].myBoxCollider = pool_StaticChestHolders[INDEX].myStaticChestGameObject.transform.GetComponent<BoxCollider> ();
    296.                 }
    297.  
    298.                 pool_StaticChestHolders[INDEX].chestEnabled = false;
    299.                 pool_StaticChestHolders[INDEX].myMeshRendererBox.enabled = false;
    300.                 pool_StaticChestHolders[INDEX].myMeshRendererLid.enabled = false;
    301.                 pool_StaticChestHolders[INDEX].myBoxCollider.enabled = false;
    302.             }
    303.             else
    304.             {
    305.                 //Debug.Log("disable pool index: " + INDEX + " is out of bounds for pool: " + transform.name + "(" + pool.Length + ")");
    306.             }
    307.         }
    308.     }
    309.  
    310.     [Command]
    311.     public void CmdResetChest(int INDEX)
    312.     {
    313.         RpcResetChest(INDEX);
    314.     }
    315.  
    316.     [ClientRpc]
    317.     void RpcResetChest(int INDEX)
    318.     {
    319.         if (!isServer && initializedPool)
    320.         {
    321.             if (INDEX < pool.Length)
    322.             {
    323.                 pool_StaticChestHolders[INDEX].myStaticChestScript.Reset_Chest();
    324.             }
    325.             else
    326.             {
    327.                 //Debug.Log("enable pool index: " + INDEX + " is out of bounds for pool: " + transform.name + "(" + pool.Length + ")");
    328.             }
    329.         }
    330.     }
    331.  
    332.  
    333.  
    334.     [Command]
    335.     public void Cmd_UpdateChest_Opened(int INDEX, bool OPEN)
    336.     {
    337.         Rpc_UpdateChest_Opened(INDEX, OPEN);
    338.     }
    339.  
    340.     [ClientRpc]
    341.     void Rpc_UpdateChest_Opened(int INDEX, bool OPEN)
    342.     {
    343.         if (!isServer && initializedPool)
    344.         {
    345.             if (INDEX < pool.Length)
    346.             {
    347.                 if (OPEN)
    348.                 {
    349.                     pool_StaticChestHolders[INDEX].myStaticChestScript.fcMain.m_Lid.m_LidStatusOld = FCLid.eState.Open;
    350.                     pool_StaticChestHolders[INDEX].myStaticChestScript.fcMain.m_Lid.Open();
    351.                     pool_StaticChestHolders[INDEX].myStaticChestScript.fcMain.m_Lid.m_OpenValue = 1f;
    352.                     pool_StaticChestHolders[INDEX].myStaticChestScript.fcMain.m_Lid.OpenLid();
    353.                 }
    354.             }
    355.             else
    356.             {
    357.  
    358.             }
    359.         }
    360.     }
    361.  
    362.  
    363.  
    364.     [Command]
    365.     public void Cmd_UpdateChest_Locked(int INDEX, bool LOCKED)
    366.     {
    367.         Rpc_UpdateChest_Locked(INDEX, LOCKED);
    368.     }
    369.  
    370.     [ClientRpc]
    371.     void Rpc_UpdateChest_Locked(int INDEX, bool LOCKED)
    372.     {
    373.         if (!isServer && initializedPool)
    374.         {
    375.             if (INDEX < pool.Length)
    376.             {
    377.                 if (pool_StaticChestHolders[INDEX].myStaticChestScript.locked != LOCKED)
    378.                 {
    379.                     pool_StaticChestHolders[INDEX].myStaticChestScript.locked = LOCKED;
    380.  
    381.                     if(!LOCKED)
    382.                     {
    383.                         pool_StaticChestHolders[INDEX].myStaticChestScript.fcMain.m_Lid.m_LockStatusOld = FCLid.eLockStatus.Free;
    384.                         pool_StaticChestHolders[INDEX].myStaticChestScript.fcMain.Unlock();
    385.                     }
    386.                 }
    387.             }
    388.             else
    389.             {
    390.  
    391.             }
    392.         }
    393.     }
    394.  
    395.  
    396.  
    397.     [ClientRpc]
    398.     public void Rpc_Unlock_Chest(int INDEX)
    399.     {
    400.         if (initializedPool)
    401.         {
    402.             if (INDEX < pool.Length)
    403.             {
    404.                 pool_StaticChestHolders[INDEX].myStaticChestScript.locked = false;
    405.                 pool_StaticChestHolders[INDEX].myStaticChestScript.fcMain.Unlock();
    406.             }
    407.             else
    408.             {
    409.  
    410.             }
    411.         }
    412.     }
    413.  
    414.  
    415.  
    416.     [ClientRpc]
    417.     public void Rpc_Open_Chest(int INDEX)
    418.     {
    419.         if (initializedPool)
    420.         {
    421.             if (INDEX < pool.Length)
    422.             {
    423.                 if (pool_StaticChestHolders[INDEX].myStaticChestScript.fcMain.m_Lid.m_LidStatus == FCLid.eState.Close)
    424.                 {
    425.                     pool_StaticChestHolders[INDEX].myStaticChestScript.fcMain.Open();
    426.                 }
    427.             }
    428.             else
    429.             {
    430.  
    431.             }
    432.         }
    433.     }
    434.  
    435.  
    436.  
    437.     [ClientRpc]
    438.     public void Rpc_Close_Chest(int INDEX)
    439.     {
    440.         if (initializedPool)
    441.         {
    442.             if (INDEX < pool.Length)
    443.             {
    444.                 if (pool_StaticChestHolders[INDEX].myStaticChestScript.fcMain.m_Lid.m_LidStatus == FCLid.eState.Open)
    445.                 {
    446.                     pool_StaticChestHolders[INDEX].myStaticChestScript.fcMain.Close();
    447.  
    448.                     if (ClickToMove.myInventory.lootWindow.lootGameObject != null && ClickToMove.myInventory.lootWindow.lootGameObject == pool_StaticChestHolders[INDEX].myStaticChestGameObject)
    449.                     {
    450.                         ClickToMove.myInventory.lootWindow.Close();
    451.                     }
    452.                 }
    453.             }
    454.             else
    455.             {
    456.  
    457.             }
    458.         }
    459.     }
    460.  
    461.  
    462.  
    463.     [ClientRpc]
    464.     public void Rpc_Update_LootWindow(int INDEX)
    465.     {
    466.         if (initializedPool)
    467.         {
    468.             if (INDEX < pool.Length)
    469.             {
    470.                 if (ClickToMove.openLoot)
    471.                 {
    472.                     if (ClickToMove.myInventory.lootWindow.lootGameObject != null && ClickToMove.myInventory.lootWindow.lootGameObject == pool_StaticChestHolders[INDEX].gameObject)
    473.                     {
    474.                         ClickToMove.myInventory.lootWindow.Update_Chest_Content();
    475.                     }
    476.                 }
    477.             }
    478.             else
    479.             {
    480.  
    481.             }
    482.         }
    483.     }
    484. }
    485.  
    There is also a TreasureChest.cs file and a TreasureChestHolder.cs file where other things happen regarding the treasure chests.