add ported content/asset management code
This commit is contained in:
parent
d777598a5d
commit
76d5a4288a
|
@ -169,6 +169,11 @@
|
||||||
<Compile Include="Processes\ProcessManager.cs" />
|
<Compile Include="Processes\ProcessManager.cs" />
|
||||||
<Compile Include="Processes\ProcessInfo.cs" />
|
<Compile Include="Processes\ProcessInfo.cs" />
|
||||||
<Compile Include="Framework.cs" />
|
<Compile Include="Framework.cs" />
|
||||||
|
<Compile Include="Content\IContentLoaderBase.cs" />
|
||||||
|
<Compile Include="Content\IContentLoader.cs" />
|
||||||
|
<Compile Include="Content\ContentContainer.cs" />
|
||||||
|
<Compile Include="Content\ContentManager.cs" />
|
||||||
|
<Compile Include="Content\DictionaryStoreContentLoader.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -189,6 +194,7 @@
|
||||||
<Folder Include="Graphics\ScreenEffects\" />
|
<Folder Include="Graphics\ScreenEffects\" />
|
||||||
<Folder Include="States\" />
|
<Folder Include="States\" />
|
||||||
<Folder Include="Processes\" />
|
<Folder Include="Processes\" />
|
||||||
|
<Folder Include="Content\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Resources\Fonts\Vera.ttf" />
|
<EmbeddedResource Include="Resources\Fonts\Vera.ttf" />
|
||||||
|
|
19
Blarg.GameFramework/Content/ContentContainer.cs
Normal file
19
Blarg.GameFramework/Content/ContentContainer.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Blarg.GameFramework.Content
|
||||||
|
{
|
||||||
|
public class ContentContainer<T> where T : class
|
||||||
|
{
|
||||||
|
public T Content;
|
||||||
|
public bool IsPinned;
|
||||||
|
|
||||||
|
internal ContentContainer(T content)
|
||||||
|
{
|
||||||
|
if (content == null)
|
||||||
|
throw new ArgumentNullException("content");
|
||||||
|
|
||||||
|
Content = content;
|
||||||
|
IsPinned = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
150
Blarg.GameFramework/Content/ContentManager.cs
Normal file
150
Blarg.GameFramework/Content/ContentManager.cs
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Blarg.GameFramework.Content
|
||||||
|
{
|
||||||
|
public class ContentManager : IDisposable
|
||||||
|
{
|
||||||
|
const string LOG_TAG = "CONTENT";
|
||||||
|
|
||||||
|
Dictionary<Type, IContentLoaderBase> _loaders;
|
||||||
|
|
||||||
|
public bool IsLoaded { get; private set; }
|
||||||
|
public readonly IGameApp GameApp;
|
||||||
|
|
||||||
|
public ContentManager(IGameApp gameApp)
|
||||||
|
{
|
||||||
|
if (gameApp == null)
|
||||||
|
throw new ArgumentNullException("gameApp");
|
||||||
|
|
||||||
|
_loaders = new Dictionary<Type, IContentLoaderBase>();
|
||||||
|
IsLoaded = false;
|
||||||
|
GameApp = gameApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterLoader(IContentLoaderBase loader)
|
||||||
|
{
|
||||||
|
if (loader == null)
|
||||||
|
throw new ArgumentNullException("loader");
|
||||||
|
if (_loaders.ContainsKey(loader.ContentType))
|
||||||
|
throw new InvalidOperationException("Content loader already registered for this content type.");
|
||||||
|
|
||||||
|
Framework.Logger.Info(LOG_TAG, "Registering content loader for type: {0}", loader.ContentType.ToString());
|
||||||
|
_loaders.Add(loader.ContentType, loader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Get<T>(string name) where T : class
|
||||||
|
{
|
||||||
|
var loader = GetLoader<T>();
|
||||||
|
if (loader == null)
|
||||||
|
throw new InvalidOperationException("No registered loader for this content type.");
|
||||||
|
else
|
||||||
|
return loader.Get(name, null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Get<T>(string name, object contentParameters) where T : class
|
||||||
|
{
|
||||||
|
var loader = GetLoader<T>();
|
||||||
|
if (loader == null)
|
||||||
|
throw new InvalidOperationException("No registered loader for this content type.");
|
||||||
|
else
|
||||||
|
return loader.Get(name, contentParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Pin<T>(string name) where T : class
|
||||||
|
{
|
||||||
|
var loader = GetLoader<T>();
|
||||||
|
if (loader == null)
|
||||||
|
throw new InvalidOperationException("No registered loader for this content type.");
|
||||||
|
else
|
||||||
|
return loader.Pin(name, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Pin<T>(string name, object contentParameters) where T : class
|
||||||
|
{
|
||||||
|
var loader = GetLoader<T>();
|
||||||
|
if (loader == null)
|
||||||
|
throw new InvalidOperationException("No registered loader for this content type.");
|
||||||
|
else
|
||||||
|
return loader.Pin(name, contentParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAllContent(bool removePinnedContent = false)
|
||||||
|
{
|
||||||
|
foreach (var loader in _loaders)
|
||||||
|
loader.Value.RemoveAll(removePinnedContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAllContent<T>(bool removePinnedContent = false) where T : class
|
||||||
|
{
|
||||||
|
var loader = GetLoader<T>();
|
||||||
|
if (loader == null)
|
||||||
|
throw new InvalidOperationException("No registered loader for this content type.");
|
||||||
|
else
|
||||||
|
loader.RemoveAll(removePinnedContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetNameOf<T>(T content) where T : class
|
||||||
|
{
|
||||||
|
if (content == null)
|
||||||
|
throw new ArgumentNullException("content");
|
||||||
|
|
||||||
|
var loader = GetLoader<T>();
|
||||||
|
if (loader == null)
|
||||||
|
throw new InvalidOperationException("No registered loader for this content type.");
|
||||||
|
else
|
||||||
|
return loader.GetNameOf(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IContentLoader<T> GetLoader<T>() where T : class
|
||||||
|
{
|
||||||
|
IContentLoaderBase loader;
|
||||||
|
_loaders.TryGetValue(typeof(T), out loader);
|
||||||
|
if (loader == null)
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return loader as IContentLoader<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnLoad()
|
||||||
|
{
|
||||||
|
IsLoaded = true;
|
||||||
|
|
||||||
|
Framework.Logger.Info(LOG_TAG, "Running all content loader OnLoad events.");
|
||||||
|
foreach (var loader in _loaders)
|
||||||
|
loader.Value.OnLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnUnload()
|
||||||
|
{
|
||||||
|
IsLoaded = false;
|
||||||
|
|
||||||
|
Framework.Logger.Info(LOG_TAG, "Running all content loader OnUnload events.");
|
||||||
|
foreach (var loader in _loaders)
|
||||||
|
loader.Value.OnUnload();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnLostContext()
|
||||||
|
{
|
||||||
|
Framework.Logger.Info(LOG_TAG, "Running all content loader OnLostContext events.");
|
||||||
|
foreach (var loader in _loaders)
|
||||||
|
loader.Value.OnLostContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnNewContext()
|
||||||
|
{
|
||||||
|
Framework.Logger.Info(LOG_TAG, "Running all content loader OnNewContext events.");
|
||||||
|
foreach (var loader in _loaders)
|
||||||
|
loader.Value.OnNewContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Framework.Logger.Info(LOG_TAG, "Disposing");
|
||||||
|
foreach (var loader in _loaders)
|
||||||
|
loader.Value.Dispose();
|
||||||
|
_loaders.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
205
Blarg.GameFramework/Content/DictionaryStoreContentLoader.cs
Normal file
205
Blarg.GameFramework/Content/DictionaryStoreContentLoader.cs
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Blarg.GameFramework.Content
|
||||||
|
{
|
||||||
|
public abstract class DictionaryStoreContentLoader<T> : IContentLoader<T> where T : class
|
||||||
|
{
|
||||||
|
const string LOG_TAG = "CONTENT";
|
||||||
|
|
||||||
|
string _defaultPath;
|
||||||
|
|
||||||
|
protected readonly ContentManager ContentManager;
|
||||||
|
protected readonly Dictionary<string, ContentContainer<T>> ContentStore;
|
||||||
|
protected readonly string LoggingTag;
|
||||||
|
|
||||||
|
public Type ContentType
|
||||||
|
{
|
||||||
|
get { return typeof(T); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DictionaryStoreContentLoader(ContentManager contentManager, string loggingTag, string defaultPath)
|
||||||
|
{
|
||||||
|
if (contentManager == null)
|
||||||
|
throw new ArgumentNullException("contentManager");
|
||||||
|
if (String.IsNullOrEmpty(loggingTag))
|
||||||
|
throw new ArgumentException("Logging tag is required.");
|
||||||
|
|
||||||
|
ContentManager = contentManager;
|
||||||
|
ContentStore = new Dictionary<string, ContentContainer<T>>();
|
||||||
|
|
||||||
|
LoggingTag = loggingTag;
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(defaultPath))
|
||||||
|
{
|
||||||
|
_defaultPath = defaultPath;
|
||||||
|
if (!_defaultPath.EndsWith("/"))
|
||||||
|
_defaultPath += "/";
|
||||||
|
|
||||||
|
Framework.Logger.Info(LOG_TAG, "{0}: default path set to \"{1}\"", LoggingTag, _defaultPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_defaultPath = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Get(string name, object contentParameters)
|
||||||
|
{
|
||||||
|
var content = GetContent(name, true, contentParameters);
|
||||||
|
if (content != null)
|
||||||
|
return content.Content;
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Pin(string name, object contentParameters)
|
||||||
|
{
|
||||||
|
var content = GetContent(name, true, contentParameters);
|
||||||
|
if (content != null)
|
||||||
|
{
|
||||||
|
content.IsPinned = true;
|
||||||
|
return content.Content;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ContentContainer<T> GetContent(string name, bool loadIfNotAlready, object contentParameters)
|
||||||
|
{
|
||||||
|
if (!ContentManager.IsLoaded)
|
||||||
|
throw new InvalidOperationException("Cannot load content until OnLoad has passed.");
|
||||||
|
|
||||||
|
ContentContainer<T> content = null;
|
||||||
|
|
||||||
|
string filename = AddDefaultPathIfNeeded(name);
|
||||||
|
filename = ProcessFilename(filename, contentParameters);
|
||||||
|
|
||||||
|
var found = FindContent(filename, contentParameters);
|
||||||
|
if (found != null)
|
||||||
|
{
|
||||||
|
content = found.Value.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (loadIfNotAlready)
|
||||||
|
{
|
||||||
|
T actualContentObject = LoadContent(filename, contentParameters);
|
||||||
|
if (actualContentObject != null)
|
||||||
|
{
|
||||||
|
content = new ContentContainer<T>(actualContentObject);
|
||||||
|
ContentStore.Add(filename, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAll(bool removePinnedContent = false)
|
||||||
|
{
|
||||||
|
if (ContentStore.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (removePinnedContent)
|
||||||
|
{
|
||||||
|
Framework.Logger.Info(LOG_TAG, "{0}: freeing all content.", LoggingTag);
|
||||||
|
|
||||||
|
// we're removing everything here. go through all the content and
|
||||||
|
// call Dispose() on all IDisposable's and then just clear the dictionary
|
||||||
|
foreach (var item in ContentStore)
|
||||||
|
{
|
||||||
|
var content = item.Value.Content;
|
||||||
|
if (content is IDisposable)
|
||||||
|
(content as IDisposable).Dispose();
|
||||||
|
}
|
||||||
|
ContentStore.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Framework.Logger.Info(LOG_TAG, "{0}: freeing all non-pinned content.", LoggingTag);
|
||||||
|
|
||||||
|
// can't remove items from a dictionary inside a foreach loop iterating through it
|
||||||
|
// build a list of all the content (names) that need to be removed
|
||||||
|
var keysToRemove = new List<string>();
|
||||||
|
foreach (var item in ContentStore)
|
||||||
|
{
|
||||||
|
if (item.Value.IsPinned == false)
|
||||||
|
keysToRemove.Add(item.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now remove each one by name
|
||||||
|
foreach (var key in keysToRemove)
|
||||||
|
{
|
||||||
|
var content = ContentStore[key].Content;
|
||||||
|
if (content is IDisposable)
|
||||||
|
(content as IDisposable).Dispose();
|
||||||
|
ContentStore.Remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetNameOf(T content)
|
||||||
|
{
|
||||||
|
if (content == null)
|
||||||
|
throw new ArgumentNullException("content");
|
||||||
|
|
||||||
|
foreach (var item in ContentStore)
|
||||||
|
{
|
||||||
|
if (item.Value.Content == content)
|
||||||
|
return item.Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnLoad()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnUnload()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnNewContext()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnLostContext()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual KeyValuePair<string, ContentContainer<T>>? FindContent(string file, object contentParameters)
|
||||||
|
{
|
||||||
|
// default implementation here ignores any additional content parameters completely
|
||||||
|
|
||||||
|
KeyValuePair<string, ContentContainer<T>>? result = null;
|
||||||
|
|
||||||
|
ContentContainer<T> content;
|
||||||
|
ContentStore.TryGetValue(file, out content);
|
||||||
|
if (content != null)
|
||||||
|
result = new KeyValuePair<string, ContentContainer<T>>(file, content);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract T LoadContent(string file, object contentParameters);
|
||||||
|
|
||||||
|
protected string AddDefaultPathIfNeeded(string filename)
|
||||||
|
{
|
||||||
|
if (filename.StartsWith("/") || String.IsNullOrEmpty(_defaultPath) || filename.StartsWith("assets://"))
|
||||||
|
return filename;
|
||||||
|
else
|
||||||
|
return _defaultPath + filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual string ProcessFilename(string filename, object contentParameters)
|
||||||
|
{
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Framework.Logger.Info(LOG_TAG, "{0}: disposing. Forcibly freeing any content still loaded.", LoggingTag);
|
||||||
|
RemoveAll(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
Blarg.GameFramework/Content/IContentLoader.cs
Normal file
12
Blarg.GameFramework/Content/IContentLoader.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Blarg.GameFramework.Content
|
||||||
|
{
|
||||||
|
public interface IContentLoader<T> : IContentLoaderBase where T : class
|
||||||
|
{
|
||||||
|
T Get(string name, object contentParameters);
|
||||||
|
T Pin(string name, object contentParameters);
|
||||||
|
|
||||||
|
string GetNameOf(T content);
|
||||||
|
}
|
||||||
|
}
|
16
Blarg.GameFramework/Content/IContentLoaderBase.cs
Normal file
16
Blarg.GameFramework/Content/IContentLoaderBase.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Blarg.GameFramework.Content
|
||||||
|
{
|
||||||
|
public interface IContentLoaderBase : IDisposable
|
||||||
|
{
|
||||||
|
Type ContentType { get; }
|
||||||
|
|
||||||
|
void RemoveAll(bool removePinnedContent = false);
|
||||||
|
|
||||||
|
void OnLoad();
|
||||||
|
void OnUnload();
|
||||||
|
void OnNewContext();
|
||||||
|
void OnLostContext();
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue