Skip to content

Commit 57b84c4

Browse files
authored
Merge branch 'csprance:main' into main
2 parents f1cec69 + f0118d3 commit 57b84c4

File tree

944 files changed

+66282
-5105
lines changed

Some content is hidden

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

944 files changed

+66282
-5105
lines changed

.claude/settings.local.json

Lines changed: 0 additions & 30 deletions
This file was deleted.

.github/copilot-instructions.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
### GECS AI Coding Guide
2+
3+
Concise, codebase-specific instructions for AI agents. Focus only on proven patterns in this repo.
4+
5+
#### Core Runtime (under `addons/gecs/ecs/`)
6+
7+
Entity (`entity.gd`): Node holding components (data) + relationships. Provides `add_component()`, `has_component()`, `add_relationship()`.
8+
Component (`component.gd`): Resource, data-only `@export` fields. Emits `property_changed` manually to trigger observers.
9+
System (`system.gd`): Override `query()` returning a `QueryBuilder`; implement `process(entities, components, delta)`. Use `iterate([...])` in query for batch column access (components array order matches iterate list). Optional `sub_systems()` returns `[QueryBuilder, Callable]` tuples.
10+
Observer (`observer.gd`): Reactive system: implement `watch()` (returns component instance) and handlers (`on_component_added/removed/changed`). Property changes require explicit signal emission in component setter.
11+
World (`world.gd`): Owns entities, systems, observers, archetype & relationship indices. Provides `world.query` (pooled `QueryBuilder`), archetype cache, enabled/disabled filtering baked into signatures.
12+
ECS (`ecs.gd`): Autoload singleton exposing `ECS.world` and `ECS.process(delta, group?)`.
13+
14+
#### QueryBuilder Essentials (`query_builder.gd`)
15+
16+
Chaining: `with_all([...])`, `with_any([...])`, `with_none([...])`, `with_relationship([...])`, `without_relationship([...])`, `with_group([...])`, `without_group([...])`, `.enabled()`, `.disabled()`, `.iterate([CompA, CompB])`.
17+
Component property filters supported via dictionaries: `with_all([{C_Health: {"current": {"_lt": 20}}}])`.
18+
`execute()` returns entities; `archetypes()` returns matching archetypes for high-performance column access.
19+
Cache keys (FNV-1a) reused between World `_query` and archetype retrieval; relationship changes invalidate query cache.
20+
21+
#### Archetype & Performance Model
22+
23+
Entities grouped by component signature (+ enabled bit) → O(1) query intersection using archetype match + result flattening only when needed. Enable/disable moves entity to distinct archetype; `.enabled()` / `.disabled()` skip entity-level filtering.
24+
Use `iterate()` or `archetypes()` inside systems for tight loops: access columns via `archetype.get_column(component_resource_path)`.
25+
Parallel processing: set `parallel_processing=true` and `parallel_threshold` on a System; only use pure data logic (no scene tree access) inside `process()` when parallel.
26+
27+
#### Relationships (`relationship.gd`)
28+
29+
Create: `Relationship.new(C_Likes.new(), target_entity)` or with property queries: `Relationship.new({C_Buff: {'duration': {'_gt':10}}}, {C_Player: {'level': {'_gte':5}}})`.
30+
Wildcard: pass `null` as relation or target. Removal supports count limiting: `entity.remove_relationship(Relationship.new(C_Damage.new(), null), 2)`.
31+
Reverse queries: `with_reverse_relationship([...])` maps target → sources via index.
32+
33+
#### CommandBuffer (`command_buffer.gd`)
34+
35+
Callable-based deferred execution for safe structural changes during system iteration. Each queue method appends a lambda with baked-in `is_instance_valid` guard to `Array[Callable]`. Commands execute in exact queued order.
36+
37+
System property: `cmd: CommandBuffer` (lazy-initialized). Queue methods: `add_component()`, `remove_component()`, `add_components()`, `remove_components()`, `add_entity()`, `remove_entity()`, `add_relationship()`, `remove_relationship()`, `add_custom()`. Inspection: `is_empty()`, `size()`, `get_stats()`. Manual: `execute()`, `clear()`.
38+
39+
Flush modes (`command_buffer_flush_mode` export on System):
40+
- **PER_SYSTEM** (default): auto-executes after each system completes
41+
- **PER_GROUP**: auto-executes after all systems in group complete
42+
- **MANUAL**: requires explicit `ECS.world.flush_command_buffers()`
43+
44+
Pattern: use `cmd.remove_entity(entity)` instead of `ECS.world.remove_entity(entity)` inside system `process()` for safe forward iteration. Use `cmd.add_component(entity, comp)` instead of `entity.add_component(comp)` when modifying entities during iteration.
45+
46+
#### Reactive Patterns
47+
48+
Emit `property_changed` from component setters to enable observers. Observers internally call `match()` query then fire callbacks if entity remains in result set for add/change; removal bypasses query check.
49+
50+
#### Testing & Perf Workflow
51+
52+
Test root: `addons/gecs/tests/` (core + performance). Always prefix paths with `res://`.
53+
Windows: `addons/gdUnit4/runtest.cmd -a "res://addons/gecs/tests"`. Linux/macOS: `addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests"`.
54+
Specific test method: `runtest.sh -a "res://addons/gecs/tests/core/test_entity.gd::test_add_and_get_component"` (no spaces around `::`).
55+
Performance tests log JSONL to `reports/perf/` with fields: `timestamp,test,scale,time_ms,godot_version`. Keep filenames stable for tooling (`tools/perf_viewer`).
56+
Perf viewer task (uv): see VS Code task "Perf Viewer: Generate Report & Open" or run `uv run perf-viewer --dir reports/perf --out perf_report.html`.
57+
58+
#### Conventions
59+
60+
Naming: Components `C_Foo`, Systems `FooSystem`, Observers `FooObserver`. Files often prefixed (`c_foo.gd`, `s_foo.gd`). Data-only components—push logic to Systems/Observers.
61+
System grouping via `@export var group`; process selectively: `ECS.process(delta, "physics")`.
62+
Use `q` shortcut (world-bound) inside systems & observers; avoid manual scene-tree scans beyond groups (QueryBuilder handles indexing).
63+
64+
#### Safe Extension Guidelines
65+
66+
Add new query predicates by following patterns in `query_builder.gd` (invalidate cache on structural changes; integrate with relationship signals if needed).
67+
When altering archetype logic, maintain signature stability (sorted component paths + enabled bit) to preserve cache correctness.
68+
Document user-facing API changes in `addons/gecs/README.md`; add/adjust tests (include property query + relationship edge cases; perf tests for scaling).
69+
70+
#### Common Pitfalls
71+
72+
Missing `res://` in test paths → tests not discovered.
73+
Adding behavior to Components → breaks data-only design (move to System/Observer).
74+
Forgetting to emit `property_changed` → observers won’t trigger on mutations.
75+
Not using `iterate()` for batch loops → unnecessary per-entity `get_component()` overhead.
76+
Scene tree access inside parallel system processing → undefined behavior (avoid).
77+
78+
#### Release Process
79+
80+
Tag (`git tag vX.Y.Z && git push`) to generate `release-vX.Y.Z` and `godot-asset-library-vX.Y.Z` (no tests). Don’t hand-edit release branches.
81+
82+
#### Example Optimized System
83+
84+
```gdscript
85+
class_name VelocitySystem
86+
extends System
87+
func query():
88+
return q.with_all([C_Velocity, C_Transform]).iterate([C_Velocity, C_Transform])
89+
func process(entities: Array[Entity], components: Array, delta: float) -> void:
90+
var velocities = components[0]
91+
var transforms = components[1]
92+
for i in entities.size():
93+
transforms[i].transform.global_position += velocities[i].velocity * delta
94+
```
95+
96+
#### Agent Checklist Before Commit
97+
98+
1. Query usage follows builder chain & avoids manual scans.
99+
2. Components remain data-only; property setters emit signal if observers required.
100+
3. Systems using performance paths rely on `iterate()` / `archetypes()`; parallel flag only with safe code.
101+
4. Added/changed behaviors have matching tests; performance-impacting changes log JSONL.
102+
5. No release branch modification; docs updated if public API changed.
103+
104+
Feedback welcome—request clarification for any unclear section to iterate.

