Fix restartround crash and cleanup ServerStorageComponent (#1340)

This commit is contained in:
DrSmugleaf
2020-07-17 11:03:07 +02:00
committed by GitHub
parent 90ca60c56a
commit 53a2392edc
10 changed files with 342 additions and 259 deletions

View File

@@ -31,7 +31,7 @@
"Wrench", "Wrench",
"Crowbar", "Crowbar",
"MeleeWeapon", "MeleeWeapon",
"Storeable", "Storable",
"Dice", "Dice",
"Construction", "Construction",
"Door", "Door",

View File

@@ -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;

View File

@@ -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
{ {

View File

@@ -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))

View File

@@ -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;

View File

@@ -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;
} }
} }
} }

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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>