Skip to content

Integration

RoqueDeicide edited this page Dec 17, 2014 · 2 revisions

Files and Folders

In order to properly integrate CryCIL into your project you will need at least one file: IMonoInterface.h; you can also use the file CryCilHeader.h which is not necessary, but, it's convenient. Both files are located within the repository in the MonoInterface folder. When you download them, make sure you use appropriate version, that is the same as the one you downloaded from Releases. Each release has a tag which you can use to get to the required code quickly.

You need to familiarize yourself with the folders that are used by CryCIL when loading managed code. There are two folders that are searched for assemblies: _\Bin32/64\Modules\CryCIL_ is searched for assemblies that are common for all games; \<Game folder>\Modules\CryCIL\ is searched for assemblies that are specific to the loaded game.

Code Setup

Common Actions

You will need to save one object of type HMODULE - this is basically a handle for the DLL that will link you project with CryCIL. You will need to shutdown CryCIL subsystems when your program is closing. This can be done by invoking the function MonoEnv->Shutdown() somewhere in the code that is responsible for program-wide cleanup.

In a standard CryEngine game the cleanup is done in ~CGameStartup(), so that is where you can invoke the function.

This is the code from sample Game code provided with EaaS SDK modified for CryCIL (monoInterfaceDll is a field defined at the very end of CGameStartup class that stores HMODULE):

CGameStartup::~CGameStartup()
{
    if (m_pMod)
    {
        m_pMod->Shutdown();
        m_pMod = 0;
    }

    if (m_modDll)
    {
        CryFreeLibrary(m_modDll);
        m_modDll = 0;
    }
    CryLogAlways("Released mod DLL.");
    // Shut down Mono Environment.
    if (this->monoInterfaceDll && MonoEnv)
    {
        MonoEnv->Shutdown();
        MonoEnv = nullptr;
    }
    CryLogAlways("Released MonoInterface DLL.");
    CGameStartupStatic::g_pGameStartup = NULL;

    ShutdownFramework();
}

With CryCilHeader.h

Code located within CryCilHeader.h takes care of a bunch of stuff, so after you include aforementioned header file there is basically one action that you will to do: trigger CryCIL initialization by invoking function InitializeCryCil that is defined in CryCilHeader.h.

In a standard CryEngine game the startup is done in CGameStartup::Init() function, so it is the best place for invocation:

IGameRef CGameStartup::Init(SSystemInitParams &startupParams)
{
    if (!InitFramework(startupParams))
    {
        return 0;
    }
    // Initialize listeners (optional).
    List<IMonoSystemEventListener *> listeners(10);

    add your listeners here.

    // Initialize CryCIL. Must be done after above if() operator.
    this->monoInterfaceDll = InitializeCryCIL(this->m_pFramework, nullptr or &listeners);
}

Without CryCilHeader.h

You will have to setup everything here:

You must define IMonoInterface *MonoEnv variable.

You need to load MonoInterface.dll into memory:

IGameRef CGameStartup::Init(SSystemInitParams &startupParams)
{
    if (!InitFramework(startupParams))
    {
        return 0;
    }
    // Load MonoInterface library. Store the value in the field (optional as you can use a variable).
    this->monoInterfaceDll = CryLoadLibrary(MONOINTERFACE_LIBRARY);
    // Check if the library was loaded.
    if (!this->monoInterfaceDll)
    {
        // Crash the game.
        CryFatalError("Unable to locate %s", MONOINTERFACE_LIBRARY);
    }
}

You need to get the pointer to the function that MonoInterface.dll exports that needs to be invoked to initialize CryCIL:

IGameRef CGameStartup::Init(SSystemInitParams &startupParams)
{
    if (!InitFramework(startupParams))
    {
        return 0;
    }
    // Load MonoInterface library. Store the value in the field (optional as you can use a variable).
    this->monoInterfaceDll = CryLoadLibrary(MONOINTERFACE_LIBRARY);
    // Check if the library was loaded.
    if (!this->monoInterfaceDll)
    {
        // Crash the game.
        CryFatalError("Unable to locate %s", MONOINTERFACE_LIBRARY);
    }
    // Get the address of the function.
    InitializeMonoInterface initFunc =
        (InitializeMonoInterface)CryGetProcAddress(monoInterfaceDll, MONO_INTERFACE_INIT);
    // Check the address.
    if (!initFunc)
    {
        CryFatalError("Could not locate %s function within %s.", MONO_INTERFACE_INIT, MONOINTERFACE_LIBRARY);
    }
}

