Skip to content

Commit 092c9c2

Browse files
committed
feat: Added bulk visibility operations
1 parent 7be5454 commit 092c9c2

File tree

6 files changed

+217
-84
lines changed

6 files changed

+217
-84
lines changed

MLAPI/Configuration/MLAPIConstants.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ internal static class MLAPIConstants
2828
internal const byte MLAPI_CLIENT_RPC_REQUEST = 18;
2929
internal const byte MLAPI_CLIENT_RPC_RESPONSE = 19;
3030
internal const byte MLAPI_CUSTOM_MESSAGE = 20;
31+
internal const byte MLAPI_DESTROY_OBJECTS = 21;
3132
internal const byte INVALID = 32;
3233

3334
internal static readonly string[] MESSAGE_NAMES = {
@@ -52,7 +53,7 @@ internal static class MLAPIConstants
5253
"MLAPI_CLIENT_RPC_REQUEST",
5354
"MLAPI_CLIENT_RPC_RESPONSE",
5455
"MLAPI_CUSTOM_MESSAGE",
55-
"",
56+
"MLAPI_DESTROY_OBJECTS",
5657
"",
5758
"",
5859
"",

MLAPI/Core/NetworkedObject.cs

Lines changed: 120 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,61 @@ public void NetworkShow(ulong clientId, Stream payload = null)
210210
{
211211
throw new NotServerException("Only server can change visibility");
212212
}
213+
214+
if (observers.Contains(clientId))
215+
{
216+
throw new VisibilityChangeException("The object is already visible");
217+
}
213218

214-
if (!observers.Contains(clientId))
219+
// Send spawn call
220+
observers.Add(clientId);
221+
222+
SpawnManager.SendSpawnCallForObject(clientId, this, payload);
223+
}
224+
225+
/// <summary>
226+
/// Shows a list of previously hidden objects to a client
227+
/// </summary>
228+
/// <param name="networkedObjects">The objects to show</param>
229+
/// <param name="clientId">The client to show the objects to</param>
230+
/// <param name="payload">An optional payload to send as part of the spawns</param>
231+
public static void NetworkShow(List<NetworkedObject> networkedObjects, ulong clientId, Stream payload = null)
232+
{
233+
if (!NetworkingManager.Singleton.IsServer)
234+
{
235+
throw new NotServerException("Only server can change visibility");
236+
}
237+
238+
// Do the safety loop first to prevent putting the MLAPI in an invalid state.
239+
for (int i = 0; i < networkedObjects.Count; i++)
240+
{
241+
if (!networkedObjects[i].IsSpawned)
242+
{
243+
throw new SpawnStateException("Object is not spawned");
244+
}
245+
246+
if (networkedObjects[i].observers.Contains(clientId))
247+
{
248+
throw new VisibilityChangeException("NetworkedObject with NetworkId: " + networkedObjects[i].NetworkId + " is already visible");
249+
}
250+
}
251+
252+
using (PooledBitStream stream = PooledBitStream.Get())
215253
{
216-
// Send spawn call
217-
observers.Add(clientId);
254+
using (PooledBitWriter writer = PooledBitWriter.Get(stream))
255+
{
256+
writer.WriteUInt16Packed((ushort)networkedObjects.Count);
257+
}
218258

219-
SpawnManager.SendSpawnCallForObject(clientId, this, payload);
259+
for (int i = 0; i < networkedObjects.Count; i++)
260+
{
261+
// Send spawn call
262+
networkedObjects[i].observers.Add(clientId);
263+
264+
SpawnManager.WriteSpawnCallForObject(stream, clientId, networkedObjects[i], payload);
265+
}
266+
267+
InternalMessageSender.Send(MLAPIConstants.MLAPI_ADD_OBJECTS, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null);
220268
}
221269
}
222270

@@ -235,21 +283,80 @@ public void NetworkHide(ulong clientId)
235283
{
236284
throw new NotServerException("Only server can change visibility");
237285
}
238-
239-
if (observers.Contains(clientId) && clientId != NetworkingManager.Singleton.ServerClientId)
286+
287+
if (!observers.Contains(clientId))
288+
{
289+
throw new VisibilityChangeException("The object is already hidden");
290+
}
291+
292+
if (clientId == NetworkingManager.Singleton.ServerClientId)
240293
{
241-
// Send destroy call
242-
observers.Remove(clientId);
294+
throw new VisibilityChangeException("Cannot hide an object from the server");
295+
}
296+
297+
298+
// Send destroy call
299+
observers.Remove(clientId);
243300

