Saya telah memutuskan saya ingin menulis kelas ResourceManager / ResourceCache pusat untuk mesin game hobi saya, tetapi saya mengalami kesulitan merancang skema caching.
Idenya adalah bahwa ResourceManager memiliki target empuk untuk total memori yang digunakan oleh semua sumber daya game digabungkan. Kelas-kelas lain akan membuat objek sumber daya, yang akan berada dalam keadaan tidak diturunkan, dan meneruskannya ke ResourceManager. ResourceManager kemudian memutuskan kapan memuat / membongkar sumber daya yang diberikan, dengan mengingat batas lunaknya.
Ketika sumber daya dibutuhkan oleh kelas lain, permintaan dikirim ke ResourceManager untuknya, (baik menggunakan string id atau pengidentifikasi unik). Jika sumber daya dimuat, maka referensi baca-saja ke sumber daya diteruskan ke fungsi pemanggilan, (dibungkus dengan lemah_ptr dihitung direferensikan). Jika sumber daya tidak dimuat, maka manajer akan menandai objek yang akan dimuat pada kesempatan berikutnya, (biasanya di akhir menggambar bingkai).
Perhatikan bahwa, meskipun sistem saya melakukan penghitungan referensi, ia hanya menghitung ketika sumber daya sedang dibaca, (jadi penghitungan referensi mungkin 0, tetapi suatu entitas mungkin masih melacaknya).
Juga dimungkinkan untuk menandai sumber daya untuk memuat jauh sebelum penggunaan pertama. Berikut ini sedikit sketsa kelas yang saya gunakan:
typedef unsigned int ResourceId;
// Resource is an abstract data type.
class Resource
{
Resource();
virtual ~Resource();
virtual bool load() = 0;
virtual bool unload() = 0;
virtual size_t getSize() = 0; // Used in determining how much memory is
// being used.
bool isLoaded();
bool isMarkedForUnloading();
bool isMarkedForReload();
void reference();
void dereference();
};
// This template class works as a weak_ptr, takes as a parameter a sub-class
// of Resource. Note it only hands give a const reference to the Resource, as
// it is read only.
template <class T>
class ResourceGuard
{
public:
ResourceGuard(T *_resource): resource(_resource)
{
resource->reference();
}
virtual ~ResourceGuard() { resource->dereference();}
const T* operator*() const { return (resource); }
};
class ResourceManager
{
// Assume constructor / destructor stuff
public:
// Returns true if resource loaded successfully, or was already loaded.
bool loadResource(ResourceId uid);
// Returns true if the resource could be reloaded,(if it is being read
// it can't be reloaded until later).
bool reloadResource(ResourceId uid)
// Returns true if the resource could be unloaded,(if it is being read
// it can't be unloaded until later)
bool unloadResource(ResourceId uid);
// Add a resource, with it's named identifier.
ResourceId addResource(const char * name,Resource *resource);
// Get the uid of a resource. Returns 0 if it doesn't exist.
ResourceId getResourceId(const char * name);
// This is the call most likely to be used when a level is running,
// load/reload/unload might get called during level transitions.
template <class T>
ResourceGuard<T> &getResource(ResourceId resourceId)
{
// Calls a private method, pretend it exits
T *temp = dynamic_cast<T*> (_getResource(resourceId));
assert(temp != NULL);
return (ResourceGuard<T>(temp));
}
// Generally, this will automatically load/unload data, and is called
// once per frame. It's also where the caching scheme comes into play.
void update();
};
Masalahnya adalah, untuk menjaga agar total penggunaan data tetap berada di sekitar / di bawah batas lunak, manajer harus memiliki cara cerdas untuk menentukan objek mana yang dibongkar.
Saya sedang berpikir untuk menggunakan semacam sistem prioritas, (mis. Prioritas Sementara, Prioritas yang Sering Digunakan, Prioritas Permanen), dikombinasikan dengan waktu dereferensi terakhir, dan ukuran sumber daya, untuk menentukan kapan harus menghapusnya. Tapi saya tidak bisa memikirkan skema yang layak untuk digunakan, atau struktur data yang tepat diperlukan untuk mengelolanya dengan cepat.
Bisakah seseorang yang telah menerapkan sistem seperti ini memberikan gambaran tentang bagaimana mereka bekerja. Apakah ada pola desain yang jelas saya lewatkan? Apakah saya membuat ini terlalu rumit? Idealnya saya membutuhkan sistem yang efisien, dan sulit disalahgunakan. Ada ide?