BarotraumaServer compiles
Cleanup + fixes coming up next
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<string, int> skillLevels = new Dictionary<string, int>();
|
||||
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<string, int> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Wire>();
|
||||
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<ConnectionPanel>(panel);
|
||||
}
|
||||
else if (GameMain.Server != null)
|
||||
{
|
||||
panel.Item.CreateServerEvent<ConnectionPanel>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<int> discoveredLocations = new List<int>();
|
||||
for (int i = 0; i < locations.Count; i++)
|
||||
{
|
||||
if (locations[i].Discovered) discoveredLocations.Add(i);
|
||||
}
|
||||
mapElement.Add(new XAttribute("discovered", string.Join(",", discoveredLocations)));
|
||||
|
||||
List<int> passedConnections = new List<int>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<MapEntity> 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<MapEntity> 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<string> errorMsgs = new List<string>();
|
||||
|
||||
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<Items.Components.Vent>() == 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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class FileReceiver
|
||||
{
|
||||
public class FileTransferIn : IDisposable
|
||||
{
|
||||
public string FileName
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string FilePath
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ulong FileSize
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public ulong Received
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public FileTransferType FileType
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public FileTransferStatus Status
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public float BytesPerSecond
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public float Progress
|
||||
{
|
||||
get { return Received / (float)FileSize; }
|
||||
}
|
||||
|
||||
public FileStream WriteStream
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public int TimeStarted
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public NetConnection Connection
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public int SequenceChannel;
|
||||
|
||||
public FileTransferIn(NetConnection connection, string filePath, FileTransferType fileType)
|
||||
{
|
||||
FilePath = filePath;
|
||||
FileName = Path.GetFileName(FilePath);
|
||||
FileType = fileType;
|
||||
|
||||
Connection = connection;
|
||||
|
||||
WriteStream = new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
TimeStarted = Environment.TickCount;
|
||||
|
||||
Status = FileTransferStatus.NotStarted;
|
||||
}
|
||||
|
||||
public void ReadBytes(NetIncomingMessage inc)
|
||||
{
|
||||
byte[] all = inc.ReadBytes(inc.LengthBytes - inc.PositionInBytes);
|
||||
Received += (ulong)all.Length;
|
||||
WriteStream.Write(all, 0, all.Length);
|
||||
|
||||
int passed = Environment.TickCount - TimeStarted;
|
||||
float psec = passed / 1000.0f;
|
||||
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.Log("Received "+all.Length+" bytes of the file "+FileName+" ("+Received+"/"+FileSize+" received)");
|
||||
}
|
||||
|
||||
BytesPerSecond = Received / psec;
|
||||
|
||||
Status = Received >= FileSize ? FileTransferStatus.Finished : FileTransferStatus.Receiving;
|
||||
}
|
||||
|
||||
private bool disposed = false;
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed) return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
if (WriteStream != null)
|
||||
{
|
||||
WriteStream.Flush();
|
||||
WriteStream.Close();
|
||||
WriteStream.Dispose();
|
||||
WriteStream = null;
|
||||
}
|
||||
}
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
}
|
||||
|
||||
const int MaxFileSize = 1000000;
|
||||
|
||||
public delegate void OnFinishedDelegate(FileTransferIn fileStreamReceiver);
|
||||
public OnFinishedDelegate OnFinished;
|
||||
|
||||
private List<FileTransferIn> activeTransfers;
|
||||
|
||||
private string downloadFolder;
|
||||
|
||||
public List<FileTransferIn> ActiveTransfers
|
||||
{
|
||||
get { return activeTransfers; }
|
||||
}
|
||||
|
||||
public FileReceiver(string downloadFolder)
|
||||
{
|
||||
if (GameMain.Server != null)
|
||||
{
|
||||
throw new InvalidOperationException("Creating a file receiver is not allowed when a server is running.");
|
||||
}
|
||||
|
||||
activeTransfers = new List<FileTransferIn>();
|
||||
|
||||
this.downloadFolder = downloadFolder;
|
||||
}
|
||||
|
||||
public void ReadMessage(NetIncomingMessage inc)
|
||||
{
|
||||
if (GameMain.Server != null)
|
||||
{
|
||||
throw new InvalidOperationException("Receiving files when a server is running is not allowed");
|
||||
}
|
||||
|
||||
System.Diagnostics.Debug.Assert(!activeTransfers.Any(t =>
|
||||
t.Status == FileTransferStatus.Error ||
|
||||
t.Status == FileTransferStatus.Canceled ||
|
||||
t.Status == FileTransferStatus.Finished), "List of active file transfers contains entires that should have been removed");
|
||||
|
||||
byte transferMessageType = inc.ReadByte();
|
||||
switch (transferMessageType)
|
||||
{
|
||||
case (byte)FileTransferMessageType.Initiate:
|
||||
var existingTransfer = activeTransfers.Find(t => t.SequenceChannel == inc.SequenceChannel);
|
||||
if (existingTransfer != null)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer error: file transfer initiated on a sequence channel that's already in use");
|
||||
return;
|
||||
}
|
||||
|
||||
byte fileType = inc.ReadByte();
|
||||
ushort chunkLen = inc.ReadUInt16();
|
||||
ulong fileSize = inc.ReadUInt64();
|
||||
string fileName = inc.ReadString();
|
||||
|
||||
string errorMsg;
|
||||
if (!ValidateInitialData(fileType, fileName, fileSize, out errorMsg))
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer failed (" + errorMsg + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.Log("Received file transfer initiation message: ");
|
||||
DebugConsole.Log(" File: "+fileName);
|
||||
DebugConsole.Log(" Size: " + fileSize);
|
||||
DebugConsole.Log(" Sequence channel: " + inc.SequenceChannel);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(downloadFolder))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(downloadFolder);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Could not start a file transfer: failed to create the folder \""+downloadFolder+"\".", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var newTransfer = new FileTransferIn(inc.SenderConnection, Path.Combine(downloadFolder, fileName), (FileTransferType)fileType);
|
||||
newTransfer.SequenceChannel = inc.SequenceChannel;
|
||||
newTransfer.Status = FileTransferStatus.Receiving;
|
||||
newTransfer.FileSize = fileSize;
|
||||
|
||||
activeTransfers.Add(newTransfer);
|
||||
|
||||
break;
|
||||
case (byte)FileTransferMessageType.Data:
|
||||
var activeTransfer = activeTransfers.Find(t => t.Connection == inc.SenderConnection && t.SequenceChannel == inc.SequenceChannel);
|
||||
if (activeTransfer == null)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer error: received data without a transfer initiation message");
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeTransfer.Received + (ulong)(inc.LengthBytes-inc.PositionInBytes) > activeTransfer.FileSize)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer error: Received more data than expected");
|
||||
activeTransfer.Status = FileTransferStatus.Error;
|
||||
StopTransfer(activeTransfer);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
activeTransfer.ReadBytes(inc);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer error: "+e.Message);
|
||||
activeTransfer.Status = FileTransferStatus.Error;
|
||||
StopTransfer(activeTransfer, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeTransfer.Status == FileTransferStatus.Finished)
|
||||
{
|
||||
activeTransfer.Dispose();
|
||||
|
||||
string errorMessage = "";
|
||||
if (ValidateReceivedData(activeTransfer, out errorMessage))
|
||||
{
|
||||
OnFinished(activeTransfer);
|
||||
StopTransfer(activeTransfer);
|
||||
}
|
||||
else
|
||||
{
|
||||
new GUIMessageBox("File transfer aborted", errorMessage);
|
||||
|
||||
activeTransfer.Status = FileTransferStatus.Error;
|
||||
StopTransfer(activeTransfer, true);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case (byte)FileTransferMessageType.Cancel:
|
||||
byte sequenceChannel = inc.ReadByte();
|
||||
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.SenderConnection && t.SequenceChannel == sequenceChannel);
|
||||
if (matchingTransfer != null)
|
||||
{
|
||||
new GUIMessageBox("File transfer cancelled", "The server has cancelled the transfer of the file \"" + matchingTransfer.FileName + "\".");
|
||||
StopTransfer(matchingTransfer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateInitialData(byte type, string fileName, ulong fileSize, out string errorMessage)
|
||||
{
|
||||
errorMessage = "";
|
||||
|
||||
if (fileSize > MaxFileSize)
|
||||
{
|
||||
errorMessage = "File too large (" + MathUtils.GetBytesReadable((long)fileSize) + ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Enum.IsDefined(typeof(FileTransferType), (int)type))
|
||||
{
|
||||
errorMessage = "Unknown file type";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(fileName) ||
|
||||
fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1)
|
||||
{
|
||||
errorMessage = "Illegal characters in file name ''" + fileName + "''";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case (byte)FileTransferType.Submarine:
|
||||
if (Path.GetExtension(fileName) != ".sub")
|
||||
{
|
||||
errorMessage = "Wrong file extension ''" + Path.GetExtension(fileName) + "''! (Expected .sub)";
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ValidateReceivedData(FileTransferIn fileTransfer, out string ErrorMessage)
|
||||
{
|
||||
ErrorMessage = "";
|
||||
switch (fileTransfer.FileType)
|
||||
{
|
||||
case FileTransferType.Submarine:
|
||||
Stream stream = null;
|
||||
|
||||
try
|
||||
{
|
||||
stream = SaveUtil.DecompressFiletoStream(fileTransfer.FilePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ErrorMessage = "Loading received submarine ''" + fileTransfer.FileName + "'' failed! {" + e.Message + "}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stream == null)
|
||||
{
|
||||
ErrorMessage = "Decompressing received submarine file''" + fileTransfer.FilePath + "'' failed!";
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
stream.Position = 0;
|
||||
|
||||
XmlReaderSettings settings = new XmlReaderSettings();
|
||||
settings.DtdProcessing = DtdProcessing.Prohibit;
|
||||
settings.IgnoreProcessingInstructions = true;
|
||||
|
||||
using (var reader = XmlReader.Create(stream, settings))
|
||||
{
|
||||
while (reader.Read());
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
stream.Close();
|
||||
stream.Dispose();
|
||||
|
||||
ErrorMessage = "Parsing file ''" + fileTransfer.FilePath + "'' failed! The file may not be a valid submarine file.";
|
||||
return false;
|
||||
}
|
||||
|
||||
stream.Close();
|
||||
stream.Dispose();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void StopTransfer(FileTransferIn transfer, bool deleteFile = false)
|
||||
{
|
||||
if (transfer.Status != FileTransferStatus.Finished &&
|
||||
transfer.Status != FileTransferStatus.Error)
|
||||
{
|
||||
transfer.Status = FileTransferStatus.Canceled;
|
||||
}
|
||||
|
||||
if (activeTransfers.Contains(transfer)) activeTransfers.Remove(transfer);
|
||||
transfer.Dispose();
|
||||
|
||||
if (deleteFile && File.Exists(transfer.FilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(transfer.FilePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to delete file \""+transfer.FilePath+"\" ("+e.Message+")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class ClientEntityEventManager : NetEntityEventManager
|
||||
{
|
||||
private List<ClientEntityEvent> events;
|
||||
|
||||
private UInt16 ID;
|
||||
|
||||
private GameClient thisClient;
|
||||
|
||||
//when was a specific entity event last sent to the client
|
||||
// key = event id, value = NetTime.Now when sending
|
||||
public Dictionary<UInt16, float> eventLastSent;
|
||||
|
||||
public UInt16 LastReceivedID
|
||||
{
|
||||
get { return lastReceivedID; }
|
||||
}
|
||||
|
||||
private UInt16 lastReceivedID;
|
||||
|
||||
public ClientEntityEventManager(GameClient client)
|
||||
{
|
||||
events = new List<ClientEntityEvent>();
|
||||
eventLastSent = new Dictionary<UInt16, float>();
|
||||
|
||||
thisClient = client;
|
||||
}
|
||||
|
||||
public void CreateEvent(IClientSerializable entity, object[] extraData = null)
|
||||
{
|
||||
if (GameMain.Client == null || GameMain.Client.Character == null) return;
|
||||
|
||||
if (!(entity is Entity))
|
||||
{
|
||||
DebugConsole.ThrowError("Can't create an entity event for " + entity + "!");
|
||||
return;
|
||||
}
|
||||
|
||||
ID++;
|
||||
var newEvent = new ClientEntityEvent(entity, ID);
|
||||
newEvent.CharacterStateID = GameMain.Client.Character.LastNetworkUpdateID;
|
||||
if (extraData != null) newEvent.SetData(extraData);
|
||||
|
||||
events.Add(newEvent);
|
||||
}
|
||||
|
||||
public void Write(NetOutgoingMessage msg, NetConnection serverConnection)
|
||||
{
|
||||
if (events.Count == 0 || serverConnection == null) return;
|
||||
|
||||
List<NetEntityEvent> eventsToSync = new List<NetEntityEvent>();
|
||||
|
||||
//find the index of the first event the server hasn't received
|
||||
int startIndex = events.Count;
|
||||
while (startIndex > 0 &&
|
||||
NetIdUtils.IdMoreRecent(events[startIndex-1].ID,thisClient.LastSentEntityEventID))
|
||||
{
|
||||
startIndex--;
|
||||
}
|
||||
|
||||
for (int i = startIndex; i < events.Count; i++)
|
||||
{
|
||||
//find the first event that hasn't been sent in 1.5 * roundtriptime or at all
|
||||
float lastSent = 0;
|
||||
eventLastSent.TryGetValue(events[i].ID, out lastSent);
|
||||
|
||||
if (lastSent > NetTime.Now - serverConnection.AverageRoundtripTime * 1.5f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
eventsToSync.AddRange(events.GetRange(i, events.Count - i));
|
||||
break;
|
||||
}
|
||||
if (eventsToSync.Count == 0) return;
|
||||
|
||||
//too many events for one packet
|
||||
if (eventsToSync.Count > MaxEventsPerWrite)
|
||||
{
|
||||
eventsToSync.RemoveRange(MaxEventsPerWrite, eventsToSync.Count - MaxEventsPerWrite);
|
||||
}
|
||||
if (eventsToSync.Count == 0) return;
|
||||
|
||||
foreach (NetEntityEvent entityEvent in eventsToSync)
|
||||
{
|
||||
eventLastSent[entityEvent.ID] = (float)NetTime.Now;
|
||||
}
|
||||
|
||||
msg.Write((byte)ClientNetObject.ENTITY_STATE);
|
||||
Write(msg, eventsToSync);
|
||||
}
|
||||
|
||||
private UInt16? firstNewID;
|
||||
|
||||
/// <summary>
|
||||
/// Read the events from the message, ignoring ones we've already received
|
||||
/// </summary>
|
||||
public void Read(ServerNetObject type, NetIncomingMessage msg, float sendingTime)
|
||||
{
|
||||
UInt16 unreceivedEntityEventCount = 0;
|
||||
|
||||
if (type == ServerNetObject.ENTITY_EVENT_INITIAL)
|
||||
{
|
||||
unreceivedEntityEventCount = msg.ReadUInt16();
|
||||
firstNewID = msg.ReadUInt16();
|
||||
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.NewMessage(
|
||||
"received midround syncing msg, unreceived: " + unreceivedEntityEventCount +
|
||||
", first new ID: " + firstNewID, Microsoft.Xna.Framework.Color.Yellow);
|
||||
}
|
||||
}
|
||||
else if (firstNewID != null)
|
||||
{
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.NewMessage("midround syncing complete, switching to ID " + (UInt16) (firstNewID - 1),
|
||||
Microsoft.Xna.Framework.Color.Yellow);
|
||||
}
|
||||
|
||||
lastReceivedID = (UInt16)(firstNewID - 1);
|
||||
firstNewID = null;
|
||||
}
|
||||
|
||||
UInt16 firstEventID = msg.ReadUInt16();
|
||||
int eventCount = msg.ReadByte();
|
||||
|
||||
for (int i = 0; i < eventCount; i++)
|
||||
{
|
||||
UInt16 thisEventID = (UInt16)(firstEventID + (UInt16)i);
|
||||
UInt16 entityID = msg.ReadUInt16();
|
||||
|
||||
if (entityID == 0 && thisEventID == (UInt16)(lastReceivedID + 1))
|
||||
{
|
||||
msg.ReadPadBits();
|
||||
lastReceivedID++;
|
||||
continue;
|
||||
}
|
||||
|
||||
byte msgLength = msg.ReadByte();
|
||||
|
||||
IServerSerializable entity = Entity.FindEntityByID(entityID) as IServerSerializable;
|
||||
|
||||
//skip the event if we've already received it or if the entity isn't found
|
||||
if (thisEventID != (UInt16)(lastReceivedID + 1) || entity == null)
|
||||
{
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
if (thisEventID != (UInt16) (lastReceivedID + 1))
|
||||
{
|
||||
DebugConsole.NewMessage(
|
||||
"received msg " + thisEventID + " (waiting for " + (lastReceivedID + 1) + ")",
|
||||
thisEventID < lastReceivedID + 1
|
||||
? Microsoft.Xna.Framework.Color.Yellow
|
||||
: Microsoft.Xna.Framework.Color.Red);
|
||||
}
|
||||
else if (entity == null)
|
||||
{
|
||||
DebugConsole.NewMessage(
|
||||
"received msg " + thisEventID + ", entity " + entityID + " not found",
|
||||
Microsoft.Xna.Framework.Color.Red);
|
||||
}
|
||||
}
|
||||
msg.Position += msgLength * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
long msgPosition = msg.Position;
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.NewMessage("received msg " + thisEventID + " (" + entity.ToString() + ")",
|
||||
Microsoft.Xna.Framework.Color.Green);
|
||||
}
|
||||
lastReceivedID++;
|
||||
try
|
||||
{
|
||||
ReadEvent(msg, entity, sendingTime);
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to read event for entity \"" + entity.ToString() + "!", e);
|
||||
}
|
||||
msg.Position = msgPosition + msgLength * 8;
|
||||
}
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
|
||||
{
|
||||
var clientEvent = entityEvent as ClientEntityEvent;
|
||||
if (clientEvent == null) return;
|
||||
|
||||
clientEvent.Write(buffer);
|
||||
}
|
||||
|
||||
protected void ReadEvent(NetIncomingMessage buffer, IServerSerializable entity, float sendingTime)
|
||||
{
|
||||
entity.ClientRead(ServerNetObject.ENTITY_EVENT, buffer, sendingTime);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ID = 0;
|
||||
|
||||
lastReceivedID = 0;
|
||||
|
||||
firstNewID = null;
|
||||
|
||||
events.Clear();
|
||||
eventLastSent.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user