Skip to main content
GameDev.net gamedev.net
🔒 Locked

Engine design and resources

Started by JorenJoestar Jan 9, 2009 at 6:57 AM 37 replies 6.2k views
Original Post
JorenJoestar
JorenJoestar
Hi guys! I'm designing my new engine (full), based on my previous engine (only graphic,
), and I have an open question: have you some class that represent the idea of 'resource'? How do you handle resource management? Thanks everybody!
---------------------------------------http://badfoolprototype.blogspot.com/
DocDumb
DocDumb
Al the stuff tha you load at run time like textures, meshes, sounds should be managed like resource, and the better way i think that are the smart pointers, so you can avoid memory leak and wrong resource unload or duplicate.

I hope that this can help.
someboddy
someboddy
Here is my resource management classes:

Resource class - interface:
[source lang=cpp]class SIResource{protected:	unsigned int id;	bool needed;	vector<unsigned int> dependecies;public:	SIResource();	virtual bool load()=0;	virtual bool isLoaded() const=0;	virtual void unload()=0;	virtual unsigned int getID() const;		virtual bool isNeeded() const;	virtual void setNeeded(bool needed);	virtual bool loadIfNeeded();	virtual bool readHeader()=0;	virtual bool readDependencies(const string &dependenciesList);	virtual bool isLoadedLast() const;};

Implementation:
[source lang=cpp]SIResource::SIResource(){	SIResource::id=id;}unsigned int SIResource::getID() const{	return id;}bool SIResource::isNeeded() const{	return needed;}void SIResource::setNeeded(bool needed){	if(needed&&!SIResource::needed)	{		for(vector<unsigned int>::iterator it=dependecies.begin();it!=dependecies.end();++it)			SResourcesManager::markAsNeeded(*it);	}	SIResource::needed=needed;}bool SIResource::loadIfNeeded(){	if(isNeeded()&&!isLoaded())		return load();	if(!isNeeded()&&isLoaded())		unload();	return true;}bool SIResource::readDependencies(const std::string &dependenciesList){	return sAddToUIntVector(dependecies,dependenciesList);}bool SIResource::isLoadedLast() const{	return false;}




Resource manager class - interface
[source lang=cpp]class SResourcesManager{private:	static SResourcesManager *instance;	SResourcesManager();	map<unsigned int,SIResource*> resourceMap;	map<unsigned int,SImage*> loadedImages;	map<unsigned int,SObjectPlacer*> loadedPlacers;	map<unsigned int,SLEntity*> lEntities;	map<unsigned int,SObjectBatch*> loadedBatches;	map<unsigned int,STexture*> loadedTextures;		map<unsigned int,SGUIBatch*> loadedGUIBatches;public:	static void init();	static void destroy();	static bool readFromListFile(string fileName);	static void beginMarking();	static bool markAsNeeded(unsigned int id);	static bool endMarking();	static void addImage(unsigned int id,SImage *image);	static void removeImage(unsigned int id);	static SImage *getImage(unsigned int id);		static void addPlacer(SObjectPlacer *placer);	static void removePlacer(unsigned int id);	static SObjectPlacer *getPlacer(unsigned int id);	static void addLEntity(unsigned int id,SLEntity *lEntity);	static void removeLEntity(unsigned int id);	static void clearLEntities();	static SLEntity *getLEntity(unsigned int id);	static void addAllLEntitiesToWorld(SLWorld *target);	static void addBatch(SObjectBatch *batch);	static void removeBatch(unsigned int id);	static SObjectBatch *getBatch(unsigned int id);	static bool deployBatchesWithConditionMet(SWorld *target);	static void addTexture(unsigned int id,STexture *texture);	static void removeTexture(unsigned int id);	static STexture *getTexture(unsigned int id);	static void addGUIBatch(SGUIBatch *guiBatch);	static void removeGUIBatch(unsigned int id);	static SGUIBatch *getGUIBatch(unsigned int id);};

