Storage Component (toolboxes, backpacks, etc) (#57)

* Fix
Finish and update submodule
Comments code, changes network messages
FIXES THE USE INTERACTION SO YOU CAN ACTUALLY ACTIVATE THINGS NOW
Need engine commits
We'll figure out what to do about this shit later eh mates? Maybe have a script in the build process that automatically moves them over to godot/scenes
Changes some prototypes and fixes stuff
Fixes some more bugs, makes storage values show up properly
Part 3
Part 2
Storage Take 1

* Doneso
This commit is contained in:
clusterfack
2018-04-22 06:11:38 -05:00
committed by Pieter-Jan Briers
parent 74193d1182
commit ea05c593aa
22 changed files with 1044 additions and 54 deletions

View File

@@ -69,6 +69,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="EntryPoint.cs" />
<Compile Include="GameObjects\Components\Storage\ClientStorageComponent.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="GameObjects\Components\Items\ClientHandsComponent.cs" />
<Compile Include="GameObjects\Components\Doors\ClientDoorComponent.cs" />

View File

@@ -1,4 +1,5 @@
using Content.Client.GameObjects;
using Content.Client.GameObjects.Components.Storage;
using Content.Client.Interfaces.GameObjects;
using SS14.Shared.ContentPack;
using SS14.Shared.Interfaces.GameObjects;
@@ -36,8 +37,11 @@ namespace Content.Client
factory.RegisterIgnore("Projectile");
factory.RegisterIgnore("MeleeWeapon");
factory.RegisterIgnore("Storeable");
factory.Register<HandsComponent>();
factory.RegisterReference<HandsComponent, IHandsComponent>();
factory.Register<ClientStorageComponent>();
factory.Register<ClientDoorComponent>();
}

View File

@@ -57,5 +57,10 @@ namespace Content.Client.GameObjects
{
SendNetworkMessage(new ClientChangedHandMsg(index));
}
public void UseActiveHand()
{
SendNetworkMessage(new ActivateInhandMsg());
}
}
}

View File

