diff --git a/Content.Shared/Storage/Components/MaterialReclaimerMagnetPickupComponent.cs b/Content.Shared/Storage/Components/MaterialReclaimerMagnetPickupComponent.cs new file mode 100644 index 00000000000..86c3bb83fb8 --- /dev/null +++ b/Content.Shared/Storage/Components/MaterialReclaimerMagnetPickupComponent.cs @@ -0,0 +1,23 @@ +using Content.Shared.Tag; +using Content.Shared.Whitelist; + +namespace Content.Server.Storage.Components; + +/// +/// Applies an ongoing pickup area around the attached entity. +/// +[RegisterComponent] +public sealed partial class MaterialReclaimerMagnetPickupComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite), DataField("nextScan")] + public TimeSpan NextScan = TimeSpan.Zero; + + [ViewVariables(VVAccess.ReadWrite), DataField("range")] + public float Range = 1f; + + [ViewVariables(VVAccess.ReadWrite), DataField("whitelist")] + public EntityWhitelist? Whitelist; + + [ViewVariables(VVAccess.ReadWrite), DataField("blacklist")] + public EntityWhitelist? Blacklist; +} diff --git a/Content.Shared/Storage/Components/MaterialStorageMagnetPickupComponent.cs b/Content.Shared/Storage/Components/MaterialStorageMagnetPickupComponent.cs new file mode 100644 index 00000000000..e2ced955e8d --- /dev/null +++ b/Content.Shared/Storage/Components/MaterialStorageMagnetPickupComponent.cs @@ -0,0 +1,23 @@ +using Content.Shared.Tag; +using Content.Shared.Whitelist; + +namespace Content.Server.Storage.Components; + +/// +/// Applies an ongoing pickup area around the attached entity. +/// +[RegisterComponent] +public sealed partial class MaterialStorageMagnetPickupComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite), DataField("nextScan")] + public TimeSpan NextScan = TimeSpan.Zero; + + [ViewVariables(VVAccess.ReadWrite), DataField("range")] + public float Range = 1f; + + [ViewVariables(VVAccess.ReadWrite), DataField("whitelist")] + public EntityWhitelist? Whitelist; + + [ViewVariables(VVAccess.ReadWrite), DataField("blacklist")] + public EntityWhitelist? Blacklist; +} diff --git a/Content.Shared/Storage/EntitySystems/MaterialReclaimerMagnetPickupSystem.cs b/Content.Shared/Storage/EntitySystems/MaterialReclaimerMagnetPickupSystem.cs new file mode 100644 index 00000000000..59002fd998a --- /dev/null +++ b/Content.Shared/Storage/EntitySystems/MaterialReclaimerMagnetPickupSystem.cs @@ -0,0 +1,74 @@ +using Content.Server.Storage.Components; +using Content.Shared.Materials; +using Robust.Shared.Physics.Components; +using Robust.Shared.Timing; + +namespace Content.Shared.Storage.EntitySystems; + +/// +/// +/// +public sealed class MaterialReclaimerMagnetPickupSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedMaterialReclaimerSystem _storage = default!; + + private static readonly TimeSpan ScanDelay = TimeSpan.FromSeconds(1); + + private EntityQuery _physicsQuery; + + public override void Initialize() + { + base.Initialize(); + _physicsQuery = GetEntityQuery(); + SubscribeLocalEvent(OnMagnetMapInit); + SubscribeLocalEvent(OnMagnetUnpaused); + } + + private void OnMagnetUnpaused(EntityUid uid, MaterialReclaimerMagnetPickupComponent component, ref EntityUnpausedEvent args) + { + component.NextScan += args.PausedTime; + } + + private void OnMagnetMapInit(EntityUid uid, MaterialReclaimerMagnetPickupComponent component, MapInitEvent args) + { + component.NextScan = _timing.CurTime; + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + var currentTime = _timing.CurTime; + var query = EntityQueryEnumerator(); + + while (query.MoveNext(out var uid, out var comp, out var storage, out var xform)) + { + if (comp.NextScan < currentTime) + continue; + + comp.NextScan += ScanDelay; + + var parentUid = xform.ParentUid; + + foreach (var near in _lookup.GetEntitiesInRange(uid, comp.Range, LookupFlags.Dynamic | LookupFlags.Sundries)) + { + if (comp.Blacklist is { } blacklist && blacklist.IsValid(near, EntityManager) == true) + continue; + + if (comp.Whitelist is { } whitelist && whitelist.IsValid(near, EntityManager) == false) + continue; + + if (!_physicsQuery.TryGetComponent(near, out var physics) || physics.BodyStatus != BodyStatus.OnGround) + continue; + + if (near == parentUid) + continue; + + if (!_storage.TryStartProcessItem(uid, near)) + continue; + } + } + } +} diff --git a/Content.Shared/Storage/EntitySystems/MaterialStorageMagnetPickupSystem.cs b/Content.Shared/Storage/EntitySystems/MaterialStorageMagnetPickupSystem.cs new file mode 100644 index 00000000000..9931592c1eb --- /dev/null +++ b/Content.Shared/Storage/EntitySystems/MaterialStorageMagnetPickupSystem.cs @@ -0,0 +1,74 @@ +using Content.Server.Storage.Components; +using Content.Shared.Materials; +using Robust.Shared.Physics.Components; +using Robust.Shared.Timing; + +namespace Content.Shared.Storage.EntitySystems; + +/// +/// +/// +public sealed class MaterialStorageMagnetPickupSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedMaterialStorageSystem _storage = default!; + + private static readonly TimeSpan ScanDelay = TimeSpan.FromSeconds(1); + + private EntityQuery _physicsQuery; + + public override void Initialize() + { + base.Initialize(); + _physicsQuery = GetEntityQuery(); + SubscribeLocalEvent(OnMagnetMapInit); + SubscribeLocalEvent(OnMagnetUnpaused); + } + + private void OnMagnetUnpaused(EntityUid uid, MaterialStorageMagnetPickupComponent component, ref EntityUnpausedEvent args) + { + component.NextScan += args.PausedTime; + } + + private void OnMagnetMapInit(EntityUid uid, MaterialStorageMagnetPickupComponent component, MapInitEvent args) + { + component.NextScan = _timing.CurTime; + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + var currentTime = _timing.CurTime; + var query = EntityQueryEnumerator(); + + while (query.MoveNext(out var uid, out var comp, out var storage, out var xform)) + { + if (comp.NextScan < currentTime) + continue; + + comp.NextScan += ScanDelay; + + var parentUid = xform.ParentUid; + + foreach (var near in _lookup.GetEntitiesInRange(uid, comp.Range, LookupFlags.Dynamic | LookupFlags.Sundries)) + { + if (comp.Blacklist is { } blacklist && blacklist.IsValid(near, EntityManager) == true) + continue; + + if (comp.Whitelist is { } whitelist && whitelist.IsValid(near, EntityManager) == false) + continue; + + if (!_physicsQuery.TryGetComponent(near, out var physics) || physics.BodyStatus != BodyStatus.OnGround) + continue; + + if (near == parentUid) + continue; + + if (!_storage.TryInsertMaterialEntity(uid, near, uid, storage)) + continue; + } + } + } +} diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index fa72e2f66fe..7f6abe1df9f 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -841,6 +841,11 @@ - IngotGold30 - IngotSilver30 - MaterialBananium10 + - type: MaterialStorageMagnetPickup + range: 0.30 + whitelist: + tags: + - Ore - type: entity parent: BaseLathe diff --git a/Resources/Prototypes/Entities/Structures/Machines/material_reclaimer.yml b/Resources/Prototypes/Entities/Structures/Machines/material_reclaimer.yml index bb8f6d200b7..934ee3c58c2 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/material_reclaimer.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/material_reclaimer.yml @@ -100,3 +100,19 @@ solution: output - type: StaticPrice price: 500 + - type: MaterialReclaimerMagnetPickup + range: 0.30 + whitelist: + components: + - PhysicalComposition + - SpaceGarbage + tags: + - Trash + - Recyclable + blacklist: + components: + - Material + - Pda + - IdCard + tags: + - HighRiskItem