added takeownership editor button, improved samples, add IPackState interface to serialization scripts

upm
Anton Franzluebbers 2023-08-03 13:07:40 -04:00
parent 424c9c85a6
commit 2f20f79e89
13 changed files with 349 additions and 19 deletions

View File

@ -175,6 +175,11 @@ namespace VelNet
EditorGUI.EndDisabledGroup(); EditorGUI.EndDisabledGroup();
EditorGUILayout.Space(); EditorGUILayout.Space();
if (EditorApplication.isPlaying && GUILayout.Button("Take ownership now."))
{
t.TakeOwnership();
}
if (GUILayout.Button("Find Network Components and add backreferences.")) if (GUILayout.Button("Find Network Components and add backreferences."))
{ {
NetworkComponent[] components = t.GetComponentsInChildren<NetworkComponent>(); NetworkComponent[] components = t.GetComponentsInChildren<NetworkComponent>();
@ -193,6 +198,8 @@ namespace VelNet
so.ApplyModifiedProperties(); so.ApplyModifiedProperties();
} }
// make the sceneNetworkId a new unique value // make the sceneNetworkId a new unique value
if (Application.isEditor && !Application.isPlaying && t.isSceneObject && t.sceneNetworkId == 0) if (Application.isEditor && !Application.isPlaying && t.isSceneObject && t.sceneNetworkId == 0)
{ {

View File

@ -0,0 +1,8 @@
namespace VelNet
{
public interface IPackState
{
public byte[] PackState();
public void UnpackState(byte[] state);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ff05d1e7d5ce4aa7b8a57c15e3fe6f6d
timeCreated: 1690999043

View File

@ -4,7 +4,7 @@ using UnityEngine;
namespace VelNet namespace VelNet
{ {
public abstract class NetworkSerializedObject : NetworkComponent public abstract class NetworkSerializedObject : NetworkComponent, IPackState
{ {
[Tooltip("Send rate of this object. This caps out at the framerate of the game.")] [Tooltip("Send rate of this object. This caps out at the framerate of the game.")]
public float serializationRateHz = 30; public float serializationRateHz = 30;
@ -67,5 +67,15 @@ namespace VelNet
protected abstract byte[] SendState(); protected abstract byte[] SendState();
protected abstract void ReceiveState(byte[] message); protected abstract void ReceiveState(byte[] message);
public byte[] PackState()
{
return SendState();
}
public void UnpackState(byte[] state)
{
ReceiveState(state);
}
} }
} }

View File

@ -5,7 +5,7 @@ using UnityEngine;
namespace VelNet namespace VelNet
{ {
public abstract class NetworkSerializedObjectStream : NetworkComponent public abstract class NetworkSerializedObjectStream : NetworkComponent, IPackState
{ {
[Tooltip("Send rate of this object. This caps out at the framerate of the game.")] [Tooltip("Send rate of this object. This caps out at the framerate of the game.")]
public float serializationRateHz = 30; public float serializationRateHz = 30;
@ -40,7 +40,8 @@ namespace VelNet
byte[] newBytes = mem.ToArray(); byte[] newBytes = mem.ToArray();
if (hybridOnChangeCompression) if (hybridOnChangeCompression)
{ {
if (Time.timeAsDouble - lastSendTime > slowSendInterval || !BinaryWriterExtensions.BytesSame(lastSentBytes, newBytes)) if (Time.timeAsDouble - lastSendTime > slowSendInterval ||
!BinaryWriterExtensions.BytesSame(lastSentBytes, newBytes))
{ {
SendBytes(newBytes); SendBytes(newBytes);
lastSendTime = Time.timeAsDouble; lastSendTime = Time.timeAsDouble;
@ -76,5 +77,21 @@ namespace VelNet
protected abstract void SendState(BinaryWriter binaryWriter); protected abstract void SendState(BinaryWriter binaryWriter);
protected abstract void ReceiveState(BinaryReader binaryReader); protected abstract void ReceiveState(BinaryReader binaryReader);
public byte[] PackState()
{
using MemoryStream mem = new MemoryStream();
using BinaryWriter writer = new BinaryWriter(mem);
SendState(writer);
return mem.ToArray();
}
public void UnpackState(byte[] state)
{
using MemoryStream mem = new MemoryStream(state);
using BinaryReader reader = new BinaryReader(mem);
ReceiveState(reader);
}
} }
} }

View File

@ -135,7 +135,11 @@ namespace VelNet
public readonly Dictionary<string, List<int>> groups = new Dictionary<string, List<int>>(); public readonly Dictionary<string, List<int>> groups = new Dictionary<string, List<int>>();
private VelNetPlayer masterPlayer; private VelNetPlayer masterPlayer;
public static VelNetPlayer LocalPlayer => instance != null ? instance.players.Where(p => p.Value.isLocal).Select(p => p.Value).FirstOrDefault() : null;
public static VelNetPlayer LocalPlayer => instance != null
? instance.players.Where(p => p.Value.isLocal).Select(p => p.Value).FirstOrDefault()
: null;
public static bool InRoom => LocalPlayer != null && LocalPlayer.room != "-1" && LocalPlayer.room != ""; public static bool InRoom => LocalPlayer != null && LocalPlayer.room != "-1" && LocalPlayer.room != "";
public static string Room => LocalPlayer?.room; public static string Room => LocalPlayer?.room;
@ -309,7 +313,9 @@ namespace VelNet
if (autoLogin) if (autoLogin)
{ {
Login( Login(
onlyConnectToSameVersion ? $"{Application.productName}_{Application.version}" : $"{Application.productName}", onlyConnectToSameVersion
? $"{Application.productName}_{Application.version}"
: $"{Application.productName}",
Hash128.Compute(SystemInfo.deviceUniqueIdentifier).ToString() Hash128.Compute(SystemInfo.deviceUniqueIdentifier).ToString()
); );
} }
@ -526,8 +532,10 @@ namespace VelNet
} }
else else
{ {
masterPlayer = players.Aggregate((p1, p2) => p1.Value.userid.CompareTo(p2.Value.userid) > 0 ? p1 : p2).Value; masterPlayer = players.Aggregate((p1, p2) =>
VelNetLogger.Error("Got an invalid master client id from the server. Using fallback."); p1.Value.userid.CompareTo(p2.Value.userid) > 0 ? p1 : p2).Value;
VelNetLogger.Error(
"Got an invalid master client id from the server. Using fallback.");
} }
// no master player yet, add the scene objects // no master player yet, add the scene objects
@ -536,7 +544,8 @@ namespace VelNet
{ {
if (sceneObjects[i].sceneNetworkId == 0) if (sceneObjects[i].sceneNetworkId == 0)
{ {
VelNetLogger.Error("Scene Network ID is 0. Make sure to assign one first.", sceneObjects[i]); VelNetLogger.Error("Scene Network ID is 0. Make sure to assign one first.",
sceneObjects[i]);
} }
sceneObjects[i].networkId = -1 + "-" + sceneObjects[i].sceneNetworkId; sceneObjects[i].networkId = -1 + "-" + sceneObjects[i].sceneNetworkId;
@ -553,7 +562,8 @@ namespace VelNet
if (objects.ContainsKey(sceneObjects[i].networkId)) if (objects.ContainsKey(sceneObjects[i].networkId))
{ {
VelNetLogger.Error($"Duplicate NetworkID: {sceneObjects[i].networkId} {sceneObjects[i].name} {objects[sceneObjects[i].networkId]}"); VelNetLogger.Error(
$"Duplicate NetworkID: {sceneObjects[i].networkId} {sceneObjects[i].name} {objects[sceneObjects[i].networkId]}");
} }
else else
{ {
@ -1123,7 +1133,8 @@ namespace VelNet
} }
} }
public static void SendCustomMessage(byte[] message, bool include_self = false, bool reliable = true, bool ordered = false) public static void SendCustomMessage(byte[] message, bool include_self = false, bool reliable = true,
bool ordered = false)
{ {
using MemoryStream mem = new MemoryStream(); using MemoryStream mem = new MemoryStream();
using BinaryWriter writer = new BinaryWriter(mem); using BinaryWriter writer = new BinaryWriter(mem);
@ -1143,7 +1154,8 @@ namespace VelNet
SendToGroup(group, mem.ToArray(), reliable); SendToGroup(group, mem.ToArray(), reliable);
} }
internal static bool SendToRoom(byte[] message, bool include_self = false, bool reliable = true, bool ordered = false) internal static bool SendToRoom(byte[] message, bool include_self = false, bool reliable = true,
bool ordered = false)
{ {
byte sendType = (byte)MessageSendType.MESSAGE_OTHERS; byte sendType = (byte)MessageSendType.MESSAGE_OTHERS;
if (include_self && ordered) sendType = (byte)MessageSendType.MESSAGE_ALL_ORDERED; if (include_self && ordered) sendType = (byte)MessageSendType.MESSAGE_ALL_ORDERED;
@ -1230,6 +1242,16 @@ namespace VelNet
return NetworkInstantiate(prefabName); return NetworkInstantiate(prefabName);
} }
public static NetworkObject NetworkInstantiate(NetworkObject prefab)
{
if (instance.prefabs.Contains(prefab))
{
return NetworkInstantiate(prefab.name);
}
throw new ArgumentException("Can't instantiate object that isn't added to the network manager.");
}
/// <summary> /// <summary>
/// Instantiates a prefab for all players. /// Instantiates a prefab for all players.
/// </summary> /// </summary>
@ -1241,7 +1263,8 @@ namespace VelNet
string networkId = AllocateNetworkId(); string networkId = AllocateNetworkId();
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;
} }
@ -1271,7 +1294,8 @@ namespace VelNet
string networkId = AllocateNetworkId(); string networkId = AllocateNetworkId();
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;
} }
@ -1302,7 +1326,8 @@ namespace VelNet
NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName); NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName);
if (prefab == null) 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"); 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; return null;
} }
@ -1324,12 +1349,14 @@ namespace VelNet
} }
internal static NetworkObject ActuallyInstantiate(string networkId, string prefabName, VelNetPlayer owner, Vector3 position, Quaternion rotation) internal static NetworkObject ActuallyInstantiate(string networkId, string prefabName, VelNetPlayer owner,
Vector3 position, Quaternion rotation)
{ {
NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName); NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName);
if (prefab == null) 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"); 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; return null;
} }

