Fix throwing.

This commit is contained in:
Pieter-Jan Briers
2020-07-02 23:24:27 +02:00
parent 610ab8bf50
commit bc24a852f9
10 changed files with 149 additions and 90 deletions

View File

@@ -0,0 +1,23 @@
using Content.Shared.GameObjects.Components.Projectiles;
using Robust.Shared.GameObjects;
#nullable enable
namespace Content.Client.GameObjects.Components.Projectiles
{
[RegisterComponent]
public class ProjectileComponent : SharedProjectileComponent
{
protected override EntityUid Shooter => _shooter;
private EntityUid _shooter;
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{
if (curState is ProjectileComponentState compState)
{
_shooter = compState.Shooter;
IgnoreShooter = compState.IgnoreShooter;
}
}
}
}

View File

@@ -0,0 +1,12 @@
using Content.Shared.GameObjects;
using Robust.Shared.GameObjects;
namespace Content.Client.GameObjects.Components.Projectiles
{
[RegisterComponent]
public class ThrownItemComponent : ProjectileComponent
{
public override string Name => "ThrownItem";
public override uint? NetID => ContentNetIDs.THROWN_ITEM;
}
}

View File

@@ -31,7 +31,6 @@
"Multitool",
"Wrench",
"Crowbar",
"Projectile",
"MeleeWeapon",
"Storeable",
"Dice",

View File

@@ -1,23 +1,21 @@
using System.Collections.Generic;
using Content.Server.GameObjects.Components.Mobs;
using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Projectiles;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Physics;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Projectiles
{
[RegisterComponent]
public class ProjectileComponent : Component, ICollideSpecial, ICollideBehavior
public class ProjectileComponent : SharedProjectileComponent, ICollideBehavior
{
public override string Name => "Projectile";
public bool IgnoreShooter = true;
protected override EntityUid Shooter => _shooter;
private EntityUid _shooter = EntityUid.Invalid;
@@ -56,18 +54,7 @@ namespace Content.Server.GameObjects.Components.Projectiles
public void IgnoreEntity(IEntity shooter)
{
_shooter = shooter.Uid;
}
/// <summary>
/// Special collision override, can be used to give custom behaviors deciding when to collide
/// </summary>
/// <param name="collidedwith"></param>
/// <returns></returns>
bool ICollideSpecial.PreventCollide(IPhysBody collidedwith)
{
if (IgnoreShooter && collidedwith.Owner.Uid == _shooter)
return true;
return false;
Dirty();
}
/// <summary>
@@ -106,5 +93,10 @@ namespace Content.Server.GameObjects.Components.Projectiles
{
if (collideCount > 0 && DeleteOnCollide) Owner.Delete();
}
public override ComponentState GetComponentState()
{
return new ProjectileComponentState(NetID!.Value, _shooter, IgnoreShooter);
}
}
}

View File

@@ -1,26 +1,27 @@
using System.Collections.Generic;
using Content.Server.GameObjects.Components.Projectiles;
using Content.Server.GameObjects.Components.Projectiles;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects;
using Content.Shared.Physics;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Timers;
namespace Content.Server.GameObjects.Components
{
[RegisterComponent]
internal class ThrownItemComponent : ProjectileComponent, ICollideBehavior
{
#pragma warning disable 649
[Dependency] private readonly IEntitySystemManager _entitySystemManager;
#pragma warning restore 649
public const float DefaultThrowTime = 0.25f;
private bool _shouldCollide = true;
public override string Name => "ThrownItem";
public override uint? NetID => ContentNetIDs.THROWN_ITEM;
/// <summary>
/// User who threw the item.
@@ -34,6 +35,7 @@ namespace Content.Server.GameObjects.Components
{
damage.TakeDamage(DamageType.Brute, 10, Owner, User);
}
// Stop colliding with mobs, this mimics not having enough velocity to do damage
// after impacting the first object.
// For realism this should actually be changed when the velocity of the object is less than a threshold.
@@ -44,20 +46,56 @@ namespace Content.Server.GameObjects.Components
}
}
public void PostCollide(int collideCount)
private void StopThrow()
{
if (collideCount > 0 && Owner.TryGetComponent(out CollidableComponent body) && body.PhysicsShapes.Count >= 1)
if (Owner.TryGetComponent(out CollidableComponent body) && body.PhysicsShapes.Count >= 1)
{
body.PhysicsShapes[0].CollisionMask &= (int)~CollisionGroup.MobImpassable;
body.PhysicsShapes[0].CollisionMask &= (int) ~CollisionGroup.ThrownItem;
// KYS, your job is finished. Trigger ILand as well.
var physics = Owner.GetComponent<PhysicsComponent>();
(physics.Controller as ThrowController).StopThrow();
physics.RemoveController();
physics.LinearVelocity = Vector2.Zero;
physics.Status = BodyStatus.OnGround;
body.Status = BodyStatus.OnGround;
Owner.RemoveComponent<ThrownItemComponent>();
_entitySystemManager.GetEntitySystem<InteractionSystem>().LandInteraction(User, Owner, Owner.Transform.GridPosition);
EntitySystem.Get<InteractionSystem>().LandInteraction(User, Owner, Owner.Transform.GridPosition);
}
}
void ICollideBehavior.PostCollide(int collideCount)
{
if (collideCount > 0)
{
StopThrow();
}
}
public void StartThrow(Vector2 initialImpulse)
{
var comp = Owner.GetComponent<PhysicsComponent>();
comp.Status = BodyStatus.InAir;
comp.Momentum = initialImpulse;
StartStopTimer();
}
private void StartStopTimer()
{
Timer.Spawn((int) (DefaultThrowTime * 1000), MaybeStopThrow);
}
private void MaybeStopThrow()
{
if (Deleted)
{
return;
}
if (IoCManager.Resolve<IPhysicsManager>().IsWeightless(Owner.Transform.GridPosition))
{
StartStopTimer();
return;
}
StopThrow();
}
}
}

