get that crap outta here (completely rewrites inventorysystem) (#5807)

* some work

* equip: done
unequip: todo

* unequipping done & refactored events

* workin

* movin

* reee namespaces

* stun

* mobstate

* fixes

* some work on events

* removes serverside itemcomp & misc fixes

* work

* smol merge fix

* ports template to prototype & finishes ui

* moves relay & adds containerenumerator

* actions & cuffs

* my god what is actioncode

* more fixes

* im loosing my grasp on reality

* more fixes

* more work

* explosions

* yes

* more work

* more fixes

* merge master & misc fixed because i forgot to commit before merging master

* more fixes

* fixes

* moar

* more work

* moar fixes

* suffixmap

* more work on client

* motivation low

* no. no containers

* mirroring client to server

* fixes

* move serverinvcomp

* serverinventorycomponent is dead

* gaming

* only strippable & ai left...

* only ai and richtext left

* fixes ai

* fixes

* fixes sprite layers

* more fixes

* resolves optional

* yes

* stable™️

* fixes

* moar fixes

* moar

* fix some tests

* lmao

* no comment

* good to merge™️

* fixes build but for real

* adresses some reviews

* adresses some more reviews

* nullables, yo

* fixes lobbyscreen

* timid refactor to differentiate actor & target

* adresses more reviews

* more

* my god what a mess

* removed the rest of duplicates

* removed duplicate slotflags and renamed shoes to feet

* removes another unused one

* yes

* fixes lobby & makes tryunequip return unequipped item

* fixes

* some funny renames

* fixes

* misc improvements to attemptevents

* fixes

* merge fixes

Co-authored-by: Paul Ritter <ritter.paul1@gmail.com>
This commit is contained in:
Paul Ritter
2021-12-30 22:56:10 +01:00
committed by GitHub
parent 7a5adb47a1
commit 512d6a38c3
199 changed files with 2493 additions and 3300 deletions

View File

@@ -4,6 +4,7 @@ using Content.Client.Stylesheets;
using Content.Shared.Actions;
using Content.Shared.Actions.Components;
using Content.Shared.Actions.Prototypes;
using Content.Shared.Inventory;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
@@ -231,7 +232,7 @@ namespace Content.Client.Actions.UI
{
ActionPrototype actionPrototype => new ActionAttempt(actionPrototype),
ItemActionPrototype itemActionPrototype =>
(Item != null && IoCManager.Resolve<IEntityManager>().TryGetComponent<ItemActionsComponent?>(Item, out var itemActions)) ?
Item.HasValue && IoCManager.Resolve<IEntityManager>().TryGetComponent<ItemActionsComponent?>(Item, out var itemActions) ?
new ItemActionAttempt(itemActionPrototype, Item.Value, itemActions) : null,
_ => null
};

View File

@@ -1,14 +1,7 @@
using Content.Client.Inventory;
using Content.Client.Items.Components;
using Content.Shared.Clothing;
using Content.Shared.Inventory;
using Content.Shared.Item;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
@@ -20,85 +13,11 @@ namespace Content.Client.Clothing
[NetworkedComponent()]
public class ClothingComponent : ItemComponent
{
[DataField("femaleMask")]
private FemaleClothingMask _femaleMask = FemaleClothingMask.UniformFull;
public override string Name => "Clothing";
private string? _clothingEquippedPrefix;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("ClothingPrefix")]
public string? ClothingEquippedPrefix
{
get => _clothingEquippedPrefix;
set
{
if (_clothingEquippedPrefix == value)
return;
_clothingEquippedPrefix = value;
if(!Initialized) return;
if (!Owner.TryGetContainer(out IContainer? container))
return;
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(container.Owner, out ClientInventoryComponent? inventory))
return;
if (!inventory.TryFindItemSlots(Owner, out EquipmentSlotDefines.Slots? slots))
return;
inventory.SetSlotVisuals(slots.Value, Owner);
}
}
protected override void Initialize()
{
base.Initialize();
ClothingEquippedPrefix = ClothingEquippedPrefix;
}
[ViewVariables(VVAccess.ReadWrite)]
public FemaleClothingMask FemaleMask
{
get => _femaleMask;
set => _femaleMask = value;
}
public (RSI rsi, RSI.StateId stateId)? GetEquippedStateInfo(EquipmentSlotDefines.SlotFlags slot, string? speciesId=null)
{
if (RsiPath == null)
return null;
var rsi = IoCManager.Resolve<IResourceCache>().GetResource<RSIResource>(SharedSpriteComponent.TextureRoot / RsiPath).RSI;
var prefix = ClothingEquippedPrefix ?? EquippedPrefix;
var stateId = prefix != null ? $"{prefix}-equipped-{slot}" : $"equipped-{slot}";
if (speciesId != null)
{
var speciesState = $"{stateId}-{speciesId}";
if (rsi.TryGetState(speciesState, out _))
{
return (rsi, speciesState);
}
}
if (rsi.TryGetState(stateId, out _))
{
return (rsi, stateId);
}
return null;
}
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{
if (curState is not ClothingComponentState state)
{
return;
}
ClothingEquippedPrefix = state.ClothingEquippedPrefix;
EquippedPrefix = state.EquippedPrefix;
}
[DataField("femaleMask")]
public FemaleClothingMask FemaleMask { get; } = FemaleClothingMask.UniformFull;
}
public enum FemaleClothingMask : byte

View File

@@ -0,0 +1,162 @@
using System.Collections.Generic;
using Content.Client.Inventory;
using Content.Shared.CharacterAppearance;
using Content.Shared.Clothing;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
namespace Content.Client.Clothing;
public class ClothingSystem : EntitySystem
{
/// <summary>
/// This is a shitty hotfix written by me (Paul) to save me from renaming all files.
/// For some context, im currently refactoring inventory. Part of that is slots not being indexed by a massive enum anymore, but by strings.
/// Problem here: Every rsi-state is using the old enum-names in their state. I already used the new inventoryslots ALOT. tldr: its this or another week of renaming files.
/// </summary>
private static readonly Dictionary<string, string> TemporarySlotMap = new()
{
{"head", "HELMET"},
{"eyes", "EYES"},
{"ears", "EARS"},
{"mask", "MASK"},
{"outerClothing", "OUTERCLOTHING"},
{"jumpsuit", "INNERCLOTHING"},
{"neck", "NECK"},
{"back", "BACKPACK"},
{"belt", "BELT"},
{"gloves", "HAND"},
{"shoes", "FEET"},
{"id", "IDCARD"},
{"pocket1", "POCKET1"},
{"pocket2", "POCKET2"},
};
[Dependency] private IResourceCache _cache = default!;
[Dependency] private InventorySystem _inventorySystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ClothingComponent, GotEquippedEvent>(OnGotEquipped);
SubscribeLocalEvent<SpriteComponent, DidUnequipEvent>(OnDidUnequip);
}
private void OnDidUnequip(EntityUid uid, SpriteComponent component, DidUnequipEvent args)
{
component.LayerSetVisible(args.Slot, false);
}
public void InitClothing(EntityUid uid, ClientInventoryComponent? component = null, SpriteComponent? sprite = null)
{
if (!_inventorySystem.TryGetSlots(uid, out var slots, component) || !Resolve(uid, ref sprite, ref component)) return;
foreach (var slot in slots)
{
sprite.LayerMapReserveBlank(slot.Name);
if (!_inventorySystem.TryGetSlotContainer(uid, slot.Name, out var containerSlot, out _, component) ||
!containerSlot.ContainedEntity.HasValue) continue;
RenderEquipment(uid, containerSlot.ContainedEntity.Value, slot.Name, component, sprite);
}
}
private void OnGotEquipped(EntityUid uid, ClothingComponent component, GotEquippedEvent args)
{
if (!TryComp<SpriteComponent>(args.Equipee, out var sprite) || !TryComp<ClientInventoryComponent>(args.Equipee, out var invComp))
{
return;
}
var data = GetEquippedStateInfo(args.Equipment, args.Slot, invComp.SpeciesId, component);
if (data != null)
{
var (rsi, state) = data.Value;
sprite.LayerSetVisible(args.Slot, true);
sprite.LayerSetState(args.Slot, state, rsi);
sprite.LayerSetAutoAnimated(args.Slot, true);
if (args.Slot == "jumpsuit" && sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _))
{
sprite.LayerSetState(HumanoidVisualLayers.StencilMask, component.FemaleMask switch
{
FemaleClothingMask.NoMask => "female_none",
FemaleClothingMask.UniformTop => "female_top",
_ => "female_full",
});
}
return;
}
sprite.LayerSetVisible(args.Slot, false);
}
private void RenderEquipment(EntityUid uid, EntityUid equipment, string slot,
ClientInventoryComponent? inventoryComponent = null, SpriteComponent? sprite = null, ClothingComponent? clothingComponent = null)
{
if(!Resolve(uid, ref inventoryComponent, ref sprite))
return;
if (!Resolve(equipment, ref clothingComponent, false))
{
sprite.LayerSetVisible(slot, false);
return;
}
var data = GetEquippedStateInfo(equipment, slot, inventoryComponent.SpeciesId, clothingComponent);
if (data == null) return;
var (rsi, state) = data.Value;
sprite.LayerSetVisible(slot, true);
sprite.LayerSetState(slot, state, rsi);
sprite.LayerSetAutoAnimated(slot, true);
if (slot == "jumpsuit" && sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _))
{
sprite.LayerSetState(HumanoidVisualLayers.StencilMask, clothingComponent.FemaleMask switch
{
FemaleClothingMask.NoMask => "female_none",
FemaleClothingMask.UniformTop => "female_top",
_ => "female_full",
});
}
}
public (RSI rsi, RSI.StateId stateId)? GetEquippedStateInfo(EntityUid uid, string slot, string? speciesId=null, ClothingComponent? component = null)
{
if (!Resolve(uid, ref component))
return null;
if (component.RsiPath == null)
return null;
var rsi = _cache.GetResource<RSIResource>(SharedSpriteComponent.TextureRoot / component.RsiPath).RSI;
var correctedSlot = slot;
TemporarySlotMap.TryGetValue(correctedSlot, out correctedSlot);
var stateId = component.EquippedPrefix != null ? $"{component.EquippedPrefix}-equipped-{correctedSlot}" : $"equipped-{correctedSlot}";
if (speciesId != null)
{
var speciesState = $"{stateId}-{speciesId}";
if (rsi.TryGetState(speciesState, out _))
{
return (rsi, speciesState);
}
}
if (rsi.TryGetState(stateId, out _))
{
return (rsi, stateId);
}
return null;
}
}

View File

@@ -57,7 +57,6 @@ namespace Content.Client.Entry
"MagicMirror",
"FloorTile",
"ShuttleController",
"HumanInventoryController",
"RandomInsulation",
"Electrified",
"Electrocution",

View File

@@ -1,4 +1,5 @@
using Content.Client.Items.UI;
using Content.Client.HUD;
using Content.Client.Items.UI;
using Content.Shared.Hands.Components;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
@@ -10,7 +11,7 @@ namespace Content.Client.Hands
private bool _activeHand;
private bool _highlighted;
public HandButton(Texture texture, Texture storageTexture, string textureName, Texture blockedTexture, HandLocation location) : base(texture, storageTexture, textureName)
public HandButton(int size, string textureName, string storageTextureName, IGameHud gameHud, Texture blockedTexture, HandLocation location) : base(size, textureName, storageTextureName, gameHud)
{
Location = location;

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Content.Client.HUD;
using Content.Client.Inventory;
using Content.Client.Items.Managers;
using Content.Client.Items.UI;
using Content.Client.Resources;
@@ -32,7 +33,7 @@ namespace Content.Client.Hands
private readonly HandsSystem _handsSystem;
private readonly HandsComponent _handsComponent;
private Texture StorageTexture => _gameHud.GetHudTexture("back.png");
private string StorageTexture => "back.png";
private Texture BlockedTexture => _resourceCache.GetTexture("/Textures/Interface/Inventory/blocked.png");
private ItemStatusPanel StatusPanel { get; }
@@ -166,9 +167,8 @@ namespace Content.Client.Hands
HandLocation.Right => "hand_r.png",
_ => "hand_l.png"
};
var buttonTexture = _gameHud.GetHudTexture(buttonTextureName);
return new HandButton(buttonTexture, StorageTexture, buttonTextureName, BlockedTexture, buttonLocation);
return new HandButton(ClientInventorySystem.ButtonSize, buttonTextureName, StorageTexture, _gameHud, BlockedTexture, buttonLocation);
}
private void UpdateHudTheme(int idx)

View File

@@ -1,17 +1,13 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Client.Clothing;
using Content.Shared.CharacterAppearance;
using Content.Client.Items.UI;
using Content.Shared.Inventory;
using Content.Shared.Movement.EntitySystems;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
using static Content.Shared.Inventory.EquipmentSlotDefines;
using static Content.Shared.Inventory.SharedInventoryComponent.ClientInventoryMessage;
namespace Content.Client.Inventory
{
@@ -19,242 +15,21 @@ namespace Content.Client.Inventory
/// A character UI which shows items the user has equipped within his inventory
/// </summary>
[RegisterComponent]
[ComponentReference(typeof(SharedInventoryComponent))]
public class ClientInventoryComponent : SharedInventoryComponent
[ComponentReference(typeof(InventoryComponent))]
[Friend(typeof(ClientInventorySystem))]
public class ClientInventoryComponent : InventoryComponent
{
[Dependency] private readonly IEntityManager _entMan = default!;
public Control BottomLeftButtons = default!;
public Control BottomRightButtons = default!;
public Control TopQuickButtons = default!;
private readonly Dictionary<Slots, EntityUid> _slots = new();
public SS14Window InventoryWindow = default!;
public IReadOnlyDictionary<Slots, EntityUid> AllSlots => _slots;
[ViewVariables] public InventoryInterfaceController InterfaceController { get; private set; } = default!;
[ComponentDependency]
private ISpriteComponent? _sprite;
private bool _playerAttached = false;
public readonly Dictionary<string, List<ItemSlotButton>> SlotButtons = new();
[ViewVariables]
[DataField("speciesId")] public string? SpeciesId { get; set; }
protected override void OnRemove()
{
base.OnRemove();
if (_playerAttached)
{
InterfaceController?.PlayerDetached();
}
InterfaceController?.Dispose();
}
protected override void Initialize()
{
base.Initialize();
var controllerType = ReflectionManager.LooseGetType(InventoryInstance.InterfaceControllerTypeName);
var args = new object[] {this};
InterfaceController = DynamicTypeFactory.CreateInstance<InventoryInterfaceController>(controllerType, args);
InterfaceController.Initialize();
if (_sprite != null)
{
foreach (var mask in InventoryInstance.SlotMasks.OrderBy(s => InventoryInstance.SlotDrawingOrder(s)))
{
if (mask == Slots.NONE)
{
continue;
}
_sprite.LayerMapReserveBlank(mask);
}
}
// Component state already came in but we couldn't set anything visually because, well, we didn't initialize yet.
foreach (var (slot, entity) in _slots)
{
_setSlot(slot, entity);
}
}
public override bool IsEquipped(EntityUid item)
{
return item != default && _slots.Values.Any(e => e == item);
}
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{
base.HandleComponentState(curState, nextState);
if (curState is not InventoryComponentState state)
return;
var doneSlots = new HashSet<Slots>();
foreach (var (slot, entity) in state.Entities)
{
if (!_entMan.EntityExists(entity))
{
continue;
}
if (!_slots.ContainsKey(slot) || _slots[slot] != entity)
{
_slots[slot] = entity;
_setSlot(slot, entity);
}
doneSlots.Add(slot);
}
if (state.HoverEntity != null)
{
var (slot, (entity, fits)) = state.HoverEntity.Value;
InterfaceController?.HoverInSlot(slot, entity, fits);
}
foreach (var slot in _slots.Keys.ToList())
{
if (!doneSlots.Contains(slot))
{
_clearSlot(slot);
_slots.Remove(slot);
}
}
EntitySystem.Get<MovementSpeedModifierSystem>().RefreshMovementSpeedModifiers(Owner);
}
private void _setSlot(Slots slot, EntityUid entity)
{
SetSlotVisuals(slot, entity);
InterfaceController?.AddToSlot(slot, entity);
}
internal void SetSlotVisuals(Slots slot, EntityUid entity)
{
if (_sprite == null)
{
return;
}
if (_entMan.TryGetComponent(entity, out ClothingComponent? clothing))
{
var flag = SlotMasks[slot];
var data = clothing.GetEquippedStateInfo(flag, SpeciesId);
if (data != null)
{
var (rsi, state) = data.Value;
_sprite.LayerSetVisible(slot, true);
_sprite.LayerSetState(slot, state, rsi);
_sprite.LayerSetAutoAnimated(slot, true);
if (slot == Slots.INNERCLOTHING && _sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _))
{
_sprite.LayerSetState(HumanoidVisualLayers.StencilMask, clothing.FemaleMask switch
{
FemaleClothingMask.NoMask => "female_none",
FemaleClothingMask.UniformTop => "female_top",
_ => "female_full",
});
}
return;
}
}
_sprite.LayerSetVisible(slot, false);
}
internal void ClearAllSlotVisuals()
{
if (_sprite == null)
return;
foreach (var slot in InventoryInstance.SlotMasks)
{
if (slot != Slots.NONE)
{
_sprite.LayerSetVisible(slot, false);
}
}
}
private void _clearSlot(Slots slot)
{
InterfaceController?.RemoveFromSlot(slot);
_sprite?.LayerSetVisible(slot, false);
}
public void SendEquipMessage(Slots slot)
{
var equipMessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Equip);
#pragma warning disable 618
SendNetworkMessage(equipMessage);
#pragma warning restore 618
}
public void SendUseMessage(Slots slot)
{
var equipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Use);
#pragma warning disable 618
SendNetworkMessage(equipmessage);
#pragma warning restore 618
}
public void SendHoverMessage(Slots slot)
{
#pragma warning disable 618
SendNetworkMessage(new ClientInventoryMessage(slot, ClientInventoryUpdate.Hover));
#pragma warning restore 618
}
public void SendOpenStorageUIMessage(Slots slot)
{
#pragma warning disable 618
SendNetworkMessage(new OpenSlotStorageUIMessage(slot));
#pragma warning restore 618
}
public void PlayerDetached()
{
InterfaceController.PlayerDetached();
_playerAttached = false;
}
public void PlayerAttached()
{
InterfaceController.PlayerAttached();
_playerAttached = true;
}
public override bool TryGetSlot(Slots slot, [NotNullWhen(true)] out EntityUid? item)
{
// dict TryGetValue uses default EntityUid, not null.
if (!_slots.ContainsKey(slot))
{
item = null;
return false;
}
item = _slots[slot];
return item != null;
}
public bool TryFindItemSlots(EntityUid item, [NotNullWhen(true)] out Slots? slots)
{
slots = null;
foreach (var (slot, entity) in _slots)
{
if (entity == item)
{
slots = slot;
return true;
}
}
return false;
}
public bool AttachedToGameHud;
}
}

View File