View File

@ -0,0 +1,177 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &419466048389313172
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 419466048389313162}
- component: {fileID: 419466048389313163}
- component: {fileID: 419466048389313160}
- component: {fileID: 419466048389313161}
- component: {fileID: 419466048389313174}
- component: {fileID: 419466048389313175}
- component: {fileID: 5526065058146758772}
- component: {fileID: 7493820295801030223}
m_Layer: 0
m_Name: TestNetworkedGameObjectMoving
m_TagString: draggable
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &419466048389313162
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 419466048389313172}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &419466048389313163
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 419466048389313172}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &419466048389313160
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 419466048389313172}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!65 &419466048389313161
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 419466048389313172}
m_Material: {fileID: 0}
m_IsTrigger: 0
m_Enabled: 1
serializedVersion: 2
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!114 &419466048389313174
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 419466048389313172}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5515094c5c544b6b8ed7fd51a86548d4, type: 3}
m_Name:
m_EditorClassIdentifier:
ownershipLocked: 0
networkId:
sceneNetworkId: 0
prefabName:
isSceneObject: 0
syncedComponents:
- {fileID: 7493820295801030223}
- {fileID: 419466048389313175}
--- !u!114 &419466048389313175
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 419466048389313172}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3f1f9b0bbd93a484a987c51f1107ebe5, type: 3}
m_Name:
m_EditorClassIdentifier:
networkObject: {fileID: 419466048389313174}
serializationRateHz: 60
hybridOnChangeCompression: 1
position: 1
rotation: 1
scale: 0
useLocalTransform: 0
teleportDistance: 0
teleportAngle: 0
--- !u!54 &5526065058146758772
Rigidbody:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 419466048389313172}
serializedVersion: 2
m_Mass: 1
m_Drag: 1
m_AngularDrag: 1
m_UseGravity: 0
m_IsKinematic: 0
m_Interpolate: 0
m_Constraints: 0
m_CollisionDetection: 0
--- !u!114 &7493820295801030223
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 419466048389313172}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 89cb4504498539945b9d89e5e0bc8c54, type: 3}
m_Name:
m_EditorClassIdentifier:
networkObject: {fileID: 419466048389313174}
serializationRateHz: 30
hybridOnChangeCompression: 1
impulseForce: 200
returningForce: 1

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ca24b76e2d421f7468d28a27a9858d29
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -750,6 +750,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_SendPointerHoverToParent: 1
m_HorizontalAxis: Horizontal m_HorizontalAxis: Horizontal
m_VerticalAxis: Vertical m_VerticalAxis: Vertical
m_SubmitButton: Submit m_SubmitButton: Submit
@ -2599,6 +2600,7 @@ MonoBehaviour:
prefabs: prefabs:
- {fileID: 9102273340480352682, guid: e07dfcf3af0e6ad438df1df54cd960a5, type: 3} - {fileID: 9102273340480352682, guid: e07dfcf3af0e6ad438df1df54cd960a5, type: 3}
- {fileID: 419466048389313174, guid: c0c7ee35b5be203468523c819c9da422, type: 3} - {fileID: 419466048389313174, guid: c0c7ee35b5be203468523c819c9da422, type: 3}
- {fileID: 419466048389313174, guid: ca24b76e2d421f7468d28a27a9858d29, type: 3}
sceneObjects: [] sceneObjects: []
deletedSceneObjects: [] deletedSceneObjects: []
--- !u!114 &1099803618 --- !u!114 &1099803618