View File

@@ -56,7 +56,7 @@ namespace Content.Server.Throw
if (colComp.PhysicsShapes.Count == 0)
colComp.PhysicsShapes.Add(new PhysShapeAabb());
colComp.PhysicsShapes[0].CollisionMask |= (int) (CollisionGroup.MobImpassable | CollisionGroup.Impassable);
colComp.PhysicsShapes[0].CollisionMask |= (int) CollisionGroup.ThrownItem;
colComp.Status = BodyStatus.InAir;
}
var angle = new Angle(targetLoc.ToMapPos(mapManager) - sourceLoc.ToMapPos(mapManager));
@@ -83,8 +83,7 @@ namespace Content.Server.Throw
// scaling is handled elsewhere, this is just multiplying by 60 independent of timing as a fix until elsewhere values are updated
var spd = throwForce * 60;
physComp.SetController<ThrowController>();
(physComp.Controller as ThrowController)?.StartThrow(angle.ToVec() * spd);
projComp.StartThrow(angle.ToVec() * spd);
if (throwSourceEnt != null && throwSourceEnt.TryGetComponent<PhysicsComponent>(out var physics)
&& physics.Controller is MoverController mover)
@@ -135,7 +134,7 @@ namespace Content.Server.Throw
// Calculate the force necessary to land a throw based on throw duration, mass and distance.
var distance = (targetLoc.ToMapPos(mapManager) - sourceLoc.ToMapPos(mapManager)).Length;
var throwDuration = ThrowController.DefaultThrowTime;
var throwDuration = ThrownItemComponent.DefaultThrowTime;
var mass = 1f;
if (thrownEnt.TryGetComponent(out PhysicsComponent physicsComponent))
{

View File

@@ -0,0 +1,45 @@
using System;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Physics;
using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.Components.Projectiles
{
public abstract class SharedProjectileComponent : Component, ICollideSpecial
{
private bool _ignoreShooter = true;
public override string Name => "Projectile";
public override uint? NetID => ContentNetIDs.PROJECTILE;
protected abstract EntityUid Shooter { get; }
public bool IgnoreShooter
{
get => _ignoreShooter;
set
{
_ignoreShooter = value;
Dirty();
}
}
[NetSerializable, Serializable]
protected class ProjectileComponentState : ComponentState
{
public ProjectileComponentState(uint netId, EntityUid shooter, bool ignoreShooter) : base(netId)
{
Shooter = shooter;
IgnoreShooter = ignoreShooter;
}
public EntityUid Shooter { get; }
public bool IgnoreShooter { get; }
}
public bool PreventCollide(IPhysBody collidedwith)
{
return IgnoreShooter && collidedwith.Owner.Uid == Shooter;
}
}
}

View File

@@ -56,6 +56,8 @@
public const uint THIRST = 1050;
public const uint FLASHABLE = 1051;
public const uint PROJECTILE = 1052;
public const uint THROWN_ITEM = 1053;
// Net IDs for integration tests.
public const uint PREDICTION_TEST = 10001;

View File

@@ -24,6 +24,7 @@ namespace Content.Shared.Physics
MapGrid = MapGridHelpers.CollisionGroup, // Map grids, like shuttles. This is the actual grid itself, not the walls or other entities connected to the grid.
MobMask = Impassable | MobImpassable | VaultImpassable | SmallImpassable,
ThrownItem = MobImpassable | Impassable,
// 32 possible groups
AllMask = -1,
}

View File

@@ -1,52 +0,0 @@
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Timers;
namespace Content.Shared.Physics
{
public class ThrowController: VirtualController
{
private float _throwTime;
private PhysicsComponent _component;
public const float DefaultThrowTime = 0.25f;
public float ThrowTime
{
get => _throwTime;
set => _throwTime = value;
}
public override PhysicsComponent ControlledComponent
{
set => _component = value;
}
public void StartThrow(Vector2 initialImpulse)
{
_component.Momentum = initialImpulse;
_component.Status = BodyStatus.InAir;
Timer.Spawn((int) (ThrowTime * 1000), StopThrow);
}
public void StopThrow()
{
if (_component == null || _component.Owner.Deleted) return;
if (IoCManager.Resolve<IPhysicsManager>().IsWeightless(_component.Owner.Transform.GridPosition))
{
Timer.Spawn((int) (ThrowTime * 1000), StopThrow);
return;
}
_component.Status = BodyStatus.OnGround;
_component.LinearVelocity = Vector2.Zero;
}
public ThrowController()
{
ThrowTime = DefaultThrowTime;
}
}
}