@@ -1,20 +1,52 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Content.Client.Clothing;
using Content.Client.HUD;
using Content.Shared.Input;
using Content.Client.Items.Managers;
using Content.Client.Items.UI;
using Content.Shared.CCVar;
using Content.Shared.Hands.Components;
using Content.Shared.Inventory;
using Content.Shared.Movement.EntitySystems;
using Content.Shared.Slippery;
using Content.Shared.Inventory.Events;
using Content.Shared.Item;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.Client.Inventory
{
[UsedImplicitly]
public sealed class ClientInventorySystem : EntitySystem
public sealed class ClientInventorySystem : InventorySystem
{
[Dependency] private readonly IGameHud _gameHud = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IConfigurationManager _config = default!;
[Dependency] private readonly IItemSlotManager _itemSlotManager = default!;
[Dependency] private readonly ClothingSystem _clothingSystem = default!;
public const int ButtonSize = 64;
private const int ButtonSeparation = 4;
private const int RightSeparation = 2;
/// <summary>
/// Stores delegates used to create controls for a given <see cref="InventoryTemplatePrototype"/>.
/// </summary>
private readonly
Dictionary<string, Func<EntityUid, Dictionary<string, List<ItemSlotButton>>, (SS14Window window, Control bottomLeft, Control bottomRight, Control
topQuick)>>
_uiGenerateDelegates = new();
public override void Initialize()
{
@@ -25,29 +57,96 @@ namespace Content.Client.Inventory
InputCmdHandler.FromDelegate(_ => HandleOpenInventoryMenu()))
.Register<ClientInventorySystem>();
SubscribeLocalEvent<ClientInventoryComponent, PlayerAttachedEvent>((_, component, _) => component.PlayerAttached());
SubscribeLocalEvent<ClientInventoryComponent, PlayerDetachedEvent>((_, component, _) => component.PlayerDetached());
SubscribeLocalEvent<ClientInventoryComponent, PlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<ClientInventoryComponent, PlayerDetachedEvent>(OnPlayerDetached);
SubscribeLocalEvent<ClientInventoryComponent, SlipAttemptEvent>(OnSlipAttemptEvent);
SubscribeLocalEvent<ClientInventoryComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
SubscribeLocalEvent<ClientInventoryComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<ClientInventoryComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<ClientInventoryComponent, DidEquipEvent>(OnDidEquip);
SubscribeLocalEvent<ClientInventoryComponent, DidUnequipEvent>(OnDidUnequip);
_config.OnValueChanged(CCVars.HudTheme, UpdateHudTheme);
}
// jesus christ, this is duplicated to server/client, should really just be shared..
private void OnSlipAttemptEvent(EntityUid uid, ClientInventoryComponent component, SlipAttemptEvent args)
public override bool TryEquip(EntityUid actor, EntityUid target, EntityUid itemUid, string slot, bool silent = false, bool force = false,
InventoryComponent? inventory = null, SharedItemComponent? item = null)
{
if (component.TryGetSlot(EquipmentSlotDefines.Slots.SHOES, out EntityUid? shoes))
if(!target.IsClientSide() && !actor.IsClientSide() && !itemUid.IsClientSide()) RaiseNetworkEvent(new TryEquipNetworkMessage(actor, target, itemUid, slot, silent, force));
return base.TryEquip(actor, target, itemUid, slot, silent, force, inventory, item);
}
public override bool TryUnequip(EntityUid actor, EntityUid target, string slot, [NotNullWhen(true)] out EntityUid? removedItem, bool silent = false, bool force = false,
InventoryComponent? inventory = null)
{
RaiseLocalEvent(shoes.Value, args, false);
if(!target.IsClientSide() && !actor.IsClientSide()) RaiseNetworkEvent(new TryUnequipNetworkMessage(actor, target, slot, silent, force));
return base.TryUnequip(actor, target, slot, out removedItem, silent, force, inventory);
}
private void OnDidUnequip(EntityUid uid, ClientInventoryComponent component, DidUnequipEvent args)
{
if (component.SlotButtons.TryGetValue(args.Slot, out var buttons))
{
foreach (var button in buttons)
{
_itemSlotManager.SetItemSlot(button, null);
}
}
}
private void OnRefreshMovespeed(EntityUid uid, ClientInventoryComponent component, RefreshMovementSpeedModifiersEvent args)
private void OnDidEquip(EntityUid uid, ClientInventoryComponent component, DidEquipEvent args)
{
foreach (var (_, ent) in component.AllSlots)
if (component.SlotButtons.TryGetValue(args.Slot, out var buttons))
{
if (ent != default)
foreach (var button in buttons)
{
RaiseLocalEvent(ent, args, false);
_itemSlotManager.SetItemSlot(button, args.Equipment);
}
}
}
private void OnPlayerDetached(EntityUid uid, ClientInventoryComponent component, PlayerDetachedEvent? args = null)
{
if(!component.AttachedToGameHud) return;
_gameHud.InventoryButtonVisible = false;
_gameHud.BottomLeftInventoryQuickButtonContainer.RemoveChild(component.BottomLeftButtons);
_gameHud.BottomRightInventoryQuickButtonContainer.RemoveChild(component.BottomRightButtons);
_gameHud.TopInventoryQuickButtonContainer.RemoveChild(component.TopQuickButtons);
component.AttachedToGameHud = false;
}
private void OnShutdown(EntityUid uid, ClientInventoryComponent component, ComponentShutdown args)
{
OnPlayerDetached(uid, component);
}
private void OnPlayerAttached(EntityUid uid, ClientInventoryComponent component, PlayerAttachedEvent args)
{
if(component.AttachedToGameHud) return;
_gameHud.InventoryButtonVisible = true;
_gameHud.BottomLeftInventoryQuickButtonContainer.AddChild(component.BottomLeftButtons);
_gameHud.BottomRightInventoryQuickButtonContainer.AddChild(component.BottomRightButtons);
_gameHud.TopInventoryQuickButtonContainer.AddChild(component.TopQuickButtons);
component.AttachedToGameHud = true;
}
private void UpdateHudTheme(int obj)
{
if (!_gameHud.ValidateHudTheme(obj))
{
return;
}
foreach (var inventoryComponent in EntityManager.EntityQuery<ClientInventoryComponent>(true))
{
foreach (var slotButton in inventoryComponent.SlotButtons)
{
foreach (var btn in slotButton.Value)
{
btn.RefreshTextures(_gameHud);
}
}
}
}
@@ -55,9 +154,183 @@ namespace Content.Client.Inventory
public override void Shutdown()
{
CommandBinds.Unregister<ClientInventorySystem>();
_config.UnsubValueChanged(CCVars.HudTheme, UpdateHudTheme);
base.Shutdown();
}
private void OnInit(EntityUid uid, ClientInventoryComponent component, ComponentInit args)
{
_clothingSystem.InitClothing(uid, component);
if (!TryGetUIElements(uid, out var window, out var bottomLeft, out var bottomRight, out var topQuick,
component))
return;
component.InventoryWindow = window;
component.BottomLeftButtons = bottomLeft;
component.BottomRightButtons = bottomRight;
component.TopQuickButtons = topQuick;
}
private void HoverInSlotButton(EntityUid uid, string slot, ItemSlotButton button, InventoryComponent? inventoryComponent = null, SharedHandsComponent? hands = null)
{
if (!Resolve(uid, ref inventoryComponent))
return;
if (!Resolve(uid, ref hands, false))
return;
if (!hands.TryGetActiveHeldEntity(out var heldEntity))
return;
if(!TryGetSlotContainer(uid, slot, out var containerSlot, out var slotDef, inventoryComponent))
return;
_itemSlotManager.HoverInSlot(button, heldEntity,
CanEquip(uid, heldEntity, slot, out _, slotDef, inventoryComponent) &&
containerSlot.CanInsert(heldEntity, EntityManager));
}
private void HandleSlotButtonPressed(EntityUid uid, string slot, ItemSlotButton button,
GUIBoundKeyEventArgs args)
{
if (TryGetSlotEntity(uid, slot, out var itemUid))
{
if (!_itemSlotManager.OnButtonPressed(args, itemUid.Value) && args.Function == EngineKeyFunctions.UIClick)
{
RaiseNetworkEvent(new UseSlotNetworkMessage(uid, slot));
}
return;
}
if (args.Function != EngineKeyFunctions.UIClick) return;
TryEquipActiveHandTo(uid, slot);
}
private bool TryGetUIElements(EntityUid uid, [NotNullWhen(true)] out SS14Window? invWindow,
[NotNullWhen(true)] out Control? invBottomLeft, [NotNullWhen(true)] out Control? invBottomRight,
[NotNullWhen(true)] out Control? invTopQuick, ClientInventoryComponent? component = null)
{
invWindow = null;
invBottomLeft = null;
invBottomRight = null;
invTopQuick = null;
if (!Resolve(uid, ref component))
return false;
if(!_prototypeManager.TryIndex<InventoryTemplatePrototype>(component.TemplateId, out var template))
return false;
if (!_uiGenerateDelegates.TryGetValue(component.TemplateId, out var genfunc))
{
_uiGenerateDelegates[component.TemplateId] = genfunc = (entityUid, list) =>
{
var window = new SS14Window()
{
Title = Loc.GetString("human-inventory-window-title"),
Resizable = false
};
window.OnClose += () => _gameHud.InventoryButtonDown = false;
var windowContents = new LayoutContainer
{
MinSize = (ButtonSize * 4 + ButtonSeparation * 3 + RightSeparation,
ButtonSize * 4 + ButtonSeparation * 3)
};
window.Contents.AddChild(windowContents);
ItemSlotButton GetButton(SlotDefinition definition, string textureBack)
{
var btn = new ItemSlotButton(ButtonSize, $"{definition.TextureName}.png", textureBack,
_gameHud)
{
OnStoragePressed = (e) =>
{
if (e.Function != EngineKeyFunctions.UIClick &&
e.Function != ContentKeyFunctions.ActivateItemInWorld)
return;
RaiseNetworkEvent(new OpenSlotStorageNetworkMessage(entityUid, definition.Name));
}
};
btn.OnHover = (_) =>
{
HoverInSlotButton(entityUid, definition.Name, btn);
};
btn.OnPressed = (e) =>
{
HandleSlotButtonPressed(entityUid, definition.Name, btn, e);
};
return btn;
}
void AddButton(SlotDefinition definition, Vector2i position)
{
var button = GetButton(definition, "back.png");
LayoutContainer.SetPosition(button, position);
windowContents.AddChild(button);
if (!list.ContainsKey(definition.Name))
list[definition.Name] = new();
list[definition.Name].Add(button);
}
void AddHUDButton(BoxContainer container, SlotDefinition definition)
{
var button = GetButton(definition, "back.png");
container.AddChild(button);
if (!list.ContainsKey(definition.Name))
list[definition.Name] = new();
list[definition.Name].Add(button);
}
var topQuick = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
SeparationOverride = 5
};
var bottomRight = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
SeparationOverride = 5
};
var bottomLeft = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
SeparationOverride = 5
};
const int sizep = (ButtonSize + ButtonSeparation);
foreach (var slotDefinition in template.Slots)
{
switch (slotDefinition.UIContainer)
{
case SlotUIContainer.BottomLeft:
AddHUDButton(bottomLeft, slotDefinition);
break;
case SlotUIContainer.BottomRight:
AddHUDButton(bottomRight, slotDefinition);
break;
case SlotUIContainer.Top:
AddHUDButton(topQuick, slotDefinition);
break;
}
AddButton(slotDefinition, slotDefinition.UIWindowPosition * sizep);
}
return (window, bottomLeft, bottomRight, topQuick);
};
}
var res = genfunc(uid, component.SlotButtons);
invWindow = res.window;
invBottomLeft = res.bottomLeft;
invBottomRight = res.bottomRight;
invTopQuick = res.topQuick;
return true;
}
private void HandleOpenInventoryMenu()
{
_gameHud.InventoryButtonDown = !_gameHud.InventoryButtonDown;

View File

@@ -1,334 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Content.Client.HUD;
using Content.Client.Items.Managers;
using Content.Client.Items.UI;
using Content.Shared.CCVar;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using static Content.Shared.Inventory.EquipmentSlotDefines;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Content.Client.Inventory
{
// Dynamically instantiated by ClientInventoryComponent.
[UsedImplicitly]
public class HumanInventoryInterfaceController : InventoryInterfaceController
{
[Dependency] private readonly IGameHud _gameHud = default!;
[Dependency] private readonly IItemSlotManager _itemSlotManager = default!;
[Dependency] private readonly INetConfigurationManager _configManager = default!;
private readonly Dictionary<Slots, List<ItemSlotButton>> _inventoryButtons
= new();
private ItemSlotButton _hudButtonPocket1 = default!;
private ItemSlotButton _hudButtonPocket2 = default!;
private ItemSlotButton _hudButtonShoes = default!;
private ItemSlotButton _hudButtonJumpsuit = default!;
private ItemSlotButton _hudButtonGloves = default!;
private ItemSlotButton _hudButtonNeck = default!;
private ItemSlotButton _hudButtonHead = default!;
private ItemSlotButton _hudButtonBelt = default!;
private ItemSlotButton _hudButtonBack = default!;
private ItemSlotButton _hudButtonOClothing = default!;
private ItemSlotButton _hudButtonId = default!;
private ItemSlotButton _hudButtonMask = default!;
private ItemSlotButton _hudButtonEyes = default!;
private ItemSlotButton _hudButtonEars = default!;
private Control _topQuickButtonsContainer = default!;
private Control _bottomLeftQuickButtonsContainer = default!;
private Control _bottomRightQuickButtonsContainer = default!;
public HumanInventoryInterfaceController(ClientInventoryComponent owner) : base(owner)
{
}
public override void Initialize()
{
base.Initialize();
_configManager.OnValueChanged(CCVars.HudTheme, UpdateHudTheme, invokeImmediately: true);
_window = new HumanInventoryWindow(_gameHud);
_window.OnClose += () => GameHud.InventoryButtonDown = false;
foreach (var (slot, button) in _window.Buttons)
{
button.OnPressed = (e) => AddToInventory(e, slot);
button.OnStoragePressed = (e) => OpenStorage(e, slot);
button.OnHover = (_) => RequestItemHover(slot);
_inventoryButtons.Add(slot, new List<ItemSlotButton> {button});
}
void AddButton(out ItemSlotButton variable, Slots slot, string textureName)
{
var texture = _gameHud.GetHudTexture($"{textureName}.png");
var storageTexture = _gameHud.GetHudTexture("back.png");
variable = new ItemSlotButton(texture, storageTexture, textureName)
{
OnPressed = (e) => AddToInventory(e, slot),
OnStoragePressed = (e) => OpenStorage(e, slot),
OnHover = (_) => RequestItemHover(slot)
};
_inventoryButtons[slot].Add(variable);
}
AddButton(out _hudButtonPocket1, Slots.POCKET1, "pocket");
AddButton(out _hudButtonPocket2, Slots.POCKET2, "pocket");
AddButton(out _hudButtonId, Slots.IDCARD, "id");
AddButton(out _hudButtonBack, Slots.BACKPACK, "back");
AddButton(out _hudButtonBelt, Slots.BELT, "belt");
AddButton(out _hudButtonShoes, Slots.SHOES, "shoes");
AddButton(out _hudButtonJumpsuit, Slots.INNERCLOTHING, "uniform");
AddButton(out _hudButtonOClothing, Slots.OUTERCLOTHING, "suit");
AddButton(out _hudButtonGloves, Slots.GLOVES, "gloves");
AddButton(out _hudButtonNeck, Slots.NECK, "neck");
AddButton(out _hudButtonMask, Slots.MASK, "mask");
AddButton(out _hudButtonEyes, Slots.EYES, "glasses");
AddButton(out _hudButtonEars, Slots.EARS, "ears");
AddButton(out _hudButtonHead, Slots.HEAD, "head");
_topQuickButtonsContainer = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
_hudButtonShoes,
_hudButtonJumpsuit,
_hudButtonOClothing,
_hudButtonGloves,
_hudButtonNeck,
_hudButtonMask,
_hudButtonEyes,
_hudButtonEars,
_hudButtonHead
},
SeparationOverride = 5
};
_bottomRightQuickButtonsContainer = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
_hudButtonPocket1,
_hudButtonPocket2,
_hudButtonId,
},
SeparationOverride = 5
};
_bottomLeftQuickButtonsContainer = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
_hudButtonBelt,
_hudButtonBack
},
SeparationOverride = 5
};
}
public override SS14Window? Window => _window;
private HumanInventoryWindow? _window;
public override IEnumerable<ItemSlotButton> GetItemSlotButtons(Slots slot)
{
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
{
return Enumerable.Empty<ItemSlotButton>();
}
return buttons;
}
public override void AddToSlot(Slots slot, EntityUid entity)
{
base.AddToSlot(slot, entity);
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
return;
foreach (var button in buttons)
{
_itemSlotManager.SetItemSlot(button, entity);
button.OnPressed = (e) => HandleInventoryKeybind(e, slot);
}
}
public override void RemoveFromSlot(Slots slot)
{
base.RemoveFromSlot(slot);
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
{
return;
}
foreach (var button in buttons)
{
ClearButton(button, slot);
}
}
public override void HoverInSlot(Slots slot, EntityUid entity, bool fits)
{
base.HoverInSlot(slot, entity, fits);
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
{
return;
}
foreach (var button in buttons)
{
_itemSlotManager.HoverInSlot(button, entity, fits);
}
}
protected override void HandleInventoryKeybind(GUIBoundKeyEventArgs args, Slots slot)
{
if (!_inventoryButtons.ContainsKey(slot))
return;
if (!Owner.TryGetSlot(slot, out var item))
return;
if (!_itemSlotManager.OnButtonPressed(args, item.Value))
base.HandleInventoryKeybind(args, slot);
}
private void ClearButton(ItemSlotButton button, Slots slot)
{
button.OnPressed = (e) => AddToInventory(e, slot);
_itemSlotManager.SetItemSlot(button, default);
}
public override void PlayerAttached()
{
base.PlayerAttached();
GameHud.BottomLeftInventoryQuickButtonContainer.AddChild(_bottomLeftQuickButtonsContainer);
GameHud.BottomRightInventoryQuickButtonContainer.AddChild(_bottomRightQuickButtonsContainer);
GameHud.TopInventoryQuickButtonContainer.AddChild(_topQuickButtonsContainer);
// Update all the buttons to make sure they check out.
foreach (var (slot, buttons) in _inventoryButtons)
{
foreach (var button in buttons)
{
ClearButton(button, slot);
}
if (Owner.TryGetSlot(slot, out var entity))
{
AddToSlot(slot, entity.Value);
}
}
}
public override void PlayerDetached()
{
base.PlayerDetached();
GameHud.BottomRightInventoryQuickButtonContainer.RemoveChild(_bottomRightQuickButtonsContainer);
GameHud.BottomLeftInventoryQuickButtonContainer.RemoveChild(_bottomLeftQuickButtonsContainer);
GameHud.TopInventoryQuickButtonContainer.RemoveChild(_topQuickButtonsContainer);
foreach (var (slot, list) in _inventoryButtons)
{
foreach (var button in list)
{
ClearButton(button, slot);
}
}
}
public void UpdateHudTheme(int idx)
{
if (!_gameHud.ValidateHudTheme(idx))
{
return;
}
foreach (var (_, list) in _inventoryButtons)
{
foreach (var button in list)
{
button.Button.Texture = _gameHud.GetHudTexture($"{button.TextureName}.png");
button.StorageButton.TextureNormal = _gameHud.GetHudTexture("back.png");
}
}
}
private class HumanInventoryWindow : SS14Window
{
private const int ButtonSize = 64;
private const int ButtonSeparation = 4;
private const int RightSeparation = 2;
public IReadOnlyDictionary<Slots, ItemSlotButton> Buttons { get; }
public HumanInventoryWindow(IGameHud gameHud)
{
Title = Loc.GetString("human-inventory-window-title");
Resizable = false;
var buttonDict = new Dictionary<Slots, ItemSlotButton>();
Buttons = buttonDict;
const int width = ButtonSize * 4 + ButtonSeparation * 3 + RightSeparation;
const int height = ButtonSize * 4 + ButtonSeparation * 3;
var windowContents = new LayoutContainer {MinSize = (width, height)};
Contents.AddChild(windowContents);
void AddButton(Slots slot, string textureName, Vector2 position)
{
var texture = gameHud.GetHudTexture($"{textureName}.png");
var storageTexture = gameHud.GetHudTexture("back.png");
var button = new ItemSlotButton(texture, storageTexture, textureName);
LayoutContainer.SetPosition(button, position);
windowContents.AddChild(button);
buttonDict.Add(slot, button);
}
const int sizep = (ButtonSize + ButtonSeparation);
// Left column.
AddButton(Slots.EYES, "glasses", (0, 0));
AddButton(Slots.NECK, "neck", (0, sizep));
AddButton(Slots.INNERCLOTHING, "uniform", (0, 2 * sizep));
AddButton(Slots.POCKET1, "pocket", (0, 3 * sizep));
// Middle column.
AddButton(Slots.HEAD, "head", (sizep, 0));
AddButton(Slots.MASK, "mask", (sizep, sizep));
AddButton(Slots.OUTERCLOTHING, "suit", (sizep, 2 * sizep));
AddButton(Slots.SHOES, "shoes", (sizep, 3 * sizep));
// Right column
AddButton(Slots.EARS, "ears", (2 * sizep, 0));
AddButton(Slots.IDCARD, "id", (2 * sizep, sizep));
AddButton(Slots.GLOVES, "gloves", (2 * sizep, 2 * sizep));
AddButton(Slots.POCKET2, "pocket", (2 * sizep, 3 * sizep));
// Far right column.
AddButton(Slots.BACKPACK, "back", (3 * sizep, 0));
AddButton(Slots.BELT, "belt", (3 * sizep, sizep));
}
}
}
}

View File

@@ -1,99 +0,0 @@
using System;
using System.Collections.Generic;
using Content.Client.HUD;
using Content.Client.Items.UI;
using Content.Shared.Input;
using Content.Shared.Inventory;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.IoC;
namespace Content.Client.Inventory
{
public abstract class InventoryInterfaceController : IDisposable
{
[Dependency] protected readonly IGameHud GameHud = default!;
protected InventoryInterfaceController(ClientInventoryComponent owner)
{
Owner = owner;
}
public virtual void Initialize()
{
}
public abstract SS14Window? Window { get; }
protected ClientInventoryComponent Owner { get; }
public virtual void PlayerAttached()
{
GameHud.InventoryButtonVisible = true;
}
public virtual void PlayerDetached()
{
GameHud.InventoryButtonVisible = false;
}
public virtual void Dispose()
{
}
/// <returns>the button controls associated with the
/// specified slot, if any. Empty if none.</returns>
public abstract IEnumerable<ItemSlotButton> GetItemSlotButtons(EquipmentSlotDefines.Slots slot);
public virtual void AddToSlot(EquipmentSlotDefines.Slots slot, EntityUid entity)
{
}
public virtual void HoverInSlot(EquipmentSlotDefines.Slots slot, EntityUid entity, bool fits)
{
}
public virtual void RemoveFromSlot(EquipmentSlotDefines.Slots slot)
{
}
protected virtual void HandleInventoryKeybind(GUIBoundKeyEventArgs args, EquipmentSlotDefines.Slots slot)
{
if (args.Function == EngineKeyFunctions.UIClick)
{
UseItemOnInventory(slot);
}
}
protected void AddToInventory(GUIBoundKeyEventArgs args, EquipmentSlotDefines.Slots slot)
{
if (args.Function != EngineKeyFunctions.UIClick)
{
return;
}
Owner.SendEquipMessage(slot);
}
protected void UseItemOnInventory(EquipmentSlotDefines.Slots slot)
{
Owner.SendUseMessage(slot);
}
protected void OpenStorage(GUIBoundKeyEventArgs args, EquipmentSlotDefines.Slots slot)
{
if (args.Function != EngineKeyFunctions.UIClick && args.Function != ContentKeyFunctions.ActivateItemInWorld)
{
return;
}
Owner.SendOpenStorageUIMessage(slot);
}
protected void RequestItemHover(EquipmentSlotDefines.Slots slot)
{
Owner.SendHoverMessage(slot);
}
}
}