244-
using (PooledBitStream stream = PooledBitStream.Get())
301+
using (PooledBitStream stream = PooledBitStream.Get())
302+
{
303+
using (PooledBitWriter writer = PooledBitWriter.Get(stream))
245304
{
246-
using (PooledBitWriter writer = PooledBitWriter.Get(stream))
247-
{
248-
writer.WriteUInt64Packed(NetworkId);
305+
writer.WriteUInt64Packed(NetworkId);
249306

250-
InternalMessageSender.Send(MLAPIConstants.MLAPI_DESTROY_OBJECT, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null);
307+
InternalMessageSender.Send(MLAPIConstants.MLAPI_DESTROY_OBJECT, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null);
308+
}
309+
}
310+
}
311+
312+
/// <summary>
313+
/// Hides a list of objects from a client
314+
/// </summary>
315+
/// <param name="networkedObjects">The objects to hide</param>
316+
/// <param name="clientId">The client to hide the objects from</param>
317+
public static void NetworkHide(List<NetworkedObject> networkedObjects, ulong clientId)
318+
{
319+
if (!NetworkingManager.Singleton.IsServer)
320+
{
321+
throw new NotServerException("Only server can change visibility");
322+
}
323+
324+
if (clientId == NetworkingManager.Singleton.ServerClientId)
325+
{
326+
throw new VisibilityChangeException("Cannot hide an object from the server");
327+
}
328+
329+
// Do the safety loop first to prevent putting the MLAPI in an invalid state.
330+
for (int i = 0; i < networkedObjects.Count; i++)
331+
{
332+
if (!networkedObjects[i].IsSpawned)
333+
{
334+
throw new SpawnStateException("Object is not spawned");
335+
}
336+
337+
if (!networkedObjects[i].observers.Contains(clientId))
338+
{
339+
throw new VisibilityChangeException("NetworkedObject with NetworkId: " + networkedObjects[i].NetworkId + " is already hidden");
340+
}
341+
}
342+
343+
344+
using (PooledBitStream stream = PooledBitStream.Get())
345+
{
346+
using (PooledBitWriter writer = PooledBitWriter.Get(stream))
347+
{
348+
writer.WriteUInt16Packed((ushort)networkedObjects.Count);
349+
350+
for (int i = 0; i < networkedObjects.Count; i++)
351+
{
352+
// Send destroy call
353+
networkedObjects[i].observers.Remove(clientId);
354+
355+
writer.WriteUInt64Packed(networkedObjects[i].NetworkId);
251356
}
252357
}
358+
359+
InternalMessageSender.Send(MLAPIConstants.MLAPI_DESTROY_OBJECTS, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null);
253360
}
254361
}
255362

MLAPI/Core/NetworkingManager.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,9 @@ private void HandleIncomingData(ulong clientId, string channelName, ArraySegment
836836
case MLAPIConstants.MLAPI_ADD_OBJECTS:
837837
if (IsClient) InternalMessageHandler.HandleAddObjects(clientId, messageStream);
838838
break;
839+
case MLAPIConstants.MLAPI_DESTROY_OBJECTS:
840+
if (IsClient) InternalMessageHandler.HandleDestroyObjects(clientId, messageStream);
841+
break;
839842
case MLAPIConstants.MLAPI_TIME_SYNC:
840843
if (IsClient) InternalMessageHandler.HandleTimeSync(clientId, messageStream);
841844
break;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
3+
namespace MLAPI.Exceptions
4+
{
5+
/// <summary>
6+
/// Exception thrown when a visibility change fails
7+
/// </summary>
8+
public class VisibilityChangeException : Exception
9+
{
10+
/// <summary>
11+
/// Constructs a VisibilityChangeException
12+
/// </summary>
13+
public VisibilityChangeException()
14+
{
15+
16+
}
17+
18+
/// <summary>
19+
/// Constructs a VisibilityChangeException with a message
20+
/// </summary>
21+
/// <param name="message">The exception message</param>
22+
public VisibilityChangeException(string message) : base(message)
23+
{
24+
25+
}
26+
27+
/// <summary>
28+
/// Constructs a VisibilityChangeException with a message and a inner exception
29+
/// </summary>
30+
/// <param name="message">The exception message</param>
31+
/// <param name="inner">The inner exception</param>
32+
public VisibilityChangeException(string message, Exception inner) : base(message, inner)
33+
{
34+
35+
}
36+
}
37+
}

MLAPI/Messaging/InternalMessageHandler.cs

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -403,43 +403,23 @@ internal static void HandleAddObjects(ulong clientId, Stream stream)
403403
using (PooledBitReader reader = PooledBitReader.Get(stream))
404404
{
405405
ushort objectCount = reader.ReadUInt16Packed();
406+
406407
for (int i = 0; i < objectCount; i++)
407408
{
408-
bool isPlayerObject = reader.ReadBool();
409-
ulong networkId = reader.ReadUInt64Packed();
410-
ulong ownerId = reader.ReadUInt64Packed();
411-
412-
ulong prefabHash;
413-
ulong instanceId;
414-
bool softSync;
415-
416-
if (NetworkingManager.Singleton.NetworkConfig.UsePrefabSync)
417-
{
418-
softSync = false;
419-
instanceId = 0;
420-
prefabHash = reader.ReadUInt64Packed();
421-
}
422-
else
423-
{
424-
softSync = reader.ReadBool();
425-
426-
if (softSync)
427-
{
428-
instanceId = reader.ReadUInt64Packed();
429-
prefabHash = 0;
430-
}
431-
else
432-
{
433-
prefabHash = reader.ReadUInt64Packed();
434-
instanceId = 0;
435-
}
436-
}
437-
438-
Vector3 pos = new Vector3(reader.ReadSinglePacked(), reader.ReadSinglePacked(), reader.ReadSinglePacked());
439-
Quaternion rot = Quaternion.Euler(reader.ReadSinglePacked(), reader.ReadSinglePacked(), reader.ReadSinglePacked());
440-
441-
NetworkedObject netObject = SpawnManager.CreateLocalNetworkedObject(softSync, instanceId, prefabHash, pos, rot);
442-
SpawnManager.SpawnNetworkedObjectLocally(netObject, networkId, softSync, isPlayerObject, ownerId, stream, false, 0, true, false);
409+
HandleAddObject(clientId, stream);
410+
}
411+
}
412+
}
413+
414+
internal static void HandleDestroyObjects(ulong clientId, Stream stream)
415+
{
416+
using (PooledBitReader reader = PooledBitReader.Get(stream))
417+
{
418+
ushort objectCount = reader.ReadUInt16Packed();
419+
420+
for (int i = 0; i < objectCount; i++)
421+
{
422+
HandleDestroyObject(clientId, stream);
443423
}
444424
}
445425
}

