Merge remote-tracking branch 'Regalis11/master' into vanillawork

This commit is contained in:
Nilanth Animosus
2018-07-20 15:38:07 +01:00
58 changed files with 675 additions and 310 deletions
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.8.1.5")] [assembly: AssemblyVersion("0.8.1.7")]
[assembly: AssemblyFileVersion("0.8.1.5")] [assembly: AssemblyFileVersion("0.8.1.7")]
+2 -2
View File
@@ -99,7 +99,7 @@ namespace Barotrauma
public Camera() public Camera()
{ {
zoom = 1.0f; zoom = prevZoom = 1.0f;
rotation = 0.0f; rotation = 0.0f;
position = Vector2.Zero; position = Vector2.Zero;
@@ -112,7 +112,7 @@ namespace Barotrauma
viewMatrix = viewMatrix =
Matrix.CreateTranslation(new Vector3(GameMain.GraphicsWidth / 2.0f, GameMain.GraphicsHeight / 2.0f, 0)); Matrix.CreateTranslation(new Vector3(GameMain.GraphicsWidth / 2.0f, GameMain.GraphicsHeight / 2.0f, 0));
UpdateTransform(); UpdateTransform(false);
} }
public Vector2 TargetPos public Vector2 TargetPos
@@ -81,6 +81,9 @@ namespace Barotrauma
if (Limbs == null) if (Limbs == null)
{ {
DebugConsole.ThrowError("Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace); DebugConsole.ThrowError("Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace);
GameAnalyticsManager.AddErrorEventOnce("Ragdoll.Draw:LimbsRemoved",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace);
return; return;
} }
@@ -207,7 +207,7 @@ namespace Barotrauma
GameMain.GameSession.CrewManager.RemoveCharacter(this); GameMain.GameSession.CrewManager.RemoveCharacter(this);
} }
if (GameMain.Client != null && GameMain.Client.Character == this) GameMain.Client.Character = null; if (GameMain.NetworkMember?.Character == this) GameMain.NetworkMember.Character = null;
if (Lights.LightManager.ViewTarget == this) Lights.LightManager.ViewTarget = null; if (Lights.LightManager.ViewTarget == this) Lights.LightManager.ViewTarget = null;
} }
@@ -32,7 +32,7 @@ namespace Barotrauma
public static void TakeDamage(float amount) public static void TakeDamage(float amount)
{ {
healthBar.Flash(); healthBar?.Flash();
damageOverlayTimer = MathHelper.Clamp(amount * 0.1f, 0.2f, 1.0f); damageOverlayTimer = MathHelper.Clamp(amount * 0.1f, 0.2f, 1.0f);
} }
@@ -188,6 +188,7 @@ namespace Barotrauma
controlled = this; controlled = this;
IsRemotePlayer = false; IsRemotePlayer = false;
GameMain.Client.HasSpawned = true;
GameMain.Client.Character = this; GameMain.Client.Character = this;
GameMain.LightManager.LosEnabled = true; GameMain.LightManager.LosEnabled = true;
} }
@@ -286,6 +287,7 @@ namespace Barotrauma
if (GameMain.Client.ID == ownerId) if (GameMain.Client.ID == ownerId)
{ {
GameMain.Client.HasSpawned = true;
GameMain.Client.Character = character; GameMain.Client.Character = character;
Controlled = character; Controlled = character;
@@ -438,6 +438,8 @@ namespace Barotrauma
NewMessage("Resolution set to 0 x 0 (screen resolution will be used)", Color.Green); NewMessage("Resolution set to 0 x 0 (screen resolution will be used)", Color.Green);
NewMessage("Fullscreen enabled", Color.Green); NewMessage("Fullscreen enabled", Color.Green);
GameSettings.ShowUserStatisticsPrompt = true;
GameSettings.VerboseLogging = false; GameSettings.VerboseLogging = false;
if (GameMain.Config.MasterServerUrl != "http://www.undertowgames.com/baromaster") if (GameMain.Config.MasterServerUrl != "http://www.undertowgames.com/baromaster")
@@ -214,12 +214,9 @@ namespace Barotrauma
if (GameMain.GameSession != null) if (GameMain.GameSession != null)
{ {
if (GameSettings.SendUserStatistics) Mission mission = GameMain.GameSession.Mission;
{ GameAnalyticsManager.AddDesignEvent("QuitRound:" + (save ? "Save" : "NoSave"));
Mission mission = GameMain.GameSession.Mission; GameAnalyticsManager.AddDesignEvent("EndRound:" + (mission == null ? "NoMission" : (mission.Completed ? "MissionCompleted" : "MissionFailed")));
GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("QuitRound:" + (save ? "Save" : "NoSave"));
GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("EndRound:" + (mission == null ? "NoMission" : (mission.Completed ? "MissionCompleted" : "MissionFailed")));
}
GameMain.GameSession = null; GameMain.GameSession = null;
} }
@@ -244,12 +244,18 @@ namespace Barotrauma
new string[] { "Yes", "No" }); new string[] { "Yes", "No" });
userStatsPrompt.Buttons[0].OnClicked += (btn, userdata) => userStatsPrompt.Buttons[0].OnClicked += (btn, userdata) =>
{ {
GameSettings.ShowUserStatisticsPrompt = false;
GameSettings.SendUserStatistics = true; GameSettings.SendUserStatistics = true;
GameAnalyticsManager.Init(); GameAnalyticsManager.Init();
return true; return true;
}; };
userStatsPrompt.Buttons[0].OnClicked += userStatsPrompt.Close; userStatsPrompt.Buttons[0].OnClicked += userStatsPrompt.Close;
userStatsPrompt.Buttons[1].OnClicked += (btn, userdata) => { GameSettings.SendUserStatistics = false; return true; }; userStatsPrompt.Buttons[1].OnClicked += (btn, userdata) =>
{
GameSettings.ShowUserStatisticsPrompt = false;
GameSettings.SendUserStatistics = false;
return true;
};
userStatsPrompt.Buttons[1].OnClicked += userStatsPrompt.Close; userStatsPrompt.Buttons[1].OnClicked += userStatsPrompt.Close;
} }
else if (GameSettings.SendUserStatistics) else if (GameSettings.SendUserStatistics)
@@ -27,7 +27,7 @@ namespace Barotrauma
return verticeList; return verticeList;
} }
public static VertexPositionTexture[] GenerateWallShapes(List<VoronoiCell> cells) public static VertexPositionTexture[] GenerateWallShapes(List<VoronoiCell> cells, Level level)
{ {
float inwardThickness = 500.0f, outWardThickness = 30.0f; float inwardThickness = 500.0f, outWardThickness = 30.0f;
@@ -80,6 +80,10 @@ namespace Barotrauma
#if DEBUG #if DEBUG
DebugConsole.ThrowError("Invalid left normal"); DebugConsole.ThrowError("Invalid left normal");
#endif #endif
GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidLeftNormal:" + level.Seed,
GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
"Invalid left normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + leftNormal + ", seed: " + level.Seed + ")");
if (cell.body != null) if (cell.body != null)
{ {
GameMain.World.RemoveBody(cell.body); GameMain.World.RemoveBody(cell.body);
@@ -106,6 +110,10 @@ namespace Barotrauma
#if DEBUG #if DEBUG
DebugConsole.ThrowError("Invalid right normal"); DebugConsole.ThrowError("Invalid right normal");
#endif #endif
GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidRightNormal:" + level.Seed,
GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
"Invalid right normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + rightNormal + ", seed: " + level.Seed + ")");
if (cell.body != null) if (cell.body != null)
{ {
GameMain.World.RemoveBody(cell.body); GameMain.World.RemoveBody(cell.body);
@@ -44,6 +44,9 @@ namespace Barotrauma.Networking
private FileReceiver fileReceiver; private FileReceiver fileReceiver;
//has the client been given a character to control this round
public bool HasSpawned;
public byte ID public byte ID
{ {
get { return myID; } get { return myID; }
@@ -480,7 +483,7 @@ namespace Barotrauma.Networking
if (gameStarted && Screen.Selected == GameMain.GameScreen) if (gameStarted && Screen.Selected == GameMain.GameScreen)
{ {
endVoteTickBox.Visible = Voting.AllowEndVoting && myCharacter != null; endVoteTickBox.Visible = Voting.AllowEndVoting && HasSpawned;
if (respawnManager != null) if (respawnManager != null)
{ {
@@ -666,6 +669,7 @@ namespace Barotrauma.Networking
private IEnumerable<object> StartGame(NetIncomingMessage inc) private IEnumerable<object> StartGame(NetIncomingMessage inc)
{ {
if (Character != null) Character.Remove(); if (Character != null) Character.Remove();
HasSpawned = false;
GameMain.LightManager.LightingEnabled = true; GameMain.LightManager.LightingEnabled = true;
@@ -815,7 +819,7 @@ namespace Barotrauma.Networking
string subName = inc.ReadString(); string subName = inc.ReadString();
string subHash = inc.ReadString(); string subHash = inc.ReadString();
var matchingSub = Submarine.SavedSubmarines.Find(s => s.Name == subName && s.MD5Hash.Hash == subHash); var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash);
if (matchingSub != null) if (matchingSub != null)
{ {
submarines.Add(matchingSub); submarines.Add(matchingSub);
@@ -1016,29 +1020,32 @@ namespace Barotrauma.Networking
ChatMessage.ClientRead(inc); ChatMessage.ClientRead(inc);
break; break;
default: default:
DebugConsole.ThrowError("Error while reading update from server (unknown object header \""+objHeader+"\"!)"); List<string> errorLines = new List<string>
if (prevObjHeader != null)
{ {
DebugConsole.ThrowError("Previous object type: " + prevObjHeader.ToString()); "Error while reading update from server (unknown object header \"" + objHeader + "\"!)",
} prevObjHeader != null ? "Previous object type: " + prevObjHeader.ToString() : "Error occurred on the very first object!",
else "Previous object was " + (inc.Position - prevBitPos) + " bits long (" + (inc.PositionInBytes - prevBytePos) + " bytes)"
{ };
DebugConsole.ThrowError("Error occurred on the very first object!");
}
DebugConsole.ThrowError("Previous object was " + (inc.Position - prevBitPos) + " bits long (" + (inc.PositionInBytes - prevBytePos) + " bytes)");
if (prevObjHeader == ServerNetObject.ENTITY_EVENT || prevObjHeader == ServerNetObject.ENTITY_EVENT_INITIAL) if (prevObjHeader == ServerNetObject.ENTITY_EVENT || prevObjHeader == ServerNetObject.ENTITY_EVENT_INITIAL)
{ {
foreach (IServerSerializable ent in entities) foreach (IServerSerializable ent in entities)
{ {
if (ent == null) if (ent == null)
{ {
DebugConsole.ThrowError(" - NULL"); errorLines.Add(" - NULL");
continue; continue;
} }
Entity e = ent as Entity; Entity e = ent as Entity;
DebugConsole.ThrowError(" - "+e.ToString()); errorLines.Add(" - " + e.ToString());
} }
} }
foreach (string line in errorLines)
{
DebugConsole.ThrowError(line);
}
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadInGameUpdate", GameAnalyticsSDK.Net.EGAErrorSeverity.Critical, string.Join("\n", errorLines));
DebugConsole.ThrowError("Writing object data to \"crashreport_object.bin\", please send this file to us at http://github.com/Regalis11/Barotrauma/issues"); DebugConsole.ThrowError("Writing object data to \"crashreport_object.bin\", please send this file to us at http://github.com/Regalis11/Barotrauma/issues");
FileStream fl = File.Open("crashreport_object.bin", FileMode.Create); FileStream fl = File.Open("crashreport_object.bin", FileMode.Create);
@@ -1181,8 +1188,12 @@ namespace Barotrauma.Networking
case FileTransferType.Submarine: case FileTransferType.Submarine:
new GUIMessageBox("Download finished", "File \"" + transfer.FileName + "\" was downloaded succesfully."); new GUIMessageBox("Download finished", "File \"" + transfer.FileName + "\" was downloaded succesfully.");
var newSub = new Submarine(transfer.FilePath); var newSub = new Submarine(transfer.FilePath);
Submarine.SavedSubmarines.RemoveAll(s => s.Name == newSub.Name && s.MD5Hash.Hash == newSub.MD5Hash.Hash); var existingSubs = Submarine.SavedSubmarines.Where(s => s.Name == newSub.Name && s.MD5Hash.Hash == newSub.MD5Hash.Hash).ToList();
Submarine.SavedSubmarines.Add(newSub); foreach (Submarine existingSub in existingSubs)
{
existingSub.Dispose();
}
Submarine.AddToSavedSubs(newSub);
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
@@ -1277,6 +1288,23 @@ namespace Barotrauma.Networking
{ {
base.Draw(spriteBatch); base.Draw(spriteBatch);
if (Screen.Selected == GameMain.GameScreen && !GUI.DisableHUD)
{
if (EndVoteCount > 0)
{
if (!HasSpawned)
{
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 180.0f, 40),
"Votes to end the round (y/n): " + EndVoteCount + "/" + (EndVoteMax - EndVoteCount), Color.White, null, 0, GUI.SmallFont);
}
else
{
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 140.0f, 40),
"Votes (y/n): " + EndVoteCount + "/" + (EndVoteMax - EndVoteCount), Color.White, null, 0, GUI.SmallFont);
}
}
}
if (fileReceiver != null && fileReceiver.ActiveTransfers.Count > 0) if (fileReceiver != null && fileReceiver.ActiveTransfers.Count > 0)
{ {
Vector2 pos = new Vector2(GameMain.NetLobbyScreen.InfoFrame.Rect.X, GameMain.GraphicsHeight - 35); Vector2 pos = new Vector2(GameMain.NetLobbyScreen.InfoFrame.Rect.X, GameMain.GraphicsHeight - 35);
@@ -1560,14 +1588,13 @@ namespace Barotrauma.Networking
{ {
if (!gameStarted) return false; if (!gameStarted) return false;
if (!Voting.AllowEndVoting || myCharacter==null) if (!Voting.AllowEndVoting || !HasSpawned)
{ {
tickBox.Visible = false; tickBox.Visible = false;
return false; return false;
} }
Vote(VoteType.EndRound, tickBox.Selected); Vote(VoteType.EndRound, tickBox.Selected);
return false; return false;
} }
} }
@@ -63,6 +63,15 @@ namespace Barotrauma.Networking
log.LogFrame.Draw(spriteBatch); log.LogFrame.Draw(spriteBatch);
} }
if (Screen.Selected == GameMain.GameScreen && !GUI.DisableHUD)
{
if (EndVoteCount > 0)
{
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 180.0f, 40),
"Votes to end the round (y/n): " + EndVoteCount + "/" + (EndVoteMax - EndVoteCount), Color.White, null, 0, GUI.SmallFont);
}
}
if (!ShowNetStats) return; if (!ShowNetStats) return;
GUI.Font.DrawString(spriteBatch, "Unique Events: " + entityEventManager.UniqueEvents.Count, new Vector2(10, 50), Color.White); GUI.Font.DrawString(spriteBatch, "Unique Events: " + entityEventManager.UniqueEvents.Count, new Vector2(10, 50), Color.White);
@@ -191,6 +191,9 @@ namespace Barotrauma.Networking
if (GameSettings.VerboseLogging) if (GameSettings.VerboseLogging)
{ {
DebugConsole.ThrowError("Failed to read event for entity \"" + entity.ToString() + "\"!", e); DebugConsole.ThrowError("Failed to read event for entity \"" + entity.ToString() + "\"!", e);
GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:ReadFailed" + entity.ToString(),
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to read event for entity \"" + entity.ToString() + "\"!\n" + e.StackTrace);
} }
msg.Position = msgPosition + msgLength * 8; msg.Position = msgPosition + msgLength * 8;
} }
@@ -119,20 +119,6 @@ namespace Barotrauma.Networking
inGameHUD.Draw(spriteBatch); inGameHUD.Draw(spriteBatch);
if (EndVoteCount > 0)
{
if (GameMain.NetworkMember.myCharacter == null)
{
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 180.0f, 40),
"Votes to end the round (y/n): " + EndVoteCount + "/" + (EndVoteMax - EndVoteCount), Color.White, null, 0, GUI.SmallFont);
}
else
{
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 140.0f, 40),
"Votes (y/n): " + EndVoteCount + "/" + (EndVoteMax - EndVoteCount), Color.White, null, 0, GUI.SmallFont);
}
}
if (respawnManager != null) if (respawnManager != null)
{ {
string respawnInfo = ""; string respawnInfo = "";
@@ -2,6 +2,7 @@
using Lidgren.Network; using Lidgren.Network;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace Barotrauma namespace Barotrauma
{ {
@@ -151,7 +152,7 @@ namespace Barotrauma
{ {
int votes = inc.ReadByte(); int votes = inc.ReadByte();
string subName = inc.ReadString(); string subName = inc.ReadString();
Submarine sub = Submarine.SavedSubmarines.Find(sm => sm.Name == subName); Submarine sub = Submarine.SavedSubmarines.FirstOrDefault(sm => sm.Name == subName);
SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes); SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes);
} }
} }
@@ -203,7 +203,7 @@ namespace Barotrauma
if (GameSettings.SendUserStatistics) if (GameSettings.SendUserStatistics)
{ {
CrashMessageBox( "A crash report (\"crashreport.log\") was saved in the root folder of the game and sent to the developers."); CrashMessageBox( "A crash report (\"crashreport.log\") was saved in the root folder of the game and sent to the developers.");
GameAnalytics.AddErrorEvent(EGAErrorSeverity.Error, crashReport); GameAnalytics.AddErrorEvent(EGAErrorSeverity.Critical, crashReport);
GameAnalytics.OnStop(); GameAnalytics.OnStop();
} }
else else
@@ -144,7 +144,7 @@ namespace Barotrauma
return true; return true;
}; };
} }
if (Submarine.SavedSubmarines.Count > 0) subList.Select(Submarine.SavedSubmarines[0]); if (Submarine.SavedSubmarines.Any()) subList.Select(Submarine.SavedSubmarines.First());
} }
public void UpdateLoadMenu() public void UpdateLoadMenu()
@@ -149,6 +149,8 @@ namespace Barotrauma
null, null, null, null,
Alignment.TopRight, "", frame); Alignment.TopRight, "", frame);
} }
RefreshItemTab();
} }
public void Update(float deltaTime) public void Update(float deltaTime)
@@ -293,6 +295,7 @@ namespace Barotrauma
{ {
CreateItemFrame(ip, selectedItemList, selectedItemList.Rect.Width); CreateItemFrame(ip, selectedItemList, selectedItemList.Rect.Width);
} }
selectedItemList.UpdateScrollBarSize();
} }
public void SelectTab(Tab tab) public void SelectTab(Tab tab)
@@ -88,7 +88,7 @@ namespace Barotrauma
campaignUI.OnLocationSelected = SelectLocation; campaignUI.OnLocationSelected = SelectLocation;
campaignUI.UpdateCharacterLists(); campaignUI.UpdateCharacterLists();
if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.SetCustomDimension01("singleplayer"); GameAnalyticsManager.SetCustomDimension01("singleplayer");
} }
public override void AddToGUIUpdateList() public override void AddToGUIUpdateList()
@@ -143,7 +143,7 @@ namespace Barotrauma
SelectTab(null, 0); SelectTab(null, 0);
if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.SetCustomDimension01(""); GameAnalyticsManager.SetCustomDimension01("");
} }
public bool SelectTab(GUIButton button, object obj) public bool SelectTab(GUIButton button, object obj)
@@ -501,7 +501,7 @@ namespace Barotrauma
} }
} }
if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.SetCustomDimension01("multiplayer"); GameAnalyticsManager.SetCustomDimension01("multiplayer");
if (GameModePreset.list.Count > 0 && modeList.Selected == null) modeList.Select(0); if (GameModePreset.list.Count > 0 && modeList.Selected == null) modeList.Select(0);
@@ -737,8 +737,20 @@ namespace Barotrauma
//hash will be null if opening the sub file failed -> don't select the sub //hash will be null if opening the sub file failed -> don't select the sub
if (string.IsNullOrWhiteSpace(hash)) if (string.IsNullOrWhiteSpace(hash))
{ {
(component as GUITextBlock).TextColor = Color.DarkRed * 0.8f; if (component is GUITextBlock textBlock)
component.CanBeFocused = false; {
textBlock.TextColor = Color.DarkRed * 0.8f;
textBlock.CanBeFocused = false;
}
else
{
DebugConsole.ThrowError("Failed to select submarine. Selected GUIComponent was of the type \"" + (component == null ? "null" : component.GetType().ToString()) + "\".");
GameAnalyticsManager.AddErrorEventOnce(
"NetLobbyScreen.SelectSub:InvalidComponent",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to select submarine. Selected GUIComponent was of the type \"" + (component == null ? "null" : component.GetType().ToString()) + "\".");
}
StartButton.Enabled = false; StartButton.Enabled = false;
@@ -782,8 +794,8 @@ namespace Barotrauma
CanBeFocused = false CanBeFocused = false
}; };
var matchingSub = Submarine.SavedSubmarines.Find(s => s.Name == sub.Name && s.MD5Hash.Hash == sub.MD5Hash.Hash); var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name && s.MD5Hash.Hash == sub.MD5Hash.Hash);
if (matchingSub == null) matchingSub = Submarine.SavedSubmarines.Find(s => s.Name == sub.Name); if (matchingSub == null) matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name);
if (matchingSub == null) if (matchingSub == null)
{ {
@@ -1467,8 +1479,8 @@ namespace Barotrauma
return false; return false;
} }
Submarine sub = Submarine.SavedSubmarines.Find(m => m.Name == subName && m.MD5Hash.Hash == md5Hash); Submarine sub = Submarine.SavedSubmarines.FirstOrDefault(m => m.Name == subName && m.MD5Hash.Hash == md5Hash);
if (sub == null) sub = Submarine.SavedSubmarines.Find(m => m.Name == subName); if (sub == null) sub = Submarine.SavedSubmarines.FirstOrDefault(m => m.Name == subName);
var matchingListSub = subList.children.Find(c => c.UserData == sub); var matchingListSub = subList.children.Find(c => c.UserData == sub);
if (matchingListSub != null) if (matchingListSub != null)
@@ -349,7 +349,7 @@ namespace Barotrauma
cam.UpdateTransform(); cam.UpdateTransform();
if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.SetCustomDimension01("editor"); GameAnalyticsManager.SetCustomDimension01("editor");
} }
public override void Deselect() public override void Deselect()
@@ -56,7 +56,7 @@ namespace Barotrauma.Sounds
AL.BufferData(sound.alBufferId, reader.Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16, sound.castBuffer, AL.BufferData(sound.alBufferId, reader.Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16, sound.castBuffer,
readSamples * sizeof(short), reader.SampleRate); readSamples * sizeof(short), reader.SampleRate);
ALHelper.Check(); ALHelper.Check(oggFile);
} }
//AL.Source(alSourceId, ALSourcei.Buffer, alBufferId); //AL.Source(alSourceId, ALSourcei.Buffer, alBufferId);
@@ -100,12 +100,12 @@ namespace Barotrauma.Sounds
public void Dispose() public void Dispose()
{ {
//var state = AL.GetSourceState(alSourceId);
//if (state == ALSourceState.Playing || state == ALSourceState.Paused)
// Stop();
System.Diagnostics.Debug.WriteLine(alBufferId); System.Diagnostics.Debug.WriteLine(alBufferId);
//AL.DeleteSource(alSourceId); if (alBufferId > 0)
AL.DeleteBuffer(alBufferId); {
AL.DeleteBuffer(alBufferId);
alBufferId = 0;
}
//if (ALHelper.Efx.IsInitialized) //if (ALHelper.Efx.IsInitialized)
// ALHelper.Efx.DeleteFilter(alFilterId); // ALHelper.Efx.DeleteFilter(alFilterId);
@@ -45,16 +45,24 @@ namespace Barotrauma.Sounds
//logHandler(String.Format("Total memory : {0:0.###} {1} ", usedHeap, sizes[order]), 0, 6); //logHandler(String.Format("Total memory : {0:0.###} {1} ", usedHeap, sizes[order]), 0, 6);
} }
public static void Check() public static void Check(string extraErrorMsg = "")
{ {
ALError error; ALError error;
if ((error = AL.GetError()) != ALError.NoError) if ((error = AL.GetError()) != ALError.NoError)
{ {
string errorMsg = "OpenAL error: " + AL.GetErrorString(error);
if (!string.IsNullOrEmpty(extraErrorMsg)) errorMsg += " {" + extraErrorMsg + "} ";
errorMsg += "\n" + Environment.StackTrace;
#if DEBUG #if DEBUG
DebugConsole.ThrowError("OpenAL error: " + AL.GetErrorString(error) + "\n" + Environment.StackTrace); DebugConsole.ThrowError(errorMsg);
#else #else
DebugConsole.NewMessage("OpenAL error: " + AL.GetErrorString(error) + "\n" + Environment.StackTrace, Microsoft.Xna.Framework.Color.Red); DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
#endif #endif
GameAnalyticsManager.AddErrorEventOnce(
"OggStream.Check:" + AL.GetErrorString(error) + extraErrorMsg,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
errorMsg);
} }
} }
} }
@@ -83,9 +91,17 @@ namespace Barotrauma.Sounds
public Action<string, int, int> LogHandler; public Action<string, int, int> LogHandler;
#endif #endif
public OggStream(string filename, int bufferCount = DefaultBufferCount) : this(File.OpenRead(filename), bufferCount) { } public string FileName
public OggStream(Stream stream, int bufferCount = DefaultBufferCount)
{ {
get;
private set;
}
public OggStream(string filename, int bufferCount = DefaultBufferCount) : this(File.OpenRead(filename), filename, bufferCount) { }
public OggStream(Stream stream, string fileName, int bufferCount = DefaultBufferCount)
{
this.FileName = fileName;
BufferCount = bufferCount; BufferCount = bufferCount;
alBufferIds = AL.GenBuffers(bufferCount); alBufferIds = AL.GenBuffers(bufferCount);
@@ -94,7 +110,7 @@ namespace Barotrauma.Sounds
if (ALHelper.XRam.IsInitialized) if (ALHelper.XRam.IsInitialized)
{ {
ALHelper.XRam.SetBufferMode(BufferCount, ref alBufferIds[0], XRamExtension.XRamStorage.Hardware); ALHelper.XRam.SetBufferMode(BufferCount, ref alBufferIds[0], XRamExtension.XRamStorage.Hardware);
ALHelper.Check(); ALHelper.Check(fileName);
} }
if (ALHelper.Efx.IsInitialized) if (ALHelper.Efx.IsInitialized)
@@ -163,7 +179,7 @@ namespace Barotrauma.Sounds
AL.SourcePlay(alSourceId); AL.SourcePlay(alSourceId);
this.Volume = volume; this.Volume = volume;
ALHelper.Check(); ALHelper.Check(FileName);
Preparing = false; Preparing = false;
@@ -177,7 +193,7 @@ namespace Barotrauma.Sounds
OggStreamer.Instance.RemoveStream(this); OggStreamer.Instance.RemoveStream(this);
AL.SourcePause(alSourceId); AL.SourcePause(alSourceId);
ALHelper.Check(); ALHelper.Check(FileName);
} }
public void Resume() public void Resume()
@@ -187,7 +203,7 @@ namespace Barotrauma.Sounds
OggStreamer.Instance.AddStream(this); OggStreamer.Instance.AddStream(this);
AL.SourcePlay(alSourceId); AL.SourcePlay(alSourceId);
ALHelper.Check(); ALHelper.Check(FileName);
} }
public void Stop() public void Stop()
@@ -226,7 +242,7 @@ namespace Barotrauma.Sounds
set set
{ {
AL.Source(alSourceId, ALSourcef.Gain, volume = value); AL.Source(alSourceId, ALSourcef.Gain, volume = value);
ALHelper.Check(); ALHelper.Check(FileName);
} }
} }
@@ -256,20 +272,20 @@ namespace Barotrauma.Sounds
/*if (ALHelper.Efx.IsInitialized) /*if (ALHelper.Efx.IsInitialized)
ALHelper.Efx.DeleteFilter(alFilterId);*/ ALHelper.Efx.DeleteFilter(alFilterId);*/
ALHelper.Check(); ALHelper.Check(FileName);
} }
void StopPlayback() void StopPlayback()
{ {
AL.SourceStop(alSourceId); AL.SourceStop(alSourceId);
ALHelper.Check(); ALHelper.Check(FileName);
} }
void Empty() void Empty()
{ {
int queued; int queued;
AL.GetSource(alSourceId, ALGetSourcei.BuffersQueued, out queued); AL.GetSource(alSourceId, ALGetSourcei.BuffersQueued, out queued);
ALHelper.Check(); ALHelper.Check(FileName);
if (queued > 0) if (queued > 0)
{ {
@@ -292,12 +308,12 @@ namespace Barotrauma.Sounds
if (processed > 0) if (processed > 0)
{ {
AL.SourceUnqueueBuffers(alSourceId, processed, salvaged); AL.SourceUnqueueBuffers(alSourceId, processed, salvaged);
ALHelper.Check(); ALHelper.Check(FileName);
} }
// Try turning it off again? // Try turning it off again?
AL.SourceStop(alSourceId); AL.SourceStop(alSourceId);
ALHelper.Check(); ALHelper.Check(FileName);
Empty(); Empty();
} }
@@ -314,7 +330,7 @@ namespace Barotrauma.Sounds
// Fill first buffer synchronously // Fill first buffer synchronously
OggStreamer.Instance.FillBuffer(this, alBufferIds[0]); OggStreamer.Instance.FillBuffer(this, alBufferIds[0]);
AL.SourceQueueBuffer(alSourceId, alBufferIds[0]); AL.SourceQueueBuffer(alSourceId, alBufferIds[0]);
ALHelper.Check(); ALHelper.Check(FileName);
// Schedule the others asynchronously // Schedule the others asynchronously
OggStreamer.Instance.AddStream(this); OggStreamer.Instance.AddStream(this);
@@ -429,7 +445,7 @@ namespace Barotrauma.Sounds
} }
AL.BufferData(bufferId, stream.Reader.Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16, castBuffer, AL.BufferData(bufferId, stream.Reader.Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16, castBuffer,
readSamples * sizeof(short), stream.Reader.SampleRate); readSamples * sizeof(short), stream.Reader.SampleRate);
ALHelper.Check(); ALHelper.Check(stream.FileName);
return readSamples != BufferSize; return readSamples != BufferSize;
} }
@@ -466,10 +482,10 @@ namespace Barotrauma.Sounds
int queued; int queued;
AL.GetSource(stream.alSourceId, ALGetSourcei.BuffersQueued, out queued); AL.GetSource(stream.alSourceId, ALGetSourcei.BuffersQueued, out queued);
ALHelper.Check(); ALHelper.Check(stream.FileName);
int processed; int processed;
AL.GetSource(stream.alSourceId, ALGetSourcei.BuffersProcessed, out processed); AL.GetSource(stream.alSourceId, ALGetSourcei.BuffersProcessed, out processed);
ALHelper.Check(); ALHelper.Check(stream.FileName);
if (processed == 0 && queued == stream.BufferCount) continue; if (processed == 0 && queued == stream.BufferCount) continue;
@@ -496,7 +512,7 @@ namespace Barotrauma.Sounds
} }
AL.SourceQueueBuffers(stream.alSourceId, tempBuffers.Length, tempBuffers); AL.SourceQueueBuffers(stream.alSourceId, tempBuffers.Length, tempBuffers);
ALHelper.Check(); ALHelper.Check(stream.FileName);
if (finished && !stream.IsLooped) if (finished && !stream.IsLooped)
continue; continue;
@@ -514,7 +530,7 @@ namespace Barotrauma.Sounds
if (state == ALSourceState.Stopped) if (state == ALSourceState.Stopped)
{ {
AL.SourcePlay(stream.alSourceId); AL.SourcePlay(stream.alSourceId);
ALHelper.Check(); ALHelper.Check(stream.FileName);
} }
} }
} }
@@ -54,7 +54,7 @@ namespace Barotrauma
{ {
DebugConsole.ThrowError("Failed to load sound "+file+"!", e); DebugConsole.ThrowError("Failed to load sound "+file+"!", e);
} }
ALHelper.Check(); ALHelper.Check(file);
} }
baseVolume = 1.0f; baseVolume = 1.0f;
@@ -219,7 +219,7 @@ namespace Barotrauma
(SoundManager.IsPlaying(alSourceId) || SoundManager.IsPaused(alSourceId))) (SoundManager.IsPlaying(alSourceId) || SoundManager.IsPaused(alSourceId)))
{ {
SoundManager.Stop(alSourceId); SoundManager.Stop(alSourceId);
ALHelper.Check(); ALHelper.Check(filePath);
} }
foreach (Sound s in loadedSounds) foreach (Sound s in loadedSounds)
@@ -228,7 +228,7 @@ namespace Barotrauma
} }
SoundManager.ClearAlSource(AlBufferId); SoundManager.ClearAlSource(AlBufferId);
ALHelper.Check(); ALHelper.Check(filePath);
if (oggSound != null) if (oggSound != null)
{ {
@@ -143,7 +143,7 @@ namespace Barotrauma.Sounds
volume = 0.0f; volume = 0.0f;
} }
if (sourceIndex<1 || soundsPlaying[sourceIndex] != sound) if (sourceIndex < 1 || soundsPlaying[sourceIndex] != sound)
{ {
sourceIndex = Play(sound, position, volume, 0.0f, true); sourceIndex = Play(sound, position, volume, 0.0f, true);
} }
@@ -153,7 +153,7 @@ namespace Barotrauma.Sounds
AL.Source(alSources[sourceIndex], ALSourceb.Looping, true); AL.Source(alSources[sourceIndex], ALSourceb.Looping, true);
} }
ALHelper.Check(); ALHelper.Check(sound?.FilePath);
return sourceIndex; return sourceIndex;
} }
@@ -165,7 +165,7 @@ namespace Barotrauma.Sounds
return; return;
AL.SourcePause(alSources[sourceIndex]); AL.SourcePause(alSources[sourceIndex]);
ALHelper.Check(); ALHelper.Check(soundsPlaying[sourceIndex]?.FilePath);
} }
public static void Resume(int sourceIndex) public static void Resume(int sourceIndex)
@@ -176,7 +176,7 @@ namespace Barotrauma.Sounds
return; return;
AL.SourcePlay(alSources[sourceIndex]); AL.SourcePlay(alSources[sourceIndex]);
ALHelper.Check(); ALHelper.Check(soundsPlaying[sourceIndex]?.FilePath);
} }
public static void Stop(int sourceIndex) public static void Stop(int sourceIndex)
@@ -291,7 +291,7 @@ namespace Barotrauma.Sounds
ALHelper.Efx.Filter(lowpassFilterId, OpenTK.Audio.OpenAL.EfxFilterf.LowpassGainHF, lowPassHfGain = value); ALHelper.Efx.Filter(lowpassFilterId, OpenTK.Audio.OpenAL.EfxFilterf.LowpassGainHF, lowPassHfGain = value);
ALHelper.Efx.BindFilterToSource(alSources[i], lowpassFilterId); ALHelper.Efx.BindFilterToSource(alSources[i], lowpassFilterId);
ALHelper.Check(); ALHelper.Check(soundsPlaying[i]?.FilePath);
} }
} }
} }
@@ -316,7 +316,7 @@ namespace Barotrauma.Sounds
ALHelper.Efx.Filter(lowpassFilterId, OpenTK.Audio.OpenAL.EfxFilterf.LowpassGainHF, lowPassGain); ALHelper.Efx.Filter(lowpassFilterId, OpenTK.Audio.OpenAL.EfxFilterf.LowpassGainHF, lowPassGain);
ALHelper.Efx.BindFilterToSource(alSources[sourceIndex], lowpassFilterId); ALHelper.Efx.BindFilterToSource(alSources[sourceIndex], lowpassFilterId);
ALHelper.Check(); ALHelper.Check(soundsPlaying[sourceIndex]?.FilePath);
} }
public static OggStream StartStream(string file, float volume = 1.0f) public static OggStream StartStream(string file, float volume = 1.0f)
@@ -331,7 +331,7 @@ namespace Barotrauma.Sounds
oggStream.Play(volume); oggStream.Play(volume);
ALHelper.Check(); ALHelper.Check(file);
return oggStream; return oggStream;
} }
@@ -361,6 +361,7 @@ namespace Barotrauma.Sounds
for (int i = 0; i < DefaultSourceCount; i++) for (int i = 0; i < DefaultSourceCount; i++)
{ {
string soundPath = soundsPlaying[i]?.FilePath;
var state = OpenTK.Audio.OpenAL.AL.GetSourceState(alSources[i]); var state = OpenTK.Audio.OpenAL.AL.GetSourceState(alSources[i]);
if (state == OpenTK.Audio.OpenAL.ALSourceState.Playing || state == OpenTK.Audio.OpenAL.ALSourceState.Paused) if (state == OpenTK.Audio.OpenAL.ALSourceState.Playing || state == OpenTK.Audio.OpenAL.ALSourceState.Paused)
{ {
@@ -368,8 +369,7 @@ namespace Barotrauma.Sounds
} }
OpenTK.Audio.OpenAL.AL.DeleteSource(alSources[i]); OpenTK.Audio.OpenAL.AL.DeleteSource(alSources[i]);
ALHelper.Check(soundPath);
ALHelper.Check();
} }
if (oggStream != null) if (oggStream != null)
@@ -254,9 +254,12 @@ namespace Barotrauma
partial void DisposeTexture() partial void DisposeTexture()
{ {
//check if another sprite is using the same texture //check if another sprite is using the same texture
foreach (Sprite s in list) if (!string.IsNullOrEmpty(file)) //file can be empty if the sprite is created directly from a Texture2D instance
{ {
if (s.file == file) return; foreach (Sprite s in list)
{
if (s.file == file) return;
}
} }
//if not, free the texture //if not, free the texture
@@ -267,6 +270,5 @@ namespace Barotrauma
} }
} }
} }
} }
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.8.1.5")] [assembly: AssemblyVersion("0.8.1.7")]
[assembly: AssemblyFileVersion("0.8.1.5")] [assembly: AssemblyFileVersion("0.8.1.7")]
@@ -119,7 +119,7 @@ namespace Barotrauma
subs = Submarine.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.HideInMenus)).ToList(); subs = Submarine.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.HideInMenus)).ToList();
if (subs == null || subs.Count()==0) if (subs == null || subs.Count() == 0)
{ {
throw new Exception("No submarines are available."); throw new Exception("No submarines are available.");
} }
@@ -187,7 +187,7 @@ namespace Barotrauma
if (GameMain.Server.SubSelectionMode == SelectionMode.Random) if (GameMain.Server.SubSelectionMode == SelectionMode.Random)
{ {
var nonShuttles = Submarine.SavedSubmarines.FindAll(c => !c.HasTag(SubmarineTag.Shuttle) && !c.HasTag(SubmarineTag.HideInMenus)); var nonShuttles = Submarine.SavedSubmarines.Where(c => !c.HasTag(SubmarineTag.Shuttle) && !c.HasTag(SubmarineTag.HideInMenus)).ToList();
SelectedSub = nonShuttles[Rand.Range(0, nonShuttles.Count)]; SelectedSub = nonShuttles[Rand.Range(0, nonShuttles.Count)];
} }
if (GameMain.Server.ModeSelectionMode == SelectionMode.Random) if (GameMain.Server.ModeSelectionMode == SelectionMode.Random)
@@ -261,7 +261,7 @@
<Sprite texture="signalcomp.png" depth="0.8" sourcerect="48,16,16,16"/> <Sprite texture="signalcomp.png" depth="0.8" sourcerect="48,16,16,16"/>
<RelayComponent canbeselected = "true"> <RelayComponent canbeselected="true" vulnerabletoemp="false">
<GuiFrame rect="0,0,200,160" alignment="Center" style="ItemUI"/> <GuiFrame rect="0,0,200,160" alignment="Center" style="ItemUI"/>
</RelayComponent> </RelayComponent>
@@ -21,7 +21,7 @@
<Sprite texture = "reactor.png" sourcerect="0,0,321,192" depth="0.8"/> <Sprite texture = "reactor.png" sourcerect="0,0,321,192" depth="0.8"/>
<Reactor canbeselected = "true"> <Reactor canbeselected="true" vulnerabletoemp="false">
<GuiFrame rect="0,0,760,460" alignment="Center" style="ItemUI"/> <GuiFrame rect="0,0,760,460" alignment="Center" style="ItemUI"/>
<RequiredSkill name="Construction" level="30"/> <RequiredSkill name="Construction" level="30"/>
<StatusEffect type="InWater" target="This" Temperature="-500.0"/> <StatusEffect type="InWater" target="This" Temperature="-500.0"/>
@@ -38,6 +38,9 @@ namespace Barotrauma
#if DEBUG #if DEBUG
DebugConsole.ThrowError("Attempted to access a removed AITarget\n" + Environment.StackTrace); DebugConsole.ThrowError("Attempted to access a removed AITarget\n" + Environment.StackTrace);
#endif #endif
GameAnalyticsManager.AddErrorEventOnce("AITarget.WorldPosition:EntityRemoved",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Attempted to access a removed AITarget\n" + Environment.StackTrace);
return Vector2.Zero; return Vector2.Zero;
} }
@@ -54,6 +57,9 @@ namespace Barotrauma
#if DEBUG #if DEBUG
DebugConsole.ThrowError("Attempted to access a removed AITarget\n" + Environment.StackTrace); DebugConsole.ThrowError("Attempted to access a removed AITarget\n" + Environment.StackTrace);
#endif #endif
GameAnalyticsManager.AddErrorEventOnce("AITarget.WorldPosition:EntityRemoved",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Attempted to access a removed AITarget\n" + Environment.StackTrace);
return Vector2.Zero; return Vector2.Zero;
} }
@@ -274,6 +274,12 @@ namespace Barotrauma
private void UpdateEscape(float deltaTime) private void UpdateEscape(float deltaTime)
{ {
if (selectedAiTarget == null || selectedAiTarget.Entity == null || selectedAiTarget.Entity.Removed)
{
state = AIState.None;
return;
}
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(SimPosition - selectedAiTarget.SimPosition) * 5); SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(SimPosition - selectedAiTarget.SimPosition) * 5);
SteeringManager.SteeringWander(1.0f); SteeringManager.SteeringWander(1.0f);
SteeringManager.SteeringAvoid(deltaTime, 2f); SteeringManager.SteeringAvoid(deltaTime, 2f);
@@ -25,6 +25,11 @@ namespace Barotrauma
if (limbs == null) if (limbs == null)
{ {
DebugConsole.ThrowError("Attempted to access a potentially removed ragdoll. Character: " + character.Name + ", id: " + character.ID + ", removed: " + character.Removed + ", ragdoll removed: " + !list.Contains(this)); DebugConsole.ThrowError("Attempted to access a potentially removed ragdoll. Character: " + character.Name + ", id: " + character.ID + ", removed: " + character.Removed + ", ragdoll removed: " + !list.Contains(this));
GameAnalyticsManager.AddErrorEventOnce(
"Ragdoll.Limbs:AccessRemoved",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Attempted to access a potentially removed ragdoll. Character: " + character.Name + ", id: " + character.ID + ", removed: " + character.Removed + ", ragdoll removed: " + !list.Contains(this) + "\n" + Environment.StackTrace);
return new Limb[0]; return new Limb[0];
} }
return limbs; return limbs;
@@ -88,6 +93,8 @@ namespace Barotrauma
protected List<PhysicsBody> collider; protected List<PhysicsBody> collider;
protected int colliderIndex = 0; protected int colliderIndex = 0;
private Category prevCollisionCategory = Category.None;
public PhysicsBody Collider public PhysicsBody Collider
{ {
get get
@@ -269,11 +276,7 @@ namespace Barotrauma
get { return ignorePlatforms; } get { return ignorePlatforms; }
set set
{ {
if (ignorePlatforms == value) return;
ignorePlatforms = value; ignorePlatforms = value;
UpdateCollisionCategories();
} }
} }
@@ -365,8 +368,8 @@ namespace Barotrauma
foreach (var joint in LimbJoints) foreach (var joint in LimbJoints)
{ {
joint.BodyB.SetTransform( joint.LimbB?.body?.SetTransform(
joint.BodyA.Position + (joint.LocalAnchorA - joint.LocalAnchorB)*0.1f, joint.BodyA.Position + (joint.LocalAnchorA - joint.LocalAnchorB) * 0.1f,
(joint.LowerLimit + joint.UpperLimit) / 2.0f); (joint.LowerLimit + joint.UpperLimit) / 2.0f);
} }
@@ -391,7 +394,7 @@ namespace Barotrauma
Limb torso = GetLimb(LimbType.Torso); Limb torso = GetLimb(LimbType.Torso);
Limb head = GetLimb(LimbType.Head); Limb head = GetLimb(LimbType.Head);
MainLimb = torso == null ? head : torso; MainLimb = torso ?? head;
} }
public void AddJoint(XElement subElement, float scale = 1.0f) public void AddJoint(XElement subElement, float scale = 1.0f)
@@ -739,7 +742,15 @@ namespace Barotrauma
public void FindHull(Vector2? worldPosition = null, bool setSubmarine = true) public void FindHull(Vector2? worldPosition = null, bool setSubmarine = true)
{ {
Vector2 findPos = worldPosition==null ? this.WorldPosition : (Vector2)worldPosition; Vector2 findPos = worldPosition == null ? this.WorldPosition : (Vector2)worldPosition;
if (!MathUtils.IsValid(findPos))
{
GameAnalyticsManager.AddErrorEventOnce(
"Ragdoll.FindHull:InvalidPosition",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Attempted to find a hull at an invalid position (" + findPos + ")\n" + Environment.StackTrace);
return;
}
Hull newHull = Hull.FindHull(findPos, currentHull); Hull newHull = Hull.FindHull(findPos, currentHull);
@@ -799,10 +810,7 @@ namespace Barotrauma
} }
CurrentHull = newHull; CurrentHull = newHull;
character.Submarine = currentHull?.Submarine;
character.Submarine = currentHull == null ? null : currentHull.Submarine;
UpdateCollisionCategories();
} }
public void Teleport(Vector2 moveAmount, Vector2 velocityChange) public void Teleport(Vector2 moveAmount, Vector2 velocityChange)
@@ -843,6 +851,9 @@ namespace Barotrauma
wall | Physics.CollisionProjectile | Physics.CollisionStairs wall | Physics.CollisionProjectile | Physics.CollisionStairs
: wall | Physics.CollisionProjectile | Physics.CollisionPlatform | Physics.CollisionStairs; : wall | Physics.CollisionProjectile | Physics.CollisionPlatform | Physics.CollisionStairs;
if (collisionCategory == prevCollisionCategory) return;
prevCollisionCategory = collisionCategory;
Collider.CollidesWith = collisionCategory; Collider.CollidesWith = collisionCategory;
foreach (Limb limb in Limbs) foreach (Limb limb in Limbs)
@@ -868,6 +879,7 @@ namespace Barotrauma
UpdateNetPlayerPosition(deltaTime); UpdateNetPlayerPosition(deltaTime);
CheckDistFromCollider(); CheckDistFromCollider();
UpdateCollisionCategories();
Vector2 flowForce = Vector2.Zero; Vector2 flowForce = Vector2.Zero;
@@ -1090,20 +1102,17 @@ namespace Barotrauma
float tfloorY = rayStart.Y + (rayEnd.Y - rayStart.Y) * closestFraction; float tfloorY = rayStart.Y + (rayEnd.Y - rayStart.Y) * closestFraction;
float targetY = tfloorY + Collider.height * 0.5f + Collider.radius + colliderHeightFromFloor; float targetY = tfloorY + Collider.height * 0.5f + Collider.radius + colliderHeightFromFloor;
if (Math.Abs(Collider.SimPosition.Y - targetY) > 0.01f && Collider.SimPosition.Y<targetY && !forceImmediate) if (Math.Abs(Collider.SimPosition.Y - targetY) > 0.01f)
{ {
Vector2 newSpeed = Collider.LinearVelocity; if (forceImmediate)
newSpeed.Y = (targetY - Collider.SimPosition.Y)*5.0f; {
Collider.LinearVelocity = newSpeed; Collider.LinearVelocity = new Vector2(Collider.LinearVelocity.X, 0);
} Collider.SetTransform(new Vector2(Collider.SimPosition.X, targetY), Collider.Rotation);
else }
{ else
Vector2 newSpeed = Collider.LinearVelocity; {
newSpeed.Y = 0.0f; Collider.LinearVelocity = new Vector2(Collider.LinearVelocity.X, (targetY - Collider.SimPosition.Y) * 5.0f);
Collider.LinearVelocity = newSpeed; }
Vector2 newPos = Collider.SimPosition;
newPos.Y = targetY;
Collider.SetTransform(newPos, Collider.Rotation);
} }
} }
} }
@@ -1165,6 +1174,16 @@ namespace Barotrauma
public void SetPosition(Vector2 simPosition, bool lerp = false) public void SetPosition(Vector2 simPosition, bool lerp = false)
{ {
if (!MathUtils.IsValid(simPosition))
{
DebugConsole.ThrowError("Attempted to move a ragdoll (" + character.Name + ") to an invalid position (" + simPosition + "). " + Environment.StackTrace);
GameAnalyticsManager.AddErrorEventOnce(
"Ragdoll.SetPosition:InvalidPosition",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Attempted to move a ragdoll (" + character.Name + ") to an invalid position (" + simPosition + "). " + Environment.StackTrace);
return;
}
Vector2 limbMoveAmount = simPosition - MainLimb.SimPosition; Vector2 limbMoveAmount = simPosition - MainLimb.SimPosition;
Collider.SetTransform(simPosition, Collider.Rotation); Collider.SetTransform(simPosition, Collider.Rotation);
@@ -1245,8 +1264,6 @@ namespace Barotrauma
{ {
//set the position of the ragdoll to make sure limbs don't get stuck inside walls when re-enabling collisions //set the position of the ragdoll to make sure limbs don't get stuck inside walls when re-enabling collisions
SetPosition(Collider.SimPosition, true); SetPosition(Collider.SimPosition, true);
UpdateCollisionCategories();
collisionsDisabled = false; collisionsDisabled = false;
} }
} }
@@ -1445,22 +1462,17 @@ namespace Barotrauma
private Vector2 GetFlowForce() private Vector2 GetFlowForce()
{ {
Vector2 limbPos = ConvertUnits.ToDisplayUnits(Limbs[0].SimPosition); Vector2 limbPos = Limbs[0].Position;
Vector2 force = Vector2.Zero; Vector2 force = Vector2.Zero;
foreach (MapEntity e in MapEntity.mapEntityList) foreach (Gap gap in Gap.GapList)
{ {
Gap gap = e as Gap; if (gap.Open <= 0.0f || gap.FlowTargetHull != currentHull || gap.LerpedFlowForce == Vector2.Zero) continue;
if (gap == null || gap.FlowTargetHull != currentHull || gap.LerpedFlowForce == Vector2.Zero) continue;
Vector2 gapPos = gap.SimPosition; Vector2 gapPos = gap.SimPosition;
float dist = Vector2.Distance(limbPos, gapPos); float dist = Vector2.Distance(limbPos, gapPos);
force += Vector2.Normalize(gap.LerpedFlowForce) * (Math.Max(gap.LerpedFlowForce.Length() - dist, 0.0f) / 500.0f); force += Vector2.Normalize(gap.LerpedFlowForce) * (Math.Max(gap.LerpedFlowForce.Length() - dist, 0.0f) / 500.0f);
} }
if (force.Length() > 20.0f) return force;
return force; return force;
} }
@@ -1960,7 +1960,7 @@ namespace Barotrauma
characterType = "Enemy"; characterType = "Enemy";
else if (AIController is HumanAIController) else if (AIController is HumanAIController)
characterType = "AICrew"; characterType = "AICrew";
GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("Kill:" + characterType + ":" + SpeciesName + ":" + causeOfDeath); GameAnalyticsManager.AddDesignEvent("Kill:" + characterType + ":" + SpeciesName + ":" + causeOfDeath);
} }
if (OnDeath != null) OnDeath(this, causeOfDeath); if (OnDeath != null) OnDeath(this, causeOfDeath);
@@ -1898,6 +1898,15 @@ namespace Barotrauma
if (string.IsNullOrWhiteSpace(command)) return; if (string.IsNullOrWhiteSpace(command)) return;
string[] splitCommand = SplitCommand(command); string[] splitCommand = SplitCommand(command);
if (splitCommand.Length == 0)
{
DebugConsole.ThrowError("Failed to execute command \"" + command + "\"!");
GameAnalyticsManager.AddErrorEventOnce(
"DebugConsole.ExecuteCommand:LengthZero",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to execute command \"" + command + "\"!");
return;
}
if (!splitCommand[0].ToLowerInvariant().Equals("admin")) if (!splitCommand[0].ToLowerInvariant().Equals("admin"))
{ {
@@ -1976,6 +1985,13 @@ namespace Barotrauma
return; return;
} }
if (!MathUtils.IsValid(cursorWorldPos))
{
GameMain.Server.SendConsoleMessage("Could not execute command \"" + command + "\" - invalid cursor position.", client);
NewMessage(client.Name + " attempted to execute the console command \"" + command + "\" with invalid cursor position.", Color.White);
return;
}
try try
{ {
matchingCommand.ServerExecuteOnClientRequest(client, cursorWorldPos, splitCommand.Skip(1).ToArray()); matchingCommand.ServerExecuteOnClientRequest(client, cursorWorldPos, splitCommand.Skip(1).ToArray());
@@ -1,16 +1,48 @@
using GameAnalyticsSDK.Net; using GameAnalyticsSDK.Net;
using System; using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
namespace Barotrauma namespace Barotrauma
{ {
public static class GameAnalyticsManager public static class GameAnalyticsManager
{ {
private static HashSet<string> sentEventIdentifiers = new HashSet<string>();
public static void Init() public static void Init()
{ {
#if DEBUG #if DEBUG
GameAnalytics.SetEnabledInfoLog(true); GameAnalytics.SetEnabledInfoLog(true);
#endif #endif
GameAnalytics.ConfigureBuild(GameMain.Version.ToString());
string exePath = Assembly.GetEntryAssembly().Location;
string exeName = null;
Md5Hash exeHash = null;
exeName = Path.GetFileNameWithoutExtension(exePath).Replace(":", "");
var md5 = MD5.Create();
try
{
using (var stream = File.OpenRead(exePath))
{
exeHash = new Md5Hash(stream);
}
}
catch (Exception e)
{
DebugConsole.ThrowError("Error while calculating MD5 hash for the executable \"" + exePath + "\"", e);
}
GameAnalytics.ConfigureBuild(GameMain.Version.ToString()
+ (string.IsNullOrEmpty(exeName) ? "Unknown" : exeName) + ":"
+ ((exeHash?.ShortHash == null) ? "Unknown" : exeHash.ShortHash));
GameAnalytics.AddDesignEvent("Executable:"
+ (string.IsNullOrEmpty(exeName) ? "Unknown" : exeName) + ":"
+ ((exeHash?.ShortHash == null) ? "Unknown" : exeHash.ShortHash));
GameAnalytics.ConfigureAvailableCustomDimensions01("singleplayer", "multiplayer", "editor"); GameAnalytics.ConfigureAvailableCustomDimensions01("singleplayer", "multiplayer", "editor");
GameAnalytics.Initialize("a3a073c20982de7c15d21e840e149122", "9010ad9a671233b8d9610d76cec8c897d9ff3ba7"); GameAnalytics.Initialize("a3a073c20982de7c15d21e840e149122", "9010ad9a671233b8d9610d76cec8c897d9ff3ba7");
@@ -21,5 +53,47 @@ namespace Barotrauma
contentPackageName.Replace(":", "").Substring(0, Math.Min(32, contentPackageName.Length))); contentPackageName.Replace(":", "").Substring(0, Math.Min(32, contentPackageName.Length)));
} }
} }
/// <summary>
/// Adds an error event to GameAnalytics if an event with the same identifier has not been added yet.
/// </summary>
public static void AddErrorEventOnce(string identifier, EGAErrorSeverity errorSeverity, string message)
{
if (!GameSettings.SendUserStatistics) return;
if (sentEventIdentifiers.Contains(identifier)) return;
GameAnalytics.AddErrorEvent(errorSeverity, message);
sentEventIdentifiers.Add(identifier);
}
public static void AddDesignEvent(string eventID)
{
if (!GameSettings.SendUserStatistics) return;
GameAnalytics.AddDesignEvent(eventID);
}
public static void AddDesignEvent(string eventID, double value)
{
if (!GameSettings.SendUserStatistics) return;
GameAnalytics.AddDesignEvent(eventID, value);
}
public static void AddProgressionEvent(EGAProgressionStatus progressionStatus, string progression01)
{
if (!GameSettings.SendUserStatistics) return;
GameAnalytics.AddProgressionEvent(progressionStatus, progression01);
}
public static void AddProgressionEvent(EGAProgressionStatus progressionStatus, string progression01, string progression02)
{
if (!GameSettings.SendUserStatistics) return;
GameAnalytics.AddProgressionEvent(progressionStatus, progression01, progression02);
}
public static void SetCustomDimension01(string dimension)
{
if (!GameSettings.SendUserStatistics) return;
GameAnalytics.SetCustomDimension01(dimension);
}
} }
} }
@@ -57,6 +57,7 @@ namespace Barotrauma
public void CreateItems() public void CreateItems()
{ {
CreateItems(purchasedItems); CreateItems(purchasedItems);
OnItemsChanged?.Invoke();
} }
public static void CreateItems(List<ItemPrefab> itemsToSpawn) public static void CreateItems(List<ItemPrefab> itemsToSpawn)
@@ -235,12 +235,11 @@ namespace Barotrauma
} }
} }
if (GameSettings.SendUserStatistics) GameAnalyticsManager.AddDesignEvent("Submarine:" + submarine.Name);
{ GameAnalyticsManager.AddDesignEvent("Level", ToolBox.StringToInt(level.Seed));
GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("Submarine:" + submarine.Name); GameAnalyticsManager.AddProgressionEvent(GameAnalyticsSDK.Net.EGAProgressionStatus.Start,
GameAnalyticsSDK.Net.GameAnalytics.AddProgressionEvent(GameAnalyticsSDK.Net.EGAProgressionStatus.Start,
GameMode.Name, (Mission == null ? "None" : Mission.GetType().ToString())); GameMode.Name, (Mission == null ? "None" : Mission.GetType().ToString()));
}
#if CLIENT #if CLIENT
roundSummary = new RoundSummary(this); roundSummary = new RoundSummary(this);
@@ -253,11 +252,10 @@ namespace Barotrauma
public void EndRound(string endMessage) public void EndRound(string endMessage)
{ {
if (Mission != null) Mission.End(); if (Mission != null) Mission.End();
if (GameSettings.SendUserStatistics) GameAnalyticsManager.AddProgressionEvent(
{ (Mission == null || Mission.Completed) ? GameAnalyticsSDK.Net.EGAProgressionStatus.Complete : GameAnalyticsSDK.Net.EGAProgressionStatus.Fail,
GameAnalyticsSDK.Net.GameAnalytics.AddProgressionEvent((Mission == null || Mission.Completed) ? GameAnalyticsSDK.Net.EGAProgressionStatus.Complete : GameAnalyticsSDK.Net.EGAProgressionStatus.Fail, GameMode.Name,
GameMode.Name, (Mission == null ? "None" : Mission.GetType().ToString())); (Mission == null ? "None" : Mission.GetType().ToString()));
}
#if CLIENT #if CLIENT
if (roundSummary != null) if (roundSummary != null)
@@ -164,7 +164,7 @@ namespace Barotrauma
GameMain.Config.Save("config.xml"); GameMain.Config.Save("config.xml");
} }
} }
public static bool ShowUserStatisticsPrompt { get; private set; } public static bool ShowUserStatisticsPrompt { get; set; }
public GameSettings(string filePath) public GameSettings(string filePath)
{ {
@@ -334,8 +334,12 @@ namespace Barotrauma
new XAttribute("soundvolume", soundVolume), new XAttribute("soundvolume", soundVolume),
new XAttribute("verboselogging", VerboseLogging), new XAttribute("verboselogging", VerboseLogging),
new XAttribute("savedebugconsolelogs", SaveDebugConsoleLogs), new XAttribute("savedebugconsolelogs", SaveDebugConsoleLogs),
new XAttribute("enablesplashscreen", EnableSplashScreen), new XAttribute("enablesplashscreen", EnableSplashScreen));
new XAttribute("senduserstatistics", sendUserStatistics));
if (!ShowUserStatisticsPrompt)
{
doc.Root.Add(new XAttribute("senduserstatistics", sendUserStatistics));
}
if (WasGameUpdated) if (WasGameUpdated)
{ {
@@ -398,7 +402,16 @@ namespace Barotrauma
new XAttribute("gender", characterGender)); new XAttribute("gender", characterGender));
doc.Root.Add(playerElement); doc.Root.Add(playerElement);
doc.Save(filePath); try
{
doc.Save(filePath);
}
catch (Exception e)
{
DebugConsole.ThrowError("Saving game settings failed.", e);
GameAnalyticsManager.AddErrorEventOnce("GameSettings.Save:SaveFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Saving game settings failed.\n" + e.Message + "\n" + e.StackTrace);
}
} }
private IEnumerable<object> ApplyUnsavedChanges() private IEnumerable<object> ApplyUnsavedChanges()
@@ -345,17 +345,31 @@ namespace Barotrauma.Items.Components
private void CreateDoorBody() private void CreateDoorBody()
{ {
Vector2 position = ConvertUnits.ToSimUnits(item.Position + (dockingTarget.door.Item.WorldPosition - item.WorldPosition));
if (!MathUtils.IsValid(position))
{
string errorMsg =
"Attempted to create a door body at an invalid position (item pos: " + item.Position
+ ", item world pos: " + item.WorldPosition
+ ", docking target world pos: " + DockingTarget.door.Item.WorldPosition + ")\n" + Environment.StackTrace;
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce(
"DockingPort.CreateDoorBody:InvalidPosition",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
errorMsg);
position = Vector2.Zero;
}
doorBody = BodyFactory.CreateRectangle(GameMain.World, doorBody = BodyFactory.CreateRectangle(GameMain.World,
dockingTarget.door.Body.width, dockingTarget.door.Body.width,
dockingTarget.door.Body.height, dockingTarget.door.Body.height,
1.0f, 1.0f,
position,
dockingTarget.door); dockingTarget.door);
doorBody.CollisionCategories = Physics.CollisionWall; doorBody.CollisionCategories = Physics.CollisionWall;
doorBody.BodyType = BodyType.Static; doorBody.BodyType = BodyType.Static;
doorBody.SetTransform(
ConvertUnits.ToSimUnits(item.Position + (dockingTarget.door.Item.WorldPosition - item.WorldPosition)),
0.0f);
} }
private void CreateHull() private void CreateHull()
@@ -349,6 +349,14 @@ namespace Barotrauma.Items.Components
private void PushCharactersAway() private void PushCharactersAway()
{ {
if (!MathUtils.IsValid(item.SimPosition))
{
DebugConsole.ThrowError("Failed to push a character out of a doorway - position of the door is not valid (" + item.SimPosition + ")");
GameAnalyticsManager.AddErrorEventOnce("PushCharactersAway:DoorPosInvalid", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to push a character out of a doorway - position of the door is not valid (" + item.SimPosition + ").");
return;
}
//push characters out of the doorway when the door is closing/opening //push characters out of the doorway when the door is closing/opening
Vector2 simPos = ConvertUnits.ToSimUnits(new Vector2(item.Rect.X, item.Rect.Y)); Vector2 simPos = ConvertUnits.ToSimUnits(new Vector2(item.Rect.X, item.Rect.Y));
@@ -360,6 +368,16 @@ namespace Barotrauma.Items.Components
foreach (Character c in Character.CharacterList) foreach (Character c in Character.CharacterList)
{ {
if (!c.Enabled) continue;
if (!MathUtils.IsValid(c.SimPosition))
{
DebugConsole.ThrowError("Failed to push a character out of a doorway - position of the character \"" + c.Name + "\" is not valid (" + c.SimPosition + ")");
GameAnalyticsManager.AddErrorEventOnce("PushCharactersAway:CharacterPosInvalid", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to push a character out of a doorway - position of the character \"" + c.Name + "\" is not valid (" + c.SimPosition + ")." +
" Removed: " + c.Removed +
" Remoteplayer: " + c.IsRemotePlayer);
continue;
}
int dir = isHorizontal ? Math.Sign(c.SimPosition.Y - item.SimPosition.Y) : Math.Sign(c.SimPosition.X - item.SimPosition.X); int dir = isHorizontal ? Math.Sign(c.SimPosition.Y - item.SimPosition.Y) : Math.Sign(c.SimPosition.X - item.SimPosition.X);
List<PhysicsBody> bodies = c.AnimController.Limbs.Select(l => l.body).ToList(); List<PhysicsBody> bodies = c.AnimController.Limbs.Select(l => l.body).ToList();
@@ -368,17 +386,24 @@ namespace Barotrauma.Items.Components
foreach (PhysicsBody body in bodies) foreach (PhysicsBody body in bodies)
{ {
float diff = 0.0f; float diff = 0.0f;
if (!MathUtils.IsValid(body.SimPosition))
{
DebugConsole.ThrowError("Failed to push a limb out of a doorway - position of the body (character \"" + c.Name + "\") is not valid (" + body.SimPosition + ")");
GameAnalyticsManager.AddErrorEventOnce("PushCharactersAway:LimbPosInvalid", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to push a character out of a doorway - position of the character \"" + c.Name + "\" is not valid (" + body.SimPosition + ")." +
" Removed: " + c.Removed +
" Remoteplayer: " + c.IsRemotePlayer);
continue;
}
if (isHorizontal) if (isHorizontal)
{ {
if (body.SimPosition.X < simPos.X || body.SimPosition.X > simPos.X + simSize.X) continue; if (body.SimPosition.X < simPos.X || body.SimPosition.X > simPos.X + simSize.X) continue;
diff = body.SimPosition.Y - item.SimPosition.Y; diff = body.SimPosition.Y - item.SimPosition.Y;
} }
else else
{ {
if (body.SimPosition.Y > simPos.Y || body.SimPosition.Y < simPos.Y - simSize.Y) continue; if (body.SimPosition.Y > simPos.Y || body.SimPosition.Y < simPos.Y - simSize.Y) continue;
diff = body.SimPosition.X - item.SimPosition.X; diff = body.SimPosition.X - item.SimPosition.X;
} }
@@ -34,7 +34,6 @@ namespace Barotrauma.Items.Components
set { powerConsumption = value; } set { powerConsumption = value; }
} }
[Serialize(false, true)] [Serialize(false, true)]
public override bool IsActive public override bool IsActive
{ {
@@ -60,6 +59,13 @@ namespace Barotrauma.Items.Components
set { voltage = Math.Max(0.0f, value); } set { voltage = Math.Max(0.0f, value); }
} }
[Editable(ToolTip = "Can the item be damaged by electomagnetic pulses."), Serialize(true, true)]
public bool VulnerableToEMP
{
get;
set;
}
public Powered(Item item, XElement element) public Powered(Item item, XElement element)
: base(item, element) : base(item, element)
{ {
@@ -783,12 +783,6 @@ namespace Barotrauma
public override void Update(float deltaTime, Camera cam) public override void Update(float deltaTime, Camera cam)
{ {
if (Level.Loaded != null && WorldPosition.Y < Level.MaxEntityDepth)
{
Spawner.AddToRemoveQueue(this);
return;
}
ApplyStatusEffects(ActionType.Always, deltaTime, null); ApplyStatusEffects(ActionType.Always, deltaTime, null);
foreach (ItemComponent ic in components) foreach (ItemComponent ic in components)
@@ -851,6 +845,12 @@ namespace Barotrauma
MathHelper.Clamp(body.LinearVelocity.X, -MaxVel, MaxVel), MathHelper.Clamp(body.LinearVelocity.X, -MaxVel, MaxVel),
MathHelper.Clamp(body.LinearVelocity.Y, -MaxVel, MaxVel)); MathHelper.Clamp(body.LinearVelocity.Y, -MaxVel, MaxVel));
} }
if (CurrentHull == null && body.SimPosition.Y < ConvertUnits.ToSimUnits(Level.MaxEntityDepth))
{
Spawner.AddToRemoveQueue(this);
return;
}
} }
UpdateNetPosition(); UpdateNetPosition();
@@ -1430,6 +1430,10 @@ namespace Barotrauma
msg.Write(((Rectangle)value).Width); msg.Write(((Rectangle)value).Width);
msg.Write(((Rectangle)value).Height); msg.Write(((Rectangle)value).Height);
} }
else if (value is Enum)
{
msg.Write((int)value);
}
else else
{ {
throw new System.NotImplementedException("Serializing item properties of the type \"" + value.GetType() + "\" not supported"); throw new System.NotImplementedException("Serializing item properties of the type \"" + value.GetType() + "\" not supported");
@@ -1487,6 +1491,24 @@ namespace Barotrauma
{ {
property.TrySetValue(new Vector4(msg.ReadInt32(), msg.ReadInt32(), msg.ReadInt32(), msg.ReadInt32())); property.TrySetValue(new Vector4(msg.ReadInt32(), msg.ReadInt32(), msg.ReadInt32(), msg.ReadInt32()));
} }
else if (typeof(Enum).IsAssignableFrom(type))
{
int intVal = msg.ReadInt32();
try
{
property.TrySetValue(Enum.ToObject(type, intVal));
}
catch (Exception e)
{
#if DEBUG
DebugConsole.ThrowError("Failed to convert the int value \"" + intVal + "\" to " + type, e);
#endif
GameAnalyticsManager.AddErrorEventOnce(
"Item.ReadPropertyChange:" + Name + ":" + type,
GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
"Failed to convert the int value \"" + intVal + "\" to " + type + " (item " + Name + ")");
}
}
else else
{ {
return; return;
@@ -79,14 +79,12 @@ namespace Barotrauma
float distSqr = Vector2.DistanceSquared(item.WorldPosition, worldPosition); float distSqr = Vector2.DistanceSquared(item.WorldPosition, worldPosition);
if (distSqr > displayRangeSqr) continue; if (distSqr > displayRangeSqr) continue;
//ignore reactors (don't want to blow them up)
if (item.GetComponent<Reactor>() != null) continue;
float distFactor = 1.0f - (float)Math.Sqrt(distSqr) / displayRange; float distFactor = 1.0f - (float)Math.Sqrt(distSqr) / displayRange;
//damage repairable power-consuming items //damage repairable power-consuming items
var powerTransfer = item.GetComponent<Powered>(); var powered = item.GetComponent<Powered>();
if (powerTransfer != null && item.FixRequirements.Count > 0) if (powered == null || !powered.VulnerableToEMP) continue;
if (item.FixRequirements.Count > 0)
{ {
item.Condition -= 100 * empStrength * distFactor; item.Condition -= 100 * empStrength * distFactor;
} }
@@ -323,18 +323,9 @@ namespace Barotrauma
//choose random edge (ignoring ones where the adjacent cell is outside limits) //choose random edge (ignoring ones where the adjacent cell is outside limits)
else else
{ {
//if (allowedEdges.Count==0)
//{
// edgeIndex = Rand.Int(currentCell.edges.Count, false);
//}
//else
//{
edgeIndex = Rand.Int(allowedEdges.Count, Rand.RandSync.Server); edgeIndex = Rand.Int(allowedEdges.Count, Rand.RandSync.Server);
if (mirror && edgeIndex > 0) edgeIndex = allowedEdges.Count - edgeIndex; if (mirror && edgeIndex > 0) edgeIndex = allowedEdges.Count - edgeIndex;
edgeIndex = currentCell.edges.IndexOf(allowedEdges[edgeIndex]); edgeIndex = currentCell.edges.IndexOf(allowedEdges[edgeIndex]);
//}
} }
currentCell = currentCell.edges[edgeIndex].AdjacentCell(currentCell); currentCell = currentCell.edges[edgeIndex].AdjacentCell(currentCell);
@@ -358,7 +349,7 @@ namespace Barotrauma
return pathCells; return pathCells;
} }
public static List<Body> GeneratePolygons(List<VoronoiCell> cells, out List<Vector2[]> renderTriangles, bool setSolid=true) public static List<Body> GeneratePolygons(List<VoronoiCell> cells, Level level, out List<Vector2[]> renderTriangles, bool setSolid = true)
{ {
renderTriangles = new List<Vector2[]>(); renderTriangles = new List<Vector2[]>();
var bodies = new List<Body>(); var bodies = new List<Body>();
@@ -366,6 +357,14 @@ namespace Barotrauma
List<Vector2> tempVertices = new List<Vector2>(); List<Vector2> tempVertices = new List<Vector2>();
List<Vector2> bodyPoints = new List<Vector2>(); List<Vector2> bodyPoints = new List<Vector2>();
Body cellBody = new Body(GameMain.World)
{
SleepingAllowed = false,
BodyType = BodyType.Static,
CollisionCategories = Physics.CollisionLevel
};
bodies.Add(cellBody);
for (int n = cells.Count - 1; n >= 0; n-- ) for (int n = cells.Count - 1; n >= 0; n-- )
{ {
VoronoiCell cell = cells[n]; VoronoiCell cell = cells[n];
@@ -413,13 +412,11 @@ namespace Barotrauma
bodyPoints[i] = ConvertUnits.ToSimUnits(bodyPoints[i]); bodyPoints[i] = ConvertUnits.ToSimUnits(bodyPoints[i]);
} }
if (cell.CellType == CellType.Empty) continue; if (cell.CellType == CellType.Empty) continue;
cellBody.UserData = cell;
var triangles = MathUtils.TriangulateConvexHull(bodyPoints, ConvertUnits.ToSimUnits(cell.Center)); var triangles = MathUtils.TriangulateConvexHull(bodyPoints, ConvertUnits.ToSimUnits(cell.Center));
Body cellBody = new Body(GameMain.World);
for (int i = 0; i < triangles.Count; i++) for (int i = 0; i < triangles.Count; i++)
{ {
//don't create a triangle if any of the vertices are too close to each other //don't create a triangle if any of the vertices are too close to each other
@@ -429,16 +426,20 @@ namespace Barotrauma
Vector2.Distance(triangles[i][1], triangles[i][2]) < 0.05f) continue; Vector2.Distance(triangles[i][1], triangles[i][2]) < 0.05f) continue;
Vertices bodyVertices = new Vertices(triangles[i]); Vertices bodyVertices = new Vertices(triangles[i]);
FixtureFactory.AttachPolygon(bodyVertices, 5.0f, cellBody); var newFixture = FixtureFactory.AttachPolygon(bodyVertices, 5.0f, cellBody);
newFixture.UserData = cell;
if (newFixture.Shape.MassData.Area < FarseerPhysics.Settings.Epsilon)
{
DebugConsole.ThrowError("Invalid triangle created by CaveGenerator (" + triangles[i][0] + ", " + triangles[i][1] + ", " + triangles[i][2] + ")");
GameAnalyticsManager.AddErrorEventOnce(
"CaveGenerator.GeneratePolygons:InvalidTriangle",
GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
"Invalid triangle created by CaveGenerator (" + triangles[i][0] + ", " + triangles[i][1] + ", " + triangles[i][2] + "). Seed: " + level.Seed);
}
} }
cellBody.UserData = cell;
cellBody.SleepingAllowed = false;
cellBody.BodyType = BodyType.Kinematic;
cellBody.CollisionCategories = Physics.CollisionLevel;
cell.body = cellBody; cell.body = cellBody;
bodies.Add(cellBody);
} }
return bodies; return bodies;
@@ -449,11 +449,11 @@ namespace Barotrauma
List<VoronoiCell> cellsWithBody = new List<VoronoiCell>(cells); List<VoronoiCell> cellsWithBody = new List<VoronoiCell>(cells);
List<Vector2[]> triangles; List<Vector2[]> triangles;
bodies = CaveGenerator.GeneratePolygons(cellsWithBody, out triangles); bodies = CaveGenerator.GeneratePolygons(cellsWithBody, this, out triangles);
#if CLIENT #if CLIENT
renderer.SetBodyVertices(CaveGenerator.GenerateRenderVerticeList(triangles).ToArray(), generationParams.WallColor); renderer.SetBodyVertices(CaveGenerator.GenerateRenderVerticeList(triangles).ToArray(), generationParams.WallColor);
renderer.SetWallVertices(CaveGenerator.GenerateWallShapes(cells), generationParams.WallColor); renderer.SetWallVertices(CaveGenerator.GenerateWallShapes(cells, this), generationParams.WallColor);
#endif #endif
TopBarrier = BodyFactory.CreateEdge(GameMain.World, TopBarrier = BodyFactory.CreateEdge(GameMain.World,
@@ -700,7 +700,7 @@ namespace Barotrauma
SeaFloorTopPos = bottomPositions.Max(p => p.Y); SeaFloorTopPos = bottomPositions.Max(p => p.Y);
extraWalls = new LevelWall[] { new LevelWall(bottomPositions, new Vector2(0.0f, -2000.0f), backgroundColor) }; extraWalls = new LevelWall[] { new LevelWall(bottomPositions, new Vector2(0.0f, -2000.0f), backgroundColor, this) };
BottomBarrier = BodyFactory.CreateEdge(GameMain.World, BottomBarrier = BodyFactory.CreateEdge(GameMain.World,
ConvertUnits.ToSimUnits(new Vector2(borders.X, 0)), ConvertUnits.ToSimUnits(new Vector2(borders.X, 0)),
@@ -18,10 +18,9 @@ namespace Barotrauma
private List<Body> bodies; private List<Body> bodies;
public LevelWall(List<Vector2> edgePositions, Vector2 extendAmount, Color color) public LevelWall(List<Vector2> edgePositions, Vector2 extendAmount, Color color, Level level)
{ {
cells = new List<VoronoiCell>(); cells = new List<VoronoiCell>();
for (int i = 0; i < edgePositions.Count - 1; i++) for (int i = 0; i < edgePositions.Count - 1; i++)
{ {
Vector2[] vertices = new Vector2[4]; Vector2[] vertices = new Vector2[4];
@@ -47,14 +46,13 @@ namespace Barotrauma
cells.Add(wallCell); cells.Add(wallCell);
} }
List<Vector2[]> triangles; bodies = CaveGenerator.GeneratePolygons(cells, level, out List<Vector2[]> triangles, false);
bodies = CaveGenerator.GeneratePolygons(cells, out triangles, false);
#if CLIENT #if CLIENT
List<VertexPositionTexture> bodyVertices = CaveGenerator.GenerateRenderVerticeList(triangles); List<VertexPositionTexture> bodyVertices = CaveGenerator.GenerateRenderVerticeList(triangles);
SetBodyVertices(bodyVertices.ToArray(), color); SetBodyVertices(bodyVertices.ToArray(), color);
SetWallVertices(CaveGenerator.GenerateWallShapes(cells), color); SetWallVertices(CaveGenerator.GenerateWallShapes(cells, level), color);
#endif #endif
} }
@@ -423,6 +423,7 @@ namespace Barotrauma.RuinGeneration
Alignment[] alignments = new Alignment[] { Alignment.Top, Alignment.Bottom, Alignment.Right, Alignment.Left, Alignment.Center }; Alignment[] alignments = new Alignment[] { Alignment.Top, Alignment.Bottom, Alignment.Right, Alignment.Left, Alignment.Center };
var prop = RuinStructure.GetRandom(RuinStructureType.Prop, alignments[Rand.Int(alignments.Length, Rand.RandSync.Server)]); var prop = RuinStructure.GetRandom(RuinStructureType.Prop, alignments[Rand.Int(alignments.Length, Rand.RandSync.Server)]);
if (prop == null) continue;
Vector2 size = (prop.Prefab is StructurePrefab) ? ((StructurePrefab)prop.Prefab).Size : Vector2.Zero; Vector2 size = (prop.Prefab is StructurePrefab) ? ((StructurePrefab)prop.Prefab).Size : Vector2.Zero;
@@ -51,7 +51,11 @@ namespace Barotrauma
public static bool LockX, LockY; public static bool LockX, LockY;
public static List<Submarine> SavedSubmarines = new List<Submarine>(); private static List<Submarine> savedSubmarines = new List<Submarine>();
public static IEnumerable<Submarine> SavedSubmarines
{
get { return savedSubmarines; }
}
public static readonly Vector2 GridSize = new Vector2(16.0f, 16.0f); public static readonly Vector2 GridSize = new Vector2(16.0f, 16.0f);
@@ -217,7 +221,7 @@ namespace Barotrauma
public Vector2 Velocity public Vector2 Velocity
{ {
get { return subBody==null ? Vector2.Zero : subBody.Velocity; } get { return subBody == null ? Vector2.Zero : subBody.Velocity; }
set set
{ {
if (subBody == null) return; if (subBody == null) return;
@@ -244,7 +248,7 @@ namespace Barotrauma
public override string ToString() public override string ToString()
{ {
return "Barotrauma.Submarine ("+name+")"; return "Barotrauma.Submarine (" + name + ")";
} }
public override bool Removed public override bool Removed
@@ -296,9 +300,19 @@ namespace Barotrauma
string previewImageData = doc.Root.GetAttributeString("previewimage", ""); string previewImageData = doc.Root.GetAttributeString("previewimage", "");
if (!string.IsNullOrEmpty(previewImageData)) if (!string.IsNullOrEmpty(previewImageData))
{ {
using (MemoryStream mem = new MemoryStream(Convert.FromBase64String(previewImageData))) try
{ {
PreviewImage = new Sprite(TextureLoader.FromStream(mem), null, null); using (MemoryStream mem = new MemoryStream(Convert.FromBase64String(previewImageData)))
{
PreviewImage = new Sprite(TextureLoader.FromStream(mem), null, null);
}
}
catch (Exception e)
{
DebugConsole.ThrowError("Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted.", e);
GameAnalyticsManager.AddErrorEventOnce("Submarine..ctor:PreviewImageLoadingFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted.");
PreviewImage = null;
} }
} }
#endif #endif
@@ -557,7 +571,7 @@ namespace Barotrauma
} }
} }
public static bool RectsOverlap(Rectangle rect1, Rectangle rect2, bool inclusive=true) public static bool RectsOverlap(Rectangle rect1, Rectangle rect2, bool inclusive = true)
{ {
if (inclusive) if (inclusive)
{ {
@@ -602,7 +616,7 @@ namespace Barotrauma
if (fraction < closestFraction) if (fraction < closestFraction)
{ {
closestFraction = fraction; closestFraction = fraction;
if (fixture.Body!=null) closestBody = fixture.Body; if (fixture.Body != null) closestBody = fixture.Body;
} }
return fraction; return fraction;
} }
@@ -669,7 +683,7 @@ namespace Barotrauma
get { return flippedX; } get { return flippedX; }
} }
public void FlipX(List<Submarine> parents=null) public void FlipX(List<Submarine> parents = null)
{ {
if (parents == null) parents = new List<Submarine>(); if (parents == null) parents = new List<Submarine>();
parents.Add(this); parents.Add(this);
@@ -784,14 +798,14 @@ namespace Barotrauma
subBody.Update(deltaTime); subBody.Update(deltaTime);
for (int i = 0; i < 2; i++ ) for (int i = 0; i < 2; i++)
{ {
if (MainSubs[i] == null) continue; if (MainSubs[i] == null) continue;
if (this != MainSubs[i] && MainSubs[i].DockedTo.Contains(this)) return; if (this != MainSubs[i] && MainSubs[i].DockedTo.Contains(this)) return;
} }
//send updates more frequently if moving fast //send updates more frequently if moving fast
networkUpdateTimer -= MathHelper.Clamp(Velocity.Length()*10.0f, 0.1f, 5.0f) * deltaTime; networkUpdateTimer -= MathHelper.Clamp(Velocity.Length() * 10.0f, 0.1f, 5.0f) * deltaTime;
if (networkUpdateTimer < 0.0f) if (networkUpdateTimer < 0.0f)
{ {
@@ -875,9 +889,18 @@ namespace Barotrauma
//saving/loading ---------------------------------------------------- //saving/loading ----------------------------------------------------
public static void AddToSavedSubs(Submarine sub)
{
savedSubmarines.Add(sub);
}
public static void RefreshSavedSubs() public static void RefreshSavedSubs()
{ {
SavedSubmarines.Clear(); for (int i = savedSubmarines.Count - 1; i>= 0; i--)
{
savedSubmarines[i].Dispose();
}
System.Diagnostics.Debug.Assert(savedSubmarines.Count == 0);
if (!Directory.Exists(SavePath)) if (!Directory.Exists(SavePath))
{ {
@@ -921,7 +944,7 @@ namespace Barotrauma
foreach (string path in filePaths) foreach (string path in filePaths)
{ {
SavedSubmarines.Add(new Submarine(path)); savedSubmarines.Add(new Submarine(path));
} }
} }
@@ -971,7 +994,7 @@ namespace Barotrauma
catch (Exception e) catch (Exception e)
{ {
DebugConsole.ThrowError("Loading submarine \"" + file + "\" failed! ("+e.Message+")"); DebugConsole.ThrowError("Loading submarine \"" + file + "\" failed! (" + e.Message + ")");
return null; return null;
} }
} }
@@ -1152,7 +1175,7 @@ namespace Barotrauma
public static Submarine Load(string fileName, bool unloadPrevious) public static Submarine Load(string fileName, bool unloadPrevious)
{ {
return Load(fileName, SavePath, unloadPrevious); return Load(fileName, SavePath, unloadPrevious);
} }
public static Submarine Load(string fileName, string folder, bool unloadPrevious) public static Submarine Load(string fileName, string folder, bool unloadPrevious)
@@ -1285,6 +1308,15 @@ namespace Barotrauma
DockedTo.Clear(); DockedTo.Clear();
} }
public void Dispose()
{
savedSubmarines.Remove(this);
#if CLIENT
PreviewImage?.Remove();
PreviewImage = null;
#endif
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null) public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{ {
msg.Write(ID); msg.Write(ID);
@@ -370,27 +370,22 @@ namespace Barotrauma
public bool OnCollision(Fixture f1, Fixture f2, Contact contact) public bool OnCollision(Fixture f1, Fixture f2, Contact contact)
{ {
Limb limb = f2.Body.UserData as Limb; if (f2.Body.UserData is Limb limb)
if (limb != null)
{ {
bool collision = CheckLimbCollision(contact, limb); bool collision = CheckLimbCollision(contact, limb);
if (collision) HandleLimbCollision(contact, limb); if (collision) HandleLimbCollision(contact, limb);
return collision; return collision;
} }
VoronoiCell cell = f2.Body.UserData as VoronoiCell; if (f2.UserData is VoronoiCell cell)
if (cell != null)
{ {
HandleLevelCollision(contact, Vector2.Normalize(ConvertUnits.ToDisplayUnits(Body.SimPosition) - cell.Center)); HandleLevelCollision(contact, Vector2.Normalize(ConvertUnits.ToDisplayUnits(Body.SimPosition) - cell.Center));
return true; return true;
} }
Structure structure = f2.Body.UserData as Structure; if (f2.Body.UserData is Structure structure)
if (structure != null)
{ {
Vector2 normal; contact.GetWorldManifold(out Vector2 normal, out FixedArray2<Vector2> points);
FixedArray2<Vector2> points;
contact.GetWorldManifold(out normal, out points);
if (contact.FixtureA.Body == f1.Body) if (contact.FixtureA.Body == f1.Body)
{ {
normal = -normal; normal = -normal;
@@ -400,8 +395,7 @@ namespace Barotrauma
return true; return true;
} }
Submarine otherSub = f2.Body.UserData as Submarine; if (f2.Body.UserData is Submarine otherSub)
if (otherSub != null)
{ {
HandleSubCollision(contact, otherSub); HandleSubCollision(contact, otherSub);
return true; return true;
@@ -486,8 +480,8 @@ namespace Barotrauma
levelContact.GetWorldManifold(out contactNormal, out temp); levelContact.GetWorldManifold(out contactNormal, out temp);
//if the contact normal is pointing from the limb towards the level cell it's touching, flip the normal //if the contact normal is pointing from the limb towards the level cell it's touching, flip the normal
VoronoiCell cell = levelContact.FixtureB.Body.UserData is VoronoiCell ? VoronoiCell cell = levelContact.FixtureB.UserData is VoronoiCell ?
((VoronoiCell)levelContact.FixtureB.Body.UserData) : ((VoronoiCell)levelContact.FixtureA.Body.UserData); ((VoronoiCell)levelContact.FixtureB.UserData) : ((VoronoiCell)levelContact.FixtureA.UserData);
var cellDiff = ConvertUnits.ToDisplayUnits(limb.body.SimPosition) - cell.Center; var cellDiff = ConvertUnits.ToDisplayUnits(limb.body.SimPosition) - cell.Center;
if (Vector2.Dot(contactNormal, cellDiff) < 0) if (Vector2.Dot(contactNormal, cellDiff) < 0)
@@ -603,8 +597,8 @@ namespace Barotrauma
levelContact.GetWorldManifold(out contactNormal, out temp); levelContact.GetWorldManifold(out contactNormal, out temp);
//if the contact normal is pointing from the sub towards the level cell we collided with, flip the normal //if the contact normal is pointing from the sub towards the level cell we collided with, flip the normal
VoronoiCell cell = levelContact.FixtureB.Body.UserData is VoronoiCell ? VoronoiCell cell = levelContact.FixtureB.UserData is VoronoiCell ?
((VoronoiCell)levelContact.FixtureB.Body.UserData) : ((VoronoiCell)levelContact.FixtureA.Body.UserData); ((VoronoiCell)levelContact.FixtureB.UserData) : ((VoronoiCell)levelContact.FixtureA.UserData);
var cellDiff = ConvertUnits.ToDisplayUnits(Body.SimPosition) - cell.Center; var cellDiff = ConvertUnits.ToDisplayUnits(Body.SimPosition) - cell.Center;
if (Vector2.Dot(contactNormal, cellDiff) < 0) if (Vector2.Dot(contactNormal, cellDiff) < 0)
@@ -271,7 +271,7 @@ namespace Barotrauma.Networking
case (byte)FileTransferType.Submarine: case (byte)FileTransferType.Submarine:
string fileName = inc.ReadString(); string fileName = inc.ReadString();
string fileHash = inc.ReadString(); string fileHash = inc.ReadString();
var requestedSubmarine = Submarine.SavedSubmarines.Find(s => s.Name == fileName && s.MD5Hash.Hash == fileHash); var requestedSubmarine = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == fileName && s.MD5Hash.Hash == fileHash);
if (requestedSubmarine != null) if (requestedSubmarine != null)
{ {
@@ -209,7 +209,7 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen.RandomizeSettings(); GameMain.NetLobbyScreen.RandomizeSettings();
started = true; started = true;
if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("GameServer:Start"); GameAnalyticsManager.AddDesignEvent("GameServer:Start");
yield return CoroutineStatus.Success; yield return CoroutineStatus.Success;
} }
@@ -1370,7 +1370,7 @@ namespace Barotrauma.Networking
} }
} }
if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("Traitors:" + (TraitorManager == null ? "Disabled" : "Enabled")); GameAnalyticsManager.AddDesignEvent("Traitors:" + (TraitorManager == null ? "Disabled" : "Enabled"));
SendStartMessage(roundStartSeed, Submarine.MainSub, GameMain.GameSession.GameMode.Preset, connectedClients); SendStartMessage(roundStartSeed, Submarine.MainSub, GameMain.GameSession.GameMode.Preset, connectedClients);
@@ -1584,23 +1584,6 @@ namespace Barotrauma.Networking
BanClient(client, reason, range, duration); BanClient(client, reason, range, duration);
} }
public void BanClient(NetConnection conn, string reason, bool range = false, TimeSpan? duration = null)
{
Client client = connectedClients.Find(c => c.Connection == conn);
if (client == null)
{
conn.Disconnect("You have been banned from the server");
if (!banList.IsBanned(conn.RemoteEndPoint.Address.ToString()))
{
banList.BanPlayer("Unnamed", conn.RemoteEndPoint.Address.ToString(), reason, duration);
}
}
else
{
BanClient(client, reason, range);
}
}
public void BanClient(Client client, string reason, bool range = false, TimeSpan? duration = null) public void BanClient(Client client, string reason, bool range = false, TimeSpan? duration = null)
{ {
if (client == null) return; if (client == null) return;
@@ -2267,10 +2250,7 @@ namespace Barotrauma.Networking
log.Save(); log.Save();
} }
if (GameSettings.SendUserStatistics) GameAnalyticsManager.AddDesignEvent("GameServer:ShutDown");
{
GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("GameServer:ShutDown");
}
server.Shutdown("The server has been shut down"); server.Shutdown("The server has been shut down");
} }
} }
@@ -30,6 +30,9 @@ namespace Barotrauma.Networking
catch (Exception exception) catch (Exception exception)
{ {
DebugConsole.ThrowError("Failed to write an event for the entity \"" + e.Entity + "\"", exception); DebugConsole.ThrowError("Failed to write an event for the entity \"" + e.Entity + "\"", exception);
GameAnalyticsManager.AddErrorEventOnce("NetEntityEventManager.Write:WriteFailed" + e.Entity.ToString(),
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to write an event for the entity \"" + e.Entity + "\"\n" + exception.StackTrace);
//write an empty event to avoid messing up IDs //write an empty event to avoid messing up IDs
//(otherwise the clients might read the next event in the message and think its ID //(otherwise the clients might read the next event in the message and think its ID
@@ -49,6 +52,9 @@ namespace Barotrauma.Networking
if (tempEventBuffer.LengthBytes > 255) if (tempEventBuffer.LengthBytes > 255)
{ {
DebugConsole.ThrowError("Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes"); DebugConsole.ThrowError("Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes");
GameAnalyticsManager.AddErrorEventOnce("NetEntityEventManager.Write:TooLong" + e.Entity.ToString(),
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes");
} }
//the ID has been taken by another entity (the original entity has been removed) -> write an empty event //the ID has been taken by another entity (the original entity has been removed) -> write an empty event
@@ -93,7 +93,7 @@ namespace Barotrauma
{ {
case VoteType.Sub: case VoteType.Sub:
string subName = inc.ReadString(); string subName = inc.ReadString();
Submarine sub = Submarine.SavedSubmarines.Find(s => s.Name == subName); Submarine sub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName);
sender.SetVote(voteType, sub); sender.SetVote(voteType, sub);
#if CLIENT #if CLIENT
UpdateVoteTexts(GameMain.Server.ConnectedClients, voteType); UpdateVoteTexts(GameMain.Server.ConnectedClients, voteType);
@@ -360,6 +360,44 @@ namespace Barotrauma
this.radius = radius; this.radius = radius;
} }
private bool IsValidValue(float value, string valueName)
{
if (!MathUtils.IsValid(value))
{
string errorMsg =
"Attempted to apply invalid " + valueName +
" to a physics body (userdata: " + UserData == null ? "null" : UserData.ToString() +
"), value: " + value + "\n" + Environment.StackTrace;
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce(
"PhysicsBody.SetPosition:InvalidPosition",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
errorMsg);
return false;
}
return true;
}
private bool IsValidValue(Vector2 value, string valueName)
{
if (!MathUtils.IsValid(value))
{
string errorMsg =
"Attempted to apply invalid " + valueName +
" to a physics body (userdata: " + UserData == null ? "null" : UserData.ToString() +
"), value: " + value + "\n" + Environment.StackTrace;
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce(
"PhysicsBody.SetPosition:InvalidPosition",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
errorMsg);
return false;
}
return true;
}
public void ResetDynamics() public void ResetDynamics()
{ {
body.ResetDynamics(); body.ResetDynamics();
@@ -367,6 +405,7 @@ namespace Barotrauma
public void ApplyLinearImpulse(Vector2 impulse) public void ApplyLinearImpulse(Vector2 impulse)
{ {
if (!IsValidValue(impulse, "impulse")) return;
body.ApplyLinearImpulse(impulse); body.ApplyLinearImpulse(impulse);
} }
@@ -375,6 +414,9 @@ namespace Barotrauma
/// </summary> /// </summary>
public void ApplyLinearImpulse(Vector2 impulse, float maxVelocity) public void ApplyLinearImpulse(Vector2 impulse, float maxVelocity)
{ {
if (!IsValidValue(impulse, "impulse")) return;
if (!IsValidValue(maxVelocity, "max velocity")) return;
float currSpeed = body.LinearVelocity.Length(); float currSpeed = body.LinearVelocity.Length();
Vector2 velocityAddition = impulse / Mass; Vector2 velocityAddition = impulse / Mass;
Vector2 newVelocity = body.LinearVelocity + velocityAddition; Vector2 newVelocity = body.LinearVelocity + velocityAddition;
@@ -385,21 +427,26 @@ namespace Barotrauma
public void ApplyLinearImpulse(Vector2 impulse, Vector2 point) public void ApplyLinearImpulse(Vector2 impulse, Vector2 point)
{ {
if (!IsValidValue(impulse, "impulse")) return;
body.ApplyLinearImpulse(impulse, point); body.ApplyLinearImpulse(impulse, point);
} }
public void ApplyForce(Vector2 force) public void ApplyForce(Vector2 force)
{ {
if (!IsValidValue(force, "force")) return;
body.ApplyForce(force); body.ApplyForce(force);
} }
public void ApplyForce(Vector2 force, Vector2 point) public void ApplyForce(Vector2 force, Vector2 point)
{ {
if (!IsValidValue(force, "force")) return;
if (!IsValidValue(point, "point")) return;
body.ApplyForce(force, point); body.ApplyForce(force, point);
} }
public void ApplyTorque(float torque) public void ApplyTorque(float torque)
{ {
if (!IsValidValue(torque, "torque")) return;
body.ApplyTorque(torque); body.ApplyTorque(torque);
} }
@@ -409,6 +456,9 @@ namespace Barotrauma
System.Diagnostics.Debug.Assert(Math.Abs(simPosition.X) < 1000000.0f); System.Diagnostics.Debug.Assert(Math.Abs(simPosition.X) < 1000000.0f);
System.Diagnostics.Debug.Assert(Math.Abs(simPosition.Y) < 1000000.0f); System.Diagnostics.Debug.Assert(Math.Abs(simPosition.Y) < 1000000.0f);
if (!IsValidValue(simPosition, "position")) return;
if (!IsValidValue(rotation, "rotation")) return;
body.SetTransform(simPosition, rotation); body.SetTransform(simPosition, rotation);
SetPrevTransform(simPosition, rotation); SetPrevTransform(simPosition, rotation);
} }
@@ -419,13 +469,19 @@ namespace Barotrauma
System.Diagnostics.Debug.Assert(Math.Abs(simPosition.X) < 1000000.0f); System.Diagnostics.Debug.Assert(Math.Abs(simPosition.X) < 1000000.0f);
System.Diagnostics.Debug.Assert(Math.Abs(simPosition.Y) < 1000000.0f); System.Diagnostics.Debug.Assert(Math.Abs(simPosition.Y) < 1000000.0f);
if (!IsValidValue(simPosition, "position")) return;
if (!IsValidValue(rotation, "rotation")) return;
body.SetTransformIgnoreContacts(ref simPosition, rotation); body.SetTransformIgnoreContacts(ref simPosition, rotation);
SetPrevTransform(simPosition, rotation); SetPrevTransform(simPosition, rotation);
} }
public void SetPrevTransform(Vector2 position, float rotation) public void SetPrevTransform(Vector2 simPosition, float rotation)
{ {
prevPosition = position; if (!IsValidValue(simPosition, "position")) return;
if (!IsValidValue(rotation, "rotation")) return;
prevPosition = simPosition;
prevRotation = rotation; prevRotation = rotation;
} }
@@ -440,16 +496,19 @@ namespace Barotrauma
prevPosition = (Vector2)targetPosition; prevPosition = (Vector2)targetPosition;
} }
body.SetTransform((Vector2)targetPosition, targetRotation == null ? body.Rotation : (float)targetRotation); SetTransform((Vector2)targetPosition, targetRotation == null ? body.Rotation : (float)targetRotation);
targetPosition = null; targetPosition = null;
} }
public void MoveToPos(Vector2 pos, float force, Vector2? pullPos = null) public void MoveToPos(Vector2 simPosition, float force, Vector2? pullPos = null)
{ {
if (pullPos == null) pullPos = body.Position; if (pullPos == null) pullPos = body.Position;
if (!IsValidValue(simPosition, "position")) return;
if (!IsValidValue(force, "force")) return;
Vector2 vel = body.LinearVelocity; Vector2 vel = body.LinearVelocity;
Vector2 deltaPos = pos - (Vector2)pullPos; Vector2 deltaPos = simPosition - (Vector2)pullPos;
deltaPos *= force; deltaPos *= force;
body.ApplyLinearImpulse((deltaPos - vel * 0.5f) * body.Mass, (Vector2)pullPos); body.ApplyLinearImpulse((deltaPos - vel * 0.5f) * body.Mass, (Vector2)pullPos);
} }
@@ -474,8 +533,8 @@ namespace Barotrauma
dragForce = Math.Min(drag, Mass * 500.0f) * -velDir; dragForce = Math.Min(drag, Mass * 500.0f) * -velDir;
} }
body.ApplyForce(dragForce + buoyancy); ApplyForce(dragForce + buoyancy);
body.ApplyTorque(body.AngularVelocity * body.Mass * -0.08f); ApplyTorque(body.AngularVelocity * body.Mass * -0.08f);
} }
@@ -559,18 +618,17 @@ namespace Barotrauma
public void SmoothRotate(float targetRotation, float force = 10.0f) public void SmoothRotate(float targetRotation, float force = 10.0f)
{ {
float nextAngle = body.Rotation + body.AngularVelocity * (float)Timing.Step; float nextAngle = body.Rotation + body.AngularVelocity * (float)Timing.Step;
float angle = MathUtils.GetShortestAngle(nextAngle, targetRotation); float angle = MathUtils.GetShortestAngle(nextAngle, targetRotation);
float torque = angle * 60.0f * (force / 100.0f);
float torque = angle * 60.0f * (force/100.0f);
if (body.IsKinematic) if (body.IsKinematic)
{ {
if (!IsValidValue(torque, "torque")) return;
body.AngularVelocity = torque; body.AngularVelocity = torque;
} }
else else
{ {
body.ApplyTorque(body.Mass * torque); ApplyTorque(body.Mass * torque);
} }
} }
@@ -223,6 +223,7 @@ namespace Barotrauma
return false; return false;
} }
propertyInfo.SetValue(obj, enumVal); propertyInfo.SetValue(obj, enumVal);
return true;
} }
else else
{ {
+26
View File
@@ -1,3 +1,29 @@
---------------------------------------------------------------------------------------------------------
v0.8.1.7
---------------------------------------------------------------------------------------------------------
- Fixed crashes when trying to load submarines in the sub editor.
---------------------------------------------------------------------------------------------------------
v0.8.1.6
---------------------------------------------------------------------------------------------------------
- Fixed a memory leak in submarine preview images which caused crashes in the server lobby screen and
submarine editor.
- Fixed clients not seeing the "vote to end the round" tickbox if they don't have a character assigned to
them (despite the server allowing voting if the client has had a character earlier during the round).
- Fixed clients being able to crash servers if they had the permission to use console commands that
use the position of the client's cursor.
- Fixed crashing if a wire is used by a statuseffect (for example if a detonator tries to trigger a wire
contained inside it).
- Fixed GameAnalytics being stopped if the dedicated server is restarted with the "restart" console command.-
- Fixed wiring items outside the submarine.
- Fixed chatbox discarding the second chat message instead of the first one when the maximum number of
chat messages is reached.
- Some error checking and debug logging to diagnose and prevent a crash caused by doors pushing characters away.
- The spawnitem command doesn't require multi-word item names to be surrounded with quotes anymore.
- Added the option to make powered items immune to electromagnetic pulses.
--------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------
v0.8.1.5 v0.8.1.5
--------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------