Cstrike: cs_set/reset_user_model/team - Stagger user's info updates across multiple frames (bug 3134)

This commit is contained in:
Arkshine 2015-07-06 20:05:48 +02:00
parent aedde87f42
commit 8be119aa6a
13 changed files with 752 additions and 121 deletions

View File

@ -11,6 +11,12 @@
"Game Master" "Game Master"
{ {
"globalvars.engine.txt"
{
"engine" "engine_ds"
"engine" "engine_ls"
}
"entities.games/cstrike/offsets-cairtank.txt" "entities.games/cstrike/offsets-cairtank.txt"
{ {
"game" "cstrike" "game" "cstrike"

View File

@ -42,11 +42,16 @@ StringHashMap<int> ItemAliasList;
int TeamOffset; int TeamOffset;
int MenuOffset; int MenuOffset;
server_static_t *ServerStatic;
double *RealTime;
void InitializeHacks() void InitializeHacks()
{ {
CtrlDetours_ClientCommand(true); CtrlDetours_ClientCommand(true);
CtrlDetours_BuyCommands(true); CtrlDetours_BuyCommands(true);
CtrlDetours_Natives(true); CtrlDetours_Natives(true);
InitGlobalVars();
} }
void ShutdownHacks() void ShutdownHacks()
@ -301,8 +306,8 @@ void CtrlDetours_ClientCommand(bool set)
#endif #endif
ClientCommandDetour = DETOUR_CREATE_STATIC_FIXED(C_ClientCommand, base); ClientCommandDetour = DETOUR_CREATE_STATIC_FIXED(C_ClientCommand, base);
OffsetConfig->GetOffsetByClass("CBasePlayer", "m_iTeam", &TeamOffset); CommonConfig->GetOffsetByClass("CBasePlayer", "m_iTeam", &TeamOffset);
OffsetConfig->GetOffsetByClass("CBasePlayer", "m_iMenu", &MenuOffset); CommonConfig->GetOffsetByClass("CBasePlayer", "m_iMenu", &MenuOffset);
if (!ClientCommandDetour || !UseBotArgs || !BotArgs || !TeamOffset || !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<uintptr_t*>(reinterpret_cast<byte*>(g_engfuncs.pfnGetCurrentPlayer) + offset);
ServerStatic = reinterpret_cast<server_static_t*>(base - 4);
}
#else
if (CommonConfig->GetMemSig("svs", &address))
{
ServerStatic = reinterpret_cast<server_static_t*>(address);
}
#endif
if (CommonConfig->GetAddress("realtime", &address))
{
RealTime = reinterpret_cast<double*>(*reinterpret_cast<uintptr_t*>(address));
}
}

View File

@ -17,8 +17,10 @@
#include <amxxmodule.h> #include <amxxmodule.h>
#include <IGameConfigs.h> #include <IGameConfigs.h>
#include <CDetour/detours.h> #include <CDetour/detours.h>
#include <engine_strucs.h>
void InitializeHacks(); void InitializeHacks();
void InitGlobalVars();
void ShutdownHacks(); void ShutdownHacks();
void ToggleDetour_ClientCommands(bool enable); void ToggleDetour_ClientCommands(bool enable);
void ToggleDetour_BuyCommands(bool enable); void ToggleDetour_BuyCommands(bool enable);
@ -26,7 +28,7 @@ void ToggleDetour_BuyCommands(bool enable);
extern AMX_NATIVE_INFO CstrikeNatives[]; extern AMX_NATIVE_INFO CstrikeNatives[];
extern IGameConfig *MainConfig; extern IGameConfig *MainConfig;
extern IGameConfig *OffsetConfig; extern IGameConfig *CommonConfig;
extern int ForwardInternalCommand; extern int ForwardInternalCommand;
extern int ForwardOnBuy; extern int ForwardOnBuy;
@ -40,6 +42,10 @@ extern UTIL_FindEntityByStringFunc CS_UTIL_FindEntityByString;
extern CDetour *GiveDefaultItemsDetour; extern CDetour *GiveDefaultItemsDetour;
extern enginefuncs_t *g_pengfuncsTable; extern enginefuncs_t *g_pengfuncsTable;
extern DLL_FUNCTIONS *g_pFunctionTable;
extern bool NoKifesMode; extern bool NoKifesMode;
extern server_static_t *ServerStatic;
extern double *RealTime;
#endif // CSTRIKE_HACKS_H #endif // CSTRIKE_HACKS_H

View File

@ -18,9 +18,7 @@
#include "CstrikeUserMessages.h" #include "CstrikeUserMessages.h"
#include "CstrikeHLTypeConversion.h" #include "CstrikeHLTypeConversion.h"
#include <CDetour/detours.h> #include <CDetour/detours.h>
#include <am-vector.h>
CCstrikePlayer g_players[33];
int Zooming[33];
bool NoKifesMode = false; bool NoKifesMode = false;
@ -536,7 +534,7 @@ static cell AMX_NATIVE_CALL cs_set_user_team(AMX *amx, cell *params)
set_pdata<int>(pPlayer, m_iModelName, model); set_pdata<int>(pPlayer, m_iModelName, model);
} }
MDLL_ClientUserInfoChanged(pPlayer, GETINFOKEYBUFFER(pPlayer)); Players[index].ResetModel(pPlayer);
char teaminfo[32]; char teaminfo[32];
@ -863,17 +861,11 @@ static cell AMX_NATIVE_CALL cs_set_user_model(AMX *amx, cell *params)
return 0; return 0;
} }
char modelName[32];
int length; int length;
const char *newModel = MF_GetAmxString(amx, params[2], 0, &length);
strcpy(modelName, MF_GetAmxString(amx, params[2], 0, &length)); Players[index].SetModel(newModel);
Players[index].UpdateModel(MF_GetPlayerEdict(index));
g_players[index].SetModel(modelName);
g_players[index].SetModelled(true);
EnableMessageHooks();
SETCLIENTKEYVALUE(index, GETINFOKEYBUFFER(pPlayer), "model", const_cast<char*>(g_players[index].GetModel()));
return 1; return 1;
} }
@ -886,9 +878,7 @@ static cell AMX_NATIVE_CALL cs_reset_user_model(AMX *amx, cell *params)
CHECK_PLAYER(index); CHECK_PLAYER(index);
edict_t *pPlayer = MF_GetPlayerEdict(index); edict_t *pPlayer = MF_GetPlayerEdict(index);
g_players[index].SetModelled(false); Players[index].ResetModel(pPlayer);
MDLL_ClientUserInfoChanged(pPlayer, GETINFOKEYBUFFER(pPlayer));
return 1; return 1;
} }
@ -1317,7 +1307,7 @@ static cell AMX_NATIVE_CALL cs_set_user_zoom(AMX *amx, cell *params)
int mode = params[3]; int mode = params[3];
int weapon = *static_cast<int *>(MF_PlayerPropAddr(index, Player_CurrentWeapon)); int weapon = *static_cast<int *>(MF_PlayerPropAddr(index, Player_CurrentWeapon));
Zooming[index] = 0; Players[index].ResetZoom();
if (type == CS_RESET_ZOOM) if (type == CS_RESET_ZOOM)
{ {
@ -1365,7 +1355,7 @@ static cell AMX_NATIVE_CALL cs_set_user_zoom(AMX *amx, cell *params)
if (!mode) if (!mode)
{ {
Zooming[index] = value; Players[index].SetZoom(value);
EnableMessageHooks(); EnableMessageHooks();
} }
@ -1766,42 +1756,3 @@ AMX_NATIVE_INFO CstrikeNatives[] =
{nullptr, nullptr} {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);
}

View File

@ -12,47 +12,49 @@
// //
#include "CstrikePlayer.h" #include "CstrikePlayer.h"
#include <string.h> // strcpy()
////////////////////////////////////////////////////////////////////// CPlayer Players[33];
// Construction/Destruction ke::Vector<int> ModelsUpdateQueue;
//////////////////////////////////////////////////////////////////////
CCstrikePlayer::CCstrikePlayer() void ClientDisconnect(edict_t *pEntity)
{ {
modelled = false; int index = ENTINDEX(pEntity);
inspectModel = false;
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) if (!strcmp(key, "model") && Players[clientIndex].HasModel(value))
SetInspectModel(false); {
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) ServerStatic->clients[ModelsUpdateQueue.popCopy()].sendinfo = true;
{
strcpy(model, modelIn);
}
bool CCstrikePlayer::GetInspectModel() RETURN_META(MRES_IGNORED);
{
return inspectModel;
}
void CCstrikePlayer::SetInspectModel(bool inspectModelIn)
{
inspectModel = inspectModelIn;
} }

View File

@ -11,30 +11,125 @@
// Counter-Strike Module // Counter-Strike Module
// //
#if !defined(INCLUDED_CCSTRIKEPLAYER) #ifndef _CSTRIKE_PLAYER_H_
#define INCLUDED_CCSTRIKEPLAYER #define _CSTRIKE_PLAYER_H_
class CCstrikePlayer #include <amxxmodule.h>
#include "CstrikeUtils.h"
#include "CstrikeHacks.h"
#include <am-vector.h>
extern ke::Vector<int> 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: public:
CCstrikePlayer();
bool GetModelled(); CPlayer()
bool SetModelled(bool modelledIn); {
const char* GetModel(); ResetModel();
void SetModel(const char* modelIn); ResetZoom();
}
bool GetInspectModel(); bool HasModel(const char *model = nullptr)
void SetInspectModel(bool inspectModelIn); {
if (*m_Model != '\0')
{
if (model && *model)
{
return strcmp(m_Model, model) != 0;
}
return true;
}
private: return false;
bool inspectModel; }
bool modelled;
char model[32]; 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 CPlayer Players[33];
extern int Zooming[33];
#endif // !defined(INCLUDED_CCSTRIKEPLAYER) #endif // _CSTRIKE_PLAYER_H_

View File

@ -76,14 +76,15 @@ void OnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *p
if (msg_type == MessageIdSetFOV) if (msg_type == MessageIdSetFOV)
{ {
int index = ENTINDEX(pEntity); int index = ENTINDEX(pEntity);
int zoom = Players[index].GetZoom();
if (Zooming[index]) if (zoom)
{ {
GET_OFFSET_NO_ERROR("CBasePlayer", m_iFOV); GET_OFFSET_NO_ERROR("CBasePlayer", m_iFOV);
if (get_pdata<int>(pEntity, m_iFOV) != Zooming[index]) if (get_pdata<int>(pEntity, m_iFOV) != zoom)
{ {
set_pdata<int>(pEntity, m_iFOV, Zooming[index]); set_pdata<int>(pEntity, m_iFOV, zoom);
ShouldBlock = true; ShouldBlock = true;
ShouldBlockHLTV = 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); int index = ENTINDEX(pEntity);
if (Zooming[index]) if (Players[index].GetZoom())
Zooming[index] = 0; Players[index].ResetZoom();
if (g_players[index].GetModelled())
g_players[index].SetInspectModel(true);
} }
break; break;
} }

View File

@ -78,7 +78,7 @@ bool UTIL_CheckForPublic(const char *publicname);
static int member = -1; \ static int member = -1; \
if (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__);\ MF_LogError(amx, AMX_ERR_NATIVE, "Invalid %s offset. Native %s is disabled", #member, __FUNCTION__);\
return 0; \ return 0; \
@ -89,7 +89,7 @@ bool UTIL_CheckForPublic(const char *publicname);
static int member = -1; \ static int member = -1; \
if (member == -1) \ if (member == -1) \
{ \ { \
if (!OffsetConfig->GetOffsetByClass(classname, #member, &member) || member < 0)\ if (!CommonConfig->GetOffsetByClass(classname, #member, &member) || member < 0)\
{ \ { \
return; \ return; \
} \ } \

View File

@ -17,9 +17,10 @@
#include "CstrikeHacks.h" #include "CstrikeHacks.h"
#include "CstrikeHLTypeConversion.h" #include "CstrikeHLTypeConversion.h"
#include <IGameConfigs.h> #include <IGameConfigs.h>
#include "engine_strucs.h"
IGameConfig *MainConfig; IGameConfig *MainConfig;
IGameConfig *OffsetConfig; IGameConfig *CommonConfig;
IGameConfigManager *ConfigManager; IGameConfigManager *ConfigManager;
int AmxxCheckGame(const char *game) int AmxxCheckGame(const char *game)
@ -49,7 +50,7 @@ void OnAmxxAttach()
error[0] = '\0'; 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); MF_Log("Could not read common.games gamedata: %s", error);
return; return;
@ -79,12 +80,17 @@ void OnPluginsLoaded()
{ {
G_OffsetHandler = new OffsetHandler; 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() void OnAmxxDetach()
{ {
ConfigManager->CloseGameConfigFile(MainConfig); ConfigManager->CloseGameConfigFile(MainConfig);
ConfigManager->CloseGameConfigFile(OffsetConfig); ConfigManager->CloseGameConfigFile(CommonConfig);
ShutdownHacks(); ShutdownHacks();
} }

View File

@ -122,11 +122,11 @@
// #define FN_ClientKill ClientKill /* pfnClientKill() (wd) Player has typed "kill" */ // #define FN_ClientKill ClientKill /* pfnClientKill() (wd) Player has typed "kill" */
// #define FN_ClientPutInServer ClientPutInServer /* pfnClientPutInServer() (wd) Client is entering the game */ // #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_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_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_ServerDeactivate ServerDeactivate /* pfnServerDeactivate() (wd) Server is leaving the map (shutdown or changelevel); SDK2 */
// #define FN_PlayerPreThink PlayerPreThink /* pfnPlayerPreThink() */ // #define FN_PlayerPreThink PlayerPreThink /* pfnPlayerPreThink() */
#define FN_PlayerPostThink PlayerPostThink /* pfnPlayerPostThink() */ // #define FN_PlayerPostThink PlayerPostThink /* pfnPlayerPostThink() */
// #define FN_StartFrame StartFrame /* pfnStartFrame() */ // #define FN_StartFrame StartFrame /* pfnStartFrame() */
// #define FN_ParmsNewLevel ParmsNewLevel /* pfnParmsNewLevel() */ // #define FN_ParmsNewLevel ParmsNewLevel /* pfnParmsNewLevel() */
// #define FN_ParmsChangeLevel ParmsChangeLevel /* pfnParmsChangeLevel() */ // #define FN_ParmsChangeLevel ParmsChangeLevel /* pfnParmsChangeLevel() */

512
public/engine_strucs.h Normal file
View File

@ -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 <extdll.h>
#include <meta_api.h>
#include <osdep.h>
#include <FileSystem.h>
#include <entity_state.h>
#include <usercmd.h>
#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_

View File

@ -3151,3 +3151,27 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
return len; return len;
} }
} }
template unsigned int strncopy<char, char>(char *, const char *src, size_t count);
template unsigned int strncopy<cell, char>(cell *, const char *src, size_t count);
template unsigned int strncopy<cell, cell>(cell *, const cell *src, size_t count);
template <typename D, typename S>
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);
}

View File

@ -2509,5 +2509,6 @@ void Mem_Deallocator(const char *sourceFile, const unsigned int sourceLine, cons
#endif //MEMORY_TEST #endif //MEMORY_TEST
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
template <typename D, typename S> unsigned int strncopy(D *dest, const S *src, size_t count);
#endif // #ifndef __AMXXMODULE_H__ #endif // #ifndef __AMXXMODULE_H__