send optional position data with an instantiation event to spawn in a known location, consolidate code for local instantiation

main
Anton Franzluebbers 2023-01-26 16:53:23 -05:00
parent 3ae57a1dbf
commit 357d4a5dd8
4 changed files with 142 additions and 42 deletions

View File

@ -27,7 +27,15 @@ namespace VelNet
public string networkId; public string networkId;
/// <summary> /// <summary>
/// This is generated at editor time and used to generated the network id at runtime. /// This is used internally to handle spawning of objects for players that joined late.
/// This way objects can be spawned in a static location
/// </summary>
internal bool instantiatedWithTransform = false;
internal Vector3 initialPosition;
internal Quaternion initialRotation;
/// <summary>
/// This is generated at editor time and used to generate the network id at runtime.
/// This is needed because finding all objects of type at runtime doesn't have a guaranteed order. /// This is needed because finding all objects of type at runtime doesn't have a guaranteed order.
/// </summary> /// </summary>
public int sceneNetworkId; public int sceneNetworkId;

View File

@ -51,6 +51,7 @@ namespace VelNet
ObjectSync, ObjectSync,
TakeOwnership, TakeOwnership,
Instantiate, Instantiate,
InstantiateWithTransform,
Destroy, Destroy,
DeleteSceneObjects, DeleteSceneObjects,
Custom Custom
@ -1089,6 +1090,7 @@ namespace VelNet
Debug.LogError("Joining room before logging in.", instance); Debug.LogError("Joining room before logging in.", instance);
return; return;
} }
MemoryStream stream = new MemoryStream(); MemoryStream stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(stream); BinaryWriter writer = new BinaryWriter(stream);
@ -1235,36 +1237,15 @@ namespace VelNet
/// <returns>The NetworkObject for the instantiated object.</returns> /// <returns>The NetworkObject for the instantiated object.</returns>
public static NetworkObject NetworkInstantiate(string prefabName) public static NetworkObject NetworkInstantiate(string prefabName)
{ {
VelNetPlayer localPlayer = LocalPlayer; VelNetPlayer owner = LocalPlayer;
NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName); string networkId = AllocateNetworkId();
if (prefab == null)
{
VelNetLogger.Error("Couldn't find a prefab with that name: " + prefabName + "\nMake sure to add the prefab to list of prefabs in VelNetManager");
return null;
}
string networkId = localPlayer.userid + "-" + localPlayer.lastObjectId++;
if (instance.objects.ContainsKey(networkId)) if (instance.objects.ContainsKey(networkId))
{ {
VelNetLogger.Error("Can't instantiate object. Obj with that network ID was already instantiated.", instance.objects[networkId]); VelNetLogger.Error("Can't instantiate object. Obj with that network ID was already instantiated.", instance.objects[networkId]);
return null; return null;
} }
NetworkObject newObject = Instantiate(prefab); NetworkObject newObject = ActuallyInstantiate(networkId, prefabName, owner);
newObject.networkId = networkId;
newObject.prefabName = prefabName;
newObject.owner = localPlayer;
try
{
newObject.OwnershipChanged?.Invoke(localPlayer);
}
catch (Exception e)
{
VelNetLogger.Error("Error in event handling.\n" + e);
}
instance.objects.Add(newObject.networkId, newObject);
// only sent to others, as I already instantiated this. Nice that it happens immediately. // only sent to others, as I already instantiated this. Nice that it happens immediately.
using MemoryStream mem = new MemoryStream(); using MemoryStream mem = new MemoryStream();
@ -1277,10 +1258,54 @@ namespace VelNet
return newObject; return newObject;
} }
public static void SomebodyInstantiatedNetworkObject(string networkId, string prefabName, VelNetPlayer owner) /// <summary>
/// Instantiates a prefab for all players at a specific location
/// </summary>
/// <param name="prefabName">This prefab *must* by added to the list of prefabs in the scene's VelNetManager for all players.</param>
/// <param name="position"></param>
/// <param name="rotation"></param>
/// <returns>The NetworkObject for the instantiated object.</returns>
public static NetworkObject NetworkInstantiate(string prefabName, Vector3 position, Quaternion rotation)
{
VelNetPlayer owner = LocalPlayer;
string networkId = AllocateNetworkId();
if (instance.objects.ContainsKey(networkId))
{
VelNetLogger.Error("Can't instantiate object. Obj with that network ID was already instantiated.", instance.objects[networkId]);
return null;
}
NetworkObject newObject = ActuallyInstantiate(networkId, prefabName, owner, position, rotation);
// only sent to others, as I already instantiated this. Nice that it happens immediately.
using MemoryStream mem = new MemoryStream();
using BinaryWriter writer = new BinaryWriter(mem);
writer.Write((byte)MessageType.InstantiateWithTransform);
writer.Write(newObject.networkId);
writer.Write(prefabName);
writer.Write(position);
writer.Write(rotation);
SendToRoom(mem.ToArray(), include_self: false, reliable: true);
return newObject;
}
/// <summary>
/// This happens locally on all clients
/// </summary>
/// <param name="networkId"></param>
/// <param name="prefabName"></param>
/// <param name="owner"></param>
/// <returns></returns>
internal static NetworkObject ActuallyInstantiate(string networkId, string prefabName, VelNetPlayer owner)
{ {
NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName); NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName);
if (prefab == null) return; if (prefab == null)
{
VelNetLogger.Error("Couldn't find a prefab with that name: " + prefabName + "\nMake sure to add the prefab to list of prefabs in VelNetManager");
return null;
}
NetworkObject newObject = Instantiate(prefab); NetworkObject newObject = Instantiate(prefab);
newObject.networkId = networkId; newObject.networkId = networkId;
newObject.prefabName = prefabName; newObject.prefabName = prefabName;
@ -1295,6 +1320,42 @@ namespace VelNet
} }
instance.objects.Add(newObject.networkId, newObject); instance.objects.Add(newObject.networkId, newObject);
return newObject;
}
internal static NetworkObject ActuallyInstantiate(string networkId, string prefabName, VelNetPlayer owner, Vector3 position, Quaternion rotation)
{
NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName);
if (prefab == null)
{
VelNetLogger.Error("Couldn't find a prefab with that name: " + prefabName + "\nMake sure to add the prefab to list of prefabs in VelNetManager");
return null;
}
NetworkObject newObject = Instantiate(prefab, position, rotation);
newObject.instantiatedWithTransform = true;
newObject.initialPosition = position;
newObject.initialRotation = rotation;
newObject.networkId = networkId;
newObject.prefabName = prefabName;
newObject.owner = owner;
try
{
newObject.OwnershipChanged?.Invoke(owner);
}
catch (Exception e)
{
VelNetLogger.Error("Error in event handling.\n" + e);
}
instance.objects.Add(newObject.networkId, newObject);
return newObject;
}
private static string AllocateNetworkId()
{
return LocalPlayer.userid + "-" + LocalPlayer.lastObjectId++;
} }
public static void NetworkDestroy(NetworkObject obj) public static void NetworkDestroy(NetworkObject obj)

