/// <summary>
    /// returns the vp_MPNetworkPlayer associated with a certain
    /// photon player id
    /// </summary>
    public static vp_MPNetworkPlayer Get(int id)
    {
        vp_MPNetworkPlayer player = null;

        if (!PlayersByID.TryGetValue(id, out player))
        {
            foreach (vp_MPNetworkPlayer p in Players.Values)
            {
                if (p == null)
                {
                    continue;
                }
                if (p.ID == id)
                {
                    PlayersByID.Add(id, p);
                    return(p);
                }
            }
        }

        return(player);
    }
    /// <summary>
    /// removes departed players and refreshes components of remaining
    /// players. this includes team color, spawnpoint targets, collider
    /// event logic, body materials and gameobject names in the editor
    /// </summary>
    public static void RefreshPlayers()
    {
        // --- removes departed players ---

        List <int>        nullIDs         = null;
        List <Transform>  nullTransforms  = null;
        List <GameObject> departedPlayers = null;

        // find network players whose photon players have left
        foreach (vp_MPNetworkPlayer p in vp_MPNetworkPlayer.Players.Values)
        {
            if (p == null)
            {
                continue;
            }
            if ((p.photonView == null) || (p.photonView.owner == null))
            {
                if (departedPlayers == null)
                {
                    departedPlayers = new List <GameObject>();
                }
                departedPlayers.Add(p.gameObject);
            }
        }

        if (departedPlayers != null)
        {
            foreach (GameObject g in departedPlayers)
            {
                UnityEngine.Object.DestroyImmediate(g);
            }
        }

        // find transforms that have no network player
        foreach (Transform key in Players.Keys)
        {
            vp_MPNetworkPlayer player;
            Players.TryGetValue(key, out player);
            if (player == null)
            {
                if (nullTransforms == null)
                {
                    nullTransforms = new List <Transform>();
                }
                nullTransforms.Add(key);
                continue;
            }

            if (!PlayersByID.ContainsValue(player))
            {
                if (player.ID != 0)
                {
                    PlayersByID.Add(player.ID, player);
                }
            }
        }

        // find ids that have no player
        foreach (int key in PlayersByID.Keys)
        {
            vp_MPNetworkPlayer player;
            PlayersByID.TryGetValue(key, out player);
            if (player == null)
            {
                if (nullIDs == null)
                {
                    nullIDs = new List <int>();
                }
                nullIDs.Add(key);
            }
        }

        // remove null IDs and transforms
        if (nullTransforms != null)
        {
            foreach (Transform t in nullTransforms)
            {
                Players.Remove(t);
            }
        }

        if (nullIDs != null)
        {
            foreach (int i in nullIDs)
            {
                PlayersByID.Remove(i);
            }
        }

        // --- refresh components of remaining players ---

        foreach (vp_MPNetworkPlayer p in vp_MPNetworkPlayer.Players.Values)
        {
            if (p == null)
            {
                continue;
            }
            p.RefreshComponents();
        }
    }