Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualKaiserJohan

Posted 07 September 2012 - 05:12 AM

Hello,

In my engine I thought about passing around references internally between the different subsystems rather than pointers. I liked the idea because I wouldn't bother with checking for null-ptrs == less code, it looks clean and I don't have to bother about the subsystems lifetime as they are tied to the Engine object.

But, I realised early on, initialization of the subsystems might be tricky due to some subsystems depend on others. I singled out two systems (so far) the memory and logging, that are common to all the (again, so far) subsystems.
I put those into a private class "EngineCore", as they would be constructed first and destroyed last.

Each other subsystem might have reference to those two.

Below is what it looks like so far:

class Engine : EngineCore
		{
		public:
				Engine();
				~Engine();
				bool Init();
				bool Start();
				bool Stop();
				bool Destroy();
				bool isRunning();
				void Tick();
				/* Managers */
				EngineSettings& GetEngineSettings();
				IMemoryManager& GetMemoryManager();
				IRenderManager& GetRenderManager();
				IGameObjectManager& GetGameObjectManager();
				ILogManager& GetLogger();
				/* Factories */
				IThreadingFactory& GetThreadingFactory();

				#ifdef ANDROID
						static JNIEnv* mJNIEnv;
				#endif
		private:
				bool mRunning;
				bool mInitialized;
				EngineSettings mEngineSettings;
				/* Managers */
				RenderManagerImpl mRenderManager;
				GameObjectManagerImpl mGameObjectManager;
				/* Factories */
				ThreadingFactory mThreadingFactory;
		};


and

/*
		 * The most vital parts of the engine, the logging and the memory management,
		 * which must be initialied first and destroyed last.
		 */
		class EngineCore
		{
		public:
				EngineCore() { }
				~EngineCore() { }
		protected:
				LogManagerImpl mLog;
				MemoryManagerImpl mMemoryManager;
		};

so I can setup for example the ThreadingFactory (and in turn its members) for example like:

ThreadingFactory::ThreadingFactory(ILogManager& logger, IMemoryAllocator& memAllocator) : mMemoryAllocator(memAllocator), mLogger(logger),
                mCreatedThreads(memAllocator), mCreatedMutexes(memAllocator), mCreatedCondVars(memAllocator), mCreatedThreadPools(memAllocator)
		{
		}


Now I have not gotten very far, but when I realised I had to put a special case for the Memory manager and LoggingManager, I started to get a bad feeling that later down the road, some wierd coupling between two subsystems might happen and I wouldn't know if I could avoid it.

So my question is, is it a sound design solution/hack to put the two core-systems into an EngineCore, and will this design eventually bite me later down the road?

EDIT: Im pasting the stuff directly from google code and the code segments are wierdly formated... why is this?

#2KaiserJohan

Posted 07 September 2012 - 05:11 AM

Hello,

In my engine I thought about passing around references internally between the different subsystems rather than pointers. I liked the idea because I wouldn't bother with checking for null-ptrs == less code, it looks clean and I don't have to bother about the subsystems lifetime as they are tied to the Engine object.

But, I realised early on, initialization of the subsystems might be tricky due to some subsystems depend on others. I singled out two systems (so far) the memory and logging, that are common to all the (again, so far) subsystems.
I put those into a private class "EngineCore", as they would be constructed first and destroyed last.

Each other subsystem might have reference to those two.

Below is what it looks like so far:

class Engine : EngineCore
		{
		public:
				Engine();
				~Engine();
				bool Init();
				bool Start();
				bool Stop();
				bool Destroy();
				bool isRunning();
				void Tick();
				/* Managers */
				EngineSettings& GetEngineSettings();
				IMemoryManager& GetMemoryManager();
				IRenderManager& GetRenderManager();
				IGameObjectManager& GetGameObjectManager();
				ILogManager& GetLogger();
				/* Factories */
				IThreadingFactory& GetThreadingFactory();

				#ifdef ANDROID
						static JNIEnv* mJNIEnv;
				#endif
		private:
				bool mRunning;
				bool mInitialized;
				EngineSettings mEngineSettings;
				/* Managers */
				RenderManagerImpl mRenderManager;
				GameObjectManagerImpl mGameObjectManager;
				/* Factories */
				ThreadingFactory mThreadingFactory;
		};


