From 1fd2945c183d14d54962d734425c436bb9968a95 Mon Sep 17 00:00:00 2001 From: Willi Schinmeyer Date: Sat, 1 Mar 2025 18:46:45 +0100 Subject: [PATCH 1/5] Remove *_G2Map_GetG2PtrFromHandle This gets rid of the confusing and brittle g2Tmp static variable, replacing it with individual local variables instead. --- codemp/client/cl_cgameapi.cpp | 64 +++++++++++++---------------- codemp/client/cl_uiapi.cpp | 71 ++++++++++++++------------------ codemp/qcommon/q_shared.h | 2 + codemp/server/server.h | 1 - codemp/server/sv_gameapi.cpp | 77 +++++++++++++++++------------------ 5 files changed, 97 insertions(+), 118 deletions(-) diff --git a/codemp/client/cl_cgameapi.cpp b/codemp/client/cl_cgameapi.cpp index 49ad244ebc..9ec7314418 100644 --- a/codemp/client/cl_cgameapi.cpp +++ b/codemp/client/cl_cgameapi.cpp @@ -59,23 +59,6 @@ static inline CGhoul2Info_v *CL_G2Map_GetG2FromHandle( g2handleptr_t g2h ) 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; @@ -667,13 +650,15 @@ static qboolean CL_G2API_GetBoltMatrix_NoRecNoRot( void *ghoul2, const int model return re->G2API_GetBoltMatrix( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)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_G2Map_GetG2FromHandle(*g2HandlePtr); + int ret = re->G2API_InitGhoul2Model( &g2, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias ); + CL_G2Map_Update( g2HandlePtr, g2 ); return ret; } @@ -693,13 +678,15 @@ static void CL_G2API_CollisionDetectCache( CollisionRecord_t *collRecMap, void* re->G2API_CollisionDetectCache( collRecMap, *(CL_G2Map_GetG2FromHandle((g2handleptr_t)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_G2Map_GetG2FromHandle( *g2HandlePtr ); + re->G2API_CleanGhoul2Models( &g2 ); + CL_G2Map_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 ) { @@ -752,30 +739,35 @@ static void CL_G2API_CopySpecificGhoul2Model( void *g2From, int modelFrom, void re->G2API_CopySpecificG2Model( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)g2From)), modelFrom, *(CL_G2Map_GetG2FromHandle((g2handleptr_t)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_G2Map_GetG2FromHandle( *g2ToPtr ); + re->G2API_DuplicateGhoul2Instance( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)rawG2FromHandle)), &g2To ); + CL_G2Map_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_G2Map_GetG2FromHandle( *g2HandlePtr ); + qboolean ret = re->G2API_HasGhoul2ModelOnIndex( &g2, modelIndex ); + CL_G2Map_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_G2Map_GetG2FromHandle(*g2HandlePtr); + qboolean ret = re->G2API_RemoveGhoul2Model( &g2, modelIndex ); + CL_G2Map_Update( g2HandlePtr, g2 ); return ret; } diff --git a/codemp/client/cl_uiapi.cpp b/codemp/client/cl_uiapi.cpp index ac0ebcc3a9..3d7cfdb901 100644 --- a/codemp/client/cl_uiapi.cpp +++ b/codemp/client/cl_uiapi.cpp @@ -58,23 +58,6 @@ static inline CGhoul2Info_v *CL_UI_G2Map_GetG2FromHandle( g2handleptr_t g2h ) 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; @@ -411,17 +394,18 @@ static qboolean CL_G2API_GetBoltMatrix_NoRecNoRot( void *ghoul2, const int model return re->G2API_GetBoltMatrix( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)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 = CL_UI_G2Map_GetG2FromHandle( *g2HandlePtr ); + int ret = re->G2API_InitGhoul2Model( &g2, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias ); + CL_UI_G2Map_Update( g2HandlePtr, g2 ); return ret; } @@ -502,18 +486,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 = CL_UI_G2Map_GetG2FromHandle( *g2HandlePtr ); + re->G2API_CleanGhoul2Models( &g2 ); + CL_UI_G2Map_Update( g2HandlePtr, g2 ); } static qboolean CL_G2API_SetBoneAngles( @@ -665,31 +649,36 @@ static void CL_G2API_CopySpecificGhoul2Model( void *g2From, int modelFrom, void re->G2API_CopySpecificG2Model( *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)g2From)), modelFrom, *(CL_UI_G2Map_GetG2FromHandle((g2handleptr_t)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 = CL_UI_G2Map_GetG2FromHandle(g2HandleFrom); + CGhoul2Info_v *g2To = CL_UI_G2Map_GetG2FromHandle( *g2HandlePtrTo ); + re->G2API_DuplicateGhoul2Instance( *g2From, &g2To); + CL_UI_G2Map_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 = CL_UI_G2Map_GetG2FromHandle( *g2HandlePtr ); + qboolean ret = re->G2API_HasGhoul2ModelOnIndex( &g2, modelIndex ); + CL_UI_G2Map_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 +687,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 = CL_UI_G2Map_GetG2FromHandle(*g2HandlePtr); + qboolean ret = re->G2API_RemoveGhoul2Model( &g2, modelIndex ); + CL_UI_G2Map_Update( g2HandlePtr, g2 ); return ret; } diff --git a/codemp/qcommon/q_shared.h b/codemp/qcommon/q_shared.h index fb7e636bd7..1f5864c0be 100644 --- a/codemp/qcommon/q_shared.h +++ b/codemp/qcommon/q_shared.h @@ -152,6 +152,8 @@ 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; #define NULL_HANDLE ((qhandle_t)0) diff --git a/codemp/server/server.h b/codemp/server/server.h index d96252fb67..62cfd8a12a 100644 --- a/codemp/server/server.h +++ b/codemp/server/server.h @@ -394,7 +394,6 @@ 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 ); diff --git a/codemp/server/sv_gameapi.cpp b/codemp/server/sv_gameapi.cpp index 4be41259fd..b2afd33031 100644 --- a/codemp/server/sv_gameapi.cpp +++ b/codemp/server/sv_gameapi.cpp @@ -59,23 +59,6 @@ CGhoul2Info_v *SV_G2Map_GetG2FromHandle( g2handleptr_t g2h ) 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; @@ -1729,13 +1712,15 @@ static qboolean SV_G2API_GetBoltMatrix_NoRecNoRot( void *ghoul2, const int model return re->G2API_GetBoltMatrix( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)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 **rawG2HandlePtr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias ) { #ifdef _FULL_G2_LEAK_CHECKING 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* g2HandlePtr = reinterpret_cast(rawG2HandlePtr); + assert(g2HandlePtr); + CGhoul2Info_v *g2 = SV_G2Map_GetG2FromHandle( *g2HandlePtr ); + int ret = re->G2API_InitGhoul2Model( &g2, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias ); + SV_G2Map_Update( g2HandlePtr, g2 ); return ret; } @@ -1755,14 +1740,15 @@ static void SV_G2API_CollisionDetectCache( CollisionRecord_t *collRecMap, void* re->G2API_CollisionDetectCache( collRecMap, *(SV_G2Map_GetG2FromHandle((g2handleptr_t)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_G2Map_GetG2FromHandle( *g2HandlePtr ); + re->G2API_CleanGhoul2Models( &g2 ); + SV_G2Map_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 ) { @@ -1805,41 +1791,52 @@ static void SV_G2API_CopySpecificGhoul2Model( void *g2From, int modelFrom, void re->G2API_CopySpecificG2Model( *(SV_G2Map_GetG2FromHandle((g2handleptr_t)g2From)), modelFrom, *(SV_G2Map_GetG2FromHandle((g2handleptr_t)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_G2Map_GetG2FromHandle( *g2HandlePtrTo ); + re->G2API_DuplicateGhoul2Instance( *SV_G2Map_GetG2FromHandle(g2HandleFrom), &g2 ); + SV_G2Map_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_G2Map_GetG2FromHandle( *g2HandlePtr ); + qboolean ret = re->G2API_HasGhoul2ModelOnIndex( &g2, modelIndex ); + SV_G2Map_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_G2Map_GetG2FromHandle( *g2HandlePtr ); + qboolean ret = re->G2API_RemoveGhoul2Model( &g2, modelIndex ); + SV_G2Map_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_G2Map_GetG2FromHandle( *g2HandlePtr ); + qboolean ret = re->G2API_RemoveGhoul2Models( &g2 ); + SV_G2Map_Update( g2HandlePtr, g2 ); return ret; } From 6ab0312e32d0e7ba5752c9a65864e682362bac4e Mon Sep 17 00:00:00 2001 From: Willi Schinmeyer Date: Sat, 1 Mar 2025 09:05:49 +0100 Subject: [PATCH 2/5] refactor g2 handle mapper into class --- codemp/CMakeLists.txt | 2 + codemp/client/cl_cgameapi.cpp | 156 ++++++++++----------------- codemp/client/cl_uiapi.cpp | 122 ++++++++------------- codemp/game/g_public.h | 2 +- codemp/qcommon/g2_handle_mapper.cpp | 70 ++++++++++++ codemp/qcommon/g2_handle_mapper.h | 59 ++++++++++ codemp/server/server.h | 5 +- codemp/server/sv_gameapi.cpp | 161 +++++++++++----------------- codemp/server/sv_world.cpp | 9 +- 9 files changed, 302 insertions(+), 284 deletions(-) create mode 100644 codemp/qcommon/g2_handle_mapper.cpp create mode 100644 codemp/qcommon/g2_handle_mapper.h 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 9ec7314418..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,44 +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 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 @@ -495,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 ); @@ -588,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 ) ) { @@ -624,30 +586,30 @@ 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 **rawG2HandlePtr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias ) { @@ -656,26 +618,26 @@ static int CL_G2API_InitGhoul2Model( void **rawG2HandlePtr, const char *fileName #endif g2handleptr_t* g2HandlePtr = reinterpret_cast(rawG2HandlePtr); assert(g2HandlePtr); - CGhoul2Info_v* g2 = CL_G2Map_GetG2FromHandle(*g2HandlePtr); + CGhoul2Info_v* g2 = cl_g2Mapping.Lookup(*g2HandlePtr); int ret = re->G2API_InitGhoul2Model( &g2, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias ); - CL_G2Map_Update( g2HandlePtr, g2 ); + 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 **rawG2HandlePtr) { @@ -684,30 +646,30 @@ static void CL_G2API_CleanGhoul2Models( void **rawG2HandlePtr) { #endif g2handleptr_t* g2HandlePtr = reinterpret_cast(rawG2HandlePtr); assert(g2HandlePtr); - CGhoul2Info_v *g2= CL_G2Map_GetG2FromHandle( *g2HandlePtr ); + CGhoul2Info_v *g2= cl_g2Mapping.Lookup( *g2HandlePtr ); re->G2API_CleanGhoul2Models( &g2 ); - CL_G2Map_Update( g2HandlePtr, 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; @@ -721,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 @@ -731,12 +693,12 @@ 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 *rawG2FromHandle, void **rawG2ToHandlePtr ) { @@ -745,17 +707,17 @@ static void CL_G2API_DuplicateGhoul2Instance( void *rawG2FromHandle, void **rawG #endif if ( !rawG2FromHandle || !rawG2ToHandlePtr ) return; g2handleptr_t* g2ToPtr = reinterpret_cast(rawG2ToHandlePtr); - CGhoul2Info_v *g2To = CL_G2Map_GetG2FromHandle( *g2ToPtr ); - re->G2API_DuplicateGhoul2Instance( *(CL_G2Map_GetG2FromHandle((g2handleptr_t)rawG2FromHandle)), &g2To ); - CL_G2Map_Update( g2ToPtr, g2To ); + 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 ) { g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo); - CGhoul2Info_v *g2 = CL_G2Map_GetG2FromHandle( *g2HandlePtr ); + CGhoul2Info_v *g2 = cl_g2Mapping.Lookup( *g2HandlePtr ); qboolean ret = re->G2API_HasGhoul2ModelOnIndex( &g2, modelIndex ); - CL_G2Map_Update( g2HandlePtr, g2 ); + cl_g2Mapping.Update( *g2HandlePtr, g2 ); return ret; } @@ -765,23 +727,23 @@ static qboolean CL_G2API_RemoveGhoul2Model( void *ghlInfo, int modelIndex ) { g_G2AllocServer = 0; #endif g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo); - CGhoul2Info_v* g2 = CL_G2Map_GetG2FromHandle(*g2HandlePtr); + CGhoul2Info_v* g2 = cl_g2Mapping.Lookup(*g2HandlePtr); qboolean ret = re->G2API_RemoveGhoul2Model( &g2, modelIndex ); - CL_G2Map_Update( g2HandlePtr, g2 ); + 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; @@ -791,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 ); } @@ -860,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 ); } @@ -869,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; } @@ -892,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 ) { @@ -908,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 ) { @@ -972,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 3d7cfdb901..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,44 +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 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 @@ -329,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 ); @@ -356,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) { @@ -364,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 ) { @@ -372,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 ) { @@ -381,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 ) { @@ -391,7 +353,7 @@ 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 **rawG2HandlePtr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias ) { @@ -403,9 +365,9 @@ static int CL_G2API_InitGhoul2Model( void **rawG2HandlePtr, const char *fileName g_G2AllocServer = 0; #endif g2handleptr_t* g2HandlePtr = reinterpret_cast(rawG2HandlePtr); - CGhoul2Info_v *g2 = CL_UI_G2Map_GetG2FromHandle( *g2HandlePtr ); + CGhoul2Info_v *g2 = ui_g2Mapping.Lookup( *g2HandlePtr ); int ret = re->G2API_InitGhoul2Model( &g2, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias ); - CL_UI_G2Map_Update( g2HandlePtr, g2 ); + ui_g2Mapping.Update( *g2HandlePtr, g2 ); return ret; } @@ -414,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 ); } @@ -438,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, @@ -472,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, @@ -495,9 +457,9 @@ static void CL_G2API_CleanGhoul2Models( void **rawG2HandlePtr ) { g_G2AllocServer = 0; #endif g2handleptr_t* g2HandlePtr = reinterpret_cast(rawG2HandlePtr); - CGhoul2Info_v *g2 = CL_UI_G2Map_GetG2FromHandle( *g2HandlePtr ); + CGhoul2Info_v *g2 = ui_g2Mapping.Lookup( *g2HandlePtr ); re->G2API_CleanGhoul2Models( &g2 ); - CL_UI_G2Map_Update( g2HandlePtr, g2 ); + ui_g2Mapping.Update( *g2HandlePtr, g2 ); } static qboolean CL_G2API_SetBoneAngles( @@ -518,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, @@ -548,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, @@ -576,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, @@ -602,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; @@ -626,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 @@ -638,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 ) { @@ -646,7 +608,7 @@ 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 *rawG2HandleFrom, void **rawG2HandlePtrTo ) { @@ -659,10 +621,10 @@ static void CL_G2API_DuplicateGhoul2Instance( void *rawG2HandleFrom, void **rawG #endif g2handleptr_t g2HandleFrom = reinterpret_cast(rawG2HandleFrom); g2handleptr_t* g2HandlePtrTo = reinterpret_cast(rawG2HandlePtrTo); - CGhoul2Info_v* g2From = CL_UI_G2Map_GetG2FromHandle(g2HandleFrom); - CGhoul2Info_v *g2To = CL_UI_G2Map_GetG2FromHandle( *g2HandlePtrTo ); + CGhoul2Info_v* g2From = ui_g2Mapping.Lookup(g2HandleFrom); + CGhoul2Info_v *g2To = ui_g2Mapping.Lookup( *g2HandlePtrTo ); re->G2API_DuplicateGhoul2Instance( *g2From, &g2To); - CL_UI_G2Map_Update( g2HandlePtrTo, g2To ); + ui_g2Mapping.Update( *g2HandlePtrTo, g2To ); } // FIXME: shouldn't ghlInfo be a void**? @@ -672,9 +634,9 @@ static qboolean CL_G2API_HasGhoul2ModelOnIndex( void *ghlInfo, int modelIndex ) } g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo); - CGhoul2Info_v *g2 = CL_UI_G2Map_GetG2FromHandle( *g2HandlePtr ); + CGhoul2Info_v *g2 = ui_g2Mapping.Lookup( *g2HandlePtr ); qboolean ret = re->G2API_HasGhoul2ModelOnIndex( &g2, modelIndex ); - CL_UI_G2Map_Update( g2HandlePtr, g2 ); + ui_g2Mapping.Update( *g2HandlePtr, g2 ); return ret; } @@ -688,9 +650,9 @@ static qboolean CL_G2API_RemoveGhoul2Model( void *ghlInfo, int modelIndex ) { g_G2AllocServer = 0; #endif g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo); - CGhoul2Info_v* g2 = CL_UI_G2Map_GetG2FromHandle(*g2HandlePtr); + CGhoul2Info_v* g2 = ui_g2Mapping.Lookup(*g2HandlePtr); qboolean ret = re->G2API_RemoveGhoul2Model( &g2, modelIndex ); - CL_UI_G2Map_Update( g2HandlePtr, g2 ); + ui_g2Mapping.Update( *g2HandlePtr, g2 ); return ret; } @@ -699,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 ) { @@ -707,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 ) { @@ -715,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 ) { @@ -723,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 ) { @@ -731,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 ) { @@ -750,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; } @@ -773,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 ) { @@ -794,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 ) { @@ -802,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 ) { @@ -810,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 ) { @@ -818,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 ); } @@ -828,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..4af8500594 100644 --- a/codemp/game/g_public.h +++ b/codemp/game/g_public.h @@ -302,7 +302,7 @@ typedef struct sharedEntityMapper_s { #else struct Vehicle_s **m_pVehicle; //vehicle data #endif - void **ghoul2; //g2 instance + void **ghoul2; //g2 instance - CGhoul2Info_v** in native, g2handle_t** in QVM; resolve via SV_EntityMapperReadGhoul2 & sv_g2Mapping int *localAnimIndex; //index locally (game/cgame) to anim data for this skel vec3_t *modelScale; //needed for g2 collision 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/server/server.h b/codemp/server/server.h index 62cfd8a12a..e28de66373 100644 --- a/codemp/server/server.h +++ b/codemp/server/server.h @@ -393,9 +393,6 @@ 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 ); -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 ); @@ -408,7 +405,7 @@ ENTITYMAP_READER_PROTO( playerState_t*, SV_EntityMapperReadPlayerState ); #endif ENTITYMAP_READER_PROTO( parms_t*, SV_EntityMapperReadParms ); -void *SV_EntityMapperReadGhoul2( void **inPtr ); +g2handleptr_t SV_EntityMapperReadGhoul2( void **inPtr ); // // sv_bot.c diff --git a/codemp/server/sv_gameapi.cpp b/codemp/server/sv_gameapi.cpp index b2afd33031..d0bcd344ad 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,44 +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]; -} - -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 @@ -661,12 +624,12 @@ ENTITYMAP_READER( playerState_t*, SV_EntityMapperReadPlayerState ); #endif ENTITYMAP_READER( parms_t*, SV_EntityMapperReadParms ); -void *SV_EntityMapperReadGhoul2( void **inPtr ) { +g2handleptr_t SV_EntityMapperReadGhoul2( void **inPtr ) { if ( gvm->dllHandle ) { - return *inPtr; + return reinterpret_cast(*inPtr); } else { - // For QVMs the address is actually a handle we have to interpret as uint32_t - return (void*)(intptr_t)(*(uint32_t*)inPtr); + // For QVMs the address is actually a handle we have to interpret as int32_t/g2handle_t + return static_cast(*reinterpret_cast(inPtr)); } } @@ -1686,58 +1649,58 @@ 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 **rawG2HandlePtr, 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 - g2handleptr_t* g2HandlePtr = reinterpret_cast(rawG2HandlePtr); - assert(g2HandlePtr); - CGhoul2Info_v *g2 = SV_G2Map_GetG2FromHandle( *g2HandlePtr ); + 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_G2Map_Update( g2HandlePtr, g2 ); + 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 **rawG2HandlePtr ) { @@ -1746,24 +1709,24 @@ static void SV_G2API_CleanGhoul2Models( void **rawG2HandlePtr ) { #endif g2handleptr_t* g2HandlePtr = reinterpret_cast(rawG2HandlePtr); assert(g2HandlePtr); - CGhoul2Info_v *g2 = SV_G2Map_GetG2FromHandle( *g2HandlePtr ); + CGhoul2Info_v *g2 = sv_g2Mapping.Lookup( *g2HandlePtr ); re->G2API_CleanGhoul2Models( &g2 ); - SV_G2Map_Update( g2HandlePtr, 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 ); } @@ -1774,7 +1737,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 @@ -1783,12 +1746,12 @@ 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 *rawG2HandleFrom, void **rawG2HandlePtrTo ) { @@ -1799,18 +1762,18 @@ static void SV_G2API_DuplicateGhoul2Instance( void *rawG2HandleFrom, void **rawG g2handleptr_t* g2HandlePtrTo = reinterpret_cast(rawG2HandlePtrTo); if ( !g2HandleFrom || !g2HandlePtrTo ) return; - CGhoul2Info_v *g2 = SV_G2Map_GetG2FromHandle( *g2HandlePtrTo ); - re->G2API_DuplicateGhoul2Instance( *SV_G2Map_GetG2FromHandle(g2HandleFrom), &g2 ); - SV_G2Map_Update( g2HandlePtrTo, g2 ); + 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 ) { g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo); assert(g2HandlePtr); - CGhoul2Info_v *g2 = SV_G2Map_GetG2FromHandle( *g2HandlePtr ); + CGhoul2Info_v *g2 = sv_g2Mapping.Lookup( *g2HandlePtr ); qboolean ret = re->G2API_HasGhoul2ModelOnIndex( &g2, modelIndex ); - SV_G2Map_Update( g2HandlePtr, g2 ); + sv_g2Mapping.Update( *g2HandlePtr, g2 ); return ret; } @@ -1821,9 +1784,9 @@ static qboolean SV_G2API_RemoveGhoul2Model( void *ghlInfo, int modelIndex ) { #endif g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo); assert(g2HandlePtr); - CGhoul2Info_v *g2 = SV_G2Map_GetG2FromHandle( *g2HandlePtr ); + CGhoul2Info_v *g2 = sv_g2Mapping.Lookup( *g2HandlePtr ); qboolean ret = re->G2API_RemoveGhoul2Model( &g2, modelIndex ); - SV_G2Map_Update( g2HandlePtr, g2 ); + sv_g2Mapping.Update( *g2HandlePtr, g2 ); return ret; } @@ -1834,57 +1797,57 @@ static qboolean SV_G2API_RemoveGhoul2Models( void *ghlInfo ) { #endif g2handleptr_t* g2HandlePtr = reinterpret_cast(ghlInfo); assert(g2HandlePtr); - CGhoul2Info_v *g2 = SV_G2Map_GetG2FromHandle( *g2HandlePtr ); + CGhoul2Info_v *g2 = sv_g2Mapping.Lookup( *g2HandlePtr ); qboolean ret = re->G2API_RemoveGhoul2Models( &g2 ); - SV_G2Map_Update( g2HandlePtr, 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 ); } @@ -1894,7 +1857,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; } @@ -1917,7 +1880,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 ) { @@ -1934,48 +1897,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 ) { @@ -1987,12 +1950,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 ); } diff --git a/codemp/server/sv_world.cpp b/codemp/server/sv_world.cpp index 2db0ec2724..d6e195bd79 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; @@ -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->ghoul2)), 0)); } #endif @@ -754,11 +757,11 @@ Ghoul2 Insert Start touch->s->NPC_class == CLASS_VEHICLE && SV_EntityMapperReadVehicle(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->ghoul2)), 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->ghoul2)), angles, touch->r->currentOrigin, sv.time, touch->s->number, clip->start, clip->end, *touch->modelScale, G2VertSpaceServer, 0, clip->useLod, fRadius); } tN = 0; From 38fea0a61bdd24f5e19b1c2fdfa60615047b9caf Mon Sep 17 00:00:00 2001 From: Willi Schinmeyer Date: Mon, 21 Apr 2025 10:32:52 +0200 Subject: [PATCH 3/5] Make sharedEntityMapper_t.ghoul2 a union This expresses its dual nature a bit more clearly than a void pointer. --- codemp/game/g_public.h | 7 +++++-- codemp/server/server.h | 2 +- codemp/server/sv_gameapi.cpp | 16 ++++++++-------- codemp/server/sv_world.cpp | 8 ++++---- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/codemp/game/g_public.h b/codemp/game/g_public.h index 4af8500594..d84c76c624 100644 --- a/codemp/game/g_public.h +++ b/codemp/game/g_public.h @@ -260,7 +260,7 @@ typedef struct sharedEntity_qvm_s { //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 + g2handle_t ghoul2; //g2 instance int localAnimIndex; //index locally (game/cgame) to anim data for this skel vec3_t modelScale; //needed for g2 collision @@ -302,7 +302,10 @@ typedef struct sharedEntityMapper_s { #else struct Vehicle_s **m_pVehicle; //vehicle data #endif - void **ghoul2; //g2 instance - CGhoul2Info_v** in native, g2handle_t** in QVM; resolve via SV_EntityMapperReadGhoul2 & sv_g2Mapping + union { // use SV_EntityMapperReadGhoul2 to correctly dereference this + 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 diff --git a/codemp/server/server.h b/codemp/server/server.h index e28de66373..5aaf278b78 100644 --- a/codemp/server/server.h +++ b/codemp/server/server.h @@ -405,7 +405,7 @@ ENTITYMAP_READER_PROTO( playerState_t*, SV_EntityMapperReadPlayerState ); #endif ENTITYMAP_READER_PROTO( parms_t*, SV_EntityMapperReadParms ); -g2handleptr_t SV_EntityMapperReadGhoul2( void **inPtr ); +g2handleptr_t SV_EntityMapperReadGhoul2( sharedEntityMapper_t *svEnt ); // // sv_bot.c diff --git a/codemp/server/sv_gameapi.cpp b/codemp/server/sv_gameapi.cpp index d0bcd344ad..38d6c80c29 100644 --- a/codemp/server/sv_gameapi.cpp +++ b/codemp/server/sv_gameapi.cpp @@ -541,7 +541,7 @@ static void SV_UpdateSharedEntitiesMapping( void ) { entM->s = &ent->s; entM->playerState = &ent->playerState; entM->m_pVehicle = &ent->m_pVehicle; - entM->ghoul2 = &ent->ghoul2; + entM->ghoul2Native = reinterpret_cast(&ent->ghoul2); entM->localAnimIndex = &ent->localAnimIndex; entM->modelScale = &ent->modelScale; entM->r = &ent->r; @@ -579,7 +579,7 @@ static void SV_UpdateSharedEntitiesMapping( void ) { #else entM->m_pVehicle = (struct Vehicle_s**)&ent->m_pVehicle; #endif - entM->ghoul2 = (void**)&ent->ghoul2; + entM->ghoul2QVM = &ent->ghoul2; entM->localAnimIndex = &ent->localAnimIndex; entM->modelScale = &ent->modelScale; entM->r = &ent->r; @@ -624,12 +624,12 @@ ENTITYMAP_READER( playerState_t*, SV_EntityMapperReadPlayerState ); #endif ENTITYMAP_READER( parms_t*, SV_EntityMapperReadParms ); -g2handleptr_t SV_EntityMapperReadGhoul2( void **inPtr ) { - if ( gvm->dllHandle ) { - return reinterpret_cast(*inPtr); - } else { - // For QVMs the address is actually a handle we have to interpret as int32_t/g2handle_t - return static_cast(*reinterpret_cast(inPtr)); +g2handleptr_t SV_EntityMapperReadGhoul2(sharedEntityMapper_t* svEnt) { + if (gvm->dllHandle) { + return *svEnt->ghoul2Native; + } + else { + return static_cast(*svEnt->ghoul2QVM); } } diff --git a/codemp/server/sv_world.cpp b/codemp/server/sv_world.cpp index d6e195bd79..44a319cec0 100644 --- a/codemp/server/sv_world.cpp +++ b/codemp/server/sv_world.cpp @@ -703,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; @@ -747,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_g2Mapping.Lookup(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 @@ -757,11 +757,11 @@ Ghoul2 Insert Start touch->s->NPC_class == CLASS_VEHICLE && SV_EntityMapperReadVehicle(touch->m_pVehicle)) { //for vehicles cache the transform data. - re->G2API_CollisionDetectCache(G2Trace, *sv_g2Mapping.Lookup(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_g2Mapping.Lookup(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; From 105647d355aeee0e1fdd7e84c2e0953ad1c1f015 Mon Sep 17 00:00:00 2001 From: Willi Schinmeyer Date: Mon, 21 Apr 2025 11:58:30 +0200 Subject: [PATCH 4/5] Use union for pointers in sharedEntityMapper_t It seems dangerous to pretend that the pointers to pointers inside sharedEntityMapper_t are all ordinary pointers. Instead, let's use a union type to clearly distinguish between ordinary native pointers and 32-bit pointers into QVM memory that need to be translated first. I chose to only use a single union-pointer-type, instead of one per pointed-to type, for simplicity. I added some light type annotations using no-op defines, but there's no actual type checking. I did all this in the pursuit of properly marking Vehicle_t as having different memory layouts in native and QVM. It is only used for null-checks at the moment, which is safe, but if somebody were to try to access its fields, they need to be aware of the type mismatch. --- codemp/game/g_public.h | 60 +++++++++++++--------- codemp/icarus/GameInterface.cpp | 12 ++--- codemp/icarus/Q3_Interface.cpp | 2 +- codemp/qcommon/msg.cpp | 2 +- codemp/qcommon/q_shared.h | 5 ++ codemp/server/server.h | 13 +---- codemp/server/sv_gameapi.cpp | 90 ++++++++++++++------------------- codemp/server/sv_snapshot.cpp | 2 +- codemp/server/sv_world.cpp | 2 +- 9 files changed, 91 insertions(+), 97 deletions(-) diff --git a/codemp/game/g_public.h b/codemp/game/g_public.h index d84c76c624..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,10 +261,10 @@ 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 + 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,26 @@ 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 - union { // use SV_EntityMapperReadGhoul2 to correctly dereference this + 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 }; @@ -315,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..3b331d228a 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 ); @@ -334,7 +334,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 +647,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/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 1f5864c0be..8befd7f494 100644 --- a/codemp/qcommon/q_shared.h +++ b/codemp/qcommon/q_shared.h @@ -155,6 +155,11 @@ typedef int32_t qhandle_t, thandle_t, fxHandle_t, sfxHandle_t, fileHandle_t, cli // 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 5aaf278b78..c68c776b04 100644 --- a/codemp/server/server.h +++ b/codemp/server/server.h @@ -393,18 +393,7 @@ void SV_InitGameProgs ( void ); void SV_ShutdownGameProgs ( void ); qboolean SV_inPVS (const vec3_t p1, const vec3_t p2); -#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_EntityMapperReadPointer(pointerMapper_t ptr); g2handleptr_t SV_EntityMapperReadGhoul2( sharedEntityMapper_t *svEnt ); // diff --git a/codemp/server/sv_gameapi.cpp b/codemp/server/sv_gameapi.cpp index 38d6c80c29..18241f3b0d 100644 --- a/codemp/server/sv_gameapi.cpp +++ b/codemp/server/sv_gameapi.cpp @@ -538,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->ghoul2Native = reinterpret_cast(&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; @@ -573,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->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; @@ -605,24 +601,14 @@ 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; } - -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 ); + else { + return VM_ArgPtr(*ptr.qvm); + } +} g2handleptr_t SV_EntityMapperReadGhoul2(sharedEntityMapper_t* svEnt) { if (gvm->dllHandle) { 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 44a319cec0..700cf1df74 100644 --- a/codemp/server/sv_world.cpp +++ b/codemp/server/sv_world.cpp @@ -755,7 +755,7 @@ 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_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); } From f81e89390cae67f7cb8ad33d98048919f6604e7f Mon Sep 17 00:00:00 2001 From: Willi Schinmeyer Date: Mon, 21 Apr 2025 12:24:23 +0200 Subject: [PATCH 5/5] remove client_t.gentity and SV_GentityNum We need to use the gentityMapper instead, to properly handle QVM. --- codemp/icarus/GameInterface.cpp | 9 +++++---- codemp/server/server.h | 5 +---- codemp/server/sv_bot.cpp | 5 ++--- codemp/server/sv_client.cpp | 2 -- codemp/server/sv_game.cpp | 15 --------------- codemp/server/sv_gameapi.cpp | 1 - codemp/server/sv_init.cpp | 1 - 7 files changed, 8 insertions(+), 30 deletions(-) diff --git a/codemp/icarus/GameInterface.cpp b/codemp/icarus/GameInterface.cpp index 3b331d228a..229c2a32b2 100644 --- a/codemp/icarus/GameInterface.cpp +++ b/codemp/icarus/GameInterface.cpp @@ -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; } } diff --git a/codemp/server/server.h b/codemp/server/server.h index c68c776b04..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,12 +380,10 @@ 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 ); 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 18241f3b0d..43c62e003a 100644 --- a/codemp/server/sv_gameapi.cpp +++ b/codemp/server/sv_gameapi.cpp @@ -3017,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