ReGameDLL_CS/regamedll/dlls/saverestore.cpp
2023-12-14 03:16:27 +07:00

1108 lines
27 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"
TYPEDESCRIPTION g_EntvarsDescription[] =
{
DEFINE_ENTITY_FIELD(classname, FIELD_STRING),
DEFINE_ENTITY_GLOBAL_FIELD(globalname, FIELD_STRING),
DEFINE_ENTITY_FIELD(origin, FIELD_POSITION_VECTOR),
DEFINE_ENTITY_FIELD(oldorigin, FIELD_POSITION_VECTOR),
DEFINE_ENTITY_FIELD(velocity, FIELD_VECTOR),
DEFINE_ENTITY_FIELD(basevelocity, FIELD_VECTOR),
DEFINE_ENTITY_FIELD(movedir, FIELD_VECTOR),
DEFINE_ENTITY_FIELD(angles, FIELD_VECTOR),
DEFINE_ENTITY_FIELD(avelocity, FIELD_VECTOR),
DEFINE_ENTITY_FIELD(punchangle, FIELD_VECTOR),
DEFINE_ENTITY_FIELD(v_angle, FIELD_VECTOR),
DEFINE_ENTITY_FIELD(fixangle, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(idealpitch, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(pitch_speed, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(ideal_yaw, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(yaw_speed, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(modelindex, FIELD_INTEGER),
DEFINE_ENTITY_GLOBAL_FIELD(model, FIELD_MODELNAME),
DEFINE_ENTITY_FIELD(viewmodel, FIELD_MODELNAME),
DEFINE_ENTITY_FIELD(weaponmodel, FIELD_MODELNAME),
DEFINE_ENTITY_FIELD(absmin, FIELD_POSITION_VECTOR),
DEFINE_ENTITY_FIELD(absmax, FIELD_POSITION_VECTOR),
DEFINE_ENTITY_GLOBAL_FIELD(mins, FIELD_VECTOR),
DEFINE_ENTITY_GLOBAL_FIELD(maxs, FIELD_VECTOR),
DEFINE_ENTITY_GLOBAL_FIELD(size, FIELD_VECTOR),
DEFINE_ENTITY_FIELD(ltime, FIELD_TIME),
DEFINE_ENTITY_FIELD(nextthink, FIELD_TIME),
DEFINE_ENTITY_FIELD(solid, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(movetype, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(skin, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(body, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(effects, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(gravity, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(friction, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(light_level, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(frame, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(scale, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(sequence, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(animtime, FIELD_TIME),
DEFINE_ENTITY_FIELD(framerate, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(controller, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(blending, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(rendermode, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(renderamt, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(rendercolor, FIELD_VECTOR),
DEFINE_ENTITY_FIELD(renderfx, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(health, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(frags, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(weapons, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(takedamage, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(deadflag, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(view_ofs, FIELD_VECTOR),
DEFINE_ENTITY_FIELD(button, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(impulse, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(chain, FIELD_EDICT),
DEFINE_ENTITY_FIELD(dmg_inflictor, FIELD_EDICT),
DEFINE_ENTITY_FIELD(enemy, FIELD_EDICT),
DEFINE_ENTITY_FIELD(aiment, FIELD_EDICT),
DEFINE_ENTITY_FIELD(owner, FIELD_EDICT),
DEFINE_ENTITY_FIELD(groundentity, FIELD_EDICT),
DEFINE_ENTITY_FIELD(spawnflags, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(flags, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(colormap, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(team, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(max_health, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(teleport_time, FIELD_TIME),
DEFINE_ENTITY_FIELD(armortype, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(armorvalue, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(waterlevel, FIELD_INTEGER),
DEFINE_ENTITY_FIELD(watertype, FIELD_INTEGER),
DEFINE_ENTITY_GLOBAL_FIELD(target, FIELD_STRING),
DEFINE_ENTITY_GLOBAL_FIELD(targetname, FIELD_STRING),
DEFINE_ENTITY_FIELD(netname, FIELD_STRING),
DEFINE_ENTITY_FIELD(message, FIELD_STRING),
DEFINE_ENTITY_FIELD(dmg_take, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(dmg_save, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(dmg, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(dmgtime, FIELD_TIME),
DEFINE_ENTITY_FIELD(noise, FIELD_SOUNDNAME),
DEFINE_ENTITY_FIELD(noise1, FIELD_SOUNDNAME),
DEFINE_ENTITY_FIELD(noise2, FIELD_SOUNDNAME),
DEFINE_ENTITY_FIELD(noise3, FIELD_SOUNDNAME),
DEFINE_ENTITY_FIELD(speed, FIELD_FLOAT),
DEFINE_ENTITY_FIELD(air_finished, FIELD_TIME),
DEFINE_ENTITY_FIELD(pain_finished, FIELD_TIME),
DEFINE_ENTITY_FIELD(radsuit_finished, FIELD_TIME),
};
void EntvarsKeyvalue(entvars_t *pev, KeyValueData *pkvd)
{
for (int i = 0; i < ARRAYSIZE(g_EntvarsDescription); i++)
{
TYPEDESCRIPTION *pField = &g_EntvarsDescription[i];
if (!Q_stricmp(pField->fieldName, pkvd->szKeyName))
{
switch (pField->fieldType)
{
case FIELD_STRING:
case FIELD_MODELNAME:
case FIELD_SOUNDNAME:
*(string_t *)((char *)pev + pField->fieldOffset) = ALLOC_STRING(pkvd->szValue);
break;
case FIELD_FLOAT:
case FIELD_TIME:
*(float *)((char *)pev + pField->fieldOffset) = Q_atof(pkvd->szValue);
break;
case FIELD_INTEGER:
*(string_t *)((char *)pev + pField->fieldOffset) = Q_atoi(pkvd->szValue);
break;
case FIELD_VECTOR:
case FIELD_POSITION_VECTOR:
UTIL_StringToVector((float *)((char *)pev + pField->fieldOffset), pkvd->szValue);
break;
default:
case FIELD_EVARS:
case FIELD_CLASSPTR:
case FIELD_EDICT:
case FIELD_ENTITY:
case FIELD_POINTER:
ALERT(at_error, "Bad field in entity!!\n");
break;
}
pkvd->fHandled = TRUE;
break;
}
}
}
const int CSaveRestoreBuffer::m_Sizes[] =
{
sizeof(float), // FIELD_FLOAT
sizeof(int), // FIELD_STRING
sizeof(int), // FIELD_ENTITY
sizeof(int), // FIELD_CLASSPTR
sizeof(int), // FIELD_EHANDLE
sizeof(int), // FIELD_entvars_t
sizeof(int), // FIELD_EDICT
sizeof(float) * 3, // FIELD_VECTOR
sizeof(float) * 3, // FIELD_POSITION_VECTOR
sizeof(int *), // FIELD_POINTER
sizeof(int), // FIELD_INTEGER
sizeof(int *), // FIELD_FUNCTION
sizeof(int), // FIELD_BOOLEAN
sizeof(short), // FIELD_SHORT
sizeof(char), // FIELD_CHARACTER
sizeof(float), // FIELD_TIME
sizeof(int), // FIELD_MODELNAME
sizeof(int), // FIELD_SOUNDNAME
};
CSaveRestoreBuffer::CSaveRestoreBuffer()
{
m_pData = nullptr;
}
CSaveRestoreBuffer::CSaveRestoreBuffer(SAVERESTOREDATA *pdata)
{
m_pData = pdata;
}
CSaveRestoreBuffer::~CSaveRestoreBuffer()
{
;
}
int CSaveRestoreBuffer::EntityIndex(CBaseEntity *pEntity)
{
if (!pEntity)
return -1;
return EntityIndex(pEntity->pev);
}
int CSaveRestoreBuffer::EntityIndex(entvars_t *pevLookup)
{
if (!pevLookup)
return -1;
return EntityIndex(ENT(pevLookup));
}
int CSaveRestoreBuffer::EntityIndex(EOFFSET eoLookup)
{
return EntityIndex(ENT(eoLookup));
}
int CSaveRestoreBuffer::EntityIndex(edict_t *pentLookup)
{
if (!m_pData || !pentLookup)
return -1;
for (int i = 0; i < m_pData->tableCount; i++)
{
ENTITYTABLE *pTable = &m_pData->pTable[i];
if (pTable->pent == pentLookup)
return i;
}
return -1;
}
edict_t *CSaveRestoreBuffer::EntityFromIndex(int entityIndex)
{
if (!m_pData || entityIndex < 0)
return nullptr;
for (int i = 0; i < m_pData->tableCount; i++)
{
ENTITYTABLE *pTable = &m_pData->pTable[i];
if (pTable->id == entityIndex)
return pTable->pent;
}
return nullptr;
}
int CSaveRestoreBuffer::EntityFlagsSet(int entityIndex, int flags)
{
if (!m_pData || entityIndex < 0)
return 0;
if (!m_pData || entityIndex < 0 || entityIndex > m_pData->tableCount)
return 0;
m_pData->pTable[entityIndex].flags |= flags;
return m_pData->pTable[entityIndex].flags;
}
int CSaveRestoreBuffer::EntityFlags(int entityIndex, int flags)
{
return EntityFlagsSet(entityIndex, flags);
}
void CSaveRestoreBuffer::BufferRewind(int size)
{
if (!m_pData)
return;
if (m_pData->size < size)
size = m_pData->size;
m_pData->pCurrentData -= size;
m_pData->size -= size;
}
#ifndef _WIN32
extern "C"
{
inline unsigned _rotr(unsigned val, int shift)
{
unsigned lobit;
unsigned num = val;
shift &= 0x1f;
while (shift--)
{
lobit = num & 1;
num >>= 1;
if (lobit)
num |= 0x80000000;
}
return num;
}
}
#endif // _WIN32
unsigned int CSaveRestoreBuffer::HashString(const char *pszToken)
{
unsigned int hash = 0;
while (*pszToken)
hash = _rotr(hash, 4) ^ *pszToken++;
return hash;
}
unsigned short CSaveRestoreBuffer::TokenHash(const char *pszToken)
{
unsigned short hash = (unsigned short)(HashString(pszToken) % (unsigned)m_pData->tokenCount);
for (int i = 0; i < m_pData->tokenCount; i++)
{
int index = hash + i;
if (index >= m_pData->tokenCount)
index -= m_pData->tokenCount;
if (!m_pData->pTokens[index] || !Q_strcmp(pszToken, m_pData->pTokens[index]))
{
m_pData->pTokens[index] = (char *)pszToken;
return index;
}
}
ALERT(at_error, "CSaveRestoreBuffer :: TokenHash() is COMPLETELY FULL!");
return 0;
}
void CSave::WriteData(const char *pname, int size, const char *pdata)
{
BufferField(pname, size, pdata);
}
NOXREF void CSave::WriteShort(const char *pname, const short *data, int count)
{
BufferField(pname, sizeof(short) * count, (const char *)data);
}
void CSave::WriteInt(const char *pname, const int *data, int count)
{
BufferField(pname, sizeof(int) * count, (const char *)data);
}
void CSave::WriteFloat(const char *pname, const float *data, int count)
{
BufferField(pname, sizeof(float) * count, (const char *)data);
}
void CSave::WriteTime(const char *pname, const float *data, int count)
{
BufferHeader(pname, sizeof(float) * count);
for (int i = 0; i < count; i++)
{
float tmp = data[0];
if (m_pData) {
tmp -= m_pData->time;
}
BufferData((const char *)&tmp, sizeof(float));
data++;
}
}
NOXREF void CSave::WriteString(const char *pname, const char *pdata)
{
BufferField(pname, Q_strlen(pdata) + 1, pdata);
}
void CSave::WriteString(const char *pname, const int *stringId, int count)
{
int i;
int size = 0;
for (i = 0; i < count; i++) {
size += Q_strlen(STRING(stringId[i])) + 1;
}
BufferHeader(pname, size);
for (i = 0; i < count; i++)
{
const char *pString = STRING(stringId[i]);
BufferData(pString, Q_strlen(pString) + 1);
}
}
void CSave::WriteVector(const char *pname, const Vector &value)
{
WriteVector(pname, &value.x, 1);
}
void CSave::WriteVector(const char *pname, const float *value, int count)
{
BufferHeader(pname, sizeof(float) * 3 * count);
BufferData((const char *)value, sizeof(float) * 3 * count);
}
NOXREF void CSave::WritePositionVector(const char *pname, const Vector &value)
{
if (m_pData && m_pData->fUseLandmark)
{
Vector tmp = value - m_pData->vecLandmarkOffset;
WriteVector(pname, tmp);
}
WriteVector(pname, value);
}
void CSave::WritePositionVector(const char *pname, const float *value, int count)
{
BufferHeader(pname, sizeof(float) * 3 * count);
for (int i = 0; i < count; i++)
{
Vector tmp(value[0], value[1], value[2]);
if (m_pData && m_pData->fUseLandmark) {
tmp -= m_pData->vecLandmarkOffset;
}
BufferData((const char *)&tmp.x, sizeof(float) * 3);
value += 3;
}
}
void CSave::WriteFunction(const char *pname, void **data, int count)
{
const char *functionName = NAME_FOR_FUNCTION((uint32)*data);
if (functionName)
BufferField(pname, Q_strlen(functionName) + 1, functionName);
else
ALERT(at_error, "Invalid function pointer in entity!");
}
int CSave::WriteEntVars(const char *pname, entvars_t *pev)
{
return WriteFields(pname, pev, g_EntvarsDescription, ARRAYSIZE(g_EntvarsDescription));
}
int CSave::WriteFields(const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount)
{
int i;
int emptyCount = 0;
for (i = 0; i < fieldCount; i++)
{
void *pOutputData = ((char *)pBaseData + pFields[i].fieldOffset);
if (DataEmpty((const char *)pOutputData, pFields[i].fieldSize * m_Sizes[pFields[i].fieldType]))
emptyCount++;
}
int entityArray[MAX_ENTITY_ARRAY];
int actualCount = fieldCount - emptyCount;
WriteInt(pname, &actualCount, 1);
for (i = 0; i < fieldCount; i++)
{
TYPEDESCRIPTION *pTest = &pFields[i];
void *pOutputData = ((char *)pBaseData + pTest->fieldOffset);
if (DataEmpty((const char *)pOutputData, pTest->fieldSize * m_Sizes[pTest->fieldType]))
continue;
switch (pTest->fieldType)
{
case FIELD_FLOAT:
WriteFloat(pTest->fieldName, (float *)pOutputData, pTest->fieldSize);
break;
case FIELD_TIME:
WriteTime(pTest->fieldName, (float *)pOutputData, pTest->fieldSize);
break;
case FIELD_MODELNAME:
case FIELD_SOUNDNAME:
case FIELD_STRING:
WriteString(pTest->fieldName, (int *)pOutputData, pTest->fieldSize);
break;
case FIELD_CLASSPTR:
case FIELD_EVARS:
case FIELD_EDICT:
case FIELD_ENTITY:
case FIELD_EHANDLE:
{
if (pTest->fieldSize > MAX_ENTITY_ARRAY)
ALERT(at_error, "Can't save more than %d entities in an array!!!\n", MAX_ENTITY_ARRAY);
for (int j = 0; j < pTest->fieldSize; j++)
{
switch (pTest->fieldType)
{
case FIELD_EVARS:
entityArray[j] = EntityIndex(((entvars_t **)pOutputData)[j]);
break;
case FIELD_CLASSPTR:
entityArray[j] = EntityIndex(((CBaseEntity **)pOutputData)[j]);
break;
case FIELD_EDICT:
entityArray[j] = EntityIndex(((edict_t **)pOutputData)[j]);
break;
case FIELD_ENTITY:
entityArray[j] = EntityIndex(((EOFFSET *)pOutputData)[j]);
break;
case FIELD_EHANDLE:
entityArray[j] = EntityIndex((CBaseEntity *)(((EHANDLE *)pOutputData)[j]));
break;
default:
break;
}
}
WriteInt(pTest->fieldName, entityArray, pTest->fieldSize);
break;
}
case FIELD_POSITION_VECTOR:
WritePositionVector(pTest->fieldName, (float *)pOutputData, pTest->fieldSize);
break;
case FIELD_VECTOR:
WriteVector(pTest->fieldName, (float *)pOutputData, pTest->fieldSize);
break;
case FIELD_BOOLEAN:
case FIELD_INTEGER:
WriteInt(pTest->fieldName, (int *)pOutputData, pTest->fieldSize);
break;
case FIELD_SHORT:
WriteData(pTest->fieldName, 2 * pTest->fieldSize, ((char *)pOutputData));
break;
case FIELD_CHARACTER:
WriteData(pTest->fieldName, pTest->fieldSize, ((char *)pOutputData));
break;
case FIELD_POINTER:
WriteInt(pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize);
break;
case FIELD_FUNCTION:
WriteFunction(pTest->fieldName, &pOutputData, pTest->fieldSize);
break;
default:
ALERT(at_error, "Bad field type\n");
break;
}
}
return 1;
}
NOXREF void CSave::BufferString(char *pdata, int len)
{
char c = 0;
BufferData(pdata, len);
BufferData(&c, 1);
}
int CSave::DataEmpty(const char *pdata, int size)
{
for (int i = 0; i < size; i++)
{
if (pdata[i])
return 0;
}
return 1;
}
void CSave::BufferField(const char *pname, int size, const char *pdata)
{
BufferHeader(pname, size);
BufferData(pdata, size);
}
void CSave::BufferHeader(const char *pname, int size)
{
short hashvalue = TokenHash(pname);
if (size > (1 << (sizeof(short) * 8)))
ALERT(at_error, "CSave :: BufferHeader() size parameter exceeds 'short'!");
BufferData((const char *)&size, sizeof(short));
BufferData((const char *)&hashvalue, sizeof(short));
}
void CSave::BufferData(const char *pdata, int size)
{
if (!m_pData)
return;
if (m_pData->size + size > m_pData->bufferSize)
{
ALERT(at_error, "Save/Restore overflow!");
m_pData->size = m_pData->bufferSize;
return;
}
Q_memcpy(m_pData->pCurrentData, pdata, size);
m_pData->pCurrentData += size;
m_pData->size += size;
}
int CRestore::ReadField(void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData)
{
float time = 0.0f;
Vector position(0, 0, 0);
if (m_pData)
{
time = m_pData->time;
if (m_pData->fUseLandmark) {
position = m_pData->vecLandmarkOffset;
}
}
for (int i = 0; i < fieldCount; i++)
{
int fieldNumber = (i + startField) % fieldCount;
TYPEDESCRIPTION *pTest = &pFields[fieldNumber];
if (!Q_stricmp(pTest->fieldName, pName))
{
if (!m_global || !(pTest->flags & FTYPEDESC_GLOBAL))
{
for (int j = 0; j < pTest->fieldSize; j++)
{
void *pOutputData = ((char *)pBaseData + pTest->fieldOffset + (j * m_Sizes[pTest->fieldType]));
void *pInputData = (char *)pData + j * m_Sizes[pTest->fieldType];
switch (pTest->fieldType)
{
case FIELD_TIME:
{
float timeData = *(float *)pInputData;
timeData += time;
*((float *)pOutputData) = timeData;
break;
}
case FIELD_FLOAT: *((float *)pOutputData) = *(float *)pInputData; break;
case FIELD_MODELNAME:
case FIELD_SOUNDNAME:
case FIELD_STRING:
{
char *pString = (char *)pData;
for (int stringCount = 0; stringCount < j; stringCount++)
{
while (*pString)
pString++;
pString++;
}
pInputData = pString;
if (!Q_strlen((char *)pInputData))
*((int *)pOutputData) = 0;
else
{
int string = ALLOC_STRING((char *)pInputData);
*((int *)pOutputData) = string;
if (!FStringNull(string) && m_precache)
{
if (pTest->fieldType == FIELD_MODELNAME)
PRECACHE_MODEL((char *)STRING(string));
else if (pTest->fieldType == FIELD_SOUNDNAME)
PRECACHE_SOUND((char *)STRING(string));
}
}
break;
}
case FIELD_EVARS:
{
int entityIndex = *(int *)pInputData;
edict_t *pent = EntityFromIndex(entityIndex);
if (pent)
*((entvars_t **)pOutputData) = VARS(pent);
else
*((entvars_t **)pOutputData) = nullptr;
break;
}
case FIELD_CLASSPTR:
{
int entityIndex = *(int *)pInputData;
edict_t *pent = EntityFromIndex(entityIndex);
if (pent)
*((CBaseEntity **)pOutputData) = CBaseEntity::Instance(pent);
else
*((CBaseEntity **)pOutputData) = nullptr;
break;
}
case FIELD_EDICT:
{
int entityIndex = *(int *)pInputData;
edict_t *pent = EntityFromIndex(entityIndex);
*((edict_t **)pOutputData) = pent;
break;
}
case FIELD_EHANDLE:
{
pOutputData = (char *)pOutputData + j * (sizeof(EHANDLE) - m_Sizes[pTest->fieldType]);
int entityIndex = *(int *)pInputData;
edict_t *pent = EntityFromIndex(entityIndex);
if (pent)
*((EHANDLE *)pOutputData) = CBaseEntity::Instance(pent);
else
*((EHANDLE *)pOutputData) = nullptr;
break;
}
case FIELD_ENTITY:
{
int entityIndex = *(int *)pInputData;
edict_t *pent = EntityFromIndex(entityIndex);
if (pent)
*((EOFFSET *)pOutputData) = OFFSET(pent);
else
*((EOFFSET *)pOutputData) = 0;
break;
}
case FIELD_VECTOR:
{
((float *)pOutputData)[0] = ((float *)pInputData)[0];
((float *)pOutputData)[1] = ((float *)pInputData)[1];
((float *)pOutputData)[2] = ((float *)pInputData)[2];
break;
}
case FIELD_POSITION_VECTOR:
{
((float *)pOutputData)[0] = ((float *)pInputData)[0] + position.x;
((float *)pOutputData)[1] = ((float *)pInputData)[1] + position.y;
((float *)pOutputData)[2] = ((float *)pInputData)[2] + position.z;
break;
}
case FIELD_BOOLEAN:
case FIELD_INTEGER:
*((int *)pOutputData) = *(int *)pInputData;
break;
case FIELD_SHORT:
*((short *)pOutputData) = *(short *)pInputData;
break;
case FIELD_CHARACTER:
*((char *)pOutputData) = *(char *)pInputData;
break;
case FIELD_POINTER:
*((int *)pOutputData) = *(int *)pInputData;
break;
case FIELD_FUNCTION:
{
if (!Q_strlen((char *)pInputData))
*((int *)pOutputData) = 0;
else
*((int *)pOutputData) = FUNCTION_FROM_NAME((char *)pInputData);
break;
}
default:
ALERT(at_error, "Bad field type\n");
break;
}
}
}
return fieldNumber;
}
}
return -1;
}
int CRestore::ReadEntVars(const char *pname, entvars_t *pev)
{
return ReadFields(pname, pev, g_EntvarsDescription, ARRAYSIZE(g_EntvarsDescription));
}
int CRestore::ReadFields(const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount)
{
unsigned short i = ReadShort();
unsigned short token = ReadShort();
if (token != TokenHash(pname))
{
BufferRewind(2 * sizeof(short));
return 0;
}
int fileCount = ReadInt();
int lastField = 0;
for (i = 0; i < fieldCount; i++)
{
if (!m_global || !(pFields[i].flags & FTYPEDESC_GLOBAL))
Q_memset(((char *)pBaseData + pFields[i].fieldOffset), 0, pFields[i].fieldSize * m_Sizes[pFields[i].fieldType]);
}
for (i = 0; i < fileCount; i++)
{
HEADER header;
BufferReadHeader(&header);
lastField = ReadField(pBaseData, pFields, fieldCount, lastField, header.size, m_pData->pTokens[header.token], header.pData);
lastField++;
}
return 1;
}
void CRestore::BufferReadHeader(HEADER *pheader)
{
pheader->size = ReadShort();
pheader->token = ReadShort();
pheader->pData = BufferPointer();
BufferSkipBytes(pheader->size);
}
short CRestore::ReadShort()
{
short tmp = 0;
BufferReadBytes((char *)&tmp, sizeof(short));
return tmp;
}
int CRestore::ReadInt()
{
int tmp = 0;
BufferReadBytes((char *)&tmp, sizeof(int));
return tmp;
}
NOXREF int CRestore::ReadNamedInt(const char *pName)
{
HEADER header;
BufferReadHeader(&header);
return ((int *)header.pData)[0];
}
NOXREF char *CRestore::ReadNamedString(const char *pName)
{
HEADER header;
BufferReadHeader(&header);
return (char *)header.pData;
}
char *CRestore::BufferPointer()
{
if (!m_pData)
return nullptr;
return m_pData->pCurrentData;
}
void CRestore::BufferReadBytes(char *pOutput, int size)
{
if (!m_pData || Empty())
return;
if ((m_pData->size + size) > m_pData->bufferSize)
{
ALERT(at_error, "Restore overflow!");
m_pData->size = m_pData->bufferSize;
return;
}
if (pOutput)
Q_memcpy(pOutput, m_pData->pCurrentData, size);
m_pData->pCurrentData += size;
m_pData->size += size;
}
void CRestore::BufferSkipBytes(int bytes)
{
BufferReadBytes(nullptr, bytes);
}
NOXREF int CRestore::BufferSkipZString()
{
if (!m_pData)
return 0;
int maxLen = m_pData->bufferSize - m_pData->size;
int len = 0;
char *pszSearch = m_pData->pCurrentData;
while (*pszSearch++ && len < maxLen)
len++;
len++;
BufferSkipBytes(len);
return len;
}
NOXREF int CRestore::BufferCheckZString(const char *string)
{
if (!m_pData)
return 0;
int maxLen = m_pData->bufferSize - m_pData->size;
int len = Q_strlen(string);
if (len <= maxLen)
{
if (!Q_strncmp(string, m_pData->pCurrentData, len))
return 1;
}
return 0;
}
CGlobalState::CGlobalState()
{
Reset();
}
void CGlobalState::Reset()
{
m_pList = nullptr;
m_listCount = 0;
}
globalentity_t *CGlobalState::Find(string_t globalname)
{
if (!globalname)
return nullptr;
globalentity_t *pTest = m_pList;
const char *pEntityName = STRING(globalname);
while (pTest)
{
if (!Q_strcmp(pEntityName, pTest->name))
break;
pTest = pTest->pNext;
}
return pTest;
}
// This is available all the time now on impulse 104, remove later
void CGlobalState::DumpGlobals()
{
static char *estates[] = { "Off", "On", "Dead" };
globalentity_t *pTest;
ALERT(at_console, "-- Globals --\n");
pTest = m_pList;
while (pTest)
{
ALERT(at_console, "%s: %s (%s)\n", pTest->name, pTest->levelName, estates[pTest->state]);
pTest = pTest->pNext;
}
}
void CGlobalState::EntityAdd(string_t globalname, string_t mapName, GLOBALESTATE state)
{
DbgAssert(!Find(globalname));
globalentity_t *pNewEntity = (globalentity_t *)calloc(sizeof(globalentity_t), 1);
DbgAssert(pNewEntity != nullptr);
pNewEntity->pNext = m_pList;
m_pList = pNewEntity;
Q_strcpy(pNewEntity->name, STRING(globalname));
Q_strcpy(pNewEntity->levelName, STRING(mapName));
pNewEntity->state = state;
m_listCount++;
}
void CGlobalState::EntitySetState(string_t globalname, GLOBALESTATE state)
{
globalentity_t *pEnt = Find(globalname);
if (pEnt)
{
pEnt->state = state;
}
}
const globalentity_t *CGlobalState::EntityFromTable(string_t globalname)
{
globalentity_t *pEnt = Find(globalname);
return pEnt;
}
GLOBALESTATE CGlobalState::EntityGetState(string_t globalname)
{
globalentity_t *pEnt = Find(globalname);
if (pEnt)
{
return pEnt->state;
}
return GLOBAL_OFF;
}
TYPEDESCRIPTION CGlobalState::m_SaveData[] =
{
DEFINE_FIELD(CGlobalState, m_listCount, FIELD_INTEGER)
};
TYPEDESCRIPTION CGlobalState::m_GlobalEntitySaveData[] =
{
DEFINE_ARRAY(globalentity_t, name, FIELD_CHARACTER, 64),
DEFINE_ARRAY(globalentity_t, levelName, FIELD_CHARACTER, MAX_MAPNAME_LENGHT),
DEFINE_FIELD(globalentity_t, state, FIELD_INTEGER)
};
int CGlobalState::Save(CSave &save)
{
int i;
globalentity_t *pEntity;
if (!save.WriteFields("GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData)))
{
return 0;
}
pEntity = m_pList;
for (i = 0; i < m_listCount && pEntity; i++)
{
if (!save.WriteFields("GENT", pEntity, m_GlobalEntitySaveData, ARRAYSIZE(m_GlobalEntitySaveData)))
{
return 0;
}
pEntity = pEntity->pNext;
}
return 1;
}
int CGlobalState::Restore(CRestore &restore)
{
int i, listCount;
globalentity_t tmpEntity;
ClearStates();
if (!restore.ReadFields("GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData)))
{
return 0;
}
// Get new list count
listCount = m_listCount;
// Clear loaded data
m_listCount = 0;
for (i = 0; i < listCount; i++)
{
if (!restore.ReadFields("GENT", &tmpEntity, m_GlobalEntitySaveData, ARRAYSIZE(m_GlobalEntitySaveData)))
{
return 0;
}
EntityAdd(MAKE_STRING(tmpEntity.name), MAKE_STRING(tmpEntity.levelName), tmpEntity.state);
}
return 1;
}
void CGlobalState::EntityUpdate(string_t globalname, string_t mapname)
{
globalentity_t *pEnt = Find(globalname);
if (pEnt)
{
Q_strcpy(pEnt->levelName, STRING(mapname));
}
}
void CGlobalState::ClearStates()
{
globalentity_t *pFree = m_pList;
while (pFree)
{
globalentity_t *pNext = pFree->pNext;
free(pFree);
pFree = pNext;
}
Reset();
}
void EXT_FUNC SaveGlobalState(SAVERESTOREDATA *pSaveData)
{
CSave saveHelper(pSaveData);
gGlobalState.Save(saveHelper);
}
void EXT_FUNC RestoreGlobalState(SAVERESTOREDATA *pSaveData)
{
CRestore restoreHelper(pSaveData);
gGlobalState.Restore(restoreHelper);
}
void EXT_FUNC ResetGlobalState()
{
gGlobalState.ClearStates();
// Init the HUD on a new game / load game
gInitHUD = TRUE;
}