A complete reference to the SharedPhysicsSystem public API in Space Station 14: all method families, overloads, limitations, rare methods and practical examples of use on the server and client. Use it when you need to accurately select the PhysicsSystem method and not break contacts/collisions/prediction.
This skill is the public API directory SharedPhysicsSystem :)
For the general architecture, first read SS14 Physics System Core.
RegenerateContacts is needed.Initialize()Shutdown()Step(float frameTime, bool prediction)SetGravity(Vector2 value)UpdateIsPredicted(EntityUid? uid, PhysicsComponent? physics = null) (virtual)Public runtime fields/state:
GravityAwakeBodiesEffectiveCurTime (substep-aware time)When to use:
Initialize/Shutdown/Step directly.SetGravity and UpdateIsPredicted-flow are useful.ApplyAngularImpulse(EntityUid uid, float impulse, FixturesComponent? manager = null, PhysicsComponent? body = null)ApplyForce(EntityUid uid, Vector2 force, Vector2 point, FixturesComponent? manager = null, PhysicsComponent? body = null)ApplyForce(EntityUid uid, Vector2 force, FixturesComponent? manager = null, PhysicsComponent? body = null)ApplyTorque(EntityUid uid, float torque, FixturesComponent? manager = null, PhysicsComponent? body = null)ApplyLinearImpulse(EntityUid uid, Vector2 impulse, FixturesComponent? manager = null, PhysicsComponent? body = null)ApplyLinearImpulse(EntityUid uid, Vector2 impulse, Vector2 point, FixturesComponent? manager = null, PhysicsComponent? body = null)Nuance:
DestroyContacts(PhysicsComponent body)DestroyContact(Contact contact)ResetDynamics(EntityUid uid, PhysicsComponent body, bool dirty = true)ResetMassData(EntityUid uid, FixturesComponent? manager = null, PhysicsComponent? body = null)SetAngularVelocity(EntityUid uid, float value, bool dirty = true, FixturesComponent? manager = null, PhysicsComponent? body = null)SetLinearVelocity(EntityUid uid, Vector2 velocity, bool dirty = true, bool wakeBody = true, FixturesComponent? manager = null, PhysicsComponent? body = null)SetAngularDamping(EntityUid uid, PhysicsComponent body, float value, bool dirty = true)SetLinearDamping(EntityUid uid, PhysicsComponent body, float value, bool dirty = true)SetFriction(EntityUid uid, PhysicsComponent body, float value, bool dirty = true)SetInertia(EntityUid uid, PhysicsComponent body, float value, bool dirty = true)SetLocalCenter(EntityUid uid, PhysicsComponent body, Vector2 value)[Obsolete] SetAwake(EntityUid uid, PhysicsComponent body, bool value, bool updateSleepTime = true)SetAwake(Entity<PhysicsComponent> ent, bool value, bool updateSleepTime = true)SetSleepingAllowed(EntityUid uid, PhysicsComponent body, bool value, bool dirty = true)SetSleepTime(PhysicsComponent body, float value)WakeBody(EntityUid uid, bool force = false, FixturesComponent? manager = null, PhysicsComponent? body = null)TrySetBodyType(EntityUid uid, BodyType value, FixturesComponent? manager = null, PhysicsComponent? body = null, TransformComponent? xform = null)SetBodyType(EntityUid uid, BodyType value, FixturesComponent? manager = null, PhysicsComponent? body = null, TransformComponent? xform = null)SetBodyStatus(EntityUid uid, PhysicsComponent body, BodyStatus status, bool dirty = true)SetCanCollide(EntityUid uid, bool value, bool dirty = true, bool force = false, FixturesComponent? manager = null, PhysicsComponent? body = null)SetFixedRotation(EntityUid uid, bool value, bool dirty = true, FixturesComponent? manager = null, PhysicsComponent? body = null)Critical:
BodyType affects the solver.BodyStatus is a game status flag, not a replacement for BodyType ⚠️GetLinearVelocity(EntityUid uid, Vector2 point, PhysicsComponent? component = null, TransformComponent? xform = null)GetMapLinearVelocity(EntityCoordinates coordinates)GetMapLinearVelocity(EntityUid uid, PhysicsComponent? component = null, TransformComponent? xform = null)GetMapAngularVelocity(EntityUid uid, PhysicsComponent? component = null, TransformComponent? xform = null)GetMapVelocities(EntityUid uid, PhysicsComponent? component = null, TransformComponent? xform = null)When to use:
SetDensity(EntityUid uid, string fixtureId, Fixture fixture, float value, bool update = true, FixturesComponent? manager = null)SetFriction(EntityUid uid, string fixtureId, Fixture fixture, float value, bool update = true, FixturesComponent? manager = null)SetHard(EntityUid uid, Fixture fixture, bool value, FixturesComponent? manager = null)SetRestitution(EntityUid uid, Fixture fixture, float value, bool update = true, FixturesComponent? manager = null)ScaleFixtures(Entity<FixturesComponent?> ent, float factor)IsCurrentlyHardCollidable(Entity<FixturesComponent?, PhysicsComponent?> bodyA, Entity<FixturesComponent?, PhysicsComponent?> bodyB)IsHardCollidable(Entity<FixturesComponent?, PhysicsComponent?> bodyA, Entity<FixturesComponent?, PhysicsComponent?> bodyB)AddCollisionMask(EntityUid uid, string fixtureId, Fixture fixture, int mask, FixturesComponent? manager = null, PhysicsComponent? body = null)SetCollisionMask(EntityUid uid, string fixtureId, Fixture fixture, int mask, FixturesComponent? manager = null, PhysicsComponent? body = null)RemoveCollisionMask(EntityUid uid, string fixtureId, Fixture fixture, int mask, FixturesComponent? manager = null, PhysicsComponent? body = null)AddCollisionLayer(EntityUid uid, string fixtureId, Fixture fixture, int layer, FixturesComponent? manager = null, PhysicsComponent? body = null)SetCollisionLayer(EntityUid uid, string fixtureId, Fixture fixture, int layer, FixturesComponent? manager = null, PhysicsComponent? body = null)RemoveCollisionLayer(EntityUid uid, string fixtureId, Fixture fixture, int layer, FixturesComponent? manager = null, PhysicsComponent? body = null)Practice:
RegenerateContacts is often needed.Two fixtures are considered to be in contact if at least one condition is met:
(A.mask & B.layer) != 0(B.mask & A.layer) != 0That is, this is not strict two-way filtering, but the logic “at least one side wants contact.”
// Basic contact check of a pair of fixtures.
var shouldCollide =
(fixtureA.CollisionMask & fixtureB.CollisionLayer) != 0 ||
(fixtureB.CollisionMask & fixtureA.CollisionLayer) != 0;
Important:
shouldCollide is responsible for contact in broadphase/narrowphase.Hard = true on both sides.✓ - the layer will be caught by this mask, · - it will not.
| layer \ mask | Opaque | Impassable | MidImpassable | HighImpassable | LowImpassable | GhostImpassable | BulletImpassable | InteractImpassable | DoorPassable |
|---|---|---|---|---|---|---|---|---|---|
| Opaque | ✓ | · | · | · | · | · | · | · | · |
| Impassable | · | ✓ | · | · | · | · | · | · | · |
| MidImpassable | · | · | ✓ | · | · | · | · | · | · |
| HighImpassable | · | · | · | ✓ | · | · | · | · | · |
| LowImpassable | · | · | · | · | ✓ | · | · | · | · |
| GhostImpassable | · | · | · | · | · | ✓ | · | · | · |
| BulletImpassable | · | · | · | · | · | · | ✓ | · | · |
| InteractImpassable | · | · | · | · | · | · | · | ✓ | · |
| DoorPassable | · | · | · | · | · | · | · | · | ✓ |
The Who to grant to column describes a practical intent (a typical content profile), and not a hard and fast rule.
| Group | Use as | Composition | To whom to issue |
|---|---|---|---|
None | layer/mask | 0 | temporarily disabled filter, service cases |
Opaque | layer | base bit | objects that block light/part of the rays |
Impassable | layer/mask bit | base bit | full-fledged obstacles on the ground |
MidImpassable | layer/mask bit | base bit | "medium height": mobs, racks, some furniture |
HighImpassable | layer/mask bit | base bit | top of obstacles (tables, high blockers) |
LowImpassable | layer/mask bit | base bit | low obstacles important for small/under-table logic |
GhostImpassable | layer/mask bit | base bit | Ghost/Watcher Blockers |
BulletImpassable | layer/mask bit | base bit | everything that should stop bullets |
InteractImpassable | layer/mask bit | base bit | lock InRangeUnobstructed/interaction |
DoorPassable | layer/mask bit | base bit | special "door-passable" surfaces |
MapGrid | layer | map/grid specialbit | grid system layer |
AllMask | mask | -1 | rare force cases (almost always redundant) |
SingularityLayer | layer+mask | Opaque+Impassable+Mid+High+Low+Bullet+Interact+DoorPassable | singularity/similar "all-consuming" entities |
MobMask | mask | Impassable+High+Mid+Low | humanoids/regular ground mobs |
MobLayer | layer | Opaque+BulletImpassable | base layer of normal mobs |
SmallMobMask | mask | Impassable+Low | small mobs (mice, etc.) |
SmallMobLayer | layer | Opaque+BulletImpassable | small mobs layer |
FlyingMobMask | mask | Impassable+High | small flying entities |
FlyingMobLayer | layer | Opaque+BulletImpassable | flying mobs layer |
LargeMobMask | mask | Impassable+High+Mid+Low | large entities/vehicles/mechs |
LargeMobLayer | layer | Opaque+High+Mid+Low+BulletImpassable | large objects that "take up" more height |
MachineMask | mask | Impassable+Mid+Low | large machines/stationary structures |
MachineLayer | layer | Opaque+Mid+Low+BulletImpassable | machines, automatic machines, frames |
ConveyorMask | layer or mask in place | Impassable+Mid+Low+DoorPassable | conveyors and door compatibility |
CrateMask | mask | Impassable+High+Low | containers/cages that require "low traffic" under flaps |
TableMask | mask | Impassable+Mid | tables/surfaces with which other tables must interact |
TableLayer | layer | MidImpassable | tables, railings, part of narrow barriers |
TabletopMachineMask | mask | Impassable+High | desktop machines/windows |
TabletopMachineLayer | layer | Opaque+BulletImpassable | small desktop devices |
GlassAirlockLayer | layer | High+Mid+Bullet+Interact | glass airlock/window profiles |
AirlockLayer | layer | Opaque+GlassAirlockLayer | regular airlock profiles |
HumanoidBlockLayer | layer | High+Mid | assemblies/intermediate "human blocks" |
SlipLayer | layer | Mid+Low | non-hard slip/puddle/trap triggers |
ItemMask | mask | Impassable+High | objects, grenades, small props |
ThrownItem | layer | Impassable+High+Bullet | special throw profiles (rare point case) |
WallLayer | layer | Opaque+Impassable+High+Mid+Low+Bullet+Interact | full walls/barriers |
GlassLayer | layer | Impassable+High+Mid+Low+Bullet+Interact | windows/glass obstacles |
HalfWallLayer | layer | Mid+Low | "semi-high" obstacles |
FlimsyLayer | layer | Opaque+High+Mid+Low+Interact | "fragile" walls that should not catch bullets like wall |
SpecialWallLayer | layer+mask | Opaque+High+Mid+Low+Bullet | force-wall type: blocks movement/bullets, but does not block interact the same way as WallLayer |
FullTileMask | mask | Impassable+High+Mid+Low+Interact | full tile blocker (walls, windows, doors, memorials, etc.) |
FullTileLayer | layer | Opaque+High+Mid+Low+Bullet+Interact | rare non-hard/full-tile sensors and special fixtures |
SubfloorMask | mask | Impassable+Low | underground/pipes/underground networks |
mask = MobMask, layer = MobLayer.mask = SmallMobMask, layer = SmallMobLayer.mask = FlyingMobMask, layer = FlyingMobLayer.mask = MachineMask, layer = MachineLayer or Mid+Low for generic base.mask = TableMask, layer = TableLayer.mask = TabletopMachineMask, layer = TabletopMachineLayer.mask = FullTileMask, layer = GlassLayer.mask = FullTileMask, layer = AirlockLayer (with welding in WallLayer).mask = FullTileMask or TabletopMachineMask according to door type, layer = GlassAirlockLayer.mask = FullTileMask, layer = WallLayer.mask = ItemMask, layer often 0 (if the layer is not needed).hard = false, mask = ItemMask, layer = SlipLayer.mask = SubfloorMask, usually with collision turned off to the desired anchored-state.layer = GhostImpassable, mask = 0.layer = mask = SingularityLayer.✓ - contact is possible via layer/mask, · - no.
For Airlock the standard profile is adopted here: layer = AirlockLayer, mask = FullTileMask.
For Item and SubfloorPipe the common case with null layer is accepted.
| Profile | Mob | SmallMob | FlyingMob | Machine | Table | Airlock | Wall | Item | SlipTrigger(non-hard) | SubfloorPipe |
|---|---|---|---|---|---|---|---|---|---|---|
| Mob | · | · | · | ✓ | ✓ | ✓ | ✓ | · | ✓ | · |
| SmallMob | · | · | · | ✓ | · | · | ✓ | · | ✓ | · |
| FlyingMob | · | · | · | · | · | ✓ | ✓ | · | · | · |
| Machine | ✓ | ✓ | · | ✓ | ✓ | ✓ | ✓ | · | ✓ | ✓ |
| Table | ✓ | · | · | ✓ | ✓ | ✓ | ✓ | · | ✓ | · |
| Airlock | ✓ | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | · |
| Wall | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Item | · | · | · | · | · | ✓ | ✓ | · | · | · |
| SlipTrigger(non-hard) | ✓ | ✓ | · | ✓ | ✓ | ✓ | ✓ | · | · | ✓ |
| SubfloorPipe | · | · | · | ✓ | · | · | ✓ | · | ✓ | · |
MobMask+MobLayer, TabletopMachineMask+TabletopMachineLayer) instead of manually assembling bits.mask = FullTileMask, and change the behavior to layer (WallLayer, GlassLayer, AirlockLayer).hard = false, and filter through layer/mask.DoorPassable/SubfloorMask, not ad-hoc exceptions.AllMask to regular gameplay entities.WallLayer and SpecialWallLayer without an explicit goal for interaction/blocking behavior.InteractImpassable where the object must be shot/passed for interaction checks.layer/mask and do not re-sync contacts (RegenerateContacts) if there is a noticeable change in behavior.# Typical mob: standard ground collision.