4 using Microsoft.Xna.Framework;
6 using System.Collections.Generic;
35 private readonly Action<Item> onSpawned;
37 public ItemSpawnInfo(
ItemPrefab prefab, Vector2 worldPosition, Action<Item> onSpawned,
float? condition =
null,
int? quality =
null)
39 Prefab = prefab ??
throw new ArgumentException(
"ItemSpawnInfo prefab cannot be null.");
43 this.onSpawned = onSpawned;
48 Prefab = prefab ??
throw new ArgumentException(
"ItemSpawnInfo prefab cannot be null.");
53 this.onSpawned = onSpawned;
58 Prefab = prefab ??
throw new ArgumentException(
"ItemSpawnInfo prefab cannot be null.");
62 this.onSpawned = onSpawned;
78 spawnedItem =
new Item(
Prefab, Vector2.Zero,
null)
113 if (spawnedItem is not
Item item) {
throw new ArgumentException($
"The entity passed to ItemSpawnInfo.OnSpawned must be an Item (value was {spawnedItem?.ToString() ?? "null"})."); }
114 onSpawned?.Invoke(item);
118 class CharacterSpawnInfo : IEntitySpawnInfo
120 public readonly Identifier Identifier;
126 private readonly Action<Character> onSpawned;
128 public CharacterSpawnInfo(Identifier identifier, Vector2 worldPosition, Action<Character> onSpawn =
null)
130 this.Identifier = identifier;
131 if (identifier.IsEmpty) {
throw new ArgumentException($
"{nameof(CharacterSpawnInfo)} identifier cannot be null."); }
133 this.onSpawned = onSpawn;
136 public CharacterSpawnInfo(Identifier identifier, Vector2 position,
Submarine sub, Action<Character> onSpawn =
null)
138 this.Identifier = identifier;
139 if (identifier.IsEmpty) {
throw new ArgumentException($
"{nameof(CharacterSpawnInfo)} identifier cannot be null."); }
142 this.onSpawned = onSpawn;
145 public CharacterSpawnInfo(Identifier identifier, Vector2 position, CharacterInfo characterInfo, Action<Character> onSpawn =
null) : this (identifier, position, onSpawn)
147 CharacterInfo = characterInfo;
152 var character = Identifier.IsEmpty ? null :
155 ToolBox.RandomSeed(8), CharacterInfo, createNetworkEvent:
false);
159 public void OnSpawned(
Entity spawnedCharacter)
161 if (!(spawnedCharacter is Character character)) {
throw new ArgumentException($
"The entity passed to CharacterSpawnInfo.OnSpawned must be a Character (value was {spawnedCharacter?.ToString() ?? "null"})."); }
162 onSpawned?.Invoke(character);
166 class SubmarineSpawnInfo : IEntitySpawnInfo
168 public readonly
string Name;
172 private readonly Action<Character> onSpawned;
174 public SubmarineSpawnInfo(
string name, Vector2 worldPosition, Action<Character> onSpawn =
null)
176 this.Name = name ??
throw new ArgumentException(
"ItemSpawnInfo prefab cannot be null.");
178 this.onSpawned = onSpawn;
184 var submarine =
string.IsNullOrEmpty(Name) ? null :
185 new Submarine(SubmarineInfo.SavedSubmarines.First(s => s.Name.Equals(Name, StringComparison.OrdinalIgnoreCase)));
189 public void OnSpawned(
Entity spawnedCharacter)
191 if (!(spawnedCharacter is Character character)) {
throw new ArgumentException($
"The entity passed to CharacterSpawnInfo.OnSpawned must be a Character (value was {spawnedCharacter?.ToString() ?? "null"})."); }
192 onSpawned?.Invoke(character);
196 private readonly Queue<Either<IEntitySpawnInfo, Entity>> spawnOrRemoveQueue;
213 $
", {ID}, {InventoryID}, {SlotIndex})";
219 if (!(entity is
Item { ParentInventory: { Owner: { } } } item)) {
return; }
222 SlotIndex = item.ParentInventory.FindIndex(item);
225 if (item.Container ==
null) {
return; }
227 foreach (
ItemComponent component
in item.Container.Components)
230 container.
Inventory == item.ParentInventory)
243 => $
"Spawn {base.ToString()}";
250 => $
"Remove {base.ToString()}";
256 spawnOrRemoveQueue =
new Queue<Either<IEntitySpawnInfo, Entity>>();
261 return "EntitySpawner";
267 if (itemPrefab ==
null)
269 string errorMsg =
"Attempted to add a null item to entity spawn queue.\n" + Environment.StackTrace.CleanupStackTrace();
270 DebugConsole.ThrowError(errorMsg);
271 GameAnalyticsManager.AddErrorEventOnce(
"EntitySpawner.AddToSpawnQueue1:ItemPrefabNull", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
274 spawnOrRemoveQueue.Enqueue(
new ItemSpawnInfo(itemPrefab, worldPosition, onSpawned, condition, quality));
280 if (itemPrefab ==
null)
282 string errorMsg =
"Attempted to add a null item to entity spawn queue.\n" + Environment.StackTrace.CleanupStackTrace();
283 DebugConsole.ThrowError(errorMsg);
284 GameAnalyticsManager.AddErrorEventOnce(
"EntitySpawner.AddToSpawnQueue2:ItemPrefabNull", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
287 spawnOrRemoveQueue.Enqueue(
new ItemSpawnInfo(itemPrefab, position, sub, onSpawned, condition, quality));
293 if (itemPrefab ==
null)
295 string errorMsg =
"Attempted to add a null item to entity spawn queue.\n" + Environment.StackTrace.CleanupStackTrace();
296 DebugConsole.ThrowError(errorMsg);
297 GameAnalyticsManager.AddErrorEventOnce(
"EntitySpawner.AddToSpawnQueue3:ItemPrefabNull", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
300 spawnOrRemoveQueue.Enqueue(
new ItemSpawnInfo(itemPrefab, inventory, onSpawned, condition, quality)
302 SpawnIfInventoryFull = spawnIfInventoryFull,
303 IgnoreLimbSlots = ignoreLimbSlots,
311 if (speciesName.IsEmpty)
313 string errorMsg =
"Attempted to add an empty/null species name to entity spawn queue.\n" + Environment.StackTrace.CleanupStackTrace();
314 DebugConsole.ThrowError(errorMsg);
315 GameAnalyticsManager.AddErrorEventOnce(
"EntitySpawner.AddToSpawnQueue4:SpeciesNameNullOrEmpty", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
318 spawnOrRemoveQueue.Enqueue(
new CharacterSpawnInfo(speciesName, worldPosition, onSpawn));
324 if (speciesName.IsEmpty)
326 string errorMsg =
"Attempted to add an empty/null species name to entity spawn queue.\n" + Environment.StackTrace.CleanupStackTrace();
327 DebugConsole.ThrowError(errorMsg);
328 GameAnalyticsManager.AddErrorEventOnce(
"EntitySpawner.AddToSpawnQueue5:SpeciesNameNullOrEmpty", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
331 spawnOrRemoveQueue.Enqueue(
new CharacterSpawnInfo(speciesName, position, sub, onSpawn));
337 if (speciesName.IsEmpty)
339 string errorMsg =
"Attempted to add an empty/null species name to entity spawn queue.\n" + Environment.StackTrace.CleanupStackTrace();
340 DebugConsole.ThrowError(errorMsg);
341 GameAnalyticsManager.AddErrorEventOnce(
"EntitySpawner.AddToSpawnQueue4:SpeciesNameNullOrEmpty", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
344 spawnOrRemoveQueue.Enqueue(
new CharacterSpawnInfo(speciesName, worldPosition, characterInfo, onSpawn));
358 Client client =
GameMain.Server.ConnectedClients.Find(c => c.Character == character);
359 if (client !=
null)
GameMain.Server.SetClientCharacter(client,
null);
364 spawnOrRemoveQueue.Enqueue(entity);
372 spawnOrRemoveQueue.Enqueue(item);
374 if (containedItems ==
null) {
return; }
375 foreach (
Item containedItem
in containedItems)
377 if (containedItem !=
null)
389 foreach (var spawnOrRemove
in spawnOrRemoveQueue)
391 if (spawnOrRemove.TryGet(out
IEntitySpawnInfo spawnInfo) && predicate(spawnInfo)) {
return true; }
402 foreach (var spawnOrRemove
in spawnOrRemoveQueue)
404 if (spawnOrRemove.TryGet(out
IEntitySpawnInfo spawnInfo) && predicate(spawnInfo)) { count++; }
411 foreach (var spawnOrRemove
in spawnOrRemoveQueue)
413 if (spawnOrRemove.TryGet(out
Entity entityToRemove) && entityToRemove == entity) {
return true; }
418 public void Update(
bool createNetworkEvents =
true)
421 while (spawnOrRemoveQueue.Count > 0)
423 var spawnOrRemove = spawnOrRemoveQueue.Dequeue();
424 if (spawnOrRemove.TryGet(out
Entity entityToRemove))
426 if (entityToRemove is
Item item)
428 item.SendPendingNetworkUpdates();
430 if (createNetworkEvents)
432 CreateNetworkEventProjSpecific(
new RemoveEntity(entityToRemove));
434 entityToRemove.Remove();
438 var spawnedEntity = spawnInfo.Spawn();
439 if (spawnedEntity ==
null) {
continue; }
440 if (createNetworkEvents)
442 CreateNetworkEventProjSpecific(
new SpawnEntity(spawnedEntity));
444 spawnInfo.OnSpawned(spawnedEntity);
450 partial
void CreateNetworkEventProjSpecific(SpawnOrRemove spawnOrRemove);
454 spawnOrRemoveQueue.Clear();
Stores information about the Character that is needed between rounds in the menu etc....
virtual Vector2 WorldPosition
Entity(Submarine submarine, ushort id)
const ushort EntitySpawnerID
readonly ushort ID
Unique, but non-persistent identifier. Stays the same if the entities are created in the exactly same...
readonly ItemPrefab Prefab
readonly Vector2 Position
readonly Submarine Submarine
bool SpawnIfInventoryFull
ItemSpawnInfo(ItemPrefab prefab, Vector2 position, Submarine sub, Action< Item > onSpawned, float? condition=null, int? quality=null)
void OnSpawned(Entity spawnedItem)
ItemSpawnInfo(ItemPrefab prefab, Inventory inventory, Action< Item > onSpawned, float? condition=null, int? quality=null)
ItemSpawnInfo(ItemPrefab prefab, Vector2 worldPosition, Action< Item > onSpawned, float? condition=null, int? quality=null)
readonly Inventory Inventory
override string ToString()
RemoveEntity(Entity entity)
SpawnEntity(Entity entity)
override string ToString()
SpawnOrRemove(Entity entity)
override string ToString()
readonly UInt16 InventoryID
readonly byte ItemContainerIndex
void AddCharacterToSpawnQueue(Identifier speciesName, Vector2 worldPosition, Action< Character > onSpawn=null)
bool IsInRemoveQueue(Entity entity)
void Update(bool createNetworkEvents=true)
void AddItemToRemoveQueue(Item item)
int CountSpawnQueue(Predicate< IEntitySpawnInfo > predicate)
How many entities in the spawn queue match the given predicate
void AddCharacterToSpawnQueue(Identifier speciesName, Vector2 worldPosition, CharacterInfo characterInfo, Action< Character > onSpawn=null)
void AddItemToSpawnQueue(ItemPrefab itemPrefab, Vector2 position, Submarine sub, float? condition=null, int? quality=null, Action< Item > onSpawned=null)
void AddItemToSpawnQueue(ItemPrefab itemPrefab, Vector2 worldPosition, float? condition=null, int? quality=null, Action< Item > onSpawned=null)
void AddCharacterToSpawnQueue(Identifier speciesName, Vector2 position, Submarine sub, Action< Character > onSpawn=null)
readonly List<(Entity entity, bool isRemoval)> receivedEvents
override string ToString()
void AddItemToSpawnQueue(ItemPrefab itemPrefab, Inventory inventory, float? condition=null, int? quality=null, Action< Item > onSpawned=null, bool spawnIfInventoryFull=true, bool ignoreLimbSlots=false, InvSlotType slot=InvSlotType.None)
void AddEntityToRemoveQueue(Entity entity)
bool IsInSpawnQueue(Predicate< IEntitySpawnInfo > predicate)
Are there any entities in the spawn queue that match the given predicate
void EntitySpawned(Entity entity)
static GameSession?? GameSession
static NetworkMember NetworkMember
readonly EventManager EventManager
virtual bool TryPutItem(Item item, Character user, IEnumerable< InvSlotType > allowedSlots=null, bool createNetworkEvent=true, bool ignoreCondition=false)
If there is room, puts the item in the inventory and returns true, otherwise returns false
virtual IEnumerable< Item > AllItems
All items contained in the inventory. Stacked items are returned as individual instances....
void ForceToSlot(Item item, int index)
Forces an item to a specific slot. Doesn't remove the item from existing slots/inventories or do any ...
Item GetItemAt(int index)
Get the item stored in the specified inventory slot. If the slot contains a stack of items,...
bool CanBePut(Item item)
Can the item be put in the inventory (i.e. is there a suitable free slot or a stack the item can be p...
ItemInventory OwnInventory
IEnumerable< InvSlotType > AllowedSlots
void SetTransform(Vector2 simPosition, float rotation, bool findNewHull=true, bool setPrevTransform=true)
The base class for components holding the different functionalities of the item
readonly ItemInventory Inventory
override Vector2? Position
void OnSpawned(Entity entity)
Interface for entities that the server can send events to the clients