diff --git a/include/core.h b/include/core.h index d2f780a..27022c6 100644 --- a/include/core.h +++ b/include/core.h @@ -978,6 +978,9 @@ private: float m_buttonPushTime; // time to push the button float m_liftUsageTime; // time to use lift + int m_pingOffset[2]; + int m_ping[3]; // bots pings in scoreboard + Vector m_liftTravelPos; // lift travel position Vector m_moveAngles; // bot move angles bool m_moveToGoal; // bot currently moving to goal?? @@ -1288,11 +1291,15 @@ class BotManager : public Singleton { private: Array m_creationTab; // bot creation tab + Bot *m_bots[32]; // all available bots float m_maintainTime; // time to maintain bot creation quota + int m_lastWinner; // the team who won previous round int m_roundCount; // rounds passed + bool m_economicsGood[2]; // is team able to buy anything + bool m_deathMsgSent; // for fakeping protected: int CreateBot (String name, int skill, int personality, int team, int member); @@ -1340,6 +1347,14 @@ public: void CheckTeamEconomics (int team); static void CallGameEntity (entvars_t *vars); + + inline void SetDeathMsgState (bool sent) { m_deathMsgSent = sent; } + inline bool GetDeathMsgState (void) { return m_deathMsgSent; } + +public: + void CalculatePingOffsets (void); + void SendPingDataOffsets (edict_t *to); + void SendDeathMsgFix (void); }; // texts localizer @@ -1369,14 +1384,14 @@ public: ~NetworkMsg (void) { }; void Execute (void *p); - void Reset (void) { m_message = NETMSG_UNDEFINED; m_state = 0; m_bot = NULL; }; + inline void Reset (void) { m_message = NETMSG_UNDEFINED; m_state = 0; m_bot = NULL; }; void HandleMessageIfRequired (int messageType, int requiredType); - void SetMessage (int message) { m_message = message; } - void SetBot (Bot *bot) { m_bot = bot; } + inline void SetMessage (int message) { m_message = message; } + inline void SetBot (Bot *bot) { m_bot = bot; } - int GetId (int messageType) { return m_registerdMessages[messageType]; } - void SetId (int messageType, int messsageIdentifier) { m_registerdMessages[messageType] = messsageIdentifier; } + inline int GetId (int messageType) { return m_registerdMessages[messageType]; } + inline void SetId (int messageType, int messsageIdentifier) { m_registerdMessages[messageType] = messsageIdentifier; } }; // waypoint operation class @@ -1581,14 +1596,14 @@ public: return m_eptr->strval; } - inline const char *GetName(void) + inline const char *GetName (void) { return m_eptr->name; } - inline void SetFloat(float val) + inline void SetFloat (float val) { - g_engfuncs.pfnCVarSetFloat(m_eptr->name, val); + g_engfuncs.pfnCVarSetFloat (m_eptr->name, val); } inline void SetInt (int val) @@ -1603,12 +1618,10 @@ public: }; // prototypes of bot functions... -extern int GetMaxClients (void); extern int GetWeaponReturn (bool isString, const char *weaponAlias, int weaponIndex = -1); extern int GetTeam (edict_t *ent); extern float GetShootingConeDeviation (edict_t *ent, Vector *position); -extern float GetWorldTime (void); extern float GetWaveLength (const char *fileName); extern bool TryFileOpen (char *fileName); @@ -1667,6 +1680,16 @@ static inline bool IsNullString (const char *input) return *input == '\0'; } +static inline float GetWorldTime (void) +{ + return g_pGlobals->time; +} + +static inline int GetMaxClients (void) +{ + return g_pGlobals->maxClients; +} + // very global convars extern ConVar yb_jasonmode; extern ConVar yb_communication_type; diff --git a/project/yapb.rc b/project/yapb.rc index 4596a5e..0ad7c5b 100644 --- a/project/yapb.rc +++ b/project/yapb.rc @@ -26,7 +26,7 @@ #include <../include/resource.h> // generated by update tool -- do not edit -- -#define PRODUCT_BUILD_TOOL 3844 +#define PRODUCT_BUILD_TOOL 3846 VS_VERSION_INFO VERSIONINFO FILEVERSION PRODUCT_VERSION_DWORD, PRODUCT_BUILD_TOOL diff --git a/source/botmanager.cpp b/source/botmanager.cpp index 5836ac0..af991b5 100644 --- a/source/botmanager.cpp +++ b/source/botmanager.cpp @@ -803,8 +803,8 @@ Bot::Bot (edict_t *bot, int skill, int personality, int team, int member) SET_CLIENT_KEYVALUE (clientIndex, buffer, "_ah", "0"); SET_CLIENT_KEYVALUE (clientIndex, buffer, "_vgui_menus", "0"); - if (g_gameVersion != CSV_OLD) - SET_CLIENT_KEYVALUE (clientIndex, buffer, "*bot", const_cast (yb_latency_display.GetBool () ? "1" : "0")); + if (g_gameVersion != CSV_OLD && yb_latency_display.GetInt () == 1) + SET_CLIENT_KEYVALUE (clientIndex, buffer, "*bot", "1"); rejectReason[0] = 0; // reset the reject reason template string MDLL_ClientConnect (bot, "BOT", FormatBuffer ("127.0.0.%d", ENTINDEX (bot) + 100), rejectReason); @@ -827,7 +827,6 @@ Bot::Bot (edict_t *bot, int skill, int personality, int team, int member) m_moneyAmount = 0; m_logotypeIndex = g_randGen.Long (0, 5); - m_msecVal = static_cast (g_pGlobals->frametime * 1000.0); // assign how talkative this bot will be @@ -1255,3 +1254,138 @@ void Bot::StartGame (void) ChatMessage (CHAT_WELCOME); } } + +void BotManager::CalculatePingOffsets (void) +{ + if (yb_latency_display.GetInt () != 2) + return; + + int averagePing = 0; + int numHumans = 0; + + for (int i = 0; i < GetMaxClients (); i++) + { + edict_t *ent = INDEXENT (i + 1); + + if (!IsValidPlayer (ent)) + continue; + + numHumans++; + + int ping, loss; + PLAYER_CNX_STATS (ent, &ping, &loss); + + if (ping < 0 || ping > 100) + ping = g_randGen.Long (3, 15); + + averagePing += ping; + } + + if (numHumans > 0) + averagePing /= numHumans; + else + averagePing = g_randGen.Long (30, 40); + + for (int i = 0; i < GetMaxClients (); i++) + { + Bot *bot = GetBot (i); + + if (bot == NULL) + continue; + + int botPing = g_randGen.Long (averagePing - averagePing * 0.2f, averagePing + averagePing * 0.2f) + g_randGen.Long (bot->m_skill / 100 * 0.5, bot->m_skill / 100); + + if (botPing <= 5) + botPing = g_randGen.Long (10, 23); + else if (botPing > 100) + botPing = g_randGen.Long (30, 40); + + for (int j = 0; j < 2; j++) + { + for (bot->m_pingOffset[j] = 0; bot->m_pingOffset[j] < 4; bot->m_pingOffset[j]++) + { + if ((botPing - bot->m_pingOffset[j]) % 4 == 0) + { + bot->m_ping[j] = (botPing - bot->m_pingOffset[j]) / 4; + break; + } + } + } + bot->m_ping[2] = botPing; + } +} + +void BotManager::SendPingDataOffsets (edict_t *to) +{ + if (yb_latency_display.GetInt () != 2) + return; + + if (!IsValidPlayer (to) || IsValidBot (to)) + return; + + if (!((to->v.button & IN_SCORE) || (to->v.oldbuttons & IN_SCORE))) + return; + + static int sending; + sending = 0; + + // missing from sdk + static const int SVC_PINGS = 17; + + for (int i = 0; i < GetMaxClients (); i++) + { + Bot *bot = GetBot (i); + + if (bot == NULL) + continue; + + switch (sending) + { + case 0: + { + // start a new message + MESSAGE_BEGIN (MSG_ONE_UNRELIABLE, SVC_PINGS, NULL, to); + WRITE_BYTE ((m_bots[i]->m_pingOffset[sending] * 64) + (1 + 2 * i)); + WRITE_SHORT (m_bots[i]->m_ping[sending]); + + sending++; + } + case 1: + { + // append additional data + WRITE_BYTE ((m_bots[i]->m_pingOffset[sending] * 128) + (2 + 4 * i)); + WRITE_SHORT (m_bots[i]->m_ping[sending]); + + sending++; + } + case 2: + { + // append additional data and end message + WRITE_BYTE (4 + 8 * i); + WRITE_SHORT (m_bots[i]->m_ping[sending]); + WRITE_BYTE (0); + MESSAGE_END (); + + sending = 0; + } + } + } + + // end message if not yet sent + if (sending) + { + WRITE_BYTE (0); + MESSAGE_END (); + } +} + +void BotManager::SendDeathMsgFix (void) +{ + if (yb_latency_display.GetInt () == 2 && m_deathMsgSent) + { + m_deathMsgSent = false; + + for (int i = 0; i < GetMaxClients (); i++) + SendPingDataOffsets (g_clients[i].ent); + } +} \ No newline at end of file diff --git a/source/globals.cpp b/source/globals.cpp index b7e1e56..0adf3bb 100644 --- a/source/globals.cpp +++ b/source/globals.cpp @@ -134,7 +134,7 @@ metamod_funcs_t gMetaFunctionTable = NULL, // pfnGetNewDLLFunctions () NULL, // pfnGetNewDLLFunctions_Post () GetEngineFunctions, // pfnGetEngineFunctions () - NULL, // pfnGetEngineFunctions_Post () + GetEngineFunctions_Post, // pfnGetEngineFunctions_Post () }; // metamod plugin information diff --git a/source/interface.cpp b/source/interface.cpp index 77abd9b..d2c7ccc 100644 --- a/source/interface.cpp +++ b/source/interface.cpp @@ -1155,23 +1155,17 @@ int Spawn (edict_t *ent) return result; } -void Touch (edict_t *pentTouched, edict_t *pentOther) +void UpdateClientData (const struct edict_s *ent, int sendweapons, struct clientdata_s *cd) { - // this function is called when two entities' bounding boxes enter in collision. For example, - // when a player walks upon a gun, the player entity bounding box collides to the gun entity - // bounding box, and the result is that this function is called. It is used by the game for - // taking the appropriate action when such an event occurs (in our example, the player who - // is walking upon the gun will "pick it up"). Entities that "touch" others are usually - // entities having a velocity, as it is assumed that static entities (entities that don't - // move) will never touch anything. Hence, in our example, the pentTouched will be the gun - // (static entity), whereas the pentOther will be the player (as it is the one moving). When - // the two entities both have velocities, for example two players colliding, this function - // is called twice, once for each entity moving. + extern ConVar yb_latency_display; + + if (yb_latency_display.GetInt () == 2) + g_botManager->SendPingDataOffsets (const_cast (ent)); if (g_isMetamod) RETURN_META (MRES_IGNORED); - (*g_functionTable.pfnTouch) (pentTouched, pentOther); + (*g_functionTable.pfnUpdateClientData) (ent, sendweapons, cd); } void ClientPutInServer (edict_t *ent) @@ -2295,6 +2289,7 @@ void StartFrame (void) CheckWelcomeMessage (); } + g_botManager->SetDeathMsgState (false); if (secondTimer < GetWorldTime ()) { @@ -2333,6 +2328,7 @@ void StartFrame (void) if (csdm_active != NULL && csdm_active->value > 0) yb_csdm_mode.SetInt (mp_freeforall != NULL && mp_freeforall->value > 0 ? 2 : 1); } + g_botManager->CalculatePingOffsets (); } extern ConVar yb_danger_factor; @@ -2572,6 +2568,17 @@ void pfnMessageEnd (void) RETURN_META (MRES_IGNORED); MESSAGE_END (); + + // send latency fix + g_botManager->SendDeathMsgFix (); +} + +void pfnMessageEnd_Post (void) +{ + // send latency fix + g_botManager->SendDeathMsgFix (); + + RETURN_META (MRES_IGNORED); } void pfnWriteByte (int value) @@ -2953,7 +2960,7 @@ export int GetEntityAPI2 (gamefuncs_t *functionTable, int *interfaceVersion) functionTable->pfnServerDeactivate = ServerDeactivate; functionTable->pfnKeyValue = KeyValue; functionTable->pfnStartFrame = StartFrame; - functionTable->pfnTouch = Touch; + functionTable->pfnUpdateClientData = UpdateClientData; return TRUE; } @@ -3031,6 +3038,15 @@ export int GetEngineFunctions (enginefuncs_t *functionTable, int *interfaceVersi return TRUE; } +export int GetEngineFunctions_Post (enginefuncs_t *functionTable, int *interfaceVersion) +{ + memset (functionTable, 0, sizeof (enginefuncs_t)); + + functionTable->pfnMessageEnd = pfnMessageEnd_Post; + + return TRUE; +} + export int Server_GetBlendingInterface (int version, void **ppinterface, void *pstudio, float (*rotationmatrix)[3][4], float (*bonetransform)[128][3][4]) { // this function synchronizes the studio model animation blending interface (i.e, what parts diff --git a/source/netmsg.cpp b/source/netmsg.cpp index 7cac750..c7ae052 100644 --- a/source/netmsg.cpp +++ b/source/netmsg.cpp @@ -274,6 +274,8 @@ void NetworkMsg::Execute (void *p) break; case 2: + g_botManager->SetDeathMsgState (true); + if (killerIndex != 0 && killerIndex != victimIndex) { edict_t *killer = INDEXENT (killerIndex); diff --git a/source/support.cpp b/source/support.cpp index e8d06ef..01faf26 100644 --- a/source/support.cpp +++ b/source/support.cpp @@ -991,20 +991,6 @@ void ServerCommand (const char *format, ...) SERVER_COMMAND (FormatBuffer ("%s\n", string)); // execute command } -float GetWorldTime (void) -{ - // this function returns engine current time on this server - - return g_pGlobals->time; -} - -int GetMaxClients (void) -{ - // this function returns current players on server - - return g_pGlobals->maxClients; -} - const char *GetMapName (void) { // this function gets the map name and store it in the map_name global string variable.