Custom Resource Types - ClanLib Game SDK

#

## Custom Resource Types

Extending the resource management system to incorporate a new resource type can be tricky, but with a little guidance, it is fairly straight forward.

### Intoduction

For this tutorial we will be using a simple class called Object

    class Object
    {
    public:
    	Object();
    	Object(int x, int y);
    	int x;
    	int y;
    };

### Modifing the class

First you will need to add a constructor that will load from the resource management system and an instance of CL_Resource to store our resource information in.

    class Object
    {
    public:
    	Object();
    	Object(int x, int y);
    	Object(const std::string &resource_id, CL_ResourceManager *manager);
    	int x;
    	int y;

    private:
    	CL_Resource resource;
    };

### Creating your resourcedata class

Now, before we actually define our new constructor for Object, lets create our new CL_ResourceData derivative class that will actually do the loading. This class is also fairly simple; it needs a constructor that takes a CL_Resource and two functions: on_load() and on_unload(). These functions will be called by the resource manager when the resource is loaded and unloaded respectively.

    class CL_ResourceData_Object : public CL_ResourceData
    {
    public:
    	ResourceData_Object(CL_Resource &resource);
    	virtual ~ResourceData_Object();
    	Object &get_object();
    private:
    	void on_load();
    	void on_unload();
    	Object object;
    };

The constructor tells the resource to attach the data through this instance of CL_ResourceData. Later when you ask your resource manager to load the object it will call the on_load() function which actually reads in your data. Notice that the call to get_attribute takes two parameters in this instance. The first is obviously the variable name, but the second is the default value which is used when the attribute is not found.

    ResourceData_Object::ResourceData_Object(CL_Resource &resource)
    : CL_ResourceData(resource)
    {
    	resource.attach_data("object", this);
    }
    ResourceData_Object::on_load()
    {
    	CL_Resource resource = get_resource();
    	int x = atoi( (resource.get_element().get_attribute("x","50")).c_str() );
    	int y = atoi( (resource.get_element().get_attribute("y","75")).c_str() );

    	object.x = x;
    	object.y = y;
    }
    ResourceData_Object::on_unload()
    {
    	object = Object();
    }

### The callback function

In order for this to work, we have to create a custom callback function to load your new resource types. The callback function just looks to see if the new resource is of our custom type, and in that event creates a new instance of our resourcedata type.

    static void resource_added(CL_Resource &resource)
    {
    	std::string type = resource.get_type();

    	if (type == "object") new ResourceData_Object(resource);
    }

And then in your initialization routines just add a line like:

    CL_Slot slot_resource_added - CL_ResourceManager::sig_resource_added().connect(&resource_added);

### Adding object's constructor

Now just add that constructor for Object that we nearly forgot about. This function will just ask the our CL_ResourceManager for the instance of our object, then we tell it load it up. Then just get our our data from the resource, but if it returns no data then the name you specified is not of type Object. Then just get out your data however you like, a copy constuctor or overloaded = operator comes in real handy here.

    Object::Object(const std::string &resource_id, CL_ResourceManager *manager)
    {
    	resource = manager->get_resource(resource_id);
    	resource.load();

    	ResourceData_Object *data =
    		(ResourceData_Object *) resource.get_data("object");

    	if(!data)
    		throw CL_Error("Resource '" + resource_id + "' is not of type 'object'");

    	x = data->get_object().x;
    	y = data->get_object().y;

    	resource.unload();
    }

### Finale

The last thing to do is to call your resource. For a resource file looking like:

    <resources>
    	<object name="object01" x="20" y="20" />
    </resources>

Just create your object like this:

    Object *my_object = new Object("object01", new CL_ResourceManager("my_resourcefile.xml"));

Thats it!

### TODO:

- Explain how to use the resource manager's provider to load files.
- Explain how to make the resource manager cache objects.
Questions or comments, write to the ClanLib mailing list.