MLAPI/Spawning/SpawnManager.cs

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -361,54 +361,59 @@ internal static void SendSpawnCallForObject(ulong clientId, NetworkedObject netO
361361
{
362362
using (PooledBitStream stream = PooledBitStream.Get())
363363
{
364-
using (PooledBitWriter writer = PooledBitWriter.Get(stream))
364+
WriteSpawnCallForObject(stream, clientId, netObject, payload);
365+
366+
InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_ADD_OBJECT, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null);
367+
}
368+
}
369+
370+
internal static void WriteSpawnCallForObject(MLAPI.Serialization.BitStream stream, ulong clientId, NetworkedObject netObject, Stream payload)
371+
{
372+
using (PooledBitWriter writer = PooledBitWriter.Get(stream))
373+
{
374+
writer.WriteBool(netObject.IsPlayerObject);
375+
writer.WriteUInt64Packed(netObject.NetworkId);
376+
writer.WriteUInt64Packed(netObject.OwnerClientId);
377+
378+
if (NetworkingManager.Singleton.NetworkConfig.UsePrefabSync)
365379
{
366-
writer.WriteBool(netObject.IsPlayerObject);
367-
writer.WriteUInt64Packed(netObject.NetworkId);
368-
writer.WriteUInt64Packed(netObject.OwnerClientId);
380+
writer.WriteUInt64Packed(netObject.PrefabHash);
381+
}
382+
else
383+
{
384+
writer.WriteBool(netObject.IsSceneObject == null ? true : netObject.IsSceneObject.Value);
369385

370-
if (NetworkingManager.Singleton.NetworkConfig.UsePrefabSync)
386+
if (netObject.IsSceneObject == null || netObject.IsSceneObject.Value)
371387
{
372-
writer.WriteUInt64Packed(netObject.PrefabHash);
388+
writer.WriteUInt64Packed(netObject.NetworkedInstanceId);
373389
}
374390
else
375391
{
376-
writer.WriteBool(netObject.IsSceneObject == null ? true : netObject.IsSceneObject.Value);
377-
378-
if (netObject.IsSceneObject == null || netObject.IsSceneObject.Value)
379-
{
380-
writer.WriteUInt64Packed(netObject.NetworkedInstanceId);
381-
}
382-
else
383-
{
384-
writer.WriteUInt64Packed(netObject.PrefabHash);
385-
}
392+
writer.WriteUInt64Packed(netObject.PrefabHash);
386393
}
394+
}
387395

388-
writer.WriteSinglePacked(netObject.transform.position.x);
389-
writer.WriteSinglePacked(netObject.transform.position.y);
390-
writer.WriteSinglePacked(netObject.transform.position.z);
396+
writer.WriteSinglePacked(netObject.transform.position.x);
397+
writer.WriteSinglePacked(netObject.transform.position.y);
398+
writer.WriteSinglePacked(netObject.transform.position.z);
391399

392-
writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.x);
393-
writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.y);
394-
writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.z);
400+
writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.x);
401+
writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.y);
402+
writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.z);
395403

396-
writer.WriteBool(payload != null);
397-
398-
if (payload != null)
399-
{
400-
writer.WriteInt32Packed((int)payload.Length);
401-
}
404+
writer.WriteBool(payload != null);
402405

403-
if (NetworkingManager.Singleton.NetworkConfig.EnableNetworkedVar)
404-
{
405-
netObject.WriteNetworkedVarData(stream, clientId);
406-
}
406+
if (payload != null)
407+
{
408+
writer.WriteInt32Packed((int) payload.Length);
409+
}
407410

408-
if (payload != null) stream.CopyFrom(payload);
411+
if (NetworkingManager.Singleton.NetworkConfig.EnableNetworkedVar)
412+
{
413+
netObject.WriteNetworkedVarData(stream, clientId);
409414
}
410-
411-
InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_ADD_OBJECT, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null);
415+
416+
if (payload != null) stream.CopyFrom(payload);
412417
}
413418
}
414419

0 commit comments

Comments
 (0)