Reworked Object spawning system

This commit is contained in:
Albin Corén 2018-04-05 21:21:57 +02:00
parent 5310c400c3
commit b8e1e925d4
8 changed files with 329 additions and 172 deletions

View File

@ -50,11 +50,13 @@ namespace MLAPI.Data
/// <summary>
/// A list of spawnable prefabs
/// </summary>
public List<GameObject> SpawnablePrefabs = new List<GameObject>();
public List<NetworkedPrefab> NetworkedPrefabs = new List<NetworkedPrefab>();
internal Dictionary<string, int> NetworkPrefabIds;
internal Dictionary<int, string> NetworkPrefabNames;
/// <summary>
/// The default player prefab
/// </summary>
public GameObject PlayerPrefab;
public string PlayerPrefabName;
/// <summary>
/// The size of the receive message buffer. This is the max message size.
/// </summary>
@ -132,7 +134,7 @@ namespace MLAPI.Data
/// <summary>
/// Wheter or not to enable scene switching
/// </summary>
public bool EnableSceneSwitching = false;
public bool EnableSceneSwitching = true;
private byte[] ConfigHash = null;
/// <summary>
@ -172,7 +174,10 @@ namespace MLAPI.Data
}
if(HandleObjectSpawning)
{
writer.Write(SpawnablePrefabs.Count);
for (int i = 0; i < NetworkedPrefabs.Count; i++)
{
writer.Write(NetworkedPrefabs[i].name);
}
}
writer.Write(HandleObjectSpawning);
writer.Write(EnableEncryption);

View File

