Thread: Is this a good resource manager?

  1. #1
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607

    Is this a good resource manager?

    This is the resource manager architecture that my game engine uses. The only other type I could think of was the templated sort that Shamino suggested. The problem there is that each resource is constructed differently and so you cannot create a virtual function for creation because you have no idea what parameters, if any, the resource will need.

    What I like about this system is that you can easily construct any type of resource you want and as long as it is derived from the base resource class it will work fine.

    To cleanup the entire system all you have to do is delete the derived resource manager class. So essentially in a game you would call this in the ShutDown() or Cleanup() function for the engine. This would then iterate the huge vector in the main manager class and properly cleanup the resources.

    The Add() function returns the index of the object in the vector so that it can be accessed later. Lightweight wrappers can then be created for each object type. These wrappers would be to simply remember the indices for each different object type. So a CTextureMgr would have a vector that contained all of the indices into the main vector for all CTexture objects.

    So if your master vector looked like this:

    0 - CTexture
    1 - CD3DXMesh
    2 - CDXSoundSegment
    3 - CD3DXMesh
    4 - CTexture
    ...

    The various object manager vectors would look like this:

    CTexMgr - 0,4
    CD3DXMeshMgr - 1,3
    CDXSoundSegmentMgr - 2

    Here is some code to illustrate the basic system:

    Code:
    // ResMgrTest.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <vector>
    #include <conio.h>
    
    class BaseResource
    {
      public:
        BaseResource() { printf("Creating BaseResource\n"); }
          
        virtual ~BaseResource()
        {
          printf("Destroying BaseResource\n\n");
        }
    };
    
    class DerivedResource:public BaseResource
    {
      public:
        DerivedResource() {printf("Creating DerivedResource\n"); }
        
        virtual ~DerivedResource()
        {
          printf("Destroying DerivedResource\n");
        }
        
    };
    
    class DerivedResource2:public BaseResource
    {
      public:
        DerivedResource2() {printf("Creating DerivedResource2\n"); }
        
        virtual ~DerivedResource2()
        {
          printf("Destroying DerivedResource2\n");
        }
    };
      
    class DerivedResource3:public BaseResource
    {
      public:
        DerivedResource3() {printf("Creating DerivedResource3\n"); }
        
        virtual ~DerivedResource3()
        {
          printf("Destroying DerivedResource3\n");
        }
    };
      
    class BaseMgr
    {
      protected:
        std::vector<BaseResource *> m_vResources;
      public:
        BaseMgr() {printf("Creating BaseMgr\n"); }
        
        virtual ~BaseMgr()
        {
          printf("Destroying BaseMgr\n\n");
          for (int i=0;i<m_vResources.size();i++)
          {
            delete m_vResources[i];
          }
        }
        
        void Add(BaseResource *pObj) 
        {
          printf("Adding resource to BaseMgr\n");
          
          m_vResources.push_back(pObj); 
        }
          
    };
    
    class DerivedMgr:public BaseMgr
    {
      public:
        DerivedMgr() {printf("Creating DerivedMgr\n"); }
    
        virtual ~DerivedMgr()
        {
          printf("Destroying DerivedMgr\n");
        }
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
      //Create the master manager class
      DerivedMgr *pMgr=new DerivedMgr();
      
      printf("\n");
      
      //Create 2 DerivedResource objects and add to master vector
      for (int i=0;i<2;i++)
      {
        DerivedResource *pRes=new DerivedResource();
      
        pMgr->Add(pRes);
        printf("\n");
      }
    	
      //Create 2 DerivedResource2 objects and add to master vector
      for (int i=0;i<2;i++)
      {
        DerivedResource2 *pRes2=new DerivedResource2();
      
        pMgr->Add(pRes2);
        printf("\n");
      }
    	
      //Create 2 DerivedResource3 objects and add to master vector
      for (int i=0;i<2;i++)
      {
        DerivedResource3 *pRes3=new DerivedResource3();
      
        pMgr->Add(pRes3);
        printf("\n");
      }
    	
       //Wait for a key
       printf("\n ** Press any key to shut down the resource system **\n\n"); 
       getch();
    	
       //Clean up the entire system
       delete pMgr;
    	
       //Wait for a key
       getch();
       return 0;
    }
    Comments? Criticisms? Suggestions?

    I'm about to fully implement this system to my game engine so I need some input from some of you that have tried to do resource management in your engines.
    Last edited by VirtualAce; 07-12-2007 at 01:44 AM.

  2. #2
    Registered User
    Join Date
    Apr 2006
    Posts
    43
    Returning an absolute index seems lika a bad idea since you basically make it impossible to delete any resource during the engines lifetime, you might want to toss out textures from the old level and load new ones for instance (without having to reinitialize all your other resources).

    It might be better with a (dumb or smart) pointer or small wrapper class instead.

    I'm not sure why you would want the same create-method for all different types of resources? Can you give us an example of how you were thinking of instantiate the resources?

  3. #3
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    And if you have deleted the resource why would you retain its index?


    This is the resource manager architecture that my game engine uses. The only other type I could think of was the templated sort that Shamino suggested. The problem there is that each resource is constructed differently and so you cannot create a virtual function for creation because you have no idea what parameters, if any, the resource will need.
    You cannot have the same create function for all objects because they differ too much. It would be nice since you could put this in the base class or in a template class but it just doesn't work out very well. Textures, sounds, and various objects all get created very differently and it's impossible to create a universal function for all of them. Unless of course you want your game code to look like one of those horrid Windows API functions that have about 20 parameters being passed to it. You did read my post didn't you?
    Last edited by VirtualAce; 07-12-2007 at 10:58 PM.

  4. #4
    Registered User
    Join Date
    Apr 2006
    Posts
    43
    Bubba, if you allocate resource 1, 2 and 3 and then delete resource 1, then your other two resources suddenly changes indices (at least according to your comment, the code doesn't seem to have any return value from Add...), so you can't delete just one resource and continue using the others in a well defined manner.
    The Add() function returns the index of the object in the vector so that it can be accessed later

    My other point is WHY would it be nice to have the instantiation in the base class, since all resources probably takes different parameters. I can't figure out a place in the code where you would have need of using the base class interface for doing the instantiation of different resources in a unified manner and was hoping you would give me an example of how you would use it.

    I did read your post, but I don't understand your reasoning, and I though that was what you wanted input on. Also, english is not my native language so I might be missing something, it has happened before =)

  5. #5
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    The only way in my game engine that resources will change is when another resource is destroyed. Since resource IDs are essentially ways to access resources it would not make sense to use a resource ID to access a resource that has been removed.

    So if resource ID 1 is a camera and you destroy the camera, why would you need to re-access the camera if you destroyed it?

    In essence this system is NOT designed for real-time insertion and deletion of elements. My main focus in the game is maintaining interactive framerates. We've all seen what happens when you attempt to cache out and cache in in real time games. You get pauses and other odd things while the resources are cached. I want to stay away from this as much as possible. If I deleted a resource at index 20 here is what I would have to do:

    Code:
    for (DWORD i=20;i<static_cast<DWORD>(m_vResources[i].size());i++)
    {
      m_vResources[i]->SetID(i);
    }
    This is extremely slow so I would want to avoid this as much as possible. Ideally I would like to have everything in memory for the current level or sector of space. Since this is a space simulation I believe I can get away with this. Of course a large FPS style game could not do this and would have to use a deque or perhaps a list or even a set or map. This would map unique ID's to objects and when you deleted the object it would not change the unique ID of the other objects. ID's would be assigned not based on index but on a random number generator (which I have the code for several).

    But in my space game I really do not need this type of support. I'll illustrate.


    1 space sector
    • Skysphere - 1 texture, 1 detail texture
    • Music - 3 or 4 selections of music played at random along with 1 or 2 battle mode selections
    • Sounds - explosions, lasers, engine, and various other HUD functions
    • Spaceships - 1 texture per different type. Some ships use the same textures.
    • Animations - mainly explosions, lasers, etc. Probably 3 to 4 frames per and only about 6 to 7 different animations per sector
    • Models - 1 model per ship type but multiple ships of the same type.
    • Planets - 2 textures, 1 model
    • Shaders - post process, bloom, and other types. Probably 4 in memory at all times.


    So you can see unless I have a lot of activity going on...and I mean a lot I should have no trouble with this setup. You could have 25 cargo ships all using the same model, same texture, etc....with 20 fighters using prob 2 to 3 diff models (1 texture per) firing 5000 lasers which may have 3 or 4 different types at any one time.

    All of these are very possible with a simple vector. So the idea is I will not be destroying objects at run-time unless it is absolutely necessary. If it does not work I can simply change the STL container type and make minor modifications to the add/remove functions and the system still works quite well.

    It's not good to dynamically load/unload a large number of objects/resources in any game at any time. The trick is shoving all you can into memory without overloading the system and/or running out of memory. Even in large outdoor type games or in GTA type games the trick is to re-use as many textures/models/animations as possible w/o the player knowing you are re-using them.

    EDIT:

    I thought long and hard about what you said concerning indexes and switched the container type to a map. Each resource now has a unique ID used to access the resource.
    Last edited by VirtualAce; 07-13-2007 at 03:11 AM.

  6. #6
    Registered User
    Join Date
    Apr 2006
    Posts
    43
    Yes, I know all of that =)

    But then basically what you want is just reference counting of all your resources so that they are released when you quit. No active "managing" of your resources exactly...(which I think of more as deciding what to load into main memory, what to dump to disk, what LOD to use, etc).
    You just want to load everything once and then never change them during runtime.

    ID for network transport can be a handled by a resource map as you said, most easily a global integer that's bumped up for each created object, no need for random number generation that you still would need to check for clashes.

    I'll try to get my previous point across once more, that your system, as it is now, CAN'T delete anything, not just performance wise...I think you understand what you're doing, just not reading what I write =)

    First, the code you showed for how to do deletion seems to be saying "i" for both the old and for the new ID, but I guess that's a typo?
    But, fixing this still doesn't solve the problem that all your old application references to IDs above 20 now will point to the wrong item.

    If camera is resource 1, player texture is resource 2 and shooting sound is resource 3, you can't delete resource 1 since that will cause resource 3 to be renumbered as 2 and then the player will get the shooting sound as a texture...You need a pointer or mapping scheme to make this work.

    As you wrote:
    If it does not work I can simply change the STL container type and make minor modifications to the add/remove functions and the system still works quite well.
    Jupp, but you will need to change it from returning an absolute index, then I'll be happy =)

    /f

  7. #7

    Join Date
    May 2005
    Posts
    1,042
    I am silly.
    Last edited by BobMcGee123; 07-14-2007 at 05:54 PM.
    I'm not immature, I'm refined in the opposite direction.

  8. #8
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Heh. Bob don't post when you are drunk.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Resource manager tree
    By VirtualAce in forum Game Programming
    Replies: 23
    Last Post: 09-07-2007, 10:27 PM
  2. Generic Resource Manager, 90% done! Boost enabled!
    By Shamino in forum C++ Programming
    Replies: 2
    Last Post: 02-20-2006, 07:37 PM
  3. VC++ 6 Menu resource question
    By Mecnels in forum Windows Programming
    Replies: 1
    Last Post: 04-22-2003, 12:04 PM
  4. Is it necessary to write a specific memory manager ?
    By Morglum in forum Game Programming
    Replies: 18
    Last Post: 07-01-2002, 01:41 PM
  5. any good resource site
    By kas2002 in forum C++ Programming
    Replies: 1
    Last Post: 06-04-2002, 05:38 PM