Introducing CryEngine 3 Event Listeners

In this article I will introduce you to event handling within CryEngine 3 and give a brief overview of the many listeners you can utilise within your project.

Learning the CryEngine code can be daunting at first. It’s large, non-trivial and complex. Approximately 220,000 lines of C++ are provided with the CryEngine FreeSDK, and much of that is densely packed  headers. A good first step is to purchase one or more of the books which introduce you to programming with the engine. I have personally read and can recommend:

Each of them has their strengths and weaknesses, and despite overlaps in some areas of content you should more than get your money’s worth from reading them. They’re a steal if you buy them for Kindle. For this article I will assume you have at least basic knowledge of CryEngine, and decent C++ skills.

Let’s get started!

One of the key design patterns you will see throughout the CryEngine SDK is the observer pattern. In this pattern one object maintains a list of dependant objects and is responsible for notifying them of changes in it’s state. Within CryEngine they are generally denoted as classes and structs whose name end in Listener e.g. IGameRulesKillListener.

Before writing any code you should become familiar, at least generally, with each of the listeners which are available. But first, let’s look at how you attach yourself to a subject class as a listening object.

Perhaps the first listener you might come across is IGameFrameworkListener. An IGameFrameworkListener is an object that listens for events from the framework. These are high level type events, such as when the game is saved or loaded, when a level ends or at the end of the update cycle. In order to start listening to these events you need to register yourself with the subject. Typically, this would be done during the init phase for your object.

First, you need to make sure your object inherits from IGameFrameworkListener, so add that to your listening class declaration. Next, add the pure virtual methods declared within the listener struct / class. In this case you would add a set of declarations similar to these:

// IGameFramework
virtual void OnPostUpdate (float fDeltaTime) {};
virtual void OnSaveGame (ISaveGame* pSaveGame) {};
virtual void OnLoadGame (ILoadGame* pLoadGame) {};
virtual void OnLevelEnd (const char* nextLevel) {};
virtual void OnActionEvent (const SActionEvent& event) {};
virtual void OnPreRender() {};

I’ve stubbed most of mine out for now with empty implementations. If you don’t do that be sure to add the definition of the functions into your cpp file or your compile will fail.

Then, somewhere in the code, most likely within the init routine, you will make a call to RegisterListener on the game framework e.g.

if(IGame *pGame = gEnv->pGame)
{
pGame->GetIGameFramework()->RegisterListener(this, "CFlowSaveGameNode", FRAMEWORKLISTENERPRIORITY_DEFAULT);
}

You will also need to add a piece of code to unregister the listener when you are unloaded e.g.

g_pGame->GetIGameFramework()->UnregisterListener(this);

Once that is all compiled and running you should be able to see your implementations of the virtual functions being called at the appropriate points in the code execution. Pretty easy so far! The hard part is knowing what interfaces CryTek have made available for you to listen with.

List of Known Observers

I’ve run Doxygen on the gamesdk code to get an idea of what is available. At this time roughly forty classes are declared as listeners.  I’ll give a brief summary of each of them below.

IBasicEventListener

Provides access to basic events, such as entering and leaving a menu, mouse clicks, or keyboard character input.

