Photon OnPremise Server

Hi,

I am supporting the development of a multiplayer application in, of course, Unity. Up to this point, the devs have been using Photon Cloud on the backend for multi-player and voice. I'll have plenty of questions about implementing voice, but I am concerned now with an exception being thrown when we attempt to connect to the new OnPremise server.

So far, we've changed the connection settings in the PhotonServerSettings Inspector window. We aren't using name server, are leaving the appid realtime and voiceid to random numbers, setting a version number = 1, running in the background and setting the IP and port numbers for the OnPremise server. I should add that when I run the Stardust test client, it is able to connect to the server just fine with 3 to 5 connections, and i am using loadbalancing though I only have 1 box hosting the server.

Here is the exception being thrown. Any ideas would be greatly appreciated:

IndexOutOfRangeException: Index was outside the bounds of the array.
ExitGames.Client.Photon.Protocol16.SerializeDictionaryHeader (ExitGames.Client.Photon.StreamBuffer writer, System.Object dict, System.Boolean& setKeyType, System.Boolean& setValueType) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/Protocol16.cs:1048)
ExitGames.Client.Photon.Protocol16.SerializeDictionaryHeader (ExitGames.Client.Photon.StreamBuffer writer, System.Type dictType) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/Protocol16.cs:1038)
ExitGames.Client.Photon.Protocol16.SerializeDictionaryHeader (ExitGames.Client.Photon.StreamBuffer writer, System.Object dict, System.Boolean& setKeyType, System.Boolean& setValueType) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/Protocol16.cs:1082)
ExitGames.Client.Photon.Protocol16.SerializeDictionary (ExitGames.Client.Photon.StreamBuffer dout, System.Collections.IDictionary serObject, System.Boolean setType) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/Protocol16.cs:1030)
ExitGames.Client.Photon.Protocol16.Serialize (ExitGames.Client.Photon.StreamBuffer dout, System.Object serObject, System.Boolean setType) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/Protocol16.cs:627)
ExitGames.Client.Photon.Protocol16.SerializeObjectArray (ExitGames.Client.Photon.StreamBuffer dout, System.Collections.IList objects, System.Boolean setType) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/Protocol16.cs:1000)
ExitGames.Client.Photon.Protocol16.Serialize (ExitGames.Client.Photon.StreamBuffer dout, System.Object serObject, System.Boolean setType) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/Protocol16.cs:619)
ExitGames.Client.Photon.Protocol16.SerializeHashTable (ExitGames.Client.Photon.StreamBuffer dout, ExitGames.Client.Photon.Hashtable serObject, System.Boolean setType) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/Protocol16.cs:1017)
ExitGames.Client.Photon.Protocol16.Serialize (ExitGames.Client.Photon.StreamBuffer dout, System.Object serObject, System.Boolean setType) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/Protocol16.cs:604)
ExitGames.Client.Photon.Protocol16.SerializeParameterTable (ExitGames.Client.Photon.StreamBuffer stream, System.Collections.Generic.Dictionary`2[TKey,TValue] parameters) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/Protocol16.cs:527)
ExitGames.Client.Photon.Protocol16.SerializeOperationRequest (ExitGames.Client.Photon.StreamBuffer stream, System.Byte operationCode, System.Collections.Generic.Dictionary`2[TKey,TValue] parameters, System.Boolean setType) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/Protocol16.cs:442)
ExitGames.Client.Photon.EnetPeer.SerializeOperationToMessage (System.Byte opCode, System.Collections.Generic.Dictionary`2[TKey,TValue] parameters, ExitGames.Client.Photon.EgMessageType messageType, System.Boolean encrypt) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/EnetPeer.cs:1095)
ExitGames.Client.Photon.EnetPeer.EnqueueOperation (System.Collections.Generic.Dictionary`2[TKey,TValue] parameters, System.Byte opCode, ExitGames.Client.Photon.SendOptions sendParams, ExitGames.Client.Photon.EgMessageType messageType) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/EnetPeer.cs:936)
ExitGames.Client.Photon.PhotonPeer.SendOperation (System.Byte operationCode, System.Collections.Generic.Dictionary`2[TKey,TValue] operationParameters, ExitGames.Client.Photon.SendOptions sendOptions) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/PhotonPeer.cs:1505)
Photon.Realtime.LoadBalancingPeer.OpRaiseEvent (System.Byte eventCode, System.Object customEventContent, Photon.Realtime.RaiseEventOptions raiseEventOptions, ExitGames.Client.Photon.SendOptions sendOptions) (at Assets/DownloadedAssets/Photon/PhotonRealtime/Code/LoadbalancingPeer.cs:864)
Photon.Realtime.LoadBalancingClient.OpRaiseEvent (System.Byte eventCode, System.Object customEventContent, Photon.Realtime.RaiseEventOptions raiseEventOptions, ExitGames.Client.Photon.SendOptions sendOptions) (at Assets/DownloadedAssets/Photon/PhotonRealtime/Code/LoadBalancingClient.cs:1603)
Photon.Pun.PhotonNetwork.RaiseEventInternal (System.Byte eventCode, System.Object eventContent, Photon.Realtime.RaiseEventOptions raiseEventOptions, ExitGames.Client.Photon.SendOptions sendOptions) (at Assets/DownloadedAssets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs:2193)
Photon.Pun.PhotonNetwork.SendInstantiate (Photon.Pun.InstantiateParameters parameters, System.Boolean sceneObject) (at Assets/DownloadedAssets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs:2523)
Photon.Pun.PhotonNetwork.NetworkInstantiate (Photon.Pun.InstantiateParameters parameters, System.Boolean sceneObject, System.Boolean instantiateEvent) (at Assets/DownloadedAssets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs:2447)
Photon.Pun.PhotonNetwork.Instantiate (System.String prefabName, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, System.Byte group, System.Object[] data) (at Assets/DownloadedAssets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs:2297)
NetworkMesherHelpers.NetworkModel.GenerateNetworkMesh (System.String nodePath, System.String linkPath, System.String statPath, System.String alertPath) (at Assets/Scripts/NetworkMesherHelpers/NetworkModel.cs:603)
GameManager.OnJoinedRoom () (at Assets/Scripts/Management/GameManager.cs:28)
Photon.Realtime.MatchMakingCallbacksContainer.OnJoinedRoom () (at Assets/DownloadedAssets/Photon/PhotonRealtime/Code/LoadBalancingClient.cs:3348)
Photon.Realtime.LoadBalancingClient.OnEvent (ExitGames.Client.Photon.EventData photonEvent) (at Assets/DownloadedAssets/Photon/PhotonRealtime/Code/LoadBalancingClient.cs:2476)
ExitGames.Client.Photon.PeerBase.DeserializeMessageAndCallback (ExitGames.Client.Photon.StreamBuffer stream) (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/PeerBase.cs:633)
ExitGames.Client.Photon.EnetPeer.DispatchIncomingCommands () (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/EnetPeer.cs:545)
ExitGames.Client.Photon.PhotonPeer.DispatchIncomingCommands () (at C:/Dev/photon-sdk-dotnet/PhotonDotnet/PhotonPeer.cs:1473)
Photon.Pun.PhotonHandler.FixedUpdate () (at Assets/DownloadedAssets/Photon/PhotonUnityNetworking/Code/PhotonHandler.cs:130)

Comments

  • Hi, @ar3k_g
    I will redirect you PUN forum section.

    but please provide versions of server and client software you are using.
    Please could you provide data you have sent to get this exception

    Or probably you could provide an example which helps us reproduce the issue

    best,
    ilya
  • Sure,

    Server Version: Photon-OnPremise-Server-SDK_v4-0-29-11263
    Unity version: Unity 2018.3.11f1 (64-bit)

    Code (NetoworkManagement.cs):

    using ExitGames.Client.Photon;
    using Photon.Pun;
    using Photon.Realtime;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;

    public class NetworkManagement : MonoBehaviourPunCallbacks//, IInRoomCallbacks
    {
    public static NetworkManagement instance;
    public SharedInfo sharedInfo;
    public bool networkedScene;
    public GameObject playerCamera;

    #region private varibles

    private Dictionary> networkedObjects;

    #endregion

    // Start is called before the first frame update
    private void Start()
    {
    instance = this;
    networkedObjects = new Dictionary>();
    if (networkedScene)
    {
    Connect();
    }
    else
    {
    if (PhotonNetwork.IsConnected)
    {
    PhotonNetwork.Disconnect();
    }
    }
    }


    #region Public Methods

    ///
    /// Start the connection process.
    /// - If already connected, we attempt joining a random room
    /// - If not yet connected, Connect this application instance to Photon Cloud Network
    ///
    public void Connect()
    {
    // we check if we are connected or not, we join if we are , else we initiate the connection to the server.
    if (PhotonNetwork.IsConnected)
    {
    // #Critical we need at this point to attempt joining a Random Room.
    // If it fails, we'll get notified in OnJoinRandomFailed() and we'll create one.
    //JoinRoom();

    }
    else
    {
    // #critical, we must first and foremost connect to Photon Online Server.

    PhotonNetwork.ConnectUsingSettings();
    }
    }



    private void JoinRoom()
    {
    PhotonNetwork.JoinOrCreateRoom(SceneManager.GetActiveScene().name, new RoomOptions { MaxPlayers = 4, CleanupCacheOnLeave = false }, TypedLobby.Default);
    }

    public static NetworkManagement getInstance()
    {
    return instance;
    }

    public void AddNetworkedObject(int player, GameObject passedGameObject)
    {
    if (!networkedObjects.ContainsKey(player))
    {
    networkedObjects.Add(player, new List());
    }
    networkedObjects[player].Add(passedGameObject);
    }

    #endregion

    #region MonoBehaviourPunCallbacks Callbacks

    public override void OnConnectedToMaster()
    {
    Debug.Log("Connected to master");

    // #Critical: The first we try to do is to join a potential existing room.
    // If there is, good, else, we'll be called back with OnJoinRandomFailed()
    JoinRoom();
    }

    public override void OnDisconnected(DisconnectCause cause)
    {
    Debug.LogWarningFormat("OnDisconnected() was called by PUN with reason{0}", cause);
    }

    public override void OnJoinRandomFailed(short returnCode, string message)
    {
    Debug.Log("Creating a new room.");

    // #Critical: we failed to join a random room, maybe none exists or they are full.
    // No worries, we create a new room.
    PhotonNetwork.CreateRoom(null, new RoomOptions { MaxPlayers = 4, CleanupCacheOnLeave = false });
    }

    //public override void OnPlayerEnteredRoom(Player newPlayer)
    //{
    // photonView.RPC("Something", newPlayer, );
    //}

    public override void OnPlayerLeftRoom(Player otherPlayer)
    {
    Debug.Log("Player [" + otherPlayer.ActorNumber + "] " + otherPlayer.NickName);
    int playerName = otherPlayer.ActorNumber;

    // Remove drawings of player who leaves
    // TODO: Make this just destroy all lines created by that player on each individual client, to reduce network traffic, OR
    // TODO: Only have one client send this out to reduce network traffic
    sharedInfo.EraseAllLines(playerName);

    // Remove networked objects of that player (such as hands, and head)
    if (networkedObjects.ContainsKey(playerName))
    {
    foreach (GameObject curGameObject in networkedObjects[playerName])
    {
    Debug.Log("Destroying " + curGameObject.name);
    if (curGameObject) // If more than 2 clients are in the room, then multiple will be deleting. This makes sure that we aren't trying to delete something that isnt' there
    {
    PhotonNetwork.Destroy(curGameObject);
    // TODO: May want to also remove from networkedObjects, but will probably have to change to regular for loop for this
    }
    }
    }
    }

    public readonly byte InstantiateVrAvatarEventCode = 123;

    public override void OnJoinedRoom()
    {
    Debug.Log("Successfully joined room.");

    Room currentRoom = PhotonNetwork.CurrentRoom;

    PhotonNetwork.Instantiate("NetworkedHeadAvatar", Vector3.zero, Quaternion.identity, 0);
    PhotonNetwork.Instantiate("NetworkedHandAvatarL", Vector3.zero, Quaternion.identity, 0);
    PhotonNetwork.Instantiate("NetworkedHandAvatarR", Vector3.zero, Quaternion.identity, 0);

    //Change spawn position
    Transform spawnPoint = GameObject.Find("PlayerSpawn" + currentRoom.PlayerCount).transform;
    GameObject.Find("VRPlayerNetworked").transform.SetPositionAndRotation(spawnPoint.position, spawnPoint.rotation);

    //Enable camera now.
    playerCamera.SetActive(true);
    }

    public override void OnJoinedLobby()
    {
    JoinRoom();
    }

    #endregion
    }
  • Oh, sorry:

    You said: Or probably you could provide an example which helps us reproduce the issue

    *****

    I am not certain what you mean by this. The class handling the connection is, I have been told, NetworkManagement. The code for this is above. I have this and the stack trace. I suppose I could hook up the VS debugger to Unity and let it do its thing while I run from the Unity editor. But even if I find where the exception is being thrown, I'm not sure what to do with it. I've been reading, and so far I haven't found an example out there that looks quite like the exception being thrown as outlined above.
  • I guess nothing?
  • Sorry for the delay.
    Actually, I think the problem is a client-side one and it's not related to connect. This is misleading.
    Your callstack (please read those!) shows that PhotonNetwork.Instantiate() is being called by GenerateNetworkMesh when you joined a room.
    We can't debug that code for you but it's quite clear you are trying to send something that Photon (the client) can't send. Maybe it's the sheer size of what you are sending.
    Please have a look and debug this.

    Overall, GenerateNetworkMesh implies that you are generating a level or such. You should not have to sync the result of what you generated. Instead, enable any client to generate on it's own when you provide the seed or parameters of the generation.
    There is a sample for that in PUN 2.
    https://doc.photonengine.com/en-us/pun/v2/demos-and-tutorials/package-demos/proceduraldemo

  • Yeah, I'm not sure about this. Something interesting:

    1. If I connect to the Photon Cloud using Serialization Protocol 18, everything works fine
    2. If I connect to the Photon Cloud using Serialization Protocol 16, the app blows up with an index out of bounds exception when calling PhotonNetwork.Instantiate,
    3. If I connect to my self hosted server using 16, app blows up with same exception at the same place.

    This isn't a question of the amount of data being pushed from the client to the server, as it's negligible. The GenerateNetworkMesh is simply custom code that reads in data from a file and pushes that on as part of the Instantiate call, but as I said, the amount of data is completely negligible. I find it interesting that I have the same problem on the Photon Cloud AND the self hosted server when using Serialization Protocol 16,

    What you think?
  • Tobias
    Tobias admin
    edited April 2019
    Yes, it's definitely a serialization problem client side. If it's Cloud or Server does not matter for this, aside from the point that PUN 2 now uses a new serialization protocol for the Cloud but not the Server (which doesn't know that yet).

    Can you provide the data (type and values) which you're sending? Anything we can use to reproduce this and fix it?

    You can mail us: developer@exitgames.com. Please point to this discussion, so we get the context right.
  • ar3k_g
    ar3k_g
    edited April 2019
    Ah, I see. I will only point out that when using Serialization Protocol v18 that I do not get this error. And sure,we are sending String arrays and ArrayLists. I'm going to give you all of the code, because I don't know what to isolate. Search for: //This is where we instantiate! to find the instantiation point. Will have to break up my messages into three or so posts as the body is too long for one post here:

    Edit: Very sorry for the multiple posts. I just dug into this code and copy and pasted. I didn't write it, I want to make that clear. It works when using Serialization Protocol 18, but I didn't say it was well written :-).

    /1/
    
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using UnityEngine;
    using System.Xml;
    using ExitGames.Client.Photon;
    using Photon.Pun;
    using Photon.Realtime;
    using UnityEngine.Experimental.PlayerLoop;
    using UnityEngine.UI;
    
    namespace NetworkMesherHelpers
    {
    
        public class NetworkModel : MonoBehaviourPunCallbacks, IPunObservable
        {
            public static Dictionary<string, Dictionary<string, Dictionary<string, NodeObject>>> nodeMasterTree;
            public Dictionary<string, NodeObject> nodeMasterList;
            public List<NodeLink> linkMasterList;
            public List<GameObject> allNodes;
            public List<GameObject> allLayers;
            public List<string> allSubnets;
    
            public GameObject buttonPrefab;
    
            //Prefabs for the nodes
            public GameObject clientPrefab, controllerPrefab, cardPrefab, laptopPrefab, routerPrefab, sensorPrefab, serverPrefab, switchPrefab, linkPrefab, drRouterPrefab, bdrRouterPrefab;
    
            public NetworkModelConfig config;
    
            private void Start()
            {
                GameObject photonMenu = GameObject.Find(
                    "VRPlayerNetworked/OVRCameraRig/TrackingSpace/LeftHandAnchor/PhotonMenuContainer/PhotonMenu");
                Transform subnetButtonMenu = photonMenu.transform.Find("FiltersMenu/Subnets");
                Transform firstButtonTransform = subnetButtonMenu.Find("NoSubnetFilter");
    
                Buttons buttonsComponent = photonMenu.GetComponent<Buttons>();
    
                int subnetCount = 0;
    
                nodeMasterTree = new Dictionary<string, Dictionary<string, Dictionary<string, NodeObject>>>();
                nodeMasterList = new Dictionary<string, NodeObject>();
                linkMasterList = new List<NodeLink>();
    
                ModelFilter filter = GetComponent<ModelFilter>();
    
                var nodeAttributeList = (Dictionary<string, Dictionary<string, Dictionary<string, string[]>>>)photonView.InstantiationData[0];
                var linkAttributeList = (object[])photonView.InstantiationData[1];
                var statAttributeList =
                    (Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string[]>>>>) photonView
                        .InstantiationData[2];
                var alertAttributeList = (object[])photonView.InstantiationData[3];
    
                this.name = "Networks";
    
                //For each network in dictionary
                foreach (string network in nodeAttributeList.Keys)
                {
                    //Add network to NodeMasterList
                    Dictionary<string, Dictionary<string, NodeObject>> curNetworkDictionary = new Dictionary<string, Dictionary<string, NodeObject>>();
                    nodeMasterTree.Add(network, curNetworkDictionary);
    
                    GameObject curNetworkObject = new GameObject(network);
                    curNetworkObject.transform.SetParent(this.transform);
                    
                    //For each layer in network:
                    foreach (string layer in nodeAttributeList[network].Keys)
                    {
                        //Add network's layer to NodeMasterList
                        Dictionary<string, NodeObject> curLayerDictionary = new Dictionary<string, NodeObject>();
                        curNetworkDictionary.Add(layer, curLayerDictionary);
    
                        //Add layer to filter dictionary. Default is on.
                        filter.AddNewLayer(layer, true);
                        
                        GameObject curLayerGameObject = GameObject.Find(layer + "(Clone)");
                        if (!curLayerGameObject)
                        {
                            curLayerGameObject = PhotonNetwork.Instantiate(layer, (Vector3.up * config.GetLayerOffsetV(layer)) + (Vector3.up * .55f) + (Vector3.right * config.GetLayerOffsetH(layer)), Quaternion.identity);
                        }
                        curLayerGameObject.name = layer;
                        curLayerGameObject.transform.SetParent(curNetworkObject.transform);
    
                        NetworkLayer curLayerObject = curLayerGameObject.GetComponent<NetworkLayer>();
    
                        float maxNodeDistance = 0;
                        List<Transform> layerChildren = new List<Transform>();
    
                        //For each ID in layer:
                        foreach (string id in nodeAttributeList[network][layer].Keys)
                        {
                            var curAttributeSet = nodeAttributeList[network][layer][id];
                            Dictionary<string, string[]> curNodeStats = null;
                            try
                            {
                                curNodeStats = statAttributeList[network][layer][id];
                            }
                            catch (KeyNotFoundException e)
                            {
                                Debug.LogWarning("No stat found for network " + network + ", layer " + layer + ", ID " + id);
                            }
    
  • ar3k_g
    ar3k_g
    edited April 2019
    /2/
    
     var nodeOid = curAttributeSet[0];
                            var nodeRoom = curAttributeSet[1];
                            var nodeServer = curAttributeSet[2];
                            var nodeId = curAttributeSet[3];
                            var nodeLayer = curAttributeSet[4];
                            var nodeSubnet = curAttributeSet[5];
                            var nodeAsset = curAttributeSet[6];
                            var nodeLevel = int.Parse(curAttributeSet[7]);
    
                            var posX = float.Parse(curAttributeSet[8]);
                            var posY = float.Parse(curAttributeSet[9]);
                            var posZ = float.Parse(curAttributeSet[10]);
    
                            posX *= config.nodeScale.x;// * (nodeLevel + 1);
                            posY *= config.nodeScale.y;// * (layerOffsetV + layerOffsetAdjust) * offsetScaleV;
                            posZ *= config.nodeScale.z;// * (nodeLevel + 1) + layerOffsetH;
    
                            float posMax = Math.Max(posX, posZ);
                            maxNodeDistance = Math.Max(maxNodeDistance, posMax);
    
                            Vector3 layerPos = curLayerGameObject.transform.position;
                            Vector3 nodePos = new Vector3(posX, posY, posZ);
    
                            GameObject curNodeGameObject;
                            switch (nodeAsset)
                            {
                                case ("Client"):
                                    curNodeGameObject = clientPrefab;
                                    break;
                                case ("Controller"):
                                    curNodeGameObject = controllerPrefab;
                                    break;
                                case ("EthernetCard"):
                                    curNodeGameObject = cardPrefab;
                                    break;
                                case ("Laptop"):
                                    curNodeGameObject = laptopPrefab;
                                    break;
                                case ("Router"):
                                    curNodeGameObject = routerPrefab;
                                    break;
                                case ("Sensor"):
                                    curNodeGameObject = sensorPrefab;
                                    break;
                                case ("Server"):
                                    curNodeGameObject = serverPrefab;
                                    break;
                                case ("Switch"):
                                    curNodeGameObject = switchPrefab;
                                    break;
                                case ("DR-Router"):
                                    curNodeGameObject = drRouterPrefab;
                                    break;
                                case ("BDR-Router"):
                                    curNodeGameObject = bdrRouterPrefab;
                                    break;
                                default:
                                    curNodeGameObject = routerPrefab;
                                    break;
                            }
                            
                            curNodeGameObject = Instantiate(curNodeGameObject, layerPos, Quaternion.identity);
                            curNodeGameObject.name = nodeId;
                            curNodeGameObject.transform.Translate((nodePos));
                            curNodeGameObject.transform.Translate(Vector3.up * config.heightAboveLayer);
                            layerChildren.Add(curNodeGameObject.transform);
                            
    
                            NodeObject curNode = curNodeGameObject.GetComponent<NodeObject>();
                            curLayerObject.AddNode(curNode);
    
                            //Find unique subnets
                            if (!allSubnets.Contains(nodeSubnet))
                            {
                                allSubnets.Add(nodeSubnet);
                                filter.AddNewSubnet(nodeSubnet, true);
    
                                //Dynamically create subnet buttons.
                                if (nodeSubnet != "" && nodeSubnet != " ")
                                {
                                    
    
                                    subnetButtonMenu.gameObject.SetActive(true);
    
                                    //Create button
                                    GameObject newButton = GameObject.Instantiate(buttonPrefab, firstButtonTransform.position,
                                        firstButtonTransform.rotation, subnetButtonMenu.transform);
    
                                    //Name the button[subnet name]
                                    newButton.name = nodeSubnet;
    
                                    //Set the text to subnet name.
                                    newButton.GetComponentInChildren<Text>().fontSize = 30;
                                    newButton.GetComponentInChildren<Text>().text = nodeSubnet;
    
                                    //Set the onclick to Buttons.FilterSubnetButton("[subnet name],[subnet name]")
                                    newButton.GetComponent<Button>().onClick.AddListener(delegate { buttonsComponent.FilterSubnetButton(nodeSubnet); });
    
                                    //Fix position issue
                                    newButton.transform.Translate(Vector3.left * 155 * photonMenu.transform.lossyScale.x);
    
                                    //If subnetCount is even, move button to the right by 310.
                                    if (subnetCount % 2 > 0)
                                    {
                                        newButton.transform.Translate(Vector3.right * 310 * photonMenu.transform.lossyScale.x);
                                    }
    
                                    //Move the button down
                                    newButton.transform.Translate(Vector3.down * (subnetCount / 2 + 1) * 100 * photonMenu.transform.lossyScale.y);
    
                                    subnetCount++;
                                }
                            }
    
                            //Add this NodeObject to NodeMasterList
                            curLayerDictionary.Add(id, curNode);
                            nodeMasterList.Add(nodeOid, curNode);
    
                            //Set the attributes for the NetObject.
                            curNode.oid = nodeOid;
                            curNode.serverId = nodeServer;
                            curNode.srcId = nodeId;
                            curNode.layer = nodeLayer;
                            curNode.subnet = nodeSubnet;
                            curNode.asset = nodeAsset;
                            curNode.level = nodeLevel;
                            curNode.model = this;
    
                            curNode.setStats(curNodeStats);
    
                            //Set the text.
                            curNode.SetText();
    
                            allNodes.Add(curNodeGameObject);
    
                        }//End node loop
    
     maxNodeDistance *= 2f;
                        maxNodeDistance += 1f;
                        //Vector3 curLayerScale = curLayerObject.transform.localScale;
    
                        Transform glassTransform = curLayerGameObject.transform.GetChild(0);
    
                        Vector3 curLayerScale = glassTransform.localScale;
    
                        curLayerScale.x *= maxNodeDistance;
                        //curLayerScale.y *= maxNodeDistance;
                        curLayerScale.z *= maxNodeDistance;
    
                        glassTransform.localScale = curLayerScale;
                        
                        //Scale the collider
                        BoxCollider layerCollider = curLayerGameObject.GetComponent<BoxCollider>();
    
                        Vector3 curLayerColliderSize = layerCollider.size;
    
                        curLayerColliderSize.x *= maxNodeDistance;
                        curLayerColliderSize.z *= maxNodeDistance;
    
    
  • ar3k_g
    ar3k_g
    edited April 2019
    /3/
    
     for (int i = 1; i <= 4; i++)
                        {
                            Transform sign = curLayerGameObject.transform.GetChild(i);
                            Vector3 updatePosition = sign.localPosition;
                            updatePosition.x *= maxNodeDistance;
                            updatePosition.z *= maxNodeDistance;
                            sign.localPosition = updatePosition;
                        }
    
                        layerCollider.size = curLayerColliderSize;
    
                        foreach (Transform curtTransform in layerChildren)
                        {
                            curtTransform.SetParent(curLayerGameObject.transform);
                            curtTransform.LookAt(curtTransform.parent);
    
                            //Top of the glass pane will be at (0, y, 0) where y is (glass pane height / 2) * scale of layer object.
                            float topOfPane = (.14f / 2f) * curLayerScale.y;
    
                            //Make sure nodes aren't stuck in layer. Do this more elegantly later when we don't have a demo in less than two days.
                            //curtTransform.Translate(Vector3.up * topOfPane);
                            
                            Quaternion newRotation = curtTransform.rotation;
                            newRotation.x = 0;
                            newRotation.z = 0;
                            curtTransform.rotation = newRotation;
                        }
    
                        allLayers.Add(curLayerGameObject);
    
                    }//End layer loop
    
                }//End network loop
    
                GameObject linkContainer = new GameObject("Links");
                linkContainer.transform.SetParent(transform);
    
                //For each link in linkMasterList:
                foreach (object curObject in linkAttributeList)
                {
                    string[] curLink = (string[])curObject;
    
                    string linkOid = curLink[0];
    
                    //Grab network.
                    string curNetwork = curLink[2];
    
                    //Grab source, dest oids
                    string srcOid = curLink[3];
                    string destOid = curLink[4];
    
                    if (!nodeMasterList.ContainsKey(srcOid) || !nodeMasterList.ContainsKey(destOid))
                    {
                        Debug.LogWarning("Link was not found");
                        if (!nodeMasterList.ContainsKey(srcOid))
                        {
                            Debug.LogWarning("Source missing: " + srcOid);
                        }
    
                        if (!nodeMasterList.ContainsKey(destOid))
                        {
                            Debug.LogWarning("Dest missing:  " + destOid);
                        }
    
                        continue;
                    }
                    
                    NodeObject srcNode = nodeMasterList[srcOid];
                    NodeObject destNode = nodeMasterList[destOid];
    
                    if (!srcNode || !destNode) continue;
    
                    //Create link object.
                    NodeLink linkObject = Instantiate(linkPrefab, Vector3.zero, Quaternion.identity).GetComponent<NodeLink>();
                    
                    //Add source, dest to link object.
                    linkObject.sourceNode = srcNode;
                    linkObject.destNode = destNode;
                    
                    //Add link type to link object.
                    linkObject.setLinkType(int.Parse(curLink[5]));
    
                    //Add link object to source node object.
                    srcNode.links.Add(linkObject);
                    destNode.links.Add(linkObject);
    
                    linkObject.transform.SetParent(linkContainer.transform);
    
                    //Add link object to master list.
                    linkMasterList.Add(linkObject);
                }//End link loop
    
                foreach (object[] t in alertAttributeList)
                {
                    string[] alert = (string[]) t;
                    string oid = alert[1];
    
                    if (!nodeMasterList.ContainsKey(oid))
                    {
                        Debug.LogWarning("An alert was found with the following missing node: " + oid);
                        continue;
                    }
    
                    NodeObject nodeToUse = nodeMasterList[oid];
                    nodeToUse.AddAlert(alert);
                    nodeToUse.SetAlertText();
                }
    
                transform.Translate(Vector3.up * 3.5f);
            }
    
    /// <summary>
            /// public method which will populate and return a dictionary of network nodes.
            /// </summary>
            /// <returns></returns>
            public static void GenerateNetworkMesh(string nodePath, string linkPath, string statPath, string alertPath)
            {
                // Read in the LurayNode and LurayLink files. In C#, File.ReadAllLines will return a string array with all the lines in the file.
                string[] nodeLines = File.ReadAllLines(nodePath);
                string[] linkLines = File.ReadAllLines(linkPath);
                string[] statLines = File.ReadAllLines(statPath);
                string[] alertLines = File.ReadAllLines(alertPath);
                
                string[] curLine;
    
                // To use in loops
                string serverName;
                string roomName;
                string layerName;
                string nodeId;
                string protocolName;
    
  • ar3k_g
    ar3k_g
    edited April 2019
    /4/
    
    //If either file is less than 2 lines long, error out. There is no reason to continue further since there's no usable data.
                if (nodeLines.Length < 2 || linkLines.Length < 2)
                {
                    throw new System.Exception("No usable data: Node or Link file is too short.");
                }
    
                // Otherwise, create a Dictionary.We'll call it nodeMasterTree, and make it a nested dictionary.
                var nodeFieldList = new Dictionary<string, Dictionary<string, Dictionary<string, string[]>>>();
                var statFieldList =
                    new Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string[]>>>>();
                ArrayList linkMasterList = new ArrayList();
                ArrayList alertMasterList = new ArrayList();
    
                //Node data validation.
                for (int i = 1; i < nodeLines.Length; i++)
                {
                    //Dictionaries to populate with nodes.
                    Dictionary<string, Dictionary<string, string[]>> curServer;
                    Dictionary<string, string[]> curLayer;
    
                    curLine = nodeLines[i].Split(',');
                    roomName = curLine[1];
                    serverName = curLine[2];
                    layerName = curLine[4];
                    nodeId = curLine[3];
    
                    if (roomName != GameManager.instance.room)
                    {
                        continue;
                    }
    
                    // If nodeMasterTree contains no entry for the node's network, create one.
                    if (nodeFieldList.ContainsKey(serverName))
                    {
                        curServer = nodeFieldList[serverName];
                    }
                    else
                    {
                        curServer = new Dictionary<string, Dictionary<string, string[]>>();
                        nodeFieldList.Add(serverName, curServer);
                    }
    
                    // If the network dictionary contains no entry for the node's layer, create one.
                    if (curServer.ContainsKey(layerName))
                    {
                        curLayer = curServer[layerName];
                    }
                    else
                    {
                        curLayer = new Dictionary<string, string[]>();
                        curServer.Add(layerName, curLayer);
                    }
    
                    // If the layer dictionary already contains an entry for the source ID, error out. We shouldn't have duplicates in the file.
                    if (curLayer.ContainsKey(nodeId))
                    {
                        Debug.LogError("Duplicate node detected. We shouldn't have duplicates in the file.");
                        string curLineFormatted = "";
                        foreach (string attr in curLine)
                        {
                            curLineFormatted += attr + " ";
                        }
                        Debug.Log(curLineFormatted);
                    }
                    // If we haven't errored out, create a Node object and pass in all the data from the current line.
                    //curNode = NetObject.getNetObject(curLine);
    
                    //Add the Node object to the layer dictionary with source ID as the key.
                    curLayer.Add(nodeId, curLine);
                }
    
                //Link data validation and processing
                for (int i = 1; i < linkLines.Length; i++)
                {
                    //Dictionaries to populate with nodes.
                    Dictionary<string, Dictionary<string, string[]>> curServer;
    
                    curLine = linkLines[i].Split(',');
    
                    roomName = curLine[1];
                    if (roomName != GameManager.instance.room)
                    {
                        continue;
                    }
    
                    serverName = curLine[2];
    
                    // If nodeMasterTree contains no entry for the link's network, error out.
                    if (!nodeFieldList.ContainsKey(serverName))
                    {
                        Debug.LogError("No nodes found with server: " + serverName + " - " + linkPath + " line " + (i + 1));
                        continue;
                    }
    
                    curServer = nodeFieldList[serverName];
    
                    
  • ar3k_g
    ar3k_g
    edited April 2019
    /5/
    
    //I'll redo the validation in the refactor!
                    /*
                     // There's some code duplication here, and I'm going to want to reduce that later.
                    // For source node
                    nodeId = curLine[1];
                    layerName = curLine[2];
    
                    // If the server dictionary contains no entry for the node's layer, error out
                    curServer = nodeFieldList[serverName];
    
                    if (!curServer.ContainsKey(layerName))
                    {
                        Debug.LogError("No nodes found in server: " + serverName + " with layer: " + layerName + " - " + linkPath + " line " + (i + 1));
                        continue;
                    }
    
    
                    // If the layer dictionary contains no entry for the source ID, error out.
                    curLayer = curServer[layerName];
    
                    if (!curLayer.ContainsKey(nodeId))
                    {
                        Debug.LogError("No nodes found in server: " + serverName + " with layer: " + layerName + " and ID: " + nodeId + " - " + linkPath + " line " + (i + 1));
                        continue;
                    }
                     */
    
    
                    // If we haven't errored out, put curLine on the linked list.
                    linkMasterList.Add(curLine);
    
                }
    
                //Stats data validation and processing
                for (int i = 1; i < statLines.Length; i++)
                {
                    //Dictionaries to populate with nodes.
                    Dictionary<string, Dictionary<string, Dictionary<string, string[]>>> curServer;
                    Dictionary<string, Dictionary<string, string[]>> curLayer;
                    Dictionary<string, string[]> curNode;
    
                    curLine = statLines[i].Split(',');
                    serverName = curLine[1];
                    nodeId = curLine[2];
                    layerName = curLine[3];
                    protocolName = curLine[4];
    
                    // If nodeMasterTree contains no entry for the node's network, create one.
                    if (statFieldList.ContainsKey(serverName))
                    {
                        curServer = statFieldList[serverName];
                    }
                    else
                    {
                        curServer = new Dictionary<string, Dictionary<string, Dictionary<string, string[]>>>();
                        statFieldList.Add(serverName, curServer);
                    }
    
                    // If the network dictionary contains no entry for the node's layer, create one.
                    if (curServer.ContainsKey(layerName))
                    {
                        curLayer = curServer[layerName];
                    }
                    else
                    {
                        curLayer = new Dictionary<string, Dictionary<string, string[]>>();
                        curServer.Add(layerName, curLayer);
                    }
    
                    // If the layer dictionary already contains an entry for the source ID, error out. We shouldn't have duplicates in the file.
                    if (curLayer.ContainsKey(nodeId))
                    {
                        curNode = curLayer[nodeId];
                    }
                    else
                    {
                        curNode = new Dictionary<string, string[]>();
                        curLayer.Add(nodeId, curNode);
                    }
    
                    // If the layer dictionary already contains an entry for the source ID, error out. We shouldn't have duplicates in the file.
                    if (curNode.ContainsKey(protocolName))
                    {
                        Debug.LogError("Duplicate node detected. We shouldn't have duplicates in the file.");
                    }
                    
                    //Add the Node object to the layer dictionary with source ID as the key.
                    curNode.Add(protocolName, curLine);
                }
    
                // Alerts validation and processing
                for(int i = 1; i < alertLines.Length; i++)
                {
                    curLine = alertLines[i].Split(',');
    
                    roomName = curLine[0];
                    if (roomName != GameManager.instance.room)
                    {
                        continue;
                    }
    
                    alertMasterList.Add(curLine);
                }
                
                
    
                object[] masterLists = { nodeFieldList, linkMasterList.ToArray(), statFieldList, alertMasterList.ToArray() };
    
                //This is where we instantiate!
                Debug.Log("*************Instantiating Network******************");
                PhotonNetwork.Instantiate("Networks", Vector3.zero, Quaternion.identity, 0, masterLists);
                
            }
    
            public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
            {
                //throw new NotImplementedException();
            }
    
    
            #region PUN Callbacks
    
            public override void OnPlayerLeftRoom(Player otherPlayer)
            {
                Debug.Log("Player left");
            }
    
            #endregion
        } //End NetworkMesh
    } //End Namespace NetworkMeshHelpers
    
    
  • Ah, clue: it barfs on dictionaries.
  • Erm. That's a lot of code.
    I'm sorry but I can't read that all (and much less so, as you also don't really seem to be willing to work through this inherited code).
    This time, I fixed the formatting. Next time, I will have to ignore a post entirely, if it's not formatted (and thus unreadable).

    If protocol 1.8 works for this: Fine. You may use that.
    It would be nicer, if you'd simplify the data for the network transfer. It's really important to have lean, simple messages with the lowest amount of data per update. It doesn't look like this is a given in this case.

    I'm sorry that we're not of more help in this case. Clean up and refactor is currently the best advice I can give.
  • [quote="ar3k_g;d-13769"IndexOutOfRangeException: Index was outside the bounds of the array. [/quote]

    This exception means that you're trying to access a collection item by index, using an invalid index. An index is invalid when it's lower than the collection's lower bound or greater than or equal to the number of elements it contains. Indexing an empty list will always throw an exception. Use a method like Add to append the item to the end of the list, or Insert to place the item in the middle of the list somewhere, etc. You cannot index into a list if that offset doesn't exist. IndexOutOfRangeException exception is thrown as a result of developer error. Instead of handling the exception, you should diagnose the cause of the error and correct your code.