diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ddedaf4a3..29a64b6d7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -277,7 +277,7 @@ jobs: github.event.action == 'published' && startsWith(github.ref, 'refs/tags/') run: | - 7z a -tzip rehlds-bin-${{ env.APP_VERSION }}.zip bin/linux32/ hlsdk/ + 7z a -tzip rehlds-bin-${{ env.APP_VERSION }}.zip bin/ hlsdk/ 7z a -t7z -m0=lzma2 -mx=9 -mfb=64 -aoa rehlds-dbg-${{ env.APP_VERSION }}.7z debug/ - name: Publish artifacts diff --git a/rehlds/HLTV/Core/src/BSPModel.cpp b/rehlds/HLTV/Core/src/BSPModel.cpp index 15f091d0b..65892bcfd 100644 --- a/rehlds/HLTV/Core/src/BSPModel.cpp +++ b/rehlds/HLTV/Core/src/BSPModel.cpp @@ -170,7 +170,7 @@ byte *BSPModel::LeafPVS(mleaf_t *leaf) byte *BSPModel::DecompressVis(unsigned char *in) { - static unsigned char decompressed[MODEL_MAX_PVS]; + static unsigned char decompressed[MAX_MAP_LEAFS / 8]; if (in == nullptr) { return m_novis; } diff --git a/rehlds/HLTV/Core/src/BSPModel.h b/rehlds/HLTV/Core/src/BSPModel.h index 259960fcb..1ceb8dfdc 100644 --- a/rehlds/HLTV/Core/src/BSPModel.h +++ b/rehlds/HLTV/Core/src/BSPModel.h @@ -32,6 +32,7 @@ #include "l_studio.h" #include "edict.h" +#include "bspfile.h" // values for model_t's needload #define NL_PRESENT 0 @@ -87,9 +88,7 @@ class BSPModel: public IBSPModel { protected: model_t m_model; - - enum { MODEL_MAX_PVS = 1024 }; - byte m_novis[MODEL_MAX_PVS]; + byte m_novis[MAX_MAP_LEAFS / 8]; byte *m_base; int m_visframecount; diff --git a/rehlds/engine/cmodel.cpp b/rehlds/engine/cmodel.cpp index 1e4851230..3236e1bb4 100644 --- a/rehlds/engine/cmodel.cpp +++ b/rehlds/engine/cmodel.cpp @@ -31,17 +31,17 @@ unsigned char *gPAS; unsigned char *gPVS; int gPVSRowBytes; -unsigned char mod_novis[MODEL_MAX_PVS]; +unsigned char mod_novis[MAX_MAP_LEAFS / 8]; void Mod_Init(void) { SW_Mod_Init(); - Q_memset(mod_novis, 255, MODEL_MAX_PVS); + Q_memset(mod_novis, 0xFF, MAX_MAP_LEAFS / 8); } unsigned char *Mod_DecompressVis(unsigned char *in, model_t *model) { - static unsigned char decompressed[MODEL_MAX_PVS]; + static unsigned char decompressed[MAX_MAP_LEAFS / 8]; if (in == NULL) { diff --git a/rehlds/engine/cmodel.h b/rehlds/engine/cmodel.h index 5b8d5eb1f..dd99cec07 100644 --- a/rehlds/engine/cmodel.h +++ b/rehlds/engine/cmodel.h @@ -29,15 +29,10 @@ #pragma once #include "maintypes.h" -#include "model.h" - -// Looks like no more than 8096 visibility leafs per world model -const int MODEL_MAX_PVS = 1024; extern unsigned char *gPAS; extern unsigned char *gPVS; extern int gPVSRowBytes; -extern unsigned char mod_novis[MODEL_MAX_PVS]; void Mod_Init(void); unsigned char *Mod_DecompressVis(unsigned char *in, model_t *model); diff --git a/rehlds/engine/common.cpp b/rehlds/engine/common.cpp index badf9931b..e70d03ca1 100644 --- a/rehlds/engine/common.cpp +++ b/rehlds/engine/common.cpp @@ -1978,6 +1978,34 @@ NOXREF int COM_ExpandFilename(char *filename) return *filename != 0; } +// small helper function shared by lots of modules +qboolean COM_IsAbsolutePath(const char *pStr) +{ + if (strchr(pStr, ':') || pStr[0] == '/' || pStr[0] == '\\') + return FALSE; + + return TRUE; +} + +qboolean COM_IsValidPath(const char *pszFilename) +{ + if (!pszFilename) + return FALSE; + + if (Q_strlen(pszFilename) <= 0 || + Q_strstr(pszFilename, "\\\\") || // to protect network paths + Q_strstr(pszFilename, ":") || // to protect absolute paths + Q_strstr(pszFilename, "..") || // to protect relative paths + Q_strstr(pszFilename, "~") || + Q_strstr(pszFilename, "\n") || // CFileSystem_Stdio::FS_fopen doesn't allow this + Q_strstr(pszFilename, "\r")) // CFileSystem_Stdio::FS_fopen doesn't allow this + { + return FALSE; + } + + return TRUE; +} + int EXT_FUNC COM_FileSize(const char *filename) { FileHandle_t fp; diff --git a/rehlds/engine/common.h b/rehlds/engine/common.h index 1a7fc081a..94d940480 100644 --- a/rehlds/engine/common.h +++ b/rehlds/engine/common.h @@ -187,6 +187,8 @@ void COM_CreatePath(char *path); NOXREF void COM_CopyFile(char *netpath, char *cachepath); NOXREF int COM_ExpandFilename(char *filename); int COM_FileSize(const char *filename); +qboolean COM_IsAbsolutePath(const char *pStr); +qboolean COM_IsValidPath(const char *pszFilename); unsigned char *COM_LoadFile(const char *path, int usehunk, int *pLength); void COM_FreeFile(void *buffer); void COM_CopyFileChunk(FileHandle_t dst, FileHandle_t src, int nSize); diff --git a/rehlds/engine/host_cmd.cpp b/rehlds/engine/host_cmd.cpp index d76815cb8..3d6558c2b 100644 --- a/rehlds/engine/host_cmd.cpp +++ b/rehlds/engine/host_cmd.cpp @@ -205,11 +205,19 @@ void Host_Motd_f(void) char *next; pFileList = motdfile.string; - if (*pFileList == '/' || Q_strstr(pFileList, ":") || Q_strstr(pFileList, "..") || Q_strstr(pFileList, "\\")) + if (!COM_IsValidPath(pFileList) || COM_IsAbsolutePath(pFileList)) { Con_Printf("Unable to open %s (contains illegal characters)\n", pFileList); return; } + + const char *pchExtension = COM_FileExtension(pFileList); + if (Q_stricmp(pchExtension, "txt") != 0) + { + Con_Printf("Invalid motdfile name %s (wrong file extension, must be .txt)\n", pFileList); + return; + } + pFile = FS_Open(pFileList, "rb"); if (!pFile) { diff --git a/rehlds/engine/pr_cmds.cpp b/rehlds/engine/pr_cmds.cpp index e1d956a7e..e83cbb429 100644 --- a/rehlds/engine/pr_cmds.cpp +++ b/rehlds/engine/pr_cmds.cpp @@ -1447,6 +1447,9 @@ int EXT_FUNC PF_precache_model_I_internal(const char *s) { for (int i = 0; i < MAX_MODELS; i++) { + if (!g_psv.model_precache[i]) + continue; + // use case-sensitive names to increase performance #ifdef REHLDS_FIXES if (!Q_strcmp(g_psv.model_precache[i], s)) @@ -1545,7 +1548,7 @@ int EXT_FUNC PF_precache_generic_I_internal(const char *s) { for (int i = 0; i < MAX_GENERIC; i++) { - if (!Q_stricmp(g_psv.generic_precache[i], s)) + if (g_psv.generic_precache[i] && !Q_stricmp(g_psv.generic_precache[i], s)) return i; } Host_Error("%s: '%s' Precache can only be done in spawn functions", __func__, s); diff --git a/rehlds/engine/r_studio.cpp b/rehlds/engine/r_studio.cpp index 5b12b835e..4124bf67f 100644 --- a/rehlds/engine/r_studio.cpp +++ b/rehlds/engine/r_studio.cpp @@ -881,6 +881,15 @@ void EXT_FUNC AnimationAutomove(const edict_t *pEdict, float flTime) void EXT_FUNC GetBonePosition(const edict_t *pEdict, int iBone, float *rgflOrigin, float *rgflAngles) { pstudiohdr = (studiohdr_t *)Mod_Extradata(g_psv.models[pEdict->v.modelindex]); + +#ifdef REHLDS_FIXES + if (!pstudiohdr) + return; + + if (iBone < 0 || iBone >= pstudiohdr->numbones) + return; // invalid bone +#endif + g_pSvBlendingAPI->SV_StudioSetupBones( g_psv.models[pEdict->v.modelindex], pEdict->v.frame, @@ -906,14 +915,23 @@ void EXT_FUNC GetAttachment(const edict_t *pEdict, int iAttachment, float *rgflO mstudioattachment_t *pattachment; vec3_t angles; - angles[0] = -pEdict->v.angles[0]; - angles[1] = pEdict->v.angles[1]; - angles[2] = pEdict->v.angles[2]; - pstudiohdr = (studiohdr_t *)Mod_Extradata(g_psv.models[pEdict->v.modelindex]); + +#ifdef REHLDS_FIXES + if (!pstudiohdr) + return; + + if (iAttachment < 0 || iAttachment >= pstudiohdr->numattachments) + return; // invalid attachment +#endif + pattachment = (mstudioattachment_t *)((char *)pstudiohdr + pstudiohdr->attachmentindex); pattachment += iAttachment; + angles[0] = -pEdict->v.angles[0]; + angles[1] = pEdict->v.angles[1]; + angles[2] = pEdict->v.angles[2]; + g_pSvBlendingAPI->SV_StudioSetupBones( g_psv.models[pEdict->v.modelindex], pEdict->v.frame, diff --git a/rehlds/engine/server.h b/rehlds/engine/server.h index 2b10515a8..4bdd7efb6 100644 --- a/rehlds/engine/server.h +++ b/rehlds/engine/server.h @@ -405,7 +405,6 @@ enum GameType_e extern GameType_e g_eGameType; -extern int fatbytes; extern int giNextUserMsg; extern int hashstrings_collisions; @@ -418,10 +417,6 @@ extern delta_t *g_pweapondelta; extern delta_t *g_pusercmddelta; #endif -extern unsigned char fatpvs[1024]; -extern int fatpasbytes; -extern unsigned char fatpas[1024]; - extern int gPacketSuppressed; extern char localinfo[MAX_LOCALINFO]; diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index cb67538e0..fa79fe9c5 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -680,22 +680,22 @@ qboolean SV_BuildSoundMsg(edict_t *entity, int channel, const char *sample, int if (volume < 0 || volume > 255) { - Con_Printf("%s: volume = %i", __func__, volume); + Con_Printf("%s: volume = %i\n", __func__, volume); volume = (volume < 0) ? 0 : 255; } if (attenuation < 0.0f || attenuation > 4.0f) { - Con_Printf("%s: attenuation = %f", __func__, attenuation); + Con_Printf("%s: attenuation = %f\n", __func__, attenuation); attenuation = (attenuation < 0.0f) ? 0.0f : 4.0f; } if (channel < 0 || channel > 7) { - Con_Printf("%s: channel = %i", __func__, channel); + Con_Printf("%s: channel = %i\n", __func__, channel); channel = (channel < 0) ? CHAN_AUTO : CHAN_NETWORKVOICE_BASE; } if (pitch < 0 || pitch > 255) { - Con_Printf("%s: pitch = %i", __func__, pitch); + Con_Printf("%s: pitch = %i\n", __func__, pitch); pitch = (pitch < 0) ? 0 : 255; } @@ -707,7 +707,7 @@ qboolean SV_BuildSoundMsg(edict_t *entity, int channel, const char *sample, int sound_num = Q_atoi(sample + 1); if (sound_num >= CVOXFILESENTENCEMAX) { - Con_Printf("%s: invalid sentence number: %s", __func__, sample + 1); + Con_Printf("%s: invalid sentence number: %s\n", __func__, sample + 1); return FALSE; } } @@ -1112,8 +1112,18 @@ void SV_SendServerinfo_internal(sizebuf_t *msg, client_t *client) else MSG_WriteByte(msg, 0); - COM_FileBase(com_gamedir, message); - MSG_WriteString(msg, message); + const char *pszGameDir = message; + +#ifdef REHLDS_FIXES + // Give the client a chance to connect in to the server with different game + const char *gd = Info_ValueForKey(client->userinfo, "_gd"); + if (gd[0]) + pszGameDir = gd; + else +#endif + COM_FileBase(com_gamedir, message); + + MSG_WriteString(msg, pszGameDir); MSG_WriteString(msg, Cvar_VariableString("hostname")); MSG_WriteString(msg, g_psv.modelname); @@ -4030,9 +4040,10 @@ void SV_EmitEvents_internal(client_t *cl, packet_entities_t *pack, sizebuf_t *ms } int fatbytes; -unsigned char fatpvs[1024]; +unsigned char fatpvs[MAX_MAP_LEAFS / 8]; + int fatpasbytes; -unsigned char fatpas[1024]; +unsigned char fatpas[MAX_MAP_LEAFS / 8]; void SV_AddToFatPVS(vec_t *org, mnode_t *node) { @@ -4074,6 +4085,9 @@ unsigned char* EXT_FUNC SV_FatPVS(float *org) #endif // REHLDS_FIXES fatbytes = (g_psv.worldmodel->numleafs + 31) >> 3; + if (fatbytes >= (MAX_MAP_LEAFS / 8)) + Sys_Error("%s: MAX_MAP_LEAFS limit exceeded\n", __func__); + Q_memset(fatpvs, 0, fatbytes); SV_AddToFatPVS(org, g_psv.worldmodel->nodes); return fatpvs; @@ -4131,6 +4145,9 @@ unsigned char* EXT_FUNC SV_FatPAS(float *org) #endif // REHLDS_FIXES fatpasbytes = (g_psv.worldmodel->numleafs + 31) >> 3; + if (fatpasbytes >= (MAX_MAP_LEAFS / 8)) + Sys_Error("%s: MAX_MAP_LEAFS limit exceeded\n", __func__); + Q_memset(fatpas, 0, fatpasbytes); SV_AddToFatPAS(org, g_psv.worldmodel->nodes); return fatpas; @@ -6155,7 +6172,7 @@ int SV_SpawnServer(qboolean bIsDemo, char *server, char *startspot) if (g_psvs.maxclients <= 1) { int row = (g_psv.worldmodel->numleafs + 7) / 8; - if (row < 0 || row > MODEL_MAX_PVS) + if (row < 0 || row > (MAX_MAP_LEAFS / 8)) { Sys_Error("%s: oversized g_psv.worldmodel->numleafs: %i", __func__, g_psv.worldmodel->numleafs); } diff --git a/rehlds/engine/sv_user.cpp b/rehlds/engine/sv_user.cpp index 5e2c0018b..0912cc089 100644 --- a/rehlds/engine/sv_user.cpp +++ b/rehlds/engine/sv_user.cpp @@ -511,6 +511,14 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check) pe->vuser4[2] = check->v.vuser4[2]; } +bool EXT_FUNC SV_AllowPhysent_mod(edict_t* check, edict_t* sv_player) { + return true; +} + +bool SV_AllowPhysent(edict_t* check, edict_t* sv_player) { + return g_RehldsHookchains.m_SV_AllowPhysent.callChain(SV_AllowPhysent_mod, check, sv_player); +} + void SV_AddLinksToPM_(areanode_t *node, float *pmove_mins, float *pmove_maxs) { struct link_s *l; @@ -547,6 +555,11 @@ void SV_AddLinksToPM_(areanode_t *node, float *pmove_mins, float *pmove_maxs) if (check->v.solid != SOLID_BSP && check->v.solid != SOLID_BBOX && check->v.solid != SOLID_SLIDEBOX && check->v.solid != SOLID_NOT) continue; + // Apply our own custom checks + if (!SV_AllowPhysent(check, sv_player)) { + continue; + } + e = NUM_FOR_EDICT(check); ve = &pmove->visents[pmove->numvisent]; pmove->numvisent = pmove->numvisent + 1; diff --git a/rehlds/public/rehlds/bspfile.h b/rehlds/public/rehlds/bspfile.h index 3c4dfee7b..4998fcf81 100644 --- a/rehlds/public/rehlds/bspfile.h +++ b/rehlds/public/rehlds/bspfile.h @@ -32,6 +32,7 @@ #define HLBSP_VERSION 30 // half-life regular version #define MAX_MAP_HULLS 4 +#define MAX_MAP_LEAFS 32767 // signed short limit #define CONTENTS_ORIGIN -7 // removed at csg time #define CONTENTS_CLIP -8 // changed to contents_solid diff --git a/rehlds/public/rehlds/rehlds_api.h b/rehlds/public/rehlds/rehlds_api.h index debea3317..bc8358194 100644 --- a/rehlds/public/rehlds/rehlds_api.h +++ b/rehlds/public/rehlds/rehlds_api.h @@ -37,7 +37,7 @@ #include "pr_dlls.h" #define REHLDS_API_VERSION_MAJOR 3 -#define REHLDS_API_VERSION_MINOR 12 +#define REHLDS_API_VERSION_MINOR 13 //Steam_NotifyClientConnect hook typedef IHookChain IRehldsHook_Steam_NotifyClientConnect; @@ -255,6 +255,10 @@ typedef IVoidHookChainRegistry IRehldsHook_SV_ClientPrintf; typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_ClientPrintf; +//SV_AllowPhysent hook +typedef IHookChain IRehldsHook_SV_AllowPhysent; +typedef IHookChainRegistry IRehldsHookRegistry_SV_AllowPhysent; + class IRehldsHookchains { public: virtual ~IRehldsHookchains() { } @@ -313,6 +317,7 @@ class IRehldsHookchains { virtual IRehldsHookRegistry_EV_Precache* EV_Precache() = 0; virtual IRehldsHookRegistry_SV_AddResource* SV_AddResource() = 0; virtual IRehldsHookRegistry_SV_ClientPrintf* SV_ClientPrintf() = 0; + virtual IRehldsHookRegistry_SV_AllowPhysent* SV_AllowPhysent() = 0; }; struct RehldsFuncs_t { diff --git a/rehlds/rehlds/rehlds_api_impl.cpp b/rehlds/rehlds/rehlds_api_impl.cpp index 5a41c1e96..d18622036 100644 --- a/rehlds/rehlds/rehlds_api_impl.cpp +++ b/rehlds/rehlds/rehlds_api_impl.cpp @@ -879,6 +879,10 @@ IRehldsHookRegistry_SV_ClientPrintf* CRehldsHookchains::SV_ClientPrintf(){ return &m_SV_ClientPrintf; } +IRehldsHookRegistry_SV_AllowPhysent* CRehldsHookchains::SV_AllowPhysent() { + return &m_SV_AllowPhysent; +} + int EXT_FUNC CRehldsApi::GetMajorVersion() { return REHLDS_API_VERSION_MAJOR; diff --git a/rehlds/rehlds/rehlds_api_impl.h b/rehlds/rehlds/rehlds_api_impl.h index 28b1c3e74..699bd1649 100644 --- a/rehlds/rehlds/rehlds_api_impl.h +++ b/rehlds/rehlds/rehlds_api_impl.h @@ -250,6 +250,10 @@ typedef IVoidHookChainRegistryImpl CRehldsHook_SV_ClientPrintf; typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_SV_ClientPrintf; +//SV_AllowPhysent hook +typedef IHookChainImpl CRehldsHook_SV_AllowPhysent; +typedef IHookChainRegistryImpl CRehldsHookRegistry_SV_AllowPhysent; + class CRehldsHookchains : public IRehldsHookchains { public: CRehldsHookRegistry_Steam_NotifyClientConnect m_Steam_NotifyClientConnect; @@ -306,6 +310,7 @@ class CRehldsHookchains : public IRehldsHookchains { CRehldsHookRegistry_EV_Precache m_EV_Precache; CRehldsHookRegistry_SV_AddResource m_SV_AddResource; CRehldsHookRegistry_SV_ClientPrintf m_SV_ClientPrintf; + CRehldsHookRegistry_SV_AllowPhysent m_SV_AllowPhysent; public: EXT_FUNC virtual IRehldsHookRegistry_Steam_NotifyClientConnect* Steam_NotifyClientConnect(); @@ -362,6 +367,7 @@ class CRehldsHookchains : public IRehldsHookchains { EXT_FUNC virtual IRehldsHookRegistry_EV_Precache* EV_Precache(); EXT_FUNC virtual IRehldsHookRegistry_SV_AddResource* SV_AddResource(); EXT_FUNC virtual IRehldsHookRegistry_SV_ClientPrintf* SV_ClientPrintf(); + EXT_FUNC virtual IRehldsHookRegistry_SV_AllowPhysent* SV_AllowPhysent(); }; extern CRehldsHookchains g_RehldsHookchains; diff --git a/rehlds/version/version.h b/rehlds/version/version.h index 9c1ad7184..55a454b1e 100644 --- a/rehlds/version/version.h +++ b/rehlds/version/version.h @@ -6,5 +6,5 @@ #pragma once #define VERSION_MAJOR 3 -#define VERSION_MINOR 12 +#define VERSION_MINOR 13 #define VERSION_MAINTENANCE 0