Add objects despawning in networking
This commit is contained in:
@@ -11,6 +11,7 @@ enum class NetworkMessageIDs : uint8
|
|||||||
HandshakeReply,
|
HandshakeReply,
|
||||||
ReplicatedObject,
|
ReplicatedObject,
|
||||||
SpawnObject,
|
SpawnObject,
|
||||||
|
DespawnObject,
|
||||||
|
|
||||||
MAX,
|
MAX,
|
||||||
};
|
};
|
||||||
@@ -25,4 +26,5 @@ public:
|
|||||||
static void NetworkReplicatorUpdate();
|
static void NetworkReplicatorUpdate();
|
||||||
static void OnNetworkMessageReplicatedObject(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
static void OnNetworkMessageReplicatedObject(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||||
static void OnNetworkMessageSpawnObject(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
static void OnNetworkMessageSpawnObject(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||||
|
static void OnNetworkMessageDespawnObject(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ namespace
|
|||||||
OnNetworkMessageHandshakeReply,
|
OnNetworkMessageHandshakeReply,
|
||||||
NetworkInternal::OnNetworkMessageReplicatedObject,
|
NetworkInternal::OnNetworkMessageReplicatedObject,
|
||||||
NetworkInternal::OnNetworkMessageSpawnObject,
|
NetworkInternal::OnNetworkMessageSpawnObject,
|
||||||
|
NetworkInternal::OnNetworkMessageDespawnObject,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ PACK_STRUCT(struct NetworkMessageSpawnObject
|
|||||||
char ObjectTypeName[128]; // TODO: introduce networked-name to synchronize unique names as ushort (less data over network)
|
char ObjectTypeName[128]; // TODO: introduce networked-name to synchronize unique names as ushort (less data over network)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
PACK_STRUCT(struct NetworkMessageDespawnObject
|
||||||
|
{
|
||||||
|
NetworkMessageIDs ID = NetworkMessageIDs::SpawnObject;
|
||||||
|
Guid ObjectId;
|
||||||
|
});
|
||||||
|
|
||||||
struct NetworkReplicatedObject
|
struct NetworkReplicatedObject
|
||||||
{
|
{
|
||||||
ScriptingObjectReference<ScriptingObject> Object;
|
ScriptingObjectReference<ScriptingObject> Object;
|
||||||
@@ -93,6 +99,7 @@ namespace
|
|||||||
CriticalSection ObjectsLock;
|
CriticalSection ObjectsLock;
|
||||||
HashSet<NetworkReplicatedObject> Objects;
|
HashSet<NetworkReplicatedObject> Objects;
|
||||||
Array<ScriptingObjectReference<ScriptingObject>> SpawnQueue;
|
Array<ScriptingObjectReference<ScriptingObject>> SpawnQueue;
|
||||||
|
Array<Guid> DespawnQueue;
|
||||||
Dictionary<Guid, Guid> IdsRemappingTable;
|
Dictionary<Guid, Guid> IdsRemappingTable;
|
||||||
NetworkStream* CachedWriteStream = nullptr;
|
NetworkStream* CachedWriteStream = nullptr;
|
||||||
NetworkStream* CachedReadStream = nullptr;
|
NetworkStream* CachedReadStream = nullptr;
|
||||||
@@ -262,11 +269,32 @@ void NetworkReplicator::SpawnObject(ScriptingObject* obj)
|
|||||||
it = Objects.Find(obj->GetID());
|
it = Objects.Find(obj->GetID());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register for spawning (batched spawning during update)
|
// Register for spawning (batched during update)
|
||||||
ASSERT_LOW_LAYER(!SpawnQueue.Contains(obj));
|
ASSERT_LOW_LAYER(!SpawnQueue.Contains(obj));
|
||||||
SpawnQueue.Add(obj);
|
SpawnQueue.Add(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkReplicator::DespawnObject(ScriptingObject* obj)
|
||||||
|
{
|
||||||
|
if (!obj || NetworkManager::State == NetworkConnectionState::Offline)
|
||||||
|
return;
|
||||||
|
ScopeLock lock(ObjectsLock);
|
||||||
|
const auto it = Objects.Find(obj->GetID());
|
||||||
|
if (it == Objects.End())
|
||||||
|
return;
|
||||||
|
auto& item = it->Item;
|
||||||
|
if (item.Object != obj || !item.Spawned || item.OwnerClientId != NetworkManager::LocalClientId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Register for despawning (batched during update)
|
||||||
|
const Guid id = obj->GetID();
|
||||||
|
ASSERT_LOW_LAYER(!DespawnQueue.Contains(id));
|
||||||
|
DespawnQueue.Add(id);
|
||||||
|
|
||||||
|
// Prevent spawning
|
||||||
|
SpawnQueue.Remove(obj);
|
||||||
|
}
|
||||||
|
|
||||||
uint32 NetworkReplicator::GetObjectClientId(ScriptingObject* obj)
|
uint32 NetworkReplicator::GetObjectClientId(ScriptingObject* obj)
|
||||||
{
|
{
|
||||||
uint32 id = 0;
|
uint32 id = 0;
|
||||||
@@ -389,6 +417,30 @@ void NetworkInternal::NetworkReplicatorUpdate()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Despawn
|
||||||
|
if (DespawnQueue.Count() != 0)
|
||||||
|
{
|
||||||
|
PROFILE_CPU_NAMED("DespawnQueue");
|
||||||
|
for (const Guid& e : DespawnQueue)
|
||||||
|
{
|
||||||
|
// Send despawn message
|
||||||
|
NetworkMessageDespawnObject msgData;
|
||||||
|
msgData.ObjectId = e;
|
||||||
|
if (isClient)
|
||||||
|
{
|
||||||
|
// Remap local client object ids into server ids
|
||||||
|
IdsRemappingTable.KeyOf(msgData.ObjectId, &msgData.ObjectId);
|
||||||
|
}
|
||||||
|
NetworkMessage msg = peer->BeginSendMessage();
|
||||||
|
msg.WriteStructure(msgData);
|
||||||
|
if (isClient)
|
||||||
|
peer->EndSendMessage(NetworkChannelType::ReliableOrdered, msg);
|
||||||
|
else
|
||||||
|
peer->EndSendMessage(NetworkChannelType::ReliableOrdered, msg, CachedTargets);
|
||||||
|
}
|
||||||
|
DespawnQueue.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
// Spawn
|
// Spawn
|
||||||
if (SpawnQueue.Count() != 0)
|
if (SpawnQueue.Count() != 0)
|
||||||
{
|
{
|
||||||
@@ -603,3 +655,32 @@ void NetworkInternal::OnNetworkMessageSpawnObject(NetworkEvent& event, NetworkCl
|
|||||||
// TODO: if we're server then spawn this object further on other clients
|
// TODO: if we're server then spawn this object further on other clients
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkInternal::OnNetworkMessageDespawnObject(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer)
|
||||||
|
{
|
||||||
|
NetworkMessageDespawnObject msgData;
|
||||||
|
event.Message.ReadStructure(msgData);
|
||||||
|
ScopeLock lock(ObjectsLock);
|
||||||
|
NetworkReplicatedObject* e = ResolveObject(msgData.ObjectId);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
auto& item = *e;
|
||||||
|
ScriptingObject* obj = item.Object.Get();
|
||||||
|
if (!obj || !item.Spawned)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Reject despawn from someone who is not an object owner
|
||||||
|
if (client && e->OwnerClientId != client->ClientId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Remove object
|
||||||
|
Objects.Remove(obj);
|
||||||
|
Delete(obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if NETWORK_REPLICATOR_DEBUG_LOG
|
||||||
|
LOG(Error, "[NetworkReplicator] Failed to despawn object {}", msgData.ObjectId);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,6 +66,13 @@ public:
|
|||||||
/// <param name="obj">The object to spawn on other clients.</param>
|
/// <param name="obj">The object to spawn on other clients.</param>
|
||||||
API_FUNCTION() static void SpawnObject(ScriptingObject* obj);
|
API_FUNCTION() static void SpawnObject(ScriptingObject* obj);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Despawns the object from the other clients.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Does nothing if network is offline.</remarks>
|
||||||
|
/// <param name="obj">The object to despawn on other clients.</param>
|
||||||
|
API_FUNCTION() static void DespawnObject(ScriptingObject* obj);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Client Id of the network object owner.
|
/// Gets the Client Id of the network object owner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user