using Barotrauma.Items.Components;
using Barotrauma.Networking;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Barotrauma
{
partial class EntitySpawner : Entity, IServerSerializable
{
///
/// Thread-safe queue for received entity spawn/remove events from the server.
///
private readonly ConcurrentQueue<(Entity entity, bool isRemoval)> receivedEventsQueue = new ConcurrentQueue<(Entity entity, bool isRemoval)>();
///
/// Gets a thread-safe snapshot of received events.
///
public IEnumerable<(Entity entity, bool isRemoval)> GetReceivedEventsSnapshot()
{
return receivedEventsQueue.ToArray();
}
///
/// Clears all received events from the queue.
///
void ResetReceivedEvents()
{
while (receivedEventsQueue.TryDequeue(out _)) { }
}
public void ClientEventRead(IReadMessage message, float sendingTime)
{
bool remove = message.ReadBoolean();
if (remove)
{
ushort entityId = message.ReadUInt16();
var entity = FindEntityByID(entityId);
if (entity != null)
{
DebugConsole.Log($"Received entity removal message for \"{entity}\".");
if (entity is Item item && item.Container?.GetComponent() != null)
{
if (item.Prefab.ContentPackage == ContentPackageManager.VanillaCorePackage &&
/* we don't need info of every deconstructed item, we can get a good sample size just by logging 5% */
Rand.Range(0.0f, 1.0f) < 0.05f)
{
GameAnalyticsManager.AddDesignEvent("ItemDeconstructed:" + (GameMain.GameSession?.GameMode?.Preset.Identifier ?? "none".ToIdentifier()) + ":" + item.Prefab.Identifier);
}
}
entity.Remove();
}
else
{
DebugConsole.Log("Received entity removal message for ID " + entityId + ". Entity with a matching ID not found.");
}
receivedEventsQueue.Enqueue((entity, true));
}
else
{
switch (message.ReadByte())
{
case (byte)SpawnableType.Item:
var newItem = Item.ReadSpawnData(message, true);
if (newItem == null)
{
DebugConsole.ThrowError("Received an item spawn message, but spawning the item failed.");
}
else
{
if (newItem.Container?.GetComponent() != null)
{
if (newItem.Prefab.ContentPackage == ContentPackageManager.VanillaCorePackage &&
/* we don't need info of every fabricated item, we can get a good sample size just by logging 5% */
Rand.Range(0.0f, 1.0f) < 0.05f)
{
GameAnalyticsManager.AddDesignEvent("ItemFabricated:" + (GameMain.GameSession?.GameMode?.Preset.Identifier ?? "none".ToIdentifier()) + ":" + newItem.Prefab.Identifier);
}
}
receivedEventsQueue.Enqueue((newItem, false));
}
break;
case (byte)SpawnableType.Character:
var character = Character.ReadSpawnData(message);
if (character == null)
{
DebugConsole.ThrowError("Received character spawn message, but spawning the character failed.");
}
else
{
receivedEventsQueue.Enqueue((character, false));
}
break;
default:
DebugConsole.ThrowError("Received invalid entity spawn message (unknown spawnable type)");
break;
}
}
}
}
}