Added new HTN operations and preconditions (#27486)

* Added new HTN operations & preconditions

* Ok I forgot about partial

* Namespace pierce the skies

* Some fixes, debug and new operators

* Bruh git eat my files
This commit is contained in:
Tornado Tech
2024-05-08 19:18:03 +10:00
committed by GitHub
parent 29860a0cf7
commit 31491775e5
14 changed files with 401 additions and 8 deletions

View File

@@ -35,7 +35,7 @@ public sealed partial class GunAmmoPrecondition : HTNPrecondition
else
percent = ammoEv.Count / (float) ammoEv.Capacity;
percent = Math.Clamp(percent, 0f, 1f);
percent = System.Math.Clamp(percent, 0f, 1f);
if (MaxPercent < percent)
return false;

View File

@@ -0,0 +1,12 @@
namespace Content.Server.NPC.HTN.Preconditions;
public sealed partial class KeyNotExistsPrecondition : HTNPrecondition
{
[DataField(required: true)]
public string Key = string.Empty;
public override bool IsMet(NPCBlackboard blackboard)
{
return !blackboard.ContainsKey(Key);
}
}

View File

@@ -0,0 +1,23 @@
namespace Content.Server.NPC.HTN.Preconditions.Math;
/// <summary>
/// Checks for the presence of data in the blackboard and makes a comparison with the specified boolean
/// </summary>
public sealed partial class KeyBoolEqualsPrecondition : HTNPrecondition
{
[Dependency] private readonly IEntityManager _entManager = default!;
[DataField(required: true)]
public string Key = string.Empty;
[DataField(required: true)]
public bool Value;
public override bool IsMet(NPCBlackboard blackboard)
{
if (!blackboard.TryGetValue<bool>(Key, out var value, _entManager))
return false;
return Value == value;
}
}

View File

@@ -0,0 +1,18 @@
namespace Content.Server.NPC.HTN.Preconditions.Math;
public sealed partial class KeyFloatEqualsPrecondition : HTNPrecondition
{
[Dependency] private readonly IEntityManager _entManager = default!;
[DataField(required: true)]
public string Key = string.Empty;
[DataField(required: true)]
public float Value;
public override bool IsMet(NPCBlackboard blackboard)
{
return blackboard.TryGetValue<float>(Key, out var value, _entManager) &&
MathHelper.CloseTo(value, value);
}
}

View File

@@ -0,0 +1,17 @@
namespace Content.Server.NPC.HTN.Preconditions.Math;
public sealed partial class KeyFloatGreaterPrecondition : HTNPrecondition
{
[Dependency] private readonly IEntityManager _entManager = default!;
[DataField(required: true)]
public string Key = string.Empty;
[DataField(required: true)]
public float Value;
public override bool IsMet(NPCBlackboard blackboard)
{
return blackboard.TryGetValue<float>(Key, out var value, _entManager) && value > Value;
}
}

View File

@@ -0,0 +1,17 @@
namespace Content.Server.NPC.HTN.Preconditions.Math;
public sealed partial class KeyFloatLessPrecondition : HTNPrecondition
{
[Dependency] private readonly IEntityManager _entManager = default!;
[DataField(required: true)]
public string Key = string.Empty;
[DataField(required: true)]
public float Value;
public override bool IsMet(NPCBlackboard blackboard)
{
return blackboard.TryGetValue<float>(Key, out var value, _entManager) && value < Value;
}
}

View File

@@ -0,0 +1,33 @@
using System.Threading;
using System.Threading.Tasks;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Math;
/// <summary>
/// Gets the key, and adds the value to that float
/// </summary>
public sealed partial class AddFloatOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
[DataField(required: true)]
public string TargetKey = string.Empty;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float Amount;
public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
if (!blackboard.TryGetValue<float>(TargetKey, out var value, _entManager))
return (false, null);
return (
true,
new Dictionary<string, object>
{
{ TargetKey, value + Amount }
}
);
}
}

View File

@@ -0,0 +1,28 @@
using System.Threading;
using System.Threading.Tasks;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Math;
/// <summary>
/// Just sets a blackboard key to a bool
/// </summary>
public sealed partial class SetBoolOperator : HTNOperator
{
[DataField(required: true)]
public string TargetKey = string.Empty;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public bool Value;
public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
return (
true,
new Dictionary<string, object>
{
{ TargetKey, Value }
}
);
}
}

View File

@@ -1,24 +1,28 @@
using System.Threading;
using System.Threading.Tasks;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Math;
/// <summary>
/// Just sets a blackboard key to a float
/// </summary>
public sealed partial class SetFloatOperator : HTNOperator
{
[DataField("targetKey", required: true)] public string TargetKey = string.Empty;
[DataField(required: true)]
public string TargetKey = string.Empty;
[ViewVariables(VVAccess.ReadWrite), DataField("amount")]
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float Amount;
public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
return (true, new Dictionary<string, object>()
{
{TargetKey, Amount},
});
return (
true,
new Dictionary<string, object>
{
{ TargetKey, Amount }
}
);
}
}

View File