@@ -0,0 +1,200 @@
using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Storage;
using SS14.Client.GameObjects;
using SS14.Client.UserInterface;
using SS14.Client.UserInterface.Controls;
using SS14.Client.UserInterface.CustomControls;
using SS14.Shared.GameObjects;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.Network;
using SS14.Shared.IoC;
using SS14.Shared.Log;
using SS14.Shared.Maths;
using SS14.Shared.Utility;
using System;
using System.Collections.Generic;
namespace Content.Client.GameObjects.Components.Storage
{
/// <summary>
/// Client version of item storage containers, contains a UI which displays stored entities and their size
/// </summary>
public class ClientStorageComponent : SharedStorageComponent
{
private Dictionary<EntityUid, int> StoredEntities { get; set; } = new Dictionary<EntityUid, int>();
private int StorageSizeUsed;
private int StorageCapacityMax;
private StorageWindow Window;
public override void OnAdd()
{
base.OnAdd();
Window = new StorageWindow()
{ StorageEntity = this};
}
public override void OnRemove()
{
Window.Dispose();
base.OnRemove();
}
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
{
switch (message)
{
//Updates what we are storing for the UI
case StorageHeldItemsMessage msg:
HandleStorageMessage(msg);
break;
//Opens the UI
case OpenStorageUIMessage msg:
OpenUI();
break;
}
}
/// <summary>
/// Copies received values from server about contents of storage container
/// </summary>
/// <param name="storagestate"></param>
private void HandleStorageMessage(StorageHeldItemsMessage storagestate)
{
StoredEntities = new Dictionary<EntityUid, int>(storagestate.StoredEntities);
StorageSizeUsed = storagestate.StorageSizeUsed;
StorageCapacityMax = storagestate.StorageSizeMax;
Window.BuildEntityList();
}
/// <summary>
/// Opens the storage UI
/// </summary>
private void OpenUI()
{
Window.AddToScreen();
Window.Open();
}
/// <summary>
/// Function for clicking one of the stored entity buttons in the UI, tells server to remove that entity
/// </summary>
/// <param name="entityuid"></param>
private void Interact(EntityUid entityuid)
{
SendNetworkMessage(new RemoveEntityMessage(entityuid));
}
/// <summary>
/// GUI class for client storage component
/// </summary>
private class StorageWindow : SS14Window
{
private Control VSplitContainer;
private VBoxContainer EntityList;
private Label Information;
public ClientStorageComponent StorageEntity;
protected override ResourcePath ScenePath => new ResourcePath("/Scenes/Storage/Storage.tscn");
protected override void Initialize()
{
base.Initialize();
HideOnClose = true;
// Get all the controls.
VSplitContainer = Contents.GetChild("VSplitContainer");
EntityList = VSplitContainer.GetChild("ListScrollContainer").GetChild<VBoxContainer>("EntityList");
Information = VSplitContainer.GetChild<Label>("Information");
}
/// <summary>
/// Loops through stored entities creating buttons for each, updates information labels
/// </summary>
public void BuildEntityList()
{
EntityList.DisposeAllChildren();
var storagelist = StorageEntity.StoredEntities;
foreach (var entityuid in storagelist)
{
var entity = IoCManager.Resolve<IEntityManager>().GetEntity(entityuid.Key);
var button = new EntityButton()
{
EntityuID = entityuid.Key
};
var container = button.GetChild("HBoxContainer");
button.ActualButton.OnToggled += OnItemButtonToggled;
//Name and Size labels set
container.GetChild<Label>("Name").Text = entity.Name;
container.GetChild<Control>("Control").GetChild<Label>("Size").Text = string.Format("{0}", entityuid.Value);
//Gets entity sprite and assigns it to button texture
if (entity.TryGetComponent(out SpriteComponent sprite))
{
var tex = sprite.CurrentSprite;
var rect = container.GetChild("TextureWrap").GetChild<TextureRect>("TextureRect");
if (tex != null)
{
rect.Texture = tex;
// Copypasted but replaced with 32 dunno if good
var scale = (float)32 / tex.Height;
rect.Scale = new Vector2(scale, scale);
}
else
{
rect.Dispose();
}
}
EntityList.AddChild(button);
}
//Sets information about entire storage container current capacity
if(StorageEntity.StorageCapacityMax != 0)
{
Information.Text = String.Format("Items: {0}, Stored: {1}/{2}", storagelist.Count, StorageEntity.StorageSizeUsed, StorageEntity.StorageCapacityMax);
}
else
{
Information.Text = String.Format("Items: {0}", storagelist.Count);
}
}
/// <summary>
/// Function assigned to button toggle which removes the entity from storage
/// </summary>
/// <param name="args"></param>
private void OnItemButtonToggled(BaseButton.ButtonToggledEventArgs args)
{
var control = (EntityButton)args.Button.Parent;
args.Button.Pressed = false;
StorageEntity.Interact(control.EntityuID);
}
}
/// <summary>
/// Button created for each entity that represents that item in the storage UI, with a texture, and name and size label
/// </summary>
private class EntityButton : Control
{
public EntityUid EntityuID { get; set; }
public Button ActualButton { get; private set; }
protected override ResourcePath ScenePath => new ResourcePath("/Scenes/Storage/StorageEntity.tscn");
protected override void Initialize()
{
base.Initialize();
ActualButton = GetChild<Button>("Button");
}
}
}
}

View File