View File

@ -10,11 +10,12 @@ namespace VelNet
{ {
private Renderer rend; private Renderer rend;
public Color color; public Color color;
public NetworkObject spawnableObj;
protected void Start() protected void Start()
{ {
rend = GetComponent<MeshRenderer>(); rend = GetComponent<MeshRenderer>();
if (IsMine) if (IsMine)
{ {
color = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f)); color = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f));
@ -35,7 +36,17 @@ namespace VelNet
if (Input.GetKeyDown(KeyCode.Space)) if (Input.GetKeyDown(KeyCode.Space))
{ {
VelNetManager.NetworkInstantiate("TestNetworkedGameObject"); if (Input.GetKey(KeyCode.LeftShift))
{
for (int i = 0; i < 100; i++)
{
VelNetManager.NetworkInstantiate(spawnableObj);
}
}
else
{
VelNetManager.NetworkInstantiate(spawnableObj);
}
} }
if (Input.GetKeyDown(KeyCode.BackQuote)) if (Input.GetKeyDown(KeyCode.BackQuote))

View File

@ -0,0 +1,50 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using VelNet;
public class SyncedCustomObj : NetworkSerializedObjectStream
{
private Renderer rend;
private Rigidbody rb;
public float impulseForce = 1;
public float returningForce = 1;
private IEnumerator Start()
{
rend = GetComponent<Renderer>();
rb = GetComponent<Rigidbody>();
while (true)
{
if (IsMine)
{
rb.AddForce(new Vector3(
Random.Range(-1f, 1f) * impulseForce,
Random.Range(-1f, 1f) * impulseForce,
Random.Range(-1f, 1f) * impulseForce
));
}
yield return new WaitForSeconds(Random.Range(1f, 3f));
}
}
private void FixedUpdate()
{
if (IsMine)
{
// return to center
rb.velocity -= (transform.position).normalized * Time.fixedDeltaTime * returningForce;
}
}
protected override void SendState(BinaryWriter binaryWriter)
{
}
protected override void ReceiveState(BinaryReader binaryReader)
{
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 89cb4504498539945b9d89e5e0bc8c54
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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.8", "version": "1.1.9",
"unity": "2019.1", "unity": "2019.1",
"description": "A custom networking library for Unity.", "description": "A custom networking library for Unity.",
"keywords": [ "keywords": [