diff --git a/Android/game-reflex-poc/build.gradle b/Android/game-reflex-poc/build.gradle index 6803f1a..f844081 100644 --- a/Android/game-reflex-poc/build.gradle +++ b/Android/game-reflex-poc/build.gradle @@ -1,5 +1,5 @@ // file: Android/game-reflex-poc/build.gradle -// version: 9 +// version: 10 plugins { id 'com.android.application' @@ -18,7 +18,7 @@ android { minSdk 21 targetSdk 36 versionCode 1 - versionName '0.1.0-0-pre.11' + versionName '0.1.0-1-alpha.1' } compileOptions { diff --git a/Android/game-snake-poc/build.gradle b/Android/game-snake-poc/build.gradle index 0eb10c8..a4bb181 100644 --- a/Android/game-snake-poc/build.gradle +++ b/Android/game-snake-poc/build.gradle @@ -1,5 +1,5 @@ // file: Android/game-snake-poc/build.gradle -// version: 9 +// version: 10 plugins { id 'com.android.application' @@ -18,7 +18,7 @@ android { minSdk 21 targetSdk 36 versionCode 1 - versionName '0.1.0-0-pre.11' + versionName '0.1.0-1-alpha.1' } compileOptions { diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ef065e..8b382bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,17 @@ - + # Changelog +## 0.1.0-1-alpha.1 — 2026-09-16 + +- validation de la fin de phase `0-pre.*` avec Snake jouable sur Desktop et Galaxy S9+ ARM64 ; +- stabilisation du contrat de sortie `QuitRequest` / `QuitDecision` introduit pendant les derniers correctifs `0-pre.11` ; +- introduction de `RuntimeProvenance` dans `engine-v1-platform-api` ; +- séparation explicite entre famille de plateforme, classe de device, exécution native/WASM, hôte runtime et profil d'entrée ; +- préparation des futurs leaderboards/Hall of Fame pour segmenter les scores selon l'environnement sans imposer de comparaison automatique ; +- planification d'un POC Web/WASM dans Tauri comme prochain jalon alpha. + ## 0.1.0-0-pre.4 — 2026-09-16 - validation de `0-pre.3` enregistrée avec suite workspace complète et smokes Desktop propres ; diff --git a/Cargo.toml b/Cargo.toml index 1e9353e..a9d57e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ # file: Cargo.toml -# version: 26 +# version: 27 [workspace] resolver = "3" @@ -17,7 +17,7 @@ members = [ ] [workspace.package] -version = "0.1.0-0-pre.11.fix.5" +version = "0.1.0-1-alpha.1" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/games" diff --git a/README.md b/README.md index c67c716..695da96 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ - + # games.sasedev @@ -23,7 +23,7 @@ Workspace expérimental puis productif pour des jeux multiplateformes principale ## Baseline -Version courante : `0.1.0-0-pre.3`. +Version courante : `0.1.0-1-alpha.1`. Les deux premiers jeux sont des POC structurels : `game-reflex-poc` et `game-snake-poc`. Ils existent d'abord pour valider les frontières du workspace, le moteur, les assets et le packaging multiplateforme. diff --git a/ROADMAP.md b/ROADMAP.md index 5d4be5e..ac75621 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,5 +1,5 @@ - + # Roadmap @@ -15,8 +15,9 @@ - [x] `0-pre.8` — bridge Java/JNI minimal et input tactile Android. - [x] `0-pre.9` — assets communs + spécifiques empaquetés sans copie dans les crates. - [x] `0-pre.10` — POC Reflex jouable Desktop + Android. -- [ ] `0-pre.11` — POC Snake jouable et validation de la réutilisation du moteur. -- [ ] `1-alpha.1` — première API moteur V1 volontairement stabilisée. +- [x] `0-pre.11` — POC Snake jouable et validation de la réutilisation du moteur. +- [ ] `1-alpha.1` — première API moteur V1 volontairement stabilisée et provenance runtime/input pour les futures sessions et scores. +- [ ] `1-alpha.2` — POC Web/WASM embarqué dans Tauri, sans site distant, et validation de la frontière des services Web/ads. - [ ] `2-beta.1` — stabilisation, packaging, tests multi-appareils. - [ ] `3-rc.1` — candidat de release du socle 0.1.0. - [ ] `0.1.0` — première baseline stable du framework POC. diff --git a/crates/engines/engine-v1-platform-api/src/environment.rs b/crates/engines/engine-v1-platform-api/src/environment.rs new file mode 100644 index 0000000..9601c67 --- /dev/null +++ b/crates/engines/engine-v1-platform-api/src/environment.rs @@ -0,0 +1,122 @@ +// file: crates/engines/engine-v1-platform-api/src/environment.rs +// version: 1 + +/// Broad physical device class relevant to interaction and score provenance. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum DeviceClass { + /// Conventional desktop or laptop computer. + Desktop, + /// Phone-sized touch device. + Phone, + /// Tablet-sized touch device. + Tablet, + /// Device class is intentionally unknown or not yet classified. + Unknown, +} + +/// Code execution model used by the game runtime. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ExecutionModel { + /// Native machine code for the target platform. + Native, + /// WebAssembly execution. + Wasm, +} + +/// Primary control profile relevant to gameplay comparability. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum InputProfile { + /// Gamepad or equivalent controller is the primary input. + Gamepad, + /// Keyboard and mouse are the primary input devices. + KeyboardMouse, + /// Multiple materially different input modes are active for the same session. + Mixed, + /// Touchscreen or touch gestures are the primary input. + Touch, + /// Input profile is intentionally unknown or not yet classified. + Unknown, +} + +/// Broad platform family hosting the game. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum PlatformFamily { + /// Android application environment. + Android, + /// Desktop operating-system environment. + Desktop, + /// Browser-oriented Web environment. + Web, +} + +/// Host container in which the game runtime executes. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum RuntimeHost { + /// Conventional Web browser. + Browser, + /// Native process managed directly by the operating system. + Native, + /// Tauri desktop WebView host. + TauriWebView, +} + +/// Descriptive provenance attached to one runtime session. +/// +/// This structure is intentionally descriptive: it does not decide whether two scores should be +/// compared. Leaderboard policy remains a game/backend responsibility. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct RuntimeProvenance { + device_class: DeviceClass, + execution_model: ExecutionModel, + input_profile: InputProfile, + platform_family: PlatformFamily, + runtime_host: RuntimeHost, +} + +impl RuntimeProvenance { + /// Creates an explicit runtime provenance declaration. + #[must_use] + pub const fn new( + device_class: DeviceClass, + execution_model: ExecutionModel, + input_profile: InputProfile, + platform_family: PlatformFamily, + runtime_host: RuntimeHost, + ) -> Self { + return Self { device_class, execution_model, input_profile, platform_family, runtime_host }; + } + + /// Returns the physical device class. + #[must_use] + pub const fn device_class(self) -> DeviceClass { + return self.device_class; + } + + /// Returns the execution model. + #[must_use] + pub const fn execution_model(self) -> ExecutionModel { + return self.execution_model; + } + + /// Returns the primary input profile. + #[must_use] + pub const fn input_profile(self) -> InputProfile { + return self.input_profile; + } + + /// Returns the broad platform family. + #[must_use] + pub const fn platform_family(self) -> PlatformFamily { + return self.platform_family; + } + + /// Returns the runtime host container. + #[must_use] + pub const fn runtime_host(self) -> RuntimeHost { + return self.runtime_host; + } +} + +#[cfg(test)] +#[path = "../unit_tests/environment.rs"] +mod tests; diff --git a/crates/engines/engine-v1-platform-api/src/lib.rs b/crates/engines/engine-v1-platform-api/src/lib.rs index f07bcb7..218efbb 100644 --- a/crates/engines/engine-v1-platform-api/src/lib.rs +++ b/crates/engines/engine-v1-platform-api/src/lib.rs @@ -1,5 +1,5 @@ // file: crates/engines/engine-v1-platform-api/src/lib.rs -// version: 2 +// version: 3 #![warn(missing_docs)] #![deny(unreachable_pub)] @@ -7,8 +7,21 @@ //! Platform service contracts shared by engine generation V1. +mod environment; mod service; +/// Re-export of the physical device class used by runtime provenance. +pub use self::environment::DeviceClass; +/// Re-export of the native/WebAssembly execution model. +pub use self::environment::ExecutionModel; +/// Re-export of the primary gameplay input profile. +pub use self::environment::InputProfile; +/// Re-export of the broad runtime platform family. +pub use self::environment::PlatformFamily; +/// Re-export of the runtime host container. +pub use self::environment::RuntimeHost; +/// Re-export of descriptive runtime/session provenance. +pub use self::environment::RuntimeProvenance; /// Re-export of optional monetization capability declarations. pub use self::service::MonetizationCapabilities; /// Re-export of the minimal platform service capability enumeration. diff --git a/crates/engines/engine-v1-platform-api/unit_tests/environment.rs b/crates/engines/engine-v1-platform-api/unit_tests/environment.rs new file mode 100644 index 0000000..f66a074 --- /dev/null +++ b/crates/engines/engine-v1-platform-api/unit_tests/environment.rs @@ -0,0 +1,41 @@ +// file: crates/engines/engine-v1-platform-api/unit_tests/environment.rs +// version: 1 + +#[test] +fn android_phone_touch_provenance_preserves_dimensions() { + game_logging_lib::with_test_tracing("android_phone_touch_provenance_preserves_dimensions", || { + let provenance = crate::RuntimeProvenance::new( + crate::DeviceClass::Phone, + crate::ExecutionModel::Native, + crate::InputProfile::Touch, + crate::PlatformFamily::Android, + crate::RuntimeHost::Native, + ); + assert_eq!(provenance.device_class(), crate::DeviceClass::Phone); + assert_eq!(provenance.execution_model(), crate::ExecutionModel::Native); + assert_eq!(provenance.input_profile(), crate::InputProfile::Touch); + assert_eq!(provenance.platform_family(), crate::PlatformFamily::Android); + assert_eq!(provenance.runtime_host(), crate::RuntimeHost::Native); + }); +} + +#[test] +fn tauri_wasm_provenance_remains_distinct_from_native_desktop() { + game_logging_lib::with_test_tracing("tauri_wasm_provenance_remains_distinct_from_native_desktop", || { + let native = crate::RuntimeProvenance::new( + crate::DeviceClass::Desktop, + crate::ExecutionModel::Native, + crate::InputProfile::KeyboardMouse, + crate::PlatformFamily::Desktop, + crate::RuntimeHost::Native, + ); + let tauri = crate::RuntimeProvenance::new( + crate::DeviceClass::Desktop, + crate::ExecutionModel::Wasm, + crate::InputProfile::KeyboardMouse, + crate::PlatformFamily::Desktop, + crate::RuntimeHost::TauriWebView, + ); + assert_ne!(native, tauri); + }); +} diff --git a/deltas/0.1.0/1-alpha.1.md b/deltas/0.1.0/1-alpha.1.md new file mode 100644 index 0000000..28f72ce --- /dev/null +++ b/deltas/0.1.0/1-alpha.1.md @@ -0,0 +1,87 @@ + + + +# Delta 0.1.0-1-alpha.1 + +## Base + +Base validée : `0.1.0-0-pre.11.fix.5`. + +## Passage en alpha + +Les deux POC sont désormais jouables et réutilisent le même moteur sur Desktop. Snake a également été validé sur un Galaxy S9+ ARM64 réel. + +La phase `0-pre.*` est donc close. `1-alpha.*` commence la stabilisation volontaire de l'API moteur V1. + +## Provenance runtime + +`engine-v1-platform-api` introduit `RuntimeProvenance` et cinq dimensions orthogonales : + +```text +PlatformFamily +DeviceClass +ExecutionModel +RuntimeHost +InputProfile +``` + +Objectif : conserver avec une session, un score, un replay ou un événement analytics assez de contexte pour distinguer notamment : + +```text +Android / Phone / Native / Native / Touch +Desktop / Desktop / Native / Native / KeyboardMouse +Desktop / Desktop / Wasm / TauriWebView / KeyboardMouse +Web / Phone / Wasm / Browser / Touch +``` + +Aucune API de comparaison automatique n'est introduite. La politique de leaderboard reste propre au jeu/backend. + +## Identité joueur + +Authentification et provenance sont volontairement séparées. + +Un score anonyme et un score authentifié peuvent porter la même provenance. Le futur modèle de compte ne devra donc pas être utilisé pour déduire l'environnement technique. + +## Documentation + +- ajout de `docs/architecture/010-RUNTIME_PROVENANCE.md` ; +- extension de la documentation des leaderboards ; +- enregistrement de la validation `0-pre.11.fix.5` ; +- ajout de `1-alpha.2` pour le POC Web/WASM dans Tauri. + +## Android + +Les `versionName` Reflex et Snake passent à : + +```text +0.1.0-1-alpha.1 +``` + +## Validation + +```bash +cargo fmt --all +cargo fmt --all -- --check + +python3 scripts/audit_rust_workspace_rules.py +python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android deltas history + +cargo check --workspace +cargo clippy --workspace --all-targets --all-features -- -D warnings + +cargo test -p engine-v1-platform-api --all-targets --all-features +cargo test -p engine-v1-common --all-targets --all-features +cargo test -p engine-v1-sdl --all-targets --all-features +cargo test -p game-reflex-poc --all-targets --all-features +cargo test -p game-snake-poc --all-targets --all-features +``` + +## Smokes + +Aucun changement de gameplay n'est introduit par ce delta. Un smoke Desktop court de Reflex et Snake suffit après les gates Rust. + +## Transition + +Si les gates sont propres, passer à `0.1.0-1-alpha.2` pour le POC WASM + Tauri. + +En cas d'échec imputable au projet, produire `0.1.0-1-alpha.1.fix.1`. diff --git a/docs/000-README.md b/docs/000-README.md index 456cfdf..1a5b53e 100644 --- a/docs/000-README.md +++ b/docs/000-README.md @@ -1,5 +1,5 @@ - + # Documentation games.sasedev @@ -14,6 +14,8 @@ - [`architecture/003-SDL3_PLATFORM_ABSTRACTION.md`](architecture/003-SDL3_PLATFORM_ABSTRACTION.md) — frontière SDL3 entre Desktop, Android et Web. - [`architecture/004-INPUT_AND_CONTROLS.md`](architecture/004-INPUT_AND_CONTROLS.md) — abstraction clavier, souris, gamepad, tactile, gestes et capteurs. - [`architecture/005-ASSET_ARCHITECTURE.md`](architecture/005-ASSET_ARCHITECTURE.md) — assets communs/spécifiques hors crates et packaging. +- [`architecture/009-ENGINE_V1_RENDER_SCENE.md`](architecture/009-ENGINE_V1_RENDER_SCENE.md) — scène 2D portable, rectangles normalisés et backend SDL3. +- [`architecture/010-RUNTIME_PROVENANCE.md`](architecture/010-RUNTIME_PROVENANCE.md) — provenance plateforme/device/runtime/input pour sessions, scores et analytics. ## Jeux @@ -57,4 +59,3 @@ Voir [`../RULES.md`](../RULES.md), notamment [`rules/RULES_COMMANDS.md`](rules/R - [`../history/README.md`](../history/README.md) — convention et navigation de l'historique transitoire immuable des jalons validés. -- [`architecture/009-ENGINE_V1_RENDER_SCENE.md`](architecture/009-ENGINE_V1_RENDER_SCENE.md) — scène 2D portable, rectangles normalisés et backend SDL3. diff --git a/docs/architecture/010-RUNTIME_PROVENANCE.md b/docs/architecture/010-RUNTIME_PROVENANCE.md new file mode 100644 index 0000000..b8937a4 --- /dev/null +++ b/docs/architecture/010-RUNTIME_PROVENANCE.md @@ -0,0 +1,74 @@ + + + +# Provenance d'environnement d'exécution + +## Objectif + +Une session de jeu doit pouvoir décrire son environnement sans en déduire automatiquement une règle de classement. + +Cette provenance servira notamment aux futurs leaderboards, Hall of Fame, analytics, replays et diagnostics. + +## Dimensions V1 + +`engine-v1-platform-api` expose cinq dimensions indépendantes. + +`PlatformFamily` décrit la famille de plateforme : Android, Desktop ou Web. + +`DeviceClass` décrit la forme physique pertinente pour l'interaction : Phone, Tablet, Desktop ou Unknown. + +`ExecutionModel` distingue le code natif du WebAssembly. + +`RuntimeHost` distingue un processus natif, un navigateur et une WebView Tauri. + +`InputProfile` décrit le mode de contrôle principal : Touch, KeyboardMouse, Gamepad, Mixed ou Unknown. + +## Exemples + +Un Galaxy S9+ exécutant l'APK actuel peut être décrit comme : + +```text +PlatformFamily = Android +DeviceClass = Phone +ExecutionModel = Native +RuntimeHost = Native +InputProfile = Touch +``` + +Un runner SDL Desktop natif : + +```text +PlatformFamily = Desktop +DeviceClass = Desktop +ExecutionModel = Native +RuntimeHost = Native +InputProfile = KeyboardMouse +``` + +Le futur POC Tauri/WASM : + +```text +PlatformFamily = Desktop +DeviceClass = Desktop +ExecutionModel = Wasm +RuntimeHost = TauriWebView +InputProfile = KeyboardMouse +``` + +Une version Web dans un navigateur de téléphone pourra au contraire être `PlatformFamily = Web`, `DeviceClass = Phone`, `ExecutionModel = Wasm`, `RuntimeHost = Browser`, `InputProfile = Touch`. + +## Classements et équité + +La provenance ne contient aucune méthode du type `is_fair`, `difficulty` ou `comparable_with`. + +La difficulté relative des contrôles dépend du jeu. Un jeu de réflexe, un Snake, un puzzle et un jeu au gamepad peuvent produire des conclusions différentes. + +Le futur backend de score pourra donc conserver une provenance complète et appliquer une politique par jeu : classement commun, classement séparé par profil d'entrée, filtres par plateforme, ou catégories multiples. + +L'identité joueur reste orthogonale. Un score pourra appartenir à un utilisateur authentifié ou anonyme tout en conservant exactement la même provenance runtime. + +## Données et vie privée + +La provenance V1 décrit des catégories techniques générales. Elle ne requiert ni modèle précis de téléphone, ni identifiant matériel, ni adresse réseau. + +Un besoin futur de diagnostic plus fin devra être ajouté explicitement plutôt que d'élargir silencieusement cette structure. diff --git a/docs/services/001-ONLINE_AND_VIRAL_SERVICES.md b/docs/services/001-ONLINE_AND_VIRAL_SERVICES.md index 02024d9..b543f19 100644 --- a/docs/services/001-ONLINE_AND_VIRAL_SERVICES.md +++ b/docs/services/001-ONLINE_AND_VIRAL_SERVICES.md @@ -1,5 +1,5 @@ - + # Services en ligne, compétition et viralité @@ -9,6 +9,10 @@ Un classement peut être local, propre à une plateforme ou cross-platform via u Un backend cross-platform peut recevoir Android, Desktop et Web via HTTP et/ou WebSocket puis stocker les résultats dans une base commune. +Chaque score pourra conserver une provenance d'exécution structurée : famille de plateforme, classe de device, exécution native/WASM, hôte runtime et profil d'entrée. Cette information permet de filtrer ou segmenter un classement sans présumer qu'une plateforme est toujours plus facile qu'une autre. + +L'identité reste indépendante de cette provenance : un joueur authentifié comme un joueur anonyme peut produire un score portant les mêmes métadonnées d'environnement. + ## Challenges quotidiens Un seed quotidien peut fournir les mêmes conditions à tous les joueurs. Ce mécanisme combine contenu peu coûteux, compétition, rétention et partage. diff --git a/history/0.1.0/0-pre.11.fix.5.md b/history/0.1.0/0-pre.11.fix.5.md new file mode 100644 index 0000000..69d83d5 --- /dev/null +++ b/history/0.1.0/0-pre.11.fix.5.md @@ -0,0 +1,34 @@ + + + +# Historique 0.1.0-0-pre.11.fix.5 + +## Statut + +Validé par l'utilisateur le 2026-09-16. + +## Gates Rust + +- audits Rust/workspace propres ; +- audit Markdown : `1 table(s), 77 file(s)` ; +- `cargo check --workspace` propre ; +- Clippy workspace strict propre ; +- `engine-v1-common` : 8/8 tests ; +- `engine-v1-sdl` : 5/5 tests ; +- `game-snake-poc` : 5/5 tests. + +## Desktop + +Le runner Snake démarre et s'arrête proprement. Le contrat générique `QuitRequest` reste fonctionnel avec `Escape` via la politique par défaut `Exit`. + +## Android physique + +Le Galaxy S9+ de test est détecté en `arm64-v8a`. + +Le build Rust ARM64 et l'assemblage APK sont propres. L'APK est installé et lancé sur le téléphone réel. + +Les contrôles tactiles par swipe sont nettement meilleurs sur appareil physique que sur l'émulateur piloté à la souris et sont jugés suffisants pour ce POC. + +## Conclusion + +Le second jeu réutilise effectivement le moteur sur Desktop et Android. La phase `0-pre.*` est terminée et la stabilisation `1-alpha.*` peut commencer.