Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7486d7539 | ||
|
|
eb1776e614 | ||
|
|
191377fae2 |
No files matched your search
@@ -25,8 +25,8 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
||||
- Newly added: LATE shift phase (start 700s) with a reachability test; PROTESTER archetype + events + colors; CALL_SOMEONE reaction; `DoorState` core class + `L` binding + visual indicator; flashlight (`G`, SpotLight3D, perception bonus at evening/late); persistence wired (`Save.save_shift_result` on shift end, history + best score on the review screen); `NavigationRegion3D` flat navmesh + `NavigationAgent3D` NPC paths (steps now visual-only); strings moved to `res://content/strings.en.json` (41 keys, loader keeps `lookup`/`fmt`); `export_presets.cfg` (Linux/Windows/macOS) + `tools/build_releases.sh` + `docs/RELEASING.md`; README Downloads section.
|
||||
- Run tests: `godot --headless --path . --script res://src/test/test_runner.gd`
|
||||
- Boot check: `godot --headless --path . --quit-after 120`
|
||||
- Screenshot tool: `godot --path . --script res://src/test/take_screenshot.gd` (writes to `user://screenshot.png`).
|
||||
- Release build: `./tools/build_releases.sh` requires export templates (see `docs/RELEASING.md`).
|
||||
- Screenshot tools: `godot --path . -s res://src/test/take_screenshot.gd` (single shot to `user://screenshot.png`); `godot --path . -s res://src/test/capture_screenshots.gd` (staged README gallery shots to `user://screenshots/`, copied to `docs/screenshots/`).
|
||||
- Release build verified locally: export templates for 4.3 installed at `~/.local/share/godot/export_templates/4.3.stable/`; `./tools/build_releases.sh` produced Linux/Windows/macOS artifacts for 0.1.0 in `build/` and the Linux binary passed a headless smoke test. Publishing to Gitea still needs a token (see `tools/publish_release.sh`, `docs/RELEASING.md`).
|
||||
|
||||
## Known Issues / Notes
|
||||
|
||||
@@ -34,7 +34,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
||||
- Headless (dummy renderer) logs "Parameter m is null" from `mesh_get_surface_count`; it does not occur with a real GL driver and does not affect logic.
|
||||
- Steps are visual-only (no collider) so NPCs can path to the entrance; the guard spawns on the landing so it never needs to climb.
|
||||
- Persistence tests write into the real `user://shift_results.json` (harmless local pollution of the demo history).
|
||||
- Export presets and release scripts are **not yet verified with real export templates** (none installed on this machine); see `docs/RELEASING.md` before first release.
|
||||
- macOS export required `rendering/textures/vram_compression/import_etc2_astc=true` in `project.godot` (universal build demands ETC2 ASTC enabled).
|
||||
- Joke Shop `door_staff_lines` authored but not yet surfaced in the prototype UI (tracked in TODO).
|
||||
|
||||
## Open Questions
|
||||
|
||||
@@ -6,6 +6,15 @@ The central design goal is simple:
|
||||
|
||||
> The player wins by choosing the lowest level of escalation that keeps everyone safe.
|
||||
|
||||
## Screenshots
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|  |  |
|
||||
|
||||
*Screenshots are generated by [`src/test/capture_screenshots.gd`](src/test/capture_screenshots.gd) from the current build.*
|
||||
|
||||
## ⬇️ Downloads
|
||||
|
||||
| Platform | Package |
|
||||
@@ -168,7 +177,7 @@ The unit test runner is the project's own lightweight harness (no editor plugin
|
||||
|
||||
## Architecture
|
||||
|
||||
The full arc42-style architecture documentation lives in [`docs/architecture.md`](docs/architecture.md). It covers goals, constraints, context, solution strategy, building blocks, runtime views, deployment, cross-cutting concepts, quality requirements, risks, and a glossary.
|
||||
The full arc42-style architecture documentation lives in [`docs/architecture.md`](docs/architecture.md). It covers goals, constraints, context, solution strategy, building blocks, runtime views, deployment, cross-cutting concepts, quality requirements, risks, a glossary, the CI/CD build pipeline, semantic versioning, and release management.
|
||||
|
||||
## Project Documentation
|
||||
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
# TODO
|
||||
|
||||
## 🔴 PRIORITY — Ship downloadable builds (so the README Downloads links work)
|
||||
|
||||
Goal: users hitting the README **Downloads** section can actually download a playable version from
|
||||
`https://git.allucanget.biz/zwitschi/security-game/releases`.
|
||||
|
||||
- [x] Install Godot 4.3 export templates locally (see `docs/RELEASING.md` step 1).
|
||||
- [x] Run `./tools/build_releases.sh` and confirm the three artifacts appear in `build/`.
|
||||
- [x] Smoke-test the Linux binary launches (`./build/step-line-linux-0.1.0.x86_64 --headless --quit-after 120` → 0 script errors).
|
||||
- [ ] Create a Gitea release `v0.1.0` (tag matching `config/version` in `project.godot`) — **needs `GITEA_TOKEN`**: `GITEA_TOKEN=... ./tools/publish_release.sh 0.1.0`.
|
||||
- [ ] Verify the README Downloads links resolve: visit the release page and download one artifact.
|
||||
- [x] (Local workflow) `tools/publish_release.sh` exists so future releases need only a `GITEA_TOKEN`.
|
||||
|
||||
### Follow-ups once the first release is live
|
||||
|
||||
- [ ] CI packaging: build and upload artifacts automatically on tags.
|
||||
|
||||
## Future Systems (design-level backlog)
|
||||
|
||||
- [ ] Body-camera replay timeline in the shift review.
|
||||
- [ ] Long (10-15 minute) shift lengths and phase-based lighting (darkened evening / late phases).
|
||||
- [ ] Venue selection screen (wire `switch_scenario` to a startup menu).
|
||||
- [ ] CI packaging: upload `build/` artifacts to releases automatically on tags.
|
||||
- [ ] IDE/editor-based GUT integration when a Godot editor workflow is introduced.
|
||||
- [ ] Reduce RefCounted reference cycles (NPCController <-> FSM) noted in `MEMORY.md`.
|
||||
|
||||
|
||||
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -54,6 +54,18 @@ Artifacts are written to `build/`:
|
||||
|
||||
The repository lives at `https://git.allucanget.biz/zwitschi/security-game`.
|
||||
|
||||
Preferred path — use the helper script with a token:
|
||||
|
||||
```bash
|
||||
GITEA_TOKEN=your_api_token ./tools/publish_release.sh 0.1.0
|
||||
```
|
||||
|
||||
The script creates the release from `project.godot`'s `config/version`, uploads
|
||||
all three `build/` artifacts, and prints the release URL. The token needs only
|
||||
`write:repository` scope on the Gitea host.
|
||||
|
||||
Manual alternative:
|
||||
|
||||
### Via the web UI
|
||||
|
||||
1. Create a **New Release** with tag `v<version>`.
|
||||
|
||||
@@ -28,6 +28,15 @@ This document follows the structure of the arc42 architecture documentation temp
|
||||
- Venue-specific policies must be configurable rather than hard-coded into individual NPCs.
|
||||
- The game must preserve the de-escalation-first design described in [`PLAN.md`](../PLAN.md).
|
||||
- The project uses the repository workflow described in [`AGENTS.md`](../AGENTS.md).
|
||||
- The project follows [Semantic Versioning](https://semver.org/) (`MAJOR.MINOR.PATCH`).
|
||||
|
||||
### Version management
|
||||
|
||||
- **MAJOR** — incompatible changes to the game's core systems, save format, or public-facing behavior.
|
||||
- **MINOR** — new venues, NPC archetypes, systems, or features that are backward compatible.
|
||||
- **PATCH** — bug fixes and small polish that do not change behavior.
|
||||
|
||||
The single source of truth for the version is `config/version` in `project.godot` (currently `0.1.0`). Each release is tagged in git as `v<version>` (e.g. `v0.1.0`). The `0.x` series is pre-1.0, so MINOR bumps may introduce breaking changes while the prototype is still stabilizing. `tools/build_releases.sh` and `tools/publish_release.sh` read the version from `project.godot`, so bumping it there is the only required step before a release. The full bump checklist lives in [`RELEASING.md`](RELEASING.md).
|
||||
|
||||
## 3. Context and Scope
|
||||
|
||||
@@ -103,6 +112,25 @@ The initial target is a single-player local game. The expected runtime consists
|
||||
|
||||
Future options include external analytics, cloud saves, or replay sharing, but they are not part of the initial architecture.
|
||||
|
||||
### CI/CD build pipeline
|
||||
|
||||
A continuous-integration pipeline keeps the headless test suite green on every change, with a planned extension to build and publish release artifacts automatically.
|
||||
|
||||
- **CI workflow** (`.github/workflows/ci.yml`) runs on every push to `main` and on every pull request. It installs the pinned Godot 4.3 editor, caches the `.godot` import artifacts, imports the project to build the class cache, and runs the headless test suite (`res://src/test/test_runner.gd`). The job fails on a non-zero exit code or any `SCRIPT ERROR` in the output.
|
||||
- **Planned extension** grows the pipeline from "test only" to "test, build, and publish": a test stage (headless tests plus a `--quit-after 120` boot smoke test as the merge gate), a build stage (install export templates, run `tools/build_releases.sh`), and a publish stage (on a version tag, upload artifacts via `tools/publish_release.sh` with a `GITEA_TOKEN` secret).
|
||||
- **Hosting note:** the repository lives on Gitea/Forgejo (`https://git.allucanget.biz/zwitschi/security-game`); the workflow is authored for GitHub Actions and should be mirrored or ported to the host's own runner if Actions is unavailable there. Export templates must match the pinned engine version, and macOS builds are unsigned (production releases need notarization or clear quarantine guidance).
|
||||
|
||||
### Release management
|
||||
|
||||
Releases are produced from a tagged commit and published to the repository host's release page, where the README "Downloads" links point.
|
||||
|
||||
- `export_presets.cfg` — committed Linux, Windows Desktop, and macOS export presets so builds are reproducible.
|
||||
- `tools/build_releases.sh` — exports all three desktop artifacts into `build/`, named `step-line-<platform>-<version>.<ext>`.
|
||||
- `tools/publish_release.sh` — creates a release and uploads the artifacts via the Gitea/Forgejo API (requires `GITEA_TOKEN`).
|
||||
- [`RELEASING.md`](RELEASING.md) — step-by-step guide and release checklist.
|
||||
|
||||
The release process is: bump the version, run the full test suite and boot smoke test, run `tools/build_releases.sh`, run `tools/publish_release.sh` (or create the release via the web UI), and verify the README "Downloads" links resolve to the new release.
|
||||
|
||||
## 8. Cross-Cutting Concepts
|
||||
|
||||
- **Event-based incident recording:** Important actions emit records consumed by evidence, reputation, and review systems.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 75 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
+1
-1
@@ -92,7 +92,7 @@ custom_template/release=""
|
||||
debug/export_console_wrapper=0
|
||||
binary_format/embed_pck=false
|
||||
texture_format/s3tc_bptc=true
|
||||
texture_format/etc2_astc=false
|
||||
texture_format/etc2_astc=true
|
||||
codesign/enable=false
|
||||
codesign/timestamp=true
|
||||
codesign/identity_type=0
|
||||
|
||||
@@ -105,3 +105,4 @@ print_debug={
|
||||
|
||||
renderer/rendering_method="gl_compatibility"
|
||||
renderer/rendering_method.mobile="gl_compatibility"
|
||||
textures/vram_compression/import_etc2_astc=true
|
||||
@@ -0,0 +1,85 @@
|
||||
extends SceneTree
|
||||
## Dev helper: run the game windowed and capture staged screenshots for the
|
||||
## README. Saves 1600x900 PNGs to user://screenshots/.
|
||||
## Usage: godot --path . --script res://src/test/capture_screenshots.gd
|
||||
|
||||
const OUT_DIR := "user://screenshots"
|
||||
const MAX_FRAMES := 2400 # hard cap (~40s)
|
||||
|
||||
var frames := 0
|
||||
var gm: Node = null
|
||||
var state := 0
|
||||
var state_frames := 0
|
||||
var targeted := false
|
||||
|
||||
func _initialize() -> void:
|
||||
root.size = Vector2i(1600, 900)
|
||||
var packed: PackedScene = load("res://scenes/main.tscn")
|
||||
var inst: Node = packed.instantiate()
|
||||
root.add_child(inst)
|
||||
|
||||
func _process(_delta: float) -> bool:
|
||||
frames += 1
|
||||
# The main scene's _ready may not have run when _initialize added it;
|
||||
# look for GameManager lazily each frame until it exists.
|
||||
if gm == null:
|
||||
gm = root.find_child("GameManager", true, false)
|
||||
if gm == null and frames > 120:
|
||||
push_error("GameManager not found")
|
||||
quit(1)
|
||||
return true
|
||||
if frames > MAX_FRAMES:
|
||||
print("timeout reached")
|
||||
quit(0)
|
||||
return true
|
||||
_advance()
|
||||
return false
|
||||
|
||||
func _advance() -> void:
|
||||
state_frames += 1
|
||||
match state:
|
||||
0:
|
||||
# 2s overview from the guard post.
|
||||
if state_frames >= 120:
|
||||
_shoot("01-venue-overview.png")
|
||||
state = 1
|
||||
state_frames = 0
|
||||
1:
|
||||
# Wait for a nearby NPC so the interaction HUD has a target.
|
||||
if gm != null and gm.npcs.size() > 0:
|
||||
gm.call("_cycle_nearby_target")
|
||||
targeted = true
|
||||
state = 2
|
||||
state_frames = 0
|
||||
2:
|
||||
# Give the HUD a moment, then shoot the interaction shot.
|
||||
if state_frames >= 30:
|
||||
_shoot("02-targeting-npc.png")
|
||||
if targeted and gm != null:
|
||||
gm.call("_toggle_inspection")
|
||||
state = 3
|
||||
state_frames = 0
|
||||
3:
|
||||
if state_frames >= 30:
|
||||
_shoot("03-access-inspection.png")
|
||||
if gm != null:
|
||||
gm.hud.hide_inspection()
|
||||
# Re-target (target may have moved) before opening the radio form.
|
||||
if gm.npcs.size() > 0:
|
||||
gm.call("_cycle_nearby_target")
|
||||
gm.call("_open_radio", false)
|
||||
state = 4
|
||||
state_frames = 0
|
||||
4:
|
||||
if state_frames >= 30:
|
||||
_shoot("04-radio-report.png")
|
||||
state = 5
|
||||
quit(0)
|
||||
|
||||
func _shoot(file_name: String) -> void:
|
||||
var dir := DirAccess.open("user://")
|
||||
if dir == null or not dir.dir_exists("screenshots"):
|
||||
dir.make_dir_recursive("screenshots")
|
||||
var img: Image = root.get_texture().get_image()
|
||||
var err := img.save_png(OUT_DIR.path_join(file_name))
|
||||
print("%s -> err=%d (%dx%d)" % [file_name, err, img.get_width(), img.get_height()])
|
||||
Regular → Executable
File mode changed.
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
# Publish a release to the Gitea/Forgejo host, uploading the built artifacts.
|
||||
#
|
||||
# Requires:
|
||||
# - GITEA_TOKEN (a token with write access to the repo)
|
||||
# - build artifacts from tools/build_releases.sh (or already exported)
|
||||
#
|
||||
# Usage:
|
||||
# GITEA_TOKEN=xxx ./tools/publish_release.sh [version]
|
||||
# (version defaults to config/version from project.godot)
|
||||
set -euo pipefail
|
||||
|
||||
REPO="${REPO:-zwitschi/security-game}"
|
||||
HOST="${HOST:-https://git.allucanget.biz}"
|
||||
API="$HOST/api/v1/repos/$REPO/releases"
|
||||
VERSION="${1:-$(grep -oP 'config/version="\K[^"]+' project.godot)}"
|
||||
TAG="v$VERSION"
|
||||
|
||||
if [[ -z "${GITEA_TOKEN:-}" ]]; then
|
||||
echo "error: GITEA_TOKEN is not set (see docs/RELEASING.md)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Artifacts must already exist (run tools/build_releases.sh first).
|
||||
printf -v BS 'build/step-line-linux-%s.x86_64' "$VERSION"
|
||||
printf -v BS_WIN 'build/step-line-windows-%s.exe' "$VERSION"
|
||||
printf -v BS_MAC 'build/step-line-macos-%s.zip' "$VERSION"
|
||||
for f in "$BS" "$BS_WIN" "$BS_MAC"; do
|
||||
if [[ ! -f "$f" ]]; then
|
||||
echo "error: missing artifact $f — run ./tools/build_releases.sh first" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "==> Creating release $TAG on $HOST/$REPO"
|
||||
RELEASE_JSON="$(curl -s -X POST "$API" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"$TAG\",\"name\":\"$TAG\",\"body\":\"Step Line $VERSION — playable prototype. See README for controls.\",\"draft\":false,\"prerelease\":false}")"
|
||||
|
||||
RELEASE_ID="$(echo "$RELEASE_JSON" | python3 -c "import sys,json;print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)"
|
||||
if [[ -z "$RELEASE_ID" ]]; then
|
||||
echo "error: could not create release; response:" >&2
|
||||
echo "$RELEASE_JSON" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Release id: $RELEASE_ID"
|
||||
|
||||
for f in "$BS" "$BS_WIN" "$BS_MAC"; do
|
||||
echo "==> Uploading $(basename "$f")"
|
||||
curl -s -X POST "$API/$RELEASE_ID/assets" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@$f" >/dev/null
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Release live: $HOST/$REPO/releases/tag/$TAG"
|
||||
Reference in new issue
Block a user