Nameless Engine
Loading...
Searching...
No Matches
ne::GameManager Class Reference

#include <GameManager.h>

Public Member Functions

 GameManager (const GameManager &)=delete
 
GameManageroperator= (const GameManager &)=delete
 
void setGarbageCollectorRunInterval (long long iGcRunIntervalInSec)
 
void queueGarbageCollection (bool bForce, const std::optional< std::function< void()> > &onFinished={})
 
void addDeferredTask (const std::function< void()> &task)
 
void addTaskToThreadPool (const std::function< void()> &task)
 
void createWorld (const std::function< void(const std::optional< Error > &)> &onCreated, size_t iWorldSize=Globals::getDefaultWorldSize())
 
void loadNodeTreeAsWorld (const std::function< void(const std::optional< Error > &)> &onLoaded, const std::filesystem::path &pathToNodeTree, size_t iWorldSize=Globals::getDefaultWorldSize())
 
sgc::GcPtr< NodegetWorldRootNode ()
 
float getWorldTimeInSeconds ()
 
size_t getWorldSize ()
 
size_t getTotalSpawnedNodeCount ()
 
size_t getCalledEveryFrameNodeCount ()
 
WindowgetWindow () const
 
GameInstancegetGameInstance () const
 
CameraManagergetCameraManager () const
 
float getTimeSincePrevFrameInSec () const
 
long long getGarbageCollectorRunIntervalInSec () const
 
bool isNodeSpawned (size_t iNodeId)
 
bool isBeingDestroyed () const
 

Static Public Member Functions

static GameManagerget ()
 

Private Member Functions

 GameManager (Window *pWindow)
 
std::optional< Errorinitialize (std::optional< RendererType > preferredRenderer)
 
void destroy ()
 
template<typename MyGameInstance >
requires std::derived_from<MyGameInstance, GameInstance>
void setGameInstance ()
 
void onGameStarted ()
 
void onBeforeNewFrame (float timeSincePrevCallInSec)
 
void onKeyboardInput (KeyboardKey key, KeyboardModifiers modifiers, bool bIsPressedDown)
 
void onMouseInput (MouseButton button, KeyboardModifiers modifiers, bool bIsPressedDown)
 
void onMouseMove (double xOffset, double yOffset)
 
void onMouseScrollMove (int iOffset)
 
void onWindowFocusChanged (bool bIsFocused) const
 
void onFramebufferSizeChanged (int iWidth, int iHeight) const
 
void onWindowClose () const
 
void onTickFinished ()
 
void runGarbageCollection (bool bForce=false)
 
void executeDeferredTasks ()
 
void triggerActionEvents (std::variant< KeyboardKey, MouseButton > key, KeyboardModifiers modifiers, bool bIsPressedDown)
 
void triggerAxisEvents (KeyboardKey key, KeyboardModifiers modifiers, bool bIsPressedDown)
 
void destroyAndCleanExistingWorld ()
 

Private Attributes

WindowpWindow
 
std::unique_ptr< GameInstancepGameInstance
 
std::pair< std::recursive_mutex, std::unique_ptr< World > > mtxWorld
 
std::unique_ptr< RendererpRenderer
 
std::unique_ptr< CameraManagerpCameraManager
 
ThreadPool threadPool
 
std::pair< std::recursive_mutex, std::queue< std::function< void()> > > mtxDeferredTasks
 
InputManager inputManager
 
std::chrono::steady_clock::time_point lastGcRunTime
 
float timeSincePrevFrameInSec = 0.0F
 
long long iGcRunIntervalInSec = 120
 
std::thread::id mainThreadId
 
bool bShouldAcceptNewDeferredTasks = true
 
bool bIsInitialized = false
 
bool bIsBeingDestroyed = false
 

Static Private Attributes

static const char * sGcLeakReasons
 

Friends

class Window
 

Detailed Description

Controls main game objects: game instance, input manager, renderer, audio engine, physics engine and etc.

Remarks
Owned by Window object.

Constructor & Destructor Documentation

◆ GameManager()

ne::GameManager::GameManager ( Window pWindow)
private

Creates uninitialized GameManager.

Remarks
Use initialize to initialize the manager.
Parameters
pWindowWindow that owns this object.

Member Function Documentation

◆ addDeferredTask()

void ne::GameManager::addDeferredTask ( const std::function< void()> &  task)