View File

@@ -7,14 +7,13 @@ using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.ViewVariables;
using static Content.Shared.Inventory.EquipmentSlotDefines;
namespace Content.Client.Inventory
{
[UsedImplicitly]
public class StrippableBoundUserInterface : BoundUserInterface
{
public Dictionary<Slots, string>? Inventory { get; private set; }
public Dictionary<(string ID, string Name), string>? Inventory { get; private set; }
public Dictionary<string, string>? Hands { get; private set; }
public Dictionary<EntityUid, string>? Handcuffs { get; private set; }
@@ -55,9 +54,9 @@ namespace Content.Client.Inventory
{
foreach (var (slot, name) in Inventory)
{
_strippingMenu.AddButton(SlotNames[slot], name, (ev) =>
_strippingMenu.AddButton(slot.Name, name, (ev) =>
{
SendMessage(new StrippingInventoryButtonPressed(slot));
SendMessage(new StrippingInventoryButtonPressed(slot.ID));
});
}
}

View File

@@ -9,10 +9,10 @@ namespace Content.Client.Items.Managers
{
bool OnButtonPressed(GUIBoundKeyEventArgs args, EntityUid item);
void UpdateCooldown(ItemSlotButton? cooldownTexture, EntityUid entity);
bool SetItemSlot(ItemSlotButton button, EntityUid entity);
bool SetItemSlot(ItemSlotButton button, EntityUid? entity);
void HoverInSlot(ItemSlotButton button, EntityUid entity, bool fits);
event Action<EntitySlotHighlightedEventArgs>? EntityHighlightedUpdated;
bool IsHighlighted(EntityUid uid);
bool IsHighlighted(EntityUid? uid);
/// <summary>
/// Highlight all slot controls that contain the specified entity.

View File

@@ -28,9 +28,9 @@ namespace Content.Client.Items.Managers
public event Action<EntitySlotHighlightedEventArgs>? EntityHighlightedUpdated;
public bool SetItemSlot(ItemSlotButton button, EntityUid entity)
public bool SetItemSlot(ItemSlotButton button, EntityUid? entity)
{
if (entity == default)
if (entity == null)
{
button.SpriteView.Sprite = null;
button.StorageButton.Visible = false;
@@ -141,9 +141,10 @@ namespace Content.Client.Items.Managers
button.HoverSpriteView.Sprite = hoverSprite;
}
public bool IsHighlighted(EntityUid uid)
public bool IsHighlighted(EntityUid? uid)
{
return _highlightEntities.Contains(uid);
if (uid == null) return false;
return _highlightEntities.Contains(uid.Value);
}
public void HighlightEntity(EntityUid uid)

View File

@@ -1,15 +1,18 @@
using System;
using Content.Client.Cooldown;
using Content.Client.HUD;
using Content.Client.Items.Managers;
using Content.Client.Stylesheets;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.Utility;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
namespace Content.Client.Items.UI
{
@@ -19,7 +22,7 @@ namespace Content.Client.Items.UI
[Dependency] private readonly IItemSlotManager _itemSlotManager = default!;
public EntityUid Entity { get; set; }
public EntityUid? Entity { get; set; }
public TextureRect Button { get; }
public SpriteView SpriteView { get; }
public SpriteView HoverSpriteView { get; }
@@ -35,19 +38,19 @@ namespace Content.Client.Items.UI
private readonly PanelContainer _highlightRect;
public string TextureName { get; set; }
private string _textureName;
private string _storageTextureName;
public ItemSlotButton(Texture texture, Texture storageTexture, string textureName)
public ItemSlotButton(int size, string textureName, string storageTextureName, IGameHud gameHud)
{
_textureName = textureName;
_storageTextureName = storageTextureName;
IoCManager.InjectDependencies(this);
MinSize = (64, 64);
TextureName = textureName;
MinSize = (size, size);
AddChild(Button = new TextureRect
{
Texture = texture,
TextureScale = (2, 2),
MouseFilter = MouseFilterMode.Stop
});
@@ -75,7 +78,6 @@ namespace Content.Client.Items.UI
AddChild(StorageButton = new TextureButton
{
TextureNormal = storageTexture,
Scale = (0.75f, 0.75f),
HorizontalAlignment = HAlignment.Right,
VerticalAlignment = VAlignment.Bottom,
@@ -108,6 +110,14 @@ namespace Content.Client.Items.UI
{
Visible = false,
});
RefreshTextures(gameHud);
}
public void RefreshTextures(IGameHud gameHud)
{
Button.Texture = gameHud.GetHudTexture(_textureName);
StorageButton.TextureNormal = gameHud.GetHudTexture(_storageTextureName);
}
protected override void EnteredTree()

View File

@@ -4,6 +4,7 @@ using Content.Client.Inventory;
using Content.Client.Preferences;
using Content.Shared.CharacterAppearance.Systems;
using Content.Shared.GameTicking;
using Content.Shared.Inventory;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Robust.Client.GameObjects;
@@ -15,7 +16,6 @@ using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using static Content.Shared.Inventory.EquipmentSlotDefines;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Content.Client.Lobby.UI
@@ -141,29 +141,30 @@ namespace Content.Client.Lobby.UI
public static void GiveDummyJobClothes(EntityUid dummy, HumanoidCharacterProfile profile)
{
var protoMan = IoCManager.Resolve<IPrototypeManager>();
var entMan = IoCManager.Resolve<IEntityManager>();
var inventory = entMan.GetComponent<ClientInventoryComponent>(dummy);
var invSystem = EntitySystem.Get<ClientInventorySystem>();
var highPriorityJob = profile.JobPriorities.FirstOrDefault(p => p.Value == JobPriority.High).Key;
// ReSharper disable once ConstantNullCoalescingCondition
var job = protoMan.Index<JobPrototype>(highPriorityJob ?? SharedGameTicker.FallbackOverflowJob);
inventory.ClearAllSlotVisuals();
if (job.StartingGear != null)
if (job.StartingGear != null && invSystem.TryGetSlots(dummy, out var slots))
{
var gear = protoMan.Index<StartingGearPrototype>(job.StartingGear);
foreach (var slot in AllSlots)
foreach (var slot in slots)
{
var itemType = gear.GetGear(slot, profile);
var itemType = gear.GetGear(slot.Name, profile);
if(invSystem.TryUnequip(dummy, slot.Name, out var unequippedItem, true, true))
{
entMan.DeleteEntity(unequippedItem.Value);
}
if (itemType != string.Empty)
{
var item = entMan.SpawnEntity(itemType, MapCoordinates.Nullspace);
inventory.SetSlotVisuals(slot, item);
entMan.DeleteEntity(item);
invSystem.TryEquip(dummy, item, slot.Name, true, true);
}
}
}

View File

@@ -46,17 +46,17 @@ namespace Content.Client.Smoking
{
case SmokableState.Lit:
if (clothing != null)
clothing.ClothingEquippedPrefix = _litPrefix;
clothing.EquippedPrefix = _litPrefix;
sprite.LayerSetState(0, _litIcon);
break;
case SmokableState.Burnt:
if (clothing != null)
clothing.ClothingEquippedPrefix = _burntPrefix;
clothing.EquippedPrefix = _burntPrefix;
sprite.LayerSetState(0, _burntIcon);
break;
case SmokableState.Unlit:
if (clothing != null)
clothing.ClothingEquippedPrefix = _unlitPrefix;
clothing.EquippedPrefix = _unlitPrefix;
sprite.LayerSetState(0, _unlitIcon);
break;
}

View File

@@ -1,11 +1,11 @@
using System.Threading.Tasks;
using Content.Server.Buckle.Components;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Shared.ActionBlocker;
using Content.Shared.Body.Components;
using Content.Shared.Body.Part;
using Content.Shared.Buckle.Components;
using Content.Shared.Item;
using Content.Shared.Standing;
using NUnit.Framework;
using Robust.Shared.GameObjects;
@@ -252,7 +252,7 @@ namespace Content.IntegrationTests.Tests.Buckle
var akms = entityManager.SpawnEntity(ItemDummyId, coordinates);
// Equip items
Assert.True(entityManager.TryGetComponent(akms, out ItemComponent item));
Assert.True(entityManager.TryGetComponent(akms, out SharedItemComponent item));
Assert.True(hands.PutInHand(item));
}
});

View File

@@ -1,11 +1,13 @@
using System.Threading.Tasks;
using Content.Server.Clothing.Components;
using Content.Server.Inventory.Components;
using Content.Server.Inventory;
using Content.Shared.Inventory;
using Content.Shared.Item;
using NUnit.Framework;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using static Content.Shared.Inventory.EquipmentSlotDefines;
namespace Content.IntegrationTests.Tests
{
@@ -19,23 +21,25 @@ namespace Content.IntegrationTests.Tests
{
var server = StartServer();
server.Assert(() =>
await server.WaitAssertion(() =>
{
// Spawn everything.
var mapMan = IoCManager.Resolve<IMapManager>();
var invSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<InventorySystem>();
mapMan.CreateNewMapEntity(MapId.Nullspace);
var entMgr = IoCManager.Resolve<IEntityManager>();
var container = entMgr.SpawnEntity(null, MapCoordinates.Nullspace);
var inv = entMgr.AddComponent<InventoryComponent>(container);
entMgr.AddComponent<ServerInventoryComponent>(container);
entMgr.AddComponent<ContainerManagerComponent>(container);
var child = entMgr.SpawnEntity(null, MapCoordinates.Nullspace);
var item = entMgr.AddComponent<ClothingComponent>(child);
var item = entMgr.AddComponent<ItemComponent>(child);
item.SlotFlags = SlotFlags.HEAD;
// Equip item.
Assert.That(inv.Equip(Slots.HEAD, item, false), Is.True);
Assert.That(invSystem.TryEquip(container, child, "head"), Is.True);
// Delete parent.
entMgr.DeleteEntity(container);
@@ -43,8 +47,6 @@ namespace Content.IntegrationTests.Tests
// Assert that child item was also deleted.
Assert.That(item.Deleted, Is.True);
});
await server.WaitIdleAsync();
}
}
}

View File

@@ -3,19 +3,19 @@ using System.Linq;
using System.Threading.Tasks;
using Content.Client.Actions;
using Content.Client.Actions.UI;
using Content.Client.Items.Components;
using Content.Server.Actions;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Shared.Actions;
using Content.Shared.Actions.Components;
using Content.Shared.Actions.Prototypes;
using Content.Shared.Cooldown;
using Content.Shared.Item;
using NUnit.Framework;
using Robust.Client.UserInterface;
using Robust.Server.Player;
using Robust.Shared;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -268,7 +268,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
// grant an extra item action, before pickup, initially disabled
itemActions.GrantOrUpdate(ItemActionType.DebugToggle, false);
serverEntManager.GetComponent<HandsComponent>(serverPlayerEnt).PutInHand(serverEntManager.GetComponent<ItemComponent>(serverFlashlight), false);
serverEntManager.GetComponent<HandsComponent>(serverPlayerEnt).PutInHand(serverEntManager.GetComponent<SharedItemComponent>(serverFlashlight), false);
// grant an extra item action, after pickup, with a cooldown
itemActions.GrantOrUpdate(ItemActionType.DebugInstant, cooldown: cooldown);
@@ -360,7 +360,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
{
// pick the item up again, the states should be back to what they were when dropped,
// as the states "stick" with the item
serverEntManager.GetComponent<HandsComponent>(serverPlayerEnt).PutInHand(serverEntManager.GetComponent<ItemComponent>(serverFlashlight), false);
serverEntManager.GetComponent<HandsComponent>(serverPlayerEnt).PutInHand(serverEntManager.GetComponent<SharedItemComponent>(serverFlashlight), false);
Assert.That(serverActionsComponent.ItemActionStates().TryGetValue(serverFlashlight, out var lightStates));
Assert.That(lightStates.TryGetValue(ItemActionType.ToggleLight, out var lightState));
Assert.That(lightState.Equals(new ActionState(true, toggledOn: true)));

View File

@@ -1,18 +1,17 @@
using System.Threading.Tasks;
using Content.Server.Inventory.Components;
using Content.Server.Inventory;
using Content.Shared.Inventory;
using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using static Content.Shared.Inventory.EquipmentSlotDefines;
namespace Content.IntegrationTests.Tests
{
// Tests the behavior of HumanInventoryControllerComponent.
// Tests the behavior of InventoryComponent.
// i.e. the interaction between uniforms and the pocket/ID slots.
// and also how big items don't fit in pockets.
[TestFixture]
[TestOf(typeof(HumanInventoryControllerComponent))]
public class HumanInventoryUniformSlotsTest : ContentIntegrationTest
{
private const string Prototypes = @"
@@ -21,7 +20,7 @@ namespace Content.IntegrationTests.Tests
id: HumanDummy
components:
- type: Inventory
- type: HumanInventoryController
- type: ContainerContainer
- type: entity
name: UniformDummy
@@ -67,8 +66,11 @@ namespace Content.IntegrationTests.Tests
EntityUid pocketItem = default;
InventoryComponent inventory = null;
InventorySystem invSystem = default!;
server.Assert(() =>
{
invSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<InventorySystem>();
var mapMan = IoCManager.Resolve<IMapManager>();
mapMan.CreateNewMapEntity(MapId.Nullspace);
@@ -81,26 +83,25 @@ namespace Content.IntegrationTests.Tests
pocketItem = entityMan.SpawnEntity("FlashlightDummy", MapCoordinates.Nullspace);
var tooBigItem = entityMan.SpawnEntity("ToolboxDummy", MapCoordinates.Nullspace);
inventory = entityMan.GetComponent<InventoryComponent>(human);
Assert.That(inventory.CanEquip(Slots.INNERCLOTHING, uniform));
Assert.That(invSystem.CanEquip(human, uniform, "jumpsuit", out _));
// Can't equip any of these since no uniform!
Assert.That(inventory.CanEquip(Slots.IDCARD, idCard), Is.False);
Assert.That(inventory.CanEquip(Slots.POCKET1, pocketItem), Is.False);
Assert.That(inventory.CanEquip(Slots.POCKET1, tooBigItem), Is.False); // This one fails either way.
Assert.That(invSystem.CanEquip(human, idCard, "id", out _), Is.False);
Assert.That(invSystem.CanEquip(human, pocketItem, "pocket1", out _), Is.False);
Assert.That(invSystem.CanEquip(human, tooBigItem, "pocket2", out _), Is.False); // This one fails either way.
inventory.Equip(Slots.INNERCLOTHING, uniform);
Assert.That(invSystem.TryEquip(human, uniform, "jumpsuit"));
Assert.That(inventory.Equip(Slots.IDCARD, idCard));
Assert.That(inventory.Equip(Slots.POCKET1, pocketItem));
Assert.That(inventory.CanEquip(Slots.POCKET1, tooBigItem), Is.False); // Still failing!
Assert.That(invSystem.TryEquip(human, idCard, "id"));
Assert.That(invSystem.CanEquip(human, tooBigItem, "pocket1", out _), Is.False); // Still failing!
Assert.That(invSystem.TryEquip(human, pocketItem, "pocket1"));
Assert.That(IsDescendant(idCard, human));
Assert.That(IsDescendant(pocketItem, human));
// Now drop the jumpsuit.
inventory.Unequip(Slots.INNERCLOTHING);
Assert.That(invSystem.TryUnequip(human, "jumpsuit"));
});
server.RunTicks(2);
@@ -113,9 +114,9 @@ namespace Content.IntegrationTests.Tests
Assert.That(IsDescendant(pocketItem, human), Is.False);
// Ensure everything null here.
Assert.That(inventory.GetSlotItem(Slots.INNERCLOTHING), Is.Null);
Assert.That(inventory.GetSlotItem(Slots.IDCARD), Is.Null);
Assert.That(inventory.GetSlotItem(Slots.POCKET1), Is.Null);
Assert.That(!invSystem.TryGetSlotEntity(human, "jumpsuit", out _));
Assert.That(!invSystem.TryGetSlotEntity(human, "id", out _));
Assert.That(!invSystem.TryGetSlotEntity(human, "pocket1", out _));
});
await server.WaitIdleAsync();

View File

@@ -1,10 +1,11 @@
#nullable enable annotations
using System.Threading.Tasks;
using Content.Client.Items.Components;
using Content.Server.Hands.Components;
using Content.Server.Interaction;
using Content.Server.Items;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Weapons.Melee;
using NUnit.Framework;
using Robust.Shared.Containers;
@@ -13,6 +14,7 @@ using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Reflection;
using ItemComponent = Content.Server.Clothing.Components.ItemComponent;
namespace Content.IntegrationTests.Tests.Interaction.Click
{
@@ -97,7 +99,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
Assert.That(interactHand);
Assert.That(sEntities.TryGetComponent<HandsComponent>(user, out var hands));
Assert.That(hands.PutInHand(sEntities.GetComponent<ItemComponent>(item)));
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
Assert.That(interactUsing);
@@ -169,7 +171,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
Assert.That(interactHand, Is.False);
Assert.That(sEntities.TryGetComponent<HandsComponent?>(user, out var hands));
Assert.That(hands.PutInHand(sEntities.GetComponent<ItemComponent>(item)));
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
Assert.That(interactUsing, Is.False);
@@ -238,7 +240,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
Assert.That(interactHand);
Assert.That(sEntities.TryGetComponent<HandsComponent>(user, out var hands));
Assert.That(hands.PutInHand(sEntities.GetComponent<ItemComponent>(item)));
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
Assert.That(interactUsing);
@@ -308,7 +310,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
Assert.That(interactHand, Is.False);
Assert.That(sEntities.TryGetComponent<HandsComponent?>(user, out var hands));
Assert.That(hands.PutInHand(sEntities.GetComponent<ItemComponent>(item)));
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
Assert.That(interactUsing, Is.False);
@@ -393,7 +395,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
Assert.That(interactHand);
Assert.That(sEntities.TryGetComponent<HandsComponent?>(user, out var hands));
Assert.That(hands.PutInHand(sEntities.GetComponent<ItemComponent>(item)));
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
Assert.That(interactUsing, Is.False);

View File

@@ -1,19 +1,16 @@
using System;
using System.Threading.Tasks;
using Content.Server.Inventory;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Server.Stunnable;
using Content.Shared.Inventory;
using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using static Content.Shared.Inventory.EquipmentSlotDefines;
namespace Content.IntegrationTests.Tests
{
[TestFixture]
[TestOf(typeof(InventoryHelpers))]
public class InventoryHelpersTest : ContentIntegrationTest
{
private const string Prototypes = @"
@@ -22,6 +19,7 @@ namespace Content.IntegrationTests.Tests
id: InventoryStunnableDummy
components:
- type: Inventory
- type: ContainerContainer
- type: StatusEffects
allowed:
- Stun
@@ -53,43 +51,41 @@ namespace Content.IntegrationTests.Tests
var sEntities = server.ResolveDependency<IEntityManager>();
EntityUid human = default;
InventoryComponent inventory = null;
await server.WaitAssertion(() =>
{
var mapMan = IoCManager.Resolve<IMapManager>();
var systemMan = IoCManager.Resolve<IEntitySystemManager>();
mapMan.CreateNewMapEntity(MapId.Nullspace);
human = sEntities.SpawnEntity("InventoryStunnableDummy", MapCoordinates.Nullspace);
inventory = sEntities.GetComponent<InventoryComponent>(human);
var human = sEntities.SpawnEntity("InventoryStunnableDummy", MapCoordinates.Nullspace);
var invSystem = systemMan.GetEntitySystem<InventorySystem>();
// Can't do the test if this human doesn't have the slots for it.
Assert.That(inventory.HasSlot(Slots.INNERCLOTHING));
Assert.That(inventory.HasSlot(Slots.IDCARD));
Assert.That(invSystem.HasSlot(human, "jumpsuit"));
Assert.That(invSystem.HasSlot(human, "id"));
Assert.That(inventory.SpawnItemInSlot(Slots.INNERCLOTHING, "InventoryJumpsuitJanitorDummy", true));
Assert.That(invSystem.SpawnItemInSlot(human, "jumpsuit", "InventoryJumpsuitJanitorDummy", true));
// Do we actually have the uniform equipped?
Assert.That(inventory.TryGetSlotItem(Slots.INNERCLOTHING, out ItemComponent uniform));
Assert.That(sEntities.GetComponent<MetaDataComponent>(uniform.Owner).EntityPrototype is
Assert.That(invSystem.TryGetSlotEntity(human, "jumpsuit", out var uniform));
Assert.That(sEntities.GetComponent<MetaDataComponent>(uniform.Value).EntityPrototype is
{
ID: "InventoryJumpsuitJanitorDummy"
});
EntitySystem.Get<StunSystem>().TryStun(human, TimeSpan.FromSeconds(1f), true);
systemMan.GetEntitySystem<StunSystem>().TryStun(human, TimeSpan.FromSeconds(1f), true);
// Since the mob is stunned, they can't equip this.
Assert.That(inventory.SpawnItemInSlot(Slots.IDCARD, "InventoryIDCardDummy", true), Is.False);
Assert.That(invSystem.SpawnItemInSlot(human, "id", "InventoryIDCardDummy", true), Is.False);
// Make sure we don't have the ID card equipped.
Assert.That(inventory.TryGetSlotItem(Slots.IDCARD, out ItemComponent _), Is.False);
Assert.That(invSystem.TryGetSlotEntity(human, "item", out _), Is.False);
// Let's try skipping the interaction check and see if it equips it!
Assert.That(inventory.SpawnItemInSlot(Slots.IDCARD, "InventoryIDCardDummy"));
Assert.That(inventory.TryGetSlotItem(Slots.IDCARD, out ItemComponent id));
Assert.That(sEntities.GetComponent<MetaDataComponent>(id.Owner).EntityPrototype is
Assert.That(invSystem.SpawnItemInSlot(human, "id", "InventoryIDCardDummy", true, true));
Assert.That(invSystem.TryGetSlotEntity(human, "id", out var idUid));
Assert.That(sEntities.GetComponent<MetaDataComponent>(idUid.Value).EntityPrototype is
{
ID: "InventoryIDCardDummy"
});

View File

@@ -1,11 +1,11 @@
using System.Linq;
using System.Threading.Tasks;
using Content.Server.Hands.Components;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Server.PDA;
using Content.Shared.Access.Components;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Inventory;
using Content.Shared.Item;
using Content.Shared.PDA;
using NUnit.Framework;
using Robust.Server.Player;
@@ -58,6 +58,8 @@ namespace Content.IntegrationTests.Tests.PDA
var sPlayerManager = server.ResolveDependency<IPlayerManager>();
var sEntityManager = server.ResolveDependency<IEntityManager>();
var invSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<InventorySystem>();
await server.WaitAssertion(() =>
{
var player = sPlayerManager.Sessions.Single().AttachedEntity.GetValueOrDefault();
@@ -71,7 +73,7 @@ namespace Content.IntegrationTests.Tests.PDA
// Put PDA in hand
var dummyPda = sEntityManager.SpawnEntity(PdaDummy, sEntityManager.GetComponent<TransformComponent>(player).MapPosition);
var pdaItemComponent = sEntityManager.GetComponent<ItemComponent>(dummyPda);
var pdaItemComponent = sEntityManager.GetComponent<SharedItemComponent>(dummyPda);
sEntityManager.GetComponent<HandsComponent>(player).PutInHand(pdaItemComponent);
var pdaComponent = sEntityManager.GetComponent<PDAComponent>(dummyPda);
@@ -91,7 +93,7 @@ namespace Content.IntegrationTests.Tests.PDA
// Put ID card in hand
var idDummy = sEntityManager.SpawnEntity(IdCardDummy, sEntityManager.GetComponent<TransformComponent>(player).MapPosition);
var idItemComponent = sEntityManager.GetComponent<ItemComponent>(idDummy);
var idItemComponent = sEntityManager.GetComponent<SharedItemComponent>(idDummy);
sEntityManager.GetComponent<HandsComponent>(player).PutInHand(idItemComponent);
var idCardComponent = sEntityManager.GetComponent<IdCardComponent>(idDummy);
@@ -103,20 +105,16 @@ namespace Content.IntegrationTests.Tests.PDA
Assert.That(id, Is.EqualTo(idCardComponent));
// Remove all IDs and PDAs
var inventory = sEntityManager.GetComponent<InventoryComponent>(player);
Assert.That(invSystem.TryGetSlots(player, out var slots));
foreach (var slot in inventory.Slots)
{
var item = inventory.GetSlotItem(slot);
if (item == null)
foreach (var slot in slots)
{
if(!invSystem.TryGetSlotEntity(player, slot.Name, out var item))
continue;
}
if (sEntityManager.HasComponent<PDAComponent>(item.Owner))
if (sEntityManager.HasComponent<PDAComponent>(item))
{
inventory.ForceUnequip(slot);
invSystem.TryUnequip(player, slot.Name, force: true);
}
}

View File

@@ -1,7 +1,7 @@
using Content.Server.Hands.Components;
using Content.Server.Interaction;
using Content.Server.Items;
using Content.Shared.Interaction.Helpers;
using Content.Shared.Item;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -25,7 +25,7 @@ namespace Content.Server.AI.Operators.Inventory
var entMan = IoCManager.Resolve<IEntityManager>();
if (entMan.Deleted(_target)
|| !entMan.HasComponent<ItemComponent>(_target)
|| !entMan.HasComponent<SharedItemComponent>(_target)
|| _target.IsInContainer()
|| !_owner.InRangeUnobstructed(_target, popup: true))
{

View File

@@ -1,5 +1,5 @@
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Shared.Item;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -29,7 +29,7 @@ namespace Content.Server.AI.Operators.Inventory
return Outcome.Failed;
}
if (!entMan.TryGetComponent(_target, out ItemComponent? itemComponent))
if (!entMan.TryGetComponent(_target, out SharedItemComponent? itemComponent))
{
return Outcome.Failed;
}

View File

@@ -1,7 +1,7 @@
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Nutrition.Components;
using Content.Server.Nutrition.EntitySystems;
using Content.Shared.Item;
using Content.Shared.Nutrition.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -34,7 +34,7 @@ namespace Content.Server.AI.Operators.Nutrition
// TODO: Also have this check storage a la backpack etc.
if (entities.Deleted(_target) ||
!entities.TryGetComponent(_owner, out HandsComponent? handsComponent) ||
!entities.TryGetComponent(_target, out ItemComponent? itemComponent))
!entities.TryGetComponent(_target, out SharedItemComponent? itemComponent))
{
return Outcome.Failed;
}

View File

@@ -1,6 +1,6 @@
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Nutrition.Components;
using Content.Shared.Item;
using Content.Shared.Nutrition.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -33,7 +33,7 @@ namespace Content.Server.AI.Operators.Nutrition
// TODO: Also have this check storage a la backpack etc.
if (entities.Deleted(_target) ||
!entities.TryGetComponent(_owner, out HandsComponent? handsComponent) ||
!entities.TryGetComponent(_target, out ItemComponent? itemComponent))
!entities.TryGetComponent(_target, out SharedItemComponent? itemComponent))
{
return Outcome.Failed;
}

View File

@@ -10,7 +10,7 @@ namespace Content.Server.AI.Utility.Considerations.Clothing
{
public sealed class ClothingInInventoryCon : Consideration
{
public ClothingInInventoryCon Slot(EquipmentSlotDefines.SlotFlags slotFlags, Blackboard context)
public ClothingInInventoryCon Slot(SlotFlags slotFlags, Blackboard context)
{
// Ideally we'd just use a variable but then if we were iterating through multiple AI at once it'd be
// Stuffed so we need to store it on the AI's context.
@@ -21,16 +21,17 @@ namespace Content.Server.AI.Utility.Considerations.Clothing
protected override float GetScore(Blackboard context)
{
var slots = context.GetState<ClothingSlotConState>().GetValue();
var slotFlags = EquipmentSlotDefines.SlotMasks[slots];
if (slots == null) return 0.0f;
foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(entity, out ClothingComponent? clothingComponent))
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(entity, out ClothingComponent? clothingComponent) ||
!EntitySystem.Get<InventorySystem>().TryGetSlot(entity, slots, out var slotDef))
{
continue;
}
if ((clothingComponent.SlotFlags & slotFlags) != 0)
if ((clothingComponent.SlotFlags & slotDef.SlotFlags) != 0)
{
return 1.0f;
}

View File

@@ -7,7 +7,7 @@ namespace Content.Server.AI.Utility.Considerations.Clothing
public class ClothingInSlotCon : Consideration
{
public ClothingInSlotCon Slot(EquipmentSlotDefines.Slots slot, Blackboard context)
public ClothingInSlotCon Slot(string slot, Blackboard context)
{
context.GetState<ClothingSlotConState>().SetValue(slot);
return this;
@@ -17,7 +17,7 @@ namespace Content.Server.AI.Utility.Considerations.Clothing
{
var slot = context.GetState<ClothingSlotConState>().GetValue();
var inventory = context.GetState<EquippedClothingState>().GetValue();
return inventory.ContainsKey(slot) ? 1.0f : 0.0f;
return slot != null && inventory.ContainsKey(slot) ? 1.0f : 0.0f;
}
}
}

View File

@@ -2,7 +2,7 @@ using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Hands;
using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.Items;
using Content.Shared.Item;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -16,7 +16,7 @@ namespace Content.Server.AI.Utility.Considerations.Inventory
// If not then check if we have a free hand
var target = context.GetState<TargetEntityState>().GetValue();
if (target == null || !IoCManager.Resolve<IEntityManager>().HasComponent<ItemComponent>(target))
if (target == null || !IoCManager.Resolve<IEntityManager>().HasComponent<SharedItemComponent>(target))
{
return 0.0f;
}

View File

@@ -1,7 +1,7 @@
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.Items;
using Content.Shared.Item;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -13,7 +13,7 @@ namespace Content.Server.AI.Utility.Considerations.Inventory
{
var target = context.GetState<TargetEntityState>().GetValue();
if (target == null || !IoCManager.Resolve<IEntityManager>().HasComponent<ItemComponent>(target))
if (target == null || !IoCManager.Resolve<IEntityManager>().HasComponent<SharedItemComponent>(target))
{
return 0.0f;
}

View File

@@ -27,7 +27,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Gloves
return new []
{
considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.GLOVES, context)
considerationsManager.Get<ClothingInSlotCon>().Slot("gloves", context)
.InverseBoolCurve(context),
};
}
@@ -39,7 +39,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Gloves
foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(entity, out ClothingComponent? clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.GLOVES) != 0)
(clothing.SlotFlags & SlotFlags.GLOVES) != 0)
{
yield return new EquipGloves {Owner = owner, Target = entity, Bonus = Bonus};
}

View File

@@ -23,9 +23,9 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Gloves
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
return new[]
{
considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.GLOVES, context)
considerationsManager.Get<ClothingInSlotCon>().Slot("gloves", context)
.InverseBoolCurve(context),
considerationsManager.Get<ClothingInInventoryCon>().Slot(EquipmentSlotDefines.SlotFlags.GLOVES, context)
considerationsManager.Get<ClothingInInventoryCon>().Slot(SlotFlags.GLOVES, context)
.InverseBoolCurve(context),
};
}
@@ -37,7 +37,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Gloves
foreach (var entity in context.GetState<NearbyClothingState>().GetValue())
{
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(entity, out ClothingComponent? clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.GLOVES) != 0)
(clothing.SlotFlags & SlotFlags.GLOVES) != 0)
{
yield return new PickUpGloves {Owner = owner, Target = entity, Bonus = Bonus};
}

View File

@@ -26,7 +26,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
return new[] {
considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.HEAD, context)
considerationsManager.Get<ClothingInSlotCon>().Slot("head", context)
.InverseBoolCurve(context),
};
}
@@ -38,7 +38,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head
foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(entity, out ClothingComponent? clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.HEAD) != 0)
(clothing.SlotFlags & SlotFlags.HEAD) != 0)
{
yield return new EquipHead {Owner = owner, Target = entity, Bonus = Bonus};
}

View File

@@ -23,9 +23,9 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
return new[]
{
considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.HEAD, context)
considerationsManager.Get<ClothingInSlotCon>().Slot("head", context)
.InverseBoolCurve(context),
considerationsManager.Get<ClothingInInventoryCon>().Slot(EquipmentSlotDefines.SlotFlags.HEAD, context)
considerationsManager.Get<ClothingInInventoryCon>().Slot(SlotFlags.HEAD, context)
.InverseBoolCurve(context)
};
}
@@ -37,7 +37,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head
foreach (var entity in context.GetState<NearbyClothingState>().GetValue())
{
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(entity, out ClothingComponent? clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.HEAD) != 0)
(clothing.SlotFlags & SlotFlags.HEAD) != 0)
{
yield return new PickUpHead {Owner = owner, Target = entity, Bonus = Bonus};
}

View File

@@ -27,7 +27,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing
return new[]
{
considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.OUTERCLOTHING, context)
considerationsManager.Get<ClothingInSlotCon>().Slot("outerClothing", context)
.InverseBoolCurve(context),
};
}
@@ -39,7 +39,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing
foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(entity, out ClothingComponent? clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.OUTERCLOTHING) != 0)
(clothing.SlotFlags & SlotFlags.OUTERCLOTHING) != 0)
{
yield return new EquipOuterClothing {Owner = owner, Target = entity, Bonus = Bonus};
}

