public override void FlipX(bool relativeToSub) { if (DockingTarget != null) { if (IsHorizontal) { DockingDir = 0; DockingDir = GetDir(DockingTarget); DockingTarget.DockingDir = -DockingDir; } if (joint != null) { CreateJoint(joint is WeldJoint); LinkHullsToGaps(); } else if (DockingTarget.joint != null) { if (!GameMain.World.BodyList.Contains(DockingTarget.joint.BodyA) || !GameMain.World.BodyList.Contains(DockingTarget.joint.BodyB)) { DockingTarget.CreateJoint(DockingTarget.joint is WeldJoint); } DockingTarget.LinkHullsToGaps(); } } }
public void Undock(bool applyEffects = true) { if (DockingTarget == null || !docked) { return; } forceLockTimer = 0.0f; dockingCooldown = 0.1f; if (applyEffects) { ApplyStatusEffects(ActionType.OnSecondaryUse, 1.0f); } DockingTarget.item.Submarine.ConnectedDockingPorts.Remove(item.Submarine); item.Submarine.ConnectedDockingPorts.Remove(DockingTarget.item.Submarine); if (Door != null && DockingTarget.Door != null) { WayPoint myWayPoint = WayPoint.WayPointList.Find(wp => Door.LinkedGap == wp.ConnectedGap); WayPoint targetWayPoint = WayPoint.WayPointList.Find(wp => DockingTarget.Door.LinkedGap == wp.ConnectedGap); if (myWayPoint != null && targetWayPoint != null) { myWayPoint.FindHull(); myWayPoint.linkedTo.Remove(targetWayPoint); targetWayPoint.FindHull(); targetWayPoint.linkedTo.Remove(myWayPoint); } } item.linkedTo.Clear(); docked = false; Item.Submarine.EnableObstructedWaypoints(DockingTarget.Item.Submarine); obstructedWayPointsDisabled = false; Item.Submarine.RefreshOutdoorNodes(); DockingTarget.Undock(); DockingTarget = null; if (doorBody != null) { GameMain.World.Remove(doorBody); doorBody = null; } var wire = item.GetComponent <Wire>(); wire?.Drop(null); if (joint != null) { GameMain.World.Remove(joint); joint = null; } hulls[0]?.Remove(); hulls[0] = null; hulls[1]?.Remove(); hulls[1] = null; if (gap != null) { gap.Remove(); gap = null; } if (bodies != null) { foreach (Body body in bodies) { if (body == null) { continue; } GameMain.World.Remove(body); } bodies = null; } outsideBlocker?.Body.Remove(outsideBlocker); outsideBlocker = null; #if SERVER if (GameMain.Server != null && (!item.Submarine?.Loading ?? true)) { item.CreateServerEvent(this); } #endif OnUnDocked?.Invoke(); OnUnDocked = null; }
private void CreateHulls() { var hullRects = new Rectangle[] { item.WorldRect, DockingTarget.item.WorldRect }; var subs = new Submarine[] { item.Submarine, DockingTarget.item.Submarine }; bodies = new Body[4]; if (DockingTarget.Door != null) { CreateDoorBody(); } if (Door != null) { DockingTarget.CreateDoorBody(); } if (IsHorizontal) { if (hullRects[0].Center.X > hullRects[1].Center.X) { hullRects = new Rectangle[] { DockingTarget.item.WorldRect, item.WorldRect }; subs = new Submarine[] { DockingTarget.item.Submarine, item.Submarine }; } int scaledDockedDistance = (int)(DockedDistance / 2 * item.Scale); hullRects[0] = new Rectangle(hullRects[0].Center.X, hullRects[0].Y, scaledDockedDistance, hullRects[0].Height); hullRects[1] = new Rectangle(hullRects[1].Center.X - scaledDockedDistance, hullRects[1].Y, scaledDockedDistance, hullRects[1].Height); //expand hulls if needed, so there's no empty space between the sub's hulls and docking port hulls int leftSubRightSide = int.MinValue, rightSubLeftSide = int.MaxValue; foreach (Hull hull in Hull.hullList) { for (int i = 0; i < 2; i++) { if (hull.Submarine != subs[i]) { continue; } if (hull.WorldRect.Y - 5 < hullRects[i].Y - hullRects[i].Height) { continue; } if (hull.WorldRect.Y - hull.WorldRect.Height + 5 > hullRects[i].Y) { continue; } if (i == 0) //left hull { if (hull.WorldPosition.X > hullRects[0].Center.X) { continue; } leftSubRightSide = Math.Max(hull.WorldRect.Right, leftSubRightSide); } else //upper hull { if (hull.WorldPosition.X < hullRects[1].Center.X) { continue; } rightSubLeftSide = Math.Min(hull.WorldRect.X, rightSubLeftSide); } } } if (leftSubRightSide == int.MinValue || rightSubLeftSide == int.MaxValue) { DebugConsole.NewMessage("Creating hulls between docking ports failed. Could not find a hull next to the docking port."); return; } //expand left hull to the rightmost hull of the sub at the left side //(unless the difference is more than 100 units - if the distance is very large //there's something wrong with the positioning of the docking ports or submarine hulls) int leftHullDiff = (hullRects[0].X - leftSubRightSide) + 5; if (leftHullDiff > 0) { if (leftHullDiff > 100) { DebugConsole.NewMessage("Creating hulls between docking ports failed. The leftmost docking port seems to be very far from any hulls in the left-side submarine."); return; } else { hullRects[0].X -= leftHullDiff; hullRects[0].Width += leftHullDiff; } } int rightHullDiff = (rightSubLeftSide - hullRects[1].Right) + 5; if (rightHullDiff > 0) { if (rightHullDiff > 100) { DebugConsole.NewMessage("Creating hulls between docking ports failed. The rightmost docking port seems to be very far from any hulls in the right-side submarine."); return; } else { hullRects[1].Width += rightHullDiff; } } int expand = 5; for (int i = 0; i < 2; i++) { hullRects[i].X -= expand; hullRects[i].Width += expand * 2; hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition)); hulls[i] = new Hull(MapEntityPrefab.Find(null, "hull"), hullRects[i], subs[i]); hulls[i].AddToGrid(subs[i]); hulls[i].FreeID(); for (int j = 0; j < 2; j++) { bodies[i + j * 2] = GameMain.World.CreateEdge( ConvertUnits.ToSimUnits(new Vector2(hullRects[i].X, hullRects[i].Y - hullRects[i].Height * j)), ConvertUnits.ToSimUnits(new Vector2(hullRects[i].Right, hullRects[i].Y - hullRects[i].Height * j))); } } if (rightHullDiff <= 100 && hulls[0].Submarine != null) { outsideBlocker = hulls[0].Submarine.PhysicsBody.FarseerBody.CreateRectangle( ConvertUnits.ToSimUnits(hullRects[0].Width + hullRects[1].Width), ConvertUnits.ToSimUnits(hullRects[0].Height), density: 0.0f, offset: ConvertUnits.ToSimUnits(new Vector2(hullRects[0].Right, hullRects[0].Y - hullRects[0].Height / 2) - hulls[0].Submarine.HiddenSubPosition)); outsideBlocker.UserData = this; } gap = new Gap(new Rectangle(hullRects[0].Right - 2, hullRects[0].Y, 4, hullRects[0].Height), true, subs[0]); } else { if (hullRects[0].Center.Y > hullRects[1].Center.Y) { hullRects = new Rectangle[] { DockingTarget.item.WorldRect, item.WorldRect }; subs = new Submarine[] { DockingTarget.item.Submarine, item.Submarine }; } int scaledDockedDistance = (int)(DockedDistance / 2 * item.Scale); hullRects[0] = new Rectangle(hullRects[0].X, hullRects[0].Y - hullRects[0].Height / 2 + scaledDockedDistance, hullRects[0].Width, scaledDockedDistance); hullRects[1] = new Rectangle(hullRects[1].X, hullRects[1].Y - hullRects[1].Height / 2, hullRects[1].Width, scaledDockedDistance); //expand hulls if needed, so there's no empty space between the sub's hulls and docking port hulls int upperSubBottom = int.MaxValue, lowerSubTop = int.MinValue; foreach (Hull hull in Hull.hullList) { for (int i = 0; i < 2; i++) { if (hull.Submarine != subs[i]) { continue; } if (hull.WorldRect.Right - 5 < hullRects[i].X) { continue; } if (hull.WorldRect.X + 5 > hullRects[i].Right) { continue; } if (i == 0) //lower hull { if (hull.WorldPosition.Y > hullRects[i].Y - hullRects[i].Height / 2) { continue; } lowerSubTop = Math.Max(hull.WorldRect.Y, lowerSubTop); } else //upper hull { if (hull.WorldPosition.Y < hullRects[i].Y - hullRects[i].Height / 2) { continue; } upperSubBottom = Math.Min(hull.WorldRect.Y - hull.WorldRect.Height, upperSubBottom); } } } if (upperSubBottom == int.MaxValue || lowerSubTop == int.MinValue) { DebugConsole.NewMessage("Creating hulls between docking ports failed. Could not find a hull next to the docking port."); return; } //expand lower hull to the topmost hull of the lower sub //(unless the difference is more than 100 units - if the distance is very large //there's something wrong with the positioning of the docking ports or submarine hulls) int lowerHullDiff = ((hullRects[0].Y - hullRects[0].Height) - lowerSubTop) + 5; if (lowerHullDiff > 0) { if (lowerHullDiff > 100) { DebugConsole.NewMessage("Creating hulls between docking ports failed. The lower docking port seems to be very far from any hulls in the lower submarine."); return; } else { hullRects[0].Height += lowerHullDiff; } } int upperHullDiff = (upperSubBottom - hullRects[1].Y) + 5; if (upperHullDiff > 0) { if (upperHullDiff > 100) { DebugConsole.NewMessage("Creating hulls between docking ports failed. The upper docking port seems to be very far from any hulls in the upper submarine."); return; } else { hullRects[1].Y += upperHullDiff; hullRects[1].Height += upperHullDiff; } } //difference between the edges of the hulls (to avoid a gap between the hulls) //0 is lower int midHullDiff = ((hullRects[1].Y - hullRects[1].Height) - hullRects[0].Y) + 2; if (midHullDiff > 100) { DebugConsole.NewMessage("Creating hulls between docking ports failed. The upper hull seems to be very far from the lower hull."); return; } else if (midHullDiff > 0) { hullRects[0].Height += midHullDiff / 2 + 1; hullRects[1].Y -= midHullDiff / 2 + 1; hullRects[1].Height += midHullDiff / 2 + 1; } int expand = 5; for (int i = 0; i < 2; i++) { hullRects[i].Y += expand; hullRects[i].Height += expand * 2; hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition)); hulls[i] = new Hull(MapEntityPrefab.Find(null, "hull"), hullRects[i], subs[i]); hulls[i].AddToGrid(subs[i]); hulls[i].FreeID(); for (int j = 0; j < 2; j++) { bodies[i + j * 2] = GameMain.World.CreateEdge( ConvertUnits.ToSimUnits(new Vector2(hullRects[i].X + hullRects[i].Width * j, hullRects[i].Y)), ConvertUnits.ToSimUnits(new Vector2(hullRects[i].X + hullRects[i].Width * j, hullRects[i].Y - hullRects[i].Height))); } } if (midHullDiff <= 100 && hulls[0].Submarine != null) { outsideBlocker = hulls[0].Submarine.PhysicsBody.FarseerBody.CreateRectangle( ConvertUnits.ToSimUnits(hullRects[0].Width), ConvertUnits.ToSimUnits(hullRects[0].Height + hullRects[1].Height), density: 0.0f, offset: ConvertUnits.ToSimUnits(new Vector2(hullRects[0].Center.X, hullRects[0].Y) - hulls[0].Submarine.HiddenSubPosition)); outsideBlocker.UserData = this; } gap = new Gap(new Rectangle(hullRects[0].X, hullRects[0].Y + 2, hullRects[0].Width, 4), false, subs[0]); } LinkHullsToGaps(); hulls[0].ShouldBeSaved = false; hulls[1].ShouldBeSaved = false; item.linkedTo.Add(hulls[0]); item.linkedTo.Add(hulls[1]); gap.FreeID(); gap.DisableHullRechecks = true; gap.ShouldBeSaved = false; item.linkedTo.Add(gap); foreach (Body body in bodies) { if (body == null) { continue; } body.BodyType = BodyType.Static; body.Friction = 0.5f; body.CollisionCategories = Physics.CollisionWall; } }
public void Undock() { if (DockingTarget == null || !docked) { return; } forceLockTimer = 0.0f; ApplyStatusEffects(ActionType.OnSecondaryUse, 1.0f); DockingTarget.item.Submarine.DockedTo.Remove(item.Submarine); item.Submarine.DockedTo.Remove(DockingTarget.item.Submarine); if (door != null && DockingTarget.door != null) { WayPoint myWayPoint = WayPoint.WayPointList.Find(wp => door.LinkedGap == wp.ConnectedGap); WayPoint targetWayPoint = WayPoint.WayPointList.Find(wp => DockingTarget.door.LinkedGap == wp.ConnectedGap); if (myWayPoint != null && targetWayPoint != null) { myWayPoint.linkedTo.Remove(targetWayPoint); targetWayPoint.linkedTo.Remove(myWayPoint); } } item.linkedTo.Clear(); docked = false; DockingTarget.Undock(); DockingTarget = null; if (doorBody != null) { GameMain.World.RemoveBody(doorBody); doorBody = null; } var wire = item.GetComponent <Wire>(); if (wire != null) { wire.Drop(null); } if (joint != null) { GameMain.World.RemoveJoint(joint); joint = null; } hulls[0]?.Remove(); hulls[0] = null; hulls[1]?.Remove(); hulls[1] = null; if (gap != null) { gap.Remove(); gap = null; } if (bodies != null) { foreach (Body body in bodies) { if (body == null) { continue; } GameMain.World.RemoveBody(body); } bodies = null; } Item.Submarine.EnableObstructedWaypoints(); obstructedWayPointsDisabled = false; #if SERVER if (GameMain.Server != null) { item.CreateServerEvent(this); } #endif }
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime) { bool isDocked = msg.ReadBoolean(); for (int i = 0; i < 2; i++) { if (hulls[i] == null) { continue; } item.linkedTo.Remove(hulls[i]); hulls[i].Remove(); hulls[i] = null; } if (gap != null) { item.linkedTo.Remove(gap); gap.Remove(); gap = null; } if (isDocked) { ushort dockingTargetID = msg.ReadUInt16(); bool isLocked = msg.ReadBoolean(); Entity targetEntity = Entity.FindEntityByID(dockingTargetID); if (targetEntity == null || !(targetEntity is Item)) { DebugConsole.ThrowError("Invalid docking port network event (can't dock to " + (targetEntity?.ToString() ?? "null") + ")"); return; } DockingTarget = (targetEntity as Item).GetComponent <DockingPort>(); if (DockingTarget == null) { DebugConsole.ThrowError("Invalid docking port network event (" + targetEntity + " doesn't have a docking port component)"); return; } Dock(DockingTarget); if (joint == null) { string errorMsg = "Error while reading a docking port network event (Dock method did not create a joint between the ports)." + " Submarine: " + (item.Submarine?.Info.Name ?? "null") + ", target submarine: " + (DockingTarget.item.Submarine?.Info.Name ?? "null"); if (item.Submarine?.ConnectedDockingPorts.ContainsKey(DockingTarget.item.Submarine) ?? false) { errorMsg += "\nAlready docked."; } if (item.Submarine == DockingTarget.item.Submarine) { errorMsg += "\nTrying to dock the submarine to itself."; } GameAnalyticsManager.AddErrorEventOnce("DockingPort.ClientRead:JointNotCreated", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); } if (isLocked) { if (DockingTarget.joint != null) { DockingTarget.Lock(isNetworkMessage: true); } else { Lock(isNetworkMessage: true); } } } else { Undock(); } }