1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-11-19 19:06:45 -05:00

Lots of optimizations.

This commit is contained in:
Tim Sarbin 2018-12-09 14:55:01 -05:00
parent 0ead3f15c8
commit 0b3124750d
21 changed files with 137 additions and 71 deletions

View File

@ -15,8 +15,8 @@ namespace OpenDiablo2.Common.Interfaces
void Sync(); void Sync();
void Quit(); void Quit();
uint GetTicks(); uint GetTicks();
ISprite LoadSprite(string resourcePath, string palette, Point location); ISprite LoadSprite(string resourcePath, string palette, Point location, bool cacheFrames = false);
ISprite LoadSprite(string resourcePath, string palette); ISprite LoadSprite(string resourcePath, string palette, bool cacheFrames = false);
IFont LoadFont(string resourcePath, string palette); IFont LoadFont(string resourcePath, string palette);
ILabel CreateLabel(IFont font); ILabel CreateLabel(IFont font);
ILabel CreateLabel(IFont font, string text); ILabel CreateLabel(IFont font, string text);

View File

@ -35,5 +35,8 @@ namespace OpenDiablo2.Common.Interfaces
/// <param name="cacheItemPolicy">Pass in a new policy to control how this item is handled. Typically you can leave this null.</param> /// <param name="cacheItemPolicy">Pass in a new policy to control how this item is handled. Typically you can leave this null.</param>
/// <returns>The item requested</returns> /// <returns>The item requested</returns>
T AddOrGetExisting<T>(string key, Func<T> valueFactory, CacheItemPolicy cacheItemPolicy = null); T AddOrGetExisting<T>(string key, Func<T> valueFactory, CacheItemPolicy cacheItemPolicy = null);
bool Exists(string key);
T GetExisting<T>(string key) where T : class, new();
void Add<T>(string key, T value, CacheItemPolicy cacheItemPolicy = null);
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Runtime.CompilerServices;
namespace OpenDiablo2.Common.Models namespace OpenDiablo2.Common.Models
{ {
@ -33,6 +34,7 @@ namespace OpenDiablo2.Common.Models
return _current & 0xff; return _current & 0xff;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool EnsureBits(int bitCount) public bool EnsureBits(int bitCount)
{ {
if (bitCount <= _bitCount) return true; if (bitCount <= _bitCount) return true;

View File

@ -1,6 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
namespace OpenDiablo2.Common.Models namespace OpenDiablo2.Common.Models
{ {
@ -22,17 +23,11 @@ namespace OpenDiablo2.Common.Models
ImageData = null; ImageData = null;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public UInt32 GetColor(int x, int y, Palette palette) public UInt32 GetColor(int x, int y, Palette palette)
{ {
var i = x + (y * Width); var index = ImageData[x + (y * Width)];
if (i >= ImageData.Length) return index == -1 ? 0 : palette.Colors[index];
return 0;
var index = ImageData[i];
if (index == -1)
return 0;
return palette.Colors[index];
} }
} }

View File

@ -40,5 +40,12 @@ namespace OpenDiablo2.Core
throw; throw;
} }
} }
public bool Exists(string key) => _cache.Contains(key);
public T GetExisting<T>(string key) where T : class, new() => (_cache.Get(key) as Lazy<T>)?.Value;
public void Add<T>(string key, T value, CacheItemPolicy cacheItemPolicy = null) => _cache.Add(key, value, cacheItemPolicy ?? new CacheItemPolicy());
} }
} }

View File

@ -22,9 +22,7 @@ namespace OpenDiablo2.Core
private IScene currentScene; private IScene currentScene;
private IScene nextScene = null; private IScene nextScene = null;
private readonly MPQ[] MPQs;
private readonly Dictionary<string, SoundEntry> soundTable = new Dictionary<string, SoundEntry>(); private readonly Dictionary<string, SoundEntry> soundTable = new Dictionary<string, SoundEntry>();
public Dictionary<string, Palette> PaletteTable { get; private set; } = new Dictionary<string, Palette>(); public Dictionary<string, Palette> PaletteTable { get; private set; } = new Dictionary<string, Palette>();
@ -92,7 +90,9 @@ namespace OpenDiablo2.Core
if (ms < 33) if (ms < 33)
{ {
Thread.Sleep(33 - (int)ms); Thread.Sleep(33 - (int)ms);
continue; } else
{
log.Info($"Full frame time used - {ms} milliseconds to frame");
} }
// Prevent falco-punch updates // Prevent falco-punch updates

