add ported content/asset management code

This commit is contained in:
Gered 2013-08-24 11:18:39 -04:00
parent d777598a5d
commit 76d5a4288a
6 changed files with 408 additions and 0 deletions

View file

@ -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" />

View 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;
}
}
}

View 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();
}
}
}

View 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);
}
}
}

View 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);
}
}

View 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();
}
}