282 lines
12 KiB
C#

using MLAPI.Data;
using MLAPI.MonoBehaviours.Core;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace MLAPI.NetworkingManagerComponents.Core
{
internal static class SpawnManager
{
internal static Dictionary<uint, NetworkedObject> spawnedObjects;
internal static Stack<uint> releasedNetworkObjectIds;
private static uint networkObjectIdCounter;
internal static uint GetNetworkObjectId()
{
if (releasedNetworkObjectIds.Count > 0)
{
return releasedNetworkObjectIds.Pop();
}
else
{
networkObjectIdCounter++;
return networkObjectIdCounter;
}
}
private static NetworkingManager netManager
{
get
{
return NetworkingManager.singleton;
}
}
internal static void RemoveOwnership(uint netId)
{
NetworkedObject netObject = SpawnManager.spawnedObjects[netId];
NetworkingManager.singleton.connectedClients[netObject.OwnerClientId].OwnedObjects.RemoveAll(x => x.NetworkId == netId);
netObject.ownerClientId = new NetId(0, 0, false, true).GetClientId();
using (MemoryStream stream = new MemoryStream(8))
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(netId);
writer.Write(netObject.ownerClientId);
}
netManager.Send("MLAPI_CHANGE_OWNER", "MLAPI_INTERNAL", stream.GetBuffer());
}
}
internal static void ChangeOwnership(uint netId, uint clientId)
{
NetworkedObject netObject = SpawnManager.spawnedObjects[netId];
NetworkingManager.singleton.connectedClients[netObject.OwnerClientId].OwnedObjects.RemoveAll(x => x.NetworkId == netId);
NetworkingManager.singleton.connectedClients[clientId].OwnedObjects.Add(netObject);
netObject.ownerClientId = clientId;
using (MemoryStream stream = new MemoryStream(8))
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(netId);
writer.Write(clientId);
}
netManager.Send("MLAPI_CHANGE_OWNER", "MLAPI_INTERNAL", stream.GetBuffer());
}
}
internal static void DestroyNonSceneObjects()
{
if(spawnedObjects != null)
{
foreach (KeyValuePair<uint, NetworkedObject> netObject in spawnedObjects)
{
if (netObject.Value.sceneObject != null && netObject.Value.sceneObject.Value == false)
MonoBehaviour.Destroy(netObject.Value.gameObject);
}
}
}
internal static void DestroySceneObjects()
{
NetworkedObject[] netObjects = MonoBehaviour.FindObjectsOfType<NetworkedObject>();
for (int i = 0; i < netObjects.Length; i++)
{
if (netObjects[i].sceneObject == null || netObjects[i].sceneObject.Value == true)
MonoBehaviour.Destroy(netObjects[i].gameObject);
}
}
internal static void MarkSceneObjects()
{
NetworkedObject[] netObjects = MonoBehaviour.FindObjectsOfType<NetworkedObject>();
for (int i = 0; i < netObjects.Length; i++)
{
if (netObjects[i].sceneObject == null)
netObjects[i].sceneObject = true;
}
}
internal static void FlushSceneObjects()
{
if (!NetworkingManager.singleton.isServer)
return;
List<NetworkedObject> sceneObjectsToSync = new List<NetworkedObject>();
foreach (KeyValuePair<uint, NetworkedObject> pair in SpawnManager.spawnedObjects)
{
if (pair.Value.sceneObject == null || pair.Value.sceneObject == true)
sceneObjectsToSync.Add(pair.Value);
}
int sizeOfStream = 2 + (38 * sceneObjectsToSync.Count); //The two is the base size, it's a ushort containing the amount of objects. Each object takes 38 bytes
using (MemoryStream stream = new MemoryStream(sizeOfStream))
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write((ushort)sceneObjectsToSync.Count);
for (int i = 0; i < sceneObjectsToSync.Count; i++)
{
writer.Write(false); //isLocalPlayer
writer.Write(sceneObjectsToSync[i].NetworkId);
writer.Write(sceneObjectsToSync[i].OwnerClientId);
writer.Write(NetworkingManager.singleton.NetworkConfig.NetworkPrefabIds[sceneObjectsToSync[i].NetworkedPrefabName]);
writer.Write(sceneObjectsToSync[i].transform.position.x);
writer.Write(sceneObjectsToSync[i].transform.position.y);
writer.Write(sceneObjectsToSync[i].transform.position.z);
writer.Write(sceneObjectsToSync[i].transform.rotation.eulerAngles.x);
writer.Write(sceneObjectsToSync[i].transform.rotation.eulerAngles.y);
writer.Write(sceneObjectsToSync[i].transform.rotation.eulerAngles.z);
}
}
NetworkingManager.singleton.Send("MLAPI_ADD_OBJECTS", "MLAPI_INTERNAL", stream.GetBuffer());
}
}
internal static GameObject SpawnPrefabIndexClient(int networkedPrefabId, uint networkId, uint owner, Vector3 position, Quaternion rotation)
{
if (!netManager.NetworkConfig.NetworkPrefabNames.ContainsKey(networkedPrefabId))
{
Debug.LogWarning("MLAPI: Cannot spawn the object, invalid prefabIndex");
return null;
}
GameObject go = MonoBehaviour.Instantiate(netManager.NetworkConfig.NetworkedPrefabs[networkedPrefabId].prefab);
NetworkedObject netObject = go.GetComponent<NetworkedObject>();
if (netObject == null)
{
Debug.LogWarning("MLAPI: Please add a NetworkedObject component to the root of all spawnable objects");
netObject = go.AddComponent<NetworkedObject>();
}
netObject.NetworkedPrefabName = netManager.NetworkConfig.NetworkPrefabNames[networkedPrefabId];
netObject._isSpawned = true;
netObject._isPooledObject = false;
netObject.networkId = networkId;
netObject.ownerClientId = owner;
netObject.transform.position = position;
netObject.transform.rotation = rotation;
spawnedObjects.Add(netObject.NetworkId, netObject);
netObject.InvokeBehaviourNetworkSpawn();
return go;
}
internal static void SpawnPrefabIndexServer(NetworkedObject netObject, uint? clientOwnerId = null)
{
if (netObject.isSpawned)
{
Debug.LogWarning("MLAPI: Object already spawned");
return;
}
else if (!netManager.isServer)
{
Debug.LogWarning("MLAPI: Only server can spawn objects");
return;
}
else if (!netManager.NetworkConfig.NetworkPrefabIds.ContainsKey(netObject.NetworkedPrefabName))
{
Debug.LogWarning("MLAPI: The prefab name " + netObject.NetworkedPrefabName + " does not exist as a networkedPrefab");
return;
}
else if (!netManager.NetworkConfig.HandleObjectSpawning)
{
Debug.LogWarning("MLAPI: NetworkConfig is set to not handle object spawning");
return;
}
uint netId = GetNetworkObjectId();
netObject.networkId = netId;
spawnedObjects.Add(netId, netObject);
netObject._isSpawned = true;
netObject.sceneObject = false;
netObject.InvokeBehaviourNetworkSpawn();
if (clientOwnerId != null)
{
netObject.ownerClientId = clientOwnerId.Value;
NetworkingManager.singleton.connectedClients[clientOwnerId.Value].OwnedObjects.Add(netObject);
}
using (MemoryStream stream = new MemoryStream(37))
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(false);
writer.Write(netObject.NetworkId);
writer.Write(netObject.OwnerClientId);
writer.Write(netManager.NetworkConfig.NetworkPrefabIds[netObject.NetworkedPrefabName]);
writer.Write(netObject.transform.position.x);
writer.Write(netObject.transform.position.y);
writer.Write(netObject.transform.position.z);
writer.Write(netObject.transform.rotation.eulerAngles.x);
writer.Write(netObject.transform.rotation.eulerAngles.y);
writer.Write(netObject.transform.rotation.eulerAngles.z);
}
netManager.Send("MLAPI_ADD_OBJECT", "MLAPI_INTERNAL", stream.GetBuffer());
}
}
internal static GameObject SpawnPlayerObject(uint clientId, uint networkId, Vector3 position, Quaternion rotation)
{
if (string.IsNullOrEmpty(netManager.NetworkConfig.PlayerPrefabName) || !netManager.NetworkConfig.NetworkPrefabIds.ContainsKey(netManager.NetworkConfig.PlayerPrefabName))
{
Debug.LogWarning("MLAPI: There is no player prefab in the NetworkConfig, or it's not registered at as a spawnable prefab");
return null;
}
GameObject go = MonoBehaviour.Instantiate(netManager.NetworkConfig.NetworkedPrefabs[netManager.NetworkConfig.NetworkPrefabIds[netManager.NetworkConfig.PlayerPrefabName]].prefab, position, rotation);
NetworkedObject netObject = go.GetComponent<NetworkedObject>();
if (netObject == null)
{
Debug.LogWarning("MLAPI: Please add a NetworkedObject component to the root of the player prefab");
netObject = go.AddComponent<NetworkedObject>();
}
if (NetworkingManager.singleton.isServer)
netObject.networkId = GetNetworkObjectId();
else
netObject.networkId = networkId;
netObject._isPooledObject = false;
netObject.ownerClientId = clientId;
netObject._isPlayerObject = true;
netObject._isSpawned = true;
netObject.sceneObject = false;
netManager.connectedClients[clientId].PlayerObject = go;
spawnedObjects.Add(netObject.NetworkId, netObject);
netObject.InvokeBehaviourNetworkSpawn();
return go;
}
internal static void OnDestroyObject(uint networkId, bool destroyGameObject)
{
if (!spawnedObjects.ContainsKey(networkId) || (netManager != null && !netManager.NetworkConfig.HandleObjectSpawning))
return;
if (!new NetId(spawnedObjects[networkId].OwnerClientId).IsInvalid() && !spawnedObjects[networkId].isPlayerObject)
{
//Someone owns it.
NetworkingManager.singleton.connectedClients[spawnedObjects[networkId].OwnerClientId].OwnedObjects.RemoveAll(x => x.NetworkId == networkId);
}
GameObject go = spawnedObjects[networkId].gameObject;
if (netManager != null && netManager.isServer)
{
releasedNetworkObjectIds.Push(networkId);
if (spawnedObjects[networkId] != null)
{
using (MemoryStream stream = new MemoryStream(4))
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(networkId);
}
netManager.Send("MLAPI_DESTROY_OBJECT", "MLAPI_INTERNAL", stream.GetBuffer());
}
}
}
if (destroyGameObject && go != null)
MonoBehaviour.Destroy(go);
spawnedObjects.Remove(networkId);
}
}
}