Actions System + UI (#2710)
Co-authored-by: Vera Aguilera Puerto <6766154+Zumorica@users.noreply.github.com>
This commit is contained in:
@@ -100,7 +100,7 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
return;
|
||||
}
|
||||
|
||||
status?.ShowAlert(AlertType.Fire, onClickAlert: OnClickAlert);
|
||||
status?.ShowAlert(AlertType.Fire);
|
||||
|
||||
if (FireStacks > 0)
|
||||
{
|
||||
@@ -152,14 +152,6 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClickAlert(ClickAlertEventArgs args)
|
||||
{
|
||||
if (args.Player.TryGetComponent(out FlammableComponent flammable))
|
||||
{
|
||||
flammable.Resist();
|
||||
}
|
||||
}
|
||||
|
||||
public void CollideWith(IEntity collidedWith)
|
||||
{
|
||||
if (!collidedWith.TryGetComponent(out FlammableComponent otherFlammable))
|
||||
|
||||
@@ -5,18 +5,22 @@ using Content.Server.Explosions;
|
||||
using Content.Server.GameObjects.Components.Body.Respiratory;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.GameObjects.Components.Atmos.GasTank;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects.Verbs;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects.Components.UserInterface;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.ComponentDependencies;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
@@ -30,13 +34,15 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
[ComponentReference(typeof(IActivate))]
|
||||
public class GasTankComponent : SharedGasTankComponent, IExamine, IGasMixtureHolder, IUse, IDropped, IActivate
|
||||
{
|
||||
private const float MaxExplosionRange = 14f;
|
||||
private const float MaxExplosionRange = 14f;
|
||||
private const float DefaultOutputPressure = Atmospherics.OneAtmosphere;
|
||||
|
||||
private float _pressureResistance;
|
||||
|
||||
private int _integrity = 3;
|
||||
|
||||
[ComponentDependency] private readonly ItemActionsComponent? _itemActions = null;
|
||||
|
||||
[ViewVariables] private BoundUserInterface? _userInterface;
|
||||
|
||||
[ViewVariables] public GasMixture? Air { get; set; }
|
||||
@@ -191,14 +197,18 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
|
||||
private void UpdateUserInterface(bool initialUpdate = false)
|
||||
{
|
||||
var internals = GetInternalsComponent();
|
||||
_userInterface?.SetState(
|
||||
new GasTankBoundUserInterfaceState
|
||||
{
|
||||
TankPressure = Air?.Pressure ?? 0,
|
||||
OutputPressure = initialUpdate ? OutputPressure : (float?) null,
|
||||
InternalsConnected = IsConnected,
|
||||
CanConnectInternals = IsFunctional && GetInternalsComponent() != null
|
||||
CanConnectInternals = IsFunctional && internals != null
|
||||
});
|
||||
|
||||
if (internals == null) return;
|
||||
_itemActions?.GrantOrUpdate(ItemActionType.ToggleInternals, IsFunctional, IsConnected);
|
||||
}
|
||||
|
||||
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message)
|
||||
@@ -214,8 +224,9 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleInternals()
|
||||
internal void ToggleInternals()
|
||||
{
|
||||
if (!ActionBlockerSystem.CanUse(GetInternalsComponent()?.Owner)) return;
|
||||
if (IsConnected)
|
||||
{
|
||||
DisconnectFromInternals();
|
||||
@@ -311,6 +322,11 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
_integrity++;
|
||||
}
|
||||
|
||||
public void Dropped(DroppedEventArgs eventArgs)
|
||||
{
|
||||
DisconnectFromInternals(eventArgs.User);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open interaction window
|
||||
/// </summary>
|
||||
@@ -341,10 +357,21 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
component.OpenInterface(actor.playerSession);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dropped(DroppedEventArgs eventArgs)
|
||||
[UsedImplicitly]
|
||||
public class ToggleInternalsAction : IToggleItemAction
|
||||
{
|
||||
public void ExposeData(ObjectSerializer serializer) {}
|
||||
|
||||
public bool DoToggleAction(ToggleItemActionEventArgs args)
|
||||
{
|
||||
DisconnectFromInternals(eventArgs.User);
|
||||
if (!args.Item.TryGetComponent<GasTankComponent>(out var gasTankComponent)) return false;
|
||||
// no change
|
||||
if (gasTankComponent.IsConnected == args.ToggledOn) return false;
|
||||
gasTankComponent.ToggleInternals();
|
||||
// did we successfully toggle to the desired status?
|
||||
return gasTankComponent.IsConnected == args.ToggledOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +108,7 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
|
||||
if (Buckled)
|
||||
{
|
||||
_serverAlertsComponent.ShowAlert(BuckledTo != null ? BuckledTo.BuckledAlertType : AlertType.Buckled,
|
||||
onClickAlert: OnClickAlert);
|
||||
_serverAlertsComponent.ShowAlert(BuckledTo?.BuckledAlertType ?? AlertType.Buckled);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -117,14 +116,6 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClickAlert(ClickAlertEventArgs args)
|
||||
{
|
||||
if (args.Player.TryGetComponent(out BuckleComponent? buckle))
|
||||
{
|
||||
buckle.TryUnbuckle(args.Player);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reattaches this entity to the strap, modifying its position and rotation.
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace Content.Server.GameObjects.Components.GUI
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IHandsComponent))]
|
||||
[ComponentReference(typeof(ISharedHandsComponent))]
|
||||
[ComponentReference(typeof(SharedHandsComponent))]
|
||||
public class HandsComponent : SharedHandsComponent, IHandsComponent, IBodyPartAdded, IBodyPartRemoved
|
||||
{
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
||||
@@ -82,7 +83,7 @@ namespace Content.Server.GameObjects.Components.GUI
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsHolding(IEntity entity)
|
||||
public override bool IsHolding(IEntity entity)
|
||||
{
|
||||
foreach (var hand in _hands)
|
||||
{
|
||||
@@ -165,6 +166,7 @@ namespace Content.Server.GameObjects.Components.GUI
|
||||
}
|
||||
|
||||
Dirty();
|
||||
|
||||
var success = hand.Container.Insert(item.Owner);
|
||||
if (success)
|
||||
{
|
||||
@@ -172,6 +174,9 @@ namespace Content.Server.GameObjects.Components.GUI
|
||||
OnItemChanged?.Invoke();
|
||||
}
|
||||
|
||||
_entitySystemManager.GetEntitySystem<InteractionSystem>().EquippedHandInteraction(Owner, item.Owner,
|
||||
ToSharedHand(hand));
|
||||
|
||||
_entitySystemManager.GetEntitySystem<InteractionSystem>().HandSelectedInteraction(Owner, item.Owner);
|
||||
|
||||
return success;
|
||||
@@ -266,6 +271,9 @@ namespace Content.Server.GameObjects.Components.GUI
|
||||
return false;
|
||||
}
|
||||
|
||||
_entitySystemManager.GetEntitySystem<InteractionSystem>().UnequippedHandInteraction(Owner, item.Owner,
|
||||
ToSharedHand(hand));
|
||||
|
||||
if (doDropInteraction && !DroppedInteraction(item, false))
|
||||
return false;
|
||||
|
||||
@@ -288,6 +296,61 @@ namespace Content.Server.GameObjects.Components.GUI
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public bool Drop(string slot, BaseContainer targetContainer, bool doMobChecks = true, bool doDropInteraction = true)
|
||||
{
|
||||
if (slot == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(slot));
|
||||
}
|
||||
|
||||
if (targetContainer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(targetContainer));
|
||||
}
|
||||
|
||||
var hand = GetHand(slot);
|
||||
if (!CanDrop(slot, doMobChecks) || hand?.Entity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hand.Container.CanRemove(hand.Entity))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!targetContainer.CanInsert(hand.Entity))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var item = hand.Entity.GetComponent<ItemComponent>();
|
||||
|
||||
if (!hand.Container.Remove(hand.Entity))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
_entitySystemManager.GetEntitySystem<InteractionSystem>().UnequippedHandInteraction(Owner, item.Owner,
|
||||
ToSharedHand(hand));
|
||||
|
||||
if (doDropInteraction && !DroppedInteraction(item, doMobChecks))
|
||||
return false;
|
||||
|
||||
item.RemovedFromSlot();
|
||||
|
||||
if (!targetContainer.Insert(item.Owner))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
OnItemChanged?.Invoke();
|
||||
|
||||
Dirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Drop(IEntity entity, EntityCoordinates coords, bool doMobChecks = true, bool doDropInteraction = true)
|
||||
{
|
||||
if (entity == null)
|
||||
@@ -323,57 +386,6 @@ namespace Content.Server.GameObjects.Components.GUI
|
||||
return Drop(slot, Owner.Transform.Coordinates, mobChecks, doDropInteraction);
|
||||
}
|
||||
|
||||
public bool Drop(string slot, BaseContainer targetContainer, bool doMobChecks = true, bool doDropInteraction = true)
|
||||
{
|
||||
if (slot == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(slot));
|
||||
}
|
||||
|
||||
if (targetContainer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(targetContainer));
|
||||
}
|
||||
|
||||
var hand = GetHand(slot);
|
||||
if (!CanDrop(slot, doMobChecks) || hand?.Entity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hand.Container.CanRemove(hand.Entity))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!targetContainer.CanInsert(hand.Entity))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var item = hand.Entity.GetComponent<ItemComponent>();
|
||||
|
||||
if (!hand.Container.Remove(hand.Entity))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (doDropInteraction && !DroppedInteraction(item, doMobChecks))
|
||||
return false;
|
||||
|
||||
item.RemovedFromSlot();
|
||||
|
||||
if (!targetContainer.Insert(item.Owner))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
OnItemChanged?.Invoke();
|
||||
|
||||
Dirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Drop(IEntity entity, BaseContainer targetContainer, bool doMobChecks = true, bool doDropInteraction = true)
|
||||
{
|
||||
if (entity == null)
|
||||
@@ -463,19 +475,28 @@ namespace Content.Server.GameObjects.Components.GUI
|
||||
|
||||
for (var i = 0; i < _hands.Count; i++)
|
||||
{
|
||||
var location = i == 0
|
||||
? HandLocation.Right
|
||||
: i == _hands.Count - 1
|
||||
? HandLocation.Left
|
||||
: HandLocation.Middle;
|
||||
|
||||
var hand = _hands[i].ToShared(i, location);
|
||||
var hand = _hands[i].ToShared(i, IndexToHandLocation(i));
|
||||
hands[i] = hand;
|
||||
}
|
||||
|
||||
return new HandsComponentState(hands, ActiveHand);
|
||||
}
|
||||
|
||||
private HandLocation IndexToHandLocation(int index)
|
||||
{
|
||||
return index == 0
|
||||
? HandLocation.Right
|
||||
: index == _hands.Count - 1
|
||||
? HandLocation.Left
|
||||
: HandLocation.Middle;
|
||||
}
|
||||
|
||||
private SharedHand ToSharedHand(Hand hand)
|
||||
{
|
||||
var index = _hands.IndexOf(hand);
|
||||
return hand.ToShared(index, IndexToHandLocation(index));
|
||||
}
|
||||
|
||||
public void SwapHands()
|
||||
{
|
||||
if (ActiveHand == null)
|
||||
|
||||
@@ -25,6 +25,7 @@ using static Content.Shared.GameObjects.Components.Inventory.SharedInventoryComp
|
||||
namespace Content.Server.GameObjects.Components.GUI
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedInventoryComponent))]
|
||||
public class InventoryComponent : SharedInventoryComponent, IExAct, IEffectBlocker, IPressureProtection
|
||||
{
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
||||
@@ -572,5 +573,20 @@ namespace Content.Server.GameObjects.Components.GUI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsEquipped(IEntity item)
|
||||
{
|
||||
if (item == null) return false;
|
||||
foreach (var containerSlot in _slotContainers.Values)
|
||||
{
|
||||
// we don't want a recursive check here
|
||||
if (containerSlot.Contains(item))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
#nullable enable
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Items.Clothing;
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects.Verbs;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Content.Shared.Utility;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.ComponentDependencies;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
@@ -45,6 +53,8 @@ namespace Content.Server.GameObjects.Components.Interactable
|
||||
[ViewVariables(VVAccess.ReadWrite)] public string? TurnOnFailSound;
|
||||
[ViewVariables(VVAccess.ReadWrite)] public string? TurnOffSound;
|
||||
|
||||
[ComponentDependency] private readonly ItemActionsComponent? _itemActions = null;
|
||||
|
||||
/// <summary>
|
||||
/// Client-side ItemStatus level
|
||||
/// </summary>
|
||||
@@ -98,8 +108,9 @@ namespace Content.Server.GameObjects.Components.Interactable
|
||||
/// Illuminates the light if it is not active, extinguishes it if it is active.
|
||||
/// </summary>
|
||||
/// <returns>True if the light's status was toggled, false otherwise.</returns>
|
||||
private bool ToggleStatus(IEntity user)
|
||||
public bool ToggleStatus(IEntity user)
|
||||
{
|
||||
if (!ActionBlockerSystem.CanUse(user)) return false;
|
||||
return Activated ? TurnOff() : TurnOn(user);
|
||||
}
|
||||
|
||||
@@ -112,6 +123,7 @@ namespace Content.Server.GameObjects.Components.Interactable
|
||||
|
||||
SetState(false);
|
||||
Activated = false;
|
||||
UpdateLightAction();
|
||||
|
||||
if (makeNoise)
|
||||
{
|
||||
@@ -132,6 +144,7 @@ namespace Content.Server.GameObjects.Components.Interactable
|
||||
{
|
||||
if (TurnOnFailSound != null) EntitySystem.Get<AudioSystem>().PlayFromEntity(TurnOnFailSound, Owner);
|
||||
Owner.PopupMessage(user, Loc.GetString("Cell missing..."));
|
||||
UpdateLightAction();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -142,10 +155,12 @@ namespace Content.Server.GameObjects.Components.Interactable
|
||||
{
|
||||
if (TurnOnFailSound != null) EntitySystem.Get<AudioSystem>().PlayFromEntity(TurnOnFailSound, Owner);
|
||||
Owner.PopupMessage(user, Loc.GetString("Dead cell..."));
|
||||
UpdateLightAction();
|
||||
return false;
|
||||
}
|
||||
|
||||
Activated = true;
|
||||
UpdateLightAction();
|
||||
SetState(true);
|
||||
|
||||
if (TurnOnSound != null) EntitySystem.Get<AudioSystem>().PlayFromEntity(TurnOnSound, Owner);
|
||||
@@ -175,6 +190,11 @@ namespace Content.Server.GameObjects.Components.Interactable
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLightAction()
|
||||
{
|
||||
_itemActions?.Toggle(ItemActionType.ToggleLight, Activated);
|
||||
}
|
||||
|
||||
public void OnUpdate(float frameTime)
|
||||
{
|
||||
if (Cell == null)
|
||||
@@ -249,4 +269,17 @@ namespace Content.Server.GameObjects.Components.Interactable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public class ToggleLightAction : IToggleItemAction
|
||||
{
|
||||
public void ExposeData(ObjectSerializer serializer) {}
|
||||
|
||||
public bool DoToggleAction(ToggleItemActionEventArgs args)
|
||||
{
|
||||
if (!args.Item.TryGetComponent<HandheldLightComponent>(out var lightComponent)) return false;
|
||||
if (lightComponent.Activated == args.ToggledOn) return false;
|
||||
return lightComponent.ToggleStatus(args.Performer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Pops up a message when equipped / unequipped (including hands).
|
||||
/// For debugging purposes.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class DebugEquipComponent : Component, IEquipped, IEquippedHand, IUnequipped, IUnequippedHand
|
||||
{
|
||||
public override string Name => "DebugEquip";
|
||||
public void Equipped(EquippedEventArgs eventArgs)
|
||||
{
|
||||
eventArgs.User.PopupMessage("equipped " + Owner.Name);
|
||||
}
|
||||
|
||||
public void EquippedHand(EquippedHandEventArgs eventArgs)
|
||||
{
|
||||
eventArgs.User.PopupMessage("equipped hand " + Owner.Name);
|
||||
}
|
||||
|
||||
public void Unequipped(UnequippedEventArgs eventArgs)
|
||||
{
|
||||
eventArgs.User.PopupMessage("unequipped " + Owner.Name);
|
||||
}
|
||||
|
||||
public void UnequippedHand(UnequippedHandEventArgs eventArgs)
|
||||
{
|
||||
eventArgs.User.PopupMessage("unequipped hand" + Owner.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Players;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Mobs
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedActionsComponent))]
|
||||
public sealed class ServerActionsComponent : SharedActionsComponent
|
||||
{
|
||||
[Dependency] private readonly IServerEntityManager _entityManager = default!;
|
||||
|
||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession? session = null)
|
||||
{
|
||||
base.HandleNetworkMessage(message, netChannel, session);
|
||||
|
||||
if (message is not BasePerformActionMessage performActionMessage) return;
|
||||
if (session == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(session));
|
||||
}
|
||||
|
||||
var player = session.AttachedEntity;
|
||||
if (player != Owner) return;
|
||||
var attempt = ActionAttempt(performActionMessage, session);
|
||||
if (attempt == null) return;
|
||||
|
||||
if (!attempt.TryGetActionState(this, out var actionState) || !actionState.Enabled)
|
||||
{
|
||||
Logger.DebugS("action", "user {0} attempted to use" +
|
||||
" action {1} which is not granted to them", player.Name,
|
||||
attempt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (actionState.IsOnCooldown(GameTiming))
|
||||
{
|
||||
Logger.DebugS("action", "user {0} attempted to use" +
|
||||
" action {1} which is on cooldown", player.Name,
|
||||
attempt);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (performActionMessage.BehaviorType)
|
||||
{
|
||||
case BehaviorType.Instant:
|
||||
attempt.DoInstantAction(player);
|
||||
break;
|
||||
case BehaviorType.Toggle:
|
||||
if (performActionMessage is not IToggleActionMessage toggleMsg) return;
|
||||
if (toggleMsg.ToggleOn == actionState.ToggledOn)
|
||||
{
|
||||
Logger.DebugS("action", "user {0} attempted to" +
|
||||
" toggle action {1} to {2}, but it is already toggled {2}", player.Name,
|
||||
attempt.Action.Name, toggleMsg.ToggleOn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (attempt.DoToggleAction(player, toggleMsg.ToggleOn))
|
||||
{
|
||||
attempt.ToggleAction(this, toggleMsg.ToggleOn);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if client predicted the toggle will work, need to reset
|
||||
// that prediction
|
||||
Dirty();
|
||||
}
|
||||
break;
|
||||
case BehaviorType.TargetPoint:
|
||||
if (performActionMessage is not ITargetPointActionMessage targetPointMsg) return;
|
||||
if (!CheckRangeAndSetFacing(targetPointMsg.Target, player)) return;
|
||||
attempt.DoTargetPointAction(player, targetPointMsg.Target);
|
||||
break;
|
||||
case BehaviorType.TargetEntity:
|
||||
if (performActionMessage is not ITargetEntityActionMessage targetEntityMsg) return;
|
||||
if (!EntityManager.TryGetEntity(targetEntityMsg.Target, out var entity))
|
||||
{
|
||||
Logger.DebugS("action", "user {0} attempted to" +
|
||||
" perform target entity action {1} but could not find entity with " +
|
||||
"provided uid {2}", player.Name, attempt.Action.Name,
|
||||
targetEntityMsg.Target);
|
||||
return;
|
||||
}
|
||||
if (!CheckRangeAndSetFacing(entity.Transform.Coordinates, player)) return;
|
||||
|
||||
attempt.DoTargetEntityAction(player, entity);
|
||||
break;
|
||||
case BehaviorType.None:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private IActionAttempt? ActionAttempt(BasePerformActionMessage message, ICommonSession session)
|
||||
{
|
||||
IActionAttempt? attempt;
|
||||
switch (message)
|
||||
{
|
||||
case PerformActionMessage performActionMessage:
|
||||
if (!ActionManager.TryGet(performActionMessage.ActionType, out var action))
|
||||
{
|
||||
Logger.DebugS("action", "user {0} attempted to perform" +
|
||||
" unrecognized action {1}", session.AttachedEntity,
|
||||
performActionMessage.ActionType);
|
||||
return null;
|
||||
}
|
||||
attempt = new ActionAttempt(action);
|
||||
break;
|
||||
case PerformItemActionMessage performItemActionMessage:
|
||||
if (!ActionManager.TryGet(performItemActionMessage.ActionType, out var itemAction))
|
||||
{
|
||||
Logger.DebugS("action", "user {0} attempted to perform" +
|
||||
" unrecognized item action {1}",
|
||||
session.AttachedEntity, performItemActionMessage.ActionType);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!EntityManager.TryGetEntity(performItemActionMessage.Item, out var item))
|
||||
{
|
||||
Logger.DebugS("action", "user {0} attempted to perform" +
|
||||
" item action {1} for unknown item {2}",
|
||||
session.AttachedEntity, performItemActionMessage.ActionType, performItemActionMessage.Item);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!item.TryGetComponent<ItemActionsComponent>(out var actionsComponent))
|
||||
{
|
||||
Logger.DebugS("action", "user {0} attempted to perform" +
|
||||
" item action {1} for item {2} which has no ItemActionsComponent",
|
||||
session.AttachedEntity, performItemActionMessage.ActionType, item);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (actionsComponent.Holder != session.AttachedEntity)
|
||||
{
|
||||
Logger.DebugS("action", "user {0} attempted to perform" +
|
||||
" item action {1} for item {2} which they are not holding",
|
||||
session.AttachedEntity, performItemActionMessage.ActionType, item);
|
||||
return null;
|
||||
}
|
||||
|
||||
attempt = new ItemActionAttempt(itemAction, item, actionsComponent);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
if (message.BehaviorType != attempt.Action.BehaviorType)
|
||||
{
|
||||
Logger.DebugS("action", "user {0} attempted to" +
|
||||
" perform action {1} as a {2} behavior, but this action is actually a" +
|
||||
" {3} behavior", session.AttachedEntity, attempt, message.BehaviorType,
|
||||
attempt.Action.BehaviorType);
|
||||
return null;
|
||||
}
|
||||
|
||||
return attempt;
|
||||
}
|
||||
|
||||
private bool CheckRangeAndSetFacing(EntityCoordinates target, IEntity player)
|
||||
{
|
||||
// ensure it's within their clickable range
|
||||
var targetWorldPos = target.ToMapPos(EntityManager);
|
||||
var rangeBox = new Box2(player.Transform.WorldPosition, player.Transform.WorldPosition)
|
||||
.Enlarged(_entityManager.MaxUpdateRange);
|
||||
if (!rangeBox.Contains(targetWorldPos))
|
||||
{
|
||||
Logger.DebugS("action", "user {0} attempted to" +
|
||||
" perform target action further than allowed range",
|
||||
player.Name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ActionBlockerSystem.CanChangeDirection(player)) return true;
|
||||
|
||||
// don't set facing unless they clicked far enough away
|
||||
var diff = targetWorldPos - player.Transform.WorldPosition;
|
||||
if (diff.LengthSquared > 0.01f)
|
||||
{
|
||||
player.Transform.LocalRotation = new Angle(diff);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
@@ -42,11 +43,6 @@ namespace Content.Server.GameObjects.Components.Mobs
|
||||
base.OnRemove();
|
||||
}
|
||||
|
||||
public override ComponentState GetComponentState()
|
||||
{
|
||||
return new AlertsComponentState(CreateAlertStatesArray());
|
||||
}
|
||||
|
||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession session = null)
|
||||
{
|
||||
base.HandleNetworkMessage(message, netChannel, session);
|
||||
@@ -67,14 +63,21 @@ namespace Content.Server.GameObjects.Components.Mobs
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Implement clicking other status effects in the HUD
|
||||
if (AlertManager.TryDecode(msg.EncodedAlert, out var alert))
|
||||
if (!IsShowingAlert(msg.AlertType))
|
||||
{
|
||||
PerformAlertClickCallback(alert, player);
|
||||
Logger.DebugS("alert", "user {0} attempted to" +
|
||||
" click alert {1} which is not currently showing for them",
|
||||
player.Name, msg.AlertType);
|
||||
break;
|
||||
}
|
||||
|
||||
if (AlertManager.TryGet(msg.AlertType, out var alert))
|
||||
{
|
||||
alert.OnClick.AlertClicked(new ClickAlertEventArgs(player, alert));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.WarningS("alert", "unrecognized encoded alert {0}", msg.EncodedAlert);
|
||||
Logger.WarningS("alert", "unrecognized encoded alert {0}", msg.AlertType);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -145,15 +145,7 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
mind.Mind.Visit(Owner);
|
||||
_controller = entity;
|
||||
|
||||
status.ShowAlert(_pilotingAlertType, onClickAlert: OnClickAlert);
|
||||
}
|
||||
|
||||
private void OnClickAlert(ClickAlertEventArgs args)
|
||||
{
|
||||
if (args.Player.TryGetComponent(out ShuttleControllerComponent? controller))
|
||||
{
|
||||
controller.RemoveController();
|
||||
}
|
||||
status.ShowAlert(_pilotingAlertType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user