and

/*
		 * The most vital parts of the engine, the logging and the memory management,
		 * which must be initialied first and destroyed last.
		 */
		class EngineCore
		{
		public:
				EngineCore() { }
				~EngineCore() { }
		protected:
				LogManagerImpl mLog;
				MemoryManagerImpl mMemoryManager;
		};

so I can setup for example the ThreadingFactory (and in turn its members) for example like:

ThreadingFactory::ThreadingFactory(ILogManager& logger, IMemoryAllocator& memAllocator) : mMemoryAllocator(memAllocator), mLogger(logger),
																				mCreatedThreads(memAllocator), mCreatedMutexes(memAllocator), mCreatedCondVars(memAllocator), mCreatedThreadPools(memAllocator)
		{
		}


Now I have not gotten very far, but when I realised I had to put a special case for the Memory manager and LoggingManager, I started to get a bad feeling that later down the road, some wierd coupling between two subsystems might happen and I wouldn't know if I could avoid it.

So my question is, is it a sound design solution/hack to put the two core-systems into an EngineCore, and will this design eventually bite me later down the road?

EDIT: Im pasting the stuff directly from google code and the code segments are wierdly formated... why is this?

#1KaiserJohan

Posted 07 September 2012 - 05:10 AM

Hello,

In my engine I thought about passing around references internally between the different subsystems rather than pointers. I liked the idea because I wouldn't bother with checking for null-ptrs == less code, it looks clean and I don't have to bother about the subsystems lifetime as they are tied to the Engine object.

But, I realised early on, initialization of the subsystems might be tricky due to some subsystems depend on others. I singled out two systems (so far) the memory and logging, that are common to all the (again, so far) subsystems.
I put those into a private class "EngineCore", as they would be constructed first and destroyed last.

Each other subsystem might have reference to those two.

Below is what it looks like so far:

class Engine : EngineCore
	    {
	    public:
			    Engine();
			    ~Engine();
			    bool Init();
			    bool Start();
			    bool Stop();
			    bool Destroy();
			    bool isRunning();
			    void Tick();
			    /* Managers */
			    EngineSettings& GetEngineSettings();
			    IMemoryManager& GetMemoryManager();
			    IRenderManager& GetRenderManager();
			    IGameObjectManager& GetGameObjectManager();
			    ILogManager& GetLogger();
			    /* Factories */
			    IThreadingFactory& GetThreadingFactory();

			    #ifdef ANDROID
					    static JNIEnv* mJNIEnv;
			    #endif
	    private:
			    bool mRunning;
			    bool mInitialized;
			    EngineSettings mEngineSettings;
			    /* Managers */
			    RenderManagerImpl mRenderManager;
			    GameObjectManagerImpl mGameObjectManager;
			    /* Factories */
			    ThreadingFactory mThreadingFactory;
	    };


and

/*
		 * The most vital parts of the engine, the logging and the memory management,
		 * which must be initialied first and destroyed last.
		 */
	    class EngineCore
	    {
	    public:
			    EngineCore() { }
			    ~EngineCore() { }
	    protected:
			    LogManagerImpl mLog;
			    MemoryManagerImpl mMemoryManager;
	    };

so I can setup for example the ThreadingFactory (and in turn its members) for example like:

ThreadingFactory::ThreadingFactory(ILogManager& logger, IMemoryAllocator& memAllocator) : mMemoryAllocator(memAllocator), mLogger(logger),
																			    mCreatedThreads(memAllocator), mCreatedMutexes(memAllocator), mCreatedCondVars(memAllocator), mCreatedThreadPools(memAllocator)
	    {
	    }


Now I have not gotten very far, but when I realised I had to put a special case for the Memory manager and LoggingManager, I started to get a bad feeling that later down the road, some wierd coupling between two subsystems might happen and I wouldn't know if I could avoid it.

So my question is, is it a sound design solution/hack to put the two core-systems into an EngineCore, and will this design eventually bite me later down the road?

PARTNERS