Cleanbot tweaks (#15821)

This commit is contained in:
metalgearsloth
2023-05-02 00:30:15 +10:00
committed by GitHub
parent 65d42352a5
commit 638009f5d3
8 changed files with 209 additions and 42 deletions

View File

@@ -31,6 +31,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
base.Initialize();
SubscribeLocalEvent<AbsorbentComponent, ComponentInit>(OnAbsorbentInit);
SubscribeLocalEvent<AbsorbentComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<AbsorbentComponent, InteractNoHandEvent>(OnInteractNoHand);
SubscribeLocalEvent<AbsorbentComponent, SolutionChangedEvent>(OnAbsorbentSolutionChange);
}
@@ -79,31 +80,38 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
Dirty(component);
}
private void OnAfterInteract(EntityUid uid, AbsorbentComponent component, AfterInteractEvent args)
private void OnInteractNoHand(EntityUid uid, AbsorbentComponent component, InteractNoHandEvent args)
{
if (!args.CanReach || args.Handled || _useDelay.ActiveDelay(uid))
if (args.Handled || args.Target == null)
return;
if (!_solutionSystem.TryGetSolution(args.Used, AbsorbentComponent.SolutionName, out var absorberSoln))
return;
// Didn't click anything so don't do anything.
if (args.Target is not { Valid: true } target)
{
return;
Mop(uid, args.Target.Value, uid, component);
args.Handled = true;
}
private void OnAfterInteract(EntityUid uid, AbsorbentComponent component, AfterInteractEvent args)
{
if (!args.CanReach || args.Handled || args.Target == null)
return;
Mop(args.User, args.Target.Value, args.Used, component);
args.Handled = true;
}
private void Mop(EntityUid user, EntityUid target, EntityUid used, AbsorbentComponent component)
{
if (!_solutionSystem.TryGetSolution(used, AbsorbentComponent.SolutionName, out var absorberSoln))
return;
// If it's a puddle try to grab from
if (!TryPuddleInteract(args.User, uid, target, component, absorberSoln))
if (!TryPuddleInteract(user, used, target, component, absorberSoln))
{
// Do a transfer, try to get water onto us and transfer anything else to them.
// If it's anything else transfer to
if (!TryTransferAbsorber(args.User, uid, target, component, absorberSoln))
if (!TryTransferAbsorber(user, used, target, component, absorberSoln))
return;
}
args.Handled = true;
}
/// <summary>

View File

@@ -0,0 +1,106 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Fluids.EntitySystems;
using Content.Server.NPC.Pathfinding;
using Content.Shared.Fluids.Components;
using Robust.Shared.Map;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Fluid;
/// <summary>
/// Picks a nearby evaporatable puddle.
/// </summary>
public sealed class PickPuddleOperator : HTNOperator
{
// This is similar to PickAccessibleComponent however I have an idea on generic utility queries
// that can also be re-used for melee that needs further fleshing out.
[Dependency] private readonly IComponentFactory _factory = default!;
[Dependency] private readonly IEntityManager _entManager = default!;
private PathfindingSystem _pathfinding = default!;
private EntityLookupSystem _lookup = default!;
[DataField("rangeKey", required: true)]
public string RangeKey = string.Empty;
[DataField("target")] public string Target = "Target";
[DataField("targetKey", required: true)]
public string TargetKey = string.Empty;
/// <summary>
/// Where the pathfinding result will be stored (if applicable). This gets removed after execution.
/// </summary>
[DataField("pathfindKey")]
public string PathfindKey = NPCBlackboard.PathfindKey;
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_lookup = sysManager.GetEntitySystem<EntityLookupSystem>();
_pathfinding = sysManager.GetEntitySystem<PathfindingSystem>();
}
/// <inheritdoc/>
[Obsolete("Obsolete")]
public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
var range = blackboard.GetValueOrDefault<float>(RangeKey, _entManager);
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
if (!blackboard.TryGetValue<EntityCoordinates>(NPCBlackboard.OwnerCoordinates, out var coordinates, _entManager))
{
return (false, null);
}
var targets = new List<EntityUid>();
var puddleSystem = _entManager.System<PuddleSystem>();
var solSystem = _entManager.System<SolutionContainerSystem>();
foreach (var comp in _lookup.GetComponentsInRange<PuddleComponent>(coordinates, range))
{
if (comp.Owner == owner ||
!solSystem.TryGetSolution(comp.Owner, comp.SolutionName, out var puddleSolution) ||
puddleSystem.CanFullyEvaporate(puddleSolution))
{
continue;
}
targets.Add((comp.Owner));
}
if (targets.Count == 0)
{
return (false, null);
}
foreach (var target in targets)
{
var path = await _pathfinding.GetPath(
owner,
target,
1f,
cancelToken,
flags: _pathfinding.GetFlags(blackboard));
if (path.Result != PathResult.Path)
{
return (false, null);
}
var xform = _entManager.GetComponent<TransformComponent>(target);
return (true, new Dictionary<string, object>()
{
{ Target, target },
{ TargetKey, xform.Coordinates },
{ PathfindKey, path}
});
}
return (false, null);
}
}

View File

@@ -0,0 +1,31 @@
using Content.Server.Interaction;
using Content.Shared.Timing;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
public sealed class InteractWithOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
/// <summary>
/// Key that contains the target entity.
/// </summary>
[DataField("targetKey", required: true)]
public string TargetKey = default!;
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
if (_entManager.System<UseDelaySystem>().ActiveDelay(owner) ||
!blackboard.TryGetValue<EntityUid>(TargetKey, out var moveTarget, _entManager) ||
!_entManager.TryGetComponent<TransformComponent>(moveTarget, out var targetXform))
{
return HTNOperatorStatus.Continuing;
}
_entManager.System<InteractionSystem>().UserInteraction(owner, targetXform.Coordinates, moveTarget);
return HTNOperatorStatus.Finished;
}
}

View File

@@ -22,6 +22,9 @@ public sealed class PickAccessibleComponentOperator : HTNOperator
[DataField("targetKey", required: true)]
public string TargetKey = string.Empty;
[DataField("target")]
public string TargetEntity = "Target";
[DataField("component", required: true)]
public string Component = string.Empty;
@@ -58,7 +61,7 @@ public sealed class PickAccessibleComponentOperator : HTNOperator
var compType = registration.Type;
var query = _entManager.GetEntityQuery(compType);
var targets = new List<Component>();
var targets = new List<EntityUid>();
// TODO: Need to get ones that are accessible.
// TODO: Look at unreal HTN to see repeatable ones maybe?
@@ -68,7 +71,7 @@ public sealed class PickAccessibleComponentOperator : HTNOperator
if (entity == owner || !query.TryGetComponent(entity, out var comp))
continue;
targets.Add(comp);
targets.Add(entity);
}
if (targets.Count == 0)
@@ -76,16 +79,12 @@ public sealed class PickAccessibleComponentOperator : HTNOperator
return (false, null);
}
blackboard.TryGetValue<float>(RangeKey, out var maxRange, _entManager);
if (maxRange == 0f)
maxRange = 7f;
while (targets.Count > 0)
foreach (var target in targets)
{
var path = await _pathfinding.GetRandomPath(
var path = await _pathfinding.GetPath(
owner,
maxRange,
target,
1f,
cancelToken,
flags: _pathfinding.GetFlags(blackboard));
@@ -94,11 +93,12 @@ public sealed class PickAccessibleComponentOperator : HTNOperator
return (false, null);
}
var target = path.Path.Last().Coordinates;
var xform = _entManager.GetComponent<TransformComponent>(target);
return (true, new Dictionary<string, object>()
{
{ TargetKey, target },
{ TargetEntity, target },
{ TargetKey, xform.Coordinates },
{ PathfindKey, path }
});
}

View File

@@ -1,7 +1,9 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using Content.Server.Interaction;
using Content.Shared.Access.Systems;
using Content.Shared.ActionBlocker;
using Content.Shared.Interaction;
using Robust.Shared.Utility;
namespace Content.Server.NPC;
@@ -18,6 +20,7 @@ public sealed class NPCBlackboard : IEnumerable<KeyValuePair<string, object>>
{"FollowCloseRange", 3f},
{"FollowRange", 7f},
{"IdleRange", 7f},
{"InteractRange", SharedInteractionSystem.InteractionRange},
{"MaximumIdleTime", 7f},
{MedibotInjectRange, 4f},
{MeleeMissChance, 0.3f},

View File

@@ -194,18 +194,30 @@
drawdepth: Mobs
sprite: Mobs/Silicon/Bots/cleanbot.rsi
state: cleanbot
- type: Drain
range: 1
unitsDestroyedPerSecond: 6
- type: Construction
graph: CleanBot
node: bot
- type: SentienceTarget
flavorKind: station-event-random-sentience-flavor-mechanical
- type: Absorbent
pickupAmount: 10
- type: UseDelay
delay: 2
- type: SolutionRegeneration
solution: absorbed
generated:
reagents:
- ReagentId: Water
Quantity: 10
- type: SolutionPurge
solution: absorbed
preserve:
- Water
quantity: 10
- type: SolutionContainerManager
solutions:
drainBuffer:
maxVol: 30
absorbed:
maxVol: 50
- type: MovementSpeedModifier
baseWalkSpeed: 2
baseSprintSpeed: 3

View File

@@ -13,13 +13,11 @@
- tasks:
- id: PickPuddlePrimitive
- id: MoveToAccessiblePrimitive
- id: SetIdleTimePrimitive
- id: WaitIdleTimePrimitive
- id: InteractWithPrimitive
- type: htnPrimitive
id: PickPuddlePrimitive
operator: !type:PickAccessibleComponentOperator
operator: !type:PickPuddleOperator
rangeKey: BufferRange
targetKey: MovementTarget
component: Puddle

View File

@@ -32,14 +32,18 @@
# Primitives
- type: htnPrimitive
id: PickRandomRotationPrimitive
operator: !type:PickRandomRotationOperator
targetKey: RotateTarget
id: InteractWithPrimitive
preconditions:
- !type:TargetInRangePrecondition
targetKey: Target
rangeKey: InteractRange
operator: !type:InteractWithOperator
targetKey: Target
- type: htnPrimitive
id: RotateToTargetPrimitive
operator: !type:RotateToTargetOperator
targetKey: RotateTarget
id: MoveToAccessiblePrimitive
operator: !type:MoveToOperator
pathfindInPlanning: false
- type: htnPrimitive
id: PickAccessiblePrimitive
@@ -48,9 +52,14 @@
targetKey: MovementTarget
- type: htnPrimitive
id: MoveToAccessiblePrimitive
operator: !type:MoveToOperator
pathfindInPlanning: false
id: PickRandomRotationPrimitive
operator: !type:PickRandomRotationOperator
targetKey: RotateTarget
- type: htnPrimitive
id: RotateToTargetPrimitive
operator: !type:RotateToTargetOperator
targetKey: RotateTarget
- type: htnPrimitive
id: RandomIdleTimePrimitive