Files
RobustToolbox/Robust.UnitTesting/Shared/Physics/Testbed_Test.cs
T
fefcc7cba3 Physics (#1602)
* Physics worlds

* Paul's a good boy

* Build working

* Ingame and not lagging to hell

* Why didn't you commit ahhhhh

* Hard collisions working

* Solver parity

* Decent broadphase work done

* BroadPhase outline done

* BroadPhase working

* waiting for pvs

* Fix static PVS AABB

* Stop static bodies from awakening

* Optimise a bunch of stuff

* Even more broadphase stuff

* I'm fucking stupid

* Optimise fixture updates

* Collision solver start

* Building

* A is for Argumentative

* Fix contact caching island flags

* Circle shapes actually workeded

* Damping

* DS2 consumables only

* Slightly more stable

* Even slightlier more stablier

* VV your heart out

* Initial joint support

* 90% of joints I just wanted to push as I'd scream if I lost progress

* JOINT PURGATORY

* Joints barely functional lmao

* Okay these joints slightly more functional

* Remove station FrictionJoint

* Also that

* Some Box2D ports

* Cleanup mass

* Edge shape

* Active contacts

* Fix active contacts

* Optimise active contacts even more

* Boxes be stacking

* I would die for smug oh my fucking god

* In which everything is fixed

* Distance joints working LETS GO

* Remove frequency on distancejoint

* Fix some stuff and break joints

* Crashing fixed mehbeh

* ICollideSpecial and more resilience

* auto-clear

* showbb vera

* Slap that TODO in there

* Fix restartround crash

* Random fixes

* Fix fixture networking

* Add intersection method for broadphase

* Fix contacts

* Licenses done

* Optimisations

* Fix wall clips

* Config caching for island

* allocations optimisations

* Optimise casts

* Optimise events queue for physics

* Contact manager optimisations

* Optimise controllers

* Sloth joint or something idk

* Controller graph

* Remove content cvar

* Random cleanup

* Finally remove VirtualController

* Manifold structs again

* Optimise this absolute retardation

* Optimise

* fix license

* Cleanup physics interface

* AHHHHHHHHHHHHH

* Fix collisions again

* snivybus

* Fix potential nasty manifold bug

* Tests go snivy

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-01 03:09:36 +11:00

263 lines
9.8 KiB
C#

/*
MIT License
Copyright (c) 2019 Erin Catto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
These tests are derived from box2d's testbed tests but done in a way as to be automated and useful for CI.
*/
using System.Threading.Tasks;
using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Physics.Dynamics.Shapes;
namespace Robust.UnitTesting.Shared.Physics
{
[TestFixture]
public class Testbed_Test : RobustIntegrationTest
{
[Test]
public async Task TestBoxStack()
{
var server = StartServer();
await server.WaitIdleAsync();
var mapManager = server.ResolveDependency<IMapManager>();
var entitySystemManager = server.ResolveDependency<IEntitySystemManager>();
var physicsSystem = entitySystemManager.GetEntitySystem<SharedPhysicsSystem>();
MapId mapId;
var columnCount = 1;
var rowCount = 15;
PhysicsComponent[] bodies = new PhysicsComponent[columnCount * rowCount];
Vector2 firstPos = Vector2.Zero;
await server.WaitPost(() =>
{
mapId = mapManager.CreateMap();
physicsSystem.Maps[mapId].Gravity = new Vector2(0, -9.8f);
var entityManager = IoCManager.Resolve<IEntityManager>();
// TODO: Need a blank entity we can spawn for testbed.
var ground = entityManager.SpawnEntity("BlankEntity", new MapCoordinates(0, 0, mapId)).AddComponent<PhysicsComponent>();
var horizontal = new EdgeShape(new Vector2(-20, 0), new Vector2(20, 0));
var horizontalFixture = new Fixture(ground, horizontal)
{
CollisionLayer = 1,
CollisionMask = 1,
Hard = true
};
ground.AddFixture(horizontalFixture);
var vertical = new EdgeShape(new Vector2(10, 0), new Vector2(10, 10));
var verticalFixture = new Fixture(ground, vertical)
{
CollisionLayer = 1,
CollisionMask = 1,
Hard = true
};
ground.AddFixture(verticalFixture);
var xs = new[]
{
0.0f, -10.0f, -5.0f, 5.0f, 10.0f
};
PhysShapeAabb shape;
for (var j = 0; j < columnCount; j++)
{
for (var i = 0; i < rowCount; i++)
{
var x = 0.0f;
var box = entityManager.SpawnEntity("BlankEntity",
new MapCoordinates(new Vector2(xs[j] + x, 0.55f + 2.1f * i), mapId)).AddComponent<PhysicsComponent>();
box.BodyType = BodyType.Dynamic;
box.SleepingAllowed = false;
shape = new PhysShapeAabb {LocalBounds = Box2.UnitCentered};
box.FixedRotation = true;
// TODO: Need to detect shape and work out if we need to use fixedrotation
var fixture = new Fixture(box, shape)
{
CollisionMask = 1,
CollisionLayer = 1,
Hard = true,
};
box.AddFixture(fixture);
bodies[j * rowCount + i] = box;
}
}
firstPos = bodies[0].Owner.Transform.WorldPosition;
});
await server.WaitRunTicks(1);
// Check that gravity workin
await server.WaitAssertion(() =>
{
Assert.That(firstPos != bodies[0].Owner.Transform.WorldPosition);
});
// Assert
await server.WaitRunTicks(150);
// Assert settled, none below 0, etc.
await server.WaitAssertion(() =>
{
for (var j = 0; j < columnCount; j++)
{
for (var i = 0; i < bodies.Length; i++)
{
var body = bodies[j * columnCount + i];
var worldPos = body.Owner.Transform.WorldPosition;
// TODO: Multi-column support but I cbf right now
// Can't be more exact as some level of sinking is allowed.
Assert.That(worldPos.EqualsApprox(new Vector2(0.0f, i + 0.5f), 0.1f), $"Expected y-value of {i + 0.5f} but found {worldPos.Y}");
}
}
});
}
[Test]
public async Task TestCircleStack()
{
var server = StartServer();
await server.WaitIdleAsync();
var mapManager = server.ResolveDependency<IMapManager>();
var entitySystemManager = server.ResolveDependency<IEntitySystemManager>();
var physicsSystem = entitySystemManager.GetEntitySystem<SharedPhysicsSystem>();
MapId mapId;
var columnCount = 1;
var rowCount = 15;
PhysicsComponent[] bodies = new PhysicsComponent[columnCount * rowCount];
Vector2 firstPos = Vector2.Zero;
await server.WaitPost(() =>
{
mapId = mapManager.CreateMap();
physicsSystem.Maps[mapId].Gravity = new Vector2(0, -9.8f);
var entityManager = IoCManager.Resolve<IEntityManager>();
// TODO: Need a blank entity we can spawn for testbed.
var ground = entityManager.SpawnEntity("BlankEntity", new MapCoordinates(0, 0, mapId)).AddComponent<PhysicsComponent>();
var horizontal = new EdgeShape(new Vector2(-20, 0), new Vector2(20, 0));
var horizontalFixture = new Fixture(ground, horizontal)
{
CollisionLayer = 1,
CollisionMask = 1,
Hard = true
};
ground.AddFixture(horizontalFixture);
var vertical = new EdgeShape(new Vector2(10, 0), new Vector2(10, 10));
var verticalFixture = new Fixture(ground, vertical)
{
CollisionLayer = 1,
CollisionMask = 1,
Hard = true
};
ground.AddFixture(verticalFixture);
var xs = new[]
{
0.0f, -10.0f, -5.0f, 5.0f, 10.0f
};
PhysShapeCircle shape;
for (var j = 0; j < columnCount; j++)
{
for (var i = 0; i < rowCount; i++)
{
var x = 0.0f;
var circle = entityManager.SpawnEntity("BlankEntity",
new MapCoordinates(new Vector2(xs[j] + x, 0.55f + 2.1f * i), mapId)).AddComponent<PhysicsComponent>();
circle.BodyType = BodyType.Dynamic;
circle.SleepingAllowed = false;
shape = new PhysShapeCircle {Radius = 0.5f};
var fixture = new Fixture(circle, shape)
{
CollisionMask = 1,
CollisionLayer = 1,
Hard = true,
};
circle.AddFixture(fixture);
bodies[j * rowCount + i] = circle;
}
}
firstPos = bodies[0].Owner.Transform.WorldPosition;
});
await server.WaitRunTicks(1);
// Check that gravity workin
await server.WaitAssertion(() =>
{
Assert.That(firstPos != bodies[0].Owner.Transform.WorldPosition);
});
// Assert
await server.WaitRunTicks(150);
// Assert settled, none below 0, etc.
await server.WaitAssertion(() =>
{
for (var j = 0; j < columnCount; j++)
{
for (var i = 0; i < bodies.Length; i++)
{
var body = bodies[j * columnCount + i];
var worldPos = body.Owner.Transform.WorldPosition;
// TODO: Multi-column support but I cbf right now
// Can't be more exact as some level of sinking is allowed.
Assert.That(worldPos.EqualsApprox(new Vector2(0.0f, i + 0.5f), 0.1f), $"Expected y-value of {i + 0.5f} but found {worldPos.Y}");
}
}
});
}
}
}