Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8951ad9
fix(object): Prevent crash if Object::m_drawable is a nullptr on save…
Caball009 May 17, 2026
2219f63
refactor(netpacket): Simplify NetPacket functions for packet buffer r…
xezon May 17, 2026
7dc2632
bugfix: Restore retail compatibility after retail behavior flags chan…
Caball009 May 19, 2026
5ef7985
fix(gameengine): Remove music tracks as prerequisite to initialize th…
xezon May 19, 2026
1594474
bugfix(physics): Prevent dead units from repeatedly dealing crash dam…
Stubbjax May 20, 2026
f8476f0
bugfix(physics): Prevent building crash damage from dealing damage to…
Stubbjax May 20, 2026
5a4187c
fix(network): Verify accepted type of incoming game messages (#2708)
stephanmeesters May 20, 2026
7cb3c11
fix(particlesys): Add or simplify null-checks to createParticleSystem…
stephanmeesters May 20, 2026
f7ecdb4
refactor(network): Use switch cases in utility functions for network …
Caball009 May 20, 2026
c1bce4f
perf(network): Replace extern global network variables with const one…
Caball009 May 20, 2026
5852010
bugfix(aigroup): Prevent game crash when a player is selected in Repl…
Caball009 May 20, 2026
842c7a5
fix(recorder): Fix memory leak of RecorderClass::m_crcInfo (#2713)
Caball009 May 20, 2026
bf8d5be
bugfix(gameengine): Fix logic in GameEngine::canUpdateRegularGameLogi…
xezon May 21, 2026
9a402fb
fix(particlesys): Decouple particle systems from logic crc (#2742)
xezon May 25, 2026
92df977
fix(particlesys): Simplify ParticleSystemManagerDummy setup (#2740)
xezon May 25, 2026
adcf69e
fix(memory): Fix audio event related memory leaks when pausing the ga…
Caball009 May 28, 2026
cc4a683
bugfix(water): Fix river visuals in black shroud (#2749)
stephanmeesters May 28, 2026
8a06f35
unify(message): Merge MessageStream, MetaEvent code (#2756)
xezon May 30, 2026
d7f7203
fix(metaevent): Ignore order in which modifier keys are released to t…
xezon May 30, 2026
ed7e96f
unify(shroud): Merge W3DShroud code from Zero Hour and implicitly fix…
Mr-Sheerlock May 31, 2026
a59cccb
merge(thesuperhackers): sync upstream with cross-platform integrity
fbraz3 May 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/prompts/sync-thesuperhackers-upstream.prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Expect many conflicts because the projects intentionally diverged. Every conflic
- Preserve platform isolation. Do not allow platform-specific code to leak into gameplay logic.
- Keep legacy compatibility paths only where they are still intentionally maintained by this repository, but do not let original-binary compatibility override the `GeneralsX` cross-platform objective.
- Treat INI parser changes as high risk on macOS: upstream numeric parsing optimizations may require platform-specific compatibility handling for Apple deployment targets.
- **Never replace our CI/CD infrastructure with upstream versions.** Our `.github/workflows/`, `.github/ISSUE_TEMPLATE/`, `.github/copilot-instructions.md` and all CI configuration must be kept intact. Reject any upstream additions or modifications to these paths.
- Review conflicts with extra care in these areas:
- build system and presets
- SDL3, DXVK, OpenAL, FFmpeg, and platform abstraction layers
Expand Down
63 changes: 63 additions & 0 deletions scripts/clang-tidy-plugin/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Custom clang-tidy plugin for GeneralsGameCode
# This plugin provides checks for custom types like AsciiString and UnicodeString

cmake_minimum_required(VERSION 3.20)
project(GeneralsGameCodeClangTidyPlugin)

# Find LLVM and Clang
find_package(LLVM REQUIRED CONFIG)
find_package(Clang REQUIRED CONFIG)

message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
message(STATUS "Using ClangConfig.cmake in: ${Clang_DIR}")

# Set up include directories
include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${CLANG_INCLUDE_DIRS})

# Add definitions
add_definitions(${LLVM_DEFINITIONS})
add_definitions(${CLANG_DEFINITIONS})

# Set C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Source files
set(SOURCES
GeneralsGameCodeTidyModule.cpp
readability/UseIsEmptyCheck.cpp
readability/UseThisInsteadOfSingletonCheck.cpp
)

# Header files
set(HEADERS
GeneralsGameCodeTidyModule.h
readability/UseIsEmptyCheck.h
readability/UseThisInsteadOfSingletonCheck.h
)

# Create the module library
add_library(GeneralsGameCodeClangTidyPlugin MODULE ${SOURCES} ${HEADERS})

# Link against required libraries
target_link_libraries(GeneralsGameCodeClangTidyPlugin
PRIVATE
clangTidy
clangTidyReadabilityModule
clangAST
clangASTMatchers
clangBasic
clangFrontend
clangLex
clangTooling
LLVMSupport
)

# Set output directory
set_target_properties(GeneralsGameCodeClangTidyPlugin PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)

30 changes: 30 additions & 0 deletions scripts/clang-tidy-plugin/GeneralsGameCodeTidyModule.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===--- GeneralsGameCodeTidyModule.cpp - GeneralsGameCode Tidy Module ---===//
//
// Custom clang-tidy module for GeneralsGameCode
// Provides GeneralsGameCode-specific checks
//
//===----------------------------------------------------------------------===//

#include "GeneralsGameCodeTidyModule.h"
#include "readability/UseIsEmptyCheck.h"
#include "readability/UseThisInsteadOfSingletonCheck.h"
#include "llvm/Support/Registry.h"

namespace clang::tidy::generalsgamecode {

void GeneralsGameCodeTidyModule::addCheckFactories(
ClangTidyCheckFactories &CheckFactories) {
CheckFactories.registerCheck<readability::UseIsEmptyCheck>(
"generals-use-is-empty");
CheckFactories.registerCheck<readability::UseThisInsteadOfSingletonCheck>(
"generals-use-this-instead-of-singleton");
}

} // namespace clang::tidy::generalsgamecode

static llvm::Registry<::clang::tidy::ClangTidyModule>::Add<
::clang::tidy::generalsgamecode::GeneralsGameCodeTidyModule>
X("generalsgamecode", "GeneralsGameCode-specific checks");

volatile int GeneralsGameCodeTidyModuleAnchorSource = 0;

24 changes: 24 additions & 0 deletions scripts/clang-tidy-plugin/GeneralsGameCodeTidyModule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===--- GeneralsGameCodeTidyModule.h - GeneralsGameCode Tidy Module -----===//
//
// Custom clang-tidy module for GeneralsGameCode
// Provides checks for custom types like AsciiString and UnicodeString
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GENERALSGAMECODE_GENERALSGAMECODETIDYMODULE_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GENERALSGAMECODE_GENERALSGAMECODETIDYMODULE_H

#include "clang-tidy/ClangTidyModule.h"

namespace clang::tidy::generalsgamecode {

/// This module is for GeneralsGameCode-specific checks.
class GeneralsGameCodeTidyModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override;
};

} // namespace clang::tidy::generalsgamecode

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GENERALSGAMECODE_GENERALSGAMECODETIDYMODULE_H

250 changes: 250 additions & 0 deletions scripts/clang-tidy-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
# GeneralsGameCode Clang-Tidy Custom Checks

Custom clang-tidy checks for the GeneralsGameCode codebase. **This is primarily designed for Windows**, where checks are built directly into clang-tidy. Mac/Linux users can optionally use the plugin version.

## Quick Start

### Windows

**Option 1: Use Pre-built clang-tidy**
- Precompiled binaries can be found at: https://github.com/TheSuperHackers/GeneralsTools

**Option 2: Build It Yourself**

Follow the manual steps in the [Windows: Building Checks Into clang-tidy](#windows-building-checks-into-clang-tidy) section below.

**Usage**
```powershell
llvm-project\build\bin\clang-tidy.exe -p build/clang-tidy `
--checks='-*,generals-use-is-empty,generals-use-this-instead-of-singleton' `
file.cpp
```

### macOS/Linux (Plugin Version)

If you prefer the plugin approach on macOS/Linux:

```bash
# Build the plugin
cd scripts/clang-tidy-plugin
mkdir build && cd build
cmake .. -DLLVM_DIR=/path/to/llvm/lib/cmake/llvm
cmake --build . --config Release

# Use with --load flag
clang-tidy -p build/clang-tidy \
--checks='-*,generals-use-is-empty' \
-load scripts/clang-tidy-plugin/build/lib/libGeneralsGameCodeClangTidyPlugin.so \
file.cpp
```

**Note:** On Windows, plugin loading via `--load` is **not supported** due to DLL static initialization limitations. Windows users must use the built-in version.

## Checks

### `generals-use-is-empty`

Finds uses of `getLength() == 0`, `getLength() > 0`, `compare("") == 0`, or `compareNoCase("") == 0` on `AsciiString` and `UnicodeString`, and `Get_Length() == 0` on `StringClass` and `WideStringClass`, and suggests using `isEmpty()`/`Is_Empty()` or `!isEmpty()`/`!Is_Empty()` instead.

**Examples:**

```cpp
// Before (AsciiString/UnicodeString)
if (str.getLength() == 0) { ... }
if (str.getLength() > 0) { ... }
if (str.compare("") == 0) { ... }
if (str.compareNoCase("") == 0) { ... }
if (str.compare(AsciiString::TheEmptyString) == 0) { ... }

// After (AsciiString/UnicodeString)
if (str.isEmpty()) { ... }
if (!str.isEmpty()) { ... }
if (str.isEmpty()) { ... }
if (str.isEmpty()) { ... }
if (str.isEmpty()) { ... }

// Before (StringClass/WideStringClass)
if (str.Get_Length() == 0) { ... }
if (str.Get_Length() > 0) { ... }

// After (StringClass/WideStringClass)
if (str.Is_Empty()) { ... }
if (!str.Is_Empty()) { ... }
```

### `generals-use-this-instead-of-singleton`

Finds uses of singleton global variables (like `TheGameLogic->method()` or `TheGlobalData->member`) inside member functions of the same class type, and suggests using the member directly (e.g., `method()` or `member`) instead of the singleton reference.

**Examples:**

```cpp
// Before
void GameLogic::update() {
UnsignedInt now = TheGameLogic->getFrame();
TheGameLogic->setFrame(now + 1);
TheGameLogic->m_frame = 10;
}

// After
void GameLogic::update() {
UnsignedInt now = getFrame();
setFrame(now + 1);
m_frame = 10;
}
```

## Prerequisites

Before using clang-tidy, you need to generate a compile commands database:

```bash
cmake -B build/clang-tidy -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -G Ninja
```

This creates `build/clang-tidy/compile_commands.json` which tells clang-tidy how to compile each file.

## Windows: Building Checks Into clang-tidy

Since plugin loading via `--load` doesn't work on Windows, the checks are integrated directly into the clang-tidy source tree. This is the recommended approach for Windows.

### Step 1: Clone and Build LLVM

### Step 2: Copy Plugin Files to LLVM Source Tree

```powershell
# Create the plugin directory in clang-tools-extra
mkdir llvm-project\clang-tools-extra\clang-tidy\plugins\generalsgamecode

# Copy the plugin source files
cp -r scripts\clang-tidy-plugin\*.cpp llvm-project\clang-tools-extra\clang-tidy\plugins\generalsgamecode\
cp -r scripts\clang-tidy-plugin\*.h llvm-project\clang-tools-extra\clang-tidy\plugins\generalsgamecode\
cp -r scripts\clang-tidy-plugin\readability llvm-project\clang-tools-extra\clang-tidy\plugins\generalsgamecode\
```

**Important:** After copying, you need to update the include paths in the headers:
- Change `#include "clang-tidy/ClangTidyCheck.h"` to `#include "../../../ClangTidyCheck.h"`
- Change `#include "clang-tidy/ClangTidyModule.h"` to `#include "../../ClangTidyModule.h"`

### Step 3: Create CMakeLists.txt for the Module

Create `llvm-project/clang-tools-extra/clang-tidy/plugins/generalsgamecode/CMakeLists.txt`:

```cmake
add_clang_library(clangTidyGeneralsGameCodeModule STATIC
GeneralsGameCodeTidyModule.cpp
readability/UseIsEmptyCheck.cpp
readability/UseThisInsteadOfSingletonCheck.cpp

LINK_LIBS
clangTidy
clangTidyUtils
)

clang_target_link_libraries(clangTidyGeneralsGameCodeModule
PRIVATE
clangAST
clangASTMatchers
clangBasic
clangLex
clangTooling
)
```

### Step 4: Register the Module

**Modify `llvm-project/clang-tools-extra/clang-tidy/CMakeLists.txt`:**

Add the subdirectory:
```cmake
add_subdirectory(plugins/generalsgamecode)
```

Add to `ALL_CLANG_TIDY_CHECKS`:
```cmake
set(ALL_CLANG_TIDY_CHECKS
...
clangTidyGeneralsGameCodeModule
...
)
```

**Modify `llvm-project/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h`:**

Add the anchor to force linker inclusion:
```cpp
// This anchor is used to force the linker to link the GeneralsGameCodeModule.
extern volatile int GeneralsGameCodeModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED GeneralsGameCodeModuleAnchorDestination =
GeneralsGameCodeModuleAnchorSource;
```

**Modify `llvm-project/clang-tools-extra/clang-tidy/plugins/generalsgamecode/GeneralsGameCodeTidyModule.cpp`:**

Ensure the anchor is defined:
```cpp
namespace clang::tidy {
// ... module registration ...

// Force linker to include this module
volatile int GeneralsGameCodeModuleAnchorSource = 0;
}
```

### Step 5: Rebuild clang-tidy

```powershell
cd llvm-project\build
ninja clang-tidy
```

### Step 6: Use the Built-in Checks

Once rebuilt, the checks are always available - no `--load` flag needed:

```powershell
llvm-project\build\bin\clang-tidy.exe -p build/clang-tidy `
--checks='-*,generals-use-is-empty,generals-use-this-instead-of-singleton' `
file.cpp
```


## macOS/Linux: Building the Plugin

If you're on macOS or Linux and want to use the plugin version:

### Prerequisites

**macOS:**
```bash
brew install llvm@21
```

**Linux (Ubuntu/Debian):**
```bash
sudo apt-get install llvm-21-dev clang-21 libclang-21-dev
```

### Building the Plugin

```bash
cd scripts/clang-tidy-plugin
mkdir build && cd build
cmake .. -DLLVM_DIR=/path/to/llvm/lib/cmake/llvm -DClang_DIR=/path/to/clang/lib/cmake/clang
cmake --build . --config Release
```

The plugin will be built as a shared library (`.so` on Linux, `.dylib` on macOS) in the `build/lib/` directory.

### Using the Plugin

```bash
clang-tidy -p build/clang-tidy \
--checks='-*,generals-use-is-empty,generals-use-this-instead-of-singleton' \
-load scripts/clang-tidy-plugin/build/lib/libGeneralsGameCodeClangTidyPlugin.so \
file.cpp
```

**Important:** The plugin must be built with the same LLVM version as the `clang-tidy` executable in your PATH. The CMake build will display which LLVM version it found (e.g., `Found LLVM 21.1.7`). Verify this matches your `clang-tidy --version` output.

- Windows plugins not working is a known limitation - see [GitHub issue #159710](https://github.com/llvm/llvm-project/issues/159710) and [LLVM Discourse discussion](https://discourse.llvm.org/t/clang-tidy-is-clang-tidy-out-of-tree-check-plugin-load-mechanism-guaranteed-to-work-with-msvc/84111)
Loading