struct IBasicEventListener
{
 enum EAction
 {
 eA_Default,
 eA_None,
 eA_ActivateAndEat
 };
virtual ~IBasicEventListener();
 virtual EAction OnClose(HWND hWnd) = 0;
 virtual EAction OnMouseActivate(HWND hWnd) = 0;
 virtual EAction OnEnterSizeMove(HWND hWnd) = 0;
 virtual EAction OnExitSizeMove(HWND hWnd) = 0;
 virtual EAction OnEnterMenuLoop(HWND hWnd) = 0;
 virtual EAction OnExitMenuLoop(HWND hWnd) = 0;
 virtual EAction OnHotKey(HWND hWnd) = 0;
 virtual EAction OnSycChar(HWND hWnd) = 0;
 virtual EAction OnChar(HWND hWnd, WPARAM wParam) = 0;
 virtual EAction OnIMEChar(HWND hWnd) = 0;
 virtual EAction OnSysKeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam) = 0;
 virtual EAction OnSetCursor(HWND hWnd) = 0;
 virtual EAction OnMouseMove(HWND hWnd, LPARAM lParam) = 0;
 virtual EAction OnLeftButtonDown(HWND hWnd, LPARAM lParam) = 0;
 virtual EAction OnLeftButtonUp(HWND hWnd, LPARAM lParam) = 0;
 virtual EAction OnLeftButtonDoubleClick(HWND hWnd, LPARAM lParam) = 0;
 virtual EAction OnMouseWheel(HWND hWnd, LPARAM lParam, short WheelDelta) = 0;
 virtual EAction OnMove(HWND hWnd, LPARAM lParam) = 0;
 virtual EAction OnSize(HWND hWnd, LPARAM lParam) = 0;
 virtual EAction OnActivate(HWND hWnd, WPARAM wParam) = 0;
 virtual EAction OnSetFocus(HWND hWnd) = 0;
 virtual EAction OnKillFocus(HWND hWnd) = 0;
 virtual EAction OnWindowPositionChanged(HWND hWnd) = 0;
 virtual EAction OnWindowStyleChanged(HWND hWnd) = 0;
 virtual EAction OnInputLanguageChanged(HWND hWnd, WPARAM wParam, LPARAM lParam) = 0;
 virtual EAction OnSysCommand(HWND hWnd, WPARAM wParam) = 0;
};

IDataListener

This is utilised by patching and downloading objects. It provides a simple interface to inform you when a download completes or if it fails.

struct IDataListener
{
 virtual void DataDownloaded (CDownloadableResourcePtr inResource) = 0;
 virtual void DataFailedToDownload (CDownloadableResourcePtr inResource) = 0;
 virtual ~IDataListener ();
};

IDataPatcherListener

Used by the CDataPatchDownloader class.

struct IDataPatcherListener
{
 virtual void DataPatchAvailable () = 0;
 virtual void DataPatchNotAvailable () = 0;
 virtual ~IDataPatcherListener () {}
};

IEnvironmentalWeaponEventListener

Unknown at time of writing.

struct IEnvironmentalWeaponEventListener
{
 // Called when Rip anim is started
 virtual void OnRipStart () = 0;
// Called at the point within the rip action that the actual 'detach/Unroot' occurs
 virtual void OnRipDetach () = 0;
// Called at the end of the rip anim
 virtual void OnRipEnd () = 0;
virtual ~IEnvironmentalWeaponEventListener () {};
};

IFireModeListener

Only used within the CFireMode class.

struct IFireModeListener
{
 virtual ~IFireModeListener () {}
 virtual void OnFireModeDeleted () = 0;
 virtual void OnFireModeActivated (bool activated) = 0;
};

IGameLobbyEventListener

Used within the anti-cheat code.

class IGameLobbyEventListener
{
 public:
 virtual ~IGameLobbyEventListener () {}
virtual void InsertedUser (CryUserID userId, const char* userName) = 0;
 virtual void SessionChanged (const CrySessionHandle inOldSession, const CrySessionHandle inNewSession) = 0;
};

IGameRulesActorActionListener

Used by the game rules routines. Purpose is unknown at time of writing.

class IGameRulesActorActionListener
{
 public:
 virtual ~IGameRulesActorActionListener () {}
virtual void OnAction (const ActionId& actionId, int activationMode, float value) = 0;
};

IGameRulesClientConnectionListener

This notifies you of client connection events.

class IGameRulesClientConnectionListener
{
 public:
 virtual ~IGameRulesClientConnectionListener () {}
virtual void OnClientConnect (int channelId, bool isReset, EntityId playerId) = 0;
 virtual void OnClientDisconnect (int channelId, EntityId playerId) = 0;
 virtual void OnClientEnteredGame (int channelId, bool isReset, EntityId playerId) = 0;
 virtual void OnOwnClientEnteredGame () = 0;
};