Adds a function to be executed on the main thread next time onBeforeNewFrame is called.

Warning
Don't capture gc pointers in std::function, this is not supported and will cause memory leaks/crashes!
If you are using member functions/fields inside of the task you need to make sure that the owner object of these member functions/fields will not be deleted until this task is finished. If you use GameInstance or Node member functions/fields inside of the task and submitting a deferred tasks from the main thread then ignore this warning, they are safe to use in deferred tasks and will not be deleted until the task is finished. If you are submitting a deferred task that operates on a GameInstance/Node from a non main thread then you need to do a few additional checks inside of your deferred task, for example:
// We are on a non-main thread inside of a node:
addDeferredTask([this, iNodeId](){ // capturing `this` to use `Node` (self) functions, also
capturing self ID
// We are inside of a deferred task (on the main thread) and we don't know if the node (`this`)
// was garbage collected or not because we submitted our task from a non-main thread.
// REMEMBER: we can't capture `gc` pointers in `std::function`, this is not supported
// and will cause memory leaks/crashes!
const auto pGameManager = GameManager::get(); // using engine's private class `GameManager`
// `pGameManager` is guaranteed to be valid inside of a deferred task.
// Otherwise, if running this code outside of a deferred task you need to do 2 checks:
// if (pGameManager == nullptr) return;
// if (pGameManager->isBeingDestroyed()) return;
if (!pGameManager->isNodeSpawned(iNodeId)){
// Node was despawned and it may be dangerous to run the callback.
return;
}
// Can safely interact with `this` (self) - we are on the main thread.
});
static GameManager * get()
Definition: GameManager.cpp:305
void addDeferredTask(const std::function< void()> &task)
Definition: GameManager.cpp:576
Remarks
In the task you don't need to check if the game is being destroyed, the engine makes sure all tasks are finished before the game is destroyed.
Parameters
taskFunction to execute.

◆ addTaskToThreadPool()

void ne::GameManager::addTaskToThreadPool ( const std::function< void()> &  task)

Adds a function to be executed on the thread pool.

Warning
Don't capture gc pointers in std::function, this is not supported and will cause memory leaks/crashes!
If you are using a member functions/fields inside of the task you need to make sure that the owner object of these member functions/fields will not be deleted until this task is finished.
Remarks
In the task you don't need to check if the game is being destroyed, the engine makes sure all tasks are finished before the game is destroyed.
Parameters
taskFunction to execute.

◆ createWorld()

void ne::GameManager::createWorld ( const std::function< void(const std::optional< Error > &)> &  onCreated,
size_t  iWorldSize = Globals::getDefaultWorldSize() 
)

Adds a deferred task (see addDeferredTask) to create a new world that contains only one node - root node.

Remarks
Causes GameInstance::onWorldLoaded to be called after the world is loaded.
Replaces the old world (if existed).
Engine will execute all deferred tasks before changing the world (before destroying all nodes), so even if deferred tasks queue looks like this: ... – create/load world task – call node's member function task – ..., on create/load world task the engine will finish all other tasks and only when deferred tasks queue is empty start to create/load world so you don't need to care about the order of deferred tasks.
Parameters
onCreatedCallback function that will be called on the main thread after the world is created. Contains optional error (if world creation failed) as the only argument. Use GameInstance member functions as callback functions for created worlds, because all nodes and other game objects will be destroyed while the world is changing.
iWorldSizeSize of the new world in game units. Must be power of 2 (128, 256, 512, 1024, 2048, etc.). World size needs to be specified for internal purposes such as Directional Light shadow map size. You don't need to care why we need this information, you only need to know that if you leave world bounds lighting or physics may be incorrect (the editor or engine will warn you if something is leaving world bounds, pay attention to the logs).

◆ destroy()

void ne::GameManager::destroy ( )
private

Contains destructor logic: runs GC for the last time, destroys game instance, etc.

Warning
Should be called from the main thread.
Remarks
Can be safely called multiple times (additional calls will be ignored).
Can be used to destroy the game without clearing the actual game pointer.

◆ destroyAndCleanExistingWorld()

void ne::GameManager::destroyAndCleanExistingWorld ( )
private

Destroys the current world (if exists) and runs GC to clean everything up.

Warning
This function should be called from the main thread. If this function is called outside of the main thread an error will be shown.

◆ executeDeferredTasks()

