* ECS up disposals Also significantly reduced its CPU usage. * Make update significantly less S L O W * Start units pressurised * Client-side flush lerping * Fix powered not toggling UI * Fix flush button * InteractUsing * Minor optimisations * Fix collisions * Make visual state ECS * Almost done with shared * Most stuff moved * Optimise item sleeping
164 lines
5.8 KiB
C#
164 lines
5.8 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Content.Shared.Physics;
|
|
using Content.Shared.Physics.Pull;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.Log;
|
|
using Robust.Shared.Physics;
|
|
using Robust.Shared.Physics.Dynamics;
|
|
|
|
namespace Content.Shared.Throwing
|
|
{
|
|
/// <summary>
|
|
/// Handles throwing landing and collisions.
|
|
/// </summary>
|
|
public class ThrownItemSystem : EntitySystem
|
|
{
|
|
private List<IThrowCollide> _throwCollide = new();
|
|
|
|
private const string ThrowingFixture = "throw-fixture";
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
SubscribeLocalEvent<ThrownItemComponent, PhysicsSleepMessage>(HandleSleep);
|
|
SubscribeLocalEvent<ThrownItemComponent, StartCollideEvent>(HandleCollision);
|
|
SubscribeLocalEvent<ThrownItemComponent, PreventCollideEvent>(PreventCollision);
|
|
SubscribeLocalEvent<ThrownItemComponent, ThrownEvent>(ThrowItem);
|
|
SubscribeLocalEvent<ThrownItemComponent, LandEvent>(LandItem);
|
|
SubscribeLocalEvent<PullStartedMessage>(HandlePullStarted);
|
|
}
|
|
|
|
private void LandItem(EntityUid uid, ThrownItemComponent component, LandEvent args)
|
|
{
|
|
if (!component.Owner.TryGetComponent(out PhysicsComponent? physicsComponent)) return;
|
|
|
|
var fixture = physicsComponent.GetFixture(ThrowingFixture);
|
|
if (fixture == null)
|
|
{
|
|
Logger.Error($"Tried to remove throwing fixture for {component.Owner} but none found?");
|
|
return;
|
|
}
|
|
|
|
Get<SharedBroadphaseSystem>().DestroyFixture(physicsComponent, fixture);
|
|
}
|
|
|
|
private void ThrowItem(EntityUid uid, ThrownItemComponent component, ThrownEvent args)
|
|
{
|
|
if (!component.Owner.TryGetComponent(out PhysicsComponent? physicsComponent) ||
|
|
physicsComponent.Fixtures.Count != 1) return;
|
|
|
|
if (physicsComponent.GetFixture(ThrowingFixture) != null)
|
|
{
|
|
Logger.Error($"Found existing throwing fixture on {component.Owner}");
|
|
return;
|
|
}
|
|
|
|
var shape = physicsComponent.Fixtures[0].Shape;
|
|
Get<SharedBroadphaseSystem>().CreateFixture(physicsComponent, new Fixture(physicsComponent, shape) {CollisionLayer = (int) CollisionGroup.ThrownItem, Hard = false, ID = ThrowingFixture});
|
|
}
|
|
|
|
private void HandleCollision(EntityUid uid, ThrownItemComponent component, StartCollideEvent args)
|
|
{
|
|
var thrower = component.Thrower;
|
|
var otherBody = args.OtherFixture.Body;
|
|
|
|
if (otherBody.Owner == thrower) return;
|
|
ThrowCollideInteraction(thrower, args.OurFixture.Body, otherBody);
|
|
}
|
|
|
|
private void PreventCollision(EntityUid uid, ThrownItemComponent component, PreventCollideEvent args)
|
|
{
|
|
if (args.BodyB.Owner == component.Thrower)
|
|
{
|
|
args.Cancel();
|
|
}
|
|
}
|
|
|
|
private void HandleSleep(EntityUid uid, ThrownItemComponent thrownItem, PhysicsSleepMessage message)
|
|
{
|
|
LandComponent(thrownItem);
|
|
}
|
|
|
|
private void HandlePullStarted(PullStartedMessage message)
|
|
{
|
|
// TODO: this isn't directed so things have to be done the bad way
|
|
if (message.Pulled.Owner.TryGetComponent(out ThrownItemComponent? thrownItem))
|
|
LandComponent(thrownItem);
|
|
}
|
|
|
|
private void LandComponent(ThrownItemComponent thrownItem)
|
|
{
|
|
if (thrownItem.Owner.Deleted) return;
|
|
|
|
var user = thrownItem.Thrower;
|
|
var landing = thrownItem.Owner;
|
|
var coordinates = landing.Transform.Coordinates;
|
|
|
|
// LandInteraction
|
|
// TODO: Refactor these to system messages
|
|
var landMsg = new LandEvent(user, landing, coordinates);
|
|
RaiseLocalEvent(landing.Uid, landMsg);
|
|
if (landMsg.Handled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var comps = landing.GetAllComponents<ILand>().ToArray();
|
|
var landArgs = new LandEventArgs(user, coordinates);
|
|
|
|
// Call Land on all components that implement the interface
|
|
foreach (var comp in comps)
|
|
{
|
|
if (landing.Deleted) break;
|
|
comp.Land(landArgs);
|
|
}
|
|
|
|
ComponentManager.RemoveComponent(landing.Uid, thrownItem);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calls ThrowCollide on all components that implement the IThrowCollide interface
|
|
/// on a thrown entity and the target entity it hit.
|
|
/// </summary>
|
|
public void ThrowCollideInteraction(IEntity? user, IPhysBody thrown, IPhysBody target)
|
|
{
|
|
// TODO: Just pass in the bodies directly
|
|
var collideMsg = new ThrowCollideEvent(user, thrown.Owner, target.Owner);
|
|
RaiseLocalEvent(target.Owner.Uid, collideMsg);
|
|
if (collideMsg.Handled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var eventArgs = new ThrowCollideEventArgs(user, thrown.Owner, target.Owner);
|
|
|
|
foreach (var comp in target.Owner.GetAllComponents<IThrowCollide>())
|
|
{
|
|
_throwCollide.Add(comp);
|
|
}
|
|
|
|
foreach (var collide in _throwCollide)
|
|
{
|
|
if (target.Owner.Deleted) break;
|
|
collide.HitBy(eventArgs);
|
|
}
|
|
|
|
_throwCollide.Clear();
|
|
|
|
foreach (var comp in thrown.Owner.GetAllComponents<IThrowCollide>())
|
|
{
|
|
_throwCollide.Add(comp);
|
|
}
|
|
|
|
foreach (var collide in _throwCollide)
|
|
{
|
|
if (thrown.Owner.Deleted) break;
|
|
collide.DoHit(eventArgs);
|
|
}
|
|
|
|
_throwCollide.Clear();
|
|
}
|
|
}
|
|
}
|