diff --git a/codemp/CMakeLists.txt b/codemp/CMakeLists.txt
index bcb0b5f5d4..d8fff5cc7e 100644
--- a/codemp/CMakeLists.txt
+++ b/codemp/CMakeLists.txt
@@ -227,6 +227,8 @@ if(BuildMPEngine OR BuildMPDed)
"${MPDir}/qcommon/cvar.cpp"
"${MPDir}/qcommon/disablewarnings.h"
"${MPDir}/qcommon/files.cpp"
+ "${MPDir}/qcommon/g2_handle_mapper.h"
+ "${MPDir}/qcommon/g2_handle_mapper.cpp"
"${MPDir}/qcommon/game_version.h"
"${MPDir}/qcommon/GenericParser2.cpp"
"${MPDir}/qcommon/GenericParser2.h"
diff --git a/codemp/client/cl_cgameapi.cpp b/codemp/client/cl_cgameapi.cpp
index 49ad244ebc..3d61cc0ae1 100644
--- a/codemp/client/cl_cgameapi.cpp
+++ b/codemp/client/cl_cgameapi.cpp
@@ -30,8 +30,7 @@ along with this program; if not, see .
#include "FXExport.h"
#include "FxUtil.h"
#include "qcommon/vm_local.h"
-
-#include
+#include "qcommon/g2_handle_mapper.h"
extern IHeapAllocator *G2VertSpaceClient;
extern botlib_export_t *botlib_export;
@@ -40,61 +39,7 @@ extern botlib_export_t *botlib_export;
static cgameExport_t *cge; // cgame export table
static vm_t *cgvm; // cgame vm, valid for legacy and new api
-typedef std::unordered_map g2HandleToG2_m;
-
-static g2HandleToG2_m g2Mapping;
-static g2handle_t g2NextHandle = (g2handle_t)1; // Start at 1, because 0 has special meaning
-
-static inline CGhoul2Info_v *CL_G2Map_GetG2FromHandle( g2handleptr_t g2h )
-{ // Returns the pointer to the g2 object if the handle is valid
- // Native libraries should not use the pointer, but in theory they could use
- // it. Thus we don't perform any mapping for native libraries to avoid
- // issues with custom modules.
- if ( cgvm->dllHandle ) return (CGhoul2Info_v*)g2h;
-
- g2handle_t g2handle = (g2handle_t)g2h;
- g2HandleToG2_m::iterator ghlIt = g2Mapping.find(g2handle);
-
- if (ghlIt == g2Mapping.end()) return NULL;
- return g2Mapping[g2handle];
-}
-
-static inline CGhoul2Info_v **CL_G2Map_GetG2PtrFromHandle( g2handleptr_t *g2h )
-{ // Returns a pointer to the g2 object pointer in the map so g2 functions can update the pointer
- // Native libraries should not use the pointer, but in theory they could use
- // it. Thus we don't perform any mapping for native libraries to avoid
- // issues with custom modules.
- if ( cgvm->dllHandle ) return (CGhoul2Info_v **)g2h;
-
- g2handle_t g2handle = *((g2handle_t*)g2h);
- if ( !g2handle )
- { // Special case: the g2 handle is not valid, yet. Return a pointer to a static temporary pointer. Insertion is handled by calling CL_G2Map_Update after calling the G2API
- static CGhoul2Info_v *g2Tmp;
- g2Tmp = NULL;
- return &g2Tmp;
- }
- return &g2Mapping[g2handle];
-}
-
-static void CL_G2Map_Update( g2handleptr_t *g2h, CGhoul2Info_v *g2Ptr )
-{ // Inserts and/or erases to/from the map and updates the handle pointer
- if ( cgvm->dllHandle ) return;
-
- g2handle_t *g2handle = (g2handle_t*)g2h;
- if ( !*g2handle && g2Ptr )
- { // Got a 0 handle, but a non-0 pointer: add to map and set handle
- // Unlikely to happen, but should we ever cycle through the whole integer range start searching for gaps
- while ( CL_G2Map_GetG2FromHandle(g2NextHandle) || !g2NextHandle ) g2NextHandle++;
-
- g2Mapping[g2NextHandle] = g2Ptr;
- *g2handle = g2NextHandle++;
- }
- else if ( *g2h && !g2Ptr )
- { // Got a non-0 handle, but 0 pointer: remove from map and set handle to 0
- g2Mapping.erase( *g2handle );
- *g2handle = 0;
- }
-}
+static Ghoul2HandleMapper cl_g2Mapping{ cgvm };
//
// cgame vmMain calls
@@ -512,7 +457,7 @@ static void CL_R_AddRefEntityToScene( const refEntity_t *refEnt ) {
refEntity_t refEntCopy = *refEnt;
// Get the ghoul2 instance from the handle
- refEntCopy.ghoul2 = CL_G2Map_GetG2FromHandle( (g2handleptr_t)refEnt->ghoul2 );
+ refEntCopy.ghoul2 = cl_g2Mapping.Lookup(reinterpret_cast(refEnt->ghoul2));
// Pass our copy
re->AddRefEntityToScene( &refEntCopy );
@@ -605,7 +550,7 @@ static void CL_RMG_Init( int /* terrainID */, const char * /* terrainInfo */ ) {
static qboolean CGFX_PlayBoltedEffectID( int id, vec3_t org, void *ghoul2, const int boltNum, const int entNum, const int modelNum, int iLooptime, qboolean isRelative ) {
if ( !ghoul2 ) return qfalse;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2));
int boltInfo=0;
if ( re->G2API_AttachEnt( &boltInfo, g2, modelNum, boltNum, entNum, modelNum ) )
{
@@ -641,86 +586,90 @@ static void CL_G2API_ListModelBones( void *ghlInfo, int frame ) {
static void CL_G2API_SetGhoul2ModelIndexes( void *ghoul2, qhandle_t *modelList, qhandle_t *skinList ) {
if ( !ghoul2 ) return;
- re->G2API_SetGhoul2ModelIndexes( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelList, skinList );
+ re->G2API_SetGhoul2ModelIndexes( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelList, skinList );
}
static qboolean CL_G2API_HaveWeGhoul2Models( void *ghoul2) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_HaveWeGhoul2Models( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)) );
+ return re->G2API_HaveWeGhoul2Models( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)) );
}
static qboolean CL_G2API_GetBoltMatrix( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_GetBoltMatrix( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
+ return re->G2API_GetBoltMatrix( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
}
static qboolean CL_G2API_GetBoltMatrix_NoReconstruct( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) {
if ( !ghoul2 ) return qfalse;
re->G2API_BoltMatrixReconstruction( qfalse );
- return re->G2API_GetBoltMatrix( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
+ return re->G2API_GetBoltMatrix( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
}
static qboolean CL_G2API_GetBoltMatrix_NoRecNoRot( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) {
if ( !ghoul2 ) return qfalse;
// Intentionally not setting bolt matrix reconstruction state per original code comments
re->G2API_BoltMatrixSPMethod( qtrue );
- return re->G2API_GetBoltMatrix( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
+ return re->G2API_GetBoltMatrix( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
}
-static int CL_G2API_InitGhoul2Model( void **ghoul2Ptr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias ) {
+static int CL_G2API_InitGhoul2Model( void **rawG2HandlePtr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias ) {
#ifdef _FULL_G2_LEAK_CHECKING
g_G2AllocServer = 0;
#endif
- CGhoul2Info_v **g2Ptr = CL_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghoul2Ptr );
- int ret = re->G2API_InitGhoul2Model( g2Ptr, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias );
- CL_G2Map_Update( (g2handleptr_t*)ghoul2Ptr, *g2Ptr );
+ g2handleptr_t* g2HandlePtr = reinterpret_cast(rawG2HandlePtr);
+ assert(g2HandlePtr);
+ CGhoul2Info_v* g2 = cl_g2Mapping.Lookup(*g2HandlePtr);
+ int ret = re->G2API_InitGhoul2Model( &g2, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias );
+ cl_g2Mapping.Update( *g2HandlePtr, g2 );
return ret;
}
static qboolean CL_G2API_SetSkin( void *ghoul2, int modelIndex, qhandle_t customSkin, qhandle_t renderSkin ) {
if ( !ghoul2 ) return qfalse;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2));
return re->G2API_SetSkin( g2, modelIndex, customSkin, renderSkin );
}
static void CL_G2API_CollisionDetect( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, int traceFlags, int useLod, float fRadius ) {
if ( !ghoul2 ) return;
- re->G2API_CollisionDetect( collRecMap, *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), angles, position, frameNumber, entNum, rayStart, rayEnd, scale, G2VertSpaceClient, traceFlags, useLod, fRadius );
+ re->G2API_CollisionDetect( collRecMap, *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), angles, position, frameNumber, entNum, rayStart, rayEnd, scale, G2VertSpaceClient, traceFlags, useLod, fRadius );
}
static void CL_G2API_CollisionDetectCache( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, int traceFlags, int useLod, float fRadius ) {
if ( !ghoul2 ) return;
- re->G2API_CollisionDetectCache( collRecMap, *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), angles, position, frameNumber, entNum, rayStart, rayEnd, scale, G2VertSpaceClient, traceFlags, useLod, fRadius );
+ re->G2API_CollisionDetectCache( collRecMap, *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), angles, position, frameNumber, entNum, rayStart, rayEnd, scale, G2VertSpaceClient, traceFlags, useLod, fRadius );
}
-static void CL_G2API_CleanGhoul2Models( void **ghoul2Ptr ) {
+static void CL_G2API_CleanGhoul2Models( void **rawG2HandlePtr) {
#ifdef _FULL_G2_LEAK_CHECKING
g_G2AllocServer = 0;
#endif
- CGhoul2Info_v **g2Ptr = CL_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghoul2Ptr );
- re->G2API_CleanGhoul2Models( g2Ptr );
- CL_G2Map_Update( (g2handleptr_t*)ghoul2Ptr, *g2Ptr );
+ g2handleptr_t* g2HandlePtr = reinterpret_cast(rawG2HandlePtr);
+ assert(g2HandlePtr);
+ CGhoul2Info_v *g2= cl_g2Mapping.Lookup( *g2HandlePtr );
+ re->G2API_CleanGhoul2Models( &g2 );
+ cl_g2Mapping.Update( *g2HandlePtr, g2 );
}
static qboolean CL_G2API_SetBoneAngles( void *ghoul2, int modelIndex, const char *boneName, const vec3_t angles, const int flags, const int up, const int right, const int forward, qhandle_t *modelList, int blendTime , int currentTime ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_SetBoneAngles( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boneName, angles, flags, (const Eorientations)up, (const Eorientations)right, (const Eorientations)forward, modelList, blendTime , currentTime );
+ return re->G2API_SetBoneAngles( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boneName, angles, flags, (const Eorientations)up, (const Eorientations)right, (const Eorientations)forward, modelList, blendTime , currentTime );
}
static qboolean CL_G2API_SetBoneAnim( void *ghoul2, const int modelIndex, const char *boneName, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_SetBoneAnim( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boneName, startFrame, endFrame, flags, animSpeed, currentTime, setFrame, blendTime );
+ return re->G2API_SetBoneAnim( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boneName, startFrame, endFrame, flags, animSpeed, currentTime, setFrame, blendTime );
}
static qboolean CL_G2API_GetBoneAnim( void *ghoul2, const char *boneName, const int currentTime, float *currentFrame, int *startFrame, int *endFrame, int *flags, float *animSpeed, int *modelList, const int modelIndex ) {
if ( !ghoul2 ) return qfalse;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2));
return re->G2API_GetBoneAnim( g2, modelIndex, boneName, currentTime, currentFrame, startFrame, endFrame, flags, animSpeed, modelList );
}
static qboolean CL_G2API_GetBoneFrame( void *ghoul2, const char *boneName, const int currentTime, float *currentFrame, int *modelList, const int modelIndex ) {
if ( !ghoul2 ) return qfalse;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2));
int iDontCare1 = 0, iDontCare2 = 0, iDontCare3 = 0;
float fDontCare1 = 0;
@@ -734,7 +683,7 @@ static void CL_G2API_GetGLAName( void *ghoul2, int modelIndex, char *fillBuf ) {
return;
}
- char *tmp = re->G2API_GetGLAName( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex );
+ char *tmp = re->G2API_GetGLAName( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex );
if ( tmp )
strcpy( fillBuf, tmp );
else
@@ -744,52 +693,57 @@ static void CL_G2API_GetGLAName( void *ghoul2, int modelIndex, char *fillBuf ) {
static int CL_G2API_CopyGhoul2Instance( void *g2From, void *g2To, int modelIndex ) {
if ( !g2From || !g2To ) return 0;
- return re->G2API_CopyGhoul2Instance( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)g2From)), *(CL_G2Map_GetG2FromHandle((g2handleptr_t)g2To)), modelIndex );
+ return re->G2API_CopyGhoul2Instance( *cl_g2Mapping.Lookup(reinterpret_cast(g2From)), *cl_g2Mapping.Lookup(reinterpret_cast(g2To)), modelIndex );
}
static void CL_G2API_CopySpecificGhoul2Model( void *g2From, int modelFrom, void *g2To, int modelTo ) {
if ( !g2From || !g2To) return;
- re->G2API_CopySpecificG2Model( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)g2From)), modelFrom, *(CL_G2Map_GetG2FromHandle((g2handleptr_t)g2To)), modelTo );
+ re->G2API_CopySpecificG2Model( *cl_g2Mapping.Lookup(reinterpret_cast(g2From)), modelFrom, *cl_g2Mapping.Lookup(reinterpret_cast(g2To)), modelTo );
}
-static void CL_G2API_DuplicateGhoul2Instance( void *g2From, void **g2To ) {
+static void CL_G2API_DuplicateGhoul2Instance( void *rawG2FromHandle, void **rawG2ToHandlePtr ) {
#ifdef _FULL_G2_LEAK_CHECKING
g_G2AllocServer = 0;
#endif
- if ( !g2From || !g2To ) return;
- CGhoul2Info_v **g2ToPtr = CL_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)g2To );
- re->G2API_DuplicateGhoul2Instance( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)g2From)), g2ToPtr );
- CL_G2Map_Update( (g2handleptr_t*)g2To, *g2ToPtr );
+ if ( !rawG2FromHandle || !rawG2ToHandlePtr ) return;
+ g2handleptr_t* g2ToPtr = reinterpret_cast(rawG2ToHandlePtr);
+ CGhoul2Info_v *g2To = cl_g2Mapping.Lookup( *g2ToPtr );
+ re->G2API_DuplicateGhoul2Instance( *cl_g2Mapping.Lookup(reinterpret_cast(rawG2FromHandle)), &g2To );
+ cl_g2Mapping.Update( *g2ToPtr, g2To );
}
+// FIXME: shouldn't ghlInfo be a void**?
static qboolean CL_G2API_HasGhoul2ModelOnIndex( void *ghlInfo, int modelIndex ) {
- CGhoul2Info_v **g2Ptr = CL_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghlInfo );
- qboolean ret = re->G2API_HasGhoul2ModelOnIndex( g2Ptr, modelIndex );
- CL_G2Map_Update( (g2handleptr_t*)ghlInfo, *g2Ptr );
+ g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo);
+ CGhoul2Info_v *g2 = cl_g2Mapping.Lookup( *g2HandlePtr );
+ qboolean ret = re->G2API_HasGhoul2ModelOnIndex( &g2, modelIndex );
+ cl_g2Mapping.Update( *g2HandlePtr, g2 );
return ret;
}
+// FIXME: shouldn't ghlInfo be a void**?
static qboolean CL_G2API_RemoveGhoul2Model( void *ghlInfo, int modelIndex ) {
#ifdef _FULL_G2_LEAK_CHECKING
g_G2AllocServer = 0;
#endif
- CGhoul2Info_v **g2Ptr = CL_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghlInfo );
- qboolean ret = re->G2API_RemoveGhoul2Model( g2Ptr, modelIndex );
- CL_G2Map_Update( (g2handleptr_t*)ghlInfo, *g2Ptr );
+ g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo);
+ CGhoul2Info_v* g2 = cl_g2Mapping.Lookup(*g2HandlePtr);
+ qboolean ret = re->G2API_RemoveGhoul2Model( &g2, modelIndex );
+ cl_g2Mapping.Update( *g2HandlePtr, g2 );
return ret;
}
static qboolean CL_G2API_SkinlessModel( void *ghlInfo, int modelIndex ) {
if ( !ghlInfo ) return qfalse;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghlInfo));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(ghlInfo));
return re->G2API_SkinlessModel( g2, modelIndex );
}
static int CL_G2API_GetNumGoreMarks( void *ghlInfo, int modelIndex ) {
#ifdef _G2_GORE
if ( !ghlInfo ) return 0;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghlInfo));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(ghlInfo));
return re->G2API_GetNumGoreMarks( g2, modelIndex );
#else
return 0;
@@ -799,62 +753,62 @@ static int CL_G2API_GetNumGoreMarks( void *ghlInfo, int modelIndex ) {
static void CL_G2API_AddSkinGore( void *ghlInfo, SSkinGoreData *gore ) {
#ifdef _G2_GORE
if ( !ghlInfo ) return;
- re->G2API_AddSkinGore( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghlInfo)), *(SSkinGoreData *)gore );
+ re->G2API_AddSkinGore( *cl_g2Mapping.Lookup(reinterpret_cast(ghlInfo)), *(SSkinGoreData *)gore );
#endif
}
static void CL_G2API_ClearSkinGore( void *ghlInfo ) {
#ifdef _G2_GORE
if ( !ghlInfo ) return;
- re->G2API_ClearSkinGore( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghlInfo)) );
+ re->G2API_ClearSkinGore( *cl_g2Mapping.Lookup(reinterpret_cast(ghlInfo)) );
#endif
}
static int CL_G2API_Ghoul2Size( void *ghlInfo ) {
if ( !ghlInfo ) return 0;
- return re->G2API_Ghoul2Size( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghlInfo)) );
+ return re->G2API_Ghoul2Size( *cl_g2Mapping.Lookup(reinterpret_cast(ghlInfo)) );
}
static int CL_G2API_AddBolt( void *ghoul2, int modelIndex, const char *boneName ) {
if ( !ghoul2 ) return -1;
- return re->G2API_AddBolt( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boneName );
+ return re->G2API_AddBolt( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boneName );
}
static qboolean CL_G2API_AttachEnt( int *boltInfo, void *ghlInfoTo, int toBoltIndex, int entNum, int toModelNum ) {
if ( !ghlInfoTo ) return qfalse;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghlInfoTo));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(ghlInfoTo));
return re->G2API_AttachEnt( boltInfo, g2, 0, toBoltIndex, entNum, toModelNum );
}
static void CL_G2API_SetBoltInfo( void *ghoul2, int modelIndex, int boltInfo ) {
if ( !ghoul2 ) return;
- re->G2API_SetBoltInfo( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boltInfo );
+ re->G2API_SetBoltInfo( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boltInfo );
}
static qboolean CL_G2API_SetRootSurface( void *ghoul2, const int modelIndex, const char *surfaceName ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_SetRootSurface( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, surfaceName );
+ return re->G2API_SetRootSurface( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, surfaceName );
}
static qboolean CL_G2API_SetSurfaceOnOff( void *ghoul2, const char *surfaceName, const int flags ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_SetSurfaceOnOff( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), surfaceName, flags );
+ return re->G2API_SetSurfaceOnOff( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), surfaceName, flags );
}
static qboolean CL_G2API_SetNewOrigin( void *ghoul2, const int boltIndex ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_SetNewOrigin( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boltIndex );
+ return re->G2API_SetNewOrigin( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boltIndex );
}
static qboolean CL_G2API_DoesBoneExist( void *ghoul2, int modelIndex, const char *boneName ) {
if ( !ghoul2 ) return qfalse;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2));
return re->G2API_DoesBoneExist( g2, modelIndex, boneName );
}
static int CL_G2API_GetSurfaceRenderStatus( void *ghoul2, const int modelIndex, const char *surfaceName ) {
if ( !ghoul2 ) return -1;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2));
return re->G2API_GetSurfaceRenderStatus( g2, modelIndex, surfaceName );
}
@@ -868,7 +822,7 @@ static void CL_G2API_SetTime( int time, int clock ) {
static void CL_G2API_AbsurdSmoothing( void *ghoul2, qboolean status ) {
if ( !ghoul2 ) return;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2));
re->G2API_AbsurdSmoothing( g2, status );
}
@@ -877,7 +831,7 @@ static void CL_G2API_SetRagDoll( void *ghoul2, sharedRagDollParams_t *params ) {
CRagDollParams rdParams;
if ( !params ) {
- re->G2API_ResetRagDoll( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)) );
+ re->G2API_ResetRagDoll( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)) );
return;
}
@@ -900,7 +854,7 @@ static void CL_G2API_SetRagDoll( void *ghoul2, sharedRagDollParams_t *params ) {
rdParams.RagPhase = (CRagDollParams::ERagPhase)params->RagPhase;
rdParams.effectorsToTurnOff = (CRagDollParams::ERagEffector)params->effectorsToTurnOff;
- re->G2API_SetRagDoll( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), &rdParams );
+ re->G2API_SetRagDoll( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), &rdParams );
}
static void CL_G2API_AnimateG2Models( void *ghoul2, int time, sharedRagDollUpdateParams_t *params ) {
@@ -916,58 +870,58 @@ static void CL_G2API_AnimateG2Models( void *ghoul2, int time, sharedRagDollUpdat
rduParams.me = params->me;
rduParams.settleFrame = params->settleFrame;
- re->G2API_AnimateG2ModelsRag( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), time, &rduParams );
+ re->G2API_AnimateG2ModelsRag( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), time, &rduParams );
}
static qboolean CL_G2API_RagPCJConstraint( void *ghoul2, const char *boneName, vec3_t min, vec3_t max ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_RagPCJConstraint( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boneName, min, max );
+ return re->G2API_RagPCJConstraint( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boneName, min, max );
}
static qboolean CL_G2API_RagPCJGradientSpeed( void *ghoul2, const char *boneName, const float speed ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_RagPCJGradientSpeed( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boneName, speed );
+ return re->G2API_RagPCJGradientSpeed( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boneName, speed );
}
static qboolean CL_G2API_RagEffectorGoal( void *ghoul2, const char *boneName, vec3_t pos ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_RagEffectorGoal( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boneName, pos );
+ return re->G2API_RagEffectorGoal( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boneName, pos );
}
static qboolean CL_G2API_GetRagBonePos( void *ghoul2, const char *boneName, vec3_t pos, vec3_t entAngles, vec3_t entPos, vec3_t entScale ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_GetRagBonePos( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boneName, pos, entAngles, entPos, entScale );
+ return re->G2API_GetRagBonePos( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boneName, pos, entAngles, entPos, entScale );
}
static qboolean CL_G2API_RagEffectorKick( void *ghoul2, const char *boneName, vec3_t velocity ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_RagEffectorKick( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boneName, velocity );
+ return re->G2API_RagEffectorKick( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boneName, velocity );
}
static qboolean CL_G2API_RagForceSolve( void *ghoul2, qboolean force ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_RagForceSolve( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), force );
+ return re->G2API_RagForceSolve( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), force );
}
static qboolean CL_G2API_SetBoneIKState( void *ghoul2, int time, const char *boneName, int ikState, sharedSetBoneIKStateParams_t *params ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_SetBoneIKState( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), time, boneName, ikState, params );
+ return re->G2API_SetBoneIKState( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), time, boneName, ikState, params );
}
static qboolean CL_G2API_IKMove( void *ghoul2, int time, sharedIKMoveParams_t *params ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_IKMove( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), time, params );
+ return re->G2API_IKMove( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), time, params );
}
static qboolean CL_G2API_RemoveBone( void *ghoul2, const char *boneName, int modelIndex ) {
if ( !ghoul2 ) return qfalse;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2));
return re->G2API_RemoveBone( g2, modelIndex, boneName );
}
static void CL_G2API_AttachInstanceToEntNum( void *ghoul2, int entityNum, qboolean server ) {
if ( !ghoul2 ) return;
- re->G2API_AttachInstanceToEntNum( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), entityNum, server );
+ re->G2API_AttachInstanceToEntNum( *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2)), entityNum, server );
}
static void CL_G2API_ClearAttachedInstance( int entityNum ) {
@@ -980,13 +934,13 @@ static void CL_G2API_CleanEntAttachments( void ) {
static qboolean CL_G2API_OverrideServer( void *serverInstance ) {
if ( !serverInstance ) return qfalse;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)serverInstance));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(serverInstance));
return re->G2API_OverrideServerWithClientData( g2, 0 );
}
static void CL_G2API_GetSurfaceName( void *ghoul2, int surfNumber, int modelIndex, char *fillBuf ) {
if ( !ghoul2 ) return;
- CGhoul2Info_v &g2 = *(CL_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *cl_g2Mapping.Lookup(reinterpret_cast(ghoul2));
char *tmp = re->G2API_GetSurfaceName( g2, modelIndex, surfNumber );
strcpy( fillBuf, tmp );
}
diff --git a/codemp/client/cl_uiapi.cpp b/codemp/client/cl_uiapi.cpp
index ac0ebcc3a9..4b75663762 100644
--- a/codemp/client/cl_uiapi.cpp
+++ b/codemp/client/cl_uiapi.cpp
@@ -29,8 +29,7 @@ along with this program; if not, see .
#include "FXExport.h"
#include "FxUtil.h"
#include "qcommon/vm_local.h"
-
-#include
+#include "qcommon/g2_handle_mapper.h"
extern IHeapAllocator *G2VertSpaceClient;
extern botlib_export_t *botlib_export;
@@ -39,61 +38,7 @@ extern botlib_export_t *botlib_export;
static uiExport_t *uie; // ui export table
static vm_t *uivm; // ui vm, valid for legacy and new api
-typedef std::unordered_map g2HandleToG2_m;
-
-static g2HandleToG2_m g2Mapping;
-static g2handle_t g2NextHandle = (g2handle_t)1; // Start at 1, because 0 has special meaning
-
-static inline CGhoul2Info_v *CL_UI_G2Map_GetG2FromHandle( g2handleptr_t g2h )
-{ // Returns the pointer to the g2 object if the handle is valid
- // Native libraries should not use the pointer, but in theory they could use
- // it. Thus we don't perform any mapping for native libraries to avoid
- // issues with custom modules.
- if ( uivm->dllHandle ) return (CGhoul2Info_v*)g2h;
-
- g2handle_t g2handle = (g2handle_t)g2h;
- g2HandleToG2_m::iterator ghlIt = g2Mapping.find(g2handle);
-
- if (ghlIt == g2Mapping.end()) return NULL;
- return g2Mapping[g2handle];
-}
-
-static inline CGhoul2Info_v **CL_UI_G2Map_GetG2PtrFromHandle( g2handleptr_t *g2h )
-{ // Returns a pointer to the g2 object pointer in the map so g2 functions can update the pointer
- // Native libraries should not use the pointer, but in theory they could use
- // it. Thus we don't perform any mapping for native libraries to avoid
- // issues with custom modules.
- if ( uivm->dllHandle ) return (CGhoul2Info_v **)g2h;
-
- g2handle_t g2handle = *((g2handle_t*)g2h);
- if ( !g2handle )
- { // Special case: the g2 handle is not valid, yet. Return a pointer to a static temporary pointer. Insertion is handled by calling CL_UI_G2Map_Update after calling the G2API
- static CGhoul2Info_v *g2Tmp;
- g2Tmp = NULL;
- return &g2Tmp;
- }
- return &g2Mapping[g2handle];
-}
-
-static void CL_UI_G2Map_Update( g2handleptr_t *g2h, CGhoul2Info_v *g2Ptr )
-{ // Inserts and/or erases to/from the map and updates the handle pointer
- if ( uivm->dllHandle ) return;
-
- g2handle_t *g2handle = (g2handle_t*)g2h;
- if ( !*g2handle && g2Ptr )
- { // Got a 0 handle, but a non-0 pointer: add to map and set handle
- // Unlikely to happen, but should we ever cycle through the whole integer range start searching for gaps
- while ( CL_UI_G2Map_GetG2FromHandle(g2NextHandle) || !g2NextHandle ) g2NextHandle++;
-
- g2Mapping[g2NextHandle] = g2Ptr;
- *g2handle = g2NextHandle++;
- }
- else if ( *g2h && !g2Ptr )
- { // Got a non-0 handle, but 0 pointer: remove from map and set handle to 0
- g2Mapping.erase( *g2handle );
- *g2handle = 0;
- }
-}
+static Ghoul2HandleMapper ui_g2Mapping{ uivm };
//
// ui vmMain calls
@@ -346,7 +291,7 @@ void CL_R_AddRefEntityToScene( const refEntity_t *refEnt ) {
refEntity_t refEntCopy = *refEnt;
// Get the ghoul2 instance from the handle
- refEntCopy.ghoul2 = CL_UI_G2Map_GetG2FromHandle( (g2handleptr_t)refEnt->ghoul2 );
+ refEntCopy.ghoul2 = ui_g2Mapping.Lookup( reinterpret_cast(refEnt->ghoul2) );
// Pass our copy
re->AddRefEntityToScene( &refEntCopy );
@@ -373,7 +318,7 @@ static void CL_G2API_SetGhoul2ModelIndexes( void *ghoul2, qhandle_t *modelList,
return;
}
- re->G2API_SetGhoul2ModelIndexes( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelList, skinList );
+ re->G2API_SetGhoul2ModelIndexes( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelList, skinList );
}
static qboolean CL_G2API_HaveWeGhoul2Models( void *ghoul2) {
@@ -381,7 +326,7 @@ static qboolean CL_G2API_HaveWeGhoul2Models( void *ghoul2) {
return qfalse;
}
- return re->G2API_HaveWeGhoul2Models( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)) );
+ return re->G2API_HaveWeGhoul2Models( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)) );
}
static qboolean CL_G2API_GetBoltMatrix( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) {
@@ -389,7 +334,7 @@ static qboolean CL_G2API_GetBoltMatrix( void *ghoul2, const int modelIndex, cons
return qfalse;
}
- return re->G2API_GetBoltMatrix( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
+ return re->G2API_GetBoltMatrix( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
}
static qboolean CL_G2API_GetBoltMatrix_NoReconstruct( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) {
@@ -398,7 +343,7 @@ static qboolean CL_G2API_GetBoltMatrix_NoReconstruct( void *ghoul2, const int mo
}
re->G2API_BoltMatrixReconstruction( qfalse );
- return re->G2API_GetBoltMatrix( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
+ return re->G2API_GetBoltMatrix( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
}
static qboolean CL_G2API_GetBoltMatrix_NoRecNoRot( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) {
@@ -408,20 +353,21 @@ static qboolean CL_G2API_GetBoltMatrix_NoRecNoRot( void *ghoul2, const int model
re->G2API_BoltMatrixReconstruction( qfalse );
re->G2API_BoltMatrixSPMethod( qtrue );
- return re->G2API_GetBoltMatrix( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
+ return re->G2API_GetBoltMatrix( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
}
-static int CL_G2API_InitGhoul2Model( void **ghoul2Ptr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias ) {
- if ( !ghoul2Ptr ) {
+static int CL_G2API_InitGhoul2Model( void **rawG2HandlePtr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias ) {
+ if ( !rawG2HandlePtr ) {
return 0;
}
#ifdef _FULL_G2_LEAK_CHECKING
g_G2AllocServer = 0;
#endif
- CGhoul2Info_v **g2Ptr = CL_UI_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghoul2Ptr );
- int ret = re->G2API_InitGhoul2Model( g2Ptr, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias );
- CL_UI_G2Map_Update( (g2handleptr_t*)ghoul2Ptr, *g2Ptr );
+ g2handleptr_t* g2HandlePtr = reinterpret_cast(rawG2HandlePtr);
+ CGhoul2Info_v *g2 = ui_g2Mapping.Lookup( *g2HandlePtr );
+ int ret = re->G2API_InitGhoul2Model( &g2, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias );
+ ui_g2Mapping.Update( *g2HandlePtr, g2 );
return ret;
}
@@ -430,7 +376,7 @@ static qboolean CL_G2API_SetSkin( void *ghoul2, int modelIndex, qhandle_t custom
return qfalse;
}
- CGhoul2Info_v &g2 = *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2));
return re->G2API_SetSkin( g2, modelIndex, customSkin, renderSkin );
}
@@ -454,7 +400,7 @@ static void CL_G2API_CollisionDetect(
re->G2API_CollisionDetect(
collRecMap,
- *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)),
+ *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)),
angles,
position,
frameNumber,
@@ -488,7 +434,7 @@ static void CL_G2API_CollisionDetectCache(
re->G2API_CollisionDetectCache(
collRecMap,
- *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)),
+ *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)),
angles,
position,
frameNumber,
@@ -502,18 +448,18 @@ static void CL_G2API_CollisionDetectCache(
fRadius);
}
-static void CL_G2API_CleanGhoul2Models( void **ghoul2Ptr ) {
- if ( !ghoul2Ptr ) {
+static void CL_G2API_CleanGhoul2Models( void **rawG2HandlePtr ) {
+ if ( !rawG2HandlePtr ) {
return;
}
#ifdef _FULL_G2_LEAK_CHECKING
g_G2AllocServer = 0;
#endif
-
- CGhoul2Info_v **g2Ptr = CL_UI_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghoul2Ptr );
- re->G2API_CleanGhoul2Models( g2Ptr );
- CL_UI_G2Map_Update( (g2handleptr_t*)ghoul2Ptr, *g2Ptr );
+ g2handleptr_t* g2HandlePtr = reinterpret_cast(rawG2HandlePtr);
+ CGhoul2Info_v *g2 = ui_g2Mapping.Lookup( *g2HandlePtr );
+ re->G2API_CleanGhoul2Models( &g2 );
+ ui_g2Mapping.Update( *g2HandlePtr, g2 );
}
static qboolean CL_G2API_SetBoneAngles(
@@ -534,7 +480,7 @@ static qboolean CL_G2API_SetBoneAngles(
}
return re->G2API_SetBoneAngles(
- *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)),
+ *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)),
modelIndex,
boneName,
angles,
@@ -564,7 +510,7 @@ static qboolean CL_G2API_SetBoneAnim(
}
return re->G2API_SetBoneAnim(
- *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)),
+ *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)),
modelIndex,
boneName,
startFrame,
@@ -592,7 +538,7 @@ static qboolean CL_G2API_GetBoneAnim(
return qfalse;
}
- CGhoul2Info_v &g2 = *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2));
return re->G2API_GetBoneAnim(
g2,
modelIndex,
@@ -618,7 +564,7 @@ static qboolean CL_G2API_GetBoneFrame(
return qfalse;
}
- CGhoul2Info_v &g2 = *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2));
int iDontCare1 = 0, iDontCare2 = 0, iDontCare3 = 0;
float fDontCare1 = 0;
@@ -642,7 +588,7 @@ static void CL_G2API_GetGLAName( void *ghoul2, int modelIndex, char *fillBuf ) {
return;
}
- char *tmp = re->G2API_GetGLAName( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex );
+ char *tmp = re->G2API_GetGLAName( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex );
if ( tmp )
strcpy( fillBuf, tmp );
else
@@ -654,7 +600,7 @@ static int CL_G2API_CopyGhoul2Instance( void *g2From, void *g2To, int modelIndex
return 0;
}
- return re->G2API_CopyGhoul2Instance( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)g2From)), *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)g2To)), modelIndex );
+ return re->G2API_CopyGhoul2Instance( *ui_g2Mapping.Lookup(reinterpret_cast(g2From)), *ui_g2Mapping.Lookup(reinterpret_cast(g2To)), modelIndex );
}
static void CL_G2API_CopySpecificGhoul2Model( void *g2From, int modelFrom, void *g2To, int modelTo ) {
@@ -662,34 +608,39 @@ static void CL_G2API_CopySpecificGhoul2Model( void *g2From, int modelFrom, void
return;
}
- re->G2API_CopySpecificG2Model( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)g2From)), modelFrom, *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)g2To)), modelTo );
+ re->G2API_CopySpecificG2Model( *ui_g2Mapping.Lookup(reinterpret_cast(g2From)), modelFrom, *ui_g2Mapping.Lookup(reinterpret_cast(g2To)), modelTo );
}
-static void CL_G2API_DuplicateGhoul2Instance( void *g2From, void **g2To ) {
- if ( !g2From || !g2To ) {
+static void CL_G2API_DuplicateGhoul2Instance( void *rawG2HandleFrom, void **rawG2HandlePtrTo ) {
+ if ( !rawG2HandleFrom || !rawG2HandlePtrTo ) {
return;
}
#ifdef _FULL_G2_LEAK_CHECKING
g_G2AllocServer = 0;
#endif
-
- CGhoul2Info_v **g2ToPtr = CL_UI_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)g2To );
- re->G2API_DuplicateGhoul2Instance( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)g2From)), g2ToPtr );
- CL_UI_G2Map_Update( (g2handleptr_t*)g2To, *g2ToPtr );
+ g2handleptr_t g2HandleFrom = reinterpret_cast(rawG2HandleFrom);
+ g2handleptr_t* g2HandlePtrTo = reinterpret_cast(rawG2HandlePtrTo);
+ CGhoul2Info_v* g2From = ui_g2Mapping.Lookup(g2HandleFrom);
+ CGhoul2Info_v *g2To = ui_g2Mapping.Lookup( *g2HandlePtrTo );
+ re->G2API_DuplicateGhoul2Instance( *g2From, &g2To);
+ ui_g2Mapping.Update( *g2HandlePtrTo, g2To );
}
+// FIXME: shouldn't ghlInfo be a void**?
static qboolean CL_G2API_HasGhoul2ModelOnIndex( void *ghlInfo, int modelIndex ) {
if ( !ghlInfo ) {
return qfalse;
}
- CGhoul2Info_v **g2Ptr = CL_UI_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghlInfo );
- qboolean ret = re->G2API_HasGhoul2ModelOnIndex( g2Ptr, modelIndex );
- CL_UI_G2Map_Update( (g2handleptr_t*)ghlInfo, *g2Ptr );
+ g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo);
+ CGhoul2Info_v *g2 = ui_g2Mapping.Lookup( *g2HandlePtr );
+ qboolean ret = re->G2API_HasGhoul2ModelOnIndex( &g2, modelIndex );
+ ui_g2Mapping.Update( *g2HandlePtr, g2 );
return ret;
}
+// FIXME: shouldn't ghlInfo be a void**?
static qboolean CL_G2API_RemoveGhoul2Model( void *ghlInfo, int modelIndex ) {
if ( !ghlInfo ) {
return qfalse;
@@ -698,10 +649,10 @@ static qboolean CL_G2API_RemoveGhoul2Model( void *ghlInfo, int modelIndex ) {
#ifdef _FULL_G2_LEAK_CHECKING
g_G2AllocServer = 0;
#endif
-
- CGhoul2Info_v **g2Ptr = CL_UI_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghlInfo );
- qboolean ret = re->G2API_RemoveGhoul2Model( g2Ptr, modelIndex );
- CL_UI_G2Map_Update( (g2handleptr_t*)ghlInfo, *g2Ptr );
+ g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo);
+ CGhoul2Info_v* g2 = ui_g2Mapping.Lookup(*g2HandlePtr);
+ qboolean ret = re->G2API_RemoveGhoul2Model( &g2, modelIndex );
+ ui_g2Mapping.Update( *g2HandlePtr, g2 );
return ret;
}
@@ -710,7 +661,7 @@ static int CL_G2API_AddBolt( void *ghoul2, int modelIndex, const char *boneName
return -1;
}
- return re->G2API_AddBolt( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boneName );
+ return re->G2API_AddBolt( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boneName );
}
static void CL_G2API_SetBoltInfo( void *ghoul2, int modelIndex, int boltInfo ) {
@@ -718,7 +669,7 @@ static void CL_G2API_SetBoltInfo( void *ghoul2, int modelIndex, int boltInfo ) {
return;
}
- re->G2API_SetBoltInfo( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boltInfo );
+ re->G2API_SetBoltInfo( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boltInfo );
}
static qboolean CL_G2API_SetRootSurface( void *ghoul2, const int modelIndex, const char *surfaceName ) {
@@ -726,7 +677,7 @@ static qboolean CL_G2API_SetRootSurface( void *ghoul2, const int modelIndex, con
return qfalse;
}
- return re->G2API_SetRootSurface( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, surfaceName );
+ return re->G2API_SetRootSurface( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, surfaceName );
}
static qboolean CL_G2API_SetSurfaceOnOff( void *ghoul2, const char *surfaceName, const int flags ) {
@@ -734,7 +685,7 @@ static qboolean CL_G2API_SetSurfaceOnOff( void *ghoul2, const char *surfaceName,
return qfalse;
}
- return re->G2API_SetSurfaceOnOff( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), surfaceName, flags );
+ return re->G2API_SetSurfaceOnOff( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), surfaceName, flags );
}
static qboolean CL_G2API_SetNewOrigin( void *ghoul2, const int boltIndex ) {
@@ -742,7 +693,7 @@ static qboolean CL_G2API_SetNewOrigin( void *ghoul2, const int boltIndex ) {
return qfalse;
}
- return re->G2API_SetNewOrigin( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boltIndex );
+ return re->G2API_SetNewOrigin( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boltIndex );
}
static int CL_G2API_GetTime( void ) {
@@ -761,7 +712,7 @@ static void CL_G2API_SetRagDoll( void *ghoul2, sharedRagDollParams_t *params ) {
CRagDollParams rdParams;
if ( !params ) {
- re->G2API_ResetRagDoll( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)) );
+ re->G2API_ResetRagDoll( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)) );
return;
}
@@ -784,7 +735,7 @@ static void CL_G2API_SetRagDoll( void *ghoul2, sharedRagDollParams_t *params ) {
rdParams.RagPhase = (CRagDollParams::ERagPhase)params->RagPhase;
rdParams.effectorsToTurnOff = (CRagDollParams::ERagEffector)params->effectorsToTurnOff;
- re->G2API_SetRagDoll( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), &rdParams );
+ re->G2API_SetRagDoll( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), &rdParams );
}
static void CL_G2API_AnimateG2Models( void *ghoul2, int time, sharedRagDollUpdateParams_t *params ) {
@@ -805,7 +756,7 @@ static void CL_G2API_AnimateG2Models( void *ghoul2, int time, sharedRagDollUpdat
rduParams.me = params->me;
rduParams.settleFrame = params->settleFrame;
- re->G2API_AnimateG2ModelsRag( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), time, &rduParams );
+ re->G2API_AnimateG2ModelsRag( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), time, &rduParams );
}
static qboolean CL_G2API_SetBoneIKState( void *ghoul2, int time, const char *boneName, int ikState, sharedSetBoneIKStateParams_t *params ) {
@@ -813,7 +764,7 @@ static qboolean CL_G2API_SetBoneIKState( void *ghoul2, int time, const char *bon
return qfalse;
}
- return re->G2API_SetBoneIKState( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), time, boneName, ikState, params );
+ return re->G2API_SetBoneIKState( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), time, boneName, ikState, params );
}
static qboolean CL_G2API_IKMove( void *ghoul2, int time, sharedIKMoveParams_t *params ) {
@@ -821,7 +772,7 @@ static qboolean CL_G2API_IKMove( void *ghoul2, int time, sharedIKMoveParams_t *p
return qfalse;
}
- return re->G2API_IKMove( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), time, params );
+ return re->G2API_IKMove( *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2)), time, params );
}
static void CL_G2API_GetSurfaceName( void *ghoul2, int surfNumber, int modelIndex, char *fillBuf ) {
@@ -829,7 +780,7 @@ static void CL_G2API_GetSurfaceName( void *ghoul2, int surfNumber, int modelInde
return;
}
- CGhoul2Info_v &g2 = *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *ui_g2Mapping.Lookup(reinterpret_cast(ghoul2));
char *tmp = re->G2API_GetSurfaceName( g2, modelIndex, surfNumber );
strcpy( fillBuf, tmp );
}
@@ -839,8 +790,8 @@ static qboolean CL_G2API_AttachG2Model( void *ghoul2From, int modelIndexFrom, vo
return qfalse;
}
- CGhoul2Info_v *g2From = (CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2From));
- CGhoul2Info_v *g2To = (CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2To));
+ CGhoul2Info_v *g2From = ui_g2Mapping.Lookup(reinterpret_cast(ghoul2From));
+ CGhoul2Info_v *g2To = ui_g2Mapping.Lookup(reinterpret_cast(ghoul2To));
return re->G2API_AttachG2Model(*g2From, modelIndexFrom, *g2To, toBoltIndex, toModel);
}
diff --git a/codemp/game/g_public.h b/codemp/game/g_public.h
index 6caaf26215..8c5c36decb 100644
--- a/codemp/game/g_public.h
+++ b/codemp/game/g_public.h
@@ -210,6 +210,11 @@ typedef struct parms_s {
typedef struct Vehicle_s Vehicle_t;
#endif
+// In the QVM, the Vehicle_s memory layout differs, because it contains pointers.
+// We don't currently actually access any of its fields, so the type is a stub for now,
+// to be properly defined if and when somebody needs it.
+typedef struct Vehicle_qvm_s Vehicle_qvm_t;
+
// the server looks at a sharedEntity, which is the start of the game's gentity_t structure
//mod authors should not touch this struct
typedef struct sharedEntity_s {
@@ -256,11 +261,11 @@ typedef struct sharedEntity_s {
typedef struct sharedEntity_qvm_s {
entityState_t s; // communicated by server to clients
- uint32_t playerState; //needs to be in the gentity for bg entity access
- //if you want to actually see the contents I guess
- //you will have to be sure to VMA it first.
- uint32_t m_pVehicle; //vehicle data
- uint32_t ghoul2; //g2 instance
+ qvmPointerTo(playerState_t) playerState; //needs to be in the gentity for bg entity access
+ //if you want to actually see the contents I guess
+ //you will have to be sure to VMA it first.
+ qvmPointerTo(Vehicle_qvm_t) m_pVehicle; //vehicle data (careful: QVM memory layout differs from native Vehicle_t!)
+ g2handle_t ghoul2; //g2 instance
int localAnimIndex; //index locally (game/cgame) to anim data for this skel
vec3_t modelScale; //needed for g2 collision
@@ -270,15 +275,15 @@ typedef struct sharedEntity_qvm_s {
//Script/ICARUS-related fields
int taskID[NUM_TIDS];
- uint32_t parms;
- uint32_t behaviorSet[NUM_BSETS];
- uint32_t script_targetname;
+ qvmPointerTo(parms_t) parms;
+ qvmPointerTo(char) behaviorSet[NUM_BSETS];
+ qvmPointerTo(char) script_targetname;
int delayScriptTime;
- uint32_t fullName;
+ qvmPointerTo(char) fullName;
//rww - targetname and classname are now shared as well. ICARUS needs access to them.
- uint32_t targetname;
- uint32_t classname; // set in QuakeEd
+ qvmPointerTo(char) targetname;
+ qvmPointerTo(char) classname; // set in QuakeEd
//rww - and yet more things to share. This is because the nav code is in the exe because it's all C++.
int waypoint; //Set once per frame, if you've moved, and if someone asks
@@ -292,17 +297,29 @@ typedef struct sharedEntity_qvm_s {
int next_roff_time; //rww - npc's need to know when they're getting roff'd
} sharedEntity_qvm_t;
+// A pointer to a pointer in module memory.
+// Dereference and translate using SV_EntityMapperReadPointer.
+typedef union pointerMapper_u {
+ void** native; // pointer to a real pointer, which can be typecast and used directly
+ qvmPointer_t* qvm; // pointer to a 32-bit-qvm address, which must be resolved using VM_ArgPtr(*qvm)
+} pointerMapper_t;
+// Documentation helper to annotate the underlying type.
+// Doesn't actually store anything.
+#define pointerMapperFor(T) pointerMapper_t
+
typedef struct sharedEntityMapper_s {
entityState_t *s; // communicated by server to clients
- playerState_t **playerState; //needs to be in the gentity for bg entity access
+ pointerMapperFor(playerState_t) playerState; //needs to be in the gentity for bg entity access
//if you want to actually see the contents I guess
//you will have to be sure to VMA it first.
-#if (!defined(MACOS_X) && !defined(__GCC__) && !defined(__GNUC__))
- Vehicle_t **m_pVehicle; //vehicle data
-#else
- struct Vehicle_s **m_pVehicle; //vehicle data
-#endif
- void **ghoul2; //g2 instance
+ pointerMapperFor(Vehicle_t | Vehicle_qvm_t) m_pVehicle; // vehicle data (careful: QVM memory layout differs from native Vehicle_t!)
+ // ghoul2 is a bit of a special case because it doesn't point to QVM memory;
+ // use SV_EntityMapperReadGhoul2 to correctly dereference this,
+ // then use the sv_g2Mapping to resolve the resulting handle.
+ union {
+ g2handleptr_t *ghoul2Native; // in native code, it's a pointer to a pointer
+ g2handle_t *ghoul2QVM; // but in QVM, it's a pointer to a 32 bit handle - hence the union
+ };
int *localAnimIndex; //index locally (game/cgame) to anim data for this skel
vec3_t *modelScale; //needed for g2 collision
@@ -312,15 +329,15 @@ typedef struct sharedEntityMapper_s {
//Script/ICARUS-related fields
int (*taskID)[NUM_TIDS];
- parms_t **parms;
- char **behaviorSet[NUM_BSETS];
- char **script_targetname;
+ pointerMapperFor(parms_t) parms;
+ pointerMapperFor(char) behaviorSet[NUM_BSETS];
+ pointerMapperFor(char) script_targetname;
int *delayScriptTime;
- char **fullName;
+ pointerMapperFor(char) fullName;
//rww - targetname and classname are now shared as well. ICARUS needs access to them.
- char **targetname;
- char **classname; // set in QuakeEd
+ pointerMapperFor(char) targetname;
+ pointerMapperFor(char) classname; // set in QuakeEd
//rww - and yet more things to share. This is because the nav code is in the exe because it's all C++.
int *waypoint; //Set once per frame, if you've moved, and if someone asks
diff --git a/codemp/icarus/GameInterface.cpp b/codemp/icarus/GameInterface.cpp
index 0376cc5742..229c2a32b2 100644
--- a/codemp/icarus/GameInterface.cpp
+++ b/codemp/icarus/GameInterface.cpp
@@ -145,7 +145,7 @@ int ICARUS_RunScript( sharedEntityMapper_t *ent, const char *name )
if ( ( ICARUS_entFilter == -1 ) || ( ICARUS_entFilter == ent->s->number ) )
{
- Q3_DebugPrint( WL_VERBOSE, "%d Script %s executed by %s %s\n", svs.time, (char *) name, SV_EntityMapperReadString(ent->classname), SV_EntityMapperReadString(ent->targetname) );
+ Q3_DebugPrint( WL_VERBOSE, "%d Script %s executed by %s %s\n", svs.time, (char *) name, reinterpret_cast(SV_EntityMapperReadPointer(ent->classname)), reinterpret_cast(SV_EntityMapperReadPointer(ent->targetname)) );
}
return true;
@@ -253,7 +253,7 @@ void ICARUS_FreeEnt( sharedEntityMapper_t *ent )
return;
//Remove them from the ICARUSE_EntList list so that when their g_entity index is reused, ICARUS doesn't try to affect the new (incorrect) ent.
- script_targetname = SV_EntityMapperReadString( ent->script_targetname );
+ script_targetname = reinterpret_cast(SV_EntityMapperReadPointer( ent->script_targetname ));
if VALIDSTRING( script_targetname )
{
char temp[1024];
@@ -288,7 +288,7 @@ Determines whether or not an entity needs ICARUS information
bool ICARUS_ValidEnt( sharedEntityMapper_t *ent )
{
- const char *script_targetname = SV_EntityMapperReadString( ent->script_targetname );
+ const char* script_targetname = reinterpret_cast(SV_EntityMapperReadPointer(ent->script_targetname));
int i;
//Targeted by a script
@@ -298,7 +298,7 @@ bool ICARUS_ValidEnt( sharedEntityMapper_t *ent )
//Potentially able to call a script
for ( i = 0; i < NUM_BSETS; i++ )
{
- if VALIDSTRING( SV_EntityMapperReadString(ent->behaviorSet[i]) )
+ if VALIDSTRING( reinterpret_cast(SV_EntityMapperReadPointer(ent->behaviorSet[i])) )
{
//Com_Printf( "WARNING: Entity %d (%s) has behaviorSet but no script_targetname -- using targetname\n", ent->s.number, ent->targetname );
@@ -307,16 +307,17 @@ bool ICARUS_ValidEnt( sharedEntityMapper_t *ent )
//and while this allows us to read it on our "fake" entity here, we can't modify pointers like this. We can however do
//something completely hackish such as the following.
assert(ent->s->number >= 0 && ent->s->number < MAX_GENTITIES);
- sharedEntity_t *trueEntity = SV_GentityNum(ent->s->number);
//This works because we're modifying the actual shared game vm data and turning one pointer into another.
//While these pointers both look like garbage to us in here, they are not.
if ( VM_IsCurrentQVM() )
{
- sharedEntity_qvm_t *trueEntityQVM = (sharedEntity_qvm_t*)trueEntity;
- trueEntityQVM->script_targetname = trueEntityQVM->targetname;
+ *ent->script_targetname.qvm = *ent->targetname.qvm;
+ }
+ else
+ {
+ *ent->script_targetname.native = *ent->targetname.native;
}
- else trueEntity->script_targetname = trueEntity->targetname;
return true;
}
}
@@ -334,7 +335,7 @@ Associate the entity's id and name so that it can be referenced later
void ICARUS_AssociateEnt( sharedEntityMapper_t *ent )
{
- const char *script_targetname = SV_EntityMapperReadString( ent->script_targetname );
+ const char *script_targetname = reinterpret_cast(SV_EntityMapperReadPointer( ent->script_targetname ));
char temp[1024];
if ( VALIDSTRING( script_targetname ) == false )
@@ -647,7 +648,7 @@ void ICARUS_PrecacheEnt( sharedEntityMapper_t *ent )
for ( i = 0; i < NUM_BSETS; i++ )
{
- if ( !(behaviorStr = SV_EntityMapperReadString(ent->behaviorSet[i])) )
+ if ( !(behaviorStr = reinterpret_cast(SV_EntityMapperReadPointer(ent->behaviorSet[i]))) )
continue;
if ( GetIDForString( BSTable, behaviorStr ) == -1 )
diff --git a/codemp/icarus/Q3_Interface.cpp b/codemp/icarus/Q3_Interface.cpp
index d9d52682a9..729e4e046a 100644
--- a/codemp/icarus/Q3_Interface.cpp
+++ b/codemp/icarus/Q3_Interface.cpp
@@ -694,7 +694,7 @@ void Q3_DebugPrint( int level, const char *format, ... )
if ( ( entNum < 0 ) || ( entNum >= MAX_GENTITIES ) )
entNum = 0;
- Com_Printf ( S_COLOR_BLUE"DEBUG: %s(%d): %s\n", SV_EntityMapperReadString(SV_GentityMapperNum(entNum)->script_targetname), entNum, buffer );
+ Com_Printf ( S_COLOR_BLUE"DEBUG: %s(%d): %s\n", SV_EntityMapperReadPointer(SV_GentityMapperNum(entNum)->script_targetname), entNum, buffer );
break;
}
default:
diff --git a/codemp/qcommon/g2_handle_mapper.cpp b/codemp/qcommon/g2_handle_mapper.cpp
new file mode 100644
index 0000000000..adae2311bf
--- /dev/null
+++ b/codemp/qcommon/g2_handle_mapper.cpp
@@ -0,0 +1,70 @@
+#include "g2_handle_mapper.h"
+
+#include
+
+Ghoul2HandleMapper::Ghoul2HandleMapper(vm_t*& vm)
+ : mNextKey(1) // Start at 1, because 0 has special meaning
+ , mVM(vm)
+{
+}
+
+CGhoul2Info_v* Ghoul2HandleMapper::Lookup(g2handleptr_t handle) const
+{
+ // use real pointers in native modules
+ if (mVM->dllHandle) return reinterpret_cast(handle);
+
+ g2handle_t g2handle = static_cast(handle);
+ auto it = mMap.find(g2handle);
+
+ if (it == mMap.end()) return nullptr;
+ return it->second;
+}
+
+void Ghoul2HandleMapper::Update(g2handleptr_t& handleInout, CGhoul2Info_v* const newValue)
+{
+ // native modules use real pointers instead of this mapper
+ if (!mVM->dllHandle) return;
+
+ if (handleInout) {
+ if (newValue) {
+ // update
+ mMap[handleInout] = newValue;
+ }
+ else {
+ // deletion
+ if (mMap.erase(handleInout)) {
+ // remember released key for recycling
+ mFreeList.push_back(handleInout);
+ }
+ handleInout = 0;
+ }
+ }
+ else {
+ if (newValue) {
+ // insertion
+ const g2handle_t key = NextKey();
+ auto& res = mMap.insert({ key, newValue });
+ if (!res.second) {
+ Com_Error(ERR_FATAL, "NextKey %d already present in Ghoul2HandleMapper", key);
+ }
+ handleInout = static_cast(key);
+ }
+ else {
+ // replace nothing with nothing - do nothing
+ }
+ }
+}
+
+Ghoul2HandleMapper::Map::key_type Ghoul2HandleMapper::NextKey()
+{
+ if (mFreeList.empty()) {
+ if (mNextKey == std::numeric_limits::max()) {
+ // We'll probably run out of memory before this happens?
+ Com_Error(ERR_FATAL, "used up all available g2handle_t values, please restart the game");
+ }
+ return mNextKey++;
+ }
+ auto res = mFreeList.back();
+ mFreeList.pop_back();
+ return res;
+}
diff --git a/codemp/qcommon/g2_handle_mapper.h b/codemp/qcommon/g2_handle_mapper.h
new file mode 100644
index 0000000000..7ded997adc
--- /dev/null
+++ b/codemp/qcommon/g2_handle_mapper.h
@@ -0,0 +1,59 @@
+/*
+===========================================================================
+Copyright(C) 2025, OpenJK contributors
+
+This file is part of the OpenJK source code.
+
+OpenJK is free software; you can redistribute it and /or modify it
+under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program 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 this program; if not, see < http://www.gnu.org/licenses/>.
+========================================================================== =
+*/
+
+#pragma once
+
+#include
+#include
+
+#include "qcommon/qcommon.h"
+#include "ghoul2/ghoul2_shared.h"
+
+// When using a QVM, we cannot pass CGhoul2Info_v* pointers directly into the modules (as the memory is not accessible),
+// so this class translates them into opaque g2handle_t values instead.
+// Native (non-QVM) modules in theory should also treat these pointers as opaque handles, but they might not,
+// so we expose the original pointers unchanged in that case.
+class Ghoul2HandleMapper {
+ typedef std::unordered_map Map;
+ typedef std::deque FreeList;
+
+public:
+ Ghoul2HandleMapper(vm_t*& vm);
+
+ // Resolves a handle.
+ // NULL and invalid handles yield NULL.
+ CGhoul2Info_v* Lookup(g2handleptr_t handle) const;
+ // Update creates, updates or deletes an entry, based on which arguments are null.
+ // Passing a null handle and a value creates a mapping entry and returns it in the handle.
+ // Passing a valid handle and a null value deletes the entry and nulls the handle.
+ // Passing a valid handle and a new value updates the entry value and keeps the handle unchanged.
+ void Update(g2handleptr_t& handleInout, CGhoul2Info_v* newValue);
+
+private:
+ // Uses the latest entry in the Free List, or otherwise the first unused index.
+ // ERR_FATALs when out of keys.
+ Map::key_type NextKey();
+
+ Map mMap;
+ Map::key_type mNextKey;
+ // We keep track of released handles so they can be re-used.
+ FreeList mFreeList;
+ vm_t*& mVM;
+};
\ No newline at end of file
diff --git a/codemp/qcommon/msg.cpp b/codemp/qcommon/msg.cpp
index c0c8261b2b..704db1ce9e 100644
--- a/codemp/qcommon/msg.cpp
+++ b/codemp/qcommon/msg.cpp
@@ -1176,7 +1176,7 @@ void MSG_ReadDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to,
print = 1;
if (sv.state)
{
- Com_Printf( "%3i: #%-3i (%s) ", msg->readcount, number, SV_EntityMapperReadString(SV_GentityMapperNum(number)->classname) );
+ Com_Printf( "%3i: #%-3i (%s) ", msg->readcount, number, SV_EntityMapperReadPointer(SV_GentityMapperNum(number)->classname) );
}
else
{
diff --git a/codemp/qcommon/q_shared.h b/codemp/qcommon/q_shared.h
index fb7e636bd7..8befd7f494 100644
--- a/codemp/qcommon/q_shared.h
+++ b/codemp/qcommon/q_shared.h
@@ -152,7 +152,14 @@ typedef union fileBuffer_u {
} fileBuffer_t;
typedef int32_t qhandle_t, thandle_t, fxHandle_t, sfxHandle_t, fileHandle_t, clipHandle_t, g2handle_t;
+// In QVMs, this is an opaque numeric g2handle_t, while in native modules, it's a CGhoul2Info_v*
+// (which modules are not _supposed_ to inspect, but conceivably might...)
typedef intptr_t g2handleptr_t;
+// A pointer into QVM memory. Needs to be translated using VM_ArgPtr to resolve it.
+typedef uint32_t qvmPointer_t;
+// A helper to annotate qvmPointer_t with the pointer type.
+// This is purely for documentation, the type information isn't actually stored anywhere.
+#define qvmPointerTo(T) qvmPointer_t
#define NULL_HANDLE ((qhandle_t)0)
#define NULL_SOUND ((sfxHandle_t)0)
diff --git a/codemp/server/server.h b/codemp/server/server.h
index d96252fb67..dff3310bf2 100644
--- a/codemp/server/server.h
+++ b/codemp/server/server.h
@@ -153,8 +153,7 @@ typedef struct client_s {
int lastMessageNum; // for delta compression
int lastClientCommand; // reliable client message sequence
char lastClientCommandString[MAX_STRING_CHARS];
- sharedEntity_t *gentity; // SV_GentityNum(clientnum)
- sharedEntityMapper_t *gentityMapper;
+ sharedEntityMapper_t *gentityMapper; // SV_GentityMapperNum(clientnum)
char name[MAX_NAME_LENGTH]; // extracted from userinfo, high bits masked
// downloading
@@ -381,35 +380,18 @@ void SV_SendClientSnapshot( client_t *client );
//
int SV_NumForGentity( const sharedEntity_t *ent );
int SV_NumForGentityMapper( const sharedEntityMapper_t *ent );
-sharedEntity_t *SV_GentityNum( int num );
sharedEntityMapper_t *SV_GentityMapperNum( int num );
playerState_t *SV_GameClientNum( int num );
svEntity_t *SV_SvEntityForGentity( sharedEntity_t *gEnt );
svEntity_t *SV_SvEntityForGentityMapper( sharedEntityMapper_t *gEnt );
-sharedEntity_t *SV_GEntityForSvEntity( svEntity_t *svEnt );
sharedEntityMapper_t *SV_GEntityMapperForSvEntity( svEntity_t *svEnt );
sharedEntityMapper_t *SV_GEntityMapperForGentity( const sharedEntity_t *gEnt );
void SV_InitGameProgs ( void );
void SV_ShutdownGameProgs ( void );
qboolean SV_inPVS (const vec3_t p1, const vec3_t p2);
-CGhoul2Info_v *SV_G2Map_GetG2FromHandle( g2handleptr_t g2h );
-CGhoul2Info_v **SV_G2Map_GetG2PtrFromHandle( g2handleptr_t g2h );
-void SV_G2Map_Update( g2handleptr_t *g2h, CGhoul2Info_v *g2Ptr );
-
-#define ENTITYMAP_READER_PROTO( type, funcName ) type funcName( type *inPtr );
-
-ENTITYMAP_READER_PROTO( char*, SV_EntityMapperReadString );
-ENTITYMAP_READER_PROTO( void*, SV_EntityMapperReadData );
-ENTITYMAP_READER_PROTO( playerState_t*, SV_EntityMapperReadPlayerState );
-#if (!defined(MACOS_X) && !defined(__GCC__) && !defined(__GNUC__))
- ENTITYMAP_READER_PROTO( Vehicle_t*, SV_EntityMapperReadVehicle );
-#else
- ENTITYMAP_READER_PROTO( struct Vehicle_s*, SV_EntityMapperReadVehicle );
-#endif
-ENTITYMAP_READER_PROTO( parms_t*, SV_EntityMapperReadParms );
-
-void *SV_EntityMapperReadGhoul2( void **inPtr );
+void* SV_EntityMapperReadPointer(pointerMapper_t ptr);
+g2handleptr_t SV_EntityMapperReadGhoul2( sharedEntityMapper_t *svEnt );
//
// sv_bot.c
diff --git a/codemp/server/sv_bot.cpp b/codemp/server/sv_bot.cpp
index 3518c20e5b..875a8b08d3 100644
--- a/codemp/server/sv_bot.cpp
+++ b/codemp/server/sv_bot.cpp
@@ -201,7 +201,6 @@ int SV_BotAllocateClient(void) {
return -1;
}
- cl->gentity = SV_GentityNum( i );
cl->gentityMapper = SV_GentityMapperNum( i );
cl->gentityMapper->s->number = i;
cl->state = CS_ACTIVE;
@@ -264,8 +263,8 @@ void BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *poin
if (bot_reachability->integer) parm0 |= 2;
if (bot_groundonly->integer) parm0 |= 4;
botlib_export->BotLibVarSet("bot_highlightarea", bot_highlightarea->string);
- botlib_export->Test(parm0, NULL, svs.clients[0].gentity->r.currentOrigin,
- svs.clients[0].gentity->r.currentAngles);
+ botlib_export->Test(parm0, NULL, svs.clients[0].gentityMapper->r->currentOrigin,
+ svs.clients[0].gentityMapper->r->currentAngles);
} //end if
//draw all debug polys
for (i = 0; i < bot_maxdebugpolys; i++) {
diff --git a/codemp/server/sv_client.cpp b/codemp/server/sv_client.cpp
index ac444e16e1..10f4a6ad79 100644
--- a/codemp/server/sv_client.cpp
+++ b/codemp/server/sv_client.cpp
@@ -302,7 +302,6 @@ void SV_DirectConnect( netadr_t from ) {
// this is the only place a client_t is ever initialized
*newcl = temp;
clientNum = newcl - svs.clients;
- newcl->gentity = SV_GentityNum( clientNum );
newcl->gentityMapper = SV_GentityMapperNum( clientNum );
// save the challenge
@@ -560,7 +559,6 @@ void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) {
// set up the entity for the client
clientNum = client - svs.clients;
- client->gentity = SV_GentityNum( clientNum );
client->gentityMapper = SV_GentityMapperNum( clientNum );
client->gentityMapper->s->number = clientNum;
diff --git a/codemp/server/sv_game.cpp b/codemp/server/sv_game.cpp
index 22e08a046f..071185df9c 100644
--- a/codemp/server/sv_game.cpp
+++ b/codemp/server/sv_game.cpp
@@ -47,14 +47,6 @@ int SV_NumForGentityMapper( const sharedEntityMapper_t *ent ) {
return ent - sv.gentitiesMapper;
}
-sharedEntity_t *SV_GentityNum( int num ) {
- sharedEntity_t *ent;
-
- ent = (sharedEntity_t *)((byte *)sv.gentities + sv.gentitySize*(num));
-
- return ent;
-}
-
sharedEntityMapper_t *SV_GentityMapperNum( int num ) {
if ( num < 0 || num >= (int)ARRAY_LEN(sv.gentitiesMapper) ) return NULL;
return &sv.gentitiesMapper[num];
@@ -82,13 +74,6 @@ svEntity_t *SV_SvEntityForGentityMapper( sharedEntityMapper_t *gEnt ) {
return &sv.svEntities[ gEnt->s->number ];
}
-sharedEntity_t *SV_GEntityForSvEntity( svEntity_t *svEnt ) {
- int num;
-
- num = svEnt - sv.svEntities;
- return SV_GentityNum( num );
-}
-
sharedEntityMapper_t *SV_GEntityMapperForSvEntity( svEntity_t *svEnt ) {
int num;
diff --git a/codemp/server/sv_gameapi.cpp b/codemp/server/sv_gameapi.cpp
index 4be41259fd..43c62e003a 100644
--- a/codemp/server/sv_gameapi.cpp
+++ b/codemp/server/sv_gameapi.cpp
@@ -31,8 +31,7 @@ along with this program; if not, see .
#include "qcommon/timing.h"
#include "NPCNav/navigator.h"
#include "qcommon/vm_local.h"
-
-#include
+#include "qcommon/g2_handle_mapper.h"
botlib_export_t *botlib_export;
@@ -40,61 +39,8 @@ botlib_export_t *botlib_export;
static gameExport_t *ge; // game export table
static vm_t *gvm; // game vm, valid for legacy and new api
-typedef std::unordered_map g2HandleToG2_m;
-
-static g2HandleToG2_m g2Mapping;
-static g2handle_t g2NextHandle = (g2handle_t)1; // Start at 1, because 0 has special meaning
-
-CGhoul2Info_v *SV_G2Map_GetG2FromHandle( g2handleptr_t g2h )
-{ // Returns the pointer to the g2 object if the handle is valid
- // Native libraries should not use the pointer, but in theory they could use
- // it. Thus we don't perform any mapping for native libraries to avoid
- // issues with custom modules.
- if ( gvm->dllHandle ) return (CGhoul2Info_v*)g2h;
-
- g2handle_t g2handle = (g2handle_t)g2h;
- g2HandleToG2_m::iterator ghlIt = g2Mapping.find(g2handle);
-
- if (ghlIt == g2Mapping.end()) return NULL;
- return g2Mapping[g2handle];
-}
-
- CGhoul2Info_v **SV_G2Map_GetG2PtrFromHandle( g2handleptr_t *g2h )
-{ // Returns a pointer to the g2 object pointer in the map so g2 functions can update the pointer
- // Native libraries should not use the pointer, but in theory they could use
- // it. Thus we don't perform any mapping for native libraries to avoid
- // issues with custom modules.
- if ( gvm->dllHandle ) return (CGhoul2Info_v **)g2h;
-
- g2handle_t g2handle = *((g2handle_t*)g2h);
- if ( !g2handle )
- { // Special case: the g2 handle is not valid, yet. Return a pointer to a static temporary pointer. Insertion is handled by calling SV_G2Map_Update after calling the G2API
- static CGhoul2Info_v *g2Tmp;
- g2Tmp = NULL;
- return &g2Tmp;
- }
- return &g2Mapping[g2handle];
-}
-
-void SV_G2Map_Update( g2handleptr_t *g2h, CGhoul2Info_v *g2Ptr )
-{ // Inserts and/or erases to/from the map and updates the handle pointer
- if ( gvm->dllHandle ) return;
-
- g2handle_t *g2handle = (g2handle_t*)g2h;
- if ( !*g2handle && g2Ptr )
- { // Got a 0 handle, but a non-0 pointer: add to map and set handle
- // Unlikely to happen, but should we ever cycle through the whole integer range start searching for gaps
- while ( SV_G2Map_GetG2FromHandle(g2NextHandle) || !g2NextHandle ) g2NextHandle++;
-
- g2Mapping[g2NextHandle] = g2Ptr;
- *g2handle = g2NextHandle++;
- }
- else if ( *g2h && !g2Ptr )
- { // Got a non-0 handle, but 0 pointer: remove from map and set handle to 0
- g2Mapping.erase( *g2handle );
- *g2handle = 0;
- }
-}
+// non-static because sv_world.cpp also needs to access it
+Ghoul2HandleMapper sv_g2Mapping{gvm};
//
// game vmMain calls
@@ -592,31 +538,31 @@ static void SV_UpdateSharedEntitiesMapping( void ) {
entM = &sv.gentitiesMapper[i];
// Assign all values
- entM->s = &ent->s;
- entM->playerState = &ent->playerState;
- entM->m_pVehicle = &ent->m_pVehicle;
- entM->ghoul2 = &ent->ghoul2;
- entM->localAnimIndex = &ent->localAnimIndex;
- entM->modelScale = &ent->modelScale;
- entM->r = &ent->r;
- entM->taskID = &ent->taskID;
- entM->parms = &ent->parms;
+ entM->s = &ent->s;
+ entM->playerState.native = reinterpret_cast(&ent->playerState);
+ entM->m_pVehicle.native = reinterpret_cast(&ent->m_pVehicle);
+ entM->ghoul2Native = reinterpret_cast(&ent->ghoul2);
+ entM->localAnimIndex = &ent->localAnimIndex;
+ entM->modelScale = &ent->modelScale;
+ entM->r = &ent->r;
+ entM->taskID = &ent->taskID;
+ entM->parms.native = reinterpret_cast(&ent->parms);
for ( j = 0; j < NUM_BSETS; j++ ) {
- entM->behaviorSet[j] = &(ent->behaviorSet[j]);
+ entM->behaviorSet[j].native = reinterpret_cast((&(ent->behaviorSet[j])));
}
- entM->script_targetname = &ent->script_targetname;
- entM->delayScriptTime = &ent->delayScriptTime;
- entM->fullName = &ent->fullName;
- entM->targetname = &ent->targetname;
- entM->classname = &ent->classname;
- entM->waypoint = &ent->waypoint;
- entM->lastWaypoint = &ent->lastWaypoint;
- entM->lastValidWaypoint = &ent->lastValidWaypoint;
- entM->noWaypointTime = &ent->noWaypointTime;
- entM->combatPoint = &ent->combatPoint;
- entM->failedWaypoints = &ent->failedWaypoints;
- entM->failedWaypointCheckTime = &ent->failedWaypointCheckTime;
- entM->next_roff_time = &ent->next_roff_time;
+ entM->script_targetname.native = reinterpret_cast(&ent->script_targetname);
+ entM->delayScriptTime = &ent->delayScriptTime;
+ entM->fullName.native = reinterpret_cast(&ent->fullName);
+ entM->targetname.native = reinterpret_cast(&ent->targetname);
+ entM->classname.native = reinterpret_cast(&ent->classname);
+ entM->waypoint = &ent->waypoint;
+ entM->lastWaypoint = &ent->lastWaypoint;
+ entM->lastValidWaypoint = &ent->lastValidWaypoint;
+ entM->noWaypointTime = &ent->noWaypointTime;
+ entM->combatPoint = &ent->combatPoint;
+ entM->failedWaypoints = &ent->failedWaypoints;
+ entM->failedWaypointCheckTime = &ent->failedWaypointCheckTime;
+ entM->next_roff_time = &ent->next_roff_time;
}
} else {
sharedEntity_qvm_t *ent;
@@ -627,26 +573,22 @@ static void SV_UpdateSharedEntitiesMapping( void ) {
// Assign all values
entM->s = &ent->s;
- entM->playerState = (playerState_t**)&ent->playerState;
-#if (!defined(MACOS_X) && !defined(__GCC__) && !defined(__GNUC__))
- entM->m_pVehicle = (Vehicle_t**)&ent->m_pVehicle;
-#else
- entM->m_pVehicle = (struct Vehicle_s**)&ent->m_pVehicle;
-#endif
- entM->ghoul2 = (void**)&ent->ghoul2;
+ entM->playerState.qvm = &ent->playerState;
+ entM->m_pVehicle.qvm = &ent->m_pVehicle;
+ entM->ghoul2QVM = &ent->ghoul2;
entM->localAnimIndex = &ent->localAnimIndex;
entM->modelScale = &ent->modelScale;
entM->r = &ent->r;
entM->taskID = &ent->taskID;
- entM->parms = (parms_t**)&ent->parms;
+ entM->parms.qvm = &ent->parms;
for ( j = 0; j < NUM_BSETS; j++ ) {
- entM->behaviorSet[j] = (char**)&(ent->behaviorSet[j]);
+ entM->behaviorSet[j].qvm = &(ent->behaviorSet[j]);
}
- entM->script_targetname = (char**)&ent->script_targetname;
+ entM->script_targetname.qvm = &ent->script_targetname;
entM->delayScriptTime = &ent->delayScriptTime;
- entM->fullName = (char**)&ent->fullName;
- entM->targetname = (char**)&ent->targetname;
- entM->classname = (char**)&ent->classname;
+ entM->fullName.qvm = &ent->fullName;
+ entM->targetname.qvm = &ent->targetname;
+ entM->classname.qvm = &ent->classname;
entM->waypoint = &ent->waypoint;
entM->lastWaypoint = &ent->lastWaypoint;
entM->lastValidWaypoint = &ent->lastValidWaypoint;
@@ -659,31 +601,21 @@ static void SV_UpdateSharedEntitiesMapping( void ) {
}
}
-#define ENTITYMAP_READER( type, funcName ) \
- type funcName( type *inPtr ) { \
- if ( gvm->dllHandle ) { \
- return *inPtr; \
- } else { \
- return (type)VM_ArgPtr((intptr_t)(*(uint32_t*)inPtr)); \
- } \
+void* SV_EntityMapperReadPointer(pointerMapper_t ptr) {
+ if (gvm->dllHandle) {
+ return *ptr.native;
}
+ else {
+ return VM_ArgPtr(*ptr.qvm);
+ }
+}
-ENTITYMAP_READER( char*, SV_EntityMapperReadString );
-ENTITYMAP_READER( void*, SV_EntityMapperReadData );
-ENTITYMAP_READER( playerState_t*, SV_EntityMapperReadPlayerState );
-#if (!defined(MACOS_X) && !defined(__GCC__) && !defined(__GNUC__))
- ENTITYMAP_READER( Vehicle_t*, SV_EntityMapperReadVehicle );
-#else
- ENTITYMAP_READER( struct Vehicle_s*, SV_EntityMapperReadVehicle );
-#endif
-ENTITYMAP_READER( parms_t*, SV_EntityMapperReadParms );
-
-void *SV_EntityMapperReadGhoul2( void **inPtr ) {
- if ( gvm->dllHandle ) {
- return *inPtr;
- } else {
- // For QVMs the address is actually a handle we have to interpret as uint32_t
- return (void*)(intptr_t)(*(uint32_t*)inPtr);
+g2handleptr_t SV_EntityMapperReadGhoul2(sharedEntityMapper_t* svEnt) {
+ if (gvm->dllHandle) {
+ return *svEnt->ghoul2Native;
+ }
+ else {
+ return static_cast(*svEnt->ghoul2QVM);
}
}
@@ -1703,81 +1635,84 @@ static void SV_G2API_ListModelBones( void *ghlInfo, int frame ) {
static void SV_G2API_SetGhoul2ModelIndexes( void *ghoul2, qhandle_t *modelList, qhandle_t *skinList ) {
if ( !ghoul2 ) return;
- re->G2API_SetGhoul2ModelIndexes( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelList, skinList );
+ re->G2API_SetGhoul2ModelIndexes( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelList, skinList );
}
static qboolean SV_G2API_HaveWeGhoul2Models( void *ghoul2) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_HaveWeGhoul2Models( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)) );
+ return re->G2API_HaveWeGhoul2Models( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)));
}
static qboolean SV_G2API_GetBoltMatrix( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_GetBoltMatrix( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
+ return re->G2API_GetBoltMatrix( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
}
static qboolean SV_G2API_GetBoltMatrix_NoReconstruct( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) {
if ( !ghoul2 ) return qfalse;
re->G2API_BoltMatrixReconstruction( qfalse );
- return re->G2API_GetBoltMatrix( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
+ return re->G2API_GetBoltMatrix( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
}
static qboolean SV_G2API_GetBoltMatrix_NoRecNoRot( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) {
if ( !ghoul2 ) return qfalse;
re->G2API_BoltMatrixReconstruction( qfalse );
re->G2API_BoltMatrixSPMethod( qtrue );
- return re->G2API_GetBoltMatrix( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
+ return re->G2API_GetBoltMatrix( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale );
}
-static int SV_G2API_InitGhoul2Model( void **ghoul2Ptr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias ) {
+static int SV_G2API_InitGhoul2Model( void **rawG2HandleReceiver, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias ) {
#ifdef _FULL_G2_LEAK_CHECKING
- g_G2AllocServer = 1;
+ g_G2AllocServer = 1;
#endif
- CGhoul2Info_v **g2Ptr = SV_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghoul2Ptr );
- int ret = re->G2API_InitGhoul2Model( g2Ptr, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias );
- SV_G2Map_Update( (g2handleptr_t*)ghoul2Ptr, *g2Ptr );
+ g2handleptr_t* g2HandleReceiver = reinterpret_cast(rawG2HandleReceiver);
+ assert(g2HandleReceiver); // as required by G2API
+ CGhoul2Info_v* g2 = sv_g2Mapping.Lookup(*g2HandleReceiver); // likely NULL
+ int ret = re->G2API_InitGhoul2Model( &g2, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias );
+ sv_g2Mapping.Update(*g2HandleReceiver, g2);
return ret;
}
static qboolean SV_G2API_SetSkin( void *ghoul2, int modelIndex, qhandle_t customSkin, qhandle_t renderSkin ) {
if ( !ghoul2 ) return qfalse;
- CGhoul2Info_v &g2 = *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2));
return re->G2API_SetSkin( g2, modelIndex, customSkin, renderSkin );
}
static void SV_G2API_CollisionDetect( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, int traceFlags, int useLod, float fRadius ) {
if ( !ghoul2 ) return;
- re->G2API_CollisionDetect( collRecMap, *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), angles, position, frameNumber, entNum, rayStart, rayEnd, scale, G2VertSpaceServer, traceFlags, useLod, fRadius );
+ re->G2API_CollisionDetect( collRecMap, *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), angles, position, frameNumber, entNum, rayStart, rayEnd, scale, G2VertSpaceServer, traceFlags, useLod, fRadius );
}
static void SV_G2API_CollisionDetectCache( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, int traceFlags, int useLod, float fRadius ) {
if ( !ghoul2 ) return;
- re->G2API_CollisionDetectCache( collRecMap, *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), angles, position, frameNumber, entNum, rayStart, rayEnd, scale, G2VertSpaceServer, traceFlags, useLod, fRadius );
+ re->G2API_CollisionDetectCache( collRecMap, *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), angles, position, frameNumber, entNum, rayStart, rayEnd, scale, G2VertSpaceServer, traceFlags, useLod, fRadius );
}
-static void SV_G2API_CleanGhoul2Models( void **ghoul2Ptr ) {
+static void SV_G2API_CleanGhoul2Models( void **rawG2HandlePtr ) {
#ifdef _FULL_G2_LEAK_CHECKING
g_G2AllocServer = 1;
#endif
-
- CGhoul2Info_v **g2Ptr = SV_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghoul2Ptr );
- re->G2API_CleanGhoul2Models( g2Ptr );
- SV_G2Map_Update( (g2handleptr_t*)ghoul2Ptr, *g2Ptr );
+ g2handleptr_t* g2HandlePtr = reinterpret_cast(rawG2HandlePtr);
+ assert(g2HandlePtr);
+ CGhoul2Info_v *g2 = sv_g2Mapping.Lookup( *g2HandlePtr );
+ re->G2API_CleanGhoul2Models( &g2 );
+ sv_g2Mapping.Update( *g2HandlePtr, g2 );
}
static qboolean SV_G2API_SetBoneAngles( void *ghoul2, int modelIndex, const char *boneName, const vec3_t angles, const int flags, const int up, const int right, const int forward, qhandle_t *modelList, int blendTime , int currentTime ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_SetBoneAngles( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boneName, angles, flags, (const Eorientations)up, (const Eorientations)right, (const Eorientations)forward, modelList, blendTime , currentTime );
+ return re->G2API_SetBoneAngles( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boneName, angles, flags, (const Eorientations)up, (const Eorientations)right, (const Eorientations)forward, modelList, blendTime , currentTime );
}
static qboolean SV_G2API_SetBoneAnim( void *ghoul2, const int modelIndex, const char *boneName, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_SetBoneAnim( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boneName, startFrame, endFrame, flags, animSpeed, currentTime, setFrame, blendTime );
+ return re->G2API_SetBoneAnim( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boneName, startFrame, endFrame, flags, animSpeed, currentTime, setFrame, blendTime );
}
static qboolean SV_G2API_GetBoneAnim( void *ghoul2, const char *boneName, const int currentTime, float *currentFrame, int *startFrame, int *endFrame, int *flags, float *animSpeed, int *modelList, const int modelIndex ) {
if ( !ghoul2 ) return qfalse;
- CGhoul2Info_v &g2 = *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2));
return re->G2API_GetBoneAnim( g2, modelIndex, boneName, currentTime, currentFrame, startFrame, endFrame, flags, animSpeed, modelList );
}
@@ -1788,7 +1723,7 @@ static void SV_G2API_GetGLAName( void *ghoul2, int modelIndex, char *fillBuf ) {
return;
}
- char *tmp = re->G2API_GetGLAName( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex );
+ char *tmp = re->G2API_GetGLAName( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex );
if ( tmp )
strcpy( fillBuf, tmp );
else
@@ -1797,97 +1732,108 @@ static void SV_G2API_GetGLAName( void *ghoul2, int modelIndex, char *fillBuf ) {
static int SV_G2API_CopyGhoul2Instance( void *g2From, void *g2To, int modelIndex ) {
if ( !g2From || !g2To ) return 0;
- return re->G2API_CopyGhoul2Instance( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)g2From)), *(SV_G2Map_GetG2FromHandle((g2handleptr_t)g2To)), modelIndex );
+ return re->G2API_CopyGhoul2Instance(*sv_g2Mapping.Lookup(reinterpret_cast(g2From)), *sv_g2Mapping.Lookup(reinterpret_cast(g2To)), modelIndex );
}
static void SV_G2API_CopySpecificGhoul2Model( void *g2From, int modelFrom, void *g2To, int modelTo ) {
if ( !g2From || !g2To ) return;
- re->G2API_CopySpecificG2Model( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)g2From)), modelFrom, *(SV_G2Map_GetG2FromHandle((g2handleptr_t)g2To)), modelTo );
+ re->G2API_CopySpecificG2Model( *sv_g2Mapping.Lookup(reinterpret_cast(g2From)), modelFrom, *sv_g2Mapping.Lookup(reinterpret_cast(g2To)), modelTo );
}
-static void SV_G2API_DuplicateGhoul2Instance( void *g2From, void **g2To ) {
+static void SV_G2API_DuplicateGhoul2Instance( void *rawG2HandleFrom, void **rawG2HandlePtrTo ) {
#ifdef _FULL_G2_LEAK_CHECKING
g_G2AllocServer = 1;
#endif
- if ( !g2From || !g2To ) return;
+ g2handleptr_t g2HandleFrom = reinterpret_cast(rawG2HandleFrom);
+ g2handleptr_t* g2HandlePtrTo = reinterpret_cast(rawG2HandlePtrTo);
+ if ( !g2HandleFrom || !g2HandlePtrTo ) return;
- CGhoul2Info_v **g2ToPtr = SV_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)g2To );
- re->G2API_DuplicateGhoul2Instance( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)g2From)), g2ToPtr );
- SV_G2Map_Update( (g2handleptr_t*)g2To, *g2ToPtr );
+ CGhoul2Info_v *g2 = sv_g2Mapping.Lookup( *g2HandlePtrTo );
+ re->G2API_DuplicateGhoul2Instance( *sv_g2Mapping.Lookup(g2HandleFrom), &g2 );
+ sv_g2Mapping.Update( *g2HandlePtrTo, g2 );
}
+// FIXME: shouldn't ghlInfo be a void**?
static qboolean SV_G2API_HasGhoul2ModelOnIndex( void *ghlInfo, int modelIndex ) {
- CGhoul2Info_v **g2Ptr = SV_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghlInfo );
- qboolean ret = re->G2API_HasGhoul2ModelOnIndex( g2Ptr, modelIndex );
- SV_G2Map_Update( (g2handleptr_t*)ghlInfo, *g2Ptr );
+ g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo);
+ assert(g2HandlePtr);
+ CGhoul2Info_v *g2 = sv_g2Mapping.Lookup( *g2HandlePtr );
+ qboolean ret = re->G2API_HasGhoul2ModelOnIndex( &g2, modelIndex );
+ sv_g2Mapping.Update( *g2HandlePtr, g2 );
return ret;
}
+// FIXME: shouldn't ghlInfo be a void**?
static qboolean SV_G2API_RemoveGhoul2Model( void *ghlInfo, int modelIndex ) {
#ifdef _FULL_G2_LEAK_CHECKING
g_G2AllocServer = 1;
#endif
- CGhoul2Info_v **g2Ptr = SV_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghlInfo );
- qboolean ret = re->G2API_RemoveGhoul2Model( g2Ptr, modelIndex );
- SV_G2Map_Update( (g2handleptr_t*)ghlInfo, *g2Ptr );
+ g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo);
+ assert(g2HandlePtr);
+ CGhoul2Info_v *g2 = sv_g2Mapping.Lookup( *g2HandlePtr );
+ qboolean ret = re->G2API_RemoveGhoul2Model( &g2, modelIndex );
+ sv_g2Mapping.Update( *g2HandlePtr, g2 );
return ret;
}
+// FIXME: shouldn't ghlInfo be a void**?
static qboolean SV_G2API_RemoveGhoul2Models( void *ghlInfo ) {
#ifdef _FULL_G2_LEAK_CHECKING
g_G2AllocServer = 1;
#endif
- CGhoul2Info_v **g2Ptr = SV_G2Map_GetG2PtrFromHandle( (g2handleptr_t*)ghlInfo );
- qboolean ret = re->G2API_RemoveGhoul2Models( g2Ptr );
- SV_G2Map_Update( (g2handleptr_t*)ghlInfo, *g2Ptr );
+ g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo);
+ assert(g2HandlePtr);
+ CGhoul2Info_v *g2 = sv_g2Mapping.Lookup( *g2HandlePtr );
+ qboolean ret = re->G2API_RemoveGhoul2Models( &g2 );
+ sv_g2Mapping.Update( *g2HandlePtr, g2 );
return ret;
}
static int SV_G2API_Ghoul2Size( void *ghlInfo ) {
if ( !ghlInfo ) return 0;
- return re->G2API_Ghoul2Size( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghlInfo)) );
+ return re->G2API_Ghoul2Size( *sv_g2Mapping.Lookup(reinterpret_cast(ghlInfo)) );
}
static int SV_G2API_AddBolt( void *ghoul2, int modelIndex, const char *boneName ) {
if ( !ghoul2 ) return -1;
- return re->G2API_AddBolt( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boneName );
+ return re->G2API_AddBolt( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boneName );
}
static void SV_G2API_SetBoltInfo( void *ghoul2, int modelIndex, int boltInfo ) {
if ( !ghoul2 ) return;
- re->G2API_SetBoltInfo( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, boltInfo );
+ re->G2API_SetBoltInfo( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, boltInfo );
}
static qboolean SV_G2API_SetRootSurface( void *ghoul2, const int modelIndex, const char *surfaceName ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_SetRootSurface( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), modelIndex, surfaceName );
+ return re->G2API_SetRootSurface( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), modelIndex, surfaceName );
}
static qboolean SV_G2API_SetSurfaceOnOff( void *ghoul2, const char *surfaceName, const int flags ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_SetSurfaceOnOff( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), surfaceName, flags );
+ return re->G2API_SetSurfaceOnOff( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), surfaceName, flags );
}
static qboolean SV_G2API_SetNewOrigin( void *ghoul2, const int boltIndex ) {
if ( !ghoul2 ) return qfalse;
- return re->G2API_SetNewOrigin( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boltIndex );
+ return re->G2API_SetNewOrigin( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boltIndex );
}
static qboolean SV_G2API_DoesBoneExist( void *ghoul2, int modelIndex, const char *boneName ) {
if ( !ghoul2 ) return qfalse;
- CGhoul2Info_v &g2 = *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2));
return re->G2API_DoesBoneExist( g2, modelIndex, boneName );
}
static int SV_G2API_GetSurfaceRenderStatus( void *ghoul2, const int modelIndex, const char *surfaceName ) {
if ( !ghoul2 ) return -1;
- CGhoul2Info_v &g2 = *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2));
return re->G2API_GetSurfaceRenderStatus( g2, modelIndex, surfaceName );
}
static void SV_G2API_AbsurdSmoothing( void *ghoul2, qboolean status ) {
if ( !ghoul2 ) return;
- CGhoul2Info_v &g2 = *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2));
re->G2API_AbsurdSmoothing( g2, status );
}
@@ -1897,7 +1843,7 @@ static void SV_G2API_SetRagDoll( void *ghoul2, sharedRagDollParams_t *params ) {
CRagDollParams rdParams;
if ( !params ) {
- re->G2API_ResetRagDoll( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)) );
+ re->G2API_ResetRagDoll( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)) );
return;
}
@@ -1920,7 +1866,7 @@ static void SV_G2API_SetRagDoll( void *ghoul2, sharedRagDollParams_t *params ) {
rdParams.RagPhase = (CRagDollParams::ERagPhase)params->RagPhase;
rdParams.effectorsToTurnOff = (CRagDollParams::ERagEffector)params->effectorsToTurnOff;
- re->G2API_SetRagDoll( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), &rdParams );
+ re->G2API_SetRagDoll( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), &rdParams );
}
static void SV_G2API_AnimateG2Models( void *ghoul2, int time, sharedRagDollUpdateParams_t *params ) {
@@ -1937,48 +1883,48 @@ static void SV_G2API_AnimateG2Models( void *ghoul2, int time, sharedRagDollUpdat
rduParams.me = params->me;
rduParams.settleFrame = params->settleFrame;
- re->G2API_AnimateG2ModelsRag( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), time, &rduParams );
+ re->G2API_AnimateG2ModelsRag( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), time, &rduParams );
}
static qboolean SV_G2API_RagPCJConstraint( void *ghoul2, const char *boneName, vec3_t min, vec3_t max ) {
- return re->G2API_RagPCJConstraint( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boneName, min, max );
+ return re->G2API_RagPCJConstraint( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boneName, min, max );
}
static qboolean SV_G2API_RagPCJGradientSpeed( void *ghoul2, const char *boneName, const float speed ) {
- return re->G2API_RagPCJGradientSpeed( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boneName, speed );
+ return re->G2API_RagPCJGradientSpeed( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boneName, speed );
}
static qboolean SV_G2API_RagEffectorGoal( void *ghoul2, const char *boneName, vec3_t pos ) {
- return re->G2API_RagEffectorGoal( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boneName, pos );
+ return re->G2API_RagEffectorGoal( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boneName, pos );
}
static qboolean SV_G2API_GetRagBonePos( void *ghoul2, const char *boneName, vec3_t pos, vec3_t entAngles, vec3_t entPos, vec3_t entScale ) {
- return re->G2API_GetRagBonePos( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boneName, pos, entAngles, entPos, entScale );
+ return re->G2API_GetRagBonePos( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boneName, pos, entAngles, entPos, entScale );
}
static qboolean SV_G2API_RagEffectorKick( void *ghoul2, const char *boneName, vec3_t velocity ) {
- return re->G2API_RagEffectorKick( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), boneName, velocity );
+ return re->G2API_RagEffectorKick( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), boneName, velocity );
}
static qboolean SV_G2API_RagForceSolve( void *ghoul2, qboolean force ) {
- return re->G2API_RagForceSolve( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), force );
+ return re->G2API_RagForceSolve( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), force );
}
static qboolean SV_G2API_SetBoneIKState( void *ghoul2, int time, const char *boneName, int ikState, sharedSetBoneIKStateParams_t *params ) {
- return re->G2API_SetBoneIKState( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), time, boneName, ikState, params );
+ return re->G2API_SetBoneIKState( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), time, boneName, ikState, params );
}
static qboolean SV_G2API_IKMove( void *ghoul2, int time, sharedIKMoveParams_t *params ) {
- return re->G2API_IKMove( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), time, params );
+ return re->G2API_IKMove( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), time, params );
}
static qboolean SV_G2API_RemoveBone( void *ghoul2, const char *boneName, int modelIndex ) {
- CGhoul2Info_v &g2 = *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2));
return re->G2API_RemoveBone( g2, modelIndex, boneName );
}
static void SV_G2API_AttachInstanceToEntNum( void *ghoul2, int entityNum, qboolean server ) {
- re->G2API_AttachInstanceToEntNum( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2)), entityNum, server );
+ re->G2API_AttachInstanceToEntNum( *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2)), entityNum, server );
}
static void SV_G2API_ClearAttachedInstance( int entityNum ) {
@@ -1990,12 +1936,12 @@ static void SV_G2API_CleanEntAttachments( void ) {
}
static qboolean SV_G2API_OverrideServer( void *serverInstance ) {
- CGhoul2Info_v &g2 = *(SV_G2Map_GetG2FromHandle((g2handleptr_t)serverInstance));
+ CGhoul2Info_v &g2 = *sv_g2Mapping.Lookup(reinterpret_cast(serverInstance));
return re->G2API_OverrideServerWithClientData( g2, 0 );
}
static void SV_G2API_GetSurfaceName( void *ghoul2, int surfNumber, int modelIndex, char *fillBuf ) {
- CGhoul2Info_v &g2 = *(SV_G2Map_GetG2FromHandle((g2handleptr_t)ghoul2));
+ CGhoul2Info_v &g2 = *sv_g2Mapping.Lookup(reinterpret_cast(ghoul2));
char *tmp = re->G2API_GetSurfaceName( g2, modelIndex, surfNumber );
strcpy( fillBuf, tmp );
}
@@ -3071,7 +3017,6 @@ void SV_InitGame( qboolean restart ) {
// clear level pointers
sv.entityParsePoint = CM_EntityString();
for ( i=0, cl=svs.clients; iinteger; i++, cl++ ) {
- cl->gentity = NULL;
cl->gentityMapper = NULL;
}
diff --git a/codemp/server/sv_init.cpp b/codemp/server/sv_init.cpp
index f493edb004..24a8236e64 100644
--- a/codemp/server/sv_init.cpp
+++ b/codemp/server/sv_init.cpp
@@ -673,7 +673,6 @@ Ghoul2 Insert End
client->state = CS_ACTIVE;
client->gentityMapper = SV_GentityMapperNum( i );
client->gentityMapper->s->number = i;
- client->gentity = SV_GentityNum( i );
client->deltaMessage = -1;
client->nextSnapshotTime = svs.time; // generate a snapshot immediately
diff --git a/codemp/server/sv_snapshot.cpp b/codemp/server/sv_snapshot.cpp
index 769673af6f..350a22cbe4 100644
--- a/codemp/server/sv_snapshot.cpp
+++ b/codemp/server/sv_snapshot.cpp
@@ -581,7 +581,7 @@ static void SV_BuildClientSnapshot( client_t *client ) {
sharedEntityMapper_t *veh = SV_GentityMapperNum(ps->m_iVehicleNum);
playerState_t *vps;
- if (veh && (vps = SV_EntityMapperReadPlayerState(veh->playerState)))
+ if (veh && (vps = reinterpret_cast(SV_EntityMapperReadPointer(veh->playerState))))
{ //Now VMA it and we've got ourselves a playerState
frame->vps = *vps;
#ifdef _ONEBIT_COMBO
diff --git a/codemp/server/sv_world.cpp b/codemp/server/sv_world.cpp
index 2db0ec2724..700cf1df74 100644
--- a/codemp/server/sv_world.cpp
+++ b/codemp/server/sv_world.cpp
@@ -26,6 +26,7 @@ along with this program; if not, see .
#include "server.h"
#include "ghoul2/ghoul2_shared.h"
#include "qcommon/cm_public.h"
+#include "qcommon/g2_handle_mapper.h"
/*
================
@@ -535,6 +536,8 @@ static float VectorDistance(vec3_t p1, vec3_t p2)
}
#endif
+extern Ghoul2HandleMapper sv_g2Mapping;
+
static void SV_ClipMoveToEntities( moveclip_t *clip ) {
static int touchlist[MAX_GENTITIES];
int i, num;
@@ -700,7 +703,7 @@ Ghoul2 Insert Start
#else
//rww - since this is multiplayer and we don't have the luxury of violating networking rules in horrible ways,
//this must be done somewhat differently.
- if ((clip->traceFlags & G2TRFLAG_DOGHOULTRACE) && trace.entityNum == touch->s->number && SV_EntityMapperReadGhoul2(touch->ghoul2) && ((clip->traceFlags & G2TRFLAG_HITCORPSES) || !(touch->s->eFlags & EF_DEAD)))
+ if ((clip->traceFlags & G2TRFLAG_DOGHOULTRACE) && trace.entityNum == touch->s->number && SV_EntityMapperReadGhoul2(touch) && ((clip->traceFlags & G2TRFLAG_HITCORPSES) || !(touch->s->eFlags & EF_DEAD)))
{ //standard behavior will be to ignore g2 col on dead ents, but if traceFlags is set to allow, then we'll try g2 col on EF_DEAD people too.
static G2Trace_t G2Trace;
vec3_t angles;
@@ -744,7 +747,7 @@ Ghoul2 Insert Start
#ifndef FINAL_BUILD
if (sv_showghoultraces->integer)
{
- Com_Printf( "Ghoul2 trace lod=%1d length=%6.0f to %s\n",clip->useLod,VectorDistance(clip->start, clip->end), re->G2API_GetModelName(*(SV_G2Map_GetG2FromHandle((g2handleptr_t)SV_EntityMapperReadGhoul2(touch->ghoul2))), 0));
+ Com_Printf( "Ghoul2 trace lod=%1d length=%6.0f to %s\n",clip->useLod,VectorDistance(clip->start, clip->end), re->G2API_GetModelName(*sv_g2Mapping.Lookup(SV_EntityMapperReadGhoul2(touch)), 0));
}
#endif
@@ -752,13 +755,13 @@ Ghoul2 Insert Start
com_optvehtrace->integer &&
touch->s->eType == ET_NPC &&
touch->s->NPC_class == CLASS_VEHICLE &&
- SV_EntityMapperReadVehicle(touch->m_pVehicle))
+ SV_EntityMapperReadPointer(touch->m_pVehicle))
{ //for vehicles cache the transform data.
- re->G2API_CollisionDetectCache(G2Trace, *(SV_G2Map_GetG2FromHandle((g2handleptr_t)SV_EntityMapperReadGhoul2(touch->ghoul2))), angles, touch->r->currentOrigin, sv.time, touch->s->number, clip->start, clip->end, *touch->modelScale, G2VertSpaceServer, 0, clip->useLod, fRadius);
+ re->G2API_CollisionDetectCache(G2Trace, *sv_g2Mapping.Lookup(SV_EntityMapperReadGhoul2(touch)), angles, touch->r->currentOrigin, sv.time, touch->s->number, clip->start, clip->end, *touch->modelScale, G2VertSpaceServer, 0, clip->useLod, fRadius);
}
else
{
- re->G2API_CollisionDetect(G2Trace, *(SV_G2Map_GetG2FromHandle((g2handleptr_t)SV_EntityMapperReadGhoul2(touch->ghoul2))), angles, touch->r->currentOrigin, sv.time, touch->s->number, clip->start, clip->end, *touch->modelScale, G2VertSpaceServer, 0, clip->useLod, fRadius);
+ re->G2API_CollisionDetect(G2Trace, *sv_g2Mapping.Lookup(SV_EntityMapperReadGhoul2(touch)), angles, touch->r->currentOrigin, sv.time, touch->s->number, clip->start, clip->end, *touch->modelScale, G2VertSpaceServer, 0, clip->useLod, fRadius);
}
tN = 0;