From 535f29862141ef11e3a2a818d74fce0d46fbf3bf Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 31 Jul 2019 14:05:36 +0300 Subject: [PATCH] Fixed "meta unload" segfault. Added fake responces to server queries. Added dynamic link ents. (except android). --- include/crlib/cr-array.h | 2 +- include/crlib/cr-complete.h | 1 + include/crlib/cr-hook.h | 132 +++++++++++++++++++ include/crlib/cr-http.h | 27 +++- include/crlib/cr-lambda.h | 1 - include/crlib/cr-library.h | 36 +++++- include/crlib/cr-platform.h | 26 +++- include/engine.h | 134 +++++++++++++++++++- include/yapb.h | 24 +++- project/yapb.vcxproj | 2 + project/yapb.vcxproj.filters | 6 + source/android.cpp | 236 ++++++++++++++++++++++++++++++++++ source/engine.cpp | 45 ++++++- source/interface.cpp | 237 ++--------------------------------- source/manager.cpp | 26 +++- source/support.cpp | 74 +++++++++++ 16 files changed, 763 insertions(+), 246 deletions(-) create mode 100644 include/crlib/cr-hook.h create mode 100644 source/android.cpp diff --git a/include/crlib/cr-array.h b/include/crlib/cr-array.h index d6ab767..65060ab 100644 --- a/include/crlib/cr-array.h +++ b/include/crlib/cr-array.h @@ -205,7 +205,7 @@ public: if (index + count > m_capacity) { return false; } - for (size_t i = m_length; i < m_length + count; i++) { + for (size_t i = index; i < index + count; i++) { alloc.destruct (&m_data[i]); } m_length -= count; diff --git a/include/crlib/cr-complete.h b/include/crlib/cr-complete.h index 4bdd9d4..6a0bb9a 100644 --- a/include/crlib/cr-complete.h +++ b/include/crlib/cr-complete.h @@ -27,6 +27,7 @@ #include #include #include +#include CR_NAMESPACE_BEGIN diff --git a/include/crlib/cr-hook.h b/include/crlib/cr-hook.h new file mode 100644 index 0000000..2ec4e35 --- /dev/null +++ b/include/crlib/cr-hook.h @@ -0,0 +1,132 @@ +// +// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd"). +// Copyright (c) YaPB Development Team. +// +// This software is licensed under the BSD-style license. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://yapb.ru/license +// + +#pragma once + +#include + +#if !defined (CR_WINDOWS) +# include +#endif + +CR_NAMESPACE_BEGIN + +class SimpleHook : DenyCopying { +private: + enum : uint32 { + CodeLength = 12 + }; + +private: + bool m_patched; + + uint32 m_pageSize; + uint32 m_origFunc; + uint32 m_hookFunc; + + uint8 m_origBytes[CodeLength]; + uint8 m_hookBytes[CodeLength]; + +private: + void setPageSize () { +#if defined (CR_WINDOWS) + SYSTEM_INFO sysinfo; + GetSystemInfo (&sysinfo); + + m_pageSize = sysinfo.dwPageSize; +#else + m_pageSize = sysconf (_SC_PAGESIZE); +#endif + } + + inline void *align (void *address) { + return reinterpret_cast ((reinterpret_cast (address) & ~(m_pageSize - 1))); + } + + bool unprotect () { + auto orig = reinterpret_cast (m_origFunc); + +#if defined (CR_WINDOWS) + DWORD oldProt; + + FlushInstructionCache (GetCurrentProcess (), orig, m_pageSize); + return VirtualProtect (orig, m_pageSize, PAGE_EXECUTE_READWRITE, &oldProt); +#else + auto aligned = align (orig); + return !mprotect (aligned, m_pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); +#endif + } + +public: + SimpleHook () : m_patched (false), m_origFunc (0), m_hookFunc (0), m_pageSize (0) { + setPageSize (); + } + + ~SimpleHook () { + disable (); + } + +public: + bool patch (void *address, void *replacement) { + uint8 *ptr = reinterpret_cast (address); + + while (*reinterpret_cast (ptr) == 0x25ff) { + ptr = **reinterpret_cast ((ptr + 2)); + } + m_origFunc = reinterpret_cast (ptr); + + if (!m_origFunc) { + return false; + } + m_hookFunc = reinterpret_cast (replacement); + + m_hookBytes[0] = 0x68; + m_hookBytes[5] = 0xc3; + + *reinterpret_cast (&m_hookBytes[1]) = m_hookFunc; + + if (unprotect ()) { + memcpy (m_origBytes, reinterpret_cast (m_origFunc), CodeLength); + return enable (); + } + return false; + } + + bool enable () { + if (m_patched) { + return false; + } + m_patched = true; + + if (unprotect ()) { + memcpy (reinterpret_cast (m_origFunc), m_hookBytes, CodeLength); + return true; + } + return false; + } + + bool disable () { + if (!m_patched) { + return false; + } + m_patched = false; + + if (unprotect ()) { + memcpy (reinterpret_cast (m_origFunc), m_origBytes, CodeLength); + return true; + } + return false; + } + + bool enabled () const { + return m_patched; + } +}; + +CR_NAMESPACE_END \ No newline at end of file diff --git a/include/crlib/cr-http.h b/include/crlib/cr-http.h index 55f7677..69d5914 100644 --- a/include/crlib/cr-http.h +++ b/include/crlib/cr-http.h @@ -20,14 +20,13 @@ # include # include # include +# include # include # include # include # include # include #elif defined (CR_WINDOWS) -# define WIN32_LEAN_AND_MEAN -# include # include #endif @@ -138,6 +137,30 @@ public: template int32 recv (U *buffer, int32 length) { return ::recv (m_socket, reinterpret_cast (buffer), length, 0); } + +public: + static int32 CR_STDCALL sendto (int socket, const void *message, size_t length, int flags, const struct sockaddr *dest, int32 destLength) { +#if defined (CR_WINDOWS) + WSABUF buffer = { length, const_cast (reinterpret_cast (message)) }; + DWORD sendLength = 0; + + if (WSASendTo (socket, &buffer, 1, &sendLength, flags, dest, destLength, NULL, NULL) == SOCKET_ERROR) { + errno = WSAGetLastError (); + return -1; + } + return static_cast (sendLength); +#else + iovec iov = { const_cast (message), length }; + msghdr msg = { 0, }; + + msg.msg_name = reinterpret_cast (const_cast (dest)); + msg.msg_namelen = destLength; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + return sendmsg (socket, &msg, flags); +#endif + } }; namespace detail { diff --git a/include/crlib/cr-lambda.h b/include/crlib/cr-lambda.h index f29efd0..de9aa89 100644 --- a/include/crlib/cr-lambda.h +++ b/include/crlib/cr-lambda.h @@ -169,5 +169,4 @@ public: } }; - CR_NAMESPACE_END \ No newline at end of file diff --git a/include/crlib/cr-library.h b/include/crlib/cr-library.h index d008206..600ed8b 100644 --- a/include/crlib/cr-library.h +++ b/include/crlib/cr-library.h @@ -46,8 +46,8 @@ public: } public: - inline bool load (const String &file) noexcept { -#ifdef CR_WINDOWS + bool load (const String &file) noexcept { +#if defined (CR_WINDOWS) m_handle = LoadLibraryA (file.chars ()); #else m_handle = dlopen (file.chars (), RTLD_NOW); @@ -55,15 +55,39 @@ public: return m_handle != nullptr; } + bool locate (void *address) { +#if defined (CR_WINDOWS) + MEMORY_BASIC_INFORMATION mbi; + + if (!VirtualQuery (address, &mbi, sizeof (mbi))) { + return false; + } + + if (mbi.State != MEM_COMMIT) { + return false; + } + m_handle = reinterpret_cast (mbi.AllocationBase); +#else + Dl_info dli; + memset (&dli, 0, sizeof (dli)); + + if (dladdr (address, &dli)) { + return load (dli.dli_fname); + } +#endif + return m_handle != nullptr; + } + void unload () noexcept { if (!*this) { return; } -#ifdef CR_WINDOWS +#if defined (CR_WINDOWS) FreeLibrary (static_cast (m_handle)); #else dlclose (m_handle); #endif + m_handle = nullptr; } template R resolve (const char *function) const { @@ -72,7 +96,7 @@ public: } return reinterpret_cast ( -#ifdef CR_WINDOWS +#if defined (CR_WINDOWS) GetProcAddress (static_cast (m_handle), function) #else dlsym (m_handle, function) @@ -80,6 +104,10 @@ public: ); } + void *handle () const { + return m_handle; + } + public: explicit operator bool () const { return m_handle != nullptr; diff --git a/include/crlib/cr-platform.h b/include/crlib/cr-platform.h index c1668d8..9ca67a7 100644 --- a/include/crlib/cr-platform.h +++ b/include/crlib/cr-platform.h @@ -34,11 +34,13 @@ CR_NAMESPACE_BEGIN # define CR_CXX_CLANG #endif -// configure export macros +// configure macroses #if defined(CR_WINDOWS) # define CR_EXPORT extern "C" __declspec (dllexport) +# define CR_STDCALL __stdcall #elif defined(CR_LINUX) || defined(CR_OSX) # define CR_EXPORT extern "C" __attribute__((visibility("default"))) +# define CR_STDCALL #else # error "Can't configure export macros. Compiler unrecognized." #endif @@ -56,11 +58,14 @@ CR_NAMESPACE_BEGIN CR_NAMESPACE_END #if defined(CR_WINDOWS) +# define WIN32_LEAN_AND_MEAN +# include # include #else # include # include # include +# include #endif #include @@ -154,6 +159,25 @@ struct Platform : public Singleton { #endif } + float seconds () { +#if defined(CR_WINDOWS) + LARGE_INTEGER count, freq; + + count.QuadPart = 0; + freq.QuadPart = 0; + + QueryPerformanceFrequency (&freq); + QueryPerformanceCounter (&count); + + return static_cast (count.QuadPart) / static_cast (freq.QuadPart); +#else + timeval tv; + gettimeofday (&tv, NULL); + + return static_cast (tv.tv_sec) + (static_cast (tv.tv_usec)) / 1000000.0; +#endif + } + void abort (const char *msg = "OUT OF MEMORY!") noexcept { fprintf (stderr, "%s\n", msg); diff --git a/include/engine.h b/include/engine.h index f011b8b..df2d994 100644 --- a/include/engine.h +++ b/include/engine.h @@ -165,7 +165,7 @@ public: void precache (); // initialize levels - void levelInitialize (edict_t *ents, int max); + void levelInitialize (edict_t *entities, int max); // display world line void drawLine (edict_t *ent, const Vector &start, const Vector &end, int width, int noise, const Color &color, int brightness, int speed, int life, DrawLine type = DrawLine::Simple); @@ -304,8 +304,8 @@ public: int getTeam (edict_t *ent); // adds translation pair from config - void addTranslation (const String &original, const String &translated) { - m_language.push (original, translated); + void addTranslation (const String &m_origBytes, const String &translated) { + m_language.push (m_origBytes, translated); } // clear the translation table @@ -572,4 +572,132 @@ public: void enableAnimation (bool enable) { m_doAnimation = enable; } +}; + +// simple handler for parsing and rewriting queries (fake queries) +class QueryBuffer { + SmallArray m_buffer; + size_t m_cursor; + +public: + QueryBuffer (const uint8 *msg, size_t length, size_t shift) : m_cursor (0) { + m_buffer.insert (0, msg, length); + m_cursor += shift; + } + +public: + template T read () { + T result; + auto size = sizeof (T); + + if (m_cursor + size > m_buffer.length ()) { + return 0; + } + + memcpy (&result, m_buffer.data () + m_cursor, size); + m_cursor += size; + + return result; + } + + // must be called right after read + template void write (T value) { + auto size = sizeof (value); + memcpy (m_buffer.data () + m_cursor - size, &value, size); + } + + template void skip () { + auto size = sizeof (T); + + if (m_cursor + size > m_buffer.length ()) { + return; + } + m_cursor += size; + } + + void skipString () { + if (m_buffer.length () < m_cursor) { + return; + } + for (; m_cursor < m_buffer.length () && m_buffer[m_cursor] != '\0'; ++m_cursor) { } + ++m_cursor; + } + + void shiftToEnd () { + m_cursor = m_buffer.length (); + } + +public: + Twin data () { + return { m_buffer.data (), m_buffer.length () }; + } +}; + +// for android +#if defined (CR_ANDROID) + extern "C" void player (entvars_t *pev); +#endif + +class DynamicEntityLink : public Singleton { +private: +#if defined (CR_WINDOWS) +# define CastType HMODULE +# define LookupSymbol GetProcAddress +#else +# define CastType void * +# define LookupSymbol dlsym +#endif + +private: + using Handle = void *; + using Name = const char *; + +private: + template struct FunctionHash { + uint32 operator () (Name key) const { + char *str = const_cast (key); + uint32 hash = 0; + + while (*str++) { + hash = ((hash << 5) + hash) + *str; + } + return hash; + } + }; + +private: + SharedLibrary m_self; + SimpleHook m_dlsym; + Dictionary > m_exports; + +public: + DynamicEntityLink () = default; + + ~DynamicEntityLink () { + m_dlsym.disable (); + } +public: + Handle search (Handle module, Name function); + +public: + void initialize () { + if (plat.isAndroid) { + return; + } + m_dlsym.patch (reinterpret_cast (&LookupSymbol), reinterpret_cast (&DynamicEntityLink::replacement)); + m_self.locate (&engfuncs); + } + + EntityFunction getPlayerFunction () { +#if defined (CR_ANDROID) + return player; +#else + return reinterpret_cast (search (Game::get ().lib ().handle (), "player")); +#endif + } + +public: + static Handle CR_STDCALL replacement (Handle module, Name function) { + return DynamicEntityLink::get ().search (module, function); + } }; \ No newline at end of file diff --git a/include/yapb.h b/include/yapb.h index 45071a0..23cd693 100644 --- a/include/yapb.h +++ b/include/yapb.h @@ -8,7 +8,7 @@ // #pragma once - +#define _CRTDBG_MAP_ALLOC #include #include @@ -846,6 +846,8 @@ private: float m_oldCombatDesire; // holds old desire for filtering float m_avoidTime; // time to avoid players around float m_itemCheckTime; // time next search for items needs to be done + float m_joinServerTime; // time when bot joined the game + float m_playServerTime; // time bot spent in the game bool m_moveToGoal; // bot currently moving to goal?? bool m_isStuck; // bot is stuck @@ -1322,6 +1324,7 @@ public: int getHumansCount (bool ignoreSpectators = false); int getAliveHumansCount (); int getBotCount (); + float getConnectionTime (int botId); void setBombPlanted (bool isPlanted); void slowFrame (); @@ -1894,6 +1897,8 @@ private: SmallArray m_clients; SmallArray > m_tags; + SimpleHook m_sendToHook; + public: BotUtils (); ~BotUtils () = default; @@ -1968,6 +1973,9 @@ public: // send modified pings to all the clients void sendPings (edict_t *to); + // installs the sendto function intreception + void installSendTo (); + public: // re-show welcome after changelevel ? @@ -1990,6 +1998,16 @@ public: return m_clients[index]; } + // disables send hook + bool disableSendTo () { + return m_sendToHook.disable (); + } + + // enables send hook + bool enableSendTo () { + return m_sendToHook.enable (); + } + // checks if string is not empty bool isEmptyStr (const char *input) const { if (input == nullptr) { @@ -1997,6 +2015,9 @@ public: } return *input == '\0'; } + +public: + static int32 CR_STDCALL sendTo (int socket, const void *message, size_t length, int flags, const struct sockaddr *dest, int destLength); }; // bot command manager @@ -2185,6 +2206,7 @@ static auto &util = BotUtils::get (); static auto &ctrl = BotControl::get (); static auto &game = Game::get (); static auto &illum = LightMeasure::get (); +static auto &ents = DynamicEntityLink::get (); // very global convars extern ConVar yb_jasonmode; diff --git a/project/yapb.vcxproj b/project/yapb.vcxproj index 17edc5f..46c3d3a 100644 --- a/project/yapb.vcxproj +++ b/project/yapb.vcxproj @@ -19,6 +19,7 @@ + @@ -44,6 +45,7 @@ + diff --git a/project/yapb.vcxproj.filters b/project/yapb.vcxproj.filters index 123e8a9..69eb41d 100644 --- a/project/yapb.vcxproj.filters +++ b/project/yapb.vcxproj.filters @@ -111,6 +111,9 @@ include\crlib + + include\crlib + @@ -143,6 +146,9 @@ source + + source + diff --git a/source/android.cpp b/source/android.cpp new file mode 100644 index 0000000..ff55027 --- /dev/null +++ b/source/android.cpp @@ -0,0 +1,236 @@ +// +// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd"). +// Copyright (c) YaPB Development Team. +// +// This software is licensed under the BSD-style license. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://yapb.ru/license +// + +#include + +// until hook code will be compatible with ARM, it's here +#if defined (CR_ANDROID) +void android_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev) { + if (!addr) { + addr = game.lib ().resolve (name); + } + if (!addr) { + return; + } + addr (pev); +} + +#define LINK_ENTITY(entityName) \ + CR_EXPORT void entityName (entvars_t *pev) { \ + static EntityFunction addr; \ + android_LinkEntity (addr, #entityName, pev); \ + } +#else +#define LINK_ENTITY(entityName) +#endif + +// entities in counter-strike... +LINK_ENTITY (DelayedUse) +LINK_ENTITY (ambient_generic) +LINK_ENTITY (ammo_338magnum) +LINK_ENTITY (ammo_357sig) +LINK_ENTITY (ammo_45acp) +LINK_ENTITY (ammo_50ae) +LINK_ENTITY (ammo_556nato) +LINK_ENTITY (ammo_556natobox) +LINK_ENTITY (ammo_57mm) +LINK_ENTITY (ammo_762nato) +LINK_ENTITY (ammo_9mm) +LINK_ENTITY (ammo_buckshot) +LINK_ENTITY (armoury_entity) +LINK_ENTITY (beam) +LINK_ENTITY (bodyque) +LINK_ENTITY (button_target) +LINK_ENTITY (cycler) +LINK_ENTITY (cycler_prdroid) +LINK_ENTITY (cycler_sprite) +LINK_ENTITY (cycler_weapon) +LINK_ENTITY (cycler_wreckage) +LINK_ENTITY (env_beam) +LINK_ENTITY (env_beverage) +LINK_ENTITY (env_blood) +LINK_ENTITY (env_bombglow) +LINK_ENTITY (env_bubbles) +LINK_ENTITY (env_debris) +LINK_ENTITY (env_explosion) +LINK_ENTITY (env_fade) +LINK_ENTITY (env_funnel) +LINK_ENTITY (env_global) +LINK_ENTITY (env_glow) +LINK_ENTITY (env_laser) +LINK_ENTITY (env_lightning) +LINK_ENTITY (env_message) +LINK_ENTITY (env_rain) +LINK_ENTITY (env_render) +LINK_ENTITY (env_shake) +LINK_ENTITY (env_shooter) +LINK_ENTITY (env_snow) +LINK_ENTITY (env_sound) +LINK_ENTITY (env_spark) +LINK_ENTITY (env_sprite) +LINK_ENTITY (fireanddie) +LINK_ENTITY (func_bomb_target) +LINK_ENTITY (func_breakable) +LINK_ENTITY (func_button) +LINK_ENTITY (func_buyzone) +LINK_ENTITY (func_conveyor) +LINK_ENTITY (func_door) +LINK_ENTITY (func_door_rotating) +LINK_ENTITY (func_escapezone) +LINK_ENTITY (func_friction) +LINK_ENTITY (func_grencatch) +LINK_ENTITY (func_guntarget) +LINK_ENTITY (func_healthcharger) +LINK_ENTITY (func_hostage_rescue) +LINK_ENTITY (func_illusionary) +LINK_ENTITY (func_ladder) +LINK_ENTITY (func_monsterclip) +LINK_ENTITY (func_mortar_field) +LINK_ENTITY (func_pendulum) +LINK_ENTITY (func_plat) +LINK_ENTITY (func_platrot) +LINK_ENTITY (func_pushable) +LINK_ENTITY (func_rain) +LINK_ENTITY (func_recharge) +LINK_ENTITY (func_rot_button) +LINK_ENTITY (func_rotating) +LINK_ENTITY (func_snow) +LINK_ENTITY (func_tank) +LINK_ENTITY (func_tankcontrols) +LINK_ENTITY (func_tanklaser) +LINK_ENTITY (func_tankmortar) +LINK_ENTITY (func_tankrocket) +LINK_ENTITY (func_trackautochange) +LINK_ENTITY (func_trackchange) +LINK_ENTITY (func_tracktrain) +LINK_ENTITY (func_train) +LINK_ENTITY (func_traincontrols) +LINK_ENTITY (func_vehicle) +LINK_ENTITY (func_vehiclecontrols) +LINK_ENTITY (func_vip_safetyzone) +LINK_ENTITY (func_wall) +LINK_ENTITY (func_wall_toggle) +LINK_ENTITY (func_water) +LINK_ENTITY (func_weaponcheck) +LINK_ENTITY (game_counter) +LINK_ENTITY (game_counter_set) +LINK_ENTITY (game_end) +LINK_ENTITY (game_player_equip) +LINK_ENTITY (game_player_hurt) +LINK_ENTITY (game_player_team) +LINK_ENTITY (game_score) +LINK_ENTITY (game_team_master) +LINK_ENTITY (game_team_set) +LINK_ENTITY (game_text) +LINK_ENTITY (game_zone_player) +LINK_ENTITY (gibshooter) +LINK_ENTITY (grenade) +LINK_ENTITY (hostage_entity) +LINK_ENTITY (info_bomb_target) +LINK_ENTITY (info_hostage_rescue) +LINK_ENTITY (info_intermission) +LINK_ENTITY (info_landmark) +LINK_ENTITY (info_map_parameters) +LINK_ENTITY (info_null) +LINK_ENTITY (info_player_deathmatch) +LINK_ENTITY (info_player_start) +LINK_ENTITY (info_target) +LINK_ENTITY (info_teleport_destination) +LINK_ENTITY (info_vip_start) +LINK_ENTITY (infodecal) +LINK_ENTITY (item_airtank) +LINK_ENTITY (item_airbox) +LINK_ENTITY (item_antidote) +LINK_ENTITY (item_assaultsuit) +LINK_ENTITY (item_battery) +LINK_ENTITY (item_healthkit) +LINK_ENTITY (item_kevlar) +LINK_ENTITY (item_longjump) +LINK_ENTITY (item_security) +LINK_ENTITY (item_sodacan) +LINK_ENTITY (item_suit) +LINK_ENTITY (item_thighpack) +LINK_ENTITY (light) +LINK_ENTITY (light_environment) +LINK_ENTITY (light_spot) +LINK_ENTITY (momentary_door) +LINK_ENTITY (momentary_rot_button) +LINK_ENTITY (monster_hevsuit_dead) +LINK_ENTITY (monster_mortar) +LINK_ENTITY (monster_scientist) +LINK_ENTITY (multi_manager) +LINK_ENTITY (multisource) +LINK_ENTITY (path_corner) +LINK_ENTITY (path_track) +LINK_ENTITY (player) +LINK_ENTITY (player_loadsaved) +LINK_ENTITY (player_weaponstrip) +LINK_ENTITY (point_clientcommand) +LINK_ENTITY (point_servercommand) +LINK_ENTITY (soundent) +LINK_ENTITY (spark_shower) +LINK_ENTITY (speaker) +LINK_ENTITY (target_cdaudio) +LINK_ENTITY (test_effect) +LINK_ENTITY (trigger) +LINK_ENTITY (trigger_auto) +LINK_ENTITY (trigger_autosave) +LINK_ENTITY (trigger_camera) +LINK_ENTITY (trigger_cdaudio) +LINK_ENTITY (trigger_changelevel) +LINK_ENTITY (trigger_changetarget) +LINK_ENTITY (trigger_counter) +LINK_ENTITY (trigger_endsection) +LINK_ENTITY (trigger_gravity) +LINK_ENTITY (trigger_hurt) +LINK_ENTITY (trigger_monsterjump) +LINK_ENTITY (trigger_multiple) +LINK_ENTITY (trigger_once) +LINK_ENTITY (trigger_push) +LINK_ENTITY (trigger_random) +LINK_ENTITY (trigger_random_time) +LINK_ENTITY (trigger_random_unique) +LINK_ENTITY (trigger_relay) +LINK_ENTITY (trigger_setorigin) +LINK_ENTITY (trigger_teleport) +LINK_ENTITY (trigger_transition) +LINK_ENTITY (weapon_ak47) +LINK_ENTITY (weapon_aug) +LINK_ENTITY (weapon_awp) +LINK_ENTITY (weapon_c4) +LINK_ENTITY (weapon_deagle) +LINK_ENTITY (weapon_elite) +LINK_ENTITY (weapon_famas) +LINK_ENTITY (weapon_fiveseven) +LINK_ENTITY (weapon_flashbang) +LINK_ENTITY (weapon_g3sg1) +LINK_ENTITY (weapon_galil) +LINK_ENTITY (weapon_glock18) +LINK_ENTITY (weapon_hegrenade) +LINK_ENTITY (weapon_knife) +LINK_ENTITY (weapon_m249) +LINK_ENTITY (weapon_m3) +LINK_ENTITY (weapon_m4a1) +LINK_ENTITY (weapon_mac10) +LINK_ENTITY (weapon_mp5navy) +LINK_ENTITY (weapon_p228) +LINK_ENTITY (weapon_p90) +LINK_ENTITY (weapon_scout) +LINK_ENTITY (weapon_sg550) +LINK_ENTITY (weapon_sg552) +LINK_ENTITY (weapon_shield) +LINK_ENTITY (weapon_shieldgun) +LINK_ENTITY (weapon_smokegrenade) +LINK_ENTITY (weapon_tmp) +LINK_ENTITY (weapon_ump45) +LINK_ENTITY (weapon_usp) +LINK_ENTITY (weapon_xm1014) +LINK_ENTITY (weaponbox) +LINK_ENTITY (world_items) +LINK_ENTITY (worldspawn) diff --git a/source/engine.cpp b/source/engine.cpp index 91add79..324a129 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -64,7 +64,7 @@ void Game::precache () { registerCvars (true); } -void Game::levelInitialize (edict_t *ents, int max) { +void Game::levelInitialize (edict_t *entities, int max) { // this function precaches needed models and initialize class variables m_spawnCount[Team::CT] = 0; @@ -72,7 +72,7 @@ void Game::levelInitialize (edict_t *ents, int max) { // go thru the all entities on map, and do whatever we're want for (int i = 0; i < max; ++i) { - auto ent = ents + i; + auto ent = entities + i; // only valid entities if (!ent || ent->free || ent->v.classname == 0) { @@ -85,6 +85,9 @@ void Game::levelInitialize (edict_t *ents, int max) { // initialize some structures bots.initRound (); + + // install the sendto hook to fake queries + util.installSendTo (); } else if (strcmp (classname, "player_weaponstrip") == 0) { if ((is (GameFlags::Legacy)) && (STRING (ent->v.target))[0] == '\0') { @@ -1479,3 +1482,41 @@ float LightMeasure::getLightLevel (const Vector &point) { float LightMeasure::getSkyColor () { return static_cast (Color (sv_skycolor_r.int_ (), sv_skycolor_g.int_ (), sv_skycolor_b.int_ ()).avg ()); } + +DynamicEntityLink::Handle DynamicEntityLink::search (Handle module, Name function) { + const auto lookup = [&] (Handle handle) { + Handle ret = nullptr; + + if (m_dlsym.disable ()) { + ret = LookupSymbol (reinterpret_cast (handle), function); + m_dlsym.enable (); + } + return ret; + }; + static const auto &gamedll = game.lib (); + static const auto &yapb = m_self; + + // if requested module is yapb, put in cache the looked up symbol + if (yapb.handle () == module) { + if (m_exports.exists (function)) { + return m_exports[function]; + } + auto address = lookup (yapb.handle ()); + + if (!address) { + auto gameAddress = lookup (gamedll.handle ()); + + if (gameAddress) { + m_exports[function] = gameAddress; + } + } + else { + m_exports[function] = address; + } + + if (m_exports.exists (function)) { + return m_exports[function]; + } + } + return lookup (module); +} diff --git a/source/interface.cpp b/source/interface.cpp index 4770ae6..7a12539 100644 --- a/source/interface.cpp +++ b/source/interface.cpp @@ -115,7 +115,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) { // register logger logger.initialize (strings.format ("%slogs/yapb.log", graph.getDataDirectory (false)), [] (const char *msg) { game.print (msg); - }); + }); conf.initWeapons (); @@ -961,6 +961,7 @@ CR_EXPORT int Meta_Detach (PLUG_LOADTIME, PL_UNLOAD_REASON) { // save collected experience on shutdown graph.savePractice (); + util.disableSendTo (); return TRUE; } @@ -980,15 +981,13 @@ CR_EXPORT void Meta_Init () { # endif # pragma comment(linker, "/SECTION:.data,RW") # endif -# define DLL_STDCALL __stdcall # if defined(CR_CXX_MSVC) && !defined(CR_ARCH_X64) -# define DLL_GIVEFNPTRSTODLL extern "C" void DLL_STDCALL +# define DLL_GIVEFNPTRSTODLL extern "C" void CR_STDCALL # elif defined(CR_CXX_CLANG) || defined(CR_ARCH_X64) -# define DLL_GIVEFNPTRSTODLL CR_EXPORT void DLL_STDCALL +# define DLL_GIVEFNPTRSTODLL CR_EXPORT void CR_STDCALL # endif #elif defined(CR_LINUX) || defined (CR_OSX) || defined (CR_ANDROID) # define DLL_GIVEFNPTRSTODLL CR_EXPORT void -# define DLL_STDCALL #endif DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t *pGlobals) { @@ -1010,237 +1009,21 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t if (game.postload ()) { return; } - auto api_GiveFnptrsToDll = game.lib ().resolve (__FUNCTION__); + auto api_GiveFnptrsToDll = game.lib ().resolve (__FUNCTION__); if (!api_GiveFnptrsToDll) { logger.fatal ("Could not resolve symbol \"%s\" in the game dll.", __FUNCTION__); } GetEngineFunctions (functionTable, nullptr); + // initialize dynamic linkents + ents.initialize (); + // give the engine functions to the other DLL... if (api_GiveFnptrsToDll) { api_GiveFnptrsToDll (functionTable, pGlobals); } } -void helper_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev) { - if (addr == nullptr) { - addr = game.lib ().resolve (name); - } - - if (addr == nullptr) { - return; - } - addr (pev); -} - -#define LINK_ENTITY(entityName) \ - CR_EXPORT void entityName (entvars_t *pev) { \ - static EntityFunction addr; \ - helper_LinkEntity (addr, #entityName, pev); \ - } - -// entities in counter-strike... -LINK_ENTITY (DelayedUse) -LINK_ENTITY (ambient_generic) -LINK_ENTITY (ammo_338magnum) -LINK_ENTITY (ammo_357sig) -LINK_ENTITY (ammo_45acp) -LINK_ENTITY (ammo_50ae) -LINK_ENTITY (ammo_556nato) -LINK_ENTITY (ammo_556natobox) -LINK_ENTITY (ammo_57mm) -LINK_ENTITY (ammo_762nato) -LINK_ENTITY (ammo_9mm) -LINK_ENTITY (ammo_buckshot) -LINK_ENTITY (armoury_entity) -LINK_ENTITY (beam) -LINK_ENTITY (bodyque) -LINK_ENTITY (button_target) -LINK_ENTITY (cycler) -LINK_ENTITY (cycler_prdroid) -LINK_ENTITY (cycler_sprite) -LINK_ENTITY (cycler_weapon) -LINK_ENTITY (cycler_wreckage) -LINK_ENTITY (env_beam) -LINK_ENTITY (env_beverage) -LINK_ENTITY (env_blood) -LINK_ENTITY (env_bombglow) -LINK_ENTITY (env_bubbles) -LINK_ENTITY (env_debris) -LINK_ENTITY (env_explosion) -LINK_ENTITY (env_fade) -LINK_ENTITY (env_funnel) -LINK_ENTITY (env_global) -LINK_ENTITY (env_glow) -LINK_ENTITY (env_laser) -LINK_ENTITY (env_lightning) -LINK_ENTITY (env_message) -LINK_ENTITY (env_rain) -LINK_ENTITY (env_render) -LINK_ENTITY (env_shake) -LINK_ENTITY (env_shooter) -LINK_ENTITY (env_snow) -LINK_ENTITY (env_sound) -LINK_ENTITY (env_spark) -LINK_ENTITY (env_sprite) -LINK_ENTITY (fireanddie) -LINK_ENTITY (func_bomb_target) -LINK_ENTITY (func_breakable) -LINK_ENTITY (func_button) -LINK_ENTITY (func_buyzone) -LINK_ENTITY (func_conveyor) -LINK_ENTITY (func_door) -LINK_ENTITY (func_door_rotating) -LINK_ENTITY (func_escapezone) -LINK_ENTITY (func_friction) -LINK_ENTITY (func_grencatch) -LINK_ENTITY (func_guntarget) -LINK_ENTITY (func_healthcharger) -LINK_ENTITY (func_hostage_rescue) -LINK_ENTITY (func_illusionary) -LINK_ENTITY (func_ladder) -LINK_ENTITY (func_monsterclip) -LINK_ENTITY (func_mortar_field) -LINK_ENTITY (func_pendulum) -LINK_ENTITY (func_plat) -LINK_ENTITY (func_platrot) -LINK_ENTITY (func_pushable) -LINK_ENTITY (func_rain) -LINK_ENTITY (func_recharge) -LINK_ENTITY (func_rot_button) -LINK_ENTITY (func_rotating) -LINK_ENTITY (func_snow) -LINK_ENTITY (func_tank) -LINK_ENTITY (func_tankcontrols) -LINK_ENTITY (func_tanklaser) -LINK_ENTITY (func_tankmortar) -LINK_ENTITY (func_tankrocket) -LINK_ENTITY (func_trackautochange) -LINK_ENTITY (func_trackchange) -LINK_ENTITY (func_tracktrain) -LINK_ENTITY (func_train) -LINK_ENTITY (func_traincontrols) -LINK_ENTITY (func_vehicle) -LINK_ENTITY (func_vehiclecontrols) -LINK_ENTITY (func_vip_safetyzone) -LINK_ENTITY (func_wall) -LINK_ENTITY (func_wall_toggle) -LINK_ENTITY (func_water) -LINK_ENTITY (func_weaponcheck) -LINK_ENTITY (game_counter) -LINK_ENTITY (game_counter_set) -LINK_ENTITY (game_end) -LINK_ENTITY (game_player_equip) -LINK_ENTITY (game_player_hurt) -LINK_ENTITY (game_player_team) -LINK_ENTITY (game_score) -LINK_ENTITY (game_team_master) -LINK_ENTITY (game_team_set) -LINK_ENTITY (game_text) -LINK_ENTITY (game_zone_player) -LINK_ENTITY (gibshooter) -LINK_ENTITY (grenade) -LINK_ENTITY (hostage_entity) -LINK_ENTITY (info_bomb_target) -LINK_ENTITY (info_hostage_rescue) -LINK_ENTITY (info_intermission) -LINK_ENTITY (info_landmark) -LINK_ENTITY (info_map_parameters) -LINK_ENTITY (info_null) -LINK_ENTITY (info_player_deathmatch) -LINK_ENTITY (info_player_start) -LINK_ENTITY (info_target) -LINK_ENTITY (info_teleport_destination) -LINK_ENTITY (info_vip_start) -LINK_ENTITY (infodecal) -LINK_ENTITY (item_airtank) -LINK_ENTITY (item_airbox) -LINK_ENTITY (item_antidote) -LINK_ENTITY (item_assaultsuit) -LINK_ENTITY (item_battery) -LINK_ENTITY (item_healthkit) -LINK_ENTITY (item_kevlar) -LINK_ENTITY (item_longjump) -LINK_ENTITY (item_security) -LINK_ENTITY (item_sodacan) -LINK_ENTITY (item_suit) -LINK_ENTITY (item_thighpack) -LINK_ENTITY (light) -LINK_ENTITY (light_environment) -LINK_ENTITY (light_spot) -LINK_ENTITY (momentary_door) -LINK_ENTITY (momentary_rot_button) -LINK_ENTITY (monster_hevsuit_dead) -LINK_ENTITY (monster_mortar) -LINK_ENTITY (monster_scientist) -LINK_ENTITY (multi_manager) -LINK_ENTITY (multisource) -LINK_ENTITY (path_corner) -LINK_ENTITY (path_track) -LINK_ENTITY (player) -LINK_ENTITY (player_loadsaved) -LINK_ENTITY (player_weaponstrip) -LINK_ENTITY (point_clientcommand) -LINK_ENTITY (point_servercommand) -LINK_ENTITY (soundent) -LINK_ENTITY (spark_shower) -LINK_ENTITY (speaker) -LINK_ENTITY (target_cdaudio) -LINK_ENTITY (test_effect) -LINK_ENTITY (trigger) -LINK_ENTITY (trigger_auto) -LINK_ENTITY (trigger_autosave) -LINK_ENTITY (trigger_camera) -LINK_ENTITY (trigger_cdaudio) -LINK_ENTITY (trigger_changelevel) -LINK_ENTITY (trigger_changetarget) -LINK_ENTITY (trigger_counter) -LINK_ENTITY (trigger_endsection) -LINK_ENTITY (trigger_gravity) -LINK_ENTITY (trigger_hurt) -LINK_ENTITY (trigger_monsterjump) -LINK_ENTITY (trigger_multiple) -LINK_ENTITY (trigger_once) -LINK_ENTITY (trigger_push) -LINK_ENTITY (trigger_random) -LINK_ENTITY (trigger_random_time) -LINK_ENTITY (trigger_random_unique) -LINK_ENTITY (trigger_relay) -LINK_ENTITY (trigger_setorigin) -LINK_ENTITY (trigger_teleport) -LINK_ENTITY (trigger_transition) -LINK_ENTITY (weapon_ak47) -LINK_ENTITY (weapon_aug) -LINK_ENTITY (weapon_awp) -LINK_ENTITY (weapon_c4) -LINK_ENTITY (weapon_deagle) -LINK_ENTITY (weapon_elite) -LINK_ENTITY (weapon_famas) -LINK_ENTITY (weapon_fiveseven) -LINK_ENTITY (weapon_flashbang) -LINK_ENTITY (weapon_g3sg1) -LINK_ENTITY (weapon_galil) -LINK_ENTITY (weapon_glock18) -LINK_ENTITY (weapon_hegrenade) -LINK_ENTITY (weapon_knife) -LINK_ENTITY (weapon_m249) -LINK_ENTITY (weapon_m3) -LINK_ENTITY (weapon_m4a1) -LINK_ENTITY (weapon_mac10) -LINK_ENTITY (weapon_mp5navy) -LINK_ENTITY (weapon_p228) -LINK_ENTITY (weapon_p90) -LINK_ENTITY (weapon_scout) -LINK_ENTITY (weapon_sg550) -LINK_ENTITY (weapon_sg552) -LINK_ENTITY (weapon_shield) -LINK_ENTITY (weapon_shieldgun) -LINK_ENTITY (weapon_smokegrenade) -LINK_ENTITY (weapon_tmp) -LINK_ENTITY (weapon_ump45) -LINK_ENTITY (weapon_usp) -LINK_ENTITY (weapon_xm1014) -LINK_ENTITY (weaponbox) -LINK_ENTITY (world_items) -LINK_ENTITY (worldspawn) +// add linkents for android +#include "android.cpp" diff --git a/source/manager.cpp b/source/manager.cpp index 1afc0ae..8407a52 100644 --- a/source/manager.cpp +++ b/source/manager.cpp @@ -111,9 +111,6 @@ void BotManager::touchKillerEntity (Bot *bot) { MDLL_Touch (m_killerEntity, bot->ent ()); } -// it's already defined in interface.cpp -extern "C" void player (entvars_t *pev); - void BotManager::execGameEntity (entvars_t *vars) { // this function calls gamedll player() function, in case to create player entity in game @@ -121,7 +118,7 @@ void BotManager::execGameEntity (entvars_t *vars) { CALL_GAME_ENTITY (PLID, "player", vars); return; } - player (vars); + ents.getPlayerFunction () (vars); } void BotManager::forEach (ForEachBot handler) { @@ -682,6 +679,23 @@ int BotManager::getBotCount () { return m_bots.length (); } +float BotManager::getConnectionTime (int botId) { + // this function get's fake bot player time. + + for (const auto &bot : m_bots) { + if (bot->index () == botId) { + auto current = plat.seconds (); + + if (current - bot->m_joinServerTime > bot->m_playServerTime || current - bot->m_joinServerTime <= 0) { + bot->m_playServerTime = 60.0f * rg.float_ (30.0f, 240.0f); + bot->m_joinServerTime = current - bot->m_playServerTime * rg.float_ (0.2f, 0.8f); + } + return current - bot->m_joinServerTime; + } + } + return 0.0f; +} + Twin BotManager::countTeamPlayers () { int ts = 0, cts = 0; @@ -846,6 +860,10 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int member) { m_frameInterval = game.timebase (); m_slowFrameTimestamp = 0.0f; + // stuff from jk_botti + m_playServerTime = 60.0f * rg.float_ (30.0f, 240.0f); + m_joinServerTime = plat.seconds () - m_playServerTime * rg.float_ (0.2f, 0.8f); + switch (personality) { case 1: m_personality = Personality::Rusher; diff --git a/source/support.cpp b/source/support.cpp index 21d12e2..0afbb65 100644 --- a/source/support.cpp +++ b/source/support.cpp @@ -9,6 +9,7 @@ #include ConVar yb_display_welcome_text ("yb_display_welcome_text", "1"); +ConVar yb_enable_query_hook ("yb_enable_query_hook", "1"); BotUtils::BotUtils () { m_needToSendWelcome = false; @@ -585,6 +586,79 @@ void BotUtils::sendPings (edict_t *to) { return; } +void BotUtils::installSendTo () { + // if previously requested to disable? + if (!yb_enable_query_hook.bool_ ()) { + if (m_sendToHook.enabled ()) { + disableSendTo (); + } + return; + } + + // do not enable on not dedicated server + if (!game.isDedicated ()) { + return; + } + + // enable only on modern games + if (game.is (GameFlags::Modern) && (plat.isLinux || plat.isWindows) && !plat.isAndroid && !m_sendToHook.enabled ()) { + m_sendToHook.patch (reinterpret_cast (&sendto), reinterpret_cast (&BotUtils::sendTo)); + } +} + +int32 BotUtils::sendTo (int socket, const void *message, size_t length, int flags, const sockaddr *dest, int destLength) { + const auto send = [&] (const Twin &msg) -> int32 { + return Socket::sendto (socket, msg.first, msg.second, flags, dest, destLength); + }; + auto packet = reinterpret_cast (message); + + // player replies response + if (length > 5 && packet[0] == 0xff && packet[1] == 0xff && packet[2] == 0xff && packet[3] == 0xff) { + if (packet[4] == 'D') { + QueryBuffer buffer (packet, length, 5); + auto count = buffer.read (); + + for (uint8 i = 0; i < count; ++i) { + buffer.read (); // number + buffer.write (i); // override number + + buffer.skipString (); // name + buffer.skip (); // score + + buffer.read (); // override connection time + buffer.write (bots.getConnectionTime (i)); + } + return send (buffer.data ()); + } + else if (packet[4] == 'I') { + QueryBuffer buffer (packet, length, 5); + buffer.skip (); // protocol + + // skip server name, folder, map game + for (size_t i = 0; i < 4; i++) { + buffer.skipString (); + } + buffer.skip (); // steam app id + + buffer.skip (); // players + buffer.skip (); // maxplayers + buffer.skip (); // bots + buffer.write (0); // zero out bot count + + return send (buffer.data ()); + } + else if (packet[4] == 'm') { + QueryBuffer buffer (packet, length, 5); + + buffer.shiftToEnd (); // shift to the end of buffer + buffer.write (0); // zero out bot count + + return send (buffer.data ()); + } + } + return send ({ packet, length }); +} + int BotUtils::buildNumber () { // this function generates build number from the compiler date macros