View File

@@ -24,9 +24,9 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing
return new[]
{
considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.OUTERCLOTHING, context)
considerationsManager.Get<ClothingInSlotCon>().Slot("outerClothing", context)
.InverseBoolCurve(context),
considerationsManager.Get<ClothingInInventoryCon>().Slot(EquipmentSlotDefines.SlotFlags.OUTERCLOTHING, context)
considerationsManager.Get<ClothingInInventoryCon>().Slot(SlotFlags.OUTERCLOTHING, context)
.InverseBoolCurve(context)
};
}
@@ -38,7 +38,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing
foreach (var entity in context.GetState<NearbyClothingState>().GetValue())
{
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(entity, out ClothingComponent? clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.OUTERCLOTHING) != 0)
(clothing.SlotFlags & SlotFlags.OUTERCLOTHING) != 0)
{
yield return new PickUpOuterClothing {Owner = owner, Target = entity, Bonus = Bonus};
}

View File

@@ -27,7 +27,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes
return new[]
{
considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.SHOES, context)
considerationsManager.Get<ClothingInSlotCon>().Slot("shoes", context)
.InverseBoolCurve(context),
};
}
@@ -39,7 +39,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes
foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(entity, out ClothingComponent? clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.SHOES) != 0)
(clothing.SlotFlags & SlotFlags.FEET) != 0)
{
yield return new EquipShoes {Owner = owner, Target = entity, Bonus = Bonus};
}

View File

@@ -24,9 +24,9 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes
return new[]
{
considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.SHOES, context)
considerationsManager.Get<ClothingInSlotCon>().Slot("shoes", context)
.InverseBoolCurve(context),
considerationsManager.Get<ClothingInInventoryCon>().Slot(EquipmentSlotDefines.SlotFlags.SHOES, context)
considerationsManager.Get<ClothingInInventoryCon>().Slot(SlotFlags.FEET, context)
.InverseBoolCurve(context)
};
}
@@ -38,7 +38,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes
foreach (var entity in context.GetState<NearbyClothingState>().GetValue())
{
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(entity, out ClothingComponent? clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.SHOES) != 0)
(clothing.SlotFlags & SlotFlags.FEET) != 0)
{
yield return new PickUpShoes {Owner = owner, Target = entity, Bonus = Bonus};
}

View File

@@ -1,13 +1,11 @@
using Content.Shared.Inventory;
namespace Content.Server.AI.WorldState.States.Clothing
{
public sealed class ClothingSlotConState : PlanningStateData<EquipmentSlotDefines.Slots>
public sealed class ClothingSlotConState : PlanningStateData<string>
{
public override string Name => "ClothingSlotCon";
public override void Reset()
{
Value = EquipmentSlotDefines.Slots.NONE;
Value = "";
}
}
}

View File

@@ -2,12 +2,12 @@ using Content.Shared.Inventory;
namespace Content.Server.AI.WorldState.States.Clothing
{
public sealed class ClothingSlotFlagConState : PlanningStateData<EquipmentSlotDefines.SlotFlags>
public sealed class ClothingSlotFlagConState : PlanningStateData<SlotFlags>
{
public override string Name => "ClothingSlotFlagCon";
public override void Reset()
{
Value = EquipmentSlotDefines.SlotFlags.NONE;
Value = SlotFlags.NONE;
}
}
}

View File

@@ -1,34 +1,35 @@
using System.Collections.Generic;
using Content.Server.Inventory.Components;
using Content.Shared.Inventory;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using InventoryComponent = Content.Shared.Inventory.InventoryComponent;
namespace Content.Server.AI.WorldState.States.Clothing
{
[UsedImplicitly]
public sealed class EquippedClothingState : StateData<Dictionary<EquipmentSlotDefines.Slots, EntityUid>>
public sealed class EquippedClothingState : StateData<Dictionary<string, EntityUid>>
{
public override string Name => "EquippedClothing";
public override Dictionary<EquipmentSlotDefines.Slots, EntityUid> GetValue()
public override Dictionary<string, EntityUid> GetValue()
{
var result = new Dictionary<EquipmentSlotDefines.Slots, EntityUid>();
var result = new Dictionary<string, EntityUid>();
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(Owner, out InventoryComponent? inventoryComponent))
var invSystem = EntitySystem.Get<InventorySystem>();
if (!invSystem.TryGetSlots(Owner, out var slotDefinitions))
{
return result;
}
foreach (var slot in EquipmentSlotDefines.AllSlots)
foreach (var slot in slotDefinitions)
{
if (!inventoryComponent.HasSlot(slot)) continue;
var slotItem = inventoryComponent.GetSlotItem(slot);
if (!invSystem.HasSlot(Owner, slot.Name)) continue;
if (slotItem != null)
if (invSystem.TryGetSlotEntity(Owner, slot.Name, out var entityUid))
{
result.Add(slot, slotItem.Owner);
result.Add(slot.Name, entityUid.Value);
}
}

View File

@@ -2,13 +2,13 @@ using System;
using System.Linq;
using System.Threading.Tasks;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.NodeContainer;
using Content.Server.Power.Components;
using Content.Server.UserInterface;
using Content.Shared.ActionBlocker;
using Content.Shared.AME;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Popups;
using Content.Shared.Sound;
using Robust.Server.GameObjects;
@@ -245,7 +245,7 @@ namespace Content.Server.AME.Components
_jarSlot.Remove(jar);
UpdateUserInterface();
if (!_entities.TryGetComponent<HandsComponent?>(user, out var hands) || !_entities.TryGetComponent<ItemComponent?>(jar, out var item))
if (!_entities.TryGetComponent<HandsComponent?>(user, out var hands) || !_entities.TryGetComponent<SharedItemComponent?>(jar, out var item))
return;
if (hands.CanPutInHand(item))
hands.PutInHand(item);

View File

@@ -1,18 +1,19 @@
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Shared.Hands.Components;
using Content.Shared.Inventory;
using Content.Shared.PDA;
using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.PDA;
using Robust.Shared.IoC;
namespace Content.Server.Access.Systems
{
public class IdCardSystem : SharedIdCardSystem
{
[Dependency] private readonly InventorySystem _inventorySystem = default!;
public override void Initialize()
{
base.Initialize();
@@ -101,7 +102,12 @@ namespace Content.Server.Access.Systems
return true;
// check inventory slot?
return TryGetIdCardSlot(uid, out idCard);
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid) && TryGetIdCard(idUid.Value, out idCard))
{
return true;
}
return false;
}
/// <summary>
@@ -121,17 +127,5 @@ namespace Content.Server.Access.Systems
return false;
}
/// <summary>
/// Try get id card from mobs ID inventory slot
/// </summary>
public bool TryGetIdCardSlot(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard)
{
idCard = null;
return EntityManager.TryGetComponent(uid, out InventoryComponent? inventoryComponent) &&
inventoryComponent.HasSlot(EquipmentSlotDefines.Slots.IDCARD) &&
inventoryComponent.TryGetSlotItem(EquipmentSlotDefines.Slots.IDCARD, out ItemComponent? item) &&
TryGetIdCard(item.Owner, out idCard);
}
}
}

View File

@@ -1,9 +1,9 @@
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Popups;
using Content.Shared.ActionBlocker;
using Content.Shared.Actions.Behaviors;
using Content.Shared.Cooldown;
using Content.Shared.Item;
using Content.Shared.Popups;
using Content.Shared.Sound;
using JetBrains.Annotations;
@@ -57,9 +57,9 @@ namespace Content.Server.Actions.Spells
// TODO: Look this is shitty and ideally a test would do it
var spawnedProto = entMan.SpawnEntity(ItemProto, entMan.GetComponent<TransformComponent>(caster).MapPosition);
if (!entMan.TryGetComponent(spawnedProto, out ItemComponent? itemComponent))
if (!entMan.TryGetComponent(spawnedProto, out SharedItemComponent? itemComponent))
{
Logger.Error($"Tried to use {nameof(GiveItemSpell)} but prototype has no {nameof(ItemComponent)}?");
Logger.Error($"Tried to use {nameof(GiveItemSpell)} but prototype has no {nameof(SharedItemComponent)}?");
entMan.DeleteEntity(spawnedProto);
return;
}

View File

@@ -10,7 +10,7 @@ using Content.Server.Disposal.Tube.Components;
using Content.Server.EUI;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Ghost.Roles;
using Content.Server.Inventory.Components;
using Content.Server.Inventory;
using Content.Server.Mind.Commands;
using Content.Server.Mind.Components;
using Content.Server.Players;
@@ -19,6 +19,7 @@ using Content.Shared.Body.Components;
using Content.Shared.Database;
using Content.Shared.GameTicking;
using Content.Shared.Interaction.Helpers;
using Content.Shared.Inventory;
using Content.Shared.Popups;
using Content.Shared.Verbs;
using Robust.Server.Console;

View File

@@ -1,7 +1,5 @@
using Content.Server.Administration.UI;
using Content.Server.EUI;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Server.Preferences.Managers;
using Content.Shared.Administration;
using Content.Shared.Inventory;
@@ -15,6 +13,7 @@ using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Prototypes;
using InventoryComponent = Content.Shared.Inventory.InventoryComponent;
namespace Content.Server.Administration.Commands
{
@@ -88,23 +87,27 @@ namespace Content.Server.Administration.Commands
profile = prefs.SelectedCharacter as HumanoidCharacterProfile;
}
foreach (var slot in inventoryComponent.Slots)
var invSystem = EntitySystem.Get<InventorySystem>();
if (invSystem.TryGetSlots(target, out var slotDefinitions, inventoryComponent))
{
inventoryComponent.ForceUnequip(slot);
var gearStr = startingGear.GetGear(slot, profile);
foreach (var slot in slotDefinitions)
{
invSystem.TryUnequip(target, slot.Name, true, true, inventoryComponent);
var gearStr = startingGear.GetGear(slot.Name, profile);
if (gearStr == string.Empty)
{
continue;
}
var equipmentEntity = entityManager.SpawnEntity(gearStr, entityManager.GetComponent<TransformComponent>(target).Coordinates);
if (slot == EquipmentSlotDefines.Slots.IDCARD &&
if (slot.Name == "id" &&
entityManager.TryGetComponent<PDAComponent?>(equipmentEntity, out var pdaComponent) &&
pdaComponent.ContainedID != null)
{
pdaComponent.ContainedID.FullName = entityManager.GetComponent<MetaDataComponent>(target).EntityName;
}
inventoryComponent.Equip(slot, entityManager.GetComponent<ItemComponent>(equipmentEntity), false);
invSystem.TryEquip(target, equipmentEntity, slot.Name, true, inventory: inventoryComponent);
}
}
}
}

