Document project architecture and asset provenance
This commit is contained in:
parent
930acdb1a6
commit
866cc0fc06
10 changed files with 705 additions and 0 deletions
48
CONTRIBUTING.md
Normal file
48
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
NETfishing is currently developed through focused changes on the repository's
|
||||||
|
active development branch. Coordinate scope with the project owner before
|
||||||
|
starting substantial work.
|
||||||
|
|
||||||
|
## Change discipline
|
||||||
|
|
||||||
|
- Keep a change focused; avoid unrelated cleanup.
|
||||||
|
- Inspect the working tree before editing and preserve existing work.
|
||||||
|
- Do not change protocol, save, settings, identity, or portable-data versions
|
||||||
|
as release-label housekeeping.
|
||||||
|
- Treat the host as authoritative for catches, purchases, sales, jobs, mail,
|
||||||
|
and other shared state.
|
||||||
|
- Keep presentation-only systems out of save files and network messages.
|
||||||
|
- Store runtime assets under repository-owned paths; never reference a
|
||||||
|
workstation sync or temporary directory.
|
||||||
|
- Record the source and license of newly imported assets.
|
||||||
|
- Do not commit `.godot/`, test data, logs, captures, or build outputs.
|
||||||
|
|
||||||
|
## Before requesting review
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git diff --check
|
||||||
|
scripts/run_validations.sh quick
|
||||||
|
git status --short
|
||||||
|
```
|
||||||
|
|
||||||
|
Choose additional focused tests from [`docs/TESTING.md`](docs/TESTING.md).
|
||||||
|
Changes involving networking should run the network suite and a real
|
||||||
|
two-process check. Visual changes still require graphical review; headless
|
||||||
|
tests are supporting evidence, not a replacement.
|
||||||
|
|
||||||
|
## Commits
|
||||||
|
|
||||||
|
- Stage audited paths explicitly.
|
||||||
|
- Use a concise imperative subject that describes the outcome.
|
||||||
|
- Do not mix generated build artifacts with source changes.
|
||||||
|
- Do not rewrite published release tags.
|
||||||
|
- Describe behavior, compatibility impact, validation, and asset provenance in
|
||||||
|
the review or release record.
|
||||||
|
|
||||||
|
## Style
|
||||||
|
|
||||||
|
Follow the conventions already present in the surrounding GDScript, scene, and
|
||||||
|
resource files. Prefer typed values, named constants, shared resources, and
|
||||||
|
small domain-specific services. Avoid duplicating protocol definitions or
|
||||||
|
using display strings as persistent identifiers.
|
||||||
50
CREDITS.md
Normal file
50
CREDITS.md
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
# Credits
|
||||||
|
|
||||||
|
## Project direction
|
||||||
|
|
||||||
|
NETfishing is designed, directed, reviewed, and released by its project
|
||||||
|
creator. A public-facing creator or studio credit has not yet been recorded in
|
||||||
|
this repository.
|
||||||
|
|
||||||
|
## Development assistance
|
||||||
|
|
||||||
|
Development has used automated coding assistance for implementation,
|
||||||
|
investigation, testing, documentation, and review. Design choices, supplied
|
||||||
|
artwork, acceptance decisions, repository operations, and releases remain
|
||||||
|
human-controlled.
|
||||||
|
|
||||||
|
This disclosure is intentionally about process. Commit style, code style, or
|
||||||
|
repository metadata cannot reliably prove whether a particular change was
|
||||||
|
written with or without assistance.
|
||||||
|
|
||||||
|
## Fonts
|
||||||
|
|
||||||
|
- Tuffy: Thatcher Ulrich, Karoly Barta, and Michael Evans. The bundled license
|
||||||
|
dedicates the work to the public domain; see `ui/fonts/Tuffy-LICENSE.txt`.
|
||||||
|
- Seattle Avenue: bundled as `ui/fonts/seattle_avenue.otf`. Author and
|
||||||
|
redistribution terms still need to be recorded before public distribution.
|
||||||
|
|
||||||
|
## Music
|
||||||
|
|
||||||
|
- `audio/music/title/as_in_four_wolves.ogg`: original title/ambient music by
|
||||||
|
the project owner.
|
||||||
|
|
||||||
|
## Sound effects
|
||||||
|
|
||||||
|
- “Spinning reel.wav” by tosha73, used as the source for the fishing fight and
|
||||||
|
manual-reeling loops. Freesound sound 509902, Creative Commons Zero (CC0):
|
||||||
|
https://freesound.org/s/509902/
|
||||||
|
- “Gentle Ocean Waves Loop” by kkenny101, used for the saltwater shoreline
|
||||||
|
ambience. Freesound sound 852826, Creative Commons Zero (CC0):
|
||||||
|
https://freesound.org/s/852826/
|
||||||
|
- “Quick Water Droplet” by qubodup, used for the bobber water-impact sound.
|
||||||
|
Freesound sound 792931, Creative Commons Zero (CC0):
|
||||||
|
https://freesound.org/s/792931/
|
||||||
|
|
||||||
|
## Artwork
|
||||||
|
|
||||||
|
- 2D artwork: Rheannon Eisworth, contributor.
|
||||||
|
- 3D models: original work by the project owner.
|
||||||
|
|
||||||
|
Asset categories and release-record requirements are listed in
|
||||||
|
[`docs/ASSET-PROVENANCE.md`](docs/ASSET-PROVENANCE.md).
|
||||||
82
README.md
Normal file
82
README.md
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
# NETfishing
|
||||||
|
|
||||||
|
NETfishing is a multiplayer-first fishing game built with Godot 4.7. The
|
||||||
|
current pre-alpha includes host-authoritative fishing and economy flows,
|
||||||
|
freshwater and saltwater habitats, persistent player data, social features,
|
||||||
|
customization, jobs, and a controller-aware interface.
|
||||||
|
|
||||||
|
The project is under active development. Interfaces, balance, content, and
|
||||||
|
save migrations may continue to change before a stable release.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Godot 4.7.x with the GL Compatibility renderer
|
||||||
|
- Linux, Windows, or an Android development environment supported by Godot
|
||||||
|
- Bash for the repository helper scripts
|
||||||
|
|
||||||
|
Open `project.godot` in Godot, or start the editor from the repository root:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
godot --editor --path .
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the game directly with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
godot --path .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
The validation scripts isolate Godot's settings and application-data roots.
|
||||||
|
Run the fast, deterministic suite before submitting a change:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
scripts/run_validations.sh quick
|
||||||
|
```
|
||||||
|
|
||||||
|
Additional suites and individual commands are documented in
|
||||||
|
[`docs/TESTING.md`](docs/TESTING.md).
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
Export presets are maintained for Linux, Windows, and Android. Repository
|
||||||
|
scripts expect the matching Godot export templates and platform toolchains to
|
||||||
|
already be installed:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
scripts/build_playtest.sh
|
||||||
|
scripts/build_android_debug.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Build outputs belong under the ignored `builds/` directory. Release builds
|
||||||
|
must follow the project's separate tagged-release checklist; these convenience
|
||||||
|
scripts do not create or publish tags.
|
||||||
|
|
||||||
|
## Project map
|
||||||
|
|
||||||
|
- `main/`: composition root and application orchestration
|
||||||
|
- `world/`: map, environment, water, and world presentation
|
||||||
|
- `player/`, `fishing/`, `fish/`: player and fishing domain
|
||||||
|
- `network/`: transport, identity, and host-authoritative services
|
||||||
|
- `inventory/`, `items/`, `economy/`, `progression/`, `jobs/`: game state
|
||||||
|
- `save/`, `settings/`: versioned persistence
|
||||||
|
- `ui/`: gameplay and menu presentation
|
||||||
|
- `tests/`: focused Godot validation scripts
|
||||||
|
- `scripts/`: build, bake, and validation entry points
|
||||||
|
|
||||||
|
See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) and
|
||||||
|
[`world/README-WORLD-AUTHORING.md`](world/README-WORLD-AUTHORING.md) for more
|
||||||
|
detail.
|
||||||
|
|
||||||
|
## Authorship and assets
|
||||||
|
|
||||||
|
NETfishing is human-directed and uses a mixture of human-authored assets and
|
||||||
|
software-development assistance. The project records this plainly rather than
|
||||||
|
claiming that repository history can prove how each line was produced. See
|
||||||
|
[`CREDITS.md`](CREDITS.md) and
|
||||||
|
[`docs/ASSET-PROVENANCE.md`](docs/ASSET-PROVENANCE.md).
|
||||||
|
|
||||||
|
No project-wide source license has been selected yet. Do not assume permission
|
||||||
|
to redistribute the source or bundled assets beyond rights stated in their
|
||||||
|
individual license records.
|
||||||
72
docs/ARCHITECTURE.md
Normal file
72
docs/ARCHITECTURE.md
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
# Architecture
|
||||||
|
|
||||||
|
## Composition
|
||||||
|
|
||||||
|
`main/main.tscn` is the application composition root. It owns long-lived
|
||||||
|
services, the active world, player container, save/settings managers, and the
|
||||||
|
pixelated UI viewport. Services are scene-owned rather than global autoloads,
|
||||||
|
which makes their dependencies visible in the main scene and allows focused
|
||||||
|
tests to instantiate the same composition.
|
||||||
|
|
||||||
|
The main script coordinates title, session, world, and UI lifecycle. Domain
|
||||||
|
logic remains in typed resources and services rather than being stored solely
|
||||||
|
in controls.
|
||||||
|
|
||||||
|
## Domain boundaries
|
||||||
|
|
||||||
|
- `fish/` defines species, availability, catches, pools, quality, and selection.
|
||||||
|
- `fishing/` owns cast/chase state and resolves authoritative fishing surfaces.
|
||||||
|
- `inventory/`, `items/`, `economy/`, `progression/`, and `jobs/` own persistent
|
||||||
|
player-facing game state.
|
||||||
|
- `world/` owns authored map composition and presentation. Water type is a
|
||||||
|
shared typed definition used by water bodies, fish habitat, fishing
|
||||||
|
validation, Logbook classification, and saltwater shoreline presentation.
|
||||||
|
- `ui/` observes and invokes domain services. It does not define stable item or
|
||||||
|
fish identity.
|
||||||
|
|
||||||
|
Resource files (`.tres`) are authored data. Stable IDs, not display names or
|
||||||
|
node names, connect persistent and networked state to that data.
|
||||||
|
|
||||||
|
## Networking
|
||||||
|
|
||||||
|
`NetworkSession` owns ENet session lifecycle and peer registration. Dedicated
|
||||||
|
network services validate and replicate bounded domains such as fishing,
|
||||||
|
sales, shops, item use, profiles, jobs, mail, chat, drawings, time, and weather.
|
||||||
|
|
||||||
|
The host is authoritative. Clients submit requests or evidence; the host
|
||||||
|
derives trusted context from registered peers, authoritative regions, and
|
||||||
|
server-owned state before mutating inventory, wallet, progression, or shared
|
||||||
|
world state. See [`decisions/0001-host-authority.md`](decisions/0001-host-authority.md).
|
||||||
|
|
||||||
|
Protocol compatibility is defined in `network/network_protocol.gd`. A visible
|
||||||
|
release version is not a reason to change the protocol number.
|
||||||
|
|
||||||
|
## Persistence
|
||||||
|
|
||||||
|
`PlayerDataRoot` selects and validates a portable data root. Stores receive
|
||||||
|
paths from that owner rather than inventing unrelated locations. Progression is
|
||||||
|
written by `PlayerSaveManager`; device settings and social/identity stores have
|
||||||
|
separate formats and lifecycles.
|
||||||
|
|
||||||
|
Save migrations are sequential and explicit. Existing catches and ownership
|
||||||
|
are keyed by stable IDs so authored metadata can evolve without rewriting
|
||||||
|
historical records. Current source constants—not documentation—are
|
||||||
|
authoritative for format versions.
|
||||||
|
|
||||||
|
## Presentation
|
||||||
|
|
||||||
|
Gameplay is rendered in 3D with the GL Compatibility renderer. The main UI is
|
||||||
|
presented through a uniformly scaled SubViewport. Shared UI components and
|
||||||
|
palette resources prevent page-specific geometry and style drift.
|
||||||
|
|
||||||
|
World presentation systems (time/weather visuals, procedural sky and water,
|
||||||
|
shoreline ribbons, player blob shadows) do not own gameplay collision or
|
||||||
|
network authority. Generated shoreline meshes are deterministic presentation
|
||||||
|
resources baked from explicitly configured static terrain.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
Tests are executable Godot `SceneTree` scripts. Some are pure content/domain
|
||||||
|
checks, some instantiate the main scene, and multiplayer checks run paired host
|
||||||
|
and client processes on loopback. The repository runner provides isolation and
|
||||||
|
consistent entry points; see [`TESTING.md`](TESTING.md).
|
||||||
109
docs/ASSET-PROVENANCE.md
Normal file
109
docs/ASSET-PROVENANCE.md
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
# Asset provenance
|
||||||
|
|
||||||
|
This document records where runtime assets came from and what must be verified
|
||||||
|
before redistribution. A Git commit proves when bytes entered this repository;
|
||||||
|
it does not by itself prove authorship or licensing.
|
||||||
|
|
||||||
|
## Intake policy
|
||||||
|
|
||||||
|
For every new external or supplied asset, record:
|
||||||
|
|
||||||
|
- creator or supplying party;
|
||||||
|
- original source location or delivery channel;
|
||||||
|
- source filename and repository destination;
|
||||||
|
- source and destination SHA-256 when copied without modification;
|
||||||
|
- license or explicit permission;
|
||||||
|
- any permitted transformations;
|
||||||
|
- the importing commit or release.
|
||||||
|
|
||||||
|
Runtime resources must use `res://` paths. Workstation Sync folders are intake
|
||||||
|
locations only and must never appear in scenes or resources.
|
||||||
|
|
||||||
|
## Current inventory
|
||||||
|
|
||||||
|
| Asset family | Repository location | Recorded provenance |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Fish art and portraits | `fish/species/`, `art/exported/fish/` | 2D artwork by contributor Rheannon Eisworth. |
|
||||||
|
| Item icons | `items/icons/` | 2D artwork by contributor Rheannon Eisworth. |
|
||||||
|
| Inventory notepad | `art/ui/ui_notepad.png` | 2D artwork by contributor Rheannon Eisworth; integrated without a runtime external path. |
|
||||||
|
| Environment textures | `art/exported/environment/textures/` | 2D artwork by contributor Rheannon Eisworth. |
|
||||||
|
| UI patterns | `art/patterns/` | 2D artwork by contributor Rheannon Eisworth. |
|
||||||
|
| Character and world models | `art/exported/` | Original 3D models by the project owner. Any embedded 2D artwork is by Rheannon Eisworth. |
|
||||||
|
| Tuffy font | `ui/fonts/Tuffy_Bold.otf` | Public-domain dedication in `ui/fonts/Tuffy-LICENSE.txt`. |
|
||||||
|
| Seattle Avenue font | `ui/fonts/seattle_avenue.otf` | License and attribution not present; resolve before public distribution. |
|
||||||
|
| Title music | `audio/music/title/as_in_four_wolves.ogg` | Original music composed and owned by the project owner. |
|
||||||
|
| Fishing fight loop | `audio/sfx/fishing/fighting.wav` | Edited from “Spinning reel.wav” by Freesound user tosha73, sound 509902, CC0. |
|
||||||
|
| Manual-reeling loop | `audio/sfx/fishing/reeling.wav` | Edited from the same CC0 “Spinning reel.wav” source. |
|
||||||
|
| Saltwater wave ambience | `audio/ambience/waves.wav` | “Gentle Ocean Waves Loop” by Freesound user kkenny101, sound 852826, CC0. |
|
||||||
|
| Bobber water impact | `audio/sfx/fishing/bobber.wav` | “Quick Water Droplet” by Freesound user qubodup, sound 792931, CC0. |
|
||||||
|
|
||||||
|
### Fishing fight loop source record
|
||||||
|
|
||||||
|
- Source page: https://freesound.org/s/509902/
|
||||||
|
- Creator: tosha73
|
||||||
|
- Source title: `Spinning reel.wav`
|
||||||
|
- License: Creative Commons Zero (CC0)
|
||||||
|
- Downloaded source filename: `509902__tosha73__spinning-reel.wav`
|
||||||
|
- Downloaded source SHA-256:
|
||||||
|
`9741afdb1ec9c73f5e039f0e5ac174998cb0a1f737b626531e63919d4d232fad`
|
||||||
|
- Audacity working project: `fighting.aup3`
|
||||||
|
- Audacity project SHA-256:
|
||||||
|
`9928f077ecf48d01416f8d05700707e1b07d0f731846db80e27116f5b82dbbf5`
|
||||||
|
- Runtime edit source/destination SHA-256:
|
||||||
|
`b6f3f2f94bfaf9254ac04dd96b1fd28c15e1011a1db44bb3e70eeaa95de3c212`
|
||||||
|
- Runtime format: 48 kHz, 16-bit, stereo PCM WAV; 2.593479 seconds;
|
||||||
|
configured as a forward loop by the fishing presentation.
|
||||||
|
- Manual-reeling Audacity project: `reeling.aup3`
|
||||||
|
- Manual-reeling Audacity project SHA-256:
|
||||||
|
`20ad52f6bdd16ae6561f06f8355fe309e95023e815053fd5dfbd5a5ce3c1f9f9`
|
||||||
|
- Manual-reeling runtime source/destination SHA-256:
|
||||||
|
`e403d5b7c8af1da4b28599cc0f51de3eda70d9e9296db27852fe7dc95617a29d`
|
||||||
|
- Manual-reeling runtime format: 48 kHz, 16-bit, stereo PCM WAV;
|
||||||
|
2.388083 seconds; configured as a forward loop.
|
||||||
|
- The downloaded source and Audacity projects remain in the project owner's
|
||||||
|
source-work archive; only the finished runtime edits ship in the game.
|
||||||
|
|
||||||
|
### Saltwater wave ambience source record
|
||||||
|
|
||||||
|
- Source page: https://freesound.org/s/852826/
|
||||||
|
- Creator: kkenny101
|
||||||
|
- Source title: `Gentle Ocean Waves Loop`
|
||||||
|
- License: Creative Commons Zero (CC0)
|
||||||
|
- Downloaded source filename:
|
||||||
|
`852826__kkenny101__gentle-ocean-waves-loop.wav`
|
||||||
|
- Downloaded source and runtime source/destination SHA-256:
|
||||||
|
`f93e9890583f072ac52cf197b8b5942397d3d5e889fbdb9112a0776142f50229`
|
||||||
|
- Runtime format: 48 kHz, 24-bit, mono PCM WAV; 21.769917 seconds;
|
||||||
|
configured as a forward loop.
|
||||||
|
- The downloaded source remains in the project owner's source-work archive;
|
||||||
|
only the finished runtime loop ships in the game.
|
||||||
|
|
||||||
|
### Bobber water-impact source record
|
||||||
|
|
||||||
|
- Source page: https://freesound.org/s/792931/
|
||||||
|
- Creator: qubodup
|
||||||
|
- Source title: `Quick Water Droplet`
|
||||||
|
- License: Creative Commons Zero (CC0)
|
||||||
|
- Downloaded source filename: `792931__qubodup__quick-water-droplet.wav`
|
||||||
|
- Downloaded source and runtime source/destination SHA-256:
|
||||||
|
`aef0d16384efed4a7b071c4d80c21597617f882f4e0c1d5295ac194d315eafb7`
|
||||||
|
- Runtime format: 48 kHz, 16-bit, mono PCM WAV; 0.197146 seconds; one-shot.
|
||||||
|
- The downloaded source remains in the project owner's source-work archive;
|
||||||
|
only the finished runtime sound ships in the game.
|
||||||
|
|
||||||
|
## Generated resources
|
||||||
|
|
||||||
|
Godot `.import` sidecars and deterministic shoreline `.tres` meshes are derived
|
||||||
|
repository resources, not original artwork. `.godot/imported/`, editor caches,
|
||||||
|
captures, exports, and temporary test data are not tracked.
|
||||||
|
|
||||||
|
## Release gate
|
||||||
|
|
||||||
|
Before a public binary or source release:
|
||||||
|
|
||||||
|
1. Resolve the Seattle Avenue font license and attribution gap above.
|
||||||
|
2. Record the public owner/studio credit and the contributor's redistribution
|
||||||
|
permission in the chosen project license or release records.
|
||||||
|
3. Confirm the project-wide source/content license selected by the owner.
|
||||||
|
4. Search exported resources for external filesystem paths.
|
||||||
|
5. Preserve required third-party notices with the package.
|
||||||
41
docs/BALANCE.md
Normal file
41
docs/BALANCE.md
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Balance and content notes
|
||||||
|
|
||||||
|
Balance is authored data and should change deliberately. This document records
|
||||||
|
the policy; exact current values remain authoritative in `.tres` resources and
|
||||||
|
typed scripts.
|
||||||
|
|
||||||
|
## Fish
|
||||||
|
|
||||||
|
- Stable fish IDs and catalog numbers must not be changed for display cleanup.
|
||||||
|
- Species availability may constrain water type, time, weather, bait, and other
|
||||||
|
authored context.
|
||||||
|
- Location pools control selection weight; the global catalog remains
|
||||||
|
comprehensive.
|
||||||
|
- Freshwater/saltwater habitat is validated by the host in addition to pool
|
||||||
|
membership.
|
||||||
|
- Value, rarity, quality, and weight ranges should be reviewed together because
|
||||||
|
they affect economy and catch difficulty.
|
||||||
|
|
||||||
|
## Economy and progression
|
||||||
|
|
||||||
|
- Sales and purchases are host-authoritative and must mutate inventory and
|
||||||
|
wallet exactly once.
|
||||||
|
- Reserved assets are rejected atomically; mixed valid/reserved batches must
|
||||||
|
not partially succeed.
|
||||||
|
- Item effects, shop prices, cooler capacity, fishing upgrades, jobs, and
|
||||||
|
experience are separate balance axes. Avoid changing several in an unrelated
|
||||||
|
presentation pass.
|
||||||
|
|
||||||
|
## Recording a balance change
|
||||||
|
|
||||||
|
Include in the change description:
|
||||||
|
|
||||||
|
1. affected stable IDs and resource paths;
|
||||||
|
2. old and new values;
|
||||||
|
3. intended player-facing outcome;
|
||||||
|
4. interactions with quality, availability, and economy;
|
||||||
|
5. deterministic validation performed;
|
||||||
|
6. whether existing saves remain semantically valid.
|
||||||
|
|
||||||
|
Do not bump the save schema or network protocol simply because an authored
|
||||||
|
number changed. Bump a format only when its serialized contract changes.
|
||||||
63
docs/TESTING.md
Normal file
63
docs/TESTING.md
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Testing
|
||||||
|
|
||||||
|
NETfishing validations are Godot `SceneTree` scripts. They use assertions and
|
||||||
|
exit nonzero on failure. Run them with isolated user data so development checks
|
||||||
|
cannot touch real saves, identity, trust, relationships, or settings.
|
||||||
|
|
||||||
|
## Consolidated runner
|
||||||
|
|
||||||
|
```sh
|
||||||
|
scripts/run_validations.sh quick
|
||||||
|
scripts/run_validations.sh full
|
||||||
|
scripts/run_validations.sh host
|
||||||
|
scripts/run_validations.sh network
|
||||||
|
scripts/run_validations.sh all
|
||||||
|
scripts/run_validations.sh --list
|
||||||
|
```
|
||||||
|
|
||||||
|
- `quick` runs deterministic content and domain validations.
|
||||||
|
- `full` adds socket-free scene/runtime checks suitable for headless execution.
|
||||||
|
- `host` runs single-process authoritative-host checks that bind a local UDP
|
||||||
|
port.
|
||||||
|
- `network` runs the loopback host/client validations in pairs.
|
||||||
|
- `all` runs `full`, `host`, and then `network`.
|
||||||
|
|
||||||
|
Set `GODOT_BIN` to select another executable. Set `TEST_TIMEOUT_SECONDS` to
|
||||||
|
change the per-process timeout. The runner creates one temporary XDG root per
|
||||||
|
process and removes it on exit.
|
||||||
|
|
||||||
|
## One focused test
|
||||||
|
|
||||||
|
```sh
|
||||||
|
test_root="$(mktemp -d)"
|
||||||
|
XDG_DATA_HOME="$test_root/data" \
|
||||||
|
XDG_CONFIG_HOME="$test_root/config" \
|
||||||
|
godot --headless --path . --script tests/fish_catalog_content_validation.gd
|
||||||
|
rm -rf -- "$test_root"
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not set `NETFISHING_DATA_DIR` to an arbitrary empty folder: that variable is
|
||||||
|
an explicit portable-data override and must point at a valid NETfishing data
|
||||||
|
root. Isolating XDG paths is sufficient for the validation scripts.
|
||||||
|
|
||||||
|
## Graphical checks
|
||||||
|
|
||||||
|
Headless tests cannot prove visual alignment, actual mouse routing, shader
|
||||||
|
appearance, controller feel, or window-resize behavior. Presentation changes
|
||||||
|
need a real graphical startup with isolated XDG roots and inspection at the
|
||||||
|
canonical 1280×720 layout plus relevant low/high and ultrawide resolutions.
|
||||||
|
|
||||||
|
## Network checks
|
||||||
|
|
||||||
|
Host and paired tests bind loopback UDP ports defined in their scripts. Ensure
|
||||||
|
no old Godot validation process is holding those ports and that the execution
|
||||||
|
environment permits local sockets. The runner starts paired hosts before their
|
||||||
|
clients and requires both processes to exit successfully. Network tests do not
|
||||||
|
contact external servers.
|
||||||
|
|
||||||
|
## Release checks
|
||||||
|
|
||||||
|
A release audit additionally includes clean Git/tag verification, editor import,
|
||||||
|
export-template checks, platform exports, executable smoke tests, archive
|
||||||
|
inspection, and SHA-256 verification. Those checks are intentionally not hidden
|
||||||
|
inside the development runner.
|
||||||
27
docs/decisions/0001-host-authority.md
Normal file
27
docs/decisions/0001-host-authority.md
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# ADR 0001: Host-authoritative shared state
|
||||||
|
|
||||||
|
Status: accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
NETfishing supports private hosts, open hosts, and joined clients. Catches,
|
||||||
|
currency, owned items, jobs, mail, drawings, profiles, and moderation affect
|
||||||
|
state that cannot safely trust a client's local presentation.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
The host validates requests against registered peers and host-owned context,
|
||||||
|
then performs the authoritative mutation. Clients receive results and replicated
|
||||||
|
presentation state. Client evidence is bounded and reconstructed where
|
||||||
|
possible; it is not treated as authority.
|
||||||
|
|
||||||
|
Private single-player uses the same host path. Presentation-only state does not
|
||||||
|
add RPCs or persistence.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- Shared behavior is consistent across private, open-host, and joined-client
|
||||||
|
modes.
|
||||||
|
- Tests must cover local-host and paired host/client paths.
|
||||||
|
- Stable protocol payloads and rejection cleanup require explicit handling.
|
||||||
|
- UI activation cannot be used as proof that a server-side mutation succeeded.
|
||||||
27
docs/decisions/0002-authored-data-and-stable-ids.md
Normal file
27
docs/decisions/0002-authored-data-and-stable-ids.md
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# ADR 0002: Authored resources and stable identifiers
|
||||||
|
|
||||||
|
Status: accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Fish, items, pools, availability, shop stock, and other game content evolve
|
||||||
|
independently from saved catches and network messages. Display labels and scene
|
||||||
|
node names are expected to change during development.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
Repository-owned resources are the authoritative authored data. Persistent and
|
||||||
|
networked records refer to stable IDs. Display names, filenames, node names,
|
||||||
|
coordinates, and pool names are not compatibility identifiers.
|
||||||
|
|
||||||
|
Cross-domain concepts such as water type use one typed definition rather than
|
||||||
|
duplicated strings. Comprehensive catalogs remain separate from location-
|
||||||
|
specific selection pools.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- Renaming visible UI does not require save migration.
|
||||||
|
- Removing or changing a stable ID requires an explicit compatibility plan.
|
||||||
|
- Content validation checks uniqueness, catalog completeness, pool membership,
|
||||||
|
and typed habitat compatibility.
|
||||||
|
- New authored assets need provenance records as well as resource references.
|
||||||
186
scripts/run_validations.sh
Executable file
186
scripts/run_validations.sh
Executable file
|
|
@ -0,0 +1,186 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
readonly PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
||||||
|
readonly GODOT_BIN="${GODOT_BIN:-godot}"
|
||||||
|
readonly TEST_TIMEOUT_SECONDS="${TEST_TIMEOUT_SECONDS:-120}"
|
||||||
|
readonly RUN_ROOT="$(mktemp -d -t netfishing-validations.XXXXXX)"
|
||||||
|
|
||||||
|
readonly -a QUICK_TESTS=(
|
||||||
|
"tests/android_readiness_validation.gd"
|
||||||
|
"tests/fish_catalog_content_validation.gd"
|
||||||
|
"tests/fish_quality_validation.gd"
|
||||||
|
"tests/fishing_audio_validation.gd"
|
||||||
|
"tests/fishing_surface_validation.gd"
|
||||||
|
"tests/logbook_validation.gd"
|
||||||
|
"tests/player_experience_validation.gd"
|
||||||
|
"tests/shoreline_ambience_validation.gd"
|
||||||
|
"tests/surface_drawing_validation.gd"
|
||||||
|
"tests/terrain_projection_validation.gd"
|
||||||
|
"tests/world_time_validation.gd"
|
||||||
|
"tests/world_weather_validation.gd"
|
||||||
|
)
|
||||||
|
|
||||||
|
readonly -a RUNTIME_TESTS=(
|
||||||
|
"tests/inventory_notepad_art_validation.gd"
|
||||||
|
"tests/logbook_runtime_validation.gd"
|
||||||
|
"tests/player_experience_ui_validation.gd"
|
||||||
|
"tests/ui_scaling_runtime_validation.gd"
|
||||||
|
)
|
||||||
|
|
||||||
|
readonly -a HOST_TESTS=(
|
||||||
|
"tests/art_tools_validation.gd"
|
||||||
|
"tests/economy_regression_validation.gd"
|
||||||
|
"tests/fish_hotbar_showcase_validation.gd"
|
||||||
|
"tests/fishing_authority_validation.gd"
|
||||||
|
"tests/job_system_validation.gd"
|
||||||
|
"tests/surface_drawing_runtime_validation.gd"
|
||||||
|
)
|
||||||
|
|
||||||
|
readonly -a NETWORK_TESTS=(
|
||||||
|
"tests/economy_regression_validation.gd"
|
||||||
|
"tests/fish_showcase_multiplayer_validation.gd"
|
||||||
|
"tests/fishing_multiplayer_validation.gd"
|
||||||
|
"tests/job_multiplayer_validation.gd"
|
||||||
|
"tests/surface_drawing_multiplayer_validation.gd"
|
||||||
|
"tests/world_time_multiplayer_validation.gd"
|
||||||
|
)
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -rf -- "${RUN_ROOT}"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT INT TERM
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
printf 'Usage: %s {quick|full|host|network|all|--list}\n' "$0"
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_root() {
|
||||||
|
local name="$1"
|
||||||
|
local root="${RUN_ROOT}/${name}"
|
||||||
|
mkdir -p -- "${root}/data" "${root}/config" "${root}/cache"
|
||||||
|
printf '%s\n' "${root}"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_test() {
|
||||||
|
local script="$1"
|
||||||
|
local name="${script#tests/}"
|
||||||
|
name="${name%.gd}"
|
||||||
|
local root
|
||||||
|
root="$(prepare_root "${name}")"
|
||||||
|
printf '\n==> %s\n' "${script}"
|
||||||
|
XDG_DATA_HOME="${root}/data" \
|
||||||
|
XDG_CONFIG_HOME="${root}/config" \
|
||||||
|
XDG_CACHE_HOME="${root}/cache" \
|
||||||
|
timeout "${TEST_TIMEOUT_SECONDS}s" "${GODOT_BIN}" \
|
||||||
|
--headless --path "${PROJECT_ROOT}" --script "${script}"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_network_test() {
|
||||||
|
local script="$1"
|
||||||
|
local name="${script#tests/}"
|
||||||
|
name="${name%.gd}"
|
||||||
|
local host_root client_root host_pid host_status client_status
|
||||||
|
host_root="$(prepare_root "${name}-host")"
|
||||||
|
client_root="$(prepare_root "${name}-client")"
|
||||||
|
printf '\n==> %s (host + client)\n' "${script}"
|
||||||
|
XDG_DATA_HOME="${host_root}/data" \
|
||||||
|
XDG_CONFIG_HOME="${host_root}/config" \
|
||||||
|
XDG_CACHE_HOME="${host_root}/cache" \
|
||||||
|
timeout "${TEST_TIMEOUT_SECONDS}s" "${GODOT_BIN}" \
|
||||||
|
--headless --path "${PROJECT_ROOT}" --script "${script}" -- host \
|
||||||
|
>"${host_root}/output.log" 2>&1 &
|
||||||
|
host_pid=$!
|
||||||
|
sleep 0.75
|
||||||
|
set +e
|
||||||
|
XDG_DATA_HOME="${client_root}/data" \
|
||||||
|
XDG_CONFIG_HOME="${client_root}/config" \
|
||||||
|
XDG_CACHE_HOME="${client_root}/cache" \
|
||||||
|
timeout "${TEST_TIMEOUT_SECONDS}s" "${GODOT_BIN}" \
|
||||||
|
--headless --path "${PROJECT_ROOT}" --script "${script}" -- client \
|
||||||
|
>"${client_root}/output.log" 2>&1
|
||||||
|
client_status=$?
|
||||||
|
wait "${host_pid}"
|
||||||
|
host_status=$?
|
||||||
|
set -e
|
||||||
|
printf '%s\n' '-- host output --'
|
||||||
|
sed -n '1,240p' "${host_root}/output.log"
|
||||||
|
printf '%s\n' '-- client output --'
|
||||||
|
sed -n '1,240p' "${client_root}/output.log"
|
||||||
|
if ((host_status != 0 || client_status != 0)); then
|
||||||
|
printf 'error: host exited %d; client exited %d\n' \
|
||||||
|
"${host_status}" "${client_status}" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_quick() {
|
||||||
|
local test_script
|
||||||
|
for test_script in "${QUICK_TESTS[@]}"; do
|
||||||
|
run_test "${test_script}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
run_full() {
|
||||||
|
local test_script
|
||||||
|
run_quick
|
||||||
|
for test_script in "${RUNTIME_TESTS[@]}"; do
|
||||||
|
run_test "${test_script}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
run_host() {
|
||||||
|
local test_script
|
||||||
|
for test_script in "${HOST_TESTS[@]}"; do
|
||||||
|
run_test "${test_script}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
run_network() {
|
||||||
|
local test_script
|
||||||
|
for test_script in "${NETWORK_TESTS[@]}"; do
|
||||||
|
run_network_test "${test_script}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
list_tests() {
|
||||||
|
printf '%s\n' 'Quick tests:'
|
||||||
|
printf ' %s\n' "${QUICK_TESTS[@]}"
|
||||||
|
printf '%s\n' 'Additional full-suite tests:'
|
||||||
|
printf ' %s\n' "${RUNTIME_TESTS[@]}"
|
||||||
|
printf '%s\n' 'Single-process tests requiring a local UDP bind:'
|
||||||
|
printf ' %s\n' "${HOST_TESTS[@]}"
|
||||||
|
printf '%s\n' 'Paired network tests:'
|
||||||
|
printf ' %s\n' "${NETWORK_TESTS[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
quick)
|
||||||
|
run_quick
|
||||||
|
;;
|
||||||
|
full)
|
||||||
|
run_full
|
||||||
|
;;
|
||||||
|
host)
|
||||||
|
run_host
|
||||||
|
;;
|
||||||
|
network)
|
||||||
|
run_network
|
||||||
|
;;
|
||||||
|
all)
|
||||||
|
run_full
|
||||||
|
run_host
|
||||||
|
run_network
|
||||||
|
;;
|
||||||
|
--list)
|
||||||
|
list_tests
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
printf '\nAll requested validations passed.\n'
|
||||||
Loading…
Add table
Add a link
Reference in a new issue