IGameRulesClientScoreListener

Notification event for when a client scores.

class IGameRulesClientScoreListener
{
 public:
 virtual ~IGameRulesClientScoreListener () {}
virtual void ClientScoreEvent (EGameRulesScoreType type, int points, EXPReason inReason, int currentTeamScore) = 0;
};

IGameRulesKillListener

Notification of when an entity is killed.

class IGameRulesKillListener
{
 public:
 virtual ~IGameRulesKillListener () {}
virtual void OnEntityKilledEarly (const HitInfo& hitInfo) = 0;
 virtual void OnEntityKilled (const HitInfo& hitInfo) = 0;
};

IGameRulesModuleRMIListener

Purpose is unknown at time of writing.

class IGameRulesModuleRMIListener
{
 public:
 virtual ~IGameRulesModuleRMIListener () {}
virtual void OnSingleEntityRMI (CGameRules::SModuleRMIEntityParams params) = 0;
 virtual void OnDoubleEntityRMI (CGameRules::SModuleRMITwoEntityParams params) = 0;
 virtual void OnEntityWithTimeRMI (CGameRules::SModuleRMIEntityTimeParams params) = 0;
 virtual void OnSvClientActionRMI (CGameRules::SModuleRMISvClientActionParams params, EntityId fromEid) = 0;
};

IGameRulesPickupListener

Notification for entities picking up and dropping items.

class IGameRulesPickupListener
{
 public:
 virtual ~IGameRulesPickupListener () {}
virtual void OnItemPickedUp (EntityId itemId, EntityId actorId) = 0;
 virtual void OnItemDropped (EntityId itemId, EntityId actorId) = 0;
virtual void OnPickupEntityAttached (EntityId entityId, EntityId actorId) = 0;
 virtual void OnPickupEntityDetached (EntityId entityId, EntityId actorId, bool isOnRemove) = 0;
};

IGameRulesPlayerStatsListener

Purpose is unknown at time of writing.

class IGameRulesPlayerStatsListener
{
 public:
 virtual ~IGameRulesPlayerStatsListener () {}
virtual void ClPlayerStatsNetSerializeReadDeath (const SGameRulesPlayerStat* s, uint16 prevDeathsThisRound, uint8 prevFlags) = 0;
};

IGameRulesRevivedListener

It appears to be a notification of when an entity is revived.

class IGameRulesRevivedListener
 {
 public:
 virtual ~IGameRulesRevivedListener () {}
virtual void EntityRevived (EntityId entityId) = 0;
 };

IGameRulesRoundsListener

Used by the game rules code.

class IGameRulesRoundsListener
{
 public:
 virtual ~IGameRulesRoundsListener () {}
virtual void OnRoundStart () = 0;
 virtual void OnRoundEnd () = 0;
 virtual void OnSuddenDeath () = 0;
 virtual void ClRoundsNetSerializeReadState (int newState, int curState) = 0;
 virtual void OnRoundAboutToStart () = 0;
};

IGameRulesStateListener

Used by the game rules code.

class IGameRulesStateListener
{
 public:
 virtual ~IGameRulesStateListener () {}
 virtual void OnIntroStart () = 0;
 virtual void OnGameStart () = 0;
 virtual void OnGameEnd () = 0;
 virtual void OnStateEntered (IGameRulesStateModule::EGR_GameState newGameState) = 0;
};

IGameRulesSurvivorCountListener

Used by the game rules code.

class IGameRulesSurvivorCountListener
{
 public:
 virtual ~IGameRulesSurvivorCountListener () {}
virtual void SvSurvivorCountRefresh (int count, const EntityId survivors[], int numKills) = 0;
};

IGameRulesTeamChangedListener

Used by the game rules code.

class IGameRulesTeamChangedListener
{
 public:
 virtual ~IGameRulesTeamChangedListener () {}
virtual void OnChangedTeam (EntityId entityId, int oldTeamId, int newTeamId) = 0;
};

IHUDEventListener

