diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 5e9f100cc..29a64b6d7 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -14,7 +14,7 @@ on:
jobs:
windows:
name: 'Windows'
- runs-on: windows-latest
+ runs-on: windows-2019
env:
solution: 'msvc/ReHLDS.sln'
@@ -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/README.md b/README.md
index 52e965ce4..2f41d254a 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ ReHLDS is a result of reverse engineering of original HLDS (build 6152/6153) usi
Along with reverse engineering, a lot of defects and (potential) bugs were found and fixed
-You can try play on one of the servers that using rehlds: [Game Tracker](http://www.gametracker.com/search/?search_by=server_variable&search_by2=sv_version)
+You can try playing on one of many servers that are using ReHLDS: [Game Tracker](http://www.gametracker.com/search/?search_by=server_variable&search_by2=sv_version)
## Goals of the project
@@ -51,7 +51,8 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
- sv_rehlds_stringcmdrate_burst_punish // Time in minutes for which the player will be banned (0 - Permanent, use a negative number for a kick). Default: 5
- sv_rehlds_userinfo_transmitted_fields // Userinfo fields only with these keys will be transmitted to clients via network. If not set then all fields will be transmitted (except prefixed with underscore). Each key must be prefixed by backslash, for example "\name\model\*sid\*hltv\bottomcolor\topcolor". See [wiki](https://github.com/dreamstalker/rehlds/wiki/Userinfo-keys) to collect sufficient set of keys for your server. Default: ""
- sv_rehlds_attachedentities_playeranimationspeed_fix // Fixes bug with gait animation speed increase when player has some attached entities (aiments). Can cause animation lags when cl_updaterate is low. Default: 0
-
- sv_rehlds_maxclients_from_single_ip // Limit number of connections from the single ip address. Default: 5
+
- sv_rehlds_maxclients_from_single_ip // Limit number of connections at the same time from single IP address, not confuse to already connected players. Default: 5
+
- sv_rehlds_local_gametime <1|0> // A feature of local gametime which decrease "lags" if you run same map for a long time. Default: 0
- sv_use_entity_file // Use custom entity file for a map. Path to an entity file will be "maps/[map name].ent". 0 - use original entities. 1 - use .ent files from maps directory. 2 - use .ent files from maps directory and create new .ent file if not exist.
- sv_usercmd_custom_random_seed // When enabled server will populate an additional random seed independent of the client. Default: 0
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/common/cvardef.h b/rehlds/common/cvardef.h
index aea0f9e03..5d9e45ec4 100644
--- a/rehlds/common/cvardef.h
+++ b/rehlds/common/cvardef.h
@@ -47,4 +47,16 @@ struct cvar_listener_t
const char *name;
};
+typedef void (*pfnCvar_HookVariable_t) (cvar_t *pCvar);
+
+struct cvarhook_t
+{
+ pfnCvar_HookVariable_t hook;
+
+ cvar_t *cvar;
+ cvarhook_t *next;
+};
+
+qboolean Cvar_HookVariable(const char *var_name, cvarhook_t *pHook);
+
#endif // CVARDEF_H
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 c9f07a656..e70d03ca1 100644
--- a/rehlds/engine/common.cpp
+++ b/rehlds/engine/common.cpp
@@ -1446,31 +1446,64 @@ char *COM_FileExtension(char *in)
#endif // #ifdef REHLDS_FIXES
}
-// Fills "out" with the file name without path and extension.
+// Fills "out" with the file name without path and extension
void COM_FileBase(const char *in, char *out)
{
- const char *start, *end;
- int len;
+ COM_FileBase_s(in, out, -1);
+}
- *out = 0;
+// Extracts the base name of a file (no path, no extension, assumes '/' as path separator)
+const char *COM_FileBase_s(const char *in, char *out, int size)
+{
+ if (!in || !in[0])
+ {
+ *out = '\0';
+ return NULL;
+ }
- len = Q_strlen(in);
+ int len = Q_strlen(in);
if (len <= 0)
- return;
+ return NULL;
- start = in + len - 1;
- end = in + len;
- while (start >= in && *start != '/' && *start != '\\')
+ // scan backward for '.'
+ int end = len - 1;
+ while (end && in[end] != '.' && !PATHSEPARATOR(in[end]))
+ end--;
+
+ // no '.', copy to end
+ if (in[end] != '.')
{
- if (*start == '.')
- end = start;
+ end = len - 1;
+ }
+ else
+ {
+ // Found ',', copy to left of '.'
+ end--;
+ }
+
+ // Scan backward for '/'
+ int start = len - 1;
+ while (start >= 0 && !PATHSEPARATOR(in[start]))
start--;
+
+ if (start < 0 || !PATHSEPARATOR(in[start]))
+ {
+ start = 0;
+ }
+ else
+ {
+ start++;
}
- start++;
- len = end - start;
- Q_strncpy(out, start, len);
- out[len] = 0;
+ // Length of new sting
+ int maxcopy = end - start + 1;
+ if (size >= 0 && maxcopy >= size)
+ return NULL;
+
+ // Copy partial string
+ Q_strncpy(out, &in[start], maxcopy);
+ out[maxcopy] = '\0';
+ return out;
}
void COM_DefaultExtension(char *path, char *extension)
@@ -1945,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;
@@ -1962,7 +2023,10 @@ int EXT_FUNC COM_FileSize(const char *filename)
unsigned char* EXT_FUNC COM_LoadFile(const char *path, int usehunk, int *pLength)
{
- char base[33];
+ if (!path || !path[0])
+ return NULL;
+
+ char base[MAX_PATH];
unsigned char *buf = NULL;
#ifndef SWDS
@@ -1982,8 +2046,10 @@ unsigned char* EXT_FUNC COM_LoadFile(const char *path, int usehunk, int *pLength
}
int len = FS_Size(hFile);
- COM_FileBase(path, base);
- base[32] = 0;
+ if (!COM_FileBase_s(path, base, sizeof(base)))
+ Sys_Error("%s: Bad path length: %s", __func__, path);
+
+ base[32] = '\0';
switch (usehunk)
{
diff --git a/rehlds/engine/common.h b/rehlds/engine/common.h
index 22d07e998..94d940480 100644
--- a/rehlds/engine/common.h
+++ b/rehlds/engine/common.h
@@ -169,6 +169,7 @@ NOXREF char *COM_SkipPath(char *pathname);
void COM_StripExtension(char *in, char *out);
char *COM_FileExtension(char *in);
void COM_FileBase(const char *in, char *out);
+const char *COM_FileBase_s(const char *in, char *out, int size);
void COM_DefaultExtension(char *path, char *extension);
void COM_UngetToken(void);
char *COM_Parse(char *data);
@@ -186,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/cvar.cpp b/rehlds/engine/cvar.cpp
index 9285fa254..7c7ce2b7f 100644
--- a/rehlds/engine/cvar.cpp
+++ b/rehlds/engine/cvar.cpp
@@ -32,7 +32,8 @@
All cvar names are case insensitive! Values not.
*/
-cvar_t *cvar_vars;
+cvar_t *cvar_vars = NULL;
+cvarhook_t *cvar_hooks = NULL;
char cvar_null_string[] = "";
void Cvar_Init(void)
@@ -319,8 +320,10 @@ void Cvar_DirectSet(struct cvar_s *var, const char *value)
void Cvar_Set(const char *var_name, const char *value)
{
- cvar_t *var = Cvar_FindVar(var_name);
+ cvar_t *var;
+ cvarhook_t *pHook;
+ var = Cvar_FindVar(var_name);
if (!var)
{
Con_DPrintf("%s: variable \"%s\" not found\n", __func__, var_name);
@@ -328,6 +331,15 @@ void Cvar_Set(const char *var_name, const char *value)
}
Cvar_DirectSet(var, value);
+
+ for (pHook = cvar_hooks; pHook; pHook = pHook->next)
+ {
+ if (pHook->cvar == var)
+ {
+ pHook->hook(var);
+ break;
+ }
+ }
}
void Cvar_SetValue(const char *var_name, float value)
@@ -730,3 +742,36 @@ void Cvar_CmdInit(void)
{
Cmd_AddCommand("cvarlist", Cmd_CvarList_f);
}
+
+qboolean Cvar_HookVariable(const char *var_name, cvarhook_t *pHook)
+{
+ cvar_t *cvar;
+
+ if (!pHook || !pHook->hook)
+ return FALSE;
+
+ if (pHook->cvar || pHook->next)
+ return FALSE;
+
+ cvar = Cvar_FindVar(var_name);
+ if (!cvar)
+ return FALSE;
+
+ cvarhook_t *pCur = cvar_hooks;
+ pHook->cvar = cvar;
+
+ if (pCur)
+ {
+ while (pCur->next)
+ pCur = pCur->next;
+
+ pCur->next = pHook;
+ }
+ else
+ {
+ // First in chain is null, assign pHook to it
+ cvar_hooks = pHook;
+ }
+
+ return TRUE;
+}
diff --git a/rehlds/engine/host.cpp b/rehlds/engine/host.cpp
index f30cfad65..31560b71f 100644
--- a/rehlds/engine/host.cpp
+++ b/rehlds/engine/host.cpp
@@ -57,7 +57,11 @@ cvar_t deathmatch = { "deathmatch", "0", FCVAR_SERVER, 0.0f, NULL };
cvar_t coop = { "coop", "0", FCVAR_SERVER, 0.0f, NULL };
cvar_t sys_ticrate = { "sys_ticrate", "100.0", 0, 0.0f, NULL };
+
+void sys_timescale_hook_callback(cvar_t *cvar);
+cvarhook_t sys_timescale_hook = { sys_timescale_hook_callback, NULL, NULL };
cvar_t sys_timescale = { "sys_timescale", "1.0", 0, 0.0f, NULL };
+
cvar_t fps_max = { "fps_max", "100.0", FCVAR_ARCHIVE, 0.0f, NULL };
cvar_t host_killtime = { "host_killtime", "0.0", 0, 0.0f, NULL };
cvar_t sv_stats = { "sv_stats", "1", 0, 0.0f, NULL };
@@ -143,6 +147,9 @@ void Host_InitLocal(void)
Host_InitCommands();
Cvar_RegisterVariable(&host_killtime);
Cvar_RegisterVariable(&sys_ticrate);
+ Cvar_RegisterVariable(&sys_timescale);
+ Cvar_HookVariable(sys_timescale.name, &sys_timescale_hook);
+
Cvar_RegisterVariable(&fps_max);
Cvar_RegisterVariable(&fps_override);
Cvar_RegisterVariable(&host_name);
@@ -351,22 +358,28 @@ void Host_WriteCustomConfig(void)
void SV_ClientPrintf(const char *fmt, ...)
{
- va_list va;
- char string[1024];
-
if (!host_client->fakeclient)
{
+ va_list va;
+ char string[1024];
+
va_start(va, fmt);
Q_vsnprintf(string, ARRAYSIZE(string) - 1, fmt, va);
va_end(va);
- string[ARRAYSIZE(string) - 1] = 0;
-
- MSG_WriteByte(&host_client->netchan.message, svc_print);
- MSG_WriteString(&host_client->netchan.message, string);
+ g_RehldsHookchains.m_SV_ClientPrintf.callChain(SV_ClientPrintf_internal, string);
}
}
+void EXT_FUNC SV_ClientPrintf_internal(const char *Dest)
+{
+ char string[1024];
+
+ Q_strlcpy(string, Dest, min(strlen(Dest) + 1, sizeof(string)));
+ MSG_WriteByte(&host_client->netchan.message, svc_print);
+ MSG_WriteString(&host_client->netchan.message, string);
+}
+
void SV_BroadcastPrintf(const char *fmt, ...)
{
va_list argptr;
@@ -1269,3 +1282,23 @@ void Host_Shutdown(void)
g_psv.time = 0.0f;
g_pcl.time = 0.0f;
}
+
+void sys_timescale_hook_callback(cvar_t *cvar)
+{
+ int i;
+ client_t *client = NULL;
+
+ if (!Host_IsServerActive())
+ return;
+
+ for (i = 0; i < g_psvs.maxclients; i++)
+ {
+ client = &g_psvs.clients[i];
+
+ if (!client->fakeclient && (client->active || client->spawned || client->connected))
+ {
+ MSG_WriteByte(&client->netchan.message, svc_timescale);
+ MSG_WriteFloat(&client->netchan.message, max(0.1f, sys_timescale.value));
+ }
+ }
+}
diff --git a/rehlds/engine/host.h b/rehlds/engine/host.h
index fa656f7c6..cfe84abfd 100644
--- a/rehlds/engine/host.h
+++ b/rehlds/engine/host.h
@@ -85,6 +85,7 @@ NOXREF void Info_WriteVars(FileHandle_t fp);
void Host_WriteConfiguration(void);
void Host_WriteCustomConfig(void);
void SV_ClientPrintf(const char *fmt, ...);
+void SV_ClientPrintf_internal(const char *Dest);
void SV_BroadcastPrintf(const char *fmt, ...);
void Host_ClientCommands(const char *fmt, ...);
void SV_DropClient_api(IGameClient* cl, bool crash, const char* fmt, ...);
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/mathlib.cpp b/rehlds/engine/mathlib.cpp
index 4647b9722..667f510e1 100644
--- a/rehlds/engine/mathlib.cpp
+++ b/rehlds/engine/mathlib.cpp
@@ -418,3 +418,12 @@ qboolean VectorCompare(const vec_t *v1, const vec_t *v2)
}
#endif // #if !defined(REHLDS_SSE)
+
+qboolean BoundsIntersect(const vec3_t mins1, const vec3_t maxs1, const vec3_t mins2, const vec3_t maxs2)
+{
+ if (mins1[0] > maxs2[0] || mins1[1] > maxs2[1] || mins1[2] > maxs2[2])
+ return FALSE;
+ if (maxs1[0] < mins2[0] || maxs1[1] < mins2[1] || maxs1[2] < mins2[2])
+ return FALSE;
+ return TRUE;
+}
diff --git a/rehlds/engine/mathlib_e.h b/rehlds/engine/mathlib_e.h
index 3b265a10f..921c701ed 100644
--- a/rehlds/engine/mathlib_e.h
+++ b/rehlds/engine/mathlib_e.h
@@ -171,3 +171,4 @@ void R_ConcatTransforms(float in1[3][4], float in2[3][4], float out[3][4]);
NOBODY void FloorDivMod(double numer, double denom, int *quotient, int *rem);
NOBODY int GreatestCommonDivisor(int i1, int i2);
NOBODY fixed16_t Invert24To16(fixed16_t val);
+qboolean BoundsIntersect(const vec3_t mins1, const vec3_t maxs1, const vec3_t mins2, const vec3_t maxs2);
diff --git a/rehlds/engine/model.cpp b/rehlds/engine/model.cpp
index a4581e539..12bd90fd7 100644
--- a/rehlds/engine/model.cpp
+++ b/rehlds/engine/model.cpp
@@ -29,7 +29,7 @@
#include "precompiled.h"
model_t *loadmodel;
-char loadname[32];
+char loadname[MAX_MODEL_NAME];
model_t mod_known[MAX_KNOWN_MODELS];
int mod_numknown;
unsigned char* mod_base;
@@ -330,7 +330,12 @@ model_t *Mod_LoadModel(model_t *mod, qboolean crash, qboolean trackCRC)
Con_DPrintf("loading %s\n", mod->name);
// allocate a new model
- COM_FileBase(mod->name, loadname);
+ if (!COM_FileBase_s(mod->name, loadname, sizeof(loadname)))
+ {
+ Sys_Error("%s: Bad model name length: %s", __func__, mod->name);
+ return NULL;
+ }
+
loadmodel = mod;
mod->needload = NL_PRESENT;
diff --git a/rehlds/engine/model_rehlds.h b/rehlds/engine/model_rehlds.h
index f36018187..61906f0c8 100644
--- a/rehlds/engine/model_rehlds.h
+++ b/rehlds/engine/model_rehlds.h
@@ -46,7 +46,7 @@
#include "crc.h"
extern model_t* loadmodel;
-extern char loadname[32];
+extern char loadname[MAX_MODEL_NAME];
extern model_t mod_known[MAX_KNOWN_MODELS];
extern int mod_numknown;
extern unsigned char* mod_base;
diff --git a/rehlds/engine/net_chan.cpp b/rehlds/engine/net_chan.cpp
index 88c5bae4a..94149bc20 100644
--- a/rehlds/engine/net_chan.cpp
+++ b/rehlds/engine/net_chan.cpp
@@ -1158,7 +1158,10 @@ void Netchan_CreateFileFragmentsFromBuffer(qboolean server, netchan_t *chan, con
MSG_WriteString(&buf->frag_message, filename);
MSG_WriteString(&buf->frag_message, bCompressed ? "bz2" : "uncompressed");
MSG_WriteLong(&buf->frag_message, uncompressed_size);
- send -= buf->frag_message.cursize;
+
+ // Check if we aren't send more than we should
+ if ((chunksize - send) < buf->frag_message.cursize)
+ send -= buf->frag_message.cursize;
}
buf->isbuffer = TRUE;
@@ -1321,7 +1324,7 @@ int Netchan_CreateFileFragments_(qboolean server, netchan_t *chan, const char *f
remaining = filesize;
pos = 0;
- while (remaining)
+ while (remaining > 0)
{
send = min(chunksize, remaining);
buf = Netchan_AllocFragbuf();
@@ -1353,7 +1356,10 @@ int Netchan_CreateFileFragments_(qboolean server, netchan_t *chan, const char *f
MSG_WriteString(&buf->frag_message, filename);
MSG_WriteString(&buf->frag_message, bCompressed ? "bz2" : "uncompressed");
MSG_WriteLong(&buf->frag_message, uncompressed_size);
- send -= buf->frag_message.cursize;
+
+ // Check if we aren't send more than we should
+ if ((chunksize - send) < buf->frag_message.cursize)
+ send -= buf->frag_message.cursize;
}
buf->isfile = TRUE;
buf->iscompressed = bCompressed;
@@ -1389,8 +1395,13 @@ void Netchan_FlushIncoming(netchan_t *chan, int stream)
{
fragbuf_t *p, *n;
- SZ_Clear(&net_message);
- msg_readcount = 0;
+#ifdef REHLDS_FIXES
+ if ((chan->player_slot - 1) == host_client - g_psvs.clients)
+#endif
+ {
+ SZ_Clear(&net_message);
+ msg_readcount = 0;
+ }
p = chan->incomingbufs[stream];
while (p)
diff --git a/rehlds/engine/net_ws.cpp b/rehlds/engine/net_ws.cpp
index 219b73a07..4880da9b7 100644
--- a/rehlds/engine/net_ws.cpp
+++ b/rehlds/engine/net_ws.cpp
@@ -651,7 +651,7 @@ void NET_AdjustLag()
}
lasttime = realtime;
- if (allow_cheats || fakelag.value == 0.0)
+ if (sv_cheats.value || fakelag.value == 0.0)
{
if (fakelag.value != gFakeLag)
{
@@ -689,7 +689,7 @@ qboolean NET_LagPacket(qboolean newdata, netsrc_t sock, netadr_t *from, sizebuf_
{
if (fakeloss.value != 0.0)
{
- if (allow_cheats)
+ if (sv_cheats.value)
{
static int losscount[NS_MAX] = {};
++losscount[sock];
diff --git a/rehlds/engine/pr_cmds.cpp b/rehlds/engine/pr_cmds.cpp
index df82bce5f..e83cbb429 100644
--- a/rehlds/engine/pr_cmds.cpp
+++ b/rehlds/engine/pr_cmds.cpp
@@ -1011,6 +1011,11 @@ qboolean EXT_FUNC PR_IsEmptyString(const char *s)
}
int EXT_FUNC PF_precache_sound_I(const char *s)
+{
+ return g_RehldsHookchains.m_PF_precache_sound_I.callChain(PF_precache_sound_I_internal, s);
+}
+
+int EXT_FUNC PF_precache_sound_I_internal(const char *s)
{
if (!s)
Host_Error("%s: NULL pointer", __func__);
@@ -1058,6 +1063,11 @@ int EXT_FUNC PF_precache_sound_I(const char *s)
}
unsigned short EXT_FUNC EV_Precache(int type, const char *psz)
+{
+ return g_RehldsHookchains.m_EV_Precache.callChain(EV_Precache_internal, type, psz);
+}
+
+unsigned short EXT_FUNC EV_Precache_internal(int type, const char *psz)
{
if (!psz)
Host_Error("%s: NULL pointer", __func__);
@@ -1377,6 +1387,11 @@ int SV_LookupModelIndex(const char *name)
}
int EXT_FUNC PF_precache_model_I(const char *s)
+{
+ return g_RehldsHookchains.m_PF_precache_model_I.callChain(PF_precache_model_I_internal, s);
+}
+
+int EXT_FUNC PF_precache_model_I_internal(const char *s)
{
int iOptional = 0;
if (!s)
@@ -1432,6 +1447,9 @@ int EXT_FUNC PF_precache_model_I(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))
@@ -1445,8 +1463,13 @@ int EXT_FUNC PF_precache_model_I(const char *s)
}
}
-#ifdef REHLDS_FIXES
int EXT_FUNC PF_precache_generic_I(const char *s)
+{
+ return g_RehldsHookchains.m_PF_precache_generic_I.callChain(PF_precache_generic_I_internal, s);
+}
+
+#ifdef REHLDS_FIXES
+int EXT_FUNC PF_precache_generic_I_internal(const char *s)
{
if (!s)
Host_Error("%s: NULL pointer", __func__);
@@ -1493,7 +1516,7 @@ int EXT_FUNC PF_precache_generic_I(const char *s)
return g_rehlds_sv.precachedGenericResourceCount++;
}
#else // REHLDS_FIXES
-int EXT_FUNC PF_precache_generic_I(const char *s)
+int EXT_FUNC PF_precache_generic_I_internal(const char *s)
{
if (!s)
Host_Error("%s: NULL pointer", __func__);
@@ -1525,7 +1548,7 @@ int EXT_FUNC PF_precache_generic_I(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/pr_cmds.h b/rehlds/engine/pr_cmds.h
index e7c20bc01..a7d424c23 100644
--- a/rehlds/engine/pr_cmds.h
+++ b/rehlds/engine/pr_cmds.h
@@ -120,14 +120,18 @@ edict_t *FindEntityByString(edict_t *pEdictStartSearchAfter, const char *pszFiel
int GetEntityIllum(edict_t *pEnt);
qboolean PR_IsEmptyString(const char *s);
int PF_precache_sound_I(const char *s);
+int PF_precache_sound_I_internal(const char *s);
unsigned short EV_Precache(int type, const char *psz);
+unsigned short EV_Precache_internal(int type, const char *psz);
void EV_PlayReliableEvent_api(IGameClient *cl, int entindex, unsigned short eventindex, float delay, event_args_t *pargs);
void EV_PlayReliableEvent(client_t *cl, int entindex, unsigned short eventindex, float delay, event_args_t *pargs);
void EV_PlayReliableEvent_internal(client_t *cl, int entindex, unsigned short eventindex, float delay, event_args_t *pargs);
void EV_Playback(int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2);
void EV_SV_Playback(int flags, int clientindex, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2);
int PF_precache_model_I(const char *s);
+int PF_precache_model_I_internal(const char *s);
int PF_precache_generic_I(const char *s);
+int PF_precache_generic_I_internal(const char *s);
int PF_IsMapValid_I(const char *mapname);
int PF_NumberOfEntities_I(void);
char *PF_GetInfoKeyBuffer_I(edict_t *e);
diff --git a/rehlds/engine/pr_edict.cpp b/rehlds/engine/pr_edict.cpp
index 0768a568b..2d380c536 100644
--- a/rehlds/engine/pr_edict.cpp
+++ b/rehlds/engine/pr_edict.cpp
@@ -37,6 +37,11 @@ void ED_ClearEdict(edict_t *e)
}
edict_t *ED_Alloc(void)
+{
+ return g_RehldsHookchains.m_ED_Alloc.callChain(ED_Alloc_internal);
+}
+
+edict_t *EXT_FUNC ED_Alloc_internal(void)
{
int i;
edict_t *e;
@@ -71,6 +76,11 @@ edict_t *ED_Alloc(void)
}
void ED_Free(edict_t *ed)
+{
+ g_RehldsHookchains.m_ED_Free.callChain(ED_Free_internal, ed);
+}
+
+void EXT_FUNC ED_Free_internal(edict_t *ed)
{
if (!ed->free)
{
diff --git a/rehlds/engine/pr_edict.h b/rehlds/engine/pr_edict.h
index 0c6be5ee5..da69ecafa 100644
--- a/rehlds/engine/pr_edict.h
+++ b/rehlds/engine/pr_edict.h
@@ -35,7 +35,9 @@
void ED_ClearEdict(edict_t *e);
edict_t *ED_Alloc(void);
+edict_t *ED_Alloc_internal(void);
void ED_Free(edict_t *ed);
+void ED_Free_internal(edict_t *ed);
NOXREF void ED_Count(void);
char *ED_NewString(const char *string);
char *ED_ParseEdict(char *data, edict_t *ent);
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 962a97599..24e251808 100644
--- a/rehlds/engine/server.h
+++ b/rehlds/engine/server.h
@@ -349,7 +349,6 @@ extern cvar_t sv_proxies;
extern cvar_t sv_outofdatetime;
extern cvar_t mapchangecfgfile;
-extern qboolean allow_cheats;
extern cvar_t mp_logecho;
extern cvar_t mp_logfile;
extern cvar_t sv_allow_download;
@@ -407,7 +406,6 @@ enum GameType_e
extern GameType_e g_eGameType;
-extern int fatbytes;
extern int giNextUserMsg;
extern int hashstrings_collisions;
@@ -420,10 +418,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];
@@ -500,6 +494,7 @@ int SV_CheckKeyInfo_internal(netadr_t *adr, char *protinfo, unsigned short *port
int SV_CheckForDuplicateSteamID(client_t *client);
qboolean SV_CheckForDuplicateNames(char *userinfo, qboolean bIsReconnecting, int nExcludeSlot);
int SV_CheckUserInfo(netadr_t *adr, char *userinfo, qboolean bIsReconnecting, int nReconnectSlot, char *name);
+int SV_CheckUserInfo_internal(netadr_t *adr, char *userinfo, qboolean bIsReconnecting, int nReconnectSlot, char *name);
int SV_FindEmptySlot(netadr_t *adr, int *pslot, client_t ** ppClient);
void SV_ConnectClient(void);
void SV_ConnectClient_internal(void);
@@ -560,6 +555,7 @@ NOXREF qboolean SV_HasEventsInQueue(client_t *client);
void SV_GetNetInfo(client_t *client, int *ping, int *packet_loss);
int SV_CheckVisibility(edict_t *entity, unsigned char *pset);
void SV_EmitPings(client_t *client, sizebuf_t *msg);
+void SV_EmitPings_internal(client_t *client, sizebuf_t *msg);
void SV_WriteEntitiesToClient(client_t *client, sizebuf_t *msg);
void SV_CleanupEnts(void);
qboolean SV_SendClientDatagram(client_t *client);
@@ -570,6 +566,7 @@ void SV_SendClientMessages(void);
void SV_ExtractFromUserinfo(client_t *cl);
int SV_ModelIndex(const char *name);
void SV_AddResource(resourcetype_t type, const char *name, int size, unsigned char flags, int index);
+void SV_AddResource_internal(resourcetype_t type, const char *name, int size, unsigned char flags, int index);
size_t SV_CountResourceByType(resourcetype_t type, resource_t **pResourceList = nullptr, size_t nListMax = 0, size_t *nWidthFileNameMax = nullptr);
void SV_CreateGenericResources(void);
void SV_CreateResourceList(void);
diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp
index 2c663f75c..c176ee8ed 100644
--- a/rehlds/engine/sv_main.cpp
+++ b/rehlds/engine/sv_main.cpp
@@ -100,7 +100,6 @@ redirect_t sv_redirected;
netadr_t sv_redirectto;
GameType_e g_eGameType = GT_Unitialized;
-qboolean allow_cheats;
char *gNullString = "";
int SV_UPDATE_BACKUP = SINGLEPLAYER_BACKUP;
@@ -130,6 +129,12 @@ cvar_t sv_waterfriction = { "sv_waterfriction", "1", FCVAR_SERVER, 0.0f, NULL };
cvar_t sv_zmax = { "sv_zmax", "4096", FCVAR_SPONLY, 0.0f, NULL };
cvar_t sv_wateramp = { "sv_wateramp", "0", 0, 0.0f, NULL };
+void sv_cheats_hook_callback(cvar_t *cvar);
+void mapcyclefile_hook_callback(cvar_t *cvar);
+
+cvarhook_t sv_cheats_hook = { sv_cheats_hook_callback, NULL, NULL };
+cvarhook_t mapcyclefile_hook = { mapcyclefile_hook_callback, NULL, NULL };
+
cvar_t sv_skyname = { "sv_skyname", "desert", 0, 0.0f, NULL };
cvar_t mapcyclefile = { "mapcyclefile", "mapcycle.txt", 0, 0.0f, NULL };
cvar_t motdfile = { "motdfile", "motd.txt", 0, 0.0f, NULL };
@@ -682,22 +687,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;
}
@@ -709,7 +714,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;
}
}
@@ -1114,8 +1119,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);
@@ -1165,7 +1180,7 @@ void SV_SendServerinfo_internal(sizebuf_t *msg, client_t *client)
MSG_WriteByte(msg, svc_sendextrainfo);
MSG_WriteString(msg, com_clientfallback);
- MSG_WriteByte(msg, allow_cheats);
+ MSG_WriteByte(msg, sv_cheats.value != 0);
SV_WriteDeltaDescriptionsToClient(msg);
SV_SetMoveVars();
@@ -2117,6 +2132,11 @@ void SV_ReplaceSpecialCharactersInName(char *newname, const char *oldname)
#endif
int SV_CheckUserInfo(netadr_t *adr, char *userinfo, qboolean bIsReconnecting, int nReconnectSlot, char *name)
+{
+ return g_RehldsHookchains.m_SV_CheckUserInfo.callChain(SV_CheckUserInfo_internal, adr, userinfo, bIsReconnecting, nReconnectSlot, name);
+}
+
+int EXT_FUNC SV_CheckUserInfo_internal(netadr_t *adr, char *userinfo, qboolean bIsReconnecting, int nReconnectSlot, char *name)
{
const char *s;
char newname[MAX_NAME];
@@ -4027,9 +4047,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)
{
@@ -4071,6 +4092,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;
@@ -4128,6 +4152,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;
@@ -4568,7 +4595,16 @@ int EXT_FUNC SV_CheckVisibility(edict_t *entity, unsigned char *pset)
}
}
-void SV_EmitPings(client_t *client, sizebuf_t *msg)
+void EXT_FUNC SV_EmitPings_hook(IGameClient *cl, sizebuf_t *msg)
+{
+ SV_EmitPings_internal(cl->GetClient(), msg);
+}
+
+void SV_EmitPings(client_t *client, sizebuf_t *msg) {
+ g_RehldsHookchains.m_SV_EmitPings.callChain(SV_EmitPings_hook, GetRehldsApiClient(client), msg);
+}
+
+void EXT_FUNC SV_EmitPings_internal(client_t *client, sizebuf_t *msg)
{
int ping;
int packet_loss;
@@ -5113,7 +5149,17 @@ int SV_ModelIndex(const char *name)
Sys_Error("%s: SV_ModelIndex: model %s not precached", __func__, name);
}
+void EXT_FUNC SV_AddResource_hook(resourcetype_t type, const char *name, int size, unsigned char flags, int index)
+{
+ SV_AddResource_internal(type, name, size, flags, index);
+}
+
void EXT_FUNC SV_AddResource(resourcetype_t type, const char *name, int size, unsigned char flags, int index)
+{
+ g_RehldsHookchains.m_SV_AddResource.callChain(SV_AddResource_hook, type, name, size, flags, index);
+}
+
+void SV_AddResource_internal(resourcetype_t type, const char *name, int size, unsigned char flags, int index)
{
resource_t *r;
#ifdef REHLDS_FIXES
@@ -6133,7 +6179,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);
}
@@ -6218,7 +6264,6 @@ int SV_SpawnServer(qboolean bIsDemo, char *server, char *startspot)
gGlobalVariables.serverflags = g_psvs.serverflags;
gGlobalVariables.mapname = (size_t)g_psv.name - (size_t)pr_strings;
gGlobalVariables.startspot = (size_t)g_psv.startspot - (size_t)pr_strings;
- allow_cheats = sv_cheats.value;
SV_SetMoveVars();
return 1;
@@ -6537,6 +6582,42 @@ void EXT_FUNC SV_SerializeSteamid(USERID_t* id, USERID_t* serialized)
*serialized = *id;
}
+void sv_cheats_hook_callback(cvar_t *cvar)
+{
+ int i;
+ client_t *client = NULL;
+
+ if (!Host_IsServerActive())
+ return;
+
+ for (i = 0; i < g_psvs.maxclients; i++)
+ {
+ client = &g_psvs.clients[i];
+
+ if (!client->fakeclient && (client->active || client->spawned || client->connected))
+ {
+ MSG_WriteByte(&client->netchan.message, svc_sendextrainfo);
+ MSG_WriteString(&client->netchan.message, "");
+ MSG_WriteByte(&client->netchan.message, sv_cheats.value != 0);
+ }
+ }
+}
+
+void mapcyclefile_hook_callback(cvar_t *cvar)
+{
+ char buf[MAX_PATH + 4];
+
+ if (!Q_strcmp(COM_FileExtension(cvar->string), "txt"))
+ return;
+
+ Q_snprintf(buf, sizeof(buf) - 3, "%s.txt", cvar->string);
+
+ if (!Q_strcmp(COM_FileExtension(buf), "txt"))
+ Cvar_DirectSet(cvar, buf);
+ else
+ Cvar_DirectSet(cvar, "mapcycle.txt");
+}
+
void SV_BanId_f(void)
{
char szreason[256];
@@ -7975,6 +8056,7 @@ void SV_Init(void)
Cvar_RegisterVariable(&sv_skyname);
Cvar_RegisterVariable(&sv_maxvelocity);
Cvar_RegisterVariable(&sv_cheats);
+ Cvar_HookVariable(sv_cheats.name, &sv_cheats_hook);
if (COM_CheckParm("-dev"))
Cvar_SetValue("sv_cheats", 1.0);
Cvar_RegisterVariable(&sv_spectatormaxspeed);
@@ -7986,6 +8068,7 @@ void SV_Init(void)
Cvar_RegisterVariable(&sv_logbans);
Cvar_RegisterVariable(&hpk_maxsize);
Cvar_RegisterVariable(&mapcyclefile);
+ Cvar_HookVariable(mapcyclefile.name, &mapcyclefile_hook);
Cvar_RegisterVariable(&motdfile);
Cvar_RegisterVariable(&servercfgfile);
Cvar_RegisterVariable(&mapchangecfgfile);
diff --git a/rehlds/engine/sv_user.cpp b/rehlds/engine/sv_user.cpp
index 118250ec6..64e388eda 100644
--- a/rehlds/engine/sv_user.cpp
+++ b/rehlds/engine/sv_user.cpp
@@ -511,13 +511,20 @@ 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;
edict_t *check;
int e;
physent_t *ve;
- int i;
link_t *next;
float *fmax;
float *fmin;
@@ -547,6 +554,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;
@@ -575,13 +587,7 @@ void SV_AddLinksToPM_(areanode_t *node, float *pmove_mins, float *pmove_maxs)
if (check->v.flags & FL_CLIENT)
SV_GetTrueMinMax(e - 1, &fmin, &fmax);
- for (i = 0; i < 3; i++)
- {
- if (fmin[i] > pmove_maxs[i] || fmax[i] < pmove_mins[i])
- break;
- }
-
- if (i != 3)
+ if (!BoundsIntersect(pmove_mins, pmove_maxs, fmin, fmax))
continue;
if (check->v.solid || check->v.skin != -16)
diff --git a/rehlds/engine/sys_dll.cpp b/rehlds/engine/sys_dll.cpp
index fb2a5fba8..293119d22 100644
--- a/rehlds/engine/sys_dll.cpp
+++ b/rehlds/engine/sys_dll.cpp
@@ -1318,7 +1318,7 @@ void Con_DebugLog(const char *file, const char *fmt, ...)
#endif // _WIN32
}
-void EXT_FUNC Con_Printf(const char *fmt, ...)
+void Con_Printf(const char *fmt, ...)
{
char Dest[4096];
va_list va;
@@ -1326,7 +1326,12 @@ void EXT_FUNC Con_Printf(const char *fmt, ...)
va_start(va, fmt);
Q_vsnprintf(Dest, sizeof(Dest), fmt, va);
va_end(va);
+
+ g_RehldsHookchains.m_Con_Printf.callChain(Con_Printf_internal, Dest);
+}
+void EXT_FUNC Con_Printf_internal(const char *Dest)
+{
#ifdef REHLDS_FLIGHT_REC
FR_Log("REHLDS_CON", Dest);
#endif
diff --git a/rehlds/engine/sys_dll.h b/rehlds/engine/sys_dll.h
index 228b09aed..adab1551c 100644
--- a/rehlds/engine/sys_dll.h
+++ b/rehlds/engine/sys_dll.h
@@ -135,5 +135,6 @@ void Con_Debug_f(void);
void Con_Init(void);
void Con_DebugLog(const char *file, const char *fmt, ...);
void Con_Printf(const char *fmt, ...);
+void Con_Printf_internal(const char *Dest);
void Con_SafePrintf(const char *fmt, ...);
void Con_DPrintf(const char *fmt, ...);
diff --git a/rehlds/engine/unicode_strtools.cpp b/rehlds/engine/unicode_strtools.cpp
index 818145b23..385cee971 100644
--- a/rehlds/engine/unicode_strtools.cpp
+++ b/rehlds/engine/unicode_strtools.cpp
@@ -285,7 +285,7 @@ static const uint32_t g_isPrintTable[2048] = {
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF0000, 0xFFFFFFFF, 0xFFFCFFFF, 0xFFFFFFFF, 0x000000FF, 0x0FFF0000,
0x03FF0000, 0xFFFF0000, 0xFFF7FFFF, 0xFFDF0D0B, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x9FFFFFFF,
- 0x8FFFF7EE, 0xBFFFFFFF, 0xAFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0x1CFCFCFC, 0x00000000
+ 0x8FFFF7EE, 0xBFFFFFFF, 0xAFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFE, 0x1CFCFCFC, 0x00000000
};
//-----------------------------------------------------------------------------
@@ -461,7 +461,7 @@ static uchar16 *StripWhitespaceWorker(uchar16 *pwch, int cchLength, bool *pbStri
// walk backwards from the end of the string, killing any whitespace
*pbStrippedWhitespace = false;
- uchar16 *pwchEnd = pwch + cchLength;
+ uchar16 *pwchEnd = pwch + cchLength - 1;
while (--pwchEnd >= pwch)
{
if (!iswspace(*pwchEnd) && !Q_IsMeanSpaceW(*pwchEnd))
@@ -474,7 +474,7 @@ static uchar16 *StripWhitespaceWorker(uchar16 *pwch, int cchLength, bool *pbStri
// walk forward in the string
while (pwch < pwchEnd)
{
- if (!iswspace(*pwch))
+ if (!iswspace(*pwch) && !Q_IsMeanSpaceW(*pwch))
break;
*pbStrippedWhitespace = true;
@@ -484,7 +484,7 @@ static uchar16 *StripWhitespaceWorker(uchar16 *pwch, int cchLength, bool *pbStri
return pwch;
}
-uchar16 *__cdecl StripUnprintableWorker(uchar16 *pwch, bool *pStripped)
+uchar16 *__cdecl StripUnprintableWorker(uchar16 *pwch, int *pLength, bool *pStripped)
{
uchar16* rPos = pwch;
uchar16* wPos = pwch;
@@ -503,6 +503,10 @@ uchar16 *__cdecl StripUnprintableWorker(uchar16 *pwch, bool *pStripped)
*wPos = 0;
*pStripped = rPos != wPos;
+
+ if (*pStripped)
+ *pLength = (wPos - pwch) + 1; // null termination
+
return pwch;
}
@@ -736,8 +740,8 @@ qboolean Q_StripUnprintableAndSpace(char *pch)
bStrippedAny = false;
bStrippedWhitespace = false;
int cwch = (unsigned int)Q_UTF8ToUTF16(pch, (uchar16 *)pwch_alloced, cubDest, _STRINGCONVERTFLAG_ASSERT) >> 1;
- uchar16 * pwch = StripUnprintableWorker(pwch_alloced, &bStrippedAny);
- pwch = StripWhitespaceWorker(pwch, cwch - 1, &bStrippedWhitespace);
+ uchar16 * pwch = StripUnprintableWorker(pwch_alloced, &cwch, &bStrippedAny);
+ pwch = StripWhitespaceWorker(pwch, cwch, &bStrippedWhitespace);
if (bStrippedWhitespace || bStrippedAny)
Q_UTF16ToUTF8(pwch, pch, cch, STRINGCONVERT_ASSERT_REPLACE);
diff --git a/rehlds/engine/world.cpp b/rehlds/engine/world.cpp
index 74ccc3346..8038ab755 100644
--- a/rehlds/engine/world.cpp
+++ b/rehlds/engine/world.cpp
@@ -238,7 +238,8 @@ hull_t *SV_HullForEntity(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec
// explicit hulls in the BSP model
if (ent->v.movetype != MOVETYPE_PUSH && ent->v.movetype != MOVETYPE_PUSHSTEP)
{
- Sys_Error("%s: SOLID_BSP without MOVETYPE_PUSH", __func__);
+ Sys_Error("%s: SOLID_BSP without MOVETYPE_PUSH\nEntity classname = %s, model = %s",
+ __func__, STRING(ent->v.classname), STRING(ent->v.model));
}
return SV_HullForBsp(ent, mins, maxs, offset);
@@ -358,12 +359,7 @@ void SV_TouchLinks(edict_t *ent, areanode_t *node)
if (touch->v.solid != SOLID_TRIGGER)
continue;
- if (ent->v.absmin[0] > touch->v.absmax[0]
- || ent->v.absmin[1] > touch->v.absmax[1]
- || ent->v.absmin[2] > touch->v.absmax[2]
- || ent->v.absmax[0] < touch->v.absmin[0]
- || ent->v.absmax[1] < touch->v.absmin[1]
- || ent->v.absmax[2] < touch->v.absmin[2])
+ if (!BoundsIntersect(ent->v.absmin, ent->v.absmax, touch->v.absmin, touch->v.absmax))
continue;
// check brush triggers accuracy
@@ -646,12 +642,7 @@ int SV_LinkContents(areanode_t *node, const vec_t *pos)
if (Mod_GetType(touch->v.modelindex) != mod_brush)
continue;
- if (pos[0] > touch->v.absmax[0]
- || pos[1] > touch->v.absmax[1]
- || pos[2] > touch->v.absmax[2]
- || pos[0] < touch->v.absmin[0]
- || pos[1] < touch->v.absmin[1]
- || pos[2] < touch->v.absmin[2])
+ if (!BoundsIntersect(pos, pos, touch->v.absmin, touch->v.absmax))
continue;
int contents = touch->v.skin;
@@ -1189,13 +1180,15 @@ void SV_ClipToLinks(areanode_t *node, moveclip_t *clip)
if (touch->v.solid == SOLID_TRIGGER)
Sys_Error("%s: Trigger in clipping list", __func__);
+#ifndef REHLDS_OPT_PEDANTIC
if (gNewDLLFunctions.pfnShouldCollide && !gNewDLLFunctions.pfnShouldCollide(touch, clip->passedict))
#ifdef REHLDS_FIXES
// https://github.com/dreamstalker/rehlds/issues/46
continue;
#else
return;
-#endif
+#endif // REHLDS_FIXES
+#endif // REHLDS_OPT_PEDANTIC
// monsterclip filter
if (touch->v.solid == SOLID_BSP)
@@ -1213,12 +1206,7 @@ void SV_ClipToLinks(areanode_t *node, moveclip_t *clip)
if (clip->ignoretrans && touch->v.rendermode != kRenderNormal && !(touch->v.flags & FL_WORLDBRUSH))
continue;
- if (clip->boxmins[0] > touch->v.absmax[0]
- || clip->boxmins[1] > touch->v.absmax[1]
- || clip->boxmins[2] > touch->v.absmax[2]
- || clip->boxmaxs[0] < touch->v.absmin[0]
- || clip->boxmaxs[1] < touch->v.absmin[1]
- || clip->boxmaxs[2] < touch->v.absmin[2])
+ if (!BoundsIntersect(clip->boxmins, clip->boxmaxs, touch->v.absmin, touch->v.absmax))
continue;
if (touch->v.solid != SOLID_SLIDEBOX
@@ -1247,6 +1235,16 @@ void SV_ClipToLinks(areanode_t *node, moveclip_t *clip)
continue; // don't clip against owner
}
+#ifdef REHLDS_OPT_PEDANTIC
+ if (gNewDLLFunctions.pfnShouldCollide && !gNewDLLFunctions.pfnShouldCollide(touch, clip->passedict))
+#ifdef REHLDS_FIXES
+ // https://github.com/dreamstalker/rehlds/issues/46
+ continue;
+#else
+ return;
+#endif // REHLDS_FIXES
+#endif // REHLDS_OPT_PEDANTIC
+
trace_t trace;
if (touch->v.flags & FL_MONSTER)
trace = SV_ClipMoveToEntity(touch, clip->start, clip->mins2, clip->maxs2, clip->end);
@@ -1297,12 +1295,7 @@ void SV_ClipToWorldbrush(areanode_t *node, moveclip_t *clip)
if (!(touch->v.flags & FL_WORLDBRUSH))
continue;
- if (clip->boxmins[0] > touch->v.absmax[0]
- || clip->boxmins[1] > touch->v.absmax[1]
- || clip->boxmins[2] > touch->v.absmax[2]
- || clip->boxmaxs[0] < touch->v.absmin[0]
- || clip->boxmaxs[1] < touch->v.absmin[1]
- || clip->boxmaxs[2] < touch->v.absmin[2])
+ if (!BoundsIntersect(clip->boxmins, clip->boxmaxs, touch->v.absmin, touch->v.absmax))
continue;
if (clip->trace.allsolid)
diff --git a/rehlds/engine/zone.cpp b/rehlds/engine/zone.cpp
index afd84697a..3a1ab65f7 100644
--- a/rehlds/engine/zone.cpp
+++ b/rehlds/engine/zone.cpp
@@ -679,7 +679,7 @@ void Cache_Force_Flush()
void Cache_Flush()
{
- if (g_pcl.maxclients <= 1 || allow_cheats)
+ if (g_pcl.maxclients <= 1 || sv_cheats.value)
{
Cache_Force_Flush();
}
diff --git a/rehlds/engine/zone.h b/rehlds/engine/zone.h
index 46dcd22cc..8c7b43776 100644
--- a/rehlds/engine/zone.h
+++ b/rehlds/engine/zone.h
@@ -30,7 +30,7 @@
#include "maintypes.h"
-#define ZONE_DYNAMIC_SIZE 0x20000
+#define ZONE_DYNAMIC_SIZE 0x200000
typedef struct memblock_s memblock_t;
typedef struct memzone_s memzone_t;
diff --git a/rehlds/msvc/ReHLDS.vcxproj b/rehlds/msvc/ReHLDS.vcxproj
index 2078e8301..dc153551e 100644
--- a/rehlds/msvc/ReHLDS.vcxproj
+++ b/rehlds/msvc/ReHLDS.vcxproj
@@ -463,6 +463,7 @@
{6973dca5-253c-4d84-b51e-187e035eae06}
+ false
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/progs.h b/rehlds/public/rehlds/progs.h
index 808ad3014..5ea6cf8f0 100644
--- a/rehlds/public/rehlds/progs.h
+++ b/rehlds/public/rehlds/progs.h
@@ -68,6 +68,10 @@ struct event_state_s
extern char *pr_strings;
extern globalvars_t gGlobalVariables;
+#if !defined(STRING) && defined(SWDS)
+#define STRING(offset) ((const char *)(pr_strings + (unsigned int)(offset)))
+#endif
+
//============================================================================
edict_t *ED_Alloc (void);
diff --git a/rehlds/public/rehlds/rehlds_api.h b/rehlds/public/rehlds/rehlds_api.h
index 4d0a74ede..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 10
+#define REHLDS_API_VERSION_MINOR 13
//Steam_NotifyClientConnect hook
typedef IHookChain IRehldsHook_Steam_NotifyClientConnect;
@@ -211,6 +211,53 @@ typedef IHookChainRegistry IRehldsHookRegistry_SV_Sho
typedef IHookChain IRehldsHook_GetEntityInit;
typedef IHookChainRegistry IRehldsHookRegistry_GetEntityInit;
+//SV_EmitPings hook
+typedef IHookChain IRehldsHook_SV_EmitPings;
+typedef IHookChainRegistry IRehldsHookRegistry_SV_EmitPings;
+
+//ED_Alloc hook
+typedef IHookChain IRehldsHook_ED_Alloc;
+typedef IHookChainRegistry IRehldsHookRegistry_ED_Alloc;
+
+//ED_Free hook
+typedef IVoidHookChain IRehldsHook_ED_Free;
+typedef IVoidHookChainRegistry IRehldsHookRegistry_ED_Free;
+
+//Con_Printf hook
+typedef IHookChain IRehldsHook_Con_Printf;
+typedef IHookChainRegistry IRehldsHookRegistry_Con_Printf;
+
+//SV_CheckUserInfo hook
+typedef IHookChain IRehldsHook_SV_CheckUserInfo;
+typedef IHookChainRegistry IRehldsHookRegistry_SV_CheckUserInfo;
+
+//PF_precache_generic_I hook
+typedef IHookChain IRehldsHook_PF_precache_generic_I;
+typedef IHookChainRegistry IRehldsHookRegistry_PF_precache_generic_I;
+
+//PF_precache_model_I hook
+typedef IHookChain IRehldsHook_PF_precache_model_I;
+typedef IHookChainRegistry IRehldsHookRegistry_PF_precache_model_I;
+
+//PF_precache_sound_I hook
+typedef IHookChain IRehldsHook_PF_precache_sound_I;
+typedef IHookChainRegistry IRehldsHookRegistry_PF_precache_sound_I;
+
+//EV_Precache hook
+typedef IHookChain IRehldsHook_EV_Precache;
+typedef IHookChainRegistry IRehldsHookRegistry_EV_Precache;
+
+//SV_AddResource hook
+typedef IVoidHookChain IRehldsHook_SV_AddResource;
+typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_AddResource;
+
+//SV_ClientPrintf hook
+typedef IVoidHookChain IRehldsHook_SV_ClientPrintf;
+typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_ClientPrintf;
+
+//SV_AllowPhysent hook
+typedef IHookChain IRehldsHook_SV_AllowPhysent;
+typedef IHookChainRegistry IRehldsHookRegistry_SV_AllowPhysent;
class IRehldsHookchains {
public:
@@ -259,6 +306,18 @@ class IRehldsHookchains {
virtual IRehldsHookRegistry_SV_Frame* SV_Frame() = 0;
virtual IRehldsHookRegistry_SV_ShouldSendConsistencyList* SV_ShouldSendConsistencyList() = 0;
virtual IRehldsHookRegistry_GetEntityInit* GetEntityInit() = 0;
+ virtual IRehldsHookRegistry_SV_EmitPings* SV_EmitPings() = 0;
+ virtual IRehldsHookRegistry_ED_Alloc* ED_Alloc() = 0;
+ virtual IRehldsHookRegistry_ED_Free* ED_Free() = 0;
+ virtual IRehldsHookRegistry_Con_Printf* Con_Printf() = 0;
+ virtual IRehldsHookRegistry_SV_CheckUserInfo* SV_CheckUserInfo() = 0;
+ virtual IRehldsHookRegistry_PF_precache_generic_I* PF_precache_generic_I() = 0;
+ virtual IRehldsHookRegistry_PF_precache_model_I* PF_precache_model_I() = 0;
+ virtual IRehldsHookRegistry_PF_precache_sound_I* PF_precache_sound_I() = 0;
+ 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 7cfe15e8a..8d7f9dad6 100644
--- a/rehlds/rehlds/rehlds_api_impl.cpp
+++ b/rehlds/rehlds/rehlds_api_impl.cpp
@@ -52,7 +52,9 @@ char* EXT_FUNC GetClientFallback_api() {
}
int* EXT_FUNC GetAllowCheats_api() {
- return &allow_cheats;
+ static int sv_cheats_stub = 0;
+ Con_Printf("WARNING! allow_cheats marked as deprecated! Use sv_cheats cvar directly!\n");
+ return &sv_cheats_stub;
}
bool EXT_FUNC GSBSecure_api() {
@@ -835,6 +837,54 @@ IRehldsHookRegistry_GetEntityInit* CRehldsHookchains::GetEntityInit() {
return &m_GetEntityInit;
}
+IRehldsHookRegistry_SV_EmitPings* CRehldsHookchains::SV_EmitPings() {
+ return &m_SV_EmitPings;
+}
+
+IRehldsHookRegistry_ED_Alloc* CRehldsHookchains::ED_Alloc() {
+ return &m_ED_Alloc;
+}
+
+IRehldsHookRegistry_ED_Free* CRehldsHookchains::ED_Free() {
+ return &m_ED_Free;
+}
+
+IRehldsHookRegistry_Con_Printf* CRehldsHookchains::Con_Printf() {
+ return &m_Con_Printf;
+}
+
+IRehldsHookRegistry_SV_CheckUserInfo* CRehldsHookchains::SV_CheckUserInfo() {
+ return &m_SV_CheckUserInfo;
+}
+
+IRehldsHookRegistry_PF_precache_generic_I* CRehldsHookchains::PF_precache_generic_I() {
+ return &m_PF_precache_generic_I;
+}
+
+IRehldsHookRegistry_PF_precache_model_I* CRehldsHookchains::PF_precache_model_I() {
+ return &m_PF_precache_model_I;
+}
+
+IRehldsHookRegistry_PF_precache_sound_I* CRehldsHookchains::PF_precache_sound_I() {
+ return &m_PF_precache_sound_I;
+}
+
+IRehldsHookRegistry_EV_Precache* CRehldsHookchains::EV_Precache() {
+ return &m_EV_Precache;
+}
+
+IRehldsHookRegistry_SV_AddResource* CRehldsHookchains::SV_AddResource(){
+ return &m_SV_AddResource;
+}
+
+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 835a24b1d..699bd1649 100644
--- a/rehlds/rehlds/rehlds_api_impl.h
+++ b/rehlds/rehlds/rehlds_api_impl.h
@@ -206,6 +206,54 @@ typedef IHookChainRegistryImpl CRehldsHookRegistry_SV
typedef IHookChainImpl CRehldsHook_GetEntityInit;
typedef IHookChainRegistryImpl CRehldsHookRegistry_GetEntityInit;
+//SV_EmitPings hook
+typedef IHookChainImpl CRehldsHook_SV_EmitPings;
+typedef IHookChainRegistryImpl CRehldsHookRegistry_SV_EmitPings;
+
+//ED_Alloc hook
+typedef IHookChainImpl CRehldsHook_ED_Alloc;
+typedef IHookChainRegistryImpl CRehldsHookRegistry_ED_Alloc;
+
+//ED_Free hook
+typedef IVoidHookChainImpl CRehldsHook_ED_Free;
+typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_ED_Free;
+
+//Con_Printf hook
+typedef IHookChainImpl CRehldsHook_Con_Printf;
+typedef IHookChainRegistryImpl CRehldsHookRegistry_Con_Printf;
+
+//SV_CheckUserInfo hook
+typedef IHookChainImpl CRehldsHook_SV_CheckUserInfo;
+typedef IHookChainRegistryImpl CRehldsHookRegistry_SV_CheckUserInfo;
+
+//PF_precache_generic_I hook
+typedef IHookChainImpl CRehldsHook_PF_precache_generic_I;
+typedef IHookChainRegistryImpl CRehldsHookRegistry_PF_precache_generic_I;
+
+//PF_precache_model_I hook
+typedef IHookChainImpl CRehldsHook_PF_precache_model_I;
+typedef IHookChainRegistryImpl CRehldsHookRegistry_PF_precache_model_I;
+
+//PF_precache_sound_I hook
+typedef IHookChainImpl CRehldsHook_PF_precache_sound_I;
+typedef IHookChainRegistryImpl CRehldsHookRegistry_PF_precache_sound_I;
+
+//EV_Precache hook
+typedef IHookChainImpl CRehldsHook_EV_Precache;
+typedef IHookChainRegistryImpl CRehldsHookRegistry_EV_Precache;
+
+//SV_AddResource hook
+typedef IVoidHookChainImpl CRehldsHook_SV_AddResource;
+typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_SV_AddResource;
+
+//SV_ClientPrintf hook
+typedef IVoidHookChainImpl 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;
@@ -251,6 +299,18 @@ class CRehldsHookchains : public IRehldsHookchains {
CRehldsHookRegistry_SV_Frame m_SV_Frame;
CRehldsHookRegistry_SV_ShouldSendConsistencyList m_SV_ShouldSendConsistencyList;
CRehldsHookRegistry_GetEntityInit m_GetEntityInit;
+ CRehldsHookRegistry_SV_EmitPings m_SV_EmitPings;
+ CRehldsHookRegistry_ED_Alloc m_ED_Alloc;
+ CRehldsHookRegistry_ED_Free m_ED_Free;
+ CRehldsHookRegistry_Con_Printf m_Con_Printf;
+ CRehldsHookRegistry_SV_CheckUserInfo m_SV_CheckUserInfo;
+ CRehldsHookRegistry_PF_precache_generic_I m_PF_precache_generic_I;
+ CRehldsHookRegistry_PF_precache_model_I m_PF_precache_model_I;
+ CRehldsHookRegistry_PF_precache_sound_I m_PF_precache_sound_I;
+ 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();
@@ -296,6 +356,18 @@ class CRehldsHookchains : public IRehldsHookchains {
EXT_FUNC virtual IRehldsHookRegistry_SV_Frame* SV_Frame();
EXT_FUNC virtual IRehldsHookRegistry_SV_ShouldSendConsistencyList* SV_ShouldSendConsistencyList();
EXT_FUNC virtual IRehldsHookRegistry_GetEntityInit* GetEntityInit();
+ EXT_FUNC virtual IRehldsHookRegistry_SV_EmitPings* SV_EmitPings();
+ EXT_FUNC virtual IRehldsHookRegistry_ED_Alloc* ED_Alloc();
+ EXT_FUNC virtual IRehldsHookRegistry_ED_Free* ED_Free();
+ EXT_FUNC virtual IRehldsHookRegistry_Con_Printf* Con_Printf();
+ EXT_FUNC virtual IRehldsHookRegistry_SV_CheckUserInfo* SV_CheckUserInfo();
+ EXT_FUNC virtual IRehldsHookRegistry_PF_precache_generic_I* PF_precache_generic_I();
+ EXT_FUNC virtual IRehldsHookRegistry_PF_precache_model_I* PF_precache_model_I();
+ EXT_FUNC virtual IRehldsHookRegistry_PF_precache_sound_I* PF_precache_sound_I();
+ 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 0a1f0952e..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 10
+#define VERSION_MINOR 13
#define VERSION_MAINTENANCE 0