View File

@ -82,7 +82,7 @@ namespace OpenDiablo2.Core.UI
font = renderWindow.LoadFont(ResourcePaths.FontExocet10, Palettes.Units); font = renderWindow.LoadFont(ResourcePaths.FontExocet10, Palettes.Units);
label = renderWindow.CreateLabel(font); label = renderWindow.CreateLabel(font);
sprite = renderWindow.LoadSprite(buttonLayout.ResourceName, buttonLayout.PaletteName); sprite = renderWindow.LoadSprite(buttonLayout.ResourceName, buttonLayout.PaletteName, true);
// TODO: Less stupid way of doing this would be nice // TODO: Less stupid way of doing this would be nice
buttonWidth = 0; buttonWidth = 0;

View File

@ -38,7 +38,7 @@ namespace OpenDiablo2.Core.UI
{ {
this.renderWindow = renderWindow; this.renderWindow = renderWindow;
sprite = renderWindow.LoadSprite(ResourcePaths.InventoryCharacterPanel, Palettes.Act1, FrameType.GetOffset()); sprite = renderWindow.LoadSprite(ResourcePaths.InventoryCharacterPanel, Palettes.Act1, FrameType.GetOffset(), true);
closeButton = createButton(eButtonType.Close); closeButton = createButton(eButtonType.Close);
closeButton.Location = sprite.Location + new Size(128, 388); closeButton.Location = sprite.Location + new Size(128, 388);

View File

@ -62,9 +62,9 @@ namespace OpenDiablo2.Core.UI
menuButton.OnToggle = minipanel.OnMenuToggle; menuButton.OnToggle = minipanel.OnMenuToggle;
menuButton.Toggle(); menuButton.Toggle();
panelSprite = renderWindow.LoadSprite(ResourcePaths.GamePanels, Palettes.Act1); panelSprite = renderWindow.LoadSprite(ResourcePaths.GamePanels, Palettes.Act1, true);
healthManaSprite = renderWindow.LoadSprite(ResourcePaths.HealthMana, Palettes.Act1); healthManaSprite = renderWindow.LoadSprite(ResourcePaths.HealthMana, Palettes.Act1, true);
gameGlobeOverlapSprite = renderWindow.LoadSprite(ResourcePaths.GameGlobeOverlap, Palettes.Act1); gameGlobeOverlapSprite = renderWindow.LoadSprite(ResourcePaths.GameGlobeOverlap, Palettes.Act1, true);
} }
public IPanel LeftPanel { get; private set; } public IPanel LeftPanel { get; private set; }

View File

@ -51,7 +51,7 @@ namespace OpenDiablo2.Core.UI
{ {
this.renderWindow = renderWindow; this.renderWindow = renderWindow;
sprite = renderWindow.LoadSprite(ResourcePaths.InventoryCharacterPanel, Palettes.Units, FrameType.GetOffset()); sprite = renderWindow.LoadSprite(ResourcePaths.InventoryCharacterPanel, Palettes.Units, FrameType.GetOffset(), true);
closeButton = createButton(eButtonType.Close); closeButton = createButton(eButtonType.Close);
closeButton.Location = sprite.Location + new Size(18, 384); closeButton.Location = sprite.Location + new Size(18, 384);

View File

@ -47,7 +47,7 @@ namespace OpenDiablo2.Core.UI
this.itemContainerLayout = itemContainerLayout; this.itemContainerLayout = itemContainerLayout;
this.mouseInfoProvider = mouseInfoProvider; this.mouseInfoProvider = mouseInfoProvider;
placeholderSprite = renderWindow.LoadSprite(itemContainerLayout.ResourceName, itemContainerLayout.PaletteName); placeholderSprite = renderWindow.LoadSprite(itemContainerLayout.ResourceName, itemContainerLayout.PaletteName, true);
placeholderSprite.Location = new Point(location.X, location.Y + placeholderSprite.LocalFrameSize.Height); placeholderSprite.Location = new Point(location.X, location.Y + placeholderSprite.LocalFrameSize.Height);
this.Size = placeholderSprite.FrameSize; // For all but generic size is equal to the placeholder size. Source: me. this.Size = placeholderSprite.FrameSize; // For all but generic size is equal to the placeholder size. Source: me.
} }
@ -58,7 +58,7 @@ namespace OpenDiablo2.Core.UI
if (ContainedItem != null) if (ContainedItem != null)
{ {
sprite = renderWindow.LoadSprite(ResourcePaths.GeneratePathForItem(this.ContainedItem.InvFile), Palettes.Units); sprite = renderWindow.LoadSprite(ResourcePaths.GeneratePathForItem(this.ContainedItem.InvFile), Palettes.Units, true);
sprite.Location = new Point(location.X, location.Y + sprite.LocalFrameSize.Height); sprite.Location = new Point(location.X, location.Y + sprite.LocalFrameSize.Height);
} }
} }

