Async added for skin manager.

This commit is contained in:
Harrison Deng 2019-01-20 18:05:40 -06:00
parent 019b955577
commit 1ae2b0cf8d

View File

@ -4,21 +4,56 @@ using Newtonsoft.Json;
using RecrownedAthenaeum.Pipeline; using RecrownedAthenaeum.Pipeline;
using RecrownedAthenaeum.Data; using RecrownedAthenaeum.Data;
using RecrownedAthenaeum.SpecialTypes; using RecrownedAthenaeum.SpecialTypes;
using RecrownedAthenaeum.UI.Skin.Definitions;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading;
namespace RecrownedAthenaeum.UI.Skin namespace RecrownedAthenaeum.UI.Skin
{ {
/// <summary>
/// Called when the skin manager has completed a async action.
/// </summary>
/// <param name="actionCompleted">The completed action.</param>
public delegate void AsyncComplete(SkinManager.Action actionCompleted);
/// <summary> /// <summary>
/// Manages reference to default and loading of custom skins. /// Manages reference to default and loading of custom skins.
/// </summary> /// </summary>
public class SkinManager public class SkinManager
{ {
private const string EXTENSION = ".rbskin"; private const string EXTENSION = ".rbskin";
private readonly MergedSkin mergedSkin = new MergedSkin(); private readonly MergedSkin mergedSkin = new MergedSkin();
private Thread thread;
private Action action;
private GraphicsDevice graphicsDevice;
private string selectedSkinPath;
private SkinData skinDataToUse;
/// <summary>
/// The list of paths for all found skins by <see cref="SearchSkinDirectory"/>. May be null.
/// </summary>
public volatile List<string> skinPaths;
/// <summary>
/// The event that is called when a state changes.
/// </summary>
public event AsyncComplete AsyncCompleteEvent;
/// <summary>
/// The various possible states a skin manager could be in.
/// </summary>
public enum Action
{
/// <summary>
/// After a search has completed.
/// </summary>
SEARCH,
/// <summary>
/// Having the skin generated to be in a useable state.
/// </summary>
GENERATE
}
/// <summary> /// <summary>
/// the skin that favors the selected skin, but still has a fallback to the default skin in case anything is missing. /// the skin that favors the selected skin, but still has a fallback to the default skin in case anything is missing.
@ -40,15 +75,13 @@ namespace RecrownedAthenaeum.UI.Skin
/// </summary> /// </summary>
public string skinsDirectory; public string skinsDirectory;
List<string> skinPaths = new List<string>();
/// <summary> /// <summary>
/// Updates list of skins by searching recursively in the set <see cref="skinsDirectory"/>. /// Performs a recursive asynchronous search of the directory given in a path set by <see cref="skinsDirectory"/>.
/// </summary> /// </summary>
public void SearchForSkins() public void SearchSkinDirectory()
{ {
skinPaths.Clear(); action = Action.SEARCH;
skinPaths = RecursiveSkinSearch(skinsDirectory); AttemptAsync();
} }
/// <summary> /// <summary>
@ -66,13 +99,49 @@ namespace RecrownedAthenaeum.UI.Skin
} }
/// <summary> /// <summary>
/// Generate skin from skin data. /// Generates a skin asynchronously.
/// </summary> /// </summary>
/// <param name="skinData">The skin data to generate skin from.</param> /// <param name="graphicsDevice">Graphics device to use for texture creation.</param>
/// <param name="skinData">The data to generate from.</param>
/// <param name="path">The path pointing to the file with the extension "<see cref="EXTENSION"/>".</param> /// <param name="path">The path pointing to the file with the extension "<see cref="EXTENSION"/>".</param>
/// <param name="graphicsDevice">The graphics device to generate the texture.</param> public void GenerateSkin(GraphicsDevice graphicsDevice, SkinData skinData, string path)
/// <returns>The skin generated from the skin data.</returns> {
public Skin GenerateSkinFromData(SkinData skinData, string path, GraphicsDevice graphicsDevice) action = Action.GENERATE;
this.graphicsDevice = graphicsDevice;
this.selectedSkinPath = path;
this.skinDataToUse = skinData;
AttemptAsync();
}
private void AttemptAsync()
{
if (thread != null && thread.IsAlive) throw new InvalidOperationException("Already performing task: " + action);
thread = new Thread(ThreadStart);
}
private void ThreadStart()
{
switch (action)
{
case Action.SEARCH:
SearchForSkins();
OnAsyncComplete(action);
break;
case Action.GENERATE:
SelectedSkin = GenerateSkinFromData(skinDataToUse, selectedSkinPath, graphicsDevice);
OnAsyncComplete(action);
break;
}
}
private void SearchForSkins()
{
skinPaths.Clear();
skinPaths = RecursiveSkinSearch(skinsDirectory);
}
private Skin GenerateSkinFromData(SkinData skinData, string path, GraphicsDevice graphicsDevice)
{ {
TextureAtlasDataReader textureAtlasDataReader = new TextureAtlasDataReader(); TextureAtlasDataReader textureAtlasDataReader = new TextureAtlasDataReader();
FileInfo[] skinFiles = Directory.GetParent(path).GetFiles(); FileInfo[] skinFiles = Directory.GetParent(path).GetFiles();
@ -96,7 +165,8 @@ namespace RecrownedAthenaeum.UI.Skin
{ {
cursorTexture = Texture2D.FromStream(graphicsDevice, stream); cursorTexture = Texture2D.FromStream(graphicsDevice, stream);
} }
} else }
else
{ {
cursorTexture = textureAtlas[skinData.cursorTextureName].AsTexture2D(graphicsDevice); cursorTexture = textureAtlas[skinData.cursorTextureName].AsTexture2D(graphicsDevice);
} }
@ -137,5 +207,9 @@ namespace RecrownedAthenaeum.UI.Skin
return skins; return skins;
} }
private void OnAsyncComplete(Action newState)
{
AsyncCompleteEvent?.Invoke(newState);
}
} }
} }