void ne::GameManager::executeDeferredTasks ( )
private

Executes all deferred tasks from mtxDeferredTasks.

◆ get()

GameManager * ne::GameManager::get ( )
static

Returns the last created game manager object.

Warning
Avoid using this getter, use only when there's no other good way to get game manager object.
As an addition to checking returned pointer for nullptr use isBeingDestroyed.
Returns
nullptr if no game manager object was created yet, otherwise pointer to game manager object.

◆ getCalledEveryFrameNodeCount()

size_t ne::GameManager::getCalledEveryFrameNodeCount ( )

Returns the current amount of spawned nodes that are marked as "should be called every frame".

Returns
Amount of spawned nodes that should be called every frame.

◆ getCameraManager()

CameraManager * ne::GameManager::getCameraManager ( ) const

Returns camera manager.

Returns
Do not delete this pointer. Camera manager.

◆ getGameInstance()

GameInstance * ne::GameManager::getGameInstance ( ) const

Returns game instance that this game is using (Game owns GameInstance).

Returns
Do not delete this pointer. Used game instance.

◆ getGarbageCollectorRunIntervalInSec()

long long ne::GameManager::getGarbageCollectorRunIntervalInSec ( ) const

Returns the current interval after which we need to run garbage collector again.

Returns
Interval in seconds.

◆ getTimeSincePrevFrameInSec()

float ne::GameManager::getTimeSincePrevFrameInSec ( ) const

Returns the last time value that was passed to onBeforeNewFrame function(s).

Returns
Delta time.

◆ getTotalSpawnedNodeCount()

size_t ne::GameManager::getTotalSpawnedNodeCount ( )

Returns total amount of currently spawned nodes.

Returns
Total nodes spawned right now.

◆ getWindow()

Window * ne::GameManager::getWindow ( ) const

Returns window that owns this object.

Returns
Do not delete this pointer. Window that owns this object.

◆ getWorldRootNode()

sgc::GcPtr< Node > ne::GameManager::getWorldRootNode ( )

Returns a pointer to world's root node.

Returns
nullptr if world is not created (see createWorld), otherwise world's root node.

◆ getWorldSize()

size_t ne::GameManager::getWorldSize ( )

Returns world size in game units.

Returns
World size.

◆ getWorldTimeInSeconds()

float ne::GameManager::getWorldTimeInSeconds ( )

Returns time since world creation (in seconds).

Returns
Zero if world is not created (see createWorld), otherwise time since world creation (in seconds).

◆ initialize()

std::optional< Error > ne::GameManager::initialize ( std::optional< RendererType >  preferredRenderer)
private

Initializes the manager.

Parameters
preferredRendererPreferred renderer to be used.
Returns
Error if something went wrong.

◆ isBeingDestroyed()

bool ne::GameManager::isBeingDestroyed ( ) const

Tells whether Game's destruction process was started or not.

Returns
Whether Game's destruction process was started or not.

◆ isNodeSpawned()

bool ne::GameManager::isNodeSpawned ( size_t  iNodeId)

Tells if a node with the specified ID is currently spawned or not.

Parameters
iNodeIdID of the node to check.
Returns
true if the node is spawned, false otherwise.

◆ loadNodeTreeAsWorld()

void ne::GameManager::loadNodeTreeAsWorld ( const std::function< void(const std::optional< Error > &)> &  onLoaded,
const std::filesystem::path &  pathToNodeTree,
size_t  iWorldSize = Globals::getDefaultWorldSize() 
)

Adds a deferred task (see addDeferredTask) to load and deserialize a node tree to be used as the new world.

Node tree's root node will be used as world's root node.

Remarks
Replaces the old world (if existed).
Engine will execute all deferred tasks before changing the world (before destroying all nodes), so even if deferred tasks queue looks like this: ... – create/load world task – call node's member function task – ..., on create/load world task the engine will finish all other tasks and only when deferred tasks queue is empty start to create/load world so you don't need to care about the order of deferred tasks.
Parameters
onLoadedCallback function that will be called on the main thread after the world is loaded. Contains optional error (if world loading failed) as the only argument. Use GameInstance member functions as callback functions for loaded worlds, because all nodes and other game objects will be destroyed while the world is changing.
pathToNodeTreePath to the file that contains a node tree to load, the ".toml" extension will be automatically added if not specified.
iWorldSizeSize of the world in game units. Must be power of 2 (128, 256, 512, 1024, 2048, etc.). World size needs to be specified for internal purposes such as Directional Light shadow map size. You don't need to care why we need this information, you only need to know that if you leave world bounds lighting or physics may be incorrect (the editor or engine will warn you if something is leaving world bounds, pay attention to the logs).

