From 16bc68d7687aabf0d07bad2607d7674d039aad1f Mon Sep 17 00:00:00 2001 From: juanjp600 Date: Sun, 18 Jun 2017 22:41:44 -0300 Subject: [PATCH] BarotraumaServer compiles Cleanup + fixes coming up next --- BarotraumaClient/BarotraumaClient.csproj | 22 ++ .../Source/Characters/AI/AITarget.cs | 31 ++ .../Source/Characters/AI/EnemyAIController.cs | 70 +++++ .../Source/Characters/AI/HumanAIController.cs | 40 +++ .../Source/Characters/Animation/Ragdoll.cs | 100 ++++++ .../Source/Characters/CharacterNetworking.cs | 294 ++++++++++++++++++ .../Source/Events/Missions/Mission.cs | 25 ++ .../Source/Events/Missions/MissionMode.cs | 18 ++ .../GameSession/GameModes/TraitorManager.cs | 15 + .../Source/Items/CharacterInventory.cs | 85 +++++ .../Items/Components/Machines/Steering.cs | 33 -- .../Items/Components/Signal/Connection.cs | 284 +++++++++++++++++ .../Source/Items/Components/Turret.cs | 63 ++++ BarotraumaClient/Source/Items/DockingPort.cs | 75 +++++ BarotraumaClient/Source/Items/Item.cs | 20 ++ BarotraumaClient/Source/Items/Rope.cs | 53 ++++ .../Source/Map/Levels/Ruins/RuinGenerator.cs | 30 ++ .../Source/Map/Levels/WrappingWall.cs | 39 +++ BarotraumaClient/Source/Map/Map.cs | 210 +++++++++++++ BarotraumaClient/Source/Map/Submarine.cs | 228 ++++++++++++++ .../Source/Networking/EntitySpawner.cs | 44 +++ .../Networking/FileTransfer/FileReceiver.cs | 0 .../ClientEntityEventManager.cs | 0 .../NetEntityEvent/NetEntityEvent.cs | 24 ++ .../Source/Physics/PhysicsBody.cs | 92 ++++++ BarotraumaClient/Source/Utils/SaveUtil.cs | 239 ++++++++++++++ BarotraumaServer/BarotraumaServer.csproj | 67 +++- BarotraumaServer/BarotraumaServer.csproj.rej | 12 - BarotraumaServer/BarotraumaServer.csproj.user | 8 + BarotraumaServer/Properties/AssemblyInfo.cs | 1 - BarotraumaShared/BarotraumaShared.projitems | 2 - .../Source/Characters/AI/AITarget.cs | 24 +- .../Source/Characters/AI/EnemyAIController.cs | 58 +--- .../Source/Characters/AI/HumanAIController.cs | 39 +-- .../Source/Characters/Animation/Ragdoll.cs | 99 +----- BarotraumaShared/Source/Characters/Attack.cs | 2 + .../Source/Characters/CharacterNetworking.cs | 285 +---------------- .../Source/Characters/HuskInfection.cs | 8 +- .../Source/Events/Missions/CombatMission.cs | 6 + .../Source/Events/Missions/Mission.cs | 16 +- .../Source/Events/Missions/MonsterMission.cs | 2 + .../Source/Events/Missions/SalvageMission.cs | 6 +- .../GameSession/GameModes/GameModePreset.cs | 2 + .../GameSession/GameModes/MissionMode.cs | 13 +- .../GameSession/GameModes/TraitorManager.cs | 13 +- .../Source/GameSession/InfoTextManager.cs | 2 + .../Source/Items/CharacterInventory.cs | 90 +----- .../Source/Items/Components/DockingPort.cs | 69 +--- .../Items/Components/Holdable/Pickable.cs | 2 + .../Items/Components/Holdable/RepairTool.cs | 4 + .../Items/Components/Machines/Controller.cs | 6 +- .../Items/Components/Machines/Steering.cs | 31 ++ .../Items/Components/Power/PowerTransfer.cs | 2 + .../Source/Items/Components/Rope.cs | 37 +-- .../Items/Components/Signal/Connection.cs | 284 +---------------- .../Source/Items/Components/Turret.cs | 50 +-- .../Source/Items/Components/Wearable.cs | 2 + BarotraumaShared/Source/Items/Item.cs | 32 +- .../Source/Map/Levels/Ruins/RuinGenerator.cs | 49 +-- .../Source/Map/Levels/WrappingWall.cs | 31 +- BarotraumaShared/Source/Map/Map/Map.cs | 239 ++------------ BarotraumaShared/Source/Map/Submarine.cs | 216 +------------ BarotraumaShared/Source/Map/SubmarineBody.cs | 6 +- .../Source/Map/TransitionCinematic.cs | 8 + .../Source/Networking/EntitySpawner.cs | 35 +-- .../Source/Networking/GameServerLogin.cs | 2 + .../NetEntityEvent/NetEntityEvent.cs | 20 -- .../Source/Networking/RespawnManager.cs | 12 +- BarotraumaShared/Source/Networking/Voting.cs | 4 + .../Source/Physics/PhysicsBody.cs | 80 +---- BarotraumaShared/Source/Screens/GameScreen.cs | 7 +- BarotraumaShared/Source/Utils/SaveUtil.cs | 234 +------------- Barotrauma_Solution.sln | 106 ++++--- 73 files changed, 2429 insertions(+), 2028 deletions(-) create mode 100644 BarotraumaClient/Source/Characters/AI/AITarget.cs create mode 100644 BarotraumaClient/Source/Characters/AI/EnemyAIController.cs create mode 100644 BarotraumaClient/Source/Characters/AI/HumanAIController.cs create mode 100644 BarotraumaClient/Source/Characters/Animation/Ragdoll.cs create mode 100644 BarotraumaClient/Source/Characters/CharacterNetworking.cs create mode 100644 BarotraumaClient/Source/Events/Missions/Mission.cs create mode 100644 BarotraumaClient/Source/Events/Missions/MissionMode.cs create mode 100644 BarotraumaClient/Source/GameSession/GameModes/TraitorManager.cs create mode 100644 BarotraumaClient/Source/Items/Components/Signal/Connection.cs create mode 100644 BarotraumaClient/Source/Items/Components/Turret.cs create mode 100644 BarotraumaClient/Source/Items/DockingPort.cs create mode 100644 BarotraumaClient/Source/Items/Rope.cs create mode 100644 BarotraumaClient/Source/Map/Levels/Ruins/RuinGenerator.cs create mode 100644 BarotraumaClient/Source/Map/Levels/WrappingWall.cs create mode 100644 BarotraumaClient/Source/Map/Map.cs create mode 100644 BarotraumaClient/Source/Map/Submarine.cs create mode 100644 BarotraumaClient/Source/Networking/EntitySpawner.cs rename {BarotraumaShared => BarotraumaClient}/Source/Networking/FileTransfer/FileReceiver.cs (100%) rename {BarotraumaShared => BarotraumaClient}/Source/Networking/NetEntityEvent/ClientEntityEventManager.cs (100%) create mode 100644 BarotraumaClient/Source/Networking/NetEntityEvent/NetEntityEvent.cs create mode 100644 BarotraumaClient/Source/Physics/PhysicsBody.cs create mode 100644 BarotraumaClient/Source/Utils/SaveUtil.cs delete mode 100644 BarotraumaServer/BarotraumaServer.csproj.rej diff --git a/BarotraumaClient/BarotraumaClient.csproj b/BarotraumaClient/BarotraumaClient.csproj index 51cad3291..6e8bfaaec 100644 --- a/BarotraumaClient/BarotraumaClient.csproj +++ b/BarotraumaClient/BarotraumaClient.csproj @@ -64,7 +64,11 @@ + + + + @@ -73,6 +77,7 @@ + @@ -80,10 +85,13 @@ + + + @@ -125,33 +133,45 @@ + + + + + + + + + + + + @@ -161,6 +181,7 @@ + @@ -180,6 +201,7 @@ + diff --git a/BarotraumaClient/Source/Characters/AI/AITarget.cs b/BarotraumaClient/Source/Characters/AI/AITarget.cs new file mode 100644 index 000000000..05721d77b --- /dev/null +++ b/BarotraumaClient/Source/Characters/AI/AITarget.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Barotrauma +{ + partial class AITarget + { + public static bool ShowAITargets; + + public void Draw(SpriteBatch spriteBatch) + { + if (!ShowAITargets) return; + + var rangeSprite = GUI.SubmarineIcon; + + if (soundRange > 0.0f) + rangeSprite.Draw(spriteBatch, + new Vector2(WorldPosition.X, -WorldPosition.Y), + Color.Cyan * 0.1f, rangeSprite.Origin, + 0.0f, soundRange / rangeSprite.size.X); + + if (sightRange > 0.0f) + rangeSprite.Draw(spriteBatch, + new Vector2(WorldPosition.X, -WorldPosition.Y), + Color.Orange * 0.1f, rangeSprite.Origin, + 0.0f, sightRange / rangeSprite.size.X); + } + } +} diff --git a/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs b/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs new file mode 100644 index 000000000..451477959 --- /dev/null +++ b/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Xml.Linq; +using FarseerPhysics; +using Lidgren.Network; +using Microsoft.Xna.Framework; +using FarseerPhysics.Dynamics; +using Microsoft.Xna.Framework.Graphics; + +namespace Barotrauma +{ + partial class EnemyAIController : AIController + { + public override void DebugDraw(SpriteBatch spriteBatch) + { + if (Character.IsDead) return; + + Vector2 pos = Character.WorldPosition; + pos.Y = -pos.Y; + + if (selectedAiTarget != null) + { + GUI.DrawLine(spriteBatch, pos, new Vector2(selectedAiTarget.WorldPosition.X, -selectedAiTarget.WorldPosition.Y), Color.Red); + + if (wallAttackPos != Vector2.Zero) + { + GUI.DrawRectangle(spriteBatch, ConvertUnits.ToDisplayUnits(new Vector2(wallAttackPos.X, -wallAttackPos.Y)) - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Red, false); + } + + GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 20.0f, Color.Red); + } + + if (selectedAiTarget != null) + { + GUI.DrawLine(spriteBatch, + new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y), + new Vector2(selectedAiTarget.WorldPosition.X, -selectedAiTarget.WorldPosition.Y), Color.Red); + } + + GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red); + + GUI.Font.DrawString(spriteBatch, "updatetargets: " + updateTargetsTimer, pos - Vector2.UnitY * 100.0f, Color.Red); + GUI.Font.DrawString(spriteBatch, "cooldown: " + coolDownTimer, pos - Vector2.UnitY * 120.0f, Color.Red); + + + IndoorsSteeringManager pathSteering = steeringManager as IndoorsSteeringManager; + if (pathSteering == null || pathSteering.CurrentPath == null || pathSteering.CurrentPath.CurrentNode == null) return; + + GUI.DrawLine(spriteBatch, + new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y), + new Vector2(pathSteering.CurrentPath.CurrentNode.DrawPosition.X, -pathSteering.CurrentPath.CurrentNode.DrawPosition.Y), + Color.LightGreen); + + + for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++) + { + GUI.DrawLine(spriteBatch, + new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y), + new Vector2(pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.Y), + Color.LightGreen); + + GUI.SmallFont.DrawString(spriteBatch, + pathSteering.CurrentPath.Nodes[i].ID.ToString(), + new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y - 10), + Color.LightGreen); + } + } + } +} diff --git a/BarotraumaClient/Source/Characters/AI/HumanAIController.cs b/BarotraumaClient/Source/Characters/AI/HumanAIController.cs new file mode 100644 index 000000000..4daacaff6 --- /dev/null +++ b/BarotraumaClient/Source/Characters/AI/HumanAIController.cs @@ -0,0 +1,40 @@ +using Microsoft.Xna.Framework; +using System; + +namespace Barotrauma +{ + partial class HumanAIController : AIController + { + public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch) + { + if (selectedAiTarget != null) + { + GUI.DrawLine(spriteBatch, + new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y), + new Vector2(selectedAiTarget.WorldPosition.X, -selectedAiTarget.WorldPosition.Y), Color.Red); + } + + IndoorsSteeringManager pathSteering = steeringManager as IndoorsSteeringManager; + if (pathSteering == null || pathSteering.CurrentPath == null || pathSteering.CurrentPath.CurrentNode == null) return; + + GUI.DrawLine(spriteBatch, + new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y), + new Vector2(pathSteering.CurrentPath.CurrentNode.DrawPosition.X, -pathSteering.CurrentPath.CurrentNode.DrawPosition.Y), + Color.LightGreen); + + + for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++) + { + GUI.DrawLine(spriteBatch, + new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y), + new Vector2(pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.Y), + Color.LightGreen); + + GUI.SmallFont.DrawString(spriteBatch, + pathSteering.CurrentPath.Nodes[i].ID.ToString(), + new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y - 10), + Color.LightGreen); + } + } + } +} diff --git a/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs b/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs new file mode 100644 index 000000000..a5e45a18f --- /dev/null +++ b/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using FarseerPhysics; +using FarseerPhysics.Dynamics; +using FarseerPhysics.Dynamics.Contacts; +using FarseerPhysics.Dynamics.Joints; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Barotrauma +{ + partial class Ragdoll + { + public virtual void Draw(SpriteBatch spriteBatch) + { + if (simplePhysicsEnabled) return; + + Collider.UpdateDrawPosition(); + + foreach (Limb limb in Limbs) + { + limb.Draw(spriteBatch); + } + } + + public void DebugDraw(SpriteBatch spriteBatch) + { + if (!GameMain.DebugDraw || !character.Enabled) return; + if (simplePhysicsEnabled) return; + + foreach (Limb limb in Limbs) + { + + if (limb.pullJoint != null) + { + Vector2 pos = ConvertUnits.ToDisplayUnits(limb.pullJoint.WorldAnchorA); + if (currentHull != null) pos += currentHull.Submarine.DrawPosition; + pos.Y = -pos.Y; + GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)pos.Y, 5, 5), Color.Red, true, 0.01f); + } + + limb.body.DebugDraw(spriteBatch, inWater ? Color.Cyan : Color.White); + } + + Collider.DebugDraw(spriteBatch, frozen ? Color.Red : (inWater ? Color.SkyBlue : Color.Gray)); + GUI.Font.DrawString(spriteBatch, Collider.LinearVelocity.X.ToString(), new Vector2(Collider.DrawPosition.X, -Collider.DrawPosition.Y), Color.Orange); + + foreach (RevoluteJoint joint in limbJoints) + { + Vector2 pos = ConvertUnits.ToDisplayUnits(joint.WorldAnchorA); + GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), Color.White, true); + + pos = ConvertUnits.ToDisplayUnits(joint.WorldAnchorB); + GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), Color.White, true); + } + + foreach (Limb limb in Limbs) + { + if (limb.body.TargetPosition != null) + { + Vector2 pos = ConvertUnits.ToDisplayUnits((Vector2)limb.body.TargetPosition); + if (currentHull != null) pos += currentHull.Submarine.DrawPosition; + pos.Y = -pos.Y; + + GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X - 10, (int)pos.Y - 10, 20, 20), Color.Cyan, false, 0.01f); + GUI.DrawLine(spriteBatch, pos, new Vector2(limb.WorldPosition.X, -limb.WorldPosition.Y), Color.Cyan); + } + } + + if (character.MemState.Count > 1) + { + Vector2 prevPos = ConvertUnits.ToDisplayUnits(character.MemState[0].Position); + if (currentHull != null) prevPos += currentHull.Submarine.DrawPosition; + prevPos.Y = -prevPos.Y; + + for (int i = 1; i < character.MemState.Count; i++) + { + Vector2 currPos = ConvertUnits.ToDisplayUnits(character.MemState[i].Position); + if (currentHull != null) currPos += currentHull.Submarine.DrawPosition; + currPos.Y = -currPos.Y; + + GUI.DrawRectangle(spriteBatch, new Rectangle((int)currPos.X - 3, (int)currPos.Y - 3, 6, 6), Color.Cyan * 0.6f, true, 0.01f); + GUI.DrawLine(spriteBatch, prevPos, currPos, Color.Cyan * 0.6f, 0, 3); + + prevPos = currPos; + } + } + + if (ignorePlatforms) + { + GUI.DrawLine(spriteBatch, + new Vector2(Collider.DrawPosition.X, -Collider.DrawPosition.Y), + new Vector2(Collider.DrawPosition.X, -Collider.DrawPosition.Y + 50), + Color.Orange, 0, 5); + } + } + } +} diff --git a/BarotraumaClient/Source/Characters/CharacterNetworking.cs b/BarotraumaClient/Source/Characters/CharacterNetworking.cs new file mode 100644 index 000000000..7c4ae474e --- /dev/null +++ b/BarotraumaClient/Source/Characters/CharacterNetworking.cs @@ -0,0 +1,294 @@ +using Barotrauma.Networking; +using Lidgren.Network; +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Barotrauma +{ + partial class Character + { + public virtual void ClientWrite(NetBuffer msg, object[] extraData = null) + { + if (GameMain.Server != null) return; + + if (extraData != null) + { + switch ((NetEntityEvent.Type)extraData[0]) + { + case NetEntityEvent.Type.InventoryState: + msg.WriteRangedInteger(0, 2, 0); + inventory.ClientWrite(msg, extraData); + break; + case NetEntityEvent.Type.Repair: + msg.WriteRangedInteger(0, 2, 1); + msg.Write(AnimController.Anim == AnimController.Animation.CPR); + break; + case NetEntityEvent.Type.Status: + msg.WriteRangedInteger(0, 2, 2); + break; + } + msg.WritePadBits(); + } + else + { + msg.Write((byte)ClientNetObject.CHARACTER_INPUT); + + if (memInput.Count > 60) + { + memInput.RemoveRange(60, memInput.Count - 60); + } + + msg.Write(LastNetworkUpdateID); + byte inputCount = Math.Min((byte)memInput.Count, (byte)60); + msg.Write(inputCount); + for (int i = 0; i < inputCount; i++) + { + msg.WriteRangedInteger(0, (int)InputNetFlags.MaxVal, (int)memInput[i].states); + if (memInput[i].states.HasFlag(InputNetFlags.Aim)) + { + msg.Write(memInput[i].intAim); + } + if (memInput[i].states.HasFlag(InputNetFlags.Select) || memInput[i].states.HasFlag(InputNetFlags.Use)) + { + msg.Write(memInput[i].interact); + } + } + } + } + + public virtual void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime) + { + if (GameMain.Server != null) return; + + switch (type) + { + case ServerNetObject.ENTITY_POSITION: + bool facingRight = AnimController.Dir > 0.0f; + + lastRecvPositionUpdateTime = (float)NetTime.Now; + + AnimController.Frozen = false; + Enabled = true; + + UInt16 networkUpdateID = 0; + if (msg.ReadBoolean()) + { + networkUpdateID = msg.ReadUInt16(); + } + else + { + bool aimInput = msg.ReadBoolean(); + keys[(int)InputType.Aim].Held = aimInput; + keys[(int)InputType.Aim].SetState(false, aimInput); + + bool useInput = msg.ReadBoolean(); + keys[(int)InputType.Use].Held = useInput; + keys[(int)InputType.Use].SetState(false, useInput); + + bool hasAttackLimb = msg.ReadBoolean(); + if (hasAttackLimb) + { + bool attackInput = msg.ReadBoolean(); + keys[(int)InputType.Attack].Held = attackInput; + keys[(int)InputType.Attack].SetState(false, attackInput); + } + + if (aimInput) + { + double aimAngle = ((double)msg.ReadUInt16() / 65535.0) * 2.0 * Math.PI; + cursorPosition = (ViewTarget == null ? AnimController.Collider.Position : ViewTarget.Position) + + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 60.0f; + + TransformCursorPos(); + } + facingRight = msg.ReadBoolean(); + } + + bool entitySelected = msg.ReadBoolean(); + Entity selectedEntity = null; + + AnimController.Animation animation = AnimController.Animation.None; + if (entitySelected) + { + ushort entityID = msg.ReadUInt16(); + selectedEntity = FindEntityByID(entityID); + if (selectedEntity is Character) + { + bool doingCpr = msg.ReadBoolean(); + if (doingCpr && selectedCharacter != null) + { + animation = AnimController.Animation.CPR; + } + } + } + + Vector2 pos = new Vector2( + msg.ReadFloat(), + msg.ReadFloat()); + + + int index = 0; + if (GameMain.NetworkMember.Character == this && AllowInput) + { + var posInfo = new CharacterStateInfo(pos, networkUpdateID, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation); + while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID)) + index++; + + memState.Insert(index, posInfo); + } + else + { + var posInfo = new CharacterStateInfo(pos, sendingTime, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation); + while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp) + index++; + + memState.Insert(index, posInfo); + } + + break; + case ServerNetObject.ENTITY_EVENT: + + int eventType = msg.ReadRangedInteger(0, 2); + switch (eventType) + { + case 0: + inventory.ClientRead(type, msg, sendingTime); + break; + case 1: + byte ownerID = msg.ReadByte(); + ResetNetState(); + if (ownerID == GameMain.Client.ID) + { + if (controlled != null) + { + LastNetworkUpdateID = controlled.LastNetworkUpdateID; + } + + controlled = this; + IsRemotePlayer = false; + GameMain.Client.Character = this; + } + else if (controlled == this) + { + controlled = null; + IsRemotePlayer = ownerID > 0; + } + break; + case 2: + ReadStatus(msg); + break; + } + + break; + } + } + public static Character ReadSpawnData(NetBuffer inc, bool spawn = true) + { + if (GameMain.Server != null) return null; + + bool noInfo = inc.ReadBoolean(); + ushort id = inc.ReadUInt16(); + string configPath = inc.ReadString(); + + Vector2 position = new Vector2(inc.ReadFloat(), inc.ReadFloat()); + + bool enabled = inc.ReadBoolean(); + + DebugConsole.Log("Received spawn data for " + configPath); + + Character character = null; + if (noInfo) + { + if (!spawn) return null; + + character = Character.Create(configPath, position, null, true); + character.ID = id; + } + else + { + bool hasOwner = inc.ReadBoolean(); + int ownerId = hasOwner ? inc.ReadByte() : -1; + + + string newName = inc.ReadString(); + byte teamID = inc.ReadByte(); + + bool hasAi = inc.ReadBoolean(); + bool isFemale = inc.ReadBoolean(); + int headSpriteID = inc.ReadByte(); + string jobName = inc.ReadString(); + + JobPrefab jobPrefab = null; + Dictionary skillLevels = new Dictionary(); + if (!string.IsNullOrEmpty(jobName)) + { + jobPrefab = JobPrefab.List.Find(jp => jp.Name == jobName); + int skillCount = inc.ReadByte(); + for (int i = 0; i < skillCount; i++) + { + string skillName = inc.ReadString(); + int skillLevel = inc.ReadRangedInteger(0, 100); + + skillLevels.Add(skillName, skillLevel); + } + } + + if (!spawn) return null; + + + CharacterInfo ch = new CharacterInfo(configPath, newName, isFemale ? Gender.Female : Gender.Male, jobPrefab); + ch.HeadSpriteId = headSpriteID; + + System.Diagnostics.Debug.Assert(skillLevels.Count == ch.Job.Skills.Count); + if (ch.Job != null) + { + foreach (KeyValuePair skill in skillLevels) + { + Skill matchingSkill = ch.Job.Skills.Find(s => s.Name == skill.Key); + if (matchingSkill == null) + { + DebugConsole.ThrowError("Skill \"" + skill.Key + "\" not found in character \"" + newName + "\""); + continue; + } + matchingSkill.Level = skill.Value; + } + } + + character = Create(configPath, position, ch, GameMain.Client.ID != ownerId, hasAi); + character.ID = id; + character.TeamID = teamID; + + if (GameMain.Client.ID == ownerId) + { + GameMain.Client.Character = character; + Controlled = character; + + GameMain.LightManager.LosEnabled = true; + + character.memInput.Clear(); + character.memState.Clear(); + character.memLocalState.Clear(); + } + else + { + var ownerClient = GameMain.Client.ConnectedClients.Find(c => c.ID == ownerId); + if (ownerClient != null) + { + ownerClient.Character = character; + } + } + + if (configPath == Character.HumanConfigFile) + { + GameMain.GameSession.CrewManager.characters.Add(character); + } + } + + character.Enabled = Controlled == character || enabled; + + return character; + } + } +} diff --git a/BarotraumaClient/Source/Events/Missions/Mission.cs b/BarotraumaClient/Source/Events/Missions/Mission.cs new file mode 100644 index 000000000..834118cd1 --- /dev/null +++ b/BarotraumaClient/Source/Events/Missions/Mission.cs @@ -0,0 +1,25 @@ +using Barotrauma.Networking; +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Xml.Linq; + +namespace Barotrauma +{ + partial class Mission + { + public void ShowMessage(int index) + { + if (index >= headers.Count && index >= messages.Count) return; + + string header = index < headers.Count ? headers[index] : ""; + string message = index < messages.Count ? messages[index] : ""; + + GameServer.Log("Mission info: " + header + " - " + message, ServerLog.MessageType.ServerMessage); + + new GUIMessageBox(header, message); + } + } +} diff --git a/BarotraumaClient/Source/Events/Missions/MissionMode.cs b/BarotraumaClient/Source/Events/Missions/MissionMode.cs new file mode 100644 index 000000000..05387054d --- /dev/null +++ b/BarotraumaClient/Source/Events/Missions/MissionMode.cs @@ -0,0 +1,18 @@ +using Microsoft.Xna.Framework; + +namespace Barotrauma +{ + partial class MissionMode : GameMode + { + public override void MsgBox() + { + if (mission == null) return; + + var missionMsg = new GUIMessageBox(mission.Name, mission.Description, 400, 400); + missionMsg.UserData = "missionstartmessage"; + + Networking.GameServer.Log("Mission: " + mission.Name, Networking.ServerLog.MessageType.ServerMessage); + Networking.GameServer.Log(mission.Description, Networking.ServerLog.MessageType.ServerMessage); + } + } +} diff --git a/BarotraumaClient/Source/GameSession/GameModes/TraitorManager.cs b/BarotraumaClient/Source/GameSession/GameModes/TraitorManager.cs new file mode 100644 index 000000000..c0ad48d03 --- /dev/null +++ b/BarotraumaClient/Source/GameSession/GameModes/TraitorManager.cs @@ -0,0 +1,15 @@ +using Barotrauma.Networking; +using System.Collections.Generic; + +namespace Barotrauma +{ + partial class TraitorManager + { + public static void CreateStartPopUp(string targetName) + { + new GUIMessageBox("You are the Traitor!", + "Your secret task is to assassinate " + targetName + "! Discretion is an utmost concern; sinking the submarine and killing the entire crew " + + "will arouse suspicion amongst the Fleet. If possible, make the death look like an accident.", 400, 350); + } + } +} diff --git a/BarotraumaClient/Source/Items/CharacterInventory.cs b/BarotraumaClient/Source/Items/CharacterInventory.cs index c509c3201..101eb54c1 100644 --- a/BarotraumaClient/Source/Items/CharacterInventory.cs +++ b/BarotraumaClient/Source/Items/CharacterInventory.cs @@ -78,5 +78,90 @@ namespace Barotrauma return UseItemOnSelf(slotIndex); } + + protected override void CreateSlots() + { + if (slots == null) slots = new InventorySlot[capacity]; + + int rectWidth = 40, rectHeight = 40; + + Rectangle slotRect = new Rectangle(0, 0, rectWidth, rectHeight); + for (int i = 0; i < capacity; i++) + { + if (slots[i] == null) slots[i] = new InventorySlot(slotRect); + + slots[i].Disabled = false; + + slotRect.X = (int)(SlotPositions[i].X + DrawOffset.X); + slotRect.Y = (int)(SlotPositions[i].Y + DrawOffset.Y); + + slots[i].Rect = slotRect; + + slots[i].Color = limbSlots[i] == InvSlotType.Any ? Color.White * 0.2f : Color.White * 0.4f; + } + + MergeSlots(); + } + + public void DrawOwn(SpriteBatch spriteBatch) + { + if (slots == null) CreateSlots(); + + Rectangle slotRect = new Rectangle(0, 0, 40, 40); + + for (int i = 0; i < capacity; i++) + { + slotRect.X = (int)(SlotPositions[i].X + DrawOffset.X); + slotRect.Y = (int)(SlotPositions[i].Y + DrawOffset.Y); + + if (i == 1) //head + { + spriteBatch.Draw(icons, new Vector2(slotRect.Center.X, slotRect.Center.Y), + new Rectangle(0, 0, 56, 128), Color.White * 0.7f, 0.0f, + new Vector2(28.0f, 64.0f), Vector2.One, + SpriteEffects.None, 0.1f); + } + else if (i == 3 || i == 4) + { + spriteBatch.Draw(icons, new Vector2(slotRect.Center.X, slotRect.Center.Y), + new Rectangle(92, 41 * (4 - i), 36, 40), Color.White * 0.7f, 0.0f, + new Vector2(18.0f, 20.0f), Vector2.One, + SpriteEffects.None, 0.1f); + } + else if (i == 5) + { + spriteBatch.Draw(icons, new Vector2(slotRect.Center.X, slotRect.Center.Y), + new Rectangle(57, 0, 31, 32), Color.White * 0.7f, 0.0f, + new Vector2(15.0f, 16.0f), Vector2.One, + SpriteEffects.None, 0.1f); + } + } + + base.Draw(spriteBatch); + + if (character == Character.Controlled) + { + for (int i = 0; i < capacity; i++) + { + if (selectedSlot != i && + Items[i] != null && Items[i].CanUseOnSelf && character.HasSelectedItem(Items[i])) + { + useOnSelfButton[i - 3].Draw(spriteBatch); + } + } + } + + if (selectedSlot > -1) + { + DrawSubInventory(spriteBatch, selectedSlot); + + if (selectedSlot > -1 && + !slots[selectedSlot].IsHighlighted && + (draggingItem == null || draggingItem.Container != Items[selectedSlot])) + { + selectedSlot = -1; + } + } + } } } diff --git a/BarotraumaClient/Source/Items/Components/Machines/Steering.cs b/BarotraumaClient/Source/Items/Components/Machines/Steering.cs index ef47d035a..c2ec43737 100644 --- a/BarotraumaClient/Source/Items/Components/Machines/Steering.cs +++ b/BarotraumaClient/Source/Items/Components/Machines/Steering.cs @@ -155,39 +155,6 @@ namespace Barotrauma.Items.Components } } - public void SetDestinationLevelStart() - { - AutoPilot = true; - - MaintainPos = false; - posToMaintain = null; - - levelEndTickBox.Selected = false; - - if (!levelStartTickBox.Selected) - { - levelStartTickBox.Selected = true; - UpdatePath(); - } - } - - public void SetDestinationLevelEnd() - { - AutoPilot = false; - - MaintainPos = false; - posToMaintain = null; - - levelStartTickBox.Selected = false; - - if (!levelEndTickBox.Selected) - { - levelEndTickBox.Selected = true; - UpdatePath(); - } - } - - private bool SelectDestination(GUITickBox tickBox) { unsentChanges = true; diff --git a/BarotraumaClient/Source/Items/Components/Signal/Connection.cs b/BarotraumaClient/Source/Items/Components/Signal/Connection.cs new file mode 100644 index 000000000..85b8f4723 --- /dev/null +++ b/BarotraumaClient/Source/Items/Components/Signal/Connection.cs @@ -0,0 +1,284 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +namespace Barotrauma.Items.Components +{ + partial class Connection + { + private static Texture2D panelTexture; + private static Sprite connector; + private static Sprite wireVertical; + + public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character) + { + + int width = 400, height = 200; + int x = GameMain.GraphicsWidth / 2 - width / 2, y = GameMain.GraphicsHeight - height; + + Rectangle panelRect = new Rectangle(x, y, width, height); + + spriteBatch.Draw(panelTexture, panelRect, new Rectangle(0, 512 - height, width, height), Color.White); + + //GUI.DrawRectangle(spriteBatch, panelRect, Color.Black, true); + + bool mouseInRect = panelRect.Contains(PlayerInput.MousePosition); + + int totalWireCount = 0; + foreach (Connection c in panel.Connections) + { + totalWireCount += c.Wires.Count(w => w != null); + } + + Wire equippedWire = null; + + //if the Character using the panel has a wire item equipped + //and the wire hasn't been connected yet, draw it on the panel + for (int i = 0; i < character.SelectedItems.Length; i++) + { + Item selectedItem = character.SelectedItems[i]; + + if (selectedItem == null) continue; + + Wire wireComponent = selectedItem.GetComponent(); + if (wireComponent != null) equippedWire = wireComponent; + } + + Vector2 rightPos = new Vector2(x + width - 130, y + 50); + Vector2 leftPos = new Vector2(x + 130, y + 50); + + Vector2 rightWirePos = new Vector2(x + width - 5, y + 30); + + Vector2 leftWirePos = new Vector2(x + 5, y + 30); + + int wireInterval = (height - 20) / Math.Max(totalWireCount, 1); + + foreach (Connection c in panel.Connections) + { + //if dragging a wire, let the Inventory know so that the wire can be + //dropped or dragged from the panel to the players inventory + if (draggingConnected != null) + { + int linkIndex = c.FindWireIndex(draggingConnected.Item); + if (linkIndex > -1) + { + Inventory.draggingItem = c.Wires[linkIndex].Item; + } + } + + //outputs are drawn at the right side of the panel, inputs at the left + if (c.IsOutput) + { + c.Draw(spriteBatch, panel.Item, rightPos, + new Vector2(rightPos.X - GUI.SmallFont.MeasureString(c.Name).X - 20, rightPos.Y + 3), + rightWirePos, + mouseInRect, equippedWire, + wireInterval); + + rightPos.Y += 30; + rightWirePos.Y += c.Wires.Count(w => w != null) * wireInterval; + } + else + { + c.Draw(spriteBatch, panel.Item, leftPos, + new Vector2(leftPos.X + 20, leftPos.Y - 12), + leftWirePos, + mouseInRect, equippedWire, + wireInterval); + + leftPos.Y += 30; + leftWirePos.Y += c.Wires.Count(w => w != null) * wireInterval; + //leftWireX -= wireInterval; + } + } + + if (draggingConnected != null) + { + DrawWire(spriteBatch, draggingConnected, draggingConnected.Item, PlayerInput.MousePosition, new Vector2(x + width / 2, y + height), mouseInRect, null); + + if (!PlayerInput.LeftButtonHeld()) + { + if (GameMain.Client != null) + { + panel.Item.CreateClientEvent(panel); + } + else if (GameMain.Server != null) + { + panel.Item.CreateServerEvent(panel); + } + + draggingConnected = null; + } + } + + //if the Character using the panel has a wire item equipped + //and the wire hasn't been connected yet, draw it on the panel + if (equippedWire != null) + { + if (panel.Connections.Find(c => c.Wires.Contains(equippedWire)) == null) + { + DrawWire(spriteBatch, equippedWire, equippedWire.Item, + new Vector2(x + width / 2, y + height - 100), + new Vector2(x + width / 2, y + height), mouseInRect, null); + + if (draggingConnected == equippedWire) Inventory.draggingItem = equippedWire.Item; + } + } + + //stop dragging a wire item if cursor is outside the panel + if (mouseInRect) Inventory.draggingItem = null; + + + spriteBatch.Draw(panelTexture, panelRect, new Rectangle(0, 0, width, height), Color.White); + + } + + private void Draw(SpriteBatch spriteBatch, Item item, Vector2 position, Vector2 labelPos, Vector2 wirePosition, bool mouseIn, Wire equippedWire, float wireInterval) + { + //spriteBatch.DrawString(GUI.SmallFont, Name, new Vector2(labelPos.X, labelPos.Y-10), Color.White); + GUI.DrawString(spriteBatch, labelPos, Name, IsPower ? Color.Red : Color.White, Color.Black, 0, GUI.SmallFont); + + GUI.DrawRectangle(spriteBatch, new Rectangle((int)position.X - 10, (int)position.Y - 10, 20, 20), Color.White); + spriteBatch.Draw(panelTexture, position - new Vector2(16.0f, 16.0f), new Rectangle(64, 256, 32, 32), Color.White); + + for (int i = 0; i < MaxLinked; i++) + { + if (Wires[i] == null || Wires[i].Hidden || draggingConnected == Wires[i]) continue; + + Connection recipient = Wires[i].OtherConnection(this); + + DrawWire(spriteBatch, Wires[i], (recipient == null) ? Wires[i].Item : recipient.item, position, wirePosition, mouseIn, equippedWire); + + wirePosition.Y += wireInterval; + } + + if (draggingConnected != null && Vector2.Distance(position, PlayerInput.MousePosition) < 13.0f) + { + spriteBatch.Draw(panelTexture, position - new Vector2(21.5f, 21.5f), new Rectangle(106, 250, 43, 43), Color.White); + + if (!PlayerInput.LeftButtonHeld()) + { + //find an empty cell for the new connection + int index = FindWireIndex(null); + + if (index > -1 && !Wires.Contains(draggingConnected)) + { + bool alreadyConnected = draggingConnected.IsConnectedTo(item); + + draggingConnected.RemoveConnection(item); + + if (draggingConnected.Connect(this, !alreadyConnected, true)) Wires[index] = draggingConnected; + } + } + } + + int screwIndex = (position.Y % 60 < 30) ? 0 : 1; + + if (Wires.Any(w => w != null && w != draggingConnected)) + { + spriteBatch.Draw(panelTexture, position - new Vector2(16.0f, 16.0f), new Rectangle(screwIndex * 32, 256, 32, 32), Color.White); + } + + } + + private static void DrawWire(SpriteBatch spriteBatch, Wire wire, Item item, Vector2 end, Vector2 start, bool mouseIn, Wire equippedWire) + { + if (draggingConnected == wire) + { + if (!mouseIn) return; + end = PlayerInput.MousePosition; + start.X = (start.X + end.X) / 2.0f; + } + + int textX = (int)start.X; + if (start.X < end.X) + textX -= 10; + else + textX += 10; + + bool canDrag = equippedWire == null || equippedWire == wire; + + float alpha = canDrag ? 1.0f : 0.5f; + + bool mouseOn = + canDrag && + ((PlayerInput.MousePosition.X > Math.Min(start.X, end.X) && + PlayerInput.MousePosition.X < Math.Max(start.X, end.X) && + MathUtils.LineToPointDistance(start, end, PlayerInput.MousePosition) < 6) || + Vector2.Distance(end, PlayerInput.MousePosition) < 20.0f || + new Rectangle((start.X < end.X) ? textX - 100 : textX, (int)start.Y - 5, 100, 14).Contains(PlayerInput.MousePosition)); + + string label = wire.Locked ? item.Name + "\n(Locked)" : item.Name; + + GUI.DrawString(spriteBatch, + new Vector2(start.X < end.X ? textX - GUI.SmallFont.MeasureString(label).X : textX, start.Y - 5.0f), + label, + (mouseOn ? Color.Gold : Color.White) * (wire.Locked ? 0.6f : 1.0f), Color.Black * 0.8f, + 3, GUI.SmallFont); + + var wireEnd = end + Vector2.Normalize(start - end) * 30.0f; + + float dist = Vector2.Distance(start, wireEnd); + + if (mouseOn) + { + spriteBatch.Draw(wireVertical.Texture, new Rectangle(wireEnd.ToPoint(), new Point(18, (int)dist)), wireVertical.SourceRect, + Color.Gold, + MathUtils.VectorToAngle(end - start) + MathHelper.PiOver2, //angle of line (calulated above) + new Vector2(6, 0), // point in line about which to rotate + SpriteEffects.None, + 0.0f); + } + spriteBatch.Draw(wireVertical.Texture, new Rectangle(wireEnd.ToPoint(), new Point(12, (int)dist)), wireVertical.SourceRect, + wire.Item.Color * alpha, + MathUtils.VectorToAngle(end - start) + MathHelper.PiOver2, //angle of line (calulated above) + new Vector2(6, 0), // point in line about which to rotate + SpriteEffects.None, + 0.0f); + + connector.Draw(spriteBatch, end, Color.White, new Vector2(10.0f, 10.0f), MathUtils.VectorToAngle(end - start) + MathHelper.PiOver2); + + if (draggingConnected == null && canDrag) + { + if (mouseOn) + { + ConnectionPanel.HighlightedWire = wire; + + if (!wire.Locked) + { + //start dragging the wire + if (PlayerInput.LeftButtonHeld()) draggingConnected = wire; + } + } + } + } + + public void Save(XElement parentElement) + { + XElement newElement = new XElement(IsOutput ? "output" : "input", new XAttribute("name", Name)); + + Array.Sort(Wires, delegate (Wire wire1, Wire wire2) + { + if (wire1 == null) return 1; + if (wire2 == null) return -1; + return wire1.Item.ID.CompareTo(wire2.Item.ID); + }); + + for (int i = 0; i < MaxLinked; i++) + { + if (Wires[i] == null) continue; + + //Connection recipient = wires[i].OtherConnection(this); + + //int connectionIndex = recipient.item.Connections.FindIndex(x => x == recipient); + newElement.Add(new XElement("link", + new XAttribute("w", Wires[i].Item.ID.ToString()))); + } + + parentElement.Add(newElement); + } + } +} diff --git a/BarotraumaClient/Source/Items/Components/Turret.cs b/BarotraumaClient/Source/Items/Components/Turret.cs new file mode 100644 index 000000000..2ec831fc0 --- /dev/null +++ b/BarotraumaClient/Source/Items/Components/Turret.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml.Linq; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using FarseerPhysics; +using Barotrauma.Networking; +using Lidgren.Network; + +namespace Barotrauma.Items.Components +{ + partial class Turret : Powered, IDrawableComponent, IServerSerializable + { + public void Draw(SpriteBatch spriteBatch, bool editing = false) + { + Vector2 drawPos = new Vector2(item.Rect.X, item.Rect.Y); + if (item.Submarine != null) drawPos += item.Submarine.DrawPosition; + drawPos.Y = -drawPos.Y; + + if (barrelSprite != null) + { + barrelSprite.Draw(spriteBatch, + drawPos + barrelPos, Color.White, + rotation + MathHelper.PiOver2, 1.0f, + SpriteEffects.None, item.Sprite.Depth + 0.01f); + } + + if (!editing) return; + + GUI.DrawLine(spriteBatch, + drawPos + barrelPos, + drawPos + barrelPos + new Vector2((float)Math.Cos(minRotation), (float)Math.Sin(minRotation)) * 60.0f, + Color.Green); + + GUI.DrawLine(spriteBatch, + drawPos + barrelPos, + drawPos + barrelPos + new Vector2((float)Math.Cos(maxRotation), (float)Math.Sin(maxRotation)) * 60.0f, + Color.Green); + + GUI.DrawLine(spriteBatch, + drawPos + barrelPos, + drawPos + barrelPos + new Vector2((float)Math.Cos((maxRotation + minRotation) / 2), (float)Math.Sin((maxRotation + minRotation) / 2)) * 60.0f, + Color.LightGreen); + + } + + public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime) + { + UInt16 projectileID = msg.ReadUInt16(); + Item projectile = Entity.FindEntityByID(projectileID) as Item; + + if (projectile == null) + { + DebugConsole.ThrowError("Failed to launch a projectile - item with the ID \"" + projectileID + " not found"); + return; + } + + Launch(projectile); + PlaySound(ActionType.OnUse, item.WorldPosition); + } + } +} diff --git a/BarotraumaClient/Source/Items/DockingPort.cs b/BarotraumaClient/Source/Items/DockingPort.cs new file mode 100644 index 000000000..699b05976 --- /dev/null +++ b/BarotraumaClient/Source/Items/DockingPort.cs @@ -0,0 +1,75 @@ +using Barotrauma.Networking; +using FarseerPhysics; +using FarseerPhysics.Dynamics; +using FarseerPhysics.Dynamics.Joints; +using FarseerPhysics.Factories; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Barotrauma.Items.Components +{ + partial class DockingPort : ItemComponent, IDrawableComponent, IServerSerializable + { + public void Draw(SpriteBatch spriteBatch, bool editing) + { + if (dockingState == 0.0f) return; + + Vector2 drawPos = item.DrawPosition; + drawPos.Y = -drawPos.Y; + + var rect = overlaySprite.SourceRect; + + if (IsHorizontal) + { + drawPos.Y -= rect.Height / 2; + + if (dockingDir == 1) + { + spriteBatch.Draw(overlaySprite.Texture, + drawPos, + new Rectangle( + rect.Center.X + (int)(rect.Width / 2 * (1.0f - dockingState)), rect.Y, + (int)(rect.Width / 2 * dockingState), rect.Height), Color.White); + + } + else + { + spriteBatch.Draw(overlaySprite.Texture, + drawPos - Vector2.UnitX * (rect.Width / 2 * dockingState), + new Rectangle( + rect.X, rect.Y, + (int)(rect.Width / 2 * dockingState), rect.Height), Color.White); + } + } + else + { + drawPos.X -= rect.Width / 2; + + if (dockingDir == 1) + { + spriteBatch.Draw(overlaySprite.Texture, + drawPos - Vector2.UnitY * (rect.Height / 2 * dockingState), + new Rectangle( + rect.X, rect.Y, + rect.Width, (int)(rect.Height / 2 * dockingState)), Color.White); + } + else + { + spriteBatch.Draw(overlaySprite.Texture, + drawPos, + new Rectangle( + rect.X, rect.Y + rect.Height / 2 + (int)(rect.Height / 2 * (1.0f - dockingState)), + rect.Width, (int)(rect.Height / 2 * dockingState)), Color.White); + } + } + } + + } +} diff --git a/BarotraumaClient/Source/Items/Item.cs b/BarotraumaClient/Source/Items/Item.cs index e09372970..aa385d788 100644 --- a/BarotraumaClient/Source/Items/Item.cs +++ b/BarotraumaClient/Source/Items/Item.cs @@ -264,6 +264,26 @@ namespace Barotrauma } return editingHUD; } + + public virtual void UpdateHUD(Camera cam, Character character) + { + if (condition <= 0.0f) + { + FixRequirement.UpdateHud(this, character); + return; + } + + if (HasInGameEditableProperties) + { + UpdateEditing(cam); + } + + foreach (ItemComponent ic in components) + { + if (ic.CanBeSelected) ic.UpdateHUD(character); + } + } + public virtual void DrawHUD(SpriteBatch spriteBatch, Camera cam, Character character) { if (condition <= 0.0f) diff --git a/BarotraumaClient/Source/Items/Rope.cs b/BarotraumaClient/Source/Items/Rope.cs new file mode 100644 index 000000000..2db3e76e4 --- /dev/null +++ b/BarotraumaClient/Source/Items/Rope.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using FarseerPhysics; +using FarseerPhysics.Collision.Shapes; +using FarseerPhysics.Common; +using FarseerPhysics.Dynamics; +using FarseerPhysics.Dynamics.Joints; +using FarseerPhysics.Factories; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Barotrauma.Items.Components +{ + partial class Rope : ItemComponent, IDrawableComponent + { + public void Draw(SpriteBatch spriteBatch, bool editing = false) + { + if (!IsActive) return; + + RevoluteJoint firstJoint = null; + + for (int i = 0; i < ropeBodies.Length - 1; i++) + { + if (!ropeBodies[i].Enabled) continue; + + if (firstJoint == null) firstJoint = ropeJoints[i]; + + DrawSection(spriteBatch, ropeJoints[i].WorldAnchorA, ropeJoints[i + 1].WorldAnchorA, i); + } + + if (gunJoint == null || firstJoint == null) return; + + DrawSection(spriteBatch, gunJoint.WorldAnchorA, firstJoint.WorldAnchorA, 0); + + } + + private void DrawSection(SpriteBatch spriteBatch, Vector2 start, Vector2 end, int i) + { + start.Y = -start.Y; + end.Y = -end.Y; + + spriteBatch.Draw(sprite.Texture, + ConvertUnits.ToDisplayUnits(start), null, Color.White, + MathUtils.VectorToAngle(end - start), + new Vector2(0.0f, sprite.size.Y / 2.0f), + new Vector2((ConvertUnits.ToDisplayUnits(Vector2.Distance(start, end))) / sprite.Texture.Width, 1.0f), + SpriteEffects.None, + sprite.Depth + i * 0.00001f); + } + } +} diff --git a/BarotraumaClient/Source/Map/Levels/Ruins/RuinGenerator.cs b/BarotraumaClient/Source/Map/Levels/Ruins/RuinGenerator.cs new file mode 100644 index 000000000..5a5e343b7 --- /dev/null +++ b/BarotraumaClient/Source/Map/Levels/Ruins/RuinGenerator.cs @@ -0,0 +1,30 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Voronoi2; + +namespace Barotrauma.RuinGeneration +{ + partial class Ruin + { + public void Draw(SpriteBatch spriteBatch) + { + //foreach (BTRoom room in leaves) + //{ + // GUI.DrawRectangle(spriteBatch, room.Rect, Color.White); + //} + + //foreach (Corridor corr in corridors) + //{ + // GUI.DrawRectangle(spriteBatch, corr.Rect, Color.Blue); + //} + + foreach (Line line in walls) + { + GUI.DrawLine(spriteBatch, new Vector2(line.A.X, -line.A.Y), new Vector2(line.B.X, -line.B.Y), Color.Red, 0.0f, 10); + } + } + } +} diff --git a/BarotraumaClient/Source/Map/Levels/WrappingWall.cs b/BarotraumaClient/Source/Map/Levels/WrappingWall.cs new file mode 100644 index 000000000..c1e2fb655 --- /dev/null +++ b/BarotraumaClient/Source/Map/Levels/WrappingWall.cs @@ -0,0 +1,39 @@ +using FarseerPhysics; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using Voronoi2; + +namespace Barotrauma +{ + partial class WrappingWall : IDisposable + { + private VertexBuffer wallVertices, bodyVertices; + + public VertexBuffer WallVertices + { + get { return wallVertices; } + } + + public VertexBuffer BodyVertices + { + get { return bodyVertices; } + } + + public void SetWallVertices(VertexPositionTexture[] vertices) + { + wallVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly); + wallVertices.SetData(vertices); + } + + public void SetBodyVertices(VertexPositionColor[] vertices) + { + bodyVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColor.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly); + bodyVertices.SetData(vertices); + } + } +} diff --git a/BarotraumaClient/Source/Map/Map.cs b/BarotraumaClient/Source/Map/Map.cs new file mode 100644 index 000000000..14d4da9f0 --- /dev/null +++ b/BarotraumaClient/Source/Map/Map.cs @@ -0,0 +1,210 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using Voronoi2; + +namespace Barotrauma +{ + partial class Map + { + private static Sprite iceTexture; + private static Texture2D iceCraters; + private static Texture2D iceCrack; + + public void Update(float deltaTime, Rectangle rect, float scale = 1.0f) + { + Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y); + Vector2 offset = -currentLocation.MapPosition; + + float maxDist = 20.0f; + float closestDist = 0.0f; + highlightedLocation = null; + for (int i = 0; i < locations.Count; i++) + { + Location location = locations[i]; + Vector2 pos = rectCenter + (location.MapPosition + offset) * scale; + + if (!rect.Contains(pos)) continue; + + float dist = Vector2.Distance(PlayerInput.MousePosition, pos); + if (dist < maxDist && (highlightedLocation == null || dist < closestDist)) + { + closestDist = dist; + highlightedLocation = location; + } + } + + foreach (LocationConnection connection in connections) + { + if (highlightedLocation != currentLocation && + connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(currentLocation)) + { + if (PlayerInput.LeftButtonClicked() && + selectedLocation != highlightedLocation && highlightedLocation != null) + { + selectedConnection = connection; + selectedLocation = highlightedLocation; + GameMain.LobbyScreen.SelectLocation(highlightedLocation, connection); + } + } + } + } + + public void Draw(SpriteBatch spriteBatch, Rectangle rect, float scale = 1.0f) + { + Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y); + Vector2 offset = -currentLocation.MapPosition; + + iceTexture.DrawTiled(spriteBatch, new Vector2(rect.X, rect.Y), new Vector2(rect.Width, rect.Height), Vector2.Zero, Color.White * 0.8f); + + foreach (LocationConnection connection in connections) + { + Color crackColor = Color.White * Math.Max(connection.Difficulty / 100.0f, 1.5f); + + if (selectedLocation != currentLocation && + (connection.Locations.Contains(selectedLocation) && connection.Locations.Contains(currentLocation))) + { + crackColor = Color.Red; + } + else if (highlightedLocation != currentLocation && + (connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(currentLocation))) + { + crackColor = Color.Red * 0.5f; + } + else if (!connection.Passed) + { + crackColor *= 0.2f; + } + + for (int i = 0; i < connection.CrackSegments.Count; i++) + { + var segment = connection.CrackSegments[i]; + + Vector2 start = rectCenter + (segment[0] + offset) * scale; + Vector2 end = rectCenter + (segment[1] + offset) * scale; + + if (!rect.Contains(start) && !rect.Contains(end)) + { + continue; + } + else + { + Vector2? intersection = MathUtils.GetLineRectangleIntersection(start, end, new Rectangle(rect.X, rect.Y + rect.Height, rect.Width, rect.Height)); + if (intersection != null) + { + if (!rect.Contains(start)) + { + start = (Vector2)intersection; + } + else + { + end = (Vector2)intersection; + } + } + } + + float dist = Vector2.Distance(start, end); + + int width = (int)(MathHelper.Clamp(connection.Difficulty, 2.0f, 20.0f) * scale); + + spriteBatch.Draw(iceCrack, + new Rectangle((int)start.X, (int)start.Y, (int)dist + 2, width), + new Rectangle(0, 0, iceCrack.Width, 60), crackColor, MathUtils.VectorToAngle(end - start), + new Vector2(0, 30), SpriteEffects.None, 0.01f); + } + } + + rect.Inflate(8, 8); + GUI.DrawRectangle(spriteBatch, rect, Color.Black, false, 0.0f, 8); + GUI.DrawRectangle(spriteBatch, rect, Color.LightGray); + + for (int i = 0; i < locations.Count; i++) + { + Location location = locations[i]; + Vector2 pos = rectCenter + (location.MapPosition + offset) * scale; + + Rectangle drawRect = location.Type.Sprite.SourceRect; + Rectangle sourceRect = drawRect; + drawRect.X = (int)pos.X - drawRect.Width / 2; + drawRect.Y = (int)pos.Y - drawRect.Width / 2; + + if (!rect.Intersects(drawRect)) continue; + + Color color = location.Connections.Find(c => c.Locations.Contains(currentLocation)) == null ? Color.White : Color.Green; + + color *= (location.Discovered) ? 0.8f : 0.2f; + + if (location == currentLocation) color = Color.Orange; + + if (drawRect.X < rect.X) + { + sourceRect.X += rect.X - drawRect.X; + sourceRect.Width -= sourceRect.X; + drawRect.X = rect.X; + } + else if (drawRect.Right > rect.Right) + { + sourceRect.Width -= (drawRect.Right - rect.Right); + } + + if (drawRect.Y < rect.Y) + { + sourceRect.Y += rect.Y - drawRect.Y; + sourceRect.Height -= sourceRect.Y; + drawRect.Y = rect.Y; + } + else if (drawRect.Bottom > rect.Bottom) + { + sourceRect.Height -= drawRect.Bottom - rect.Bottom; + } + + drawRect.Width = sourceRect.Width; + drawRect.Height = sourceRect.Height; + + spriteBatch.Draw(location.Type.Sprite.Texture, drawRect, sourceRect, color); + } + + for (int i = 0; i < 3; i++) + { + Location location = (i == 0) ? highlightedLocation : selectedLocation; + if (i == 2) location = currentLocation; + + if (location == null) continue; + + Vector2 pos = rectCenter + (location.MapPosition + offset) * scale; + pos.X = (int)(pos.X + location.Type.Sprite.SourceRect.Width * 0.6f); + pos.Y = (int)(pos.Y - 10); + GUI.DrawString(spriteBatch, pos, location.Name, Color.White, Color.Black * 0.8f, 3); + } + + } + + public void Save(XElement element) + { + XElement mapElement = new XElement("map"); + + mapElement.Add(new XAttribute("currentlocation", CurrentLocationIndex)); + mapElement.Add(new XAttribute("seed", Seed)); + mapElement.Add(new XAttribute("size", size)); + + List discoveredLocations = new List(); + for (int i = 0; i < locations.Count; i++) + { + if (locations[i].Discovered) discoveredLocations.Add(i); + } + mapElement.Add(new XAttribute("discovered", string.Join(",", discoveredLocations))); + + List passedConnections = new List(); + for (int i = 0; i < connections.Count; i++) + { + if (connections[i].Passed) passedConnections.Add(i); + } + mapElement.Add(new XAttribute("passed", string.Join(",", passedConnections))); + + element.Add(mapElement); + } + } +} diff --git a/BarotraumaClient/Source/Map/Submarine.cs b/BarotraumaClient/Source/Map/Submarine.cs new file mode 100644 index 000000000..a16c7fa8c --- /dev/null +++ b/BarotraumaClient/Source/Map/Submarine.cs @@ -0,0 +1,228 @@ +using Barotrauma.Networking; +using FarseerPhysics; +using FarseerPhysics.Common; +using FarseerPhysics.Dynamics; +using Lidgren.Network; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Xml.Linq; +using Voronoi2; + +namespace Barotrauma +{ + partial class Submarine : Entity, IServerSerializable + { + public static void Draw(SpriteBatch spriteBatch, bool editing = false) + { + var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.mapEntityList; + + foreach (MapEntity e in entitiesToRender) + { + e.Draw(spriteBatch, editing); + } + } + + public static void DrawFront(SpriteBatch spriteBatch, bool editing = false, Predicate predicate = null) + { + var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.mapEntityList; + + foreach (MapEntity e in entitiesToRender) + { + if (!e.DrawOverWater) continue; + + if (predicate != null) + { + if (!predicate(e)) continue; + } + + e.Draw(spriteBatch, editing, false); + } + + if (GameMain.DebugDraw) + { + foreach (Submarine sub in Submarine.Loaded) + { + Rectangle worldBorders = sub.Borders; + worldBorders.Location += sub.WorldPosition.ToPoint(); + worldBorders.Y = -worldBorders.Y; + + GUI.DrawRectangle(spriteBatch, worldBorders, Color.White, false, 0, 5); + + if (sub.subBody.MemPos.Count < 2) continue; + + Vector2 prevPos = ConvertUnits.ToDisplayUnits(sub.subBody.MemPos[0].Position); + prevPos.Y = -prevPos.Y; + + for (int i = 1; i < sub.subBody.MemPos.Count; i++) + { + Vector2 currPos = ConvertUnits.ToDisplayUnits(sub.subBody.MemPos[i].Position); + currPos.Y = -currPos.Y; + + GUI.DrawRectangle(spriteBatch, new Rectangle((int)currPos.X - 10, (int)currPos.Y - 10, 20, 20), Color.Blue * 0.6f, true, 0.01f); + GUI.DrawLine(spriteBatch, prevPos, currPos, Color.Cyan * 0.5f, 0, 5); + + prevPos = currPos; + } + } + } + } + + public static float DamageEffectCutoff; + + public static void DrawDamageable(SpriteBatch spriteBatch, Effect damageEffect, bool editing = false) + { + var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.mapEntityList; + + foreach (MapEntity e in entitiesToRender) + { + if (e.DrawDamageEffect) + e.DrawDamage(spriteBatch, damageEffect); + } + if (damageEffect != null) + { + damageEffect.Parameters["aCutoff"].SetValue(0.0f); + damageEffect.Parameters["cCutoff"].SetValue(0.0f); + + DamageEffectCutoff = 0.0f; + } + } + + public static void DrawBack(SpriteBatch spriteBatch, bool editing = false, Predicate predicate = null) + { + var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.mapEntityList; + + foreach (MapEntity e in entitiesToRender) + { + if (!e.DrawBelowWater) continue; + + if (predicate != null) + { + if (!predicate(e)) continue; + } + + e.Draw(spriteBatch, editing, true); + } + } + + public bool Save() + { + return SaveAs(filePath); + } + + public bool SaveAs(string filePath) + { + name = System.IO.Path.GetFileNameWithoutExtension(filePath); + + XDocument doc = new XDocument(new XElement("Submarine")); + SaveToXElement(doc.Root); + + hash = new Md5Hash(doc); + doc.Root.Add(new XAttribute("md5hash", hash.Hash)); + + try + { + SaveUtil.CompressStringToFile(filePath, doc.ToString()); + } + catch (Exception e) + { + DebugConsole.ThrowError("Saving submarine \"" + filePath + "\" failed!", e); + return false; + } + + return true; + } + + public void SaveToXElement(XElement element) + { + element.Add(new XAttribute("name", name)); + element.Add(new XAttribute("description", Description == null ? "" : Description)); + + element.Add(new XAttribute("tags", tags.ToString())); + + foreach (MapEntity e in MapEntity.mapEntityList) + { + if (e.MoveWithLevel || e.Submarine != this) continue; + e.Save(element); + } + } + + public static bool SaveCurrent(string filePath) + { + if (Submarine.MainSub == null) + { + Submarine.MainSub = new Submarine(filePath); + // return; + } + + Submarine.MainSub.filePath = filePath; + + return Submarine.MainSub.SaveAs(filePath); + } + + public void CheckForErrors() + { + List errorMsgs = new List(); + + if (!Hull.hullList.Any()) + { + errorMsgs.Add("No hulls found in the submarine. Hulls determine the \"borders\" of an individual room and are required for water and air distribution to work correctly."); + } + + foreach (Item item in Item.ItemList) + { + if (item.GetComponent() == null) continue; + + if (!item.linkedTo.Any()) + { + errorMsgs.Add("The submarine contains vents which haven't been linked to an oxygen generator. Select a vent and click an oxygen generator while holding space to link them."); + break; + } + } + + if (WayPoint.WayPointList.Find(wp => !wp.MoveWithLevel && wp.SpawnType == SpawnType.Path) == null) + { + errorMsgs.Add("No waypoints found in the submarine. AI controlled crew members won't be able to navigate without waypoints."); + } + + if (WayPoint.WayPointList.Find(wp => wp.SpawnType == SpawnType.Cargo) == null) + { + errorMsgs.Add("The submarine doesn't have spawnpoints for cargo (which are used for determining where to place bought items). " + + "To fix this, create a new spawnpoint and change its \"spawn type\" parameter to \"cargo\"."); + } + + if (errorMsgs.Any()) + { + new GUIMessageBox("Warning", string.Join("\n\n", errorMsgs), 400, 0); + } + + foreach (MapEntity e in MapEntity.mapEntityList) + { + if (Vector2.Distance(e.Position, HiddenSubPosition) > 20000) + { + var msgBox = new GUIMessageBox( + "Warning", + "One or more structures have been placed very far from the submarine. Show the structures?", + new string[] { "Yes", "No" }); + + msgBox.Buttons[0].OnClicked += (btn, obj) => + { + GameMain.EditMapScreen.Cam.Position = e.WorldPosition; + return true; + }; + msgBox.Buttons[0].OnClicked += msgBox.Close; + msgBox.Buttons[1].OnClicked += msgBox.Close; + + break; + + } + } + } + + } +} diff --git a/BarotraumaClient/Source/Networking/EntitySpawner.cs b/BarotraumaClient/Source/Networking/EntitySpawner.cs new file mode 100644 index 000000000..62165c7a3 --- /dev/null +++ b/BarotraumaClient/Source/Networking/EntitySpawner.cs @@ -0,0 +1,44 @@ +using Barotrauma.Networking; +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Barotrauma +{ + partial class EntitySpawner : Entity, IServerSerializable + { + public void ClientRead(ServerNetObject type, Lidgren.Network.NetBuffer message, float sendingTime) + { + if (GameMain.Server != null) return; + + bool remove = message.ReadBoolean(); + + if (remove) + { + ushort entityId = message.ReadUInt16(); + + var entity = FindEntityByID(entityId); + if (entity != null) + { + entity.Remove(); + } + } + else + { + switch (message.ReadByte()) + { + case (byte)SpawnableType.Item: + Item.ReadSpawnData(message, true); + break; + case (byte)SpawnableType.Character: + Character.ReadSpawnData(message, true); + break; + default: + DebugConsole.ThrowError("Received invalid entity spawn message (unknown spawnable type)"); + break; + } + } + } + } +} diff --git a/BarotraumaShared/Source/Networking/FileTransfer/FileReceiver.cs b/BarotraumaClient/Source/Networking/FileTransfer/FileReceiver.cs similarity index 100% rename from BarotraumaShared/Source/Networking/FileTransfer/FileReceiver.cs rename to BarotraumaClient/Source/Networking/FileTransfer/FileReceiver.cs diff --git a/BarotraumaShared/Source/Networking/NetEntityEvent/ClientEntityEventManager.cs b/BarotraumaClient/Source/Networking/NetEntityEvent/ClientEntityEventManager.cs similarity index 100% rename from BarotraumaShared/Source/Networking/NetEntityEvent/ClientEntityEventManager.cs rename to BarotraumaClient/Source/Networking/NetEntityEvent/ClientEntityEventManager.cs diff --git a/BarotraumaClient/Source/Networking/NetEntityEvent/NetEntityEvent.cs b/BarotraumaClient/Source/Networking/NetEntityEvent/NetEntityEvent.cs new file mode 100644 index 000000000..15e2c9cde --- /dev/null +++ b/BarotraumaClient/Source/Networking/NetEntityEvent/NetEntityEvent.cs @@ -0,0 +1,24 @@ +using Lidgren.Network; +using System; + +namespace Barotrauma.Networking +{ + class ClientEntityEvent : NetEntityEvent + { + private IClientSerializable serializable; + + public UInt16 CharacterStateID; + + public ClientEntityEvent(IClientSerializable entity, UInt16 id) + : base(entity, id) + { + serializable = entity; + } + + public void Write(NetBuffer msg) + { + msg.Write(CharacterStateID); + serializable.ClientWrite(msg, Data); + } + } +} diff --git a/BarotraumaClient/Source/Physics/PhysicsBody.cs b/BarotraumaClient/Source/Physics/PhysicsBody.cs new file mode 100644 index 000000000..dd32fa518 --- /dev/null +++ b/BarotraumaClient/Source/Physics/PhysicsBody.cs @@ -0,0 +1,92 @@ +using System.Xml.Linq; +using FarseerPhysics; +using FarseerPhysics.Dynamics; +using FarseerPhysics.Factories; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System.Collections.Generic; +using System; + +namespace Barotrauma +{ + partial class PhysicsBody + { + public void Draw(SpriteBatch spriteBatch, Sprite sprite, Color color, float? depth = null, float scale = 1.0f) + { + if (!Enabled) return; + + UpdateDrawPosition(); + + if (sprite == null) return; + + SpriteEffects spriteEffect = (dir == 1.0f) ? SpriteEffects.None : SpriteEffects.FlipHorizontally; + + if (GameMain.DebugDraw) + { + if (!body.Awake) color = Color.Blue; + + if (targetPosition != null) + { + Vector2 pos = ConvertUnits.ToDisplayUnits((Vector2)targetPosition); + if (Submarine != null) pos += Submarine.DrawPosition; + + GUI.DrawRectangle(spriteBatch, + new Vector2(pos.X - 5, -(pos.Y + 5)), + Vector2.One * 10.0f, Color.Red, false, 0, 3); + } + + if (offsetFromTargetPos != Vector2.Zero) + { + Vector2 pos = ConvertUnits.ToDisplayUnits(body.Position); + if (Submarine != null) pos += Submarine.DrawPosition; + + GUI.DrawLine(spriteBatch, + new Vector2(pos.X, -pos.Y), + new Vector2(DrawPosition.X, -DrawPosition.Y), + Color.Cyan, 0, 5); + } + } + + sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y), color, -drawRotation, scale, spriteEffect, depth); + } + + public void DebugDraw(SpriteBatch spriteBatch, Color color) + { + if (bodyShapeTexture == null) + { + switch (BodyShape) + { + case PhysicsBody.Shape.Rectangle: + bodyShapeTexture = GUI.CreateRectangle( + (int)ConvertUnits.ToDisplayUnits(width), + (int)ConvertUnits.ToDisplayUnits(height)); + break; + + case PhysicsBody.Shape.Capsule: + bodyShapeTexture = GUI.CreateCapsule( + (int)ConvertUnits.ToDisplayUnits(radius), + (int)ConvertUnits.ToDisplayUnits(Math.Max(height, width))); + break; + case PhysicsBody.Shape.Circle: + bodyShapeTexture = GUI.CreateCircle((int)ConvertUnits.ToDisplayUnits(radius)); + break; + } + } + + float rot = -DrawRotation; + if (bodyShape == PhysicsBody.Shape.Capsule && width > height) + { + rot -= MathHelper.PiOver2; + } + + spriteBatch.Draw( + bodyShapeTexture, + new Vector2(DrawPosition.X, -DrawPosition.Y), + null, + color, + rot, + new Vector2(bodyShapeTexture.Width / 2, bodyShapeTexture.Height / 2), + 1.0f, SpriteEffects.None, 0.0f); + } + } +} diff --git a/BarotraumaClient/Source/Utils/SaveUtil.cs b/BarotraumaClient/Source/Utils/SaveUtil.cs new file mode 100644 index 000000000..1b5570ded --- /dev/null +++ b/BarotraumaClient/Source/Utils/SaveUtil.cs @@ -0,0 +1,239 @@ +using System; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Xml.Linq; + +namespace Barotrauma +{ + public partial class SaveUtil + { + public static void SaveGame(string fileName) + { + fileName = Path.Combine(SaveFolder, fileName); + + string tempPath = Path.Combine(SaveFolder, "temp"); + + Directory.CreateDirectory(tempPath); + try + { + ClearFolder(tempPath, new string[] { GameMain.GameSession.Submarine.FilePath }); + } + catch + { + + } + + try + { + if (Submarine.MainSub != null && Submarine.Loaded.Contains(Submarine.MainSub)) + { + Submarine.MainSub.FilePath = Path.Combine(tempPath, Submarine.MainSub.Name + ".sub"); + Submarine.MainSub.SaveAs(Submarine.MainSub.FilePath); + } + } + catch (Exception e) + { + DebugConsole.ThrowError("Error saving submarine", e); + } + + try + { + GameMain.GameSession.Save(Path.Combine(tempPath, "gamesession.xml")); + } + + catch (Exception e) + { + DebugConsole.ThrowError("Error saving gamesession", e); + } + + try + { + CompressDirectory(tempPath, fileName+".save", null); + } + + catch (Exception e) + { + DebugConsole.ThrowError("Error compressing save file", e); + } + } + + public static void LoadGame(string fileName) + { + string filePath = Path.Combine(SaveFolder, fileName+".save"); + + DecompressToDirectory(filePath, TempPath, null); + + XDocument doc = ToolBox.TryLoadXml(Path.Combine(TempPath, "gamesession.xml")); + + string subPath = Path.Combine(TempPath, ToolBox.GetAttributeString(doc.Root, "submarine", ""))+".sub"; + Submarine selectedMap = new Submarine(subPath, "");// Submarine.Load(); + GameMain.GameSession = new GameSession(selectedMap, fileName, doc); + + //Directory.Delete(tempPath, true); + } + + public static XDocument LoadGameSessionDoc(string fileName) + { + string filePath = Path.Combine(SaveFolder, fileName + ".save"); + + string tempPath = Path.Combine(SaveFolder, "temp"); + + try + { + DecompressToDirectory(filePath, tempPath, null); + } + catch + { + return null; + } + + return ToolBox.TryLoadXml(Path.Combine(tempPath, "gamesession.xml")); + } + + public static void DeleteSave(string fileName) + { + fileName = Path.Combine(SaveFolder, fileName + ".save"); + + try + { + File.Delete(fileName); + } + + catch (Exception e) + { + DebugConsole.ThrowError("ERROR: deleting save file \""+fileName+" failed.", e); + } + + } + + public static string[] GetSaveFiles() + { + if (!Directory.Exists(SaveFolder)) + { + DebugConsole.ThrowError("Save folder \"" + SaveFolder + " not found! Attempting to create a new folder"); + try + { + Directory.CreateDirectory(SaveFolder); + } + catch (Exception e) + { + DebugConsole.ThrowError("Failed to create the folder \"" + SaveFolder + "\"!", e); + } + } + + string[] files = Directory.GetFiles(SaveFolder, "*.save"); + + for (int i = 0; i < files.Length; i++) + { + files[i] = Path.GetFileNameWithoutExtension(files[i]); + } + + return files; + } + + public static string CreateSavePath(string fileName="Save") + { + if (!Directory.Exists(SaveFolder)) + { + DebugConsole.ThrowError("Save folder \""+SaveFolder+"\" not found. Created new folder"); + Directory.CreateDirectory(SaveFolder); + } + + string extension = ".save"; + string pathWithoutExtension = Path.Combine(SaveFolder, fileName); + + int i = 0; + while (File.Exists(pathWithoutExtension + " " + i + extension)) + { + i++; + } + + return fileName + " " + i; + } + + public static void CompressStringToFile(string fileName, string value) + { + // A. + // Write string to temporary file. + string temp = Path.GetTempFileName(); + File.WriteAllText(temp, value); + + // B. + // Read file into byte array buffer. + byte[] b; + using (FileStream f = new FileStream(temp, FileMode.Open)) + { + b = new byte[f.Length]; + f.Read(b, 0, (int)f.Length); + } + + // C. + // Use GZipStream to write compressed bytes to target file. + using (FileStream f2 = new FileStream(fileName, FileMode.Create)) + using (GZipStream gz = new GZipStream(f2, CompressionMode.Compress, false)) + { + gz.Write(b, 0, b.Length); + } + } + + public static void CompressFile(string sDir, string sRelativePath, GZipStream zipStream) + { + //Compress file name + char[] chars = sRelativePath.ToCharArray(); + zipStream.Write(BitConverter.GetBytes(chars.Length), 0, sizeof(int)); + foreach (char c in chars) + zipStream.Write(BitConverter.GetBytes(c), 0, sizeof(char)); + + //Compress file content + byte[] bytes = File.ReadAllBytes(Path.Combine(sDir, sRelativePath)); + zipStream.Write(BitConverter.GetBytes(bytes.Length), 0, sizeof(int)); + zipStream.Write(bytes, 0, bytes.Length); + } + + public static void CompressDirectory(string sInDir, string sOutFile, ProgressDelegate progress) + { + string[] sFiles = Directory.GetFiles(sInDir, "*.*", SearchOption.AllDirectories); + int iDirLen = sInDir[sInDir.Length - 1] == Path.DirectorySeparatorChar ? sInDir.Length : sInDir.Length + 1; + + using (FileStream outFile = new FileStream(sOutFile, FileMode.Create, FileAccess.Write, FileShare.None)) + using (GZipStream str = new GZipStream(outFile, CompressionMode.Compress)) + foreach (string sFilePath in sFiles) + { + string sRelativePath = sFilePath.Substring(iDirLen); + if (progress != null) + progress(sRelativePath); + CompressFile(sInDir, sRelativePath, str); + } + } + + private static void ClearFolder(string FolderName, string[] ignoredFiles = null) + { + DirectoryInfo dir = new DirectoryInfo(FolderName); + + foreach (FileInfo fi in dir.GetFiles()) + { + bool ignore = false; + foreach (string ignoredFile in ignoredFiles) + { + if (Path.GetFullPath(fi.FullName).Equals(Path.GetFullPath(ignoredFile))) + { + ignore = true; + break; + } + } + + if (ignore) continue; + + fi.IsReadOnly = false; + fi.Delete(); + } + + foreach (DirectoryInfo di in dir.GetDirectories()) + { + ClearFolder(di.FullName, ignoredFiles); + di.Delete(); + } + } + } +} diff --git a/BarotraumaServer/BarotraumaServer.csproj b/BarotraumaServer/BarotraumaServer.csproj index 45b1cb6a0..e274e5bb5 100644 --- a/BarotraumaServer/BarotraumaServer.csproj +++ b/BarotraumaServer/BarotraumaServer.csproj @@ -1,6 +1,5 @@  - Debug AnyCPU @@ -13,35 +12,55 @@ 512 true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true - - x86 + true - full - false - bin\Debug\ + bin\x86\Debug\ TRACE;DEBUG;WINDOWS;SERVER - prompt - 4 - - + full x86 - pdbonly - true - bin\Release\ - TRACE;WINDOWS;SERVER prompt - 4 + MinimumRecommendedRules.ruleset + true + + + bin\x86\Release\ + TRACE;WINDOWS;SERVER + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + true False - ..\..\..\..\..\..\Program Files (x86)\MonoGame\v3.0\Assemblies\Windows\MonoGame.Framework.dll + C:\Program Files (x86)\MonoGame\v3.0\Assemblies\Windows\MonoGame.Framework.dll ..\packages\RestSharp.105.2.3\lib\net45\RestSharp.dll + + False + + @@ -89,7 +108,21 @@ Lidgren.Network - + + + False + Microsoft .NET Framework 4.5 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + +