Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/jackmawer/JacksWorld. An abandoned mini-project that I created while learning to use Unity with networking.
Something went wrong. Try again.
8.3 kB · 214 lines
C#
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215using System.Collections.Generic;using UnityEngine;using System.Collections;using Hashtable = ExitGames.Client.Photon.Hashtable;
/// <summary>/// Makes a scene object pickup-able. Needs a PhotonView which belongs to the scene./// </summary>/// <remarks>Includes a OnPhotonSerializeView implementation that </remarks>[RequireComponent(typeof(PhotonView))]public class PickupItem : Photon.MonoBehaviour, IPunObservable{ ///<summary>Enables you to define a timeout when the picked up item should re-spawn at the same place it was before.</summary> /// <remarks> /// Set in Inspector per GameObject! The value in code is just the default. /// /// If you don't want an item to respawn, set SecondsBeforeRespawn == 0. /// If an item does not respawn, it could be consumed or carried around and dropped somewhere else. /// /// A respawning item should stick to a fixed position. It should not be observed at all (in any PhotonView). /// It can only be consumed and can't be dropped somewhere else (cause that would double the item). /// /// This script uses PunRespawn() as RPC and as method that gets called by Invoke() after a timeout. /// No matter if the item respawns timed or by Drop, that method makes sure (temporary) owner and other status-values /// are being re-set. /// </remarks> public float SecondsBeforeRespawn = 2; /// <summary>The most likely trigger to pick up an item. Set in inspector!</summary> /// <remarks>Edit the collider and set collision masks to avoid pickups by random objects.</remarks> public bool PickupOnTrigger;
/// <summary>If the pickup item is currently yours. Interesting in OnPickedUp(PickupItem item).</summary> public bool PickupIsMine;
/// <summary>GameObject to send an event "OnPickedUp(PickupItem item)" to.</summary> /// <remarks> /// Implement OnPickedUp(PickupItem item) {} in some script on the linked game object. /// The item will be "this" and item.PickupIsMine will help you to find if this pickup was done by "this player". /// </remarks> public MonoBehaviour OnPickedUpCall;
// these values are internally used. they are public for debugging only /// <summary>If this client sent a pickup. To avoid sending multiple pickup requests before reply is there.</summary> public bool SentPickup; /// <summary>Timestamp when to respawn the item (compared to PhotonNetwork.time). </summary> public double TimeOfRespawn; // needed when we want to update new players when a PickupItem respawns /// <summary></summary> public int ViewID { get { return this.photonView.viewID; } }
public static HashSet<PickupItem> DisabledPickupItems = new HashSet<PickupItem>();
public void OnTriggerEnter(Collider other) { // we only call Pickup() if "our" character collides with this PickupItem. // note: if you "position" remote characters by setting their translation, triggers won't be hit.
PhotonView otherpv = other.GetComponent<PhotonView>(); if (this.PickupOnTrigger && otherpv != null && otherpv.isMine) { //Debug.Log("OnTriggerEnter() calls Pickup()."); this.Pickup(); } }
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) { // read the description in SecondsBeforeRespawn
if (stream.isWriting && SecondsBeforeRespawn <= 0) { stream.SendNext(this.gameObject.transform.position); } else { // this will directly apply the last received position for this PickupItem. No smoothing. Usually not needed though. Vector3 lastIncomingPos = (Vector3)stream.ReceiveNext(); this.gameObject.transform.position = lastIncomingPos; } }
public void Pickup() { if (this.SentPickup) { // skip sending more pickups until the original pickup-RPC got back to this client return; } this.SentPickup = true; this.photonView.RPC("PunPickup", PhotonTargets.AllViaServer); }
/// <summary>Makes use of RPC PunRespawn to drop an item (sent through server for all).</summary> public void Drop() { if (this.PickupIsMine) { this.photonView.RPC("PunRespawn", PhotonTargets.AllViaServer); } }
/// <summary>Makes use of RPC PunRespawn to drop an item (sent through server for all).</summary> public void Drop(Vector3 newPosition) { if (this.PickupIsMine) { this.photonView.RPC("PunRespawn", PhotonTargets.AllViaServer, newPosition); } }
[RPC] public void PunPickup(PhotonMessageInfo msgInfo) { // when this client's RPC gets executed, this client no longer waits for a sent pickup and can try again if (msgInfo.sender.isLocal) this.SentPickup = false;
// In this solution, picked up items are disabled. They can't be picked up again this way, etc. // You could check "active" first, if you're not interested in failed pickup-attempts. if (!this.gameObject.GetActive()) { // optional logging: Debug.Log("Ignored PU RPC, cause item is inactive. " + this.gameObject + " SecondsBeforeRespawn: " + SecondsBeforeRespawn + " TimeOfRespawn: " + this.TimeOfRespawn + " respawn in future: " + (TimeOfRespawn > PhotonNetwork.time)); return; // makes this RPC being ignored }
// if the RPC isn't ignored by now, this is a successful pickup. this might be "my" pickup and we should do a callback this.PickupIsMine = msgInfo.sender.isLocal; // call the method OnPickedUp(PickupItem item) if a GameObject was defined as callback target if (this.OnPickedUpCall != null) { // you could also skip callbacks for items that are not picked up by this client by using: if (this.PickupIsMine) this.OnPickedUpCall.SendMessage("OnPickedUp", this); }
// setup a respawn (or none, if the item has to be dropped) if (SecondsBeforeRespawn <= 0) { this.PickedUp(0.0f); // item doesn't auto-respawn. must be dropped } else { // how long it is until this item respanws, depends on the pickup time and the respawn time double timeSinceRpcCall = (PhotonNetwork.time - msgInfo.timestamp); double timeUntilRespawn = SecondsBeforeRespawn - timeSinceRpcCall;
//Debug.Log("msg timestamp: " + msgInfo.timestamp + " time until respawn: " + timeUntilRespawn);
if (timeUntilRespawn > 0) { this.PickedUp((float)timeUntilRespawn); } } }
internal void PickedUp(float timeUntilRespawn) { // this script simply disables the GO for a while until it respawns. this.gameObject.SetActive(false); PickupItem.DisabledPickupItems.Add(this); this.TimeOfRespawn = 0;
if (timeUntilRespawn > 0) { this.TimeOfRespawn = PhotonNetwork.time + timeUntilRespawn; Invoke("PunRespawn", timeUntilRespawn); } }
[RPC] internal void PunRespawn(Vector3 pos) { Debug.Log("PunRespawn with Position."); this.PunRespawn(); this.gameObject.transform.position = pos; }
[RPC] internal void PunRespawn() { #if DEBUG // debugging: in some cases, the respawn is "late". it's unclear why! just be aware of this. double timeDiffToRespawnTime = PhotonNetwork.time - this.TimeOfRespawn; if (timeDiffToRespawnTime > 0.1f) Debug.LogWarning("Spawn time is wrong by: " + timeDiffToRespawnTime + " (this is not an error. you just need to be aware of this.)"); #endif
// if this is called from another thread, we might want to do this in OnEnable() instead of here (depends on Invoke's implementation) PickupItem.DisabledPickupItems.Remove(this); this.TimeOfRespawn = 0; this.PickupIsMine = false;
if (this.gameObject != null) { this.gameObject.SetActive(true); } }}