◆ onBeforeNewFrame()

void ne::GameManager::onBeforeNewFrame ( float  timeSincePrevCallInSec)
private

Called before a new frame is rendered.

Parameters
timeSincePrevCallInSecTime in seconds that has passed since the last call to this function.

◆ onFramebufferSizeChanged()

void ne::GameManager::onFramebufferSizeChanged ( int  iWidth,
int  iHeight 
) const
private

Called when the framebuffer size was changed.

Parameters
iWidthNew width of the framebuffer (in pixels).
iHeightNew height of the framebuffer (in pixels).

◆ onGameStarted()

void ne::GameManager::onGameStarted ( )
private

Called by owner Window to notify game instance about game being started (everything is set up).

Remarks
Expects game instance to exist.

◆ onKeyboardInput()

void ne::GameManager::onKeyboardInput ( KeyboardKey  key,
KeyboardModifiers  modifiers,
bool  bIsPressedDown 
)
private

Called when the window (that owns this object) receives keyboard input.

Parameters
keyKeyboard key.
modifiersKeyboard modifier keys.
bIsPressedDownWhether the key down event occurred or key up.

◆ onMouseInput()

void ne::GameManager::onMouseInput ( MouseButton  button,
KeyboardModifiers  modifiers,
bool  bIsPressedDown 
)
private

Called when the window (that owns this object) receives mouse input.

Parameters
buttonMouse button.
modifiersKeyboard modifier keys.
bIsPressedDownWhether the button down event occurred or button up.

◆ onMouseMove()

void ne::GameManager::onMouseMove ( double  xOffset,
double  yOffset 
)
private

Called when the window received mouse movement.

Parameters
xOffsetMouse X movement delta in pixels (plus if moved to the right, minus if moved to the left).
yOffsetMouse Y movement delta in pixels (plus if moved up, minus if moved down).

◆ onMouseScrollMove()

void ne::GameManager::onMouseScrollMove ( int  iOffset)
private

Called when the window receives mouse scroll movement.

Parameters
iOffsetMovement offset.

◆ onTickFinished()

void ne::GameManager::onTickFinished ( )
private

Called by the owner when a tick is fully finished.

Warning
This function should be called on the main thread.

◆ onWindowClose()

void ne::GameManager::onWindowClose ( ) const
private

Called when a window that owns this game instance was requested to close (no new frames will be rendered). Prefer to do your destructor logic here.

◆ onWindowFocusChanged()

void ne::GameManager::onWindowFocusChanged ( bool  bIsFocused) const
private

Called when the window focus was changed.

Parameters
bIsFocusedWhether the window has gained or lost the focus.

◆ queueGarbageCollection()

void ne::GameManager::queueGarbageCollection ( bool  bForce,
const std::optional< std::function< void()> > &  onFinished = {} 
)

Queues a request to run a garbage collection as a deferred task on the main thread using addDeferredTask.

Remarks
Typically you don't need to call this function as garbage collection is executed regularly (see setGarbageCollectorRunInterval) but you can still call it anyway.
Note that garbage collection will also be executed additionally in some special cases, such as when World is being destructed or some nodes are being detached and despawned.
Parameters
bForceForce run garbage collection even if the last garbage collection was run not so long ago.
onFinishedOptional callback that will be triggered on the main thread when garbage collection is finished (queued as addDeferredTask).

◆ runGarbageCollection()

void ne::GameManager::runGarbageCollection ( bool  bForce = false)
private

Runs garbage collection if enough time has passed since the last garbage collection (see setGarbageCollectorRunInterval).

Warning
This function should be called from the main thread. If this function is called outside of the main thread an error will be shown.
Parameters
bForceForce run garbage collection even if the last garbage collection was run not so long ago.

◆ setGameInstance()

template<typename MyGameInstance >
requires std::derived_from<MyGameInstance, GameInstance>
void ne::GameManager::setGameInstance ( )
inlineprivate

Set GameInstance derived class to react to user inputs, window events and etc.

