Reworked Object spawning system
This commit is contained in:
parent
5310c400c3
commit
b8e1e925d4
@ -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);
|
||||
|
@ -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();
|
||||
|
12
MLAPI/Data/NetworkedPrefab.cs
Normal file
12
MLAPI/Data/NetworkedPrefab.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MLAPI.Data
|
||||
{
|
||||
[Serializable]
|
||||
public class NetworkedPrefab
|
||||
{
|
||||
public string name;
|
||||
public GameObject prefab;
|
||||
}
|
||||
}
|
@ -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" />
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user