Fix restartround crash and cleanup ServerStorageComponent (#1340)
This commit is contained in:
@@ -31,7 +31,7 @@
|
|||||||
"Wrench",
|
"Wrench",
|
||||||
"Crowbar",
|
"Crowbar",
|
||||||
"MeleeWeapon",
|
"MeleeWeapon",
|
||||||
"Storeable",
|
"Storable",
|
||||||
"Dice",
|
"Dice",
|
||||||
"Construction",
|
"Construction",
|
||||||
"Door",
|
"Door",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.GameObjects.Components;
|
using Content.Server.GameObjects.Components;
|
||||||
using Content.Shared.GameObjects.Components.Inventory;
|
using Content.Shared.GameObjects.Components.Inventory;
|
||||||
|
using Content.Server.GameObjects.Components.Items.Storage;
|
||||||
using Content.Server.GameObjects.EntitySystems.Click;
|
using Content.Server.GameObjects.EntitySystems.Click;
|
||||||
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
||||||
using Content.Server.Interfaces;
|
using Content.Server.Interfaces;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace Content.Server.GameObjects
|
|||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[ComponentReference(typeof(ItemComponent))]
|
[ComponentReference(typeof(ItemComponent))]
|
||||||
[ComponentReference(typeof(StoreableComponent))]
|
[ComponentReference(typeof(StorableComponent))]
|
||||||
[ComponentReference(typeof(IItemComponent))]
|
[ComponentReference(typeof(IItemComponent))]
|
||||||
public class ClothingComponent : ItemComponent, IUse
|
public class ClothingComponent : ItemComponent, IUse
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ namespace Content.Server.GameObjects.Components
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// only items that can be stored in an inventory, or a mob, can be eaten by a locker
|
// only items that can be stored in an inventory, or a mob, can be eaten by a locker
|
||||||
if (!entity.HasComponent<StoreableComponent>() && !entity.HasComponent<SpeciesComponent>())
|
if (!entity.HasComponent<StorableComponent>() && !entity.HasComponent<SpeciesComponent>())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!AddToContents(entity))
|
if (!AddToContents(entity))
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ using Robust.Shared.Serialization;
|
|||||||
namespace Content.Server.GameObjects.Components
|
namespace Content.Server.GameObjects.Components
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[ComponentReference(typeof(StoreableComponent))]
|
[ComponentReference(typeof(StorableComponent))]
|
||||||
[ComponentReference(typeof(IItemComponent))]
|
[ComponentReference(typeof(IItemComponent))]
|
||||||
public class ItemComponent : StoreableComponent, IInteractHand, IExAct, IEquipped, IUnequipped, IItemComponent
|
public class ItemComponent : StorableComponent, IInteractHand, IExAct, IEquipped, IUnequipped, IItemComponent
|
||||||
{
|
{
|
||||||
public override string Name => "Item";
|
public override string Name => "Item";
|
||||||
public override uint? NetID => ContentNetIDs.ITEM;
|
public override uint? NetID => ContentNetIDs.ITEM;
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using System;
|
#nullable enable
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.GameObjects.Components;
|
|
||||||
using Content.Server.GameObjects.Components.Items.Storage;
|
|
||||||
using Content.Server.GameObjects.EntitySystems.Click;
|
|
||||||
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
|
||||||
using Content.Server.Interfaces.GameObjects;
|
using Content.Server.Interfaces.GameObjects;
|
||||||
|
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
||||||
using Content.Server.Utility;
|
using Content.Server.Utility;
|
||||||
using Content.Shared.GameObjects.Components.Storage;
|
using Content.Shared.GameObjects.Components.Storage;
|
||||||
using Content.Shared.Interfaces;
|
using Content.Shared.Interfaces;
|
||||||
@@ -17,16 +15,14 @@ using Robust.Server.Player;
|
|||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
|
||||||
using Robust.Shared.Interfaces.Map;
|
using Robust.Shared.Interfaces.Map;
|
||||||
using Robust.Shared.Interfaces.Network;
|
using Robust.Shared.Interfaces.Network;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Log;
|
using Robust.Shared.Log;
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects
|
namespace Content.Server.GameObjects.Components.Items.Storage
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Storage component for containing entities within this one, matches a UI on the client which shows stored entities
|
/// Storage component for containing entities within this one, matches a UI on the client which shows stored entities
|
||||||
@@ -38,190 +34,272 @@ namespace Content.Server.GameObjects
|
|||||||
IDragDrop
|
IDragDrop
|
||||||
{
|
{
|
||||||
#pragma warning disable 649
|
#pragma warning disable 649
|
||||||
[Dependency] private readonly IMapManager _mapManager;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
private Container storage;
|
private const string LoggerName = "Storage";
|
||||||
|
|
||||||
private bool _storageInitialCalculated = false;
|
private Container? _storage;
|
||||||
private int StorageUsed = 0;
|
|
||||||
private int StorageCapacityMax = 10000;
|
|
||||||
public HashSet<IPlayerSession> SubscribedSessions = new HashSet<IPlayerSession>();
|
|
||||||
|
|
||||||
public IReadOnlyCollection<IEntity> StoredEntities => storage.ContainedEntities;
|
private bool _storageInitialCalculated;
|
||||||
|
private int _storageUsed;
|
||||||
|
private int _storageCapacityMax = 10000;
|
||||||
|
public readonly HashSet<IPlayerSession> SubscribedSessions = new HashSet<IPlayerSession>();
|
||||||
|
|
||||||
public override void Initialize()
|
public IReadOnlyCollection<IEntity>? StoredEntities => _storage?.ContainedEntities;
|
||||||
|
|
||||||
|
private void EnsureInitialCalculated()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
if (_storageInitialCalculated)
|
||||||
|
|
||||||
storage = ContainerManagerComponent.Ensure<Container>("storagebase", Owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
|
||||||
{
|
|
||||||
base.ExposeData(serializer);
|
|
||||||
|
|
||||||
serializer.DataField(ref StorageCapacityMax, "Capacity", 10000);
|
|
||||||
//serializer.DataField(ref StorageUsed, "used", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes from the storage container and updates the stored value
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="toremove"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool Remove(IEntity toremove)
|
|
||||||
{
|
|
||||||
_ensureInitialCalculated();
|
|
||||||
return storage.Remove(toremove);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void HandleEntityMaybeRemoved(EntRemovedFromContainerMessage message)
|
|
||||||
{
|
|
||||||
if (message.Container != storage)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ensureInitialCalculated();
|
RecalculateStorageUsed();
|
||||||
Logger.DebugS("Storage", "Storage (UID {0}) had entity (UID {1}) removed from it.", Owner.Uid,
|
|
||||||
message.Entity.Uid);
|
_storageInitialCalculated = true;
|
||||||
StorageUsed -= message.Entity.GetComponent<StoreableComponent>().ObjectSize;
|
|
||||||
UpdateClientInventories();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void RecalculateStorageUsed()
|
||||||
/// Inserts into the storage container
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="toinsert"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool Insert(IEntity toinsert)
|
|
||||||
{
|
{
|
||||||
return CanInsert(toinsert) && storage.Insert(toinsert);
|
_storageUsed = 0;
|
||||||
}
|
|
||||||
|
|
||||||
internal void HandleEntityMaybeInserted(EntInsertedIntoContainerMessage message)
|
if (_storage == null)
|
||||||
{
|
|
||||||
if (message.Container != storage)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ensureInitialCalculated();
|
foreach (var entity in _storage.ContainedEntities)
|
||||||
Logger.DebugS("Storage", "Storage (UID {0}) had entity (UID {1}) inserted into it.", Owner.Uid,
|
{
|
||||||
message.Entity.Uid);
|
var item = entity.GetComponent<StorableComponent>();
|
||||||
StorageUsed += message.Entity.GetComponent<StoreableComponent>().ObjectSize;
|
_storageUsed += item.ObjectSize;
|
||||||
UpdateClientInventories();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifies the object can be inserted by checking if it is storeable and if it keeps under the capacity limit
|
/// Verifies if an entity can be stored and if it fits
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="toinsert"></param>
|
/// <param name="entity">The entity to check</param>
|
||||||
/// <returns></returns>
|
/// <returns>true if it can be inserted, false otherwise</returns>
|
||||||
public bool CanInsert(IEntity toinsert)
|
public bool CanInsert(IEntity entity)
|
||||||
{
|
{
|
||||||
_ensureInitialCalculated();
|
EnsureInitialCalculated();
|
||||||
|
|
||||||
if (toinsert.TryGetComponent(out ServerStorageComponent storage))
|
if (entity.TryGetComponent(out ServerStorageComponent storage) &&
|
||||||
{
|
storage._storageCapacityMax >= _storageCapacityMax)
|
||||||
if (storage.StorageCapacityMax >= StorageCapacityMax)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toinsert.TryGetComponent(out StoreableComponent store))
|
|
||||||
{
|
|
||||||
if (store.ObjectSize > (StorageCapacityMax - StorageUsed))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Inserts storeable entities into this storage container if possible, otherwise return to the hand of the user
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="user"></param>
|
|
||||||
/// <param name="attackwith"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool InteractUsing(InteractUsingEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
Logger.DebugS("Storage", "Storage (UID {0}) attacked by user (UID {1}) with entity (UID {2}).", Owner.Uid, eventArgs.User.Uid, eventArgs.Using.Uid);
|
|
||||||
|
|
||||||
if(Owner.TryGetComponent<PlaceableSurfaceComponent>(out var placeableSurfaceComponent))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (entity.TryGetComponent(out StorableComponent store) &&
|
||||||
|
store.ObjectSize > _storageCapacityMax - _storageUsed)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
return PlayerInsertEntity(eventArgs.User);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a message to open the storage UI
|
/// Inserts into the storage container
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user"></param>
|
/// <param name="entity">The entity to insert</param>
|
||||||
/// <returns></returns>
|
/// <returns>true if the entity was inserted, false otherwise</returns>
|
||||||
bool IUse.UseEntity(UseEntityEventArgs eventArgs)
|
public bool Insert(IEntity entity)
|
||||||
{
|
{
|
||||||
_ensureInitialCalculated();
|
return CanInsert(entity) && _storage?.Insert(entity) == true;
|
||||||
OpenStorageUI(eventArgs.User);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OpenStorageUI(IEntity Character)
|
|
||||||
{
|
|
||||||
_ensureInitialCalculated();
|
|
||||||
var user_session = Character.GetComponent<BasicActorComponent>().playerSession;
|
|
||||||
Logger.DebugS("Storage", "Storage (UID {0}) \"used\" by player session (UID {1}).", Owner.Uid, user_session.AttachedEntityUid);
|
|
||||||
SubscribeSession(user_session);
|
|
||||||
SendNetworkMessage(new OpenStorageUIMessage(), user_session.ConnectedClient);
|
|
||||||
UpdateClientInventory(user_session);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the storage UI on all subscribed actors, informing them of the state of the container.
|
/// Removes from the storage container and updates the stored value
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity">The entity to remove</param>
|
||||||
|
/// <returns>true if no longer in storage, false otherwise</returns>
|
||||||
|
public bool Remove(IEntity entity)
|
||||||
|
{
|
||||||
|
EnsureInitialCalculated();
|
||||||
|
return _storage?.Remove(entity) == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleEntityMaybeInserted(EntInsertedIntoContainerMessage message)
|
||||||
|
{
|
||||||
|
if (message.Container != _storage)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureInitialCalculated();
|
||||||
|
|
||||||
|
Logger.DebugS(LoggerName, $"Storage (UID {Owner.Uid}) had entity (UID {message.Entity.Uid}) inserted into it.");
|
||||||
|
|
||||||
|
_storageUsed += message.Entity.GetComponent<StorableComponent>().ObjectSize;
|
||||||
|
|
||||||
|
UpdateClientInventories();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleEntityMaybeRemoved(EntRemovedFromContainerMessage message)
|
||||||
|
{
|
||||||
|
if (message.Container != _storage)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureInitialCalculated();
|
||||||
|
|
||||||
|
Logger.DebugS(LoggerName, $"Storage (UID {Owner.Uid}) had entity (UID {message.Entity.Uid}) removed from it.");
|
||||||
|
|
||||||
|
if (!message.Entity.TryGetComponent(out StorableComponent storable))
|
||||||
|
{
|
||||||
|
Logger.WarningS(LoggerName, $"Removed entity {message.Entity.Uid} without a StorableComponent from storage {Owner.Uid} at {Owner.Transform.MapPosition}");
|
||||||
|
|
||||||
|
RecalculateStorageUsed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_storageUsed -= storable.ObjectSize;
|
||||||
|
|
||||||
|
UpdateClientInventories();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserts an entity into storage from the player's active hand
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="player">The player to insert an entity from</param>
|
||||||
|
/// <returns>true if inserted, false otherwise</returns>
|
||||||
|
public bool PlayerInsertEntity(IEntity player)
|
||||||
|
{
|
||||||
|
EnsureInitialCalculated();
|
||||||
|
|
||||||
|
if (!player.TryGetComponent(out IHandsComponent hands) ||
|
||||||
|
hands.GetActiveHand == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var toInsert = hands.GetActiveHand;
|
||||||
|
|
||||||
|
if (!hands.Drop(toInsert.Owner))
|
||||||
|
{
|
||||||
|
Owner.PopupMessage(player, "Can't insert.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Insert(toInsert.Owner))
|
||||||
|
{
|
||||||
|
hands.PutInHand(toInsert);
|
||||||
|
Owner.PopupMessage(player, "Can't insert.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens the storage UI for an entity
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity">The entity to open the UI for</param>
|
||||||
|
public void OpenStorageUI(IEntity entity)
|
||||||
|
{
|
||||||
|
EnsureInitialCalculated();
|
||||||
|
|
||||||
|
var userSession = entity.GetComponent<BasicActorComponent>().playerSession;
|
||||||
|
|
||||||
|
Logger.DebugS(LoggerName, $"Storage (UID {Owner.Uid}) \"used\" by player session (UID {userSession.AttachedEntityUid}).");
|
||||||
|
|
||||||
|
SubscribeSession(userSession);
|
||||||
|
SendNetworkMessage(new OpenStorageUIMessage(), userSession.ConnectedClient);
|
||||||
|
UpdateClientInventory(userSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the storage UI on all subscribed actors, informing them of the state of the container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateClientInventories()
|
private void UpdateClientInventories()
|
||||||
{
|
{
|
||||||
foreach (IPlayerSession session in SubscribedSessions)
|
foreach (var session in SubscribedSessions)
|
||||||
{
|
{
|
||||||
UpdateClientInventory(session);
|
UpdateClientInventory(session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds actor to the update list.
|
/// Updates storage UI on a client, informing them of the state of the container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="actor"></param>
|
/// <param name="session">The client to be updated</param>
|
||||||
public void SubscribeSession(IPlayerSession session)
|
private void UpdateClientInventory(IPlayerSession session)
|
||||||
{
|
{
|
||||||
_ensureInitialCalculated();
|
if (session.AttachedEntity == null)
|
||||||
|
{
|
||||||
|
Logger.DebugS(LoggerName, $"Storage (UID {Owner.Uid}) detected no attached entity in player session (UID {session.AttachedEntityUid}).");
|
||||||
|
|
||||||
|
UnsubscribeSession(session);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_storage == null)
|
||||||
|
{
|
||||||
|
Logger.WarningS(LoggerName, $"{nameof(UpdateClientInventory)} called with null {nameof(_storage)}");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var storedEntities = new Dictionary<EntityUid, int>();
|
||||||
|
|
||||||
|
foreach (var entities in _storage.ContainedEntities)
|
||||||
|
{
|
||||||
|
storedEntities.Add(entities.Uid, entities.GetComponent<StorableComponent>().ObjectSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
SendNetworkMessage(new StorageHeldItemsMessage(storedEntities, _storageUsed, _storageCapacityMax), session.ConnectedClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a session to the update list.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="session">The session to add</param>
|
||||||
|
private void SubscribeSession(IPlayerSession session)
|
||||||
|
{
|
||||||
|
EnsureInitialCalculated();
|
||||||
|
|
||||||
if (!SubscribedSessions.Contains(session))
|
if (!SubscribedSessions.Contains(session))
|
||||||
{
|
{
|
||||||
Logger.DebugS("Storage", "Storage (UID {0}) subscribed player session (UID {1}).", Owner.Uid, session.AttachedEntityUid);
|
Logger.DebugS(LoggerName, $"Storage (UID {Owner.Uid}) subscribed player session (UID {session.AttachedEntityUid}).");
|
||||||
|
|
||||||
session.PlayerStatusChanged += HandlePlayerSessionChangeEvent;
|
session.PlayerStatusChanged += HandlePlayerSessionChangeEvent;
|
||||||
SubscribedSessions.Add(session);
|
SubscribedSessions.Add(session);
|
||||||
|
|
||||||
UpdateDoorState();
|
UpdateDoorState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes actor from the update list.
|
/// Removes a session from the update list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel"></param>
|
/// <param name="session">The session to remove</param>
|
||||||
public void UnsubscribeSession(IPlayerSession session)
|
public void UnsubscribeSession(IPlayerSession session)
|
||||||
{
|
{
|
||||||
if(SubscribedSessions.Contains(session))
|
if (SubscribedSessions.Contains(session))
|
||||||
{
|
{
|
||||||
Logger.DebugS("Storage", "Storage (UID {0}) unsubscribed player session (UID {1}).", Owner.Uid, session.AttachedEntityUid);
|
Logger.DebugS(LoggerName, $"Storage (UID {Owner.Uid}) unsubscribed player session (UID {session.AttachedEntityUid}).");
|
||||||
|
|
||||||
SubscribedSessions.Remove(session);
|
SubscribedSessions.Remove(session);
|
||||||
SendNetworkMessage(new CloseStorageUIMessage(), session.ConnectedClient);
|
SendNetworkMessage(new CloseStorageUIMessage(), session.ConnectedClient);
|
||||||
|
|
||||||
UpdateDoorState();
|
UpdateDoorState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandlePlayerSessionChangeEvent(object? obj, SessionStatusEventArgs sessionStatus)
|
||||||
|
{
|
||||||
|
Logger.DebugS(LoggerName, $"Storage (UID {Owner.Uid}) handled a status change in player session (UID {sessionStatus.Session.AttachedEntityUid}).");
|
||||||
|
|
||||||
|
if (sessionStatus.NewStatus != SessionStatus.InGame)
|
||||||
|
{
|
||||||
|
UnsubscribeSession(sessionStatus.Session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateDoorState()
|
private void UpdateDoorState()
|
||||||
{
|
{
|
||||||
if (Owner.TryGetComponent(out AppearanceComponent appearance))
|
if (Owner.TryGetComponent(out AppearanceComponent appearance))
|
||||||
@@ -230,42 +308,23 @@ namespace Content.Server.GameObjects
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandlePlayerSessionChangeEvent(object obj, SessionStatusEventArgs SSEA)
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
Logger.DebugS("Storage", "Storage (UID {0}) handled a status change in player session (UID {1}).", Owner.Uid, SSEA.Session.AttachedEntityUid);
|
base.Initialize();
|
||||||
if (SSEA.NewStatus != SessionStatus.InGame)
|
|
||||||
{
|
// ReSharper disable once StringLiteralTypo
|
||||||
UnsubscribeSession(SSEA.Session);
|
_storage = ContainerManagerComponent.Ensure<Container>("storagebase", Owner);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
/// Updates storage UI on a client, informing them of the state of the container.
|
|
||||||
/// </summary>
|
|
||||||
private void UpdateClientInventory(IPlayerSession session)
|
|
||||||
{
|
{
|
||||||
if (session.AttachedEntity == null)
|
base.ExposeData(serializer);
|
||||||
{
|
|
||||||
Logger.DebugS("Storage", "Storage (UID {0}) detected no attached entity in player session (UID {1}).", Owner.Uid, session.AttachedEntityUid);
|
serializer.DataField(ref _storageCapacityMax, "Capacity", 10000);
|
||||||
UnsubscribeSession(session);
|
//serializer.DataField(ref StorageUsed, "used", 0);
|
||||||
return;
|
|
||||||
}
|
|
||||||
Dictionary<EntityUid, int> storedentities = new Dictionary<EntityUid, int>();
|
|
||||||
foreach (var entities in storage.ContainedEntities)
|
|
||||||
{
|
|
||||||
storedentities.Add(entities.Uid, entities.GetComponent<StoreableComponent>().ObjectSize);
|
|
||||||
}
|
|
||||||
SendNetworkMessage(new StorageHeldItemsMessage(storedentities, StorageUsed, StorageCapacityMax), session.ConnectedClient);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession? session = null)
|
||||||
/// Receives messages to remove entities from storage, verifies the player can do them,
|
|
||||||
/// and puts the removed entity in hand or on the ground
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="channel"></param>
|
|
||||||
/// <param name="session"></param>
|
|
||||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null)
|
|
||||||
{
|
{
|
||||||
base.HandleNetworkMessage(message, channel, session);
|
base.HandleNetworkMessage(message, channel, session);
|
||||||
|
|
||||||
@@ -276,91 +335,128 @@ namespace Content.Server.GameObjects
|
|||||||
|
|
||||||
switch (message)
|
switch (message)
|
||||||
{
|
{
|
||||||
case RemoveEntityMessage _:
|
case RemoveEntityMessage remove:
|
||||||
{
|
{
|
||||||
_ensureInitialCalculated();
|
EnsureInitialCalculated();
|
||||||
var playerentity = session.AttachedEntity;
|
|
||||||
|
|
||||||
var ourtransform = Owner.GetComponent<ITransformComponent>();
|
var player = session.AttachedEntity;
|
||||||
var playertransform = playerentity.GetComponent<ITransformComponent>();
|
|
||||||
|
|
||||||
if (playertransform.GridPosition.InRange(_mapManager, ourtransform.GridPosition, 2)
|
if (player == null)
|
||||||
&& (ourtransform.IsMapTransform || playertransform.ContainsEntity(ourtransform)))
|
|
||||||
{
|
{
|
||||||
var remove = (RemoveEntityMessage)message;
|
break;
|
||||||
var entity = _entityManager.GetEntity(remove.EntityUid);
|
|
||||||
if (entity != null && storage.Contains(entity))
|
|
||||||
{
|
|
||||||
|
|
||||||
var item = entity.GetComponent<ItemComponent>();
|
|
||||||
if (item != null && playerentity.TryGetComponent(out HandsComponent hands))
|
|
||||||
{
|
|
||||||
if (hands.CanPutInHand(item) && hands.PutInHand(item))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ownerTransform = Owner.Transform;
|
||||||
|
var playerTransform = player.Transform;
|
||||||
|
|
||||||
|
if (!playerTransform.GridPosition.InRange(_mapManager, ownerTransform.GridPosition, 2) ||
|
||||||
|
!ownerTransform.IsMapTransform &&
|
||||||
|
!playerTransform.ContainsEntity(ownerTransform))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var entity = _entityManager.GetEntity(remove.EntityUid);
|
||||||
|
|
||||||
|
if (entity == null || _storage?.Contains(entity) == false)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = entity.GetComponent<ItemComponent>();
|
||||||
|
if (item == null ||
|
||||||
|
!player.TryGetComponent(out HandsComponent hands))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hands.CanPutInHand(item))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
hands.PutInHand(item);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InsertEntityMessage _:
|
case InsertEntityMessage _:
|
||||||
{
|
{
|
||||||
_ensureInitialCalculated();
|
EnsureInitialCalculated();
|
||||||
var playerEntity = session.AttachedEntity;
|
|
||||||
var storageTransform = Owner.GetComponent<ITransformComponent>();
|
var player = session.AttachedEntity;
|
||||||
var playerTransform = playerEntity.GetComponent<ITransformComponent>();
|
|
||||||
// TODO: Replace by proper entity range check once it is implemented.
|
if (player == null)
|
||||||
if (playerTransform.GridPosition.InRange(_mapManager,
|
|
||||||
storageTransform.GridPosition,
|
|
||||||
InteractionSystem.InteractionRange))
|
|
||||||
{
|
{
|
||||||
PlayerInsertEntity(playerEntity);
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var storagePosition = Owner.Transform.MapPosition;
|
||||||
|
|
||||||
|
if (!InteractionChecks.InRangeUnobstructed(player, storagePosition))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerInsertEntity(player);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CloseStorageUIMessage _:
|
case CloseStorageUIMessage _:
|
||||||
{
|
{
|
||||||
UnsubscribeSession(session as IPlayerSession);
|
if (!(session is IPlayerSession playerSession))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnsubscribeSession(playerSession);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
|
/// Inserts storable entities into this storage container if possible, otherwise return to the hand of the user
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="eventArgs"></param>
|
||||||
|
/// <returns>true if inserted, false otherwise</returns>
|
||||||
|
bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
Logger.DebugS(LoggerName, $"Storage (UID {Owner.Uid}) attacked by user (UID {eventArgs.User.Uid}) with entity (UID {eventArgs.Using.Uid}).");
|
||||||
|
|
||||||
|
if (Owner.HasComponent<PlaceableSurfaceComponent>())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PlayerInsertEntity(eventArgs.User);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a message to open the storage UI
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="eventArgs"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool IUse.UseEntity(UseEntityEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
EnsureInitialCalculated();
|
||||||
|
OpenStorageUI(eventArgs.User);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void IActivate.Activate(ActivateEventArgs eventArgs)
|
void IActivate.Activate(ActivateEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
((IUse) this).UseEntity(new UseEntityEventArgs { User = eventArgs.User });
|
((IUse) this).UseEntity(new UseEntityEventArgs { User = eventArgs.User });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _ensureInitialCalculated()
|
|
||||||
{
|
|
||||||
if (_storageInitialCalculated)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StorageUsed = 0;
|
|
||||||
|
|
||||||
if (storage == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var entity in storage.ContainedEntities)
|
|
||||||
{
|
|
||||||
var item = entity.GetComponent<StoreableComponent>();
|
|
||||||
StorageUsed += item.ObjectSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
_storageInitialCalculated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDestroyAct.OnDestroy(DestructionEventArgs eventArgs)
|
void IDestroyAct.OnDestroy(DestructionEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
var storedEntities = storage.ContainedEntities.ToList();
|
var storedEntities = StoredEntities?.ToList();
|
||||||
|
|
||||||
|
if (storedEntities == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var entity in storedEntities)
|
foreach (var entity in storedEntities)
|
||||||
{
|
{
|
||||||
Remove(entity);
|
Remove(entity);
|
||||||
@@ -374,7 +470,13 @@ namespace Content.Server.GameObjects
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var storedEntities = storage.ContainedEntities.ToList();
|
var storedEntities = StoredEntities?.ToList();
|
||||||
|
|
||||||
|
if (storedEntities == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var entity in storedEntities)
|
foreach (var entity in storedEntities)
|
||||||
{
|
{
|
||||||
var exActs = entity.GetAllComponents<IExAct>();
|
var exActs = entity.GetAllComponents<IExAct>();
|
||||||
@@ -385,53 +487,30 @@ namespace Content.Server.GameObjects
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
bool IDragDrop.DragDrop(DragDropEventArgs eventArgs)
|
||||||
/// Inserts an entity into the storage component from the players active hand.
|
|
||||||
/// </summary>
|
|
||||||
public bool PlayerInsertEntity(IEntity player)
|
|
||||||
{
|
{
|
||||||
_ensureInitialCalculated();
|
if (!eventArgs.Target.TryGetComponent<PlaceableSurfaceComponent>(out var placeableSurface) ||
|
||||||
|
!placeableSurface.IsPlaceable)
|
||||||
if (!player.TryGetComponent(out IHandsComponent hands) || hands.GetActiveHand == null)
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var toInsert = hands.GetActiveHand;
|
var storedEntities = StoredEntities?.ToList();
|
||||||
|
|
||||||
if (hands.Drop(toInsert.Owner))
|
if (storedEntities == null)
|
||||||
{
|
{
|
||||||
if (Insert(toInsert.Owner))
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var storedEntity in storedEntities)
|
||||||
|
{
|
||||||
|
if (Remove(storedEntity))
|
||||||
{
|
{
|
||||||
return true;
|
storedEntity.Transform.WorldPosition = eventArgs.DropLocation.Position;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hands.PutInHand(toInsert);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Owner.PopupMessage(player, "Can't insert.");
|
return true;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DragDrop(DragDropEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (eventArgs.Target.TryGetComponent<PlaceableSurfaceComponent>(out var placeableSurface))
|
|
||||||
{
|
|
||||||
if (!placeableSurface.IsPlaceable) return false;
|
|
||||||
|
|
||||||
// empty everything out
|
|
||||||
foreach (var storedEntity in StoredEntities.ToList())
|
|
||||||
{
|
|
||||||
if (Remove(storedEntity))
|
|
||||||
{
|
|
||||||
storedEntity.Transform.WorldPosition = eventArgs.DropLocation.Position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ using Robust.Shared.Serialization;
|
|||||||
namespace Content.Server.GameObjects.Components.Items.Storage
|
namespace Content.Server.GameObjects.Components.Items.Storage
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public class StoreableComponent : Component
|
public class StorableComponent : Component
|
||||||
{
|
{
|
||||||
public override string Name => "Storeable";
|
public override string Name => "Storable";
|
||||||
|
|
||||||
public int ObjectSize = 0;
|
public int ObjectSize = 0;
|
||||||
|
|
||||||
@@ -18,6 +18,7 @@ using System;
|
|||||||
using Content.Shared.GameObjects.EntitySystems;
|
using Content.Shared.GameObjects.EntitySystems;
|
||||||
using Content.Server.GameObjects;
|
using Content.Server.GameObjects;
|
||||||
using Content.Server.GameObjects.Components;
|
using Content.Server.GameObjects.Components;
|
||||||
|
using Content.Server.GameObjects.Components.Items.Storage;
|
||||||
using Content.Server.GameObjects.EntitySystems.Click;
|
using Content.Server.GameObjects.EntitySystems.Click;
|
||||||
|
|
||||||
namespace Content.Server.Interfaces.GameObjects.Components.Interaction
|
namespace Content.Server.Interfaces.GameObjects.Components.Interaction
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Server.GameObjects;
|
using Content.Server.GameObjects;
|
||||||
|
using Content.Server.GameObjects.Components.Items.Storage;
|
||||||
using Content.Server.GameObjects.EntitySystems.Click;
|
using Content.Server.GameObjects.EntitySystems.Click;
|
||||||
using Robust.Server.GameObjects.EntitySystemMessages;
|
using Robust.Server.GameObjects.EntitySystemMessages;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=occluder/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=occluder/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Occluders/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Occluders/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Patreon/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Patreon/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=placeable/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=preemptively/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=preemptively/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=prefs/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=prefs/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Serilog/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Serilog/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|||||||
Reference in New Issue
Block a user