@@ -1,4 +1,5 @@
using Content.Client.Interfaces.GameObjects;
using Content.Client.GameObjects;
using Content.Client.Interfaces.GameObjects;
using SS14.Client.GameObjects;
using SS14.Client.Graphics;
using SS14.Client.Graphics.Drawing;
@@ -11,6 +12,7 @@ using SS14.Client.UserInterface;
using SS14.Client.UserInterface.Controls;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.IoC;
using SS14.Shared.Log;
using SS14.Shared.Maths;
namespace Content.Client.UserInterface
@@ -63,16 +65,8 @@ namespace Content.Client.UserInterface
protected override void Draw(DrawingHandle handle)
{
if (_playerManager?.LocalPlayer == null)
{
if (!TryGetHands(out IHandsComponent hands))
return;
}
IEntity entity = _playerManager.LocalPlayer.ControlledEntity;
if (entity == null || !entity.TryGetComponent<IHandsComponent>(out var hands))
{
return;
}
var leftActive = hands.ActiveIndex == "left";
@@ -98,20 +92,35 @@ namespace Content.Client.UserInterface
}
}
public void UpdateHandIcons()
/// <summary>
/// Gets the hands component controling this gui, returns true if successful and false if failure
/// </summary>
/// <param name="hands"></param>
/// <returns></returns>
private bool TryGetHands(out IHandsComponent hands)
{
UpdateDraw();
if (_playerManager?.LocalPlayer.ControlledEntity == null)
hands = null;
if (_playerManager?.LocalPlayer == null)
{
return;
return false;
}
IEntity entity = _playerManager.LocalPlayer.ControlledEntity;
if (!entity.TryGetComponent<IHandsComponent>(out var hands))
if (entity == null || !entity.TryGetComponent(out hands))
{
return;
return false;
}
return true;
}
public void UpdateHandIcons()
{
UpdateDraw();
if (!TryGetHands(out IHandsComponent hands))
return;
var left = hands.GetEntity("left");
var right = hands.GetEntity("right");
@@ -146,14 +155,21 @@ namespace Content.Client.UserInterface
private void SendSwitchHandTo(string index)
{
IEntity entity = _playerManager.LocalPlayer.ControlledEntity;
if (!entity.TryGetComponent<IHandsComponent>(out var hands))
{
if (!TryGetHands(out IHandsComponent hands))
return;
}
hands.SendChangeHand(index);
}
private void UseActiveHand()
{
if (!TryGetHands(out IHandsComponent hands))
return;
//Todo: remove hands interface, so weird
((HandsComponent)hands).UseActiveHand();
}
protected override bool HasPoint(Vector2 point)
{
return handL.Contains((Vector2i)point) || handR.Contains((Vector2i)point);
@@ -163,18 +179,28 @@ namespace Content.Client.UserInterface
{
base.MouseDown(args);
if (args.Button != Mouse.Button.Right)
{
return;
}
var lefthandcontains = handL.Contains((Vector2i)args.RelativePosition);
var righthandcontains = handR.Contains((Vector2i)args.RelativePosition);
if (handL.Contains((Vector2i)args.RelativePosition))
if (args.Button == Mouse.Button.Left)
{
SendSwitchHandTo("left");
if (!TryGetHands(out IHandsComponent hands))
return;
if ((hands.ActiveIndex == "left" && lefthandcontains)
|| (hands.ActiveIndex == "right" && righthandcontains))
UseActiveHand();
}
if (handR.Contains((Vector2i)args.RelativePosition))
else if (args.Button == Mouse.Button.Right)
{
SendSwitchHandTo("right");
if (lefthandcontains)
{
SendSwitchHandTo("left");
}
if (righthandcontains)
{
SendSwitchHandTo("right");
}
}
}

View File

@@ -74,6 +74,8 @@
<Compile Include="GameObjects\Components\Interactable\Tools\WelderComponent.cs" />
<Compile Include="GameObjects\Components\Interactable\Tools\WirecutterComponent.cs" />
<Compile Include="GameObjects\Components\Interactable\Tools\WrenchComponent.cs" />
<Compile Include="GameObjects\Components\Items\Storage\StoreableComponent.cs" />
<Compile Include="GameObjects\Components\Items\Storage\ServerStorageComponent.cs" />
<Compile Include="GameObjects\Components\Power\PowerStorageComponent.cs" />
<Compile Include="GameObjects\Components\Power\PowerGeneratorComponent.cs" />
<Compile Include="GameObjects\Components\Power\PowerDevice.cs" />
@@ -93,7 +95,7 @@
<Compile Include="Interfaces\GameObjects\Components\Items\IItemComponent.cs" />
<Compile Include="GameObjects\Components\Items\ServerHandsComponent.cs" />
<Compile Include="GameObjects\Components\Items\InventoryComponent.cs" />
<Compile Include="GameObjects\Components\Items\ItemComponent.cs" />
<Compile Include="GameObjects\Components\Items\Storage\ItemComponent.cs" />
<Compile Include="GameObjects\Components\Damage\DamageableComponent.cs" />
<Compile Include="GameObjects\Components\Damage\DestructibleComponent.cs" />
<Compile Include="GameObjects\Components\Damage\ResistanceSet.cs" />

View File

@@ -55,8 +55,10 @@ namespace Content.Server
factory.Register<InventoryComponent>();
factory.RegisterReference<InventoryComponent, IInventoryComponent>();
factory.Register<StoreableComponent>();
factory.Register<ItemComponent>();
factory.RegisterReference<ItemComponent, IItemComponent>();
factory.RegisterReference<ItemComponent, StoreableComponent>();
factory.Register<DamageableComponent>();
factory.Register<DestructibleComponent>();
@@ -83,6 +85,8 @@ namespace Content.Server
factory.Register<ProjectileWeaponComponent>();
factory.Register<ProjectileComponent>();
factory.Register<MeleeWeaponComponent>();
factory.Register<ServerStorageComponent>();
}
/// <inheritdoc />

View File

@@ -1,10 +1,15 @@
using System;
using System.Collections.Generic;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces.GameObjects;
using Content.Shared.GameObjects;
using SS14.Server.Interfaces.GameObjects;
using SS14.Server.Interfaces.Player;
using SS14.Shared.GameObjects;
using SS14.Shared.Input;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.Network;
using SS14.Shared.IoC;
using SS14.Shared.Utility;
using YamlDotNet.RepresentationModel;
@@ -81,6 +86,8 @@ namespace Content.Server.GameObjects
return slot.Item;
}
public IItemComponent GetActiveHand => GetHand(ActiveIndex);
/// <summary>
/// Enumerates over the hand keys, returning the active hand first.
/// </summary>
@@ -233,19 +240,40 @@ namespace Content.Server.GameObjects
ActiveIndex = orderedHands[index];
}
public override void HandleMessage(object owner, ComponentMessage message)
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
{
base.HandleMessage(owner, message);
base.HandleMessage(message, netChannel, component);
switch (message)
{
case ClientChangedHandMsg msg:
if (HasHand(msg.Index))
ActiveIndex = msg.Index;
break;
{
var playerMan = IoCManager.Resolve<IPlayerManager>();
var session = playerMan.GetSessionByChannel(netChannel);
var playerentity = session.AttachedEntity;
if (playerentity == Owner && HasHand(msg.Index))
ActiveIndex = msg.Index;
break;
}
case ActivateInhandMsg msg:
{
var playerMan = IoCManager.Resolve<IPlayerManager>();
var session = playerMan.GetSessionByChannel(netChannel);
var playerentity = session.AttachedEntity;
var used = GetActiveHand?.Owner;
if (playerentity == Owner && used != null)
{
InteractionSystem.TryUseInteraction(Owner, used);
}
break;
}
//Boundkeychangedmsg only works for the player entity
case BoundKeyChangedMsg msg:
if(msg.State != BoundKeyState.Down)
if (msg.State != BoundKeyState.Down)
return;
switch (msg.Function)
{
@@ -255,6 +283,13 @@ namespace Content.Server.GameObjects
case BoundKeyFunctions.Drop:
Drop(ActiveIndex);
break;
case BoundKeyFunctions.ActivateItemInHand:
var used = GetActiveHand?.Owner;
if(used != null)
{
InteractionSystem.TryUseInteraction(Owner, used);
}
break;
}
break;
}

View File

@@ -1,12 +1,11 @@
using Content.Server.Interfaces.GameObjects;
using SS14.Server.Interfaces.GameObjects;
using SS14.Shared.GameObjects;
using System;
using SS14.Shared.Interfaces.GameObjects;
namespace Content.Server.GameObjects
{
public class ItemComponent : Component, IItemComponent, EntitySystems.IAttackHand
public class ItemComponent : StoreableComponent, IItemComponent, EntitySystems.IAttackHand
{
public override string Name => "Item";

View File

@@ -0,0 +1,184 @@
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces.GameObjects;
using Content.Shared.GameObjects.Components.Storage;
using SS14.Server.GameObjects;
using SS14.Server.GameObjects.Components.Container;
using SS14.Server.Interfaces.Player;
using SS14.Shared.GameObjects;
using SS14.Shared.GameObjects.Serialization;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.Network;
using SS14.Shared.IoC;
using SS14.Shared.Log;
using System.Collections.Generic;
namespace Content.Server.GameObjects
{
/// <summary>
/// Storage component for containing entities within this one, matches a UI on the client which shows stored entities
/// </summary>
public class ServerStorageComponent : SharedStorageComponent, IAttackby, IUse
{
private Container storage;
private int StorageUsed = 0;
private int StorageCapacityMax = 10000;
public override void OnAdd()
{
base.OnAdd();
storage = Container.Create("storagebase", Owner);
}
public override void ExposeData(EntitySerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref StorageCapacityMax, "Capacity", 10000);
}
/// <summary>
/// Removes from the storage container and updates the stored value
/// </summary>
/// <param name="toremove"></param>
/// <returns></returns>
bool Remove(IEntity toremove)
{
if(storage.Remove(toremove))
{
StorageUsed -= toremove.GetComponent<StoreableComponent>().ObjectSize;
UpdateClientInventory();
return true;
}
return false;
}
/// <summary>
/// Inserts into the storage container
/// </summary>
/// <param name="toinsert"></param>
/// <returns></returns>
bool Insert(IEntity toinsert)
{
if(CanInsert(toinsert) && storage.Insert(toinsert))
{
StorageUsed += toinsert.GetComponent<StoreableComponent>().ObjectSize;
UpdateClientInventory();
return true;
}
return false;
}
/// <summary>
/// Verifies the object can be inserted by checking if it is storeable and if it keeps under the capacity limit
/// </summary>
/// <param name="toinsert"></param>
/// <returns></returns>
bool CanInsert(IEntity toinsert)
{
if(toinsert.TryGetComponent(out StoreableComponent store))
{
if (store.ObjectSize <= (StorageCapacityMax - StorageUsed))
return true;
}
return false;
}
/// <summary>
/// Inserts storeable entities into this storage container if possible, otherwise return to the hand of the user
/// </summary>
/// <param name="user"></param>
/// <param name="attackwith"></param>
/// <returns></returns>
bool IAttackby.Attackby(IEntity user, IEntity attackwith)
{
var hands = user.GetComponent<HandsComponent>();
//Check that we can drop the item from our hands first otherwise we obviously cant put it inside
if(hands.Drop(hands.ActiveIndex))
{
var inserted = Insert(attackwith);
if (inserted)
{
return true;
}
else
{
//Return the object to the hand since its too big or something like that
hands.PutInHand(attackwith.GetComponent<IItemComponent>());
}
}
return false;
}
/// <summary>
/// Sends a message to open the storage UI
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
bool IUse.UseEntity(IEntity user)
{
SendNetworkMessage(new OpenStorageUIMessage());
return false;
}
/// <summary>
/// Updates the storage UI on all clients telling them of the entities stored in this container
/// </summary>
private void UpdateClientInventory()
{
Dictionary<EntityUid, int> storedentities = new Dictionary<EntityUid, int>();
foreach (var entities in storage.ContainedEntities)
{
storedentities.Add(entities.Uid, entities.GetComponent<StoreableComponent>().ObjectSize);
}
SendNetworkMessage(new StorageHeldItemsMessage(storedentities, StorageUsed, StorageCapacityMax));
}
/// <summary>
/// Receives messages to remove entities from storage, verifies the player can do them,
/// and puts the removed entity in hand or on the ground
/// </summary>
/// <param name="message"></param>
/// <param name="netChannel"></param>
/// <param name="component"></param>
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
{
base.HandleMessage(message, netChannel, component);
switch (message)
{
case RemoveEntityMessage msg:
var playerMan = IoCManager.Resolve<IPlayerManager>();
var session = playerMan.GetSessionByChannel(netChannel);
var playerentity = session.AttachedEntity;
var ourtransform = Owner.GetComponent<TransformComponent>();
var playertransform = playerentity.GetComponent<TransformComponent>();
if (playertransform.LocalPosition.InRange(ourtransform.LocalPosition, 2)
&& (ourtransform.IsMapTransform || playertransform.ContainsEntity(ourtransform)))
{
var remove = (RemoveEntityMessage)message;
var entity = IoCManager.Resolve<IEntityManager>().GetEntity(remove.EntityUid);
if (entity != null && storage.Contains(entity))
{
Remove(entity);
UpdateClientInventory();
var item = entity.GetComponent<IItemComponent>();
if (item != null && playerentity.TryGetComponent(out HandsComponent hands))
{
if (hands.PutInHand(item))
return;
}
entity.GetComponent<TransformComponent>().WorldPosition = Owner.GetComponent<TransformComponent>().WorldPosition;
}
}
break;
}
}
}
}

View File

@@ -0,0 +1,37 @@
using SS14.Shared.GameObjects;
using SS14.Shared.GameObjects.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Content.Server.GameObjects
{
public class StoreableComponent : Component
{
public override string Name => "Storeable";
public int ObjectSize = 0;
public override void ExposeData(EntitySerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref ObjectSize, "Size", 1);
}
}
/// <summary>
/// Enum for the storage capacity of various containers
/// </summary>
public enum ReferenceSizes
{
Wallet = 4,
Pocket = 12,
Box = 24,
Toolbox = 60,
Backpack = 100,
NoStoring = 9999
}
}

View File

@@ -148,32 +148,36 @@ namespace Content.Server.GameObjects.EntitySystems
{
return;
}
var item = hands.GetHand(hands.ActiveIndex)?.Owner;
var item = hands.GetActiveHand?.Owner;
if (!MobCanInteract(player))
return;
//TODO: Mob status code that allows or rejects interactions based on current mob status
//Check if client should be able to see that object to click on it in the first place, prevent using locaters by firing a laser or something
//Off entity click handling
if (attacked == null)
//Clicked on empty space behavior, try using ranged attack
if (attacked == null && item != null)
{
if(item != null)
{
//AFTERATTACK: Check if we clicked on an empty location, if so the only interaction we can do is afterattack
InteractAfterattack(player, item, msg.Coordinates);
return;
}
//AFTERATTACK: Check if we clicked on an empty location, if so the only interaction we can do is afterattack
InteractAfterattack(player, item, msg.Coordinates);
return;
}
//USE: Check if we clicked on the item we are holding in our active hand to use it
else if(attacked == item && item != null)
else if(attacked == null)
{
UseInteraction(player, item);
return;
}
//Verify attacked object is on the map if we managed to click on it somehow
if (!attacked.GetComponent<TransformComponent>().IsMapTransform)
{
Logger.Warning(string.Format("Player named {0} clicked on object {1} that isn't currently on the map somehow", player.Name, attacked.Name));
return;
}
//Check if ClickLocation is in object bounds here, if not lets log as warning and see why
if(attacked != null && attacked.TryGetComponent(out BoundingBoxComponent boundingbox))
if (attacked.TryGetComponent(out BoundingBoxComponent boundingbox))
{
if (!boundingbox.WorldAABB.Contains(msg.Coordinates.Position))
{
@@ -208,6 +212,15 @@ namespace Content.Server.GameObjects.EntitySystems
}
}
/// <summary>
/// TODO function for blocking activity based on mob status
/// </summary>
/// <returns></returns>
private static bool MobCanInteract(IEntity user)
{
return true; //Hook into future planned mob status system
}
/// <summary>
/// We didn't click on any entity, try doing an afterattack on the click location
/// </summary>
@@ -276,6 +289,20 @@ namespace Content.Server.GameObjects.EntitySystems
//Else check damage component to see if we damage if not attackby, and if so can we attack object
}
/// <summary>
/// Activates the Use behavior of an object
/// Verifies that the user is capable of doing the use interaction first
/// </summary>
/// <param name="user"></param>
/// <param name="used"></param>
public static void TryUseInteraction(IEntity user, IEntity used)
{
if(user != null && used != null && MobCanInteract(user))
{
UseInteraction(user, used);
}
}
/// <summary>
/// Activates/Uses an object in control/possession of a user
/// If the item has the IUse interface on one of its components we use the object in our hand

