From 74f1ab866b499b13f04e9049c7d558ee7cf3e014 Mon Sep 17 00:00:00 2001 From: jeefo Date: Mon, 23 Nov 2020 00:06:18 +0300 Subject: [PATCH] Fixed linux listenserver startup problems Fixed multiple buffer overruns and memory leaks. --- ext/crlib/cr-alloc.h | 93 ---------------------------------------- ext/crlib/cr-array.h | 31 +++++++------- ext/crlib/cr-basic.h | 5 ++- ext/crlib/cr-complete.h | 2 +- ext/crlib/cr-deque.h | 23 +++++----- ext/crlib/cr-detour.h | 63 ++++++++++++++------------- ext/crlib/cr-files.h | 8 ++-- ext/crlib/cr-hashmap.h | 10 +++-- ext/crlib/cr-lambda.h | 5 +-- ext/crlib/cr-library.h | 20 ++++++--- ext/crlib/cr-logger.h | 2 +- ext/crlib/cr-memory.h | 52 ++++++++++++++++++++++ ext/crlib/cr-override.h | 39 +++++++++++++++++ ext/crlib/cr-random.h | 2 +- ext/crlib/cr-string.h | 10 ++++- ext/crlib/cr-uniqueptr.h | 12 +++--- inc/control.h | 6 +-- inc/engine.h | 50 ++++++++++++++++----- inc/graph.h | 36 +++++++++++----- inc/yapb.h | 1 - src/android.cpp | 5 ++- src/botlib.cpp | 3 +- src/graph.cpp | 24 +++++------ src/linkage.cpp | 64 +++++++++++++++++++++++---- src/manager.cpp | 29 ++++++++----- src/module.cpp | 3 -- src/navigate.cpp | 10 ++--- vc/yapb.vcxproj | 8 ++-- vc/yapb.vcxproj.filters | 9 ++-- 29 files changed, 371 insertions(+), 254 deletions(-) delete mode 100644 ext/crlib/cr-alloc.h create mode 100644 ext/crlib/cr-memory.h create mode 100644 ext/crlib/cr-override.h diff --git a/ext/crlib/cr-alloc.h b/ext/crlib/cr-alloc.h deleted file mode 100644 index b3da32b..0000000 --- a/ext/crlib/cr-alloc.h +++ /dev/null @@ -1,93 +0,0 @@ -// -// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge. -// Copyright © 2004-2020 YaPB Project . -// -// SPDX-License-Identifier: MIT -// - -#pragma once - -#include -#include -#include - -// provide placment new to avoid stdc++ header -inline void *operator new (const size_t, void *ptr) noexcept { - return ptr; -} - -CR_NAMESPACE_BEGIN - -// default allocator for cr-objects -class Allocator : public Singleton { -public: - Allocator () = default; - ~Allocator () = default; - -public: - template T *allocate (const size_t length = 1) { - auto memory = reinterpret_cast (malloc (cr::max (1u, length * sizeof (T)))); - - if (!memory) { - plat.abort (); - } - return memory; - } - - template void deallocate (T *memory) { - free (memory); - memory = nullptr; - } - -public: - template void construct (T *memory, Args &&...args) { - new (memory) T (cr::forward (args)...); - } - - template void destruct (T *memory) { - memory->~T (); - } - -public: - template T *create (Args &&...args) { - auto memory = allocate (); - new (memory) T (cr::forward (args)...); - - return memory; - } - - template T *createArray (const size_t amount) { - auto memory = allocate (amount); - - for (size_t i = 0; i < amount; ++i) { - new (memory + i) T (); - } - return memory; - } - - - template void destroy (T *memory) { - if (memory) { - destruct (memory); - deallocate (memory); - } - } -}; - -CR_EXPOSE_GLOBAL_SINGLETON (Allocator, alloc); - -template class UniquePtr; - -// implment singleton with UniquePtr -template T &Singleton ::instance () { - static const UniquePtr instance_ { alloc.create () }; - return *instance_; -} - -// declare destructor for pure-virtual classes -#define CR_DECLARE_DESTRUCTOR() \ - void operator delete (void *ptr) { \ - alloc.deallocate (ptr); \ - } \ - -CR_NAMESPACE_END diff --git a/ext/crlib/cr-array.h b/ext/crlib/cr-array.h index 976290e..05512ba 100644 --- a/ext/crlib/cr-array.h +++ b/ext/crlib/cr-array.h @@ -8,7 +8,7 @@ #pragma once #include -#include +#include #include #include @@ -61,20 +61,20 @@ public: private: void destructElements () noexcept { for (size_t i = 0; i < length_; ++i) { - alloc.destruct (&contents_[i]); + Memory::destruct (&contents_[i]); } } void transferElements (T *dest, T *src, size_t length) noexcept { for (size_t i = 0; i < length; ++i) { - alloc.construct (&dest[i], cr::move (src[i])); - alloc.destruct (&src[i]); + Memory::construct (&dest[i], cr::move (src[i])); + Memory::destruct (&src[i]); } } void destroy () { destructElements (); - alloc.deallocate (contents_); + Memory::release (contents_); } void reset () { @@ -83,7 +83,6 @@ private: length_ = 0; } - public: bool reserve (const size_t amount) { if (length_ + amount < capacity_) { @@ -99,11 +98,11 @@ public: else { capacity = amount + capacity_ + 1; } - auto data = alloc.allocate (capacity); + auto data = Memory::get (capacity); if (contents_) { transferElements (data, contents_, length_); - alloc.deallocate (contents_); + Memory::release (contents_); } contents_ = data; @@ -152,7 +151,7 @@ public: return false; } } - alloc.construct (&contents_[index], cr::forward (object)); + Memory::construct (&contents_[index], cr::forward (object)); if (index >= length_) { length_ = index + 1; @@ -176,7 +175,7 @@ public: if (index >= length_) { for (size_t i = 0; i < count; ++i) { - alloc.construct (&contents_[i + index], cr::forward (objects[i])); + Memory::construct (&contents_[i + index], cr::forward (objects[i])); } length_ = capacity; } @@ -187,7 +186,7 @@ public: contents_[i + count - 1] = cr::move (contents_[i - 1]); } for (i = 0; i < count; ++i) { - alloc.construct (&contents_[i + index], cr::forward (objects[i])); + Memory::construct (&contents_[i + index], cr::forward (objects[i])); } length_ += count; } @@ -206,7 +205,7 @@ public: return false; } for (size_t i = index; i < index + count; ++i) { - alloc.destruct (&contents_[i]); + Memory::destruct (&contents_[i]); } length_ -= count; @@ -232,7 +231,7 @@ public: if (!reserve (1)) { return false; } - alloc.construct (&contents_[length_], cr::forward (object)); + Memory::construct (&contents_[length_], cr::forward (object)); ++length_; return true; @@ -242,7 +241,7 @@ public: if (!reserve (1)) { return false; } - alloc.construct (&contents_[length_], cr::forward (args)...); + Memory::construct (&contents_[length_], cr::forward (args)...); ++length_; return true; @@ -310,10 +309,10 @@ public: return false; } - auto data = alloc.allocate (length_); + auto data = Memory::get (length_); transferElements (data, contents_, length_); - alloc.deallocate (contents_); + Memory::release (contents_); contents_ = data; capacity_ = length_; diff --git a/ext/crlib/cr-basic.h b/ext/crlib/cr-basic.h index 5562013..7bdb9b5 100644 --- a/ext/crlib/cr-basic.h +++ b/ext/crlib/cr-basic.h @@ -92,7 +92,10 @@ protected: { } public: - static T &instance (); // implemented in cr-alloc.h + static T &instance () { + static T __instance {}; + return __instance; + } public: T *operator -> () { diff --git a/ext/crlib/cr-complete.h b/ext/crlib/cr-complete.h index 5cfe3f5..ecea87c 100644 --- a/ext/crlib/cr-complete.h +++ b/ext/crlib/cr-complete.h @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include diff --git a/ext/crlib/cr-deque.h b/ext/crlib/cr-deque.h index ee92397..cd5a50a 100644 --- a/ext/crlib/cr-deque.h +++ b/ext/crlib/cr-deque.h @@ -7,8 +7,7 @@ #pragma once -#include -#include +#include #include CR_NAMESPACE_BEGIN @@ -16,8 +15,8 @@ CR_NAMESPACE_BEGIN template class Deque : private DenyCopying { private: size_t capacity_ {}; + T *contents_ {}; - UniquePtr contents_ {}; Twin index_ {}; private: @@ -56,7 +55,7 @@ private: void extendCapacity () { auto capacity = capacity_ ? capacity_ * 2 : 8; - auto contents = cr::makeUnique (sizeof (T) * capacity); + auto contents = Memory::get (sizeof (T) * capacity); if (index_.first < index_.second) { for (size_t i = 0; i < index_.second - index_.first; ++i) { @@ -76,14 +75,16 @@ private: index_.second = index_.second + (capacity_ - index_.first); index_.first = 0; } - contents_ = cr::move (contents); + Memory::release (contents_); + + contents_ = contents; capacity_ = capacity; } void destroy () { auto destruct = [&] (size_t start, size_t end) { for (size_t i = start; i < end; ++i) { - alloc.destruct (&contents_[i]); + Memory::destruct (&contents_[i]); } }; @@ -94,7 +95,7 @@ private: destruct (index_.first, capacity_); destruct (0, index_.second); } - contents_ = nullptr; + Memory::release (contents_); } void reset () { @@ -127,17 +128,17 @@ public: template void emplaceLast (Args &&...args) { auto rear = pickRearIndex (); - alloc.construct (&contents_[index_.second], cr::forward (args)...); + Memory::construct (&contents_[index_.second], cr::forward (args)...); index_.second = rear; } template void emplaceFront (Args &&...args) { index_.first = pickFrontIndex (); - alloc.construct (&contents_[index_.first], cr::forward (args)...); + Memory::construct (&contents_[index_.first], cr::forward (args)...); } void discardFront () { - alloc.destruct (&contents_[index_.first]); + Memory::destruct (&contents_[index_.first]); if (index_.first == capacity_ - 1) { index_.first = 0; @@ -154,7 +155,7 @@ public: else { index_.second--; } - alloc.destruct (&contents_[index_.second]); + Memory::destruct (&contents_[index_.second]); } T popFront () { diff --git a/ext/crlib/cr-detour.h b/ext/crlib/cr-detour.h index b7d3058..509b509 100644 --- a/ext/crlib/cr-detour.h +++ b/ext/crlib/cr-detour.h @@ -140,35 +140,10 @@ private: } public: + Detour () = default; + Detour (StringRef module, StringRef name, T *address) { - savedBytes_.resize (jmpBuffer_.length ()); - -#if !defined (CR_WINDOWS) - (void) module; - (void) name; - - auto search = reinterpret_cast (address); - - while (*reinterpret_cast (search) == 0x25ff) { - search = **reinterpret_cast (search + 2); - } - - original_ = search; - pageSize_ = static_cast (sysconf (_SC_PAGE_SIZE)); -#else - auto handle = GetModuleHandleA (module.chars ()); - - if (!handle) { - original_ = reinterpret_cast (address); - return; - } - original_ = reinterpret_cast (GetProcAddress (handle, name.chars ())); - - if (!original_) { - original_ = reinterpret_cast (address); - return; - } -#endif + initialize (module, name, address); } ~Detour () { @@ -194,7 +169,37 @@ private: }; public: - + void initialize (StringRef module, StringRef name, T *address) { + savedBytes_.resize (jmpBuffer_.length ()); + +#if !defined (CR_WINDOWS) + (void) module; + (void) name; + + auto ptr = reinterpret_cast (address); + + while (*reinterpret_cast (ptr) == 0x25ff) { + ptr = **reinterpret_cast (ptr + 2); + } + + original_ = ptr; + pageSize_ = static_cast (sysconf (_SC_PAGE_SIZE)); +#else + auto handle = GetModuleHandleA (module.chars ()); + + if (!handle) { + original_ = reinterpret_cast (address); + return; + } + original_ = reinterpret_cast (GetProcAddress (handle, name.chars ())); + + if (!original_) { + original_ = reinterpret_cast (address); + return; + } +#endif + } + void install (void *detour, const bool enable = false) { if (!original_) { return; diff --git a/ext/crlib/cr-files.h b/ext/crlib/cr-files.h index 7c1251a..88bd2a6 100644 --- a/ext/crlib/cr-files.h +++ b/ext/crlib/cr-files.h @@ -180,8 +180,8 @@ private: FreeFunction freeFun_ = nullptr; public: - inline MemFileStorage () = default; - inline ~MemFileStorage () = default; + explicit MemFileStorage () = default; + ~MemFileStorage () = default; public: void initizalize (LoadFunction loader, FreeFunction unloader) { @@ -212,14 +212,14 @@ public: return nullptr; } *size = static_cast (file.length ()); - auto data = alloc.allocate (*size); + auto data = Memory::get (*size); file.read (data, *size); return data; } static void defaultUnload (void *buffer) { - alloc.deallocate (buffer); + Memory::release (buffer); } static String loadToString (StringRef filename) { diff --git a/ext/crlib/cr-hashmap.h b/ext/crlib/cr-hashmap.h index 9622aca..fbdd467 100644 --- a/ext/crlib/cr-hashmap.h +++ b/ext/crlib/cr-hashmap.h @@ -36,11 +36,13 @@ template <> struct Hash { template <> struct Hash { uint32 operator () (int32 key) const noexcept { - key = ((key >> 16) ^ key) * 0x119de1f3; - key = ((key >> 16) ^ key) * 0x119de1f3; - key = (key >> 16) ^ key; + auto result = static_cast (key); - return key; + result = ((result >> 16) ^ result) * 0x119de1f3; + result = ((result >> 16) ^ result) * 0x119de1f3; + result = (result >> 16) ^ result; + + return result; } }; diff --git a/ext/crlib/cr-lambda.h b/ext/crlib/cr-lambda.h index a684cf2..20c858c 100644 --- a/ext/crlib/cr-lambda.h +++ b/ext/crlib/cr-lambda.h @@ -7,7 +7,7 @@ #pragma once -#include +#include #include CR_NAMESPACE_BEGIN @@ -31,9 +31,6 @@ private: virtual R invoke (Args &&...) = 0; virtual UniquePtr clone () const = 0; - - public: - CR_DECLARE_DESTRUCTOR (); }; template class LambdaFunctor : public LambdaFunctorWrapper { diff --git a/ext/crlib/cr-library.h b/ext/crlib/cr-library.h index cfaa8ad..974e97e 100644 --- a/ext/crlib/cr-library.h +++ b/ext/crlib/cr-library.h @@ -27,6 +27,7 @@ public: private: Handle handle_ = nullptr; + bool unloadable_ = true; public: explicit SharedLibrary () = default; @@ -43,22 +44,28 @@ public: } public: - bool load (StringRef file) noexcept { + bool load (StringRef file, bool unloadable = true) noexcept { if (*this) { unload (); } + unloadable_ = unloadable; #if defined (CR_WINDOWS) handle_ = LoadLibraryA (file.chars ()); -#elif defined (CR_OSX) - handle_ = dlopen (file.chars (), RTLD_NOW | RTLD_LOCAL); #else - handle_ = dlopen (file.chars (), RTLD_NOW | RTLD_DEEPBIND | RTLD_LOCAL); + auto loadFlags = RTLD_NOW | RTLD_LOCAL; + +#if defined (CR_LINUX) && !defined (__SANITIZE_ADDRESS__) + loadFlags |= RTLD_DEEPBIND; +#endif + handle_ = dlopen (file.chars (), loadFlags); #endif return handle_ != nullptr; } bool locate (Handle address) { + unloadable_ = false; + #if defined (CR_WINDOWS) MEMORY_BASIC_INFORMATION mbi; @@ -75,16 +82,17 @@ public: plat.bzero (&dli, sizeof (dli)); if (dladdr (address, &dli)) { - return load (dli.dli_fname); + return load (dli.dli_fname, false); } #endif return handle_ != nullptr; } void unload () noexcept { - if (!*this) { + if (!handle_ || !unloadable_) { return; } + #if defined (CR_WINDOWS) FreeLibrary (static_cast (handle_)); #else diff --git a/ext/crlib/cr-logger.h b/ext/crlib/cr-logger.h index d320e8f..ae52672 100644 --- a/ext/crlib/cr-logger.h +++ b/ext/crlib/cr-logger.h @@ -23,7 +23,7 @@ private: PrintFunction printFun_; public: - SimpleLogger () = default; + explicit SimpleLogger () = default; ~SimpleLogger () = default; public: diff --git a/ext/crlib/cr-memory.h b/ext/crlib/cr-memory.h new file mode 100644 index 0000000..1571fd3 --- /dev/null +++ b/ext/crlib/cr-memory.h @@ -0,0 +1,52 @@ +// +// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge. +// Copyright © 2004-2020 YaPB Project . +// +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include +#include +#include + +// provide placment new to avoid stdc++ header +inline void *operator new (const size_t, void *ptr) noexcept { + return ptr; +} + +CR_NAMESPACE_BEGIN + +// internal memory manager +class Memory final { +public: + Memory () = default; + ~Memory () = default; + +public: + template static T *get (const size_t length = 1) { + auto memory = reinterpret_cast (malloc (cr::max (1u, length * sizeof (T)))); + + if (!memory) { + plat.abort (); + } + return memory; + } + + template static void release (T *memory) { + free (memory); + memory = nullptr; + } + +public: + template static void construct (T *memory, Args &&...args) { + new (memory) T (cr::forward (args)...); + } + + template static void destruct (T *memory) { + memory->~T (); + } +}; + +CR_NAMESPACE_END diff --git a/ext/crlib/cr-override.h b/ext/crlib/cr-override.h new file mode 100644 index 0000000..ace571d --- /dev/null +++ b/ext/crlib/cr-override.h @@ -0,0 +1,39 @@ +// +// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge. +// Copyright © 2004-2020 YaPB Project . +// +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include +#include + +void *operator new (size_t size) noexcept { + return cr::Memory::get (size); +} + +void *operator new [] (size_t size) noexcept { + return cr::Memory::get (size); +} + +void operator delete (void *ptr) noexcept { + cr::Memory::release (ptr); +} + +void operator delete [] (void *ptr) noexcept { + cr::Memory::release (ptr); +} + +void operator delete (void *ptr, size_t) noexcept { + cr::Memory::release (ptr); +} + +void operator delete [] (void *ptr, size_t) noexcept { + cr::Memory::release (ptr); +} + +CR_LINKAGE_C void __cxa_pure_virtual () { + cr::plat.abort ("pure virtual function call"); +} \ No newline at end of file diff --git a/ext/crlib/cr-random.h b/ext/crlib/cr-random.h index 2f20232..97fad28 100644 --- a/ext/crlib/cr-random.h +++ b/ext/crlib/cr-random.h @@ -18,7 +18,7 @@ private: uint64 state_ { static_cast (time (nullptr)) }; public: - Random () = default; + explicit Random () = default; ~Random () = default; private: diff --git a/ext/crlib/cr-string.h b/ext/crlib/cr-string.h index 48cec3c..5b753e3 100644 --- a/ext/crlib/cr-string.h +++ b/ext/crlib/cr-string.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include @@ -420,7 +420,13 @@ public: length = calcLength (str, length); resize (length); - memcpy (&chars_[0], str, length); + + if (str) { + memcpy (&chars_[0], str, length); + } + else { + chars_[0] = kNullChar; + } length_ = length; chars_[length_] = kNullChar; diff --git a/ext/crlib/cr-uniqueptr.h b/ext/crlib/cr-uniqueptr.h index 0d46ae4..c998834 100644 --- a/ext/crlib/cr-uniqueptr.h +++ b/ext/crlib/cr-uniqueptr.h @@ -8,7 +8,7 @@ #pragma once #include -#include +#include #include CR_NAMESPACE_BEGIN @@ -53,7 +53,7 @@ public: private: void destroy () { - alloc.destroy (ptr_); + delete ptr_; ptr_ = nullptr; } @@ -129,7 +129,7 @@ public: private: void destroy () { - alloc.destroy (ptr_); + delete[] ptr_; ptr_ = nullptr; } @@ -156,6 +156,7 @@ public: T &operator [] (size_t index) { return ptr_[index]; } + const T &operator [] (size_t index) const { return ptr_[index]; } @@ -192,11 +193,12 @@ namespace detail { } template typename detail::UniqueIf ::SingleObject makeUnique (Args &&... args) { - return UniquePtr (alloc.create (cr::forward (args)...)); + return UniquePtr (new T (cr::forward (args)...)); } template typename detail::UniqueIf ::UnknownBound makeUnique (size_t size) { - return UniquePtr (alloc.createArray ::Type> (size)); + using Type = typename detail::ClearExtent ::Type; + return UniquePtr (new Type[size] ()); } template typename detail::UniqueIf ::KnownBound makeUnique (Args &&...) = delete; diff --git a/inc/control.h b/inc/control.h index 5b67b9b..88cb00a 100644 --- a/inc/control.h +++ b/inc/control.h @@ -33,7 +33,7 @@ public: Handler handler = nullptr; public: - BotCmd () = default; + explicit BotCmd () = default; BotCmd (StringRef name, StringRef format, StringRef help, Handler handler) : name (name), format (format), help (help), handler (cr::move (handler)) { } @@ -46,7 +46,7 @@ public: MenuHandler handler; public: - BotMenu (int ident, int slots, StringRef text, MenuHandler handler) : ident (ident), slots (slots), text (text), handler (cr::move (handler)) + explicit BotMenu (int ident, int slots, StringRef text, MenuHandler handler) : ident (ident), slots (slots), text (text), handler (cr::move (handler)) { } }; @@ -56,7 +56,7 @@ public: String text; public: - PrintQueue () = default; + explicit PrintQueue () = default; PrintQueue (int32 destination, StringRef text) : destination (destination), text (text) { } diff --git a/inc/engine.h b/inc/engine.h index fd1f52d..2254e3a 100644 --- a/inc/engine.h +++ b/inc/engine.h @@ -642,26 +642,29 @@ public: class EntityLinkage : public Singleton { private: #if defined (CR_WINDOWS) -# define DETOUR_FUNCTION GetProcAddress -# define DETOUR_RETURN FARPROC -# define DETOUR_HANDLE HMODULE +# define DLSYM_FUNCTION GetProcAddress +# define DLSYM_RETURN FARPROC +# define DLSYM_HANDLE HMODULE #else -# define DETOUR_FUNCTION dlsym -# define DETOUR_RETURN SharedLibrary::Handle -# define DETOUR_HANDLE SharedLibrary::Handle +# define DLSYM_FUNCTION dlsym +# define DLSYM_RETURN SharedLibrary::Handle +# define DLSYM_HANDLE SharedLibrary::Handle #endif private: + bool m_paused { false }; + + Detour m_dlsym; + HashMap m_exports; + SharedLibrary m_self; - Detour m_dlsym { "kernel32.dll", "GetProcAddress", DETOUR_FUNCTION }; - HashMap m_exports; public: EntityLinkage () = default; public: void initialize (); - DETOUR_RETURN lookup (SharedLibrary::Handle module, const char *function); + DLSYM_RETURN lookup (SharedLibrary::Handle module, const char *function); public: void callPlayerFunction (edict_t *ent) { @@ -673,7 +676,30 @@ public: } public: - static DETOUR_RETURN CR_STDCALL replacement (SharedLibrary::Handle module, const char *function) { + void enable () { + if (m_dlsym.detoured ()) { + return; + } + m_dlsym.detour (); + } + + void disable () { + if (!m_dlsym.detoured ()) { + return; + } + m_dlsym.restore (); + } + + void setPaused (bool what) { + m_paused = what; + } + + bool isPaused () const { + return m_paused; + } + +public: + static DLSYM_RETURN CR_STDCALL replacement (SharedLibrary::Handle module, const char *function) { return EntityLinkage::instance ().lookup (module, function); } @@ -681,6 +707,10 @@ public: void clearExportTable () { m_exports.clear (); } + + bool isWorkaroundNeeded () { + return !plat.win32 && !Game::instance ().isDedicated (); + } }; // expose globals diff --git a/inc/graph.h b/inc/graph.h index cb34ce3..97078d5 100644 --- a/inc/graph.h +++ b/inc/graph.h @@ -177,7 +177,9 @@ struct PODPath { class PathWalk final : public DenyCopying { private: size_t m_cursor = 0; - Array m_storage; + size_t m_length = 0; + + UniquePtr m_path; public: explicit PathWalk () = default; @@ -193,11 +195,11 @@ public: } int32 &last () { - return m_storage.last (); + return at (length () - 1); } int32 &at (size_t index) { - return m_storage.at (m_cursor + index); + return m_path[m_cursor + index]; } void shift () { @@ -205,31 +207,39 @@ public: } void reverse () { - m_storage.reverse (); + for (size_t i = 0; i < m_length / 2; ++i) { + cr::swap (m_path[i], m_path[m_length - 1 - i]); + } } size_t length () const { - if (m_cursor > m_storage.length ()) { + if (m_cursor >= m_length) { return 0; } - return m_storage.length () - m_cursor; + return m_length - m_cursor; } bool hasNext () const { - return m_cursor < m_storage.length (); + return length () > m_cursor; } bool empty () const { return !length (); } - void push (int node) { - m_storage.push (node); + void add (int32 node) { + m_path[m_length++] = node; } void clear () { m_cursor = 0; - m_storage.clear (); + m_length = 0; + + m_path[0] = 0; + } + + void init (size_t length) { + m_path = cr::makeUnique (length); } }; @@ -250,7 +260,7 @@ private: int m_lastJumpNode; int m_findWPIndex; int m_facingAtIndex; - int m_highestDamage[kGameTeamNum]; + int m_highestDamage[kGameTeamNum] {}; float m_timeJumpStarted; float m_autoPathDistance; @@ -373,6 +383,10 @@ public: const SmallArray &getNodesInBucket (const Vector &pos); public: + size_t getMaxRouteLength () const { + return m_paths.length () / 2; + } + int getHighestDamageForTeam (int team) const { return m_highestDamage[team]; } diff --git a/inc/yapb.h b/inc/yapb.h index 77569f5..228bdfb 100644 --- a/inc/yapb.h +++ b/inc/yapb.h @@ -453,7 +453,6 @@ constexpr int kMaxNodeLinks = 8; constexpr int kMaxPracticeDamageValue = 2040; constexpr int kMaxPracticeGoalValue = 2040; constexpr int kMaxNodes = 2048; -constexpr int kMaxRouteLength = kMaxNodes / 2; constexpr int kMaxWeapons = 32; constexpr int kNumWeapons = 26; constexpr int kMaxCollideMoves = 3; diff --git a/src/android.cpp b/src/android.cpp index 357cc8a..b7faea4 100644 --- a/src/android.cpp +++ b/src/android.cpp @@ -24,7 +24,7 @@ CR_EXPORT int Server_GetBlendingInterface (int version, struct sv_blending_inter return api_GetBlendingInterface (version, ppinterface, pstudio, rotationmatrix, bonetransform); } -void android_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev) { +void forwardEntity_helper (EntityFunction &addr, const char *name, entvars_t *pev) { if (!addr) { addr = game.lib ().resolve (name); } @@ -37,7 +37,7 @@ void android_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev) #define LINK_ENTITY(entityName) \ CR_EXPORT void entityName (entvars_t *pev) { \ static EntityFunction addr; \ - android_LinkEntity (addr, #entityName, pev); \ + forwardEntity_helper (addr, __FUNCTION__, pev); \ } #else #define LINK_ENTITY(entityName) @@ -142,6 +142,7 @@ LINK_ENTITY (game_team_master) LINK_ENTITY (game_team_set) LINK_ENTITY (game_text) LINK_ENTITY (game_zone_player) +LINK_ENTITY (gib) LINK_ENTITY (gibshooter) LINK_ENTITY (grenade) LINK_ENTITY (hostage_entity) diff --git a/src/botlib.cpp b/src/botlib.cpp index a860c3f..3fb0c57 100644 --- a/src/botlib.cpp +++ b/src/botlib.cpp @@ -193,7 +193,6 @@ void Bot::checkGrenadesThrow () { allowThrowing = false; continue; } - m_throw = graph[predict].origin; auto throwPos = calcThrow (getEyesPos (), m_throw); @@ -4068,7 +4067,7 @@ void Bot::followUser_ () { clearSearchNodes (); int destIndex = graph.getNearest (m_targetEntity->v.origin); - IntArray points = graph.searchRadius (200.0f, m_targetEntity->v.origin); + auto points = graph.searchRadius (200.0f, m_targetEntity->v.origin); for (auto &newIndex : points) { // if waypoint not yet used, assign it as dest diff --git a/src/graph.cpp b/src/graph.cpp index aee884c..d78a2bc 100644 --- a/src/graph.cpp +++ b/src/graph.cpp @@ -51,10 +51,10 @@ int BotGraph::clearConnections (int index) { } struct Connection { - int index; - int number; - int distance; - float angles; + int index {}; + int number {}; + int distance {}; + float angles {}; public: Connection () { @@ -514,7 +514,7 @@ IntArray BotGraph::searchRadius (float radius, const Vector &origin, int maxCoun if (bucket.empty ()) { result.push (getNearestNoBuckets (origin, radius)); - return cr::move (result); + return result; } radius = cr::square (radius); @@ -527,7 +527,7 @@ IntArray BotGraph::searchRadius (float radius, const Vector &origin, int maxCoun result.push (at); } } - return cr::move (result); + return result; } void BotGraph::add (int type, const Vector &pos) { @@ -2564,7 +2564,7 @@ bool BotGraph::checkNodes (bool teleportPlayer) { for (auto &visit : visited) { visit = false; } - walk.push (0); // always check from node number 0 + walk.add (0); // always check from node number 0 while (!walk.empty ()) { // pop a node from the stack @@ -2579,7 +2579,7 @@ bool BotGraph::checkNodes (bool teleportPlayer) { // skip this node as it's already visited if (exists (index) && !visited[index]) { visited[index] = true; - walk.push (index); + walk.add (index); } } } @@ -2612,7 +2612,7 @@ bool BotGraph::checkNodes (bool teleportPlayer) { visit = false; } walk.clear (); - walk.push (0); // always check from node number 0 + walk.add (0); // always check from node number 0 while (!walk.empty ()) { const int current = walk.first (); // pop a node from the stack @@ -2623,7 +2623,7 @@ bool BotGraph::checkNodes (bool teleportPlayer) { continue; // skip this node as it's already visited } visited[outgoing] = true; - walk.push (outgoing); + walk.add (outgoing); } } @@ -2756,7 +2756,7 @@ void BotGraph::eraseFromDisk () { // if we're delete graph, delete all corresponding to it files forErase.push (strings.format ("%spwf/%s.pwf", data, map)); // graph itself - forErase.push (strings.format ("%strain/%s.exp", data, map)); // corresponding to practice + forErase.push (strings.format ("%strain/%s.prc", data, map)); // corresponding to practice forErase.push (strings.format ("%strain/%s.vis", data, map)); // corresponding to vistable forErase.push (strings.format ("%strain/%s.pmx", data, map)); // corresponding to matrix forErase.push (strings.format ("%sgraph/%s.graph", data, map)); // new format graph @@ -2839,8 +2839,6 @@ void BotGraph::setSearchIndex (int index) { } BotGraph::BotGraph () { - plat.bzero (m_highestDamage, sizeof (m_highestDamage)); - m_endJumpPoint = false; m_needsVisRebuild = false; m_jumpLearnNode = false; diff --git a/src/linkage.cpp b/src/linkage.cpp index c57340f..53315f0 100644 --- a/src/linkage.cpp +++ b/src/linkage.cpp @@ -10,6 +10,7 @@ ConVar cv_version ("yb_version", product.version.chars (), Var::ReadOnly); gamefuncs_t dllapi; +newgamefuncs_t newapi; enginefuncs_t engfuncs; gamedll_funcs_t dllfuncs; @@ -499,6 +500,17 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) { plat.bzero (table, sizeof (enginefuncs_t)); } + if (ents.isWorkaroundNeeded () && !game.is (GameFlags::Metamod)) { + table->pfnCreateNamedEntity = [] (int classname) -> edict_t * { + + if (ents.isPaused ()) { + ents.enable (); + ents.setPaused (false); + } + return engfuncs.pfnCreateNamedEntity (classname); + }; + } + table->pfnChangeLevel = [] (char *s1, char *s2) { // the purpose of this function is to ask the engine to shutdown the server and restart a // new one running the map whose name is s1. It is used ONLY IN SINGLE PLAYER MODE and is @@ -790,13 +802,33 @@ CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *table, int *interfaceVersion) // pass them too, else the DLL interfacing wouldn't be complete and the game possibly wouldn't // run properly. - auto api_GetNewDLLFunctions = game.lib ().resolve (__FUNCTION__); + plat.bzero (table, sizeof (newgamefuncs_t)); - if (!api_GetNewDLLFunctions || !api_GetNewDLLFunctions (table, interfaceVersion)) { - logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__); - return HLFalse; + if (!(game.is (GameFlags::Metamod))) { + auto api_GetEntityAPI = game.lib ().resolve (__FUNCTION__); + + // pass other DLLs engine callbacks to function table... + if (!api_GetEntityAPI || api_GetEntityAPI (&newapi, interfaceVersion) == 0) { + logger.error ("Could not resolve symbol \"%s\" in the game dll.", __FUNCTION__); + } + dllfuncs.newapi_table = &newapi; + + memcpy (table, &newapi, sizeof (newgamefuncs_t)); } - dllfuncs.newapi_table = table; + + table->pfnOnFreeEntPrivateData = [] (edict_t *ent) { + for (auto &bot : bots) { + if (bot->m_enemy == ent) { + bot->m_enemy = nullptr; + bot->m_lastEnemy = nullptr; + } + } + + if (game.is (GameFlags::Metamod)) { + RETURN_META (MRES_IGNORED); + } + newapi.pfnOnFreeEntPrivateData (ent); + }; return HLTrue; } @@ -851,7 +883,7 @@ CR_EXPORT int Meta_Attach (PLUG_LOADTIME now, metamod_funcs_t *functionTable, me GetEntityAPI_Post, // pfnGetEntityAPI_Post () nullptr, // pfnGetEntityAPI2 () nullptr, // pfnGetEntityAPI2_Post () - nullptr, // pfnGetNewDLLFunctions () + GetNewDLLFunctions, // pfnGetNewDLLFunctions () nullptr, // pfnGetNewDLLFunctions_Post () GetEngineFunctions, // pfnGetEngineFunctions () GetEngineFunctions_Post, // pfnGetEngineFunctions_Post () @@ -947,14 +979,23 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t api_GiveFnptrsToDll (functionTable, glob); } -DETOUR_RETURN EntityLinkage::lookup (SharedLibrary::Handle module, const char *function) { +DLSYM_RETURN EntityLinkage::lookup (SharedLibrary::Handle module, const char *function) { static const auto &gamedll = game.lib ().handle (); static const auto &self = m_self.handle (); const auto resolve = [&] (SharedLibrary::Handle handle) { - return reinterpret_cast (m_dlsym (static_cast (handle), function)); + return reinterpret_cast (m_dlsym (static_cast (handle), function)); }; + if (ents.isWorkaroundNeeded () && !strcmp (function, "CreateInterface")) { + ents.setPaused (true); + auto ret = resolve (module); + + ents.disable (); + + return ret; + } + // if requested module is yapb module, put in cache the looked up symbol if (self != module || (plat.win32 && (static_cast (reinterpret_cast (function) >> 16) & 0xffff) == 0)) { return resolve (module); @@ -979,13 +1020,18 @@ DETOUR_RETURN EntityLinkage::lookup (SharedLibrary::Handle module, const char *f } void EntityLinkage::initialize () { - if (plat.arm) { + if (plat.arm || game.is (GameFlags::Metamod)) { return; } + m_dlsym.initialize ("kernel32.dll", "GetProcAddress", DLSYM_FUNCTION); m_dlsym.install (reinterpret_cast (EntityLinkage::replacement), true); + m_self.locate (&engfuncs); } // add linkents for android #include "android.cpp" + +// override new/delete globally, need to be included in .cpp file +#include diff --git a/src/manager.cpp b/src/manager.cpp index 83d2dae..75b5d93 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -914,6 +914,7 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) { // we're not initializing all the variables in bot class, so do an ugly thing... memset this plat.bzero (this, sizeof (*this)); + int clientIndex = game.indexOfEntity (bot); pev = &bot->v; @@ -1033,6 +1034,9 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) { // just to be sure m_msgQueue.clear (); + // init path walker + m_pathWalk.init (graph.getMaxRouteLength ()); + // assign team and class m_wantedTeam = team; m_wantedSkin = skin; @@ -1104,18 +1108,18 @@ bool BotManager::isTeamStacked (int team) { void BotManager::erase (Bot *bot) { for (auto &e : m_bots) { - if (e.get () == bot) { - bot->showChaterIcon (false); - bot->markStale (); - - conf.clearUsedName (bot); // clear the bot name - - e.reset (); - m_bots.remove (e); // remove from bots array - - break; + if (e.get () != bot) { + continue; } + bot->markStale (); + + auto index = m_bots.index (e); + e.reset (); + + m_bots.erase (index, 1); // remove from bots array + break; } + } void BotManager::handleDeath (edict_t *killer, edict_t *victim) { @@ -1423,6 +1427,11 @@ void Bot::kick () { } void Bot::markStale () { + showChaterIcon (false); + + // clear the bot name + conf.clearUsedName (this); + // clear fakeclient bit pev->flags &= ~FL_FAKECLIENT; diff --git a/src/module.cpp b/src/module.cpp index 460dbcf..3a46c39 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -12,9 +12,6 @@ class YaPBModule : public IYaPBModule { public: virtual ~YaPBModule () override = default; -public: - CR_DECLARE_DESTRUCTOR (); - private: Bot *getBot (int index) { if (index < 1) { diff --git a/src/navigate.cpp b/src/navigate.cpp index a689c77..79ada7a 100644 --- a/src/navigate.cpp +++ b/src/navigate.cpp @@ -601,7 +601,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) { m_collStateIndex++; m_probeTime = game.time () + 0.5f; - if (m_collStateIndex > kMaxCollideMoves) { + if (m_collStateIndex >= kMaxCollideMoves) { m_navTimeset = game.time () - 5.0f; resetCollision (); } @@ -1181,7 +1181,7 @@ void Bot::findShortestPath (int srcIndex, int destIndex) { m_chosenGoalIndex = srcIndex; m_goalValue = 0.0f; - m_pathWalk.push (srcIndex); + m_pathWalk.add (srcIndex); while (srcIndex != destIndex) { srcIndex = (graph.m_matrix.data () + (srcIndex * graph.length ()) + destIndex)->index; @@ -1192,7 +1192,7 @@ void Bot::findShortestPath (int srcIndex, int destIndex) { return; } - m_pathWalk.push (srcIndex); + m_pathWalk.add (srcIndex); } } @@ -1406,7 +1406,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath: int currentIndex = m_routeQue.pop ().first; // safes us from bad graph... - if (m_routeQue.length () >= kMaxRouteLength - 1) { + if (m_routeQue.length () >= graph.getMaxRouteLength () - 1) { logger.error ("A* Search for bot \"%s\" has tried to build path with at least %d nodes. Seems to be graph is broken.", pev->netname.chars (), m_routeQue.length ()); kick (); // kick the bot off... @@ -1418,7 +1418,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath: // build the complete path do { - m_pathWalk.push (currentIndex); + m_pathWalk.add (currentIndex); currentIndex = m_routes[currentIndex].parent; } while (currentIndex != kInvalidNodeIndex); diff --git a/vc/yapb.vcxproj b/vc/yapb.vcxproj index 50abf9d..1fbb721 100644 --- a/vc/yapb.vcxproj +++ b/vc/yapb.vcxproj @@ -11,7 +11,6 @@ - @@ -26,7 +25,9 @@ + + @@ -97,8 +98,8 @@ DynamicLibrary false v142 - false false + false @@ -162,9 +163,8 @@ Level4 true - EditAndContinue Default - true + false false Default true diff --git a/vc/yapb.vcxproj.filters b/vc/yapb.vcxproj.filters index 6709171..b04ec55 100644 --- a/vc/yapb.vcxproj.filters +++ b/vc/yapb.vcxproj.filters @@ -75,9 +75,6 @@ inc\ext\hlsdk - - inc\ext\crlib - inc\ext\crlib @@ -147,6 +144,12 @@ inc + + inc\ext\crlib + + + inc\ext\crlib +