From ea2c71242e2a60c7d367fda8d1b51ee3eaeee569 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sun, 27 Aug 2023 00:20:23 +0200 Subject: [PATCH] Map out entity structures more More types and improvements for base entity classes. --- r5dev/game/CMakeLists.txt | 6 + r5dev/game/server/baseanimatingoverlay.h | 2 +- r5dev/game/server/baseentity.h | 41 ++- r5dev/game/server/cbase.cpp | 6 + r5dev/game/server/cbase.h | 5 + r5dev/game/server/entityoutput.cpp | 6 + r5dev/game/server/entityoutput.h | 70 +++++ r5dev/game/server/variant_t.cpp | 332 +++++++++++++++++++++++ r5dev/game/server/variant_t.h | 127 +++++++++ r5dev/game/shared/shareddefs.h | 7 + 10 files changed, 590 insertions(+), 12 deletions(-) create mode 100644 r5dev/game/server/cbase.cpp create mode 100644 r5dev/game/server/cbase.h create mode 100644 r5dev/game/server/entityoutput.cpp create mode 100644 r5dev/game/server/entityoutput.h create mode 100644 r5dev/game/server/variant_t.cpp create mode 100644 r5dev/game/server/variant_t.h diff --git a/r5dev/game/CMakeLists.txt b/r5dev/game/CMakeLists.txt index 6984ca98..0cade5e0 100644 --- a/r5dev/game/CMakeLists.txt +++ b/r5dev/game/CMakeLists.txt @@ -55,9 +55,13 @@ add_sources( SOURCE_GROUP "Server" "server/basecombatcharacter.h" "server/baseentity.cpp" "server/baseentity.h" + "server/cbase.cpp" + "server/cbase.h" "server/detour_impl.h" "server/entitylist.cpp" "server/entitylist.h" + "server/entityoutput.cpp" + "server/entityoutput.h" "server/gameinterface.cpp" "server/gameinterface.h" "server/movehelper_server.cpp" @@ -71,6 +75,8 @@ add_sources( SOURCE_GROUP "Server" "server/playerlocaldata.h" "server/util_server.cpp" "server/util_server.h" + "server/variant_t.cpp" + "server/variant_t.h" "server/vscript_server.cpp" "server/vscript_server.h" ) diff --git a/r5dev/game/server/baseanimatingoverlay.h b/r5dev/game/server/baseanimatingoverlay.h index 2b694939..7ac4c558 100644 --- a/r5dev/game/server/baseanimatingoverlay.h +++ b/r5dev/game/server/baseanimatingoverlay.h @@ -14,7 +14,7 @@ class CBaseAnimatingOverlay : public CBaseAnimating { - char gap_11E4[8]; + char gap_11E4[8]; // Redundant??? int m_maxOverlays; char gap_11f4[4]; CAnimationLayer m_AnimOverlay; diff --git a/r5dev/game/server/baseentity.h b/r5dev/game/server/baseentity.h index 8d6c513a..f672eb6d 100644 --- a/r5dev/game/server/baseentity.h +++ b/r5dev/game/server/baseentity.h @@ -17,9 +17,28 @@ #include "public/iserverentity.h" #include "engine/gl_model_private.h" #include "game/shared/collisionproperty.h" +#include "game/shared/shareddefs.h" #include "networkproperty.h" #include "entitylist.h" +#include "entityoutput.h" +//----------------------------------------------------------------------------- + +typedef void (CBaseEntity::* BASEPTR)(void); +typedef void (CBaseEntity::* ENTITYFUNCPTR)(CBaseEntity* pOther); +typedef void (CBaseEntity::* USEPTR)(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value); + +//----------------------------------------------------------------------------- +// Purpose: think contexts +//----------------------------------------------------------------------------- +struct thinkfunc_t +{ + BASEPTR m_pfnThink; + bool m_fireBeforeBaseThink; + string_t m_iszContext; + int m_nNextThinkTick; + int m_nLastThinkTick; +}; class CBaseEntity : public IServerEntity { @@ -35,10 +54,10 @@ public: string_t GetModelName(void) const; // Virtual in-engine! inline edict_t GetEdict(void) { return NetworkProp()->GetEdict(); } - inline string_t GetName(void) const { return m_iName; } + inline string_t GetEntityName(void) const { return m_iName; } protected: - char m_RefEHandle[4]; + CBaseHandle m_RefEHandle; char gap_c[4]; void* m_collideable; void* m_networkable; @@ -51,14 +70,14 @@ protected: string_t m_ModelName; int m_entIndex; char gap_74[8]; // Aligns properly in IDA and generated code after setting from 4 to 8. - const char* m_iClassname; + string_t* m_iClassname; float m_flAnimTime; float m_flSimulationTime; int m_creationTick; int m_nLastThinkTick; int m_PredictableID; int touchStamp; - char m_aThinkFunctions[32]; + CUtlVector m_aThinkFunctions; float m_entitySpawnTime; int m_spawner; bool m_wantsDamageCallbacks; @@ -68,7 +87,7 @@ protected: int m_fEffects; bool m_thinkNextFrame; char gap_cd[3]; - __int64 m_target; + string_t m_target; int m_networkedFlags; char m_nRenderFX; char m_nRenderMode; @@ -159,7 +178,7 @@ protected: Vector3D m_angAbsRotation; Vector3D m_vecVelocity; char gap_474[4]; - __int64 m_iParent; + string_t m_iParent; int m_iHammerID; float m_flSpeed; int m_iMaxHealth; @@ -179,9 +198,9 @@ protected: float m_lastTitanFootstepDamageTime; float m_flMaxspeed; int m_visibilityFlags; - char m_OnUser1[40]; - char m_OnDeath[40]; - char m_OnDestroy[40]; + COutputEvent m_OnUser1; + COutputEvent m_OnDeath; + COutputEvent m_OnDestroy; int m_cellWidth; int m_cellBits; int m_cellX; @@ -208,7 +227,7 @@ protected: float m_entityFadeDist; int m_dissolveEffectEntityHandle; float m_fadeDist; - __int64 m_iSignifierName; + string_t m_iSignifierName; int m_collectedInvalidateFlags; bool m_collectingInvalidateFlags; char gap_5d5[3]; @@ -222,7 +241,7 @@ protected: void* m_pTimedOverlay; char m_ScriptScope[32]; char m_hScriptInstance[8]; - __int64 m_iszScriptId; + string_t m_iszScriptId; int m_bossPlayer; int m_usableType; int m_usablePriority; diff --git a/r5dev/game/server/cbase.cpp b/r5dev/game/server/cbase.cpp new file mode 100644 index 00000000..5e3f63c0 --- /dev/null +++ b/r5dev/game/server/cbase.cpp @@ -0,0 +1,6 @@ +//=============================================================================// +// +// Purpose: +// +//=============================================================================// +#include "cbase.h" diff --git a/r5dev/game/server/cbase.h b/r5dev/game/server/cbase.h new file mode 100644 index 00000000..99f0b645 --- /dev/null +++ b/r5dev/game/server/cbase.h @@ -0,0 +1,5 @@ +#ifndef CBASE_H +#define CBASE_H + + +#endif // CBASE_H diff --git a/r5dev/game/server/entityoutput.cpp b/r5dev/game/server/entityoutput.cpp new file mode 100644 index 00000000..c6526e68 --- /dev/null +++ b/r5dev/game/server/entityoutput.cpp @@ -0,0 +1,6 @@ +//=============================================================================// +// +// Purpose: +// +//=============================================================================// +#include "entityoutput.h" diff --git a/r5dev/game/server/entityoutput.h b/r5dev/game/server/entityoutput.h new file mode 100644 index 00000000..22b3abce --- /dev/null +++ b/r5dev/game/server/entityoutput.h @@ -0,0 +1,70 @@ +#ifndef ENTITYOUTPUT_H +#define ENTITYOUTPUT_H +#include "variant_t.h" + +#define EVENT_FIRE_ALWAYS -1 + +class CBaseEntity; + + +//----------------------------------------------------------------------------- +// Purpose: A COutputEvent consists of an array of these CEventActions. +// Each CEventAction holds the information to fire a single input in +// a target entity, after a specific delay. +//----------------------------------------------------------------------------- +class CEventAction +{ +public: + int m_type; + char gap_4[4]; + + string_t m_iTarget; // name of the entity(s) to cause the action in + string_t m_iTargetInput; // the name of the action to fire + string_t m_iParameter; // parameter to send, 0 if none + + int m_scriptEnt; + char gap_24[4]; + char m_scriptFunc[16]; + + float m_flDelay; // the number of seconds to wait before firing the action + int m_nTimesToFire; // The number of times to fire this event, or EVENT_FIRE_ALWAYS. + + int m_iIDStamp; // unique identifier stamp + + //static int s_iNextIDStamp; !TODO[ AMOS ]: If found, make this a ptr and link it to the one in the game engine! + + CEventAction* m_pNext; +}; + +//----------------------------------------------------------------------------- +// Purpose: Stores a list of connections to other entities, for data/commands to be +// communicated along. +//----------------------------------------------------------------------------- +class CBaseEntityOutput +{ +public: + virtual ~CBaseEntityOutput() {}; + virtual int Save(/*ISave*/ __int64 /*save*/) {return 1; /*!!! IMPLEMENTATION IN ENGINE !!!*/} + virtual int Restore(/*IRestore*/ __int64 /*restore*/, int /*elementCount*/) { return 1; /*!!! IMPLEMENTATION IN ENGINE !!!*/ } + +protected: + variant_t m_Value; + CEventAction* m_ActionList; + //DECLARE_SIMPLE_DATADESC(); + + CBaseEntityOutput() {} // this class cannot be created, only it's children + +private: + CBaseEntityOutput(CBaseEntityOutput&); // protect from accidental copying +}; + + +//----------------------------------------------------------------------------- +// Purpose: parameterless entity event +//----------------------------------------------------------------------------- +class COutputEvent : public CBaseEntityOutput +{ +public: +}; + +#endif // ENTITYOUTPUT_H diff --git a/r5dev/game/server/variant_t.cpp b/r5dev/game/server/variant_t.cpp new file mode 100644 index 00000000..32db0c9d --- /dev/null +++ b/r5dev/game/server/variant_t.cpp @@ -0,0 +1,332 @@ + ////////////////////////// variant_t implementation ////////////////////////// + +#include "entityoutput.h" +#include "baseentity.h" + +//----------------------------------------------------------------------------- +// Purpose: All types must be able to display as strings for debugging purposes. +// Output : Returns a pointer to the string that represents this value. +// +// NOTE: The returned pointer should not be stored by the caller as +// subsequent calls to this function will overwrite the contents +// of the buffer! +//----------------------------------------------------------------------------- +const char* variant_t::ToString(void) const +{ + static char szBuf[512]; + + switch (fieldType) + { + case FIELD_STRING: + { + return(STRING(iszVal)); + } + + case FIELD_BOOLEAN: + { + if (bVal == 0) + { + Q_strncpy(szBuf, "false", sizeof(szBuf)); + } + else + { + Q_strncpy(szBuf, "true", sizeof(szBuf)); + } + return(szBuf); + } + + case FIELD_INTEGER: + { + Q_snprintf(szBuf, sizeof(szBuf), "%i", iVal); + return(szBuf); + } + + case FIELD_FLOAT: + { + Q_snprintf(szBuf, sizeof(szBuf), "%g", flVal); + return(szBuf); + } + + case FIELD_COLOR32: + { + Q_snprintf(szBuf, sizeof(szBuf), "%d %d %d %d", (int)rgbaVal.r, (int)rgbaVal.g, (int)rgbaVal.b, (int)rgbaVal.a); + return(szBuf); + } + + case FIELD_VECTOR: + { + Q_snprintf(szBuf, sizeof(szBuf), "[%g %g %g]", (double)vecVal[0], (double)vecVal[1], (double)vecVal[2]); + return(szBuf); + } + + case FIELD_VOID: + { + szBuf[0] = '\0'; + return(szBuf); + } + + case FIELD_EHANDLE: + { + const char* pszName = (Entity()) ? STRING(Entity()->GetEntityName()) : "<>"; + Q_strncpy(szBuf, pszName, 512); + return (szBuf); + } + } + + return("No conversion to string"); +} + +//----------------------------------------------------------------------------- +// Purpose: sets the entity +//----------------------------------------------------------------------------- +void variant_t::SetEntity(CBaseEntity* val) +{ + eVal = val; + fieldType = FIELD_EHANDLE; +} + +// BUGBUG: Add support for function pointer save/restore to variants +// BUGBUG: Must pass datamap_t to read/write fields +//void variant_t::Set(fieldtype_t ftype, void* data) +//{ +// fieldType = ftype; +// +// switch (ftype) +// { +// case FIELD_BOOLEAN: bVal = *((bool*)data); break; +// case FIELD_CHARACTER: iVal = *((char*)data); break; +// case FIELD_SHORT: iVal = *((short*)data); break; +// case FIELD_INTEGER: iVal = *((int*)data); break; +// case FIELD_STRING: iszVal = *((string_t*)data); break; +// case FIELD_FLOAT: flVal = *((float*)data); break; +// case FIELD_COLOR32: rgbaVal = *((color32*)data); break; +// +// case FIELD_VECTOR: +// case FIELD_POSITION_VECTOR: +// { +// vecVal[0] = ((float*)data)[0]; +// vecVal[1] = ((float*)data)[1]; +// vecVal[2] = ((float*)data)[2]; +// break; +// } +// +// case FIELD_EHANDLE: eVal = *((EHANDLE*)data); break; +// case FIELD_CLASSPTR: eVal = *((CBaseEntity**)data); break; +// case FIELD_VOID: +// default: +// iVal = 0; fieldType = FIELD_VOID; +// break; +// } +//} + +//----------------------------------------------------------------------------- +// Purpose: Copies the value in the variant into a block of memory +// Input : *data - the block to write into +//----------------------------------------------------------------------------- +void variant_t::SetOther(void* data) +{ + switch (fieldType) + { + case FIELD_BOOLEAN: *((bool*)data) = bVal != 0; break; + case FIELD_CHARACTER: *((char*)data) = (char)iVal; break; + case FIELD_SHORT: *((short*)data) = (short)iVal; break; + case FIELD_INTEGER: *((int*)data) = iVal; break; + case FIELD_STRING: *((string_t*)data) = iszVal; break; + case FIELD_FLOAT: *((float*)data) = flVal; break; + case FIELD_COLOR32: *((color32*)data) = rgbaVal; break; + + case FIELD_VECTOR: + case FIELD_POSITION_VECTOR: + { + ((float*)data)[0] = vecVal[0]; + ((float*)data)[1] = vecVal[1]; + ((float*)data)[2] = vecVal[2]; + break; + } + + case FIELD_EHANDLE: *((EHANDLE*)data) = eVal; break; + case FIELD_CLASSPTR: *((CBaseEntity**)data) = eVal; break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Converts the variant to a new type. This function defines which I/O +// types can be automatically converted between. Connections that require +// an unsupported conversion will cause an error message at runtime. +// Input : newType - the type to convert to +// Output : Returns true on success, false if the conversion is not legal +//----------------------------------------------------------------------------- +//bool variant_t::Convert(fieldtype_t newType) +//{ +// if (newType == fieldType) +// { +// return true; +// } +// +// // +// // Converting to a null value is easy. +// // +// if (newType == FIELD_VOID) +// { +// Set(FIELD_VOID, NULL); +// return true; +// } +// +// // +// // FIELD_INPUT accepts the variant type directly. +// // +// if (newType == FIELD_INPUT) +// { +// return true; +// } +// +// switch (fieldType) +// { +// case FIELD_INTEGER: +// { +// switch (newType) +// { +// case FIELD_FLOAT: +// { +// SetFloat((float)iVal); +// return true; +// } +// +// case FIELD_BOOLEAN: +// { +// SetBool(iVal != 0); +// return true; +// } +// } +// break; +// } +// +// case FIELD_FLOAT: +// { +// switch (newType) +// { +// case FIELD_INTEGER: +// { +// SetInt((int)flVal); +// return true; +// } +// +// case FIELD_BOOLEAN: +// { +// SetBool(flVal != 0); +// return true; +// } +// } +// break; +// } +// +// // +// // Everyone must convert from FIELD_STRING if possible, since +// // parameter overrides are always passed as strings. +// // +// case FIELD_STRING: +// { +// switch (newType) +// { +// case FIELD_INTEGER: +// { +// if (iszVal != NULL_STRING) +// { +// SetInt(atoi(STRING(iszVal))); +// } +// else +// { +// SetInt(0); +// } +// return true; +// } +// +// case FIELD_FLOAT: +// { +// if (iszVal != NULL_STRING) +// { +// SetFloat(atof(STRING(iszVal))); +// } +// else +// { +// SetFloat(0); +// } +// return true; +// } +// +// case FIELD_BOOLEAN: +// { +// if (iszVal != NULL_STRING) +// { +// SetBool(atoi(STRING(iszVal)) != 0); +// } +// else +// { +// SetBool(false); +// } +// return true; +// } +// +// case FIELD_VECTOR: +// { +// ::Vector3D tmpVec = vec3_origin; +// if (sscanf(STRING(iszVal), "[%f %f %f]", &tmpVec[0], &tmpVec[1], &tmpVec[2]) == 0) +// { +// // Try sucking out 3 floats with no []s +// sscanf(STRING(iszVal), "%f %f %f", &tmpVec[0], &tmpVec[1], &tmpVec[2]); +// } +// SetVector3D(tmpVec); +// return true; +// } +// +// case FIELD_COLOR32: +// { +// int nRed = 0; +// int nGreen = 0; +// int nBlue = 0; +// int nAlpha = 255; +// +// sscanf(STRING(iszVal), "%d %d %d %d", &nRed, &nGreen, &nBlue, &nAlpha); +// SetColor32(nRed, nGreen, nBlue, nAlpha); +// return true; +// } +// +// case FIELD_EHANDLE: +// { +// // convert the string to an entity by locating it by classname +// CBaseEntity* ent = NULL; +// if (iszVal != NULL_STRING) +// { +// // FIXME: do we need to pass an activator in here? +// ent = gEntList.FindEntityByName(NULL, iszVal); +// } +// SetEntity(ent); +// return true; +// } +// } +// +// break; +// } +// +// case FIELD_EHANDLE: +// { +// switch (newType) +// { +// case FIELD_STRING: +// { +// // take the entities targetname as the string +// string_t iszStr = NULL_STRING; +// if (eVal != NULL) +// { +// SetString(eVal->GetEntityName()); +// } +// return true; +// } +// } +// break; +// } +// } +// +// // invalid conversion +// return false; +//} diff --git a/r5dev/game/server/variant_t.h b/r5dev/game/server/variant_t.h new file mode 100644 index 00000000..a6269e2f --- /dev/null +++ b/r5dev/game/server/variant_t.h @@ -0,0 +1,127 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VARIANT_T_H +#define VARIANT_T_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/string_t.h" +#include "mathlib/vmatrix.h" +#include "mathlib/color.h" +#include "game/shared/ehandle.h" +#include "datamap.h" + +// Microsoft headers define these for '_variant_t' +// undefine them to prevent clashes with our struct. +#if defined variant_t +#undef variant_t +#endif variant_t + +class CBaseEntity; + +//----------------------------------------------------------------------------- +// A variant class for passing data in entity input/output connections. +//----------------------------------------------------------------------------- +class variant_t +{ +public: + // constructor + variant_t() : fieldType(FIELD_VOID), iVal(0) {} + + inline bool Bool( void ) const { return( fieldType == FIELD_BOOLEAN ) ? bVal : false; } + inline const char *String( void ) const { return( fieldType == FIELD_STRING ) ? STRING(iszVal) : ToString(); } + inline string_t StringID( void ) const { return( fieldType == FIELD_STRING ) ? iszVal : NULL_STRING; } + inline int Int( void ) const { return( fieldType == FIELD_INTEGER ) ? iVal : 0; } + inline float Float( void ) const { return( fieldType == FIELD_FLOAT ) ? flVal : 0; } + inline const CHandle &Entity( void ) const; + inline color32 Color32( void ) const { return rgbaVal; } + inline void Vector3D( ::Vector3D &vec ) const; + + fieldtype_t FieldType( void ) { return fieldType; } + + void SetBool( bool b ) { bVal = b; fieldType = FIELD_BOOLEAN; } + void SetString( string_t str ) { iszVal = str, fieldType = FIELD_STRING; } + void SetInt( int val ) { iVal = val, fieldType = FIELD_INTEGER; } + void SetFloat( float val ) { flVal = val, fieldType = FIELD_FLOAT; } + void SetEntity( CBaseEntity *val ); + void SetVector3D( const ::Vector3D &val ) { vecVal[0] = val[ 0 ]; vecVal[ 1 ] = val[ 1 ]; vecVal[ 2 ] = val[ 2 ]; fieldType = FIELD_VECTOR; } + void SetPositionVector3D( const ::Vector3D &val ) { vecVal[ 0 ] = val[ 0 ]; vecVal[ 1 ] = val[ 1 ]; vecVal[ 2 ] = val[ 2 ]; fieldType = FIELD_POSITION_VECTOR; } + void SetColor32( color32 val ) { rgbaVal = val; fieldType = FIELD_COLOR32; } + void SetColor32( int r, int g, int b, int a ) { rgbaVal.r = (byte)r; rgbaVal.g = (byte)g; rgbaVal.b = (byte)b; rgbaVal.a = (byte)a; fieldType = FIELD_COLOR32; } + void Set( fieldtype_t ftype, void *data ); + void SetOther( void *data ); + bool Convert( fieldtype_t newType ); + + // !TODO[AMOS]: If found, make this a ptrand link it to the one in the game engine! + //static typedescription_t m_SaveBool[]; + //static typedescription_t m_SaveInt[]; + //static typedescription_t m_SaveFloat[]; + //static typedescription_t m_SaveEHandle[]; + //static typedescription_t m_SaveString[]; + //static typedescription_t m_SaveColor[]; + //static typedescription_t m_SaveVector[]; + //static typedescription_t m_SavePositionVector[]; + //static typedescription_t m_SaveVMatrix[]; + //static typedescription_t m_SaveVMatrixWorldspace[]; + //static typedescription_t m_SaveMatrix3x4Worldspace[]; + +protected: + //------------------------------------------------------------------------- + // Returns a string representation of the value without modifying the variant. + //------------------------------------------------------------------------- + const char *ToString( void ) const; + + friend class CVariantSaveDataOps; + +private: + union + { + bool bVal; + string_t iszVal; + int iVal; + float flVal; + float vecVal[3]; + color32 rgbaVal; + }; + CHandle eVal; // this can't be in the union because it has a constructor. + + fieldtype_t fieldType; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Returns this variant as a vector. +//----------------------------------------------------------------------------- +inline void variant_t::Vector3D( ::Vector3D &vec ) const +{ + if (( fieldType == FIELD_VECTOR ) || ( fieldType == FIELD_POSITION_VECTOR )) + { + vec[ 0 ] = vecVal[ 0 ]; + vec[ 1 ] = vecVal[ 1 ]; + vec[ 2 ] = vecVal[ 2 ]; + } + else + { + vec = vec3_origin; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns this variant as an EHANDLE. +//----------------------------------------------------------------------------- +inline const CHandle &variant_t::Entity( void ) const +{ + if ( fieldType == FIELD_EHANDLE ) + return eVal; + + static const CHandle hNull( INVALID_EHANDLE ); + return( hNull ); +} + +#endif // VARIANT_T_H diff --git a/r5dev/game/shared/shareddefs.h b/r5dev/game/shared/shareddefs.h index f3119134..45078bbe 100644 --- a/r5dev/game/shared/shareddefs.h +++ b/r5dev/game/shared/shareddefs.h @@ -39,5 +39,12 @@ #define HITGROUP_GEAR 8 // alerts NPC, but doesn't do damage or bleed (1/100th damage) #define HITGROUP_COUNT 9 +typedef enum // !TODO[ AMOS ]: Confirm this! +{ + USE_OFF = 0, + USE_ON = 1, + USE_SET = 2, + USE_TOGGLE = 3 +} USE_TYPE; #endif // SHAREDDEFS_H \ No newline at end of file