diff --git a/OpenRA.Game/Download.cs b/OpenRA.Game/Download.cs index 4cd997ae7d..30eb18384a 100644 --- a/OpenRA.Game/Download.cs +++ b/OpenRA.Game/Download.cs @@ -70,6 +70,7 @@ namespace OpenRA { Game.OnQuit -= Cancel; wc.CancelAsync(); + wc.Dispose(); cancelled = true; } } diff --git a/OpenRA.Game/FileSystem/MixFile.cs b/OpenRA.Game/FileSystem/MixFile.cs index f28d17b2b9..e4739c99c2 100644 --- a/OpenRA.Game/FileSystem/MixFile.cs +++ b/OpenRA.Game/FileSystem/MixFile.cs @@ -17,7 +17,7 @@ using OpenRA.FileFormats; namespace OpenRA.FileSystem { - public class MixFile : IFolder + public sealed class MixFile : IFolder, IDisposable { readonly Dictionary index; readonly long dataStart; @@ -258,5 +258,11 @@ namespace OpenRA.FileSystem s.Write(file.Value); } } + + public void Dispose() + { + if (s != null) + s.Dispose(); + } } } diff --git a/OpenRA.Game/FileSystem/ZipFile.cs b/OpenRA.Game/FileSystem/ZipFile.cs index c7705a0949..99e87014b9 100644 --- a/OpenRA.Game/FileSystem/ZipFile.cs +++ b/OpenRA.Game/FileSystem/ZipFile.cs @@ -8,6 +8,7 @@ */ #endregion +using System; using System.Collections.Generic; using System.IO; using System.Text; @@ -16,7 +17,7 @@ using SZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile; namespace OpenRA.FileSystem { - public class ZipFile : IFolder + public sealed class ZipFile : IFolder, IDisposable { string filename; SZipFile pkg; @@ -105,6 +106,12 @@ namespace OpenRA.FileSystem pkg.Close(); pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename))); } + + public void Dispose() + { + if (pkg != null) + pkg.Close(); + } } class StaticMemoryDataSource : IStaticDataSource diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 93f081562d..6e12cd9827 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -504,6 +504,8 @@ namespace OpenRA // Ensure that the active replay is properly saved if (orderManager != null) orderManager.Dispose(); + + Renderer.Device.Dispose(); OnQuit(); } diff --git a/OpenRA.Game/GameRules/MusicInfo.cs b/OpenRA.Game/GameRules/MusicInfo.cs index 59fca18bb1..983b0786d3 100644 --- a/OpenRA.Game/GameRules/MusicInfo.cs +++ b/OpenRA.Game/GameRules/MusicInfo.cs @@ -31,7 +31,8 @@ namespace OpenRA.GameRules return; Exists = true; - Length = (int)AudLoader.SoundLength(GlobalFileSystem.Open(Filename)); + using (var s = GlobalFileSystem.Open(Filename)) + Length = (int)AudLoader.SoundLength(s); } public void Reload() @@ -40,7 +41,8 @@ namespace OpenRA.GameRules return; Exists = true; - Length = (int)AudLoader.SoundLength(GlobalFileSystem.Open(Filename)); + using (var s = GlobalFileSystem.Open(Filename)) + Length = (int)AudLoader.SoundLength(s); } } } diff --git a/OpenRA.Game/Graphics/Sheet.cs b/OpenRA.Game/Graphics/Sheet.cs index 3c8eb4f078..1467c183e6 100644 --- a/OpenRA.Game/Graphics/Sheet.cs +++ b/OpenRA.Game/Graphics/Sheet.cs @@ -40,31 +40,34 @@ namespace OpenRA.Graphics public Sheet(string filename) { - var bitmap = (Bitmap)Image.FromStream(GlobalFileSystem.Open(filename)); - Size = bitmap.Size; - - data = new byte[4*Size.Width*Size.Height]; - var b = bitmap.LockBits(bitmap.Bounds(), - ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); - - unsafe + using (var stream = GlobalFileSystem.Open(filename)) + using (var bitmap = (Bitmap)Image.FromStream(stream)) { - int* c = (int*)b.Scan0; + Size = bitmap.Size; - for (var x = 0; x < Size.Width; x++) - for (var y = 0; y < Size.Height; y++) + data = new byte[4 * Size.Width * Size.Height]; + var b = bitmap.LockBits(bitmap.Bounds(), + ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + + unsafe { - var i = 4*Size.Width*y + 4*x; + int* c = (int*)b.Scan0; - // Convert argb to bgra - var argb = *(c + (y * b.Stride >> 2) + x); - data[i++] = (byte)(argb >> 0); - data[i++] = (byte)(argb >> 8); - data[i++] = (byte)(argb >> 16); - data[i++] = (byte)(argb >> 24); + for (var x = 0; x < Size.Width; x++) + for (var y = 0; y < Size.Height; y++) + { + var i = 4 * Size.Width * y + 4 * x; + + // Convert argb to bgra + var argb = *(c + (y * b.Stride >> 2) + x); + data[i++] = (byte)(argb >> 0); + data[i++] = (byte)(argb >> 8); + data[i++] = (byte)(argb >> 16); + data[i++] = (byte)(argb >> 24); + } } + bitmap.UnlockBits(b); } - bitmap.UnlockBits(b); } public ITexture Texture diff --git a/OpenRA.Game/Graphics/SpriteFont.cs b/OpenRA.Game/Graphics/SpriteFont.cs index a37c2d21f3..d8754e2ccf 100644 --- a/OpenRA.Game/Graphics/SpriteFont.cs +++ b/OpenRA.Game/Graphics/SpriteFont.cs @@ -108,27 +108,29 @@ namespace OpenRA.Graphics Offset = { X = face.Glyph.BitmapLeft, Y = -face.Glyph.BitmapTop } }; - unsafe - { - var p = (byte*)face.Glyph.Bitmap.Buffer; - var dest = s.sheet.Data; - var destStride = s.sheet.Size.Width * 4; - - for (var j = 0; j < s.size.Y; j++) + // A new bitmap is generated each time this property is accessed, so we do need to dispose it. + using (var bitmap = face.Glyph.Bitmap) + unsafe { - for (var i = 0; i < s.size.X; i++) - if (p[i] != 0) - { - var q = destStride * (j + s.bounds.Top) + 4 * (i + s.bounds.Left); - dest[q] = c.Second.B; - dest[q + 1] = c.Second.G; - dest[q + 2] = c.Second.R; - dest[q + 3] = p[i]; - } + var p = (byte*)bitmap.Buffer; + var dest = s.sheet.Data; + var destStride = s.sheet.Size.Width * 4; - p += face.Glyph.Bitmap.Pitch; + for (var j = 0; j < s.size.Y; j++) + { + for (var i = 0; i < s.size.X; i++) + if (p[i] != 0) + { + var q = destStride * (j + s.bounds.Top) + 4 * (i + s.bounds.Left); + dest[q] = c.Second.B; + dest[q + 1] = c.Second.G; + dest[q + 2] = c.Second.R; + dest[q + 3] = p[i]; + } + + p += bitmap.Pitch; + } } - } s.sheet.CommitData(); return g; diff --git a/OpenRA.Game/Graphics/SpriteLoader.cs b/OpenRA.Game/Graphics/SpriteLoader.cs index d197bc7cc0..67d2571b99 100644 --- a/OpenRA.Game/Graphics/SpriteLoader.cs +++ b/OpenRA.Game/Graphics/SpriteLoader.cs @@ -33,10 +33,10 @@ namespace OpenRA.Graphics Sprite[] CacheSpriteFrames(string filename) { - var stream = GlobalFileSystem.OpenWithExts(filename, exts); - return SpriteSource.LoadSpriteSource(stream, filename).Frames - .Select(a => SheetBuilder.Add(a)) - .ToArray(); + using (var stream = GlobalFileSystem.OpenWithExts(filename, exts)) + return SpriteSource.LoadSpriteSource(stream, filename).Frames + .Select(a => SheetBuilder.Add(a)) + .ToArray(); } public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; } diff --git a/OpenRA.Game/Graphics/VoxelLoader.cs b/OpenRA.Game/Graphics/VoxelLoader.cs index 0846d6b8ab..6bd96377f8 100644 --- a/OpenRA.Game/Graphics/VoxelLoader.cs +++ b/OpenRA.Game/Graphics/VoxelLoader.cs @@ -210,8 +210,12 @@ namespace OpenRA.Graphics Voxel LoadFile(Pair files) { - var vxl = new VxlReader(GlobalFileSystem.OpenWithExts(files.First, ".vxl")); - var hva = new HvaReader(GlobalFileSystem.OpenWithExts(files.Second, ".hva")); + VxlReader vxl; + HvaReader hva; + using (var s = GlobalFileSystem.OpenWithExts(files.First, ".vxl")) + vxl = new VxlReader(s); + using (var s = GlobalFileSystem.OpenWithExts(files.Second, ".hva")) + hva = new HvaReader(s); return new Voxel(this, vxl, hva); } diff --git a/OpenRA.Game/IGraphicsDevice.cs b/OpenRA.Game/IGraphicsDevice.cs index aa6ced58ab..01c24b8e8f 100755 --- a/OpenRA.Game/IGraphicsDevice.cs +++ b/OpenRA.Game/IGraphicsDevice.cs @@ -34,7 +34,7 @@ namespace OpenRA public enum BlendMode { None, Alpha, Additive, Subtractive, Multiply } - public interface IGraphicsDevice + public interface IGraphicsDevice : IDisposable { IVertexBuffer CreateVertexBuffer(int length); ITexture CreateTexture(Bitmap bitmap); @@ -58,8 +58,6 @@ namespace OpenRA void DisableDepthBuffer(); void SetBlendMode(BlendMode mode); - - void Quit(); } public interface IVertexBuffer diff --git a/OpenRA.Game/InstallUtils.cs b/OpenRA.Game/InstallUtils.cs index 5e098e54f3..07e75afa10 100644 --- a/OpenRA.Game/InstallUtils.cs +++ b/OpenRA.Game/InstallUtils.cs @@ -93,8 +93,9 @@ namespace OpenRA List extracted = new List(); try { - var z = new ZipInputStream(File.OpenRead(zipFile)); - z.ExtractZip(dest, extracted, s => onProgress("Extracting " + s)); + using (var stream = File.OpenRead(zipFile)) + using (var z = new ZipInputStream(stream)) + z.ExtractZip(dest, extracted, s => onProgress("Extracting " + s)); } catch (SharpZipBaseException) { diff --git a/OpenRA.Game/MiniYaml.cs b/OpenRA.Game/MiniYaml.cs index 7b7274dd46..67f94ae51a 100755 --- a/OpenRA.Game/MiniYaml.cs +++ b/OpenRA.Game/MiniYaml.cs @@ -172,13 +172,11 @@ namespace OpenRA public static List FromFileInPackage(string path) { - StreamReader reader = new StreamReader(GlobalFileSystem.Open(path)); List lines = new List(); - - while (!reader.EndOfStream) - lines.Add(reader.ReadLine()); - reader.Close(); - + using (var stream = GlobalFileSystem.Open(path)) + using (var reader = new StreamReader(stream)) + while (!reader.EndOfStream) + lines.Add(reader.ReadLine()); return FromLines(lines.ToArray(), path); } diff --git a/OpenRA.Game/Network/Connection.cs b/OpenRA.Game/Network/Connection.cs index 8c0d964c14..e2a118ffd5 100755 --- a/OpenRA.Game/Network/Connection.cs +++ b/OpenRA.Game/Network/Connection.cs @@ -86,7 +86,7 @@ namespace OpenRA.Network if (packet.Length == 0) throw new NotImplementedException(); lock (this) - receivedPackets.Add(new ReceivedPacket { FromClient = LocalClientId, Data = packet } ); + receivedPackets.Add(new ReceivedPacket { FromClient = LocalClientId, Data = packet }); } public virtual void Receive(Action packetFn) @@ -102,10 +102,16 @@ namespace OpenRA.Network packetFn(p.FromClient, p.Data); } - public virtual void Dispose() { } + protected virtual void Dispose(bool disposing) { } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } } - class NetworkConnection : EchoConnection + sealed class NetworkConnection : EchoConnection { TcpClient socket; int clientId; @@ -193,22 +199,27 @@ namespace OpenRA.Network bool disposed = false; - public override void Dispose() + protected override void Dispose(bool disposing) { - if (disposed) return; + if (disposed) + return; disposed = true; - GC.SuppressFinalize(this); t.Abort(); - if (socket != null) - socket.Client.Close(); + if (disposing) + if (socket != null) + socket.Client.Close(); using (new PerfSample("Thread.Join")) { if (!t.Join(1000)) return; } + base.Dispose(disposing); } - ~NetworkConnection() { Dispose(); } + ~NetworkConnection() + { + Dispose(false); + } } } diff --git a/OpenRA.Game/Network/OrderManager.cs b/OpenRA.Game/Network/OrderManager.cs index 12fd17d286..5be8f59730 100755 --- a/OpenRA.Game/Network/OrderManager.cs +++ b/OpenRA.Game/Network/OrderManager.cs @@ -15,7 +15,7 @@ using OpenRA.Primitives; namespace OpenRA.Network { - public class OrderManager : IDisposable + public sealed class OrderManager : IDisposable { readonly SyncReport syncReport; readonly FrameData frameData = new FrameData(); @@ -197,22 +197,10 @@ namespace OpenRA.Network ++NetFrameNumber; } - bool disposed; - protected void Dispose(bool disposing) - { - if (disposed) - return; - - if (disposing) - Connection.Dispose(); - - disposed = true; - } - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); + if (Connection != null) + Connection.Dispose(); } } } diff --git a/OpenRA.Game/Network/ReplayConnection.cs b/OpenRA.Game/Network/ReplayConnection.cs index 275d3003d7..32afbfad6a 100755 --- a/OpenRA.Game/Network/ReplayConnection.cs +++ b/OpenRA.Game/Network/ReplayConnection.cs @@ -16,7 +16,7 @@ using OpenRA.Primitives; namespace OpenRA.Network { - public class ReplayConnection : IConnection + public sealed class ReplayConnection : IConnection { class Chunk { diff --git a/OpenRA.Game/Network/ReplayRecorderConnection.cs b/OpenRA.Game/Network/ReplayRecorderConnection.cs index 15a843d010..57b907ef8b 100644 --- a/OpenRA.Game/Network/ReplayRecorderConnection.cs +++ b/OpenRA.Game/Network/ReplayRecorderConnection.cs @@ -17,7 +17,7 @@ using OpenRA.Widgets; namespace OpenRA.Network { - class ReplayRecorderConnection : IConnection, IDisposable + sealed class ReplayRecorderConnection : IConnection { public ReplayMetadata Metadata; @@ -98,30 +98,24 @@ namespace OpenRA.Network } bool disposed; - protected void Dispose(bool disposing) - { - if (disposed) - return; - - if (disposing) - { - if (Metadata != null) - { - if (Metadata.GameInfo != null) - Metadata.GameInfo.EndTimeUtc = DateTime.UtcNow; - Metadata.Write(writer); - } - writer.Close(); - inner.Dispose(); - } - - disposed = true; - } public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); + if (disposed) + return; + disposed = true; + + if (Metadata != null) + { + if (Metadata.GameInfo != null) + Metadata.GameInfo.EndTimeUtc = DateTime.UtcNow; + Metadata.Write(writer); + } + + if (preStartBuffer != null) + preStartBuffer.Dispose(); + writer.Close(); + inner.Dispose(); } } } diff --git a/OpenRA.Game/Primitives/DisposableAction.cs b/OpenRA.Game/Primitives/DisposableAction.cs index 4734935f59..333f5ceeb9 100644 --- a/OpenRA.Game/Primitives/DisposableAction.cs +++ b/OpenRA.Game/Primitives/DisposableAction.cs @@ -12,7 +12,7 @@ using System; namespace OpenRA.Primitives { - public class DisposableAction : IDisposable + public sealed class DisposableAction : IDisposable { public DisposableAction(Action onDispose, Action onFinalize) { @@ -26,7 +26,8 @@ namespace OpenRA.Primitives public void Dispose() { - if (disposed) return; + if (disposed) + return; disposed = true; onDispose(); GC.SuppressFinalize(this); diff --git a/OpenRA.Game/Scripting/ScriptContext.cs b/OpenRA.Game/Scripting/ScriptContext.cs index 7f3eb45a75..44dc9cb417 100644 --- a/OpenRA.Game/Scripting/ScriptContext.cs +++ b/OpenRA.Game/Scripting/ScriptContext.cs @@ -81,12 +81,11 @@ namespace OpenRA.Scripting public ScriptGlobalAttribute(string name) { Name = name; } } - public class ScriptContext : IDisposable + public sealed class ScriptContext : IDisposable { public World World { get; private set; } public WorldRenderer WorldRenderer { get; private set; } - bool disposed; readonly MemoryConstrainedLuaRuntime runtime; readonly LuaFunction tick; @@ -100,6 +99,8 @@ namespace OpenRA.Scripting public readonly Cache ActorCommands; public readonly Type[] PlayerCommands; + bool disposed; + public ScriptContext(World world, WorldRenderer worldRenderer, IEnumerable scripts) { @@ -196,27 +197,13 @@ namespace OpenRA.Scripting tick.Call().Dispose(); } - protected void Dispose(bool disposing) + public void Dispose() { if (disposed) return; - - if (disposing) - runtime.Dispose(); - disposed = true; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - ~ScriptContext() - { - // Dispose unmanaged resources only - Dispose(false); + if (runtime != null) + runtime.Dispose(); } static Type[] ExtractRequiredTypes(Type t) diff --git a/OpenRA.Game/Sound.cs b/OpenRA.Game/Sound.cs index e996086076..cbf3e5f320 100644 --- a/OpenRA.Game/Sound.cs +++ b/OpenRA.Game/Sound.cs @@ -39,9 +39,11 @@ namespace OpenRA } if (filename.ToLowerInvariant().EndsWith("wav")) - return LoadWave(new WavLoader(GlobalFileSystem.Open(filename))); + using (var s = GlobalFileSystem.Open(filename)) + return LoadWave(new WavLoader(s)); - return LoadSoundRaw(AudLoader.LoadSound(GlobalFileSystem.Open(filename))); + using (var s = GlobalFileSystem.Open(filename)) + return LoadSoundRaw(AudLoader.LoadSound(s)); } static ISoundSource LoadWave(WavLoader wave) diff --git a/OpenRA.Game/Support/PerfHistory.cs b/OpenRA.Game/Support/PerfHistory.cs index 3812b94c86..4f9c00f32f 100644 --- a/OpenRA.Game/Support/PerfHistory.cs +++ b/OpenRA.Game/Support/PerfHistory.cs @@ -105,7 +105,7 @@ namespace OpenRA.Support } } - public class PerfSample : IDisposable + public sealed class PerfSample : IDisposable { readonly Stopwatch sw = Stopwatch.StartNew(); readonly string Item; diff --git a/OpenRA.Game/Support/PerfTimer.cs b/OpenRA.Game/Support/PerfTimer.cs index 05514ba73a..1492c436d8 100755 --- a/OpenRA.Game/Support/PerfTimer.cs +++ b/OpenRA.Game/Support/PerfTimer.cs @@ -16,7 +16,7 @@ using System.Threading; namespace OpenRA.Support { - public class PerfTimer : IDisposable + public sealed class PerfTimer : IDisposable { readonly string name; readonly float thresholdMs; diff --git a/OpenRA.Game/Support/Program.cs b/OpenRA.Game/Support/Program.cs index baf4d2cfd5..9204a19c79 100644 --- a/OpenRA.Game/Support/Program.cs +++ b/OpenRA.Game/Support/Program.cs @@ -57,7 +57,7 @@ namespace OpenRA if (Game.Settings.Debug.ShowFatalErrorDialog && !Game.Settings.Server.Dedicated) { - Game.Renderer.Device.Quit(); + Game.Renderer.Device.Dispose(); Platform.ShowFatalErrorDialog(); } } diff --git a/OpenRA.Irc/IrcClient.cs b/OpenRA.Irc/IrcClient.cs index c2f06cfbc6..6f655566d3 100644 --- a/OpenRA.Irc/IrcClient.cs +++ b/OpenRA.Irc/IrcClient.cs @@ -17,7 +17,7 @@ using OpenRA.Primitives; namespace OpenRA.Irc { - public class IrcClient : IDisposable + public sealed class IrcClient : IDisposable { public static readonly IrcClient Instance = new IrcClient(); @@ -252,14 +252,15 @@ namespace OpenRA.Irc ConnectionState = IrcConnectionState.Disconnecting; OnDisconnecting(); - connection.Close(); + if (connection != null) + connection.Close(); ConnectionState = IrcConnectionState.Disconnected; OnDisconnect(); LocalUser = null; connection = null; } - void IDisposable.Dispose() + public void Dispose() { Disconnect(); } diff --git a/OpenRA.Irc/IrcConnection.cs b/OpenRA.Irc/IrcConnection.cs index ae9679f83b..66c14096bb 100644 --- a/OpenRA.Irc/IrcConnection.cs +++ b/OpenRA.Irc/IrcConnection.cs @@ -14,7 +14,7 @@ using System.Net.Sockets; namespace OpenRA.Irc { - public class IrcConnection : IDisposable + public sealed class IrcConnection : IDisposable { TcpClient socket; Stream stream; @@ -49,14 +49,8 @@ namespace OpenRA.Irc public void Close() { - CloseImpl(); - GC.SuppressFinalize(this); - } - - void CloseImpl() - { - if (disposed) return; - + if (disposed) + return; disposed = true; if (socket != null) socket.Close(); if (stream != null) stream.Close(); @@ -64,16 +58,11 @@ namespace OpenRA.Irc if (reader != null) reader.Close(); } - void IDisposable.Dispose() + public void Dispose() { Close(); } - ~IrcConnection() - { - CloseImpl(); - } - void CheckDisposed() { if (disposed) diff --git a/OpenRA.Mods.RA/Move/PathSearch.cs b/OpenRA.Mods.RA/Move/PathSearch.cs index 0c198eb9a9..9036463986 100755 --- a/OpenRA.Mods.RA/Move/PathSearch.cs +++ b/OpenRA.Mods.RA/Move/PathSearch.cs @@ -15,7 +15,7 @@ using OpenRA.Primitives; namespace OpenRA.Mods.RA.Move { - public class PathSearch : IDisposable + public sealed class PathSearch : IDisposable { World world; public CellInfo[,] cellInfo; @@ -291,11 +291,12 @@ namespace OpenRA.Mods.RA.Move { if (disposed) return; - disposed = true; - GC.SuppressFinalize(this); + PutBackIntoPool(cellInfo); cellInfo = null; + + GC.SuppressFinalize(this); } ~PathSearch() { Dispose(); } diff --git a/OpenRA.Mods.RA/Scripting/CallLuaFunc.cs b/OpenRA.Mods.RA/Scripting/CallLuaFunc.cs index 7df12f1c30..71dffe2827 100644 --- a/OpenRA.Mods.RA/Scripting/CallLuaFunc.cs +++ b/OpenRA.Mods.RA/Scripting/CallLuaFunc.cs @@ -15,7 +15,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Activities { - public class CallLuaFunc : Activity, IDisposable + public sealed class CallLuaFunc : Activity, IDisposable { LuaFunction function; @@ -39,28 +39,11 @@ namespace OpenRA.Mods.RA.Activities base.Cancel(self); } - protected void Dispose(bool disposing) - { - if (function == null) - return; - - if (disposing) - { - function.Dispose(); - function = null; - } - } - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - ~CallLuaFunc() - { - // Dispose unmanaged resources only - Dispose(false); + if (function == null) return; + function.Dispose(); + function = null; } } } diff --git a/OpenRA.Mods.RA/Scripting/LuaScript.cs b/OpenRA.Mods.RA/Scripting/LuaScript.cs index 0e27b3b445..9ea1c2831b 100644 --- a/OpenRA.Mods.RA/Scripting/LuaScript.cs +++ b/OpenRA.Mods.RA/Scripting/LuaScript.cs @@ -8,6 +8,7 @@ */ #endregion +using System; using OpenRA.Graphics; using OpenRA.Scripting; using OpenRA.Traits; @@ -21,7 +22,7 @@ namespace OpenRA.Mods.RA.Scripting public object Create(ActorInitializer init) { return new LuaScript(this); } } - public class LuaScript : ITick, IWorldLoaded + public sealed class LuaScript : ITick, IWorldLoaded, IDisposable { readonly LuaScriptInfo info; ScriptContext context; @@ -42,5 +43,11 @@ namespace OpenRA.Mods.RA.Scripting { context.Tick(self); } + + public void Dispose() + { + if (context != null) + context.Dispose(); + } } } diff --git a/OpenRA.Mods.RA/Scripting/LuaScriptContext.cs b/OpenRA.Mods.RA/Scripting/LuaScriptContext.cs index 714aaab803..0c301e4919 100644 --- a/OpenRA.Mods.RA/Scripting/LuaScriptContext.cs +++ b/OpenRA.Mods.RA/Scripting/LuaScriptContext.cs @@ -18,7 +18,7 @@ using OpenRA.Primitives; namespace OpenRA.Mods.RA.Scripting { - public class LuaScriptContext : IDisposable + public sealed class LuaScriptContext : IDisposable { public Lua Lua { get; private set; } readonly Cache functionCache; @@ -133,19 +133,9 @@ namespace OpenRA.Mods.RA.Scripting } public void Dispose() - { - if (Lua == null) - return; - - GC.SuppressFinalize(this); - Lua.Dispose(); - Lua = null; - } - - ~LuaScriptContext() { if (Lua != null) - Game.RunAfterTick(Dispose); + Lua.Dispose(); } } } diff --git a/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs b/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs index c2f65552ed..ec0607dc34 100644 --- a/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs +++ b/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs @@ -32,7 +32,7 @@ namespace OpenRA.Mods.RA.Scripting public object Create(ActorInitializer init) { return new LuaScriptInterface(this); } } - public class LuaScriptInterface : IWorldLoaded, ITick + public sealed class LuaScriptInterface : IWorldLoaded, ITick, IDisposable { World world; SpawnMapActors sma; @@ -90,6 +90,11 @@ namespace OpenRA.Mods.RA.Scripting context.InvokeLuaFunction("Tick"); } + public void Dispose() + { + context.Dispose(); + } + [LuaGlobal] public object New(string typeName, LuaTable args) { diff --git a/OpenRA.Mods.RA/Scripting/ScriptTriggers.cs b/OpenRA.Mods.RA/Scripting/ScriptTriggers.cs index 7056795510..d68e9c2112 100644 --- a/OpenRA.Mods.RA/Scripting/ScriptTriggers.cs +++ b/OpenRA.Mods.RA/Scripting/ScriptTriggers.cs @@ -21,7 +21,7 @@ namespace OpenRA.Mods.RA.Scripting [Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")] public class ScriptTriggersInfo : TraitInfo { } - public class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction, IDisposable + public sealed class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction, IDisposable { public event Action OnKilledInternal = _ => {}; @@ -100,37 +100,11 @@ namespace OpenRA.Mods.RA.Scripting } } - bool disposed; - - protected void Dispose(bool disposing) - { - if (disposed) - return; - - if (disposing) - { - var toDispose = new [] { onIdle, onDamaged, onKilled, onProduction }; - - foreach (var f in toDispose.SelectMany(f => f)) - f.First.Dispose(); - - foreach (var l in toDispose) - l.Clear(); - } - - disposed = true; - } - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - ~ScriptTriggers() - { - // Dispose unmanaged resources only - Dispose(false); + var pairs = new[] { onIdle, onDamaged, onKilled, onProduction }; + pairs.SelectMany(l => l).Select(p => p.First).Do(f => f.Dispose()); + pairs.Do(l => l.Clear()); } } } diff --git a/OpenRA.Mods.RA/Widgets/HueSliderWidget.cs b/OpenRA.Mods.RA/Widgets/HueSliderWidget.cs index 7d0fdfd9bc..657145f1ea 100755 --- a/OpenRA.Mods.RA/Widgets/HueSliderWidget.cs +++ b/OpenRA.Mods.RA/Widgets/HueSliderWidget.cs @@ -18,7 +18,6 @@ namespace OpenRA.Mods.RA.Widgets { public class HueSliderWidget : SliderWidget { - Bitmap hueBitmap; Sprite hueSprite; public HueSliderWidget() {} @@ -28,20 +27,22 @@ namespace OpenRA.Mods.RA.Widgets { base.Initialize(args); - hueBitmap = new Bitmap(256, 256); - hueSprite = new Sprite(new Sheet(new Size(256, 256)), new Rectangle(0, 0, 256, 1), TextureChannel.Alpha); - - var bitmapData = hueBitmap.LockBits(hueBitmap.Bounds(), - ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); - unsafe + using (var hueBitmap = new Bitmap(256, 256)) { - int* c = (int*)bitmapData.Scan0; - for (var h = 0; h < 256; h++) - *(c + h) = HSLColor.FromHSV(h/255f, 1, 1).RGB.ToArgb(); - } - hueBitmap.UnlockBits(bitmapData); + hueSprite = new Sprite(new Sheet(new Size(256, 256)), new Rectangle(0, 0, 256, 1), TextureChannel.Alpha); - hueSprite.sheet.Texture.SetData(hueBitmap); + var bitmapData = hueBitmap.LockBits(hueBitmap.Bounds(), + ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + unsafe + { + int* c = (int*)bitmapData.Scan0; + for (var h = 0; h < 256; h++) + *(c + h) = HSLColor.FromHSV(h / 255f, 1, 1).RGB.ToArgb(); + } + hueBitmap.UnlockBits(bitmapData); + + hueSprite.sheet.Texture.SetData(hueBitmap); + } } public override void Draw() diff --git a/OpenRA.Mods.RA/Widgets/RadarWidget.cs b/OpenRA.Mods.RA/Widgets/RadarWidget.cs index 4030463dd9..4a0a5e99c4 100755 --- a/OpenRA.Mods.RA/Widgets/RadarWidget.cs +++ b/OpenRA.Mods.RA/Widgets/RadarWidget.cs @@ -68,16 +68,18 @@ namespace OpenRA.Mods.RA.Widgets mapRect = new Rectangle(previewOrigin.X, previewOrigin.Y, (int)(previewScale * width), (int)(previewScale * height)); // Only needs to be done once - var terrainBitmap = Minimap.TerrainBitmap(world.Map.Rules.TileSets[world.Map.Tileset], world.Map); - var r = new Rectangle(0, 0, width, height); - var s = new Size(terrainBitmap.Width, terrainBitmap.Height); - terrainSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); - terrainSprite.sheet.Texture.SetData(terrainBitmap); + using (var terrainBitmap = Minimap.TerrainBitmap(world.Map.Rules.TileSets[world.Map.Tileset], world.Map)) + { + var r = new Rectangle(0, 0, width, height); + var s = new Size(terrainBitmap.Width, terrainBitmap.Height); + terrainSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); + terrainSprite.sheet.Texture.SetData(terrainBitmap); - // Data is set in Tick() - customTerrainSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); - actorSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); - shroudSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); + // Data is set in Tick() + customTerrainSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); + actorSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); + shroudSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); + } } public override string GetCursor(int2 pos) @@ -197,14 +199,17 @@ namespace OpenRA.Mods.RA.Widgets if (updateTicks <= 0) { updateTicks = 12; - customTerrainSprite.sheet.Texture.SetData(Minimap.CustomTerrainBitmap(world)); + using (var bitmap = Minimap.CustomTerrainBitmap(world)) + customTerrainSprite.sheet.Texture.SetData(bitmap); } if (updateTicks == 8) - actorSprite.sheet.Texture.SetData(Minimap.ActorsBitmap(world)); + using (var bitmap = Minimap.ActorsBitmap(world)) + actorSprite.sheet.Texture.SetData(bitmap); if (updateTicks == 4) - shroudSprite.sheet.Texture.SetData(Minimap.ShroudBitmap(world)); + using (var bitmap = Minimap.ShroudBitmap(world)) + shroudSprite.sheet.Texture.SetData(bitmap); // Enable/Disable the radar var enabled = IsEnabled(); diff --git a/OpenRA.Renderer.Null/NullGraphicsDevice.cs b/OpenRA.Renderer.Null/NullGraphicsDevice.cs index 8a24761c84..3469b8a170 100644 --- a/OpenRA.Renderer.Null/NullGraphicsDevice.cs +++ b/OpenRA.Renderer.Null/NullGraphicsDevice.cs @@ -25,7 +25,7 @@ namespace OpenRA.Renderer.Null } } - public class NullGraphicsDevice : IGraphicsDevice + public sealed class NullGraphicsDevice : IGraphicsDevice { public Size WindowSize { get; internal set; } @@ -35,7 +35,7 @@ namespace OpenRA.Renderer.Null WindowSize = size; } - public void Quit() { } + public void Dispose() { } public void EnableScissor(int left, int top, int width, int height) { } public void DisableScissor() { } diff --git a/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs b/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs index 543e946b2b..c9e3473932 100755 --- a/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs +++ b/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs @@ -29,11 +29,12 @@ namespace OpenRA.Renderer.Sdl2 } } - public class Sdl2GraphicsDevice : IGraphicsDevice + public sealed class Sdl2GraphicsDevice : IGraphicsDevice { Size size; Sdl2Input input; IntPtr context, window; + bool disposed; public Size WindowSize { get { return size; } } @@ -101,10 +102,21 @@ namespace OpenRA.Renderer.Sdl2 input = new Sdl2Input(); } - public virtual void Quit() + public void Dispose() { - SDL.SDL_GL_DeleteContext(context); - SDL.SDL_DestroyWindow(window); + if (disposed) + return; + disposed = true; + if (context != IntPtr.Zero) + { + SDL.SDL_GL_DeleteContext(context); + context = IntPtr.Zero; + } + if (window != IntPtr.Zero) + { + SDL.SDL_DestroyWindow(window); + window = IntPtr.Zero; + } SDL.SDL_Quit(); } diff --git a/OpenRA.Renderer.Sdl2/Texture.cs b/OpenRA.Renderer.Sdl2/Texture.cs index f000235aba..943576cfdf 100644 --- a/OpenRA.Renderer.Sdl2/Texture.cs +++ b/OpenRA.Renderer.Sdl2/Texture.cs @@ -106,18 +106,29 @@ namespace OpenRA.Renderer.Sdl2 public void SetData(Bitmap bitmap) { + bool allocatedBitmap = false; if (!Exts.IsPowerOf2(bitmap.Width) || !Exts.IsPowerOf2(bitmap.Height)) + { bitmap = new Bitmap(bitmap, bitmap.Size.NextPowerOf2()); + allocatedBitmap = true; + } + try + { + size = new Size(bitmap.Width, bitmap.Height); + var bits = bitmap.LockBits(bitmap.Bounds(), + ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - size = new Size(bitmap.Width, bitmap.Height); - var bits = bitmap.LockBits(bitmap.Bounds(), - ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - - PrepareTexture(); - GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, bits.Width, bits.Height, - 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bits.Scan0); // TODO: weird strides - ErrorHandler.CheckGlError(); - bitmap.UnlockBits(bits); + PrepareTexture(); + GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, bits.Width, bits.Height, + 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bits.Scan0); // TODO: weird strides + ErrorHandler.CheckGlError(); + bitmap.UnlockBits(bits); + } + finally + { + if (allocatedBitmap) + bitmap.Dispose(); + } } public byte[] GetData() diff --git a/OpenRA.TilesetBuilder/FormBuilder.cs b/OpenRA.TilesetBuilder/FormBuilder.cs index 9370d91a69..25b587b96c 100644 --- a/OpenRA.TilesetBuilder/FormBuilder.cs +++ b/OpenRA.TilesetBuilder/FormBuilder.cs @@ -51,8 +51,9 @@ namespace OpenRA.TilesetBuilder this.size = TileSize; surface1.TileSize = TileSize; - Bitmap fbitmap = new Bitmap(ImageFile); - Bitmap rbitmap = fbitmap.Clone(new Rectangle(0, 0, fbitmap.Width, fbitmap.Height), + Bitmap rbitmap; + using (var fbitmap = new Bitmap(ImageFile)) + rbitmap = fbitmap.Clone(new Rectangle(0, 0, fbitmap.Width, fbitmap.Height), fbitmap.PixelFormat); int[] shadowIndex = { }; diff --git a/OpenRA.Utility/LegacyMapImporter.cs b/OpenRA.Utility/LegacyMapImporter.cs index 429d44fab4..c17c862e9d 100644 --- a/OpenRA.Utility/LegacyMapImporter.cs +++ b/OpenRA.Utility/LegacyMapImporter.cs @@ -162,7 +162,8 @@ namespace OpenRA.Utility else { // CnC - UnpackCncTileData(GlobalFileSystem.Open(iniFile.Substring(0, iniFile.Length - 4) + ".bin")); + using (var s = GlobalFileSystem.Open(iniFile.Substring(0, iniFile.Length - 4) + ".bin")) + UnpackCncTileData(s); ReadCncOverlay(file); ReadCncTrees(file); }