2
0
mirror of https://github.com/rehlds/rehlds.git synced 2025-01-01 09:35:37 +03:00
rehlds/rehlds/engine/common.cpp

2827 lines
53 KiB
C++

/*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*
*/
#include "precompiled.h"
char serverinfo[MAX_INFO_STRING];
char gpszVersionString[32];
char gpszProductString[32];
char *Info_Serverinfo(void)
{
return serverinfo;
}
#ifndef COM_Functions_region
unsigned char COM_Nibble(char c)
{
if (c >= '0' && c <= '9')
{
return (unsigned char)(c - '0');
}
if (c >= 'A' && c <= 'F')
{
return (unsigned char)(c - 'A' + 0x0A);
}
if (c >= 'a' && c <= 'f')
{
return (unsigned char)(c - 'a' + 0x0A);
}
return '0';
}
void COM_HexConvert(const char *pszInput, int nInputLength, unsigned char *pOutput)
{
unsigned char *p;
int i;
const char *pIn;
p = pOutput;
for (i = 0; i < nInputLength - 1; i += 2)
{
pIn = &pszInput[i];
if (pIn[0] == 0 || pIn[1] == 0)
break;
*p = COM_Nibble(pIn[0]) << 4 | COM_Nibble(pIn[1]);
p++;
}
}
NOXREF char *COM_BinPrintf(unsigned char *buf, int nLen)
{
NOXREFCHECK;
static char szReturn[4096];
unsigned char c;
char szChunk[10];
int i;
Q_memset(szReturn, 0, sizeof(szReturn));
for (i = 0; i < nLen; i++)
{
c = (unsigned char)buf[i];
Q_snprintf(szChunk, sizeof(szChunk), "%02x", c);
Q_strncat(szReturn, szChunk, sizeof(szReturn) - Q_strlen(szReturn) - 1);
}
return szReturn;
}
void COM_ExplainDisconnection(qboolean bPrint, char *fmt, ...)
{
va_list argptr;
static char string[1024];
va_start(argptr, fmt);
Q_vsnprintf(string, sizeof(string), fmt, argptr);
va_end(argptr);
Q_strncpy(gszDisconnectReason, string, sizeof(gszDisconnectReason) - 1);
gszDisconnectReason[sizeof(gszDisconnectReason) - 1] = 0;
gfExtendedError = 1;
if (bPrint)
{
if (gszDisconnectReason[0] != '#')
Con_Printf("%s\n", gszDisconnectReason);
}
}
NOXREF void COM_ExtendedExplainDisconnection(qboolean bPrint, char *fmt, ...)
{
NOXREFCHECK;
va_list argptr;
static char string[1024];
va_start(argptr, fmt);
Q_vsnprintf(string, sizeof(string), fmt, argptr);
va_end(argptr);
Q_strncpy(gszExtendedDisconnectReason, string, sizeof(gszExtendedDisconnectReason) - 1);
gszExtendedDisconnectReason[sizeof(gszExtendedDisconnectReason) - 1] = 0;
if (bPrint)
{
if (gszExtendedDisconnectReason[0] != '#')
Con_Printf("%s\n", gszExtendedDisconnectReason);
}
}
#endif // COM_Functions_region
#ifndef Byte_Functions_region
/*
============================================================================
BYTE ORDER FUNCTIONS
============================================================================
*/
qboolean bigendien;
short (*BigShort)(short l);
short (*LittleShort)(short l);
int (*BigLong)(int l);
int (*LittleLong)(int l);
float (*BigFloat)(float l);
float (*LittleFloat)(float l);
int LongSwap(int l)
{
return bswap(l);
}
int LongNoSwap(int l)
{
return l;
}
short ShortSwap(short l)
{
return bswap(l);
}
short ShortNoSwap(short l)
{
return l;
}
float FloatSwap(float f)
{
/*union
{
float f;
byte b[4];
} dat1, dat2;
dat1.f = f;
dat2.b[0] = dat1.b[3];
dat2.b[1] = dat1.b[2];
dat2.b[2] = dat1.b[1];
dat2.b[3] = dat1.b[0];
return dat2.f;*/
//unsigned long u = bswap(*(unsigned long *)&f);
//return *(float *)&u;
return bswap(f);
}
float FloatNoSwap(float f)
{
return f;
}
#endif // Byte_Functions_region
#ifndef MSG_Functions_region
// MESSAGE IO FUNCTIONS
// Handles byte ordering and avoids alignment errors
int msg_badread;
int msg_readcount;
// Some bit tables...
const uint32 BITTABLE[] =
{
0x00000001, 0x00000002, 0x00000004, 0x00000008,
0x00000010, 0x00000020, 0x00000040, 0x00000080,
0x00000100, 0x00000200, 0x00000400, 0x00000800,
0x00001000, 0x00002000, 0x00004000, 0x00008000,
0x00010000, 0x00020000, 0x00040000, 0x00080000,
0x00100000, 0x00200000, 0x00400000, 0x00800000,
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x00000000,
};
const uint32 ROWBITTABLE[] =
{
0x00000000, 0x00000001, 0x00000003, 0x00000007,
0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,
0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,
0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,
0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,
0xFFFFFFFF,
};
const uint32 INVBITTABLE[] =
{
0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFB, 0xFFFFFFF7,
0xFFFFFFEF, 0xFFFFFFDF, 0xFFFFFFBF, 0xFFFFFF7F,
0xFFFFFEFF, 0xFFFFFDFF, 0xFFFFFBFF, 0xFFFFF7FF,
0xFFFFEFFF, 0xFFFFDFFF, 0xFFFFBFFF, 0xFFFF7FFF,
0xFFFEFFFF, 0xFFFDFFFF, 0xFFFBFFFF, 0xFFF7FFFF,
0xFFEFFFFF, 0xFFDFFFFF, 0xFFBFFFFF, 0xFF7FFFFF,
0xFEFFFFFF, 0xFDFFFFFF, 0xFBFFFFFF, 0xF7FFFFFF,
0xEFFFFFFF, 0xDFFFFFFF, 0xBFFFFFFF, 0x7FFFFFFF,
0xFFFFFFFF,
};
void MSG_WriteChar(sizebuf_t *sb, int c)
{
unsigned char *buf = (unsigned char *)SZ_GetSpace(sb, 1);
*(char *)buf = (char)c;
}
void MSG_WriteByte(sizebuf_t *sb, int c)
{
unsigned char *buf = (unsigned char *)SZ_GetSpace(sb, 1);
*(byte *)buf = (byte)c;
}
void MSG_WriteShort(sizebuf_t *sb, int c)
{
unsigned char *buf = (unsigned char *)SZ_GetSpace(sb, 2);
*(int16 *)buf = (int16)c;
}
void MSG_WriteWord(sizebuf_t *sb, int c)
{
unsigned char *buf = (unsigned char *)SZ_GetSpace(sb, 2);
*(uint16 *)buf = (uint16)c;
}
void MSG_WriteLong(sizebuf_t *sb, int c)
{
unsigned char *buf = (unsigned char *)SZ_GetSpace(sb, 4);
*(uint32 *)buf = (uint32)c;
}
void MSG_WriteFloat(sizebuf_t *sb, float f)
{
int i = LittleLong(*(int *)&f);
SZ_Write(sb, &i, 4);
}
void MSG_WriteString(sizebuf_t *sb, const char *s)
{
if (s)
{
SZ_Write(sb, s, Q_strlen(s) + 1);
}
else
{
SZ_Write(sb, "", 1);
}
}
void MSG_WriteBuf(sizebuf_t *sb, int iSize, void *buf)
{
if (buf)
{
SZ_Write(sb, buf, iSize);
}
}
void MSG_WriteAngle(sizebuf_t *sb, float f)
{
MSG_WriteByte(sb, (int64)(fmod((double)f, 360.0) * 256.0 / 360.0) & 0xFF);
}
void MSG_WriteHiresAngle(sizebuf_t *sb, float f)
{
MSG_WriteShort(sb, (int64)(fmod((double)f, 360.0) * 65536.0 / 360.0) & 0xFFFF);
}
void MSG_WriteUsercmd(sizebuf_t *buf, usercmd_t *to, usercmd_t *from)
{
delta_t **ppdesc;
ppdesc = DELTA_LookupRegistration("usercmd_t");
MSG_StartBitWriting(buf);
DELTA_WriteDelta((byte *)from, (byte *)to, 1, *ppdesc, 0);
MSG_EndBitWriting(buf);
}
typedef struct bf_write_s
{
// For enhanced and safe bits writing functions
#if defined(REHLDS_FIXES)
#pragma pack(push, 1)
union {
uint64 u64;
uint32 u32[2];
uint8 u8[8];
} pendingData;
uint64 sse_highbits;
#pragma pack(pop)
int nCurOutputBit;
sizebuf_t *pbuf;
#else // defined(REHLDS_FIXES)
int nCurOutputBit;
unsigned char *pOutByte;
sizebuf_t *pbuf;
#endif // defined(REHLDS_FIXES)
} bf_write_t;
typedef struct bf_read_s
{
int nMsgReadCount; // was msg_readcount
sizebuf_t *pbuf;
int nBitFieldReadStartByte;
int nBytesRead;
int nCurInputBit;
unsigned char *pInByte;
} bf_read_t;
// Bit field reading/writing storage.
bf_read_t bfread;
ALIGN16 bf_write_t bfwrite;
void COM_BitOpsInit(void)
{
Q_memset(&bfwrite, 0, sizeof(bf_write_t));
Q_memset(&bfread, 0, sizeof(bf_read_t));
}
// Enhanced and safe bits writing functions
#if defined(REHLDS_FIXES)
void MSG_WBits_MaybeFlush() {
if (bfwrite.nCurOutputBit < 32)
return;
uint32* pDest = (uint32*)SZ_GetSpace(bfwrite.pbuf, 4);
if (!(bfwrite.pbuf->flags & SIZEBUF_OVERFLOWED))
*pDest = bfwrite.pendingData.u32[0];
bfwrite.pendingData.u32[0] = bfwrite.pendingData.u32[1];
bfwrite.pendingData.u32[1] = 0;
bfwrite.nCurOutputBit -= 32;
}
void MSG_WriteBits(uint32 data, int numbits)
{
uint32 maxval = _mm_cvtsi128_si32(_mm_slli_epi64(_mm_cvtsi32_si128(1), numbits)) - 1; //maxval = (1 << numbits) - 1
if (data > maxval)
data = maxval;
MSG_WBits_MaybeFlush();
__m128i pending = _mm_load_si128((__m128i*) &bfwrite.pendingData.u64);
__m128i mmdata = _mm_slli_epi64(_mm_cvtsi32_si128(data), bfwrite.nCurOutputBit); //mmdata = data << bfwrite.nCurOutputBit
pending = _mm_or_si128(pending, mmdata);
_mm_store_si128((__m128i*) &bfwrite.pendingData.u64, pending);
bfwrite.nCurOutputBit += numbits;
}
void MSG_WriteOneBit(int nValue) {
MSG_WriteBits(nValue, 1);
}
void MSG_StartBitWriting(sizebuf_t *buf)
{
bfwrite.nCurOutputBit = 0;
bfwrite.pbuf = buf;
bfwrite.pendingData.u64 = 0;
}
void MSG_EndBitWriting(sizebuf_t *buf)
{
int bytesNeed = bfwrite.nCurOutputBit / 8;
if ((bfwrite.nCurOutputBit % 8) || bytesNeed == 0) {
bytesNeed++;
}
uint8* pData = (uint8*)SZ_GetSpace(bfwrite.pbuf, bytesNeed);
if (!(bfwrite.pbuf->flags & SIZEBUF_OVERFLOWED)) {
for (int i = 0; i < bytesNeed; i++) {
pData[i] = bfwrite.pendingData.u8[i];
}
}
}
#else // defined(REHLDS_FIXES)
void MSG_WriteOneBit(int nValue)
{
if (bfwrite.nCurOutputBit >= 8)
{
SZ_GetSpace(bfwrite.pbuf, 1);
bfwrite.nCurOutputBit = 0;
++bfwrite.pOutByte;
}
if (!(bfwrite.pbuf->flags & SIZEBUF_OVERFLOWED))
{
if (nValue)
{
*bfwrite.pOutByte |= BITTABLE[bfwrite.nCurOutputBit];
}
else
{
*bfwrite.pOutByte &= INVBITTABLE[bfwrite.nCurOutputBit * 4];
}
bfwrite.nCurOutputBit++;
}
}
void MSG_StartBitWriting(sizebuf_t *buf)
{
bfwrite.nCurOutputBit = 0;
bfwrite.pbuf = buf;
bfwrite.pOutByte = &buf->data[buf->cursize];
}
void MSG_EndBitWriting(sizebuf_t *buf)
{
if (!(bfwrite.pbuf->flags & SIZEBUF_OVERFLOWED))
{
*bfwrite.pOutByte &= 255 >> (8 - bfwrite.nCurOutputBit);
SZ_GetSpace(bfwrite.pbuf, 1);
bfwrite.nCurOutputBit = 0;
bfwrite.pOutByte = 0;
bfwrite.pbuf = 0;
}
}
void MSG_WriteBits(uint32 data, int numbits)
{
if (numbits < 32)
{
if (data >= (uint32)(1 << numbits))
data = ROWBITTABLE[numbits];
}
int surplusBytes = 0;
if ((uint32)bfwrite.nCurOutputBit >= 8)
{
surplusBytes = 1;
bfwrite.nCurOutputBit = 0;
++bfwrite.pOutByte;
}
int bits = numbits + bfwrite.nCurOutputBit;
if (bits <= 32)
{
int bytesToWrite = bits >> 3;
int bitsLeft = bits & 7;
if (!bitsLeft)
--bytesToWrite;
SZ_GetSpace(bfwrite.pbuf, surplusBytes + bytesToWrite);
if (!(bfwrite.pbuf->flags & SIZEBUF_OVERFLOWED))
{
*(uint32 *)bfwrite.pOutByte = (data << bfwrite.nCurOutputBit) | *(uint32 *)bfwrite.pOutByte & ROWBITTABLE[bfwrite.nCurOutputBit];
bfwrite.nCurOutputBit = 8;
if (bitsLeft)
bfwrite.nCurOutputBit = bitsLeft;
bfwrite.pOutByte = &bfwrite.pOutByte[bytesToWrite];
}
}
else
{
SZ_GetSpace(bfwrite.pbuf, surplusBytes + 4);
if (!(bfwrite.pbuf->flags & SIZEBUF_OVERFLOWED))
{
*(uint32 *)bfwrite.pOutByte = (data << bfwrite.nCurOutputBit) | *(uint32 *)bfwrite.pOutByte & ROWBITTABLE[bfwrite.nCurOutputBit];
int leftBits = 32 - bfwrite.nCurOutputBit;
bfwrite.nCurOutputBit = bits & 7;
bfwrite.pOutByte += 4;
*(uint32 *)bfwrite.pOutByte = data >> leftBits;
}
}
}
#endif //defined(REHLDS_FIXES)
qboolean MSG_IsBitWriting(void)
{
return bfwrite.pbuf != 0;
}
void MSG_WriteSBits(int data, int numbits)
{
int idata = data;
if (numbits < 32)
{
int maxnum = (1 << (numbits - 1)) - 1;
if (data > maxnum || (maxnum = -maxnum, data < maxnum))
{
idata = maxnum;
}
}
int sigbits = idata < 0;
MSG_WriteOneBit(sigbits);
MSG_WriteBits(abs(idata), numbits - 1);
}
void MSG_WriteBitString(const char *p)
{
#ifdef REHLDS_FIXES
const uint8_t *pch = (uint8_t *)p;
#else // REHLDS_FIXES
char *pch = (char *)p;
#endif // REHLDS_FIXES
while (*pch)
{
MSG_WriteBits(*pch, 8);
++pch;
}
MSG_WriteBits(0, 8);
}
void MSG_WriteBitData(void *src, int length)
{
int i;
byte *p = (byte *)src;
for (i = 0; i < length; i++, p++)
{
MSG_WriteBits(*p, 8);
}
}
void MSG_WriteBitAngle(float fAngle, int numbits)
{
if (numbits >= 32)
{
Sys_Error("%s: Can't write bit angle with 32 bits precision\n", __func__);
}
uint32 shift = (1 << numbits);
uint32 mask = shift - 1;
int d = (int)(shift * fmod((double)fAngle, 360.0)) / 360;
d &= mask;
MSG_WriteBits(d, numbits);
}
float MSG_ReadBitAngle(int numbits)
{
return (float)(MSG_ReadBits(numbits) * (360.0 / (1 << numbits)));
}
int MSG_CurrentBit(void)
{
int nbits;
if (bfread.pbuf)
{
nbits = bfread.nCurInputBit + 8 * bfread.nBytesRead;
}
else
{
nbits = 8 * msg_readcount;
}
return nbits;
}
qboolean MSG_IsBitReading(void)
{
return bfread.pbuf != 0;
}
void MSG_StartBitReading(sizebuf_t *buf)
{
bfread.nCurInputBit = 0;
bfread.nBytesRead = 0;
bfread.nBitFieldReadStartByte = msg_readcount;
bfread.pbuf = buf;
bfread.pInByte = &buf->data[msg_readcount];
bfread.nMsgReadCount = msg_readcount + 1;
if (msg_readcount + 1 > buf->cursize)
{
msg_badread = 1;
}
}
void MSG_EndBitReading(sizebuf_t *buf)
{
if (bfread.nMsgReadCount > buf->cursize)
{
msg_badread = 1;
}
msg_readcount = bfread.nMsgReadCount;
bfread.nBitFieldReadStartByte = 0;
bfread.nCurInputBit = 0;
bfread.nBytesRead = 0;
bfread.pInByte = 0;
bfread.pbuf = 0;
}
int MSG_ReadOneBit(void)
{
int nValue;
if (msg_badread)
{
nValue = 1;
}
else
{
if (bfread.nCurInputBit >= 8)
{
++bfread.nMsgReadCount;
bfread.nCurInputBit = 0;
++bfread.nBytesRead;
++bfread.pInByte;
}
if (bfread.nMsgReadCount <= bfread.pbuf->cursize)
{
nValue = (*bfread.pInByte & BITTABLE[bfread.nCurInputBit]) != 0;
++bfread.nCurInputBit;
}
else
{
nValue = 1;
msg_badread = 1;
}
}
return nValue;
}
uint32 MSG_ReadBits(int numbits)
{
uint32 result;
#ifdef REHLDS_FIXES
if (numbits > 32) {
Sys_Error("%s: invalid numbits %d\n", __func__, numbits);
}
#endif // REHLDS_FIXES
if (msg_badread)
{
result = 1;
}
else
{
if (bfread.nCurInputBit >= 8)
{
++bfread.nMsgReadCount;
++bfread.nBytesRead;
++bfread.pInByte;
bfread.nCurInputBit = 0;
}
uint32 bits = (bfread.nCurInputBit + numbits) & 7;
if ((unsigned int)(bfread.nCurInputBit + numbits) <= 32)
{
result = (*(unsigned int *)bfread.pInByte >> bfread.nCurInputBit) & ROWBITTABLE[numbits];
uint32 bytes = (bfread.nCurInputBit + numbits) >> 3;
if (bits)
{
bfread.nCurInputBit = bits;
}
else
{
bfread.nCurInputBit = 8;
bytes--;
}
bfread.pInByte += bytes;
bfread.nMsgReadCount += bytes;
bfread.nBytesRead += bytes;
}
else
{
result = ((*(unsigned int *)(bfread.pInByte + 4) & ROWBITTABLE[bits]) << (32 - bfread.nCurInputBit)) | (*(unsigned int *)bfread.pInByte >> bfread.nCurInputBit);
bfread.nCurInputBit = bits;
bfread.pInByte += 4;
bfread.nMsgReadCount += 4;
bfread.nBytesRead += 4;
}
if (bfread.nMsgReadCount > bfread.pbuf->cursize)
{
result = 1;
msg_badread = 1;
}
}
return result;
}
uint32 MSG_PeekBits(int numbits)
{
bf_read_t savebf = bfread;
uint32 r = MSG_ReadBits(numbits);
bfread = savebf;
return r;
}
int MSG_ReadSBits(int numbits)
{
int nSignBit = MSG_ReadOneBit();
int result = MSG_ReadBits(numbits - 1);
if (nSignBit)
{
result = -result;
}
return result;
}
char *MSG_ReadBitString(void)
{
static char buf[8192];
char *p = &buf[0];
for (char c = MSG_ReadBits(8); c; c = MSG_ReadBits(8))
{
#ifdef REHLDS_FIXES
if (msg_badread) // Prevent infinite cycle if msg_badread
{
break;
}
#endif
*p++ = c;
}
*p = 0;
return buf;
}
int MSG_ReadBitData(void *dest, int length)
{
if (length > 0)
{
int i = length;
unsigned char * p = (unsigned char *)dest;
do
{
*p = (unsigned char)MSG_ReadBits(8);
p++;
--i;
}
while (i);
}
return length;
}
float MSG_ReadBitCoord(void)
{
float value = 0;
int intval = MSG_ReadOneBit();
int fractval = MSG_ReadOneBit();
if (intval || fractval)
{
int signbit = MSG_ReadOneBit();
if (intval)
{
intval = MSG_ReadBits(12);
}
if (fractval)
{
fractval = MSG_ReadBits(3);
}
value = (float)(fractval / 8.0 + intval);
if (signbit)
{
value = -value;
}
}
return value;
}
void MSG_WriteBitCoord(const float f)
{
int signbit = f <= -0.125;
int intval = abs((int32)f);
int fractval = abs((int32)f * 8) & 7;
MSG_WriteOneBit(intval);
MSG_WriteOneBit(fractval);
if (intval || fractval)
{
MSG_WriteOneBit(signbit);
if (intval)
MSG_WriteBits(intval, 12);
if (fractval)
MSG_WriteBits(fractval, 3);
}
}
void MSG_ReadBitVec3Coord(vec3_t fa)
{
int xflag = MSG_ReadOneBit();
int yflag = MSG_ReadOneBit();
int zflag = MSG_ReadOneBit();
if (xflag)
fa[0] = MSG_ReadBitCoord();
if (yflag)
fa[1] = MSG_ReadBitCoord();
if (zflag)
fa[2] = MSG_ReadBitCoord();
}
void MSG_WriteBitVec3Coord(const vec3_t fa)
{
bool xflag = fa[0] <= -0.125 || fa[0] >= 0.125;
bool yflag = fa[1] <= -0.125 || fa[1] >= 0.125;
bool zflag = fa[2] <= -0.125 || fa[2] >= 0.125;
MSG_WriteOneBit(xflag);
MSG_WriteOneBit(yflag);
MSG_WriteOneBit(zflag);
if (xflag)
MSG_WriteBitCoord(fa[0]);
if (yflag)
MSG_WriteBitCoord(fa[1]);
if (zflag)
MSG_WriteBitCoord(fa[2]);
}
float MSG_ReadCoord(void)
{
return (float)(MSG_ReadShort() * (1.0 / 8));
}
void MSG_WriteCoord(sizebuf_t *sb, const float f)
{
MSG_WriteShort(sb, (int)(f * 8.0));
}
void MSG_ReadVec3Coord(sizebuf_t *sb, vec3_t fa)
{
if (MSG_IsBitReading())
{
MSG_ReadBitVec3Coord(fa);
}
else
{
MSG_StartBitReading(sb);
MSG_ReadBitVec3Coord(fa);
MSG_EndBitReading(sb);
}
}
void MSG_WriteVec3Coord(sizebuf_t *sb, const vec3_t fa)
{
MSG_StartBitWriting(sb);
MSG_WriteBitVec3Coord(fa);
MSG_EndBitWriting(sb);
}
void MSG_BeginReading(void)
{
msg_readcount = 0;
msg_badread = 0;
}
int MSG_ReadChar(void)
{
int c;
if (msg_readcount < net_message.cursize)
{
c = net_message.data[msg_readcount];
msg_readcount++;
}
else
{
msg_badread = 1;
c = -1;
}
return c;
}
int MSG_ReadByte(void)
{
int c;
if (msg_readcount < net_message.cursize)
{
c = net_message.data[msg_readcount];
msg_readcount++;
}
else
{
msg_badread = 1;
c = -1;
}
return c;
}
int MSG_ReadShort(void)
{
int c;
if (msg_readcount + 2 <= net_message.cursize )
{
c = *(int16 *)&net_message.data[msg_readcount];
msg_readcount += 2;
}
else
{
msg_badread = 1;
c = -1;
}
return c;
}
NOXREF int MSG_ReadWord(void)
{
NOXREFCHECK;
int c;
if (msg_readcount + 2 <= net_message.cursize)
{
c = *(uint16 *)&net_message.data[msg_readcount];
msg_readcount += 2;
}
else
{
msg_badread = 1;
c = -1;
}
return c;
}
int MSG_ReadLong(void)
{
int c;
if (msg_readcount + 4 <= net_message.cursize)
{
c = *(uint32 *)&net_message.data[msg_readcount];
msg_readcount += 4;
}
else
{
msg_badread = 1;
c = -1;
}
return c;
}
float MSG_ReadFloat(void)
{
float f;
union
{
unsigned char b[4];
float f;
int l;
} dat;
if (msg_readcount + 4 <= net_message.cursize)
{
dat.b[0] = net_message.data[msg_readcount];
dat.b[1] = net_message.data[msg_readcount + 1];
dat.b[2] = net_message.data[msg_readcount + 2];
dat.b[3] = net_message.data[msg_readcount + 3];
msg_readcount += 4;
dat.l = LittleLong(dat.l);
return dat.f;
}
else
{
msg_badread = 1;
f = -1.0;
}
return f;
}
int MSG_ReadBuf(int iSize, void *pbuf)
{
if (msg_readcount + iSize <= net_message.cursize)
{
Q_memcpy(pbuf, &net_message.data[msg_readcount], iSize);
msg_readcount += iSize;
return 1;
}
msg_badread = 1;
return -1;
}
char *MSG_ReadString(void)
{
int c = 0, l = 0;
static char string[8192];
while ((c = MSG_ReadChar(), c) && c != -1 && l < ARRAYSIZE(string) - 1)
{
string[l++] = c;
}
string[l] = 0;
return string;
}
char *MSG_ReadStringLine(void)
{
int c = 0, l = 0;
static char string[2048];
while ((c = MSG_ReadChar(), c) && c != '\n' && c != -1 && l < ARRAYSIZE(string) - 1)
{
string[l++] = c;
}
string[l] = 0;
return string;
}
float MSG_ReadAngle(void)
{
int c = MSG_ReadChar();
#ifdef REHLDS_FIXES
if (c == -1) // FIXED: Added check for wrong value, but just return 0 instead of -1 * (360.0 / 256)
{
return 0;
}
#endif
return (float)(c * (360.0 / 256));
}
float MSG_ReadHiresAngle(void)
{
int c = MSG_ReadShort();
#ifdef REHLDS_FIXES
if (c == -1) // FIXED: Added check for wrong value, but just return 0 instead of -1 * (360.0 / 65536)
{
return 0;
}
#endif
return (float)(MSG_ReadShort() * (360.0 / 65536));
}
void MSG_ReadUsercmd(usercmd_t *to, usercmd_t* from)
{
MSG_StartBitReading(&net_message);
#ifdef REHLDS_OPT_PEDANTIC
DELTA_ParseDelta((byte *)from, (byte *)to, g_pusercmddelta);
#else
DELTA_ParseDelta((byte *)from, (byte *)to, SV_LookupDelta("usercmd_t"));
#endif
MSG_EndBitReading(&net_message);
COM_NormalizeAngles(to->viewangles);
}
#endif // MSG_Functions_region
#ifndef SZ_Functions_region
void SZ_Alloc(const char *name, sizebuf_t *buf, int startsize)
{
buf->buffername = name;
if (startsize < 256)
{
startsize = 256;
}
buf->data = (byte *)Hunk_AllocName(startsize, name);
buf->maxsize = startsize;
buf->cursize = 0;
buf->flags = SIZEBUF_CHECK_OVERFLOW;
}
void SZ_Clear(sizebuf_t *buf)
{
buf->flags &= ~SIZEBUF_OVERFLOWED;
buf->cursize = 0;
}
qboolean SZ_HasSpaceToRead(const sizebuf_t *buf, int length)
{
if ((msg_readcount + length) > buf->maxsize)
return FALSE;
return TRUE;
}
qboolean SZ_HasSomethingToRead(const sizebuf_t *buf, int length)
{
if ((msg_readcount + length) > buf->cursize)
return FALSE;
return TRUE;
}
void *EXT_FUNC SZ_GetSpace(sizebuf_t *buf, int length)
{
void *data;
const char *buffername = buf->buffername ? buf->buffername : "???";
if (length < 0)
{
Sys_Error("%s: %i negative length on %s", __func__, length, buffername);
}
if (buf->cursize + length > buf->maxsize)
{
#ifdef REHLDS_FIXES
if (!(buf->flags & SIZEBUF_ALLOW_OVERFLOW))
{
if (!buf->maxsize)
{
Sys_Error("%s: tried to write to an uninitialized sizebuf_t: %s", __func__, buffername);
}
else if (length > buf->maxsize)
{
Sys_Error("%s: %i is > full buffer size on %s", __func__, length, buffername);
}
else
{
Sys_Error("%s: overflow without FSB_ALLOWOVERFLOW set on %s", __func__, buffername);
}
}
if (length > buf->maxsize)
{
Con_DPrintf("%s: %i is > full buffer size on %s, ignoring", __func__, length, buffername);
}
#else // REHLDS_FIXES
if (!(buf->flags & SIZEBUF_ALLOW_OVERFLOW))
{
if (!buf->maxsize)
{
Sys_Error("%s: Tried to write to an uninitialized sizebuf_t: %s", __func__, buffername);
}
else
{
Sys_Error("%s: overflow without FSB_ALLOWOVERFLOW set on %s", __func__, buffername);
}
}
if (length > buf->maxsize)
{
if (!(buf->flags & SIZEBUF_ALLOW_OVERFLOW))
{
Sys_Error("%s: %i is > full buffer size on %s", __func__, length, buffername);
}
Con_DPrintf("%s: %i is > full buffer size on %s, ignoring", __func__, length, buffername);
}
#endif // REHLDS_FIXES
Con_Printf("%s: overflow on %s\n", __func__, buffername);
SZ_Clear(buf);
buf->flags |= SIZEBUF_OVERFLOWED;
}
data = &buf->data[buf->cursize];
buf->cursize = length + buf->cursize;
return data;
}
void SZ_Write(sizebuf_t *buf, const void *data, int length)
{
unsigned char *pData = (unsigned char *)SZ_GetSpace(buf, length);
if (!(buf->flags & SIZEBUF_OVERFLOWED))
{
Q_memcpy(pData, data, length);
}
}
void SZ_Print(sizebuf_t *buf, const char *data)
{
unsigned char *pData;
int len = Q_strlen(data) + 1;
if (buf->data[buf->cursize - 1])
{
pData = (unsigned char *)SZ_GetSpace(buf, len);
}
else
{
pData = (unsigned char *)SZ_GetSpace(buf, len - 1) - 1;
}
if (!(buf->flags & SIZEBUF_OVERFLOWED))
{
Q_memcpy(pData, data, len);
}
}
#endif // SZ_Functions_region
#ifndef COM_Functions_region
int com_argc;
char **com_argv;
char com_token[COM_TOKEN_LEN];
qboolean com_ignorecolons;
qboolean s_com_token_unget;
char *com_last_in_quotes_data = NULL;
char com_clientfallback[MAX_PATH];
char com_gamedir[MAX_PATH];
char com_cmdline[COM_MAX_CMD_LINE];
cache_user_t *loadcache;
unsigned char *loadbuf;
int loadsize;
const unsigned char mungify_table[] =
{
0x7A, 0x64, 0x05, 0xF1,
0x1B, 0x9B, 0xA0, 0xB5,
0xCA, 0xED, 0x61, 0x0D,
0x4A, 0xDF, 0x8E, 0xC7
};
const unsigned char mungify_table2[] =
{
0x05, 0x61, 0x7A, 0xED,
0x1B, 0xCA, 0x0D, 0x9B,
0x4A, 0xF1, 0x64, 0xC7,
0xB5, 0x8E, 0xDF, 0xA0
};
unsigned char mungify_table3[] =
{
0x20, 0x07, 0x13, 0x61,
0x03, 0x45, 0x17, 0x72,
0x0A, 0x2D, 0x48, 0x0C,
0x4A, 0x12, 0xA9, 0xB5
};
NOXREF char *COM_SkipPath(char *pathname)
{
NOXREFCHECK;
char *last = pathname;
while (*pathname)
{
if (*pathname == '/' || *pathname == '\\')
last = pathname + 1;
pathname++;
}
return last;
}
void COM_StripExtension(char *in, char *out)
{
char *c, *d = NULL;
int i;
// Search for the first dot after the last path separator
c = in;
while (*c)
{
if (*c == '/' || *c == '\\')
{
d = NULL; // reset dot location on path separator
}
else if (d == NULL && *c == '.')
{
d = c; // store first dot location in the file name
}
c++;
}
if (out == in)
{
if (d != NULL)
{
*d = 0;
}
}
else
{
if (d != NULL)
{
i = d - in;
Q_memcpy(out, in, i);
out[i] = 0;
}
else
{
Q_strcpy(out, in);
}
}
}
char *COM_FileExtension(char *in)
{
#ifdef REHLDS_FIXES
int len = Q_strlen(in);
if (len <= 0)
return ""; // no extension
char *src = in + len - 1;
// back up until a . or the start
while (src >= in && !PATHSEPARATOR(*src))
{
if (*src == '.')
{
src++; // skip dot
if (*src != '\0')
{
return src;
}
break;
}
src--;
}
return ""; // no extension
#else // #ifdef REHLDS_FIXES
static char exten[MAX_PATH];
char *c, *d = NULL;
int i;
// Search for the first dot after the last path separator
c = in;
while (*c)
{
if (*c == '/' || *c == '\\')
{
d = NULL; // reset dot location on path separator
}
else if (d == NULL && *c == '.')
{
d = c; // store first dot location in the file name
}
c++;
}
if (d == NULL)
{
return "";
}
d++; // skip dot
// Copy extension
for (i = 0; i < (ARRAYSIZE(exten) - 1) && *d; i++, d++)
{
exten[i] = *d;
}
exten[i] = 0;
return exten;
#endif // #ifdef REHLDS_FIXES
}
// Fills "out" with the file name without path and extension.
void COM_FileBase(const char *in, char *out)
{
const char *start, *end;
int len;
*out = 0;
len = Q_strlen(in);
if (len <= 0)
return;
start = in + len - 1;
end = in + len;
while (start >= in && *start != '/' && *start != '\\')
{
if (*start == '.')
end = start;
start--;
}
start++;
len = end - start;
Q_strncpy(out, start, len);
out[len] = 0;
}
void COM_DefaultExtension(char *path, char *extension)
{
char *src;
src = path + Q_strlen(path) - 1;
while (*src != '/' && *src != '\\' && src != path)
{
if (*src == '.')
{
return;
}
src--;
}
Q_strcat(path, extension);
}
void COM_UngetToken(void)
{
s_com_token_unget = 1;
}
char *COM_Parse(char *data)
{
int c;
uchar32 wchar;
int len;
if (s_com_token_unget)
{
s_com_token_unget = 0;
return data;
}
len = 0;
com_token[0] = 0;
if (!data)
{
return NULL;
}
if (com_last_in_quotes_data == data)
{
// continue to parse quoted string
com_last_in_quotes_data = NULL;
goto inquotes;
}
skipwhite:
// skip whitespace
while (!V_UTF8ToUChar32(data, &wchar) && wchar <= 32)
{
if (!wchar)
return NULL;
data = Q_UnicodeAdvance(data, 1);
}
c = *data;
// skip // comments till the next line
if (c == '/' && data[1] == '/')
{
while (*data && *data != '\n')
data++;
goto skipwhite; // start over new line
}
// handle quoted strings specially: copy till the end or another quote
if (c == '\"')
{
data++; // skip starting quote
while (true)
{
inquotes:
c = *data++; // get char and advance
if (!c) // EOL
{
com_token[len] = 0;
return data - 1; // we are done with that, but return data to show that token is present
}
if (c == '\"') // closing quote
{
com_token[len] = 0;
return data;
}
com_token[len] = c;
len++;
if (len == COM_TOKEN_LEN - 1) // check if buffer is full
{
// remember in-quotes state
com_last_in_quotes_data = data;
com_token[len] = 0;
return data;
}
}
}
// parse single characters
if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',' || (!com_ignorecolons && c == ':'))
{
com_token[len] = c;
len++;
com_token[len] = 0;
return data + 1;
}
// parse a regular word
do
{
com_token[len] = c;
data++;
len++;
c = *data;
if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',' || (!com_ignorecolons && c == ':'))
break;
} while (len < COM_TOKEN_LEN - 1 && (c < 0 || c > 32));
com_token[len] = 0;
return data;
}
char *COM_ParseLine(char *data)
{
#ifdef REHLDS_FIXES
unsigned int c;
#else
int c;
#endif
int len;
if (s_com_token_unget)
{
s_com_token_unget = 0;
return data;
}
len = 0;
com_token[0] = 0;
if (!data)
{
return NULL;
}
c = *data;
// parse a line out of the data
#ifdef REHLDS_FIXES
while ((c >= ' ' || c == '\t') && (len < COM_TOKEN_LEN - 1))
{
com_token[len] = c;
data++;
len++;
c = *data;
}
#else
do
{
com_token[len] = c; // TODO: Here c may be any ASCII, \n for example, but we are copy it in the token
data++;
len++;
c = *data;
} while (c >= ' ' && (len < COM_TOKEN_LEN - 1)); // TODO: Will break on \t, may be it shouldn't?
#endif
com_token[len] = 0;
if (c == 0) // end of file
{
return NULL;
}
// skip end of the line (CR, LF, etc.., but not TAB)
while ((c = *data) < ' ' && c != '\t')
{
if (c == 0)
{
return NULL; // end of file;
}
data++;
}
return data;
}
int COM_TokenWaiting(char *buffer)
{
char *p;
p = buffer;
while (*p && *p != '\n')
{
if (!isspace(*p) || isalnum(*p))
return 1;
p++;
}
return 0;
}
int COM_CheckParm(const char *parm)
{
int i;
for (i = 1 ; i < com_argc; i++)
{
if (!com_argv[i])
{
continue;
}
if (!Q_strcmp(parm, (const char*)com_argv[i]))
{
return i;
}
}
return 0;
}
void COM_InitArgv(int argc, char *argv[])
{
qboolean safe = 0;
static char *safeargvs[NUM_SAFE_ARGVS] =
{
"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly"
};
static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
int i, j;
char *c;
// Reconstruct full command line
com_cmdline[0] = 0;
for (i = 0, j = 0; i < MAX_NUM_ARGVS && i < argc && j < COM_MAX_CMD_LINE - 1; i++)
{
c = argv[i];
if (*c)
{
while (*c && j < COM_MAX_CMD_LINE - 1)
{
com_cmdline[j++] = *c++;
}
if (j >= COM_MAX_CMD_LINE - 1)
{
break;
}
com_cmdline[j++] = ' ';
}
}
com_cmdline[j] = 0;
// Copy args pointers to our array
for (com_argc = 0; (com_argc < MAX_NUM_ARGVS) && (com_argc < argc); com_argc++)
{
largv[com_argc] = argv[com_argc];
if (!Q_strcmp("-safe", argv[com_argc]))
{
safe = 1;
}
}
// Add arguments introducing more failsafeness
if (safe)
{
// force all the safe-mode switches. Note that we reserved extra space in
// case we need to add these, so we don't need an overflow check
for (int i = 0; i < NUM_SAFE_ARGVS; i++)
{
largv[com_argc] = safeargvs[i];
com_argc++;
}
}
largv[com_argc] = " ";
com_argv = largv;
}
void COM_Init(char *basedir)
{
unsigned short swaptest = 1;
if (*(byte *)&swaptest == 1)
{
bigendien = 0;
BigShort = ShortSwap;
LittleShort = ShortNoSwap;
BigLong = LongSwap;
LittleLong = LongNoSwap;
BigFloat = FloatSwap;
LittleFloat = FloatNoSwap;
}
else
{
bigendien = 1;
BigShort = ShortNoSwap;
LittleShort = ShortSwap;
BigLong = LongNoSwap;
LittleLong = LongSwap;
BigFloat = FloatNoSwap;
LittleFloat = FloatSwap;
}
COM_BitOpsInit();
}
char *va(char *format, ...)
{
va_list argptr;
static int current = 0;
static char string[16][1024];
current = (current + 1) % 16;
va_start(argptr, format);
Q_vsnprintf(string[current], ARRAYSIZE(string[current]), format, argptr);
va_end(argptr);
return string[current];
}
NOXREF char *vstr(vec_t *v)
{
NOXREFCHECK;
static int idx = 0;
static char string[16][1024];
idx++;
idx &= 15;
Q_snprintf(string[idx], ARRAYSIZE(string[idx]), "%.4f %.4f %.4f", v[0], v[1], v[2]);
return string[idx];
}
NOXREF int memsearch(unsigned char *start, int count, int search)
{
NOXREFCHECK;
for (int i = 0; i < count; i++)
{
if (start[i] == search)
{
return i;
}
}
return -1;
}
NOXREF void COM_WriteFile(char *filename, void *data, int len)
{
NOXREFCHECK;
char path[MAX_PATH];
Q_snprintf(path, MAX_PATH - 1, "%s", filename);
path[MAX_PATH - 1] = 0;
COM_FixSlashes(path);
COM_CreatePath(path);
FileHandle_t fp = FS_Open(path, "wb");
if (fp)
{
Sys_Printf("%s: %s\n", __func__, path);
FS_Write(data, len, 1, fp);
FS_Close(fp);
}
else
{
Sys_Printf("%s: failed on %s\n", __func__, path);
}
}
void COM_FixSlashes(char *pname)
{
while (*pname)
{
#ifdef _WIN32
if (*pname == '/')
{
*pname = '\\';
}
#else
if (*pname == '\\')
{
*pname = '/';
}
#endif
pname++;
}
}
void COM_CreatePath(char *path)
{
char *ofs;
char old;
if (*path == 0)
{
return;
}
for (ofs = path + 1; *ofs; ofs++)
{
if (*ofs == '/' || *ofs == '\\')
{
old = *ofs;
*ofs = 0;
FS_CreateDirHierarchy(path, 0);
*ofs = old;
}
}
}
NOXREF void COM_CopyFile(char *netpath, char *cachepath)
{
NOXREFCHECK;
int count;
int remaining;
char buf[4096];
FileHandle_t out;
FileHandle_t in = FS_Open(netpath, "rb");
if (!in)
{
return;
}
count = FS_Size(in);
COM_CreatePath(cachepath);
for (out = FS_Open(cachepath, "wb"); count; count -= remaining)
{
remaining = count;
if (remaining > 4096)
{
remaining = 4096;
}
FS_Read(buf, remaining, 1, in);
FS_Write(buf, remaining, 1, out);
}
FS_Close(in);
FS_Close(out);
}
NOXREF int COM_ExpandFilename(char *filename)
{
NOXREFCHECK;
char netpath[MAX_PATH];
FS_GetLocalPath(filename, netpath, ARRAYSIZE(netpath));
Q_strcpy(filename, netpath);
return *filename != 0;
}
int EXT_FUNC COM_FileSize(const char *filename)
{
FileHandle_t fp;
int iSize;
iSize = -1;
fp = FS_Open(filename, "rb");
if (fp)
{
iSize = FS_Size(fp);
FS_Close(fp);
}
return iSize;
}
unsigned char* EXT_FUNC COM_LoadFile(const char *path, int usehunk, int *pLength)
{
char base[33];
unsigned char *buf = NULL;
#ifndef SWDS
g_engdstAddrs->COM_LoadFile(&path, &usehunk, &pLength);
#endif
if (pLength)
{
*pLength = 0;
}
FileHandle_t hFile = FS_Open(path, "rb");
if (!hFile)
{
return NULL;
}
int len = FS_Size(hFile);
COM_FileBase(path, base);
base[32] = 0;
switch (usehunk)
{
case 0:
buf = (unsigned char *)Z_Malloc(len + 1);
break;
case 1:
buf = (unsigned char *)Hunk_AllocName(len + 1, base);
break;
case 2:
buf = (unsigned char *)Hunk_TempAlloc(len + 1);
break;
case 3:
buf = (unsigned char *)Cache_Alloc(loadcache, len + 1, base);
break;
case 4:
if (len + 1 <= loadsize)
{
buf = loadbuf;
}
else
{
buf = (unsigned char *)Hunk_TempAlloc(len + 1);
}
break;
case 5:
buf = (unsigned char *)Mem_Malloc(len + 1);
break;
default:
#ifdef REHLDS_FIXES
FS_Close(hFile);
#endif
Sys_Error("%s: bad usehunk", __func__);
}
if (!buf)
{
#ifdef REHLDS_FIXES
FS_Close(hFile);
#endif
Sys_Error("%s: not enough space for %s", __func__, path);
}
FS_Read(buf, len, 1, hFile);
FS_Close(hFile);
buf[len] = 0;
if (pLength)
{
*pLength = len;
}
return buf;
}
void EXT_FUNC COM_FreeFile(void *buffer)
{
#ifndef SWDS
g_engdstAddrs->COM_FreeFile();
#endif
if (buffer)
{
Mem_Free(buffer);
}
}
void COM_CopyFileChunk(FileHandle_t dst, FileHandle_t src, int nSize)
{
int copysize;
char copybuf[COM_COPY_CHUNK_SIZE];
copysize = nSize;
while (copysize > COM_COPY_CHUNK_SIZE)
{
FS_Read(copybuf, COM_COPY_CHUNK_SIZE, 1, src);
FS_Write(copybuf, COM_COPY_CHUNK_SIZE, 1, dst);
copysize -= COM_COPY_CHUNK_SIZE;
}
FS_Read(copybuf, copysize, 1, src);
FS_Write(copybuf, copysize, 1, dst);
FS_Flush(src);
FS_Flush(dst);
}
NOXREF unsigned char *COM_LoadFileLimit(char *path, int pos, int cbmax, int *pcbread, FileHandle_t *phFile)
{
NOXREFCHECK;
FileHandle_t hFile;
unsigned char *buf;
char base[32];
int len;
int cbload;
hFile = *phFile;
if (!hFile)
{
hFile = FS_Open(path, "rb");
if (!hFile)
return NULL;
}
len = FS_Size(hFile);
if (len < pos)
{
#ifdef REHLDS_FIXES
FS_Close(hFile);
#endif
Sys_Error("%s: invalid seek position for %s", __func__, path);
}
FS_Seek(hFile, pos, FILESYSTEM_SEEK_HEAD);
if (len > cbmax)
cbload = cbmax;
else
cbload = len;
*pcbread = cbload;
if (path)
COM_FileBase(path, base);
buf = (unsigned char *)Hunk_TempAlloc(cbload + 1);
if (!buf)
{
if (path)
{
#ifdef REHLDS_FIXES
FS_Close(hFile);
#endif
Sys_Error("%s: not enough space for %s", __func__, path);
}
FS_Close(hFile);
return NULL;
}
buf[cbload] = 0;
FS_Read(buf, cbload, 1, hFile);
*phFile = hFile;
return buf;
}
unsigned char *COM_LoadHunkFile(char *path)
{
return COM_LoadFile(path, 1, NULL);
}
unsigned char *COM_LoadTempFile(char *path, int *pLength)
{
return COM_LoadFile(path, 2, pLength);
}
void EXT_FUNC COM_LoadCacheFile(char *path, struct cache_user_s *cu)
{
loadcache = cu;
COM_LoadFile(path, 3, 0);
}
NOXREF unsigned char *COM_LoadStackFile(char *path, void *buffer, int bufsize, int *length)
{
NOXREFCHECK;
loadbuf = (unsigned char *)buffer;
loadsize = bufsize;
return COM_LoadFile(path, 4, length);
}
void COM_Shutdown(void)
{
// Do nothing.
}
NOXREF void COM_AddAppDirectory(char *pszBaseDir, const char *appName)
{
NOXREFCHECK;
FS_AddSearchPath(pszBaseDir, "PLATFORM");
}
void COM_AddDefaultDir(char *pszDir)
{
if (pszDir && *pszDir)
{
FileSystem_AddFallbackGameDir(pszDir);
}
}
void COM_StripTrailingSlash(char *ppath)
{
int len = Q_strlen(ppath);
if (len > 0)
{
if ((ppath[len - 1] == '\\') || (ppath[len - 1] == '/'))
{
ppath[len - 1] = 0;
}
}
}
void COM_ParseDirectoryFromCmd(const char *pCmdName, char *pDirName, const char *pDefault)
{
const char *pParameter = NULL;
int cmdParameterIndex = COM_CheckParm(pCmdName);
if (cmdParameterIndex && cmdParameterIndex < com_argc - 1)
{
pParameter = com_argv[cmdParameterIndex + 1];
if (*pParameter == '-' || *pParameter == '+')
{
pParameter = NULL;
}
}
// Found a valid parameter on the cmd line?
if (pParameter)
{
// Grab it
Q_strcpy(pDirName, pParameter);
}
else if (pDefault)
{
// Ok, then use the default
Q_strcpy(pDirName, pDefault);
}
else
{
// If no default either, then just terminate the string
pDirName[0] = 0;
}
COM_StripTrailingSlash(pDirName);
}
// TODO: finish me!
qboolean COM_SetupDirectories(void)
{
char pDirName[512];
com_clientfallback[0] = 0;
com_gamedir[0] = 0;
COM_ParseDirectoryFromCmd("-basedir", pDirName, "valve");
COM_ParseDirectoryFromCmd("-game", com_gamedir, pDirName);
if (FileSystem_SetGameDirectory(pDirName, (const char *)(com_gamedir[0] != 0 ? com_gamedir : 0)))
{
Info_SetValueForStarKey(Info_Serverinfo(), "*gamedir", com_gamedir, MAX_INFO_STRING);
return 1;
}
return 0;
}
void COM_CheckPrintMap(dheader_t *header, const char *mapname, qboolean bShowOutdated)
{
if (header->version == HLBSP_VERSION)
{
if (!bShowOutdated)
{
Con_Printf("%s\n", mapname);
}
}
else
{
if (bShowOutdated)
{
Con_Printf("OUTDATED: %s\n", mapname);
}
}
}
void COM_ListMaps(char *pszSubString)
{
dheader_t header;
FileHandle_t fp;
char mapwild[64];
char curDir[4096];
char pFileName[64];
const char *findfn;
int nSubStringLen = 0;
if (pszSubString && *pszSubString)
{
nSubStringLen = Q_strlen(pszSubString);
}
Con_Printf("-------------\n");
for (int bShowOutdated = 1; bShowOutdated >= 0; bShowOutdated--)
{
Q_strcpy(mapwild, "maps/*.bsp");
findfn = Sys_FindFirst(mapwild, NULL);
while (findfn != NULL)
{
if (Q_snprintf(curDir, ARRAYSIZE(curDir), "maps/%s", findfn) < ARRAYSIZE(curDir))
{
FS_GetLocalPath(curDir, curDir, ARRAYSIZE(curDir));
if (Q_strstr(curDir, com_gamedir) && (!nSubStringLen || !Q_strnicmp(findfn, pszSubString, nSubStringLen)))
{
if (Q_snprintf(pFileName, ARRAYSIZE(pFileName), "maps/%s", findfn) < ARRAYSIZE(pFileName))
{
Q_memset(&header, 0, sizeof(dheader_t));
fp = FS_Open(pFileName, "rb");
if (fp)
{
FS_Read(&header, sizeof(dheader_t), 1, fp);
FS_Close(fp);
}
COM_CheckPrintMap(&header, findfn, bShowOutdated != 0);
}
else
{
Con_Printf("Map name too long: %s\n", findfn);
}
}
}
else
{
Con_Printf("Map name too long: %s\n", findfn);
}
findfn = Sys_FindNext(NULL);
}
Sys_FindClose();
}
}
void COM_Log(char *pszFile, char *fmt, ...)
{
char *pfilename;
char string[1024];
if (!pszFile)
{
#ifdef REHLDS_FIXES
pfilename = "hllog.txt";
#else
// Why so serious?
pfilename = "c:\\hllog.txt";
#endif
}
else
{
pfilename = pszFile;
}
va_list argptr;
va_start(argptr, fmt);
Q_vsnprintf(string, ARRAYSIZE(string) - 1, fmt, argptr);
va_end(argptr);
string[ARRAYSIZE(string) - 1] = 0;
FileHandle_t fp = FS_Open(pfilename, "a+t");
if (fp)
{
FS_FPrintf(fp, "%s", string);
FS_Close(fp);
}
}
unsigned char* EXT_FUNC COM_LoadFileForMe(const char *filename, int *pLength)
{
return COM_LoadFile(filename, 5, pLength);
}
int EXT_FUNC COM_CompareFileTime(char *filename1, char *filename2, int *iCompare)
{
int ft1;
int ft2;
*iCompare = 0;
if (filename1 && filename2)
{
ft1 = FS_GetFileTime(filename1);
ft2 = FS_GetFileTime(filename2);
if (ft1 >= ft2)
{
if (ft1 > ft2)
{
*iCompare = 1;
}
return 1;
}
else
{
*iCompare = -1;
return 1;
}
}
return 0;
}
void EXT_FUNC COM_GetGameDir(char *szGameDir)
{
if (szGameDir)
{
Q_snprintf(szGameDir, MAX_PATH, "%s", com_gamedir);
}
}
int COM_EntsForPlayerSlots(int nPlayers)
{
int numedicts = gmodinfo.num_edicts;
int p = COM_CheckParm("-num_edicts");
if (p && p < com_argc - 1)
{
p = Q_atoi(com_argv[p + 1]);
if (numedicts < p)
{
numedicts = p;
}
}
return (numedicts + 15 * (nPlayers - 1));
}
void COM_NormalizeAngles(vec_t *angles)
{
int i;
for (i = 0; i < 3; i++)
{
if (angles[i] > 180.0)
{
angles[i] = (float)(fmod((double)angles[i], 360.0) - 360.0);
}
else if (angles[i] < -180.0)
{
angles[i] = (float)(fmod((double)angles[i], 360.0) + 360.0);
}
}
}
// Anti-proxy/aimbot obfuscation code
// COM_UnMunge should reversably fixup the data
void COM_Munge(unsigned char *data, int len, int seq)
{
int i;
int mungelen;
int c;
int *pc;
unsigned char *p;
int j;
mungelen = len & ~3;
mungelen /= 4;
for (i = 0; i < mungelen; i++)
{
pc = (int *)&data[i * 4];
c = *pc;
c ^= ~seq;
c = LongSwap(c);
p = (unsigned char *)&c;
for (j = 0; j < 4; j++)
{
*p++ ^= (0xa5 | (j << j) | j | mungify_table[(i + j) & 0x0f]);
}
c ^= seq;
*pc = c;
}
}
void COM_UnMunge(unsigned char *data, int len, int seq)
{
int i;
int mungelen;
int c;
int *pc;
unsigned char *p;
int j;
mungelen = len & ~3;
mungelen /= 4;
for (i = 0; i < mungelen; i++)
{
pc = (int *)&data[i * 4];
c = *pc;
c ^= seq;
p = (unsigned char *)&c;
for (j = 0; j < 4; j++)
{
*p++ ^= (0xa5 | (j << j) | j | mungify_table[(i + j) & 0x0f]);
}
c = LongSwap(c);
c ^= ~seq;
*pc = c;
}
}
#ifdef REHLDS_FIXES
// unrolled version
void COM_Munge2(unsigned char *data, int len, int seq)
{
unsigned int *pc;
unsigned int *end;
unsigned int mSeq;
mSeq = bswap(~seq) ^ seq;
len /= 4;
end = (unsigned int *)data + (len & ~15);
for (pc = (unsigned int *)data; pc < end; pc += 16)
{
pc[0] = bswap(pc[0]) ^ mSeq ^ 0xFFFFE7A5;
pc[1] = bswap(pc[1]) ^ mSeq ^ 0xBFEFFFE5;
pc[2] = bswap(pc[2]) ^ mSeq ^ 0xFFBFEFFF;
pc[3] = bswap(pc[3]) ^ mSeq ^ 0xBFEFBFED;
pc[4] = bswap(pc[4]) ^ mSeq ^ 0xBFAFEFBF;
pc[5] = bswap(pc[5]) ^ mSeq ^ 0xFFBFAFEF;
pc[6] = bswap(pc[6]) ^ mSeq ^ 0xFFEFBFAD;
pc[7] = bswap(pc[7]) ^ mSeq ^ 0xFFFFEFBF;
pc[8] = bswap(pc[8]) ^ mSeq ^ 0xFFEFF7EF;
pc[9] = bswap(pc[9]) ^ mSeq ^ 0xBFEFE7F5;
pc[10] = bswap(pc[10]) ^ mSeq ^ 0xBFBFE7E5;
pc[11] = bswap(pc[11]) ^ mSeq ^ 0xFFAFB7E7;
pc[12] = bswap(pc[12]) ^ mSeq ^ 0xBFFFAFB5;
pc[13] = bswap(pc[13]) ^ mSeq ^ 0xBFAFFFAF;
pc[14] = bswap(pc[14]) ^ mSeq ^ 0xFFAFA7FF;
pc[15] = bswap(pc[15]) ^ mSeq ^ 0xFFEFA7A5;
}
switch(len & 15)
{
case 15:
pc[14] = bswap(pc[14]) ^ mSeq ^ 0xFFAFA7FF;
case 14:
pc[13] = bswap(pc[13]) ^ mSeq ^ 0xBFAFFFAF;
case 13:
pc[12] = bswap(pc[12]) ^ mSeq ^ 0xBFFFAFB5;
case 12:
pc[11] = bswap(pc[11]) ^ mSeq ^ 0xFFAFB7E7;
case 11:
pc[10] = bswap(pc[10]) ^ mSeq ^ 0xBFBFE7E5;
case 10:
pc[9] = bswap(pc[9]) ^ mSeq ^ 0xBFEFE7F5;
case 9:
pc[8] = bswap(pc[8]) ^ mSeq ^ 0xFFEFF7EF;
case 8:
pc[7] = bswap(pc[7]) ^ mSeq ^ 0xFFFFEFBF;
case 7:
pc[6] = bswap(pc[6]) ^ mSeq ^ 0xFFEFBFAD;
case 6:
pc[5] = bswap(pc[5]) ^ mSeq ^ 0xFFBFAFEF;
case 5:
pc[4] = bswap(pc[4]) ^ mSeq ^ 0xBFAFEFBF;
case 4:
pc[3] = bswap(pc[3]) ^ mSeq ^ 0xBFEFBFED;
case 3:
pc[2] = bswap(pc[2]) ^ mSeq ^ 0xFFBFEFFF;
case 2:
pc[1] = bswap(pc[1]) ^ mSeq ^ 0xBFEFFFE5;
case 1:
pc[0] = bswap(pc[0]) ^ mSeq ^ 0xFFFFE7A5;
}
}
#else // REHLDS_FIXES
void COM_Munge2(unsigned char *data, int len, int seq)
{
int i;
int mungelen;
int c;
int *pc;
unsigned char *p;
int j;
mungelen = len & ~3;
mungelen /= 4;
for (i = 0; i < mungelen; i++)
{
pc = (int *)&data[i * 4];
c = *pc;
c ^= ~seq;
c = LongSwap(c);
p = (unsigned char *)&c;
for (j = 0; j < 4; j++)
{
*p++ ^= (0xa5 | (j << j) | j | mungify_table2[(i + j) & 0x0f]);
}
c ^= seq;
*pc = c;
}
}
#endif // REHLDS_FIXES
#ifdef REHLDS_FIXES
// unrolled version
void COM_UnMunge2(unsigned char *data, int len, int seq)
{
unsigned int *pc;
unsigned int *end;
unsigned int mSeq;
mSeq = bswap(~seq) ^ seq;
len /= 4;
end = (unsigned int *)data + (len & ~15);
for (pc = (unsigned int *)data; pc < end; pc += 16)
{
pc[0] = bswap(pc[0] ^ mSeq ^ 0xFFFFE7A5);
pc[1] = bswap(pc[1] ^ mSeq ^ 0xBFEFFFE5);
pc[2] = bswap(pc[2] ^ mSeq ^ 0xFFBFEFFF);
pc[3] = bswap(pc[3] ^ mSeq ^ 0xBFEFBFED);
pc[4] = bswap(pc[4] ^ mSeq ^ 0xBFAFEFBF);
pc[5] = bswap(pc[5] ^ mSeq ^ 0xFFBFAFEF);
pc[6] = bswap(pc[6] ^ mSeq ^ 0xFFEFBFAD);
pc[7] = bswap(pc[7] ^ mSeq ^ 0xFFFFEFBF);
pc[8] = bswap(pc[8] ^ mSeq ^ 0xFFEFF7EF);
pc[9] = bswap(pc[9] ^ mSeq ^ 0xBFEFE7F5);
pc[10] = bswap(pc[10] ^ mSeq ^ 0xBFBFE7E5);
pc[11] = bswap(pc[11] ^ mSeq ^ 0xFFAFB7E7);
pc[12] = bswap(pc[12] ^ mSeq ^ 0xBFFFAFB5);
pc[13] = bswap(pc[13] ^ mSeq ^ 0xBFAFFFAF);
pc[14] = bswap(pc[14] ^ mSeq ^ 0xFFAFA7FF);
pc[15] = bswap(pc[15] ^ mSeq ^ 0xFFEFA7A5);
}
switch(len & 15)
{
case 15:
pc[14] = bswap(pc[14] ^ mSeq ^ 0xFFAFA7FF);
case 14:
pc[13] = bswap(pc[13] ^ mSeq ^ 0xBFAFFFAF);
case 13:
pc[12] = bswap(pc[12] ^ mSeq ^ 0xBFFFAFB5);
case 12:
pc[11] = bswap(pc[11] ^ mSeq ^ 0xFFAFB7E7);
case 11:
pc[10] = bswap(pc[10] ^ mSeq ^ 0xBFBFE7E5);
case 10:
pc[9] = bswap(pc[9] ^ mSeq ^ 0xBFEFE7F5);
case 9:
pc[8] = bswap(pc[8] ^ mSeq ^ 0xFFEFF7EF);
case 8:
pc[7] = bswap(pc[7] ^ mSeq ^ 0xFFFFEFBF);
case 7:
pc[6] = bswap(pc[6] ^ mSeq ^ 0xFFEFBFAD);
case 6:
pc[5] = bswap(pc[5] ^ mSeq ^ 0xFFBFAFEF);
case 5:
pc[4] = bswap(pc[4] ^ mSeq ^ 0xBFAFEFBF);
case 4:
pc[3] = bswap(pc[3] ^ mSeq ^ 0xBFEFBFED);
case 3:
pc[2] = bswap(pc[2] ^ mSeq ^ 0xFFBFEFFF);
case 2:
pc[1] = bswap(pc[1] ^ mSeq ^ 0xBFEFFFE5);
case 1:
pc[0] = bswap(pc[0] ^ mSeq ^ 0xFFFFE7A5);
}
}
#else // REHLDS_FIXES
void COM_UnMunge2(unsigned char *data, int len, int seq)
{
int i;
int mungelen;
int c;
int *pc;
unsigned char *p;
int j;
mungelen = len & ~3;
mungelen /= 4;
for (i = 0; i < mungelen; i++)
{
pc = (int *)&data[i * 4];
c = *pc;
c ^= seq;
p = (unsigned char *)&c;
for (j = 0; j < 4; j++)
{
*p++ ^= (0xa5 | (j << j) | j | mungify_table2[(i + j) & 0x0f]);
}
c = LongSwap(c);
c ^= ~seq;
*pc = c;
}
}
#endif // REHLDS_FIXES
void COM_Munge3(unsigned char *data, int len, int seq)
{
int i;
int mungelen;
int c;
int *pc;
unsigned char *p;
int j;
mungelen = len & ~3;
mungelen /= 4;
for (i = 0; i < mungelen; i++)
{
pc = (int *)&data[i * 4];
c = *pc;
c ^= ~seq;
c = LongSwap(c);
p = (unsigned char *)&c;
for (j = 0; j < 4; j++)
{
*p++ ^= (0xa5 | (j << j) | j | mungify_table3[(i + j) & 0x0f]);
}
c ^= seq;
*pc = c;
}
}
NOXREF void COM_UnMunge3(unsigned char *data, int len, int seq)
{
NOXREFCHECK;
int i;
int mungelen;
int c;
int *pc;
unsigned char *p;
int j;
mungelen = len & ~3;
mungelen /= 4;
for (i = 0; i < mungelen; i++)
{
pc = (int *)&data[i * 4];
c = *pc;
c ^= seq;
p = (unsigned char *)&c;
for (j = 0; j < 4; j++)
{
*p++ ^= (0xa5 | (j << j) | j | mungify_table3[(i + j) & 0x0f]);
}
c = LongSwap(c);
c ^= ~seq;
*pc = c;
}
}
typedef struct
{
unsigned char chunkID[4];
long chunkSize;
short wFormatTag;
unsigned short wChannels;
unsigned long dwSamplesPerSec;
unsigned long dwAvgBytesPerSec;
unsigned short wBlockAlign;
unsigned short wBitsPerSample;
} FormatChunk;
const int WAVE_HEADER_LENGTH = 128;
unsigned int EXT_FUNC COM_GetApproxWavePlayLength(const char *filepath)
{
char buf[WAVE_HEADER_LENGTH + 1];
int filelength;
FileHandle_t hFile;
FormatChunk format;
hFile = FS_Open(filepath, "rb");
if (hFile)
{
filelength = FS_Size(hFile);
if (filelength <= WAVE_HEADER_LENGTH)
return 0;
FS_Read(buf, WAVE_HEADER_LENGTH, 1, hFile);
FS_Close(hFile);
buf[WAVE_HEADER_LENGTH] = 0;
if (!Q_strnicmp(buf, "RIFF", 4) && !Q_strnicmp(&buf[8], "WAVE", 4) && !Q_strnicmp(&buf[12], "fmt ", 4))
{
Q_memcpy(&format, &buf[12], sizeof(FormatChunk));
filelength -= WAVE_HEADER_LENGTH;
if (format.dwAvgBytesPerSec > 999)
{
return filelength / (format.dwAvgBytesPerSec / 1000);
}
return 1000 * filelength / format.dwAvgBytesPerSec;
}
}
return 0;
}
#endif // COM_Functions_region