This handles event notifications from the HUD.

struct IHUDEventListener
{
 virtual ~IHUDEventListener () {}
 virtual void OnHUDEvent (const SHUDEvent& event) = 0;
};

IMeleeCollisionHelperListener

This can be seen in class CPickAndThrowWeapon where it responds helps to calculate hits from a thrown weapon.

struct IMeleeCollisionHelperListener
{
 virtual ~IMeleeCollisionHelperListener () {}
virtual void OnSuccesfulHit (const ray_hit& hitResult) = 0;
 virtual void OnFailedHit () = 0;
};

IMPPathFollowingListener

Used by path finding managers for notification of when a path is completed.

struct IMPPathFollowingListener
{
 virtual void OnPathCompleted (EntityId attachedEntityId) = 0;
 virtual ~IMPPathFollowingListener () {};
};

IPatchPakManagerListener

Only known use is by the dedicated server to know permissions have changed and that it is time to quit.

class IPatchPakManagerListener
{
 public:
 virtual ~IPatchPakManagerListener () {}
virtual void UpdatedPermissionsNowAvailable () = 0;
};

IPlayerEventListener

Notification of actions undertaken by the player. This includes support for entering and exiting vehicles, switching between first and third person cameras, picking up, dropping and using items, death and stance changes, among others.

It also handles special moves for the player. Currently only jump and sprint are defined.

struct IPlayerEventListener
{
 enum ESpecialMove
 {
 eSM_Jump = 0,
 eSM_SpeedSprint,
 };
 virtual ~IPlayerEventListener () {}
 virtual void OnEnterVehicle (IActor* pActor, const char* strVehicleClassName, const char* strSeatName, bool bThirdPerson) {};
 virtual void OnExitVehicle (IActor* pActor) {};
 virtual void OnToggleThirdPerson (IActor* pActor, bool bThirdPerson) {};
 virtual void OnItemDropped (IActor* pActor, EntityId itemId) {};
 virtual void OnItemPickedUp (IActor* pActor, EntityId itemId) {};
 virtual void OnItemUsed (IActor* pActor, EntityId itemId) {};
 virtual void OnStanceChanged (IActor* pActor, EStance stance) {};
 virtual void OnSpecialMove (IActor* pActor, ESpecialMove move) {};
 virtual void OnDeath (IActor* pActor, bool bIsGod) {};
 virtual void OnObjectGrabbed (IActor* pActor, bool bIsGrab, EntityId objectId, bool bIsNPC, bool bIsTwoHanded) {};
 virtual void OnHealthChanged (IActor* pActor, float newHealth) {};
 virtual void OnRevive (IActor* pActor, bool bIsGod) {};
 virtual void OnSpectatorModeChanged (IActor* pActor, uint8 mode) {};
 virtual void OnPickedUpPickableAmmo (IActor* pActor, IEntityClass* pAmmoType, int count) {}
};

IPlayerProgressionEventListener

The OnEvent function listens for important game events such as EMP blasts, first blood kills and stealth kills. It is only used by the CPersistantStats class to keep a tally of these events.

struct IPlayerProgressionEventListener
{
 virtual ~IPlayerProgressionEventListener () {}
 virtual void OnEvent (EPPType type, bool skillKill, void* data) = 0;
};

IPlayerUpdateListener

Listener interface for player updates.

struct IPlayerUpdateListener
{
 virtual ~IPlayerUpdateListener () {}
 virtual void Update (float fFrameTime) = 0;
};

IPrivateGameListener

Used by the lobby manager for setting private games.

struct IPrivateGameListener
{
 virtual ~IPrivateGameListener () {}
 virtual void SetPrivateGame (const bool privateGame) = 0;
};

IProjectileListener

Here be dragons. The OnLaunch function is called whenever a projectile is launched. OnProjectilePhysicsPostStep has warnings about thread safety and doesn’t look like it is meant for external use.

