using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Timing;
+using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Systems.Storage.Controls;
origin,
currentLocation.Rotation);
+ foreach (var locations in storageComponent.SavedLocations)
+ {
+ if (!_entity.TryGetComponent<MetaDataComponent>(currentEnt, out var meta) || meta.EntityName != locations.Key)
+ continue;
+
+ float spot = 0;
+ var marked = new List<Control>();
+
+ foreach (var location in locations.Value)
+ {
+ var shape = itemSystem.GetAdjustedItemShape(currentEnt, location);
+ var bound = shape.GetBoundingBox();
+
+ var spotFree = storageSystem.ItemFitsInGridLocation(currentEnt, StorageEntity.Value, location);
+
+ if (spotFree)
+ spot++;
+
+ for (var y = bound.Bottom; y <= bound.Top; y++)
+ {
+ for (var x = bound.Left; x <= bound.Right; x++)
+ {
+ if (TryGetBackgroundCell(x, y, out var cell) && shape.Contains(x, y) && !marked.Contains(cell))
+ {
+ marked.Add(cell);
+ cell.ModulateSelfOverride = spotFree
+ ? Color.FromHsv((0.18f, 1 / spot, 0.5f / spot + 0.5f, 1f))
+ : Color.FromHex("#2222CC");
+ }
+ }
+ }
+ }
+ }
+
var validColor = usingInHand ? Color.Goldenrod : Color.FromHex("#1E8000");
for (var y = itemBounding.Bottom; y <= itemBounding.Top; y++)
SubscribeAllEvent<StorageSetItemLocationEvent>(OnSetItemLocation);
SubscribeAllEvent<StorageInsertItemIntoLocationEvent>(OnInsertItemIntoLocation);
SubscribeAllEvent<StorageRemoveItemEvent>(OnRemoveItem);
+ SubscribeAllEvent<StorageSaveItemLocationEvent>(OnSaveItemLocation);
SubscribeLocalEvent<StorageComponent, GotReclaimedEvent>(OnReclaimed);
Grid = new List<Box2i>(component.Grid),
IsUiOpen = component.IsUiOpen,
MaxItemSize = component.MaxItemSize,
- StoredItems = storedItems
+ StoredItems = storedItems,
+ SavedLocations = component.SavedLocations
};
}
var ent = EnsureEntity<StorageComponent>(nent, uid);
component.StoredItems[ent] = location;
}
+
+ component.SavedLocations = state.SavedLocations;
}
public override void Shutdown()
InsertAt((storageEnt, storageComp), (itemEnt, null), msg.Location, out _, player, stackAutomatically: false);
}
+ // TODO: if/when someone cleans up this shitcode please make all these
+ // handlers use a shared helper for checking that the ui is open etc, thanks
+ private void OnSaveItemLocation(StorageSaveItemLocationEvent msg, EntitySessionEventArgs args)
+ {
+ if (args.SenderSession.AttachedEntity is not {} player)
+ return;
+
+ var storage = GetEntity(msg.Storage);
+ var item = GetEntity(msg.Item);
+
+ if (!TryComp<StorageComponent>(storage, out var storageComp))
+ return;
+
+ if (!_ui.TryGetUi(storage, StorageComponent.StorageUiKey.Key, out var bui) ||
+ !bui.SubscribedSessions.Contains(args.SenderSession))
+ return;
+
+ if (!Exists(item))
+ {
+ Log.Error($"Player {args.SenderSession} saved location of non-existent item {msg.Item} stored in {ToPrettyString(storage)}");
+ return;
+ }
+
+ if (!ActionBlocker.CanInteract(player, item))
+ return;
+
+ SaveItemLocation(storage, item);
+ }
+
private void OnBoundUIOpen(EntityUid uid, StorageComponent storageComp, BoundUIOpenedEvent args)
{
if (!storageComp.IsUiOpen)
if (!Resolve(storageEnt, ref storageEnt.Comp) || !Resolve(itemEnt, ref itemEnt.Comp))
return false;
+ // if the item has an available saved location, use that
+ if (FindSavedLocation(storageEnt, itemEnt, out storageLocation))
+ return true;
+
var storageBounding = storageEnt.Comp.Grid.GetBoundingBox();
Angle startAngle;
return false;
}
+ /// <summary>
+ /// Tries to find a saved location for an item from its name.
+ /// If none are saved or they are all blocked nothing is returned.
+ /// </summary>
+ public bool FindSavedLocation(
+ Entity<StorageComponent?> ent,
+ Entity<ItemComponent?> item,
+ [NotNullWhen(true)] out ItemStorageLocation? storageLocation)
+ {
+ storageLocation = null;
+ if (!Resolve(ent, ref ent.Comp))
+ return false;
+
+ var name = Name(item);
+ if (!ent.Comp.SavedLocations.TryGetValue(name, out var list))
+ return false;
+
+ foreach (var location in list)
+ {
+ if (ItemFitsInGridLocation(item, ent, location))
+ {
+ storageLocation = location;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Saves an item's location in the grid for later insertion to use.
+ /// </summary>
+ public void SaveItemLocation(Entity<StorageComponent?> ent, Entity<MetaDataComponent?> item)
+ {
+ if (!Resolve(ent, ref ent.Comp))
+ return;
+
+ // needs to actually be stored in it somewhere to save it
+ if (!ent.Comp.StoredItems.TryGetValue(item, out var location))
+ return;
+
+ var name = Name(item, item.Comp);
+ if (ent.Comp.SavedLocations.TryGetValue(name, out var list))
+ {
+ // iterate to make sure its not already been saved
+ for (int i = 0; i < list.Count; i++)
+ {
+ var saved = list[i];
+
+ if (saved == location)
+ {
+ list.Remove(location);
+ return;
+ }
+ }
+
+ list.Add(location);
+ }
+ else
+ {
+ list = new List<ItemStorageLocation>()
+ {
+ location
+ };
+ ent.Comp.SavedLocations[name] = list;
+ }
+
+ Dirty(ent, ent.Comp);
+ }
+
/// <summary>
/// Checks if an item fits into a specific spot on a storage grid.
/// </summary>
public Dictionary<NetEntity, ItemStorageLocation> StoredItems = new();
+ public Dictionary<string, List<ItemStorageLocation>> SavedLocations = new();
+
public List<Box2i> Grid = new();
public ProtoId<ItemSizePrototype>? MaxItemSize;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public Dictionary<EntityUid, ItemStorageLocation> StoredItems = new();
+ /// <summary>
+ /// A dictionary storing each saved item to its location in the grid.
+ /// When trying to quick insert an item, if there is an empty location with the same name it will be placed there.
+ /// Multiple items with the same name can be saved, they will be checked individually.
+ /// </summary>
+ [DataField]
+ public Dictionary<string, List<ItemStorageLocation>> SavedLocations = new();
+
/// <summary>
/// A list of boxes that comprise a combined grid that determines the location that items can be stored.
/// </summary>
}
}
+ [Serializable, NetSerializable]
+ public sealed class StorageSaveItemLocationEvent : EntityEventArgs
+ {
+ public readonly NetEntity Item;
+
+ public readonly NetEntity Storage;
+
+ public StorageSaveItemLocationEvent(NetEntity item, NetEntity storage)
+ {
+ Item = item;
+ Storage = storage;
+ }
+ }
+
/// <summary>
/// Network event for displaying an animation of entities flying into a storage entity