private void Undock(DockingComponent dock) { if (dock.DockedWith == null) { DebugTools.Assert(false); _sawmill.Error($"Tried to undock {(dock).Owner} but not docked with anything?"); return; } if (TryComp(dock.Owner, out DoorComponent? doorA)) { doorA.ChangeAirtight = true; _doorSystem.TryClose(doorA.Owner, doorA); } if (TryComp(dock.DockedWith, out DoorComponent? doorB)) { doorB.ChangeAirtight = true; _doorSystem.TryClose(doorB.Owner, doorB); } var recentlyDocked = EnsureComp <RecentlyDockedComponent>(dock.Owner); recentlyDocked.LastDocked = dock.DockedWith.Value; recentlyDocked = EnsureComp <RecentlyDockedComponent>(dock.DockedWith.Value); recentlyDocked.LastDocked = dock.DockedWith.Value; Cleanup(dock); }
private void EnableDocking(EntityUid uid, DockingComponent component) { if (component.Enabled) { return; } if (!TryComp(uid, out PhysicsComponent? physicsComponent)) { return; } component.Enabled = true; // TODO: WTF IS THIS GARBAGE var shape = new PhysShapeCircle { // Want half of the unit vector Position = new Vector2(0f, -0.5f), Radius = DockingRadius }; // Listen it makes intersection tests easier; you can probably dump this but it requires a bunch more boilerplate var fixture = new Fixture(physicsComponent, shape) { ID = DockingFixture, Hard = false, }; // TODO: I want this to ideally be 2 fixtures to force them to have some level of alignment buuuttt // I also need collisionmanager for that yet again so they get dis. _fixtureSystem.CreateFixture(physicsComponent, fixture); }
private void OnStartup(EntityUid uid, DockingComponent component, ComponentStartup args) { // Use startup so transform already initialized if (!EntityManager.GetComponent <TransformComponent>(uid).Anchored) { return; } EnableDocking(uid, component); // This little gem is for docking deserialization if (component.DockedWith != null) { // They're still initialising so we'll just wait for both to be ready. if (MetaData(component.DockedWith.Value).EntityLifeStage < EntityLifeStage.Initialized) { return; } var otherDock = EntityManager.GetComponent <DockingComponent>(component.DockedWith.Value); DebugTools.Assert(otherDock.DockedWith != null); Dock(component, otherDock); DebugTools.Assert(component.Docked && otherDock.Docked); } }
private void Undock(DockingComponent dock) { if (dock.DockedWith == null) { DebugTools.Assert(false); Logger.ErrorS("docking", $"Tried to undock {(dock).Owner} but not docked with anything?"); return; } if (TryComp(dock.Owner, out ServerDoorComponent? doorA)) { doorA.ChangeAirtight = true; doorA.Close(); } if (TryComp(dock.DockedWith, out ServerDoorComponent? doorB)) { doorB.ChangeAirtight = true; doorB.Close(); } // Could maybe give the shuttle a light push away, or at least if there's no other docks left? Cleanup(dock); }
private void OnVerb(EntityUid uid, DockingComponent component, GetInteractionVerbsEvent args) { if (!args.CanInteract || !args.CanAccess) { return; } Verb?verb; // TODO: Have it open the UI and have the UI do this. if (!component.Docked && TryComp(uid, out PhysicsComponent? body) && TryComp(uid, out TransformComponent? xform)) { DockingComponent?otherDock = null; if (component.Enabled) { otherDock = GetDockable(body, xform); } verb = new Verb { Disabled = otherDock == null, Text = Loc.GetString("docking-component-dock"), Act = () => { if (otherDock == null) { return; } TryDock(component, otherDock); } }; } else if (component.Docked) { verb = new Verb { Disabled = !component.Docked, Text = Loc.GetString("docking-component-undock"), Act = () => { if (component.DockedWith == null || !component.Enabled) { return; } Undock(component); } }; } else { return; } args.Verbs.Add(verb); }
private void OnAutoClose(EntityUid uid, DockingComponent component, BeforeDoorAutoCloseEvent args) { // We'll just pin the door open when docked. if (component.Docked) { args.Cancel(); } }
/// <summary> /// Attempts to dock 2 ports together and will return early if it's not possible. /// </summary> private void TryDock(DockingComponent dockA, DockingComponent dockB) { if (!CanDock(dockA, dockB)) { return; } Dock(dockA, dockB); }
private void OnStartup(EntityUid uid, DockingComponent component, ComponentStartup args) { // Use startup so transform already initialized if (!EntityManager.GetComponent <TransformComponent>(uid).Anchored) { return; } EnableDocking(uid, component); }
private void OnShutdown(EntityUid uid, DockingComponent component, ComponentShutdown args) { if (component.DockedWith == null || EntityManager.GetComponent <MetaDataComponent>(uid).EntityLifeStage > EntityLifeStage.MapInitialized) { return; } Cleanup(component); }
private void OnPowerChange(EntityUid uid, DockingComponent component, PowerChangedEvent args) { if (args.Powered) { EnableDocking(uid, component); } else { DisableDocking(uid, component); } }
/// <summary> /// Attempts to dock 2 ports together and will return early if it's not possible. /// </summary> private void TryDock(DockingComponent dockA, DockingComponent dockB) { if (!TryComp(dockA.Owner, out PhysicsComponent? bodyA) || !TryComp(dockB.Owner, out PhysicsComponent? bodyB) || !dockA.Enabled || !dockB.Enabled || dockA.DockedWith != null || dockB.DockedWith != null) { return; } var fixtureA = _fixtureSystem.GetFixtureOrNull(bodyA, DockingFixture); var fixtureB = _fixtureSystem.GetFixtureOrNull(bodyB, DockingFixture); if (fixtureA == null || fixtureB == null) { return; } var transformA = bodyA.GetTransform(); var transformB = bodyB.GetTransform(); var intersect = false; for (var i = 0; i < fixtureA.Shape.ChildCount; i++) { var aabb = fixtureA.Shape.ComputeAABB(transformA, i); for (var j = 0; j < fixtureB.Shape.ChildCount; j++) { var otherAABB = fixtureB.Shape.ComputeAABB(transformB, j); if (!aabb.Intersects(otherAABB)) { continue; } // TODO: Need collisionmanager's GJK for accurate checks don't @ me son intersect = true; break; } if (intersect) { break; } } if (!intersect) { return; } Dock(dockA, dockB); }
private void OnAnchorChange(EntityUid uid, DockingComponent component, ref AnchorStateChangedEvent args) { if (args.Anchored) { EnableDocking(uid, component); } else { DisableDocking(uid, component); } }
private void OnAnchorChange(EntityUid uid, DockingComponent component, ref AnchorStateChangedEvent args) { if (args.Anchored) { EnableDocking(uid, component); } else { DisableDocking(uid, component); } _console.RefreshShuttleConsoles(); }
private void OnDockingReAnchor(EntityUid uid, DockingComponent component, ref ReAnchorEvent args) { if (!component.Docked) { return; } var other = Comp <DockingComponent>(component.DockedWith !.Value); Undock(component); Dock(component, other); _console.RefreshShuttleConsoles(); }
private void Cleanup(DockingComponent dockA) { _jointSystem.RemoveJoint(dockA.DockJoint !); var dockBUid = dockA.DockedWith; if (dockBUid == null || dockA.DockJoint == null || !TryComp(dockBUid, out DockingComponent? dockB)) { DebugTools.Assert(false); _sawmill.Error($"Tried to cleanup {dockA.Owner} but not docked?"); dockA.DockedWith = null; if (dockA.DockJoint != null) { // We'll still cleanup the dock joint on release at least _jointSystem.RemoveJoint(dockA.DockJoint); } return; } dockB.DockedWith = null; dockB.DockJoint = null; dockB.DockJointId = null; dockA.DockJoint = null; dockA.DockedWith = null; dockA.DockJointId = null; // If these grids are ever null then need to look at fixing ordering for unanchored events elsewhere. var gridAUid = EntityManager.GetComponent <TransformComponent>(dockA.Owner).GridUid; var gridBUid = EntityManager.GetComponent <TransformComponent>(dockB.Owner).GridUid; DebugTools.Assert(gridAUid != null); DebugTools.Assert(gridBUid != null); var msg = new UndockEvent { DockA = dockA, DockB = dockB, GridAUid = gridAUid !.Value, GridBUid = gridBUid !.Value, }; EntityManager.EventBus.RaiseLocalEvent(dockA.Owner, msg, false); EntityManager.EventBus.RaiseLocalEvent(dockB.Owner, msg, false); EntityManager.EventBus.RaiseEvent(EventSource.Local, msg); }
private void OnPowerChange(EntityUid uid, DockingComponent component, PowerChangedEvent args) { // This is because power can change during startup for <Reasons> and undock if (MetaData(uid).EntityLifeStage < EntityLifeStage.MapInitialized) { return; } if (args.Powered) { EnableDocking(uid, component); } else { DisableDocking(uid, component); } }
public void Undock(DockingComponent dock) { if (dock.DockedWith == null) { return; } if (TryComp <AirlockComponent>(dock.Owner, out var airlockA)) { airlockA.SetBoltsWithAudio(false); } if (TryComp <AirlockComponent>(dock.DockedWith, out var airlockB)) { airlockB.SetBoltsWithAudio(false); } if (TryComp(dock.Owner, out DoorComponent? doorA)) { doorA.ChangeAirtight = true; _doorSystem.TryClose(doorA.Owner, doorA); } if (TryComp(dock.DockedWith, out DoorComponent? doorB)) { doorB.ChangeAirtight = true; _doorSystem.TryClose(doorB.Owner, doorB); } if (!Deleted(dock.Owner)) { var recentlyDocked = EnsureComp <RecentlyDockedComponent>(dock.Owner); recentlyDocked.LastDocked = dock.DockedWith.Value; } if (!Deleted(dock.DockedWith.Value)) { var recentlyDocked = EnsureComp <RecentlyDockedComponent>(dock.DockedWith.Value); recentlyDocked.LastDocked = dock.DockedWith.Value; } Cleanup(dock); }
private void Cleanup(DockingComponent dockA) { _jointSystem.RemoveJoint(dockA.DockJoint !); var dockB = dockA.DockedWith; if (dockB == null || dockA.DockJoint == null) { DebugTools.Assert(false); Logger.Error("docking", $"Tried to cleanup {(dockA).Owner} but not docked?"); dockA.DockedWith = null; if (dockA.DockJoint != null) { // We'll still cleanup the dock joint on release at least _jointSystem.RemoveJoint(dockA.DockJoint); } return; } dockB.DockedWith = null; dockB.DockJoint = null; dockA.DockJoint = null; dockA.DockedWith = null; // If these grids are ever invalid then need to look at fixing ordering for unanchored events elsewhere. var gridAUid = _mapManager.GetGrid(EntityManager.GetComponent <TransformComponent>((dockA).Owner).GridID).GridEntityId; var gridBUid = _mapManager.GetGrid(EntityManager.GetComponent <TransformComponent>((dockB).Owner).GridID).GridEntityId; var msg = new UndockEvent { DockA = dockA, DockB = dockB, GridAUid = gridAUid, GridBUid = gridBUid, }; EntityManager.EventBus.RaiseLocalEvent((dockA).Owner, msg, false); EntityManager.EventBus.RaiseLocalEvent((dockB).Owner, msg, false); EntityManager.EventBus.RaiseEvent(EventSource.Local, msg); }
/// <summary> /// Checks if 2 docks can be connected by moving the shuttle directly onto docks. /// </summary> private bool CanDock( DockingComponent shuttleDock, TransformComponent shuttleXform, DockingComponent gridDock, TransformComponent gridXform, Vector2 targetGridRotation, Box2 shuttleAABB, IMapGridComponent grid, [NotNullWhen(true)] out Box2?shuttleDockedAABB, out Matrix3 matty, out Vector2 gridRotation) { gridRotation = Vector2.Zero; matty = Matrix3.Identity; shuttleDockedAABB = null; if (shuttleDock.Docked || gridDock.Docked || !shuttleXform.Anchored || !gridXform.Anchored) { return(false); } // First, get the station dock's position relative to the shuttle, this is where we rotate it around var stationDockPos = shuttleXform.LocalPosition + shuttleXform.LocalRotation.RotateVec(new Vector2(0f, -1f)); var stationDockMatrix = Matrix3.CreateInverseTransform(stationDockPos, -shuttleXform.LocalRotation); var gridXformMatrix = Matrix3.CreateTransform(gridXform.LocalPosition, gridXform.LocalRotation); Matrix3.Multiply(in stationDockMatrix, in gridXformMatrix, out matty); shuttleDockedAABB = matty.TransformBox(shuttleAABB); if (!ValidSpawn(grid, shuttleDockedAABB.Value)) { return(false); } gridRotation = matty.Transform(targetGridRotation); return(true); }
private void DisableDocking(EntityUid uid, DockingComponent component) { if (!component.Enabled) { return; } component.Enabled = false; if (component.DockedWith != null) { Undock(component); } if (!TryComp(uid, out PhysicsComponent? physicsComponent)) { return; } _fixtureSystem.DestroyFixture(physicsComponent, DockingFixture); }
/// <summary> /// Docks 2 ports together and assumes it is valid. /// </summary> private void Dock(DockingComponent dockA, DockingComponent dockB) { Logger.DebugS("docking", $"Docking between {dockA.Owner} and {dockB.Owner}"); // https://gamedev.stackexchange.com/questions/98772/b2distancejoint-with-frequency-equal-to-0-vs-b2weldjoint // We could also potentially use a prismatic joint? Depending if we want clamps that can extend or whatever var dockAXform = EntityManager.GetComponent <TransformComponent>(dockA.Owner); var dockBXform = EntityManager.GetComponent <TransformComponent>(dockB.Owner); var gridA = _mapManager.GetGrid(dockAXform.GridID).GridEntityId; var gridB = _mapManager.GetGrid(dockBXform.GridID).GridEntityId; SharedJointSystem.LinearStiffness( 2f, 0.7f, EntityManager.GetComponent <PhysicsComponent>(gridA).Mass, EntityManager.GetComponent <PhysicsComponent>(gridB).Mass, out var stiffness, out var damping); // These need playing around with // Could also potentially have collideconnected false and stiffness 0 but it was a bit more suss??? var joint = _jointSystem.GetOrCreateWeldJoint(gridA, gridB, DockingJoint + dockA.Owner); var gridAXform = EntityManager.GetComponent <TransformComponent>(gridA); var gridBXform = EntityManager.GetComponent <TransformComponent>(gridB); var anchorA = dockAXform.LocalPosition + dockAXform.LocalRotation.ToWorldVec() / 2f; var anchorB = dockBXform.LocalPosition + dockBXform.LocalRotation.ToWorldVec() / 2f; joint.LocalAnchorA = anchorA; joint.LocalAnchorB = anchorB; joint.ReferenceAngle = (float)(gridBXform.WorldRotation - gridAXform.WorldRotation); joint.CollideConnected = true; joint.Stiffness = stiffness; joint.Damping = damping; dockA.DockedWith = dockB.Owner; dockB.DockedWith = dockA.Owner; dockA.DockJoint = joint; dockB.DockJoint = joint; if (TryComp(dockA.Owner, out ServerDoorComponent? doorA)) { doorA.ChangeAirtight = false; doorA.Open(); } if (TryComp(dockB.Owner, out ServerDoorComponent? doorB)) { doorB.ChangeAirtight = false; doorB.Open(); } var msg = new DockEvent { DockA = dockA, DockB = dockB, GridAUid = gridA, GridBUid = gridB, }; EntityManager.EventBus.RaiseLocalEvent(dockA.Owner, msg, false); EntityManager.EventBus.RaiseLocalEvent(dockB.Owner, msg, false); EntityManager.EventBus.RaiseEvent(EventSource.Local, msg); }
/// <summary> /// Docks 2 ports together and assumes it is valid. /// </summary> public void Dock(DockingComponent dockA, DockingComponent dockB) { if (dockB.Owner.GetHashCode() < dockA.Owner.GetHashCode()) { (dockA, dockB) = (dockB, dockA); } _sawmill.Debug($"Docking between {dockA.Owner} and {dockB.Owner}"); // https://gamedev.stackexchange.com/questions/98772/b2distancejoint-with-frequency-equal-to-0-vs-b2weldjoint // We could also potentially use a prismatic joint? Depending if we want clamps that can extend or whatever var dockAXform = EntityManager.GetComponent <TransformComponent>(dockA.Owner); var dockBXform = EntityManager.GetComponent <TransformComponent>(dockB.Owner); DebugTools.Assert(dockAXform.GridUid != null); DebugTools.Assert(dockBXform.GridUid != null); var gridA = dockAXform.GridUid !.Value; var gridB = dockBXform.GridUid !.Value; SharedJointSystem.LinearStiffness( 2f, 0.7f, EntityManager.GetComponent <PhysicsComponent>(gridA).Mass, EntityManager.GetComponent <PhysicsComponent>(gridB).Mass, out var stiffness, out var damping); // These need playing around with // Could also potentially have collideconnected false and stiffness 0 but it was a bit more suss??? WeldJoint joint; // Pre-existing joint so use that. if (dockA.DockJointId != null) { DebugTools.Assert(dockB.DockJointId == dockA.DockJointId); joint = _jointSystem.GetOrCreateWeldJoint(gridA, gridB, dockA.DockJointId); } else { joint = _jointSystem.GetOrCreateWeldJoint(gridA, gridB, DockingJoint + dockA.Owner); } var gridAXform = EntityManager.GetComponent <TransformComponent>(gridA); var gridBXform = EntityManager.GetComponent <TransformComponent>(gridB); var anchorA = dockAXform.LocalPosition + dockAXform.LocalRotation.ToWorldVec() / 2f; var anchorB = dockBXform.LocalPosition + dockBXform.LocalRotation.ToWorldVec() / 2f; joint.LocalAnchorA = anchorA; joint.LocalAnchorB = anchorB; joint.ReferenceAngle = (float)(gridBXform.WorldRotation - gridAXform.WorldRotation); joint.CollideConnected = true; joint.Stiffness = stiffness; joint.Damping = damping; dockA.DockedWith = dockB.Owner; dockB.DockedWith = dockA.Owner; dockA.DockJoint = joint; dockA.DockJointId = joint.ID; dockB.DockJoint = joint; dockB.DockJointId = joint.ID; if (TryComp <AirlockComponent>(dockA.Owner, out var airlockA)) { airlockA.SetBoltsWithAudio(true); } if (TryComp <AirlockComponent>(dockB.Owner, out var airlockB)) { airlockB.SetBoltsWithAudio(true); } if (TryComp(dockA.Owner, out DoorComponent? doorA)) { doorA.ChangeAirtight = false; _doorSystem.StartOpening(doorA.Owner, doorA); } if (TryComp(dockB.Owner, out DoorComponent? doorB)) { doorB.ChangeAirtight = false; _doorSystem.StartOpening(doorB.Owner, doorB); } var msg = new DockEvent { DockA = dockA, DockB = dockB, GridAUid = gridA, GridBUid = gridB, }; EntityManager.EventBus.RaiseLocalEvent(dockA.Owner, msg, false); EntityManager.EventBus.RaiseLocalEvent(dockB.Owner, msg, false); EntityManager.EventBus.RaiseEvent(EventSource.Local, msg); }