View File

@ -35,7 +35,7 @@ namespace OpenDiablo2.Core.UI
this.gameState = gameState; this.gameState = gameState;
this.panels = panels; this.panels = panels;
sprite = renderWindow.LoadSprite(ResourcePaths.MinipanelSmall, Palettes.Units); sprite = renderWindow.LoadSprite(ResourcePaths.MinipanelSmall, Palettes.Units, true);
buttons = panelButtons.Select((x, i) => buttons = panelButtons.Select((x, i) =>
{ {

View File

@ -19,7 +19,7 @@ namespace OpenDiablo2.Core.UI
this.renderWindow = renderWindow; this.renderWindow = renderWindow;
this.panelFrameType = panelFrameType; this.panelFrameType = panelFrameType;
sprite = renderWindow.LoadSprite(ResourcePaths.Frame, Palettes.Units, new Point(0, 0)); sprite = renderWindow.LoadSprite(ResourcePaths.Frame, Palettes.Units, new Point(0, 0), true);
Location = new Point(0, 0); Location = new Point(0, 0);

View File

@ -75,7 +75,7 @@ namespace OpenDiablo2.Core.UI
{ {
this.renderWindow = renderWindow; this.renderWindow = renderWindow;
sprite = renderWindow.LoadSprite(ResourcePaths.TextBox2, Palettes.Units); sprite = renderWindow.LoadSprite(ResourcePaths.TextBox2, Palettes.Units, true);
font = renderWindow.LoadFont(ResourcePaths.FontFormal11, Palettes.Units); font = renderWindow.LoadFont(ResourcePaths.FontFormal11, Palettes.Units);
label = renderWindow.CreateLabel(font); label = renderWindow.CreateLabel(font);
linebar = renderWindow.CreateLabel(font); linebar = renderWindow.CreateLabel(font);

View File

@ -36,7 +36,7 @@ namespace OpenDiablo2.SDL2_
{ {
this.font = font; this.font = font;
sprite = new SDL2Sprite(font.FontImageSet, renderer); sprite = new SDL2Sprite(font.FontImageSet, renderer, true);
} }
public void Dispose() public void Dispose()

View File

@ -210,8 +210,8 @@ namespace OpenDiablo2.SDL2_
}; };
font.sprite.Frame = character; font.sprite.Frame = character;
SDL.SDL_SetTextureColorMod(font.sprite.texture, TextColor.R, TextColor.G, TextColor.B); SDL.SDL_SetTextureColorMod(font.sprite.Texture, TextColor.R, TextColor.G, TextColor.B);
SDL.SDL_RenderCopy(renderer, font.sprite.texture, IntPtr.Zero, ref rect); SDL.SDL_RenderCopy(renderer, font.sprite.Texture, IntPtr.Zero, ref rect);
} }

View File

@ -75,6 +75,9 @@ namespace OpenDiablo2.SDL2_
public int PlaySfx(byte[] data) public int PlaySfx(byte[] data)
{ {
if (data == null || data.Length == 0)
return -1;
var sound = SDL_mixer.Mix_QuickLoad_WAV(data); var sound = SDL_mixer.Mix_QuickLoad_WAV(data);
return SDL_mixer.Mix_PlayChannel(-1, sound, 0); return SDL_mixer.Mix_PlayChannel(-1, sound, 0);
} }

View File

@ -242,7 +242,7 @@ namespace OpenDiablo2.SDL2_
public void Draw(ISprite sprite) public void Draw(ISprite sprite)
{ {
var spr = sprite as SDL2Sprite; var spr = sprite as SDL2Sprite;
if (spr.texture == IntPtr.Zero) if (spr.Texture == IntPtr.Zero)
return; return;
var loc = spr.GetRenderPoint(); var loc = spr.GetRenderPoint();
@ -254,7 +254,7 @@ namespace OpenDiablo2.SDL2_
w = spr.FrameSize.Width, w = spr.FrameSize.Width,
h = spr.FrameSize.Height h = spr.FrameSize.Height
}; };
SDL.SDL_RenderCopy(renderer, spr.texture, IntPtr.Zero, ref destRect); SDL.SDL_RenderCopy(renderer, spr.Texture, IntPtr.Zero, ref destRect);
} }
@ -276,15 +276,15 @@ namespace OpenDiablo2.SDL2_
w = spr.FrameSize.Width, w = spr.FrameSize.Width,
h = spr.FrameSize.Height h = spr.FrameSize.Height
}; };
SDL.SDL_RenderCopy(renderer, spr.texture, IntPtr.Zero, ref destRect); SDL.SDL_RenderCopy(renderer, spr.Texture, IntPtr.Zero, ref destRect);
} }
} }
} }
public ISprite LoadSprite(string resourcePath, string palette) => LoadSprite(resourcePath, palette, Point.Empty); public ISprite LoadSprite(string resourcePath, string palette, bool cacheFrames = false) => LoadSprite(resourcePath, palette, Point.Empty, cacheFrames);
public ISprite LoadSprite(string resourcePath, string palette, Point location) public ISprite LoadSprite(string resourcePath, string palette, Point location, bool cacheFrames = false)
{ {
var result = new SDL2Sprite(resourceManager.GetImageSet(resourcePath), renderer) var result = new SDL2Sprite(resourceManager.GetImageSet(resourcePath), renderer, cacheFrames)
{ {
CurrentPalette = paletteProvider.PaletteTable[palette], CurrentPalette = paletteProvider.PaletteTable[palette],
Location = location Location = location
@ -437,7 +437,7 @@ namespace OpenDiablo2.SDL2_
SDL.SDL_SetTextureBlendMode(texId, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND); SDL.SDL_SetTextureBlendMode(texId, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
SDL.SDL_SetRenderTarget(renderer, texId); SDL.SDL_SetRenderTarget(renderer, texId);
SDL.SDL_RenderCopy(renderer, (sprite as SDL2Sprite).texture, IntPtr.Zero, IntPtr.Zero); SDL.SDL_RenderCopy(renderer, (sprite as SDL2Sprite).Texture, IntPtr.Zero, IntPtr.Zero);
SDL.SDL_SetRenderTarget(renderer, IntPtr.Zero); SDL.SDL_SetRenderTarget(renderer, IntPtr.Zero);
return new SDL2MouseCursor return new SDL2MouseCursor

View File

@ -28,7 +28,23 @@ namespace OpenDiablo2.SDL2_
{ {
internal readonly ImageSet source; internal readonly ImageSet source;
private readonly IntPtr renderer; private readonly IntPtr renderer;
internal IntPtr texture = IntPtr.Zero; private readonly bool cacheFrames;
private bool disposed = false;
private IntPtr[] texture;
private bool[] frameLoaded;
public IntPtr Texture
{
get
{
if (!frameLoaded[TextureIndex])
LoadFrame();
return texture[TextureIndex];
}
}
public Point Location { get; set; } public Point Location { get; set; }
public Size FrameSize { get; set; } public Size FrameSize { get; set; }
@ -43,21 +59,25 @@ namespace OpenDiablo2.SDL2_
if (darken == value) if (darken == value)
return; return;
darken = value; darken = value;
LoadFrame(frame); ClearAllFrames();
} }
} }
private int frame = -1; private int frame;
public int Frame public int Frame
{ {
get => frame; get => frame;
set set
{ {
if (frame == value && texture != IntPtr.Zero) if (frame == value)
return; return;
frame = Math.Max(0, Math.Min(value, TotalFrames)); frame = Math.Max(0, Math.Min(value, TotalFrames));
LoadFrame(frame);
if (cacheFrames)
return;
frameLoaded[TextureIndex] = false;
} }
} }
public int TotalFrames { get; internal set; } public int TotalFrames { get; internal set; }
@ -69,7 +89,16 @@ namespace OpenDiablo2.SDL2_
set set
{ {
blend = value; blend = value;
SDL.SDL_SetTextureBlendMode(texture, blend ? SDL.SDL_BlendMode.SDL_BLENDMODE_ADD : SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND); if (cacheFrames)
{
for (var i = 0; i < TotalFrames; i++)
if (texture[i] != IntPtr.Zero)
SDL.SDL_SetTextureBlendMode(texture[i], blend ? SDL.SDL_BlendMode.SDL_BLENDMODE_ADD : SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
}
else
if (texture[TextureIndex] != IntPtr.Zero)
SDL.SDL_SetTextureBlendMode(texture[TextureIndex], blend ? SDL.SDL_BlendMode.SDL_BLENDMODE_ADD : SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
} }
} }
@ -80,23 +109,31 @@ namespace OpenDiablo2.SDL2_
set set
{ {
palette = value; palette = value;
UpdateTextureData(); ClearAllFrames();
} }
} }
private int TextureIndex => cacheFrames ? frame : 0;
public SDL2Sprite(ImageSet source, IntPtr renderer) public SDL2Sprite(ImageSet source, IntPtr renderer, bool cacheFrames = false)
{ {
this.source = source; this.source = source;
this.renderer = renderer; this.renderer = renderer;
this.cacheFrames = cacheFrames;
texture = new IntPtr[cacheFrames ? source.Frames.Count() : 1];
frameLoaded = new bool[cacheFrames ? source.Frames.Count() : 1];
TotalFrames = source.Frames.Count(); TotalFrames = source.Frames.Count();
ClearAllFrames();
Location = Point.Empty; Location = Point.Empty;
FrameSize = new Size(Pow2((int)source.Frames.Max(x => x.Width)), Pow2((int)source.Frames.Max(x => x.Height))); FrameSize = new Size(Pow2((int)source.Frames.Max(x => x.Width)), Pow2((int)source.Frames.Max(x => x.Height)));
Frame = 0;
} }
internal Point GetRenderPoint() internal Point GetRenderPoint()
{ {
return source == null return source == null
@ -108,31 +145,30 @@ namespace OpenDiablo2.SDL2_
private void UpdateTextureData() private void UpdateTextureData()
{ {
if (texture == IntPtr.Zero) Frame = 0;
{
texture = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_ARGB8888, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, Pow2(FrameSize.Width), Pow2(FrameSize.Height));
if (texture == IntPtr.Zero)
throw new OpenDiablo2Exception("Unaple to initialize texture.");
Frame = 0;
}
} }
private unsafe void LoadFrame(int index) private unsafe void LoadFrame()
{ {
var sourceFrame = source.Frames[index]; if (texture[TextureIndex] == IntPtr.Zero)
//var fullRect = new SDL.SDL_Rect { x = 0, y = 0, w = FrameSize.Width, h = FrameSize.Height }; {
SDL.SDL_SetTextureBlendMode(texture, blend ? SDL.SDL_BlendMode.SDL_BLENDMODE_ADD : SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND); texture[TextureIndex] = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_ARGB8888, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, Pow2(FrameSize.Width), Pow2(FrameSize.Height));
SDL.SDL_LockTexture(texture, IntPtr.Zero, out IntPtr pixels, out int pitch); if (texture[TextureIndex] == IntPtr.Zero)
throw new OpenDiablo2Exception("Unaple to initialize texture.");
SDL.SDL_SetTextureBlendMode(texture[TextureIndex], blend ? SDL.SDL_BlendMode.SDL_BLENDMODE_ADD : SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
}
var sourceFrame = source.Frames[frame];
SDL.SDL_LockTexture(texture[TextureIndex], IntPtr.Zero, out IntPtr pixels, out int pitch);
try try
{ {
UInt32* data = (UInt32*)pixels; UInt32* data = (UInt32*)pixels;
var frameOffset = FrameSize.Height - sourceFrame.Height; var frameOffset = FrameSize.Height - sourceFrame.Height;
var frameWidth = FrameSize.Width; var frameWidth = FrameSize.Width;
var frameHeight = FrameSize.Height; var frameHeight = FrameSize.Height;
for (var y = 0; y < frameHeight; y++) for (int y = 0; y < frameHeight; y++)
{ {
for (int x = 0; x < frameWidth; x++) for (int x = 0; x < frameWidth; x++)
{ {
@ -151,10 +187,10 @@ namespace OpenDiablo2.SDL2_
} }
finally finally
{ {
SDL.SDL_UnlockTexture(texture); SDL.SDL_UnlockTexture(texture[TextureIndex]);
} }
frameLoaded[TextureIndex] = true;
} }
private int Pow2(int val) private int Pow2(int val)
@ -165,9 +201,27 @@ namespace OpenDiablo2.SDL2_
return result; return result;
} }
private void ClearAllFrames()
{
var framestoClear = cacheFrames ? TotalFrames : 1;
for (int i = 0; i < framestoClear; i++)
frameLoaded[i] = false;
}
public void Dispose() public void Dispose()
{ {
SDL.SDL_DestroyTexture(texture); if (disposed)
return;
var framestoClear = cacheFrames ? TotalFrames : 1;
for (var i = 0; i < framestoClear; i++)
{
SDL.SDL_DestroyTexture(texture[i]);
texture[i] = IntPtr.Zero;
}
texture = Array.Empty<IntPtr>();
disposed = true;
} }
} }

View File

@ -20,7 +20,7 @@ namespace OpenDiablo2.Scenes
builder builder
.RegisterType(type) .RegisterType(type)
.Keyed<IScene>(att.SceneType) .Keyed<IScene>(att.SceneType)
.SingleInstance(); .InstancePerDependency();
} }
} }
} }

