Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Embedded throwables are unembedded when the parent entity is destroyed #32707

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
32 changes: 32 additions & 0 deletions Content.Server/Projectiles/ProjectileSystem.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
using Content.Server.Administration.Logs;
using Content.Server.Body.Components;
using Content.Server.Destructible;
using Content.Server.Effects;
using Content.Server.Nutrition;
using Content.Server.Nutrition.Components;
using Content.Server.Weapons.Ranged.Systems;
using Content.Shared.Body.Components;
Centronias marked this conversation as resolved.
Show resolved Hide resolved
using Content.Shared.Camera;
using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.Destructible;
using Content.Shared.Projectiles;
using Robust.Shared.Physics.Events;
using Robust.Shared.Player;
Expand All @@ -22,6 +28,9 @@ public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ProjectileComponent, StartCollideEvent>(OnStartCollide);
SubscribeLocalEvent<DestructibleComponent, DestructionEventArgs>((embeddee, _, _) => UnEmbedChildren(embeddee));
SubscribeLocalEvent<BodyComponent, BeingGibbedEvent>((embeddee, _, _) => UnEmbedChildren(embeddee));
SubscribeLocalEvent<FoodComponent, BeforeFullyEatenEvent>(OnBeforeFullyEaten);
Centronias marked this conversation as resolved.
Show resolved Hide resolved
}

private void OnStartCollide(EntityUid uid, ProjectileComponent component, ref StartCollideEvent args)
Expand Down Expand Up @@ -77,4 +86,27 @@ private void OnStartCollide(EntityUid uid, ProjectileComponent component, ref St
RaiseNetworkEvent(new ImpactEffectEvent(component.ImpactEffect, GetNetCoordinates(xform.Coordinates)), Filter.Pvs(xform.Coordinates, entityMan: EntityManager));
}
}

// Remove any embedded objects in the food as it's eaten.
private void OnBeforeFullyEaten(EntityUid uid, FoodComponent c, BeforeFullyEatenEvent args)
{
if (args.Cancelled)
{
return;
}

UnEmbedChildren(uid);
}

private void UnEmbedChildren(EntityUid embeddee)
{
var children = Transform(embeddee).ChildEnumerator;
while (children.MoveNext(out var child))
{
if (TryComp<EmbeddableProjectileComponent>(child, out var component))
{
UnEmbed((child, component), null);
}
Centronias marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
76 changes: 46 additions & 30 deletions Content.Shared/Projectiles/SharedProjectileSystem.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using System.Numerics;
using Content.Shared.CombatMode.Pacification;
using Content.Shared.Damage;
using Content.Shared.Destructible;
using Content.Shared.DoAfter;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Mobs.Components;
using Content.Shared.Throwing;
using Microsoft.Extensions.ObjectPool;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Network;
Expand Down Expand Up @@ -34,10 +36,10 @@ public override void Initialize()
base.Initialize();

SubscribeLocalEvent<ProjectileComponent, PreventCollideEvent>(PreventCollision);
SubscribeLocalEvent<EmbeddableProjectileComponent, ProjectileHitEvent>(OnEmbedProjectileHit);
SubscribeLocalEvent<EmbeddableProjectileComponent, ThrowDoHitEvent>(OnEmbedThrowDoHit);
SubscribeLocalEvent<EmbeddableProjectileComponent, ProjectileHitEvent>(OnEmbedProjectileHit, before: [typeof(SharedDestructibleSystem)]);
SubscribeLocalEvent<EmbeddableProjectileComponent, ThrowDoHitEvent>(OnEmbedThrowDoHit, before: [typeof(SharedDestructibleSystem)]);
SubscribeLocalEvent<EmbeddableProjectileComponent, ActivateInWorldEvent>(OnEmbedActivate);
SubscribeLocalEvent<EmbeddableProjectileComponent, RemoveEmbeddedProjectileEvent>(OnEmbedRemove);
SubscribeLocalEvent<EmbeddableProjectileComponent, RemoveEmbeddedProjectileEvent>(OnRemoveEmbeddedProjectileEvent);
}

private void OnEmbedActivate(EntityUid uid, EmbeddableProjectileComponent component, ActivateInWorldEvent args)
Expand All @@ -55,38 +57,13 @@ private void OnEmbedActivate(EntityUid uid, EmbeddableProjectileComponent compon
new RemoveEmbeddedProjectileEvent(), eventTarget: uid, target: uid));
}

private void OnEmbedRemove(EntityUid uid, EmbeddableProjectileComponent component, RemoveEmbeddedProjectileEvent args)
private void OnRemoveEmbeddedProjectileEvent(EntityUid uid, EmbeddableProjectileComponent component, RemoveEmbeddedProjectileEvent args)
{
// Whacky prediction issues.
if (args.Cancelled || _netManager.IsClient)
return;

if (component.DeleteOnRemove)
{
QueueDel(uid);
return;
}

var xform = Transform(uid);
TryComp<PhysicsComponent>(uid, out var physics);
_physics.SetBodyType(uid, BodyType.Dynamic, body: physics, xform: xform);
_transform.AttachToGridOrMap(uid, xform);

// Reset whether the projectile has damaged anything if it successfully was removed
if (TryComp<ProjectileComponent>(uid, out var projectile))
{
projectile.Shooter = null;
projectile.Weapon = null;
projectile.DamagedEntity = false;
}

// Land it just coz uhhh yeah
var landEv = new LandEvent(args.User, true);
RaiseLocalEvent(uid, ref landEv);
_physics.WakeBody(uid, body: physics);

// try place it in the user's hand
_hands.TryPickupAnyHand(args.User, uid);
UnEmbed((uid, component), args.User);
}

private void OnEmbedThrowDoHit(EntityUid uid, EmbeddableProjectileComponent component, ThrowDoHitEvent args)
Expand Down Expand Up @@ -131,6 +108,45 @@ private void Embed(EntityUid uid, EntityUid target, EntityUid? user, EmbeddableP
RaiseLocalEvent(uid, ref ev);
}

/// <summary>
/// Makes the specified entity not be embedded in whatever it's embedded in.
/// </summary>
/// <param name="entity">The entity to make no longer embedded</param>
/// <param name="remover">The entity which is removing the embedded entity. If not null, we'll try to put the
/// embedded object in its hands. If null, there's no specific remover, eg. if the embeddee object is destroyed.</param>
public void UnEmbed(Entity<EmbeddableProjectileComponent> entity, EntityUid? remover)
{
var (uid, component) = entity;

if (component.DeleteOnRemove)
{
QueueDel(uid);
return;
}

var xform = Transform(uid);
TryComp<PhysicsComponent>(uid, out var physics);
_physics.SetBodyType(uid, BodyType.Dynamic, body: physics, xform: xform);
_transform.AttachToGridOrMap(uid, xform);

// Reset whether the projectile has damaged anything if it successfully was removed
if (TryComp<ProjectileComponent>(uid, out var projectile))
{
projectile.Shooter = null;
projectile.Weapon = null;
projectile.DamagedEntity = false;
}

// Land it just coz uhhh yeah
var landEv = new LandEvent(remover, true);
RaiseLocalEvent(uid, ref landEv);
_physics.WakeBody(uid, body: physics);

if (remover is EntityUid user)
// try place it in the user's hand
_hands.TryPickupAnyHand(user, uid);
}

private void PreventCollision(EntityUid uid, ProjectileComponent component, ref PreventCollideEvent args)
{
if (component.IgnoreShooter && (args.OtherEntity == component.Shooter || args.OtherEntity == component.Weapon))
Expand Down
Loading