View File

@@ -1,4 +1,4 @@
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.GameObjects;
using System.Collections.Generic;
namespace Content.Server.Interfaces.GameObjects
@@ -22,6 +22,11 @@ namespace Content.Server.Interfaces.GameObjects
/// <returns>The item in the held, null if no item is held</returns>
IItemComponent GetHand(string index);
/// <summary>
/// Gets item held by the current active hand
/// </summary>
IItemComponent GetActiveHand { get; }
/// <summary>
/// Puts an item into any empty hand, preferring the active hand.
/// </summary>

View File

@@ -65,6 +65,7 @@
<ItemGroup>
<Compile Include="EntryPoint.cs" />
<Compile Include="GameObjects\Components\Doors\SharedDoorComponent.cs" />
<Compile Include="GameObjects\Components\Storage\SharedStorageComponent.cs" />
<Compile Include="GameObjects\ContentNetIDs.cs" />
<Compile Include="GameObjects\PhysicalConstants.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View File

@@ -1,4 +1,5 @@
using SS14.Shared.GameObjects;
using SS14.Shared.Serialization;
using System;
using System.Collections.Generic;
@@ -24,4 +25,16 @@ namespace Content.Shared.GameObjects
ActiveIndex = activeIndex;
}
}
/// <summary>
/// A message that activates the inhand, presumed for now the activation will occur only on the active hand
/// </summary>
[Serializable, NetSerializable]
public class ActivateInhandMsg : ComponentMessage
{
public ActivateInhandMsg()
{
Directed = true;
}
}
}

