/// <summary> /// this method responds to a 'TransmitKill' vp_GlobalEvent raised by an /// object in the master scene and sends out an RPC to enforce the kill /// on remote machines. it is typically sent out by vp_PlayerDamageHandler /// or vp_DamageHandler /// </summary> protected virtual void TransmitKill(Transform targetTransform) { if (!PhotonNetwork.isMasterClient) { return; } // --- killing a PLAYER --- vp_MPNetworkPlayer player = vp_MPNetworkPlayer.Get(targetTransform); if (player != null) { player.photonView.RPC("ReceivePlayerKill", PhotonTargets.All); return; } // --- killing an OBJECT --- int viewID = vp_MPMaster.GetViewIDOfTransform(targetTransform); if (viewID > 0) { // send RPC with kill command to photonView of this script on all clients photonView.RPC("ReceiveObjectKill", PhotonTargets.Others, viewID); } // TIP: local player could be forced to drop its current weapon as a pickup here // however dropping items is not yet supported }
/// <summary> /// returns the vp_MPNetworkPlayer associated with 'transform' (if any) /// </summary> public static vp_MPNetworkPlayer Get(Transform transform) { vp_MPNetworkPlayer player = null; Players.TryGetValue(transform, out player); return(player); }
void RequestInteraction(PhotonMessageInfo info) { if (!vp_Gameplay.IsMaster) { return; } if (info.sender.IsMasterClient) { return; } // find the networkplayer corresponding to the sender id vp_MPNetworkPlayer player = vp_MPNetworkPlayer.Get(info.sender.ID); // abort if no such player if (player == null) { return; } // in order to trigger an interaction, the player must be close to the interactable if (!player.IsCloseTo(Collider)) { return; } if (player.Player == null) { return; } Interactable.TryInteract(player.Player); }
/// <summary> /// /// </summary> void DrawPlayerRow(vp_MPNetworkPlayer p, Vector2 position, Vector2 scale) { m_CurrentRowColor = ((m_CurrentRowColor == m_TranspWhiteLine) ? m_TranspBlackLine : m_TranspWhiteLine); if (p.photonView.owner == PhotonNetwork.player) { m_CurrentRowColor = m_TranspCyan; } DrawLabel(vp_MPNetworkPlayer.GetName(p.photonView.ownerId), position, scale, PlayerTextStyle, Color.white, m_CurrentRowColor); m_Pos = position; m_Pos.x += scale.x - m_Padding - GetColumnWidth(scale.x); foreach (string s in VisibleStatNames) { if (s == "Ping") { DrawStatLabel(p.Ping.ToString(), m_Pos, scale); continue; } object stat = p.Stats.Get(s); string statOut = stat.ToString(); DrawStatLabel(statOut.ToString(), m_Pos, scale); } m_Pos.x = position.x; m_Size.y = 20; }
/// <summary> /// creates a hashtable with only a few of the stats of a /// certain player /// </summary> protected virtual ExitGames.Client.Photon.Hashtable ExtractPlayerStats(vp_MPNetworkPlayer player, params string[] stats) { if (!PhotonNetwork.isMasterClient) { return(null); } // create a player hashtable with only the given stats ExitGames.Client.Photon.Hashtable table = new ExitGames.Client.Photon.Hashtable(); //string str = "Extracting stats for player: " + vp_MPNetworkPlayer.GetName(player.ID); foreach (string s in stats) { object o = player.Stats.Get(s); if (o == null) { Debug.LogError("Error: (" + this + ") Player stat '" + s + "' could not be retrieved from player " + player.ID + "."); continue; } table.Add(s, o); //str += ": " + s + "(" + o + ")"; } //Debug.Log(str); return(table); }
void RequestAutoStart(PhotonMessageInfo info) { if (!vp_Gameplay.IsMaster) { return; } // must have a rigidbody collider to check for proximity if (Collider == null) { return; } // find the networkplayer corresponding to the sender id vp_MPNetworkPlayer player = vp_MPNetworkPlayer.Get(info.sender.ID); // abort if no such player if (player == null) { return; } // in order to autostart this platform, the player must be close to it if (!player.IsCloseTo(Collider)) { return; } MovingPlatform.TryAutoStart(); }
/// <summary> /// RPC /// </summary> protected void TransmitDropItem(object[] obj) { if (!PhotonNetwork.isMasterClient) { return; } if (obj == null) { return; } if (obj.Length != 6) { return; } // item type name string itemTypeName = obj[0] as string; if ((itemTypeName == null) || string.IsNullOrEmpty(itemTypeName)) { return; } // final drop position Vector3 targetPosition = (Vector3)obj[1]; // final drop rotation float targetYaw = (float)obj[2]; // player transform Transform playerTransform = obj[3] as Transform; if (playerTransform == null) { return; } // network player from transform vp_MPNetworkPlayer player = vp_MPNetworkPlayer.Get(playerTransform); if (player == null) { return; } // pickup id int pickupID = (int)obj[4]; // ammo int unitAmount = (int)obj[5]; player.photonView.RPC("ReceiveDropItem", PhotonTargets.Others, itemTypeName, targetPosition, targetYaw, player.ID, pickupID, unitAmount); }
/// <summary> /// /// </summary> static void AddPhotonViewToPlayer(vp_MPNetworkPlayer networkPlayer, int id) { PhotonView p = null; p = (PhotonView)networkPlayer.gameObject.AddComponent <PhotonView>(); p.viewID = (id * 1000) + 1; // TODO: may crash with 'array index out of range' if a player is deactivated in its prefab p.onSerializeTransformOption = OnSerializeTransform.OnlyPosition; p.ObservedComponents = new List <Component>(); p.ObservedComponents.Add(networkPlayer); p.synchronization = ViewSynchronization.UnreliableOnChange; PhotonNetwork.networkingPeer.RegisterPhotonView(p); }
protected virtual void RequestPushRigidBody(Vector3 direction, Vector3 point, PhotonMessageInfo info) { // abort if this machine does not have authority to push things if (!vp_Gameplay.IsMaster) { return; } // abort if this rigidbody has very recently been pushed if (Time.time < m_NextAllowedPushTime) { return; } m_NextAllowedPushTime = Time.time + MinPushInterval; // find the networkplayer corresponding to the sender id vp_MPNetworkPlayer player = vp_MPNetworkPlayer.Get(info.sender.ID); // abort if no such player if (player == null) { return; } // in order to push this rigidbody the player must be either located // inside the bounds of its collider ... if (!Collider.bounds.Contains(player.Collider.bounds.center) // ... OR must be located within a distance equal to one player height // from the 'closest point on bounds' of the requested contact point && (Vector3.Distance(player.Collider.bounds.center, Rigidbody.ClosestPointOnBounds(point)) > player.Player.Height.Get())) { return; } // abort if player is trying to pull rather than push if (Vector3.Dot(direction.normalized, (player.Transform.position - point)) > 0) { return; } // push the rigidbody according to the final direction, push force mode and point of impact switch (PhysicsPushMode) { case PushForceMode.SameAsController: player.Controller.PushRigidbody(Rigidbody, direction, player.Controller.PhysicsPushMode, point); break; case PushForceMode.Simplified: player.Controller.PushRigidbody(Rigidbody, direction, vp_Controller.PushForceMode.Simplified, point); break; case PushForceMode.Kinetic: player.Controller.PushRigidbody(Rigidbody, direction, vp_Controller.PushForceMode.Kinetic, point); break; } }
/// <summary> /// respawns the network player of 'transform' at 'placement' /// </summary> public static void TransmitPlayerRespawn(Transform transform, vp_Placement placement) { if (!PhotonNetwork.isMasterClient) { return; } //UnityEngine.Debug.Log("respawning " + t.gameObject.name); vp_MPNetworkPlayer.RefreshPlayers(); vp_MPNetworkPlayer player = vp_MPNetworkPlayer.Get(transform); if (player != null) { player.photonView.RPC("ReceivePlayerRespawn", PhotonTargets.All, placement.Position, placement.Rotation); } }
/// <summary> /// respawns the network player of transform 't' at a random, team /// based placement /// </summary> public static void TransmitRespawn(Transform t) { if (!PhotonNetwork.isMasterClient) { return; } vp_MPNetworkPlayer p = vp_MPNetworkPlayer.Get(t); if ((p != null) && vp_MPTeamManager.Exists && (p.TeamNumber > 0)) { TransmitPlayerRespawn(t, GetRandomPlacement(vp_MPTeamManager.GetTeamName(p.TeamNumber))); } else { TransmitPlayerRespawn(t, GetRandomPlacement()); } }
/// <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> /// /// </summary> void DrawPlayerRow(vp_MPNetworkPlayer p, Vector2 position, Vector2 scale) { m_CurrentRowColor = ((m_CurrentRowColor == m_TranspWhiteLine) ? m_TranspBlackLine : m_TranspWhiteLine); if (p.photonView.owner == PhotonNetwork.player) m_CurrentRowColor = m_TranspCyan; DrawLabel(vp_MPNetworkPlayer.GetName(p.photonView.ownerId), position, scale, PlayerTextStyle, Color.white, m_CurrentRowColor); m_Pos = position; m_Pos.x += scale.x - m_Padding - GetColumnWidth(scale.x); foreach (string s in VisibleStatNames) { object stat = p.Stats.Get(s); string statOut = stat.ToString(); DrawStatLabel(statOut.ToString(), m_Pos, scale); } m_Pos.x = position.x; m_Size.y = 20; }
/// <summary> /// creates a hashtable with only a few of the stats of a /// certain player /// </summary> protected virtual ExitGames.Client.Photon.Hashtable ExtractPlayerStats(vp_MPNetworkPlayer player, params string[] stats) { if (!PhotonNetwork.isMasterClient) return null; // create a player hashtable with only the given stats ExitGames.Client.Photon.Hashtable table = new ExitGames.Client.Photon.Hashtable(); //string str = "Extracting stats for player: " + vp_MPNetworkPlayer.GetName(player.ID); foreach (string s in stats) { object o = player.Stats.Get(s); if (o == null) { Debug.LogError("Error: (" + this + ") Player stat '" + s + "' could not be retrieved from player " + player.ID + "."); continue; } table.Add(s, o); //str += ": " + s + "(" + o + ")"; } //Debug.Log(str); return table; }
/// <summary> /// /// </summary> static void AddPhotonViewToPlayer(vp_MPNetworkPlayer networkPlayer, int id) { PhotonView p = null; p = (PhotonView)networkPlayer.gameObject.AddComponent<PhotonView>(); p.viewID = (id * 1000) + 1; // TODO: may crash with 'array index out of range' if a player is deactivated in its prefab p.onSerializeTransformOption = OnSerializeTransform.OnlyPosition; p.ObservedComponents = new List<Component>(); p.ObservedComponents.Add(networkPlayer); p.synchronization = ViewSynchronization.UnreliableOnChange; PhotonNetwork.networkingPeer.RegisterPhotonView(p); }
/// <summary> /// /// </summary> protected override void TransmitDamage(Transform targetTransform, Transform sourceTransform, float damage) { if (!PhotonNetwork.isMasterClient) { return; } vp_MPNetworkPlayer target = vp_MPNetworkPlayer.Get(targetTransform); if ((target == null) || // if target is an object (not a player) ... (target.DamageHandler.CurrentHealth > 0.0f)) // ... or it's a player that was only damaged (not killed) ... { // ... transmit a simple health update (update remote clients with // its health from the master scene) and bail out base.TransmitDamage(targetTransform, sourceTransform, damage); return; } // if this was healing and not damage, nothing more to do here if (damage <= 0.0f) { return; } // if we get here then target was a player that got killed, so // see if we know about the damage source vp_MPNetworkPlayer source = vp_MPNetworkPlayer.Get(sourceTransform); if (source == null) { return; } // we know who did it! if this injury killed the target, update the // local (master scene) stats for both players TIP: hit statistics // can be implemented here if ((target.DamageHandler.CurrentHealth + damage) > 0.0f) { // you get one 'Score' and one 'Kill' for every takedown of a player // on a different team if (target != source) { if ((target.TeamNumber != source.TeamNumber) || // inter-team kill ((target.TeamNumber == 0) && (source.TeamNumber == 0)) // or there are no teams! ) { source.Stats.Set("Frags", (int)source.Stats.Get("Frags") + 1); source.Stats.Set("Score", (int)source.Stats.Get("Score") + 1); target.Stats.Set("Deaths", (int)target.Stats.Get("Deaths") + 1); target.Stats.Set("Score", (int)target.Stats.Get("Score") - 1); } else // intra-team kill { // you loose one 'Score' for every friendly kill // the teammate's stats are not affected source.Stats.Set("Score", (int)source.Stats.Get("Score") - 1); } } // killing yourself shall always award one 'Death' and minus one 'Score' else { target.Stats.Set("Deaths", (int)target.Stats.Get("Deaths") + 1); target.Stats.Set("Score", (int)target.Stats.Get("Score") - 1); } } // send RPC with updated stats to the photonView of the gamelogic // object on all clients. NOTES: // 1) we only broadcast the stats that have actually changed // 2) we can't send a target and sender with the same ID, since // adding the same key twice to a hashtable is impossible if (target != source) // kill { vp_MPMaster.Instance.TransmitPlayerState(new int[] { target.ID, source.ID }, new string[] { "Deaths", "Score" }, new string[] { "Frags", "Score" }); } else // suicide { vp_MPMaster.Instance.TransmitPlayerState(new int[] { target.ID }, new string[] { "Deaths", "Score" }); } }
/// <summary> /// /// </summary> protected override void TransmitDamage(Transform targetTransform, Transform sourceTransform, float damage) { if (!PhotonNetwork.isMasterClient) { return; } vp_MPNetworkPlayer target = vp_MPNetworkPlayer.Get(targetTransform); if ((target == null) || // if target is an object (not a player) ... (target.DamageHandler.CurrentHealth > 0.0f)) // ... or it's a player that was only damaged (not killed) ... { // ... transmit a simple health update (update remote clients with // its health from the master scene) and bail out base.TransmitDamage(targetTransform, sourceTransform, damage); return; } // if this was healing and not damage, nothing more to do here if (damage <= 0.0f) { return; } // if we get here then target was a player that got killed, so // see if we know about the damage source vp_MPNetworkPlayer source = vp_MPNetworkPlayer.Get(sourceTransform); if (source == null) { return; } // we know who did it! if this injury killed the target, update the // local (master scene) stats for both players TIP: hit statistics // can be implemented here if ((target.DamageHandler.CurrentHealth + damage) > 0.0f) { if (target != source) { source.Stats.Set("Killstreak", (int)source.Stats.Get("Killstreak") + 1); target.Stats.Set("Killstreak", (int)0); } else { target.Stats.Set("Killstreak", (int)0); } } // send RPC with updated stats to the photonView of the gamelogic // object on all clients. NOTES: // 1) we only broadcast the stats that have actually changed // 2) we can't send a target and sender with the same ID, since // adding the same key twice to a hashtable is impossible if (target != source) // kill { vp_MPMaster.Instance.TransmitPlayerState(new int[] { target.ID, source.ID }, new string[] { "Killstreak" }, new string[] { "Killstreak" }); } else // suicide { vp_MPMaster.Instance.TransmitPlayerState(new int[] { target.ID }, new string[] { "Killstreak" }); } }