View File

@@ -1,5 +1,7 @@
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Shared.Inventory;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager.Attributes;
@@ -10,7 +12,7 @@ namespace Content.Server.Atmos.Components
/// Used in internals as breath tool.
/// </summary>
[RegisterComponent]
public class BreathToolComponent : Component, IEquipped, IUnequipped
public class BreathToolComponent : Component
{
[Dependency] private readonly IEntityManager _entities = default!;
@@ -18,11 +20,11 @@ namespace Content.Server.Atmos.Components
/// Tool is functional only in allowed slots
/// </summary>
[DataField("allowedSlots")]
private EquipmentSlotDefines.SlotFlags _allowedSlots = EquipmentSlotDefines.SlotFlags.MASK;
public SlotFlags AllowedSlots = SlotFlags.MASK;
public override string Name => "BreathMask";
public bool IsFunctional { get; private set; }
public EntityUid ConnectedInternalsEntity { get; private set; }
public bool IsFunctional;
public EntityUid ConnectedInternalsEntity;
protected override void Shutdown()
{
@@ -30,23 +32,6 @@ namespace Content.Server.Atmos.Components
DisconnectInternals();
}
void IEquipped.Equipped(EquippedEventArgs eventArgs)
{
if ((EquipmentSlotDefines.SlotMasks[eventArgs.Slot] & _allowedSlots) != _allowedSlots) return;
IsFunctional = true;
if (_entities.TryGetComponent(eventArgs.User, out InternalsComponent? internals))
{
ConnectedInternalsEntity = eventArgs.User;
internals.ConnectBreathTool(Owner);
}
}
void IUnequipped.Unequipped(UnequippedEventArgs eventArgs)
{
DisconnectInternals();
}
public void DisconnectInternals()
{
var old = ConnectedInternalsEntity;

View File

@@ -7,6 +7,7 @@ using Content.Server.Popups;
using Content.Shared.Atmos;
using Content.Shared.Body.Components;
using Content.Shared.Body.Events;
using Content.Shared.Inventory.Events;
using Content.Shared.MobState.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -27,6 +28,26 @@ public class LungSystem : EntitySystem
{
base.Initialize();
SubscribeLocalEvent<LungComponent, AddedToBodyEvent>(OnAddedToBody);
SubscribeLocalEvent<BreathToolComponent, GotEquippedEvent>(OnGotEquipped);
SubscribeLocalEvent<BreathToolComponent, GotUnequippedEvent>(OnGotUnequipped);
}
private void OnGotUnequipped(EntityUid uid, BreathToolComponent component, GotUnequippedEvent args)
{
component.DisconnectInternals();
}
private void OnGotEquipped(EntityUid uid, BreathToolComponent component, GotEquippedEvent args)
{
if ((args.SlotFlags & component.AllowedSlots) != component.AllowedSlots) return;
component.IsFunctional = true;
if (TryComp(args.Equipee, out InternalsComponent? internals))
{
component.ConnectedInternalsEntity = args.Equipee;
internals.ConnectBreathTool(uid);
}
}
private void OnAddedToBody(EntityUid uid, LungComponent component, AddedToBodyEvent args)

View File

@@ -1,17 +1,16 @@
using System.Linq;
using Content.Server.Act;
using Content.Server.Administration;
using Content.Server.Administration.Logs;
using Content.Server.Chat.Managers;
using Content.Server.GameTicking;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Players;
using Content.Server.Popups;
using Content.Shared.Administration;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Database;
using Content.Shared.Item;
using Content.Shared.Popups;
using Robust.Server.Player;
using Robust.Shared.Console;
@@ -108,7 +107,7 @@ namespace Content.Server.Chat.Commands
{
foreach (var entity in entities)
{
if (_entities.HasComponent<ItemComponent>(entity))
if (_entities.HasComponent<SharedItemComponent>(entity))
continue;
var suicide = _entities.GetComponents<ISuicideAct>(entity).FirstOrDefault();
if (suicide != null)

View File

@@ -3,8 +3,6 @@ using System.Linq;
using Content.Server.Administration.Managers;
using Content.Server.Ghost.Components;
using Content.Server.Headset;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Server.MoMMI;
using Content.Server.Preferences.Managers;
using Content.Server.Radio.EntitySystems;
@@ -171,9 +169,10 @@ namespace Content.Server.Chat.Managers
message = message[0].ToString().ToUpper() +
message.Remove(0, 1);
if (_entManager.TryGetComponent(source, out InventoryComponent? inventory) &&
inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.EARS, out ItemComponent? item) &&
_entManager.TryGetComponent(item.Owner, out HeadsetComponent? headset))
var invSystem = EntitySystem.Get<InventorySystem>();
if (invSystem.TryGetSlotEntity(source, "ears", out var entityUid) &&
_entManager.TryGetComponent(entityUid, out HeadsetComponent? headset))
{
headset.RadioRequested = true;
}

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using Content.Server.Chemistry.Components.SolutionManager;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Labels.Components;
using Content.Server.Power.Components;
using Content.Server.UserInterface;
@@ -12,6 +11,7 @@ using Content.Shared.Chemistry.Components;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Popups;
using Content.Shared.Random.Helpers;
using Content.Shared.Sound;
@@ -319,7 +319,7 @@ namespace Content.Server.Chemistry.Components
//Try to give them the bottle
if (_entities.TryGetComponent<HandsComponent?>(user, out var hands) &&
_entities.TryGetComponent<ItemComponent?>(bottle, out var item))
_entities.TryGetComponent<SharedItemComponent?>(bottle, out var item))
{
if (hands.CanPutInHand(item))
{
@@ -368,7 +368,7 @@ namespace Content.Server.Chemistry.Components
//Try to give them the bottle
if (_entities.TryGetComponent<HandsComponent?>(user, out var hands) &&
_entities.TryGetComponent<ItemComponent?>(pill, out var item))
_entities.TryGetComponent<SharedItemComponent?>(pill, out var item))
{
if (hands.CanPutInHand(item))
{

View File

@@ -1,8 +1,6 @@
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Shared.FixedPoint;
using Content.Shared.Foam;
using Content.Shared.Inventory;
@@ -40,20 +38,22 @@ namespace Content.Server.Chemistry.Components
if (!_entMan.TryGetComponent(entity, out BloodstreamComponent? bloodstream))
return;
var invSystem = EntitySystem.Get<InventorySystem>();
// TODO: Add a permeability property to clothing
// For now it just adds to protection for each clothing equipped
var protection = 0f;
if (_entMan.TryGetComponent(entity, out InventoryComponent? inventory))
if (invSystem.TryGetSlots(entity, out var slotDefinitions))
{
foreach (var slot in inventory.Slots)
foreach (var slot in slotDefinitions)
{
if (slot == EquipmentSlotDefines.Slots.BACKPACK ||
slot == EquipmentSlotDefines.Slots.POCKET1 ||
slot == EquipmentSlotDefines.Slots.POCKET2 ||
slot == EquipmentSlotDefines.Slots.IDCARD)
if (slot.Name == "back" ||
slot.Name == "pocket1" ||
slot.Name == "pocket2" ||
slot.Name == "id")
continue;
if (inventory.TryGetSlotItem(slot, out ItemComponent? _))
if (invSystem.TryGetSlotEntity(entity, slot.Name, out _))
protection += 0.025f;
}
}

View File

@@ -1,94 +1,67 @@
using Content.Server.Hands.Components;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Shared.Clothing;
using Content.Shared.Interaction;
using Content.Shared.Inventory;
using Content.Shared.Item;
using Content.Shared.Popups;
using Content.Shared.Sound;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
using static Content.Shared.Inventory.EquipmentSlotDefines;
namespace Content.Server.Clothing.Components
{
[RegisterComponent]
[ComponentReference(typeof(SharedItemComponent))]
[ComponentReference(typeof(ItemComponent))]
[NetworkedComponent()]
public class ItemComponent : SharedItemComponent{}
[RegisterComponent]
[NetworkedComponent]
[ComponentReference(typeof(SharedItemComponent))]
public class ClothingComponent : ItemComponent, IUse
{
[Dependency] private readonly IEntityManager _entities = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
public override string Name => "Clothing";
[ViewVariables]
[DataField("Slots")]
public SlotFlags SlotFlags = SlotFlags.PREVENTEQUIP; //Different from None, NONE allows equips if no slot flags are required
[DataField("QuickEquip")]
private bool _quickEquipEnabled = true;
[DataField("HeatResistance")]
private int _heatResistance = 323;
[DataField("EquipSound")]
public SoundSpecifier? EquipSound { get; set; } = default!;
[ViewVariables(VVAccess.ReadWrite)]
public int HeatResistance => _heatResistance;
[DataField("ClothingPrefix")]
private string? _clothingEquippedPrefix;
[ViewVariables(VVAccess.ReadWrite)]
public string? ClothingEquippedPrefix
{
get => _clothingEquippedPrefix;
set
{
Dirty();
_clothingEquippedPrefix = value;
}
}
public override ComponentState GetComponentState()
{
return new ClothingComponentState(ClothingEquippedPrefix, EquippedPrefix);
}
bool IUse.UseEntity(UseEntityEventArgs eventArgs)
{
if (!_quickEquipEnabled) return false;
var invSystem = EntitySystem.Get<InventorySystem>();
if (!_entities.TryGetComponent(eventArgs.User, out InventoryComponent? inv)
|| !_entities.TryGetComponent(eventArgs.User, out HandsComponent? hands)) return false;
|| !_entities.TryGetComponent(eventArgs.User, out HandsComponent? hands) || !_prototype.TryIndex<InventoryTemplatePrototype>(inv.TemplateId, out var prototype)) return false;
foreach (var (slot, flag) in SlotMasks)
foreach (var slotDef in prototype.Slots)
{
// We check if the clothing can be equipped in this slot.
if ((SlotFlags & flag) == 0) continue;
if(!invSystem.CanEquip(eventArgs.User, Owner, slotDef.Name, out _, slotDef, inv))
continue;
if (inv.TryGetSlotItem(slot, out ItemComponent? item))
if (invSystem.TryGetSlotEntity(eventArgs.User, slotDef.Name, out var slotEntity, inv))
{
if (!inv.CanUnequip(slot)) continue;
hands.Drop(Owner);
inv.Unequip(slot);
hands.PutInHand(item);
if(!invSystem.TryUnequip(eventArgs.User, slotDef.Name, true, inventory: inv))
continue;
if (!TryEquip(inv, slot, eventArgs.User))
{
hands.Drop(item.Owner);
inv.Equip(slot, item);
hands.PutInHand(_entities.GetComponent<ItemComponent>(Owner));
}
if (!invSystem.TryEquip(eventArgs.User, Owner, slotDef.Name, true, inventory: inv))
continue;
hands.PutInHandOrDrop(slotEntity.Value);
}
else
{
hands.Drop(Owner);
if (!TryEquip(inv, slot, eventArgs.User))
hands.PutInHand(_entities.GetComponent<ItemComponent>(Owner));
if (!invSystem.TryEquip(eventArgs.User, Owner, slotDef.Name, true, inventory: inv))
continue;
}
return true;
@@ -96,18 +69,5 @@ namespace Content.Server.Clothing.Components
return false;
}
public bool TryEquip(InventoryComponent inv, Slots slot, EntityUid user)
{
if (!inv.Equip(slot, this, true, out var reason))
{
if (reason != null)
Owner.PopupMessage(user, reason);
return false;
}
return true;
}
}
}

View File

@@ -1,7 +1,5 @@
using Content.Server.Alert;
using Content.Server.Atmos.Components;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Shared.Actions;
using Content.Shared.Actions.Behaviors.Item;
using Content.Shared.Actions.Components;
@@ -9,6 +7,7 @@ using Content.Shared.Alert;
using Content.Shared.Clothing;
using Content.Shared.Interaction;
using Content.Shared.Inventory;
using Content.Shared.Item;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;
@@ -16,15 +15,14 @@ using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
using static Content.Shared.Inventory.EquipmentSlotDefines;
namespace Content.Server.Clothing.Components
{
[RegisterComponent]
[ComponentReference(typeof(IActivate))]
public sealed class MagbootsComponent : SharedMagbootsComponent, IUnequipped, IEquipped, IUse, IActivate
public sealed class MagbootsComponent : SharedMagbootsComponent, IUse, IActivate
{
[ComponentDependency] private ItemComponent? _item = null;
[ComponentDependency] private SharedItemComponent? _item = null;
[ComponentDependency] private ItemActionsComponent? _itemActions = null;
[ComponentDependency] private SpriteComponent? _sprite = null;
@@ -40,7 +38,12 @@ namespace Content.Server.Clothing.Components
{
_on = value;
UpdateContainer();
if (Owner.TryGetContainer(out var container) && EntitySystem.Get<InventorySystem>()
.TryGetSlotEntity(container.Owner, "shoes", out var entityUid) && entityUid == Owner)
{
EntitySystem.Get<MagbootsSystem>().UpdateMagbootEffects(container.Owner, Owner, true, this);
}
_itemActions?.Toggle(ItemActionType.ToggleMagboots, On);
if (_item != null)
_item.EquippedPrefix = On ? "on" : null;
@@ -55,54 +58,6 @@ namespace Content.Server.Clothing.Components
On = !On;
}
void IUnequipped.Unequipped(UnequippedEventArgs eventArgs)
{
if (On && eventArgs.Slot == Slots.SHOES)
{
if (_entMan.TryGetComponent(eventArgs.User, out MovedByPressureComponent? movedByPressure))
{
movedByPressure.Enabled = true;
}
if (_entMan.TryGetComponent(eventArgs.User, out ServerAlertsComponent? alerts))
{
alerts.ClearAlert(AlertType.Magboots);
}
}
}
void IEquipped.Equipped(EquippedEventArgs eventArgs)
{
UpdateContainer();
}
private void UpdateContainer()
{
if (!Owner.TryGetContainer(out var container))
return;
if (_entMan.TryGetComponent(container.Owner, out InventoryComponent? inventoryComponent)
&& inventoryComponent.GetSlotItem(Slots.SHOES)?.Owner == Owner)
{
if (_entMan.TryGetComponent(container.Owner, out MovedByPressureComponent? movedByPressure))
{
movedByPressure.Enabled = false;
}
if (_entMan.TryGetComponent(container.Owner, out ServerAlertsComponent? alerts))
{
if (On)
{
alerts.ShowAlert(AlertType.Magboots);
}
else
{
alerts.ClearAlert(AlertType.Magboots);
}
}
}
}
bool IUse.UseEntity(UseEntityEventArgs eventArgs)
{
Toggle(eventArgs.User);

View File

@@ -1,4 +1,8 @@
using Content.Server.Alert;
using Content.Server.Atmos.Components;
using Content.Server.Clothing.Components;
using Content.Shared.Alert;
using Content.Shared.Inventory.Events;
using Content.Shared.Movement.EntitySystems;
using Content.Shared.Slippery;
using Content.Shared.Verbs;
@@ -16,6 +20,48 @@ namespace Content.Server.Clothing
SubscribeLocalEvent<MagbootsComponent, GetActivationVerbsEvent>(AddToggleVerb);
SubscribeLocalEvent<MagbootsComponent, SlipAttemptEvent>(OnSlipAttempt);
SubscribeLocalEvent<MagbootsComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
SubscribeLocalEvent<MagbootsComponent, GotEquippedEvent>(OnGotEquipped);
SubscribeLocalEvent<MagbootsComponent, GotUnequippedEvent>(OnGotUnequipped);
}
public void UpdateMagbootEffects(EntityUid parent, EntityUid uid, bool state, MagbootsComponent? component)
{
if (!Resolve(uid, ref component))
return;
state = state && component.On;
if (TryComp(parent, out MovedByPressureComponent? movedByPressure))
{
movedByPressure.Enabled = state;
}
if (TryComp(parent, out ServerAlertsComponent? alerts))
{
if (state)
{
alerts.ShowAlert(AlertType.Magboots);
}
else
{
alerts.ClearAlert(AlertType.Magboots);
}
}
}
private void OnGotUnequipped(EntityUid uid, MagbootsComponent component, GotUnequippedEvent args)
{
if (args.Slot == "shoes")
{
UpdateMagbootEffects(args.Equipee, uid, true, component);
}
}
private void OnGotEquipped(EntityUid uid, MagbootsComponent component, GotEquippedEvent args)
{
if (args.Slot == "shoes")
{
UpdateMagbootEffects(args.Equipee, uid, false, component);
}
}
private void OnRefreshMovespeed(EntityUid uid, MagbootsComponent component, RefreshMovementSpeedModifiersEvent args)

View File

@@ -5,8 +5,6 @@ using System.Threading.Tasks;
using Content.Server.Construction.Components;
using Content.Server.DoAfter;
using Content.Server.Hands.Components;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Server.Storage.Components;
using Content.Shared.ActionBlocker;
using Content.Shared.Construction;
@@ -14,6 +12,8 @@ using Content.Shared.Construction.Prototypes;
using Content.Shared.Construction.Steps;
using Content.Shared.Coordinates;
using Content.Shared.Interaction.Helpers;
using Content.Shared.Inventory;
using Content.Shared.Item;
using Content.Shared.Popups;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
@@ -28,6 +28,8 @@ namespace Content.Server.Construction
public partial class ConstructionSystem
{
[Dependency] private readonly InventorySystem _inventorySystem = default!;
// --- WARNING! LEGACY CODE AHEAD! ---
// This entire file contains the legacy code for initial construction.
// This is bound to be replaced by a better alternative (probably using dummy entities)
@@ -61,11 +63,12 @@ namespace Content.Server.Construction
}
}
if (EntityManager.TryGetComponent(user!, out InventoryComponent? inventory))
if (_inventorySystem.TryGetContainerSlotEnumerator(user, out var containerSlotEnumerator))
{
foreach (var held in inventory.GetAllHeldItems())
while (containerSlotEnumerator.MoveNext(out var containerSlot))
{
if (EntityManager.TryGetComponent(held, out ServerStorageComponent? storage))
if(!containerSlot.ContainedEntity.HasValue) continue;
if (EntityManager.TryGetComponent(containerSlot.ContainedEntity.Value, out ServerStorageComponent? storage))
{
foreach (var storedEntity in storage.StoredEntities!)
{
@@ -73,7 +76,7 @@ namespace Content.Server.Construction
}
}
yield return held;
yield return containerSlot.ContainedEntity.Value;
}
}
@@ -330,7 +333,7 @@ namespace Content.Server.Construction
}
if (await Construct(user, "item_construction", constructionGraph, edge, targetNode) is {Valid: true} item &&
EntityManager.TryGetComponent(item, out ItemComponent? itemComp))
EntityManager.TryGetComponent(item, out SharedItemComponent? itemComp))
hands.PutInHandOrDrop(itemComp);
}

View File

@@ -1,15 +1,7 @@
using System.Collections.Generic;
using Content.Server.Items;
using Content.Server.MachineLinking.Components;
using Content.Server.Power.Components;
using Content.Shared.Conveyor;
using Content.Shared.MachineLinking;
using Robust.Server.GameObjects;
using Robust.Shared.Analyzers;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;

View File

@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using Content.Server.Items;
using Content.Server.MachineLinking.Events;
using Content.Server.MachineLinking.Models;
using Content.Server.Power.Components;
using Content.Server.Stunnable;
using Content.Shared.Conveyor;
using Content.Shared.Item;
using Content.Shared.MachineLinking;
using Content.Shared.Movement.Components;
using Content.Shared.Popups;
@@ -104,7 +104,7 @@ namespace Content.Server.Conveyor
return false;
}
if (EntityManager.HasComponent<ItemComponent>(component.Owner))
if (EntityManager.HasComponent<SharedItemComponent>(component.Owner))
{
return false;
}

View File

@@ -1,9 +1,9 @@
using System.Collections.Generic;
using Content.Server.Atmos;
using Content.Server.Disposal.Tube.Components;
using Content.Server.Items;
using Content.Shared.Atmos;
using Content.Shared.Body.Components;
using Content.Shared.Item;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -81,7 +81,7 @@ namespace Content.Server.Disposal.Unit.Components
return false;
}
return _entMan.HasComponent<ItemComponent>(entity) ||
return _entMan.HasComponent<SharedItemComponent>(entity) ||
_entMan.HasComponent<SharedBodyComponent>(entity);
}

View File

@@ -8,13 +8,13 @@ using Content.Server.Disposal.Tube.Components;
using Content.Server.Disposal.Unit.Components;
using Content.Server.DoAfter;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Power.Components;
using Content.Shared.ActionBlocker;
using Content.Shared.Atmos;
using Content.Shared.Disposal;
using Content.Shared.Disposal.Components;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Movement;
using Content.Shared.Popups;
using Content.Shared.Throwing;
@@ -369,7 +369,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
{
// TODO: We need to use a specific collision method (which sloth hasn't coded yet) for actual bounds overlaps.
// Check for itemcomp as we won't just block the disposal unit "sleeping" for something it can't collide with anyway.
if (!EntityManager.HasComponent<ItemComponent>(uid) && body.GetWorldAABB().Intersects(disposalsBounds!.Value)) continue;
if (!EntityManager.HasComponent<SharedItemComponent>(uid) && body.GetWorldAABB().Intersects(disposalsBounds!.Value)) continue;
component.RecentlyEjected.RemoveAt(i);
}
}

