diff --git a/Content.Client/Chat/ChatBox.cs b/Content.Client/Chat/ChatBox.cs
index 87bbebba1b..7f3e1aa3ec 100644
--- a/Content.Client/Chat/ChatBox.cs
+++ b/Content.Client/Chat/ChatBox.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Content.Shared.Chat;
+using Robust.Client.Console;
using Robust.Client.Graphics.Drawing;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
@@ -26,6 +27,7 @@ namespace Content.Client.Chat
public Button AllButton { get; }
public Button LocalButton { get; }
public Button OOCButton { get; }
+ public Button AdminButton { get; }
///
/// Default formatting string for the ClientChatConsole.
@@ -59,6 +61,7 @@ namespace Content.Client.Chat
outerVBox.AddChild(panelContainer);
outerVBox.AddChild(hBox);
+
var contentMargin = new MarginContainer
{
MarginLeftOverride = 4, MarginRightOverride = 4,
@@ -95,6 +98,17 @@ namespace Content.Client.Chat
ToggleMode = true,
};
+ var groupController = IoCManager.Resolve();
+ if(groupController.CanCommand("asay"))
+ {
+ AdminButton = new Button
+ {
+ Text = _localize.GetString("Admin"),
+ Name = "Admin",
+ ToggleMode = true,
+ };
+ }
+
AllButton.OnToggled += OnFilterToggled;
LocalButton.OnToggled += OnFilterToggled;
OOCButton.OnToggled += OnFilterToggled;
@@ -102,6 +116,11 @@ namespace Content.Client.Chat
hBox.AddChild(AllButton);
hBox.AddChild(LocalButton);
hBox.AddChild(OOCButton);
+ if(AdminButton != null)
+ {
+ AdminButton.OnToggled += OnFilterToggled;
+ hBox.AddChild(AdminButton);
+ }
AddChild(outerVBox);
}
diff --git a/Content.Client/Chat/ChatManager.cs b/Content.Client/Chat/ChatManager.cs
index 61d1d4ae03..2264931496 100644
--- a/Content.Client/Chat/ChatManager.cs
+++ b/Content.Client/Chat/ChatManager.cs
@@ -48,6 +48,7 @@ namespace Content.Client.Chat
private const char ConCmdSlash = '/';
private const char OOCAlias = '[';
private const char MeAlias = '@';
+ private const char AdminChatAlias = ']';
private readonly List filteredHistory = new List();
@@ -55,6 +56,7 @@ namespace Content.Client.Chat
private bool _allState;
private bool _localState;
private bool _oocState;
+ private bool _adminState;
// Flag Enums for holding filtered channels
private ChatChannel _filteredChannels;
@@ -65,6 +67,7 @@ namespace Content.Client.Chat
[Dependency] private readonly IEntityManager _entityManager;
[Dependency] private readonly IEyeManager _eyeManager;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager;
+ [Dependency] private readonly IClientConGroupController _groupController = default!;
#pragma warning restore 649
private ChatBox _currentChatBox;
@@ -150,6 +153,8 @@ namespace Content.Client.Chat
_currentChatBox.AllButton.Pressed = !_allState;
_currentChatBox.LocalButton.Pressed = !_localState;
_currentChatBox.OOCButton.Pressed = !_oocState;
+ if(chatBox.AdminButton != null)
+ _currentChatBox.AdminButton.Pressed = !_adminState;
}
public void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble)
@@ -193,6 +198,9 @@ namespace Content.Client.Chat
case ChatChannel.Dead:
color = Color.MediumPurple;
break;
+ case ChatChannel.AdminChat:
+ color = Color.Red;
+ break;
}
_currentChatBox?.AddLine(messageText, message.Channel, color);
@@ -220,6 +228,18 @@ namespace Content.Client.Chat
_console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\"");
break;
}
+ case AdminChatAlias:
+ {
+ var conInput = text.Substring(1);
+ if(_groupController.CanCommand("asay")){
+ _console.ProcessCommand($"asay \"{CommandParsing.Escape(conInput)}\"");
+ }
+ else
+ {
+ _console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\"");
+ }
+ break;
+ }
case MeAlias:
{
var conInput = text.Substring(1);
@@ -266,10 +286,23 @@ namespace Content.Client.Chat
_filteredChannels &= ~ChatChannel.OOC;
break;
}
+ case "Admin":
+ _adminState = !_adminState;
+ if (_adminState)
+ {
+ _filteredChannels |= ChatChannel.AdminChat;
+ break;
+ }
+ else
+ {
+ _filteredChannels &= ~ChatChannel.AdminChat;
+ break;
+ }
case "ALL":
chatBox.LocalButton.Pressed ^= true;
chatBox.OOCButton.Pressed ^= true;
+ chatBox.AdminButton.Pressed ^= true;
_allState = !_allState;
break;
}
diff --git a/Content.Client/ClickMapManager.cs b/Content.Client/ClickMapManager.cs
index a9938f05c8..36d5382157 100644
--- a/Content.Client/ClickMapManager.cs
+++ b/Content.Client/ClickMapManager.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System;
using System.Collections.Generic;
using System.Text;
@@ -11,8 +12,6 @@ using Robust.Shared.ViewVariables;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
-#nullable enable
-
namespace Content.Client
{
internal class ClickMapManager : IClickMapManager, IPostInjectInit
diff --git a/Content.Client/GameObjects/Components/ClickableComponent.cs b/Content.Client/GameObjects/Components/ClickableComponent.cs
index 3b36e8d38a..57d9420167 100644
--- a/Content.Client/GameObjects/Components/ClickableComponent.cs
+++ b/Content.Client/GameObjects/Components/ClickableComponent.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System;
using Robust.Client.Graphics.ClientEye;
using Robust.Client.Interfaces.GameObjects.Components;
@@ -8,8 +9,6 @@ using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
-#nullable enable
-
namespace Content.Client.GameObjects.Components
{
[RegisterComponent]
diff --git a/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs b/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs
index 2791aa7ddb..69d364fd5f 100644
--- a/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs
+++ b/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs
@@ -1,24 +1,17 @@
+#nullable enable
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Content.Shared.GameObjects.Components.Instruments;
using Content.Shared.Physics;
-using JetBrains.Annotations;
-using NFluidsynth;
using Robust.Shared.GameObjects;
using Robust.Client.Audio.Midi;
-using Robust.Client.Player;
-using Robust.Shared.Interfaces.Log;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
-using Robust.Shared.Log;
using Robust.Shared.Players;
using Robust.Shared.Serialization;
-using Robust.Shared.Timing;
using Robust.Shared.ViewVariables;
-using Logger = Robust.Shared.Log.Logger;
using MidiEvent = Robust.Shared.Audio.Midi.MidiEvent;
using Timer = Robust.Shared.Timers.Timer;
@@ -32,24 +25,23 @@ namespace Content.Client.GameObjects.Components.Instruments
///
/// Called when a midi song stops playing.
///
- public event Action OnMidiPlaybackEnded;
+ public event Action? OnMidiPlaybackEnded;
#pragma warning disable 649
- [Dependency] private readonly IMidiManager _midiManager;
+ [Dependency] private readonly IMidiManager _midiManager = default!;
- [Dependency] private readonly IGameTiming _gameTiming;
+ [Dependency] private readonly IGameTiming _gameTiming = default!;
- [Dependency] private readonly IClientNetManager _netManager;
+ [Dependency] private readonly IClientNetManager _netManager = default!;
#pragma warning restore 649
- [CanBeNull]
- private IMidiRenderer _renderer;
+ private IMidiRenderer? _renderer;
private byte _instrumentProgram = 1;
- private byte _instrumentBank = 0;
+ private byte _instrumentBank;
- private uint _sequenceDelay = 0;
+ private uint _sequenceDelay;
private uint _sequenceStartTick;
@@ -209,7 +201,7 @@ namespace Content.Client.GameObjects.Components.Instruments
serializer.DataField(ref _instrumentBank, "bank", (byte) 0);
}
- public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null)
+ public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession? session = null)
{
base.HandleNetworkMessage(message, channel, session);
@@ -240,7 +232,7 @@ namespace Content.Client.GameObjects.Components.Instruments
.Min(x => x.Tick) - 1;
}
- var sqrtLag = MathF.Sqrt(_netManager.ServerChannel.Ping / 1000f);
+ var sqrtLag = MathF.Sqrt(_netManager.ServerChannel!.Ping / 1000f);
var delay = (uint) (_renderer!.SequencerTimeScale * (.2 + sqrtLag));
var delta = delay - _sequenceStartTick;
@@ -265,12 +257,12 @@ namespace Content.Client.GameObjects.Components.Instruments
}
break;
- case InstrumentStartMidiMessage startMidiMessage:
+ case InstrumentStartMidiMessage _:
{
SetupRenderer(true);
break;
}
- case InstrumentStopMidiMessage stopMidiMessage:
+ case InstrumentStopMidiMessage _:
{
EndRenderer(true);
break;
@@ -278,7 +270,7 @@ namespace Content.Client.GameObjects.Components.Instruments
}
}
- public override void HandleComponentState(ComponentState curState, ComponentState nextState)
+ public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{
base.HandleComponentState(curState, nextState);
if (!(curState is InstrumentState state)) return;
@@ -370,7 +362,7 @@ namespace Content.Client.GameObjects.Components.Instruments
private TimeSpan _lastMeasured = TimeSpan.MinValue;
- private int _sentWithinASec = 0;
+ private int _sentWithinASec;
private static readonly TimeSpan OneSecAgo = TimeSpan.FromSeconds(-1);
diff --git a/Content.Client/GameObjects/Components/Mobs/ClientOverlayEffectsComponent.cs b/Content.Client/GameObjects/Components/Mobs/ClientOverlayEffectsComponent.cs
index 580a3de334..acd8928375 100644
--- a/Content.Client/GameObjects/Components/Mobs/ClientOverlayEffectsComponent.cs
+++ b/Content.Client/GameObjects/Components/Mobs/ClientOverlayEffectsComponent.cs
@@ -28,7 +28,7 @@ namespace Content.Client.GameObjects.Components.Mobs
///
/// An enum representing the current state being applied to the user
///
- private readonly List _currentEffects = new List();
+ private List _currentEffects = new List();
[ViewVariables(VVAccess.ReadOnly)]
public List ActiveOverlays
@@ -49,7 +49,9 @@ namespace Content.Client.GameObjects.Components.Mobs
switch (message)
{
case PlayerAttachedMsg _:
- SetEffects(ActiveOverlays);
+ var overlays = new List(_currentEffects);
+ _currentEffects.Clear();
+ SetEffects(overlays);
break;
case PlayerDetachedMsg _:
ActiveOverlays = new List();
@@ -61,14 +63,20 @@ namespace Content.Client.GameObjects.Components.Mobs
{
base.HandleComponentState(curState, nextState);
- if(_playerManager?.LocalPlayer != null && _playerManager.LocalPlayer.ControlledEntity != Owner)
- return;
-
- if (!(curState is OverlayEffectComponentState state) || ActiveOverlays.Equals(state.Overlays))
+ if (!(curState is OverlayEffectComponentState state))
{
return;
}
+ if (_playerManager?.LocalPlayer != null && _playerManager.LocalPlayer.ControlledEntity != Owner)
+ {
+ _currentEffects = state.Overlays;
+ return;
+ }
+
+ if (ActiveOverlays.Equals(state.Overlays))
+ return;
+
ActiveOverlays = state.Overlays;
}
diff --git a/Content.Client/GameObjects/Components/Mobs/StatusControl.cs b/Content.Client/GameObjects/Components/Mobs/StatusControl.cs
index 591bf9e1c9..7df0225a90 100644
--- a/Content.Client/GameObjects/Components/Mobs/StatusControl.cs
+++ b/Content.Client/GameObjects/Components/Mobs/StatusControl.cs
@@ -1,5 +1,5 @@
-using Content.Shared.GameObjects.Components.Mobs;
-using JetBrains.Annotations;
+#nullable enable
+using Content.Shared.GameObjects.Components.Mobs;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
@@ -9,7 +9,7 @@ namespace Content.Client.GameObjects.Components.Mobs
{
public readonly StatusEffect Effect;
- public StatusControl(StatusEffect effect, [CanBeNull] Texture texture)
+ public StatusControl(StatusEffect effect, Texture? texture)
{
Effect = effect;
diff --git a/Content.Client/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Client/GameObjects/Components/Mobs/StunnableComponent.cs
index 7ff78391ca..7c01000dd4 100644
--- a/Content.Client/GameObjects/Components/Mobs/StunnableComponent.cs
+++ b/Content.Client/GameObjects/Components/Mobs/StunnableComponent.cs
@@ -1,9 +1,8 @@
+#nullable enable
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Movement;
using Robust.Shared.GameObjects;
-#nullable enable
-
namespace Content.Client.GameObjects.Components.Mobs
{
[RegisterComponent]
diff --git a/Content.Client/GameObjects/Components/Movement/PlayerInputMoverComponent.cs b/Content.Client/GameObjects/Components/Movement/PlayerInputMoverComponent.cs
index 50bcbd2790..fcdde82ef8 100644
--- a/Content.Client/GameObjects/Components/Movement/PlayerInputMoverComponent.cs
+++ b/Content.Client/GameObjects/Components/Movement/PlayerInputMoverComponent.cs
@@ -1,14 +1,13 @@
+#nullable enable
using Content.Shared.GameObjects.Components.Movement;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
-#nullable enable
-
namespace Content.Client.GameObjects.Components.Movement
{
[RegisterComponent]
[ComponentReference(typeof(IMoverComponent))]
- public class PlayerInputMoverComponent : SharedPlayerInputMoverComponent, IMoverComponent
+ public class PlayerInputMoverComponent : SharedPlayerInputMoverComponent
{
public override GridCoordinates LastPosition { get; set; }
public override float StepSoundDistance { get; set; }
diff --git a/Content.Client/GameObjects/Components/Nutrition/HungerComponent.cs b/Content.Client/GameObjects/Components/Nutrition/HungerComponent.cs
index fa66e98812..8323fb5e7a 100644
--- a/Content.Client/GameObjects/Components/Nutrition/HungerComponent.cs
+++ b/Content.Client/GameObjects/Components/Nutrition/HungerComponent.cs
@@ -1,9 +1,8 @@
+#nullable enable
using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Nutrition;
using Robust.Shared.GameObjects;
-#nullable enable
-
namespace Content.Client.GameObjects.Components.Nutrition
{
[RegisterComponent]
diff --git a/Content.Client/GameObjects/Components/Nutrition/ThirstComponent.cs b/Content.Client/GameObjects/Components/Nutrition/ThirstComponent.cs
index 10b63d054b..b77d59a34a 100644
--- a/Content.Client/GameObjects/Components/Nutrition/ThirstComponent.cs
+++ b/Content.Client/GameObjects/Components/Nutrition/ThirstComponent.cs
@@ -1,9 +1,8 @@
+#nullable enable
using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Nutrition;
using Robust.Shared.GameObjects;
-#nullable enable
-
namespace Content.Client.GameObjects.Components.Nutrition
{
[RegisterComponent]
diff --git a/Content.Client/GameObjects/Components/Projectiles/ProjectileComponent.cs b/Content.Client/GameObjects/Components/Projectiles/ProjectileComponent.cs
index 27e8ed6285..9abf4a557b 100644
--- a/Content.Client/GameObjects/Components/Projectiles/ProjectileComponent.cs
+++ b/Content.Client/GameObjects/Components/Projectiles/ProjectileComponent.cs
@@ -1,8 +1,7 @@
+#nullable enable
using Content.Shared.GameObjects.Components.Projectiles;
using Robust.Shared.GameObjects;
-#nullable enable
-
namespace Content.Client.GameObjects.Components.Projectiles
{
[RegisterComponent]
diff --git a/Content.Client/GameObjects/Components/Weapons/ClientFlashableComponent.cs b/Content.Client/GameObjects/Components/Weapons/FlashableComponent.cs
similarity index 96%
rename from Content.Client/GameObjects/Components/Weapons/ClientFlashableComponent.cs
rename to Content.Client/GameObjects/Components/Weapons/FlashableComponent.cs
index b521ff0371..d7c5199396 100644
--- a/Content.Client/GameObjects/Components/Weapons/ClientFlashableComponent.cs
+++ b/Content.Client/GameObjects/Components/Weapons/FlashableComponent.cs
@@ -16,7 +16,7 @@ using Timer = Robust.Shared.Timers.Timer;
namespace Content.Client.GameObjects.Components.Weapons
{
[RegisterComponent]
- public sealed class ClientFlashableComponent : SharedFlashableComponent
+ public sealed class FlashableComponent : SharedFlashableComponent
{
private CancellationTokenSource _cancelToken;
private TimeSpan _startTime;
@@ -31,7 +31,7 @@ namespace Content.Client.GameObjects.Components.Weapons
}
var playerManager = IoCManager.Resolve();
- if (playerManager.LocalPlayer.ControlledEntity != Owner)
+ if (playerManager?.LocalPlayer != null && playerManager.LocalPlayer.ControlledEntity != Owner)
{
return;
}
diff --git a/Content.Client/GameObjects/EntitySystems/MoverSystem.cs b/Content.Client/GameObjects/EntitySystems/MoverSystem.cs
index 37689e355c..84fe87bf25 100644
--- a/Content.Client/GameObjects/EntitySystems/MoverSystem.cs
+++ b/Content.Client/GameObjects/EntitySystems/MoverSystem.cs
@@ -1,4 +1,5 @@
-using Content.Shared.GameObjects.Components.Movement;
+#nullable enable
+using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Physics;
using JetBrains.Annotations;
@@ -7,8 +8,6 @@ using Robust.Client.Player;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.IoC;
-#nullable enable
-
namespace Content.Client.GameObjects.EntitySystems
{
[UsedImplicitly]
diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs
index 5e54b537dc..197774ed33 100644
--- a/Content.Client/Input/ContentContexts.cs
+++ b/Content.Client/Input/ContentContexts.cs
@@ -14,6 +14,7 @@ namespace Content.Client.Input
var common = contexts.GetContext("common");
common.AddFunction(ContentKeyFunctions.FocusChat);
common.AddFunction(ContentKeyFunctions.FocusOOC);
+ common.AddFunction(ContentKeyFunctions.FocusAdminChat);
common.AddFunction(ContentKeyFunctions.ExamineEntity);
common.AddFunction(ContentKeyFunctions.OpenTutorial);
common.AddFunction(ContentKeyFunctions.TakeScreenshot);
diff --git a/Content.Client/State/GameScreen.cs b/Content.Client/State/GameScreen.cs
index a0d947c4e8..7e36c9cca0 100644
--- a/Content.Client/State/GameScreen.cs
+++ b/Content.Client/State/GameScreen.cs
@@ -4,6 +4,7 @@ using Content.Client.Chat;
using Content.Client.Interfaces.Chat;
using Content.Client.UserInterface;
using Content.Shared.Input;
+using Robust.Client.Console;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.State;
using Robust.Client.Interfaces.UserInterface;
@@ -25,6 +26,7 @@ namespace Content.Client.State
[Dependency] private readonly IGameHud _gameHud;
[Dependency] private readonly IInputManager _inputManager;
[Dependency] private readonly IChatManager _chatManager;
+ [Dependency] private readonly IClientConGroupController _groupController = default!;
#pragma warning restore 649
[ViewVariables] private ChatBox _gameChat;
@@ -34,6 +36,7 @@ namespace Content.Client.State
base.Startup();
_gameChat = new ChatBox();
+
_userInterfaceManager.StateRoot.AddChild(_gameChat);
LayoutContainer.SetAnchorAndMarginPreset(_gameChat, LayoutContainer.LayoutPreset.TopRight, margin: 10);
LayoutContainer.SetAnchorAndMarginPreset(_gameChat, LayoutContainer.LayoutPreset.TopRight, margin: 10);
@@ -50,6 +53,9 @@ namespace Content.Client.State
_inputManager.SetInputCommand(ContentKeyFunctions.FocusOOC,
InputCmdHandler.FromDelegate(s => FocusOOC(_gameChat)));
+
+ _inputManager.SetInputCommand(ContentKeyFunctions.FocusAdminChat,
+ InputCmdHandler.FromDelegate(s => FocusAdminChat(_gameChat)));
}
public override void Shutdown()
@@ -81,5 +87,17 @@ namespace Content.Client.State
chat.Input.GrabKeyboardFocus();
chat.Input.InsertAtCursor("[");
}
+
+ internal static void FocusAdminChat(ChatBox chat)
+ {
+ if (chat == null || chat.UserInterfaceManager.KeyboardFocused != null)
+ {
+ return;
+ }
+
+ chat.Input.IgnoreNext = true;
+ chat.Input.GrabKeyboardFocus();
+ chat.Input.InsertAtCursor("]");
+ }
}
}
diff --git a/Content.Client/UserInterface/CreditsWindow.cs b/Content.Client/UserInterface/CreditsWindow.cs
index 56ac89f153..1bdd4c7a76 100644
--- a/Content.Client/UserInterface/CreditsWindow.cs
+++ b/Content.Client/UserInterface/CreditsWindow.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -13,8 +14,6 @@ using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
-#nullable enable
-
namespace Content.Client.UserInterface
{
public sealed class CreditsWindow : SS14Window
diff --git a/Content.Client/UserInterface/TutorialWindow.cs b/Content.Client/UserInterface/TutorialWindow.cs
index d34ac4cb0d..bf6796e789 100644
--- a/Content.Client/UserInterface/TutorialWindow.cs
+++ b/Content.Client/UserInterface/TutorialWindow.cs
@@ -76,6 +76,7 @@ Open character window: [color=#a4885c]{8}[/color]
Open crafting window: [color=#a4885c]{9}[/color]
Focus chat: [color=#a4885c]{10}[/color]
Focus OOC: [color=#a4885c]{26}[/color]
+Focus Admin Chat: [color=#a4885c]{27}[/color]
Use hand/object in hand: [color=#a4885c]{22}[/color]
Do wide attack: [color=#a4885c]{23}[/color]
Use targeted entity: [color=#a4885c]{11}[/color]
@@ -112,7 +113,8 @@ Toggle sandbox window: [color=#a4885c]{21}[/color]",
Key(WideAttack),
Key(SmartEquipBackpack),
Key(SmartEquipBelt),
- Key(FocusOOC)));
+ Key(FocusOOC),
+ Key(FocusAdminChat)));
//Gameplay
VBox.AddChild(new Label { FontOverride = headerFont, Text = "\nGameplay" });
diff --git a/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs b/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs
index 794dfb0fe6..93d2db7549 100644
--- a/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs
+++ b/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -15,8 +16,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Timing;
-#nullable enable
-
namespace Content.IntegrationTests.Tests.Networking
{
// This test checks that the prediction & reconciling system is working correctly with a simple boolean flag.
diff --git a/Content.Server/AI/Utility/Actions/Clothing/Gloves/EquipGloves.cs b/Content.Server/AI/Utility/Actions/Clothing/Gloves/EquipGloves.cs
index 1d382044d1..96317b6ad2 100644
--- a/Content.Server/AI/Utility/Actions/Clothing/Gloves/EquipGloves.cs
+++ b/Content.Server/AI/Utility/Actions/Clothing/Gloves/EquipGloves.cs
@@ -1,14 +1,15 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.Gloves
{
@@ -36,12 +37,18 @@ namespace Content.Server.AI.Utility.Actions.Clothing.Gloves
base.UpdateBlackboard(context);
context.GetState().SetValue(_entity);
}
+
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
- protected override Consideration[] Considerations { get; } = {
- new ClothingInSlotCon(EquipmentSlotDefines.Slots.GLOVES,
- new InverseBoolCurve()),
- new CanPutTargetInHandsCon(
- new BoolCurve()),
- };
+ return new[]
+ {
+ considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.GLOVES, context)
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .BoolCurve(context),
+ };
+ }
}
}
diff --git a/Content.Server/AI/Utility/Actions/Clothing/Gloves/PickUpGloves.cs b/Content.Server/AI/Utility/Actions/Clothing/Gloves/PickUpGloves.cs
index b2402d4065..703ed5362f 100644
--- a/Content.Server/AI/Utility/Actions/Clothing/Gloves/PickUpGloves.cs
+++ b/Content.Server/AI/Utility/Actions/Clothing/Gloves/PickUpGloves.cs
@@ -1,12 +1,14 @@
+using System;
+using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.Gloves
{
@@ -30,14 +32,20 @@ namespace Content.Server.AI.Utility.Actions.Clothing.Gloves
base.UpdateBlackboard(context);
context.GetState().SetValue(_entity);
}
+
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
- protected override Consideration[] Considerations { get; } = {
- new ClothingInSlotCon(EquipmentSlotDefines.Slots.GLOVES,
- new InverseBoolCurve()),
- new CanPutTargetInHandsCon(
- new BoolCurve()),
- new ClothingInInventoryCon(EquipmentSlotDefines.SlotFlags.GLOVES,
- new InverseBoolCurve()),
- };
+ return new[]
+ {
+ considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.GLOVES, context)
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get().Slot(EquipmentSlotDefines.SlotFlags.GLOVES, context)
+ .InverseBoolCurve(context)
+ };
+ }
}
}
diff --git a/Content.Server/AI/Utility/Actions/Clothing/Head/EquipHead.cs b/Content.Server/AI/Utility/Actions/Clothing/Head/EquipHead.cs
index 95bd1a772f..1935416dc7 100644
--- a/Content.Server/AI/Utility/Actions/Clothing/Head/EquipHead.cs
+++ b/Content.Server/AI/Utility/Actions/Clothing/Head/EquipHead.cs
@@ -1,14 +1,15 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.Head
{
@@ -37,11 +38,18 @@ namespace Content.Server.AI.Utility.Actions.Clothing.Head
context.GetState().SetValue(_entity);
}
- protected override Consideration[] Considerations { get; } = {
- new ClothingInSlotCon(EquipmentSlotDefines.Slots.HEAD,
- new InverseBoolCurve()),
- new CanPutTargetInHandsCon(
- new BoolCurve()),
- };
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.HEAD, context)
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .BoolCurve(context),
+ };
+
+ }
}
}
diff --git a/Content.Server/AI/Utility/Actions/Clothing/Head/PickUpHead.cs b/Content.Server/AI/Utility/Actions/Clothing/Head/PickUpHead.cs
index 98a999cc8d..0c06d707d5 100644
--- a/Content.Server/AI/Utility/Actions/Clothing/Head/PickUpHead.cs
+++ b/Content.Server/AI/Utility/Actions/Clothing/Head/PickUpHead.cs
@@ -1,12 +1,14 @@
+using System;
+using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.Head
{
@@ -31,13 +33,19 @@ namespace Content.Server.AI.Utility.Actions.Clothing.Head
context.GetState().SetValue(_entity);
}
- protected override Consideration[] Considerations { get; } = {
- new ClothingInSlotCon(EquipmentSlotDefines.Slots.HEAD,
- new InverseBoolCurve()),
- new CanPutTargetInHandsCon(
- new BoolCurve()),
- new ClothingInInventoryCon(EquipmentSlotDefines.SlotFlags.HEAD,
- new InverseBoolCurve()),
- };
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.HEAD, context)
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get().Slot(EquipmentSlotDefines.SlotFlags.HEAD, context)
+ .InverseBoolCurve(context)
+ };
+ }
}
}
diff --git a/Content.Server/AI/Utility/Actions/Clothing/OuterClothing/EquipOuterClothing.cs b/Content.Server/AI/Utility/Actions/Clothing/OuterClothing/EquipOuterClothing.cs
index 6d1eae4445..e593098cf5 100644
--- a/Content.Server/AI/Utility/Actions/Clothing/OuterClothing/EquipOuterClothing.cs
+++ b/Content.Server/AI/Utility/Actions/Clothing/OuterClothing/EquipOuterClothing.cs
@@ -1,14 +1,15 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.OuterClothing
{
@@ -37,11 +38,17 @@ namespace Content.Server.AI.Utility.Actions.Clothing.OuterClothing
context.GetState().SetValue(_entity);
}
- protected override Consideration[] Considerations { get; } = {
- new ClothingInSlotCon(EquipmentSlotDefines.Slots.OUTERCLOTHING,
- new InverseBoolCurve()),
- new CanPutTargetInHandsCon(
- new BoolCurve()),
- };
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.OUTERCLOTHING, context)
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .BoolCurve(context),
+ };
+ }
}
}
diff --git a/Content.Server/AI/Utility/Actions/Clothing/OuterClothing/PickUpOuterClothing.cs b/Content.Server/AI/Utility/Actions/Clothing/OuterClothing/PickUpOuterClothing.cs
index 359c4ccdd4..a192fda3e7 100644
--- a/Content.Server/AI/Utility/Actions/Clothing/OuterClothing/PickUpOuterClothing.cs
+++ b/Content.Server/AI/Utility/Actions/Clothing/OuterClothing/PickUpOuterClothing.cs
@@ -1,12 +1,14 @@
+using System;
+using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.OuterClothing
{
@@ -31,13 +33,19 @@ namespace Content.Server.AI.Utility.Actions.Clothing.OuterClothing
context.GetState().SetValue(_entity);
}
- protected override Consideration[] Considerations { get; } = {
- new ClothingInSlotCon(EquipmentSlotDefines.Slots.OUTERCLOTHING,
- new InverseBoolCurve()),
- new CanPutTargetInHandsCon(
- new BoolCurve()),
- new ClothingInInventoryCon(EquipmentSlotDefines.SlotFlags.OUTERCLOTHING,
- new InverseBoolCurve()),
- };
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.OUTERCLOTHING, context)
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get().Slot(EquipmentSlotDefines.SlotFlags.OUTERCLOTHING, context)
+ .InverseBoolCurve(context)
+ };
+ }
}
}
diff --git a/Content.Server/AI/Utility/Actions/Clothing/Shoes/EquipShoes.cs b/Content.Server/AI/Utility/Actions/Clothing/Shoes/EquipShoes.cs
index 78dd53ab73..fdbc2c78e7 100644
--- a/Content.Server/AI/Utility/Actions/Clothing/Shoes/EquipShoes.cs
+++ b/Content.Server/AI/Utility/Actions/Clothing/Shoes/EquipShoes.cs
@@ -1,14 +1,15 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.Shoes
{
@@ -37,11 +38,17 @@ namespace Content.Server.AI.Utility.Actions.Clothing.Shoes
context.GetState().SetValue(_entity);
}
- protected override Consideration[] Considerations { get; } = {
- new ClothingInSlotCon(EquipmentSlotDefines.Slots.SHOES,
- new InverseBoolCurve()),
- new CanPutTargetInHandsCon(
- new BoolCurve()),
- };
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.SHOES, context)
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .BoolCurve(context),
+ };
+ }
}
}
diff --git a/Content.Server/AI/Utility/Actions/Clothing/Shoes/PickUpShoes.cs b/Content.Server/AI/Utility/Actions/Clothing/Shoes/PickUpShoes.cs
index f755873688..60e4d00196 100644
--- a/Content.Server/AI/Utility/Actions/Clothing/Shoes/PickUpShoes.cs
+++ b/Content.Server/AI/Utility/Actions/Clothing/Shoes/PickUpShoes.cs
@@ -1,12 +1,14 @@
+using System;
+using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.Shoes
{
@@ -31,13 +33,19 @@ namespace Content.Server.AI.Utility.Actions.Clothing.Shoes
context.GetState().SetValue(_entity);
}
- protected override Consideration[] Considerations { get; } = {
- new ClothingInSlotCon(EquipmentSlotDefines.Slots.SHOES,
- new InverseBoolCurve()),
- new CanPutTargetInHandsCon(
- new BoolCurve()),
- new ClothingInInventoryCon(EquipmentSlotDefines.SlotFlags.SHOES,
- new InverseBoolCurve()),
- };
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get().Slot(EquipmentSlotDefines.Slots.SHOES, context)
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get().Slot(EquipmentSlotDefines.SlotFlags.SHOES, context)
+ .InverseBoolCurve(context)
+ };
+ }
}
}
diff --git a/Content.Server/AI/Utility/Actions/Combat/Melee/EquipMelee.cs b/Content.Server/AI/Utility/Actions/Combat/Melee/EquipMelee.cs
index 81c799701c..29bdea8394 100644
--- a/Content.Server/AI/Utility/Actions/Combat/Melee/EquipMelee.cs
+++ b/Content.Server/AI/Utility/Actions/Combat/Melee/EquipMelee.cs
@@ -1,14 +1,15 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Combat.Melee;
using Content.Server.AI.Utility.Considerations.Inventory;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Combat;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Combat.Melee
{
@@ -37,15 +38,21 @@ namespace Content.Server.AI.Utility.Actions.Combat.Melee
context.GetState().SetValue(_entity);
}
- protected override Consideration[] Considerations { get; } = {
- new MeleeWeaponEquippedCon(
- new InverseBoolCurve()),
- new CanPutTargetInHandsCon(
- new BoolCurve()),
- new MeleeWeaponSpeedCon(
- new QuadraticCurve(1.0f, 0.5f, 0.0f, 0.0f)),
- new MeleeWeaponDamageCon(
- new QuadraticCurve(1.0f, 0.25f, 0.0f, 0.0f)),
- };
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get()
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 0.5f, 0.0f, 0.0f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 0.25f, 0.0f, 0.0f),
+ };
+ }
}
}
diff --git a/Content.Server/AI/Utility/Actions/Combat/Melee/MeleeWeaponAttackEntity.cs b/Content.Server/AI/Utility/Actions/Combat/Melee/MeleeWeaponAttackEntity.cs
index 2da20091a1..de65a16279 100644
--- a/Content.Server/AI/Utility/Actions/Combat/Melee/MeleeWeaponAttackEntity.cs
+++ b/Content.Server/AI/Utility/Actions/Combat/Melee/MeleeWeaponAttackEntity.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Combat;
@@ -7,7 +8,6 @@ using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Combat;
using Content.Server.AI.Utility.Considerations.Combat.Melee;
using Content.Server.AI.Utility.Considerations.Movement;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Combat;
@@ -15,6 +15,7 @@ using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.AI.WorldState.States.Movement;
using Content.Server.GameObjects.Components.Weapon.Melee;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Combat.Melee
{
@@ -30,16 +31,15 @@ namespace Content.Server.AI.Utility.Actions.Combat.Melee
public override void SetupOperators(Blackboard context)
{
- var equipped = context.GetState().GetValue();
MoveToEntityOperator moveOperator;
+ var equipped = context.GetState().GetValue();
if (equipped != null && equipped.TryGetComponent(out MeleeWeaponComponent meleeWeaponComponent))
{
moveOperator = new MoveToEntityOperator(Owner, _entity, meleeWeaponComponent.Range - 0.01f);
}
- // I think it's possible for this to happen given planning is time-sliced?
- // TODO: At this point we should abort
else
{
+ // TODO: Abort
moveOperator = new MoveToEntityOperator(Owner, _entity);
}
@@ -58,27 +58,28 @@ namespace Content.Server.AI.Utility.Actions.Combat.Melee
var equipped = context.GetState().GetValue();
context.GetState().SetValue(equipped);
}
+
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
- protected override Consideration[] Considerations { get; } = {
- // Check if we have a weapon; easy-out
- new MeleeWeaponEquippedCon(
- new BoolCurve()),
- // Don't attack a dead target
- new TargetIsDeadCon(
- new InverseBoolCurve()),
- // Deprioritise a target in crit
- new TargetIsCritCon(
- new QuadraticCurve(-0.8f, 1.0f, 1.0f, 0.0f)),
- // Somewhat prioritise distance
- new DistanceCon(
- new QuadraticCurve(-1.0f, 1.0f, 1.02f, 0.0f)),
- // Prefer weaker targets
- new TargetHealthCon(
- new QuadraticCurve(1.0f, 0.4f, 0.0f, -0.02f)),
- new MeleeWeaponSpeedCon(
- new QuadraticCurve(1.0f, 0.5f, 0.0f, 0.0f)),
- new MeleeWeaponDamageCon(
- new QuadraticCurve(1.0f, 0.25f, 0.0f, 0.0f)),
- };
+ return new[]
+ {
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get()
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .QuadraticCurve(context, -0.8f, 1.0f, 1.0f, 0.0f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 1.0f, 0.02f, 0.0f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 0.4f, 0.0f, -0.02f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 0.5f, 0.0f, 0.0f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 0.25f, 0.0f, 0.0f),
+ };
+ }
}
}
diff --git a/Content.Server/AI/Utility/Actions/Combat/Melee/PickUpMeleeWeapon.cs b/Content.Server/AI/Utility/Actions/Combat/Melee/PickUpMeleeWeapon.cs
index 216152e4d8..1d1ec0ec96 100644
--- a/Content.Server/AI/Utility/Actions/Combat/Melee/PickUpMeleeWeapon.cs
+++ b/Content.Server/AI/Utility/Actions/Combat/Melee/PickUpMeleeWeapon.cs
@@ -1,14 +1,16 @@
+using System;
+using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Combat.Melee;
using Content.Server.AI.Utility.Considerations.Containers;
using Content.Server.AI.Utility.Considerations.Hands;
using Content.Server.AI.Utility.Considerations.Movement;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Combat;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Combat.Melee
{
@@ -33,20 +35,26 @@ namespace Content.Server.AI.Utility.Actions.Combat.Melee
context.GetState().SetValue(_entity);
context.GetState().SetValue(_entity);
}
+
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
- protected override Consideration[] Considerations { get; } = {
- new TargetAccessibleCon(
- new BoolCurve()),
- new FreeHandCon(
- new BoolCurve()),
- new HasMeleeWeaponCon(
- new InverseBoolCurve()),
- new DistanceCon(
- new QuadraticCurve(-1.0f, 1.0f, 1.02f, 0.0f)),
- new MeleeWeaponDamageCon(
- new QuadraticCurve(1.0f, 0.25f, 0.0f, 0.0f)),
- new MeleeWeaponSpeedCon(
- new QuadraticCurve(-1.0f, 0.5f, 1.0f, 0.0f)),
- };
+ return new[]
+ {
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get()
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 1.0f, 0.02f, 0.0f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 0.25f, 0.0f, 0.0f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, -1.0f, 0.5f, 1.0f, 0.0f),
+ };
+ }
}
}
diff --git a/Content.Server/AI/Utility/Actions/Combat/Melee/UnarmedAttackEntity.cs b/Content.Server/AI/Utility/Actions/Combat/Melee/UnarmedAttackEntity.cs
index 6883b294bf..7355e216db 100644
--- a/Content.Server/AI/Utility/Actions/Combat/Melee/UnarmedAttackEntity.cs
+++ b/Content.Server/AI/Utility/Actions/Combat/Melee/UnarmedAttackEntity.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Combat.Melee;
@@ -6,13 +7,13 @@ using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Combat;
using Content.Server.AI.Utility.Considerations.Combat.Melee;
using Content.Server.AI.Utility.Considerations.Movement;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Combat;
using Content.Server.AI.WorldState.States.Movement;
using Content.Server.GameObjects.Components.Weapon.Melee;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Combat.Melee
{
@@ -56,23 +57,25 @@ namespace Content.Server.AI.Utility.Actions.Combat.Melee
context.GetState().SetValue(Owner);
}
- protected override Consideration[] Considerations { get; } = {
- new CanUnarmedCombatCon(
- new BoolCurve()),
- // Don't attack a dead target
- new TargetIsDeadCon(
- new InverseBoolCurve()),
- // Deprioritise a target in crit
- new TargetIsCritCon(
- new QuadraticCurve(-0.8f, 1.0f, 1.0f, 0.0f)),
- // Somewhat prioritise distance
- new DistanceCon(
- new QuadraticCurve(-1.0f, 1.0f, 1.02f, 0.0f)),
- // Prefer weaker targets
- new TargetHealthCon(
- new QuadraticCurve(1.0f, 0.4f, 0.0f, -0.02f)),
- // TODO: Consider our Speed and Damage to compare this to using a weapon
- // Also need to unequip our weapon if we have one (xenos can't hold one so no issue for now)
- };
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get()
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .QuadraticCurve(context, -0.8f, 1.0f, 1.0f, 0.0f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, -1.0f, 1.0f, 1.02f, 0.0f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 0.4f, 0.0f, -0.02f),
+ // TODO: Consider our Speed and Damage to compare this to using a weapon
+ // Also need to unequip our weapon if we have one (xenos can't hold one so no issue for now)
+ };
+ }
}
}
\ No newline at end of file
diff --git a/Content.Server/AI/Utility/Actions/Idle/CloseLastEntityStorage.cs b/Content.Server/AI/Utility/Actions/Idle/CloseLastEntityStorage.cs
index 29b7e7b918..cd311a3270 100644
--- a/Content.Server/AI/Utility/Actions/Idle/CloseLastEntityStorage.cs
+++ b/Content.Server/AI/Utility/Actions/Idle/CloseLastEntityStorage.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory;
@@ -5,10 +6,10 @@ using Content.Server.AI.Operators.Movement;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Movement;
using Content.Server.AI.Utility.Considerations.State;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Inventory;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Idle
{
@@ -21,13 +22,6 @@ namespace Content.Server.AI.Utility.Actions.Idle
public CloseLastEntityStorage(IEntity owner) : base(owner) {}
- protected override Consideration[] Considerations => new Consideration[]
- {
- new StoredStateIsNullCon(
- new InverseBoolCurve()),
- new DistanceCon(
- new QuadraticCurve(-1.0f, 1.0f, 1.02f, 0.0f)),
- };
public override void SetupOperators(Blackboard context)
{
var lastStorage = context.GetState().GetValue();
@@ -37,6 +31,21 @@ namespace Content.Server.AI.Utility.Actions.Idle
new MoveToEntityOperator(Owner, lastStorage),
new CloseLastStorageOperator(Owner),
});
+ }
+
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get().Set(typeof(LastOpenedStorageState), context)
+ .InverseBoolCurve(context),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 1.0f, 0.02f, 0.0f),
+
+ };
}
+
}
}
\ No newline at end of file
diff --git a/Content.Server/AI/Utility/Actions/Idle/WanderAndWait.cs b/Content.Server/AI/Utility/Actions/Idle/WanderAndWait.cs
index 52f03c4046..3abb90dd3f 100644
--- a/Content.Server/AI/Utility/Actions/Idle/WanderAndWait.cs
+++ b/Content.Server/AI/Utility/Actions/Idle/WanderAndWait.cs
@@ -1,10 +1,11 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Generic;
using Content.Server.AI.Operators.Movement;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.ActionBlocker;
-using Content.Server.AI.Utility.Curves;
+using Content.Server.AI.Utility.Considerations.Containers;
using Content.Server.AI.WorldState;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
@@ -22,12 +23,9 @@ namespace Content.Server.AI.Utility.Actions.Idle
public sealed class WanderAndWait : UtilityAction
{
public override bool CanOverride => false;
- public override float Bonus => IdleBonus;
+ public override float Bonus => 1.0f;
- public WanderAndWait(IEntity owner) : base(owner)
- {
- // TODO: Need a Success method that gets called to update context (e.g. when we last did X)
- }
+ public WanderAndWait(IEntity owner) : base(owner) {}
public override void SetupOperators(Blackboard context)
{
@@ -49,12 +47,18 @@ namespace Content.Server.AI.Utility.Actions.Idle
new WaitOperator(waitTime),
});
}
+
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
- protected override Consideration[] Considerations { get; } = {
- new CanMoveCon(
- new BoolCurve())
- // Last wander? If we also want to sit still
- };
+ return new[]
+ {
+ considerationsManager.Get()
+ .BoolCurve(context),
+
+ };
+ }
private GridCoordinates FindRandomGrid()
{
diff --git a/Content.Server/AI/Utility/Actions/Nutrition/Drink/PickUpDrink.cs b/Content.Server/AI/Utility/Actions/Nutrition/Drink/PickUpDrink.cs
index c376641bb9..cc8f98810a 100644
--- a/Content.Server/AI/Utility/Actions/Nutrition/Drink/PickUpDrink.cs
+++ b/Content.Server/AI/Utility/Actions/Nutrition/Drink/PickUpDrink.cs
@@ -1,13 +1,15 @@
+using System;
+using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Containers;
using Content.Server.AI.Utility.Considerations.Hands;
using Content.Server.AI.Utility.Considerations.Movement;
using Content.Server.AI.Utility.Considerations.Nutrition.Drink;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Nutrition.Drink
{
@@ -25,25 +27,31 @@ namespace Content.Server.AI.Utility.Actions.Nutrition.Drink
{
ActionOperators = new GoPickupEntitySequence(Owner, _entity).Sequence;
}
-
- protected override Consideration[] Considerations => new Consideration[]
- {
- new TargetAccessibleCon(
- new BoolCurve()),
- new FreeHandCon(
- new BoolCurve()),
- new ThirstCon(
- new LogisticCurve(1000f, 1.3f, -1.0f, 0.5f)),
- new DistanceCon(
- new QuadraticCurve(-1.0f, 1.0f, 1.02f, 0.0f)),
- new DrinkValueCon(
- new QuadraticCurve(1.0f, 0.4f, 0.0f, 0.0f)),
- };
-
+
protected override void UpdateBlackboard(Blackboard context)
{
base.UpdateBlackboard(context);
context.GetState().SetValue(_entity);
}
+
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get()
+ .LogisticCurve(context, 1000f, 1.3f, -1.0f, 0.5f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 1.0f, 0.02f, 0.0f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 0.4f, 0.0f, 0.0f),
+ };
+ }
+
}
}
diff --git a/Content.Server/AI/Utility/Actions/Nutrition/Drink/UseDrinkInInventory.cs b/Content.Server/AI/Utility/Actions/Nutrition/Drink/UseDrinkInInventory.cs
index eae360a69e..408addf0d1 100644
--- a/Content.Server/AI/Utility/Actions/Nutrition/Drink/UseDrinkInInventory.cs
+++ b/Content.Server/AI/Utility/Actions/Nutrition/Drink/UseDrinkInInventory.cs
@@ -1,13 +1,14 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Hands;
using Content.Server.AI.Utility.Considerations.Nutrition.Drink;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Nutrition.Drink
{
@@ -29,21 +30,26 @@ namespace Content.Server.AI.Utility.Actions.Nutrition.Drink
new UseItemInHandsOperator(Owner, _entity),
});
}
-
- protected override Consideration[] Considerations => new Consideration[]
- {
- new TargetInOurHandsCon(
- new BoolCurve()),
- new ThirstCon(
- new LogisticCurve(1000f, 1.3f, -0.3f, 0.5f)),
- new DrinkValueCon(
- new QuadraticCurve(1.0f, 0.4f, 0.0f, 0.0f))
- };
-
+
protected override void UpdateBlackboard(Blackboard context)
{
base.UpdateBlackboard(context);
context.GetState().SetValue(_entity);
+ }
+
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get()
+ .LogisticCurve(context, 1000f, 1.3f, -0.3f, 0.5f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 0.4f, 0.0f, 0.0f),
+ };
}
}
}
diff --git a/Content.Server/AI/Utility/Actions/Nutrition/Food/PickUpFood.cs b/Content.Server/AI/Utility/Actions/Nutrition/Food/PickUpFood.cs
index cd12fab1c7..4b6c54a927 100644
--- a/Content.Server/AI/Utility/Actions/Nutrition/Food/PickUpFood.cs
+++ b/Content.Server/AI/Utility/Actions/Nutrition/Food/PickUpFood.cs
@@ -1,13 +1,15 @@
+using System;
+using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Containers;
using Content.Server.AI.Utility.Considerations.Hands;
using Content.Server.AI.Utility.Considerations.Movement;
-using Content.Server.AI.Utility.Considerations.Nutrition;
-using Content.Server.AI.Utility.Curves;
+using Content.Server.AI.Utility.Considerations.Nutrition.Food;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Nutrition.Food
{
@@ -26,24 +28,29 @@ namespace Content.Server.AI.Utility.Actions.Nutrition.Food
ActionOperators = new GoPickupEntitySequence(Owner, _entity).Sequence;
}
- protected override Consideration[] Considerations => new Consideration[]
- {
- new TargetAccessibleCon(
- new BoolCurve()),
- new FreeHandCon(
- new BoolCurve()),
- new HungerCon(
- new LogisticCurve(1000f, 1.3f, -1.0f, 0.5f)),
- new DistanceCon(
- new QuadraticCurve(-1.0f, 1.0f, 1.02f, 0.0f)),
- new FoodValueCon(
- new QuadraticCurve(1.0f, 0.4f, 0.0f, 0.0f)),
- };
-
protected override void UpdateBlackboard(Blackboard context)
{
base.UpdateBlackboard(context);
context.GetState().SetValue(_entity);
+ }
+
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get()
+ .LogisticCurve(context, 1000f, 1.3f, -1.0f, 0.5f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 1.0f, 0.02f, 0.0f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 0.4f, 0.0f, 0.0f),
+ };
}
}
}
diff --git a/Content.Server/AI/Utility/Actions/Nutrition/Food/UseFoodInInventory.cs b/Content.Server/AI/Utility/Actions/Nutrition/Food/UseFoodInInventory.cs
index 2996cf3769..162d69c29b 100644
--- a/Content.Server/AI/Utility/Actions/Nutrition/Food/UseFoodInInventory.cs
+++ b/Content.Server/AI/Utility/Actions/Nutrition/Food/UseFoodInInventory.cs
@@ -1,13 +1,15 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations;
+using Content.Server.AI.Utility.Considerations.Containers;
using Content.Server.AI.Utility.Considerations.Hands;
-using Content.Server.AI.Utility.Considerations.Nutrition;
-using Content.Server.AI.Utility.Curves;
+using Content.Server.AI.Utility.Considerations.Nutrition.Food;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Nutrition.Food
{
@@ -30,20 +32,26 @@ namespace Content.Server.AI.Utility.Actions.Nutrition.Food
});
}
- protected override Consideration[] Considerations => new Consideration[]
- {
- new TargetInOurHandsCon(
- new BoolCurve()),
- new HungerCon(
- new LogisticCurve(1000f, 1.3f, -0.3f, 0.5f)),
- new FoodValueCon(
- new QuadraticCurve(1.0f, 0.4f, 0.0f, 0.0f))
- };
-
protected override void UpdateBlackboard(Blackboard context)
{
base.UpdateBlackboard(context);
context.GetState().SetValue(_entity);
+ }
+
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get()
+ .BoolCurve(context),
+ considerationsManager.Get()
+ .LogisticCurve(context, 1000f, 1.3f, -0.3f, 0.5f),
+ considerationsManager.Get()
+ .QuadraticCurve(context, 1.0f, 0.4f, 0.0f, 0.0f),
+
+ };
}
}
}
diff --git a/Content.Server/AI/Utility/Actions/Test/MoveRightAndLeftTen.cs b/Content.Server/AI/Utility/Actions/Test/MoveRightAndLeftTen.cs
index a2f49c1c79..d2625eddb8 100644
--- a/Content.Server/AI/Utility/Actions/Test/MoveRightAndLeftTen.cs
+++ b/Content.Server/AI/Utility/Actions/Test/MoveRightAndLeftTen.cs
@@ -1,10 +1,11 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Movement;
using Content.Server.AI.Utility.Considerations;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.IoC;
using Robust.Shared.Maths;
namespace Content.Server.AI.Utility.Actions.Test
@@ -18,11 +19,6 @@ namespace Content.Server.AI.Utility.Actions.Test
public MoveRightAndLeftTen(IEntity owner) : base(owner) {}
- protected override Consideration[] Considerations { get; } = {
- new DummyCon(
- new BoolCurve())
- };
-
public override void SetupOperators(Blackboard context)
{
var currentPosition = Owner.Transform.GridPosition;
@@ -36,5 +32,16 @@ namespace Content.Server.AI.Utility.Actions.Test
originalPosOp
});
}
+
+ protected override IReadOnlyCollection> GetConsiderations(Blackboard context)
+ {
+ var considerationsManager = IoCManager.Resolve();
+
+ return new[]
+ {
+ considerationsManager.Get()
+ .BoolCurve(context),
+ };
+ }
}
}
diff --git a/Content.Server/AI/Utility/Actions/UtilityAction.cs b/Content.Server/AI/Utility/Actions/UtilityAction.cs
index 1d5a385beb..2453750532 100644
--- a/Content.Server/AI/Utility/Actions/UtilityAction.cs
+++ b/Content.Server/AI/Utility/Actions/UtilityAction.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using Content.Server.AI.Operators;
using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.WorldState;
+using Content.Server.AI.WorldState.States.Utility;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Utility;
@@ -42,7 +43,9 @@ namespace Content.Server.AI.Utility.Actions
/// All the considerations are multiplied together to get the final score; a consideration of 0.0 means the action is not possible.
/// Ideally you put anything that's easy to assess and can cause an early-out first just so the rest aren't evaluated.
///
- protected abstract Consideration[] Considerations { get; }
+ /// Uses Func as you don't want to eval the later considerations unless necessary, but we also need the total count
+ /// so can't use IEnumerable
+ protected abstract IReadOnlyCollection> GetConsiderations(Blackboard context);
///
/// To keep the operators simple we can chain them together here, e.g. move to can be chained with other operators.
@@ -109,7 +112,8 @@ namespace Content.Server.AI.Utility.Actions
public float GetScore(Blackboard context, float min)
{
UpdateBlackboard(context);
- DebugTools.Assert(Considerations.Length > 0);
+ var considerations = GetConsiderations(context);
+ DebugTools.Assert(considerations.Count > 0);
// I used the IAUS video although I did have some confusion on how to structure it overall
// as some of the slides seemed contradictory
@@ -121,19 +125,14 @@ namespace Content.Server.AI.Utility.Actions
// 23:00 Building a better centaur
var finalScore = 1.0f;
var minThreshold = min / Bonus;
- var modificationFactor = 1.0f - 1.0f / Considerations.Length;
+ context.GetState().SetValue(considerations.Count);
// See 10:09 for this and the adjustments
- foreach (var consideration in Considerations)
+ foreach (var consideration in considerations)
{
- var score = consideration.GetScore(context);
- var makeUpValue = (1.0f - score) * modificationFactor;
- var adjustedScore = score + makeUpValue * score;
- var response = consideration.ComputeResponseCurve(adjustedScore);
-
- finalScore *= response;
-
- DebugTools.Assert(!float.IsNaN(response));
+ var score = consideration.Invoke();
+ finalScore *= score;
+ DebugTools.Assert(!float.IsNaN(score));
// The score can only ever go down from each consideration so if we're below minimum no point continuing.
if (0.0f >= finalScore || finalScore < minThreshold) {
diff --git a/Content.Server/AI/Utility/AiLogic/UtilityAI.cs b/Content.Server/AI/Utility/AiLogic/UtilityAI.cs
index e886d0ff61..5847deb850 100644
--- a/Content.Server/AI/Utility/AiLogic/UtilityAI.cs
+++ b/Content.Server/AI/Utility/AiLogic/UtilityAI.cs
@@ -13,6 +13,7 @@ using Content.Server.GameObjects.EntitySystems.JobQueues;
using Robust.Server.AI;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
+using Robust.Shared.Log;
using Robust.Shared.Utility;
namespace Content.Server.AI.Utility.AiLogic
@@ -147,6 +148,14 @@ namespace Content.Server.AI.Utility.AiLogic
private void ReceivedAction()
{
+ switch (_actionRequest.Exception)
+ {
+ case null:
+ break;
+ default:
+ Logger.FatalS("ai", _actionRequest.Exception.ToString());
+ throw _actionRequest.Exception;
+ }
var action = _actionRequest.Result;
_actionRequest = null;
// Actions with lower scores should be implicitly dumped by GetAction
diff --git a/Content.Server/AI/Utility/Considerations/ActionBlocker/CanMoveCon.cs b/Content.Server/AI/Utility/Considerations/ActionBlocker/CanMoveCon.cs
index 0a1828d495..0be12ebd50 100644
--- a/Content.Server/AI/Utility/Considerations/ActionBlocker/CanMoveCon.cs
+++ b/Content.Server/AI/Utility/Considerations/ActionBlocker/CanMoveCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects.EntitySystems;
@@ -9,9 +8,7 @@ namespace Content.Server.AI.Utility.Considerations.ActionBlocker
{
public sealed class CanMoveCon : Consideration
{
- public CanMoveCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var self = context.GetState().GetValue();
if (!ActionBlockerSystem.CanMove(self))
diff --git a/Content.Server/AI/Utility/Considerations/Clothing/ClothingInInventoryCon.cs b/Content.Server/AI/Utility/Considerations/Clothing/ClothingInInventoryCon.cs
index 7101e1ba1b..5a0dce18f6 100644
--- a/Content.Server/AI/Utility/Considerations/Clothing/ClothingInInventoryCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Clothing/ClothingInInventoryCon.cs
@@ -1,5 +1,5 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
+using Content.Server.AI.WorldState.States.Clothing;
using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects;
using Content.Shared.GameObjects.Components.Inventory;
@@ -8,25 +8,27 @@ namespace Content.Server.AI.Utility.Considerations.Clothing
{
public sealed class ClothingInInventoryCon : Consideration
{
- private readonly EquipmentSlotDefines.SlotFlags _slot;
-
- public ClothingInInventoryCon(EquipmentSlotDefines.SlotFlags slotFlags, IResponseCurve curve) : base(curve)
+ public ClothingInInventoryCon Slot(EquipmentSlotDefines.SlotFlags slotFlags, Blackboard context)
{
- _slot = slotFlags;
+ // 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.
+ context.GetState().SetValue(slotFlags);
+ return this;
}
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
- var inventory = context.GetState().GetValue();
+ var slots = context.GetState().GetValue();
+ var slotFlags = EquipmentSlotDefines.SlotMasks[slots];
- foreach (var entity in inventory)
+ foreach (var entity in context.GetState().GetValue())
{
if (!entity.TryGetComponent(out ClothingComponent clothingComponent))
{
continue;
}
- if ((clothingComponent.SlotFlags & _slot) != 0)
+ if ((clothingComponent.SlotFlags & slotFlags) != 0)
{
return 1.0f;
}
diff --git a/Content.Server/AI/Utility/Considerations/Clothing/ClothingInSlotCon.cs b/Content.Server/AI/Utility/Considerations/Clothing/ClothingInSlotCon.cs
index 11b30c0027..dfc0b548a7 100644
--- a/Content.Server/AI/Utility/Considerations/Clothing/ClothingInSlotCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Clothing/ClothingInSlotCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Clothing;
using Content.Shared.GameObjects.Components.Inventory;
@@ -7,18 +6,18 @@ namespace Content.Server.AI.Utility.Considerations.Clothing
{
public class ClothingInSlotCon : Consideration
{
- private EquipmentSlotDefines.Slots _slot;
- public ClothingInSlotCon(EquipmentSlotDefines.Slots slot, IResponseCurve curve) : base(curve)
+ public ClothingInSlotCon Slot(EquipmentSlotDefines.Slots slot, Blackboard context)
{
- _slot = slot;
+ context.GetState().SetValue(slot);
+ return this;
}
-
- public override float GetScore(Blackboard context)
+
+ protected override float GetScore(Blackboard context)
{
+ var slot = context.GetState().GetValue();
var inventory = context.GetState().GetValue();
-
- return inventory.ContainsKey(_slot) ? 1.0f : 0.0f;
+ return inventory.ContainsKey(slot) ? 1.0f : 0.0f;
}
}
}
diff --git a/Content.Server/AI/Utility/Considerations/Combat/Melee/CanUnarmedCombatCon.cs b/Content.Server/AI/Utility/Considerations/Combat/Melee/CanUnarmedCombatCon.cs
index f77e6ce5c4..ad9c4d4ea6 100644
--- a/Content.Server/AI/Utility/Considerations/Combat/Melee/CanUnarmedCombatCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Combat/Melee/CanUnarmedCombatCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects.Components.Weapon.Melee;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Combat.Melee
{
public sealed class CanUnarmedCombatCon : Consideration
{
- public CanUnarmedCombatCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
return context.GetState().GetValue().HasComponent() ? 1.0f : 0.0f;
}
diff --git a/Content.Server/AI/Utility/Considerations/Combat/Melee/HasMeleeWeaponCon.cs b/Content.Server/AI/Utility/Considerations/Combat/Melee/HasMeleeWeaponCon.cs
index 5d9567589f..e8f9e74224 100644
--- a/Content.Server/AI/Utility/Considerations/Combat/Melee/HasMeleeWeaponCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Combat/Melee/HasMeleeWeaponCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects.Components.Weapon.Melee;
@@ -7,11 +6,9 @@ namespace Content.Server.AI.Utility.Considerations.Combat.Melee
{
public sealed class HasMeleeWeaponCon : Consideration
{
- public HasMeleeWeaponCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
- foreach (var item in context.GetState().GetValue())
+ foreach (var item in context.GetState().GetValue())
{
if (item.HasComponent())
{
diff --git a/Content.Server/AI/Utility/Considerations/Combat/Melee/MeleeWeaponDamageCon.cs b/Content.Server/AI/Utility/Considerations/Combat/Melee/MeleeWeaponDamageCon.cs
index 31165ec6c0..9f62896520 100644
--- a/Content.Server/AI/Utility/Considerations/Combat/Melee/MeleeWeaponDamageCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Combat/Melee/MeleeWeaponDamageCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Combat;
using Content.Server.GameObjects.Components.Weapon.Melee;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Combat.Melee
{
public sealed class MeleeWeaponDamageCon : Consideration
{
- public MeleeWeaponDamageCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var target = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/Combat/Melee/MeleeWeaponEquippedCon.cs b/Content.Server/AI/Utility/Considerations/Combat/Melee/MeleeWeaponEquippedCon.cs
index 3bca99db7a..856c8b9932 100644
--- a/Content.Server/AI/Utility/Considerations/Combat/Melee/MeleeWeaponEquippedCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Combat/Melee/MeleeWeaponEquippedCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects.Components.Weapon.Melee;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Combat.Melee
{
public sealed class MeleeWeaponEquippedCon : Consideration
{
- public MeleeWeaponEquippedCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var equipped = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/Combat/Melee/MeleeWeaponSpeedCon.cs b/Content.Server/AI/Utility/Considerations/Combat/Melee/MeleeWeaponSpeedCon.cs
index 1c16870804..fc56a593f7 100644
--- a/Content.Server/AI/Utility/Considerations/Combat/Melee/MeleeWeaponSpeedCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Combat/Melee/MeleeWeaponSpeedCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Combat;
using Content.Server.GameObjects.Components.Weapon.Melee;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Combat.Melee
{
public sealed class MeleeWeaponSpeedCon : Consideration
{
- public MeleeWeaponSpeedCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var target = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/Combat/TargetHealthCon.cs b/Content.Server/AI/Utility/Considerations/Combat/TargetHealthCon.cs
index 5f02a42ac2..96db4f5f35 100644
--- a/Content.Server/AI/Utility/Considerations/Combat/TargetHealthCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Combat/TargetHealthCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects;
@@ -8,9 +7,7 @@ namespace Content.Server.AI.Utility.Considerations.Combat
{
public sealed class TargetHealthCon : Consideration
{
- public TargetHealthCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var target = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/Combat/TargetIsCritCon.cs b/Content.Server/AI/Utility/Considerations/Combat/TargetIsCritCon.cs
index 7528323e9f..0fd1990748 100644
--- a/Content.Server/AI/Utility/Considerations/Combat/TargetIsCritCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Combat/TargetIsCritCon.cs
@@ -1,16 +1,12 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects;
-using Content.Shared.GameObjects;
namespace Content.Server.AI.Utility.Considerations.Combat
{
public sealed class TargetIsCritCon : Consideration
{
- public TargetIsCritCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var target = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/Combat/TargetIsDeadCon.cs b/Content.Server/AI/Utility/Considerations/Combat/TargetIsDeadCon.cs
index c3c7ebc80c..8cdf0b520b 100644
--- a/Content.Server/AI/Utility/Considerations/Combat/TargetIsDeadCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Combat/TargetIsDeadCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Combat
{
public sealed class TargetIsDeadCon : Consideration
{
- public TargetIsDeadCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var target = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/Consideration.cs b/Content.Server/AI/Utility/Considerations/Consideration.cs
index 25694ec5e7..4e49b58cb9 100644
--- a/Content.Server/AI/Utility/Considerations/Consideration.cs
+++ b/Content.Server/AI/Utility/Considerations/Consideration.cs
@@ -1,25 +1,67 @@
using System;
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
+using Content.Server.AI.WorldState.States.Utility;
namespace Content.Server.AI.Utility.Considerations
{
public abstract class Consideration
{
- protected IResponseCurve Curve { get; }
+ protected abstract float GetScore(Blackboard context);
- public Consideration(IResponseCurve curve)
+ private float GetAdjustedScore(Blackboard context)
{
- Curve = curve;
+ var score = GetScore(context);
+ var considerationsCount = context.GetState().GetValue();
+ var modificationFactor = 1.0f - 1.0f / considerationsCount;
+ var makeUpValue = (1.0f - score) * modificationFactor;
+ var adjustedScore = score + makeUpValue * score;
+ return Math.Clamp(adjustedScore, 0.0f, 1.0f);
}
- public abstract float GetScore(Blackboard context);
-
- public float ComputeResponseCurve(float score)
+ public Func BoolCurve(Blackboard context)
{
- var clampedScore = Math.Clamp(score, 0.0f, 1.0f);
- var curvedResponse = Math.Clamp(Curve.GetResponse(clampedScore), 0.0f, 1.0f);
- return curvedResponse;
+ float Result()
+ {
+ var adjustedScore = GetAdjustedScore(context);
+ // ReSharper disable once CompareOfFloatsByEqualityOperator
+ return adjustedScore == 1.0f ? 1.0f : 0.0f;
+ }
+
+ return Result;
+ }
+
+ public Func InverseBoolCurve(Blackboard context)
+ {
+ float Result()
+ {
+ var adjustedScore = GetAdjustedScore(context);
+ // ReSharper disable once CompareOfFloatsByEqualityOperator
+ return adjustedScore == 1.0f ? 0.0f : 1.0f;
+ }
+
+ return Result;
+ }
+
+ public Func LogisticCurve(Blackboard context, float slope, float exponent, float yOffset, float xOffset)
+ {
+ float Result()
+ {
+ var adjustedScore = GetAdjustedScore(context);
+ return Math.Clamp(exponent * (1 / (1 + (float) Math.Pow(Math.Log(1000) * slope, -1 * adjustedScore + xOffset))) + yOffset, 0.0f, 1.0f);
+ }
+
+ return Result;
+ }
+
+ public Func QuadraticCurve(Blackboard context, float slope, float exponent, float yOffset, float xOffset)
+ {
+ float Result()
+ {
+ var adjustedScore = GetAdjustedScore(context);
+ return Math.Clamp(slope * (float) Math.Pow(adjustedScore - xOffset, exponent) + yOffset, 0.0f, 1.0f);
+ }
+
+ return Result;
}
}
}
diff --git a/Content.Server/AI/Utility/Considerations/ConsiderationsManager.cs b/Content.Server/AI/Utility/Considerations/ConsiderationsManager.cs
new file mode 100644
index 0000000000..1ff677f402
--- /dev/null
+++ b/Content.Server/AI/Utility/Considerations/ConsiderationsManager.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using Robust.Shared.Interfaces.Reflection;
+using Robust.Shared.IoC;
+
+namespace Content.Server.AI.Utility.Considerations
+{
+ public class ConsiderationsManager
+ {
+ private Dictionary _considerations = new Dictionary();
+
+ public void Initialize()
+ {
+ var reflectionManager = IoCManager.Resolve();
+ var typeFactory = IoCManager.Resolve();
+
+ foreach (var conType in reflectionManager.GetAllChildren(typeof(Consideration)))
+ {
+ var con = (Consideration) typeFactory.CreateInstance(conType);
+ _considerations.Add(conType, con);
+ }
+ }
+
+ public T Get() where T : Consideration
+ {
+ return (T) _considerations[typeof(T)];
+ }
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/AI/Utility/Considerations/Containers/TargetAccessibleCon.cs b/Content.Server/AI/Utility/Considerations/Containers/TargetAccessibleCon.cs
index f502fddb00..5af9ac5a79 100644
--- a/Content.Server/AI/Utility/Considerations/Containers/TargetAccessibleCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Containers/TargetAccessibleCon.cs
@@ -1,7 +1,5 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
-using Content.Server.GameObjects;
using Content.Server.GameObjects.Components;
using Content.Server.GameObjects.Components.Items.Storage;
using Robust.Shared.Containers;
@@ -13,9 +11,7 @@ namespace Content.Server.AI.Utility.Considerations.Containers
///
public sealed class TargetAccessibleCon : Consideration
{
- public TargetAccessibleCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var target = context.GetState().GetValue();
if (target == null)
diff --git a/Content.Server/AI/Utility/Considerations/DummyCon.cs b/Content.Server/AI/Utility/Considerations/DummyCon.cs
index 07d0587ddb..91e9135f50 100644
--- a/Content.Server/AI/Utility/Considerations/DummyCon.cs
+++ b/Content.Server/AI/Utility/Considerations/DummyCon.cs
@@ -1,12 +1,9 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
namespace Content.Server.AI.Utility.Considerations
{
public class DummyCon : Consideration
{
- public DummyCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context) => 1.0f;
+ protected override float GetScore(Blackboard context) => 1.0f;
}
}
diff --git a/Content.Server/AI/Utility/Considerations/Hands/FreeHandCon.cs b/Content.Server/AI/Utility/Considerations/Hands/FreeHandCon.cs
index 2b2162d80f..ba968bfe25 100644
--- a/Content.Server/AI/Utility/Considerations/Hands/FreeHandCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Hands/FreeHandCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Hands
{
public class FreeHandCon : Consideration
{
- public FreeHandCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var owner = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/Hands/TargetInOurHandsCon.cs b/Content.Server/AI/Utility/Considerations/Hands/TargetInOurHandsCon.cs
index 2d849717f1..72958d9d73 100644
--- a/Content.Server/AI/Utility/Considerations/Hands/TargetInOurHandsCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Hands/TargetInOurHandsCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects;
@@ -11,9 +10,7 @@ namespace Content.Server.AI.Utility.Considerations.Hands
///
public sealed class TargetInOurHandsCon : Consideration
{
- public TargetInOurHandsCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var owner = context.GetState().GetValue();
var target = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/Inventory/CanPutTargetInHandsCon.cs b/Content.Server/AI/Utility/Considerations/Inventory/CanPutTargetInHandsCon.cs
index 581255786e..7a75efe411 100644
--- a/Content.Server/AI/Utility/Considerations/Inventory/CanPutTargetInHandsCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Inventory/CanPutTargetInHandsCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Hands;
@@ -9,9 +8,7 @@ namespace Content.Server.AI.Utility.Considerations.Inventory
{
public class CanPutTargetInHandsCon : Consideration
{
- public CanPutTargetInHandsCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
// First check if target in inventory already
// If not then check if we have a free hand
@@ -22,9 +19,7 @@ namespace Content.Server.AI.Utility.Considerations.Inventory
return 0.0f;
}
- var inventory = context.GetState().GetValue();
-
- foreach (var item in inventory)
+ foreach (var item in context.GetState().GetValue())
{
if (item == target)
{
diff --git a/Content.Server/AI/Utility/Considerations/Inventory/TargetInOurInventoryCon.cs b/Content.Server/AI/Utility/Considerations/Inventory/TargetInOurInventoryCon.cs
index 10368f92a9..4d4e1b6970 100644
--- a/Content.Server/AI/Utility/Considerations/Inventory/TargetInOurInventoryCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Inventory/TargetInOurInventoryCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory;
@@ -8,11 +7,8 @@ namespace Content.Server.AI.Utility.Considerations.Inventory
{
public class TargetInOurInventoryCon : Consideration
{
- public TargetInOurInventoryCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
- var inventory = context.GetState().GetValue();
var target = context.GetState().GetValue();
if (target == null || !target.HasComponent())
@@ -20,7 +16,7 @@ namespace Content.Server.AI.Utility.Considerations.Inventory
return 0.0f;
}
- foreach (var item in inventory)
+ foreach (var item in context.GetState().GetValue())
{
if (item == target)
{
diff --git a/Content.Server/AI/Utility/Considerations/Movement/DistanceCon.cs b/Content.Server/AI/Utility/Considerations/Movement/DistanceCon.cs
index b8dfee7354..7b099bfcd0 100644
--- a/Content.Server/AI/Utility/Considerations/Movement/DistanceCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Movement/DistanceCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
@@ -6,9 +5,7 @@ namespace Content.Server.AI.Utility.Considerations.Movement
{
public sealed class DistanceCon : Consideration
{
- public DistanceCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var self = context.GetState().GetValue();
var target = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/Nutrition/Drink/DrinkValueCon.cs b/Content.Server/AI/Utility/Considerations/Nutrition/Drink/DrinkValueCon.cs
index 73e6505e7e..b69f9a53ad 100644
--- a/Content.Server/AI/Utility/Considerations/Nutrition/Drink/DrinkValueCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Nutrition/Drink/DrinkValueCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects.Components.Chemistry;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Nutrition.Drink
{
public sealed class DrinkValueCon : Consideration
{
- public DrinkValueCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var target = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/Nutrition/Drink/ThirstCon.cs b/Content.Server/AI/Utility/Considerations/Nutrition/Drink/ThirstCon.cs
index e2c387fbbc..b228d16026 100644
--- a/Content.Server/AI/Utility/Considerations/Nutrition/Drink/ThirstCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Nutrition/Drink/ThirstCon.cs
@@ -1,4 +1,3 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects.Components.Nutrition;
@@ -8,9 +7,7 @@ namespace Content.Server.AI.Utility.Considerations.Nutrition.Drink
{
public class ThirstCon : Consideration
{
- public ThirstCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var owner = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/Nutrition/Food/FoodValueCon.cs b/Content.Server/AI/Utility/Considerations/Nutrition/Food/FoodValueCon.cs
index a316799c3d..78277572ae 100644
--- a/Content.Server/AI/Utility/Considerations/Nutrition/Food/FoodValueCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Nutrition/Food/FoodValueCon.cs
@@ -1,15 +1,12 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects.Components.Chemistry;
-namespace Content.Server.AI.Utility.Considerations.Nutrition
+namespace Content.Server.AI.Utility.Considerations.Nutrition.Food
{
public sealed class FoodValueCon : Consideration
{
- public FoodValueCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var target = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/Nutrition/Food/HungerCon.cs b/Content.Server/AI/Utility/Considerations/Nutrition/Food/HungerCon.cs
index 2d154e12f5..a09eff2924 100644
--- a/Content.Server/AI/Utility/Considerations/Nutrition/Food/HungerCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Nutrition/Food/HungerCon.cs
@@ -1,17 +1,14 @@
-using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects.Components.Nutrition;
using Content.Shared.GameObjects.Components.Nutrition;
-namespace Content.Server.AI.Utility.Considerations.Nutrition
+namespace Content.Server.AI.Utility.Considerations.Nutrition.Food
{
public sealed class HungerCon : Consideration
{
- public HungerCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
+ protected override float GetScore(Blackboard context)
{
var owner = context.GetState().GetValue();
diff --git a/Content.Server/AI/Utility/Considerations/State/StoredStateEntityIsNullCon.cs b/Content.Server/AI/Utility/Considerations/State/StoredStateEntityIsNullCon.cs
new file mode 100644
index 0000000000..a2750b6ed1
--- /dev/null
+++ b/Content.Server/AI/Utility/Considerations/State/StoredStateEntityIsNullCon.cs
@@ -0,0 +1,26 @@
+using System;
+using Content.Server.AI.WorldState;
+using Content.Server.AI.WorldState.States.Utility;
+
+namespace Content.Server.AI.Utility.Considerations.State
+{
+ ///
+ /// Simple NullCheck on a StoredState
+ ///
+ public sealed class StoredStateEntityIsNullCon : Consideration
+ {
+ public StoredStateEntityIsNullCon Set(Type type, 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.
+ context.GetState().SetValue(type);
+ return this;
+ }
+
+ protected override float GetScore(Blackboard context)
+ {
+ var stateData = context.GetState().GetValue();
+ return stateData == null ? 1.0f : 0.0f;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/AI/Utility/Considerations/State/StoredStateIsNullCon.cs b/Content.Server/AI/Utility/Considerations/State/StoredStateIsNullCon.cs
deleted file mode 100644
index b93757bf9e..0000000000
--- a/Content.Server/AI/Utility/Considerations/State/StoredStateIsNullCon.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using Content.Server.AI.Utility.Curves;
-using Content.Server.AI.WorldState;
-
-namespace Content.Server.AI.Utility.Considerations.State
-{
- ///
- /// Simple NullCheck on a StoredState
- ///
- public sealed class StoredStateIsNullCon : Consideration where T : StoredStateData
- {
- public StoredStateIsNullCon(IResponseCurve curve) : base(curve) {}
-
- public override float GetScore(Blackboard context)
- {
- var state = context.GetState();
- if (state.GetValue() == null)
- {
- return 1.0f;
- }
-
- return 0.0f;
- }
- }
-}
\ No newline at end of file
diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/Gloves/EquipAnyGlovesExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/Gloves/EquipAnyGlovesExp.cs
index 700dff2f94..4a8e10b0a6 100644
--- a/Content.Server/AI/Utility/ExpandableActions/Clothing/Gloves/EquipAnyGlovesExp.cs
+++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/Gloves/EquipAnyGlovesExp.cs
@@ -21,12 +21,8 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Gloves
public override IEnumerable GetActions(Blackboard context)
{
var owner = context.GetState().GetValue();
- if (!owner.TryGetComponent(out AiControllerComponent controller))
- {
- throw new InvalidOperationException();
- }
- foreach (var entity in context.GetState().GetValue())
+ foreach (var entity in context.GetState().GetValue())
{
if (entity.TryGetComponent(out ClothingComponent clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.GLOVES) != 0)
diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/EquipAnyHeadExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/EquipAnyHeadExp.cs
index 1d71661dcf..9164111d01 100644
--- a/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/EquipAnyHeadExp.cs
+++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/EquipAnyHeadExp.cs
@@ -20,7 +20,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head
{
var owner = context.GetState().GetValue();
- foreach (var entity in context.GetState().GetValue())
+ foreach (var entity in context.GetState().GetValue())
{
if (entity.TryGetComponent(out ClothingComponent clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.HEAD) != 0)
diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/PickUpAnyNearbyHeadExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/PickUpAnyNearbyHeadExp.cs
index dfb2f6d2a9..85806e99ee 100644
--- a/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/PickUpAnyNearbyHeadExp.cs
+++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/Head/PickUpAnyNearbyHeadExp.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Utility.Actions;
using Content.Server.AI.Utility.Actions.Clothing.Head;
@@ -5,6 +6,7 @@ using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Clothing;
using Content.Server.GameObjects;
+using Content.Server.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Inventory;
namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head
@@ -16,6 +18,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head
public override IEnumerable GetActions(Blackboard context)
{
var owner = context.GetState().GetValue();
+
foreach (var entity in context.GetState().GetValue())
{
if (entity.TryGetComponent(out ClothingComponent clothing) &&
diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/OuterClothing/EquipAnyOuterClothingExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/OuterClothing/EquipAnyOuterClothingExp.cs
index b7a7980974..007b801d27 100644
--- a/Content.Server/AI/Utility/ExpandableActions/Clothing/OuterClothing/EquipAnyOuterClothingExp.cs
+++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/OuterClothing/EquipAnyOuterClothingExp.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Utility.Actions;
using Content.Server.AI.Utility.Actions.Clothing.OuterClothing;
@@ -5,6 +6,7 @@ using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects;
+using Content.Server.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Inventory;
namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing
@@ -20,7 +22,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing
{
var owner = context.GetState().GetValue();
- foreach (var entity in context.GetState().GetValue())
+ foreach (var entity in context.GetState().GetValue())
{
if (entity.TryGetComponent(out ClothingComponent clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.OUTERCLOTHING) != 0)
diff --git a/Content.Server/AI/Utility/ExpandableActions/Clothing/Shoes/EquipAnyShoesExp.cs b/Content.Server/AI/Utility/ExpandableActions/Clothing/Shoes/EquipAnyShoesExp.cs
index 517fd735c0..f750fba71a 100644
--- a/Content.Server/AI/Utility/ExpandableActions/Clothing/Shoes/EquipAnyShoesExp.cs
+++ b/Content.Server/AI/Utility/ExpandableActions/Clothing/Shoes/EquipAnyShoesExp.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using Content.Server.AI.Utility.Actions;
using Content.Server.AI.Utility.Actions.Clothing.Shoes;
@@ -5,6 +6,7 @@ using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects;
+using Content.Server.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Inventory;
namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes
@@ -20,7 +22,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes
{
var owner = context.GetState().GetValue();
- foreach (var entity in context.GetState().GetValue())
+ foreach (var entity in context.GetState().GetValue())
{
if (entity.TryGetComponent(out ClothingComponent clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.SHOES) != 0)
diff --git a/Content.Server/AI/Utility/ExpandableActions/Combat/Melee/EquipMeleeExp.cs b/Content.Server/AI/Utility/ExpandableActions/Combat/Melee/EquipMeleeExp.cs
index 67bfac1c98..d0aade8647 100644
--- a/Content.Server/AI/Utility/ExpandableActions/Combat/Melee/EquipMeleeExp.cs
+++ b/Content.Server/AI/Utility/ExpandableActions/Combat/Melee/EquipMeleeExp.cs
@@ -4,6 +4,7 @@ using Content.Server.AI.Utility.Actions.Combat.Melee;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory;
+using Content.Server.GameObjects.Components.Weapon.Melee;
namespace Content.Server.AI.Utility.ExpandableActions.Combat.Melee
{
@@ -15,8 +16,13 @@ namespace Content.Server.AI.Utility.ExpandableActions.Combat.Melee
{
var owner = context.GetState().GetValue();
- foreach (var entity in context.GetState().GetValue())
+ foreach (var entity in context.GetState().GetValue())
{
+ if (!entity.HasComponent())
+ {
+ continue;
+ }
+
yield return new EquipMelee(owner, entity, Bonus);
}
}
diff --git a/Content.Server/AI/Utility/ExpandableActions/Nutrition/UseDrinkInHandsExp.cs b/Content.Server/AI/Utility/ExpandableActions/Nutrition/UseDrinkInHandsExp.cs
index 830249bf89..fac523cd96 100644
--- a/Content.Server/AI/Utility/ExpandableActions/Nutrition/UseDrinkInHandsExp.cs
+++ b/Content.Server/AI/Utility/ExpandableActions/Nutrition/UseDrinkInHandsExp.cs
@@ -4,6 +4,7 @@ using Content.Server.AI.Utility.Actions.Nutrition.Drink;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory;
+using Content.Server.GameObjects.Components.Nutrition;
namespace Content.Server.AI.Utility.ExpandableActions.Nutrition
{
@@ -15,8 +16,13 @@ namespace Content.Server.AI.Utility.ExpandableActions.Nutrition
{
var owner = context.GetState().GetValue();
- foreach (var entity in context.GetState().GetValue())
+ foreach (var entity in context.GetState().GetValue())
{
+ if (!entity.HasComponent())
+ {
+ continue;
+ }
+
yield return new UseDrinkInInventory(owner, entity, Bonus);
}
}
diff --git a/Content.Server/AI/Utility/ExpandableActions/Nutrition/UseFoodInInventoryExp.cs b/Content.Server/AI/Utility/ExpandableActions/Nutrition/UseFoodInInventoryExp.cs
index 69e32c7f2f..2df0385f6f 100644
--- a/Content.Server/AI/Utility/ExpandableActions/Nutrition/UseFoodInInventoryExp.cs
+++ b/Content.Server/AI/Utility/ExpandableActions/Nutrition/UseFoodInInventoryExp.cs
@@ -4,6 +4,7 @@ using Content.Server.AI.Utility.Actions.Nutrition.Food;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory;
+using Content.Server.GameObjects.Components.Nutrition;
namespace Content.Server.AI.Utility.ExpandableActions.Nutrition
{
@@ -15,8 +16,13 @@ namespace Content.Server.AI.Utility.ExpandableActions.Nutrition
{
var owner = context.GetState().GetValue();
- foreach (var entity in context.GetState().GetValue())
+ foreach (var entity in context.GetState().GetValue())
{
+ if (!entity.HasComponent())
+ {
+ continue;
+ }
+
yield return new UseFoodInInventory(owner, entity, Bonus);
}
}
diff --git a/Content.Server/AI/WorldState/Blackboard.cs b/Content.Server/AI/WorldState/Blackboard.cs
index b40daa2baa..160a65875d 100644
--- a/Content.Server/AI/WorldState/Blackboard.cs
+++ b/Content.Server/AI/WorldState/Blackboard.cs
@@ -56,6 +56,11 @@ namespace Content.Server.AI.WorldState
}
}
+ public void GetState(Type type, out IAiState state)
+ {
+ state = _states[type];
+ }
+
///
/// Get the AI state class
///
diff --git a/Content.Server/AI/WorldState/StateData.cs b/Content.Server/AI/WorldState/StateData.cs
index cc55f767e7..4acf5c00eb 100644
--- a/Content.Server/AI/WorldState/StateData.cs
+++ b/Content.Server/AI/WorldState/StateData.cs
@@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
+using Content.Server.Interfaces.GameTicking;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.Interfaces.Timing;
+using Robust.Shared.IoC;
namespace Content.Server.AI.WorldState
{
@@ -22,6 +25,11 @@ namespace Content.Server.AI.WorldState
void CheckCache();
}
+ public interface IStoredState
+ {
+
+ }
+
///
/// The default class for state values. Also see CachedStateData and PlanningStateData
///
@@ -44,7 +52,7 @@ namespace Content.Server.AI.WorldState
/// Useful for group blackboard sharing or to avoid repeating the same action (e.g. bark phrases).
///
///
- public abstract class StoredStateData : IAiState
+ public abstract class StoredStateData : IAiState, IStoredState
{
// Probably not the best class name but couldn't think of anything better
public abstract string Name { get; }
@@ -108,11 +116,11 @@ namespace Content.Server.AI.WorldState
protected IEntity Owner { get; private set; }
private bool _cached;
protected T Value;
- private DateTime _lastCache = DateTime.Now;
+ private TimeSpan _lastCache = TimeSpan.Zero;
///
/// How long something stays in the cache before new values are retrieved
///
- protected float CacheTime { get; set; } = 2.0f;
+ protected double CacheTime { get; set; } = 2.0f;
public void Setup(IEntity owner)
{
@@ -121,7 +129,9 @@ namespace Content.Server.AI.WorldState
public void CheckCache()
{
- if (!_cached || (DateTime.Now - _lastCache).TotalSeconds >= CacheTime)
+ var curTime = IoCManager.Resolve().CurTime;
+
+ if (!_cached || (curTime - _lastCache).TotalSeconds >= CacheTime)
{
_cached = false;
return;
@@ -142,7 +152,7 @@ namespace Content.Server.AI.WorldState
{
Value = GetTrueValue();
_cached = true;
- _lastCache = DateTime.Now;
+ _lastCache = IoCManager.Resolve().CurTime;
}
return Value;
diff --git a/Content.Server/AI/WorldState/States/Clothing/ClothingSlotConState.cs b/Content.Server/AI/WorldState/States/Clothing/ClothingSlotConState.cs
new file mode 100644
index 0000000000..e1f87353d7
--- /dev/null
+++ b/Content.Server/AI/WorldState/States/Clothing/ClothingSlotConState.cs
@@ -0,0 +1,13 @@
+using Content.Shared.GameObjects.Components.Inventory;
+
+namespace Content.Server.AI.WorldState.States.Clothing
+{
+ public sealed class ClothingSlotConState : PlanningStateData
+ {
+ public override string Name => "ClothingSlotCon";
+ public override void Reset()
+ {
+ Value = EquipmentSlotDefines.Slots.NONE;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/AI/WorldState/States/Clothing/ClothingSlotFlagConState.cs b/Content.Server/AI/WorldState/States/Clothing/ClothingSlotFlagConState.cs
new file mode 100644
index 0000000000..6af98349a0
--- /dev/null
+++ b/Content.Server/AI/WorldState/States/Clothing/ClothingSlotFlagConState.cs
@@ -0,0 +1,13 @@
+using Content.Shared.GameObjects.Components.Inventory;
+
+namespace Content.Server.AI.WorldState.States.Clothing
+{
+ public sealed class ClothingSlotFlagConState : PlanningStateData
+ {
+ public override string Name => "ClothingSlotFlagCon";
+ public override void Reset()
+ {
+ Value = EquipmentSlotDefines.SlotFlags.NONE;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/AI/WorldState/States/Inventory/InventoryState.cs b/Content.Server/AI/WorldState/States/Inventory/InventoryState.cs
index d139eac9cf..347dc0402e 100644
--- a/Content.Server/AI/WorldState/States/Inventory/InventoryState.cs
+++ b/Content.Server/AI/WorldState/States/Inventory/InventoryState.cs
@@ -6,25 +6,19 @@ using Robust.Shared.Interfaces.GameObjects;
namespace Content.Server.AI.WorldState.States.Inventory
{
[UsedImplicitly]
- public sealed class InventoryState : StateData>
+ public sealed class EnumerableInventoryState : StateData>
{
- public override string Name => "Inventory";
+ public override string Name => "EnumerableInventory";
- public override List GetValue()
+ public override IEnumerable GetValue()
{
- var inventory = new List();
-
if (Owner.TryGetComponent(out HandsComponent handsComponent))
{
foreach (var item in handsComponent.GetAllHeldItems())
{
- inventory.Add(item.Owner);
+ yield return item.Owner;
}
}
-
- // TODO: InventoryComponent (Pockets were throwing)
-
- return inventory;
}
}
}
diff --git a/Content.Server/AI/WorldState/States/Utility/ConsiderationState.cs b/Content.Server/AI/WorldState/States/Utility/ConsiderationState.cs
new file mode 100644
index 0000000000..66903bee54
--- /dev/null
+++ b/Content.Server/AI/WorldState/States/Utility/ConsiderationState.cs
@@ -0,0 +1,10 @@
+namespace Content.Server.AI.WorldState.States.Utility
+{
+ ///
+ /// Used by the utility AI to calc the adjusted scores
+ ///
+ public class ConsiderationState : StoredStateData
+ {
+ public override string Name => "Consideration";
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/AI/WorldState/States/Utility/StoredStateIsNullState.cs b/Content.Server/AI/WorldState/States/Utility/StoredStateIsNullState.cs
new file mode 100644
index 0000000000..9893af3258
--- /dev/null
+++ b/Content.Server/AI/WorldState/States/Utility/StoredStateIsNullState.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Content.Server.AI.WorldState.States.Utility
+{
+ public sealed class StoredStateIsNullState : PlanningStateData
+ {
+ public override string Name => "StoredStateIsNull";
+ public override void Reset()
+ {
+ Value = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Chat/ChatCommands.cs b/Content.Server/Chat/ChatCommands.cs
index 266c5ef994..5ff3828f58 100644
--- a/Content.Server/Chat/ChatCommands.cs
+++ b/Content.Server/Chat/ChatCommands.cs
@@ -4,6 +4,7 @@ using Content.Server.Interfaces.Chat;
using Content.Server.Interfaces.GameObjects;
using Content.Server.Players;
using Content.Shared.GameObjects;
+using Robust.Server.Console;
using Robust.Server.Interfaces.Console;
using Robust.Server.Interfaces.Player;
using Robust.Shared.Enums;
@@ -80,6 +81,19 @@ namespace Content.Server.Chat
}
}
+ internal class AdminChatCommand : IClientCommand
+ {
+ public string Command => "asay";
+ public string Description => "Send chat messages to the private admin chat channel.";
+ public string Help => "asay ";
+
+ public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
+ {
+ var chat = IoCManager.Resolve();
+ chat.SendAdminChat(player, string.Join(" ", args));
+ }
+ }
+
internal class SuicideCommand : IClientCommand
{
public string Command => "suicide";
diff --git a/Content.Server/Chat/ChatManager.cs b/Content.Server/Chat/ChatManager.cs
index 60c6eb4a64..21dedca1df 100644
--- a/Content.Server/Chat/ChatManager.cs
+++ b/Content.Server/Chat/ChatManager.cs
@@ -7,6 +7,7 @@ using Content.Server.Observer;
using Content.Server.Players;
using Content.Shared.Chat;
using Content.Shared.GameObjects.EntitySystems;
+using Robust.Server.Console;
using Robust.Server.Interfaces.Player;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
@@ -28,6 +29,7 @@ namespace Content.Server.Chat
[Dependency] private readonly IPlayerManager _playerManager;
[Dependency] private readonly ILocalizationManager _localizationManager;
[Dependency] private readonly IMoMMILink _mommiLink;
+ [Dependency] private readonly IConGroupController _conGroupController;
#pragma warning restore 649
public void Initialize()
@@ -112,6 +114,23 @@ namespace Content.Server.Chat
_netManager.ServerSendToMany(msg, clients.ToList());
}
+ public void SendAdminChat(IPlayerSession player, string message)
+ {
+ if(!_conGroupController.CanCommand(player, "asay"))
+ {
+ SendOOC(player, message);
+ return;
+ }
+ var clients = _playerManager.GetPlayersBy(x => _conGroupController.CanCommand(x, "asay")).Select(p => p.ConnectedClient);;
+
+ var msg = _netManager.CreateNetMessage();
+
+ msg.Channel = ChatChannel.AdminChat;
+ msg.Message = message;
+ msg.MessageWrap = $"{_localizationManager.GetString("ADMIN")}: {player.SessionId}: {{0}}";
+ _netManager.ServerSendToMany(msg, clients.ToList());
+ }
+
public void SendHookOOC(string sender, string message)
{
var msg = _netManager.CreateNetMessage();
diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs
index b7220dc612..9bf2032e06 100644
--- a/Content.Server/EntryPoint.cs
+++ b/Content.Server/EntryPoint.cs
@@ -1,4 +1,5 @@
-using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
+using Content.Server.AI.Utility.Considerations;
+ using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
using Content.Server.Interfaces;
using Content.Server.AI.WorldState;
@@ -72,6 +73,7 @@ namespace Content.Server
_gameTicker.Initialize();
IoCManager.Resolve().Initialize();
IoCManager.Resolve().Initialize();
+ IoCManager.Resolve().Initialize();
IoCManager.Resolve().Initialize();
}
diff --git a/Content.Server/GameObjects/Components/Access/AccessComponent.cs b/Content.Server/GameObjects/Components/Access/AccessComponent.cs
index 060f418634..101f215c15 100644
--- a/Content.Server/GameObjects/Components/Access/AccessComponent.cs
+++ b/Content.Server/GameObjects/Components/Access/AccessComponent.cs
@@ -1,11 +1,10 @@
+#nullable enable
using System.Collections.Generic;
using Content.Server.Interfaces;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
-#nullable enable
-
namespace Content.Server.GameObjects.Components.Access
{
///
diff --git a/Content.Server/GameObjects/Components/Access/AccessReaderComponent.cs b/Content.Server/GameObjects/Components/Access/AccessReaderComponent.cs
index 40aaf8ebd2..9fffb5f77b 100644
--- a/Content.Server/GameObjects/Components/Access/AccessReaderComponent.cs
+++ b/Content.Server/GameObjects/Components/Access/AccessReaderComponent.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,8 +12,6 @@ using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
-#nullable enable
-
namespace Content.Server.GameObjects.Components.Access
{
///
@@ -69,7 +68,6 @@ namespace Content.Server.GameObjects.Components.Access
return _accessLists.Count == 0 || _accessLists.Any(a => a.IsSubsetOf(accessTags));
}
- [CanBeNull]
public static ICollection FindAccessTags(IEntity entity)
{
if (entity.TryGetComponent(out IAccess accessComponent))
diff --git a/Content.Server/GameObjects/Components/Access/PresetIdCardComponent.cs b/Content.Server/GameObjects/Components/Access/PresetIdCardComponent.cs
index 3895218154..67c6d08a76 100644
--- a/Content.Server/GameObjects/Components/Access/PresetIdCardComponent.cs
+++ b/Content.Server/GameObjects/Components/Access/PresetIdCardComponent.cs
@@ -1,3 +1,4 @@
+#nullable enable
using Content.Shared.Jobs;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
@@ -5,8 +6,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
-#nullable enable
-
namespace Content.Server.GameObjects.Components.Access
{
[RegisterComponent]
diff --git a/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs b/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs
index cd5effccc2..78c30dc9b4 100644
--- a/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs
+++ b/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs
@@ -1,10 +1,10 @@
-using Content.Server.Cargo;
+#nullable enable
+using Content.Server.Cargo;
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces.GameObjects.Components.Interaction;
using Content.Shared.GameObjects.Components.Cargo;
using Content.Shared.Prototypes.Cargo;
-using JetBrains.Annotations;
using Robust.Server.GameObjects.Components.UserInterface;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
@@ -20,39 +20,43 @@ namespace Content.Server.GameObjects.Components.Cargo
public class CargoConsoleComponent : SharedCargoConsoleComponent, IActivate
{
#pragma warning disable 649
- [Dependency] private readonly ICargoOrderDataManager _cargoOrderDataManager;
+ [Dependency] private readonly ICargoOrderDataManager _cargoOrderDataManager = default!;
#pragma warning restore 649
[ViewVariables]
public int Points = 1000;
- private BoundUserInterface _userInterface;
+ private BoundUserInterface _userInterface = default!;
[ViewVariables]
- public GalacticMarketComponent Market { get; private set; }
- [ViewVariables]
- public CargoOrderDatabaseComponent Orders { get; private set; }
-
- private CargoBankAccount _bankAccount;
+ public GalacticMarketComponent Market { get; private set; } = default!;
[ViewVariables]
- [CanBeNull]
- public CargoBankAccount BankAccount
+ public CargoOrderDatabaseComponent Orders { get; private set; } = default!;
+
+ private CargoBankAccount? _bankAccount;
+
+ [ViewVariables]
+ public CargoBankAccount? BankAccount
{
get => _bankAccount;
private set
{
if (_bankAccount == value)
+ {
return;
+ }
+
if (_bankAccount != null)
{
_bankAccount.OnBalanceChange -= UpdateUIState;
}
_bankAccount = value;
+
if (value != null)
{
- _bankAccount.OnBalanceChange += UpdateUIState;
+ value.OnBalanceChange += UpdateUIState;
}
UpdateUIState();
@@ -61,9 +65,9 @@ namespace Content.Server.GameObjects.Components.Cargo
private bool _requestOnly = false;
- private PowerReceiverComponent _powerReceiver;
+ private PowerReceiverComponent _powerReceiver = default!;
private bool Powered => _powerReceiver.Powered;
- private CargoConsoleSystem _cargoConsoleSystem;
+ private CargoConsoleSystem _cargoConsoleSystem = default!;
public override void Initialize()
{
@@ -98,8 +102,11 @@ namespace Content.Server.GameObjects.Components.Cargo
{
case CargoConsoleAddOrderMessage msg:
{
- if (msg.Amount <= 0)
+ if (msg.Amount <= 0 || _bankAccount == null)
+ {
break;
+ }
+
_cargoOrderDataManager.AddOrder(Orders.Database.Id, msg.Requester, msg.Reason, msg.ProductId, msg.Amount, _bankAccount.Id);
break;
}
@@ -111,8 +118,12 @@ namespace Content.Server.GameObjects.Components.Cargo
case CargoConsoleApproveOrderMessage msg:
{
if (_requestOnly ||
- !Orders.Database.TryGetOrder(msg.OrderNumber, out var order))
+ !Orders.Database.TryGetOrder(msg.OrderNumber, out var order) ||
+ _bankAccount == null)
+ {
break;
+ }
+
_prototypeManager.TryIndex(order.ProductId, out CargoProductPrototype product);
if (product == null)
break;
diff --git a/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs
index 4a4dcbabef..5c5f2fd230 100644
--- a/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs
+++ b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs
@@ -224,6 +224,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
if (!ActionBlockerSystem.CanInteract(user) ||
!user.TryGetComponent(out var hands) ||
hands.GetActiveHand == null ||
+ hands.GetActiveHand.Owner == component.Owner ||
!hands.GetActiveHand.Owner.TryGetComponent(out var solution))
{
data.Visibility = VerbVisibility.Invisible;
@@ -323,6 +324,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
if (!ActionBlockerSystem.CanInteract(user) ||
!user.TryGetComponent(out var hands) ||
hands.GetActiveHand == null ||
+ hands.GetActiveHand.Owner == component.Owner ||
!hands.GetActiveHand.Owner.TryGetComponent(out var solution))
{
data.Visibility = VerbVisibility.Invisible;
diff --git a/Content.Server/GameObjects/Components/Explosion/FlashExplosiveComponent.cs b/Content.Server/GameObjects/Components/Explosion/FlashExplosiveComponent.cs
index e7829b09ed..5dab5960c2 100644
--- a/Content.Server/GameObjects/Components/Explosion/FlashExplosiveComponent.cs
+++ b/Content.Server/GameObjects/Components/Explosion/FlashExplosiveComponent.cs
@@ -21,7 +21,7 @@ namespace Content.Server.GameObjects.Components.Explosion
public override string Name => "FlashExplosive";
private float _range;
- private double _duration;
+ private float _duration;
private string _sound;
private bool _deleteOnFlash;
@@ -30,7 +30,7 @@ namespace Content.Server.GameObjects.Components.Explosion
base.ExposeData(serializer);
serializer.DataField(ref _range, "range", 7.0f);
- serializer.DataField(ref _duration, "duration", 8.0);
+ serializer.DataField(ref _duration, "duration", 8.0f);
serializer.DataField(ref _sound, "sound", "/Audio/Effects/flash_bang.ogg");
serializer.DataField(ref _deleteOnFlash, "deleteOnFlash", true);
}
@@ -41,7 +41,7 @@ namespace Content.Server.GameObjects.Components.Explosion
ContainerHelpers.TryGetContainer(Owner, out var container);
if (container == null || !container.Owner.HasComponent())
{
- ServerFlashableComponent.FlashAreaHelper(Owner, _range, _duration);
+ FlashableComponent.FlashAreaHelper(Owner, _range, _duration);
}
if (_sound != null)
diff --git a/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs b/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs
index c89827e40a..f9c67efebd 100644
--- a/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs
+++ b/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable enable
+using System;
using System.Runtime.Remoting;
using Content.Server.GameObjects.Components.Chemistry;
using Content.Server.GameObjects.Components.Items.Storage;
@@ -25,11 +26,11 @@ namespace Content.Server.GameObjects.Components.Interactable
[RegisterComponent]
[ComponentReference(typeof(ToolComponent))]
[ComponentReference(typeof(IToolComponent))]
- public class WelderComponent : ToolComponent, IExamine, IUse, ISuicideAct
+ public class WelderComponent : ToolComponent, IExamine, IUse, ISuicideAct, ISolutionChange
{
#pragma warning disable 649
- [Dependency] private IEntitySystemManager _entitySystemManager;
- [Dependency] private IServerNotifyManager _notifyManager;
+ [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
+ [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
#pragma warning restore 649
public override string Name => "Welder";
@@ -45,10 +46,11 @@ namespace Content.Server.GameObjects.Components.Interactable
///
public const float FuelLossRate = 0.5f;
- private bool _welderLit = false;
- private WelderSystem _welderSystem;
- private SpriteComponent _spriteComponent;
- private SolutionComponent _solutionComponent;
+ private bool _welderLit;
+ private WelderSystem _welderSystem = default!;
+ private SpriteComponent? _spriteComponent;
+ private SolutionComponent? _solutionComponent;
+ private PointLightComponent? _pointLightComponent;
[ViewVariables]
public float Fuel => _solutionComponent?.Solution.GetReagentQuantity("chem.WeldingFuel").Float() ?? 0f;
@@ -80,6 +82,7 @@ namespace Content.Server.GameObjects.Components.Interactable
Owner.TryGetComponent(out _solutionComponent);
Owner.TryGetComponent(out _spriteComponent);
+ Owner.TryGetComponent(out _pointLightComponent);
}
public override ComponentState GetComponentState()
@@ -99,7 +102,7 @@ namespace Content.Server.GameObjects.Components.Interactable
return base.UseTool(user, target, toolQualityNeeded) && TryWeld(fuelConsumed, user);
}
- private bool TryWeld(float value, IEntity user = null, bool silent = false)
+ private bool TryWeld(float value, IEntity? user = null, bool silent = false)
{
if (!WelderLit)
{
@@ -132,7 +135,7 @@ namespace Content.Server.GameObjects.Components.Interactable
///
/// Deactivates welding tool if active, activates welding tool if possible
///
- private bool ToggleWelderStatus(IEntity user = null)
+ private bool ToggleWelderStatus(IEntity? user = null)
{
var item = Owner.GetComponent();
@@ -141,7 +144,10 @@ namespace Content.Server.GameObjects.Components.Interactable
WelderLit = false;
// Layer 1 is the flame.
item.EquippedPrefix = "off";
- _spriteComponent.LayerSetVisible(1, false);
+ _spriteComponent?.LayerSetVisible(1, false);
+
+ if (_pointLightComponent != null) _pointLightComponent.Enabled = false;
+
PlaySoundCollection("WelderOff", -5);
_welderSystem.Unsubscribe(this);
return true;
@@ -155,7 +161,10 @@ namespace Content.Server.GameObjects.Components.Interactable
WelderLit = true;
item.EquippedPrefix = "on";
- _spriteComponent.LayerSetVisible(1, true);
+ _spriteComponent?.LayerSetVisible(1, true);
+
+ if (_pointLightComponent != null) _pointLightComponent.Enabled = true;
+
PlaySoundCollection("WelderOn", -5);
_welderSystem.Subscribe(this);
return true;
@@ -189,12 +198,11 @@ namespace Content.Server.GameObjects.Components.Interactable
if (!HasQuality(ToolQuality.Welding) || !WelderLit)
return;
- _solutionComponent.TryRemoveReagent("chem.WeldingFuel", ReagentUnit.New(FuelLossRate * frameTime));
+ _solutionComponent?.TryRemoveReagent("chem.WeldingFuel", ReagentUnit.New(FuelLossRate * frameTime));
if (Fuel == 0)
ToggleWelderStatus();
- Dirty();
}
public SuicideKind Suicide(IEntity victim, IChatManager chat)
@@ -208,5 +216,10 @@ namespace Content.Server.GameObjects.Components.Interactable
chat.EntityMe(victim, Loc.GetString("bashes {0:themselves} with the {1}!", victim, Owner.Name));
return SuicideKind.Brute;
}
+
+ public void SolutionChanged(SolutionChangeEventArgs eventArgs)
+ {
+ Dirty();
+ }
}
}
diff --git a/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs b/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs
index e1e617774e..d3ba8882db 100644
--- a/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs
+++ b/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs
@@ -1,11 +1,7 @@
-using Content.Shared.GameObjects.Components.Movement;
+#nullable enable
+using Content.Shared.GameObjects.Components.Movement;
using Robust.Shared.GameObjects;
-using Robust.Shared.GameObjects.Components;
using Robust.Shared.Map;
-using Robust.Shared.Physics;
-using Robust.Shared.ViewVariables;
-
-#nullable enable
namespace Content.Server.GameObjects.Components.Movement
{
diff --git a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs
index a7fddc81db..e91c4fac54 100644
--- a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs
+++ b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
@@ -23,8 +24,6 @@ using Robust.Shared.Localization;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
-#nullable enable
-
namespace Content.Server.GameObjects.Components.PDA
{
[RegisterComponent]
diff --git a/Content.Server/GameObjects/Components/Projectiles/FlashProjectileComponent.cs b/Content.Server/GameObjects/Components/Projectiles/FlashProjectileComponent.cs
index 381ebdd19e..756a37a44f 100644
--- a/Content.Server/GameObjects/Components/Projectiles/FlashProjectileComponent.cs
+++ b/Content.Server/GameObjects/Components/Projectiles/FlashProjectileComponent.cs
@@ -17,16 +17,16 @@ namespace Content.Server.GameObjects.Components.Projectiles
{
public override string Name => "FlashProjectile";
- private double _range;
- private double _duration;
+ private float _range;
+ private float _duration;
private bool _flashed;
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
- serializer.DataField(ref _range, "range", 1.0);
- serializer.DataField(ref _duration, "duration", 8.0);
+ serializer.DataField(ref _range, "range", 1.0f);
+ serializer.DataField(ref _duration, "duration", 8.0f);
}
public override void Initialize()
@@ -45,7 +45,7 @@ namespace Content.Server.GameObjects.Components.Projectiles
{
return;
}
- ServerFlashableComponent.FlashAreaHelper(Owner, _range, _duration);
+ FlashableComponent.FlashAreaHelper(Owner, _range, _duration);
_flashed = true;
}
diff --git a/Content.Server/GameObjects/Components/Weapon/FlashableComponent.cs b/Content.Server/GameObjects/Components/Weapon/FlashableComponent.cs
new file mode 100644
index 0000000000..11499017b3
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Weapon/FlashableComponent.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Linq;
+using Content.Server.Utility;
+using Content.Shared.GameObjects.Components.Weapons;
+using Content.Shared.GameObjects.EntitySystems;
+using Content.Shared.Physics;
+using Robust.Server.GameObjects.EntitySystems;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.Interfaces.Physics;
+using Robust.Shared.Interfaces.Timing;
+using Robust.Shared.IoC;
+using Robust.Shared.Maths;
+
+namespace Content.Server.GameObjects.Components.Weapon
+{
+ [RegisterComponent]
+ public sealed class FlashableComponent : SharedFlashableComponent
+ {
+ private double _duration;
+ private TimeSpan _lastFlash;
+
+ public void Flash(double duration)
+ {
+ var timing = IoCManager.Resolve();
+ _lastFlash = timing.CurTime;
+ _duration = duration;
+ Dirty();
+ }
+
+ public override ComponentState GetComponentState()
+ {
+ return new FlashComponentState(_duration, _lastFlash);
+ }
+
+ public static void FlashAreaHelper(IEntity source, float range, float duration, string sound = null)
+ {
+ foreach (var entity in IoCManager.Resolve().GetEntitiesInRange(source.Transform.GridPosition, range))
+ {
+ if (!InteractionChecks.InRangeUnobstructed(source, entity.Transform.MapPosition, range, ignoredEnt:entity))
+ continue;
+
+ if(entity.TryGetComponent(out FlashableComponent flashable))
+ flashable.Flash(duration);
+ }
+
+ if (!string.IsNullOrEmpty(sound))
+ {
+ IoCManager.Resolve().GetEntitySystem().PlayAtCoords(sound, source.Transform.GridPosition);
+ }
+ }
+ }
+}
diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs
index b2a35a3631..aa3f7335b8 100644
--- a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs
+++ b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs
@@ -53,7 +53,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
[ViewVariables(VVAccess.ReadWrite)]
private float _slowdownTime = 5f;
- [ViewVariables(VVAccess.ReadWrite)] public float EnergyPerUse { get; set; } = 1000;
+ [ViewVariables(VVAccess.ReadWrite)] public float EnergyPerUse { get; set; } = 50;
[ViewVariables]
public bool Activated => _activated;
@@ -89,13 +89,12 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
protected override bool OnHitEntities(IReadOnlyList entities, AttackEventArgs eventArgs)
{
- var cell = Cell;
- if (!Activated || entities.Count == 0 || cell == null)
- return false;
- if (!cell.TryUseCharge(EnergyPerUse))
- {
- return false;
- }
+ if (!Activated || entities.Count == 0 || Cell == null)
+ return true;
+
+ if (!Cell.TryUseCharge(EnergyPerUse))
+ return true;
+
EntitySystem.Get().PlayAtCoords("/Audio/Weapons/egloves.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
foreach (var entity in entities)
@@ -113,11 +112,11 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
else
stunnable.Slowdown(_slowdownTime);
}
- if(cell.CurrentCharge < EnergyPerUse)
- {
- EntitySystem.Get().PlayAtCoords(AudioHelpers.GetRandomFileFromSoundCollection("sparks"), Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
- TurnOff();
- }
+
+ if (!(Cell.CurrentCharge < EnergyPerUse)) return true;
+
+ EntitySystem.Get().PlayAtCoords(AudioHelpers.GetRandomFileFromSoundCollection("sparks"), Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
+ TurnOff();
return true;
}
diff --git a/Content.Server/GameObjects/Components/Weapon/ServerFlashableComponent.cs b/Content.Server/GameObjects/Components/Weapon/ServerFlashableComponent.cs
deleted file mode 100644
index 4dfd7c50c1..0000000000
--- a/Content.Server/GameObjects/Components/Weapon/ServerFlashableComponent.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using System;
-using System.Linq;
-using Content.Shared.GameObjects.Components.Weapons;
-using Content.Shared.Physics;
-using Robust.Server.GameObjects.EntitySystems;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.Interfaces.Physics;
-using Robust.Shared.Interfaces.Timing;
-using Robust.Shared.IoC;
-using Robust.Shared.Maths;
-
-namespace Content.Server.GameObjects.Components.Weapon
-{
- [RegisterComponent]
- public sealed class ServerFlashableComponent : SharedFlashableComponent
- {
- private double _duration;
- private TimeSpan _lastFlash;
-
- public void Flash(double duration)
- {
- var timing = IoCManager.Resolve();
- _lastFlash = timing.CurTime;
- _duration = duration;
- Dirty();
- }
-
- public override ComponentState GetComponentState()
- {
- return new FlashComponentState(_duration, _lastFlash);
- }
-
- public static void FlashAreaHelper(IEntity source, double range, double duration, string sound = null)
- {
- var physicsManager = IoCManager.Resolve();
- var entityManager = IoCManager.Resolve();
-
- foreach (var entity in entityManager.GetEntities(new TypeEntityQuery(typeof(ServerFlashableComponent))))
- {
- if (source.Transform.MapID != entity.Transform.MapID ||
- entity == source)
- {
- continue;
- }
-
- var direction = entity.Transform.WorldPosition - source.Transform.WorldPosition;
-
- if (direction.Length > range)
- {
- continue;
- }
-
- // Direction will be zero if they're hit with the source only I think
- if (direction == Vector2.Zero)
- {
- continue;
- }
-
- var ray = new CollisionRay(source.Transform.WorldPosition, direction.Normalized, (int) CollisionGroup.Opaque);
- var rayCastResults = physicsManager.IntersectRay(source.Transform.MapID, ray, direction.Length, source, false).ToList();
- if (rayCastResults.Count == 0 ||
- rayCastResults[0].HitEntity != entity)
- {
- continue;
- }
-
- var flashable = entity.GetComponent();
- flashable.Flash(duration);
- }
-
- if (sound != null)
- {
- IoCManager.Resolve().GetEntitySystem().PlayAtCoords(sound, source.Transform.GridPosition);
- }
- }
- }
-}
diff --git a/Content.Server/GameObjects/Components/WiresComponent.cs b/Content.Server/GameObjects/Components/WiresComponent.cs
index 2c8534edd6..8af306e51e 100644
--- a/Content.Server/GameObjects/Components/WiresComponent.cs
+++ b/Content.Server/GameObjects/Components/WiresComponent.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable enable
+using System;
using System.Collections.Generic;
using System.Linq;
using Content.Server.GameObjects.Components.Interactable;
@@ -32,12 +33,12 @@ namespace Content.Server.GameObjects.Components
public class WiresComponent : SharedWiresComponent, IInteractUsing, IExamine, IMapInit
{
#pragma warning disable 649
- [Dependency] private readonly IRobustRandom _random;
- [Dependency] private readonly IServerNotifyManager _notifyManager;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
#pragma warning restore 649
- private AudioSystem _audioSystem;
- private AppearanceComponent _appearance;
- private BoundUserInterface _userInterface;
+ private AudioSystem _audioSystem = default!;
+ private AppearanceComponent _appearance = default!;
+ private BoundUserInterface _userInterface = default!;
private bool _isPanelOpen;
@@ -93,7 +94,7 @@ namespace Content.Server.GameObjects.Components
}
[ViewVariables(VVAccess.ReadWrite)]
- public string SerialNumber
+ public string? SerialNumber
{
get => _serialNumber;
set
@@ -127,16 +128,16 @@ namespace Content.Server.GameObjects.Components
private readonly List _availableLetters =
new List((WireLetter[]) Enum.GetValues(typeof(WireLetter)));
- private string _boardName;
+ private string _boardName = default!;
- private string _serialNumber;
+ private string? _serialNumber;
// Used to generate wire appearance randomization client side.
// We honestly don't care what it is or such but do care that it doesn't change between UI re-opens.
[ViewVariables]
private int _wireSeed;
[ViewVariables]
- private string _layoutId;
+ private string? _layoutId;
public override void Initialize()
{
@@ -186,7 +187,7 @@ namespace Content.Server.GameObjects.Components
base.Startup();
- WireLayout layout = null;
+ WireLayout? layout = null;
var hackingSystem = EntitySystem.Get();
if (_layoutId != null)
{
@@ -299,9 +300,9 @@ namespace Content.Server.GameObjects.Components
{
[NotNull] private readonly WiresComponent _wires;
[NotNull] private readonly IWires _owner;
- [CanBeNull] private readonly WireLayout _layout;
+ private readonly WireLayout? _layout;
- public WiresBuilder(WiresComponent wires, IWires owner, WireLayout layout)
+ public WiresBuilder(WiresComponent wires, IWires owner, WireLayout? layout)
{
_wires = wires;
_owner = owner;
@@ -365,12 +366,12 @@ namespace Content.Server.GameObjects.Components
{
case WiresActionMessage msg:
var wire = WiresList.Find(x => x.Id == msg.Id);
- if (wire == null)
+ var player = serverMsg.Session.AttachedEntity;
+ if (wire == null || player == null)
{
return;
}
- var player = serverMsg.Session.AttachedEntity;
if (!player.TryGetComponent(out IHandsComponent handsComponent))
{
_notifyManager.PopupMessage(Owner.Transform.GridPosition, player,
@@ -386,7 +387,7 @@ namespace Content.Server.GameObjects.Components
}
var activeHandEntity = handsComponent.GetActiveHand?.Owner;
- ToolComponent tool = null;
+ ToolComponent? tool = null;
activeHandEntity?.TryGetComponent(out tool);
switch (msg.Action)
diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Accessible/BFSPathfinder.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Accessible/BFSPathfinder.cs
new file mode 100644
index 0000000000..ddb5628a02
--- /dev/null
+++ b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Accessible/BFSPathfinder.cs
@@ -0,0 +1,70 @@
+using System.Collections.Generic;
+using Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders;
+using Content.Server.GameObjects.EntitySystems.Pathfinding;
+using Robust.Shared.GameObjects.Systems;
+using Robust.Shared.Map;
+
+namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Accessible
+{
+ ///
+ /// The simplest pathfinder
+ ///
+ public sealed class BFSPathfinder
+ {
+ ///
+ /// Gets all of the tiles in range that can we access
+ ///
+ /// If you want Dikstra then add distances.
+ /// Doesn't use the JobQueue as it will generally be encapsulated by other jobs
+ ///
+ ///
+ /// Whether we traverse from the starting tile or the end tile
+ ///
+ public static IEnumerable GetNodesInRange(PathfindingArgs pathfindingArgs, bool fromStart = true)
+ {
+ var pathfindingSystem = EntitySystem.Get();
+ // Don't need a priority queue given not looking for shortest path
+ var openTiles = new Queue();
+ var closedTiles = new HashSet();
+ PathfindingNode startNode;
+
+ if (fromStart)
+ {
+ startNode = pathfindingSystem.GetNode(pathfindingArgs.Start);
+ }
+ else
+ {
+ startNode = pathfindingSystem.GetNode(pathfindingArgs.End);
+ }
+
+ PathfindingNode currentNode;
+ openTiles.Enqueue(startNode);
+
+ while (openTiles.Count > 0)
+ {
+ currentNode = openTiles.Dequeue();
+
+ foreach (var neighbor in currentNode.GetNeighbors())
+ {
+ // No distances stored so can just check closed tiles here
+ if (closedTiles.Contains(neighbor.TileRef)) continue;
+ closedTiles.Add(currentNode.TileRef);
+
+ // So currently tileCost gets the octile distance between the 2 so we'll also use that for our range check
+ var tileCost = PathfindingHelpers.GetTileCost(pathfindingArgs, startNode, neighbor);
+ var direction = PathfindingHelpers.RelativeDirection(neighbor, currentNode);
+
+ if (tileCost == null ||
+ tileCost > pathfindingArgs.Proximity ||
+ !PathfindingHelpers.DirectionTraversable(pathfindingArgs.CollisionMask, pathfindingArgs.Access, currentNode, direction))
+ {
+ continue;
+ }
+
+ openTiles.Enqueue(neighbor);
+ yield return neighbor;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingChunk.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingChunk.cs
index 202961dc3f..56c25d4670 100644
--- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingChunk.cs
+++ b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingChunk.cs
@@ -29,9 +29,8 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
_indices = indices;
}
- public void Initialize()
+ public void Initialize(IMapGrid grid)
{
- var grid = IoCManager.Resolve().GetGrid(GridId);
for (var x = 0; x < ChunkSize; x++)
{
for (var y = 0; y < ChunkSize; y++)
@@ -157,12 +156,6 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
return _nodes[chunkX, chunkY];
}
- public void UpdateNode(TileRef tile)
- {
- var node = GetNode(tile);
- node.UpdateTile(tile);
- }
-
private void CreateNode(TileRef tile, PathfindingChunk parent = null)
{
if (parent == null)
diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingHelpers.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingHelpers.cs
index e4c04d5a94..4c5e25390a 100644
--- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingHelpers.cs
+++ b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingHelpers.cs
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
+using Content.Server.GameObjects.Components.Access;
+using Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Accessible;
using Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders;
using Content.Server.GameObjects.EntitySystems.Pathfinding;
using Robust.Shared.Interfaces.GameObjects;
@@ -18,15 +20,10 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
{
if (pathfindingArgs.Proximity > 0.0f)
{
- // TODO: Should make this account for proximities,
- // probably some kind of breadth-first search to find a valid one
- foreach (var node in endNode.GetNeighbors())
+ foreach (var node in BFSPathfinder.GetNodesInRange(pathfindingArgs, false))
{
- if (Traversable(pathfindingArgs.CollisionMask, pathfindingArgs.Access, node))
- {
- endNode = node;
- return true;
- }
+ endNode = node;
+ return true;
}
}
diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingNode.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingNode.cs
index 855bad56e7..57e96fde61 100644
--- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingNode.cs
+++ b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingNode.cs
@@ -98,6 +98,7 @@ namespace Content.Server.GameObjects.EntitySystems.Pathfinding
///
///
/// TODO: These 2 methods currently don't account for a bunch of changes (e.g. airlock unpowered, wrenching, etc.)
+ /// TODO: Could probably optimise this slightly more.
public void AddEntity(IEntity entity)
{
// If we're a door
@@ -128,25 +129,28 @@ namespace Content.Server.GameObjects.EntitySystems.Pathfinding
}
}
+ ///
+ /// Remove the entity from this node.
+ /// Will check each category and remove it from the applicable one
+ ///
+ ///
public void RemoveEntity(IEntity entity)
{
- if (_accessReaders.ContainsKey(entity.Uid))
+ // There's no guarantee that the entity isn't deleted
+ // 90% of updates are probably entities moving around
+ // Entity can't be under multiple categories so just checking each once is fine.
+ if (_physicsUids.Contains(entity.Uid))
+ {
+ _physicsUids.Remove(entity.Uid);
+ }
+ else if (_accessReaders.ContainsKey(entity.Uid))
{
_accessReaders.Remove(entity.Uid);
- return;
- }
-
- if (entity.HasComponent())
+ }
+ else if (_blockedCollidables.ContainsKey(entity.Uid))
{
- if (entity.TryGetComponent(out PhysicsComponent physicsComponent) && physicsComponent.Anchored)
- {
- _blockedCollidables.Remove(entity.Uid);
- GenerateMask();
- }
- else
- {
- _physicsUids.Remove(entity.Uid);
- }
+ _blockedCollidables.Remove(entity.Uid);
+ GenerateMask();
}
}
diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingSystem.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingSystem.cs
index 5a718e01e2..efd558603b 100644
--- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingSystem.cs
+++ b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingSystem.cs
@@ -7,6 +7,7 @@ using Content.Server.GameObjects.EntitySystems.JobQueues;
using Content.Server.GameObjects.EntitySystems.JobQueues.Queues;
using Content.Server.GameObjects.EntitySystems.Pathfinding;
using Content.Shared.Physics;
+using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.GameObjects.Systems;
@@ -40,13 +41,13 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
private readonly PathfindingJobQueue _pathfindingQueue = new PathfindingJobQueue();
// Queued pathfinding graph updates
- private readonly Queue _collidableUpdateQueue = new Queue();
+ private readonly Queue _collidableUpdateQueue = new Queue();
private readonly Queue _moveUpdateQueue = new Queue();
private readonly Queue _accessReaderUpdateQueue = new Queue();
private readonly Queue _tileUpdateQueue = new Queue();
// Need to store previously known entity positions for collidables for when they move
- private readonly Dictionary _lastKnownPositions = new Dictionary();
+ private readonly Dictionary _lastKnownPositions = new Dictionary();
public const int TrackedCollisionLayers = (int)
(CollisionGroup.Impassable |
@@ -88,11 +89,11 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
var entity = _entitymanager.GetEntity(update.Owner);
if (update.CanCollide)
{
- HandleCollidableAdd(entity);
+ HandleEntityAdd(entity);
}
else
{
- HandleAccessRemove(entity);
+ HandleEntityRemove(entity);
}
totalUpdates++;
@@ -105,11 +106,11 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
var entity = _entitymanager.GetEntity(update.Uid);
if (update.Enabled)
{
- HandleAccessAdd(entity);
+ HandleEntityAdd(entity);
}
else
{
- HandleAccessRemove(entity);
+ HandleEntityRemove(entity);
}
totalUpdates++;
@@ -166,15 +167,22 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
private PathfindingChunk CreateChunk(GridId gridId, MapIndices indices)
{
var newChunk = new PathfindingChunk(gridId, indices);
- newChunk.Initialize();
if (!_graph.ContainsKey(gridId))
{
_graph.Add(gridId, new Dictionary());
}
+
_graph[gridId].Add(indices, newChunk);
+ newChunk.Initialize(_mapManager.GetGrid(gridId));
+
return newChunk;
}
+ ///
+ /// Return the corresponding PathfindingNode for this tile
+ ///
+ ///
+ ///
public PathfindingNode GetNode(TileRef tile)
{
var chunk = GetChunk(tile);
@@ -185,9 +193,9 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
public override void Initialize()
{
- SubscribeLocalEvent(QueueCollisionEnabledEvent);
- SubscribeLocalEvent(QueueCollidableMove);
- SubscribeLocalEvent(QueueAccessChangeEvent);
+ SubscribeLocalEvent(QueueCollisionChangeMessage);
+ SubscribeLocalEvent(QueueMoveEvent);
+ SubscribeLocalEvent(QueueAccessChangeMessage);
// Handle all the base grid changes
// Anything that affects traversal (i.e. collision layer) is handled separately.
@@ -199,7 +207,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
public override void Shutdown()
{
base.Shutdown();
- UnsubscribeLocalEvent();
+ UnsubscribeLocalEvent();
UnsubscribeLocalEvent();
UnsubscribeLocalEvent();
@@ -245,14 +253,19 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
_tileUpdateQueue.Enqueue(eventArgs.NewTile);
}
- private void QueueAccessChangeEvent(AccessReaderChangeMessage message)
+ private void QueueAccessChangeMessage(AccessReaderChangeMessage message)
{
_accessReaderUpdateQueue.Enqueue(message);
}
- private void HandleAccessAdd(IEntity entity)
+ ///
+ /// Tries to add the entity to the relevant pathfinding node
+ ///
+ /// The node will filter it to the correct category (if possible)
+ ///
+ private void HandleEntityAdd(IEntity entity)
{
- if (entity.Deleted || !entity.HasComponent())
+ if (entity.Deleted || _lastKnownPositions.ContainsKey(entity.Uid))
{
return;
}
@@ -263,82 +276,34 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
var chunk = GetChunk(tileRef);
var node = chunk.GetNode(tileRef);
node.AddEntity(entity);
+ _lastKnownPositions.Add(entity.Uid, node);
}
- private void HandleAccessRemove(IEntity entity)
+ private void HandleEntityRemove(IEntity entity)
{
- if (entity.Deleted || !entity.HasComponent())
+ if (!_lastKnownPositions.TryGetValue(entity.Uid, out var node))
{
return;
}
-
- var grid = _mapManager.GetGrid(entity.Transform.GridID);
- var tileRef = grid.GetTileRef(entity.Transform.GridPosition);
-
- var chunk = GetChunk(tileRef);
- var node = chunk.GetNode(tileRef);
- node.RemoveEntity(entity);
- }
-
- #region collidable
- ///
- /// If an entity's collision gets turned on then we need to update its current position
- ///
- ///
- private void HandleCollidableAdd(IEntity entity)
- {
- if (entity.Prototype == null ||
- entity.Deleted ||
- _lastKnownPositions.ContainsKey(entity) ||
- !entity.TryGetComponent(out CollidableComponent collidableComponent) ||
- !collidableComponent.CanCollide ||
- (TrackedCollisionLayers & collidableComponent.CollisionLayer) == 0)
- {
- return;
- }
-
- var grid = _mapManager.GetGrid(entity.Transform.GridID);
- var tileRef = grid.GetTileRef(entity.Transform.GridPosition);
- var chunk = GetChunk(tileRef);
- var node = chunk.GetNode(tileRef);
-
- node.AddEntity(entity);
- _lastKnownPositions.Add(entity, tileRef);
- }
-
- ///
- /// If an entity's collision is removed then stop tracking it from the graph
- ///
- ///
- private void HandleCollidableRemove(IEntity entity)
- {
- if (entity.Prototype == null ||
- entity.Deleted ||
- !_lastKnownPositions.ContainsKey(entity) ||
- !entity.TryGetComponent(out CollidableComponent collidableComponent) ||
- !collidableComponent.CanCollide ||
- (TrackedCollisionLayers & collidableComponent.CollisionLayer) == 0)
- {
- return;
- }
-
- var grid = _mapManager.GetGrid(entity.Transform.GridID);
- var tileRef = grid.GetTileRef(entity.Transform.GridPosition);
- var chunk = GetChunk(tileRef);
- var node = chunk.GetNode(tileRef);
node.RemoveEntity(entity);
- _lastKnownPositions.Remove(entity);
+ _lastKnownPositions.Remove(entity.Uid);
}
- private void QueueCollidableMove(MoveEvent moveEvent)
+ private void QueueMoveEvent(MoveEvent moveEvent)
{
_moveUpdateQueue.Enqueue(moveEvent);
}
+ ///
+ /// When an entity moves around we'll remove it from its old node and add it to its new node (if applicable)
+ ///
+ ///
private void HandleCollidableMove(MoveEvent moveEvent)
{
- if (!_lastKnownPositions.ContainsKey(moveEvent.Sender))
+ var entityUid = moveEvent.Sender.Uid;
+
+ if (!_lastKnownPositions.TryGetValue(entityUid, out var oldNode))
{
return;
}
@@ -347,51 +312,28 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
// If you get entities bigger than 1 tile wide you'll need some other system so god help you.
if (moveEvent.Sender.Deleted)
{
- HandleCollidableRemove(moveEvent.Sender);
+ HandleEntityRemove(moveEvent.Sender);
return;
}
-
- _lastKnownPositions.TryGetValue(moveEvent.Sender, out var oldTile);
+
var newTile = _mapManager.GetGrid(moveEvent.NewPosition.GridID).GetTileRef(moveEvent.NewPosition);
- if (oldTile == newTile)
+ if (oldNode == null || oldNode.TileRef == newTile)
{
return;
}
- _lastKnownPositions[moveEvent.Sender] = newTile;
+ var newNode = GetNode(newTile);
+ _lastKnownPositions[entityUid] = newNode;
- if (!moveEvent.Sender.HasComponent())
- {
- HandleCollidableRemove(moveEvent.Sender);
- return;
- }
-
- var gridIds = new HashSet(2) {oldTile.GridIndex, newTile.GridIndex};
-
- foreach (var gridId in gridIds)
- {
- if (oldTile.GridIndex == gridId)
- {
- var oldChunk = GetChunk(oldTile);
- var oldNode = oldChunk.GetNode(oldTile);
- oldNode.RemoveEntity(moveEvent.Sender);
- }
-
- if (newTile.GridIndex == gridId)
- {
- var newChunk = GetChunk(newTile);
- var newNode = newChunk.GetNode(newTile);
- newNode.AddEntity(moveEvent.Sender);
- }
- }
+ oldNode.RemoveEntity(moveEvent.Sender);
+ newNode.AddEntity(moveEvent.Sender);
}
- private void QueueCollisionEnabledEvent(CollisionChangeEvent collisionEvent)
+ private void QueueCollisionChangeMessage(CollisionChangeMessage collisionMessage)
{
- _collidableUpdateQueue.Enqueue(collisionEvent);
+ _collidableUpdateQueue.Enqueue(collisionMessage);
}
- #endregion
// TODO: Need to rethink the pathfinder utils (traversable etc.). Maybe just chuck them all in PathfindingSystem
// Otherwise you get the steerer using this and the pathfinders using a different traversable.
diff --git a/Content.Server/GameObjects/EntitySystems/MoverSystem.cs b/Content.Server/GameObjects/EntitySystems/MoverSystem.cs
index 8b25e4e045..51b6fa4e32 100644
--- a/Content.Server/GameObjects/EntitySystems/MoverSystem.cs
+++ b/Content.Server/GameObjects/EntitySystems/MoverSystem.cs
@@ -1,4 +1,5 @@
-using Content.Server.GameObjects;
+#nullable enable
+using Content.Server.GameObjects;
using Content.Server.GameObjects.Components;
using Content.Server.GameObjects.Components.Items.Storage;
using Content.Server.GameObjects.Components.Mobs;
@@ -24,8 +25,6 @@ using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
-#nullable enable
-
namespace Content.Server.GameObjects.EntitySystems
{
[UsedImplicitly]
diff --git a/Content.Server/Interfaces/Chat/IChatManager.cs b/Content.Server/Interfaces/Chat/IChatManager.cs
index 26af31827a..c3c9b6ceb3 100644
--- a/Content.Server/Interfaces/Chat/IChatManager.cs
+++ b/Content.Server/Interfaces/Chat/IChatManager.cs
@@ -18,6 +18,7 @@ namespace Content.Server.Interfaces.Chat
void EntityMe(IEntity source, string action);
void SendOOC(IPlayerSession player, string message);
+ void SendAdminChat(IPlayerSession player, string message);
void SendDeadChat(IPlayerSession player, string message);
void SendHookOOC(string sender, string message);
diff --git a/Content.Server/Interfaces/IAccess.cs b/Content.Server/Interfaces/IAccess.cs
index f50cae8214..f271990545 100644
--- a/Content.Server/Interfaces/IAccess.cs
+++ b/Content.Server/Interfaces/IAccess.cs
@@ -1,9 +1,8 @@
+#nullable enable
using System;
using Content.Server.GameObjects.Components.Access;
using System.Collections.Generic;
-#nullable enable
-
namespace Content.Server.Interfaces
{
///
diff --git a/Content.Server/ServerContentIoC.cs b/Content.Server/ServerContentIoC.cs
index 5af7382d2c..fba59dfaf0 100644
--- a/Content.Server/ServerContentIoC.cs
+++ b/Content.Server/ServerContentIoC.cs
@@ -1,4 +1,5 @@
-using Content.Server.AI.WorldState;
+using Content.Server.AI.Utility.Considerations;
+using Content.Server.AI.WorldState;
using Content.Server.Cargo;
using Content.Server.Chat;
using Content.Server.GameTicking;
@@ -37,6 +38,7 @@ namespace Content.Server
IoCManager.Register();
IoCManager.Register();
IoCManager.Register();
+ IoCManager.Register();
}
}
}
diff --git a/Content.Shared/Chat/ChatChannel.cs b/Content.Shared/Chat/ChatChannel.cs
index 4c9da79f0b..4b63a75b11 100644
--- a/Content.Shared/Chat/ChatChannel.cs
+++ b/Content.Shared/Chat/ChatChannel.cs
@@ -51,9 +51,14 @@ namespace Content.Shared.Chat
///
Dead = 128,
+ ///
+ /// Admin chat
+ ///
+ AdminChat = 256,
+
///
/// Unspecified.
///
- Unspecified = 256,
+ Unspecified = 512,
}
}
diff --git a/Content.Shared/Chat/MsgChatMessage.cs b/Content.Shared/Chat/MsgChatMessage.cs
index 10e73d881e..049024ccf4 100644
--- a/Content.Shared/Chat/MsgChatMessage.cs
+++ b/Content.Shared/Chat/MsgChatMessage.cs
@@ -41,7 +41,7 @@ namespace Content.Shared.Chat
public override void ReadFromBuffer(NetIncomingMessage buffer)
{
- Channel = (ChatChannel) buffer.ReadByte();
+ Channel = (ChatChannel) buffer.ReadInt16();
Message = buffer.ReadString();
MessageWrap = buffer.ReadString();
@@ -49,6 +49,7 @@ namespace Content.Shared.Chat
{
case ChatChannel.Local:
case ChatChannel.Dead:
+ case ChatChannel.AdminChat:
case ChatChannel.Emotes:
SenderEntity = buffer.ReadEntityUid();
break;
@@ -57,7 +58,7 @@ namespace Content.Shared.Chat
public override void WriteToBuffer(NetOutgoingMessage buffer)
{
- buffer.Write((byte)Channel);
+ buffer.Write((short)Channel);
buffer.Write(Message);
buffer.Write(MessageWrap);
@@ -65,6 +66,7 @@ namespace Content.Shared.Chat
{
case ChatChannel.Local:
case ChatChannel.Dead:
+ case ChatChannel.AdminChat:
case ChatChannel.Emotes:
buffer.Write(SenderEntity);
break;
diff --git a/Content.Shared/GameObjects/Components/Movement/SharedPlayerInputMoverComponent.cs b/Content.Shared/GameObjects/Components/Movement/SharedPlayerInputMoverComponent.cs
index dee6b09b08..e12c56a42e 100644
--- a/Content.Shared/GameObjects/Components/Movement/SharedPlayerInputMoverComponent.cs
+++ b/Content.Shared/GameObjects/Components/Movement/SharedPlayerInputMoverComponent.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable enable
+using System;
using Content.Shared.GameObjects.Components.Mobs;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
@@ -13,8 +14,6 @@ using Robust.Shared.Serialization;
using Robust.Shared.Timing;
using Robust.Shared.ViewVariables;
-#nullable enable
-
namespace Content.Shared.GameObjects.Components.Movement
{
public abstract class SharedPlayerInputMoverComponent : Component, IMoverComponent, ICollideSpecial
@@ -189,11 +188,16 @@ namespace Content.Shared.GameObjects.Components.Movement
_lastInputSubTick = 0;
}
- var fraction = (subTick - _lastInputSubTick) / (float) ushort.MaxValue;
+ if (subTick >= _lastInputSubTick)
+ {
+ var fraction = (subTick - _lastInputSubTick) / (float) ushort.MaxValue;
- ref var lastMoveAmount = ref Sprinting ? ref _curTickSprintMovement : ref _curTickWalkMovement;
+ ref var lastMoveAmount = ref Sprinting ? ref _curTickSprintMovement : ref _curTickWalkMovement;
- lastMoveAmount += DirVecForButtons(_heldMoveButtons) * fraction;
+ lastMoveAmount += DirVecForButtons(_heldMoveButtons) * fraction;
+
+ _lastInputSubTick = subTick;
+ }
if (enabled)
{
@@ -204,8 +208,6 @@ namespace Content.Shared.GameObjects.Components.Movement
_heldMoveButtons &= ~bit;
}
- _lastInputSubTick = subTick;
-
Dirty();
}
diff --git a/Content.Shared/GameObjects/EntitySystems/SharedMoverSystem.cs b/Content.Shared/GameObjects/EntitySystems/SharedMoverSystem.cs
index 931648c5f1..29b65486a1 100644
--- a/Content.Shared/GameObjects/EntitySystems/SharedMoverSystem.cs
+++ b/Content.Shared/GameObjects/EntitySystems/SharedMoverSystem.cs
@@ -1,4 +1,5 @@
-using System.Diagnostics.CodeAnalysis;
+#nullable enable
+using System.Diagnostics.CodeAnalysis;
using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.Physics;
using Robust.Shared.Configuration;
@@ -15,8 +16,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Players;
-#nullable enable
-
namespace Content.Shared.GameObjects.EntitySystems
{
public abstract class SharedMoverSystem : EntitySystem
diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs
index bdbc7cee49..90b5820089 100644
--- a/Content.Shared/Input/ContentKeyFunctions.cs
+++ b/Content.Shared/Input/ContentKeyFunctions.cs
@@ -12,6 +12,7 @@ namespace Content.Shared.Input
public static readonly BoundKeyFunction ExamineEntity = "ExamineEntity";
public static readonly BoundKeyFunction FocusChat = "FocusChatWindow";
public static readonly BoundKeyFunction FocusOOC = "FocusOOCWindow";
+ public static readonly BoundKeyFunction FocusAdminChat = "FocusAdminChatWindow";
public static readonly BoundKeyFunction OpenCharacterMenu = "OpenCharacterMenu";
public static readonly BoundKeyFunction OpenContextMenu = "OpenContextMenu";
public static readonly BoundKeyFunction OpenCraftingMenu = "OpenCraftingMenu";
diff --git a/Resources/Audio/Weapons/flash.ogg b/Resources/Audio/Weapons/flash.ogg
index eed2ed0d52..9305d698b8 100644
Binary files a/Resources/Audio/Weapons/flash.ogg and b/Resources/Audio/Weapons/flash.ogg differ
diff --git a/Resources/Groups/groups.yml b/Resources/Groups/groups.yml
index dc76b17683..30af430579 100644
--- a/Resources/Groups/groups.yml
+++ b/Resources/Groups/groups.yml
@@ -82,6 +82,7 @@
- warp
- hostlogin
- deleteewc
+ - asay
CanViewVar: true
CanAdminPlace: true
@@ -152,6 +153,7 @@
- warp
- deleteewc
- sudo
+ - asay
CanViewVar: true
CanAdminPlace: true
CanScript: true
diff --git a/Resources/Prototypes/Catalog/LatheRecipes/tools.yml b/Resources/Prototypes/Catalog/LatheRecipes/tools.yml
index 87635aeb03..e07bbd3b97 100644
--- a/Resources/Prototypes/Catalog/LatheRecipes/tools.yml
+++ b/Resources/Prototypes/Catalog/LatheRecipes/tools.yml
@@ -10,7 +10,7 @@
id: Screwdriver
icon:
sprite: Objects/Tools/screwdriver.rsi
- state: screwdriver
+ state: screwdriver-map
result: Screwdriver
completetime: 500
materials:
@@ -38,6 +38,7 @@
- type: latheRecipe
id: CableStack
+ name: cable coil
icon: Objects/Tools/cable_coil.png
result: CableStack
completetime: 500
diff --git a/Resources/Prototypes/Construction/structures.yml b/Resources/Prototypes/Construction/structures.yml
index 3245fe7279..7992012921 100644
--- a/Resources/Prototypes/Construction/structures.yml
+++ b/Resources/Prototypes/Construction/structures.yml
@@ -12,7 +12,7 @@
steps:
- material: Metal
amount: 2
- icon: Constructible/Walls/wall_girder.png
+ icon: Constructible/Structures/Walls/wall_girder.png
reverse:
tool: Anchoring
@@ -65,7 +65,7 @@
steps:
- material: Metal
amount: 2
- icon: Constructible/Walls/wall_girder.png
+ icon: Constructible/Structures/Walls/wall_girder.png
reverse:
tool: Anchoring
diff --git a/Resources/Prototypes/Entities/Items/tools.yml b/Resources/Prototypes/Entities/Items/tools.yml
index 12ff44c951..b7be1f5173 100644
--- a/Resources/Prototypes/Entities/Items/tools.yml
+++ b/Resources/Prototypes/Entities/Items/tools.yml
@@ -96,9 +96,12 @@
reagents:
- ReagentId: chem.WeldingFuel
Quantity: 100
-
- type: Welder
useSoundCollection: Welder
+ - type: PointLight
+ enabled: false
+ radius: 1.5
+ color: orange
- type: entity
name: wrench
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
index f1c7228713..ed6b0bdc1c 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
@@ -23,6 +23,7 @@
- type: Icon
sprite: Mobs/Species/xeno.rsi
state: running
+ - type: Clickable
- type: Physics
mass: 85
- type: Collidable
diff --git a/Resources/keybinds.yml b/Resources/keybinds.yml
index 5c2a9da3c3..8a715222da 100644
--- a/Resources/keybinds.yml
+++ b/Resources/keybinds.yml
@@ -46,6 +46,9 @@ binds:
- function: FocusOOCWindow
type: State
key: LBracket
+- function: FocusAdminChatWindow
+ type: State
+ key: RBracket
- function: EditorLinePlace
type: State
key: MouseLeft
diff --git a/RobustToolbox b/RobustToolbox
index afa0eb8ada..d1ee8775f4 160000
--- a/RobustToolbox
+++ b/RobustToolbox
@@ -1 +1 @@
-Subproject commit afa0eb8ada3d81feb8eaa5ebecc5dd91657807d9
+Subproject commit d1ee8775f4293629ba0c1535c1cff45ea57a55c7
diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings
index 961aacf984..5d7127034d 100644
--- a/SpaceStation14.sln.DotSettings
+++ b/SpaceStation14.sln.DotSettings
@@ -1,4 +1,6 @@
+ False
+ False
WARNING
WARNING
WARNING
@@ -46,6 +48,7 @@
<data />
<data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data>
True
+ True
True
True
True