catch ESC key/GameUI Created 7 years ago2016-11-30 14:23:23 UTC by Bacsu Bacsu

Created 7 years ago2016-11-30 14:23:23 UTC by Bacsu Bacsu

Posted 7 years ago2016-11-30 14:23:23 UTC Post #332494
Hey everyone,

Some time ago the source code of the goldsrc mod Natural Selection was released to public. It is a FPS with some RTS elements. One player (commander) has a top down view and is able to drop buildings and equipment. They will shown as ghostbuildings if they are predroped. Also it has a custom chat input.
The problem now is to catch the ESC key and prevent the GameUI to open if a ghostbuilding or the chatpanel is open.

what has been tried so far

using HUD_Key_Event at input.cpp:
its not possible to block the key there. The key only pass this function at the second time. First press, gameUI opens, key not shown there. Second press, GameUI close, key shown there with key up info.

update function member:
another idea was to update the function member to "cancelselect" which is bound to ESC key. Those only works if you type "cancelselect" at the console but not if you hit the ESC key.

idea

using interface "GameUI007":
It's kinda hard to find any documentation about interfaces and how to use them imo.
Created file IGameUI.h with the class. Created CGameUI class at the cdll_int.cpp and EXPOSE_SINGLE_INTERFACE(CGameUI, IGameUI, GAMEUI_INTERFACE_VERSION);

This isn't working atm.

questions

Is it worth to give the GameUI007 a try to get this work?
Does anyone has some information about how to use this GameUI007?


information about interface GameUI007
http://forums.steampowered.com/forums/showthread.php?t=1819505
https://github.com/FWGS/libvinterface/blob/master/Interface/IGameUI.h
Posted 7 years ago2016-12-03 15:52:58 UTC Post #332528
Sorry, didn't notice this thread before.
The GameUI007 interface is only retrieved from the GameUI library in "valve/cl_dlls/GameUI.ext".

This is the engine code for it (reverse engineered):
char szDllName[ 512 ];
snprintf(szDllName, sizeof( szDllName ), "valve/cl_dlls/gameui.so");
COM_FixSlashes(szDllName);
FS_GetLocalCopy(szDllName);
this->m_hStaticGameUIModule = Sys_LoadModule(szDllName);
CreateInterfaceFn gameUIFactory = Sys_GetFactory(this->m_hStaticGameUIModule);
this->m_FactoryList[this->m_iNumFactories] = gameUIFactory;
if ( gameUIFactory )
{
staticGameUIFuncs = (IGameUI *)gameUIFactory ("GameUI007", nullptr);
staticGameConsole = (IGameConsole *)gameUIFactory ("GameConsole003", nullptr);
staticCareerUI = (ICareerUI *)gameUIFactory ("CareerUI001", nullptr);
++this->m_iNumFactories;
}
You cannot override GameUI because it will always load from valve/cl_dlls, and it will always load the interface from that library.

I've created a new issue requesting that GameUI be open sourced so it can be overridden by mod developers: https://github.com/ValveSoftware/halflife/issues/1763

I don't expect a response from anybody.

One thing you can try - and this is an epic hack - is to try to overwrite the vtable for the class so it redirects calls to your own implementation, and then pass them through to the original afterwards. To do this, you'll need to implement the interface in a class with only virtual function implementations and no member variables, then memcpy an instance of the class over the instance you get from GameUI.

I did this in my prototype engine to redirect filesystem calls:
https://github.com/SamVanheer/PrototypeEngine/blob/de14c82fff407bfa99e0153df8c4ec8710974df7/src/engine/CEngine.cpp#L107
https://github.com/SamVanheer/PrototypeEngine/blob/de14c82fff407bfa99e0153df8c4ec8710974df7/src/engine/CFileSystemWrapper.h
https://github.com/SamVanheer/PrototypeEngine/blob/de14c82fff407bfa99e0153df8c4ec8710974df7/src/engine/CFileSystemWrapper.cpp

You'll need to create one instance to memcpy the original vtable from first, then memcpy yours in. Make sure all calls end up in the original eventually, because if GameUI's version calls its own methods using the vtable entry, it'll call yours instead. If it expects its own method to do something, this could cause crashes.

Also make sure you reverse this when the client shuts down so GameUI doesn't crash trying to call the client after it has unloaded.

Pseudo code:
//vtable points to original methods
CGameUIWrapper g_OriginalGameUI;

IGameUI* g_pGameUI = nullptr;

void RedirectGameUI()
{
g_pGameUI = (IGameUI *)gameUIFactory ("GameUI007", nullptr);

//sizeof( CGameUIWrapper ) is just the vtable pointer
memcpy( &g_OriginalGameUI, g_pGameUI, sizeof( g_OriginalGameUI ) );
CGameUIWrapper wrapper;
memcpy( g_pGameUI, &wrapper, sizeof( wrapper ) );
//g_pGameUI now calls CGameUIWrapper methods
}

void RestoreGameUI()
{
memcpy( g_pGameUI, &g_OriginalGameUI, sizeof( g_OriginalGameUI ) );
}
I can't guarantee that it'll work, it worked for me but my code completely overrides the original engine so there's no chance of code calling it beforehand.

It's your best chance at gaining control over the GameUI implementation without support from Valve.
You must be logged in to post a response.