View File

@@ -1,8 +1,7 @@
using System;
using System.Threading.Tasks;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Stunnable.Components;
using Content.Shared.Item;
using Content.Shared.Stunnable;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -33,7 +32,7 @@ namespace Content.Server.DoAfter
// NeedHand
private readonly string? _activeHand;
private readonly ItemComponent? _activeItem;
private readonly SharedItemComponent? _activeItem;
public DoAfter(DoAfterEventArgs eventArgs, IEntityManager entityManager)
{

View File

@@ -1,12 +1,11 @@
using Content.Server.DoAfter;
using Content.Server.Engineering.Components;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers;
using Content.Shared.Item;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.Engineering.EntitySystems
{
@@ -47,7 +46,7 @@ namespace Content.Server.Engineering.EntitySystems
var entity = EntityManager.SpawnEntity(component.Prototype, EntityManager.GetComponent<TransformComponent>(component.Owner).Coordinates);
if (EntityManager.TryGetComponent<HandsComponent?>(args.User, out var hands)
&& EntityManager.TryGetComponent<ItemComponent?>(entity, out var item))
&& EntityManager.TryGetComponent<SharedItemComponent?>(entity, out var item))
{
hands.PutInHandOrDrop(item);
}

View File

@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using Content.Server.Flash.Components;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Server.Stunnable;
using Content.Server.Weapon.Melee;
using Content.Shared.Examine;
@@ -20,6 +18,7 @@ using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using InventoryComponent = Content.Shared.Inventory.InventoryComponent;
namespace Content.Server.Flash
{
@@ -28,6 +27,7 @@ namespace Content.Server.Flash
[Dependency] private readonly IEntityLookup _entityLookup = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly StunSystem _stunSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
public override void Initialize()
{
@@ -187,8 +187,8 @@ namespace Content.Server.Flash
private void OnInventoryFlashAttempt(EntityUid uid, InventoryComponent component, FlashAttemptEvent args)
{
// Forward the event to the glasses, if any.
if(component.TryGetSlotItem(EquipmentSlotDefines.Slots.EYES, out ItemComponent? glasses))
RaiseLocalEvent(glasses.Owner, args);
if(_inventorySystem.TryGetSlotEntity(uid, "eyes", out var slotEntity, component))
RaiseLocalEvent(slotEntity.Value, args);
}
private void OnFlashImmunityFlashAttempt(EntityUid uid, FlashImmunityComponent component, FlashAttemptEvent args)

View File

@@ -6,17 +6,12 @@ using Content.Server.Access.Systems;
using Content.Server.Ghost;
using Content.Server.Ghost.Components;
using Content.Server.Hands.Components;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Server.PDA;
using Content.Server.Players;
using Content.Server.Roles;
using Content.Server.Spawners.Components;
using Content.Server.Speech.Components;
using Content.Server.Station;
using Content.Shared.Access.Components;
using Content.Shared.Administration.Logs;
using Content.Shared.CharacterAppearance.Systems;
using Content.Shared.Database;
using Content.Shared.GameTicking;
using Content.Shared.Ghost;
@@ -33,7 +28,6 @@ using Robust.Shared.Map;
using Robust.Shared.Random;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using static Content.Server.Station.StationSystem;
namespace Content.Server.GameTicking
{
@@ -43,6 +37,7 @@ namespace Content.Server.GameTicking
private const string ObserverPrototypeName = "MobObserver";
[Dependency] private readonly IdCardSystem _cardSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
/// <summary>
/// Can't yet be removed because every test ever seems to depend on it. I'll make removing this a different PR.
@@ -244,15 +239,15 @@ namespace Content.Server.GameTicking
#region Equip Helpers
public void EquipStartingGear(EntityUid entity, StartingGearPrototype startingGear, HumanoidCharacterProfile? profile)
{
if (EntityManager.TryGetComponent(entity, out InventoryComponent? inventory))
if (_inventorySystem.TryGetSlots(entity, out var slotDefinitions))
{
foreach (var slot in EquipmentSlotDefines.AllSlots)
foreach (var slot in slotDefinitions)
{
var equipmentStr = startingGear.GetGear(slot, profile);
var equipmentStr = startingGear.GetGear(slot.Name, profile);
if (!string.IsNullOrEmpty(equipmentStr))
{
var equipmentEntity = EntityManager.SpawnEntity(equipmentStr, EntityManager.GetComponent<TransformComponent>(entity).Coordinates);
inventory.Equip(slot, EntityManager.GetComponent<ItemComponent>(equipmentEntity));
_inventorySystem.TryEquip(entity, equipmentEntity, slot.Name, true);
}
}
}
@@ -270,17 +265,10 @@ namespace Content.Server.GameTicking
public void EquipIdCard(EntityUid entity, string characterName, JobPrototype jobPrototype)
{
if (!EntityManager.TryGetComponent(entity, out InventoryComponent? inventory))
if (!_inventorySystem.TryGetSlotEntity(entity, "id", out var idUid))
return;
if (!inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.IDCARD, out ItemComponent? item))
{
return;
}
var itemEntity = item.Owner;
if (!EntityManager.TryGetComponent(itemEntity, out PDAComponent? pdaComponent) || pdaComponent.ContainedID == null)
if (!EntityManager.TryGetComponent(idUid, out PDAComponent? pdaComponent) || pdaComponent.ContainedID == null)
return;
var card = pdaComponent.ContainedID;

View File

@@ -4,8 +4,6 @@ using System.Linq;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Chat.Managers;
using Content.Server.Hands.Components;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Server.PDA;
using Content.Server.Players;
using Content.Server.Spawners.Components;
@@ -42,6 +40,7 @@ public class TraitorDeathMatchRuleSystem : GameRuleSystem
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly MaxTimeRestartRuleSystem _restarter = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
public override string Prototype => "TraitorDeathMatch";
@@ -86,13 +85,13 @@ public class TraitorDeathMatchRuleSystem : GameRuleSystem
// Delete anything that may contain "dangerous" role-specific items.
// (This includes the PDA, as everybody gets the captain PDA in this mode for true-all-access reasons.)
if (mind.OwnedEntity is {Valid: true} owned && TryComp(owned, out InventoryComponent? inventory))
if (mind.OwnedEntity is {Valid: true} owned)
{
var victimSlots = new[] {EquipmentSlotDefines.Slots.IDCARD, EquipmentSlotDefines.Slots.BELT, EquipmentSlotDefines.Slots.BACKPACK};
var victimSlots = new[] {"id", "belt", "back"};
foreach (var slot in victimSlots)
{
if (inventory.TryGetSlotItem(slot, out ItemComponent? vItem))
Del(vItem.Owner);
if(_inventory.TryUnequip(owned, slot, out var entityUid, true, true))
Del(entityUid.Value);
}
// Replace their items:
@@ -101,15 +100,15 @@ public class TraitorDeathMatchRuleSystem : GameRuleSystem
// pda
var newPDA = Spawn(PDAPrototypeName, ownedCoords);
inventory.Equip(EquipmentSlotDefines.Slots.IDCARD, Comp<ItemComponent>(newPDA));
_inventory.TryEquip(owned, newPDA, "id", true);
// belt
var newTmp = Spawn(BeltPrototypeName, ownedCoords);
inventory.Equip(EquipmentSlotDefines.Slots.BELT, Comp<ItemComponent>(newTmp));
_inventory.TryEquip(owned, newTmp, "belt", true);
// backpack
newTmp = Spawn(BackpackPrototypeName, ownedCoords);
inventory.Equip(EquipmentSlotDefines.Slots.BACKPACK, Comp<ItemComponent>(newTmp));
_inventory.TryEquip(owned, newTmp, "back", true);
// Like normal traitors, they need access to a traitor account.
var uplinkAccount = new UplinkAccount(startingBalance, owned);

View File

@@ -1,7 +1,6 @@
using Content.Server.Actions;
using Content.Server.DoAfter;
using Content.Server.Hands.Components;
using Content.Server.Inventory.Components;
using Content.Server.Popups;
using Content.Shared.Actions;
using Content.Shared.Actions.Components;
@@ -10,7 +9,6 @@ using Content.Shared.Damage;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.MobState;
using Content.Shared.MobState.EntitySystems;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Containers;

View File

@@ -4,12 +4,12 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Act;
using Content.Server.Interaction;
using Content.Server.Items;
using Content.Server.Popups;
using Content.Server.Pulling;
using Content.Shared.Audio;
using Content.Shared.Body.Part;
using Content.Shared.Hands.Components;
using Content.Shared.Item;
using Content.Shared.Popups;
using Content.Shared.Pulling.Components;
using Content.Shared.Sound;
@@ -39,7 +39,7 @@ namespace Content.Server.Hands.Components
protected override void OnHeldEntityRemovedFromHand(EntityUid heldEntity, HandState handState)
{
if (_entities.TryGetComponent(heldEntity, out ItemComponent? item))
if (_entities.TryGetComponent(heldEntity, out SharedItemComponent? item))
{
item.RemovedFromSlot();
_entitySystemManager.GetEntitySystem<InteractionSystem>().UnequippedHandInteraction(Owner, heldEntity, handState);
@@ -153,19 +153,19 @@ namespace Content.Server.Hands.Components
/// <summary>
/// Tries to get the ItemComponent on the entity held by a hand.
/// </summary>
public ItemComponent? GetItem(string handName)
public SharedItemComponent? GetItem(string handName)
{
if (!TryGetHeldEntity(handName, out var heldEntity))
return null;
_entities.TryGetComponent(heldEntity, out ItemComponent? item);
_entities.TryGetComponent(heldEntity, out SharedItemComponent? item);
return item;
}
/// <summary>
/// Tries to get the ItemComponent on the entity held by a hand.
/// </summary>
public bool TryGetItem(string handName, [NotNullWhen(true)] out ItemComponent? item)
public bool TryGetItem(string handName, [NotNullWhen(true)] out SharedItemComponent? item)
{
item = null;
@@ -178,23 +178,23 @@ namespace Content.Server.Hands.Components
/// <summary>
/// Tries to get the ItemComponent off the entity in the active hand.
/// </summary>
public ItemComponent? GetActiveHand
public SharedItemComponent? GetActiveHand
{
get
{
if (!TryGetActiveHeldEntity(out var heldEntity))
return null;
_entities.TryGetComponent(heldEntity, out ItemComponent? item);
_entities.TryGetComponent(heldEntity, out SharedItemComponent? item);
return item;
}
}
public IEnumerable<ItemComponent> GetAllHeldItems()
public IEnumerable<SharedItemComponent> GetAllHeldItems()
{
foreach (var entity in GetAllHeldEntities())
{
if (_entities.TryGetComponent(entity, out ItemComponent? item))
if (_entities.TryGetComponent(entity, out SharedItemComponent? item))
yield return item;
}
}
@@ -202,7 +202,7 @@ namespace Content.Server.Hands.Components
/// <summary>
/// Checks if any hand can pick up an item.
/// </summary>
public bool CanPutInHand(ItemComponent item, bool mobCheck = true)
public bool CanPutInHand(SharedItemComponent item, bool mobCheck = true)
{
var entity = item.Owner;

View File

@@ -3,8 +3,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Hands.Components;
using Content.Server.Interaction;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Server.Inventory;
using Content.Server.Stack;
using Content.Server.Storage.Components;
using Content.Server.Throwing;
@@ -13,6 +12,7 @@ using Content.Shared.Examine;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
using Content.Shared.Input;
using Content.Shared.Inventory;
using Content.Shared.Physics.Pull;
using Content.Shared.Popups;
using JetBrains.Annotations;
@@ -26,14 +26,13 @@ using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Players;
using Robust.Shared.Utility;
using static Content.Shared.Inventory.EquipmentSlotDefines;
namespace Content.Server.Hands.Systems
{
[UsedImplicitly]
internal sealed class HandsSystem : SharedHandsSystem
{
[Dependency] private readonly InteractionSystem _interactionSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly StackSystem _stackSystem = default!;
[Dependency] private readonly HandVirtualItemSystem _virtualItemSystem = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
@@ -261,15 +260,15 @@ namespace Content.Server.Hands.Systems
private void HandleSmartEquipBackpack(ICommonSession? session)
{
HandleSmartEquip(session, Slots.BACKPACK);
HandleSmartEquip(session, "back");
}
private void HandleSmartEquipBelt(ICommonSession? session)
{
HandleSmartEquip(session, Slots.BELT);
HandleSmartEquip(session, "belt");
}
private void HandleSmartEquip(ICommonSession? session, Slots equipmentSlot)
private void HandleSmartEquip(ICommonSession? session, string equipmentSlot)
{
if (session is not IPlayerSession playerSession)
return;
@@ -277,14 +276,13 @@ namespace Content.Server.Hands.Systems
if (playerSession.AttachedEntity is not {Valid: true} plyEnt || !EntityManager.EntityExists(plyEnt))
return;
if (!EntityManager.TryGetComponent(plyEnt, out SharedHandsComponent? hands) ||
!EntityManager.TryGetComponent(plyEnt, out InventoryComponent? inventory))
if (!EntityManager.TryGetComponent(plyEnt, out SharedHandsComponent? hands))
return;
if (!inventory.TryGetSlotItem(equipmentSlot, out ItemComponent? equipmentItem) ||
!EntityManager.TryGetComponent(equipmentItem.Owner, out ServerStorageComponent? storageComponent))
if (!_inventorySystem.TryGetSlotEntity(plyEnt, equipmentSlot, out var slotEntity) ||
!EntityManager.TryGetComponent(slotEntity, out ServerStorageComponent? storageComponent))
{
plyEnt.PopupMessage(Loc.GetString("hands-system-missing-equipment-slot", ("slotName", SlotNames[equipmentSlot].ToLower())));
plyEnt.PopupMessage(Loc.GetString("hands-system-missing-equipment-slot", ("slotName", equipmentSlot)));
return;
}
@@ -296,7 +294,7 @@ namespace Content.Server.Hands.Systems
{
if (storageComponent.StoredEntities.Count == 0)
{
plyEnt.PopupMessage(Loc.GetString("hands-system-empty-equipment-slot", ("slotName", SlotNames[equipmentSlot].ToLower())));
plyEnt.PopupMessage(Loc.GetString("hands-system-empty-equipment-slot", ("slotName", equipmentSlot)));
}
else
{

View File

@@ -5,16 +5,15 @@ using System.Threading.Tasks;
using Content.Server.Administration.Logs;
using Content.Server.CombatMode;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Pulling;
using Content.Server.Storage.Components;
using Content.Shared.ActionBlocker;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.DragDrop;
using Content.Shared.Input;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers;
using Content.Shared.Item;
using Content.Shared.Popups;
using Content.Shared.Pulling.Components;
using Content.Shared.Weapons.Melee;
@@ -358,7 +357,7 @@ namespace Content.Server.Interaction
}
}
}
else if (!wideAttack && target != null && HasComp<ItemComponent>(target.Value))
else if (!wideAttack && target != null && HasComp<SharedItemComponent>(target.Value))
{
// We pick up items if our hand is empty, even if we're in combat mode.
InteractHand(user, target.Value);

View File

@@ -1,40 +0,0 @@
using Content.Shared.Hands;
using Content.Shared.Inventory;
using Content.Shared.Popups;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.Inventory.Components
{
/// <summary>
/// Pops up a message when equipped / unequipped (including hands).
/// For debugging purposes.
/// </summary>
[RegisterComponent]
public class DebugEquipComponent : Component, IEquipped, IEquippedHand, IUnequipped, IUnequippedHand
{
[Dependency] private readonly IEntityManager _entMan = default!;
public override string Name => "DebugEquip";
void IEquipped.Equipped(EquippedEventArgs eventArgs)
{
eventArgs.User.PopupMessage("equipped " + _entMan.GetComponent<MetaDataComponent>(Owner).EntityName);
}
void IEquippedHand.EquippedHand(EquippedHandEventArgs eventArgs)
{
eventArgs.User.PopupMessage("equipped hand " + _entMan.GetComponent<MetaDataComponent>(Owner).EntityName);
}
void IUnequipped.Unequipped(UnequippedEventArgs eventArgs)
{
eventArgs.User.PopupMessage("unequipped " + _entMan.GetComponent<MetaDataComponent>(Owner).EntityName);
}
void IUnequippedHand.UnequippedHand(UnequippedHandEventArgs eventArgs)
{
eventArgs.User.PopupMessage("unequipped hand" + _entMan.GetComponent<MetaDataComponent>(Owner).EntityName);
}
}
}

View File

@@ -1,91 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using Content.Server.Items;
using Content.Shared.Item;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using static Content.Shared.Inventory.EquipmentSlotDefines;
namespace Content.Server.Inventory.Components
{
// Handles the special behavior of pockets/ID card slot and their relation to uniforms.
[RegisterComponent]
[ComponentReference(typeof(IInventoryController))]
public class HumanInventoryControllerComponent : Component, IInventoryController
{
public override string Name => "HumanInventoryController";
private InventoryComponent _inventory = default!;
protected override void Initialize()
{
base.Initialize();
_inventory = Owner.EnsureComponent<InventoryComponent>();
}
bool IInventoryController.CanEquip(Slots slot, EntityUid entity, bool flagsCheck, [NotNullWhen(false)] out string? reason)
{
var slotMask = SlotMasks[slot];
reason = null;
if ((slotMask & (SlotFlags.POCKET | SlotFlags.IDCARD)) != SlotFlags.NONE)
{
// Can't wear stuff in ID card or pockets unless you have a uniform.
if (_inventory.GetSlotItem(Slots.INNERCLOTHING) == null)
{
reason = Loc.GetString(slotMask == SlotFlags.IDCARD
? "human-inventory-controller-component-need-uniform-to-store-in-id-slot-text"
: "human-inventory-controller-component-need-uniform-to-store-in-pockets-text");
return false;
}
if (slotMask == SlotFlags.POCKET)
{
var itemComponent = IoCManager.Resolve<IEntityManager>().GetComponent<ItemComponent>(entity);
// If this item is small enough then it always fits in pockets.
if (itemComponent.Size <= (int) ReferenceSizes.Pocket)
{
return true;
}
else if (!flagsCheck)
{
reason = Loc.GetString("human-inventory-controller-component-too-large-text");
}
}
}
// Standard flag check.
return flagsCheck;
}
public void CheckUniformExists() { Owner.SpawnTimer(0, DropIdAndPocketsIfWeNoLongerHaveAUniform); }
// Hey, it's descriptive.
private void DropIdAndPocketsIfWeNoLongerHaveAUniform()
{
if (Deleted)
{
return;
}
if (_inventory.GetSlotItem(Slots.INNERCLOTHING) != null)
{
return;
}
void DropMaybe(Slots slot)
{
if (_inventory.GetSlotItem(slot) != null)
{
_inventory.Unequip(slot);
}
}
DropMaybe(Slots.POCKET1);
DropMaybe(Slots.POCKET2);
DropMaybe(Slots.IDCARD);
}
}
}

View File

@@ -1,28 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using Robust.Shared.GameObjects;
using static Content.Shared.Inventory.EquipmentSlotDefines;
namespace Content.Server.Inventory.Components
{
/// <summary>
/// Allows for overriding inventory-related behavior on an entity.
/// </summary>
public interface IInventoryController
{
/// <summary>
/// Can be implemented to override "can this item be equipped" behavior.
/// </summary>
/// <param name="slot">The slot to be equipped into.</param>
/// <param name="entity">The entity to equip.</param>
/// <param name="flagsCheck">Whether the entity passes default slot masks & flags checks.</param>
/// <param name="reason">The translated reason why the item cannot be equiped, if this function returns false. Can be null.</param>
/// <returns>True if the entity can be equipped, false otherwise</returns>
bool CanEquip(Slots slot, EntityUid entity, bool flagsCheck, [NotNullWhen(false)] out string? reason)
{
reason = null;
return flagsCheck;
}
bool CanEquip(Slots slot, EntityUid entity, bool flagsCheck) => CanEquip(slot, entity, flagsCheck, out _);
}
}

View File

@@ -1,576 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Clothing.Components;
using Content.Server.Hands.Components;
using Content.Server.Interaction;
using Content.Server.Items;
using Content.Server.Storage.Components;
using Content.Shared.ActionBlocker;
using Content.Shared.Acts;
using Content.Shared.Inventory;
using Content.Shared.Movement.EntitySystems;
using Content.Shared.Popups;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Players;
using Robust.Shared.ViewVariables;
using static Content.Shared.Inventory.EquipmentSlotDefines;
using static Content.Shared.Inventory.SharedInventoryComponent.ClientInventoryMessage;
namespace Content.Server.Inventory.Components
{
[RegisterComponent]
[ComponentReference(typeof(SharedInventoryComponent))]
public class InventoryComponent : SharedInventoryComponent, IExAct
{
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private readonly IEntityManager _entities = default!;
[ViewVariables] private readonly Dictionary<Slots, ContainerSlot> _slotContainers = new();
private KeyValuePair<Slots, (EntityUid entity, bool fits)>? _hoverEntity;
public IEnumerable<Slots> Slots => _slotContainers.Keys;
public event Action? OnItemChanged;
protected override void Initialize()
{
base.Initialize();
foreach (var slotName in InventoryInstance.SlotMasks)
{
if (slotName != EquipmentSlotDefines.Slots.NONE)
{
AddSlot(slotName);
}
}
}
protected override void OnRemove()
{
var slots = _slotContainers.Keys.ToList();
foreach (var slot in slots)
{
if (TryGetSlotItem(slot, out ItemComponent? item))
{
_entities.DeleteEntity(item.Owner);
}
RemoveSlot(slot);
}
base.OnRemove();
}
public IEnumerable<EntityUid> GetAllHeldItems()
{
foreach (var (_, container) in _slotContainers)
{
foreach (var entity in container.ContainedEntities)
{
yield return entity;
}
}
}
/// <summary>
/// Helper to get container name for specified slot on this component
/// </summary>
/// <param name="slot"></param>
/// <returns></returns>
private string GetSlotString(Slots slot)
{
return Name + "_" + Enum.GetName(typeof(Slots), slot);
}
/// <summary>
/// Gets the clothing equipped to the specified slot.
/// </summary>
/// <param name="slot">The slot to get the item for.</param>
/// <returns>Null if the slot is empty, otherwise the item.</returns>
public ItemComponent? GetSlotItem(Slots slot)
{
return GetSlotItem<ItemComponent>(slot);
}
public IEnumerable<T?> LookupItems<T>() where T : Component
{
return _slotContainers.Values
.SelectMany(x => x.ContainedEntities.Select(e => _entities.GetComponentOrNull<T>(e)))
.Where(x => x != null);
}
public T? GetSlotItem<T>(Slots slot) where T : ItemComponent
{
if (!_slotContainers.ContainsKey(slot))
{
return null;
}
var containedEntity = _slotContainers[slot].ContainedEntity;
if (containedEntity != null && _entities.GetComponent<MetaDataComponent>(containedEntity.Value).EntityDeleted)
{
_slotContainers.Remove(slot);
containedEntity = null;
Dirty();
}
return containedEntity.HasValue ? _entities.GetComponent<T>(containedEntity.Value) : null;
}
public bool TryGetSlotItem<T>(Slots slot, [NotNullWhen(true)] out T? itemComponent) where T : ItemComponent
{
itemComponent = GetSlotItem<T>(slot);
return itemComponent != null;
}
/// <summary>
/// Equips slothing to the specified slot.
/// </summary>
/// <remarks>
/// This will fail if there is already an item in the specified slot.
/// </remarks>
/// <param name="slot">The slot to put the item in.</param>
/// <param name="item">The item to insert into the slot.</param>
/// <param name="mobCheck">Whether to perform an ActionBlocker check to the entity.</param>
/// <param name="reason">The translated reason why the item cannot be equipped, if this function returns false. Can be null.</param>
/// <returns>True if the item was successfully inserted, false otherwise.</returns>
public bool Equip(Slots slot, ItemComponent item, bool mobCheck, [NotNullWhen(false)] out string? reason)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item),
"Clothing must be passed here. To remove some clothing from a slot, use Unequip()");
}
if (!CanEquip(slot, item, mobCheck, out reason))
{
return false;
}
var inventorySlot = _slotContainers[slot];
if (!inventorySlot.Insert(item.Owner))
{
reason = Loc.GetString("inventory-component-on-equip-cannot");
return false;
}
// TODO: Make clothing component not inherit ItemComponent, for fuck's sake.
// TODO: Make clothing component not required for playing a sound on equip... Move it to its own component.
if (mobCheck && item is ClothingComponent { EquipSound: {} equipSound })
{
SoundSystem.Play(Filter.Pvs(Owner), equipSound.GetSound(), Owner, AudioParams.Default.WithVolume(-2f));
}
_entitySystemManager.GetEntitySystem<InteractionSystem>().EquippedInteraction(Owner, item.Owner, slot);
OnItemChanged?.Invoke();
Dirty();
UpdateMovementSpeed();
return true;
}
public bool Equip(Slots slot, ItemComponent item, bool mobCheck = true) =>
Equip(slot, item, mobCheck, out var _);
public bool Equip(Slots slot, EntityUid entity, bool mobCheck = true) =>
Equip(slot, _entities.GetComponent<ItemComponent>(entity), mobCheck);
/// <summary>
/// Checks whether an item can be put in the specified slot.
/// </summary>
/// <param name="slot">The slot to check for.</param>
/// <param name="item">The item to check for.</param>
/// <param name="reason">The translated reason why the item cannot be equiped, if this function returns false. Can be null.</param>
/// <returns>True if the item can be inserted into the specified slot.</returns>
public bool CanEquip(Slots slot, ItemComponent item, bool mobCheck, [NotNullWhen(false)] out string? reason)
{
var pass = false;
reason = null;
if (mobCheck && !EntitySystem.Get<ActionBlockerSystem>().CanEquip(Owner))
{
reason = Loc.GetString("inventory-component-can-equip-cannot");
return false;
}
if (item is ClothingComponent clothing)
{
if (clothing.SlotFlags != SlotFlags.PREVENTEQUIP && (clothing.SlotFlags & SlotMasks[slot]) != 0)
{
pass = true;
}
else
{
reason = Loc.GetString("inventory-component-can-equip-does-not-fit");
}
}
if (_entities.TryGetComponent(Owner, out IInventoryController? controller))
{
pass = controller.CanEquip(slot, item.Owner, pass, out var controllerReason);
reason = controllerReason ?? reason;
}
if (!pass)
{
reason = reason ?? Loc.GetString("inventory-component-can-equip-cannot");
return false;
}
var canEquip = pass && _slotContainers[slot].CanInsert(item.Owner);
if (!canEquip)
{
reason = Loc.GetString("inventory-component-can-equip-cannot");
}
return canEquip;
}
public bool CanEquip(Slots slot, ItemComponent item, bool mobCheck = true) =>
CanEquip(slot, item, mobCheck, out var _);
public bool CanEquip(Slots slot, EntityUid entity, bool mobCheck = true) =>
CanEquip(slot, _entities.GetComponent<ItemComponent>(entity), mobCheck);
/// <summary>
/// Drops the item in a slot.
/// </summary>
/// <param name="slot">The slot to drop the item from.</param>
/// <returns>True if an item was dropped, false otherwise.</returns>
/// <param name="mobCheck">Whether to perform an ActionBlocker check to the entity.</param>
public bool Unequip(Slots slot, bool mobCheck = true)
{
if (!CanUnequip(slot, mobCheck))
{
return false;
}
var inventorySlot = _slotContainers[slot];
if (inventorySlot.ContainedEntity is not {Valid: true} entity)
{
return false;
}
if (!inventorySlot.Remove(entity))
{
return false;
}
// TODO: The item should be dropped to the container our owner is in, if any.
_entities.GetComponent<TransformComponent>(entity).AttachParentToContainerOrGrid();
_entitySystemManager.GetEntitySystem<InteractionSystem>().UnequippedInteraction(Owner, entity, slot);
OnItemChanged?.Invoke();
Dirty();
UpdateMovementSpeed();
return true;
}
private void UpdateMovementSpeed()
{
EntitySystem.Get<MovementSpeedModifierSystem>().RefreshMovementSpeedModifiers(Owner);
}
public void ForceUnequip(Slots slot)
{
var inventorySlot = _slotContainers[slot];
if (inventorySlot.ContainedEntity is not {Valid: true} entity)
{
return;
}
var item = _entities.GetComponent<ItemComponent>(entity);
inventorySlot.ForceRemove(entity);
var itemTransform = _entities.GetComponent<TransformComponent>(entity);
itemTransform.AttachParentToContainerOrGrid();
_entitySystemManager.GetEntitySystem<InteractionSystem>().UnequippedInteraction(Owner, item.Owner, slot);
OnItemChanged?.Invoke();
Dirty();
}
/// <summary>
/// Checks whether an item can be dropped from the specified slot.
/// </summary>
/// <param name="slot">The slot to check for.</param>
/// <param name="mobCheck">Whether to perform an ActionBlocker check to the entity.</param>
/// <returns>
/// True if there is an item in the slot and it can be dropped, false otherwise.
/// </returns>
public bool CanUnequip(Slots slot, bool mobCheck = true)
{
if (mobCheck && !EntitySystem.Get<ActionBlockerSystem>().CanUnequip(Owner))
return false;
var inventorySlot = _slotContainers[slot];
return inventorySlot.ContainedEntity != null && inventorySlot.CanRemove(inventorySlot.ContainedEntity.Value);
}
/// <summary>
/// Adds a new slot to this inventory component.
/// </summary>
/// <param name="slot">The name of the slot to add.</param>
/// <exception cref="InvalidOperationException">
/// Thrown if the slot with specified name already exists.
/// </exception>
public ContainerSlot AddSlot(Slots slot)
{
if (HasSlot(slot))
{
throw new InvalidOperationException($"Slot '{slot}' already exists.");
}
Dirty();
var container = ContainerHelpers.CreateContainer<ContainerSlot>(Owner, GetSlotString(slot));
container.OccludesLight = false;
_slotContainers[slot] = container;
OnItemChanged?.Invoke();
return _slotContainers[slot];
}
/// <summary>
/// Removes a slot from this inventory component.
/// </summary>
/// <remarks>
/// If the slot contains an item, the item is dropped.
/// </remarks>
/// <param name="slot">The name of the slot to remove.</param>
public void RemoveSlot(Slots slot)
{
if (!HasSlot(slot))
{
throw new InvalidOperationException($"Slot '{slot}' does not exist.");
}
ForceUnequip(slot);
var container = _slotContainers[slot];
container.Shutdown();
_slotContainers.Remove(slot);
OnItemChanged?.Invoke();
Dirty();
}
/// <summary>
/// Checks whether a slot with the specified name exists.
/// </summary>
/// <param name="slot">The slot name to check.</param>
/// <returns>True if the slot exists, false otherwise.</returns>
public bool HasSlot(Slots slot)
{
return _slotContainers.ContainsKey(slot);
}
/// <summary>
/// The underlying Container System just notified us that an entity was removed from it.
/// We need to make sure we process that removed entity as being unequipped from the slot.
/// </summary>
public void ForceUnequip(IContainer container, EntityUid entity)
{
// make sure this is one of our containers.
// Technically the correct way would be to enumerate the possible slot names
// comparing with this container, but I might as well put the dictionary to good use.
if (container is not ContainerSlot slot || !_slotContainers.ContainsValue(slot))
return;
if (_entities.TryGetComponent(entity, out ItemComponent? itemComp))
{
itemComp.RemovedFromSlot();
}
OnItemChanged?.Invoke();
Dirty();
}
/// <summary>
/// Message that tells us to equip or unequip items from the inventory slots
/// </summary>
/// <param name="msg"></param>
private async void HandleInventoryMessage(ClientInventoryMessage msg)
{
switch (msg.Updatetype)
{
case ClientInventoryUpdate.Equip:
{
var hands = _entities.GetComponent<HandsComponent>(Owner);
var activeHand = hands.ActiveHand;
var activeItem = hands.GetActiveHand;
if (activeHand != null && activeItem != null && _entities.TryGetComponent(activeItem.Owner, out ItemComponent? item))
{
hands.TryDropNoInteraction();
if (!Equip(msg.Inventoryslot, item, true, out var reason))
{
hands.PutInHand(item);
Owner.PopupMessageCursor(reason);
}
}
break;
}
case ClientInventoryUpdate.Use:
{
var interactionSystem = _entitySystemManager.GetEntitySystem<InteractionSystem>();
var hands = _entities.GetComponent<HandsComponent>(Owner);
var activeHand = hands.GetActiveHand;
var itemContainedInSlot = GetSlotItem(msg.Inventoryslot);
if (itemContainedInSlot != null)
{
if (activeHand != null)
{
await interactionSystem.InteractUsing(Owner, activeHand.Owner, itemContainedInSlot.Owner,
new EntityCoordinates());
}
else if (Unequip(msg.Inventoryslot))
{
hands.PutInHand(itemContainedInSlot);
}
}
break;
}
case ClientInventoryUpdate.Hover:
{
var hands = _entities.GetComponent<HandsComponent>(Owner);
var activeHand = hands.GetActiveHand;
if (activeHand != null && GetSlotItem(msg.Inventoryslot) == null)
{
var canEquip = CanEquip(msg.Inventoryslot, activeHand, true, out var reason);
_hoverEntity =
new KeyValuePair<Slots, (EntityUid entity, bool fits)>(msg.Inventoryslot,
(Uid: activeHand.Owner, canEquip));
Dirty();
}
break;
}
}
}
/// <inheritdoc />
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel,
ICommonSession? session = null)
{
base.HandleNetworkMessage(message, netChannel, session);
if (session == null)
{
throw new ArgumentNullException(nameof(session));
}
switch (message)
{
case ClientInventoryMessage msg:
var playerentity = session.AttachedEntity;
if (playerentity == Owner)
HandleInventoryMessage(msg);
break;
case OpenSlotStorageUIMessage msg:
if (!HasSlot(msg.Slot)) // client input sanitization
return;
var item = GetSlotItem(msg.Slot);
if (item != null && _entities.TryGetComponent(item.Owner, out ServerStorageComponent? storage))
storage.OpenStorageUI(Owner);
break;
}
}
public override ComponentState GetComponentState()
{
var list = new List<KeyValuePair<Slots, EntityUid>>();
foreach (var (slot, container) in _slotContainers)
{
if (container is {ContainedEntity: { }})
{
list.Add(new KeyValuePair<Slots, EntityUid>(slot, container.ContainedEntity.Value));
}
}
var hover = _hoverEntity;
_hoverEntity = null;
return new InventoryComponentState(list, hover);
}
void IExAct.OnExplosion(ExplosionEventArgs eventArgs)
{
if (eventArgs.Severity < ExplosionSeverity.Heavy)
{
return;
}
foreach (var slot in _slotContainers.Values.ToList())
{
foreach (var entity in slot.ContainedEntities)
{
var exActs = _entities.GetComponents<IExAct>(entity).ToList();
foreach (var exAct in exActs)
{
exAct.OnExplosion(eventArgs);
}
}
}
}
public override bool IsEquipped(EntityUid item)
{
if (item == default) return false;
foreach (var containerSlot in _slotContainers.Values)
{
// we don't want a recursive check here
if (containerSlot.Contains(item))
{
return true;
}
}
return false;
}
public override bool TryGetSlot(Slots slot, [NotNullWhen(true)] out EntityUid? item)
{
if (_slotContainers.TryGetValue(slot, out var container))
{
item = container.ContainedEntity;
return item != null;
}
item = null;
return false;
}
}
}

View File

@@ -1,48 +0,0 @@
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using static Content.Shared.Inventory.EquipmentSlotDefines;
namespace Content.Server.Inventory
{
public static class InventoryHelpers
{
public static bool SpawnItemInSlot(this InventoryComponent inventory, Slots slot, string prototype, bool mobCheck = false)
{
var entityManager = IoCManager.Resolve<IEntityManager>();
var protoManager = IoCManager.Resolve<IPrototypeManager>();
var user = inventory.Owner;
// Let's do nothing if the owner of the inventory has been deleted.
if (entityManager.Deleted(user))
return false;
// If we don't have that slot or there's already an item there, we do nothing.
if (!inventory.HasSlot(slot) || inventory.TryGetSlotItem(slot, out ItemComponent? _))
return false;
// If the prototype in question doesn't exist, we do nothing.
if (!protoManager.HasIndex<EntityPrototype>(prototype))
return false;
// Let's spawn this first...
var item = entityManager.SpawnEntity(prototype, entityManager.GetComponent<TransformComponent>(user).MapPosition);
// Helper method that deletes the item and returns false.
bool DeleteItem()
{
entityManager.DeleteEntity(item);
return false;
}
// If this doesn't have an item component, then we can't do anything with it.
if (!entityManager.TryGetComponent(item, out ItemComponent? itemComp))
return DeleteItem();
// We finally try to equip the item, otherwise we delete it.
return inventory.Equip(slot, itemComp, mobCheck) || DeleteItem();
}
}
}

View File

@@ -1,88 +0,0 @@
using Content.Server.Atmos;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Server.Temperature.Systems;
using Content.Shared.Inventory;
using Content.Shared.Slippery;
using Content.Shared.Damage;
using Content.Shared.Electrocution;
using Content.Shared.Movement.EntitySystems;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
namespace Content.Server.Inventory
{
class InventorySystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<HumanInventoryControllerComponent, EntRemovedFromContainerMessage>(HandleRemovedFromContainer);
SubscribeLocalEvent<InventoryComponent, EntRemovedFromContainerMessage>(HandleInvRemovedFromContainer);
SubscribeLocalEvent<InventoryComponent, HighPressureEvent>(OnHighPressureEvent);
SubscribeLocalEvent<InventoryComponent, LowPressureEvent>(OnLowPressureEvent);
SubscribeLocalEvent<InventoryComponent, DamageModifyEvent>(OnDamageModify);
SubscribeLocalEvent<InventoryComponent, ElectrocutionAttemptEvent>(OnElectrocutionAttempt);
SubscribeLocalEvent<InventoryComponent, SlipAttemptEvent>(OnSlipAttemptEvent);
SubscribeLocalEvent<InventoryComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
SubscribeLocalEvent<InventoryComponent, ModifyChangedTemperatureEvent>(OnModifyTemperature);
}
private void OnModifyTemperature(EntityUid uid, InventoryComponent component, ModifyChangedTemperatureEvent args)
{
RelayInventoryEvent(component, args);
}
private void OnSlipAttemptEvent(EntityUid uid, InventoryComponent component, SlipAttemptEvent args)
{
if (component.TryGetSlotItem(EquipmentSlotDefines.Slots.SHOES, out ItemComponent? shoes))
{
RaiseLocalEvent(shoes.Owner, args, false);
}
}
private void OnRefreshMovespeed(EntityUid uid, InventoryComponent component, RefreshMovementSpeedModifiersEvent args)
{
RelayInventoryEvent(component, args);
}
private static void HandleInvRemovedFromContainer(EntityUid uid, InventoryComponent component, EntRemovedFromContainerMessage args)
{
component.ForceUnequip(args.Container, args.Entity);
}
private static void HandleRemovedFromContainer(EntityUid uid, HumanInventoryControllerComponent component, EntRemovedFromContainerMessage args)
{
component.CheckUniformExists();
}
private void OnHighPressureEvent(EntityUid uid, InventoryComponent component, HighPressureEvent args)
{
RelayInventoryEvent(component, args);
}
private void OnLowPressureEvent(EntityUid uid, InventoryComponent component, LowPressureEvent args)
{
RelayInventoryEvent(component, args);
}
private void OnElectrocutionAttempt(EntityUid uid, InventoryComponent component, ElectrocutionAttemptEvent args)
{
RelayInventoryEvent(component, args);
}
private void OnDamageModify(EntityUid uid, InventoryComponent component, DamageModifyEvent args)
{
RelayInventoryEvent(component, args);
}
private void RelayInventoryEvent<T>(InventoryComponent component, T args) where T : EntityEventArgs
{
foreach (var equipped in component.GetAllHeldItems())
{
RaiseLocalEvent(equipped, args, false);
}
}
}
}

View File

@@ -0,0 +1,8 @@
using Content.Shared.Inventory;
using Robust.Shared.GameObjects;
namespace Content.Server.Inventory;
[RegisterComponent]
[ComponentReference(typeof(InventoryComponent))]
public class ServerInventoryComponent : InventoryComponent { }

View File

@@ -0,0 +1,70 @@
using Content.Server.Atmos;
using Content.Server.Hands.Components;
using Content.Server.Interaction;
using Content.Server.Storage.Components;
using Content.Server.Temperature.Systems;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using InventoryComponent = Content.Shared.Inventory.InventoryComponent;
namespace Content.Server.Inventory
{
class ServerInventorySystem : InventorySystem
{
[Dependency] private readonly InteractionSystem _interactionSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<InventoryComponent, HighPressureEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, LowPressureEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, ModifyChangedTemperatureEvent>(RelayInventoryEvent);
SubscribeNetworkEvent<TryEquipNetworkMessage>(OnNetworkEquip);
SubscribeNetworkEvent<TryUnequipNetworkMessage>(OnNetworkUnequip);
SubscribeNetworkEvent<OpenSlotStorageNetworkMessage>(OnOpenSlotStorage);
SubscribeNetworkEvent<UseSlotNetworkMessage>(OnUseSlot);
}
private void OnUseSlot(UseSlotNetworkMessage ev)
{
if (!TryComp<HandsComponent>(ev.Uid, out var hands) || !TryGetSlotEntity(ev.Uid, ev.Slot, out var itemUid))
return;
var activeHand = hands.GetActiveHand;
if (activeHand != null)
{
_interactionSystem.InteractUsing(ev.Uid, activeHand.Owner, itemUid.Value,
new EntityCoordinates());
}
else if (TryUnequip(ev.Uid, ev.Slot))
{
hands.PutInHand(itemUid.Value);
}
}
private void OnOpenSlotStorage(OpenSlotStorageNetworkMessage ev)
{
if (TryGetSlotEntity(ev.Uid, ev.Slot, out var entityUid) && TryComp<ServerStorageComponent>(entityUid, out var storageComponent))
{
storageComponent.OpenStorageUI(ev.Uid);
}
}
private void OnNetworkUnequip(TryUnequipNetworkMessage ev)
{
TryUnequip(ev.Actor, ev.Target, ev.Slot, ev.Silent, ev.Force);
}
private void OnNetworkEquip(TryEquipNetworkMessage ev)
{
TryEquip(ev.Actor, ev.Target, ev.ItemUid, ev.Slot, ev.Silent, ev.Force);
}
}
}

View File

@@ -1,30 +0,0 @@
using System.Collections.Generic;
using Content.Shared.Item;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.Items
{
[RegisterComponent]
[ComponentReference(typeof(SharedItemComponent))]
public class ItemComponent : SharedItemComponent
{
public override void RemovedFromSlot()
{
foreach (var component in IoCManager.Resolve<IEntityManager>().GetComponents<ISpriteRenderableComponent>(Owner))
{
component.Visible = true;
}
}
public override void EquippedToSlot()
{
foreach (var component in IoCManager.Resolve<IEntityManager>().GetComponents<ISpriteRenderableComponent>(Owner))
{
component.Visible = false;
}
}
}
}

View File

@@ -1,6 +1,6 @@
using Content.Server.Hands.Components;
using Content.Server.Holiday;
using Content.Server.Items;
using Content.Shared.Item;
using Content.Shared.Roles;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
@@ -33,7 +33,7 @@ namespace Content.Server.Jobs
var entity = entMan.SpawnEntity(Prototype, entMan.GetComponent<TransformComponent>(mob).Coordinates);
if (!entMan.TryGetComponent(entity, out ItemComponent? item) || !entMan.TryGetComponent(mob, out HandsComponent? hands))
if (!entMan.TryGetComponent(entity, out SharedItemComponent? item) || !entMan.TryGetComponent(mob, out HandsComponent? hands))
return;
hands.PutInHand(item, false);

View File

@@ -6,7 +6,6 @@ using Content.Server.Chat.Managers;
using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Popups;
using Content.Server.Power.Components;
using Content.Server.UserInterface;
@@ -16,6 +15,7 @@ using Content.Shared.Body.Part;
using Content.Shared.Chemistry.Components;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Kitchen;
using Content.Shared.Kitchen.Components;
using Content.Shared.Popups;
@@ -284,7 +284,7 @@ namespace Content.Server.Kitchen.Components
return true;
}
if (!_entities.TryGetComponent(itemEntity, typeof(ItemComponent), out var food))
if (!_entities.TryGetComponent(itemEntity, typeof(SharedItemComponent), out var food))
{
Owner.PopupMessage(eventArgs.User, "microwave-component-interact-using-transfer-fail");
return false;

View File

@@ -2,13 +2,13 @@
using System.Linq;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Kitchen.Components;
using Content.Server.Kitchen.Events;
using Content.Server.Power.Components;
using Content.Server.Stack;
using Content.Server.UserInterface;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Kitchen.Components;
using Content.Shared.Popups;
using Content.Shared.Random.Helpers;
@@ -264,7 +264,7 @@ namespace Content.Server.Kitchen.EntitySystems
if (user == null ||
!EntityManager.TryGetComponent<HandsComponent?>(user.Value, out var hands) ||
!EntityManager.TryGetComponent<ItemComponent?>(beaker, out var item))
!EntityManager.TryGetComponent<SharedItemComponent?>(beaker, out var item))
return;
hands.PutInHandOrDrop(item);

View File

@@ -1,5 +1,3 @@
using System;
using Content.Server.Items;
using Content.Shared.Whitelist;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;

View File

@@ -1,6 +1,6 @@
using Content.Server.Clothing.Components;
using Content.Server.Items;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Light.Component;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
@@ -38,7 +38,7 @@ namespace Content.Server.Light.Components
{
base.Initialize();
if (_entMan.TryGetComponent<ItemComponent?>(Owner, out var item))
if (_entMan.TryGetComponent<SharedItemComponent?>(Owner, out var item))
{
item.EquippedPrefix = "unlit";
}
@@ -55,7 +55,7 @@ namespace Content.Server.Light.Components
{
if (!Activated && CurrentState == ExpendableLightState.BrandNew)
{
if (_entMan.TryGetComponent<ItemComponent?>(Owner, out var item))
if (_entMan.TryGetComponent<SharedItemComponent?>(Owner, out var item))
{
item.EquippedPrefix = "lit";
}
@@ -130,7 +130,7 @@ namespace Content.Server.Light.Components
if (_entMan.TryGetComponent(Owner, out ClothingComponent? clothing))
{
clothing.ClothingEquippedPrefix = on ? "Activated" : string.Empty;
clothing.EquippedPrefix = on ? "Activated" : string.Empty;
}
}
@@ -163,7 +163,7 @@ namespace Content.Server.Light.Components
UpdateSpriteAndSounds(Activated);
UpdateVisualizer();
if (_entMan.TryGetComponent<ItemComponent?>(Owner, out var item))
if (_entMan.TryGetComponent<SharedItemComponent?>(Owner, out var item))
{
item.EquippedPrefix = "unlit";
}

View File

@@ -1,13 +1,27 @@
using System.Threading.Tasks;
using Content.Server.Clothing.Components;
using Content.Server.Light.EntitySystems;
using Content.Server.PowerCell.Components;
using Content.Shared.ActionBlocker;
using Content.Shared.Actions;
using Content.Shared.Actions.Behaviors.Item;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Light.Component;
using Content.Shared.Popups;
using Content.Shared.Rounding;
using Content.Shared.Sound;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.Analyzers;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Player;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Content.Server.Light.Components

View File

@@ -1,7 +1,5 @@
using Content.Shared.Smoking;
using Content.Shared.Sound;
using Content.Shared.Temperature;
using Content.Server.Items;
using Content.Server.Light.EntitySystems;
using Robust.Server.GameObjects;
using Robust.Shared.Analyzers;

View File

@@ -1,7 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using Content.Server.Clothing.Components;
using Content.Server.Items;
using Content.Server.Light.Components;
using Content.Server.Popups;
using Content.Server.PowerCell.Components;
@@ -228,11 +226,6 @@ namespace Content.Server.Light.EntitySystems
light.Enabled = on;
}
if (EntityManager.TryGetComponent(component.Owner, out ClothingComponent? clothing))
{
clothing.ClothingEquippedPrefix = Loc.GetString(on ? "on" : "off");
}
if (EntityManager.TryGetComponent(component.Owner, out ItemComponent? item))
{
item.EquippedPrefix = Loc.GetString(on ? "on" : "off");

View File

@@ -1,9 +1,9 @@
using System.Collections.Generic;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Items;
using Content.Server.Light.Components;
using Content.Shared.Audio;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Smoking;
using Content.Shared.Temperature;
using Robust.Shared.Audio;
@@ -90,7 +90,7 @@ namespace Content.Server.Light.EntitySystems
component.PointLightComponent.Enabled = component.CurrentState == SmokableState.Lit;
}
if (EntityManager.TryGetComponent(component.Owner, out ItemComponent? item))
if (EntityManager.TryGetComponent(component.Owner, out SharedItemComponent? item))
{
switch (component.CurrentState)
{

View File

@@ -38,7 +38,7 @@ namespace Content.Server.Medical.SuitSensors
/// Activate sensor if user wear it in this slot.
/// </summary>
[DataField("activationSlot")]
public EquipmentSlotDefines.Slots ActivationSlot = EquipmentSlotDefines.Slots.INNERCLOTHING;
public string ActivationSlot = "jumpsuit";
/// <summary>
/// How often does sensor update its owners status (in seconds).

View File

@@ -8,6 +8,7 @@ using Content.Shared.ActionBlocker;
using Content.Shared.Damage;
using Content.Shared.Examine;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Medical.SuitSensor;
using Content.Shared.MobState.Components;
using Content.Shared.Verbs;
@@ -37,8 +38,8 @@ namespace Content.Server.Medical.SuitSensors
{
base.Initialize();
SubscribeLocalEvent<SuitSensorComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<SuitSensorComponent, EquippedEvent>(OnEquipped);
SubscribeLocalEvent<SuitSensorComponent, UnequippedEvent>(OnUnequipped);
SubscribeLocalEvent<SuitSensorComponent, GotEquippedEvent>(OnEquipped);
SubscribeLocalEvent<SuitSensorComponent, GotUnequippedEvent>(OnUnequipped);
SubscribeLocalEvent<SuitSensorComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<SuitSensorComponent, GetInteractionVerbsEvent>(OnVerb);
}
@@ -91,15 +92,15 @@ namespace Content.Server.Medical.SuitSensors
}
}
private void OnEquipped(EntityUid uid, SuitSensorComponent component, EquippedEvent args)
private void OnEquipped(EntityUid uid, SuitSensorComponent component, GotEquippedEvent args)
{
if (args.Slot != component.ActivationSlot)
return;
component.User = args.User;
component.User = args.Equipee;
}
private void OnUnequipped(EntityUid uid, SuitSensorComponent component, UnequippedEvent args)
private void OnUnequipped(EntityUid uid, SuitSensorComponent component, GotUnequippedEvent args)
{
if (args.Slot != component.ActivationSlot)
return;
@@ -216,7 +217,7 @@ namespace Content.Server.Medical.SuitSensors
// try to get mobs id from ID slot
var userName = Loc.GetString("suit-sensor-component-unknown-name");
var userJob = Loc.GetString("suit-sensor-component-unknown-job");
if (_idCardSystem.TryGetIdCardSlot(sensor.User.Value, out var card))
if (_idCardSystem.TryFindIdCard(sensor.User.Value, out var card))
{
if (card.FullName != null)
userName = card.FullName;

View File

@@ -1,12 +1,9 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.DoAfter;
using Content.Server.Hands.Components;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Server.Nutrition.Components;
using Content.Server.Popups;
using Content.Shared.ActionBlocker;
@@ -17,20 +14,17 @@ using Content.Shared.Database;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers;
using Content.Shared.Inventory;
using Content.Shared.MobState.Components;
using Content.Shared.Tag;
using Content.Shared.Verbs;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Player;
using System.Collections.Generic;
using Robust.Shared.Utility;
using Content.Server.Inventory.Components;
using Content.Shared.Inventory;
using Content.Shared.Hands;
using Content.Shared.Inventory;
using Content.Shared.Item;
namespace Content.Server.Nutrition.EntitySystems
{
@@ -47,6 +41,7 @@ namespace Content.Server.Nutrition.EntitySystems
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly SharedAdminLogSystem _logSystem = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
public override void Initialize()
{
@@ -228,7 +223,7 @@ namespace Content.Server.Nutrition.EntitySystems
EntityManager.DeleteEntity((component).Owner);
// Put the trash in the user's hand
if (EntityManager.TryGetComponent(finisher, out ItemComponent? item) &&
if (EntityManager.TryGetComponent(finisher, out SharedItemComponent? item) &&
handsComponent.CanPutInHand(item))
{
handsComponent.PutInHand(item);
@@ -485,20 +480,20 @@ namespace Content.Server.Nutrition.EntitySystems
IngestionBlockerComponent blocker;
if (component.TryGetSlotItem(EquipmentSlotDefines.Slots.MASK, out ItemComponent? mask) &&
EntityManager.TryGetComponent(mask.Owner, out blocker) &&
if (_inventorySystem.TryGetSlotEntity(uid, "mask", out var maskUid) &&
EntityManager.TryGetComponent(maskUid, out blocker) &&
blocker.Enabled)
{
args.Blocker = mask.Owner;
args.Blocker = maskUid;
args.Cancel();
return;
}
if (component.TryGetSlotItem(EquipmentSlotDefines.Slots.HEAD, out ItemComponent? head) &&
EntityManager.TryGetComponent(head.Owner, out blocker) &&
if (_inventorySystem.TryGetSlotEntity(uid, "head", out var headUid) &&
EntityManager.TryGetComponent(headUid, out blocker) &&
blocker.Enabled)
{
args.Blocker = head.Owner;
args.Blocker = headUid;
args.Cancel();
}
}

View File

@@ -1,12 +1,12 @@
using Content.Server.Chemistry.Components.SolutionManager;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Nutrition.Components;
using Content.Shared.Chemistry.Components;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
@@ -69,7 +69,7 @@ namespace Content.Server.Nutrition.EntitySystems
{
if (ContainerHelpers.IsInContainer(component.Owner))
{
handsComponent.PutInHandOrDrop(EntityManager.GetComponent<ItemComponent>(sliceUid));
handsComponent.PutInHandOrDrop(EntityManager.GetComponent<SharedItemComponent>(sliceUid));
}
}

View File

@@ -1,7 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using Content.Server.Hands.Components;
using Content.Server.Inventory.Components;
using Content.Shared.Access.Components;
using Content.Shared.Inventory;
using Content.Shared.PDA;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -18,7 +18,7 @@ namespace Content.Server.PDA
/// <returns>The id card component.</returns>
public static IdCardComponent? GetHeldId(this EntityUid player)
{
IdCardComponent? firstIdInPda = null;
IdCardComponent? foundPDAId = null;
var entMan = IoCManager.Resolve<IEntityManager>();
@@ -26,11 +26,10 @@ namespace Content.Server.PDA
{
foreach (var item in hands.GetAllHeldItems())
{
if (firstIdInPda == null &&
entMan.TryGetComponent(item.Owner, out PDAComponent? pda) &&
if (entMan.TryGetComponent(item.Owner, out PDAComponent? pda) &&
pda.ContainedID != null)
{
firstIdInPda = pda.ContainedID;
foundPDAId = pda.ContainedID;
}
if (entMan.TryGetComponent(item.Owner, out IdCardComponent? card))
@@ -40,32 +39,32 @@ namespace Content.Server.PDA
}
}
if (firstIdInPda != null)
{
return firstIdInPda;
}
if (foundPDAId != null) return foundPDAId;
IdCardComponent? firstIdInInventory = null;
var invSystem = EntitySystem.Get<InventorySystem>();
if (entMan.TryGetComponent(player, out InventoryComponent? inventory))
if (invSystem.TryGetContainerSlotEnumerator(player, out var enumerator))
{
foreach (var item in inventory.GetAllHeldItems())
while (enumerator.MoveNext(out var containerSlot))
{
if (firstIdInInventory == null &&
entMan.TryGetComponent(item, out PDAComponent? pda) &&
if(!containerSlot.ContainedEntity.HasValue) continue;
if (entMan.TryGetComponent(containerSlot.ContainedEntity.Value, out PDAComponent? pda) &&
pda.ContainedID != null)
{
firstIdInInventory = pda.ContainedID;
foundPDAId = pda.ContainedID;
}
if (entMan.TryGetComponent(item, out IdCardComponent? card))
if (entMan.TryGetComponent(containerSlot.ContainedEntity.Value, out IdCardComponent? card))
{
return card;
}
}
}
return firstIdInInventory;
if (foundPDAId != null) return foundPDAId;
return null;
}
/// <summary>

View File

@@ -1,12 +1,11 @@
using System;
using System.Collections.Generic;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Server.Movement.Components;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.EntitySystems;
using Content.Shared.CCVar;
using Content.Shared.Inventory;
using Content.Shared.Item;
using Content.Shared.Maps;
using Content.Shared.Movement;
using Content.Shared.Movement.Components;
@@ -302,9 +301,10 @@ namespace Content.Server.Physics.Controllers
mobMover.StepSoundDistance -= distanceNeeded;
if (EntityManager.TryGetComponent<InventoryComponent?>(mover.Owner, out var inventory)
&& inventory.TryGetSlotItem<ItemComponent>(EquipmentSlotDefines.Slots.SHOES, out var item)
&& EntityManager.TryGetComponent<FootstepModifierComponent?>(item.Owner, out var modifier))
var invSystem = EntitySystem.Get<InventorySystem>();
if (invSystem.TryGetSlotEntity(mover.Owner, "shoes", out var shoes) &&
EntityManager.TryGetComponent<FootstepModifierComponent>(shoes, out var modifier))
{
modifier.PlayFootstep();
}

View File

@@ -4,7 +4,6 @@ using System.Linq;
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Nutrition.Components;
using Content.Server.Storage.Components;
using Content.Server.Stunnable;
@@ -13,6 +12,7 @@ using Content.Server.Tools.Components;
using Content.Shared.Camera;
using Content.Shared.CombatMode;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.PneumaticCannon;
using Content.Shared.Popups;
using Content.Shared.StatusEffect;
@@ -134,7 +134,7 @@ namespace Content.Server.PneumaticCannon
// this overrides the ServerStorageComponent's insertion stuff because
// it's not event-based yet and I can't cancel it, so tools and stuff
// will modify mode/power then get put in anyway
if (EntityManager.TryGetComponent<ItemComponent?>(args.Used, out var item)
if (EntityManager.TryGetComponent<SharedItemComponent?>(args.Used, out var item)
&& EntityManager.TryGetComponent<ServerStorageComponent?>(component.Owner, out var storage))
{
if (storage.CanInsert(args.Used))

View File

@@ -1,9 +1,9 @@
using System;
using System.Threading.Tasks;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Weapon.Ranged.Barrels.Components;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Popups;
using Content.Shared.Power;
using Robust.Shared.Containers;
@@ -101,7 +101,7 @@ namespace Content.Server.Power.Components
_heldBattery = null;
if (_entMan.TryGetComponent(user, out HandsComponent? handsComponent))
{
handsComponent.PutInHandOrDrop(_entMan.GetComponent<ItemComponent>(heldItem));
handsComponent.PutInHandOrDrop(_entMan.GetComponent<SharedItemComponent>(heldItem));
}
if (_entMan.TryGetComponent(heldItem, out ServerBatteryBarrelComponent? batteryBarrelComponent))

View File

@@ -1,6 +1,5 @@
using Content.Server.Administration;
using Content.Server.Power.Components;
using Content.Server.Items;
using Content.Shared.Administration;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;

View File

@@ -1,8 +1,8 @@
using System;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Shared.Audio;
using Content.Shared.Examine;
using Content.Shared.Item;
using Content.Shared.Sound;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
@@ -136,7 +136,7 @@ namespace Content.Server.PowerCell.Components
//Dirty();
if (user != null)
{
if (!_entities.TryGetComponent(user, out HandsComponent? hands) || !hands.PutInHand(_entities.GetComponent<ItemComponent>(cell.Owner)))
if (!_entities.TryGetComponent(user, out HandsComponent? hands) || !hands.PutInHand(_entities.GetComponent<SharedItemComponent>(cell.Owner)))
{
_entities.GetComponent<TransformComponent>(cell.Owner).Coordinates = _entities.GetComponent<TransformComponent>(user.Value).Coordinates;
}
@@ -164,7 +164,7 @@ namespace Content.Server.PowerCell.Components
public bool InsertCell(EntityUid cell, bool playSound = true)
{
if (Cell != null) return false;
if (!_entities.HasComponent<ItemComponent>(cell)) return false;
if (!_entities.HasComponent<SharedItemComponent>(cell)) return false;
if (!_entities.TryGetComponent<PowerCellComponent?>(cell, out var cellComponent)) return false;
if (cellComponent.CellSize != SlotSize) return false;
if (!_cellContainer.Insert(cell)) return false;

View File

@@ -1,12 +1,12 @@
using System.Linq;
using Content.Server.GameTicking;
using Content.Server.Hands.Components;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Shared.Access;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Inventory;
using Content.Shared.Item;
using Content.Shared.PDA;
using Content.Shared.Sandbox;
using Robust.Server.Console;
@@ -19,7 +19,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.ViewVariables;
using static Content.Shared.Inventory.EquipmentSlotDefines;
namespace Content.Server.Sandbox
{
@@ -124,14 +123,15 @@ namespace Content.Server.Sandbox
.EnumeratePrototypes<AccessLevelPrototype>()
.Select(p => p.ID).ToArray();
if (_entityManager.TryGetComponent(attached, out InventoryComponent? inv)
&& inv.TryGetSlotItem(Slots.IDCARD, out ItemComponent? wornItem))
var invSystem = EntitySystem.Get<InventorySystem>();
if (invSystem.TryGetSlotEntity(attached, "id", out var slotEntity))
{
if (_entityManager.HasComponent<AccessComponent>(wornItem.Owner))
if (_entityManager.HasComponent<AccessComponent>(slotEntity))
{
UpgradeId(wornItem.Owner);
UpgradeId(slotEntity.Value);
}
else if (_entityManager.TryGetComponent(wornItem.Owner, out PDAComponent? pda))
else if (_entityManager.TryGetComponent(slotEntity, out PDAComponent? pda))
{
if (pda.ContainedID == null)
{
@@ -139,7 +139,7 @@ namespace Content.Server.Sandbox
if (_entityManager.TryGetComponent(pda.Owner, out ItemSlotsComponent? itemSlots))
{
_entityManager.EntitySysManager.GetEntitySystem<ItemSlotsSystem>().
TryInsert(wornItem.Owner, pda.IdSlot, newID, null);
TryInsert(slotEntity.Value, pda.IdSlot, newID, null);
}
}
else
@@ -151,9 +151,9 @@ namespace Content.Server.Sandbox
else if (_entityManager.TryGetComponent<HandsComponent?>(attached, out var hands))
{
var card = CreateFreshId();
if (!_entityManager.TryGetComponent(attached, out inv) || !inv.Equip(Slots.IDCARD, card))
if (!invSystem.TryEquip(attached, card, "id", true, true))
{
hands.PutInHandOrDrop(_entityManager.GetComponent<ItemComponent>(card));
hands.PutInHandOrDrop(_entityManager.GetComponent<SharedItemComponent>(card));
}
}

View File

@@ -1,8 +1,8 @@
using System;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Popups;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Stacks;
using Content.Shared.Verbs;
using JetBrains.Annotations;
@@ -180,7 +180,7 @@ namespace Content.Server.Stack
if (Split(uid, amount, userTransform.Coordinates, stack) is not {} split)
return;
if (TryComp<HandsComponent>(userUid, out var hands) && TryComp<ItemComponent>(split, out var item))
if (TryComp<HandsComponent>(userUid, out var hands) && TryComp<SharedItemComponent>(split, out var item))
{
hands.PutInHandOrDrop(item);
}

Some files were not shown because too many files have changed in this diff Show More