Skip to content

Commit ca54769

Browse files
authored
More core compilation pipeline work with generated config system and DI framework (#186)
## Major Components ### Configuration System - Auto-generated configuration classes from YAML schema using Jinja2 templates - Layered configuration with DefaultProvider and YamlFileProvider - Comprehensive config validation with detailed multi-line error messages - Support for domain, app, and infrastructure configuration layers ### Domain Architecture - Refactored models to use template classes (PixelTile<T>, Palette<T>) - New models: ColorIndex, ColorIndexMap for improved type safety - Removed RGBA-specific subclasses in favor of generic implementations - Algorithm modules for palette matching and tile conversions ### Dependency Injection - Integrated Google Fruit DI framework - Component-based architecture for service composition ### Core Services - PrimaryTilesetCompiler: Read and process palette data - LayerModeConverter: Handle triple-layer and dual-layer conversions - MetatileDecompiler: Decompose metatiles into constituent parts - ImageTileizer and LayerImageMetatileizer: Template-based tileization - TilePrinter and PalettePrinter: Diagnostic output utilities ### Error Handling & Diagnostics - Multi-line error messages with source details - YAML source line highlighting with formatting - Enhanced BufferedUserDiagnostics with tag support ### Testing & Documentation - Comprehensive test coverage for new algorithms and services - Updated architectural notes and planning documents - Enhanced code style guidelines and documentation
1 parent 745b015 commit ca54769

File tree

157 files changed

+11538
-2006
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

157 files changed

+11538
-2006
lines changed

.github/workflows/build_jobs_template.yml

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,26 @@ jobs:
2828
- name: Run the test suite
2929
uses: ./.github/workflows/run_test_suite
3030

31-
build-linux-amd64-gcc:
32-
name: Build on linux-amd64 with gcc
33-
runs-on: ubuntu-latest
34-
steps:
35-
- name: Checkout Porytiles repository
36-
uses: actions/checkout@v4
37-
38-
- name: Install Porytiles build dependencies
39-
uses: ./.github/workflows/install_dependencies_linux
40-
41-
- name: Install gcc
42-
uses: ./.github/workflows/install_gcc_linux
43-
44-
- name: Build the project
45-
uses: ./.github/workflows/build_linux_gcc
46-
47-
- name: Run the test suite
48-
uses: ./.github/workflows/run_test_suite
31+
# Using some C++23 features that are supported by GCC 15, need to wait for
32+
# GitHub to update the Ubuntu version used in the GitHub Actions runners.
33+
# build-linux-amd64-gcc:
34+
# name: Build on linux-amd64 with gcc
35+
# runs-on: ubuntu-latest
36+
# steps:
37+
# - name: Checkout Porytiles repository
38+
# uses: actions/checkout@v4
39+
#
40+
# - name: Install Porytiles build dependencies
41+
# uses: ./.github/workflows/install_dependencies_linux
42+
#
43+
# - name: Install gcc
44+
# uses: ./.github/workflows/install_gcc_linux
45+
#
46+
# - name: Build the project
47+
# uses: ./.github/workflows/build_linux_gcc
48+
#
49+
# - name: Run the test suite
50+
# uses: ./.github/workflows/run_test_suite
4951

5052
build-linux-arm64-clang:
5153
name: Build on linux-arm64 with clang

.github/workflows/install_gcc_linux/action.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@ runs:
77
shell: bash
88
run: |
99
sudo apt-get update -qq
10-
sudo apt-get install -y g++
11-
g++ --version
10+
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
11+
sudo apt update
12+
sudo apt install gcc-14 g++-14 -y
13+
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100
14+
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ bar/**
3030

3131
# Ignore Python venv
3232
venv/**
33+
.venv/**

.vscode/c_cpp_properties.json

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,37 @@
11
{
2-
"configurations": [
3-
{
4-
"name": "Mac",
5-
"includePath": [
6-
"${workspaceFolder}/Porytiles1/include/**",
7-
"${workspaceFolder}/Porytiles1/lib/**",
8-
"${workspaceFolder}/Porytiles1/tools/**",
9-
"${workspaceFolder}/Porytiles1/vendor/**",
10-
"${workspaceFolder}/Porytiles2/include/**",
11-
"${workspaceFolder}/Porytiles2/lib/**",
12-
"${workspaceFolder}/Porytiles2/tools/**",
13-
"${workspaceFolder}/build/_deps/fmt-src/include/**",
14-
"${workspaceFolder}/build/_deps/cli11_proj-src/include/**",
15-
"${workspaceFolder}/build/_deps/gsl-src/include/**",
16-
"${workspaceFolder}/build/_deps/cimg-src/**",
17-
"${workspaceFolder}/build/_deps/googletest-src/googletest/include/**",
18-
"${workspaceFolder}/build/_deps/pngpp-src/include/**",
19-
"${workspaceFolder}/build/_deps/json-src/include/**",
20-
"/opt/homebrew/opt/libpng/include/**"
21-
],
22-
"defines": [
23-
"cimg_display=0"
24-
],
25-
"macFrameworkPath": [
26-
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"
27-
],
28-
"cppStandard": "c++23",
29-
"intelliSenseMode": "macos-clang-arm64",
30-
"configurationProvider": "ms-vscode.makefile-tools"
31-
}
32-
],
33-
"version": 4
2+
"configurations": [
3+
{
4+
"name": "Mac",
5+
"includePath": [
6+
"${workspaceFolder}/Porytiles1/include/**",
7+
"${workspaceFolder}/Porytiles1/lib/**",
8+
"${workspaceFolder}/Porytiles1/tools/**",
9+
"${workspaceFolder}/Porytiles1/vendor/**",
10+
"${workspaceFolder}/Porytiles2/include/**",
11+
"${workspaceFolder}/Porytiles2/lib/**",
12+
"${workspaceFolder}/Porytiles2/tools/**",
13+
"${workspaceFolder}/vscode-build/_deps/fmt-src/include/**",
14+
"${workspaceFolder}/vscode-build/_deps/cli11_proj-src/include/**",
15+
"${workspaceFolder}/vscode-build/_deps/gsl-src/include/**",
16+
"${workspaceFolder}/vscode-build/_deps/cimg-src/**",
17+
"${workspaceFolder}/vscode-build/_deps/googletest-src/googletest/include/**",
18+
"${workspaceFolder}/vscode-build/_deps/pngpp-src/include/**",
19+
"${workspaceFolder}/vscode-build/_deps/json-src/include/**",
20+
"${workspaceFolder}/vscode-build/_deps/yaml-cpp-src/include/**",
21+
"${workspaceFolder}/vscode-build/_deps/fruit-src/include/**",
22+
"${workspaceFolder}/vscode-build/_deps/fruit-build/include/**",
23+
"/opt/homebrew/opt/libpng/include/**"
24+
],
25+
"defines": [
26+
"cimg_display=0"
27+
],
28+
"macFrameworkPath": [
29+
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"
30+
],
31+
"cppStandard": "c++23",
32+
"intelliSenseMode": "macos-clang-arm64",
33+
"configurationProvider": "ms-vscode.makefile-tools"
34+
}
35+
],
36+
"version": 4
3437
}

.vscode/launch.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
"name": "LLDB - Porytiles2 Driver Debug Command",
66
"type": "lldb",
77
"request": "launch",
8-
"program": "${workspaceFolder}/build/Porytiles2/tools/driver/porytiles2",
9-
"args": ["debug", "porytiles2_test"],
8+
"program": "${workspaceFolder}/vscode-build/Porytiles2/tools/driver/porytiles2",
9+
"args": ["debug-compile-primary", "porytiles2_test_simple"],
1010
"cwd": "${workspaceFolder}/../pokeemerald-expansion"
1111
},
1212
{
1313
"name": "LLDB - Porytiles2AllTests",
1414
"type": "lldb",
1515
"request": "launch",
16-
"program": "${workspaceFolder}/build/Porytiles2/tests/Porytiles2AllTests",
16+
"program": "${workspaceFolder}/vscode-build/Porytiles2/tests/Porytiles2AllTests",
1717
"args": [],
1818
"cwd": "${workspaceFolder}"
1919
}

CLAUDE.md

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,26 @@ Uses CMake with C++23 standard. The build system requires:
2121
### Build Commands
2222
```bash
2323
# Configure debug build
24-
cmake -B build -DCMAKE_BUILD_TYPE=Debug
24+
cmake -B vscode-build -DCMAKE_BUILD_TYPE=Debug
2525

2626
# Configure debug build with coverage
27-
cmake -B build-coverage -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-fcoverage-mapping -fprofile-instr-generate"
28-
29-
# Configure release build
30-
cmake -B build-release -DCMAKE_BUILD_TYPE=Release
27+
cmake -B vscode-build-coverage -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-fcoverage-mapping -fprofile-instr-generate"
3128

3229
# Build project
33-
cmake --build build -j7
30+
cmake --build vscode-build -j7
31+
# Note: build folder may also be called `clion-build-debug`
3432
```
35-
Alternatively, if there is a build directory called `clion-build-debug`, use that instead of `build`.
3633

3734
## Testing
38-
- Doctests for legacy version at `./build/Porytiles1/tests/Porytiles1Tests`
39-
- GoogleTest unit tests at `./build/Porytiles2/tests/Porytiles2UnitTests`
40-
- GoogleTest integration tests at `./build/Porytiles2/tests/Porytiles2IntegrationTests`
41-
- GoogleTest all test runner at `./build/Porytiles2/tests/Porytiles2AllTests
35+
- GoogleTest all test runner at `./build/Porytiles2/tests/Porytiles2AllTests`
4236

4337
Prefer to simply run all tests using the all test runner.
4438

4539
Run all tests:
4640
```bash
41+
# WHEN RUNNING TESTS, ALWAYS SEND OUTPUT TO A TEMPORARY FILE SO YOU DON'T POLLUTE YOUR CONTEXT.
42+
# You can then check if the build succeeded by looking at the exit code.
43+
# If non-zero, inspect the file and see what went wrong.
4744
./build/Porytiles2/tests/Porytiles2AllTests # this runs both Porytiles2UnitTests and Porytiles2IntegrationTests
4845
```
4946

@@ -58,13 +55,49 @@ Located in `Scripts/` directory:
5855
```
5956
Uses `clang-format` with project-specific style configuration.
6057

58+
## Python Environment and Config Generation
59+
60+
### Python Virtual Environment Setup
61+
The project uses a Python virtual environment (`.venv`) for running code generation scripts.
62+
63+
**CRITICAL: ALWAYS use `.venv` when running Python scripts!**
64+
65+
If `.venv` does not exist, create it:
66+
```bash
67+
# Create virtual environment
68+
python3 -m venv .venv
69+
70+
# Activate and install dependencies
71+
source .venv/bin/activate
72+
pip install Jinja2 PyYAML
73+
```
74+
75+
### Config Generation Script
76+
The configuration system is auto-generated from `Porytiles2/config_templates/config_schema.yaml` using Jinja2 templates.
77+
78+
**To regenerate config files:**
79+
```bash
80+
# ALWAYS use the virtual environment!
81+
source .venv/bin/activate && python Scripts/generate_config.py
82+
```
83+
84+
The script generates C++ configuration files including:
85+
- Layer config interfaces (DomainConfig, AppConfig, InfraConfig)
86+
- LazyLayeredConfig implementation
87+
- ConfigProvider base class
88+
- DefaultProvider and YamlFileProvider implementations
89+
90+
**When to regenerate:**
91+
- After modifying `config_schema.yaml`
92+
- After updating any `.jinja2` template in `Porytiles2/config_templates/`
93+
6194
## Project Structure
6295
- `Porytiles1/` - Legacy version codebase, ignore this code unless otherwise instructed
6396
- `Porytiles2/` - Next-generation version with domain-driven design
6497
- `Resources/` - Test assets and example files
6598
- `Documentation/` - Doxygen configuration
6699
- `Scripts/` - Build and quality scripts
67-
- `build/` - CMake build artifacts
100+
- `vscode-build/` - CMake build artifacts
68101

69102
## Driver Programs
70103
- `./build/Porytiles1/tools/driver/porytiles` - Legacy CLI tool
@@ -73,30 +106,32 @@ Uses `clang-format` with project-specific style configuration.
73106
## Key Design Patterns
74107
Porytiles2 implements:
75108
- Domain-driven design with clear separation of concerns
76-
- Library-based architecture inspired by clang
77-
- Template-based utilities in `Porytiles2/templates/`
109+
- Utilities in `Porytiles2/utilities/` and `Porytiles2/xcut/`
110+
- Fruit DI code in `Porytiles2/di/`
78111

79112
## 7 Claude rules
80113
1. First think through the problem, read the codebase for relevant files, and write a plan to `Porytiles2/claudetasks/TODO.md`.
81114
2. The plan should have a list of todo items that you can check off as you complete them.
82115
3. Before you begin working, check in with me and I will verify the plan.
83116
4. Then, begin working on the todo items, marking them as complete as you go.
84117
5. Every step of the way, give me a high-level explanation of what changes you made.
85-
6. Make every task and code change you do as simple as possible. We want to avoid making any massive or complex changes. Every change should impact as little code as possible. Everything is about simplicity. Run the format script, unit, and integration tests after you make a code change.
118+
6. Make every task and code change you do as simple as possible. We want to avoid making any massive or complex changes. Every change should impact as little code as possible. Everything is about simplicity. Run the format script and full test suite after you make a code change.
86119
7. Finally, add a review section to the `Porytiles2/claudetasks/TODO.md` file with a summary of the changes you made and any other relevant information.
87120

88121
## Development Workflow Tools
89122
1. Format code: `./Scripts/format.sh`
90123
2. Build: `cmake --build build -j7`
91124
3. Unit Tests: `./build/Porytiles2/tests/Porytiles2UnitTests`
92125
4. Integration Tests: `./build/Porytiles2/tests/Porytiles2IntegrationTests`
126+
5. Generate config files: `source .venv/bin/activate && python Scripts/generate_config.py`
93127

94128
## C++ Code Style
95129
Use the following example snippet as a guide for code style.
96130
@./STYLE.md
97131

98132
## **CRITICAL RULES - DO NOT VIOLATE**
99133
- **ALWAYS use the code style outlined in the C++ Code Style section above**
134+
- **ALWAYS use `.venv` when running Python scripts** - Never use system Python for Scripts/generate_config.py or other Python scripts
100135
- **Ignore contents of `Porytiles1/` directory** unless I explicitly tell you to work with those files
101136
- **NEVER create mock data or simplified components** unless explicitly told to do so
102137
- **NEVER replace existing complex components with simplified versions** - always fix the actual problem

Porytiles2/CMakeLists.txt

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,80 @@ set(PORYTILES2_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/Porytiles2/include)
44

55
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -fstandalone-debug -fno-limit-debug-info -fno-omit-frame-pointer")
66

7+
# ============================================================================
8+
# Configuration Code Generation
9+
# ============================================================================
10+
11+
# Find Python interpreter - prefer venv if it exists
12+
if (EXISTS "${CMAKE_SOURCE_DIR}/.venv/bin/python3.13")
13+
set(Python3_EXECUTABLE "${CMAKE_SOURCE_DIR}/.venv/bin/python3.13")
14+
elseif (EXISTS "${CMAKE_SOURCE_DIR}/.venv/bin/python3")
15+
set(Python3_EXECUTABLE "${CMAKE_SOURCE_DIR}/.venv/bin/python3")
16+
elseif (EXISTS "${CMAKE_SOURCE_DIR}/.venv/bin/python")
17+
set(Python3_EXECUTABLE "${CMAKE_SOURCE_DIR}/.venv/bin/python")
18+
endif ()
19+
20+
find_package(Python3 COMPONENTS Interpreter REQUIRED)
21+
22+
# Define generated output files
23+
set(GENERATED_CONFIG_FILES
24+
# Layer interfaces
25+
${CMAKE_SOURCE_DIR}/Porytiles2/include/porytiles2/domain/config/domain_config.hpp
26+
${CMAKE_SOURCE_DIR}/Porytiles2/include/porytiles2/app/config/app_config.hpp
27+
${CMAKE_SOURCE_DIR}/Porytiles2/include/porytiles2/infra/config/infra_config.hpp
28+
# LazyLayeredConfig implementation
29+
${CMAKE_SOURCE_DIR}/Porytiles2/include/porytiles2/infra/config/lazy_layered_config.hpp
30+
${CMAKE_SOURCE_DIR}/Porytiles2/lib/infra/config/lazy_layered_config.cpp
31+
# ConfigProvider
32+
${CMAKE_SOURCE_DIR}/Porytiles2/include/porytiles2/infra/config/config_provider.hpp
33+
${CMAKE_SOURCE_DIR}/Porytiles2/lib/infra/config/config_provider.cpp
34+
# DefaultProvider
35+
${CMAKE_SOURCE_DIR}/Porytiles2/include/porytiles2/infra/config/default_provider.hpp
36+
${CMAKE_SOURCE_DIR}/Porytiles2/lib/infra/config/default_provider.cpp
37+
# YamlFileProvider
38+
${CMAKE_SOURCE_DIR}/Porytiles2/include/porytiles2/infra/config/yaml_file_provider.hpp
39+
${CMAKE_SOURCE_DIR}/Porytiles2/lib/infra/config/yaml_file_provider.cpp
40+
)
41+
42+
# Define schema and template files
43+
set(CONFIG_SCHEMA
44+
${CMAKE_SOURCE_DIR}/Porytiles2/config_templates/config_schema.yaml
45+
)
46+
47+
set(CONFIG_TEMPLATES
48+
${CMAKE_SOURCE_DIR}/Porytiles2/config_templates/domain_config.hpp.jinja2
49+
${CMAKE_SOURCE_DIR}/Porytiles2/config_templates/app_config.hpp.jinja2
50+
${CMAKE_SOURCE_DIR}/Porytiles2/config_templates/infra_config.hpp.jinja2
51+
${CMAKE_SOURCE_DIR}/Porytiles2/config_templates/lazy_layered_config.hpp.jinja2
52+
${CMAKE_SOURCE_DIR}/Porytiles2/config_templates/lazy_layered_config.cpp.jinja2
53+
${CMAKE_SOURCE_DIR}/Porytiles2/config_templates/config_provider.hpp.jinja2
54+
${CMAKE_SOURCE_DIR}/Porytiles2/config_templates/config_provider.cpp.jinja2
55+
${CMAKE_SOURCE_DIR}/Porytiles2/config_templates/default_provider.hpp.jinja2
56+
${CMAKE_SOURCE_DIR}/Porytiles2/config_templates/default_provider.cpp.jinja2
57+
${CMAKE_SOURCE_DIR}/Porytiles2/config_templates/yaml_file_provider.hpp.jinja2
58+
${CMAKE_SOURCE_DIR}/Porytiles2/config_templates/yaml_file_provider.cpp.jinja2
59+
)
60+
61+
# Generate config files before building
62+
add_custom_command(
63+
OUTPUT ${GENERATED_CONFIG_FILES}
64+
COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/Scripts/generate_config.py
65+
DEPENDS
66+
${CONFIG_SCHEMA}
67+
${CMAKE_SOURCE_DIR}/Scripts/generate_config.py
68+
${CONFIG_TEMPLATES}
69+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
70+
COMMENT "Generating configuration code from templates..."
71+
VERBATIM
72+
)
73+
74+
# Create target that depends on generated files
75+
add_custom_target(generate_config_code
76+
DEPENDS ${GENERATED_CONFIG_FILES}
77+
)
78+
79+
# ============================================================================
80+
781
add_subdirectory(lib)
882
add_subdirectory(tests)
983
add_subdirectory(tools)

Porytiles2/Notes/animations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Summary
44
Detailed overview of animation handling.
5-
Since decompilation-recompilation and incremental compilation
5+
Since decompilation-recompilation and patch compilation
66
are such a big piece of the Porytiles2 flow,
77
animation handling needs to be transparently symmetrical.
88

0 commit comments

Comments
 (0)