View File

@ -18,7 +18,7 @@ namespace VelNet
private VelNetManager manager; private VelNetManager manager;
/// <summary> /// <summary>
/// For instantiation /// For instantiation. This is not synced across the network
/// </summary> /// </summary>
internal int lastObjectId; internal int lastObjectId;
@ -41,12 +41,27 @@ namespace VelNet
{ {
if (kvp.Value.owner == this && kvp.Value.prefabName != "") if (kvp.Value.owner == this && kvp.Value.prefabName != "")
{ {
using MemoryStream mem = new MemoryStream(); if (kvp.Value.instantiatedWithTransform)
using BinaryWriter writer = new BinaryWriter(mem); {
writer.Write((byte)VelNetManager.MessageType.Instantiate); using MemoryStream mem = new MemoryStream();
writer.Write(kvp.Value.networkId); using BinaryWriter writer = new BinaryWriter(mem);
writer.Write(kvp.Value.prefabName); writer.Write((byte)VelNetManager.MessageType.InstantiateWithTransform);
VelNetManager.SendToRoom(mem.ToArray(), false, true); writer.Write(kvp.Value.networkId);
writer.Write(kvp.Value.prefabName);
writer.Write(kvp.Value.initialPosition);
writer.Write(kvp.Value.initialRotation);
VelNetManager.SendToRoom(mem.ToArray(), false, true);
}
else
{
using MemoryStream mem = new MemoryStream();
using BinaryWriter writer = new BinaryWriter(mem);
writer.Write((byte)VelNetManager.MessageType.Instantiate);
writer.Write(kvp.Value.networkId);
writer.Write(kvp.Value.prefabName);
VelNetManager.SendToRoom(mem.ToArray(), false, true);
}
} }
} }
@ -75,12 +90,12 @@ namespace VelNet
//individual message parameters separated by comma //individual message parameters separated by comma
VelNetManager.MessageType messageType = (VelNetManager.MessageType)reader.ReadByte(); VelNetManager.MessageType messageType = (VelNetManager.MessageType)reader.ReadByte();
if(messageType == VelNetManager.MessageType.Custom) if (messageType == VelNetManager.MessageType.Custom)
{ {
// Custom packets. These are global data that can be sent from anywhere. // Custom packets. These are global data that can be sent from anywhere.
// Any script can subscribe to the callback to receive the message data. // Any script can subscribe to the callback to receive the message data.
// todo: strange hack that any player can handle the custom message, which then simply calls velnetmanager. // todo: strange hack that any player can handle the custom message, which then simply calls velnetmanager.
int len = reader.ReadInt32(); int len = reader.ReadInt32();
try try
{ {
@ -90,6 +105,7 @@ namespace VelNet
{ {
VelNetLogger.Error(e.ToString()); VelNetLogger.Error(e.ToString());
} }
return; return;
} }
@ -103,7 +119,7 @@ namespace VelNet
{ {
// sync update for an object "I" may own // sync update for an object "I" may own
// "I" being the person sending // "I" being the person sending
case VelNetManager.MessageType.ObjectSync: case VelNetManager.MessageType.ObjectSync:
{ {
string objectKey = reader.ReadString(); string objectKey = reader.ReadString();
byte componentIdx = reader.ReadByte(); byte componentIdx = reader.ReadByte();
@ -113,7 +129,7 @@ namespace VelNet
{ {
bool isRpc = (componentIdx & 1) == 1; bool isRpc = (componentIdx & 1) == 1;
componentIdx = (byte)(componentIdx >> 1); componentIdx = (byte)(componentIdx >> 1);
// rpcs can be sent by non-owners // rpcs can be sent by non-owners
if (isRpc || manager.objects[objectKey].owner == this) if (isRpc || manager.objects[objectKey].owner == this)
{ {
@ -151,7 +167,22 @@ namespace VelNet
break; //we already have this one, ignore break; //we already have this one, ignore
} }
VelNetManager.SomebodyInstantiatedNetworkObject(networkId, prefabName, this); VelNetManager.ActuallyInstantiate(networkId, prefabName, this);
break;
}
case VelNetManager.MessageType.InstantiateWithTransform: // I'm trying to instantiate an object
{
string networkId = reader.ReadString();
string prefabName = reader.ReadString();
Vector3 position = reader.ReadVector3();
Quaternion rotation = reader.ReadQuaternion();
if (manager.objects.ContainsKey(networkId))
{
break; //we already have this one, ignore
}
VelNetManager.ActuallyInstantiate(networkId, prefabName, this, position, rotation);
break; break;
} }
@ -170,7 +201,7 @@ namespace VelNet
break; break;
} }
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }

View File

@ -1,7 +1,7 @@
{ {
"name": "edu.uga.engr.vel.velnet", "name": "edu.uga.engr.vel.velnet",
"displayName": "VelNet", "displayName": "VelNet",
"version": "1.1.7", "version": "1.1.8",
"unity": "2019.1", "unity": "2019.1",
"description": "A custom networking library for Unity.", "description": "A custom networking library for Unity.",
"keywords": [ "keywords": [
@ -35,4 +35,4 @@
"path": "Samples~/DissonanceExample" "path": "Samples~/DissonanceExample"
} }
] ]
} }