◆ setGarbageCollectorRunInterval()

void ne::GameManager::setGarbageCollectorRunInterval ( long long  iGcRunIntervalInSec)

Modifies the interval after which we need to run garbage collector again. The current value can be retrieved using getGarbageCollectorRunIntervalInSec.

Remarks
Interval should be in range [30; 300] seconds (otherwise it will be clamped).
Note that garbage collection will also be executed additionally in some special cases, such as when World is being destructed or some nodes are being detached and despawned.
Parameters
iGcRunIntervalInSecInterval in seconds.

◆ triggerActionEvents()

void ne::GameManager::triggerActionEvents ( std::variant< KeyboardKey, MouseButton >  key,
KeyboardModifiers  modifiers,
bool  bIsPressedDown 
)
private

Triggers action events from keyboard/mouse input.

Parameters
keyKeyboard/mouse key.
modifiersKeyboard modifier keys.
bIsPressedDownWhether the key down event occurred or key up.

◆ triggerAxisEvents()

void ne::GameManager::triggerAxisEvents ( KeyboardKey  key,
KeyboardModifiers  modifiers,
bool  bIsPressedDown 
)
private

Triggers axis events from keyboard input.

Parameters
keyKeyboard key.
modifiersKeyboard modifier keys.
bIsPressedDownWhether the key down event occurred or key up.

Member Data Documentation

◆ bIsBeingDestroyed

bool ne::GameManager::bIsBeingDestroyed = false
private

Whether destroy was called or not.

◆ bIsInitialized

bool ne::GameManager::bIsInitialized = false
private

Whether initialize was called or not.

◆ bShouldAcceptNewDeferredTasks

bool ne::GameManager::bShouldAcceptNewDeferredTasks = true
private

Whether addDeferredTask should accept new tasks or not.

◆ iGcRunIntervalInSec

long long ne::GameManager::iGcRunIntervalInSec = 120
private

Interval in seconds after which we need to run garbage collector again.

◆ inputManager

InputManager ne::GameManager::inputManager
private

Binds action/axis names with input keys.

◆ lastGcRunTime

std::chrono::steady_clock::time_point ne::GameManager::lastGcRunTime
private

Last time we run garbage collector.

◆ mainThreadId

std::thread::id ne::GameManager::mainThreadId
private

ID of the main thread.

◆ mtxDeferredTasks

std::pair<std::recursive_mutex, std::queue<std::function<void()> > > ne::GameManager::mtxDeferredTasks
private

Mutex for read/write operations on deferred tasks queue. Queue of functions to call on the main thread before each frame is rendered.

◆ mtxWorld

std::pair<std::recursive_mutex, std::unique_ptr<World> > ne::GameManager::mtxWorld
private

Game world, stores world's node tree.

◆ pCameraManager

std::unique_ptr<CameraManager> ne::GameManager::pCameraManager
private

Determines what camera is used as in-game eyes.

◆ pGameInstance

std::unique_ptr<GameInstance> ne::GameManager::pGameInstance
private

Reacts to user input, window events and etc.

◆ pRenderer

std::unique_ptr<Renderer> ne::GameManager::pRenderer
private

Draws graphics on window.

◆ pWindow

Window* ne::GameManager::pWindow
private

Do not delete this pointer. Window-owner of this Game.

◆ sGcLeakReasons

const char* ne::GameManager::sGcLeakReasons
inlinestaticprivate
Initial value:
=
"- you are switching a world but your game instance holds some non-nullptr gc pointers,\n"
"- you are not using STL container wrappers for gc "
"pointers (for example, you need to use `sgc::GcVector<sgc::GcPtr<T>>` instead of "
"`std::vector<sgc::GcPtr<T>>`, and other `gc_*` containers when storing gc pointers),\n"
"- you are capturing `sgc::GcPtr` pointer(s) in `std::function` (this might leak in some "
"special),\n"
"- for a more detailed list of possible issues see the \"README\" file at "
"https://github.com/Flone-dnb/sgc"

Description of reasons why a leak may occur.

◆ threadPool

ThreadPool ne::GameManager::threadPool
private

Thread pool to execute tasks.

◆ timeSincePrevFrameInSec

float ne::GameManager::timeSincePrevFrameInSec = 0.0F
private

The last time value that was passed to onBeforeNewFrame.


The documentation for this class was generated from the following files: