Files
wwdpublic/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/PickNearbyFillableItemOperator.cs
Timfa 4c7ae415a4 Fillbot (#1958)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->

# Description

<!--
Explain this PR in as much detail as applicable

Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->

The humble fillbot! Takes items from the ground and inserts them into a
lathe, silo or disposal unit it's linked to!

---

# TODO

<!--
A list of everything you have to do before this PR is "complete"
You probably won't have to complete everything before merging but it's
good to leave future references
-->

- [x] Make the robot pick up items
- [x] Make the robot insert items
- [x] Make the robot differentiate between trash inputs
- [ ] Make the robot only linkable to the correct ports

---

<!--
This is default collapsed, readers click to expand it and see all your
media
The PR media section can get very large at times, so this is a good way
to keep it clean
The title is written using HTML tags
The title must be within the <summary> tags or you won't see it
-->

<details><summary><h1>Media</h1></summary>
<p>

https://github.com/user-attachments/assets/f0cd26c0-36fb-43e2-8bdb-c100f033668b

https://github.com/user-attachments/assets/3809b033-01a6-4b4f-96e0-f4730dd2e92d

https://github.com/user-attachments/assets/ccf325f3-ee60-42f8-9e68-75fafe596a7b

</p>
</details>

---

# Changelog

<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->

🆑
- add: Added Fillbot. Link it to a lathe, material silo, ore processor
or disposal unit with a multitool and watch it gather stuff!

---------

Signed-off-by: Timfa <timfalken@hotmail.com>
Co-authored-by: VMSolidus <evilexecutive@gmail.com>
Co-authored-by: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com>
(cherry picked from commit a71192bdf05a3b7a40323bb16983c25be432bfc4)
2025-03-21 18:28:52 +03:00

108 lines
4.3 KiB
C#

using System.Threading;
using System.Threading.Tasks;
using Content.Server.Disposal.Unit.Components;
using Content.Server.NPC.Pathfinding;
using Content.Shared.Body.Part;
using Content.Shared.DeviceLinking;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Materials;
using Content.Shared.Silicons.Bots;
using Content.Shared.Tag;
using Content.Shared.Whitelist;
using Robust.Shared.Prototypes;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific;
public sealed partial class PickNearbyFillableItemOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
private SharedMaterialStorageSystem _sharedMaterialStorage = default!;
private EntityLookupSystem _lookup = default!;
private PathfindingSystem _pathfinding = default!;
private SharedHandsSystem _sharedHandsSystem = default!;
private TagSystem _tagSystem = default!;
[DataField] public string RangeKey = NPCBlackboard.FillbotPickupRange;
/// Target entity to pick up
[DataField(required: true)]
public string TargetKey = string.Empty;
/// Target entitycoordinates to move to.
[DataField(required: true)]
public string TargetMoveKey = string.Empty;
/// Target tag prototype to look for when trying to find trash.
[DataField]
public ProtoId<TagPrototype> TrashProto = "Trash";
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_lookup = sysManager.GetEntitySystem<EntityLookupSystem>();
_pathfinding = sysManager.GetEntitySystem<PathfindingSystem>();
_sharedMaterialStorage = sysManager.GetEntitySystem<SharedMaterialStorageSystem>();
_sharedHandsSystem = sysManager.GetEntitySystem<SharedHandsSystem>();
_tagSystem = sysManager.GetEntitySystem<TagSystem>();
}
public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
if (!blackboard.TryGetValue<float>(RangeKey, out var range, _entManager)
|| !_entManager.TryGetComponent<FillbotComponent>(owner, out var fillbot)
|| !_entManager.TryGetComponent<DeviceLinkSourceComponent>(owner, out var fillbotlinks)
|| fillbotlinks.LinkedPorts.Count != 1
|| fillbot.LinkedSinkEntity == null)
return (false, null);
_entManager.TryGetComponent(fillbot.LinkedSinkEntity, out MaterialStorageComponent? linkedStorage);
_entManager.TryGetComponent(fillbot.LinkedSinkEntity, out DisposalUnitComponent? disposalUnit);
foreach (var target in _lookup.GetEntitiesInRange(owner, range))
{
// only things the robot can actually pick up
if (!_sharedHandsSystem.CanPickupAnyHand(owner, target))
continue;
// only things not currently contained by something else
if (_entManager.TryGetComponent<MetaDataComponent>(target, out var meta) &&
meta.Flags.HasFlag(MetaDataFlags.InContainer))
continue;
// only things that can go inside
if (linkedStorage != null && !_sharedMaterialStorage.CanInsertMaterialEntity(target, fillbot.LinkedSinkEntity!.Value))
continue;
// trash only
if (disposalUnit != null &&
(_whitelistSystem.IsWhitelistFail(disposalUnit.Whitelist, target)
|| !_tagSystem.HasTag(target, TrashProto)
|| _entManager.HasComponent<BodyPartComponent>(target))) // Robot is unable to insert bodyparts into Disposals for some reason
continue;
const float pathRange = SharedInteractionSystem.InteractionRange - 1;
var path = await _pathfinding.GetPath(owner, target, pathRange, cancelToken);
if (path.Result == PathResult.NoPath)
continue;
return (true, new()
{
{TargetKey, target},
{TargetMoveKey, _entManager.GetComponent<TransformComponent>(target).Coordinates},
{NPCBlackboard.PathfindKey, path},
});
}
return (false, null);
}
}