diff --git a/.gitignore b/.gitignore index 2dcf45db7..c9a6323c2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ bld/ [Bb]in/ [Oo]bj/ +*.suo + #performance reports & sessions *.vsp *.psess diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj index 68a2ac24e..23966ab7d 100644 --- a/Subsurface/Barotrauma.csproj +++ b/Subsurface/Barotrauma.csproj @@ -152,6 +152,7 @@ + diff --git a/Subsurface/Content/Items/Engine/engine.png b/Subsurface/Content/Items/Engine/engine.png index ff3ed0c09..a99150aa1 100644 Binary files a/Subsurface/Content/Items/Engine/engine.png and b/Subsurface/Content/Items/Engine/engine.png differ diff --git a/Subsurface/Content/Items/Engine/engine.xml b/Subsurface/Content/Items/Engine/engine.xml index 51a20b46b..0df9c95e3 100644 --- a/Subsurface/Content/Items/Engine/engine.xml +++ b/Subsurface/Content/Items/Engine/engine.xml @@ -8,7 +8,7 @@ pickthroughwalls="true" pickdistance="150"> - + @@ -29,6 +29,34 @@ + + + + + + + + + + + + + + + + + + + + + + + character.SimPosition.Y+1.0f) allowedDistance*=0.5f; Vector2 pos = host.SimPosition; - if (character != null && character.Submarine == null) + if (character != null && character.Submarine == null && + CurrentPath.CurrentNode != null && CurrentPath.CurrentNode.Submarine != null) { //todo: take multiple subs into account - pos -= Submarine.MainSub.SimPosition; + pos -= CurrentPath.CurrentNode.Submarine.SimPosition; } if (currentPath.CurrentNode!= null && currentPath.CurrentNode.Ladders!=null) diff --git a/Subsurface/Source/GUI/GUIImage.cs b/Subsurface/Source/GUI/GUIImage.cs index 1fb92135a..16dab4c83 100644 --- a/Subsurface/Source/GUI/GUIImage.cs +++ b/Subsurface/Source/GUI/GUIImage.cs @@ -83,12 +83,11 @@ namespace Barotrauma if (state == ComponentState.Hover) currColor = hoverColor; if (state == ComponentState.Selected) currColor = selectedColor; - if (sprite!=null) + if (sprite != null && sprite.Texture != null) { spriteBatch.Draw(sprite.Texture, new Vector2(rect.X, rect.Y), sourceRect, currColor * (currColor.A / 255.0f), 0.0f, Vector2.Zero, - Scale, SpriteEffects.None, 0.0f); - } - + Scale, SpriteEffects.None, 0.0f); + } DrawChildren(spriteBatch); } diff --git a/Subsurface/Source/GameSession/CrewManager.cs b/Subsurface/Source/GameSession/CrewManager.cs index 35261dd84..c9e2e3235 100644 --- a/Subsurface/Source/GameSession/CrewManager.cs +++ b/Subsurface/Source/GameSession/CrewManager.cs @@ -277,7 +277,7 @@ namespace Barotrauma listBox.ClearChildren(); characters.Clear(); - WayPoint[] waypoints = WayPoint.SelectCrewSpawnPoints(characterInfos); + WayPoint[] waypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub); for (int i = 0; i < waypoints.Length; i++) { diff --git a/Subsurface/Source/Items/Components/Machines/Steering.cs b/Subsurface/Source/Items/Components/Machines/Steering.cs index 78befa10e..b0afc57d6 100644 --- a/Subsurface/Source/Items/Components/Machines/Steering.cs +++ b/Subsurface/Source/Items/Components/Machines/Steering.cs @@ -33,8 +33,10 @@ namespace Barotrauma.Items.Components private float autopilotRayCastTimer; private float neutralBallastLevel; + + public Vector2? TargetPosition; - bool AutoPilot + public bool AutoPilot { get { return autoPilot; } set @@ -52,7 +54,7 @@ namespace Barotrauma.Items.Components if (pathFinder==null) pathFinder = new PathFinder(WayPoint.WayPointList, false); steeringPath = pathFinder.FindPath( ConvertUnits.ToSimUnits(item.WorldPosition), - ConvertUnits.ToSimUnits(Level.Loaded.EndPosition)); + TargetPosition == null ? ConvertUnits.ToSimUnits(Level.Loaded.EndPosition) : (Vector2)TargetPosition); } else { @@ -62,6 +64,12 @@ namespace Barotrauma.Items.Components } } + public bool MaintainPos + { + get { return maintainPosTickBox.Selected; } + set { maintainPosTickBox.Selected = value; } + } + [Editable, HasDefaultValue(0.5f, true)] public float NeutralBallastLevel @@ -128,7 +136,7 @@ namespace Barotrauma.Items.Components } } - if (voltage < minVoltage) return; + if (voltage < minVoltage && powerConsumption > 0.0f) return; if (autoPilot) { @@ -158,7 +166,7 @@ namespace Barotrauma.Items.Components GuiFrame.Update(1.0f / 60.0f); GuiFrame.Draw(spriteBatch); - if (voltage < minVoltage) return; + if (voltage < minVoltage && powerConsumption > 0.0f) return; Rectangle velRect = new Rectangle(x + 20, y + 20, width - 40, height - 40); //GUI.DrawRectangle(spriteBatch, velRect, Color.White, false); diff --git a/Subsurface/Source/Items/Components/Power/PowerContainer.cs b/Subsurface/Source/Items/Components/Power/PowerContainer.cs index f6400c72e..1fcf4a172 100644 --- a/Subsurface/Source/Items/Components/Power/PowerContainer.cs +++ b/Subsurface/Source/Items/Components/Power/PowerContainer.cs @@ -113,7 +113,7 @@ namespace Barotrauma.Items.Components public override void Update(float deltaTime, Camera cam) { float chargeRate = (float)(Math.Sqrt(charge / capacity)); - //float gridPower = 0.0f; + float gridPower = 0.0f; float gridLoad = 0.0f; //if (item.linkedTo.Count == 0) return; @@ -126,7 +126,8 @@ namespace Barotrauma.Items.Components PowerTransfer pt = c2.Item.GetComponent(); if (pt == null || !pt.IsActive) continue; - gridLoad += pt.PowerLoad; + gridLoad += pt.PowerLoad; + gridPower -= pt.CurrPowerConsumption; } } @@ -171,27 +172,21 @@ namespace Barotrauma.Items.Components // -maxOutput * chargeRate, // 0.1f); - if (outputVoltage < 1.0f) + if (gridPower < gridLoad) { + // CurrPowerOutput = MathHelper.Lerp( + //CurrPowerOutput, Math.Min(maxOutput * chargeRate, gridLoad), 0.05f); + CurrPowerOutput = MathHelper.Lerp( - CurrPowerOutput, Math.Min(maxOutput * chargeRate, gridLoad), 0.05f); + CurrPowerOutput, + Math.Min(maxOutput * chargeRate, gridLoad - (gridLoad * outputVoltage)), + 0.05f); } else { CurrPowerOutput = MathHelper.Lerp(CurrPowerOutput, 0.0f, 0.05f); } - CurrPowerOutput = MathHelper.Lerp( - CurrPowerOutput, - Math.Min(maxOutput * chargeRate, gridLoad - (gridLoad * outputVoltage)), - 0.05f); - - - - //powerConsumption = MathHelper.Lerp( - // powerConsumption, - // -Math.Min(maxOutput * chargeRate, gridLoad - (power)), - // 0.1f); //powerConsumption = Math.Min(powerConsumption, 0.0f); Charge -= CurrPowerOutput / 3600.0f; diff --git a/Subsurface/Source/Items/Components/Power/PowerTransfer.cs b/Subsurface/Source/Items/Components/Power/PowerTransfer.cs index c443b8e1d..3dbf0d3e4 100644 --- a/Subsurface/Source/Items/Components/Power/PowerTransfer.cs +++ b/Subsurface/Source/Items/Components/Power/PowerTransfer.cs @@ -62,6 +62,7 @@ namespace Barotrauma.Items.Components pt.powerLoad += (fullLoad - pt.powerLoad) / inertia; pt.currPowerConsumption += (-fullPower - pt.currPowerConsumption) / inertia; pt.Item.SendSignal(0, "", "power", fullPower / Math.Max(fullLoad, 1.0f)); + pt.Item.SendSignal(0, "", "power_out", fullPower / Math.Max(fullLoad, 1.0f)); //damage the item if voltage is too high //(except if running as a client) @@ -117,7 +118,6 @@ namespace Barotrauma.Items.Components { if (!c.IsPower) continue; - var recipients = c.Recipients; foreach (Connection recipient in recipients) @@ -138,7 +138,7 @@ namespace Barotrauma.Items.Components PowerContainer powerContainer = powered as PowerContainer; if (powerTransfer != null) { - if (powerTransfer.updateTimer>0) continue; + //if (powerTransfer.updateTimer>0) continue; powerTransfer.CheckJunctions(deltaTime); } else if (powerContainer != null) diff --git a/Subsurface/Source/Items/Components/Signal/Wire.cs b/Subsurface/Source/Items/Components/Signal/Wire.cs index 6dcd34036..a1bbe5540 100644 --- a/Subsurface/Source/Items/Components/Signal/Wire.cs +++ b/Subsurface/Source/Items/Components/Signal/Wire.cs @@ -109,6 +109,8 @@ namespace Barotrauma.Items.Components } } + item.Submarine = newConnection.Item.Submarine; + for (int i = 0; i < 2; i++) { if (connections[i] != null) continue; @@ -117,16 +119,18 @@ namespace Barotrauma.Items.Components if (!addNode) break; - if (Nodes.Count > 0 && Nodes[0] == newConnection.Item.Position - item.Submarine.HiddenSubPosition) break; - if (Nodes.Count > 1 && Nodes[Nodes.Count-1] == newConnection.Item.Position - item.Submarine.HiddenSubPosition) break; + if (Nodes.Count > 0 && Nodes[0] == newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition) break; + if (Nodes.Count > 1 && Nodes[Nodes.Count-1] == newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition) break; + + if (i == 0) { - Nodes.Insert(0, newConnection.Item.Position - item.Submarine.HiddenSubPosition); + Nodes.Insert(0, newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition); } else { - Nodes.Add(newConnection.Item.Position - item.Submarine.HiddenSubPosition); + Nodes.Add(newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition); } @@ -184,7 +188,7 @@ namespace Barotrauma.Items.Components { if (Nodes.Count == 0) return; - item.FindHull(); + //item.FindHull(); //Vector2 position = item.Position; @@ -200,7 +204,11 @@ namespace Barotrauma.Items.Components // position.Y += item.CurrentHull.Rect.Y - item.CurrentHull.Rect.Height; //} - newNodePos = RoundNode(item.Position, item.CurrentHull) - item.Submarine.HiddenSubPosition; + Submarine sub = null; + if (connections[0] != null && connections[0].Item.Submarine != null) sub = connections[0].Item.Submarine; + if (connections[1] != null && connections[1].Item.Submarine != null) sub = connections[1].Item.Submarine; + + newNodePos = RoundNode(item.Position, item.CurrentHull) - sub.HiddenSubPosition; //if (Vector2.Distance(position, nodes[nodes.Count - 1]) > nodeDistance*10) //{ @@ -407,7 +415,12 @@ namespace Barotrauma.Items.Components MapEntity.DisableSelect = true; //Nodes[(int)selectedNodeIndex] = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition)-Submarine.HiddenSubPosition+Submarine.Loaded.Position; - Vector2 nodeWorldPos = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition) - item.Submarine.HiddenSubPosition - item.Submarine.Position;// Nodes[(int)selectedNodeIndex]; + + Submarine sub = null; + if (connections[0] != null && connections[0].Item.Submarine != null) sub = connections[0].Item.Submarine; + if (connections[1] != null && connections[1].Item.Submarine != null) sub = connections[1].Item.Submarine; + + Vector2 nodeWorldPos = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition) - sub.HiddenSubPosition - sub.Position;// Nodes[(int)selectedNodeIndex]; nodeWorldPos.X = MathUtils.Round(nodeWorldPos.X, Submarine.GridSize.X / 2.0f); nodeWorldPos.Y = MathUtils.Round(nodeWorldPos.Y, Submarine.GridSize.Y / 2.0f); diff --git a/Subsurface/Source/Items/Item.cs b/Subsurface/Source/Items/Item.cs index b8e908275..2243aef2e 100644 --- a/Subsurface/Source/Items/Item.cs +++ b/Subsurface/Source/Items/Item.cs @@ -523,7 +523,7 @@ namespace Barotrauma } CurrentHull = Hull.FindHull(WorldPosition, CurrentHull); - if (body != null) + if (body != null && body.Enabled) { Submarine = CurrentHull == null ? null : CurrentHull.Submarine; body.Submarine = Submarine; diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index d481627a5..7b7940112 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -22,7 +22,7 @@ namespace Barotrauma { public static string SavePath = "Submarines"; - private static readonly Vector2 HiddenSubStartPosition = new Vector2(-50000.0f, 80000.0f); + public static readonly Vector2 HiddenSubStartPosition = new Vector2(-50000.0f, 80000.0f); //position of the "actual submarine" which is rendered wherever the SubmarineBody is //should be in an unreachable place public Vector2 HiddenSubPosition @@ -113,6 +113,11 @@ namespace Barotrauma get { return loaded; } } + public SubmarineBody SubBody + { + get { return subBody; } + } + public Rectangle Borders { get diff --git a/Subsurface/Source/Map/SubmarineBody.cs b/Subsurface/Source/Map/SubmarineBody.cs index ad6dd7500..0d0b354a0 100644 --- a/Subsurface/Source/Map/SubmarineBody.cs +++ b/Subsurface/Source/Map/SubmarineBody.cs @@ -33,11 +33,11 @@ namespace Barotrauma private readonly Submarine submarine; - private readonly Body body; + public readonly Body Body; private Vector2? targetPosition; - private float mass = 10000.0f; + //private float mass = 10000.0f; public Rectangle Borders { @@ -47,11 +47,11 @@ namespace Barotrauma public Vector2 Velocity { - get { return body.LinearVelocity; } + get { return Body.LinearVelocity; } set { if (!MathUtils.IsValid(value)) return; - body.LinearVelocity = value; + Body.LinearVelocity = value; } } @@ -67,7 +67,7 @@ namespace Barotrauma public Vector2 Position { - get { return ConvertUnits.ToDisplayUnits(body.Position); } + get { return ConvertUnits.ToDisplayUnits(Body.Position); } } public bool AtDamageDepth @@ -82,7 +82,7 @@ namespace Barotrauma if (!Hull.hullList.Any()) { - body = BodyFactory.CreateRectangle(GameMain.World, 1.0f, 1.0f, 1.0f); + Body = BodyFactory.CreateRectangle(GameMain.World, 1.0f, 1.0f, 1.0f); DebugConsole.ThrowError("WARNING: no hulls found, generating a physics body for the submarine failed."); } else @@ -110,7 +110,7 @@ namespace Barotrauma //var triangulatedVertices = Triangulate.ConvexPartition(shapevertices, TriangulationAlgorithm.Bayazit); - body = BodyFactory.CreateBody(GameMain.World, this); + Body = BodyFactory.CreateBody(GameMain.World, this); foreach (Structure wall in Structure.WallList) { @@ -118,9 +118,9 @@ namespace Barotrauma FixtureFactory.AttachRectangle( ConvertUnits.ToSimUnits(rect.Width), ConvertUnits.ToSimUnits(rect.Height), - 5.0f, + 50.0f, ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2)), - body, this); + Body, this); } //foreach (Hull hull in Hull.hullList) @@ -151,24 +151,24 @@ namespace Barotrauma - body.BodyType = BodyType.Dynamic; - body.CollisionCategories = Physics.CollisionWall; - body.CollidesWith = + Body.BodyType = BodyType.Dynamic; + Body.CollisionCategories = Physics.CollisionWall; + Body.CollidesWith = Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionCharacter | Physics.CollisionProjectile | Physics.CollisionWall; - body.Restitution = Restitution; - body.Friction = Friction; - body.FixedRotation = true; - body.Mass = mass; - body.Awake = true; - body.SleepingAllowed = false; - body.IgnoreGravity = true; - body.OnCollision += OnCollision; - body.UserData = submarine; + Body.Restitution = Restitution; + Body.Friction = Friction; + Body.FixedRotation = true; + //mass = Body.Mass; + Body.Awake = true; + Body.SleepingAllowed = false; + Body.IgnoreGravity = true; + Body.OnCollision += OnCollision; + Body.UserData = submarine; } @@ -237,7 +237,7 @@ namespace Barotrauma if (dist > 1000.0f) //immediately snap the sub to the target position if more than 1000.0f units away { - Vector2 moveAmount = (Vector2)targetPosition - ConvertUnits.ToDisplayUnits(body.Position); + Vector2 moveAmount = (Vector2)targetPosition - ConvertUnits.ToDisplayUnits(Body.Position); ForceTranslate(moveAmount); @@ -270,14 +270,14 @@ namespace Barotrauma Vector2 totalForce = CalculateBuoyancy(); - if (body.LinearVelocity.LengthSquared() > 0.000001f) + if (Body.LinearVelocity.LengthSquared() > 0.000001f) { float dragCoefficient = 0.01f; - float speedLength = (body.LinearVelocity == Vector2.Zero) ? 0.0f : body.LinearVelocity.Length(); - float drag = speedLength * speedLength * dragCoefficient * mass; + float speedLength = (Body.LinearVelocity == Vector2.Zero) ? 0.0f : Body.LinearVelocity.Length(); + float drag = speedLength * speedLength * dragCoefficient * Body.Mass; - totalForce += -Vector2.Normalize(body.LinearVelocity) * drag; + totalForce += -Vector2.Normalize(Body.LinearVelocity) * drag; } ApplyForce(totalForce); @@ -292,11 +292,15 @@ namespace Barotrauma /// Amount to move in display units private void ForceTranslate(Vector2 amount) { - body.SetTransform(body.Position + ConvertUnits.ToSimUnits(amount), 0.0f); + Body.SetTransform(Body.Position + ConvertUnits.ToSimUnits(amount), 0.0f); if (Character.Controlled != null) Character.Controlled.CursorPosition += amount; - GameMain.GameScreen.Cam.Position += amount; - if (GameMain.GameScreen.Cam.TargetPos != Vector2.Zero) GameMain.GameScreen.Cam.TargetPos += amount; + if ((Character.Controlled != null && Character.Controlled.Submarine == submarine) || + Submarine.GetClosest(GameMain.GameScreen.Cam.WorldViewCenter) == submarine) + { + GameMain.GameScreen.Cam.Position += amount; + if (GameMain.GameScreen.Cam.TargetPos != Vector2.Zero) GameMain.GameScreen.Cam.TargetPos += amount; + } } @@ -308,7 +312,7 @@ namespace Barotrauma private void DisplaceCharacters(Vector2 subTranslation) { Rectangle worldBorders = Borders; - worldBorders.Location += ConvertUnits.ToDisplayUnits(body.Position).ToPoint(); + worldBorders.Location += ConvertUnits.ToDisplayUnits(Body.Position).ToPoint(); Vector2 translateDir = Vector2.Normalize(subTranslation); @@ -355,19 +359,19 @@ namespace Barotrauma float neutralPercentage = 0.07f; float buoyancy = Math.Max(neutralPercentage - waterPercentage, -neutralPercentage*2.0f); - buoyancy *= mass; + buoyancy *= Body.Mass; return new Vector2(0.0f, buoyancy*10.0f); } public void ApplyForce(Vector2 force) { - body.ApplyForce(force); + Body.ApplyForce(force); } public void SetPosition(Vector2 position) { - body.SetTransform(ConvertUnits.ToSimUnits(position), 0.0f); + Body.SetTransform(ConvertUnits.ToSimUnits(position), 0.0f); } private void UpdateDepthDamage(float deltaTime) @@ -423,7 +427,7 @@ namespace Barotrauma if (collision && limb.Mass > 100.0f) { - Vector2 normal = Vector2.Normalize(body.Position - limb.SimPosition); + Vector2 normal = Vector2.Normalize(Body.Position - limb.SimPosition); float impact = Math.Min(Vector2.Dot(Velocity - limb.LinearVelocity, -normal), 5.0f); @@ -436,7 +440,7 @@ namespace Barotrauma VoronoiCell cell = f2.Body.UserData as VoronoiCell; if (cell != null) { - var collisionNormal = Vector2.Normalize(ConvertUnits.ToDisplayUnits(body.Position) - cell.Center); + var collisionNormal = Vector2.Normalize(ConvertUnits.ToDisplayUnits(Body.Position) - cell.Center); float wallImpact = Vector2.Dot(Velocity, -collisionNormal); @@ -525,7 +529,7 @@ namespace Barotrauma foreach (Character c in Character.CharacterList) { - if (c.AnimController.CurrentHull == null) continue; + if (c.Submarine != submarine) continue; if (impact > 2.0f) c.StartStun((impact - 2.0f) * 0.1f); diff --git a/Subsurface/Source/Map/WayPoint.cs b/Subsurface/Source/Map/WayPoint.cs index b901c0775..a5f9a49c4 100644 --- a/Subsurface/Source/Map/WayPoint.cs +++ b/Subsurface/Source/Map/WayPoint.cs @@ -641,13 +641,11 @@ namespace Barotrauma return wayPoints[Rand.Int(wayPoints.Count(), false)]; } - public static WayPoint[] SelectCrewSpawnPoints(List crew) + public static WayPoint[] SelectCrewSpawnPoints(List crew, Submarine submarine) { - List unassignedWayPoints = new List(); - foreach (WayPoint wp in WayPointList) - { - if (wp.spawnType == SpawnType.Human) unassignedWayPoints.Add(wp); - } + List subWayPoints = WayPointList.FindAll(wp => wp.Submarine == submarine); + + List unassignedWayPoints = subWayPoints.FindAll(wp => wp.spawnType == SpawnType.Human); WayPoint[] assignedWayPoints = new WayPoint[crew.Count]; @@ -670,7 +668,7 @@ namespace Barotrauma if (assignedWayPoints[i] != null) continue; //try to assign a spawnpoint that matches the job, even if the spawnpoint is already assigned to someone else - foreach (WayPoint wp in WayPointList) + foreach (WayPoint wp in subWayPoints) { if (wp.spawnType != SpawnType.Human || wp.assignedJob != crew[i].Job.Prefab) continue; @@ -681,7 +679,7 @@ namespace Barotrauma if (assignedWayPoints[i] != null) continue; //try to assign a spawnpoint that isn't meant for any specific job - var nonJobSpecificPoints = WayPointList.FindAll(wp => wp.spawnType == SpawnType.Human && wp.assignedJob == null); + var nonJobSpecificPoints = subWayPoints.FindAll(wp => wp.spawnType == SpawnType.Human && wp.assignedJob == null); if (nonJobSpecificPoints.Any()) { diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 905d2e5e1..2d401dd9b 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -518,6 +518,9 @@ namespace Barotrauma.Networking string endMessage = inc.ReadString(); CoroutineManager.StartCoroutine(EndGame(endMessage)); break; + case (byte)PacketTypes.Respawn: + if (gameStarted && respawnManager != null) respawnManager.ReadNetworkEvent(inc); + break; case (byte)PacketTypes.PlayerJoined: Client otherClient = new Client(inc.ReadString(), inc.ReadByte()); @@ -672,7 +675,9 @@ namespace Barotrauma.Networking GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, Mission.MissionTypes[missionTypeIndex]); GameMain.GameSession.StartShift(levelSeed); - + + respawnManager = new RespawnManager(this); + yield return CoroutineStatus.Running; //myCharacter = ReadCharacterData(inc); @@ -1023,7 +1028,7 @@ namespace Barotrauma.Networking client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); } - private Character ReadCharacterData(NetIncomingMessage inc, bool isMyCharacter) + public Character ReadCharacterData(NetIncomingMessage inc, bool isMyCharacter) { string newName = inc.ReadString(); ushort ID = inc.ReadUInt16(); diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 6edcd4ef6..5251d4705 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -282,6 +282,8 @@ namespace Barotrauma.Networking { inGameHUD.Update((float)Physics.step); + respawnManager.Update(deltaTime); + bool isCrewDead = connectedClients.Find(c => c.Character != null && !c.Character.IsDead)==null && (myCharacter == null || myCharacter.IsDead); @@ -949,6 +951,8 @@ namespace Barotrauma.Networking GameServer.Log("Game mode: " + selectedMode.Name, Color.Cyan); GameServer.Log("Level seed: " + GameMain.NetLobbyScreen.LevelSeed, Color.Cyan); + respawnManager = new RespawnManager(this); + yield return CoroutineStatus.Running; List characterInfos = new List(); @@ -972,7 +976,7 @@ namespace Barotrauma.Networking characterInfos.Add(characterInfo); } - WayPoint[] assignedWayPoints = WayPoint.SelectCrewSpawnPoints(characterInfos); + WayPoint[] assignedWayPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub); for (int i = 0; i < connectedClients.Count; i++) { @@ -1140,6 +1144,14 @@ namespace Barotrauma.Networking } + public void RespawnClients() + { + NetOutgoingMessage msg = server.CreateMessage(); + respawnManager.WriteNetworkEvent(msg); + + SendMessage(msg, NetDeliveryMethod.ReliableUnordered); + } + private void DisconnectClient(NetConnection senderConnection, string msg = "", string targetmsg = "") { Client client = connectedClients.Find(x => x.Connection == senderConnection); @@ -1611,7 +1623,7 @@ namespace Barotrauma.Networking } } - private void WriteCharacterData(NetOutgoingMessage message, string name, Character character) + public void WriteCharacterData(NetOutgoingMessage message, string name, Character character) { message.Write(name); message.Write(character.ID); diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index 7a167d71f..6b7edd427 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -39,7 +39,9 @@ namespace Barotrauma.Networking RequestFile, FileStream, - SpectateRequest + SpectateRequest, + + Respawn } enum VoteType @@ -74,6 +76,9 @@ namespace Barotrauma.Networking protected Character myCharacter; protected CharacterInfo characterInfo; + + protected RespawnManager respawnManager; + public Voting Voting; public Character Character diff --git a/Subsurface/Source/Networking/RespawnManager.cs b/Subsurface/Source/Networking/RespawnManager.cs new file mode 100644 index 000000000..8d4be8c2d --- /dev/null +++ b/Subsurface/Source/Networking/RespawnManager.cs @@ -0,0 +1,226 @@ +using Barotrauma.Items.Components; +using FarseerPhysics; +using Lidgren.Network; +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Barotrauma.Networking +{ + class RespawnManager + { + const int MinCharactersToRespawn = 1; + + const float RespawnInterval = 20.0f; + + enum State + { + Waiting, + Transporting, + Returning + } + + private NetworkMember networkMember; + + private State state; + + private Submarine respawnShuttle; + private Steering shuttleSteering; + private List shuttleDoors; + + private float respawnTimer, shuttleReturnTimer; + + public RespawnManager(NetworkMember server) + { + this.networkMember = server; + + respawnShuttle = new Submarine("Submarines/Shuttle Mark I.sub"); + respawnShuttle.Load(false); + + ResetShuttlePos(); + + respawnShuttle.GodMode = true; + + shuttleDoors = new List(); + foreach (Item item in Item.ItemList) + { + if (item.Submarine != respawnShuttle) continue; + + var steering = item.GetComponent(); + if (steering != null) shuttleSteering = steering; + + var door = item.GetComponent(); + if (door != null) shuttleDoors.Add(door); + } + + shuttleSteering.TargetPosition = ConvertUnits.ToSimUnits(Level.Loaded.StartPosition); + + respawnTimer = RespawnInterval; + } + + private List GetClientsToRespawn() + { + return networkMember.ConnectedClients.FindAll(c => c.inGame && (c.Character == null || c.Character.IsDead)); + } + + public void Update(float deltaTime) + { + switch (state) + { + case State.Waiting: + UpdateWaiting(deltaTime); + break; + case State.Transporting: + UpdateTransporting(deltaTime); + break; + case State.Returning: + UpdateReturning(deltaTime); + break; + } + } + + private void UpdateWaiting(float deltaTime) + { + var server = networkMember as GameServer; + if (server == null) return; + + respawnShuttle.Velocity = Vector2.Zero; + + shuttleSteering.AutoPilot = false; + shuttleSteering.MaintainPos = false; + + if (GetClientsToRespawn().Count < MinCharactersToRespawn) return; + + if (respawnTimer % 10.0f < 5.0f && (respawnTimer - deltaTime) % 10.0f > 5.0f) + { + string time = respawnTimer <= 60.0f ? + (int)respawnTimer + " seconds" : + (int)Math.Floor(respawnTimer / 60.0f) + " minutes"; + + server.SendChatMessage("Transportation shuttle dispatching in " + time, ChatMessageType.Server); + } + + respawnTimer -= deltaTime; + if (respawnTimer <= 0.0f) + { + Respawn(); + + respawnTimer = RespawnInterval; + state = State.Transporting; + } + } + + private void UpdateTransporting(float deltaTime) + { + if (Character.CharacterList.Any(c => c.Submarine == respawnShuttle && !c.IsDead)) return; + + shuttleReturnTimer += deltaTime; + if (shuttleReturnTimer > 10.0f) + { + state = State.Returning; + shuttleReturnTimer = 0.0f; + } + } + + private void UpdateReturning(float deltaTime) + { + shuttleReturnTimer += deltaTime; + + if (shuttleReturnTimer > 1.0f) + { + shuttleSteering.AutoPilot = true; + shuttleSteering.MaintainPos = false; + + shuttleDoors.ForEach(s => s.IsOpen = false); + + if (shuttleSteering.SteeringPath != null && shuttleSteering.SteeringPath.CurrentIndex == shuttleSteering.SteeringPath.Nodes.Count-1) + { + CoroutineManager.StartCoroutine( + ForceShuttleToPos(new Vector2(Level.Loaded.StartPosition.X, Level.Loaded.Size.Y + 1000.0f), 100.0f)); + + state = State.Waiting; + } + + shuttleReturnTimer = 0.0f; + } + } + + private void Respawn() + { + var server = networkMember as GameServer; + if (server == null) return; + + ResetShuttlePos(); + + server.SendChatMessage("Transportation shuttle dispatched"); + + server.RespawnClients(); + + CoroutineManager.StartCoroutine(ForceShuttleToPos(Level.Loaded.StartPosition, 100.0f)); + } + + private IEnumerable ForceShuttleToPos(Vector2 position, float speed) + { + respawnShuttle.SubBody.Body.IgnoreCollisionWith(Level.Loaded.ShaftBodies[0]); + + while (Math.Abs(position.Y - respawnShuttle.WorldPosition.Y) > 100.0f) + { + Vector2 displayVel = Vector2.Normalize(position - respawnShuttle.WorldPosition) * speed; + respawnShuttle.SubBody.Body.LinearVelocity = ConvertUnits.ToSimUnits(displayVel); + yield return CoroutineStatus.Running; + } + + respawnShuttle.SubBody.Body.RestoreCollisionWith(Level.Loaded.ShaftBodies[0]); + + } + + private void ResetShuttlePos() + { + respawnShuttle.SetPosition(new Vector2(Level.Loaded.StartPosition.X, Level.Loaded.Size.Y + 1000.0f)); + + respawnShuttle.Velocity = Vector2.Zero; + } + + public void WriteNetworkEvent(NetOutgoingMessage msg) + { + var server = networkMember as GameServer; + var clients = GetClientsToRespawn(); + + msg.Write((byte)PacketTypes.Respawn); + + var waypoints = WayPoint.SelectCrewSpawnPoints(clients.Select(c => c.characterInfo).ToList(), respawnShuttle); + + msg.Write((byte)clients.Count); + for (int i = 0; i < clients.Count; i++) + { + msg.Write((byte)clients[i].ID); + clients[i].Character = Character.Create(clients[i].characterInfo, waypoints[i].WorldPosition, true, false); + clients[i].Character.GiveJobItems(waypoints[i]); + + GameMain.GameSession.CrewManager.characters.Add(clients[i].Character); + + server.WriteCharacterData(msg, clients[i].Character.Name, clients[i].Character); + } + } + + public void ReadNetworkEvent(NetIncomingMessage inc) + { + ResetShuttlePos(); + + var client = networkMember as GameClient; + + int clientCount = inc.ReadByte(); + for (int i = 0; i