View File

@@ -0,0 +1,59 @@
using SS14.Shared.GameObjects;
using SS14.Shared.Serialization;
using System;
using System.Collections.Generic;
namespace Content.Shared.GameObjects.Components.Storage
{
public abstract class SharedStorageComponent : Component
{
public sealed override string Name => "Storage";
public override uint? NetID => ContentNetIDs.STORAGE;
}
/// <summary>
/// Updates the client component about what entities this storage is holding
/// </summary>
[Serializable, NetSerializable]
public class StorageHeldItemsMessage : ComponentMessage
{
public readonly int StorageSizeMax;
public readonly int StorageSizeUsed;
public Dictionary<EntityUid, int> StoredEntities;
public StorageHeldItemsMessage(Dictionary<EntityUid, int> storedentities, int storageused, int storagemaxsize)
{
Directed = true;
StorageSizeMax = storagemaxsize;
StorageSizeUsed = storageused;
StoredEntities = storedentities;
}
}
/// <summary>
/// Component message for removing a contained entity from the storage entity
/// </summary>
[Serializable, NetSerializable]
public class RemoveEntityMessage : ComponentMessage
{
public EntityUid EntityUid;
public RemoveEntityMessage(EntityUid entityuid)
{
Directed = true;
EntityUid = entityuid;
}
}
/// <summary>
/// Component message for opening the storage UI
/// </summary>
[Serializable, NetSerializable]
public class OpenStorageUIMessage : ComponentMessage
{
public OpenStorageUIMessage()
{
Directed = true;
}
}
}

