Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
7161d9378e build(deps-dev): Bump @vitejs/plugin-react from 5.2.0 to 6.0.1
Bumps [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) from 5.2.0 to 6.0.1.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.0.1/packages/plugin-react)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 6.0.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-23 12:03:40 +00:00
4 changed files with 8 additions and 311 deletions

View File

@@ -112,7 +112,7 @@
"@types/node": "^25.3.0",
"@types/pg": "^8.16.0",
"@types/react": "^19.2.14",
"@vitejs/plugin-react": "^5.1.4",
"@vitejs/plugin-react": "^6.0.1",
"@vitest/browser": "^4.0.18",
"@vitest/browser-playwright": "^4.0.18",
"@vitest/coverage-v8": "^4.0.18",

View File

@@ -1,155 +0,0 @@
# GameEngine
SDL3 GPU 2D/3D game engine with a JSON-driven workflow system. Built with C++20, using Conan for dependency management and CMake + Ninja for builds.
## Quick Start
### Prerequisites
- C++20 compiler (MSVC, Clang, or GCC)
- [CMake](https://cmake.org/) 3.24+
- [Conan](https://conan.io/) 2.x
- [Ninja](https://ninja-build.org/) (recommended)
- Python 3.9+ (build helper)
### Build & Run (Recommended)
The `dev_commands.py` build helper runs the full pipeline: Conan install, CMake generate, configure, and build.
```bash
# Build and run the seed demo (auto-detects platform bootstrap)
python python/dev_commands.py all --run
# Equivalent explicit form on Windows
python python/dev_commands.py all --run --bootstrap bootstrap_windows --game seed
# macOS
python python/dev_commands.py all --run --bootstrap bootstrap_mac --game seed
# Linux
python python/dev_commands.py all --run --bootstrap bootstrap_linux --game seed
```
### Build Steps (Manual)
```bash
# 1. Install Conan dependencies
python python/dev_commands.py dependencies
# 2. Generate CMakeLists.txt from cmake_config.json
python python/dev_commands.py generate
# 3. Configure CMake
python python/dev_commands.py configure --preset conan-default
# 4. Build
python python/dev_commands.py build
# 5. Run
python python/dev_commands.py run -- --bootstrap bootstrap_windows --game seed
```
### Makefile (Unix)
```bash
make build # Build sdl3_app
make build TARGET=sdl3_app # Build specific target
make test # Build and run all tests
make rebuild # Clean + build
make list-targets # Show available targets
```
## CLI Arguments
The compiled `sdl3_app` binary accepts:
| Flag | Default | Description |
|------|---------|-------------|
| `--bootstrap` | `bootstrap_mac` | Platform bootstrap package |
| `--game` | `standalone_cubes` | Game package to load |
| `--project-root` | Current directory | Path to gameengine root |
## Packages
Game content and platform initialization are defined as JSON packages in `packages/`:
| Package | Type | Description |
|---------|------|-------------|
| `bootstrap_windows` | bootloader | Windows init, SDL3 GPU with D3D12 |
| `bootstrap_mac` | bootloader | macOS init, SDL3 GPU with Metal |
| `bootstrap_linux` | bootloader | Linux init, SDL3 GPU with Vulkan |
| `seed` | game | FPS demo: room with spinning cube, WASD movement, mouse look, jump. Bullet3 physics |
| `standalone_cubes` | game | 11x11 grid of spinning colored cubes with per-cube animation offsets |
| `quake3` | game | Quake 3 BSP map viewer with FPS controls |
| `soundboard` | game | Audio cues + GUI controls |
| `engine_tester` | game | Validation tour with teleport checkpoints, captures, and diagnostics |
| `asset_loader` | library | Universal asset loading with cross-engine unit conversion (JSON-driven) |
| `assets` | library | Shared runtime assets (audio, fonts, images) |
| `materialx` | library | MaterialX integration |
## Architecture
```
src/
main.cpp # Entry point, CLI parsing, workflow bootstrap
services/
interfaces/ # Abstract service interfaces (16 services)
i_audio_service.hpp
i_graphics_service.hpp
i_input_service.hpp
i_physics_service.hpp
i_scene_service.hpp
i_window_service.hpp
i_workflow_executor.hpp
...
impl/ # Concrete implementations
workflow/ # Workflow step implementations
diagnostics/ # Logging
app/ # CLI, platform services
packages/ # JSON-driven game content
{package}/
package.json # Package metadata, config, shader list
workflows/*.json # Workflow definitions (v2.2.0 format)
shaders/spirv/ # SPIR-V shaders (Vulkan, D3D12)
shaders/msl/ # Metal shaders (macOS)
scene/*.json # Scene definitions
assets/ # Package-specific assets
python/
dev_commands.py # Build helper CLI
generate_cmake.py # CMakeLists.txt generator from cmake_config.json
export_room_gltf.py # Seed demo room glTF exporter
```
## Dependencies (Conan)
| Library | Version | Purpose |
|---------|---------|---------|
| SDL | 3.2.20 | Windowing, input, GPU API |
| Bullet3 | 3.25 | 3D physics |
| Box2D | 3.1.1 | 2D physics |
| EnTT | 3.16.0 | Entity Component System |
| Assimp | 6.0.2 | 3D model import |
| glm | 1.0.1 | Math library |
| nlohmann_json | 3.11.3 | JSON parsing |
| RapidJSON | cci.20230929 | JSON parsing (performance) |
| FFmpeg | 8.0.1 | Audio/video decoding |
| FreeType | 2.13.2 | Font rendering |
| Cairo | 1.18.0 | 2D vector graphics |
| stb | cci.20230920 | Image loading |
| LunaSVG | 3.0.1 | SVG rendering |
| libzip | 1.10.1 | ZIP archive support |
| cpptrace | 1.0.4 | Stack traces |
| CLI11 | 2.6.0 | Command-line parsing |
| GTest | 1.17.0 | Testing framework |
## Testing
```bash
# Via Makefile
make test
# Via dev_commands.py
python python/dev_commands.py build --target test_exit_step
```

View File

@@ -34,123 +34,11 @@ import argparse
import os
import platform
import subprocess
import sys
from pathlib import Path
from typing import Iterable, Sequence
IS_WINDOWS = platform.system() == "Windows"
def _conan_cmd() -> list[str]:
"""Return the command prefix for invoking Conan.
Searches for the ``conan`` executable using several strategies so the
script works regardless of how Python/Conan were installed.
**Windows coverage**:
- Windows Store Python (``pip install --user``) — ``nt_user`` sysconfig
- python.org installer (global or per-user) — interpreter scripts dir
- python.org / Chocolatey ``pip install --user`` — ``%APPDATA%\\Python``
- Chocolatey (global) — typically on PATH or interpreter scripts dir
**macOS coverage**:
- Homebrew Python — on PATH (``/opt/homebrew/bin`` or ``/usr/local/bin``)
- System Python ``pip install --user`` — ``~/Library/Python/X.Y/bin``
- pyenv / conda / virtualenv — on PATH when activated, scripts dir otherwise
**Linux coverage**:
- apt / dnf system Python — on PATH (``/usr/bin`` or ``/usr/local/bin``)
- ``pip install --user`` — ``~/.local/bin``
- pyenv / conda / virtualenv — on PATH when activated, scripts dir otherwise
Strategy order:
1. ``shutil.which`` — anything already on PATH.
2. Python-adjacent Scripts/bin dirs — interpreter-level, user-level,
``%APPDATA%\\Python`` (Windows), ``~/Library/Python`` (macOS),
``~/.local/bin`` (Linux), and site-packages siblings.
3. ``sys.executable -m conans.conan`` — package importable but no script.
Raises ``FileNotFoundError`` with install instructions if nothing works.
"""
import shutil
import sysconfig
import site
# 1. Already on PATH (system install, brew, pyenv, conda, activated venv,
# choco with PATH, apt/dnf)
if shutil.which("conan"):
return ["conan"]
# 2. Search Scripts/bin dirs adjacent to the running interpreter
exe_name = "conan.exe" if IS_WINDOWS else "conan"
bin_dir = "Scripts" if IS_WINDOWS else "bin"
search_dirs: list[str] = []
# Interpreter-level scripts (venv/Scripts, C:\PythonXXX\Scripts,
# C:\Users\X\AppData\Local\Programs\Python\PythonXXX\Scripts,
# /usr/local/bin, /opt/homebrew/bin)
interp_scripts = sysconfig.get_path("scripts")
if interp_scripts:
search_dirs.append(interp_scripts)
# User-level scripts via sysconfig (Windows Store Python, ~/.local/bin)
scheme = "nt_user" if IS_WINDOWS else "posix_user"
try:
user_scripts = sysconfig.get_path("scripts", scheme)
if user_scripts:
search_dirs.append(user_scripts)
except KeyError:
pass
if IS_WINDOWS:
# python.org / Chocolatey "pip install --user" puts scripts under
# %APPDATA%\Python\PythonXYZ\Scripts — not covered by nt_user when
# running from Windows Store Python
appdata = os.environ.get("APPDATA", "")
if appdata:
ver = f"Python{sys.version_info.major}{sys.version_info.minor}"
search_dirs.append(os.path.join(appdata, "Python", ver, "Scripts"))
# Also check unversioned (older pip layouts)
search_dirs.append(os.path.join(appdata, "Python", "Scripts"))
else:
# macOS system Python: ~/Library/Python/X.Y/bin
if platform.system() == "Darwin":
ver = f"{sys.version_info.major}.{sys.version_info.minor}"
search_dirs.append(
os.path.expanduser(f"~/Library/Python/{ver}/bin")
)
# Linux/macOS: ~/.local/bin (pip install --user default)
search_dirs.append(os.path.expanduser("~/.local/bin"))
# Site-packages sibling dirs (covers additional layouts)
try:
for sp in site.getsitepackages():
search_dirs.append(os.path.join(os.path.dirname(sp), bin_dir))
except AttributeError:
pass
for d in dict.fromkeys(search_dirs): # dedupe, preserve order
candidate = os.path.join(d, exe_name)
if os.path.isfile(candidate):
return [candidate]
# 3. Module invocation (conan is importable but no script on disk)
try:
from importlib.metadata import distribution
distribution("conan") # raises PackageNotFoundError if absent
return [sys.executable, "-m", "conans.conan"]
except Exception:
pass
raise FileNotFoundError(
"Could not find Conan. Install it with: pip install conan"
)
DEFAULT_GENERATOR = "ninja-msvc" if IS_WINDOWS else "ninja"
GENERATOR_DEFAULT_DIR = {
"vs": "build",
@@ -308,9 +196,8 @@ def _has_cmake_cache(build_dir: str) -> bool:
def dependencies(args: argparse.Namespace) -> None:
"""Run Conan profile detection and install dependencies with C++20."""
conan = _conan_cmd()
cmd_detect = [*conan, "profile", "detect", "-f"]
cmd_install = [*conan, "install", ".", "-of", "build-ninja", "-b", "missing",
cmd_detect = ["conan", "profile", "detect", "-f"]
cmd_install = ["conan", "install", ".", "-of", "build-ninja", "-b", "missing",
"-s", "compiler.cppstd=20"]
conan_install_args = _strip_leading_double_dash(args.conan_install_args)
if conan_install_args:
@@ -338,14 +225,7 @@ def generate(args: argparse.Namespace) -> None:
def _fix_cmake_user_presets() -> None:
"""Ensure CMakeUserPresets.json only includes existing, non-conflicting preset files.
Conan regenerates preset files when the build layout changes (e.g.
``build-ninja/build/generators/`` vs ``build-ninja/build/Release/generators/``).
If the old file still exists, CMake fails with "Duplicate preset". This
function removes missing includes *and* detects preset name collisions,
keeping only the newest file when duplicates are found.
"""
"""Ensure CMakeUserPresets.json only includes existing preset files."""
import json as json_mod
presets_path = Path("CMakeUserPresets.json")
if not presets_path.exists():
@@ -353,39 +233,11 @@ def _fix_cmake_user_presets() -> None:
try:
data = json_mod.loads(presets_path.read_text())
includes = data.get("include", [])
# Drop missing files
valid = [p for p in includes if Path(p).exists()]
# Detect and resolve duplicate preset names across included files
seen_names: dict[str, str] = {} # preset_name -> include_path
duplicates: set[str] = set()
for inc_path in valid:
try:
inc_data = json_mod.loads(Path(inc_path).read_text())
except (json_mod.JSONDecodeError, OSError):
continue
for key in ("configurePresets", "buildPresets", "testPresets"):
for preset in inc_data.get(key, []):
name = preset.get("name", "")
if name in seen_names and seen_names[name] != inc_path:
# Keep the newer file, drop the older one
older = seen_names[name]
newer = inc_path
if Path(older).stat().st_mtime > Path(newer).stat().st_mtime:
older, newer = newer, older
duplicates.add(older)
seen_names[name] = newer
else:
seen_names[name] = inc_path
deduped = [p for p in valid if p not in duplicates]
if deduped != includes:
data["include"] = deduped
if len(valid) != len(includes):
data["include"] = valid
presets_path.write_text(json_mod.dumps(data, indent=4) + "\n")
removed = len(includes) - len(deduped)
print(f" Fixed CMakeUserPresets.json: removed {removed} stale/duplicate include(s)")
print(f" Fixed CMakeUserPresets.json: kept {len(valid)}/{len(includes)} includes")
except (json_mod.JSONDecodeError, OSError):
pass

View File

@@ -22,7 +22,7 @@
"@storybook/addon-vitest": "10.2.19",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.4",
"@vitejs/plugin-react": "^6.0.1",
"sass": "^1.97.3",
"storybook": "10.2.19",
"typescript": "^5.9.3",