From 53df621dfcefc4ff12a84c8d8d526375b580dc11 Mon Sep 17 00:00:00 2001 From: jeefo Date: Sun, 2 Apr 2023 12:17:12 +0300 Subject: [PATCH] build: reworked build and package to simplify process build: reworked build and package to simplify process build: windows dll is now compiled by clang, msvc build added to extras package fix: clear all the implicit conversions in the code (also fixed some bugs) fix: crash on never xash3d-fwgs engine fix: fixed bad bot behaviors on aarch64 fix: crash on some maps due to missing previous node fix: finally removed memset(this) within bot creatin --- .github/ISSUE_TEMPLATE/bug_report.md | 30 -- .github/workflows/build.yml | 147 +++----- cfg/addons/yapb/conf/yapb.cfg | 92 ++++- ext/crlib | 2 +- i386pe.lds => ext/ldscripts/i386pe.lds | 0 ldscript.lds => ext/ldscripts/version.lds | 0 inc/config.h | 22 +- inc/control.h | 24 +- inc/engine.h | 42 +-- inc/graph.h | 77 ++-- inc/manager.h | 38 +- inc/message.h | 18 +- inc/product.h | 16 +- inc/support.h | 14 +- inc/version.h | 17 +- inc/version.h.in | 16 +- inc/yapb.h | 166 +++++---- meson.build | 371 +++++++++---------- meson_options.txt | 9 + package.py | 431 +++++++++++----------- src/botlib.cpp | 120 +++--- src/chatlib.cpp | 6 +- src/combat.cpp | 38 +- src/config.cpp | 3 + src/control.cpp | 12 +- src/engine.cpp | 9 +- src/graph.cpp | 99 +++-- src/linkage.cpp | 14 +- src/manager.cpp | 14 +- src/message.cpp | 2 +- src/module.cpp | 2 +- src/navigate.cpp | 72 ++-- src/support.cpp | 6 +- vc/yapb.rc | 22 +- vc/yapb.vcxproj | 2 +- 35 files changed, 1004 insertions(+), 949 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md rename i386pe.lds => ext/ldscripts/i386pe.lds (100%) rename ldscript.lds => ext/ldscripts/version.lds (100%) create mode 100644 meson_options.txt diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 0ce4642..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: bug -assignees: jeefo - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Video** -If it's problem with AI behaviour, add video to help explain your problem. - -**Environment details:** - - OS: [e.g. windows 10 / linux debian 10.4] - - Engine: [e.g. rehlds 3.8.0.702 / vanilla 8684] - - GameDLL: [e.g. regamedll 5.18.0.479 / vanilla] - - Metamod: [e.g. metamod-r / metamod-p / metamod] - - Bot Version: [e.g. 4.1.566] - - Game mode: [e.g. csdm / public / zombie] - -Additionally, please provide list of AMX Mod X plugins: ``amxx plugins`` and list of Metamod plugins: ``meta plugins``. - -**Additional context** -Add any other context about the problem here. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 51c9792..4f4d6db 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,117 +12,84 @@ on: types: [published] jobs: - unix: + bot-build: + runs-on: ubuntu-latest + container: + image: j4sdk/x86-buildtools:lunar + options: --hostname github-actions + strategy: matrix: - include: - - name: linux-x86 - bin: yapb.so - opts: CXX=gcc-11 CXX_LD=gold meson setup build - - - name: macos-x86 - bin: yapb.dylib - opts: meson setup build --cross-file=x86-darwin - - name: ${{ matrix.name }} - - runs-on: ubuntu-latest - container: j4sdk/x86-buildtools:latest - + arch: ['linux-x86', 'linux-x86-gcc', 'linux-aarch64', 'darwin-x86', 'windows-x86', 'windows-x86-gcc'] + fail-fast: false + steps: - - name: Checkout Repository + - name: Checkout repository uses: actions/checkout@v3 with: fetch-depth: 0 submodules: true - - - name: Configure Build + - name: Configure meson + shell: bash run: | - ${{ matrix.opts }} - - - name: Compile Source + if [[ ${{matrix.arch}} == linux-x86 ]]; then + CXX=clang CXX_LD=lld meson setup ${{matrix.arch}} + elif [[ ${{matrix.arch}} == linux-x86-gcc ]]; then + CXX=gcc CXX_LD=gold meson setup ${{matrix.arch}} + else + meson setup ${{matrix.arch}}/ --cross-file ${{matrix.arch}} + fi + - name: Build sources + shell: bash run: | - meson compile -v -C build - - - name: Upload Artifacts + meson compile -C ${{matrix.arch}} + echo "artifcat=${{matrix.arch}}/`ls ${{matrix.arch}}/ | egrep '^yapb.(so|dylib|dll)$' | head -1`" >> $GITHUB_ENV + - name: Upload artifacts uses: actions/upload-artifact@v3 with: - name: ${{ matrix.bin }} - path: build/${{ matrix.bin }} + name: ${{matrix.arch}} + path: ${{env.artifcat}} + + bot-msvc: + env: + name: windows-x86-msvc - windows: - name: windows-x86 - runs-on: windows-2022 + name: bot-build (windows-x86-msvc) + runs-on: windows-latest steps: - - name: Checkout Repository + - name: Checkout repository uses: actions/checkout@v3 with: fetch-depth: 0 submodules: true - - - name: Setup MSBuild + - name: Setup msbuild uses: ilammy/msvc-dev-cmd@v1 with: arch: amd64_x86 - - - name: Setup Meson + - name: Install meson run: | python -m pip install --upgrade meson ninja - - - name: Configure Build + - name: Configure meson run: | - meson setup build - - - name: Compile Source + meson setup ${{env.name}} + - name: Build sources run: | - meson compile -v -C build - - - name: Upload Artifacts + meson compile -C ${{env.name}} + - name: Upload artifacts uses: actions/upload-artifact@v3 with: - name: yapb.dll - path: build/yapb.dll + name: ${{env.name}} + path: ${{env.name}}/yapb.dll - linux-arm64: - name: linux-arm64 - - runs-on: self-hosted - continue-on-error: true - - steps: - - name: Checkout Repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - submodules: true - - - name: Configure Build - run: | - CXX=clang-12 CXX_LD=lld-12 meson setup build - - - name: Compile Source - run: | - meson compile -v -C build - - - name: Rename Binary - run: | - mv build/yapb.so build/yapb.arm64.so - - - name: Upload Artifacts - uses: actions/upload-artifact@v3 - with: - name: yapb.arm64.so - path: build/yapb.arm64.so - - publish: + bot-release: if: | github.event_name == 'release' && github.event.action == 'published' - name: publish + name: bot-release runs-on: ubuntu-latest - needs: [unix, windows, linux-arm64] + needs: [bot-build, bot-msvc] steps: - name: Checkout Repository @@ -130,38 +97,32 @@ jobs: with: fetch-depth: 0 submodules: true - - - name: Install Signing Tools + - name: Install signing tools run: | - sudo apt-get update && sudo apt-get upgrade -y + sudo apt-get update sudo apt-get install -y --no-install-recommends osslsigncode - - name: Get Artifacts uses: actions/download-artifact@v3 with: path: artifacts - - name: Setup Python uses: actions/setup-python@v4 with: python-version: '3.x' - - - name: Setup Meson + - name: Configure meson run: | - python -m pip install --upgrade meson ninja urllib3 - - - name: Create Packages + python -m pip install --upgrade meson ninja requests + - name: Create packages run: | meson setup dist ninja -C dist package env: - CS_CERTIFICATE: ${{ secrets.CS_CERTIFICATE }} - CS_CERTIFICATE_PASSWORD: ${{ secrets.CS_CERTIFICATE_PASSWORD }} - - - name: Publish Release + CS_CERTIFICATE: ${{secrets.CS_CERTIFICATE}} + CS_CERTIFICATE_PASSWORD: ${{secrets.CS_CERTIFICATE_PASSWORD}} + - name: Publish release uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/') with: files: pkg/* env: - GITHUB_TOKEN: ${{ secrets.API_TOKEN }} + GITHUB_TOKEN: ${{secrets.API_TOKEN}} diff --git a/cfg/addons/yapb/conf/yapb.cfg b/cfg/addons/yapb/conf/yapb.cfg index 9bd415c..03fb3ab 100644 --- a/cfg/addons/yapb/conf/yapb.cfg +++ b/cfg/addons/yapb/conf/yapb.cfg @@ -74,6 +74,13 @@ yb_walking_allowed "1" // yb_camping_allowed "1" +// +// Allows bots to partially avoid grenades. +// --- +// Default: "1", Min: "0", Max: "1" +// +yb_avoid_grenades "1" + // // Lower bound of time from which time for camping is calculated // --- @@ -130,6 +137,13 @@ yb_destroy_breakables_around "1" // yb_object_pickup_radius "450.0" +// +// The radius on which bot destroy breakables around it, when not touching with them. +// --- +// Default: "400.0", Min: "64.0", Max: "1024.0" +// +yb_object_destroy_radius "400.0" + // // Specifies the paths for the bot chatter sound files. // --- @@ -158,6 +172,13 @@ yb_attack_monsters "0" // yb_pickup_custom_items "0" +// +// Allows or disallows bots to pickup best weapons. +// --- +// Default: "1", Min: "0", Max: "1" +// +yb_pickup_best "1" + // // Allows or disallows bots to do map objectives, i.e. plant/defuse bombs, and saves hostages. // --- @@ -268,19 +289,40 @@ yb_password_key "_ybpw" // yb_csdm_mode "0" +// +// Specifies the maximum health of breakable object, that bot will consider to destroy. +// --- +// Default: "500.0", Min: "1.0", Max: "3000.0" +// +yb_breakable_health_limit "500.0" + // // Specifies whether bot should not 'fix' camp directions of camp waypoints when loading old PWF format. // --- -// Default: "1", Min: "0", Max: "1" +// Default: "0", Min: "0", Max: "1" // -yb_graph_fixcamp "1" +yb_graph_fixcamp "0" // // Specifies the URL from bots will be able to download graph in case of missing local one. Set to empty, if no downloads needed. // --- // Default: "yapb.jeefo.net" // -yb_graph_url "yapb.jeefo.net" +yb_graph_url "yapb-gcdn.akamaized.net" + +// +// Every N graph nodes placed on map, the graph will be saved automatically (without checks). +// --- +// Default: "15", Min: "0", Max: "2048" +// +yb_graph_auto_save_count "15" + +// +// Maximum distance to draw graph nodes from editor viewport. +// --- +// Default: "400", Min: "64", Max: "3072" +// +yb_graph_draw_distance "400" // // Kick bots to automatically make room for human players. @@ -289,6 +331,13 @@ yb_graph_url "yapb.jeefo.net" // yb_autovacate "1" +// +// Kick the bot immediately when a human player joins the server (yb_autovacate must be enabled). +// --- +// Default: "1", Min: "0", Max: "1" +// +yb_kick_after_player_connect "1" + // // Specifies the number bots to be added to the game. // --- @@ -402,7 +451,7 @@ yb_show_avatars "1" yb_show_latency "2" // -// Allows to save bot names upon changelevel, so bot names will be the same after a map change +// Allows to save bot names upon changelevel, so bot names will be the same after a map change. // --- // Default: "1", Min: "0", Max: "1" // @@ -436,6 +485,20 @@ yb_ping_base_min "7" // yb_ping_base_max "34" +// +// Interval in which bots are added to the game. +// --- +// Default: "0.1", Min: "0.1", Max: "1.0" +// +yb_quota_adding_interval "0.1" + +// +// Interval on which overall bot quota are checked. +// --- +// Default: "0.4", Min: "0.4", Max: "2.0" +// +yb_quota_maintain_interval "0.4" + // // Specifies the language for bot messages and menus. // --- @@ -443,6 +506,27 @@ yb_ping_base_max "34" // yb_language "en" +// +// Randomly disconnect and connect bots, simulating players join/quit. +// --- +// Default: "0", Min: "0", Max: "1" +// +yb_rotate_bots "0" + +// +// Specifies minimum amount of seconds bot keep connected, if rotation active. +// --- +// Default: "360.0", Min: "120.0", Max: "7200.0" +// +yb_rotate_stay_min "360.0" + +// +// Specifies maximum amount of seconds bot keep connected, if rotation active. +// --- +// Default: "3600.0", Min: "1800.0", Max: "14400.0" +// +yb_rotate_stay_max "3600.0" + // // Enables or disables extra hard difficulty for bots. // --- diff --git a/ext/crlib b/ext/crlib index 19242b1..dade2ad 160000 --- a/ext/crlib +++ b/ext/crlib @@ -1 +1 @@ -Subproject commit 19242b19194bf39dc97a5d51d27bd1f60f701597 +Subproject commit dade2ade585d7fbd3ac91dec93cd70c92225e832 diff --git a/i386pe.lds b/ext/ldscripts/i386pe.lds similarity index 100% rename from i386pe.lds rename to ext/ldscripts/i386pe.lds diff --git a/ldscript.lds b/ext/ldscripts/version.lds similarity index 100% rename from ldscript.lds rename to ext/ldscripts/version.lds diff --git a/inc/config.h b/inc/config.h index 91e3168..d86ca2d 100644 --- a/inc/config.h +++ b/inc/config.h @@ -38,20 +38,20 @@ public: }; private: - Array m_chat; - Array > m_chatter; + Array m_chat {}; + Array > m_chatter {}; - Array m_botNames; - Array m_replies; - SmallArray m_weapons; - SmallArray m_weaponProps; + Array m_botNames {}; + Array m_replies {}; + SmallArray m_weapons {}; + SmallArray m_weaponProps {}; - StringArray m_logos; - StringArray m_avatars; + StringArray m_logos {}; + StringArray m_avatars {}; - HashMap > m_language; - HashMap m_difficulty; - HashMap m_custom; + HashMap > m_language {}; + HashMap m_difficulty {}; + HashMap m_custom {}; // default tables for personality weapon preferences, overridden by weapon.cfg SmallArray m_normalWeaponPrefs = { 0, 2, 1, 4, 5, 6, 3, 12, 10, 24, 25, 13, 11, 8, 7, 22, 23, 18, 21, 17, 19, 15, 17, 9, 14, 16 }; diff --git a/inc/control.h b/inc/control.h index 640f727..38412f3 100644 --- a/inc/control.h +++ b/inc/control.h @@ -63,21 +63,21 @@ public: }; private: - StringArray m_args; - Array m_cmds; - Array m_menus; - Deque m_printQueue; - IntArray m_campIterator; + StringArray m_args {}; + Array m_cmds {}; + Array m_menus {}; + Deque m_printQueue {}; + IntArray m_campIterator {}; - edict_t *m_ent; - Bot *m_djump; + edict_t *m_ent {}; + Bot *m_djump {}; - bool m_isFromConsole; - bool m_rapidOutput; - bool m_isMenuFillCommand; - bool m_ignoreTranslate; + bool m_isFromConsole {}; + bool m_rapidOutput {}; + bool m_isMenuFillCommand {}; + bool m_ignoreTranslate {}; - int m_menuServerFillTeam; + int m_menuServerFillTeam {}; int m_interMenuData[4] = { 0, }; float m_printQueueFlushTimestamp {}; diff --git a/inc/engine.h b/inc/engine.h index 9f63681..10611e7 100644 --- a/inc/engine.h +++ b/inc/engine.h @@ -112,27 +112,27 @@ public: using EntitySearch = Lambda ; private: - int m_drawModels[DrawLine::Count] { }; - int m_spawnCount[Team::Unassigned] { }; + int m_drawModels[DrawLine::Count] {}; + int m_spawnCount[Team::Unassigned] {}; // bot client command - StringArray m_botArgs; + StringArray m_botArgs {}; - edict_t *m_startEntity; - edict_t *m_localEntity; + edict_t *m_startEntity {}; + edict_t *m_localEntity {}; - Array m_breakables; - SmallArray m_cvars; - SharedLibrary m_gameLib; - EngineWrap m_engineWrap; + Array m_breakables {}; + SmallArray m_cvars {}; + SharedLibrary m_gameLib {}; + EngineWrap m_engineWrap {}; - bool m_precached; + bool m_precached {}; int m_gameFlags {}; int m_mapFlags {}; - float m_oneSecondFrame; // per second updated - float m_halfSecondFrame; // per half second update + float m_oneSecondFrame {}; // per second updated + float m_halfSecondFrame {}; // per half second update public: Game (); @@ -240,8 +240,8 @@ public: } // gets custom engine argv for client command - const char *botArgv (size_t index) const { - if (index >= m_botArgs.length ()) { + const char *botArgv (int32 index) const { + if (static_cast (index) >= m_botArgs.length ()) { return ""; } return m_botArgs[index].chars (); @@ -517,7 +517,7 @@ public: class LightMeasure final : public Singleton { private: lightstyle_t m_lightstyle[MAX_LIGHTSTYLES] {}; - int m_lightstyleValue[MAX_LIGHTSTYLEVALUE] {}; + uint32 m_lightstyleValue[MAX_LIGHTSTYLEVALUE] {}; bool m_doAnimation = false; Color m_point; @@ -563,8 +563,8 @@ public: // simple handler for parsing and rewriting queries (fake queries) class QueryBuffer { - SmallArray m_buffer; - size_t m_cursor; + SmallArray m_buffer {}; + size_t m_cursor {}; public: QueryBuffer (const uint8 *msg, size_t length, size_t shift) : m_cursor (0) { @@ -640,7 +640,7 @@ private: #if defined (CR_WINDOWS) # define DLSYM_FUNCTION GetProcAddress # define DLCLOSE_FUNCTION FreeLibrary -# define DLSYM_RETURN PVOID +# define DLSYM_RETURN SharedLibrary::Handle # define DLSYM_HANDLE HMODULE #else # define DLSYM_FUNCTION dlsym @@ -654,7 +654,7 @@ private: Detour m_dlsym; Detour m_dlclose; - HashMap m_exports; + HashMap m_exports; SharedLibrary m_self; @@ -663,7 +663,7 @@ public: public: void initialize (); - DLSYM_RETURN lookup (SharedLibrary::Handle module, const char *function); + SharedLibrary::Func lookup (SharedLibrary::Handle module, const char *function); int close (DLSYM_HANDLE module) { if (m_self.handle () == module) { @@ -701,7 +701,7 @@ public: } public: - static DLSYM_RETURN CR_STDCALL lookupHandler (SharedLibrary::Handle module, const char *function) { + static SharedLibrary::Func CR_STDCALL lookupHandler (SharedLibrary::Handle module, const char *function) { return EntityLinkage::instance ().lookup (module, function); } diff --git a/inc/graph.h b/inc/graph.h index 4b49053..b91c127 100644 --- a/inc/graph.h +++ b/inc/graph.h @@ -186,10 +186,10 @@ struct PODPath { // this structure links nodes returned from pathfinder class PathWalk final : public DenyCopying { private: - size_t m_cursor = 0; - size_t m_length = 0; + size_t m_cursor {}; + size_t m_length {}; - UniquePtr m_path; + UniquePtr m_path {}; public: explicit PathWalk () = default; @@ -263,60 +263,59 @@ private: int x, y, z; }; - int m_editFlags; - int m_loadAttempts; - int m_cacheNodeIndex; - int m_lastJumpNode; - int m_findWPIndex; - int m_facingAtIndex; + int m_editFlags {}; + int m_loadAttempts {}; + int m_cacheNodeIndex {}; + int m_lastJumpNode {}; + int m_findWPIndex {}; + int m_facingAtIndex {}; int m_highestDamage[kGameTeamNum] {}; - int m_autoSaveCount; + int m_autoSaveCount {}; - float m_timeJumpStarted; - float m_autoPathDistance; - float m_pathDisplayTime; - float m_arrowDisplayTime; + float m_timeJumpStarted {}; + float m_autoPathDistance {}; + float m_pathDisplayTime {}; + float m_arrowDisplayTime {}; - bool m_isOnLadder; - bool m_endJumpPoint; - bool m_jumpLearnNode; - bool m_hasChanged; - bool m_needsVisRebuild; - bool m_narrowChecked; + bool m_isOnLadder {}; + bool m_endJumpPoint {}; + bool m_jumpLearnNode {}; + bool m_hasChanged {}; + bool m_needsVisRebuild {}; + bool m_narrowChecked {}; - Vector m_learnVelocity; - Vector m_learnPosition; - Vector m_bombOrigin; - Vector m_lastNode; + Vector m_learnVelocity {}; + Vector m_learnPosition {}; + Vector m_bombOrigin {}; + Vector m_lastNode {}; - IntArray m_terrorPoints; - IntArray m_ctPoints; - IntArray m_goalPoints; - IntArray m_campPoints; - IntArray m_sniperPoints; - IntArray m_rescuePoints; - IntArray m_visitedGoals; + IntArray m_terrorPoints {}; + IntArray m_ctPoints {}; + IntArray m_goalPoints {}; + IntArray m_campPoints {}; + IntArray m_sniperPoints {}; + IntArray m_rescuePoints {}; + IntArray m_visitedGoals {}; SmallArray m_buckets[kMaxBucketsInsidePos][kMaxBucketsInsidePos][kMaxBucketsInsidePos]; - SmallArray m_matrix; - SmallArray m_practice; - SmallArray m_paths; - SmallArray m_vistable; + SmallArray m_matrix {}; + SmallArray m_practice {}; + SmallArray m_paths {}; + SmallArray m_vistable {}; - String m_graphAuthor; - String m_graphModified; + String m_graphAuthor {}; + String m_graphModified {}; ExtenHeader m_extenHeader {}; StorageHeader m_graphHeader {}; - edict_t *m_editor; + edict_t *m_editor {}; public: BotGraph (); ~BotGraph () = default; public: - int getFacingIndex (); int getFarest (const Vector &origin, float maxDistance = 32.0); int getNearest (const Vector &origin, float minDistance = kInfiniteDistance, int flags = -1); diff --git a/inc/manager.h b/inc/manager.h index a92aaac..95b442e 100644 --- a/inc/manager.h +++ b/inc/manager.h @@ -54,13 +54,13 @@ public: using UniqueBot = UniquePtr ; private: - float m_timeRoundStart; - float m_timeRoundEnd; - float m_timeRoundMid; + float m_timeRoundStart {}; + float m_timeRoundEnd {}; + float m_timeRoundMid {}; - float m_autoKillCheckTime; // time to kill all the bots ? - float m_maintainTime; // time to maintain bot creation - float m_quotaMaintainTime; // time to maintain bot quota + float m_autoKillCheckTime {}; // time to kill all the bots ? + float m_maintainTime {}; // time to maintain bot creation + float m_quotaMaintainTime {}; // time to maintain bot quota float m_grenadeUpdateTime {}; // time to update active grenades float m_entityUpdateTime {}; // time to update intresting entities float m_plantSearchUpdateTime {}; // time to update for searching planted bomb @@ -68,26 +68,26 @@ private: float m_timeBombPlanted {}; // time the bomb were planted float m_lastRadioTime[kGameTeamNum] {}; // global radio time - int m_lastWinner; // the team who won previous round - int m_lastDifficulty; // last bots difficulty - int m_bombSayStatus; // some bot is issued whine about bomb + int m_lastWinner {}; // the team who won previous round + int m_lastDifficulty {}; // last bots difficulty + int m_bombSayStatus {}; // some bot is issued whine about bomb int m_lastRadio[kGameTeamNum] {}; // last radio message for team bool m_leaderChoosen[kGameTeamNum] {}; // is team leader choose theese round bool m_economicsGood[kGameTeamNum] {}; // is team able to buy anything - bool m_bombPlanted; - bool m_botsCanPause; - bool m_roundOver; + bool m_bombPlanted {}; + bool m_botsCanPause {}; + bool m_roundOver {}; - Array m_activeGrenades; // holds currently active grenades on the map - Array m_intrestingEntities; // holds currently intresting entities on the map + Array m_activeGrenades {}; // holds currently active grenades on the map + Array m_intrestingEntities {}; // holds currently intresting entities on the map - Deque m_saveBotNames; // bots names that persist upon changelevel - Deque m_addRequests; // bot creation tab - SmallArray m_filters; // task filters - SmallArray m_bots; // all available bots + Deque m_saveBotNames {}; // bots names that persist upon changelevel + Deque m_addRequests {}; // bot creation tab + SmallArray m_filters {}; // task filters + SmallArray m_bots {}; // all available bots - edict_t *m_killerEntity; // killer entity for bots + edict_t *m_killerEntity {}; // killer entity for bots FrustumData m_frustumData {}; protected: diff --git a/inc/message.h b/inc/message.h index e332c70..7ca4434 100644 --- a/inc/message.h +++ b/inc/message.h @@ -82,22 +82,22 @@ private: }; private: - HashMap m_textMsgCache; // cache strings for faster access for textmsg - HashMap m_showMenuCache; // cache for the showmenu message - HashMap m_statusIconCache; // cache for status icon message - HashMap m_teamInfoCache; // cache for teaminfo message + HashMap m_textMsgCache {}; // cache strings for faster access for textmsg + HashMap m_showMenuCache {}; // cache for the showmenu message + HashMap m_statusIconCache {}; // cache for status icon message + HashMap m_teamInfoCache {}; // cache for teaminfo message private: Bot *m_bot {}; // owner of a message NetMsg m_current {}; // ongoing message id - SmallArray m_args; // args collected from write* functions + SmallArray m_args {}; // args collected from write* functions - HashMap m_wanted; // wanted messages - HashMap m_reverseMap; // maps engine message id to our message id + HashMap m_wanted {}; // wanted messages + HashMap m_reverseMap {}; // maps engine message id to our message id - HashMap m_maps; // maps our message to id to engine message id - HashMap m_handlers; // maps our message id to handler function + HashMap m_maps {}; // maps our message to id to engine message id + HashMap m_handlers {}; // maps our message id to handler function private: void netMsgTextMsg (); diff --git a/inc/product.h b/inc/product.h index 7b8d23a..b18aed3 100644 --- a/inc/product.h +++ b/inc/product.h @@ -19,13 +19,13 @@ class Product final : public Singleton { public: struct Build { - StringRef hash { MODULE_BUILD_HASH }; - StringRef author { MODULE_BUILD_AUTHOR }; - StringRef count { MODULE_BUILD_COUNT }; - StringRef machine { MODULE_BUILD_MACHINE }; - StringRef compiler { MODULE_BUILD_COMPILER }; - StringRef id { MODULE_BOT_BUILD_ID }; - } build { }; + StringRef hash { MODULE_COMMIT_COUNT }; + StringRef count { MODULE_COMMIT_HASH }; + StringRef author { MODULE_AUTHOR }; + StringRef machine { MODULE_MACHINE }; + StringRef compiler { MODULE_COMPILER }; + StringRef id { MODULE_BUILD_ID }; + } build {}; public: StringRef name { "YaPB" }; @@ -38,7 +38,7 @@ public: StringRef logtag { "YB" }; StringRef dtime { __DATE__ " " __TIME__ }; StringRef date { __DATE__ }; - StringRef version { MODULE_BOT_VERSION "." MODULE_BUILD_COUNT }; + StringRef version { MODULE_VERSION "." MODULE_COMMIT_COUNT }; StringRef cmdPri { "yb" }; StringRef cmdSec { "yapb" }; }; diff --git a/inc/support.h b/inc/support.h index 1195b11..7e5f70b 100644 --- a/inc/support.h +++ b/inc/support.h @@ -21,15 +21,15 @@ CR_DECLARE_SCOPED_ENUM (Noise, class BotSupport final : public Singleton { private: - bool m_needToSendWelcome; - float m_welcomeReceiveTime; + bool m_needToSendWelcome {}; + float m_welcomeReceiveTime {}; - StringArray m_sentences; - SmallArray m_clients; - SmallArray > m_tags; + StringArray m_sentences {}; + SmallArray m_clients {}; + SmallArray > m_tags {}; - HashMap m_weaponAlias; - HashMap m_noiseCache; + HashMap m_weaponAlias {}; + HashMap m_noiseCache {}; Detour m_sendToDetour { "ws2_32.dll", "sendto", sendto }; public: diff --git a/inc/version.h b/inc/version.h index 14bcffd..c5143da 100644 --- a/inc/version.h +++ b/inc/version.h @@ -8,12 +8,11 @@ #pragma once // fallback if no git or custom build -#define MODULE_BUILD_HASH "0" -#define MODULE_BUILD_AUTHOR "yapb@jeefo.net" -#define MODULE_BUILD_COUNT "0" -#define MODULE_BUILD_MACHINE "localhost" -#define MODULE_BUILD_COMPILER "unknown" - -#define MODULE_BOT_VERSION "4.3" -#define MODULE_BOT_VERSION_FILE 4,3,0,000 -#define MODULE_BOT_BUILD_ID "0:0" +#define MODULE_COMMIT_COUNT "0" +#define MODULE_COMMIT_HASH "0" +#define MODULE_AUTHOR "default@mail.net" +#define MODULE_MACHINE "localhost" +#define MODULE_COMPILER "default" +#define MODULE_VERSION "4.0" +#define MODULE_VERSION_FILE 4,0,0,000 +#define MODULE_BUILD_ID "0:0" diff --git a/inc/version.h.in b/inc/version.h.in index 259f362..bd2185b 100644 --- a/inc/version.h.in +++ b/inc/version.h.in @@ -9,12 +9,12 @@ // generated by meson build system #ifndef MODULE_BUILD_HASH -# define MODULE_BUILD_HASH "@hash@" -# define MODULE_BUILD_AUTHOR @author@ -# define MODULE_BUILD_COUNT "@count@" -# define MODULE_BUILD_MACHINE "@machine@" -# define MODULE_BUILD_COMPILER "@compiler@" -# define MODULE_BOT_VERSION "@version@" -# define MODULE_BOT_VERSION_FILE @version_win@,@count@ -# define MODULE_BOT_BUILD_ID "@count@:@hash@" +# define MODULE_COMMIT_COUNT "@count@" +# define MODULE_COMMIT_HASH "@hash@" +# define MODULE_AUTHOR @author@ +# define MODULE_MACHINE "@machine@" +# define MODULE_COMPILER "@compiler@" +# define MODULE_VERSION "@version@" +# define MODULE_VERSION_FILE @winver@,@count@ +# define MODULE_BUILD_ID "@count@:@hash@" #endif diff --git a/inc/yapb.h b/inc/yapb.h index 1cb84b4..62554ea 100644 --- a/inc/yapb.h +++ b/inc/yapb.h @@ -349,7 +349,7 @@ CR_DECLARE_SCOPED_ENUM (Reload, ) // collision probes -CR_DECLARE_SCOPED_ENUM (CollisionProbe, +CR_DECLARE_SCOPED_ENUM (CollisionProbe, uint32, Jump = cr::bit (0), // probe jump when colliding Duck = cr::bit (1), // probe duck when colliding Strafe = cr::bit (2) // probe strafing when colliding @@ -367,7 +367,7 @@ CR_DECLARE_SCOPED_ENUM (BotMsg, ) // sensing states -CR_DECLARE_SCOPED_ENUM (Sense, +CR_DECLARE_SCOPED_ENUM_TYPE (Sense, uint32, SeeingEnemy = cr::bit (0), // seeing an enemy HearingEnemy = cr::bit (1), // hearing an enemy SuspectEnemy = cr::bit (2), // suspect enemy behind obstacle @@ -378,7 +378,7 @@ CR_DECLARE_SCOPED_ENUM (Sense, ) // positions to aim at -CR_DECLARE_SCOPED_ENUM (AimFlags, +CR_DECLARE_SCOPED_ENUM_TYPE (AimFlags, uint32, Nav = cr::bit (0), // aim at nav point Camp = cr::bit (1), // aim at camp vector PredictPath = cr::bit (2), // aim at predicted path @@ -590,12 +590,12 @@ struct Client { // define chatting collection structure struct ChatCollection { - int chatProbability; - float chatDelay; - float timeNextChat; - int entityIndex; - String sayText; - StringArray lastUsedSentences; + int chatProbability {}; + float chatDelay {}; + float timeNextChat {}; + int entityIndex {}; + String sayText {}; + StringArray lastUsedSentences {}; }; // include bot graph stuff @@ -622,7 +622,7 @@ private: int m_oldButtons {}; // our old buttons int m_reloadState {}; // current reload state - int m_voicePitch; // bot voice pitch + int m_voicePitch {}; // bot voice pitch int m_loosedBombNodeIndex {}; // nearest to loosed bomb node int m_plantedBombNodeIndex {}; // nearest to planted bomb node int m_currentNodeIndex {}; // current node index @@ -635,19 +635,18 @@ private: int m_tryOpenDoor {}; // attempt's to open the door int m_liftState {}; // state of lift handling int m_radioSelect {}; // radio entry - - + float m_headedTime {}; float m_prevTime {}; // time previously checked movement speed - float m_heavyTimestamp; // is it time to execute heavy-weight functions + float m_heavyTimestamp {}; // is it time to execute heavy-weight functions float m_prevSpeed {}; // speed some frames before float m_timeDoorOpen {}; // time to next door open check float m_lastChatTime {}; // time bot last chatted float m_timeLogoSpray {}; // time bot last spray logo float m_knifeAttackTime {}; // time to rush with knife (at the beginning of the round) float m_duckDefuseCheckTime {}; // time to check for ducking for defuse - float m_frameInterval; // bot's frame interval - float m_lastCommandTime; // time bot last thinked + float m_frameInterval {}; // bot's frame interval + float m_lastCommandTime {}; // time bot last thinked float m_reloadCheckTime {}; // time to check reloading float m_zoomCheckTime {}; // time to check zoom again float m_shieldCheckTime {}; // time to check shiled drawing again @@ -685,15 +684,15 @@ private: float m_minSpeed {}; // minimum speed in normal mode float m_oldCombatDesire {}; // holds old desire for filtering 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 + float m_joinServerTime {}; // time when bot joined the game + float m_playServerTime {}; // time bot spent in the game float m_changeViewTime {}; // timestamp to change look at while at freezetime float m_breakableTime {}; // breakeble acquired time bool m_moveToGoal {}; // bot currently moving to goal?? bool m_isStuck {}; // bot is stuck bool m_isReloading {}; // bot is reloading a gun - bool m_forceRadio; // should bot use radio anyway? + bool m_forceRadio {}; // should bot use radio anyway? bool m_defendedBomb {}; // defend action issued bool m_defendHostage {}; // defend action issued bool m_duckDefuse {}; // should or not bot duck to defuse bomb @@ -708,14 +707,14 @@ private: bool m_moveToC4 {}; // ct is moving to bomb bool m_grenadeRequested {}; // bot requested change to grenade - Pickup m_pickupType; // type of entity which needs to be used/picked up - PathWalk m_pathWalk; // pointer to current node from path - Dodge m_combatStrafeDir; // direction to strafe - Fight m_fightStyle; // combat style to use - CollisionState m_collisionState; // collision State - FindPath m_pathType; // which pathfinder to use + Pickup m_pickupType {}; // type of entity which needs to be used/picked up + PathWalk m_pathWalk {}; // pointer to current node from path + Dodge m_combatStrafeDir {}; // direction to strafe + Fight m_fightStyle {}; // combat style to use + CollisionState m_collisionState {}; // collision State + FindPath m_pathType {}; // which pathfinder to use uint8 m_enemyParts {}; // visibility flags - TraceResult m_lastTrace[TraceChannel::Num]; // last trace result + TraceResult m_lastTrace[TraceChannel::Num] {}; // last trace result edict_t *m_pickupItem {}; // pointer to entity of item to use/pickup edict_t *m_itemIgnore {}; // pointer to entity to ignore for pickup @@ -725,31 +724,31 @@ private: edict_t *m_targetEntity {}; // the entity that the bot is trying to reach edict_t *m_avoidGrenade {}; // pointer to grenade entity to avoid - Vector m_liftTravelPos; // lift travel position - Vector m_moveAngles; // bot move angles - Vector m_idealAngles; // angle wanted - Vector m_randomizedIdealAngles; // angle wanted with noise - Vector m_angularDeviation; // angular deviation from current to ideal angles - Vector m_aimSpeed; // aim speed calculated - Vector m_aimLastError; // last calculated aim error - Vector m_prevOrigin; // origin some frames before - Vector m_lookAt; // vector bot should look at - Vector m_throw; // origin of node to throw grenades - Vector m_enemyOrigin; // target origin chosen for shooting - Vector m_grenade; // calculated vector for grenades - Vector m_entity; // origin of entities like buttons etc. - Vector m_camp; // aiming vector when camping. - Vector m_desiredVelocity; // desired velocity for jump nodes - Vector m_breakableOrigin; // origin of breakable + Vector m_liftTravelPos {}; // lift travel position + Vector m_moveAngles {}; // bot move angles + Vector m_idealAngles {}; // angle wanted + Vector m_randomizedIdealAngles {}; // angle wanted with noise + Vector m_angularDeviation {}; // angular deviation from current to ideal angles + Vector m_aimSpeed {}; // aim speed calculated + Vector m_aimLastError {}; // last calculated aim error + Vector m_prevOrigin {}; // origin some frames before + Vector m_lookAt {}; // vector bot should look at + Vector m_throw {}; // origin of node to throw grenades + Vector m_enemyOrigin {}; // target origin chosen for shooting + Vector m_grenade {}; // calculated vector for grenades + Vector m_entity {}; // origin of entities like buttons etc. + Vector m_camp {}; // aiming vector when camping. + Vector m_desiredVelocity {}; // desired velocity for jump nodes + Vector m_breakableOrigin {}; // origin of breakable - Array m_ignoredBreakable; // list of ignored breakables - Array m_hostages; // pointer to used hostage entities - Array m_routes; // pointer - Array m_goalHistory; // history of selected goals + Array m_ignoredBreakable {}; // list of ignored breakables + Array m_hostages {}; // pointer to used hostage entities + Array m_routes {}; // pointer + Array m_goalHistory {}; // history of selected goals - BinaryHeap m_routeQue; + BinaryHeap m_routeQue {}; Path *m_path {}; // pointer to the current path node - String m_chatBuffer; // space for strings (say text...) + String m_chatBuffer {}; // space for strings (say text...) FrustumPlane m_frustum[FrustumSide::Num] {}; private: @@ -879,8 +878,8 @@ private: void focusEnemy (); void selectBestWeapon (); void selectSecondary (); - void selectWeaponByName (const char *name); - void selectWeaponById (int num); + void selectWeaponByName (StringRef name); + void selectWeaponByIndex (int index); void completeTask (); void tasks (); @@ -938,17 +937,17 @@ private: } public: - entvars_t *pev; + entvars_t *pev {}; - int m_index; // saved bot index - int m_wantedTeam; // player team bot wants select - int m_wantedSkin; // player model bot wants to select - int m_difficulty; // bots hard level - int m_moneyAmount; // amount of money in bot's bank + int m_index {}; // saved bot index + int m_wantedTeam {}; // player team bot wants select + int m_wantedSkin {}; // player model bot wants to select + int m_difficulty {}; // bots hard level + int m_moneyAmount {}; // amount of money in bot's bank float m_spawnTime {}; // time this bot spawned float m_timeTeamOrder {}; // time of last radio command - float m_slowFrameTimestamp; // time to per-second think + float m_slowFrameTimestamp {}; // time to per-second think float m_nextBuyTime {}; // next buy time float m_checkDarkTime {}; // check for darkness time float m_preventFlashing {}; // bot turned away from flashbang @@ -957,11 +956,11 @@ public: float m_blindSidemoveSpeed {}; // mad side move speeds when bot is blind float m_fallDownTime {}; // time bot started to fall float m_duckForJump {}; // is bot needed to duck for double jump - float m_baseAgressionLevel; // base aggression level (on initializing) - float m_baseFearLevel; // base fear level (on initializing) - float m_agressionLevel; // dynamic aggression level (in game) - float m_fearLevel; // dynamic fear level (in game) - float m_nextEmotionUpdate; // next time to sanitize emotions + float m_baseAgressionLevel {}; // base aggression level (on initializing) + float m_baseFearLevel {}; // base fear level (on initializing) + float m_agressionLevel {}; // dynamic aggression level (in game) + float m_fearLevel {}; // dynamic fear level (in game) + float m_nextEmotionUpdate {}; // next time to sanitize emotions float m_updateTime {}; // skip some frames in bot thinking float m_updateInterval {}; // interval between frames float m_goalValue {}; // ranking value for this node @@ -980,21 +979,21 @@ public: float m_shootTime {}; // time to shoot float m_timeLastFired {}; // time to last firing float m_difficultyChange {}; // time when auto-difficulty was last applied to this bot - float m_kpdRatio; // kill per death ratio - float m_healthValue; // clamped bot health - float m_stayTime; // stay time before reconnect + float m_kpdRatio {}; // kill per death ratio + float m_healthValue {}; // clamped bot health + float m_stayTime {}; // stay time before reconnect int m_blindNodeIndex {}; // node index to cover when blind int m_flashLevel {}; // flashlight level - int m_basePing; // base ping for bot + int m_basePing {}; // base ping for bot int m_numEnemiesLeft {}; // number of enemies alive left on map int m_numFriendsLeft {}; // number of friend alive left on map - int m_retryJoin; // retry count for chosing team/class - int m_startAction; // team/class selection state + int m_retryJoin {}; // retry count for chosing team/class + int m_startAction {}; // team/class selection state int m_voteKickIndex {}; // index of player to vote against int m_lastVoteKick {}; // last index int m_voteMap {}; // number of map to vote for - int m_logotypeIndex; // index for logotype + int m_logotypeIndex {}; // index for logotype int m_buyState {}; // current count in buying int m_blindButton {}; // buttons bot press, when blind int m_radioOrder {}; // actual command @@ -1002,14 +1001,14 @@ public: int m_chosenGoalIndex {}; // used for experience, same as above int m_lastDamageType {}; // stores last damage int m_team {}; // bot team - int m_currentWeapon; // one current weapon for each bot - int m_weaponType; // current weapon type + int m_currentWeapon {}; // one current weapon for each bot + int m_weaponType {}; // current weapon type int m_ammoInClip[kMaxWeapons] {}; // ammo in clip for each weapons int m_ammo[MAX_AMMO_SLOTS] {}; // total ammo amounts bool m_isVIP {}; // bot is vip? - bool m_notKilled; // has the player been killed or has he just respawned - bool m_notStarted; // team/class not chosen yet + bool m_notKilled {}; // has the player been killed or has he just respawned + bool m_notStarted {}; // team/class not chosen yet bool m_ignoreBuyDelay {}; // when reaching buyzone in the middle of the round don't do pauses bool m_inBombZone {}; // bot in the bomb zone or not bool m_inBuyZone {}; // bot currently in buy zone @@ -1033,17 +1032,17 @@ public: edict_t *m_lastVictim {}; // pointer to killed entity edict_t *m_trackingEdict {}; // pointer to last tracked player when camping/hiding - Vector m_pathOrigin; // origin of node - Vector m_destOrigin; // origin of move destination - Vector m_position; // position to move to in move to position task - Vector m_doubleJumpOrigin; // origin of double jump - Vector m_lastEnemyOrigin; // vector to last enemy origin + Vector m_pathOrigin {}; // origin of node + Vector m_destOrigin {}; // origin of move destination + Vector m_position {}; // position to move to in move to position task + Vector m_doubleJumpOrigin {}; // origin of double jump + Vector m_lastEnemyOrigin {}; // vector to last enemy origin - ChatCollection m_sayTextBuffer; // holds the index & the actual message of the last unprocessed text message of a player - BurstMode m_weaponBurstMode; // bot using burst mode? (famas/glock18, but also silencer mode) - Personality m_personality; // bots type - Array m_tasks; - Deque m_msgQueue; + ChatCollection m_sayTextBuffer {}; // holds the index & the actual message of the last unprocessed text message of a player + BurstMode m_weaponBurstMode {}; // bot using burst mode? (famas/glock18, but also silencer mode) + Personality m_personality {}; // bots type + Array m_tasks {}; + Deque m_msgQueue {}; public: Bot (edict_t *bot, int difficulty, int personality, int team, int skin); @@ -1101,6 +1100,7 @@ public: bool canSkipNextTrace (TraceChannel channel); int getAmmo (); + int getAmmo (int id); int getNearestToPlantedBomb (); float getFrameInterval (); @@ -1111,6 +1111,8 @@ public: int getAmmoInClip () const { return m_ammoInClip[m_currentWeapon]; } + + bool isLowOnAmmo (const int index, const float factor) const; Vector getCenter () const { return (pev->absmax + pev->absmin) * 0.5; diff --git a/meson.build b/meson.build index 8fb896d..87bb438 100644 --- a/meson.build +++ b/meson.build @@ -5,13 +5,12 @@ # SPDX-License-Identifier: MIT # +# version is now passed into the bot dll project ( 'yapb', 'cpp', - version: '4.3', license: 'MIT', - default_options: [ 'buildtype=release', 'b_ndebug=if-release', @@ -22,211 +21,202 @@ project ( 'optimization=3', 'default_library=static', 'cpp_eh=none', + 'cpp_rtti=false', 'b_vscrt=static_from_buildtype', 'b_lto=true', + 'b_lto_mode=default', 'b_lundef=true', ], - meson_version: '>=0.56.0') + meson_version: '>=0.58.0') -find_program ('ninja', required: true) -find_program ('git', required: true) -find_program ('hostname', required: true) +find_program('ninja', required: true) -cpp = meson.get_compiler ('cpp') -sys = host_machine.system () -target = host_machine.cpu_family () -version = meson.project_version () -count = run_command ('git', 'rev-list', '--count', 'HEAD', check: false).stdout ().strip () - -cpp_id = cpp.get_id () -cpp_version = cpp.version () - -optmize = get_option ('buildtype') == 'release' or get_option ('buildtype') == 'debugoptimized' - -msvc = cpp_id == 'msvc' or cpp_id == 'clang-cl' -gcc = cpp_id == 'gcc' -clang = cpp_id == 'clang' - -win32 = sys == 'windows' -linux = sys == 'linux' -mac = sys == 'darwin' -aarch64 = target == 'aarch64' +compiler= meson.get_compiler('cpp') +cross = meson.is_cross_build () +os = host_machine.system() +cpu = host_machine.cpu_family() +cxx = compiler.get_id() +build_type = get_option ('buildtype') +# cpp and ldflags from scratch +cxxflags = [] ldflags = [] -ccflags = [] -cdata = configuration_data() +# custom flags +flags_versioned = ['-DVERSION_GENERATED'] -if win32 - cdata.set ('version_win', ','.join (version.split ('.'))) - cdata.set ('machine', run_command ('hostname', check: false).stdout ().strip ()) -else - cdata.set ('version_win', version) - cdata.set ('machine', run_command ('hostname', '-f', check: false).stdout ().strip ()) +# git is optional, but it's setups our version info +git = find_program('git', required: false) + +if git.found() + run_command('git', 'config', '--global', '--add', 'safe.directory', '*', check: false) + + # get the commit data + count = run_command('git', 'rev-list', '--count', 'HEAD', check: false).stdout().strip() + hash = run_command ('git', 'rev-parse', '--short', 'HEAD', check: false).stdout().strip() + author = run_command ('git', 'log', '--pretty="%ae"', '-1', check: false).stdout().strip() + + hostname = find_program('hostname', required: false) + + if hostname.found() + machine = run_command('hostname', check: false).stdout().strip() + else + machine = 'unknown' + endif + + bot_version = meson.project_version() + cxx_version = compiler.version() + + if os == 'windows' + winver = ','.join(bot_version.split('.')) + else + winver = bot_version + endif + + cxxflags += flags_versioned + version_data = configuration_data() + + version_data.set('count', count) + version_data.set('hash', hash) + version_data.set('author', author) + version_data.set('machine', machine) + version_data.set('version', bot_version) + version_data.set('winver', winver) + version_data.set('compiler', '@0@ @1@'.format (cxx, cxx_version)) + + configure_file (input: 'inc/version.h.in', output: 'version.build.h', configuration: version_data) endif -cdata.set ('hash', run_command ('git', 'rev-parse', '--short', 'HEAD', check: false).stdout ().strip ()) -cdata.set ('author', run_command ('git', 'log', '--pretty="%ae"', '-1', check: false).stdout ().strip ()) - -cdata.set ('count', count) -cdata.set ('version', version) - -cdata.set ('compiler', cpp_id + ' ' + cpp_version) - -configure_file (input: 'inc/version.h.in', output: 'version.build.h', configuration: cdata) - -ccflags += '-DVERSION_GENERATED' - -if clang or gcc - ccflags += [ - '-fno-threadsafe-statics', - '-fno-exceptions', - '-fno-rtti' +# configure flags gcc and clang +if cxx == 'clang' or cxx == 'gcc' + cxxflags += [ + '-mtune=generic', '-fno-threadsafe-statics' ] - if not aarch64 - ccflags += '-m32' + if cpu == 'aarch64' + cxxflags += [ + '-march=armv8-a+fp+simd', + ] + else + cxxflags += [ + '-march=x86-64', '-mmmx', '-msse', '-msse2', '-msse3', '-mssse3', '-mfpmath=sse' + ] endif - - if not mac - ccflags += [ - '-pedantic', + + # setup optimization flags + if build_type == 'release' + cxxflags += [ + '-funroll-loops', '-fomit-frame-pointer', '-fno-stack-protector', '-fvisibility=hidden', '-fvisibility-inlines-hidden' + ] + + if os != 'darwin' and os != 'windows' and cpu != 'aarch64' + cxxflags += [ + '-fdata-sections', + '-ffunction-sections' + ] + + ldflags += [ + '-Wl,--version-script=../ext/ldscripts/version.lds', + '-Wl,--gc-sections' + ] + + if cxx == 'gcc' + cxxflags += [ + '-fgraphite-identity', '-floop-nest-optimize' + ] + ldflags += [ + '-fgraphite-identity', '-floop-nest-optimize', '-flto-partition=none' + ] + endif + endif + else + cxxflags += ['-g3', '-ggdb', '-DDEBUG', '-D_FORTIFY_SOURCE=2'] + endif + + # special script for mingw-64 builds + if os == 'windows' and cxx == 'gcc' and compiler.version().version_compare('<12.0') + ldflags += [ + '-Xlinker', '--script', '-Xlinker', '../ext/ldscripts/i386pe.lds' + ] + endif + + # always statically link libgcc on non darwin platforms + if os != 'darwin' + if cross or (cxx != 'clang' and os == 'windows') + ldflags += '-static-libgcc' + endif + else + cxxflags += '-mmacosx-version-min=10.9' + + ldflags += [ + '-lstdc++', '-mmacosx-version-min=10.9' + ] + endif + + # by default we buid 32bit binaries + if cpu != 'aarch64' and not get_option('64bit') + cxxflags += '-m32' + ldflags += '-m32' + + if cross and cxx == 'clang' and os == 'windows' + ldflags += '-Wl,/MACHINE:X86' + cxxflags += '-Wl,/MACHINE:X86' + endif + endif + + # link needed libraries + if os == 'linux' + ldflags += [ + '-lm','-ldl' + ] + elif os == 'windows' + if cxx == 'gcc' or (cross and cxx == 'clang') + ldflags += '-Wl,--kill-at' + endif + + ldflags += [ + '-luser32', '-lws2_32' + ] + endif +elif os == 'windows' and (cxx =='msvc' or cxx == 'clang-cl') + if not get_option('64bit') and cxx == 'clang' + cxxflags += '/MACHINE:X86' + ldflags += '/MACHINE:X86' + endif + + cxxflags += [ + '/TP', '/D _WIN32_WINNT=0x0501', '/D _USING_V110_SDK71_', '/Zc:threadSafeInit-' + ] + + # minor optimizations for release build + if build_type == 'release' + cxxflags += [ + '/GS-', '/Ob2', '/Oy', '/Oi', '/Ot', '/fp:precise', '/GF', '/GS-', '/GF', '/arch:SSE2' + ] + + # add wpo if msvc + if cxx == 'msvc' + cxxflags += [ + '/GL' + ] + endif + + # add linker flags + ldflags += [ + '/LTCG', 'delayimp.lib', '/DELAYLOAD:user32.dll', '/DELAYLOAD:ws2_32.dll', '/SUBSYSTEM:WINDOWS,5.01', ] endif - if optmize - if (clang or gcc) and not mac - if not aarch64 and not (clang and win32) - ccflags += [ - '-fdata-sections', - '-ffunction-sections' - ] - endif - - if gcc - ccflags += '-fgraphite-identity' - ldflags += '-flto-partition=none' - endif - - if not aarch64 and not (clang and win32) - ldflags += [ - '-Wl,--version-script=../ldscript.lds', - '-Wl,--gc-sections' - ] - endif - endif - endif - - if linux - ldflags += [ - '-lm', - '-ldl' - ] - if not aarch64 - ldflags += '-m32' - endif - endif -endif - -if linux or mac or (win32 and (gcc or clang)) - if mac - ccflags += '-mmacosx-version-min=10.9' - ldflags += [ - '-lstdc++', - '-mmacosx-version-min=10.9' - ] - else - ldflags += '-static-libgcc' - endif - - if not optmize - ccflags += [ - '-g3', - '-ggdb', - '-DCR_DEBUG' - ] - else - ccflags += [ - '-mtune=generic', - '-fno-builtin', - '-funroll-loops', - '-fomit-frame-pointer', - '-fno-stack-protector', - '-fvisibility=hidden', - '-fvisibility-inlines-hidden' - ] - - if not aarch64 - ccflags += [ - '-msse2', - '-mfpmath=sse', - ] - else - ccflags += '-march=armv8-a+fp+simd' - endif - - if clang and not mac - ldflags += [ - '-nostdlib++', - '-Wunused-command-line-argument' - ] - elif gcc and not mac - ldflags += '-Wl,--no-undefined' - endif - endif -endif - -if win32 and msvc ldflags += [ - '/MACHINE:X86', - 'user32.lib', - 'ws2_32.lib' + 'user32.lib', 'ws2_32.lib' ] - - ccflags += [ - '/TP', - '/D _WIN32_WINNT=0x0501', - '/D _USING_V110_SDK71_', - '/Zc:threadSafeInit-' - ] - - if optmize - ccflags += [ - '/GL', - '/GS-', - '/Ob2', - '/Oy', - '/Oi', - '/Ot', - '/fp:precise', - '/GF' - ] - ldflags += [ - '/LTCG', - 'delayimp.lib', - '/DELAYLOAD:user32.dll', - '/SUBSYSTEM:WINDOWS,5.01', - ] - endif - -elif win32 and (clang or gcc) - ldflags += [ - '-Wl,--kill-at', - '-luser32', - '-lws2_32' - ] - - if clang - ldflags += '-Wl,/MACHINE:X86' - ccflags += '-Wl,/MACHINE:X86' - else - ldflags += ['-Xlinker', '--script', '-Xlinker', '../i386pe.lds'] - endif endif -add_global_arguments (ccflags, language: 'cpp') +# pass our hell to meson +add_global_arguments (cxxflags, language: 'cpp') add_global_link_arguments (ldflags, language: 'cpp') +# add the sources sources = files ( 'src/botlib.cpp', 'src/chatlib.cpp', @@ -243,24 +233,27 @@ sources = files ( 'src/support.cpp' ) +# add the include directories includes = include_directories ([ '.', 'inc', 'ext', 'ext/crlib' ], is_system: true) -if win32 +# if have git and on windows add windows-specific version info +if os == 'windows' and git.found() sources += import('windows').compile_resources ( 'vc/yapb.rc', include_directories: includes, - args: ['-DVERSION_GENERATED'] + args: flags_versioned ) endif -shared_library ( - meson.project_name (), +# instruct meson we're want our little shared lib bot +shared_library( + meson.project_name(), sources, include_directories: includes, gnu_symbol_visibility: 'hidden', name_prefix: '') -run_target ('package', - command: ['python3', meson.project_source_root () + '/package.py', '@0@.@1@'.format (version, count)]) \ No newline at end of file +run_target('package', + command: ['python3', meson.project_source_root() + '/package.py', '@0@.@1@'.format(bot_version, count)]) \ No newline at end of file diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..3d6e907 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,9 @@ +# +# YaPB - Counter-Strike Bot based on PODBot by Markus Klinge. +# Copyright © 2004-2023 YaPB Project . +# +# SPDX-License-Identifier: MIT +# + +option('64bit', type : 'boolean', value : false, + description: 'Enables bot build with as 64-bit binary.') \ No newline at end of file diff --git a/package.py b/package.py index cb36d98..d69ebe4 100644 --- a/package.py +++ b/package.py @@ -7,295 +7,310 @@ # import os, sys, subprocess, base64 -import urllib3 +import glob, requests import pathlib, shutil import zipfile, tarfile import datetime, calendar -class CodeSign (object): - def __init__(self, product, url, verify_signature=False): +class BotSign(object): + def __init__(self, product: str, url: str): self.signing = True - self.ossl_path = "/usr/bin/osslsigncode" - self.local_key = os.path.join (pathlib.Path ().absolute (), "key.pfx"); + self.ossl_path = '/usr/bin/osslsigncode' + self.local_key = os.path.join(pathlib.Path().absolute(), 'bot_release_key.pfx'); self.product = product self.url = url - self.verify_signature = verify_signature - if not os.path.exists (self.ossl_path): + if not os.path.exists(self.ossl_path): self.signing = False - if not "CS_CERTIFICATE" in os.environ: + if not 'CS_CERTIFICATE' in os.environ: self.signing = False - if not "CS_CERTIFICATE_PASSWORD" in os.environ: + if not 'CS_CERTIFICATE_PASSWORD' in os.environ: self.signing = False if self.signing: - self.password = os.environ.get ("CS_CERTIFICATE_PASSWORD") + self.password = os.environ.get('CS_CERTIFICATE_PASSWORD') - encoded = os.environ.get ("CS_CERTIFICATE") + encoded = os.environ.get('CS_CERTIFICATE') - if len (encoded) < 64: - print ('Damaged certificate. Signing disabled.') + if len(encoded) < 64: + print('Damaged certificate. Signing disabled.') self.signing = False return - decoded = base64.b64decode (encoded) + decoded = base64.b64decode(encoded) - with open (self.local_key, "wb") as key: - key.write (decoded) + with open(self.local_key, 'wb') as key: + key.write(decoded) def has(self): return self.signing - def sign_file_inplace (self, filename): - signed_filename = filename + ".signed" - sign = [] + def sign_file_inplace(self, filename): + signed_filename = filename + '.signed' + signed_cmdline = [] - sign.append (self.ossl_path) - sign.append ("sign") - sign.append ("-pkcs12") - sign.append (self.local_key) - sign.append ("-pass") - sign.append (self.password) - sign.append ("-n") - sign.append (self.product) - sign.append ("-i") - sign.append (self.url) - sign.append ("-h") - sign.append ("sha384") - sign.append ("-t") - sign.append ("http://timestamp.sectigo.com") - sign.append ("-in") - sign.append (filename) - sign.append ("-out") - sign.append (signed_filename) - - result = subprocess.run (sign, capture_output=True, text=True) + signed_cmdline.append (self.ossl_path) + signed_cmdline.append ('sign') + signed_cmdline.append ('-pkcs12') + signed_cmdline.append (self.local_key) + signed_cmdline.append ('-pass') + signed_cmdline.append (self.password) + signed_cmdline.append ('-n') + signed_cmdline.append (self.product) + signed_cmdline.append ('-i') + signed_cmdline.append (self.url) + signed_cmdline.append ('-h') + signed_cmdline.append ('sha384') + signed_cmdline.append ('-t') + signed_cmdline.append ('http://timestamp.sectigo.com') + signed_cmdline.append ('-in') + signed_cmdline.append (filename) + signed_cmdline.append ('-out') + signed_cmdline.append (signed_filename) + result = subprocess.run (signed_cmdline, capture_output=True, text=True) + if result.returncode == 0: - os.unlink (filename) - shutil.move (signed_filename, filename) + os.unlink(filename) + shutil.move(signed_filename, filename) - print ("Signing result: {}".format (result.stdout)) + return False - if self.verify_signature: - verify = [] - verify.append (self.ossl_path) - verify.append ("verify") - verify.append (filename) +class BotPackage(object): + def __init__(self, name: str, archive: str, artifact: dict, extra: bool = False): + self.name = name + self.archive = archive + self.artifact = artifact + self.extra = extra - verify = subprocess.run (verify, capture_output=True, text=True) - print (verify.stdout) - - else: - print (result.stdout) - - -class BotRelease (object): +class BotRelease(object): def __init__(self): - print ("Initializing Packaging") - - meson_src_root_env = "MESON_SOURCE_ROOT" - - if meson_src_root_env in os.environ: - os.chdir (os.environ.get (meson_src_root_env)) - - self.work_dir = os.path.join (pathlib.Path ().absolute (), "cfg") - self.bot_dir = os.path.join (self.work_dir, "addons", "yapb") - self.pkg_dir = os.path.join (pathlib.Path ().absolute (), "pkg") - - if len (sys.argv) < 2: - raise Exception("Missing required parameters.") + if len(sys.argv) < 2: + raise Exception('Missing required parameters.') + self.project = 'yapb' self.version = sys.argv[1] self.artifacts = 'artifacts' + self.graphs = 'yapb-gcdn.akamaized.net' + self.win32exe = 'https://github.com/yapb/setup/releases/latest/download/botsetup.exe' + + meson_src_root_env = 'MESON_SOURCE_ROOT' - self.cs = CodeSign ("YaPB", "https://yapb.jeefo.net/") - - if self.cs.has (): - print ("Code Signing Enabled") + if meson_src_root_env in os.environ: + os.chdir(os.environ.get(meson_src_root_env)) else: - print ("Code Signing Disabled") + raise Exception(f'No direct access, only via meson build.') - os.makedirs (self.pkg_dir, exist_ok=True) - - self.pkg_win32 = os.path.join (self.pkg_dir, "yapb-{}-windows.zip".format (self.version)) - self.pkg_linux = os.path.join (self.pkg_dir, "yapb-{}-linux.tar.xz".format (self.version)) - self.pkg_macos = os.path.join (self.pkg_dir, "yapb-{}-macos.zip".format (self.version)) + path = pathlib.Path().absolute() - self.pkg_win32_sfx = self.pkg_win32.replace ("zip", "exe") - self.pkg_win32_sfx_url = "https://github.com/yapb/setup/releases/latest/download/botsetup.exe" + if not os.path.isdir(os.path.join(path, self.artifacts)): + raise Exception('Artifacts directory missing.') - def make_directories (self): - dirs = [ - "bin", - os.path.join ("data", "pwf"), - os.path.join ("data", "train"), - os.path.join ("data", "graph"), - os.path.join ("data", "logs") - ] + print(f'Releasing {self.project} v{self.version}') - for dir in dirs: - os.makedirs (os.path.join (self.bot_dir, dir), exist_ok=True) - - def http_pull (self, url, local_file): - http = urllib3.PoolManager (10, headers = {"user-agent": "YaPB"}) - data = http.urlopen ("GET", url) + self.work_dir = os.path.join(path, 'release') + shutil.copytree(f'{path}/cfg', self.work_dir, dirs_exist_ok=True) - with open (local_file, "wb") as file: - file.write (data.data) + self.bot_dir = os.path.join(self.work_dir, 'addons', self.project) + self.pkg_dir = os.path.join(path, 'pkg') + + self.cs = BotSign('YaPB', 'https://yapb.jeefo.net/') + + if self.cs.has(): + print('Signing enabled') + else: + print('Signing disabled') + + os.makedirs(self.pkg_dir, exist_ok=True) + self.http_pull(self.win32exe, 'botsetup.exe') + + self.pkg_matrix = [] + self.pkg_matrix.append (BotPackage('windows', 'zip', {'windows-x86': 'dll'})) + self.pkg_matrix.append (BotPackage('windows', 'exe', {'windows-x86': 'dll'})) + self.pkg_matrix.append (BotPackage('linux', 'tar.xz', {'linux-x86': 'so'})) + self.pkg_matrix.append (BotPackage('darwin', 'zip', {'darwin-x86': 'dylib'})) + self.pkg_matrix.append (BotPackage('extras', 'zip', {'linux-aarch64': 'so', 'linux-x86-gcc': 'so', 'windows-x86-gcc': 'dll', 'windows-x86-msvc': 'dll'}, extra=True)) + + def create_dirs(self): + for dir in ['pwf', 'train', 'graph', 'logs']: + os.makedirs(os.path.join(self.bot_dir, 'data', dir), exist_ok=True) + + def http_pull(self, url: str, tp: str): + headers = { + 'User-Agent': 'YaPB/4', + } + with requests.get(url, headers=headers) as r: + r.raise_for_status() + + with open(tp, 'wb') as f: + f.write(r.content) - def get_graph_file (self, name): - file = os.path.join (self.bot_dir, "data", "graph", "{}.graph".format (name)) - url = "https://yapb.jeefo.net/graph/{}.graph".format (name) + def get_graph_file(self, name: str): + file = os.path.join(self.bot_dir, 'data', 'graph', f'{name}.graph') + url = f'http://{self.graphs}/graph/{name}.graph' - if os.path.exists (file): + if os.path.exists(file): return - self.http_pull (url, file) + self.http_pull(url, file) - def get_default_graphs (self): - print ("Downloading graphs: ") - - default_list = "default.graph.txt" - self.http_pull ("https://gs.yapb.jeefo.net//DEFAULT.txt", default_list) + def create_graphs(self): + default_list = 'default.graph.txt' + self.http_pull(f'http://{self.graphs}/DEFAULT.txt', default_list) - with open (default_list) as file: - files = [line.rstrip () for line in file.readlines ()] + with open(default_list) as file: + files = [line.rstrip() for line in file.readlines()] for file in files: - print (" " + file) - - self.get_graph_file (file) + print(f'Getting graphs: {file} ', end='\r', flush=True) + self.get_graph_file(file) - def unlink_binaries (self): - libs = ["yapb.so", "yapb.arm64.so", "yapb.dll", "yapb.dylib"] - - for lib in libs: - path = os.path.join (self.bot_dir, "bin", lib) - - if os.path.exists (path): - os.remove (path) + print() - def sign_binary (self, binary): - if self.cs.has () and (binary.endswith ("dll") or binary.endswith ("exe")): - print ("Signing {}".format (binary)) - self.cs.sign_file_inplace (binary) - - def copy_binary (self, binary): - dest_path = os.path.join (self.bot_dir, "bin", os.path.basename (binary)) - shutil.copy (binary, dest_path) - - self.sign_binary (dest_path) - - def compress_directory (self, path, handle): - length = len (path) + 1 + def compress_directory(self, path: str, handle: zipfile.ZipFile): + length = len(path) + 1 empty_dirs = [] - for root, dirs, files in os.walk (path): - empty_dirs.extend ([dir for dir in dirs if os.listdir (os.path.join (root, dir)) == []]) + for root, dirs, files in os.walk(path): + empty_dirs.extend([dir for dir in dirs if os.listdir(os.path.join(root, dir)) == []]) for file in files: - file_path = os.path.join (root, file) - handle.write (file_path, file_path[length:]) + file_path = os.path.join(root, file) + handle.write(file_path, file_path[length:]) for dir in empty_dirs: - dir_path = os.path.join (root, dir) + dir_path = os.path.join(root, dir) - zif = zipfile.ZipInfo (dir_path[length:] + "/") - handle.writestr (zif, "") + zif = zipfile.ZipInfo(dir_path[length:] + '/') + handle.writestr(zif, '') empty_dirs = [] - def create_zip (self, dir): - zf = zipfile.ZipFile (dir, "w", zipfile.ZIP_DEFLATED, compresslevel=9) - zf.comment = bytes (self.version, encoding = "ascii") + def create_zip(self, dest: str, custom_dir: str = None): + zf = zipfile.ZipFile(dest, 'w', zipfile.ZIP_DEFLATED, compresslevel=9) + zf.comment = bytes(self.version, encoding = 'ascii') - self.compress_directory (self.work_dir, zf) - zf.close () + self.compress_directory(custom_dir if custom_dir else self.work_dir, zf) + zf.close() - def convert_zip_txz (self, zfn, txz): - timeshift = int ((datetime.datetime.now () - datetime.datetime.utcnow ()).total_seconds ()) + def convert_zip_txz(self, zfn: str, txz: str): + timeshift = int((datetime.datetime.now() - datetime.datetime.utcnow()).total_seconds()) - with zipfile.ZipFile (zfn) as zipf: - with tarfile.open (txz, "w:xz") as tarf: - for zif in zipf.infolist (): - tif = tarfile.TarInfo (name = zif.filename) + with zipfile.ZipFile(zfn) as zipf: + with tarfile.open(txz, 'w:xz') as tarf: + for zif in zipf.infolist(): + tif = tarfile.TarInfo(name = zif.filename) tif.size = zif.file_size - tif.mtime = calendar.timegm (zif.date_time) - timeshift + tif.mtime = calendar.timegm(zif.date_time) - timeshift - tarf.addfile (tarinfo = tif, fileobj = zipf.open (zif.filename)) + tarf.addfile(tarinfo = tif, fileobj = zipf.open(zif.filename)) - os.remove (zfn) + os.remove(zfn) - def install_binary (self, ext, unlink_existing = True): - lib = "yapb.{}".format (ext) - binary = os.path.join (self.artifacts, lib) + def convert_zip_sfx(self, zfn: str, exe: str): + with open('botsetup.exe', 'rb') as sfx, open(zfn, 'rb') as zfn, open(exe, 'wb') as dest: + dest.write(sfx.read()) + dest.write(zfn.read()) - if os.path.isdir (binary): - binary = os.path.join (binary, lib) - - if not os.path.exists (binary): - print ("Packaging failed for {}. Skipping...".format (lib)) - return False + self.sign_binary(exe) + + def unlink_binaries(self): + path = os.path.join(self.bot_dir, 'bin'); + + shutil.rmtree(path, ignore_errors=True) + os.makedirs(path, exist_ok=True) + + def sign_binary(self, binary: str): + if self.cs.has() and (binary.endswith('dll') or binary.endswith('exe')): + self.cs.sign_file_inplace(binary) + + def copy_binary(self, binary: str, artifact: str): + if artifact: + dest_path = os.path.join(self.bot_dir, 'bin', artifact) + os.makedirs(dest_path, exist_ok=True) + + dest_path = os.path.join(dest_path, os.path.basename(binary)) + else: + dest_path = os.path.join(self.bot_dir, 'bin', os.path.basename(binary)) + + shutil.copy(binary, dest_path) + self.sign_binary(dest_path) + + def install_binary(self, pkg: BotPackage): + num_artifacts_errors = 0 + num_artifacts = len(pkg.artifact) + + for artifact in pkg.artifact: + binary = os.path.join(self.artifacts, artifact, f'{self.project}.{pkg.artifact[artifact]}') + binary_base = os.path.basename(binary) + + if not os.path.exists(binary): + num_artifacts_errors += 1 + print(f'[{binary_base}: FAIL]', end=' ') + continue - if unlink_existing: - self.unlink_binaries () + print(f'[{binary_base}: OK]', end=' ') + + if num_artifacts == 1: + self.unlink_binaries() - self.copy_binary (binary) + self.copy_binary(binary, artifact if pkg.extra else None) - return True - - def create_pkg_win32 (self): - print ("Generating Win32 ZIP") - - if not self.install_binary ("dll"): - return + return num_artifacts_errors < num_artifacts + + def create_pkg(self, pkg: BotPackage): + dest = os.path.join (self.pkg_dir, f'{self.project}-{self.version}-{pkg.name}.{pkg.archive}') + dest_tmp = f'{dest}.tmp' - self.create_zip (self.pkg_win32) - self.http_pull (self.pkg_win32_sfx_url, "botsetup.exe") - - print ("Generating Win32 EXE") + if os.path.exists(dest): + os.remove(dest) + self.unlink_binaries() - with open ("botsetup.exe", "rb") as sfx, open (self.pkg_win32, "rb") as zfn, open (self.pkg_win32_sfx, "wb") as exe: - exe.write (sfx.read ()) - exe.write (zfn.read ()) + print(f'Generating {os.path.basename(dest)}:', end=' ') - self.sign_binary (self.pkg_win32_sfx) - - def create_pkg_linux (self): - print ("Generating Linux TXZ") - - self.unlink_binaries () - self.install_binary ("arm64.so") - - if not self.install_binary ("so", False): + if not self.install_binary(pkg): + print(' -> Failed...') return - tmp_file = "tmp.zip" - - self.create_zip (tmp_file) - self.convert_zip_txz (tmp_file, self.pkg_linux) + if dest.endswith('zip') or dest.endswith('exe'): + if pkg.extra: + dest_dir = os.path.join(self.bot_dir, 'bin') + self.create_zip(dest_tmp, dest_dir) + else: + self.create_zip(dest_tmp) - def create_pkg_macos (self): - print ("Generating macOS ZIP") - - if not self.install_binary ("dylib"): - return - - self.create_zip (self.pkg_macos) - - def create_pkgs (self): - self.create_pkg_linux () - self.create_pkg_win32 () - self.create_pkg_macos () + if dest.endswith('exe'): + self.convert_zip_sfx(dest_tmp, dest) + else: + shutil.move(dest_tmp, dest) + elif dest.endswith('tar.xz'): + self.create_zip(dest_tmp) + self.convert_zip_txz(dest_tmp, dest) -release = BotRelease () + print('-> Success...') + self.unlink_binaries() -release.make_directories () -release.get_default_graphs () -release.create_pkgs () + if os.path.exists(dest_tmp): + os.remove(dest_tmp) + def create_pkgs(self): + for pkg in self.pkg_matrix: + self.create_pkg(pkg) + + print('Finished release') + + @staticmethod + def run(): + r = BotRelease() + + r.create_dirs() + r.create_graphs() + r.create_pkgs() + +# entry point +if __name__ == "__main__": + BotRelease.run() \ No newline at end of file diff --git a/src/botlib.cpp b/src/botlib.cpp index 1e214a2..8a3b13a 100644 --- a/src/botlib.cpp +++ b/src/botlib.cpp @@ -71,8 +71,8 @@ void Bot::pushMsgQueue (int message) { } float Bot::isInFOV (const Vector &destination) { - float entityAngle = cr::modAngles (destination.yaw ()); // find yaw angle from source to destination... - float viewAngle = cr::modAngles (pev->v_angle.y); // get bot's current view angle... + float entityAngle = cr::wrapAngle360 (destination.yaw ()); // find yaw angle from source to destination... + float viewAngle = cr::wrapAngle360 (pev->v_angle.y); // get bot's current view angle... // return the absolute value of angle to destination entity // zero degrees means straight ahead, 45 degrees to the left or @@ -232,7 +232,8 @@ void Bot::checkGrenadesThrow () { } break; - case Weapon::Flashbang: { + case Weapon::Flashbang: + { int nearest = graph.getNearest ((m_lastEnemy->v.velocity * 0.5f).get2d () + m_lastEnemy->v.origin); if (nearest != kInvalidNodeIndex) { @@ -339,7 +340,7 @@ void Bot::avoidGrenades () { if (m_preventFlashing < game.time () && m_personality == Personality::Rusher && m_difficulty == Difficulty::Expert && strcmp (model, "flashbang.mdl") == 0) { // don't look at flash bang if (!(m_states & Sense::SeeingEnemy)) { - m_lookAt.y = cr::normalizeAngles ((game.getEntityOrigin (pent) - getEyesPos ()).angles ().y + 180.0f); + m_lookAt.y = cr::wrapAngle ((game.getEntityOrigin (pent) - getEyesPos ()).angles ().y + 180.0f); m_canChooseAimDirection = false; m_preventFlashing = game.time () + rg.get (1.0f, 2.0f); @@ -636,6 +637,7 @@ void Bot::updatePickups () { const auto &config = conf.getWeapons (); const auto &primary = config[primaryWeaponCarried]; const auto &secondary = config[secondaryWeaponCarried]; + const auto &primaryProp = conf.getWeaponProp (primary.id); const auto &secondaryProp = conf.getWeaponProp (secondary.id); @@ -950,7 +952,7 @@ void Bot::showChaterIcon (bool show) { return; } - auto sendBotVoice = [] (bool show, edict_t *ent, int ownId) { + auto sendBotVoice = [&show] (edict_t *ent, int ownId) { MessageWriter (MSG_ONE, msgs.id (NetMsg::BotVoice), nullptr, ent) // begin message .writeByte (show) // switch on/off .writeByte (ownId); @@ -964,13 +966,13 @@ void Bot::showChaterIcon (bool show) { } if (!show && (client.iconFlags[ownIndex] & ClientFlags::Icon) && client.iconTimestamp[ownIndex] < game.time ()) { - sendBotVoice (false, client.ent, entindex ()); + sendBotVoice (client.ent, entindex ()); client.iconTimestamp[ownIndex] = 0.0f; client.iconFlags[ownIndex] &= ~ClientFlags::Icon; } else if (show && !(client.iconFlags[ownIndex] & ClientFlags::Icon)) { - sendBotVoice (true, client.ent, entindex ()); + sendBotVoice (client.ent, entindex ()); } } } @@ -1225,43 +1227,36 @@ bool Bot::isWeaponRestrictedAMX (int weaponIndex) { return false; } - - // check for weapon restrictions - if (cr::bit (weaponIndex) & (kPrimaryWeaponMask | kSecondaryWeaponMask | Weapon::Shield)) { - auto restrictedWeapons = game.findCvar ("amx_restrweapons"); + auto checkRestriction = [&weaponIndex] (StringRef cvar, const int *data) -> bool { + auto restrictedWeapons = game.findCvar (cvar); if (restrictedWeapons.empty ()) { return false; } - constexpr int indices[] = { 4, 25, 20, -1, 8, -1, 12, 19, -1, 5, 6, 13, 23, 17, 18, 1, 2, 21, 9, 24, 7, 16, 10, 22, -1, 3, 15, 14, 0, 11 }; - // find the weapon index - int index = indices[weaponIndex - 1]; + int index = data[weaponIndex - 1]; // validate index range if (index < 0 || index >= static_cast (restrictedWeapons.length ())) { return false; } - return restrictedWeapons[index] != '0'; + return restrictedWeapons[static_cast (index)] != '0'; + }; + + // check for weapon restrictions + if (cr::bit (weaponIndex) & (kPrimaryWeaponMask | kSecondaryWeaponMask | Weapon::Shield)) { + constexpr int ids[] = { 4, 25, 20, -1, 8, -1, 12, 19, -1, 5, 6, 13, 23, 17, 18, 1, 2, 21, 9, 24, 7, 16, 10, 22, -1, 3, 15, 14, 0, 11 }; + + // verify restrictions + return checkRestriction ("amx_restrweapons", ids); } // check for equipment restrictions else { - auto restrictedEquipment = game.findCvar ("amx_restrequipammo"); + constexpr int ids[] = { -1, -1, -1, 3, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 0, 1, 5 }; - if (restrictedEquipment.empty ()) { - return false; - } - constexpr int indices[] = { -1, -1, -1, 3, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 0, 1, 5 }; - - // find the weapon index - int index = indices[weaponIndex - 1]; - - // validate index range - if (index < 0 || index >= static_cast (restrictedEquipment.length ())) { - return false; - } - return restrictedEquipment[index] != '0'; + // verify restrictions + return checkRestriction ("amx_restrequipammo", ids); } } @@ -1294,7 +1289,7 @@ int Bot::pickBestWeapon (int *vec, int count, int moneySave) { bool needMoreRandomWeapon = (m_personality == Personality::Careful) || (rg.chance (25) && m_personality == Personality::Normal); if (needMoreRandomWeapon) { - auto buyFactor = (m_moneyAmount - static_cast (moneySave)) / (16000.0f - static_cast (moneySave)) * 3.0f; + auto buyFactor = (static_cast (m_moneyAmount) - static_cast (moneySave)) / (16000.0f - static_cast (moneySave)) * 3.0f; if (buyFactor < 1.0f) { buyFactor = 1.0f; @@ -1537,7 +1532,7 @@ void Bot::buyStuff () { break; case BuyState::ArmorVestHelm: // if armor is damaged and bot has some money, buy some armor - if (pev->armorvalue < rg.get (50, 80) && teamHasGoodEconomics && (isPistolMode || (teamHasGoodEconomics && hasPrimaryWeapon ()))) { + if (pev->armorvalue < rg.get (50.0f, 80.0f) && teamHasGoodEconomics && (isPistolMode || (teamHasGoodEconomics && hasPrimaryWeapon ()))) { // if bot is rich, buy kevlar + helmet, else buy a single kevlar if (m_moneyAmount > 1500 && !isWeaponRestricted (Weapon::ArmorHelm)) { issueCommand ("buyequip;menuselect 2"); @@ -1988,7 +1983,7 @@ void Bot::filterTasks () { timeHeard += 10.0f; ratio = timeHeard * 0.1f; } - bool lowAmmo = m_ammoInClip[m_currentWeapon] < conf.findWeaponById (m_currentWeapon).maxClip * 0.18f; + bool lowAmmo = isLowOnAmmo (m_currentWeapon, 0.18f); bool sniping = m_sniperStopTime <= game.time () && lowAmmo; if (bots.isBombPlanted () || m_isStuck || usesKnife ()) { @@ -2169,6 +2164,10 @@ BotTask *Bot::getTask () { return &m_tasks.last (); } +bool Bot::isLowOnAmmo (const int id, const float factor) const { + return static_cast (m_ammoInClip[id]) < static_cast (conf.findWeaponById (id).maxClip) * factor; +} + void Bot::clearTask (Task id) { // this function removes one task from the bot task stack. @@ -2868,7 +2867,7 @@ void Bot::updateAimDir () { auto radius = graph[index].radius; if (radius > 0.0f) { - return Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (2.0f, 4.0f); + return Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (2.0f, 4.0f); } return nullptr; }; @@ -3952,7 +3951,7 @@ void Bot::defuseBomb_ () { graph.setBombOrigin (true); if (m_numFriendsLeft != 0 && rg.chance (50)) { - if (timeToBlowUp <= 3.0) { + if (timeToBlowUp <= 3.0f) { if (cv_radio_mode.int_ () == 2) { pushChatterMessage (Chatter::BarelyDefused); } @@ -4016,7 +4015,7 @@ void Bot::defuseBomb_ () { selectWeaponByName ("weapon_knife"); if (weaponIndex > 0 && weaponIndex < kNumWeapons) { - selectWeaponById (weaponIndex); + selectWeaponByIndex (weaponIndex); } m_isReloading = false; } @@ -4588,16 +4587,16 @@ void Bot::pickupItem_ () { if (index < 7) { // secondary weapon. i.e., pistol - int wid = 0; + int weaponIndex = 0; for (index = 0; index < 7; ++index) { if (pev->weapons & cr::bit (info[index].id)) { - wid = index; + weaponIndex = index; } } - if (wid > 0) { - selectWeaponById (wid); + if (weaponIndex > 0) { + selectWeaponByIndex (weaponIndex); issueCommand ("drop"); if (hasShield ()) { @@ -4608,15 +4607,17 @@ void Bot::pickupItem_ () { } else { // primary weapon - int wid = bestWeaponCarried (); + int weaponIndex = bestWeaponCarried (); bool niceWeapon = rateGroundWeapon (m_pickupItem); - if ((wid == Weapon::Shield || wid > 6 || hasShield ()) && niceWeapon) { - selectWeaponById (wid); + auto tab = conf.getRawWeapons (); + + if ((tab->id == Weapon::Shield || weaponIndex > 6 || hasShield ()) && niceWeapon) { + selectWeaponByIndex (weaponIndex); issueCommand ("drop"); } - if (!wid || !niceWeapon) { + if (!weaponIndex || !niceWeapon) { m_itemIgnore = m_pickupItem; m_pickupItem = nullptr; m_pickupType = Pickup::None; @@ -4640,10 +4641,10 @@ void Bot::pickupItem_ () { // near to shield? else if (itemDistance < 50.0f) { // get current best weapon to check if it's a primary in need to be dropped - int wid = bestWeaponCarried (); + int weaponIndex = bestWeaponCarried (); - if (wid > 6) { - selectWeaponById (wid); + if (weaponIndex > 6) { + selectWeaponByIndex (weaponIndex); issueCommand ("drop"); } } @@ -5059,7 +5060,7 @@ void Bot::logic () { pev->button &= ~IN_DUCK; m_moveSpeed = -pev->maxspeed; - m_strafeSpeed = pev->maxspeed * m_needAvoidGrenade; + m_strafeSpeed = pev->maxspeed * static_cast (m_needAvoidGrenade); } // time to reach waypoint @@ -5222,11 +5223,11 @@ void Bot::showDebugOverlay () { } String aimFlags; - for (int i = 0; i < 9; ++i) { - bool hasFlag = m_aimFlags & cr::bit (i); + for (uint32 i = 0u; i < 9u; ++i) { + auto bit = cr::bit (i); - if (hasFlag) { - aimFlags.appendf (" %s", flags[cr::bit (i)]); + if (m_aimFlags & bit) { + aimFlags.appendf (" %s", flags[static_cast (bit)]); } } auto weapon = util.weaponIdToAlias (m_currentWeapon); @@ -5289,7 +5290,11 @@ bool Bot::hasHostage () { } int Bot::getAmmo () { - const auto &prop = conf.getWeaponProp (m_currentWeapon); + return getAmmo (m_currentWeapon); +} + +int Bot::getAmmo (int id) { + const auto &prop = conf.getWeaponProp (id); if (prop.ammo1 == -1 || prop.ammo1 > kMaxWeapons - 1) { return 0; @@ -5408,11 +5413,12 @@ void Bot::updatePracticeValue (int damage) { if (graph.length () < 1 || graph.hasChanged () || m_chosenGoalIndex < 0 || m_prevGoalIndex < 0) { return; } + auto health = static_cast (m_healthValue); // only rate goal waypoint if bot died because of the damage // FIXME: could be done a lot better, however this cares most about damage done by sniping or really deadly weapons - if (m_healthValue - damage <= 0) { - graph.setDangerValue (m_team, m_chosenGoalIndex, m_prevGoalIndex, cr::clamp (graph.getDangerValue (m_team, m_chosenGoalIndex, m_prevGoalIndex) - static_cast (m_healthValue / 20), -kMaxPracticeGoalValue, kMaxPracticeGoalValue)); + if (health - damage <= 0) { + graph.setDangerValue (m_team, m_chosenGoalIndex, m_prevGoalIndex, cr::clamp (graph.getDangerValue (m_team, m_chosenGoalIndex, m_prevGoalIndex) - health / 20, -kMaxPracticeGoalValue, kMaxPracticeGoalValue)); } } @@ -5453,10 +5459,10 @@ void Bot::updatePracticeDamage (edict_t *attacker, int damage) { graph.setDangerDamage (victimIndex, victimIndex, victimIndex, cr::clamp (graph.getDangerDamage (victimTeam, victimIndex, victimIndex), 0, kMaxPracticeDamageValue)); } } - float updateDamage = util.isFakeClient (attacker) ? 10.0f : 7.0f; + auto updateDamage = util.isFakeClient (attacker) ? 10 : 7; // store away the damage done - int damageValue = cr::clamp (graph.getDangerDamage (m_team, victimIndex, attackerIndex) + static_cast (damage / updateDamage), 0, kMaxPracticeDamageValue); + int damageValue = cr::clamp (graph.getDangerDamage (m_team, victimIndex, attackerIndex) + damage / updateDamage, 0, kMaxPracticeDamageValue); if (damageValue > graph.getHighestDamageForTeam (m_team)) { graph.setHighestDamageForTeam (m_team, damageValue); @@ -6047,7 +6053,7 @@ float Bot::getShiftSpeed () { if (getCurrentTaskId () == Task::SeekCover || (pev->flags & FL_DUCKING) || (pev->button & IN_DUCK) || (m_oldButtons & IN_DUCK) || (m_currentTravelFlags & PathFlag::Jump) || (m_path != nullptr && m_path->flags & NodeFlag::Ladder) || isOnLadder () || isInWater () || m_isStuck) { return pev->maxspeed; } - return static_cast (pev->maxspeed * 0.4f); + return pev->maxspeed * 0.4f; } void Bot::calculateFrustum () { diff --git a/src/chatlib.cpp b/src/chatlib.cpp index e583736..9535c3a 100644 --- a/src/chatlib.cpp +++ b/src/chatlib.cpp @@ -61,12 +61,12 @@ void BotSupport::addChatErrors (String &line) { // "length / 2" percent of time drop a character if (rg.chance (percentile)) { - line.erase (rg.get (length / 8, length - length / 8), 1); + line.erase (static_cast (rg.get (length / 8, length - length / 8), 1)); } // "length" / 4 precent of time swap character if (rg.chance (percentile / 2)) { - size_t pos = rg.get (length / 8, 3 * length / 8); // choose random position in string + size_t pos = static_cast (rg.get (length / 8, 3 * length / 8)); // choose random position in string cr::swap (line[pos], line[pos + 1]); } } @@ -190,7 +190,7 @@ void Bot::prepareChatMessage (StringRef message) { // get bot's victim auto getMyVictim = [&] () -> String {; - return humanizedName (game.indexOfPlayer (m_lastVictim)); + return humanizedName (game.indexOfPlayer (m_lastVictim)); }; // get the game name alias diff --git a/src/combat.cpp b/src/combat.cpp index b36b1b7..1b33a3f 100644 --- a/src/combat.cpp +++ b/src/combat.cpp @@ -461,8 +461,8 @@ Vector Bot::getBodyOffsetError (float distance) { } if (m_aimErrorTime < game.time ()) { - const float error = distance / (cr::clamp (m_difficulty, 1, 3) * 1000.0f); - Vector &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins; + const float error = distance / (cr::clamp (static_cast (m_difficulty), 1.0f, 3.0f) * 1000.0f); + auto &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins; m_aimLastError = Vector (rg.get (mins.x * error, maxs.x * error), rg.get (mins.y * error, maxs.y * error), rg.get (mins.z * error, maxs.z * error)); m_aimErrorTime = game.time () + rg.get (1.0f, 1.2f); @@ -728,7 +728,7 @@ bool Bot::needToPauseFiring (float distance) { const float yPunch = cr::deg2rad (pev->punchangle.y); const float interval = getFrameInterval (); - const float tolerance = (100.0f - m_difficulty * 25.0f) / 99.0f; + const float tolerance = (100.0f - static_cast (m_difficulty) * 25.0f) / 99.0f; // check if we need to compensate recoil if (cr::tanf (cr::sqrtf (cr::abs (xPunch * xPunch) + cr::abs (yPunch * yPunch))) * distance > offset + 30.0f + tolerance) { @@ -848,10 +848,8 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) { } } else { - const auto &prop = conf.getWeaponProp (tab[index].id); - // if automatic weapon press attack - if (tab[choosen].primaryFireHold && m_ammo[prop.ammo1] > tab[index].minPrimaryAmmo) { + if (tab[choosen].primaryFireHold && getAmmo (tab[index].id) > tab[index].minPrimaryAmmo) { pev->button |= IN_ATTACK; } @@ -953,9 +951,7 @@ void Bot::fireWeapons () { // is the bot carrying this weapon? if (weapons & cr::bit (id)) { - const auto &prop = conf.getWeaponProp (id); - - if (prop.ammo1 != -1 && prop.ammo1 < kMaxWeapons && m_ammo[prop.ammo1] >= tab[selectIndex].minPrimaryAmmo) { + if (getAmmo (id) >= tab[selectIndex].minPrimaryAmmo) { // available ammo found, reload weapon if (m_reloadState == Reload::None || m_reloadCheckTime > game.time ()) { @@ -1431,10 +1427,9 @@ void Bot::selectBestWeapon () { if (tab[selectIndex].id == m_currentWeapon && (getAmmoInClip () < 0 || getAmmoInClip () >= tab[selectIndex].minPrimaryAmmo)) { ammoLeft = true; } - const auto &prop = conf.getWeaponProp (id); // is no ammo required for this weapon OR enough ammo available to fire - if (prop.ammo1 < 0 || (prop.ammo1 < kMaxWeapons && m_ammo[prop.ammo1] >= tab[selectIndex].minPrimaryAmmo)) { + if (getAmmo (id) >= tab[selectIndex].minPrimaryAmmo) { ammoLeft = true; } @@ -1485,14 +1480,13 @@ int Bot::bestWeaponCarried () { return num; } -void Bot::selectWeaponByName (const char *name) { - issueCommand (name); +void Bot::selectWeaponByName (StringRef name) { + issueCommand (name.chars ()); } -void Bot::selectWeaponById (int num) { +void Bot::selectWeaponByIndex (int index) { auto tab = conf.getRawWeapons (); - - issueCommand (tab[num].name); + issueCommand (tab[index].name); } void Bot::decideFollowUser () { @@ -1599,7 +1593,7 @@ void Bot::checkReload () { m_reloadCheckTime = game.time () + 3.0f; if (m_reloadState != Reload::None) { - int weaponIndex = 0; + int wid = 0; int weapons = pev->weapons; if (m_reloadState == Reload::Primary) { @@ -1620,15 +1614,15 @@ void Bot::checkReload () { for (int i = 1; i < kMaxWeapons; ++i) { if (weapons & cr::bit (i)) { - weaponIndex = i; + wid = i; break; } } - const auto &prop = conf.getWeaponProp (weaponIndex); + const auto &prop = conf.getWeaponProp (wid); - if (m_ammoInClip[weaponIndex] < conf.findWeaponById (weaponIndex).maxClip * 0.8f && prop.ammo1 != -1 && prop.ammo1 < kMaxWeapons && m_ammo[prop.ammo1] > 0) { - if (m_currentWeapon != weaponIndex) { - selectWeaponByName (prop.classname.chars ()); + if (isLowOnAmmo (prop.id, 0.75f) && getAmmo (prop.id) > 0) { + if (m_currentWeapon != prop.id) { + selectWeaponByName (prop.classname); } pev->button &= ~IN_ATTACK; diff --git a/src/config.cpp b/src/config.cpp index 96ec913..3499352 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -95,6 +95,9 @@ void BotConfig::loadMainConfig (bool isFirstLoad) { } file.close (); } + else { + game.serverCommand (strings.format ("%s cvars save", product.cmdPri)); + } // android is abit hard to play, lower the difficulty by default if (plat.android && cv_difficulty.int_ () > 3) { diff --git a/src/control.cpp b/src/control.cpp index d140a35..a238356 100644 --- a/src/control.cpp +++ b/src/control.cpp @@ -45,10 +45,10 @@ int BotControl::cmdKickBot () { enum args { alias = 1, team }; // if team is specified, kick from specified tram - if (strValue (alias).find ("_ct", 0) != String::InvalidIndex || intValue (team) == 2 || strValue (team) == "ct") { + if (strValue (alias).endsWith ("_ct") || intValue (team) == 2 || strValue (team) == "ct") { bots.kickFromTeam (Team::CT); } - else if (strValue (alias).find ("_t", 0) != String::InvalidIndex || intValue (team) == 1 || strValue (team) == "t") { + else if (strValue (alias).endsWith ("_t") || intValue (team) == 1 || strValue (team) == "t") { bots.kickFromTeam (Team::Terrorist); } else { @@ -73,10 +73,10 @@ int BotControl::cmdKillBots () { enum args { alias = 1, team, max }; // if team is specified, kick from specified tram - if (strValue (alias).find ("_ct", 0) != String::InvalidIndex || intValue (team) == 2 || strValue (team) == "ct") { + if (strValue (alias).endsWith ("_ct") || intValue (team) == 2 || strValue (team) == "ct") { bots.killAllBots (Team::CT); } - else if (strValue (alias).find ("_t", 0) != String::InvalidIndex || intValue (team) == 1 || strValue (team) == "t") { + else if (strValue (alias).endsWith ("_t") || intValue (team) == 1 || strValue (team) == "t") { bots.killAllBots (Team::Terrorist); } else { @@ -488,7 +488,7 @@ int BotControl::cmdNodeSave () { else { if (graph.checkNodes (false)) { graph.saveGraphData (); - msg ("All nodes has been saved and written to disk."); + msg ("All nodes has been saved and written to disk.\n*** Please don't forget to share your work by typing \"%s g upload\". Thank you! ***", product.cmdPri); } else { msg ("Could not save save nodes to disk. Graph check has failed."); @@ -1943,7 +1943,7 @@ void BotControl::kickBotByMenu (int page) { for (auto &menu : m_menus) { if (menu.ident == id) { - menu.slots = menuKeys & static_cast (-1); + menu.slots = static_cast (static_cast (menuKeys) & static_cast (-1)); menu.text = menus; break; diff --git a/src/engine.cpp b/src/engine.cpp index 51c0005..2e4d155 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -681,7 +681,7 @@ void Game::checkCvarsBounds () { if (is (GameFlags::Xash3D)) { static cvar_t *sv_forcesimulating = engfuncs.pfnCVarGetPointer ("sv_forcesimulating"); - if (sv_forcesimulating && sv_forcesimulating->value != 1.0f) { + if (sv_forcesimulating && !cr::fequal (sv_forcesimulating->value, 1.0f)) { game.print ("Force-enable Xash3D sv_forcesimulating cvar."); engfuncs.pfnCVarSetFloat ("sv_forcesimulating", 1.0f); } @@ -798,7 +798,7 @@ bool Game::loadCSBinary () { auto entity = m_gameLib.resolve ("weapon_famas"); // detect xash engine - if (engfuncs.pfnCVarGetPointer ("build") != nullptr) { + if (engfuncs.pfnCVarGetPointer ("host_ver") != nullptr) { m_gameFlags |= (GameFlags::Legacy | GameFlags::Xash3D); if (entity != nullptr) { @@ -1035,7 +1035,7 @@ bool Game::isShootableBreakable (edict_t *ent) { auto limit = cv_breakable_health_limit.float_ (); if ((strcmp (ent->v.classname.chars (), "func_breakable") == 0 && ent->v.health < limit) || (strcmp (ent->v.classname.chars (), "func_pushable") == 0 && (ent->v.spawnflags & SF_PUSH_BREAKABLE) && ent->v.health < limit) || (strcmp (ent->v.classname.chars (), "func_wall") == 0 && ent->v.health < limit)) { - if (ent->v.takedamage != DAMAGE_NO && ent->v.impulse <= 0 && !(ent->v.flags & FL_WORLDBRUSH) && !(ent->v.spawnflags & SF_BREAK_TRIGGER_ONLY)) { + if (ent->v.takedamage > 0.0f && ent->v.impulse <= 0 && !(ent->v.flags & FL_WORLDBRUSH) && !(ent->v.spawnflags & SF_BREAK_TRIGGER_ONLY)) { return (ent->v.movetype == MOVETYPE_PUSH || ent->v.movetype == MOVETYPE_PUSHSTEP); } } @@ -1112,8 +1112,7 @@ void LightMeasure::animateLight () { m_lightstyleValue[j] = 256; continue; } - int value = m_lightstyle[j].map[index % m_lightstyle[j].length] - 'a'; - m_lightstyleValue[j] = value * 22; + m_lightstyleValue[j] = static_cast (m_lightstyle[j].map[index % m_lightstyle[j].length] - 'a') * 22u; } } diff --git a/src/graph.cpp b/src/graph.cpp index 02360bb..8b53e46 100644 --- a/src/graph.cpp +++ b/src/graph.cpp @@ -7,7 +7,7 @@ #include -ConVar cv_graph_fixcamp ("yb_graph_fixcamp", "1", "Specifies whether bot should not 'fix' camp directions of camp waypoints when loading old PWF format."); +ConVar cv_graph_fixcamp ("yb_graph_fixcamp", "0", "Specifies whether bot should not 'fix' camp directions of camp waypoints when loading old PWF format."); ConVar cv_graph_url ("yb_graph_url", product.download.chars (), "Specifies the URL from bots will be able to download graph in case of missing local one. Set to empty, if no downloads needed.", false, 0.0f, 0.0f); ConVar cv_graph_auto_save_count ("yb_graph_auto_save_count", "15", "Every N graph nodes placed on map, the graph will be saved automatically (without checks).", true, 0.0f, kMaxNodes); ConVar cv_graph_draw_distance ("yb_graph_draw_distance", "400", "Maximum distance to draw graph nodes from editor viewport.", true, 64.0f, 3072.0f); @@ -33,7 +33,6 @@ void BotGraph::reset () { for (int team = Team::Terrorist; team < kGameTeamNum; ++team) { m_highestDamage[team] = 1; } - m_graphAuthor.clear (); m_graphModified.clear (); } @@ -59,7 +58,7 @@ int BotGraph::clearConnections (int index) { struct Connection { int index {}; int number {}; - int distance {}; + float distance {}; float angles {}; public: @@ -71,7 +70,7 @@ int BotGraph::clearConnections (int index) { void reset () { index = kInvalidNodeIndex; number = kInvalidNodeIndex; - distance = kInfiniteDistanceLong; + distance = kInfiniteDistance; angles = 0.0f; } }; @@ -86,14 +85,14 @@ int BotGraph::clearConnections (int index) { cur.number = i; cur.index = link.index; - cur.distance = link.distance; + cur.distance = static_cast (link.distance); if (cur.index == kInvalidNodeIndex) { - cur.distance = kInfiniteDistanceLong; + cur.distance = kInfiniteDistance; } if (cur.distance < top.distance) { - top.distance = link.distance; + top.distance = static_cast (link.distance); top.number = i; top.index = cur.index; } @@ -173,7 +172,7 @@ int BotGraph::clearConnections (int index) { return false; } - if ((cur.distance + prev2.distance) * 1.1f / 2.0f < static_cast (prev.distance)) { + if ((cur.distance + prev2.distance) * 1.1f / 2.0f < prev.distance) { if (path.links[prev.number].index == prev.index) { ctrl.msg ("Removing a useless (P.0.1) connection from index = %d to %d.", index, prev.index); @@ -215,7 +214,7 @@ int BotGraph::clearConnections (int index) { // check pass 1 if (exists (top.index) && exists (sorted[0].index) && exists (sorted[1].index)) { if ((sorted[1].angles - top.angles < 80.0f || 360.0f - (sorted[1].angles - top.angles) < 80.0f) && (!(m_paths[sorted[0].index].flags & NodeFlag::Ladder) || !(path.flags & NodeFlag::Ladder)) && !(path.links[sorted[0].number].flags & PathFlag::Jump)) { - if ((sorted[1].distance + top.distance) * 1.1f / 2.0f < static_cast (sorted[0].distance)) { + if ((sorted[1].distance + top.distance) * 1.1f / 2.0f < sorted[0].distance) { if (path.links[sorted[0].number].index == sorted[0].index) { ctrl.msg ("Removing a useless (P.1.1) connection from index = %d to %d.", index, sorted[0].index); @@ -257,7 +256,7 @@ int BotGraph::clearConnections (int index) { } if (cur.angles - prev.angles < 40.0f) { - if (prev.distance < static_cast (cur.distance * 1.1f)) { + if (prev.distance < cur.distance * 1.1f) { // leave alone ladder connections and don't remove jump connections.. if (((path.flags & NodeFlag::Ladder) && (m_paths[cur.index].flags & NodeFlag::Ladder)) || (path.links[cur.number].flags & PathFlag::Jump)) { @@ -290,7 +289,7 @@ int BotGraph::clearConnections (int index) { ctrl.msg ("Failed to remove a useless (P.2) connection from index = %d to %d.", index, cur.index); } } - else if (cur.distance < static_cast (prev.distance * 1.1f)) { + else if (cur.distance < prev.distance * 1.1f) { // leave alone ladder connections and don't remove jump connections.. if (((path.flags & NodeFlag::Ladder) && (m_paths[prev.index].flags & NodeFlag::Ladder)) || (path.links[prev.number].flags & PathFlag::Jump)) { return false; @@ -338,7 +337,7 @@ int BotGraph::clearConnections (int index) { // check pass 3 if (exists (top.index) && exists (sorted[0].index)) { if ((top.angles - sorted[0].angles < 40.0f || (360.0f - top.angles - sorted[0].angles) < 40.0f) && (!(m_paths[sorted[0].index].flags & NodeFlag::Ladder) || !(path.flags & NodeFlag::Ladder)) && !(path.links[sorted[0].number].flags & PathFlag::Jump)) { - if (top.distance * 1.1f < static_cast (sorted[0].distance)) { + if (top.distance * 1.1f < sorted[0].distance) { if (path.links[sorted[0].number].index == sorted[0].index) { ctrl.msg ("Removing a useless (P.3.1) connection from index = %d to %d.", index, sorted[0].index); @@ -364,7 +363,7 @@ int BotGraph::clearConnections (int index) { ctrl.msg ("Failed to remove a useless (P.3) connection from index = %d to %d.", sorted[0].index, index); } } - else if (sorted[0].distance * 1.1f < static_cast (top.distance) && !(path.links[top.number].flags & PathFlag::Jump)) { + else if (sorted[0].distance * 1.1f < top.distance && !(path.links[top.number].flags & PathFlag::Jump)) { if (path.links[top.number].index == top.index) { ctrl.msg ("Removing a useless (P.3.3) connection from index = %d to %d.", index, sorted[0].index); @@ -903,7 +902,7 @@ void BotGraph::setRadius (int index, float radius) { int node = exists (index) ? index : getEditorNearest (); if (node != kInvalidNodeIndex) { - m_paths[node].radius = static_cast (radius); + m_paths[node].radius = radius; // play "done" sound... game.playSound (m_editor, "common/wpn_hudon.wav"); @@ -1235,7 +1234,7 @@ void BotGraph::calculatePathRadius (int index) { break; } - direction.y = cr::normalizeAngles (direction.y + static_cast (circleRadius)); + direction.y = cr::wrapAngle (direction.y + static_cast (circleRadius)); } if (wayBlocked) { @@ -1362,7 +1361,7 @@ bool BotGraph::loadPathMatrix () { if (distance < (matrix + (i * count) + j)->dist) { (matrix + (i * count) + j)->dist = static_cast (distance); - (matrix + (i * count) + j)->index = static_cast ((matrix + (i * count) + k)->index); + (matrix + (i * count) + j)->index = (matrix + (i * count) + k)->index; } } } @@ -1625,11 +1624,11 @@ template bool BotGraph::saveStorage (StringRef ext, StringRef name, logger.error ("Unable to open %s file for writing (filename: '%s').", name, filename); return false; } - int32 rawLength = data.template length () * sizeof (U); + auto rawLength = data.length () * sizeof (U); SmallArray compressed (rawLength + sizeof (uint8) * ULZ::Excess); // try to compress - auto compressedLength = ulz.compress (reinterpret_cast (data.data ()), rawLength, reinterpret_cast (compressed.data ())); + auto compressedLength = static_cast (ulz.compress (reinterpret_cast (data.data ()), static_cast (rawLength), reinterpret_cast (compressed.data ()))); if (compressedLength > 0) { StorageHeader hdr {}; @@ -1638,8 +1637,8 @@ template bool BotGraph::saveStorage (StringRef ext, StringRef name, hdr.version = version; hdr.options = options; hdr.length = length (); - hdr.compressed = compressedLength; - hdr.uncompressed = rawLength; + hdr.compressed = static_cast (compressedLength); + hdr.uncompressed = static_cast (rawLength); file.write (&hdr, sizeof (StorageHeader)); file.write (compressed.data (), sizeof (uint8), compressedLength); @@ -1788,15 +1787,18 @@ template bool BotGraph::loadStorage (StringRef ext, StringRef name, if ((hdr.options & options) != options) { return raiseLoadingError (isGraph, file, "Incorrect storage format for %s (filename: '%s').", name, filename); } - SmallArray compressed (hdr.compressed + sizeof (uint8) * ULZ::Excess); + auto compressedSize = static_cast (hdr.compressed); + auto numberNodes = static_cast (hdr.length); + + SmallArray compressed (compressedSize + sizeof (uint8) * ULZ::Excess); // graph is not resized upon load if (isGraph) { - resizeData (hdr.length); + resizeData (numberNodes); } // read compressed data - if (file.read (compressed.data (), sizeof (uint8), hdr.compressed) == static_cast (hdr.compressed)) { + if (file.read (compressed.data (), sizeof (uint8), compressedSize) == compressedSize) { // try to uncompress if (ulz.uncompress (compressed.data (), hdr.compressed, reinterpret_cast (data.data ()), hdr.uncompressed) == ULZ::UncompressFailure) { @@ -1837,6 +1839,7 @@ template bool BotGraph::loadStorage (StringRef ext, StringRef name, else { return raiseLoadingError (isGraph, file, "Unable to read ULZ data for %s (filename: '%s').", name, filename); } + return false; } bool BotGraph::loadGraphData () { @@ -2031,7 +2034,7 @@ bool BotGraph::isNodeReacheable (const Vector &src, const Vector &destination) { game.testLine (sourceNew, destinationNew, TraceIgnore::Monsters, m_editor, &tr); // check if we didn't hit anything, if not then it's in mid-air - if (tr.flFraction >= 1.0) { + if (tr.flFraction >= 1.0f) { return false; // can't reach this one } } @@ -2143,10 +2146,10 @@ void BotGraph::rebuildVisibility () { res &= 2; } } - shift = (path.number % 4) << 1; + shift = static_cast ((path.number % 4) << 1); - m_vistable[vis.number * m_paths.length () + path.number] &= ~(3 << shift); - m_vistable[vis.number * m_paths.length () + path.number] |= res << shift; + m_vistable[vis.number * length () + path.number] &= static_cast (~(3 << shift)); + m_vistable[vis.number * length () + path.number] |= res << shift; if (!(res & 2)) { ++crouchCount; @@ -2168,7 +2171,7 @@ bool BotGraph::isVisible (int srcIndex, int destIndex) { return false; } - uint8 res = m_vistable[srcIndex * m_paths.length () + destIndex]; + uint8 res = m_vistable[srcIndex * length () + destIndex]; res >>= (destIndex % 4) << 1; return !((res & 3) == 3); @@ -2179,7 +2182,7 @@ bool BotGraph::isDuckVisible (int srcIndex, int destIndex) { return false; } - uint8 res = m_vistable[srcIndex * m_paths.length () + destIndex]; + uint8 res = m_vistable[srcIndex * length () + destIndex]; res >>= (destIndex % 4) << 1; return !((res & 2) == 2); @@ -2190,7 +2193,7 @@ bool BotGraph::isStandVisible (int srcIndex, int destIndex) { return false; } - uint8 res = m_vistable[srcIndex * m_paths.length () + destIndex]; + uint8 res = m_vistable[srcIndex * length () + destIndex]; res >>= (destIndex % 4) << 1; return !((res & 1) == 1); @@ -2498,18 +2501,29 @@ void BotGraph::frame () { auto getNodeData = [&] (StringRef type, int node) -> String { String message, flags; - const auto &path = m_paths[node]; + const auto &p = m_paths[node]; bool jumpPoint = false; // iterate through connections and find, if it's a jump path - for (const auto &link : path.links) { + for (const auto &link : p.links) { // check if we got a valid connection if (link.index != kInvalidNodeIndex && (link.flags & PathFlag::Jump)) { jumpPoint = true; } } - flags.assignf ("%s%s%s%s%s%s%s%s%s%s%s%s", (path.flags & NodeFlag::Lift) ? " LIFT" : "", (path.flags & NodeFlag::Crouch) ? " CROUCH" : "", (path.flags & NodeFlag::Camp) ? " CAMP" : "", (path.flags & NodeFlag::TerroristOnly) ? " TERRORIST" : "", (path.flags & NodeFlag::CTOnly) ? " CT" : "", (path.flags & NodeFlag::Sniper) ? " SNIPER" : "", (path.flags & NodeFlag::Goal) ? " GOAL" : "", (path.flags & NodeFlag::Ladder) ? " LADDER" : "", (path.flags & NodeFlag::Rescue) ? " RESCUE" : "", (path.flags & NodeFlag::DoubleJump) ? " JUMPHELP" : "", (path.flags & NodeFlag::NoHostage) ? " NOHOSTAGE" : "", jumpPoint ? " JUMP" : ""); + flags.assignf ("%s%s%s%s%s%s%s%s%s%s%s%s", + (p.flags & NodeFlag::Lift) ? " LIFT" : "", + (p.flags & NodeFlag::Crouch) ? " CROUCH" : "", + (p.flags & NodeFlag::Camp) ? " CAMP" : "", + (p.flags & NodeFlag::TerroristOnly) ? " TERRORIST" : "", + (p.flags & NodeFlag::CTOnly) ? " CT" : "", + (p.flags & NodeFlag::Sniper) ? " SNIPER" : "", + (p.flags & NodeFlag::Goal) ? " GOAL" : "", + (p.flags & NodeFlag::Ladder) ? " LADDER" : "", + (p.flags & NodeFlag::Rescue) ? " RESCUE" : "", + (p.flags & NodeFlag::DoubleJump) ? " JUMPHELP" : "", + (p.flags & NodeFlag::NoHostage) ? " NOHOSTAGE" : "", jumpPoint ? " JUMP" : ""); if (flags.empty ()) { flags.assign ("(none)"); @@ -2519,7 +2533,7 @@ void BotGraph::frame () { message.assignf (" %s node:\n" " Node %d of %d, Radius: %.1f, Light: %.1f\n" " Flags: %s\n" - " Origin: (%.1f, %.1f, %.1f)\n", type, node, m_paths.length () - 1, path.radius, path.light, flags, path.origin.x, path.origin.y, path.origin.z); + " Origin: (%.1f, %.1f, %.1f)\n", type, node, m_paths.length () - 1, p.radius, p.light, flags, p.origin.x, p.origin.y, p.origin.z); return message; }; @@ -2669,11 +2683,16 @@ bool BotGraph::checkNodes (bool teleportPlayer) { } // perform DFS instead of floyd-warshall, this shit speedup this process in a bit + auto length = cr::min (static_cast (kMaxNodes), m_paths.length ()); + + // ensure valid capacity + assert (length > 8 && length < static_cast (kMaxNodes)); + PathWalk walk; - walk.init (m_paths.length ()); + walk.init (length); Array visited; - visited.resize (m_paths.length ()); + visited.resize (length); // first check incoming connectivity, initialize the "visited" table for (auto &visit : visited) { @@ -2710,10 +2729,10 @@ bool BotGraph::checkNodes (bool teleportPlayer) { // then check outgoing connectivity Array outgoingPaths; // store incoming paths for speedup - outgoingPaths.resize (m_paths.length ()); + outgoingPaths.resize (length); for (const auto &path : m_paths) { - outgoingPaths[path.number].resize (m_paths.length () + 1); + outgoingPaths[path.number].resize (length + 1); for (const auto &link : path.links) { if (exists (link.index)) { @@ -3123,8 +3142,8 @@ void BotGraph::convertFromPOD (Path &path, const PODPath &pod) { path.links[i].flags = pod.conflags[i]; path.links[i].velocity = pod.velocity[i]; } - path.vis.stand = pod.vis.stand; - path.vis.crouch = pod.vis.crouch; + path.vis.stand = 0; + path.vis.crouch = 0; } void BotGraph::convertToPOD (const Path &path, PODPath &pod) { diff --git a/src/linkage.cpp b/src/linkage.cpp index 6613b9b..4fb6af6 100644 --- a/src/linkage.cpp +++ b/src/linkage.cpp @@ -1010,12 +1010,12 @@ CR_EXPORT int Server_GetPhysicsInterface (int version, server_physics_api_t *phy return HLTrue; } -DLSYM_RETURN EntityLinkage::lookup (SharedLibrary::Handle module, const char *function) { +SharedLibrary::Func 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 m_dlsym (handle, function); }; if (ents.needsBypass () && !strcmp (function, "CreateInterface")) { @@ -1028,10 +1028,16 @@ DLSYM_RETURN EntityLinkage::lookup (SharedLibrary::Handle module, const char *fu } // if requested module is yapb module, put in cache the looked up symbol - if (self != module || (plat.win && (static_cast (reinterpret_cast (function) >> 16) & 0xffff) == 0)) { + if (self != module) { return resolve (module); } +#if defined (CR_WINDOWS) + if (HIWORD (function) == 0) { + return resolve (module); + } +#endif + if (m_exports.has (function)) { return m_exports[function]; } @@ -1057,7 +1063,7 @@ void EntityLinkage::callPlayerFunction (edict_t *ent) { playerFunction = game.lib ().resolve ("player"); } else { - playerFunction = reinterpret_cast (lookup (game.lib ().handle (), "player")); + playerFunction = reinterpret_cast (reinterpret_cast (lookup (game.lib ().handle (), "player"))); } if (!playerFunction) { diff --git a/src/manager.cpp b/src/manager.cpp index 739fa38..ec6c93f 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -132,7 +132,7 @@ void BotManager::touchKillerEntity (Bot *bot) { KeyValueData kv {}; kv.szClassName = const_cast (prop.classname.chars ()); kv.szKeyName = "damagetype"; - kv.szValue = const_cast (strings.format ("%d", cr::bit (4))); + kv.szValue = strings.format ("%d", cr::bit (4)); kv.fHandled = HLFalse; MDLL_KeyValue (m_killerEntity, &kv); @@ -782,7 +782,6 @@ void BotManager::listBots () { ctrl.msg ("%-3.5s\t%-19.16s\t%-10.12s\t%-3.4s\t%-3.4s\t%-3.4s\t%-3.5s\t%-3.8s", "index", "name", "personality", "team", "difficulty", "frags", "alive", "timeleft"); for (const auto &bot : bots) { - ; ctrl.msg ("[%-3.1d]\t%-19.16s\t%-10.12s\t%-3.4s\t%-3.1d\t%-3.1d\t%-3.4s\t%-3.0f secs", bot->index (), bot->pev->netname.chars (), bot->m_personality == Personality::Rusher ? "rusher" : bot->m_personality == Personality::Normal ? "normal" : "careful", bot->m_team == Team::CT ? "CT" : "T", bot->m_difficulty, static_cast (bot->pev->frags), bot->m_notKilled ? "yes" : "no", bot->m_stayTime - game.time ()); } ctrl.msg ("%d bots", m_bots.length ()); @@ -819,7 +818,7 @@ float BotManager::getAverageTeamKPD (bool calcForBots) { } if (calc.second > 0) { - return calc.first / calc.second; + return calc.first / static_cast (calc.second); } return 0.0f; } @@ -930,10 +929,10 @@ void BotManager::balanceBotDifficulties () { float score = bot->m_kpdRatio; // if kd ratio is going to go to low, we need to try to set higher difficulty - if (score < 0.8 || (score <= 1.2 && ratioBots < ratioPlayer)) { + if (score < 0.8f || (score <= 1.2f && ratioBots < ratioPlayer)) { updateDifficulty (bot.get (), +1); } - else if (score > 4.0f || (score >= 2.5 && ratioBots > ratioPlayer)) { + else if (score > 4.0f || (score >= 2.5f && ratioBots > ratioPlayer)) { updateDifficulty (bot.get (), -1); } } @@ -949,9 +948,6 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) { // this function does core operation of creating bot, it's called by addbot (), // when bot setup completed, (this is a bot class constructor) - // 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; @@ -1458,7 +1454,7 @@ void Bot::resetPathSearchType () { switch (m_personality) { default: case Personality::Normal: - m_pathType = morale ? FindPath::Optimal : FindPath::Safe; + m_pathType = morale ? FindPath::Optimal : FindPath::Fast; break; case Personality::Rusher: diff --git a/src/message.cpp b/src/message.cpp index 4d80a09..bac53f8 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -335,7 +335,7 @@ void MessageDispatcher::netMsgScoreInfo () { // if we're have bot, set the kd ratio if (bot != nullptr) { - bot->m_kpdRatio = bot->pev->frags / cr::max (m_args[deaths].long_, 1); + bot->m_kpdRatio = bot->pev->frags / cr::max (static_cast (m_args[deaths].long_), 1.0f); } } diff --git a/src/module.cpp b/src/module.cpp index d1a941b..08ef862 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -23,7 +23,7 @@ private: public: // get the bot version string virtual const char *getBotVersion () override { - return MODULE_BOT_VERSION "." MODULE_BUILD_COUNT; + return MODULE_VERSION "." MODULE_COMMIT_COUNT; } // checks if bots are currently in game diff --git a/src/navigate.cpp b/src/navigate.cpp index 736e0f9..4393a7e 100644 --- a/src/navigate.cpp +++ b/src/navigate.cpp @@ -82,6 +82,7 @@ int Bot::findBestGoal () { tactic = 4; return findGoalPost (tactic, defensiveNodes, offensiveNodes); } + auto difficulty = static_cast (m_difficulty); offensive = m_agressionLevel * 100.0f; defensive = m_fearLevel * 100.0f; @@ -94,8 +95,8 @@ int Bot::findBestGoal () { else if (m_team == Team::CT) { // on hostage maps force more bots to save hostages if (game.mapIs (MapFlags::HostageRescue)) { - defensive -= 25.0f - m_difficulty * 0.5f; - offensive += 25.0f + m_difficulty * 5.0f; + defensive -= 25.0f - difficulty * 0.5f; + offensive += 25.0f + difficulty * 5.0f; } else { defensive -= 25.0f; @@ -112,8 +113,8 @@ int Bot::findBestGoal () { } return m_chosenGoalIndex = findBombNode (); } - defensive += 25.0f + m_difficulty * 4.0f; - offensive -= 25.0f - m_difficulty * 0.5f; + defensive += 25.0f + difficulty * 4.0f; + offensive -= 25.0f - difficulty * 0.5f; if (m_personality != Personality::Rusher) { defensive += 10.0f; @@ -121,7 +122,7 @@ int Bot::findBestGoal () { } else if (game.mapIs (MapFlags::Demolition) && m_team == Team::Terrorist && bots.getRoundStartTime () + 10.0f < game.time ()) { // send some terrorists to guard planted bomb - if (!m_defendedBomb && bots.isBombPlanted () && getCurrentTaskId () != Task::EscapeFromBomb && getBombTimeleft () >= 15.0) { + if (!m_defendedBomb && bots.isBombPlanted () && getCurrentTaskId () != Task::EscapeFromBomb && getBombTimeleft () >= 15.0f) { return pushToHistroy (m_chosenGoalIndex = graph.getNearest (graph.getBombOrigin ())); } } @@ -456,21 +457,18 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) { // bot is stuc, but not yet decided what to do? if (m_collisionState == CollisionState::Undecided) { - int bits = 0; + uint32 bits = 0; if (isOnLadder ()) { bits |= CollisionProbe::Strafe; } - else if (isInWater ()) { - bits |= (CollisionProbe::Jump | CollisionProbe::Strafe); - } else { bits |= (CollisionProbe::Strafe | CollisionProbe::Jump); } // collision check allowed if not flying through the air if (isOnFloor () || isOnLadder () || isInWater ()) { - int state[kMaxCollideMoves * 2 + 1] {}; + uint32 state[kMaxCollideMoves * 2 + 1] {}; int i = 0; Vector src {}, dst {}; @@ -689,7 +687,7 @@ bool Bot::updateNavigation () { // if graph node radius non zero vary origin a bit depending on the body angles if (m_path->radius > 0.0f) { - m_pathOrigin += Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (0.0f, m_path->radius); + m_pathOrigin += Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (0.0f, m_path->radius); } m_navTimeset = game.time (); } @@ -726,7 +724,7 @@ bool Bot::updateNavigation () { } } - if (!(graph[m_previousNodes[0]].flags & NodeFlag::Ladder)) { + if (graph.exists (m_previousNodes[0]) && (graph[m_previousNodes[0]].flags & NodeFlag::Ladder)) { if (cr::abs (m_pathOrigin.z - pev->origin.z) > 5.0f) { m_pathOrigin.z += pev->origin.z - m_pathOrigin.z; } @@ -1325,7 +1323,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath: // this function finds a path from srcIndex to destIndex auto dangerFactor = [&] () -> float { - return rg.get (cv_path_danger_factor_min.float_ (), cv_path_danger_factor_max.float_ ()) * 2.0f / cr::clamp (m_difficulty, 1, 3); + return rg.get (cv_path_danger_factor_min.float_ (), cv_path_danger_factor_max.float_ ()) * 2.0f / cr::clamp (static_cast (m_difficulty), 1.0f, 4.0f); }; // least kills and number of nodes to goal for a team @@ -1403,11 +1401,13 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath: for (const auto &link : parent.links) { if (link.index == currentIndex) { + const auto distance = static_cast (link.distance); + // we don't like ladder or crouch point if (current.flags & (NodeFlag::Crouch | NodeFlag::Ladder)) { - return link.distance * 1.5f; + return distance * 1.5f; } - return static_cast (link.distance); + return distance; } } return 65355.0f; @@ -1608,7 +1608,7 @@ void Bot::clearSearchNodes () { } void Bot::clearRoute () { - m_routes.resize (graph.length ()); + m_routes.resize (static_cast (graph.length ())); for (int i = 0; i < graph.length (); ++i) { auto route = &m_routes[i]; @@ -1633,7 +1633,7 @@ int Bot::findAimingNode (const Vector &to) { if (destIndex == kInvalidNodeIndex) { return kInvalidNodeIndex; } - const float kMaxDistance = ((m_states & Sense::HearingEnemy) || (m_states & Sense::HearingEnemy) || m_seeEnemyTime + 3.0f > game.time ()) ? 0.0f : 512.0f; + const float kMaxDistance = ((m_states & Sense::HearingEnemy) || (m_states & Sense::SuspectEnemy) || m_seeEnemyTime + 3.0f > game.time ()) ? 0.0f : 512.0f; while (destIndex != m_currentNodeIndex) { destIndex = (graph.m_matrix.data () + (destIndex * graph.length ()) + m_currentNodeIndex)->index; @@ -2411,7 +2411,7 @@ bool Bot::advanceMovement () { // if wayzone radius non zero vary origin a bit depending on the body angles if (m_path->radius > 0.0f) { - m_pathOrigin += Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (0.0f, m_path->radius); + m_pathOrigin += Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg.get (-90.0f, 90.0f)), 0.0f).forward () * rg.get (0.0f, m_path->radius); } if (isOnLadder ()) { @@ -2432,17 +2432,17 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) { // use some TraceLines to determine if anything is blocking the current path of the bot. // first do a trace from the bot's eyes forward... - Vector src = getEyesPos (); - Vector forward = src + normal * 24.0f; + auto src = getEyesPos (); + auto forward = src + normal * 24.0f; + auto right = Vector (0.0f, pev->angles.y, 0.0f).right (); - const auto &right = Vector (0.0f, pev->angles.y, 0.0f).right (); bool traceResult = false; - auto checkDoor = [&traceResult] (TraceResult *tr) { + auto checkDoor = [&traceResult] (TraceResult *result) { if (!game.mapIs (MapFlags::HasDoors)) { return false; } - return !traceResult && tr->flFraction < 1.0f && strncmp ("func_door", tr->pHit->v.classname.chars (), 9) != 0; + return !traceResult && result->flFraction < 1.0f && strncmp ("func_door", result->pHit->v.classname.chars (), 9) != 0; }; // trace from the bot's eyes straight forward... @@ -2596,11 +2596,11 @@ bool Bot::canJumpUp (const Vector &normal) { if (!isOnFloor () && (isOnLadder () || !isInWater ())) { return false; } - const auto &right = Vector (0.0f, pev->angles.y, 0.0f).right (); // convert current view angle to vectors for traceline math... + auto right = Vector (0.0f, pev->angles.y, 0.0f).right (); // convert current view angle to vectors for traceline math... // check for normal jump height first... - Vector src = pev->origin + Vector (0.0f, 0.0f, -36.0f + 45.0f); - Vector dest = src + normal * 32.0f; + auto src = pev->origin + Vector (0.0f, 0.0f, -36.0f + 45.0f); + auto dest = src + normal * 32.0f; // trace a line forward at maximum jump height... game.testLine (src, dest, TraceIgnore::Monsters, ent (), &tr); @@ -2762,7 +2762,7 @@ bool Bot::canDuckUnder (const Vector &normal) { } // convert current view angle to vectors for TraceLine math... - const auto &right = Vector (0.0f, pev->angles.y, 0.0f).right (); + auto right = Vector (0.0f, pev->angles.y, 0.0f).right (); // now check same height to one side of the bot... src = baseHeight + right * 16.0f; @@ -2900,14 +2900,14 @@ bool Bot::isDeadlyMove (const Vector &to) { void Bot::changePitch (float speed) { // this function turns a bot towards its ideal_pitch - float idealPitch = cr::normalizeAngles (pev->idealpitch); - float curent = cr::normalizeAngles (pev->v_angle.x); + float idealPitch = cr::wrapAngle (pev->idealpitch); + float curent = cr::wrapAngle (pev->v_angle.x); // turn from the current v_angle pitch to the idealpitch by selecting // the quickest way to turn to face that direction // find the difference in the curent and ideal angle - float normalizePitch = cr::normalizeAngles (idealPitch - curent); + float normalizePitch = cr::wrapAngle (idealPitch - curent); if (normalizePitch > 0.0f) { if (normalizePitch > speed) { @@ -2920,7 +2920,7 @@ void Bot::changePitch (float speed) { } } - pev->v_angle.x = cr::normalizeAngles (curent + normalizePitch); + pev->v_angle.x = cr::wrapAngle (curent + normalizePitch); if (pev->v_angle.x > 89.9f) { pev->v_angle.x = 89.9f; @@ -2935,14 +2935,14 @@ void Bot::changePitch (float speed) { void Bot::changeYaw (float speed) { // this function turns a bot towards its ideal_yaw - float idealPitch = cr::normalizeAngles (pev->ideal_yaw); - float curent = cr::normalizeAngles (pev->v_angle.y); + float idealPitch = cr::wrapAngle (pev->ideal_yaw); + float curent = cr::wrapAngle (pev->v_angle.y); // turn from the current v_angle yaw to the ideal_yaw by selecting // the quickest way to turn to face that direction // find the difference in the curent and ideal angle - float normalizePitch = cr::normalizeAngles (idealPitch - curent); + float normalizePitch = cr::wrapAngle (idealPitch - curent); if (normalizePitch > 0.0f) { if (normalizePitch > speed) { @@ -2954,7 +2954,7 @@ void Bot::changeYaw (float speed) { normalizePitch = -speed; } } - pev->v_angle.y = cr::normalizeAngles (curent + normalizePitch); + pev->v_angle.y = cr::wrapAngle (curent + normalizePitch); pev->angles.y = pev->v_angle.y; } @@ -3084,7 +3084,7 @@ void Bot::updateLookAnglesNewbie (const Vector &direction, float delta) { Vector spring { 13.0f, 13.0f, 0.0f }; Vector damperCoefficient { 0.22f, 0.22f, 0.0f }; - const float offset = cr::clamp (m_difficulty, 1, 4) * 25.0f; + const float offset = cr::clamp (static_cast (m_difficulty), 1.0f, 4.0f) * 25.0f; Vector influence = Vector (0.25f, 0.17f, 0.0f) * (100.0f - offset) / 100.f; Vector randomization = Vector (2.0f, 0.18f, 0.0f) * (100.0f - offset) / 100.f; diff --git a/src/support.cpp b/src/support.cpp index d7cf93c..64d3908 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -285,7 +285,7 @@ void BotSupport::checkWelcome () { bool needToSendMsg = (graph.length () > 0 ? m_needToSendWelcome : true); auto receiveEntity = game.getLocalEntity (); - if (isAlive (receiveEntity) && m_welcomeReceiveTime < 1.0 && needToSendMsg) { + if (isAlive (receiveEntity) && m_welcomeReceiveTime < 1.0f && needToSendMsg) { m_welcomeReceiveTime = game.time () + 4.0f; // receive welcome message in four seconds after game has commencing } @@ -509,7 +509,7 @@ void BotSupport::simulateNoise (int playerIndex) { } } - if (noise.dist <= 0.0) { + if (noise.dist <= 0.0f) { return; // didn't issue sound? } @@ -613,7 +613,7 @@ void BotSupport::calculatePings () { if (!bot) { continue; } - int part = static_cast (average.first * 0.2f); + int part = static_cast (static_cast (average.first) * 0.2f); int botPing = bot->m_basePing + rg.get (average.first - part, average.first + part) + rg.get (bot->m_difficulty / 2, bot->m_difficulty); int botLoss = rg.get (average.second / 2, average.second); diff --git a/vc/yapb.rc b/vc/yapb.rc index 2d8a691..5a42f7c 100644 --- a/vc/yapb.rc +++ b/vc/yapb.rc @@ -16,21 +16,21 @@ #include VERSION_HEADER VS_VERSION_INFO VERSIONINFO -FILEVERSION MODULE_BOT_VERSION_FILE -PRODUCTVERSION MODULE_BOT_VERSION_FILE +FILEVERSION MODULE_VERSION_FILE +PRODUCTVERSION MODULE_VERSION_FILE FILEOS 0x40004 FILETYPE 0x2 { BLOCK "StringFileInfo" { BLOCK "040904E4" { - VALUE "CompanyName", "YaPB Project" "\0" - VALUE "FileDescription", "YaPB v" MODULE_BOT_VERSION "." MODULE_BUILD_COUNT " - The Counter-Strike Bot" "\0" - VALUE "LegalCopyright", "Copyright \251 2023 YaPB Project" "\0" - VALUE "OriginalFilename", "yapb.dll" "\0" - VALUE "ProductName", "YaPB" "\0" - VALUE "InternalName", "YaPB DLL" "\0" - VALUE "FileVersion", MODULE_BOT_VERSION "." MODULE_BUILD_COUNT "\0" - VALUE "ProductVersion", MODULE_BOT_VERSION "." MODULE_BUILD_COUNT "\0" - VALUE "SpecialBuild", MODULE_BOT_BUILD_ID "\0" + VALUE "CompanyName", "YaPB Project" "\0" + VALUE "FileDescription", "YaPB v" MODULE_VERSION "." MODULE_COMMIT_COUNT " - The Counter-Strike Bot" "\0" + VALUE "LegalCopyright", "Copyright \251 2023 YaPB Project" "\0" + VALUE "OriginalFilename", "yapb.dll" "\0" + VALUE "ProductName", "YaPB" "\0" + VALUE "InternalName", "YaPB DLL" "\0" + VALUE "FileVersion", MODULE_VERSION "." MODULE_COMMIT_COUNT "\0" + VALUE "ProductVersion", MODULE_VERSION "." MODULE_COMMIT_COUNT "\0" + VALUE "SpecialBuild", MODULE_BUILD_ID "\0" } } BLOCK "VarFileInfo" { diff --git a/vc/yapb.vcxproj b/vc/yapb.vcxproj index dddd0ef..992b7e3 100644 --- a/vc/yapb.vcxproj +++ b/vc/yapb.vcxproj @@ -151,7 +151,7 @@ Disabled ..\vc;..\inc;..\ext;..\ext\crlib;%(AdditionalIncludeDirectories) WIN32;_DEBUG;CR_DEBUG;%(PreprocessorDefinitions) - MultiThreadedDebug + MultiThreadedDebugDLL yapb.h .\debug\inf\yapb.pch