Fixed memory leak caused by submarine preview images, changed Submarine.SavedSubmarines to a property that prevents removing submarines from outside the class without disposing the preview image. Closes #498

This commit is contained in:
Joonas Rikkonen
2018-07-18 14:23:43 +03:00
parent af4d60db1d
commit 568cf1a02f
9 changed files with 81 additions and 52 deletions
@@ -815,7 +815,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);
@@ -1181,8 +1181,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++)
{ {
@@ -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);
} }
} }
@@ -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()
@@ -782,8 +782,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 +1467,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)
@@ -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
} }
} }
} }
} }
@@ -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)
@@ -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
@@ -557,7 +561,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 +606,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 +673,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 +788,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 +879,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 +934,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 +984,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 +1165,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 +1298,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);
@@ -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)
{ {
@@ -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);