@@ -0,0 +1,34 @@
using System.Threading;
using System.Threading.Tasks;
using Robust.Shared.Random;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Math;
/// <summary>
/// Sets a random float from MinAmount to MaxAmount to blackboard
/// </summary>
public sealed partial class SetRandomFloatOperator : HTNOperator
{
[Dependency] private readonly IRobustRandom _random = default!;
[DataField(required: true)]
public string TargetKey = string.Empty;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float MaxAmount = 1f;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float MinAmount = 0f;
public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
return (
true,
new Dictionary<string, object>
{
{ TargetKey, _random.NextFloat(MinAmount, MaxAmount) }
}
);
}
}

View File

@@ -0,0 +1,28 @@
using Robust.Server.Audio;
using Robust.Shared.Audio;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
public sealed partial class PlaySoundOperator : HTNOperator
{
private AudioSystem _audio = default!;
[DataField(required: true)]
public SoundSpecifier? Sound;
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_audio = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
}
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
var uid = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
_audio.PlayPvs(Sound, uid);
return base.Update(blackboard, frameTime);
}
}

View File

@@ -0,0 +1,36 @@
using Content.Server.Chat.Systems;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
public sealed partial class SayKeyOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
private ChatSystem _chat = default!;
[DataField(required: true)]
public string Key = string.Empty;
/// <summary>
/// Whether to hide message from chat window and logs.
/// </summary>
[DataField]
public bool Hidden;
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_chat = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<ChatSystem>();
}
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
if (!blackboard.TryGetValue<object>(Key, out var value, _entManager))
return HTNOperatorStatus.Failed;
var speaker = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
_chat.TrySendInGameICMessage(speaker, value.ToString() ?? "Oh no...", InGameICChatType.Speak, hideChat: Hidden, hideLog: Hidden);
return base.Update(blackboard, frameTime);
}
}

View File

@@ -0,0 +1,53 @@
- type: entity
parent: MobHuman
id: MobDebugCounter
name: debug counter
description: He can count
suffix: AI, DEBUG
components:
- type: HTN
rootTask:
task: DebugCounterCompound
blackboard:
MinimumIdleTime: !type:Single
0.5
MaximumIdleTime: !type:Single
0.5
Count: !type:Single
0
- type: entity
parent: MobHuman
id: MobDebugRandomCounter
name: debug random counter
description: He can randomize
suffix: AI, DEBUG
components:
- type: HTN
rootTask:
task: DebugRandomCounterCompound
blackboard:
MinimumIdleTime: !type:Single
1
MaximumIdleTime: !type:Single
1
Count: !type:Single
0
- type: entity
parent: MobHuman
id: MobDebugRandomLess
name: debug random less
description: He can lessing
suffix: AI, DEBUG
components:
- type: HTN
rootTask:
task: DebugRandomLessCompound
blackboard:
MinimumIdleTime: !type:Single
1
MaximumIdleTime: !type:Single
1
Count: !type:Single
0

View File

@@ -0,0 +1,90 @@
- type: htnCompound
id: DebugCounterCompound
branches:
- tasks:
- !type:HTNPrimitiveTask
operator: !type:AddFloatOperator
targetKey: Count
amount: 1
- !type:HTNPrimitiveTask
operator: !type:SayKeyOperator
key: Count
- !type:HTNPrimitiveTask
operator: !type:RandomOperator
targetKey: IdleTime
minKey: MinimumIdleTime
maxKey: MaximumIdleTime
- !type:HTNPrimitiveTask
operator: !type:WaitOperator
key: IdleTime
preconditions:
- !type:KeyExistsPrecondition
key: IdleTime
- type: htnCompound
id: DebugRandomCounterCompound
branches:
- tasks:
- !type:HTNPrimitiveTask
operator: !type:SetRandomFloatOperator
targetKey: Count
minAmount: 0
maxAmount: 100
- !type:HTNPrimitiveTask
operator: !type:SayKeyOperator
key: Count
- !type:HTNPrimitiveTask
operator: !type:RandomOperator
targetKey: IdleTime
minKey: MinimumIdleTime
maxKey: MaximumIdleTime
- !type:HTNPrimitiveTask
operator: !type:WaitOperator
key: IdleTime
preconditions:
- !type:KeyExistsPrecondition
key: IdleTime
- type: htnCompound
id: DebugRandomLessCompound
branches:
- tasks:
- !type:HTNPrimitiveTask
operator: !type:SetRandomFloatOperator
targetKey: Count
minAmount: 0
maxAmount: 100
- !type:HTNPrimitiveTask
operator: !type:SayKeyOperator
key: Count
preconditions:
- !type:KeyFloatLessPrecondition
key: Count
value: 50
- !type:HTNPrimitiveTask
operator: !type:RandomOperator
targetKey: IdleTime
minKey: MinimumIdleTime
maxKey: MaximumIdleTime
- !type:HTNPrimitiveTask
operator: !type:WaitOperator
key: IdleTime
preconditions:
- !type:KeyExistsPrecondition
key: IdleTime
- tasks:
- !type:HTNPrimitiveTask
operator: !type:SpeakOperator
speech: "fuck!"