diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000000..d8dd6c078e --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,14 @@ +# The CI image (.github/workflows/cibuild.yml) plus a non-root account, which +# the sniper SDK does not ship. Without one, a rootful-docker container writes +# root-owned files into the bind mount. devcontainer.json passes the host +# username, and updateRemoteUserUID rewrites the UID/GID to match at build time. +FROM registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest + +ARG USERNAME=dev +ARG USER_UID=1000 +ARG USER_GID=1000 + +RUN groupadd --gid "${USER_GID}" "${USERNAME}" \ + && useradd --uid "${USER_UID}" --gid "${USER_GID}" -m -s /bin/bash "${USERNAME}" \ + && echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/${USERNAME}" \ + && chmod 0440 "/etc/sudoers.d/${USERNAME}" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..8314e54688 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,72 @@ +{ + "name": "NT;RE - Steam Runtime 3 (sniper) SDK", + // The CI image (.github/workflows/cibuild.yml) plus a non-root account; see + // the Dockerfile. + "build": { + "dockerfile": "Dockerfile", + "args": { + // Account name only; file ownership comes from updateRemoteUserUID below. + "USERNAME": "${localEnv:USER:dev}" + } + }, + // SELinux hosts: without this the bind mount reads as Permission denied. + // Not :Z - that relabels the repo and breaks access from outside. + "runArgs": [ + "--security-opt", + "label=disable" + ], + // Must match the USERNAME build arg. updateRemoteUserUID rebuilds the image + // with the local UID/GID so bind-mount files stay owned by the host user. + "remoteUser": "${localEnv:USER:dev}", + "updateRemoteUserUID": true, + "postCreateCommand": "bash tools/ntre-dev-setup.sh --editor none", + "remoteEnv": { + "PATH": "${containerWorkspaceFolder}/.ide/bin:${containerEnv:PATH}" + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cmake-tools", + "llvm-vs-code-extensions.vscode-clangd" + ], + // Mirrors what tools/ntre-dev-setup.sh writes for non-container users; + // keep in sync. ${workspaceFolder} is VS Code's, not devcontainer.json's. + "settings": { + "cmake.sourceDirectory": "${workspaceFolder}/src", + "cmake.useCMakePresets": "always", + "cmake.configureOnOpen": false, + // Stops the extension downloading its own clangd. + "clangd.path": "${workspaceFolder}/.ide/bin/clangd", + "clangd.checkUpdates": false, + "clangd.onConfigChanged": "restart", + "clangd.arguments": [ + // Command-line-only option: reads include paths and predefined + // macros from the compiler that actually builds this tree. + "--query-driver=/usr/bin/g++*,/usr/bin/gcc*,/usr/bin/clang*,/usr/lib/llvm-*/bin/clang*", + "--header-insertion=never", + "--background-index", + "--completion-style=detailed", + "--pch-storage=memory" + ], + // clangd provides IntelliSense; stop cpptools double-indexing. + "C_Cpp.intelliSenseEngine": "disabled", + "files.associations": { + "*.h": "cpp", + "*.inc": "cpp" + }, + "[cpp]": { + "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" + }, + "files.watcherExclude": { + "**/src/build/**": true, + "**/.cache/**": true, + "**/.ide/**": true + }, + "search.exclude": { + "**/src/build/**": true, + "**/.ide/**": true + } + } + } + } +} diff --git a/.gitattributes b/.gitattributes index 437f140a1c..4effc43a1e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,7 @@ -buildallprojects text vpc binary -*.sh text +# eol=lf: a shell script checked out with CRLF fails to run at all. +*.sh text eol=lf *.bat text *.txt text *.c text diff --git a/.gitignore b/.gitignore index 2ac93e819a..0de5b1b13c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,16 @@ out /src/CMakeSettings.json +/src/CMakeUserPresets.json + +# Generated by tools/ntre-dev-setup.sh +/.ide/ +/.clangd +/compile_commands.json +/.zed/ + +# Personal devcontainer variants, offered alongside the tracked one +/.devcontainer/local/ # ctest /src/Testing @@ -662,11 +672,6 @@ MigrationBackup/ FodyWeavers.xsd # VS Code files for those working on multiple tools -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json *.code-workspace # Local History for Visual Studio Code @@ -699,3 +704,10 @@ FodyWeavers.xsd # Selected Background /game/neo/scripts/[Cc]hapter[Bb]ackgrounds.txt + +# Share the ntre-dev-setup.sh task entry point; the rest of .vscode stays local. +# Three patterns because *.vscode/ above excludes the directory itself, and git +# cannot re-include a file whose parent directory is excluded. +!/.vscode/ +/.vscode/* +!/.vscode/tasks.json diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000000..66edf617dc --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,32 @@ +{ + // The only tracked file under .vscode/ (see the re-include at the end of + // .gitignore); the setup task writes the per-developer settings.json and + // extensions.json. + "version": "2.0.0", + "tasks": [ + { + "label": "ntre-dev-setup: Set up VS Code", + "detail": "Installs the pinned clangd, generates the compile database and writes .vscode/settings.json + extensions.json. Linux or macOS shell (WSL on Windows).", + "type": "shell", + "command": "${workspaceFolder}/tools/ntre-dev-setup.sh", + "args": ["--editor", "vscode"], + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "shared" + } + }, + { + "label": "ntre-dev-setup: Refresh compile database", + "detail": "Run after adding, removing or renaming sources, or after pulling changes to a CMakeLists.txt.", + "type": "shell", + "command": "${workspaceFolder}/tools/ntre-dev-setup.sh", + "args": ["--reconfigure"], + "problemMatcher": [], + "presentation": { + "reveal": "silent", + "panel": "shared" + } + } + ] +} diff --git a/README.md b/README.md index 8a201afe15..6cc54f2514 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,31 @@ $ cmake --build --preset PRESET_NAME Available PRESET_NAME values: `windows-debug`, `windows-release`, `linux-debug`, `linux-release`. +## Development using Linux + +Optional tooling for working on the code, rather than for building it: a dev container definition and a setup script that give you a working C++ IntelliSense index. None of it changes how NT;RE is built. The [Qt Creator](#qt-creator-linux) and [CLI](#cli-with-ninja-windows--linux) workflows above are untouched, and every file the script generates is git-ignored. + +### Getting set up + +Either entry point is enough: + +* **Dev container** - open the repo in an editor that supports [dev containers](https://containers.dev/) (VS Code, the `devcontainer` CLI, JetBrains Gateway) and reopen in the container. It uses the same sniper SDK image as the CI runners and the manual container steps above, and runs the setup script for you on create. +* **Run it yourself** - from inside your own sniper container, or on a native toolchain new enough for C++20: + + ```bash + $ ./tools/ntre-dev-setup.sh + ``` + + Add `--editor vscode` to also write `.vscode/settings.json` and `extensions.json`; in VS Code, the *"ntre-dev-setup: Set up VS Code"* task does the same. `--editor zed` writes the equivalent `.zed/settings.json`. Run from an editor's own terminal, the default `--editor auto` picks whichever it detects. `--help` lists the rest. + +### What it sets up + +* A pinned `clangd` under `.ide/`, since distro packages are frequently too old for this tree's C++20. Use `--system-clangd` to keep your own instead, or `source .ide/env.sh` to put the pinned one on `PATH` for editors launched from a shell. +* `compile_commands.json`, symlinked at the repo root where clangd, CLion, Qt Creator and Sublime look for it, alongside a `.clangd` carrying the compile flags that need adjusting for the SteamRT toolchain. +* A `linux-debug-ide` preset in your `src/CMakeUserPresets.json` (per-developer, git-ignored) that generates the database with the [unity build](#unity-build) options off - the header of `tools/ntre-dev-setup.sh` explains why. **Do not build from it** - build with `linux-debug` as documented above. + +Re-run `./tools/ntre-dev-setup.sh --reconfigure` after adding, removing or renaming source files, or use the *"ntre-dev-setup: Refresh compile database"* task in VS Code. + ## Steam mod setup To make it appear in Steam, the install files have to appear under the sourcemods directory or be directed to it. @@ -320,6 +345,12 @@ shaders\fxc\sdk_screenspaceeffect_vs20.vcs 10.41 ``` +## Unity build + +By default, this project uses Unity Build to speed up compilation times. However, if you need to disable it for development +reasons, set the CMake options `NEO_UNITY_BUILD_CLIENT_SERVER` or `NEO_UNITY_BUILD_OTHERS` to `OFF`. This will disable +Unity Build for client/server libraries and vgui2/tier1/mathlib libraries, respectively. + ## Credits * [NeotokyoRevamp/neo](https://github.com/NeotokyoRevamp/neo) - Original fork source * [ValveSoftware/source-sdk-2013](https://github.com/ValveSoftware/source-sdk-2013) - Source SDK 2013 (2025 TF2 SDK Update) diff --git a/src/.vscode/tasks.json b/src/.vscode/tasks.json deleted file mode 100644 index 87e569e8df..0000000000 --- a/src/.vscode/tasks.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "Build All Projects", - "type": "shell", - "command": "./buildallprojects", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": { - "base": "$gcc", - "fileLocation": ["relative", "${workspaceFolder}"] - }, - "presentation": { - "reveal": "always", - "panel": "shared" - } - } - ] -} - diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd36b56868..5bda915394 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,6 +53,8 @@ option(NEO_ENABLE_CPACK "Enable CPack" OFF) option(NEO_USE_MEM_DEBUG "Enable USE_MEM_DEBUG defines" OFF) option(NEO_GENERATE_GAMEDATA "Generate SourceMod gamedata" ${NEO_DEDICATED}) option(NEO_BUILD_LAUNCHER "Build the Steam mod launcher" ON) +option(NEO_UNITY_BUILD_CLIENT_SERVER "Enable unity build for client/server libraries" ON) +option(NEO_UNITY_BUILD_OTHERS "Enable unity build for vgui2, tier1, and mathlib libraries" ON) set(NEO_MOD_APPID "3172910" CACHE STRING "Steam appid for the mod launcher's steam_appid.txt") message(STATUS "Treat compile warnings as errors: ${CMAKE_COMPILE_WARNING_AS_ERROR}") @@ -80,8 +82,20 @@ message(STATUS "Use separate build info on Linux: ${NEO_USE_SEPARATE_BUILD_INFO} message(STATUS "Enable CPack: ${NEO_ENABLE_CPACK}") message(STATUS "Build the Steam mod launcher: ${NEO_BUILD_LAUNCHER}") message(STATUS "Mod launcher appid override: ${NEO_MOD_APPID}") +message(STATUS "Enable unity build for client/server libraries (NEO_UNITY_BUILD_CLIENT_SERVER): ${NEO_UNITY_BUILD_CLIENT_SERVER}") +message(STATUS "Enable unity build for vgui2, tier1, and mathlib libraries (NEO_UNITY_BUILD_OTHERS): ${NEO_UNITY_BUILD_OTHERS}") message("") +set(UNITY_BUILD_DEF_OTHERS) +if (NEO_UNITY_BUILD_OTHERS) + set(UNITY_BUILD_DEF_OTHERS NEO_UNITY) +endif () + +set(UNITY_BUILD_DEF_CLIENT_SERVER) +if (NEO_UNITY_BUILD_CLIENT_SERVER) + set(UNITY_BUILD_DEF_CLIENT_SERVER NEO_UNITY) +endif () + if(NEO_COPY_LIBRARIES) file(MAKE_DIRECTORY "${NEO_OUTPUT_LIBRARY_PATH}") endif() diff --git a/src/game/client/CMakeLists.txt b/src/game/client/CMakeLists.txt index 9273ef7498..7fbb698e43 100644 --- a/src/game/client/CMakeLists.txt +++ b/src/game/client/CMakeLists.txt @@ -2,7 +2,7 @@ add_library(client SHARED) set_target_properties(client PROPERTIES PREFIX "" - UNITY_BUILD ON + UNITY_BUILD ${NEO_UNITY_BUILD_CLIENT_SERVER} UNITY_BUILD_MODE GROUP ) @@ -49,6 +49,7 @@ target_compile_definitions(client VECTOR VERSION_SAFE_STEAM_API_INTERFACES NEXT_BOT + ${UNITY_BUILD_DEF_CLIENT_SERVER} ) target_link_libraries(client diff --git a/src/game/client/neo/c_neo_killer_damage_infos.cpp b/src/game/client/neo/c_neo_killer_damage_infos.cpp index a8c183ce84..a60b5c26b7 100644 --- a/src/game/client/neo/c_neo_killer_damage_infos.cpp +++ b/src/game/client/neo/c_neo_killer_damage_infos.cpp @@ -2,6 +2,8 @@ #include #include "strtools.h" +#include "vgui/ILocalize.h" +#include "tier3/tier3.h" #include "c_neo_player.h" #include "neo_gamerules.h" diff --git a/src/game/client/neo/ui/neo_hud_killer_info.cpp b/src/game/client/neo/ui/neo_hud_killer_info.cpp index 1da8275978..953e1032cf 100644 --- a/src/game/client/neo/ui/neo_hud_killer_info.cpp +++ b/src/game/client/neo/ui/neo_hud_killer_info.cpp @@ -7,6 +7,7 @@ #include "c_neo_player.h" #include "neo_gamerules.h" #include "vgui/ILocalize.h" +#include "ui/neo_theme.h" #include "inputsystem/iinputsystem.h" #include "IGameUIFuncs.h" #include "igamesystem.h" diff --git a/src/game/client/viewpostprocess.cpp b/src/game/client/viewpostprocess.cpp index c6bcb2713f..d0793cabd2 100644 --- a/src/game/client/viewpostprocess.cpp +++ b/src/game/client/viewpostprocess.cpp @@ -87,7 +87,7 @@ ConVar mat_tonemap_algorithm( "mat_tonemap_algorithm", "1", FCVAR_CHEAT, "0 = Or ConVar mat_tonemap_percent_target( "mat_tonemap_percent_target", "60.0", FCVAR_CHEAT ); ConVar mat_tonemap_percent_bright_pixels( "mat_tonemap_percent_bright_pixels", "2.0", FCVAR_CHEAT ); ConVar mat_tonemap_min_avglum( "mat_tonemap_min_avglum", "3.0", FCVAR_CHEAT ); -#ifdef NEO // Unity build +#ifdef NEO_UNITY // Unity build extern ConVar mat_fullbright; #else ConVar mat_fullbright( "mat_fullbright", "0", FCVAR_CHEAT ); diff --git a/src/game/server/CMakeLists.txt b/src/game/server/CMakeLists.txt index da026598cc..eb9a890881 100644 --- a/src/game/server/CMakeLists.txt +++ b/src/game/server/CMakeLists.txt @@ -2,7 +2,7 @@ add_library(server SHARED) set_target_properties(server PROPERTIES PREFIX "" - UNITY_BUILD ON + UNITY_BUILD ${NEO_UNITY_BUILD_CLIENT_SERVER} UNITY_BUILD_MODE GROUP ) @@ -65,6 +65,7 @@ target_compile_definitions(server sprintf=use_Q_snprintf_instead_of_sprintf strncpy=use_Q_strncpy_instead NEXT_BOT + ${UNITY_BUILD_DEF_CLIENT_SERVER} ) target_link_libraries(server diff --git a/src/game/server/NextBot/Player/NextBotPlayerLocomotion.cpp b/src/game/server/NextBot/Player/NextBotPlayerLocomotion.cpp index d3f71e934f..012a7afdbc 100644 --- a/src/game/server/NextBot/Player/NextBotPlayerLocomotion.cpp +++ b/src/game/server/NextBot/Player/NextBotPlayerLocomotion.cpp @@ -10,6 +10,7 @@ #include "NextBotUtil.h" #include "NextBotPlayer.h" #include "NextBotPlayerLocomotion.h" +#include "bot/neo_bot.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" diff --git a/src/game/server/neo/bot/behavior/neo_bot_command_follow.cpp b/src/game/server/neo/bot/behavior/neo_bot_command_follow.cpp index 02bdd2a772..77ff225164 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_command_follow.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_command_follow.cpp @@ -3,6 +3,7 @@ #include "bot/neo_bot.h" #include "bot/behavior/neo_bot_command_follow.h" #include "bot/behavior/neo_bot_throw_weapon_at_player.h" +#include "bot/behavior/neo_bot_attack.h" #include "nav_mesh.h" // memdbgon must be the last include file in a .cpp file!!! diff --git a/src/game/server/neo/bot/behavior/neo_bot_ctg_enemy.h b/src/game/server/neo/bot/behavior/neo_bot_ctg_enemy.h index 152cad9457..8ae07df416 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_ctg_enemy.h +++ b/src/game/server/neo/bot/behavior/neo_bot_ctg_enemy.h @@ -2,6 +2,7 @@ #define NEO_BOT_CTG_ENEMY_H #include "bot/neo_bot.h" +#include "Path/NextBotChasePath.h" //-------------------------------------------------------------------------------------------------------- class CNEOBotCtgEnemy : public Action< CNEOBot > diff --git a/src/mathlib/CMakeLists.txt b/src/mathlib/CMakeLists.txt index 4856db4729..2ef34cea78 100644 --- a/src/mathlib/CMakeLists.txt +++ b/src/mathlib/CMakeLists.txt @@ -4,7 +4,7 @@ add_library(mathlib::mathlib ALIAS mathlib) set_target_properties(mathlib PROPERTIES PREFIX "" - UNITY_BUILD ON + UNITY_BUILD ${NEO_UNITY_BUILD_OTHERS} UNITY_BUILD_MODE GROUP ) @@ -18,7 +18,8 @@ target_include_directories(mathlib target_compile_definitions(mathlib PRIVATE - MATHLIB_LIB + MATHLIB_LIB + ${UNITY_BUILD_DEF_OTHERS} ) target_link_libraries(mathlib diff --git a/src/tier1/CMakeLists.txt b/src/tier1/CMakeLists.txt index 395eb35985..66a80d16e7 100644 --- a/src/tier1/CMakeLists.txt +++ b/src/tier1/CMakeLists.txt @@ -2,14 +2,18 @@ add_library(tier1 STATIC) add_library(tier1::tier1 ALIAS tier1) -target_compile_definitions(tier1 PRIVATE TIER1_STATIC_LIB) +target_compile_definitions(tier1 + PRIVATE + TIER1_STATIC_LIB + ${UNITY_BUILD_DEF_OTHERS} +) set(unity_before [[ #include "tier0/memdbgoff.h" ]]) set_target_properties(tier1 PROPERTIES - UNITY_BUILD ON + UNITY_BUILD ${NEO_UNITY_BUILD_OTHERS} UNITY_BUILD_MODE GROUP UNITY_BUILD_CODE_BEFORE_INCLUDE "${unity_before}" ) diff --git a/src/vgui2/vgui_controls/CMakeLists.txt b/src/vgui2/vgui_controls/CMakeLists.txt index 94be59dcef..bc59ab0c6e 100644 --- a/src/vgui2/vgui_controls/CMakeLists.txt +++ b/src/vgui2/vgui_controls/CMakeLists.txt @@ -4,10 +4,15 @@ add_library(vgui_controls::vgui_controls ALIAS vgui_controls) set_target_properties(vgui_controls PROPERTIES PREFIX "" - UNITY_BUILD ON + UNITY_BUILD ${NEO_UNITY_BUILD_OTHERS} UNITY_BUILD_MODE GROUP ) +target_compile_definitions(vgui_controls + PRIVATE + ${UNITY_BUILD_DEF_OTHERS} +) + target_include_directories(vgui_controls PRIVATE ${CMAKE_SOURCE_DIR}/common diff --git a/src/vgui2/vgui_controls/FileOpenDialog.cpp b/src/vgui2/vgui_controls/FileOpenDialog.cpp index a7c36310aa..4a5d89e059 100644 --- a/src/vgui2/vgui_controls/FileOpenDialog.cpp +++ b/src/vgui2/vgui_controls/FileOpenDialog.cpp @@ -47,7 +47,7 @@ #include #include #include -#ifdef NEO // Unity build +#ifdef NEO_UNITY // Unity build #include "Common.h" #endif @@ -63,7 +63,7 @@ using namespace vgui; static int s_nLastSortColumn = 0; -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build static int ListFileNameSortFunc([[maybe_unused]] ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 ) { bool dir1 = item1.kv->GetInt("directory") == 1; @@ -180,7 +180,7 @@ static int ListBaseInteger64SortFunc(ListPanel *pPanel, const ListPanelItem &ite return ( i1 < i2 ) ? -1 : 1; } -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build static int ListFileSizeSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 ) { return ListBaseIntegerSortFunc( pPanel, item1, item2, "filesizeint" ); @@ -197,7 +197,7 @@ static int ListFileCreatedSortFunc(ListPanel *pPanel, const ListPanelItem &item1 // NOTE: Backward order to get most recent files first return ListBaseInteger64SortFunc( pPanel, item2, item1, "createdint_low", "createdint_high" ); } -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build static int ListFileAttributesSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 ) { return ListBaseStringSortFunc( pPanel, item1, item2, "attributes" ); @@ -469,7 +469,7 @@ void FileCompletionEdit::OnMenuItemHighlight( int itemID ) //----------------------------------------------------------------------------- static CUtlDict< CUtlString, unsigned short > s_StartDirContexts; -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build struct ColumnInfo_t { char const *columnName; diff --git a/src/vgui2/vgui_controls/KeyBindingHelpDialog.cpp b/src/vgui2/vgui_controls/KeyBindingHelpDialog.cpp index 993354121b..76f8cef702 100644 --- a/src/vgui2/vgui_controls/KeyBindingHelpDialog.cpp +++ b/src/vgui2/vgui_controls/KeyBindingHelpDialog.cpp @@ -15,7 +15,7 @@ #include "vgui/Cursor.h" #include "tier1/utldict.h" #include "vgui_controls/KeyBoardEditorDialog.h" -#ifdef NEO // Unity build +#ifdef NEO_UNITY // Unity build #include "Common.h" #endif @@ -28,7 +28,7 @@ using namespace vgui; // If the user holds the key bound to help down for this long, then the dialog will stay on automatically #define KB_HELP_CONTINUE_SHOWING_TIME 1.0 -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build static bool BindingLessFunc( KeyValues * const & lhs, KeyValues * const &rhs ) { KeyValues *p1, *p2; diff --git a/src/vgui2/vgui_controls/KeyBoardEditorDialog.cpp b/src/vgui2/vgui_controls/KeyBoardEditorDialog.cpp index c4d0f45163..6c6974c8a0 100644 --- a/src/vgui2/vgui_controls/KeyBoardEditorDialog.cpp +++ b/src/vgui2/vgui_controls/KeyBoardEditorDialog.cpp @@ -15,7 +15,7 @@ #include "KeyValues.h" #include "vgui/Cursor.h" #include "tier1/utldict.h" -#ifdef NEO // Unity build +#ifdef NEO_UNITY // Unity build #include "Common.h" #endif @@ -25,7 +25,7 @@ using namespace vgui; -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build static char *CopyString( const char *in ) { if ( !in ) @@ -554,7 +554,7 @@ void CKeyBoardEditorPage::GetMappingList( Panel *panel, CUtlVector< PanelKeyBind } } -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build static bool BindingLessFunc( KeyValues * const & lhs, KeyValues * const &rhs ) { KeyValues *p1, *p2; diff --git a/src/vgui2/vgui_controls/ListPanel.cpp b/src/vgui2/vgui_controls/ListPanel.cpp index c281ece625..f8e16bbf7a 100644 --- a/src/vgui2/vgui_controls/ListPanel.cpp +++ b/src/vgui2/vgui_controls/ListPanel.cpp @@ -31,7 +31,7 @@ #include #include #include -#ifdef NEO // Unity build +#ifdef NEO_UNITY // Unity build #include "Common.h" #endif @@ -39,7 +39,7 @@ #include "tier0/memdbgon.h" using namespace vgui; -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build enum { WINDOW_BORDER_WIDTH=2 // the width of the window's border diff --git a/src/vgui2/vgui_controls/ListViewPanel.cpp b/src/vgui2/vgui_controls/ListViewPanel.cpp index 51ae830df8..05ba0347db 100644 --- a/src/vgui2/vgui_controls/ListViewPanel.cpp +++ b/src/vgui2/vgui_controls/ListViewPanel.cpp @@ -24,7 +24,7 @@ #include #include #include -#ifdef NEO // Unity build +#ifdef NEO_UNITY // Unity build #include "Common.h" #endif @@ -32,7 +32,7 @@ #include using namespace vgui; -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build enum { WINDOW_BORDER_WIDTH=2 // the width of the window's border diff --git a/src/vgui2/vgui_controls/Panel.cpp b/src/vgui2/vgui_controls/Panel.cpp index 354e0ce0dd..7fd3a20300 100644 --- a/src/vgui2/vgui_controls/Panel.cpp +++ b/src/vgui2/vgui_controls/Panel.cpp @@ -44,7 +44,7 @@ #include "tier0/vprof.h" -#ifdef NEO // Unity build +#ifdef NEO_UNITY // Unity build #include "Common.h" #endif @@ -72,7 +72,7 @@ COMPILE_TIME_ASSERT( Panel::PIN_LAST == ARRAYSIZE( g_PinCornerStrings ) ); extern int GetBuildModeDialogCount(); -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build static char *CopyString( const char *in ) { if ( !in ) diff --git a/src/vgui2/vgui_controls/PerforceFileList.cpp b/src/vgui2/vgui_controls/PerforceFileList.cpp index 09cf2d65fe..67a8a97acb 100644 --- a/src/vgui2/vgui_controls/PerforceFileList.cpp +++ b/src/vgui2/vgui_controls/PerforceFileList.cpp @@ -14,7 +14,7 @@ #include "filesystem.h" #include "p4lib/ip4.h" #include "tier2/tier2.h" -#ifdef NEO // Unity build +#ifdef NEO_UNITY // Unity build #include "Common.h" #endif @@ -25,7 +25,7 @@ using namespace vgui; -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build static int ListFileNameSortFunc([[maybe_unused]] ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 ) { bool dir1 = item1.kv->GetInt("directory") == 1; @@ -133,7 +133,7 @@ static int ListFileTypeSortFunc(ListPanel *pPanel, const ListPanelItem &item1, c //----------------------------------------------------------------------------- // Dictionary of start dir contexts //----------------------------------------------------------------------------- -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build struct ColumnInfo_t { char const *columnName; diff --git a/src/vgui2/vgui_controls/PropertyDialog.cpp b/src/vgui2/vgui_controls/PropertyDialog.cpp index eb11c9897d..381ab191e9 100644 --- a/src/vgui2/vgui_controls/PropertyDialog.cpp +++ b/src/vgui2/vgui_controls/PropertyDialog.cpp @@ -60,7 +60,7 @@ PropertyDialog::~PropertyDialog() // Purpose: Returns a pointer to the PropertySheet this dialog encapsulates // Output : PropertySheet * //----------------------------------------------------------------------------- -#ifdef NEO // Unity build +#ifdef NEO_UNITY // Unity build vgui::PropertySheet *PropertyDialog::GetPropertySheet() #else PropertySheet *PropertyDialog::GetPropertySheet() diff --git a/src/vgui2/vgui_controls/ToolWindow.cpp b/src/vgui2/vgui_controls/ToolWindow.cpp index 092c0c40fc..c584f54ba7 100644 --- a/src/vgui2/vgui_controls/ToolWindow.cpp +++ b/src/vgui2/vgui_controls/ToolWindow.cpp @@ -108,7 +108,7 @@ bool ToolWindow::IsDraggableTabContainer() const // Purpose: Returns a pointer to the PropertySheet this dialog encapsulates // Output : PropertySheet * //----------------------------------------------------------------------------- -#ifdef NEO // Unity build +#ifdef NEO_UNITY // Unity build vgui::PropertySheet *ToolWindow::GetPropertySheet() #else PropertySheet *ToolWindow::GetPropertySheet() diff --git a/src/vgui2/vgui_controls/TreeView.cpp b/src/vgui2/vgui_controls/TreeView.cpp index 937c4cd9dd..0185d7b596 100644 --- a/src/vgui2/vgui_controls/TreeView.cpp +++ b/src/vgui2/vgui_controls/TreeView.cpp @@ -28,7 +28,7 @@ #include #include #include -#ifdef NEO // Unity build +#ifdef NEO_UNITY // Unity build #include "Common.h" #endif @@ -42,7 +42,7 @@ #endif using namespace vgui; -#ifndef NEO // Unity build +#ifndef NEO_UNITY // Unity build enum { WINDOW_BORDER_WIDTH=2 // the width of the window's border diff --git a/tools/ntre-dev-setup.sh b/tools/ntre-dev-setup.sh new file mode 100755 index 0000000000..752bc0b4ac --- /dev/null +++ b/tools/ntre-dev-setup.sh @@ -0,0 +1,397 @@ +#!/usr/bin/env bash +# +# Bootstraps C++ IntelliSense: a compile_commands.json symlinked at the repo root +# and a .clangd beside it - the two interfaces every C++ indexer understands. +# +# Why a separate CMake directory: a unity build's database lists only generated +# unity_*.cxx blobs, so ~1300 translation units get no flags at all. This preset +# turns NEO_UNITY_BUILD_CLIENT_SERVER and NEO_UNITY_BUILD_OTHERS off for the +# database alone, leaving your real build directory configured however you like; +# nothing is compiled from it. +# +# Safe to re-run; it skips what is already in place. See --help. + +set -euo pipefail + +CLANGD_VERSION="22.1.6" +CLANGD_SHA256_LINUX_X86_64="a9c77443af2e447ed467e84771848d3a6ac1c56f84bcfcde717e66318de77cfa" +# clangd older than this mishandles the C++20 this tree is built with. +CLANGD_MIN_MAJOR=17 + +PRESET="linux-debug-ide" +BASE_PRESET="linux-debug" +# Globbed for the GCC 10 and Clang 19 in CONTRIBUTING.md, which install as +# gcc-10, clang-19, /usr/lib/llvm-19/bin/clang++. A driver clangd cannot query +# leaves it guessing the standard library paths. +QUERY_DRIVER='/usr/bin/g++*,/usr/bin/gcc*,/usr/bin/clang*,/usr/lib/llvm-*/bin/clang*' +EDITOR_TARGET="auto" +USE_SYSTEM_CLANGD=0 +RECONFIGURE=0 +FORCE=0 +CLANGD_VERSION_OVERRIDDEN=0 +CLANGD_SHA256_OVERRIDE="" + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +IDE_DIR="${REPO_ROOT}/.ide" +SRC_DIR="${REPO_ROOT}/src" +BUILD_DIR="${SRC_DIR}/build/${PRESET}" + +usage() { + cat <<'EOF' +Usage: tools/ntre-dev-setup.sh [options] + + --editor + Write editor-specific config too. "auto" (default) + picks VS Code or Zed when run from that editor's + terminal or task. Every editor works without this; + it just saves pointing your client at + .ide/bin/clangd by hand. + --system-clangd Use clangd from PATH instead of downloading a + pinned one (must be >= major 17). + --clangd-version Override the pinned clangd release. Downloads + unverified unless --clangd-sha256 is also given. + --clangd-sha256 SHA-256 of the linux-x86_64 zip for an overridden + --clangd-version. + --preset IntelliSense preset name (default linux-debug-ide). + --base-preset Preset it inherits build flags from (default linux-debug). + --reconfigure Regenerate the compile database even if it exists. + Do this after adding/removing/renaming sources. + --force Overwrite generated config files (.clangd etc). + -h, --help This text. +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --editor) EDITOR_TARGET="$2"; shift 2 ;; + --system-clangd) USE_SYSTEM_CLANGD=1; shift ;; + --clangd-version) CLANGD_VERSION="$2"; CLANGD_VERSION_OVERRIDDEN=1; shift 2 ;; + --clangd-sha256) CLANGD_SHA256_OVERRIDE="$2"; shift 2 ;; + --preset) PRESET="$2"; BUILD_DIR="${SRC_DIR}/build/${PRESET}"; shift 2 ;; + --base-preset) BASE_PRESET="$2"; shift 2 ;; + --reconfigure) RECONFIGURE=1; shift ;; + --force) FORCE=1; shift ;; + -h|--help) usage; exit 0 ;; + *) echo "unknown option: $1" >&2; usage >&2; exit 2 ;; + esac +done + +# The pinned hash only vouches for the pinned version; an override replaces both. +if [[ $CLANGD_VERSION_OVERRIDDEN -eq 1 ]]; then + CLANGD_SHA256_LINUX_X86_64="$CLANGD_SHA256_OVERRIDE" +fi + +say() { printf '\033[1m==>\033[0m %s\n' "$*"; } +warn() { printf '\033[33mwarning:\033[0m %s\n' "$*" >&2; } +die() { printf '\033[31merror:\033[0m %s\n' "$*" >&2; exit 1; } + +# Writes stdin to $1 unless it exists (or --force). Returns 1 when skipped. +write_if_absent() { + local path="$1" + if [[ -e "$path" && $FORCE -eq 0 ]]; then + cat > /dev/null + return 1 + fi + mkdir -p "$(dirname "$path")" + cat > "$path" + return 0 +} + +# ---------------------------------------------------------------- prerequisites +for tool in cmake ninja; do + command -v "$tool" >/dev/null || die "$tool not found in PATH" +done +command -v g++ >/dev/null || warn "g++ not in PATH; the compile database will name a compiler this machine cannot query" +[[ -f "${SRC_DIR}/CMakePresets.json" ]] || die "no src/CMakePresets.json - run this from inside the repo" + +# ------------------------------------------------------------------- 1. clangd +CLANGD_BIN="${IDE_DIR}/bin/clangd" + +clangd_major() { "$1" --version 2>/dev/null | sed -n 's/.*clangd version \([0-9]*\).*/\1/p' | head -1; } + +install_clangd() { + local os arch asset major + os="$(uname -s)"; arch="$(uname -m)" + + case "${os}/${arch}" in + Linux/x86_64) asset="clangd-linux-${CLANGD_VERSION}.zip" ;; + *) + # No pinned release for this platform - notably linux/aarch64, and + # macOS, where this tree does not build anyway. + local sys; sys="$(command -v clangd || true)" + [[ -n "$sys" ]] || die "no clangd release for ${os}/${arch}; install clangd >= ${CLANGD_MIN_MAJOR} and re-run" + major="$(clangd_major "$sys")" + [[ -n "$major" && "$major" -ge $CLANGD_MIN_MAJOR ]] \ + || die "clangd ${major:-?} at ${sys} is too old for this tree's C++20; need >= ${CLANGD_MIN_MAJOR}" + warn "no clangd release for ${os}/${arch}; falling back to ${sys}" + mkdir -p "${IDE_DIR}/bin"; ln -sfn "$sys" "$CLANGD_BIN" + return + ;; + esac + + local dest="${IDE_DIR}/toolchain/clangd_${CLANGD_VERSION}" + if [[ ! -x "${dest}/bin/clangd" ]]; then + command -v curl >/dev/null || die "curl not found; needed to fetch clangd" + command -v unzip >/dev/null || die "unzip not found; needed to unpack clangd" + say "downloading clangd ${CLANGD_VERSION} (${asset})" + local tmp; tmp="$(mktemp -d)" + trap 'rm -rf "$tmp"' RETURN + curl -fsSL -o "${tmp}/clangd.zip" \ + "https://github.com/clangd/clangd/releases/download/${CLANGD_VERSION}/${asset}" + if [[ -n "$CLANGD_SHA256_LINUX_X86_64" ]]; then + echo "${CLANGD_SHA256_LINUX_X86_64} ${tmp}/clangd.zip" | sha256sum -c - >/dev/null \ + || die "clangd download failed checksum verification" + else + warn "no checksum for clangd ${CLANGD_VERSION}; skipping verification (pass --clangd-sha256 to pin one)" + fi + mkdir -p "${IDE_DIR}/toolchain" + rm -rf "$dest" + unzip -q "${tmp}/clangd.zip" -d "${IDE_DIR}/toolchain" + fi + mkdir -p "${IDE_DIR}/bin" + ln -sfn "../toolchain/clangd_${CLANGD_VERSION}/bin/clangd" "$CLANGD_BIN" +} + +if [[ $USE_SYSTEM_CLANGD -eq 1 ]]; then + sys="$(command -v clangd || true)" + [[ -n "$sys" ]] || die "--system-clangd given but no clangd in PATH" + major="$(clangd_major "$sys")" + [[ -n "$major" && "$major" -ge $CLANGD_MIN_MAJOR ]] \ + || die "clangd $major is too old for this tree's C++20; need >= ${CLANGD_MIN_MAJOR}" + mkdir -p "${IDE_DIR}/bin"; ln -sfn "$sys" "$CLANGD_BIN" +else + install_clangd +fi +say "clangd: $("$CLANGD_BIN" --version | head -1)" + +# ------------------------------------------------------- 2. CMakeUserPresets.json +# Per-developer by design and git-ignored, so writing here never dirties the tree. +# CMake Tools, CLion and `cmake --preset` all read it. +PRESETS_FILE="${SRC_DIR}/CMakeUserPresets.json" +if [[ -f "$PRESETS_FILE" ]] && grep -q "\"${PRESET}\"" "$PRESETS_FILE"; then + say "preset ${PRESET} already present in src/CMakeUserPresets.json" +elif [[ -f "$PRESETS_FILE" ]]; then + command -v python3 >/dev/null || die "src/CMakeUserPresets.json exists without a '${PRESET}' preset; install python3 so it can be merged, or add the preset by hand" + say "adding ${PRESET} to existing src/CMakeUserPresets.json" + PRESET="$PRESET" BASE_PRESET="$BASE_PRESET" python3 - "$PRESETS_FILE" <<'EOF' +import json, os, sys +path = sys.argv[1] +doc = json.load(open(path)) +doc.setdefault("version", 3) +doc.setdefault("configurePresets", []).append({ + "name": os.environ["PRESET"], + "displayName": "Linux Debug (IntelliSense index only)", + "description": "Configure-only, unity off, for the IntelliSense database. Do not build from it.", + "inherits": os.environ["BASE_PRESET"], + "cacheVariables": { + "NEO_UNITY_BUILD_CLIENT_SERVER": "OFF", + "NEO_UNITY_BUILD_OTHERS": "OFF", + "NEO_EXTRA_ASSETS": "OFF", + "NEO_COPY_LIBRARIES": "OFF", + "NEO_USE_CCACHE": "OFF", + }, +}) +json.dump(doc, open(path, "w"), indent=2) +open(path, "a").write("\n") +EOF +else + say "writing src/CMakeUserPresets.json" + cat > "$PRESETS_FILE" </dev/null || die "cmake configure failed; re-run without >/dev/null to see why" +else + say "compile database already present (--reconfigure to regenerate)" +fi + +entries=$(python3 -c "import json,sys; print(len(json.load(open(sys.argv[1]))))" "${BUILD_DIR}/compile_commands.json" 2>/dev/null || echo '?') +unity=$(grep -c 'Unity/unity_' "${BUILD_DIR}/compile_commands.json" 2>/dev/null || true) +say "compile database: ${entries} entries, ${unity:-0} unity blobs" +[[ "${unity:-0}" == "0" ]] || warn "unity entries present - something is overriding this preset's NEO_UNITY_BUILD_* = OFF" + +# Root symlink: the location nearly every C++ tool probes by default. +ln -sfn "src/build/${PRESET}/compile_commands.json" "${REPO_ROOT}/compile_commands.json" +say "symlinked compile_commands.json at the repo root" + +# ------------------------------------------------------------------ 5. env.sh +# For shell-launched editors (nvim, helix, emacs): source it and clangd is on PATH. +cat > "${IDE_DIR}/env.sh" <