struct IProjectileListener
{
 // NB: Must be physics-thread safe IF its called from the physics OnPostStep
 virtual void OnProjectilePhysicsPostStep (CProjectile* pProjectile, EventPhysPostStep* pEvent, int bPhysicsThread) {}
// Called from Main thread
 virtual void OnLaunch (CProjectile* pProjectile, const Vec3& pos, const Vec3& velocity) {}
protected:
 // Should never be called
 virtual ~IProjectileListener () {}
};

RecordingSystemListener

Purpose is unknown at time of writing.

class IRecordingSystemListener
{
public:
 virtual ~IRecordingSystemListener() {}
virtual void OnPlaybackRequested( const SPlaybackRequest& info ) {}
 virtual void OnPlaybackStarted( const SPlaybackInfo& info ) {}
 virtual void OnPlaybackEnd( const SPlaybackInfo& info ) {}
};

ISquadEventListener

Squad managment notifications.

class ISquadEventListener
{
 public:
 // Local squad events
 enum ESquadEventType
 {
 eSET_CreatedSquad,
 eSET_MigratedSquad,
 eSET_JoinedSquad,
 eSET_LeftSquad,
 };
public:
 virtual ~ISquadEventListener () {}
virtual void AddedSquaddie (CryUserID userId) = 0;
 virtual void RemovedSquaddie (CryUserID userId) = 0;
 virtual void UpdatedSquaddie (CryUserID userId) = 0;
 virtual void SquadLeaderChanged (CryUserID userId) = 0;
virtual void SquadEvent (ISquadEventListener::ESquadEventType eventType) = 0;
};

IUIControlSchemeListener

This appears to be a notification of when the user changes the game controls.

struct IUIControlSchemeListener
{
 virtual ~IUIControlSchemeListener() {};
 virtual bool OnControlSchemeChanged(const EControlScheme controlScheme) = 0;
};

SGameRulesListener

Notification of important game rule events.

struct SGameRulesListener
{
 virtual ~SGameRulesListener () {}
virtual void GameOver (EGameOverType localWinner, bool isClientSpectator) {}
 virtual void EnteredGame () {}
 virtual void EndGameNear (EntityId id) {}
 virtual void ClientEnteredGame (EntityId clientId) {}
 virtual void ClientDisconnect (EntityId clientId) {}
 virtual void OnActorDeath (CActor* pActor) {}
 virtual void SvOnTimeLimitExpired () {}
 virtual void ClTeamScoreFeedback (int teamId, int prevScore, int newScore) {}
void GetMemoryUsage (ICrySizer* pSizer) const {}
};

Final Thoughts

That’s just a brief description of each of the observer declarations I was able to find. Hopefully this will give you an idea of what sort of events you can subscribe to and how they are used within existing code. I encourage you to work your way through the source files, it’s currently the best documentation we have available.

Advertisements

