Storage fixes (#36533)
* Storage fixes - Add size event. - Fix reclaim not running always. * Block the toggles * Standardise and popup explaining * Disable item toggles in bags * Fix verb popping up even if we can't activate * Conflicts * Validate * Stop drags if source closes * Really fixes * Real fix * Revert this
This commit is contained in:
@@ -269,6 +269,12 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
|
||||
var position = targetStorage.GetMouseGridPieceLocation(dragEnt, dragLoc);
|
||||
var newLocation = new ItemStorageLocation(DraggingRotation, position);
|
||||
|
||||
if (!_storage.ItemFitsInGridLocation(dragEnt, sourceStorage, newLocation))
|
||||
{
|
||||
window.Reclaim(control.Location, control);
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityManager.RaisePredictiveEvent(new StorageSetItemLocationEvent(
|
||||
EntityManager.GetNetEntity(draggingGhost.Entity),
|
||||
EntityManager.GetNetEntity(sourceStorage),
|
||||
@@ -276,6 +282,7 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
|
||||
|
||||
window.Reclaim(newLocation, control);
|
||||
}
|
||||
}
|
||||
// Dragging to new storage
|
||||
else if (targetStorage?.StorageEntity != null && targetStorage != window)
|
||||
{
|
||||
@@ -336,6 +343,17 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
|
||||
if (DraggingGhost == null)
|
||||
return false;
|
||||
|
||||
var player = _player.LocalEntity;
|
||||
|
||||
// If the attached storage is closed then stop dragging
|
||||
if (player == null ||
|
||||
!_storage.TryGetStorageLocation(DraggingGhost.Entity, out var container, out _, out _) ||
|
||||
!_ui.IsUiOpen(container.Owner, StorageComponent.StorageUiKey.Key, player.Value))
|
||||
{
|
||||
DraggingGhost.Orphan();
|
||||
return false;
|
||||
}
|
||||
|
||||
SetDraggingRotation();
|
||||
return true;
|
||||
}
|
||||
|
||||
10
Content.Shared/Item/ItemSizeChangedEvent.cs
Normal file
10
Content.Shared/Item/ItemSizeChangedEvent.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Content.Shared.Item;
|
||||
|
||||
/// <summary>
|
||||
/// Raised directed on an entity when its item size / shape changes.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public struct ItemSizeChangedEvent(EntityUid Entity)
|
||||
{
|
||||
public EntityUid Entity = Entity;
|
||||
}
|
||||
@@ -78,13 +78,18 @@ public sealed partial class ItemToggleComponent : Component
|
||||
[ByRefEvent]
|
||||
public record struct ItemToggleActivateAttemptEvent(EntityUid? User)
|
||||
{
|
||||
/// <summary>
|
||||
/// Should we silently fail.
|
||||
/// </summary>
|
||||
public bool Silent = false;
|
||||
|
||||
public bool Cancelled = false;
|
||||
public readonly EntityUid? User = User;
|
||||
|
||||
/// <summary>
|
||||
/// Pop-up that gets shown to users explaining why the attempt was cancelled.
|
||||
/// </summary>
|
||||
public string? Popup { get; set; }
|
||||
public string? Popup;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -93,8 +98,18 @@ public record struct ItemToggleActivateAttemptEvent(EntityUid? User)
|
||||
[ByRefEvent]
|
||||
public record struct ItemToggleDeactivateAttemptEvent(EntityUid? User)
|
||||
{
|
||||
/// <summary>
|
||||
/// Should we silently fail.
|
||||
/// </summary>
|
||||
public bool Silent = false;
|
||||
|
||||
public bool Cancelled = false;
|
||||
public readonly EntityUid? User = User;
|
||||
|
||||
/// <summary>
|
||||
/// Pop-up that gets shown to users explaining why the attempt was cancelled.
|
||||
/// </summary>
|
||||
public string? Popup;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -15,24 +15,24 @@ public sealed partial class ItemToggleSizeComponent : Component
|
||||
/// <summary>
|
||||
/// Item's size when activated
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
|
||||
[DataField, AutoNetworkedField]
|
||||
public ProtoId<ItemSizePrototype>? ActivatedSize = null;
|
||||
|
||||
/// <summary>
|
||||
/// Item's shape when activated
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField]
|
||||
[DataField, AutoNetworkedField]
|
||||
public List<Box2i>? ActivatedShape = null;
|
||||
|
||||
/// <summary>
|
||||
/// Item's size when deactivated. If none is mentioned, it uses the item's default size instead.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
|
||||
[DataField, AutoNetworkedField]
|
||||
public ProtoId<ItemSizePrototype>? DeactivatedSize = null;
|
||||
|
||||
/// <summary>
|
||||
/// Item's shape when deactivated. If none is mentioned, it uses the item's default shape instead.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField]
|
||||
[DataField, AutoNetworkedField]
|
||||
public List<Box2i>? DeactivatedShape = null;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,23 @@ public sealed class ItemToggleSystem : EntitySystem
|
||||
|
||||
var user = args.User;
|
||||
|
||||
if (ent.Comp.Activated)
|
||||
{
|
||||
var ev = new ItemToggleActivateAttemptEvent(args.User);
|
||||
RaiseLocalEvent(ent.Owner, ref ev);
|
||||
|
||||
if (ev.Cancelled)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ev = new ItemToggleDeactivateAttemptEvent(args.User);
|
||||
RaiseLocalEvent(ent.Owner, ref ev);
|
||||
|
||||
if (ev.Cancelled)
|
||||
return;
|
||||
}
|
||||
|
||||
args.Verbs.Add(new ActivationVerb()
|
||||
{
|
||||
Text = !ent.Comp.Activated ? Loc.GetString(ent.Comp.VerbToggleOn) : Loc.GetString(ent.Comp.VerbToggleOff),
|
||||
@@ -133,15 +150,20 @@ public sealed class ItemToggleSystem : EntitySystem
|
||||
if (comp.Activated)
|
||||
return true;
|
||||
|
||||
if (!comp.Predictable && _netManager.IsClient)
|
||||
return true;
|
||||
|
||||
var attempt = new ItemToggleActivateAttemptEvent(user);
|
||||
RaiseLocalEvent(uid, ref attempt);
|
||||
|
||||
if (!comp.Predictable) predicted = false;
|
||||
if (!comp.Predictable)
|
||||
predicted = false;
|
||||
|
||||
if (!predicted && _netManager.IsClient)
|
||||
return false;
|
||||
|
||||
if (attempt.Cancelled)
|
||||
{
|
||||
if (attempt.Silent)
|
||||
return false;
|
||||
|
||||
if (predicted)
|
||||
_audio.PlayPredicted(comp.SoundFailToActivate, uid, user);
|
||||
else
|
||||
@@ -159,7 +181,6 @@ public sealed class ItemToggleSystem : EntitySystem
|
||||
}
|
||||
|
||||
Activate((uid, comp), predicted, user);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -176,16 +197,31 @@ public sealed class ItemToggleSystem : EntitySystem
|
||||
if (!comp.Activated)
|
||||
return true;
|
||||
|
||||
if (!comp.Predictable && _netManager.IsClient)
|
||||
return true;
|
||||
if (!comp.Predictable)
|
||||
predicted = false;
|
||||
|
||||
var attempt = new ItemToggleDeactivateAttemptEvent(user);
|
||||
RaiseLocalEvent(uid, ref attempt);
|
||||
|
||||
if (attempt.Cancelled)
|
||||
if (!predicted && _netManager.IsClient)
|
||||
return false;
|
||||
|
||||
if (!comp.Predictable) predicted = false;
|
||||
if (attempt.Cancelled)
|
||||
{
|
||||
if (attempt.Silent)
|
||||
return false;
|
||||
|
||||
if (attempt.Popup != null && user != null)
|
||||
{
|
||||
if (predicted)
|
||||
_popup.PopupClient(attempt.Popup, uid, user.Value);
|
||||
else
|
||||
_popup.PopupEntity(attempt.Popup, uid, user.Value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Deactivate((uid, comp), predicted, user);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -39,20 +39,24 @@ public abstract class SharedItemSystem : EntitySystem
|
||||
|
||||
public void SetSize(EntityUid uid, ProtoId<ItemSizePrototype> size, ItemComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component, false))
|
||||
if (!Resolve(uid, ref component, false) || component.Size == size)
|
||||
return;
|
||||
|
||||
component.Size = size;
|
||||
Dirty(uid, component);
|
||||
var ev = new ItemSizeChangedEvent(uid);
|
||||
RaiseLocalEvent(uid, ref ev, broadcast: true);
|
||||
}
|
||||
|
||||
public void SetShape(EntityUid uid, List<Box2i>? shape, ItemComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component, false))
|
||||
if (!Resolve(uid, ref component, false) || component.Shape == shape)
|
||||
return;
|
||||
|
||||
component.Shape = shape;
|
||||
Dirty(uid, component);
|
||||
var ev = new ItemSizeChangedEvent(uid);
|
||||
RaiseLocalEvent(uid, ref ev, broadcast: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -236,6 +240,7 @@ public abstract class SharedItemSystem : EntitySystem
|
||||
{
|
||||
// Set the deactivated shape to the default item's shape before it gets changed.
|
||||
itemToggleSize.DeactivatedShape ??= new List<Box2i>(GetItemShape(item));
|
||||
Dirty(uid, itemToggleSize);
|
||||
SetShape(uid, itemToggleSize.ActivatedShape, item);
|
||||
}
|
||||
|
||||
@@ -243,6 +248,7 @@ public abstract class SharedItemSystem : EntitySystem
|
||||
{
|
||||
// Set the deactivated size to the default item's size before it gets changed.
|
||||
itemToggleSize.DeactivatedSize ??= item.Size;
|
||||
Dirty(uid, itemToggleSize);
|
||||
SetSize(uid, (ProtoId<ItemSizePrototype>) itemToggleSize.ActivatedSize, item);
|
||||
}
|
||||
}
|
||||
@@ -258,7 +264,5 @@ public abstract class SharedItemSystem : EntitySystem
|
||||
SetSize(uid, (ProtoId<ItemSizePrototype>) itemToggleSize.DeactivatedSize, item);
|
||||
}
|
||||
}
|
||||
|
||||
Dirty(uid, item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Components;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Item.ItemToggle.Components;
|
||||
using Content.Shared.Lock;
|
||||
using Content.Shared.Materials;
|
||||
using Content.Shared.Placeable;
|
||||
@@ -146,13 +147,13 @@ public abstract class SharedStorageSystem : EntitySystem
|
||||
SubscribeLocalEvent<StorageComponent, BoundUserInterfaceMessageAttempt>(OnBoundUIAttempt);
|
||||
SubscribeLocalEvent<StorageComponent, BoundUIOpenedEvent>(OnBoundUIOpen);
|
||||
SubscribeLocalEvent<StorageComponent, LockToggledEvent>(OnLockToggled);
|
||||
SubscribeLocalEvent<MetaDataComponent, StackCountChangedEvent>(OnStackCountChanged);
|
||||
|
||||
SubscribeLocalEvent<StorageComponent, EntInsertedIntoContainerMessage>(OnEntInserted);
|
||||
SubscribeLocalEvent<StorageComponent, EntRemovedFromContainerMessage>(OnEntRemoved);
|
||||
SubscribeLocalEvent<StorageComponent, ContainerIsInsertingAttemptEvent>(OnInsertAttempt);
|
||||
|
||||
SubscribeLocalEvent<StorageComponent, AreaPickupDoAfterEvent>(OnDoAfter);
|
||||
SubscribeLocalEvent<StorageComponent, GotReclaimedEvent>(OnReclaimed);
|
||||
|
||||
SubscribeLocalEvent<MetaDataComponent, StackCountChangedEvent>(OnStackCountChanged);
|
||||
|
||||
SubscribeAllEvent<OpenNestedStorageEvent>(OnStorageNested);
|
||||
SubscribeAllEvent<StorageTransferItemEvent>(OnStorageTransfer);
|
||||
@@ -161,7 +162,7 @@ public abstract class SharedStorageSystem : EntitySystem
|
||||
SubscribeAllEvent<StorageInsertItemIntoLocationEvent>(OnInsertItemIntoLocation);
|
||||
SubscribeAllEvent<StorageSaveItemLocationEvent>(OnSaveItemLocation);
|
||||
|
||||
SubscribeLocalEvent<StorageComponent, GotReclaimedEvent>(OnReclaimed);
|
||||
SubscribeLocalEvent<ItemSizeChangedEvent>(OnItemSizeChanged);
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.OpenBackpack, InputCmdHandler.FromDelegate(HandleOpenBackpack, handle: false))
|
||||
@@ -173,6 +174,21 @@ public abstract class SharedStorageSystem : EntitySystem
|
||||
UpdatePrototypeCache();
|
||||
}
|
||||
|
||||
private void OnItemSizeChanged(ref ItemSizeChangedEvent ev)
|
||||
{
|
||||
var itemEnt = new Entity<ItemComponent?>(ev.Entity, null);
|
||||
|
||||
if (!TryGetStorageLocation(itemEnt, out var container, out var storage, out var loc))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ItemFitsInGridLocation((itemEnt.Owner, itemEnt.Comp), (container.Owner, storage), loc))
|
||||
{
|
||||
ContainerSystem.Remove(itemEnt.Owner, container, force: true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNestedStorageCvar(bool obj)
|
||||
{
|
||||
NestedStorage = obj;
|
||||
@@ -322,6 +338,25 @@ public abstract class SharedStorageSystem : EntitySystem
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the storage location of an item.
|
||||
/// </summary>
|
||||
public bool TryGetStorageLocation(Entity<ItemComponent?> itemEnt, [NotNullWhen(true)] out BaseContainer? container, out StorageComponent? storage, out ItemStorageLocation loc)
|
||||
{
|
||||
loc = default;
|
||||
storage = null;
|
||||
|
||||
if (!ContainerSystem.TryGetContainingContainer(itemEnt, out container) ||
|
||||
!TryComp(container.Owner, out storage) ||
|
||||
!_itemQuery.Resolve(itemEnt, ref itemEnt.Comp, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
loc = storage.StoredItems[itemEnt];
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OpenStorageUI(EntityUid uid, EntityUid actor, StorageComponent? storageComp = null, bool silent = true)
|
||||
{
|
||||
// Handle recursively opening nested storages.
|
||||
@@ -719,14 +754,23 @@ public abstract class SharedStorageSystem : EntitySystem
|
||||
|
||||
private void OnStorageTransfer(StorageTransferItemEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (!TryGetEntity(msg.ItemEnt, out var itemEnt))
|
||||
if (!TryGetEntity(msg.ItemEnt, out var itemUid) || !TryComp(itemUid, out ItemComponent? itemComp))
|
||||
return;
|
||||
|
||||
var localPlayer = args.SenderSession.AttachedEntity;
|
||||
var itemEnt = new Entity<ItemComponent?>(itemUid.Value, itemComp);
|
||||
|
||||
if (!TryComp(localPlayer, out HandsComponent? handsComp) || !_sharedHandsSystem.TryPickup(localPlayer.Value, itemEnt.Value, handsComp: handsComp, animate: false))
|
||||
// Validate the source storage
|
||||
if (!TryGetStorageLocation(itemEnt, out var container, out _, out _) ||
|
||||
!ValidateInput(args, GetNetEntity(container.Owner), out _, out _))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp(localPlayer, out HandsComponent? handsComp) || !_sharedHandsSystem.TryPickup(localPlayer.Value, itemEnt, handsComp: handsComp, animate: false))
|
||||
return;
|
||||
|
||||
// Validate the target storage
|
||||
if (!ValidateInput(args, msg.StorageEnt, msg.ItemEnt, out var player, out var storage, out var item, held: true))
|
||||
return;
|
||||
|
||||
@@ -1525,6 +1569,8 @@ public abstract class SharedStorageSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void HandleOpenBackpack(ICommonSession? session)
|
||||
{
|
||||
HandleToggleSlotUI(session, "back");
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
item-toggle-activate = Activate
|
||||
item-toggle-deactivate = Deactivate
|
||||
|
||||
item-toggle-size-fail = Doesn't fit.
|
||||
|
||||
Reference in New Issue
Block a user