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\ProcessInfo.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>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
@ -189,6 +194,7 @@
|
|||
<Folder Include="Graphics\ScreenEffects\" />
|
||||
<Folder Include="States\" />
|
||||
<Folder Include="Processes\" />
|
||||
<Folder Include="Content\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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