From 8be119aa6a304fb330656dc451badd876d1da821 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Mon, 6 Jul 2015 20:05:48 +0200 Subject: [PATCH] Cstrike: cs_set/reset_user_model/team - Stagger user's info updates across multiple frames (bug 3134) --- gamedata/common.games/master.games.txt | 6 + modules/cstrike/cstrike/CstrikeHacks.cpp | 34 +- modules/cstrike/cstrike/CstrikeHacks.h | 8 +- modules/cstrike/cstrike/CstrikeNatives.cpp | 65 +-- modules/cstrike/cstrike/CstrikePlayer.cpp | 58 +- modules/cstrike/cstrike/CstrikePlayer.h | 131 ++++- .../cstrike/cstrike/CstrikeUserMessages.cpp | 14 +- modules/cstrike/cstrike/CstrikeUtils.h | 4 +- modules/cstrike/cstrike/amxx_api.cpp | 12 +- modules/cstrike/cstrike/moduleconfig.h | 4 +- public/engine_strucs.h | 512 ++++++++++++++++++ public/sdk/amxxmodule.cpp | 24 + public/sdk/amxxmodule.h | 1 + 13 files changed, 752 insertions(+), 121 deletions(-) create mode 100644 public/engine_strucs.h diff --git a/gamedata/common.games/master.games.txt b/gamedata/common.games/master.games.txt index a5c67fbb..bb9497c9 100644 --- a/gamedata/common.games/master.games.txt +++ b/gamedata/common.games/master.games.txt @@ -11,6 +11,12 @@ "Game Master" { + "globalvars.engine.txt" + { + "engine" "engine_ds" + "engine" "engine_ls" + } + "entities.games/cstrike/offsets-cairtank.txt" { "game" "cstrike" diff --git a/modules/cstrike/cstrike/CstrikeHacks.cpp b/modules/cstrike/cstrike/CstrikeHacks.cpp index 809d0a02..7d7f3a12 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.cpp +++ b/modules/cstrike/cstrike/CstrikeHacks.cpp @@ -42,11 +42,16 @@ StringHashMap ItemAliasList; int TeamOffset; int MenuOffset; +server_static_t *ServerStatic; +double *RealTime; + void InitializeHacks() { CtrlDetours_ClientCommand(true); CtrlDetours_BuyCommands(true); CtrlDetours_Natives(true); + + InitGlobalVars(); } void ShutdownHacks() @@ -301,8 +306,8 @@ void CtrlDetours_ClientCommand(bool set) #endif ClientCommandDetour = DETOUR_CREATE_STATIC_FIXED(C_ClientCommand, base); - OffsetConfig->GetOffsetByClass("CBasePlayer", "m_iTeam", &TeamOffset); - OffsetConfig->GetOffsetByClass("CBasePlayer", "m_iMenu", &MenuOffset); + CommonConfig->GetOffsetByClass("CBasePlayer", "m_iTeam", &TeamOffset); + CommonConfig->GetOffsetByClass("CBasePlayer", "m_iMenu", &MenuOffset); if (!ClientCommandDetour || !UseBotArgs || !BotArgs || !TeamOffset || !MenuOffset) { @@ -506,3 +511,28 @@ void CtrlDetours_Natives(bool set) } } } + +void InitGlobalVars() +{ + void *address = nullptr; + +#if defined(WIN32) + + int offset = 0; + + if (CommonConfig->GetOffset("svs", &offset)) + { + uintptr_t base = *reinterpret_cast(reinterpret_cast(g_engfuncs.pfnGetCurrentPlayer) + offset); + ServerStatic = reinterpret_cast(base - 4); + } +#else + if (CommonConfig->GetMemSig("svs", &address)) + { + ServerStatic = reinterpret_cast(address); + } +#endif + if (CommonConfig->GetAddress("realtime", &address)) + { + RealTime = reinterpret_cast(*reinterpret_cast(address)); + } +} \ No newline at end of file diff --git a/modules/cstrike/cstrike/CstrikeHacks.h b/modules/cstrike/cstrike/CstrikeHacks.h index 347f3223..29f79864 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.h +++ b/modules/cstrike/cstrike/CstrikeHacks.h @@ -17,8 +17,10 @@ #include #include #include +#include void InitializeHacks(); +void InitGlobalVars(); void ShutdownHacks(); void ToggleDetour_ClientCommands(bool enable); void ToggleDetour_BuyCommands(bool enable); @@ -26,7 +28,7 @@ void ToggleDetour_BuyCommands(bool enable); extern AMX_NATIVE_INFO CstrikeNatives[]; extern IGameConfig *MainConfig; -extern IGameConfig *OffsetConfig; +extern IGameConfig *CommonConfig; extern int ForwardInternalCommand; extern int ForwardOnBuy; @@ -40,6 +42,10 @@ extern UTIL_FindEntityByStringFunc CS_UTIL_FindEntityByString; extern CDetour *GiveDefaultItemsDetour; extern enginefuncs_t *g_pengfuncsTable; +extern DLL_FUNCTIONS *g_pFunctionTable; extern bool NoKifesMode; +extern server_static_t *ServerStatic; +extern double *RealTime; + #endif // CSTRIKE_HACKS_H diff --git a/modules/cstrike/cstrike/CstrikeNatives.cpp b/modules/cstrike/cstrike/CstrikeNatives.cpp index 26667767..bed06141 100644 --- a/modules/cstrike/cstrike/CstrikeNatives.cpp +++ b/modules/cstrike/cstrike/CstrikeNatives.cpp @@ -18,9 +18,7 @@ #include "CstrikeUserMessages.h" #include "CstrikeHLTypeConversion.h" #include - -CCstrikePlayer g_players[33]; -int Zooming[33]; +#include bool NoKifesMode = false; @@ -536,7 +534,7 @@ static cell AMX_NATIVE_CALL cs_set_user_team(AMX *amx, cell *params) set_pdata(pPlayer, m_iModelName, model); } - MDLL_ClientUserInfoChanged(pPlayer, GETINFOKEYBUFFER(pPlayer)); + Players[index].ResetModel(pPlayer); char teaminfo[32]; @@ -863,17 +861,11 @@ static cell AMX_NATIVE_CALL cs_set_user_model(AMX *amx, cell *params) return 0; } - char modelName[32]; int length; + const char *newModel = MF_GetAmxString(amx, params[2], 0, &length); - strcpy(modelName, MF_GetAmxString(amx, params[2], 0, &length)); - - g_players[index].SetModel(modelName); - g_players[index].SetModelled(true); - - EnableMessageHooks(); - - SETCLIENTKEYVALUE(index, GETINFOKEYBUFFER(pPlayer), "model", const_cast(g_players[index].GetModel())); + Players[index].SetModel(newModel); + Players[index].UpdateModel(MF_GetPlayerEdict(index)); return 1; } @@ -886,9 +878,7 @@ static cell AMX_NATIVE_CALL cs_reset_user_model(AMX *amx, cell *params) CHECK_PLAYER(index); edict_t *pPlayer = MF_GetPlayerEdict(index); - g_players[index].SetModelled(false); - - MDLL_ClientUserInfoChanged(pPlayer, GETINFOKEYBUFFER(pPlayer)); + Players[index].ResetModel(pPlayer); return 1; } @@ -1317,7 +1307,7 @@ static cell AMX_NATIVE_CALL cs_set_user_zoom(AMX *amx, cell *params) int mode = params[3]; int weapon = *static_cast(MF_PlayerPropAddr(index, Player_CurrentWeapon)); - Zooming[index] = 0; + Players[index].ResetZoom(); if (type == CS_RESET_ZOOM) { @@ -1365,7 +1355,7 @@ static cell AMX_NATIVE_CALL cs_set_user_zoom(AMX *amx, cell *params) if (!mode) { - Zooming[index] = value; + Players[index].SetZoom(value); EnableMessageHooks(); } @@ -1766,42 +1756,3 @@ AMX_NATIVE_INFO CstrikeNatives[] = {nullptr, nullptr} }; - -void ClientDisconnect(edict_t *pEntity) -{ - int index = ENTINDEX(pEntity); - g_players[index].SetModelled(false); - Zooming[index] = 0; - - RETURN_META(MRES_IGNORED); -} - -void ClientUserInfoChanged(edict_t *pEntity, char *infobuffer) -{ - int index = ENTINDEX(pEntity); - - if(g_players[index].GetModelled() && pEntity->v.deadflag == DEAD_NO) - { - RETURN_META(MRES_SUPERCEDE); - } - else - { - RETURN_META(MRES_IGNORED); - } -} - -void PlayerPostThink(edict_t* pPlayer) -{ - int entityIndex = ENTINDEX(pPlayer); - - if(g_players[entityIndex].GetModelled()) - { - if (g_players[entityIndex].GetInspectModel() && strcmp(g_players[entityIndex].GetModel(), GETCLIENTKEYVALUE(GETINFOKEYBUFFER(pPlayer), "model")) != 0) - { - //LOG_CONSOLE(PLID, "%s should have model %s and currently has %s", STRING(pPlayer->v.netname), (char*)g_players[entityIndex].GetModel(), GETCLIENTKEYVALUE(GETINFOKEYBUFFER(pPlayer), "model")); - SETCLIENTKEYVALUE(entityIndex, GETINFOKEYBUFFER(pPlayer), "model", (char*)g_players[entityIndex].GetModel()); - g_players[entityIndex].SetInspectModel(false); - } - } - RETURN_META(MRES_IGNORED); -} diff --git a/modules/cstrike/cstrike/CstrikePlayer.cpp b/modules/cstrike/cstrike/CstrikePlayer.cpp index a3953e13..a39a3343 100644 --- a/modules/cstrike/cstrike/CstrikePlayer.cpp +++ b/modules/cstrike/cstrike/CstrikePlayer.cpp @@ -12,47 +12,49 @@ // #include "CstrikePlayer.h" -#include // strcpy() -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// +CPlayer Players[33]; +ke::Vector ModelsUpdateQueue; -CCstrikePlayer::CCstrikePlayer() +void ClientDisconnect(edict_t *pEntity) { - modelled = false; - inspectModel = false; + int index = ENTINDEX(pEntity); + + Players[index].ResetModel(); + Players[index].ResetZoom(); + + RETURN_META(MRES_IGNORED); } -bool CCstrikePlayer::GetModelled() +void ClientUserInfoChanged(edict_t *pEntity, char *infobuffer) { - return modelled; + if (pEntity->pvPrivateData) + { + Players[ENTINDEX(pEntity)].UpdateModel(pEntity); + } + + RETURN_META(MRES_IGNORED); } -bool CCstrikePlayer::SetModelled(bool modelledIn) +void SetClientKeyValue(int clientIndex, char *infobuffer, const char *key, const char *value) { - if (!modelledIn) - SetInspectModel(false); + if (!strcmp(key, "model") && Players[clientIndex].HasModel(value)) + { + RETURN_META(MRES_SUPERCEDE); + } - return modelled = modelledIn; + RETURN_META(MRES_IGNORED); } -const char* CCstrikePlayer::GetModel() +void StartFrame() { - return model; -} + if (ModelsUpdateQueue.empty()) + { + g_pFunctionTable->pfnStartFrame = nullptr; + RETURN_META(MRES_IGNORED); + } -void CCstrikePlayer::SetModel(const char* modelIn) -{ - strcpy(model, modelIn); -} + ServerStatic->clients[ModelsUpdateQueue.popCopy()].sendinfo = true; -bool CCstrikePlayer::GetInspectModel() -{ - return inspectModel; -} - -void CCstrikePlayer::SetInspectModel(bool inspectModelIn) -{ - inspectModel = inspectModelIn; + RETURN_META(MRES_IGNORED); } diff --git a/modules/cstrike/cstrike/CstrikePlayer.h b/modules/cstrike/cstrike/CstrikePlayer.h index e021beb3..26a7af83 100644 --- a/modules/cstrike/cstrike/CstrikePlayer.h +++ b/modules/cstrike/cstrike/CstrikePlayer.h @@ -11,30 +11,125 @@ // Counter-Strike Module // -#if !defined(INCLUDED_CCSTRIKEPLAYER) -#define INCLUDED_CCSTRIKEPLAYER +#ifndef _CSTRIKE_PLAYER_H_ +#define _CSTRIKE_PLAYER_H_ -class CCstrikePlayer +#include +#include "CstrikeUtils.h" +#include "CstrikeHacks.h" +#include + +extern ke::Vector ModelsUpdateQueue; + +void StartFrame(); +void ClientUserInfoChanged(edict_t *pEntity, char *infobuffer); +void SetClientKeyValue(int clientIndex, char *infobuffer, const char *key, const char *value); + +class CPlayer { -public: - CCstrikePlayer(); + public: - bool GetModelled(); - bool SetModelled(bool modelledIn); - const char* GetModel(); - void SetModel(const char* modelIn); + CPlayer() + { + ResetModel(); + ResetZoom(); + } - bool GetInspectModel(); - void SetInspectModel(bool inspectModelIn); + bool HasModel(const char *model = nullptr) + { + if (*m_Model != '\0') + { + if (model && *model) + { + return strcmp(m_Model, model) != 0; + } + return true; + } -private: - bool inspectModel; - bool modelled; - char model[32]; + return false; + } + + void SetModel(const char* modelIn) + { + if (modelIn && *modelIn) + { + strncopy(m_Model, modelIn, sizeof(m_Model)); + } + else + { + ResetModel(); + } + } + + void ResetModel(edict_t *pPlayer = nullptr) + { + *m_Model = '\0'; + + if (pPlayer) + { + MDLL_ClientUserInfoChanged(pPlayer, GETINFOKEYBUFFER(pPlayer)); + + PostponeModeUpdate(ENTINDEX(pPlayer) - 1); + } + } + + void UpdateModel(edict_t *pPlayer) + { + if (!HasModel()) + { + return; + } + + char *infobuffer = GETINFOKEYBUFFER(pPlayer); + + if (strcmp(GETCLIENTKEYVALUE(infobuffer, "model"), m_Model) != 0) + { + int index = ENTINDEX(pPlayer); + + SETCLIENTKEYVALUE(index, infobuffer, "model", m_Model); + + PostponeModeUpdate(index - 1); + } + } + + int GetZoom() + { + return m_Zooming; + } + + void SetZoom(int value) + { + m_Zooming = value; + } + + void ResetZoom() + { + m_Zooming = 0; + } + + private: + + void PostponeModeUpdate(int index) + { + ServerStatic->clients[index].sendinfo = false; + + ModelsUpdateQueue.append(index); + + if (!g_pFunctionTable->pfnStartFrame) + { + g_pFunctionTable->pfnStartFrame = StartFrame; + g_pFunctionTable->pfnClientUserInfoChanged = ClientUserInfoChanged; + g_pengfuncsTable->pfnSetClientKeyValue = SetClientKeyValue; + } + } + + private: + + char m_Model[32]; + int m_Zooming; }; -extern CCstrikePlayer g_players[33]; -extern int Zooming[33]; +extern CPlayer Players[33]; -#endif // !defined(INCLUDED_CCSTRIKEPLAYER) +#endif // _CSTRIKE_PLAYER_H_ diff --git a/modules/cstrike/cstrike/CstrikeUserMessages.cpp b/modules/cstrike/cstrike/CstrikeUserMessages.cpp index 41d74ef6..9cb1cf87 100644 --- a/modules/cstrike/cstrike/CstrikeUserMessages.cpp +++ b/modules/cstrike/cstrike/CstrikeUserMessages.cpp @@ -76,14 +76,15 @@ void OnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *p if (msg_type == MessageIdSetFOV) { int index = ENTINDEX(pEntity); + int zoom = Players[index].GetZoom(); - if (Zooming[index]) + if (zoom) { GET_OFFSET_NO_ERROR("CBasePlayer", m_iFOV); - if (get_pdata(pEntity, m_iFOV) != Zooming[index]) + if (get_pdata(pEntity, m_iFOV) != zoom) { - set_pdata(pEntity, m_iFOV, Zooming[index]); + set_pdata(pEntity, m_iFOV, zoom); ShouldBlock = true; ShouldBlockHLTV = true; @@ -96,11 +97,8 @@ void OnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *p { int index = ENTINDEX(pEntity); - if (Zooming[index]) - Zooming[index] = 0; - - if (g_players[index].GetModelled()) - g_players[index].SetInspectModel(true); + if (Players[index].GetZoom()) + Players[index].ResetZoom(); } break; } diff --git a/modules/cstrike/cstrike/CstrikeUtils.h b/modules/cstrike/cstrike/CstrikeUtils.h index c5100d39..ff10c287 100644 --- a/modules/cstrike/cstrike/CstrikeUtils.h +++ b/modules/cstrike/cstrike/CstrikeUtils.h @@ -78,7 +78,7 @@ bool UTIL_CheckForPublic(const char *publicname); static int member = -1; \ if (member == -1) \ { \ - if (!OffsetConfig->GetOffsetByClass(classname, #member, &member) || member < 0)\ + if (!CommonConfig->GetOffsetByClass(classname, #member, &member) || member < 0)\ { \ MF_LogError(amx, AMX_ERR_NATIVE, "Invalid %s offset. Native %s is disabled", #member, __FUNCTION__);\ return 0; \ @@ -89,7 +89,7 @@ bool UTIL_CheckForPublic(const char *publicname); static int member = -1; \ if (member == -1) \ { \ - if (!OffsetConfig->GetOffsetByClass(classname, #member, &member) || member < 0)\ + if (!CommonConfig->GetOffsetByClass(classname, #member, &member) || member < 0)\ { \ return; \ } \ diff --git a/modules/cstrike/cstrike/amxx_api.cpp b/modules/cstrike/cstrike/amxx_api.cpp index a5c059b0..05bfe478 100644 --- a/modules/cstrike/cstrike/amxx_api.cpp +++ b/modules/cstrike/cstrike/amxx_api.cpp @@ -17,9 +17,10 @@ #include "CstrikeHacks.h" #include "CstrikeHLTypeConversion.h" #include +#include "engine_strucs.h" IGameConfig *MainConfig; -IGameConfig *OffsetConfig; +IGameConfig *CommonConfig; IGameConfigManager *ConfigManager; int AmxxCheckGame(const char *game) @@ -49,7 +50,7 @@ void OnAmxxAttach() error[0] = '\0'; - if (!ConfigManager->LoadGameConfigFile("common.games", &OffsetConfig, error, sizeof(error)) && error[0] != '\0') + if (!ConfigManager->LoadGameConfigFile("common.games", &CommonConfig, error, sizeof(error)) && error[0] != '\0') { MF_Log("Could not read common.games gamedata: %s", error); return; @@ -79,12 +80,17 @@ void OnPluginsLoaded() { G_OffsetHandler = new OffsetHandler; } + + // Used with model natives, enabled on demand. + g_pengfuncsTable->pfnSetClientKeyValue = nullptr; + g_pFunctionTable->pfnClientUserInfoChanged = nullptr; + g_pFunctionTable->pfnStartFrame = nullptr; } void OnAmxxDetach() { ConfigManager->CloseGameConfigFile(MainConfig); - ConfigManager->CloseGameConfigFile(OffsetConfig); + ConfigManager->CloseGameConfigFile(CommonConfig); ShutdownHacks(); } diff --git a/modules/cstrike/cstrike/moduleconfig.h b/modules/cstrike/cstrike/moduleconfig.h index 42cdde5c..79b9eccd 100644 --- a/modules/cstrike/cstrike/moduleconfig.h +++ b/modules/cstrike/cstrike/moduleconfig.h @@ -122,11 +122,11 @@ // #define FN_ClientKill ClientKill /* pfnClientKill() (wd) Player has typed "kill" */ // #define FN_ClientPutInServer ClientPutInServer /* pfnClientPutInServer() (wd) Client is entering the game */ // #define FN_ClientCommand ClientCommand /* pfnClientCommand() (wd) Player has sent a command (typed or from a bind) */ -#define FN_ClientUserInfoChanged ClientUserInfoChanged /* pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure */ +// #define FN_ClientUserInfoChanged ClientUserInfoChanged /* pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure */ // #define FN_ServerActivate ServerActivate /* pfnServerActivate() (wd) Server is starting a new map */ // #define FN_ServerDeactivate ServerDeactivate /* pfnServerDeactivate() (wd) Server is leaving the map (shutdown or changelevel); SDK2 */ // #define FN_PlayerPreThink PlayerPreThink /* pfnPlayerPreThink() */ -#define FN_PlayerPostThink PlayerPostThink /* pfnPlayerPostThink() */ +// #define FN_PlayerPostThink PlayerPostThink /* pfnPlayerPostThink() */ // #define FN_StartFrame StartFrame /* pfnStartFrame() */ // #define FN_ParmsNewLevel ParmsNewLevel /* pfnParmsNewLevel() */ // #define FN_ParmsChangeLevel ParmsChangeLevel /* pfnParmsChangeLevel() */ diff --git a/public/engine_strucs.h b/public/engine_strucs.h new file mode 100644 index 00000000..3191e7d0 --- /dev/null +++ b/public/engine_strucs.h @@ -0,0 +1,512 @@ +// +// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). +// Copyright (C) The AMX Mod X Development Team. +// +// This software is licensed under the GNU General Public License, version 3 or higher. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://alliedmods.net/amxmodx-license + +#ifndef _ENGINE_STRUCTS_H_ +#define _ENGINE_STRUCTS_H_ + +#include +#include +#include +#include +#include +#include + +#define MAX_CLIENTS 32 +#define MAX_EDICTS 900 +#define MAX_NAME 32 +#define MAX_LIGHTSTYLES 64 +#define MAX_PACKET_ENTITIES 256 + +#define MAX_LATENT 32 +#define FRAGMENT_SIZE 1400 +#define MAX_FRAGMENTS 25000 +#define MAX_EVENT_QUEUE 64 + +#define MAX_FLOWS 2 +#define FLOW_OUTGOING 0 +#define FLOW_INCOMING 1 + +#define MAX_KV_LEN 127 // Max key/value length (with a NULL char) +#define MAX_INFO_STRING 256 // Key + value + 2 x slash + NULL +#define INFO_MAX_BUFFER_VALUES 4 + +#define FEVENT_ORIGIN (1<<0) // Event was invoked with stated origin +#define FEVENT_ANGLES (1<<1) // Event was invoked with stated angles + +#define HL_MODEL_MAX 512 +#define HL_GENERIC_MAX 512 +#define HL_EVENT_MAX 256 +#define HL_SOUND_MAX 512 +#define HL_SOUND_HASHLOOKUP_SIZE (HL_SOUND_MAX * 2 - 1) + +// Authentication types +#define AUTH_IDTYPE_UNKNOWN 0 +#define AUTH_IDTYPE_STEAM 1 +#define AUTH_IDTYPE_VALVE 2 +#define AUTH_IDTYPE_LOCAL 3 + +#define NUM_BASELINES 64 + +// 0 == regular, 1 == file stream +#define MAX_STREAMS 2 + +// Flow control bytes per second limits +#define MAX_RATE 20000 +#define MIN_RATE 1000 + +// Default data rate +#define DEFAULT_RATE (9999.0f) + +// This is the packet payload without any header bytes (which are attached for actual sending) +#define NET_MAX_PAYLOAD 3990 + +typedef enum netsrc_s +{ + NS_CLIENT, + NS_SERVER, + NS_MULTICAST + +} netsrc_t; + +typedef enum server_state_e +{ + ss_dead = 0, + ss_loading = 1, + ss_active = 2, + +} server_state_t; + +typedef enum +{ + NA_UNUSED, + NA_LOOPBACK, + NA_BROADCAST, + NA_IP, + NA_IPX, + NA_BROADCAST_IPX, + +} netadrtype_t; + +typedef struct netadr_s +{ + netadrtype_t type; + unsigned char ip[4]; + unsigned char ipx[10]; + unsigned short port; + +} netadr_t; + +typedef struct sizebuf_s +{ + const char* buffername; + uint16 flags; + byte* data; + int maxsize; + int cursize; + +} sizebuf_t; + +typedef struct flowstats_s +{ + int size; // Size of message sent/received + double time; // Time that message was sent/received + +} flowstats_t; + +typedef struct flow_s +{ + + flowstats_t stats[MAX_LATENT]; // Data for last MAX_LATENT messages + int current; // Current message position + double nextcompute; // Time when we should recompute k/sec data + float kbytespersec; // Average data + float avgkbytespersec; + +} flow_t; + +typedef struct fragbuf_s +{ + + fragbuf_s* next; // Next buffer in chain + int bufferid; // Id of this buffer + + sizebuf_t frag_message; // Message buffer where raw data is stored + byte frag_message_buf[FRAGMENT_SIZE]; // The actual data sits here + + qboolean isfile; // Is this a file buffer? + qboolean isbuffer; // Is this file buffer from memory ( custom decal, etc. ). + qboolean iscompressed; + + char filename[MAX_PATH]; // Name of the file to save out on remote host + int foffset; // Offset in file from which to read data + int size; // Size of data to read at that offset + +} fragbuf_t; + +typedef struct fragbufwaiting_s +{ + fragbufwaiting_s* next; // Next chain in waiting list + int fragbufcount; // Number of buffers in this chain + fragbuf_t* fragbufs; // The actual buffers + +} fragbufwaiting_t; + +typedef struct netchan_s +{ + netsrc_t sock; // NS_SERVER or NS_CLIENT, depending on channel. + netadr_t remote_address; // Address this channel is talking to. + + int player_slot; + + float last_received; // For timeouts. Time last message was received. + float connect_time; // Time when channel was connected. + + double rate; // Bandwidth choke, Bytes per second + double cleartime; // If realtime > cleartime, free to send next packet + + // Sequencing variables + int incoming_sequence; // Increasing count of sequence numbers + int incoming_acknowledged; // # of last outgoing message that has been ack'd. + int incoming_reliable_acknowledged;// Toggles T/F as reliable messages are received. + int incoming_reliable_sequence; // single bit, maintained local + int outgoing_sequence; // Message we are sending to remote + int reliable_sequence; // Whether the message contains reliable payload, single bit + int last_reliable_sequence; // Outgoing sequence number of last send that had reliable data + + void* connection_status; + int (*pfnNetchan_Blocksize)(void *); + + sizebuf_t message; // Staging and holding areas + byte message_buf[NET_MAX_PAYLOAD]; + + + int reliable_length; // Reliable message buffer. We keep adding to it until reliable is acknowledged. Then we clear it. + byte reliable_buf[NET_MAX_PAYLOAD]; + + fragbufwaiting_t* waitlist[MAX_STREAMS]; // Waiting list of buffered fragments to go onto queue. Multiple outgoing buffers can be queued in succession. + + int reliable_fragment[MAX_STREAMS]; // Is reliable waiting buf a fragment? + unsigned int reliable_fragid[MAX_STREAMS]; // Buffer id for each waiting fragment + + + fragbuf_t* fragbufs[MAX_STREAMS]; // The current fragment being set + int fragbufcount[MAX_STREAMS]; // The total number of fragments in this stream + + short int frag_startpos[MAX_STREAMS]; // Position in outgoing buffer where frag data starts + short int frag_length[MAX_STREAMS]; // Length of frag data in the buffer + + fragbuf_t* incomingbufs[MAX_STREAMS]; // Incoming fragments are stored here + qboolean incomingready[MAX_STREAMS]; // Set to true when incoming data is ready + + char incomingfilename[MAX_PATH]; // Only referenced by the FRAG_FILE_STREAM component + // Name of file being downloaded + void* tempbuffer; + int tempbuffersize; + + flow_t flow[MAX_FLOWS]; // Incoming and outgoing flow metrics + +} netchan_t; + +typedef struct packet_entities_s +{ + int num_entities; + unsigned char flags[32]; + entity_state_t* entities; + +} packet_entities_t; + + +typedef struct client_frame_s +{ + double senttime; + float ping_time; + clientdata_t clientdata; + weapon_data_t weapondata[64]; + packet_entities_t entities; + +} client_frame_t; + +typedef struct event_args_s +{ + int flags; + + int entindex; // Transmitted + + float origin[3]; + float angles[3]; + float velocity[3]; + + int ducking; + + float fparam1; + float fparam2; + + int iparam1; + int iparam2; + + int bparam1; + int bparam2; + +} event_args_t; + +struct event_info_s +{ + unsigned short index; // 0 implies not in use + + short packet_index; // Use data from state info for entity in delta_packet . -1 implies separate info based on event + short entity_index; // The edict this event is associated with + + float fire_time; // if non-zero, the time when the event should be fired ( fixed up on the client ) + + event_args_t args; + int flags; // Client only - Reliable or not, etc. +}; + +typedef struct event_state_s +{ + struct event_info_s ei[MAX_EVENT_QUEUE]; + +} event_state_t; + +typedef struct USERID_s +{ + int idtype; + uint64 m_SteamID; + unsigned int clientip; + +} USERID_t; + +typedef struct consistency_s +{ + char* filename; + int issound; + int orig_index; + int value; + int check_type; + float mins[3]; + float maxs[3]; + +} consistency_t; + +typedef struct event_s +{ + unsigned short index; + const char* filename; + int filesize; + const char* pszScript; + +} event_t; + +typedef struct extra_baselines_s +{ + int number; + int classname[NUM_BASELINES]; + entity_state_t baseline[NUM_BASELINES]; +} extra_baselines_t; + +typedef struct server_log_s +{ + qboolean active; + qboolean net_log_; + netadr_t net_address_; + void* file; + +} server_log_t; + +typedef struct server_stats_s +{ + int num_samples; + + int at_capacity; + int at_empty; + + float capacity_percent; + float empty_percent; + + int minusers; + int maxusers; + + float cumulative_occupancy; + float occupancy; + + int num_sessions; + float cumulative_sessiontime; + float average_session_len; + + float cumulative_latency; + float average_latency; + +} server_stats_t; + +typedef struct server_static_s +{ + qboolean dll_initialized; + + struct client_s* clients; + int maxclients; + int maxclientslimit; + + int spawncount; + int serverflags; + + server_log_t log; + + double next_cleartime; + double next_sampletime; + + server_stats_t stats; + qboolean isSecure; + +} server_static_t; + +typedef struct server_s +{ + qboolean active; + qboolean paused; + qboolean loadgame; + + double time; + double oldtime; + + int lastcheck; + double lastchecktime; + + char name[64]; + char oldname[64]; + char startspot[64]; + char modelname[64]; + + struct model_s* worldmodel; + CRC32_t worldmapCRC; + + unsigned char clientdllmd5[16]; + + resource_t resourcelist[1280]; + int num_resources; + + consistency_t consistency_list[512]; + int num_consistency; + + const char* model_precache[HL_MODEL_MAX]; + struct model_s* models[HL_MODEL_MAX]; + unsigned char model_precache_flags[HL_MODEL_MAX]; + struct event_s event_precache[HL_EVENT_MAX]; + + const char* sound_precache[HL_SOUND_MAX]; + short int sound_precache_hashedlookup[HL_SOUND_HASHLOOKUP_SIZE]; + qboolean sound_precache_hashedlookup_built; + + const char* generic_precache[HL_GENERIC_MAX]; + char generic_precache_names[HL_GENERIC_MAX][64]; + int num_generic_names; + + char* lightstyles[MAX_LIGHTSTYLES]; + + int num_edicts; + int max_edicts; + edict_t* edicts; + + struct entity_state_s* baselines; + extra_baselines_t* instance_baselines; + server_state_t state; + + sizebuf_t datagram; + unsigned char datagram_buf[4000]; + + sizebuf_t reliable_datagram; + unsigned char reliable_datagram_buf[4000]; + + sizebuf_t multicast; + unsigned char multicast_buf[1024]; + + sizebuf_t spectator; + unsigned char spectator_buf[1024]; + + sizebuf_t signon; + unsigned char signon_data[32768]; + +} server_t; + +typedef struct client_s +{ + qboolean active; + qboolean spawned; + qboolean fully_connected; + qboolean connected; + qboolean uploading; + qboolean hasusrmsgs; + qboolean has_force_unmodified; + + netchan_t netchan; + + int chokecount; + int delta_sequence; + + qboolean fakeclient; + qboolean proxy; + usercmd_t lastcmd; + + double connecttime; + double cmdtime; + double ignorecmdtime; + + float latency; + float packet_loss; + + double localtime; + double nextping; + double svtimebase; + + sizebuf_t datagram; + byte datagram_buf[4000]; + + double connection_started; + double next_messagetime; + double next_messageinterval; + qboolean send_message; + qboolean skip_message; + + client_frame_t* frames; + event_state_t events; + edict_t* edict; + const edict_t* pViewEntity; + int userid; + USERID_t network_userid; + + char userinfo[MAX_INFO_STRING]; + + qboolean sendinfo; + float sendinfo_time; + + char hashedcdkey[64]; + char name[32]; + int topcolor; + int bottomcolor; + int entityId; + + resource_t resourcesonhand; + resource_t resourcesneeded; + + FileHandle_t upload; + qboolean uploaddoneregistering; + customization_t customdata; + + int crcValue; + int lw; + int lc; + + char physinfo[MAX_INFO_STRING]; + + qboolean m_bLoopback; + uint32 m_VoiceStreams[2]; + double m_lastvoicetime; + int m_sendrescount; + +} client_t; + +#endif //_ENGINE_STRUCTS_H_ diff --git a/public/sdk/amxxmodule.cpp b/public/sdk/amxxmodule.cpp index ea4049b0..7528f376 100644 --- a/public/sdk/amxxmodule.cpp +++ b/public/sdk/amxxmodule.cpp @@ -3151,3 +3151,27 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) return len; } } + +template unsigned int strncopy(char *, const char *src, size_t count); +template unsigned int strncopy(cell *, const char *src, size_t count); +template unsigned int strncopy(cell *, const cell *src, size_t count); + +template +unsigned int strncopy(D *dest, const S *src, size_t count) +{ + if (!count) + { + return 0; + } + + D *start = dest; + + while ((*src) && (--count)) + { + *dest++ = *(unsigned char*)src++; + } + + *dest = '\0'; + + return (dest - start); +} diff --git a/public/sdk/amxxmodule.h b/public/sdk/amxxmodule.h index c9f9e75f..adf081e9 100644 --- a/public/sdk/amxxmodule.h +++ b/public/sdk/amxxmodule.h @@ -2509,5 +2509,6 @@ void Mem_Deallocator(const char *sourceFile, const unsigned int sourceLine, cons #endif //MEMORY_TEST size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); +template unsigned int strncopy(D *dest, const S *src, size_t count); #endif // #ifndef __AMXXMODULE_H__