@ -8,13 +8,13 @@ namespace MLAPI.Data
internal GameObject[] objects;
internal ushort poolId;
internal NetworkPool(int prefabIndex, uint size, ushort poolIndex)
internal NetworkPool(int prefabId, uint size, ushort poolIndex)
{
objects = new GameObject[size];
poolId = poolIndex;
for (int i = 0; i < size; i++)
{
GameObject go = Object.Instantiate(NetworkingManager.singleton.NetworkConfig.SpawnablePrefabs[prefabIndex], Vector3.zero, Quaternion.identity);
GameObject go = MonoBehaviour.Instantiate(NetworkingManager.singleton.NetworkConfig.NetworkedPrefabs[prefabId].prefab, Vector3.zero, Quaternion.identity);
go.GetComponent<NetworkedObject>()._isPooledObject = true;
go.GetComponent<NetworkedObject>().poolId = poolId;
go.GetComponent<NetworkedObject>().Spawn();

View File

@ -0,0 +1,12 @@
using System;
using UnityEngine;
namespace MLAPI.Data
{
[Serializable]
public class NetworkedPrefab
{
public string name;
public GameObject prefab;
}
}

View File

@ -71,6 +71,7 @@
<Compile Include="Data\FieldType.cs" />
<Compile Include="Attributes\SyncedVar.cs" />
<Compile Include="Data\NetworkConfig.cs" />
<Compile Include="Data\NetworkedPrefab.cs" />
<Compile Include="Data\NetworkPool.cs" />
<Compile Include="Data\TrackedPointData.cs" />
<Compile Include="Data\TransportHost.cs" />

View File

@ -12,6 +12,15 @@ namespace MLAPI.MonoBehaviours.Core
[AddComponentMenu("MLAPI/NetworkedObject", -99)]
public sealed class NetworkedObject : MonoBehaviour
{
private void OnValidate()
{
if(string.IsNullOrEmpty(NetworkedPrefabName))
{
Debug.LogWarning("MLAPI: The networked object " + gameObject.name + " has not been assigned a networkedPrefabName. Setting it to " + gameObject.name);
NetworkedPrefabName = gameObject.name;
}
}
/// <summary>
/// Gets the unique ID of this object that is synced across the network
/// </summary>
@ -35,16 +44,9 @@ namespace MLAPI.MonoBehaviours.Core
}
internal uint ownerClientId = new NetId(0, 0, false, true).GetClientId();
/// <summary>
/// The index of the prefab used to spawn this in the spawnablePrefabs list
/// The name of the NetworkedPrefab
/// </summary>
public int SpawnablePrefabIndex
{
get
{
return spawnablePrefabIndex;
}
}
internal int spawnablePrefabIndex;
public string NetworkedPrefabName = string.Empty;
/// <summary>
/// Gets if this object is a player object
/// </summary>
@ -57,11 +59,6 @@ namespace MLAPI.MonoBehaviours.Core
}
internal bool _isPlayerObject = false;
/// <summary>
/// Gets or sets if this object should be replicated across the network. Can only be changed before the object is spawned
/// </summary>
[SerializeField]
public bool ServerOnly = false;
/// <summary>
/// Gets if this object is part of a pool
/// </summary>
public bool isPooledObject
@ -115,7 +112,7 @@ namespace MLAPI.MonoBehaviours.Core
}
}
internal bool _isSpawned = false;
internal bool sceneObject = false;
internal bool? sceneObject = null;
private void OnDestroy()
{
@ -129,7 +126,7 @@ namespace MLAPI.MonoBehaviours.Core
public void Spawn()
{
if (NetworkingManager.singleton != null)
SpawnManager.OnSpawnObject(this);
SpawnManager.SpawnPrefabIndexServer(this);
}
/// <summary>
/// Spawns an object across the network with a given owner. Can only be called from server
@ -138,7 +135,7 @@ namespace MLAPI.MonoBehaviours.Core
public void SpawnWithOwnership(uint clientId)
{
if (NetworkingManager.singleton != null)
SpawnManager.OnSpawnObject(this, clientId);
SpawnManager.SpawnPrefabIndexServer(this, clientId);
}
/// <summary>
/// Removes all ownership of an object from any client. Can only be called from server

View File

@ -9,6 +9,7 @@ using System.Linq;
using System.Security.Cryptography;
using MLAPI.NetworkingManagerComponents.Cryptography;
using MLAPI.NetworkingManagerComponents.Core;
using UnityEngine.SceneManagement;
namespace MLAPI.MonoBehaviours.Core
{
@ -152,24 +153,29 @@ namespace MLAPI.MonoBehaviours.Core
private void OnValidate()
{
if (NetworkConfig.SpawnablePrefabs != null)
if(NetworkConfig.EnableSceneSwitching && !NetworkConfig.RegisteredScenes.Contains(SceneManager.GetActiveScene().name))
{
for (int i = 0; i < NetworkConfig.SpawnablePrefabs.Count; i++)
Debug.LogWarning("MLAPI: The active scene is not registered as a networked scene. The MLAPI has added it");
NetworkConfig.RegisteredScenes.Add(SceneManager.GetActiveScene().name);
}
if(!NetworkConfig.EnableSceneSwitching && NetworkConfig.HandleObjectSpawning)
{
Debug.LogWarning("MLAPI: Please be aware that Scene objects are NOT supported if SceneManagement is turned on, even if HandleObjectSpawning is turned on");
}
if(NetworkConfig.HandleObjectSpawning)
{
for (int i = 0; i < NetworkConfig.NetworkedPrefabs.Count; i++)
{
if (NetworkConfig.SpawnablePrefabs[i] == null)
continue;
NetworkedObject netObject = NetworkConfig.SpawnablePrefabs[i].GetComponentInChildren<NetworkedObject>();
if (netObject == null)
if (string.IsNullOrEmpty(NetworkConfig.NetworkedPrefabs[i].name))
{
Debug.LogWarning("MLAPI: All SpawnablePrefabs need a NetworkedObject component. Please add one to the prefab " + NetworkConfig.SpawnablePrefabs[i].gameObject.name);
continue;
Debug.LogWarning("MLAPI: The prefab " + NetworkConfig.NetworkedPrefabs[i].prefab.name + " does not have a set NetworkedPrefab name. Setting it to " + NetworkConfig.NetworkedPrefabs[i].prefab.name);
NetworkConfig.NetworkedPrefabs[i].name = NetworkConfig.NetworkedPrefabs[i].prefab.name;
}
netObject.spawnablePrefabIndex = i;
}
}
if (NetworkConfig.PlayerPrefab != null)
if (!string.IsNullOrEmpty(NetworkConfig.PlayerPrefabName))
{
NetworkedObject netObject = NetworkConfig.PlayerPrefab.GetComponentInChildren<NetworkedObject>();
NetworkedObject netObject = NetworkConfig.NetworkedPrefabs.Find(x => x.name == NetworkConfig.PlayerPrefabName).prefab.GetComponentInChildren<NetworkedObject>();
if (netObject == null)
{
Debug.LogWarning("MLAPI: The player object needs a NetworkedObject component.");
@ -193,7 +199,7 @@ namespace MLAPI.MonoBehaviours.Core
}
}
private ConnectionConfig Init()
private ConnectionConfig Init(bool server)
{
networkTime = 0f;
lastSendTickTime = 0;
@ -218,16 +224,34 @@ namespace MLAPI.MonoBehaviours.Core
NetworkSceneManager.sceneIndexToString = new Dictionary<uint, string>();
NetworkSceneManager.sceneNameToIndex = new Dictionary<string, uint>();
if (NetworkConfig.HandleObjectSpawning)
if(NetworkConfig.HandleObjectSpawning)
{
NetworkedObject[] sceneObjects = FindObjectsOfType<NetworkedObject>();
for (int i = 0; i < sceneObjects.Length; i++)
NetworkConfig.NetworkPrefabIds = new Dictionary<string, int>();
NetworkConfig.NetworkPrefabNames = new Dictionary<int, string>();
NetworkConfig.NetworkedPrefabs.OrderBy(x => x.name);
for (int i = 0; i < NetworkConfig.NetworkedPrefabs.Count; i++)
{
uint networkId = SpawnManager.GetNetworkObjectId();
SpawnManager.spawnedObjects.Add(networkId, sceneObjects[i]);
sceneObjects[i]._isSpawned = true;
sceneObjects[i].sceneObject = true;
sceneObjects[i].InvokeBehaviourNetworkSpawn();
NetworkConfig.NetworkPrefabIds.Add(NetworkConfig.NetworkedPrefabs[i].name, i);
NetworkConfig.NetworkPrefabNames.Add(i, NetworkConfig.NetworkedPrefabs[i].name);
}
if (NetworkConfig.EnableSceneSwitching)
{
SpawnManager.MarkSceneObjects();
if (NetworkConfig.HandleObjectSpawning)
{
if (server)
{
bool isServerState = _isServer;
_isServer = true;
NetworkedObject[] networkedObjects = FindObjectsOfType<NetworkedObject>();
for (int i = 0; i < networkedObjects.Length; i++)
{
if (networkedObjects[i].sceneObject == null || networkedObjects[i].sceneObject == true)
networkedObjects[i].Spawn();
}
_isServer = isServerState;
}
}
}
}
@ -313,6 +337,7 @@ namespace MLAPI.MonoBehaviours.Core
MessageManager.messageTypes.Add("MLAPI_DESTROY_POOL_OBJECT", 7);
MessageManager.messageTypes.Add("MLAPI_CHANGE_OWNER", 8);
MessageManager.messageTypes.Add("MLAPI_SYNC_VAR_UPDATE", 9);
MessageManager.messageTypes.Add("MLAPI_ADD_OBJECTS", 10);
List<MessageType> messageTypes = new List<MessageType>(NetworkConfig.MessageTypes)
{
@ -401,7 +426,7 @@ namespace MLAPI.MonoBehaviours.Core
return;
}
ConnectionConfig cConfig = Init();
ConnectionConfig cConfig = Init(true);
if (NetworkConfig.ConnectionApproval)
{
if (ConnectionApprovalCallback == null)
@ -437,7 +462,7 @@ namespace MLAPI.MonoBehaviours.Core
return;
}
ConnectionConfig cConfig = Init();
ConnectionConfig cConfig = Init(false);
HostTopology hostTopology = new HostTopology(cConfig, NetworkConfig.MaxConnections);
serverHostId = NetworkTransport.AddHost(hostTopology, 0, null);
@ -446,7 +471,6 @@ namespace MLAPI.MonoBehaviours.Core
isListening = true;
byte error;
serverConnectionId = NetworkTransport.Connect(serverHostId, NetworkConfig.ConnectAddress, NetworkConfig.ConnectPort, 0, out error);
Debug.LogWarning("MLAPI: Connection failed: " + ((NetworkError)error).ToString());
}
/// <summary>
@ -460,7 +484,7 @@ namespace MLAPI.MonoBehaviours.Core
return;
}
ConnectionConfig cConfig = Init();
ConnectionConfig cConfig = Init(false);
HostTopology hostTopology = new HostTopology(cConfig, NetworkConfig.MaxConnections);
serverHostId = NetworkTransport.AddWebsocketHost(hostTopology, 0, null);
@ -469,7 +493,6 @@ namespace MLAPI.MonoBehaviours.Core
isListening = true;
byte error;
serverConnectionId = NetworkTransport.Connect(serverHostId, NetworkConfig.ConnectAddress, NetworkConfig.ConnectPort, 0, out error);
Debug.LogWarning("MLAPI: Connection failed: " + ((NetworkError)error).ToString());
}
/// <summary>
@ -541,7 +564,7 @@ namespace MLAPI.MonoBehaviours.Core
Debug.LogWarning("MLAPI: Cannot start host while an instance is already running");
return;
}
ConnectionConfig cConfig = Init();
ConnectionConfig cConfig = Init(true);
if (NetworkConfig.ConnectionApproval)
{
if (ConnectionApprovalCallback == null)
@ -876,7 +899,7 @@ namespace MLAPI.MonoBehaviours.Core
return;
}
byte[] aesKey = new byte[0];
if(NetworkConfig.EnableEncryption)
if (NetworkConfig.EnableEncryption)
{
ushort diffiePublicSize = messageReader.ReadUInt16();
byte[] diffiePublic = messageReader.ReadBytes(diffiePublicSize);
@ -906,7 +929,7 @@ namespace MLAPI.MonoBehaviours.Core
{
myClientId = messageReader.ReadUInt32();
uint sceneIndex = 0;
if(NetworkConfig.EnableSceneSwitching)
if (NetworkConfig.EnableSceneSwitching)
{
sceneIndex = messageReader.ReadUInt32();
}
@ -924,7 +947,7 @@ namespace MLAPI.MonoBehaviours.Core
{
rsa.PersistKeyInCsp = false;
rsa.FromXmlString(NetworkConfig.RSAPublicKey);
if(!rsa.VerifyData(serverPublicKey, new SHA512CryptoServiceProvider(), publicKeySignature))
if (!rsa.VerifyData(serverPublicKey, new SHA512CryptoServiceProvider(), publicKeySignature))
{
//Man in the middle.
Debug.LogWarning("MLAPI: Signature doesnt match for the key exchange public part. Disconnecting");
@ -951,7 +974,7 @@ namespace MLAPI.MonoBehaviours.Core
uint _clientId = messageReader.ReadUInt32();
connectedClients.Add(_clientId, new NetworkedClient() { ClientId = _clientId });
}
if(NetworkConfig.HandleObjectSpawning)
if (NetworkConfig.HandleObjectSpawning)
{
SpawnManager.DestroySceneObjects();
int objectCount = messageReader.ReadInt32();
@ -962,6 +985,7 @@ namespace MLAPI.MonoBehaviours.Core
uint ownerId = messageReader.ReadUInt32();
int prefabId = messageReader.ReadInt32();
bool isActive = messageReader.ReadBoolean();
bool sceneObject = messageReader.ReadBoolean();
float xPos = messageReader.ReadSingle();
float yPos = messageReader.ReadSingle();
@ -977,14 +1001,15 @@ namespace MLAPI.MonoBehaviours.Core
}
else
{
GameObject go = SpawnManager.SpawnObject(prefabId, networkId, ownerId,
GameObject go = SpawnManager.SpawnPrefabIndexClient(prefabId, networkId, ownerId,
new Vector3(xPos, yPos, zPos), Quaternion.Euler(xRot, yRot, zRot));
go.GetComponent<NetworkedObject>().sceneObject = sceneObject;
go.SetActive(isActive);
}
}
}
if(NetworkConfig.EnableSceneSwitching)
if (NetworkConfig.EnableSceneSwitching)
{
NetworkSceneManager.OnSceneSwitch(sceneIndex);
}
@ -1004,12 +1029,13 @@ namespace MLAPI.MonoBehaviours.Core
{
using (BinaryReader messageReader = new BinaryReader(messageReadStream))
{
if(NetworkConfig.HandleObjectSpawning)
if (NetworkConfig.HandleObjectSpawning)
{
bool isPlayerObject = messageReader.ReadBoolean();
uint networkId = messageReader.ReadUInt32();
uint ownerId = messageReader.ReadUInt32();
int prefabId = messageReader.ReadInt32();
bool sceneObject = messageReader.ReadBoolean();
float xPos = messageReader.ReadSingle();
float yPos = messageReader.ReadSingle();
@ -1026,8 +1052,9 @@ namespace MLAPI.MonoBehaviours.Core
}
else
{
SpawnManager.SpawnObject(prefabId, networkId, ownerId,
new Vector3(xPos, yPos, zPos), Quaternion.Euler(xRot, yRot, zRot));
GameObject go = SpawnManager.SpawnPrefabIndexClient(prefabId, networkId, ownerId,
new Vector3(xPos, yPos, zPos), Quaternion.Euler(xRot, yRot, zRot));
go.GetComponent<NetworkedObject>().sceneObject = sceneObject;
}
}
else
@ -1042,7 +1069,7 @@ namespace MLAPI.MonoBehaviours.Core
case 3:
//Server informs client another client disconnected
//MLAPI_CLIENT_DISCONNECT
if(isClient)
if (isClient)
{
using (MemoryStream messageReadStream = new MemoryStream(incommingData))
{
@ -1056,7 +1083,7 @@ namespace MLAPI.MonoBehaviours.Core
break;
case 4:
//Server infroms clients to destroy an object
if(isClient)
if (isClient)
{
using (MemoryStream messageReadStream = new MemoryStream(incommingData))
{
@ -1079,10 +1106,10 @@ namespace MLAPI.MonoBehaviours.Core
NetworkSceneManager.OnSceneSwitch(messageReader.ReadUInt32());
}
}
}
}
break;
case 6: //Spawn pool object
if(isClient)
if (isClient)
{
using (MemoryStream messageReadStream = new MemoryStream(incommingData))
{
@ -1103,7 +1130,7 @@ namespace MLAPI.MonoBehaviours.Core
}
break;
case 7: //Destroy pool object
if(isClient)
if (isClient)
{
using (MemoryStream messageReadStream = new MemoryStream(incommingData))
{
@ -1116,7 +1143,7 @@ namespace MLAPI.MonoBehaviours.Core
}
break;
case 8: //Change owner
if(isClient)
if (isClient)
{
using (MemoryStream messageReadStream = new MemoryStream(incommingData))
{
@ -1129,7 +1156,7 @@ namespace MLAPI.MonoBehaviours.Core
//We are current owner.
SpawnManager.spawnedObjects[netId].InvokeBehaviourOnLostOwnership();
}
if(ownerClientId == MyClientId)
if (ownerClientId == MyClientId)
{
//We are new owner.
SpawnManager.spawnedObjects[netId].InvokeBehaviourOnGainedOwnership();
@ -1154,17 +1181,17 @@ namespace MLAPI.MonoBehaviours.Core
for (int i = 0; i < dirtyCount; i++)
{
byte fieldIndex = messageReader.ReadByte();
if(!SpawnManager.spawnedObjects.ContainsKey(netId))
if (!SpawnManager.spawnedObjects.ContainsKey(netId))
{
Debug.LogWarning("MLAPI: Sync message recieved for a non existant object with id: " + netId);
return;
}
else if(SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex) == null)
else if (SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex) == null)
{
Debug.LogWarning("MLAPI: Sync message recieved for a non existant behaviour");
return;
}
else if(fieldIndex > (SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).syncedFieldTypes.Count - 1))
else if (fieldIndex > (SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).syncedFieldTypes.Count - 1))
{
Debug.LogWarning("MLAPI: Sync message recieved for field out of bounds");
return;
@ -1240,6 +1267,51 @@ namespace MLAPI.MonoBehaviours.Core
}
}
}
break;
case 10:
if (isClient) //MLAPI_ADD_OBJECTS (plural)
{
Debug.LogError("AddObjects");
using (MemoryStream messageReadStream = new MemoryStream(incommingData))
{
using (BinaryReader messageReader = new BinaryReader(messageReadStream))
{
if (NetworkConfig.HandleObjectSpawning)
{
ushort objectCount = messageReader.ReadUInt16();
for (int i = 0; i < objectCount; i++)
{
bool isPlayerObject = messageReader.ReadBoolean();
uint networkId = messageReader.ReadUInt32();
uint ownerId = messageReader.ReadUInt32();
int prefabId = messageReader.ReadInt32();
bool sceneObject = messageReader.ReadBoolean();
float xPos = messageReader.ReadSingle();
float yPos = messageReader.ReadSingle();
float zPos = messageReader.ReadSingle();
float xRot = messageReader.ReadSingle();
float yRot = messageReader.ReadSingle();
float zRot = messageReader.ReadSingle();
if (isPlayerObject)
{
connectedClients.Add(ownerId, new NetworkedClient() { ClientId = ownerId });
SpawnManager.SpawnPlayerObject(ownerId, networkId);
}
else
{
GameObject go = SpawnManager.SpawnPrefabIndexClient(prefabId, networkId, ownerId,
new Vector3(xPos, yPos, zPos), Quaternion.Euler(xRot, yRot, zRot));
go.GetComponent<NetworkedObject>().sceneObject = sceneObject;
}
}
}
}
}
}
break;
}
#endregion
@ -1472,6 +1544,8 @@ namespace MLAPI.MonoBehaviours.Core
internal void Send(string messageType, string channelName, byte[] data, uint? networkId = null, ushort? orderId = null)
{
if (connectedClients.Count == 0)
return;
if (NetworkConfig.EncryptedChannels.Contains(channelName))
{
Debug.LogWarning("MLAPI: Cannot send messages over encrypted channel to multiple clients.");
@ -1672,9 +1746,9 @@ namespace MLAPI.MonoBehaviours.Core
GameObject go = SpawnManager.SpawnPlayerObject(clientId, networkId);
connectedClients[clientId].PlayerObject = go;
}
int sizeOfStream = 16 + ((connectedClients.Count - 1) * 4);
int sizeOfStream = 17 + ((connectedClients.Count - 1) * 4);
int amountOfObjectsToSend = SpawnManager.spawnedObjects.Values.Count(x => x.ServerOnly == false);
int amountOfObjectsToSend = SpawnManager.spawnedObjects.Values.Count();
if (NetworkConfig.HandleObjectSpawning)
{
@ -1734,13 +1808,12 @@ namespace MLAPI.MonoBehaviours.Core
foreach (KeyValuePair<uint, NetworkedObject> pair in SpawnManager.spawnedObjects)
{
if (pair.Value.ServerOnly)
continue;
writer.Write(pair.Value.isPlayerObject);
writer.Write(pair.Value.NetworkId);
writer.Write(pair.Value.OwnerClientId);
writer.Write(pair.Value.SpawnablePrefabIndex);
writer.Write(NetworkConfig.NetworkPrefabIds[pair.Value.NetworkedPrefabName]);
writer.Write(pair.Value.gameObject.activeInHierarchy);
writer.Write(pair.Value.sceneObject == null ? true : pair.Value.sceneObject.Value);
writer.Write(pair.Value.transform.position.x);
writer.Write(pair.Value.transform.position.y);
@ -1761,7 +1834,7 @@ namespace MLAPI.MonoBehaviours.Core
//Inform old clients of the new player
if(NetworkConfig.HandleObjectSpawning)
sizeOfStream = 13;
sizeOfStream = 38;
else
sizeOfStream = 4;
@ -1775,6 +1848,15 @@ namespace MLAPI.MonoBehaviours.Core
writer.Write(connectedClients[clientId].PlayerObject.GetComponent<NetworkedObject>().NetworkId);
writer.Write(clientId);
writer.Write(-1);
writer.Write(false);
writer.Write(connectedClients[clientId].PlayerObject.transform.position.x);
writer.Write(connectedClients[clientId].PlayerObject.transform.position.y);
writer.Write(connectedClients[clientId].PlayerObject.transform.position.z);
writer.Write(connectedClients[clientId].PlayerObject.transform.rotation.eulerAngles.x);
writer.Write(connectedClients[clientId].PlayerObject.transform.rotation.eulerAngles.y);
writer.Write(connectedClients[clientId].PlayerObject.transform.rotation.eulerAngles.z);
}
else
{

View File

@ -51,6 +51,7 @@ namespace MLAPI.NetworkingManagerComponents.Core
Debug.LogWarning("MLAPI: The scene " + sceneName + " is not registered as a switchable scene.");
return;
}
SpawnManager.DestroySceneObjects(); //Destroy current scene objects before switching.
CurrentSceneIndex = sceneNameToIndex[sceneName];
isSwitching = true;
lastScene = SceneManager.GetActiveScene();
@ -67,6 +68,10 @@ namespace MLAPI.NetworkingManagerComponents.Core
}
}
/// <summary>
/// Called on client
/// </summary>
/// <param name="sceneIndex"></param>
internal static void OnSceneSwitch(uint sceneIndex)
{
if (!NetworkingManager.singleton.NetworkConfig.EnableSceneSwitching)
@ -79,6 +84,11 @@ namespace MLAPI.NetworkingManagerComponents.Core
Debug.LogWarning("MLAPI: Server requested a scene switch to a non registered scene");
return;
}
else if(SceneManager.GetActiveScene().name == sceneIndexToString[sceneIndex])
{
return; //This scene is already loaded. This usually happends at first load
}
SpawnManager.DestroySceneObjects();
lastScene = SceneManager.GetActiveScene();
AsyncOperation sceneLoad = SceneManager.LoadSceneAsync(sceneIndexToString[sceneIndex], LoadSceneMode.Additive);
sceneLoad.completed += OnSceneLoaded;
@ -100,6 +110,16 @@ namespace MLAPI.NetworkingManagerComponents.Core
private static void OnSceneUnload(AsyncOperation operation)
{
isSwitching = false;
if(NetworkingManager.singleton.isServer)
{
SpawnManager.MarkSceneObjects();
SpawnManager.FlushSceneObjects();
}
else
{
Debug.LogError("DESTROING OBJECTS");
SpawnManager.DestroySceneObjects();
}
}
}
}