Now here we have some options:

  1. We can setup a list of IMonoSystemEventListener *objects to pass to the initFunc.
  2. We can pass nullptr to initFunc, if we don't have any listeners.

Another set of options is about initializing MonoEnv. We defined it above, but we can't use it unless we initialize it.

  1. We can initialize it with the value that is returned by initFunc.
  2. We can setup a listener that initializes MonoEnv.

First option is simple, but creates problems for interops because you won't be able to use MonoEnv before it is fully initialized.

Second option is a bit more complicated but allows to initialize MonoEnv as it is being initialized, which may cause issues with any code that needs CryCIL to be initialized, but can be executed before that is done.

Sample code without listeners and with MonoEnv initialized with return value:

IGameRef CGameStartup::Init(SSystemInitParams &startupParams)
{
    if (!InitFramework(startupParams))
    {
        return 0;
    }
    // Load MonoInterface library. Store the value in the field (optional as you can use a variable).
    this->monoInterfaceDll = CryLoadLibrary(MONOINTERFACE_LIBRARY);
    // Check if the library was loaded.
    if (!this->monoInterfaceDll)
    {
        // Crash the game.
        CryFatalError("Unable to locate %s", MONOINTERFACE_LIBRARY);
    }
    // Get the address of the function.
    InitializeMonoInterface initFunc =
        (InitializeMonoInterface)CryGetProcAddress(monoInterfaceDll, MONO_INTERFACE_INIT);
    // Check the address.
    if (!initFunc)
    {
        CryFatalError("Could not locate %s function within %s.", MONO_INTERFACE_INIT, MONOINTERFACE_LIBRARY);
    }
    // Initialize CryCIL.
    MonoEnv = initFunc(this->m_pFramework, nullptr);
}

Sample code with listeners and with MonoEnv initialized by the listener:

IGameRef CGameStartup::Init(SSystemInitParams &startupParams)
{
    if (!InitFramework(startupParams))
    {
        return 0;
    }
    // Load MonoInterface library. Store the value in the field (optional as you can use a variable).
    this->monoInterfaceDll = CryLoadLibrary(MONOINTERFACE_LIBRARY);
    // Check if the library was loaded.
    if (!this->monoInterfaceDll)
    {
        // Crash the game.
        CryFatalError("Unable to locate %s", MONOINTERFACE_LIBRARY);
    }
    // Get the address of the function.
    InitializeMonoInterface initFunc =
        (InitializeMonoInterface)CryGetProcAddress(monoInterfaceDll, MONO_INTERFACE_INIT);
    // Check the address.
    if (!initFunc)
    {
        CryFatalError("Could not locate %s function within %s.", MONO_INTERFACE_INIT, MONOINTERFACE_LIBRARY);
    }
    // Initialize the list of listeners.
    List<IMonoSystemEventListener *> listeners(10);
    // Add listeners, we just gonna add one here.
    listeners.Add(new StartUpListener());
    // Initialize CryCIL.
    MonoEnv = initFunc(this->m_pFramework, &listeners);
}

The code for the listener that initializes MonoEnv:

struct StartUpListener : IMonoSystemEventListener
{
    virtual void SetInterface(IMonoInterface *handle)
    {
        // Initialize MonoEnv.
        MonoEnv = handle;
        // Unregister and delete this listener now since we don't need it anymore.
        MonoEnv->RemoveListener(this);
        delete this;
    }
    virtual void OnPreInitialization() {}
    virtual void OnRunTimeInitializing() {}
    virtual void OnRunTimeInitialized() {}
    virtual void OnCryamblyInitilizing() {}
    virtual void OnCompilationStarting() {}
    virtual void OnCompilationComplete(bool success) {}
    virtual List<int> *GetSubscribedStages() {}
    virtual void OnInitializationStage(int stageIndex) {}
    virtual void OnCryamblyInitilized() {}
    virtual void OnPostInitialization() {}
    virtual void Update() {}
    virtual void PostUpdate() {}
    virtual void Shutdown() {}
}