17 thoughts on “Introducing CryEngine 3 Event Listeners

  1. Hello and thank you for this and your other work / documentation.
    This is realy great and so aprichiated i can`t say it enofe.
    Is there any chance you will be doing a white paper on RMI, aspects and NetSerialization?

    Thanks again.

    1. I tend to just blog on what I am working on at the time. I can’t really see RMI, aspects or NetSerialization coming up any time soon as I am not using any of them in the near future. I might however have a little more to say on integration shortly.

      Thanks in return! It’s always good to know someone appreciates the time it takes to write these things.

  2. thanks for this, it is difficult finding information on C++ with CryEngine. I am looking like you have mentioned to create a class which has the engine callback my methods when something happens, but I’m not sure if I’m missing something here – where do you register the listener? My plan was to create a class like myListeners::IGameFrameworkListener and define the virtual methods, I put the registration in the constructor. I then instantiated this class in the Game.cpp constructor. It doesn’t work, I get heaps of unrelated errors just from including the myListeners.h file. Your article seems to be clear, but obviously I missed something. Would appreciate any tips. Joe

    1. Hi Joe! You’re right about how hard it can be to find information on C++ and CryEngine; that’s why I am writing things up as I discover them. I actually covered listeners pretty thoroughly in a previous article which should help you out. There is also another article which introduces all the event listener classes I could find in the code.

      In short, select a class that you want to listen for events and have it implement the pure virtual methods that are defined e.g. IGameFrameworkListener:

      // IGameFramework
      virtual void OnPostUpdate (float fDeltaTime) {};
      virtual void OnSaveGame (ISaveGame* pSaveGame) {};
      virtual void OnLoadGame (ILoadGame* pLoadGame) {};
      virtual void OnLevelEnd (const char* nextLevel) {};
      virtual void OnActionEvent (const SActionEvent& event) {};
      virtual void OnPreRender() {};

      You register the event listener in an init routine for that class e.g.

      // Listen for system events.
      gEnv->pGame->GetIGameFramework()->GetISystem()->GetISystemEventDispatcher()->RegisterListener (this);
      // Listen for game events.
      gEnv->pGame->GetIGameFramework()->RegisterListener (this, "ThirdPersonCamera", FRAMEWORKLISTENERPRIORITY_DEFAULT);

      Unregister it when you’re done.

      The third person camera plugin code has a fully working example of all this.

  3. Thanks for the quick reply. I got it yesterday and had a go, but still no luck. I will look into your code deeper – I know I’m missing something simple. I’ll be back, when I know what to ask, or I have the solution.
    Thanks

    Joe

  4. Ivan,
    I think the problem I have is “how do I register my class in the game?” for example when I create an Entity object I have to register the Entity in Gamefactory, surely I have to do something similar with this callback class. Simply extending the listener doesn’t notify the game that it should call my class on an event. My code compiles but I get no call back when I create breakpoints. My class is not called at all, I created breakpoints at the constructor, the init and all callback methods with no joy. All I want to see is the game hit my breakpoint.

    my Header looks like
    struct IPluginListener
    {
    virtual ~IPluginListener () {};
    virtual void Init () = 0;
    };

    struct CmyCallBacks :
    public ISystemEventListener,
    public IGameFrameworkListener,
    public IActionListener,
    public IPluginListener
    {
    public:
    CmyCallBacks(void);
    ~CmyCallBacks(void);

    // ISystemEventListener
    virtual void OnSystemEventAnyThread (ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam) {}
    virtual void OnSystemEvent (ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam);

    // IGameFrameworkListener
    virtual void OnPostUpdate (float fDeltaTime);
    virtual void OnSaveGame (ISaveGame* pSaveGame) {};
    virtual void OnLoadGame (ILoadGame* pLoadGame) {};
    virtual void OnLevelEnd (const char* nextLevel) {};
    virtual void OnActionEvent (const SActionEvent& event);
    virtual void OnPreRender () {};

    // IActionListener
    virtual void OnAction (const ActionId& action, int activationMode, float value);

    // IPluginListener
    virtual void Init ();

    };
    My init definition is identical to yours;
    void CmyCallBacks::Init ()
    {
    CRY_ASSERT (gEnv);
    CRY_ASSERT (gEnv->pGame);
    CRY_ASSERT (gEnv->pGame->GetIGameFramework ());
    CRY_ASSERT (gEnv->pGame->GetIGameFramework ()->GetISystem ());

    // Register Game Objects
    if (gEnv && gEnv->pGame && gEnv->pGame->GetIGameFramework ())
    {
    // Listen for system events.
    gEnv->pGame->GetIGameFramework ()->GetISystem ()->GetISystemEventDispatcher ()->RegisterListener (this);
    // Listen for game events.
    gEnv->pGame->GetIGameFramework ()->RegisterListener (this, "myCallBack", FRAMEWORKLISTENERPRIORITY_DEFAULT);

    }

    }

    I am testing by using editor and entering game mode in cryengine.

    1. This is it. I added this code to an existing entity and loaded the entity into the game as per normal and now it works.

      My workaround is to create a single invisible entity – as I would an AI character or any other item, and extend the listener class I want. Place one of this type of object into the scene then presto.

      Thanks you starting the conversation for this on the Net. Yours is the only page relating to cryengine callbacks outside of the docgen type pages.

      Joe

      1. You’re welcome! Glad to see it’s of use to someone else. This seemed like quite an important topic and I couldn’t find any coverage so I wrote up a quick summary.

  5. The init function is responsible for “registering the class”. The RegisterListener (this) call is adding your object to a vector of objects to be called when an event is raised. You must make sure that your init routine is called in order for anything to happen. My sample code is in a DLL that is loaded by the PluginSDk which takes care of making a call to my Init () after loading it.

    You will have to make sure your init routine is called – perhaps when the game starts, your level is loaded, or whenever is appropriate. Something that you provide needs to take care of instantiating your object and making that call to Init (), after that, it will start to receive all the event messages.

    GameStartup.cpp is a good place to start looking for where to place this Init () call. Try adding your initialisation at the end of CGameStartup::Init, after all the other code in there.

    1. Thanks, I like your solution better. CGameStartup::Init is a little too early, since I am starting in the editor. Do you know the class which is called to initialise the level after load?

      Joe

  6. I think the cleanest method is to have a class that implements ISystemEventListener and to watch out for ESYSTEM_EVENT_GAME_INITor ESYSTEM_EVENT_GAME_POST_INIT events.

    Here’s the code from my plugin:

    	void CCameraHandler::OnSystemEvent (ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam)
    	{
    		switch (event)
    		{
    			case ESYSTEM_EVENT_GAME_POST_INIT:
    				RegisterCvars ();
    				RegisterActionMaps ();
    				break;
    
    			case ESYSTEM_EVENT_SHUTDOWN:
    				Shutdown ();
    				break;
    		}
    	}
    

    Inside the gamestartup just make sure the class that implements the ISystemEventListener gets added to the listeners by calling

    gEnv->pGame->GetIGameFramework ()->GetISystem ()->GetISystemEventDispatcher ()->RegisterListener (this);

    Then you are all set to handle any of the myriad game messages that will be sent. Have a look in ISystem.h and you can see all the tasty messages you can listen for. ESYSTEM_EVENT_LEVEL_LOAD_START is one you might be very interested in.

    1. I had noticed your implementation in your examples, but was thinking there must be an appropriate init method in which to load my class, but having played around a little with it am wondering why I can’t instantiate my class in some of the CryEngine Classes. I tried declaring it (using the exact same code) in the CGameRules class but for some reason the compiler is giving me some troubles (basically indicating that my class is undefined). Your implementation works fine so I won’t reinvent the wheel. Thanks

    2. It’s fine to listen for the system event, but where do you actually register to listen for those system events? This kind of passes the buck with respect to the “when to initialize” problem. You still have to hack at least part of your object’s initialization into some arbitrary part of the startup code–unless I’m missing something, which is very likely.

      1. This is already covered in the article. Classes with listener capabilities usually have a method called ‘RegisterListener’ which you call from your class, passing in the ‘this’ pointer. By implementing the interface and calling ‘RegisterListener’ you add yourself to a list of objects held by the object you are trying to listen to. Whenever an important event occurs, the observed class will run through it’s list of listeners and call an appropriate method e.g. ‘OnPostUpdate’.

        You don’t need to hack into the init cycle of the observed class at all. You can freely add and remove yourself at any time that is suitable for the observing class (your class).

  7. I appreciate your assistance with this. The next issue is now how do you figure out the call to register the listener? I’m interested in your thought process in how to figure this out, rather than the specific solution. I thought I’d branch out and try a few different callbacks, but can’t easily see how to register every listener you’ve listed. eg. I would like to try IGameRulesKillListener. I have found that the RegisterKillListener is in the GameRules class, but can’t identify how to call it.
    I tried this
    CGameRules* pGameRules = g_pGame->GetGameRules();
    pGameRules->RegisterKillListener(this);

    but I think the GameStartup::init is too early – unless you advise me differently I will go ahead and search for a Class which is only called after the gamerules are defined.

    Joe

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s