View File

@@ -8,5 +8,6 @@
public const uint TEMPERATURE = 1002;
public const uint HANDS = 1003;
public const uint DOOR = 1004;
public const uint STORAGE = 1005;
}
}

View File

@@ -4,6 +4,7 @@
components:
- type: Transform
- type: Item
Size: 5
- type: Clickable
- type: BoundingBox
- type: Physics
@@ -18,6 +19,10 @@
sprite: Items/toolbox_r.png
- type: Icon
icon: Items/toolbox_r.png
- type: Storage
Capacity: 60
- type: Item
Size: 9999
- type: entity
name: "Mechanical Toolbox With Handle"
@@ -28,6 +33,10 @@
sprite: Items/toolbox_b.png
- type: Icon
icon: Items/toolbox_b.png
- type: Storage
Capacity: 60
- type: Item
Size: 9999
- type: entity
name: "Electrical Toolbox With Handle"
@@ -38,6 +47,10 @@
sprite: Items/toolbox_y.png
- type: Icon
icon: Items/toolbox_y.png
- type: Storage
Capacity: 60
- type: Item
Size: 9999
- type: entity
name: "Extra-Grip™ Mop"
@@ -48,6 +61,8 @@
sprite: Items/mop.png
- type: Icon
icon: Items/mop.png
- type: Item
Size: 10
#handheld lights
- type: entity