View File

@ -65,81 +65,183 @@ namespace MLAPI.NetworkingManagerComponents.Core
netManager.Send("MLAPI_CHANGE_OWNER", "MLAPI_INTERNAL", stream.GetBuffer());
}
}
internal static void DestroySceneObjects()
{
NetworkedObject[] netObjects = MonoBehaviour.FindObjectsOfType<NetworkedObject>();
for (int i = 0; i < netObjects.Length; i++)
{
if (netObjects[i].sceneObject)
MonoBehaviour.Destroy(netObjects[i].gameObject);
}
}
internal static void DestroyNonSceneObjects()
{
if(spawnedObjects != null)
{
foreach (KeyValuePair<uint, NetworkedObject> netObject in spawnedObjects)
{
if (!netObject.Value.sceneObject)
if (netObject.Value.sceneObject != null && netObject.Value.sceneObject.Value == false)
MonoBehaviour.Destroy(netObject.Value.gameObject);
}
}
}
internal static GameObject SpawnObject(int spawnablePrefabIndex, uint networkId, uint ownerId, Vector3 position, Quaternion rotation)
internal static void DestroySceneObjects()
{
if (spawnablePrefabIndex >= netManager.NetworkConfig.SpawnablePrefabs.Count)
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.SpawnablePrefabs[spawnablePrefabIndex]);
}
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.spawnablePrefabIndex = spawnablePrefabIndex;
if (netManager.isServer)
{
netObject.networkId = GetNetworkObjectId();
}
else
{
netObject.networkId = networkId;
}
netObject.ownerClientId = ownerId;
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;
netObject._isSpawned = true;
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)
{
if (netManager.NetworkConfig.PlayerPrefab == null)
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.PlayerPrefab);
}
GameObject go = MonoBehaviour.Instantiate(netManager.NetworkConfig.NetworkedPrefabs[netManager.NetworkConfig.NetworkPrefabIds[netManager.NetworkConfig.PlayerPrefabName]].prefab);
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>();
}
netObject.ownerClientId = clientId;
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();
@ -159,7 +261,7 @@ namespace MLAPI.NetworkingManagerComponents.Core
if (netManager != null && netManager.isServer)
{
releasedNetworkObjectIds.Push(networkId);
if (spawnedObjects[networkId] != null && !spawnedObjects[networkId].ServerOnly)
if (spawnedObjects[networkId] != null)
{
using (MemoryStream stream = new MemoryStream(4))
{
@ -167,11 +269,7 @@ namespace MLAPI.NetworkingManagerComponents.Core
{
writer.Write(networkId);
}
//If we are host, send to everyone except ourselves. Otherwise, send to all
if (netManager != null && netManager.isHost)
netManager.Send("MLAPI_DESTROY_OBJECT", "MLAPI_INTERNAL", stream.GetBuffer(), new NetId(0, 0, true, false).GetClientId());
else
netManager.Send("MLAPI_DESTROY_OBJECT", "MLAPI_INTERNAL", stream.GetBuffer());
netManager.Send("MLAPI_DESTROY_OBJECT", "MLAPI_INTERNAL", stream.GetBuffer());
}
}
}
@ -179,63 +277,5 @@ namespace MLAPI.NetworkingManagerComponents.Core
MonoBehaviour.Destroy(go);
spawnedObjects.Remove(networkId);
}
internal static void OnSpawnObject(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 (netObject.SpawnablePrefabIndex == -1)
{
Debug.LogWarning("MLAPI: Invalid prefab index");
return;
}
else if (netObject.ServerOnly)
{
Debug.LogWarning("MLAPI: Server only objects does not have to be spawned");
return;
}
else if (!netManager.NetworkConfig.HandleObjectSpawning)
{
Debug.LogWarning("MLAPI: NetworkingConfiguration is set to not handle object spawning");
return;
}
uint netId = GetNetworkObjectId();
netObject.networkId = netId;
spawnedObjects.Add(netId, netObject);
netObject._isSpawned = true;
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(netObject.SpawnablePrefabIndex);
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());
}
}
}
}