View File

@ -228,18 +228,19 @@ namespace OpenDiablo2.Scenes
Parallel.ForEach(new[] Parallel.ForEach(new[]
{ {
ResourcePaths.SFXAmazonSelect, ResourcePaths.SFXAmazonSelect,
ResourcePaths.SFXAmazonDeselect,
ResourcePaths.SFXAssassinSelect, ResourcePaths.SFXAssassinSelect,
ResourcePaths.SFXAssassinDeselect,
ResourcePaths.SFXBarbarianSelect, ResourcePaths.SFXBarbarianSelect,
ResourcePaths.SFXBarbarianDeselect,
ResourcePaths.SFXDruidSelect, ResourcePaths.SFXDruidSelect,
ResourcePaths.SFXDruidDeselect,
ResourcePaths.SFXNecromancerSelect, ResourcePaths.SFXNecromancerSelect,
ResourcePaths.SFXNecromancerDeselect,
ResourcePaths.SFXPaladinSelect, ResourcePaths.SFXPaladinSelect,
ResourcePaths.SFXPaladinDeselect,
ResourcePaths.SFXSorceressSelect, ResourcePaths.SFXSorceressSelect,
ResourcePaths.SFXAmazonDeselect,
ResourcePaths.SFXAssassinDeselect,
ResourcePaths.SFXBarbarianDeselect,
ResourcePaths.SFXDruidDeselect,
ResourcePaths.SFXNecromancerDeselect,
ResourcePaths.SFXPaladinDeselect,
ResourcePaths.SFXSorceressDeselect ResourcePaths.SFXSorceressDeselect
}, (path => sfxDictionary.Add(path, mpqProvider.GetBytes(path)))); }, (path => sfxDictionary.Add(path, mpqProvider.GetBytes(path))));
} }
@ -609,6 +610,7 @@ namespace OpenDiablo2.Scenes
campfireSprite.Dispose(); campfireSprite.Dispose();
headingFont.Dispose(); headingFont.Dispose();
headingLabel.Dispose(); headingLabel.Dispose();
sfxDictionary.Clear();
} }
} }
} }