View File

@@ -8,6 +8,8 @@
- type: Icon
icon: Objects/gun.png
- type: HitscanWeapon
- type: Item
Size: 24
- type: entity
name: GUN
@@ -19,3 +21,6 @@
- type: Icon
icon: Objects/projectileweapon.png
- type: ProjectileWeapon
- type: Item
Size: 24

View File

@@ -0,0 +1,207 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://Scenes/SS14Window/closewindow.png" type="Texture" id=1]
[sub_resource type="StyleBoxFlat" id=1]
content_margin_left = -1.0
content_margin_right = -1.0
content_margin_top = -1.0
content_margin_bottom = -1.0
bg_color = Color( 0.234375, 0.234375, 0.234375, 1 )
draw_center = true
border_width_left = 0
border_width_top = 0
border_width_right = 0
border_width_bottom = 0
border_color = Color( 0.8, 0.8, 0.8, 1 )
border_blend = false
corner_radius_top_left = 0
corner_radius_top_right = 0
corner_radius_bottom_right = 0
corner_radius_bottom_left = 0
corner_detail = 8
expand_margin_left = 0.0
expand_margin_right = 0.0
expand_margin_top = 0.0
expand_margin_bottom = 0.0
shadow_color = Color( 0, 0, 0, 0.6 )
shadow_size = 0
anti_aliasing = true
anti_aliasing_size = 1
[node name="SS14Window" type="Panel" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 100.0
margin_top = 38.0
margin_right = 361.0
margin_bottom = 406.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
[node name="Contents" type="Container" parent="." index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 10.0
margin_top = 40.0
margin_right = -10.0
margin_bottom = -12.0
rect_min_size = Vector2( 50, 50 )
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
_sections_unfolded = [ "Anchor", "Margin", "Mouse", "Rect" ]
[node name="VSplitContainer" type="VSplitContainer" parent="Contents" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
split_offset = 0
collapsed = false
dragger_visibility = 0
_sections_unfolded = [ "Anchor", "Grow Direction", "Hint", "Margin", "Rect" ]
[node name="Information" type="Label" parent="Contents/VSplitContainer" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 241.0
margin_bottom = 14.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 4
text = "Items: 0 Volume: 0/0 Stuff"
align = 1
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
_sections_unfolded = [ "Anchor", "Margin" ]
[node name="ListScrollContainer" type="ScrollContainer" parent="Contents/VSplitContainer" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 26.0
margin_right = 241.0
margin_bottom = 316.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = true
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 1
scroll_horizontal_enabled = true
scroll_horizontal = 0
scroll_vertical_enabled = true
scroll_vertical = 0
_sections_unfolded = [ "Anchor", "Focus", "Grow Direction", "Hint", "Margin", "Material", "Mouse", "Pause", "Rect", "Scroll", "Size Flags", "Theme", "Visibility" ]
[node name="EntityList" type="VBoxContainer" parent="Contents/VSplitContainer/ListScrollContainer" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 241.0
margin_bottom = 176.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 1
alignment = 1
_sections_unfolded = [ "Anchor", "Focus", "Hint", "Margin", "Mouse", "Rect", "Size Flags", "Theme", "custom_constants" ]
[node name="Header" type="Panel" parent="." index="1"]
editor/display_folded = true
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 0.0
margin_bottom = 25.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
custom_styles/panel = SubResource( 1 )
_sections_unfolded = [ "Margin", "Mouse", "custom_styles" ]
[node name="Header Text" type="Label" parent="Header" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_right = -25.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 4
text = "Storage Item"
align = 1
valign = 1
clip_text = true
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
_sections_unfolded = [ "Margin", "Mouse" ]
[node name="CloseButton" type="TextureButton" parent="Header" index="1"]
anchor_left = 1.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = -25.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
toggle_mode = false
enabled_focus_mode = 2
shortcut = null
group = null
texture_normal = ExtResource( 1 )
expand = true
stretch_mode = 5
_sections_unfolded = [ "Margin", "Textures" ]

View File

@@ -0,0 +1,160 @@
[gd_scene load_steps=2 format=2]
[sub_resource type="StyleBoxEmpty" id=1]
content_margin_left = -1.0
content_margin_right = -1.0
content_margin_top = -1.0
content_margin_bottom = -1.0
[node name="StorageEntity" type="PanelContainer" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_styles/panel = SubResource( 1 )
_sections_unfolded = [ "Focus", "Hint", "Material", "Mouse", "Size Flags", "Theme", "Visibility", "custom_styles" ]
[node name="Button" type="Button" parent="." index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 1024.0
margin_bottom = 600.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 3
toggle_mode = true
enabled_focus_mode = 2
shortcut = null
group = null
flat = false
align = 1
_sections_unfolded = [ "Grow Direction", "Size Flags" ]
[node name="HBoxContainer" type="HBoxContainer" parent="." index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 1024.0
margin_bottom = 600.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
alignment = 0
_sections_unfolded = [ "Anchor", "Grow Direction", "Hint", "Margin", "Mouse", "Rect", "Size Flags", "Theme", "custom_constants" ]
[node name="TextureWrap" type="Control" parent="HBoxContainer" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 32.0
margin_bottom = 600.0
rect_min_size = Vector2( 32, 32 )
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
_sections_unfolded = [ "Mouse", "Rect" ]
[node name="TextureRect" type="TextureRect" parent="HBoxContainer/TextureWrap" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = true
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 4
size_flags_vertical = 4
stretch_mode = 0
_sections_unfolded = [ "Focus", "Grow Direction", "Hint", "Margin", "Mouse", "Rect", "Size Flags", "Theme" ]
[node name="Name" type="Label" parent="HBoxContainer" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 36.0
margin_top = 293.0
margin_right = 95.0
margin_bottom = 307.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 4
text = "Backpack"
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
_sections_unfolded = [ "Anchor" ]
[node name="Control" type="Control" parent="HBoxContainer" index="2"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 99.0
margin_right = 1024.0
margin_bottom = 600.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 1
_sections_unfolded = [ "Mouse", "Size Flags" ]
[node name="Size" type="Label" parent="HBoxContainer/Control" index="0"]
anchor_left = 1.0
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
margin_left = -38.0
margin_top = -7.0
margin_right = -5.0
margin_bottom = 7.0
grow_horizontal = 0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 4
text = "Size 6"
align = 2
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
_sections_unfolded = [ "Margin", "Mouse" ]

2
engine

Submodule engine updated: b5ca9095b0...32caf088ef