Implementation:
[source lang=cpp]SResourcesManager *SResourcesManager::instance=0;SResourcesManager::SResourcesManager(){}void SResourcesManager::init(){	if(instance)		destroy();	instance=new SResourcesManager();}void SResourcesManager::destroy(){	for(map<unsigned int,SIResource*>::iterator it=instance->resourceMap.begin();it!=instance->resourceMap.end();++it)	{		it->second->unload();		delete it->second;	}	instance->resourceMap.clear();	instance=0;}bool SResourcesManager::readFromListFile(std::string fileName){	SObjectFileReader reader(fileName);	reader.beginReading();	reader.readNext();	SIResource *tmpResource=0;	while(!reader.isEOF())	{		tmpResource=0;		if(reader.getCommand()=="textureMap")			tmpResource=new STextureMap(reader.getArguments());		else if(reader.getCommand()=="objectPoll")			tmpResource=new SObjectPoll(reader.getArguments());		else if(reader.getCommand()=="level")			tmpResource=new SLevelLoader(reader.getArguments());		else if(reader.getCommand()=="texture")			tmpResource=new STextureLoader(reader.getArguments());		else if(reader.getCommand()=="guiLayout")			tmpResource=new SGUILoader(reader.getArguments());		if(tmpResource)		{			if(!tmpResource->readHeader())				return false;			instance->resourceMap.insert(pair<unsigned int,SIResource*>(tmpResource->getID(),tmpResource));		}		reader.readNext();	}	return true;}void SResourcesManager::beginMarking(){	for(map<unsigned int,SIResource*>::iterator it=instance->resourceMap.begin();it!=instance->resourceMap.end();++it)	{		it->second->setNeeded(false);	}}bool SResourcesManager::markAsNeeded(unsigned int id){	map<unsigned int,SIResource*>::iterator it=instance->resourceMap.find(id);	if(it==instance->resourceMap.end())	{				stringstream err;		err<<"Unable to find resource number ";		err<<id;		err<<".";				SSystem::addError(err.str());		return false;	}	it->second->setNeeded(true);	return true;}bool SResourcesManager::endMarking(){	queue<SIResource*> loadedLast;	for(map<unsigned int,SIResource*>::iterator it=instance->resourceMap.begin();it!=instance->resourceMap.end();++it)	{		if(it->second->isLoadedLast())			loadedLast.push(it->second);		else if(!it->second->loadIfNeeded())			return false;	}	while(!loadedLast.empty())	{		if(!loadedLast.front()->loadIfNeeded())			return false;		loadedLast.pop();	}	return true;}void SResourcesManager::addImage(unsigned int id, SImage *image){	instance->loadedImages.insert(pair<unsigned int,SImage*>(id,image));}void SResourcesManager::removeImage(unsigned int id){	instance->loadedImages.erase(id);}SImage *SResourcesManager::getImage(unsigned int id){	map<unsigned int,SImage*>::iterator it=instance->loadedImages.find(id);	if(it==instance->loadedImages.end())		return 0;	return it->second;}void SResourcesManager::addPlacer(SObjectPlacer *placer){	instance->loadedPlacers.insert(pair<unsigned int,SObjectPlacer*>(placer->getID(),placer));}void SResourcesManager::removePlacer(unsigned int id){	instance->loadedPlacers.erase(id);}SObjectPlacer *SResourcesManager::getPlacer(unsigned int id){	map<unsigned int,SObjectPlacer*>::iterator it=instance->loadedPlacers.find(id);	if(it==instance->loadedPlacers.end())		return 0;	return it->second;}void SResourcesManager::addLEntity(unsigned int id, SLEntity *lEntity){	instance->lEntities.insert(pair<unsigned int,SLEntity*>(id,lEntity));}void SResourcesManager::removeLEntity(unsigned int id){	instance->lEntities.erase(id);}void SResourcesManager::clearLEntities(){	instance->lEntities.clear();}SLEntity *SResourcesManager::getLEntity(unsigned int id){	map<unsigned int,SLEntity*>::iterator it=instance->lEntities.find(id);	if(it==instance->lEntities.end())		return 0;	return it->second;}void SResourcesManager::addAllLEntitiesToWorld(SLWorld *target){	for(map<unsigned int,SLEntity*>::iterator it=instance->lEntities.begin();it!=instance->lEntities.end();++it)		target->add(it->second);}void SResourcesManager::addBatch(SObjectBatch *batch){	instance->loadedBatches.insert(pair<unsigned int,SObjectBatch*>(batch->getID(),batch));}void SResourcesManager::removeBatch(unsigned int id){	instance->loadedBatches.erase(id);}SObjectBatch *SResourcesManager::getBatch(unsigned int id){	map<unsigned int,SObjectBatch*>::iterator it=instance->loadedBatches.find(id);	if(it==instance->loadedBatches.end())		return 0;	return it->second;}bool SResourcesManager::deployBatchesWithConditionMet(SWorld *target){	queue<unsigned int>batchesToRemove;	map<unsigned int,SObjectBatch*>::iterator it=instance->loadedBatches.begin();	while(it!=instance->loadedBatches.end())	{		SObjectBatch *batch=it->second;		if(batch->isDeployingConditionMet(target))		{			if(!batch->place(target))				return false;			if(batch->isRemoveWhenDeployed())				batchesToRemove.push(it->first);			if(batch->isDeleteWhenDeployed())				delete batch;		}		++it;	}	while(!batchesToRemove.empty())	{		instance->loadedBatches.erase(batchesToRemove.front());		batchesToRemove.pop();	}	return true;}void SResourcesManager::addTexture(unsigned int id,STexture *texture){	instance->loadedTextures.insert(pair<unsigned int,STexture*>(id,texture));}void SResourcesManager::removeTexture(unsigned int id){	instance->loadedTextures.erase(id);}STexture *SResourcesManager::getTexture(unsigned int id){	map<unsigned int,STexture*>::iterator it=instance->loadedTextures.find(id);	if(it==instance->loadedTextures.end())		return 0;	return it->second;}void SResourcesManager::addGUIBatch(SGUIBatch *guiBatch){	instance->loadedGUIBatches.insert(pair<unsigned int,SGUIBatch*>(guiBatch->getID(),guiBatch));}void SResourcesManager::removeGUIBatch(unsigned int id){	instance->loadedGUIBatches.erase(id);}SGUIBatch *SResourcesManager::getGUIBatch(unsigned int id){	map<unsigned int,SGUIBatch*>::iterator it=instance->loadedGUIBatches.find(id);	if(it==instance->loadedGUIBatches.end())		return 0;	return it->second;}
-----------------------------------------Everyboddy need someboddy!
haegarr
haegarr
In my approach, every resource is typically represented by a (type specialized) Resource instance in a dictionary of the project (a game and also a game's level is a special kind of project). I.e. there is normally a permanent object representation. This is somewhat more complex than the simple resource management, but gives some advantages (of course other systems may also implement such features but perhaps in a different way):

(1) It is simple to attach management attributes to a resource, e.g. whether the actual resource data should be loaded on game start-up, on level load, or or demand only.
(2) It is simple to have (resource type specific) parameters at hand w/o having the actual data being loaded, e.g. the size and format of a texture, or its memory footprint.
(3) It is easy to have prototypes (for instancing) on the resource basis.
(4) The source of the actual resource data can be attached as an Import. The typical types are the FileImport and the ArchiveImport, but an InetImport or whatever is possible, too.

The concept furthur allows for some features that are less runtime engine related but more editor related:

(5) It is more easy for the system and the designer to check for consistency.
(6) It is possible to group the resources. The system provides an automatic type based grouping into ResourceLibrary instances, as well as a designer driven grouping into ResourceFolder. This allows designers a better access to the project's resources/assets.
(7) It is possible to build computed resources. E.g. an ImageResource represents an, well, image; but an image itself can't be loaded directly, so the resource can be used as input for a specialized TextureConverter to provide the data for a TextureResource. Due to this, there is a difference between resources and assets, although only on a logical level.
(8) A kind of compilation is possible. E.g. the above resource computation should not be part of the resulting game level but its result (i.e. the actual asset) should, of course, then an Export can be attached for more or less automatic saving.
(9) A FileImport, as a special type of Import, can be parametrized to observe a file source, so that changes to the source can automatically start an update.
(10) The IOFormat (that is responsible for loading and perhaps saving the actual resource data) can be pre-determined from the resource type, or one can be attached to the Import to enforce the use of a concrete format.
JorenJoestar
JorenJoestar
@ Haegarr:

Your design seems really interesting, could you give me some more infos?


@ Someboddy:

Your design is good (and thank you very much for the code), are you using it in a project?


Thanks guys, your replies are great! :D
---------------------------------------http://badfoolprototype.blogspot.com/
someboddy
someboddy
Yea, I'm currently working on a small 2D game engine, and this is it's resource management code. It allows me to easily access every image, entity type, and any other type of resource using id's instead of pointers. Also, it uses a dependencies model and a marking method so when a level is changed, if a resource was used in the previous level and is needed for the new level, it will remain in the memory instead of being unloaded and loaded again.
-----------------------------------------Everyboddy need someboddy!
iliak
iliak
Hi

In my engine, each asset is accessed by an unique name, ie

Texture tex1 = ResourceManager.GetTexture("one");
Texture tex2 = ResourceManager.GetTexture("two");

TileSet tileset = ResourceManager.GetTileset("one");

Each asset has its own realm, so two different assets can have the same name (hope it's clear).

With this approch, I can access each ressource by script for exemple.

In fact, this was how I did before. I found a better way to handle assets. Let's me explain...
Instead of having a method for each kind of asset in my manager, like this :

Texture ResourceManager.GetTexture(string name);
Animation ResourceManager.GetAnimation(string name);
TileSet ResourceManager.GetTileSet(string name);
Sound ResourceManager.GetSound(string name);
Maze ResourceManager.GetMaze(string name);
...

I use generics. So I have only one method to acces every assets :
T ResourceManager.GetAsset(string name);

Texture tex = ResourceManager.GetAsset("one");
Sound snd = ResourceManager.GetAsset("gun fire");

As a (good) side effect, this allows to implement "Provider". What is a provider ? Simply put, a class that can extend known assets.
My engine knows only base assets (Texture, Animation, StringTable, TileSet, Script...) and the end user is able to extend it by providing its own Providers.
This allow me to make a Jump'n'Run game, D&D game and so on really easily.




- Iliak -
[ ArcEngine: An open source .Net gaming framework ]
[ Dungeon Eye: An open source remake of Eye of the Beholder II ]
JorenJoestar
JorenJoestar
Okay...thanks for the ideas :D

But if you want to group resources per assets? (I'm not talking about streaming)
When you enter a level, you have to load all the resources of its asset.
And when you leave, you have to unload all the asset.
In this case you are using some sort of tag, and group your resources by tag, or simply you have a list of resources in which every one has its own tag, so if you want to free them you linearly scan the list using the tag?

And then...what about "empty" resources? Consider a shadowmap...is it considered a resource? It is an empty texture, filled IF the current rendering need the shadows...how do you handle it? Do you insert it in the resource list too?


Thanks again!
---------------------------------------http://badfoolprototype.blogspot.com/
someboddy
someboddy
An empty resource should function like any other resource - except it is not connected to a file. In my design, SIResource has no fields nor methods concerning files. Sure, the load function is mainly used to load the resource from a file, but it can just as easily be used to create an empty shadowmap.
-----------------------------------------Everyboddy need someboddy!
JorenJoestar
JorenJoestar
Right, but how the object (entity, or stuff like that) use the resource? It stores the pointer to it, say a texture, and then use it? Or store the handle and every time needs to ask the resource manager to get the resource?

I'm using object that are abstract and extend the resource class, thus the "entity" that needs it store a simple pointer...
---------------------------------------http://badfoolprototype.blogspot.com/
someboddy
someboddy
That's your decision. If resource objects are never deleted, and only the resource's data itself is unloaded and reloaded each time, or if the entity that uses the resource will be deleted before the deletion of the resource, I see no reason why not to use pointers. Sure, handles have the advantage that you can store them in files(as long as they are not dynamic), but you can always convert between handles and pointers when you read/write your objects to/from files.
-----------------------------------------Everyboddy need someboddy!
TriggerB
TriggerB
My resource manager retrieves resources from the pertinent resource groups defined in an XML file(for example, Level 1, Main Menu, etc.) Then, individual objects can obtain pointers to whatever particular resources that they need, a texture for example, but the resources are still held by the manager. Classes that represent the particular resources may or may not be necessary depending on implementation. I am using SDL and sprite sheets, so I have a texture struct implemented as:

struct Texture{	SDL_Rect srcRect; //where to blit from srcSurface.	SDL_Surface* srcSurface;};


I wrote about loading textures specifically here
JorenJoestar
JorenJoestar
@someboddy
Thanks guy, I'm up with my decision. Using pointers it is my choice.


@TriggerB
I've read your post (and commented the one on gamestates), thanks!


I want to create only ONE resource manager, that can handle different types of resources and have different "assets". My first implementation will contain code specialized for every type of resources, waiting for a better solution.
Unfortunately c++ doesn't have generics :(
---------------------------------------http://badfoolprototype.blogspot.com/
Matt328
Matt328
Quote:
Unfortunately c++ doesn't have generics :(
If you mean generics as in Java then sure it does, they're just called templates.
tonyg
tonyg
Does this help any?

[Edited by - tonyg on January 12, 2009 6:11:12 AM]
JorenJoestar
JorenJoestar
Yes I know, but using I cannot figure out how to use them to achieve the architecture I have in my mind! :P
---------------------------------------http://badfoolprototype.blogspot.com/
Dae
Dae
Quote:
Original post by JorenJoestar
Yes I know, but using I cannot figure out how to use them to achieve the architecture I have in my mind! :P


Well, a resource is just a data stored in a file (loaded local or web or database, etc). So call a function with the path location (string). Then based on the type of file parse it in different ways. eg. parse bmp, parse md2, parse mp3, parse jpeg, etc. C++ doesn't have to be generic to accomplish this - you could use a conditional statement,

load("cool.mp3", "mp3")IResource load(filename, type){  data = file.open(filename)  if(type == "mp3")    return MP3Sound(data);  else    return GenericData(data); //wouldnt usually do anything, just ex}class IResource {}class MP3Sound : IResource { // parse data }


That's a resource factory.

or load("cool.mp3", MP3) and #define MP3 = 1
or mp3 = MP3Sound(); mp3->Initialize(data) and add to IResource/children
or load("cool.mp3") and then templateT load(filename) return T(data)

That's a generic resource manager (refer to iliak's post).
010001000110000101100101
iliak
iliak

Here's an example. My main resource manager is a public static class.

/// <summary>/// Resource manager/// </summary>static public class ResourceManager{	#region Providers	/// <summary>	/// Adds a provider	/// </summary>	/// <param name="provider">The provider</param>	static public void AddProvider(Provider provider)	{		if (provider == null)			throw new ArgumentNullException("provider");		if (Providers.Contains(provider))			throw new ArgumentException("Provider already present", "provider");		// Adds the provider to the list		Providers.Add(provider);		// Register asset's tags		foreach (string tag in provider.Tags)			Tags.Add(tag, provider);		// Register assets		foreach (Type type in provider.Assets)			Assets.Add(type, provider);	}	/// <summary>	/// Returns a provider's instance	/// </summary>	/// <typeparam name="T">Type of the provider</typeparam>	/// <returns>Instance or null</returns>	static public T GetProvider<T>() where T : Provider	{		foreach (Provider provider in Providers)		{			if (provider is T)				return (T)(object)provider;		}		return default(T);	}	/// <summary>	/// Returns the provider of a tag	/// </summary>	/// <param name="tag">Xml tag</param>	/// <returns>Provider or null</returns>	static public Provider GetTagProvider(string tag)	{		if (string.IsNullOrEmpty(tag))			throw new ArgumentNullException("tag");		if (!Tags.ContainsKey(tag))			return null;		return Tags[tag];	}	/// <summary>	/// Returns the <see cref="Provider"/> of an asset	/// </summary>	/// <param name="type">asset type</param>	/// <returns>Provider of the asset or null</returns>	static public Provider GetAssetProvider(Type type)	{		if (type == null)			throw new ArgumentNullException("type");		if (Assets.ContainsKey(type))			return Assets[type];		return null;	}	/// <summary>	/// Removes a specific provider	/// </summary>	/// <param name="provider">Provider to remove</param>	static public void RemoveProvider(Provider provider)	{		if (provider == null)			throw new ArgumentNullException("provider");		// Remove tags		foreach (string tag in provider.Tags)			Tags.Remove(tag);		// Remove provider		Providers.Remove(provider);	}	#endregion	/// <summary>	/// Creates an asset	/// </summary>	/// <typeparam name="T">Type of the asset</typeparam>	/// <param name="name">ASset name</param>	/// <returns>The asset or null</returns>	static public T CreateAsset<T>(string name)	{		if (!Assets.ContainsKey(typeof(T)))			throw new ArgumentException("Unknown asset type");		return Assets[typeof(T)].Create<T>(name);	}	/// <summary>	/// Removes an asset	/// </summary>	/// <typeparam name="T">Asset type</typeparam>	/// <param name="name">Name of the asset</param>	static public void RemoveAsset<T>(string name)	{		if (!Assets.ContainsKey(typeof(T)))			throw new ArgumentException("Unknown asset type");		Assets[typeof(T)].Remove<T>(name);	}	/// <summary>	/// Returns an asset	/// </summary>	/// <typeparam name="T">Asset type</typeparam>	/// <returns>A list of available assets</returns>	static public List<string> GetAssets<T>()	{		if (!Assets.ContainsKey(typeof(T)))			throw new ArgumentException("Unknown asset type");		return Assets[typeof(T)].GetAssets<T>();	}	/// <summary>	/// Returns all assets of a type	/// </summary>	/// <typeparam name="T">Asset type</typeparam>	/// <returns>Assets</returns>	static public T GetAsset<T>(string name)	{		if (!Assets.ContainsKey(typeof(T)))			throw new ArgumentException("Unknown asset type");		return Assets[typeof(T)].Get<T>(name);	}	/// <summary>	/// Flush all unused assets	/// </summary>	static public void FlushAssets()	{		foreach (Provider provider in Providers)			provider.Flush();	}	/// <summary>	/// Flush a specified asset type	/// </summary>	/// <typeparam name="T"></typeparam>	static public void FlushAsset<T>()	{		Provider provider = GetAssetProvider(typeof(T));		if (provider == null)			return;		provider.Flush<T>();	}	/// <summary>	/// Removes all assets	/// </summary>	static public void ClearAssets()	{		foreach (Provider provider in Providers)			provider.Clear();	}	/// <summary>	/// Removes a specific asset	/// </summary>	/// <typeparam name="T"></typeparam>	static public void ClearAsset<T>()	{		Provider provider = GetAssetProvider(typeof(T));		if (provider == null)			return;		provider.Clear<T>();	}}


Provider interface. A provider "provides" specific assets. It need to be register in the resource manager via ResourceManager.AddProvider().

/// <summary>/// Provider interface /// </summary>public abstract class Provider{		#region Asset management		/// <summary>		/// Creates an asset		/// </summary>		/// <typeparam name="T">Asset type</typeparam>		/// <param name="name">Name of the asset</param>		/// <returns></returns>		public abstract T Create<T>(string name);		/// <summary>		/// Returns an asset		/// </summary>		/// <typeparam name="T">Type of the asset</typeparam>		/// <param name="name">Name of the asset</param>		/// <returns></returns>		public abstract T Get<T>(string name);		/// <summary>		/// Returns a list of available assets		/// </summary>		/// <typeparam name="T">Asset type</typeparam>		/// <returns>List of available assets</returns>		public abstract List<string> GetAssets<T>();		/// <summary>		/// Delete a specific asset		/// </summary>		/// <typeparam name="T"></typeparam>		public abstract void Remove<T>(string name);		/// <summary>		/// Flush unused assets		/// </summary>		/// <typeparam name="T"></typeparam>		public abstract void Flush<T>();		/// <summary>		/// Flush all unsued assets		/// </summary>		public abstract void Flush();		/// <summary>		/// Erases a specific asset type		/// </summary>		public abstract void Clear<T>();		/// <summary>		/// Erases all assets		/// </summary>		public abstract void Clear();		#endregion		/// <summary>		/// Checks if <paramref name="T"/> is a registred asset type, and <paramref name="name"/> is not null or empty		/// </summary>		/// <typeparam name="T">Type to check</typeparam>		/// <param name="name"><c>string</c> to check</param>		protected void CheckValue<T>(string name)		{			if (string.IsNullOrEmpty(name))				throw new ArgumentNullException("name");			foreach (Type type in Assets)			{				if (type == typeof(T))					return;			}			throw new ArgumentException("Unknown asset type", "T");		}		#region IO routines		/// <summary>		/// Saves assets to a xml file		/// </summary>		/// <returns></returns>		public abstract  bool Save(XmlWriter xml);		/// <summary>		/// Loads assets from a xml node		/// </summary>		public abstract bool Load(XmlNode xml);		#endregion		#region Properties		/// <summary>		/// Display name of the asset		/// </summary>		/// <remarks>This is also used in the bank file as the name of the directory asset</remarks>		public abstract string Name { get; }		/// <summary>		/// Handled XML tags		/// </summary>		public abstract string[] Tags { get; }		/// <summary>		/// Managed assets types		/// </summary>		public abstract Type[] Assets { get; }		#endregion	}



/// <summary>/// Tileset provider/// </summary>public class TileSetProvider : Provider{	/// <summary>	/// Constructor	/// </summary>	public TileSetProvider()	{		TileSets = new Dictionary<string, TileSet>();	}	#region IO routines	/// <summary>	/// Saves all scripts	/// </summary>	/// <returns></returns>	public override bool Save(XmlWriter xml)	{		foreach (TileSet tileset in TileSets.Values)			tileset.Save(xml);		return true;	}	/// <summary>	/// Loads a script	/// </summary>	/// <param name="xml"></param>	/// <returns></returns>	public override bool Load(XmlNode xml)	{		switch (xml.Name.ToLower())		{			case "tileset":			{				string name = xml.Attributes["name"].Value;				TileSet tileset = Create<TileSet>(name);				if (tileset != null)					tileset.Load(xml);			}			break;			default:			{			}			break;		}		return true;	}	#endregion	/// <summary>	/// Returns an array of all available Tilesets	/// </summary>	/// <returns>Script's name array</returns>	public override List<string> GetAssets<T>()	{		List<string> list = new List<string>();		foreach (string key in TileSets.Keys)		{			list.Add(key);		}		list.Sort();		return list;	}	/// <summary>	/// Creates a TileSet	/// </summary>	/// <typeparam name="T"></typeparam>	/// <param name="name"></param>	/// <returns></returns>	public override T Create<T>(string name)	{		CheckValue<T>(name);		if (TileSets.ContainsKey(name))			throw new ArgumentException("TileSet already exists", name);		// Creates a Texture		TileSet tileset = new TileSet(name);		TileSets.Add(name, tileset);		return (T)(object)tileset;	}	/// <summary>	/// Returns a <c>Script</c>	/// </summary>	/// <typeparam name="T">Type of the asset</typeparam>	/// <param name="name">Asset's name</param>	/// <returns></returns>	public override T Get<T>(string name)	{		CheckValue<T>(name);		if (!TileSets.ContainsKey(name))			return default(T);		return (T)(object)TileSets[name];	}	/// <summary>	/// Flush unused scripts	/// </summary>	/// <typeparam name="T"></typeparam>	public override void Flush<T>()	{	}	/// <summary>	/// Flush all unsused assets	/// </summary>	public override void Flush()	{	}	/// <summary>	/// Removes a script	/// </summary>	/// <typeparam name="T"></typeparam>	/// <param name="name"></param>	public override void Remove<T>(string name)	{	}	/// <summary>	/// Removes all assets	/// </summary>	public override void Clear()	{	}	/// <summary>	/// Removes all specific asset type	/// </summary>	public override void Clear<T>()	{	}	#region Progerties	/// <summary>	/// Name of the asset	/// </summary>	public override string Name	{		get		{			return "Tileset";		}	}	/// <summary>	/// Scripts	/// </summary>	Dictionary<string, TileSet> TileSets;	/// <summary>	/// Handled tags	/// </summary>	public override string[] Tags	{		get		{			return new string[] { "tileset" };		}	}	/// <summary>	/// Managed assets	/// </summary>	public override Type[] Assets	{		get		{			return new Type[] { typeof(TileSet) };		}	}	#endregion}


To get a "TileSet" asset named "tileset", here's an example :

	//  class TileSetPrivder is derived from Provider interface	ResourceManager.AddProvider(new TileSetProvider());	// Loads some datas	ResourceManager.LoadBank("data.bnk");		// Gets the tileset by its name	TileSet tiles = ResourceManager.GetAsset<TileSet>("tileset");
- Iliak -
[ ArcEngine: An open source .Net gaming framework ]
[ Dungeon Eye: An open source remake of Eye of the Beholder II ]
JorenJoestar
JorenJoestar
WOW!!!
This is EXACTLY what I intented. Now I have only to translate to c++ and templates! :D

thank you very much! :D
---------------------------------------http://badfoolprototype.blogspot.com/
JorenJoestar
JorenJoestar
Ok...I have to admit that templates are not my friends... :P
This is my HEAVLY simplified code:


template public class Provider {
public:
Type* get() { return new Type(); }

}; // class Provider


class Resource {
public:
}; // class Resource

class Texture : public Resource {
public:
}; // class Texture



class TextureProvider : public Provider {
public:
Texture* get() { return NULL; }
};

template < template class ProviderImpl >
class ResourceManager {
public:

ProviderImpl *provider;

template
T* get() { return new T(); }
};


Doing something like:

TextureProvider *prov;
ResourceManager resman;
Provider *ddd;
resman.provider = ddd;

produce an error in the last line.

Why?
---------------------------------------http://badfoolprototype.blogspot.com/

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.