mirror of
https://github.com/dhewm/dhewm3.git
synced 2025-03-20 17:51:02 +00:00
idCommon::SetCallback() and GetAdditionalFunction() - for Mods
This is an ugly hack that allows both exporting additional functions (incl. methods via static function + void* userArg) to Game DLLs and setting callback functions from the Game DLL that the Engine will call, without breaking the Game API (again after this change). This is mostly meant for replacing ugly hacks with SourceHook and similar and mods (yes, this is still an ugly hack, but less ugly). See the huge comment in Common.h for more information. Right now the only thing implemented is a Callback for when images are reloaded (via reloadImages or vid_restart) - Ruiner needs that. Also increased GAME_API_VERSION to 9, because this breaks the A[PB]I (hopefully after the next release it won't be broken in the foreseeable future)
This commit is contained in:
parent
9e2b73bff6
commit
519cc68b0e
6 changed files with 212 additions and 1 deletions
|
@ -51,6 +51,8 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
#include "framework/Common.h"
|
||||
|
||||
#include "GameCallbacks_local.h"
|
||||
|
||||
#define MAX_PRINT_MSG_SIZE 4096
|
||||
#define MAX_WARNING_LIST 256
|
||||
|
||||
|
@ -162,6 +164,23 @@ public:
|
|||
virtual int ButtonState( int key );
|
||||
virtual int KeyState( int key );
|
||||
|
||||
// DG: hack to allow adding callbacks and exporting additional functions without breaking the game ABI
|
||||
// see Common.h for longer explanation...
|
||||
|
||||
// returns true if setting the callback was successful, else false
|
||||
// When a game DLL is unloaded the callbacks are automatically removed from the Engine
|
||||
// so you usually don't have to worry about that; but you can call this with cb = NULL
|
||||
// and userArg = NULL to remove a callback manually (e.g. if userArg refers to an object you deleted)
|
||||
virtual bool SetCallback(idCommon::CallbackType cbt, idCommon::FunctionPointer cb, void* userArg);
|
||||
|
||||
// returns true if that function is available in this version of dhewm3
|
||||
// *out_fnptr will be the function (you'll have to cast it probably)
|
||||
// *out_userArg will be an argument you have to pass to the function, if appropriate (else NULL)
|
||||
// NOTE: this doesn't do anything yet, but allows to add ugly mod-specific hacks without breaking the Game interface
|
||||
virtual bool GetAdditionalFunction(idCommon::FunctionType ft, idCommon::FunctionPointer* out_fnptr, void** out_userArg);
|
||||
|
||||
// DG end
|
||||
|
||||
void InitGame( void );
|
||||
void ShutdownGame( bool reloading );
|
||||
|
||||
|
@ -2688,6 +2707,8 @@ void idCommonLocal::UnloadGameDLL( void ) {
|
|||
gameEdit = NULL;
|
||||
|
||||
#endif
|
||||
|
||||
gameCallbacks.Reset(); // DG: these callbacks are invalid now because DLL has been unloaded
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3176,3 +3197,59 @@ void idCommonLocal::ShutdownGame( bool reloading ) {
|
|||
// shut down the file system
|
||||
fileSystem->Shutdown( reloading );
|
||||
}
|
||||
|
||||
// DG: below here are hacks to allow adding callbacks and exporting additional functions to the
|
||||
// Game DLL without breaking the ABI. See Common.h for longer explanation...
|
||||
|
||||
|
||||
// returns true if setting the callback was successful, else false
|
||||
// When a game DLL is unloaded the callbacks are automatically removed from the Engine
|
||||
// so you usually don't have to worry about that; but you can call this with cb = NULL
|
||||
// and userArg = NULL to remove a callback manually (e.g. if userArg refers to an object you deleted)
|
||||
bool idCommonLocal::SetCallback(idCommon::CallbackType cbt, idCommon::FunctionPointer cb, void* userArg)
|
||||
{
|
||||
switch(cbt)
|
||||
{
|
||||
case idCommon::CB_ReloadImages:
|
||||
gameCallbacks.reloadImagesCB = (idGameCallbacks::ReloadImagesCallback)cb;
|
||||
gameCallbacks.reloadImagesUserArg = userArg;
|
||||
return true;
|
||||
|
||||
default:
|
||||
Warning("Called idCommon::SetCallback() with unknown CallbackType %d!\n", cbt);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if that function is available in this version of dhewm3
|
||||
// *out_fnptr will be the function (you'll have to cast it probably)
|
||||
// *out_userArg will be an argument you have to pass to the function, if appropriate (else NULL)
|
||||
bool idCommonLocal::GetAdditionalFunction(idCommon::FunctionType ft, idCommon::FunctionPointer* out_fnptr, void** out_userArg)
|
||||
{
|
||||
if(out_userArg != NULL)
|
||||
*out_userArg = NULL;
|
||||
|
||||
if(out_fnptr == NULL)
|
||||
{
|
||||
Warning("Called idCommon::GetAdditionalFunction() with out_fnptr == NULL!\n");
|
||||
return false;
|
||||
}
|
||||
*out_fnptr = NULL;
|
||||
|
||||
// NOTE: this doesn't do anything yet, but allows to later add ugly mod-specific hacks without breaking the Game interface
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
idGameCallbacks gameCallbacks;
|
||||
|
||||
idGameCallbacks::idGameCallbacks()
|
||||
: reloadImagesCB(NULL), reloadImagesUserArg(NULL)
|
||||
{}
|
||||
|
||||
void idGameCallbacks::Reset()
|
||||
{
|
||||
reloadImagesCB = NULL;
|
||||
reloadImagesUserArg = NULL;
|
||||
}
|
||||
|
|
|
@ -211,6 +211,67 @@ public:
|
|||
|
||||
// Directly sample a keystate.
|
||||
virtual int KeyState( int key ) = 0;
|
||||
|
||||
/* Some Mods (like Ruiner and DarkMod when it still was a mod) used "SourceHook"
|
||||
* to override Doom3 Methods to call their own code before the original method
|
||||
* was executed.. this is super ugly and probably not super portable either.
|
||||
*
|
||||
* So let's offer something that's slightly less ugly: A function pointer based
|
||||
* interface to provide similar (but known!) hacks.
|
||||
* For example, Ruiner used SourceHook to intercept idCmdSystem::BufferCommandText()
|
||||
* and recreate some cooked rendering data in case reloadImages or vid_restart was executed.
|
||||
* Now, instead of doing ugly hacks with SourceHook, Ruiner can just call
|
||||
* common->SetCallback( idCommon::CB_ReloadImages,
|
||||
* (idCommon::FunctionPointer)functionToCall,
|
||||
* (void*)argForFunctionToCall );
|
||||
*
|
||||
* (the Mod needs to check if SetCallback() returned true; if it didn't the used version
|
||||
* of dhewm3 doesn't support the given CallBackType and the Mod must either error out
|
||||
* or handle the case that the callback doesn't work)
|
||||
*
|
||||
* Of course this means that for every new SourceHook hack a Mod (that's ported to dhewm3)
|
||||
* uses, a corresponding entry must be added to enum CallbackType and it must be handled,
|
||||
* which implies that the Mod will only properly work with the latest dhewm3 git code
|
||||
* or the next release..
|
||||
* I guess most mods don't need this hack though, so I think it's feasible.
|
||||
*
|
||||
* Note that this allows adding new types of callbacks without breaking the API and ABI
|
||||
* between dhewm3 and the Game DLLs; the alternative would be something like
|
||||
* idCommon::RegisterReloadImagesCallback(), and maybe other similar methods later, which
|
||||
* would break the ABI and API each time and all Mods would have to be adjusted, even if
|
||||
* they don't even need that functionality (because they never needed SourceHook or similar).
|
||||
*
|
||||
* Similar to SetCallback() I've also added GetAdditionalFunction() to get a function pointer
|
||||
* from dhewm3 that Mods can call (and that's not exported via the normal interface classes).
|
||||
* Right now GetAdditionalFunction() will always just return false and do nothing, but if
|
||||
* some Mod needs some specific function in the future, it could be implemented with
|
||||
* GetAdditionalFunction() - again without breaking the game API and ABI for all the other
|
||||
* Mods that don't need that function.
|
||||
*/
|
||||
|
||||
typedef void* (*FunctionPointer)(void*); // needs to be cast to/from real type!
|
||||
enum CallbackType {
|
||||
// called on reloadImages and vid_restart commands (before anything "real" happens)
|
||||
// expecting callback to be like void cb(void* userarg, const idCmdArgs& cmdArgs)
|
||||
// where cmdArgs contains the command+arguments that was called
|
||||
CB_ReloadImages = 1,
|
||||
};
|
||||
|
||||
// returns true if setting the callback was successful, else false
|
||||
// When a game DLL is unloaded the callbacks are automatically removed from the Engine
|
||||
// so you usually don't have to worry about that; but you can call this with cb = NULL
|
||||
// and userArg = NULL to remove a callback manually (e.g. if userArg refers to an object you deleted)
|
||||
virtual bool SetCallback(CallbackType cbt, FunctionPointer cb, void* userArg) = 0;
|
||||
|
||||
enum FunctionType {
|
||||
// None yet..
|
||||
};
|
||||
|
||||
// returns true if that function is available in this version of dhewm3
|
||||
// *out_fnptr will be the function (you'll have to cast it probably)
|
||||
// *out_userArg will be an argument you have to pass to the function, if appropriate (else NULL)
|
||||
// NOTE: this doesn't do anything yet, but allows to add ugly mod-specific hacks without breaking the Game interface
|
||||
virtual bool GetAdditionalFunction(FunctionType ft, FunctionPointer* out_fnptr, void** out_userArg) = 0;
|
||||
};
|
||||
|
||||
extern idCommon * common;
|
||||
|
|
|
@ -324,7 +324,7 @@ extern idGameEdit * gameEdit;
|
|||
===============================================================================
|
||||
*/
|
||||
|
||||
const int GAME_API_VERSION = 8;
|
||||
const int GAME_API_VERSION = 9;
|
||||
|
||||
typedef struct {
|
||||
|
||||
|
|
57
neo/framework/GameCallbacks_local.h
Normal file
57
neo/framework/GameCallbacks_local.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2018 Daniel Gibson
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// Implementation details for idCommon::SetCallback() and idCommon::GetAdditionalFunction()
|
||||
// Needed in different parts of the Engine (that are supposed to call the callbacks)
|
||||
// but *not* part of the Game API exported to Game DLLs.
|
||||
// Common.h (above idCommon::SetCallback()) has a lengthy explanation of what all this is good for..
|
||||
|
||||
#ifndef NEO_FRAMEWORK_GAMECALLBACKS_LOCAL_H_
|
||||
#define NEO_FRAMEWORK_GAMECALLBACKS_LOCAL_H_
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
struct idGameCallbacks {
|
||||
|
||||
typedef void (*ReloadImagesCallback)(void* userArg, const idCmdArgs &args);
|
||||
ReloadImagesCallback reloadImagesCB;
|
||||
void* reloadImagesUserArg;
|
||||
|
||||
|
||||
idGameCallbacks();
|
||||
|
||||
// called when Game DLL is unloaded (=> the registered callbacks become invalid)
|
||||
void Reset();
|
||||
|
||||
};
|
||||
|
||||
extern idGameCallbacks gameCallbacks;
|
||||
|
||||
|
||||
#endif /* NEO_FRAMEWORK_GAMECALLBACKS_LOCAL_H_ */
|
|
@ -33,6 +33,8 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
#include "renderer/Image.h"
|
||||
|
||||
#include "framework/GameCallbacks_local.h"
|
||||
|
||||
const char *imageFilter[] = {
|
||||
"GL_LINEAR_MIPMAP_NEAREST",
|
||||
"GL_LINEAR_MIPMAP_LINEAR",
|
||||
|
@ -1071,6 +1073,12 @@ void R_ReloadImages_f( const idCmdArgs &args ) {
|
|||
bool all;
|
||||
bool checkPrecompressed;
|
||||
|
||||
// DG: notify the game DLL about the reloadImages command
|
||||
if(gameCallbacks.reloadImagesCB != NULL)
|
||||
{
|
||||
gameCallbacks.reloadImagesCB(gameCallbacks.reloadImagesUserArg, args);
|
||||
}
|
||||
|
||||
// this probably isn't necessary...
|
||||
globalImages->ChangeTextureFilter();
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
#include "renderer/tr_local.h"
|
||||
|
||||
#include "framework/GameCallbacks_local.h"
|
||||
|
||||
// Vista OpenGL wrapper check
|
||||
#ifdef _WIN32
|
||||
#include "sys/win32/win_local.h"
|
||||
|
@ -1842,6 +1844,12 @@ void R_VidRestart_f( const idCmdArgs &args ) {
|
|||
return;
|
||||
}
|
||||
|
||||
// DG: notify the game DLL about the reloadImages and vid_restart commands
|
||||
if(gameCallbacks.reloadImagesCB != NULL)
|
||||
{
|
||||
gameCallbacks.reloadImagesCB(gameCallbacks.reloadImagesUserArg, args);
|
||||
}
|
||||
|
||||
bool full = true;
|
||||
bool forceWindow = false;
|
||||
for ( int i = 1 ; i < args.Argc() ; i++ ) {
|
||||
|
|
Loading…
Reference in a new issue