Data-driven NPC behaviors (#3271)

* Data-driven NPC behaviors

* Nuked AiLogicProcessor
* BehaviorSets are now all stored in yaml (might try making actions also yaml someday)
* Added a test to validate all BehaviorSets
* Might also try pooling actions in the future to reduce allocs but that'll be way down the line (cough physics).

* Forgot to re-add sorting nothing suss

* Remove last references

* Proper vector2i serialization for tile atmos (#3266)

* update map files

* update submodule

Co-authored-by: cyclowns <cyclowns@protonmail.ch>

* Remove weird "S" jumpsuit from existence (#3267)

* Change character names to use datasets prototypes (#3259)

* Remove old name lists in .txts

* Fix tests

* LATEST MASTER TECHNOLOGY

* Converts AdminMenu to partially use XAML (#3231)

* Cleans up Hydroponics content. (#3025)

* Adds to IgnoredComponents.cs

* Jackboots

* Half Done

* Moved to diff PR

* Everything functional

* Fixed Sprays

* Nice

* Fixed

* Update submodule

* Fix tests

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>

* Stacked sprite visualizer (#3096)

* Add Stack Visualizer

* Add cigarette pack resources

Adds transparent layers for visualizing cigarettes

* Add Bag Open/Close Visualizer

So storage opened in inventory can have different icons when opened
or closed.

* Create a component that only enumerates single item

Used for creating stuff like matchbox, or cigarettes. As a bonus.
It will only update stack visualizer for that particullar item.

* Refactoring stuff

* Fix other usage of stack in Resources

* Add docs

* Apply suggestions from code review

Apply metalgearsloth suggestions

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* Applied suggestions from metalgearsloth

* Changed SingleItemStorageComponent to StorageCounterComponent

Difference. New component doesn't spawn items, merely counts them.

* Refactored StackVisualizer

* Fix breakage with master

* Update Resources/Prototypes/Entities/Objects/Consumable/fancy.yml

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* Update with MGS suggestions

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* ApcNet updating fix (#3078)

* GridPowerComponent

* ApcNet Powered update bugfix

* PowerTest fix

* Add GridPower to Saltern

* test fix

* Update canceling cleanup

* code cleanup

* nullable & code cleanup for test

* undo power test nullable

* Replaces GridPowerSystem with ApcNetSystem

* build fix

* Update Content.Server/GameObjects/EntitySystems/ApcNetSystem.cs

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* Change all XAML to use spacestation14.io namespace (#3277)

* fix pizzaboxes (#3291)

Co-authored-by: cyclowns <cyclowns@protonmail.ch>

* Spikes fix reopened (#3203)

* DoAfter, dead and stun check, DragDropOn

* Not ignored anymore

* Copied comment deleted

* Herbert's an ass

* Woops

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>

* Make component states dependant on the player getting them (#3280)

* Make component states dependant on the player getting them

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>

* Updated submodule to v0.3.7.

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
Co-authored-by: Acruid <shatter66@gmail.com>

* Hoe fix (#3296)

* Initial (#3297)

* Sort reagent dispenser entries (#3272)

* Sort reagent dispenser entries

Saves manually doing it.

* zumzum's suggestion

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>

* Made firelocks damageable & destructible (#3303)

* Move job priority enum parity test ot unit tests (#3300)

* Spill hand contents when dropping them in a fall (#3304)

* Spill hand contents when dropping them due to falling down

* Better approach

* cleanup

* grammar

* stupid

* PauseManager moved to Shared (#3288)

* Namespace changes for moving IPauseManager to shared.

* Namespace changes for moving ITimerManager from Timers to Timing.

* Rebase Fixes.

* Update engine submodule to v0.3.8

* Improves kick, teleport and ban menus (#3312)

* Fix the admin panel not showing the account name (#3322)

* Fix name serialization for secret stashes (#3301)

* Fix name serialization for secret stashes

* Fix old usages of secret part name

* Separate ghost warp message into two (#3310)

* Separate ghost warp message into two

* Remove redundant arguments

* Address reviews

* Move properties up

* Add health overlay and a command to toggle it (#3278)

* Add health overlay bar and a command to toggle it

* Remove empty line

* Content PR for YAML hot reloading (#3319)

* Content PR for YAML hot reloading

* Add CanAdminReloadPrototypes (host permission)

* IndexedPrototype fixes

* Update RobustToolbox

* Update RobustToolbox

* Add an unconspicuous, meaningless and in no way motivated by any external force XML doc to buckle component

* Update RobustToolbox

* Update submodule to v0.3.12.

* Removed unused using statements that prevented compiling.
Removed references to IIndexedPrototype that does not exist anymore in the engine.

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
Co-authored-by: mirrorcult <notzombiedude@gmail.com>
Co-authored-by: cyclowns <cyclowns@protonmail.ch>
Co-authored-by: Visne <39844191+Visne@users.noreply.github.com>
Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
Co-authored-by: Leo <lzimann@users.noreply.github.com>
Co-authored-by: Swept <sweptwastaken@protonmail.com>
Co-authored-by: Ygg01 <y.laughing.man.y@gmail.com>
Co-authored-by: collinlunn <60152240+collinlunn@users.noreply.github.com>
Co-authored-by: komunre <49118681+komunre@users.noreply.github.com>
Co-authored-by: Acruid <shatter66@gmail.com>
Co-authored-by: Peptide90 <78795277+Peptide90@users.noreply.github.com>
Co-authored-by: Clyybber <darkmine956@gmail.com>
This commit is contained in:
metalgearsloth
2021-02-20 17:37:17 +11:00
committed by GitHub
parent 6f72f8f553
commit 4437fc7a1b
74 changed files with 548 additions and 707 deletions

View File

@@ -3,23 +3,28 @@ using System.Collections.Generic;
using System.Threading;
using Content.Server.AI.Operators;
using Content.Server.AI.Utility.Actions;
using Content.Server.AI.Utility.BehaviorSets;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Utility;
using Content.Server.GameObjects.Components.Movement;
using Content.Server.GameObjects.EntitySystems.AI;
using Content.Server.GameObjects.EntitySystems.AI.LoadBalancer;
using Content.Server.GameObjects.EntitySystems.JobQueues;
using Content.Shared.GameObjects.Components.Mobs.State;
using Robust.Server.AI;
using Content.Shared.GameObjects.Components.Movement;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Utility;
using Robust.Shared.Serialization;
namespace Content.Server.AI.Utility.AiLogic
{
public abstract class UtilityAi : AiLogicProcessor
// TODO: Need to split out the IMover stuff for NPC to a generic one that can be used for hoomans as well.
[RegisterComponent]
[ComponentReference(typeof(AiControllerComponent)), ComponentReference(typeof(IMoverComponent))]
internal sealed class UtilityAi : AiControllerComponent
{
public override string Name => "UtilityAI";
// TODO: Look at having ParallelOperators (probably no more than that as then you'd have a full-blown BT)
// Also RepeatOperators (e.g. if we're following an entity keep repeating MoveToEntity)
private AiActionSystem _planner;
@@ -27,10 +32,11 @@ namespace Content.Server.AI.Utility.AiLogic
private Blackboard _blackboard;
/// <summary>
/// The sum of all BehaviorSets gives us what actions the AI can take
/// The sum of all BehaviorSets gives us what actions the AI can take
/// </summary>
public Dictionary<Type, BehaviorSet> BehaviorSets { get; } = new();
private readonly List<IAiUtility> _availableActions = new();
public HashSet<string> BehaviorSets { get; } = new();
public List<IAiUtility> AvailableActions { get; set; } = new();
/// <summary>
/// The currently running action; most importantly are the operators.
@@ -52,86 +58,39 @@ namespace Content.Server.AI.Utility.AiLogic
private CancellationTokenSource _actionCancellation;
/// <summary>
/// If we can't do anything then stop thinking; should probably use ActionBlocker instead
/// If we can't do anything then stop thinking; should probably use ActionBlocker instead
/// </summary>
private bool _isDead = false;
private bool _isDead;
// These 2 methods will be used eventually if / when we get a director AI
public void AddBehaviorSet<T>(T behaviorSet, bool sort = true) where T : BehaviorSet
public override void ExposeData(ObjectSerializer serializer)
{
if (BehaviorSets.TryAdd(typeof(T), behaviorSet) && sort)
{
SortActions();
}
base.ExposeData(serializer);
var bSets = serializer.ReadDataField("behaviorSets", new List<string>());
if (BehaviorSets.Count == 1 && !EntitySystem.Get<AiSystem>().IsAwake(this))
if (bSets.Count > 0)
{
IoCManager.Resolve<IEntityManager>()
.EventBus
.RaiseEvent(EventSource.Local, new SleepAiMessage(this, false));
}
}
var behaviorManager = IoCManager.Resolve<INpcBehaviorManager>();
public void RemoveBehaviorSet(Type behaviorSet)
{
DebugTools.Assert(behaviorSet.IsAssignableFrom(typeof(BehaviorSet)));
if (BehaviorSets.ContainsKey(behaviorSet))
{
BehaviorSets.Remove(behaviorSet);
SortActions();
}
if (BehaviorSets.Count == 0)
{
IoCManager.Resolve<IEntityManager>()
.EventBus
.RaiseEvent(EventSource.Local, new SleepAiMessage(this, true));
}
}
/// <summary>
/// Whenever the behavior sets are changed we'll re-sort the actions by bonus
/// </summary>
protected void SortActions()
{
_availableActions.Clear();
foreach (var set in BehaviorSets.Values)
{
foreach (var action in set.Actions)
foreach (var bSet in bSets)
{
var found = false;
for (var i = 0; i < _availableActions.Count; i++)
{
if (_availableActions[i].Bonus < action.Bonus)
{
_availableActions.Insert(i, action);
found = true;
break;
}
}
if (!found)
{
_availableActions.Add(action);
}
behaviorManager.AddBehaviorSet(this, bSet, false);
}
behaviorManager.RebuildActions(this);
}
_availableActions.Reverse();
}
public override void Setup()
public override void Initialize()
{
base.Setup();
base.Initialize();
_planCooldownRemaining = PlanCooldown;
_blackboard = new Blackboard(SelfEntity);
_planner = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AiActionSystem>();
_blackboard = new Blackboard(Owner);
_planner = EntitySystem.Get<AiActionSystem>();
}
public override void Shutdown()
public override void OnRemove()
{
base.OnRemove();
var currentOp = CurrentAction?.ActionOperators.Peek();
currentOp?.Shutdown(Outcome.Failed);
CurrentAction?.Shutdown();
@@ -190,6 +149,8 @@ namespace Content.Server.AI.Utility.AiLogic
public override void Update(float frameTime)
{
base.Update(frameTime);
// If we asked for a new action we don't want to dump the existing one.
if (_actionRequest != null)
{
@@ -210,7 +171,7 @@ namespace Content.Server.AI.Utility.AiLogic
{
_planCooldownRemaining = PlanCooldown;
_actionCancellation = new CancellationTokenSource();
_actionRequest = _planner.RequestAction(new AiActionRequest(SelfEntity.Uid, _blackboard, _availableActions), _actionCancellation);
_actionRequest = _planner.RequestAction(new AiActionRequest(Owner.Uid, _blackboard, AvailableActions), _actionCancellation);
return;
}