.github/workflows/build.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ name: 🛠️ Build GECS Release
22
on:
33
push:
44
tags:
5-
- 'v*' # Triggers on any version tag like v1.0.0, v1.2.3, v3.9.1-beta, etc.
5+
- "v*" # Triggers on any version tag like v1.0.0, v1.2.3, v3.9.1-beta, etc.
66

77
permissions:
8-
contents: write # Required for git push operations
8+
contents: write # Required for git push operations
99

1010
jobs:
1111
make-submodule:
@@ -42,7 +42,7 @@ jobs:
4242
cp LICENSE addons/gecs/
4343
cp -r addons/gecs/* .
4444
rm -rf addons
45-
45+
4646
# Remove test directories to avoid dependency issues
4747
rm -rf tests/
4848
@@ -61,6 +61,8 @@ jobs:
6161
make-godot-asset-library:
6262
runs-on: ubuntu-latest
6363
if: startsWith(github.ref, 'refs/tags/')
64+
environment:
65+
name: godot-asset-library-approval
6466
steps:
6567
- name: Checkout repository
6668
uses: actions/checkout@v4
@@ -90,14 +92,14 @@ jobs:
9092
mkdir -p addons/gecs
9193
9294
# Copy addon contents and other necessary files from the tag commit
93-
git checkout "$COMMIT_SHA" -- README.md LICENSE addons/gecs
95+
git checkout "$COMMIT_SHA" -- README.md LICENSE addons/gecs script_templates
9496
9597
# Copy README.md to addon folder
9698
cp README.md addons/gecs/
9799
98100
# Copy LICENSE to addon folder
99101
cp LICENSE addons/gecs/
100-
102+
101103
# Remove test directories for Asset Library submission
102104
rm -rf addons/gecs/tests/
103105

.github/workflows/test.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: gecs-gdunit-test
2+
run-name: ${{ github.head_ref || github.ref_name }}-gecs-gdunit-test
3+
4+
on:
5+
push:
6+
branches:
7+
- main
8+
paths-ignore:
9+
- "**.yml"
10+
- "**.md"
11+
workflow_dispatch:
12+
13+
concurrency:
14+
group: gecs-gdunit-test${{ github.event.number }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
unit-test:
19+
name: "GECS Tests"
20+
runs-on: "ubuntu-22.04"
21+
timeout-minutes: 10 # The overall timeout
22+
permissions:
23+
actions: write
24+
checks: write
25+
contents: write
26+
pull-requests: write
27+
statuses: write
28+
29+
steps:
30+
# checkout your repository
31+
- uses: actions/checkout@v4
32+
with:
33+
lfs: true
34+
# run tests by using the gdUnit4-action with Godot version 4.2.1 and the latest GdUnit4 release
35+
- uses: godot-gdunit-labs/gdUnit4-action@v1.3.0
36+
with:
37+
godot-version: "4.5"
38+
paths: |
39+
res://addons/gecs/tests/
40+
res://addons/gecs_network/tests/
41+
timeout: 5
42+
report-name: test_report.xml
43+
arguments: "--quiet"

.gitignore

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,60 @@
33
/android/
44
repomix-output.txt
55

6-
# Ignore everything in addons except for gecs
7-
addons/*
8-
!addons/gecs/
9-
!addons/gecs/**
10-
# include qt_tools because it's a dependency of game
11-
!addons/qt_tools/
12-
!addons/qt_tools/**
13-
14-
game/
15-
qt/
16-
reports/
6+
reports/
7+
.claude/settings.local.json
8+
9+
release/
10+
!release/web/serve.py
11+
12+
# -----------------------------
13+
# Python / uv project artifacts
14+
# -----------------------------
15+
# Virtual environments
16+
.venv/
17+
venv/
18+
env/
19+
20+
# Bytecode caches
21+
__pycache__/
22+
*.py[cod]
23+
*$py.class
24+
25+
# Build & distribution outputs
26+
build/
27+
dist/
28+
*.egg-info/
29+
*.egg
30+
*.whl
31+
32+
# Packaging / installer leftovers
33+
.python-version
34+
35+
# Test, coverage & lint caches
36+
.pytest_cache/
37+
.mypy_cache/
38+
.ruff_cache/
39+
.coverage
40+
coverage.xml
41+
htmlcov/
42+
43+
# Common tooling caches
44+
.tox/
45+
.nox/
46+
.cache/
47+
48+
# Jupyter notebook checkpoints
49+
.ipynb_checkpoints/
50+
51+
# VS Code Python settings (optional local overrides)
52+
.vscode/*.pyenv
53+
54+
# Logs (keep performance JSONL under reports/perf so do NOT ignore those)
55+
*.log
56+
57+
# Local data science scratch files
58+
*.sqlite3
59+
*.db
60+
61+
# Ensure perf reports remain tracked (counteract earlier blanket reports/ ignore)
62+
!reports/perf/**

.vscode/launch.json

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
{
2-
// Use IntelliSense to learn about possible attributes.
3-
// Hover to view descriptions of existing attributes.
4-
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5-
"version": "0.2.0",
6-
"configurations": [
7-
{
8-
"name": "GDScript: Launch Project",
9-
"type": "godot",
10-
"request": "launch",
11-
"project": "${workspaceFolder}",
12-
"debug_collisions": true,
13-
"debug_paths": true,
14-
"debug_navigation": false,
15-
"additional_options": "-m --screen 2"
16-
}
17-
]
18-
}
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "GDScript: Launch Project",
9+
"type": "godot",
10+
"request": "launch",
11+
"project": "${workspaceFolder}",
12+
"debug_collisions": true,
13+
"debug_paths": true,
14+
"debug_navigation": false,
15+
"additional_options": "-m --screen 2"
16+
}
17+
]
18+
}

.vscode/mcp.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"servers": {
3+
"godot": {
4+
"command": "npx",
5+
"args": [
6+
"godot-mcp@0.1.0"
7+
],
8+
"cwd": "${input:cwd}",
9+
"env": {
10+
"GODOT_PATH": "${input:godot_path}",
11+
"DEBUG": "${input:debug}"
12+
},
13+
"type": "stdio"
14+
}
15+
},
16+
"inputs": [
17+
{
18+
"id": "cwd",
19+
"type": "promptString",
20+
"description": "What is the working directory for your Godot projects? (cwd)"
21+
},
22+
{
23+
"id": "godot_path",
24+
"type": "promptString",
25+
"description": "Do you want to specify a custom path to the Godot executable? (GODOT_PATH)"
26+
},
27+
{
28+
"id": "debug",
29+
"type": "promptString",
30+
"description": "Do you want to enable debug logging? (DEBUG)"
31+
}
32+
]
33+
}

.vscode/settings.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
{
2-
"godotTools.editorPath.godot4": "d:\\Godot\\Godot_v4.5-beta4_win64\\Godot_v4.5-beta4_win64.exe"
2+
"godotTools.editorPath.godot4": "D:\\Godot\\Godot_v4.5-stable_win64\\Godot_v4.5-stable_win64.exe",
3+
"godotTools.inlayHints.gdscript": true,
4+
"workbench.colorCustomizations": {
5+
"titleBar.activeBackground": "#475858",
6+
"titleBar.activeForeground": "#e7e7e7",
7+
"titleBar.inactiveBackground": "#3b4949",
8+
"titleBar.inactiveForeground": "#e7e7e7"
9+
}
310
}

0 commit comments

Comments
 (0)