108 lines
4.5 KiB
C#
108 lines
4.5 KiB
C#
#nullable enable
|
|
using Content.Server.Ghost.Components;
|
|
using Content.Server.Singularity.Components;
|
|
using Robust.Server.GameObjects;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Maths;
|
|
using Robust.Shared.Physics;
|
|
using Robust.Shared.Physics.Broadphase;
|
|
using Robust.Shared.Physics.Controllers;
|
|
using Robust.Shared.Random;
|
|
|
|
namespace Content.Server.Physics.Controllers
|
|
{
|
|
internal sealed class SingularityController : VirtualController
|
|
{
|
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
|
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
|
|
|
private float _pullAccumulator;
|
|
private float _moveAccumulator;
|
|
|
|
public override void UpdateBeforeSolve(bool prediction, float frameTime)
|
|
{
|
|
base.UpdateBeforeSolve(prediction, frameTime);
|
|
|
|
_moveAccumulator += frameTime;
|
|
_pullAccumulator += frameTime;
|
|
|
|
while (_pullAccumulator > 0.5f)
|
|
{
|
|
_pullAccumulator -= 0.5f;
|
|
|
|
foreach (var singularity in ComponentManager.EntityQuery<ServerSingularityComponent>())
|
|
{
|
|
// TODO: Use colliders instead probably yada yada
|
|
PullEntities(singularity);
|
|
// Yeah look the collision with station wasn't working and I'm 15k lines in and not debugging this shit
|
|
DestroyTiles(singularity);
|
|
}
|
|
}
|
|
|
|
while (_moveAccumulator > 1.0f)
|
|
{
|
|
_moveAccumulator -= 1.0f;
|
|
|
|
foreach (var (singularity, physics) in ComponentManager.EntityQuery<ServerSingularityComponent, PhysicsComponent>())
|
|
{
|
|
if (singularity.Owner.HasComponent<ActorComponent>()) continue;
|
|
|
|
// TODO: Need to essentially use a push vector in a random direction for us PLUS
|
|
// Any entity colliding with our larger circlebox needs to have an impulse applied to itself.
|
|
physics.BodyStatus = BodyStatus.InAir;
|
|
MoveSingulo(singularity, physics);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void MoveSingulo(ServerSingularityComponent singularity, PhysicsComponent physics)
|
|
{
|
|
// To prevent getting stuck, ServerSingularityComponent will zero the velocity of a singularity when it goes to a level <= 1 (see here).
|
|
if (singularity.Level <= 1) return;
|
|
// TODO: Could try gradual changes instead but for now just try to replicate
|
|
|
|
var pushVector = new Vector2(_robustRandom.Next(-10, 10), _robustRandom.Next(-10, 10));
|
|
|
|
if (pushVector == Vector2.Zero) return;
|
|
|
|
physics.LinearVelocity = Vector2.Zero;
|
|
physics.LinearVelocity = pushVector.Normalized * 2;
|
|
}
|
|
|
|
private void PullEntities(ServerSingularityComponent component)
|
|
{
|
|
var singularityCoords = component.Owner.Transform.Coordinates;
|
|
// TODO: Maybe if we have named fixtures needs to pull out the outer circle collider (inner will be for deleting).
|
|
var entitiesToPull = IoCManager.Resolve<IEntityLookup>().GetEntitiesInRange(singularityCoords, component.Level * 10);
|
|
foreach (var entity in entitiesToPull)
|
|
{
|
|
if (!entity.TryGetComponent<PhysicsComponent>(out var collidableComponent) || collidableComponent.BodyType == BodyType.Static) continue;
|
|
if (entity.HasComponent<GhostComponent>()) continue;
|
|
if (singularityCoords.EntityId != entity.Transform.Coordinates.EntityId) continue;
|
|
var vec = (singularityCoords - entity.Transform.Coordinates).Position;
|
|
if (vec == Vector2.Zero) continue;
|
|
|
|
var speed = 10 / vec.Length * component.Level;
|
|
|
|
collidableComponent.ApplyLinearImpulse(vec.Normalized * speed);
|
|
}
|
|
}
|
|
|
|
private void DestroyTiles(ServerSingularityComponent component)
|
|
{
|
|
if (!component.Owner.TryGetComponent(out PhysicsComponent? physicsComponent)) return;
|
|
var worldBox = physicsComponent.GetWorldAABB();
|
|
|
|
foreach (var grid in _mapManager.FindGridsIntersecting(component.Owner.Transform.MapID, worldBox))
|
|
{
|
|
foreach (var tile in grid.GetTilesIntersecting(worldBox))
|
|
{
|
|
grid.SetTile(tile.GridIndices, Tile.Empty);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|