ToyMaker Game Engine 0.0.2
ToyMaker is a game engine developed and maintained by Zoheb Shujauddin.
Loading...
Searching...
No Matches
resource_database.hpp
Go to the documentation of this file.
1
16
22
23#ifndef TOYMAKERENGINE_RESOURCEDATABASE_H
24#define TOYMAKERENGINE_RESOURCEDATABASE_H
25
26#include <memory>
27#include <string>
28#include <map>
29#include <type_traits>
30
31#include <nlohmann/json.hpp>
32
33#include "../registrator.hpp"
34
35namespace ToyMaker {
36 class IResource;
37 class IResourceFactory;
39
40 class ResourceDatabase;
41 template <typename TResource> class ResourceFactory;
42 template <typename TResource> class Resource;
43 template <typename TResource, typename TMethod> class ResourceConstructor;
44
51 class IResource {
52 public:
57 virtual ~IResource()=default;
58
64 virtual std::string getResourceTypeName_() const=0;
65 protected:
66
71 IResource()=default;
72
78 template <typename TResource>
79 static void RegisterResource();
80 private:
81 };
82
89 public:
90
95 virtual ~IResourceFactory()=default;
96
103 virtual std::shared_ptr<IResource> createResource(const nlohmann::json& resourceDescription)=0;
104 protected:
105
110 std::map<std::string, std::unique_ptr<IResourceConstructor>> mFactoryMethods {};
111 private:
112 friend class ResourceDatabase;
113 };
114
121 public:
127 virtual std::string getResourceConstructorName_() const=0;
128
135 virtual std::shared_ptr<IResource> createResource(const nlohmann::json& methodParameters)=0;
136
141 virtual ~IResourceConstructor()=default;
142
143 protected:
144
150
157 template <typename TResource, typename TResourceConstructor>
158 static void RegisterResourceConstructor();
159 private:
160 friend class ResourceDatabase;
161 };
162
214 public:
221
229 template <typename TResource>
230 static std::shared_ptr<TResource> GetRegisteredResource(const std::string& resourceName);
231
239 template <typename TResource>
240 static std::shared_ptr<TResource> ConstructAnonymousResource(const nlohmann::json& resourceDescription);
241
249 static bool HasResourceDescription(const std::string& resourceName);
250
259 template <typename TResource>
260 static bool HasResource(const std::string& resourceName);
261
269 template <typename TResource>
270 void registerFactory (const std::string& factoryName, std::unique_ptr<IResourceFactory> pFactory);
271
281 template <typename TResource, typename TResourceConstructor>
282 void registerResourceConstructor (const std::string& resourceType, const std::string& methodName, std::unique_ptr<IResourceConstructor> pFactoryMethod);
283
293 static void AddResourceDescription (const nlohmann::json& resourceDescription);
294
295
296 private:
302 static void AssertResourceDescriptionValidity(const nlohmann::json& resourceDescription);
303
310 std::map<std::string, std::unique_ptr<IResourceFactory>> mFactories {};
311
316 std::map<std::string, std::weak_ptr<IResource>> mResources {};
317
322 std::map<std::string, nlohmann::json> mResourceDescriptions {};
323
328 ResourceDatabase() = default;
329 };
330
368 template <typename TDerived>
369 class Resource: public IResource {
370 public:
378 inline std::string getResourceTypeName_() const override { return TDerived::getResourceTypeName(); }
379
380 protected:
386 explicit Resource(int explicitlyInitializeMe) { (void)explicitlyInitializeMe/* prevent unused parameter warnings */; s_registrator.emptyFunc();/* Ensures that the registrator for this resource type is not optimized out (I think) */ }
387 private:
388
395 static void registerSelf();
396
406
407 friend class Registrator<Resource<TDerived>>;
408 };
409
418 template<typename TResource>
420 public:
424 ResourceFactory() { /* IMPORTANT: do not remove */ }
425 private:
433 std::shared_ptr<IResource> createResource(const nlohmann::json& resourceDescription) override;
434 };
435
470 template<typename TResource, typename TResourceFactoryMethod>
472 public:
480 inline std::string getResourceConstructorName_() const override { return TResourceFactoryMethod::getResourceConstructorName(); }
481
482 protected:
488 explicit ResourceConstructor(int explicitlyInitializeMe) {
489 (void)explicitlyInitializeMe; // prevent unused parameter warnings
490 s_registrator.emptyFunc(); // required to prevent this class' registrator object from being optimized away
491 }
492
493 private:
498 static void registerSelf();
499
508
509 friend class Registrator<ResourceConstructor<TResource, TResourceFactoryMethod>>;
510 friend class ResourceFactory<TResource>;
511 };
512
513 // ##########################################################################################
514 // FUNCTION DEFINITIONS
515 // ##########################################################################################
516
517 template <typename TResource>
518 std::shared_ptr<TResource> ResourceDatabase::GetRegisteredResource(const std::string& resourceName) {
519 ResourceDatabase& resourceDatabase { ResourceDatabase::GetInstance() };
520 std::shared_ptr<IResource> pResource { nullptr };
521
522 // Search known resources first and validate it against the requested type
523 std::map<std::string, nlohmann::json>::iterator resourceDescPair { resourceDatabase.mResourceDescriptions.find(resourceName) };
524 assert(
525 resourceDescPair != resourceDatabase.mResourceDescriptions.end()
526 && "No resource with this name was found amongst known resources"
527 );
528 assert(
529 resourceDescPair->second["type"].get<std::string>() == TResource::getResourceTypeName()
530 && "The type of resource requested does not match the type of resource as declared \
531 in its description"
532 );
533
534 // Look through resources currently in memory
535 {
536 std::map<std::string, std::weak_ptr<IResource>>::iterator resourcePair { resourceDatabase.mResources.find(resourceName) };
537 if(resourcePair != resourceDatabase.mResources.end()) {
538 // If a corresponding entry was found but the resource itself had already been moved
539 // out of memory, remove the entry
540 if(resourcePair->second.expired()) {
541 resourceDatabase.mResources.erase(resourcePair->first);
542
543 // We got lucky, and this resource is still in memory
544 } else {
545 pResource = resourcePair->second.lock();
546 }
547 }
548 }
549
550 // If we still haven't got an in-memory copy, construct this resource using its description,
551 // as registered in our resource description table
552 if(!pResource) {
553 pResource = std::static_pointer_cast<typename Resource<TResource>::IResource, TResource>(
555 );
556 resourceDatabase.mResources[resourceName] = std::weak_ptr<IResource>{ pResource };
557 }
558
559 // Finally, cast it down to the requested type and hand it over to whoever asked
560 //
561 // TODO: how can we prevent unwanted modification of the resource by one of its
562 // users?
563 return std::static_pointer_cast<TResource>(std::static_pointer_cast<Resource<TResource>>(pResource));
564 }
565
566 template<typename TResource>
567 std::shared_ptr<TResource> ResourceDatabase::ConstructAnonymousResource(const nlohmann::json& resourceDescription) {
568 ResourceDatabase& resourceDatabase { ResourceDatabase::GetInstance() };
569 std::shared_ptr<IResource> pResource { nullptr };
570
571 AssertResourceDescriptionValidity(resourceDescription);
572
573 // Construct this resource using its description
574 pResource = resourceDatabase
575 .mFactories.at(resourceDescription.at("type").get<std::string>())
576 ->createResource(resourceDescription);
577 assert(pResource && "Resource could not be constructed");
578
579 // Finally, cast it down to the requested type and hand it over to whoever asked
580 //
581 // TODO: how can we prevent unwanted modification of the resource by one of its
582 // users?
583 return std::static_pointer_cast<TResource>(std::static_pointer_cast<Resource<TResource>>(pResource));
584 }
585
586 template<typename TResource>
587 bool ResourceDatabase::HasResource(const std::string& resourceName) {
588 ResourceDatabase& resourceDatabase { GetInstance() };
589 bool descriptionPresent { HasResourceDescription(resourceName) };
590 bool typeMatched { false };
591 bool objectLoaded { false };
592 if(descriptionPresent){
593 typeMatched = (
594 TResource::getResourceTypeName()
595 == resourceDatabase.mResourceDescriptions.at(resourceName).at("type").get<std::string>()
596 );
597 objectLoaded = (
598 resourceDatabase.mResources.find(resourceName)
599 != resourceDatabase.mResources.end()
600 );
601 }
602 return (
603 descriptionPresent && typeMatched && objectLoaded
604 );
605 }
606
607 template <typename TResource>
608 std::shared_ptr<IResource> ResourceFactory<TResource>::createResource(const nlohmann::json& resourceDescription) {
609 return mFactoryMethods.at(resourceDescription["method"].get<std::string>())->createResource(
610 resourceDescription["parameters"].get<nlohmann::json>()
611 );
612 }
613
614 template <typename TDerived>
618
619 template <typename TResource, typename TResourceFactoryMethod>
621 // ensure that the associated factory is registered before methods are added to it
622 Registrator<Resource<TResource>>& resourceRegistrator { Registrator<Resource<TResource>>::getRegistrator() };
623 resourceRegistrator.emptyFunc();
624 // actually register this method now
626 }
627
628 template <typename TResource>
630 ResourceDatabase::GetInstance().registerFactory<TResource>(TResource::getResourceTypeName(), std::make_unique<ResourceFactory<TResource>>());
631 }
632
633 template <typename TResource, typename TResourceConstructor>
635 ResourceDatabase::GetInstance().registerResourceConstructor<TResource, TResourceConstructor>(TResource::getResourceTypeName(), TResourceConstructor::getResourceConstructorName(), std::make_unique<TResourceConstructor>());
636 }
637
638 template <typename TResource>
639 void ResourceDatabase::registerFactory(const std::string& factoryName, std::unique_ptr<IResourceFactory> pFactory) {
640 assert((std::is_base_of<IResource, TResource>::value) && "Resource must be subclass of IResource");
641 mFactories[factoryName] = std::move(pFactory);
642 }
643
644 template <typename TResource, typename TResourceConstructor>
645 void ResourceDatabase::registerResourceConstructor(const std::string& resourceType, const std::string& methodName, std::unique_ptr<IResourceConstructor> pFactoryMethod) {
646 assert((std::is_base_of<IResource, TResource>::value) && "Resource must be subclass of IResource");
647 assert((std::is_base_of<IResourceConstructor, TResourceConstructor>::value) && "Resource must be subclass of IResourceConstructor");
648 mFactories.at(resourceType)->mFactoryMethods[methodName] = std::move(pFactoryMethod);
649 }
650
651}
652
653#endif
A single way that a resource may be constructed.
Definition resource_database.hpp:120
IResourceConstructor()=default
Construct a new IResourceConstructor object.
static void RegisterResourceConstructor()
Registers this resource constructor against its respective ResourceFactory during static initializati...
Definition resource_database.hpp:634
virtual std::shared_ptr< IResource > createResource(const nlohmann::json &methodParameters)=0
Creates a resource object using the parameters specified in methodParameters.
virtual ~IResourceConstructor()=default
Destroys this resource constructor (when the application is terminated.).
virtual std::string getResourceConstructorName_() const =0
Get the Resource Constructor type string for this constructor.
A class that holds references to all constructors for a type of Resource object.
Definition resource_database.hpp:88
std::map< std::string, std::unique_ptr< IResourceConstructor > > mFactoryMethods
A list of constructors that may be used to create a Resource of this kind.
Definition resource_database.hpp:110
virtual ~IResourceFactory()=default
Destroy the IResourceFactory object.
virtual std::shared_ptr< IResource > createResource(const nlohmann::json &resourceDescription)=0
Creates a resource object of a specific type using its JSON resource description.
Base class of all Resource types.
Definition resource_database.hpp:51
static void RegisterResource()
Registers this resource as a Resource type with the ResourceDatabase.
Definition resource_database.hpp:629
IResource()=default
Construct a new IResource object.
virtual ~IResource()=default
Destroy the IResource object.
virtual std::string getResourceTypeName_() const =0
Get the Resource Type string for this resource.
Helper class for registering a class at program startup.
Definition registrator.hpp:64
An object representing one method for creating a resource of a given kind.
Definition resource_database.hpp:471
static void registerSelf()
A helper function that informs the ResourceDatabase that this constructor type exists.
Definition resource_database.hpp:620
std::string getResourceConstructorName_() const override
Gets the resource constructor type string of the constructor.
Definition resource_database.hpp:480
ResourceConstructor(int explicitlyInitializeMe)
Construct a new ResourceConstructor object.
Definition resource_database.hpp:488
static Registrator< ResourceConstructor< TResource, TResourceFactoryMethod > > s_registrator
A helper class responsible for calling this class' registerSelf() method at during the static initial...
Definition resource_database.hpp:505
A database of all Resource types available for this project, and the various ResourceConstructors res...
Definition resource_database.hpp:213
static ResourceDatabase & GetInstance()
Returns the sole instance of the ResourceDatabase used by this application.
Definition resource_database.cpp:72
static std::shared_ptr< TResource > ConstructAnonymousResource(const nlohmann::json &resourceDescription)
Constructs a fresh anonymous resource using a registered constructor according to its description in ...
Definition resource_database.hpp:567
std::map< std::string, std::weak_ptr< IResource > > mResources
References to all resources that have been loaded and are being held in memory.
Definition resource_database.hpp:316
void registerResourceConstructor(const std::string &resourceType, const std::string &methodName, std::unique_ptr< IResourceConstructor > pFactoryMethod)
Registers a particular ResourceConstructor for a Resource.
Definition resource_database.hpp:645
static bool HasResource(const std::string &resourceName)
Tests whether a particular resource has already been loaded into memory.
Definition resource_database.hpp:587
static void AssertResourceDescriptionValidity(const nlohmann::json &resourceDescription)
Asserts the correctness of a resource's description, per the Resource types and constructors known to...
Definition resource_database.cpp:7
ResourceDatabase()=default
Construct a new ResourceDatabase object.
std::map< std::string, nlohmann::json > mResourceDescriptions
A list of all Resources that are known to the database, including details of how they may be construc...
Definition resource_database.hpp:322
void registerFactory(const std::string &factoryName, std::unique_ptr< IResourceFactory > pFactory)
Registers a factory responsible for tracking valid ResourceConstructors for a particular type of Reso...
Definition resource_database.hpp:639
std::map< std::string, std::unique_ptr< IResourceFactory > > mFactories
Pointers to different factories, each responsible for the creation of different kinds of resources.
Definition resource_database.hpp:310
static std::shared_ptr< TResource > GetRegisteredResource(const std::string &resourceName)
Gets a reference to or constructs a Resource by name whose description has been stored in this Resour...
Definition resource_database.hpp:518
static bool HasResourceDescription(const std::string &resourceName)
Tests whether the description of a particular named resource exists in this project's ResourceDatabas...
Definition resource_database.cpp:66
static void AddResourceDescription(const nlohmann::json &resourceDescription)
Adds the description (name, constructor, related parameters) to the resource database.
Definition resource_database.cpp:43
Tracks pointers to all ResourceConstructors responsible for creating a resource of one type.
Definition resource_database.hpp:419
ResourceFactory()
Construct a new Resource Factory object.
Definition resource_database.hpp:424
std::shared_ptr< IResource > createResource(const nlohmann::json &resourceDescription) override
Create an object of type Resource, specifying its constructor and the constructor's parameters in JSO...
Definition resource_database.hpp:608
The base class for any type whose creation and storage should be managed by the ResourceDatabase.
Definition resource_database.hpp:369
std::string getResourceTypeName_() const override
Get the resource type string for this resource.
Definition resource_database.hpp:378
Resource(int explicitlyInitializeMe)
Construct a new resource object.
Definition resource_database.hpp:386
static Registrator< Resource< TDerived > > & s_registrator
A static variable to this classes Registrator.
Definition resource_database.hpp:405
static void registerSelf()
A helper function that actually performs the task of registering this class with the ResourceDatabase...
Definition resource_database.hpp:615
Namespace containing all class definitions and functions related to the ToyMaker engine.
Definition application.hpp:25
Contains the definition for the Registrator<T> utility class, used anywhere that automatic registrati...