467 lines
14 KiB
C#
467 lines
14 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using ExitGames.Client.Photon;
|
|
using Photon.Pun;
|
|
using Photon.Realtime;
|
|
using ShiningGames.UFS2;
|
|
using UFS2.Gameplay;
|
|
using UnityEngine;
|
|
|
|
public class MultiplayerFishSpawner : MonoBehaviour, IOnEventCallback
|
|
{
|
|
public class NetworkedFish
|
|
{
|
|
public string guid;
|
|
|
|
public int fishID;
|
|
|
|
public float fishWeight;
|
|
|
|
public FishEntity fishEntity;
|
|
|
|
public Vector3 position;
|
|
|
|
public int targetAreaID;
|
|
|
|
public int actorInControl;
|
|
|
|
public MultiplayerFishEntity multiplayerFishEntity;
|
|
|
|
public Guid Guid => new Guid(guid);
|
|
|
|
public NetworkedFish(string guid, int fishID, float fishWeight)
|
|
{
|
|
this.guid = guid;
|
|
this.fishID = fishID;
|
|
this.fishWeight = fishWeight;
|
|
fishEntity = null;
|
|
position = Vector3.zero;
|
|
targetAreaID = 0;
|
|
actorInControl = -1;
|
|
multiplayerFishEntity = null;
|
|
}
|
|
}
|
|
|
|
public static MultiplayerFishSpawner Instance;
|
|
|
|
[SerializeField]
|
|
[Tooltip("Delay in seconds between sending fish synchronization packets to slave clients")]
|
|
[Range(0f, 1f)]
|
|
private float fishSyncDelay = 0.2f;
|
|
|
|
[SerializeField]
|
|
[Tooltip("Number of fishes contained in one synchronization packet")]
|
|
[Range(1f, 30f)]
|
|
private int fishSyncCount = 3;
|
|
|
|
[SerializeField]
|
|
private MultiplayerFishEntity multiplayerFishEntity_prefab;
|
|
|
|
private List<NetworkedFish> networkedFishList;
|
|
|
|
private Coroutine fishSyncCoroutine;
|
|
|
|
public static bool IsOnline => GetIsOnline();
|
|
|
|
public static bool IsMaster => GetIsMaster();
|
|
|
|
public static bool IsSlave => GetIsSlave();
|
|
|
|
public static event Action<NetworkedFish> OnNetworkedFishSpawn;
|
|
|
|
public static event Action<NetworkedFish> OnNetworkedFishDelete;
|
|
|
|
public static event Action OnFishDeleteAfterInteraction;
|
|
|
|
public static bool GetIsOnline()
|
|
{
|
|
if (Instance != null)
|
|
{
|
|
return MultiplayerManager.InRoomLocationStatic;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool GetIsMaster()
|
|
{
|
|
bool result = false;
|
|
if (GetIsOnline())
|
|
{
|
|
result = PhotonNetwork.IsMasterClient;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static bool GetIsSlave()
|
|
{
|
|
bool result = false;
|
|
if (GetIsOnline())
|
|
{
|
|
result = !PhotonNetwork.IsMasterClient;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static void CheckFishInteractionWithPlayer(FishEntity fishEntity, out bool withLocalPlayer, out bool withRemotePlayer)
|
|
{
|
|
withLocalPlayer = false;
|
|
withRemotePlayer = false;
|
|
NetworkedFish networkedFish = GetNetworkedFish(fishEntity);
|
|
if (networkedFish?.multiplayerFishEntity != null)
|
|
{
|
|
PhotonView photonView = networkedFish.multiplayerFishEntity.photonView;
|
|
withLocalPlayer = photonView.IsMine;
|
|
withRemotePlayer = !photonView.IsMine;
|
|
}
|
|
}
|
|
|
|
public static bool CheckFishInteractionWithPlayer(FishEntity fishEntity)
|
|
{
|
|
return GetNetworkedFish(fishEntity)?.multiplayerFishEntity != null;
|
|
}
|
|
|
|
public static NetworkedFish GetNetworkedFish(FishEntity fishEntity)
|
|
{
|
|
NetworkedFish result = null;
|
|
if (Instance != null && Instance.networkedFishList != null)
|
|
{
|
|
result = Instance.networkedFishList.FirstOrDefault((NetworkedFish fish) => fish.fishEntity == fishEntity);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static NetworkedFish GetNetworkedFish(string guid)
|
|
{
|
|
NetworkedFish result = null;
|
|
if (Instance != null && Instance.networkedFishList != null)
|
|
{
|
|
result = Instance.networkedFishList.FirstOrDefault((NetworkedFish fish) => fish.guid == guid);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static void FishControlRequest(FishEntity fishEntity)
|
|
{
|
|
NetworkedFish networkedFish = GetNetworkedFish(fishEntity);
|
|
PhotonNetwork.RaiseEvent(2, new object[1] { networkedFish.Guid.ToByteArray() }, new RaiseEventOptions
|
|
{
|
|
Receivers = ReceiverGroup.MasterClient
|
|
}, SendOptions.SendReliable);
|
|
}
|
|
|
|
public static void FishControlRequestCancel(FishEntity fishEntity)
|
|
{
|
|
NetworkedFish networkedFish = GetNetworkedFish(fishEntity);
|
|
PhotonNetwork.RaiseEvent(3, new object[1] { networkedFish.Guid.ToByteArray() }, new RaiseEventOptions
|
|
{
|
|
Receivers = ReceiverGroup.MasterClient
|
|
}, SendOptions.SendReliable);
|
|
}
|
|
|
|
public static MultiplayerFishEntity SpawnMultiplayerFishEntity(FishEntity fishEntity)
|
|
{
|
|
MultiplayerFishEntity multiplayerFishEntity = null;
|
|
NetworkedFish networkedFish = GetNetworkedFish(fishEntity);
|
|
if (!CheckFishInteractionWithPlayer(fishEntity) && networkedFish.actorInControl == PhotonNetwork.LocalPlayer.ActorNumber)
|
|
{
|
|
multiplayerFishEntity = PhotonNetwork.Instantiate(Instance.multiplayerFishEntity_prefab.name, fishEntity.transform.position, fishEntity.transform.rotation, 0).GetComponent<MultiplayerFishEntity>();
|
|
multiplayerFishEntity.Init(networkedFish);
|
|
}
|
|
return multiplayerFishEntity;
|
|
}
|
|
|
|
private void FishSpawner_OnDespawnFish(FishEntity fishEntity)
|
|
{
|
|
if (IsMaster)
|
|
{
|
|
NetworkedFish networkedFish = GetNetworkedFish(fishEntity);
|
|
if (networkedFish != null)
|
|
{
|
|
networkedFishList.Remove(networkedFish);
|
|
PhotonNetwork.RaiseEvent(1, new object[1] { networkedFish.Guid.ToByteArray() }, RaiseEventOptions.Default, SendOptions.SendReliable);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void FishSpawner_OnSpawnFish(FishEntity fishEntity, int levelFishDataIndex)
|
|
{
|
|
if (IsMaster)
|
|
{
|
|
NetworkedFish networkedFish = new NetworkedFish(Guid.NewGuid().ToString(), levelFishDataIndex, fishEntity.Weight);
|
|
networkedFish.fishEntity = fishEntity;
|
|
networkedFish.position = fishEntity.transform.position;
|
|
networkedFish.targetAreaID = FishTargetBaker.Instance.Areas.IndexOf(fishEntity.CurrentArea);
|
|
networkedFish.actorInControl = -1;
|
|
networkedFishList.Add(networkedFish);
|
|
SendFishUpdateEvent(networkedFish);
|
|
}
|
|
}
|
|
|
|
private void SceneLoader_OnBeginSceneLoad(string sceneLoadName)
|
|
{
|
|
networkedFishList = new List<NetworkedFish>();
|
|
}
|
|
|
|
private void SceneLoader_OnSceneLoaded(string sceneLoadName)
|
|
{
|
|
ToggleFishSyncCoroutine(MultiplayerManager.InRoomLocationStatic);
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
if (Instance != null && Instance != this)
|
|
{
|
|
UnityEngine.Object.Destroy(base.gameObject);
|
|
}
|
|
else
|
|
{
|
|
Instance = this;
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
PhotonNetwork.AddCallbackTarget(this);
|
|
FishSpawner.OnSpawnFish += FishSpawner_OnSpawnFish;
|
|
FishSpawner.OnDespawnFish += FishSpawner_OnDespawnFish;
|
|
SceneLoader.OnBeginSceneLoad += SceneLoader_OnBeginSceneLoad;
|
|
SceneLoader.OnSceneLoaded += SceneLoader_OnSceneLoaded;
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
PhotonNetwork.RemoveCallbackTarget(this);
|
|
FishSpawner.OnSpawnFish -= FishSpawner_OnSpawnFish;
|
|
FishSpawner.OnDespawnFish -= FishSpawner_OnDespawnFish;
|
|
SceneLoader.OnBeginSceneLoad -= SceneLoader_OnBeginSceneLoad;
|
|
SceneLoader.OnSceneLoaded -= SceneLoader_OnSceneLoaded;
|
|
}
|
|
|
|
private void Event_FishUpdate(string guid, int fishID, float fishWeight, Vector3 position, int targetAreaID, int actorInControl)
|
|
{
|
|
if (!IsSlave)
|
|
{
|
|
return;
|
|
}
|
|
NetworkedFish networkedFish = GetNetworkedFish(guid);
|
|
if (networkedFish != null)
|
|
{
|
|
networkedFish.position = position;
|
|
networkedFish.targetAreaID = targetAreaID;
|
|
networkedFish.fishEntity.CurrentArea = FishTargetBaker.Instance.Areas[targetAreaID];
|
|
networkedFish.actorInControl = actorInControl;
|
|
if (fishWeight != networkedFish.fishWeight)
|
|
{
|
|
networkedFish.fishWeight = fishWeight;
|
|
networkedFish.fishEntity.TryGrowFish(fishWeight);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetworkedFish networkedFish2 = new NetworkedFish(guid, fishID, fishWeight);
|
|
networkedFish2.position = position;
|
|
networkedFish2.targetAreaID = targetAreaID;
|
|
networkedFish2.actorInControl = actorInControl;
|
|
networkedFishList.Add(networkedFish2);
|
|
MultiplayerFishSpawner.OnNetworkedFishSpawn?.Invoke(networkedFish2);
|
|
}
|
|
}
|
|
|
|
private void Event_FishDelete(string guid)
|
|
{
|
|
if (IsSlave)
|
|
{
|
|
NetworkedFish networkedFish = GetNetworkedFish(guid);
|
|
if (networkedFish != null)
|
|
{
|
|
networkedFishList.Remove(networkedFish);
|
|
MultiplayerFishSpawner.OnNetworkedFishDelete?.Invoke(networkedFish);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Event_FishControlRequest(string guid, int sender)
|
|
{
|
|
if (IsMaster)
|
|
{
|
|
NetworkedFish networkedFish = GetNetworkedFish(guid);
|
|
if (networkedFish != null && PhotonNetwork.CurrentRoom.Players.TryGetValue(sender, out var requestingPlayer) && !networkedFishList.Exists((NetworkedFish element) => element.actorInControl == requestingPlayer.ActorNumber) && !CheckFishInteractionWithPlayer(networkedFish.fishEntity) && networkedFish.actorInControl == -1)
|
|
{
|
|
networkedFish.actorInControl = requestingPlayer.ActorNumber;
|
|
SendFishUpdateEvent(networkedFish);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Event_FishControlRequestCancel(string guid, int sender)
|
|
{
|
|
if (IsMaster)
|
|
{
|
|
NetworkedFish networkedFish = GetNetworkedFish(guid);
|
|
if (networkedFish != null && PhotonNetwork.CurrentRoom.Players.TryGetValue(sender, out var value) && !CheckFishInteractionWithPlayer(networkedFish.fishEntity) && networkedFish.actorInControl == value.ActorNumber)
|
|
{
|
|
networkedFish.actorInControl = -1;
|
|
SendFishUpdateEvent(networkedFish);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Event_FishDeleteAfterInteraction(string guid)
|
|
{
|
|
if (IsMaster)
|
|
{
|
|
NetworkedFish networkedFish = GetNetworkedFish(guid);
|
|
if (networkedFish != null && networkedFish.fishEntity != null)
|
|
{
|
|
FishSpawner.Despawn(networkedFish.fishEntity);
|
|
UnityEngine.Object.Destroy(networkedFish.fishEntity.gameObject);
|
|
MultiplayerFishSpawner.OnFishDeleteAfterInteraction?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OnEvent(EventData photonEvent)
|
|
{
|
|
switch (photonEvent.Code)
|
|
{
|
|
case 0:
|
|
{
|
|
object[] obj = (object[])photonEvent.CustomData;
|
|
byte[][] array = (byte[][])obj[0];
|
|
byte[] array2 = (byte[])obj[1];
|
|
float[] array3 = (float[])obj[2];
|
|
Vector3[] array4 = (Vector3[])obj[3];
|
|
byte[] array5 = (byte[])obj[4];
|
|
byte[] array6 = (byte[])obj[5];
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
if (!array[i].All((byte b) => b == 0))
|
|
{
|
|
string guid5 = new Guid(array[i]).ToString();
|
|
Event_FishUpdate(guid5, array2[i], array3[i], array4[i], array5[i], array6[i]);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
string guid4 = new Guid((byte[])((object[])photonEvent.CustomData)[0]).ToString();
|
|
Event_FishDelete(guid4);
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
string guid3 = new Guid((byte[])((object[])photonEvent.CustomData)[0]).ToString();
|
|
Event_FishControlRequest(guid3, photonEvent.Sender);
|
|
break;
|
|
}
|
|
case 3:
|
|
{
|
|
string guid2 = new Guid((byte[])((object[])photonEvent.CustomData)[0]).ToString();
|
|
Event_FishControlRequestCancel(guid2, photonEvent.Sender);
|
|
break;
|
|
}
|
|
case 4:
|
|
{
|
|
string guid = new Guid((byte[])((object[])photonEvent.CustomData)[0]).ToString();
|
|
Event_FishDeleteAfterInteraction(guid);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SendFishUpdateEvent(NetworkedFish networkedFish)
|
|
{
|
|
if (IsMaster)
|
|
{
|
|
networkedFish.position = networkedFish.fishEntity.transform.position;
|
|
networkedFish.targetAreaID = FishTargetBaker.Instance.Areas.IndexOf(networkedFish.fishEntity.CurrentArea);
|
|
byte[][] array = new byte[1][] { networkedFish.Guid.ToByteArray() };
|
|
byte[] array2 = new byte[1] { (byte)networkedFish.fishID };
|
|
float[] array3 = new float[1] { networkedFish.fishWeight };
|
|
Vector3[] array4 = new Vector3[1] { networkedFish.position };
|
|
byte[] array5 = new byte[1] { (byte)networkedFish.targetAreaID };
|
|
byte[] array6 = new byte[1] { (byte)networkedFish.actorInControl };
|
|
PhotonNetwork.RaiseEvent(0, new object[6] { array, array2, array3, array4, array5, array6 }, RaiseEventOptions.Default, SendOptions.SendReliable);
|
|
}
|
|
}
|
|
|
|
private void ToggleFishSyncCoroutine(bool toggle = false)
|
|
{
|
|
if (fishSyncCoroutine != null)
|
|
{
|
|
StopCoroutine(fishSyncCoroutine);
|
|
fishSyncCoroutine = null;
|
|
}
|
|
if (toggle)
|
|
{
|
|
fishSyncCoroutine = StartCoroutine(FishSyncCoroutine());
|
|
}
|
|
}
|
|
|
|
private void ValidateFishes()
|
|
{
|
|
List<NetworkedFish> list = new List<NetworkedFish>();
|
|
foreach (NetworkedFish networkedFish in networkedFishList)
|
|
{
|
|
if (networkedFish.actorInControl != -1 && !PhotonNetwork.CurrentRoom.Players.ContainsKey(networkedFish.actorInControl))
|
|
{
|
|
networkedFish.actorInControl = -1;
|
|
}
|
|
if (networkedFish.fishEntity == null)
|
|
{
|
|
list.Add(networkedFish);
|
|
}
|
|
}
|
|
list.ForEach(delegate(NetworkedFish element)
|
|
{
|
|
networkedFishList.Remove(element);
|
|
});
|
|
}
|
|
|
|
private IEnumerator FishSyncCoroutine()
|
|
{
|
|
int index = 0;
|
|
while (true)
|
|
{
|
|
yield return new WaitForSeconds(fishSyncDelay);
|
|
if (!IsMaster || MultiplayerManager.Instance.CurrentState != MultiplayerManager.State.InRoomLocation || networkedFishList.Count <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
byte[][] array = Enumerable.Repeat(Enumerable.Repeat((byte)0, 16).ToArray(), fishSyncCount).ToArray();
|
|
byte[] array2 = new byte[fishSyncCount];
|
|
float[] array3 = new float[fishSyncCount];
|
|
Vector3[] array4 = new Vector3[fishSyncCount];
|
|
byte[] array5 = new byte[fishSyncCount];
|
|
byte[] array6 = new byte[fishSyncCount];
|
|
for (int i = 0; i < fishSyncCount; i++)
|
|
{
|
|
if (index >= networkedFishList.Count)
|
|
{
|
|
index = 0;
|
|
}
|
|
NetworkedFish networkedFish = networkedFishList[index];
|
|
if (!CheckFishInteractionWithPlayer(networkedFish.fishEntity))
|
|
{
|
|
networkedFish.fishWeight = networkedFish.fishEntity.Weight;
|
|
networkedFish.position = networkedFish.fishEntity.transform.position;
|
|
networkedFish.targetAreaID = FishTargetBaker.Instance.Areas.IndexOf(networkedFish.fishEntity.CurrentArea);
|
|
array[i] = networkedFish.Guid.ToByteArray();
|
|
array2[i] = (byte)networkedFish.fishID;
|
|
array3[i] = networkedFish.fishWeight;
|
|
array4[i] = networkedFish.position;
|
|
array5[i] = (byte)networkedFish.targetAreaID;
|
|
array6[i] = (byte)networkedFish.actorInControl;
|
|
}
|
|
int num = index + 1;
|
|
index = num;
|
|
}
|
|
PhotonNetwork.RaiseEvent(0, new object[6] { array, array2, array3, array4, array5, array6 }, RaiseEventOptions.Default, SendOptions.SendReliable);
|
|
ValidateFishes();
|
|
}
|
|
}
|
|
}
|