From a47bd1b5f00e19ae9dc0e56c230bd950416c4526 Mon Sep 17 00:00:00 2001 From: Tony Stark Date: Fri, 11 Jul 2025 02:47:38 -0500 Subject: [PATCH 1/3] Add Bevy starter template and documentation --- client/pages/starters/full-bevy-starter.md | 100 +++++ client/pnpm-lock.yaml | 448 ++++++++++----------- client/routes.ts | 158 ++++---- 3 files changed, 405 insertions(+), 301 deletions(-) create mode 100644 client/pages/starters/full-bevy-starter.md diff --git a/client/pages/starters/full-bevy-starter.md b/client/pages/starters/full-bevy-starter.md new file mode 100644 index 0000000..1c7c14b --- /dev/null +++ b/client/pages/starters/full-bevy-starter.md @@ -0,0 +1,100 @@ +# Bevy Dojo Starter Template + +[bevy_dojo_starter](https://github.com/okhaimie-dev/bevy_dojo_starter.git) provides a comprehensive template for building 2D onchain games using Bevy game engine integrated with Dojo framework on Starknet. The template showcases a fully functional 2D game that leverages blockchain state management while maintaining smooth gameplay through Bevy's ECS architecture. + +## What's Included +### Core Components + +- [dojo.bevy](https://github.com/dojoengine/dojo.bevy) Plugin Integration: Pre-configured plugin by the Cartridge.gg team +- Automatic Indexer Connection: Direct integration with [Torii](https://github.com/dojoengine/torii) indexer for real-time blockchain state +- Katana Testnet Integration: Ready-to-use connection to [Katana](https://github.com/dojoengine/katana) sequencer for testing +- 2D Game Example: Complete working game demonstrating onchain mechanics + +### Features Demonstrated + +- Blockchain state synchronization with game state +- Real-time updates from the Torii indexer +- Transaction handling within game loops +- Seamless onchain/offchain game logic separation + +``` +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ Bevy Engine │◄──►│ dojo.bevy Plugin │◄──►│ Starknet │ +└─────────────────┘ └──────────────────┘ └─────────────────┘ + │ │ │ + ▼ ▼ ▼ +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ Game Systems │ │ State Sync │ │ Torii Indexer │ +│ & Components │ │ & Game Systems │ │ Katana Sequencer│ +└─────────────────┘ └──────────────────┘ └─────────────────┘ +``` + +## Getting Started +### Prerequisites + +- Rust ([latest stable version](https://rustup.rs/)) +- Dojo development environment +- Basic understanding of Bevy ECS patterns +- Familiarity with Cairo smart contracts + +### Installation + +- Clone the starter kit repository +- Install dependencies +- Configure your Dojo environment +- Run the example game + +1. Clone the starter kit repository +``` +git clone https://github.com/okhaimie-dev/bevy_dojo_starter.git +``` +2. Install dependencies +``` +cd bevy_dojo_starter +cargo build +``` +3. Configure your Dojo environment +``` +cd contracts +``` +``` +katana --config ./katana.toml +``` +``` +torii --config ./torii_dev.toml +``` +``` +sozo build +``` +``` +sozo migrate +``` +``` +sozo inspect +``` +``` +cd .. +``` + +Open the `src/constants/dojo.rs` file. +And modify the `WORLD_ADDRESS` and `ACTION_ADDRESS` constants. To the value you get for this respective constants from the `sozo inspect` command. + +4. Run the example game +``` +cargo run +``` + +## Next Steps + +- Explore the example game code +- Modify game mechanics to suit your needs +- Deploy to testnet for testing +- Scale to mainnet for production + +## Resources + +[Bevy Documentation](https://bevy.org/learn/quick-start/introduction/) +[Dojoengine Documentation](https://dojoengine.org/overview) + +## Contributing +Contributions are welcome! Please see our contributing guidelines for more diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml index 21cf8b3..69b9e3f 100644 --- a/client/pnpm-lock.yaml +++ b/client/pnpm-lock.yaml @@ -14,7 +14,7 @@ overrides: patchedDependencies: vocs@1.0.0-alpha.62: - hash: 7wumpnts656yvepr4seo2mjn34 + hash: 472ea4771ea28176fd7a35b8f83fe164ce160c07b9b50111ae749eb8da92176d path: patches/vocs.patch importers: @@ -23,7 +23,7 @@ importers: dependencies: '@types/react': specifier: latest - version: 19.0.12 + version: 19.1.8 react: specifier: ^19.0.0 version: 19.0.0 @@ -38,10 +38,10 @@ importers: version: 6.0.0 typescript: specifier: latest - version: 5.8.2 + version: 5.8.3 vocs: specifier: 1.0.0-alpha.62 - version: 1.0.0-alpha.62(patch_hash=7wumpnts656yvepr4seo2mjn34)(@types/node@22.13.13)(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(acorn@8.14.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.37.0)(typescript@5.8.2) + version: 1.0.0-alpha.62(patch_hash=472ea4771ea28176fd7a35b8f83fe164ce160c07b9b50111ae749eb8da92176d)(@types/node@22.13.13)(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(acorn@8.14.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.37.0)(typescript@5.8.3) devDependencies: '@types/babel__core': specifier: ^7.20.5 @@ -66,7 +66,7 @@ importers: version: 2.1.0 '@types/react-dom': specifier: ^19.0.4 - version: 19.0.4(@types/react@19.0.12) + version: 19.0.4(@types/react@19.1.8) '@types/unist': specifier: ^3.0.3 version: 3.0.3 @@ -1085,8 +1085,8 @@ packages: peerDependencies: '@types/react': ^19.0.0 - '@types/react@19.0.12': - resolution: {integrity: sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==} + '@types/react@19.1.8': + resolution: {integrity: sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==} '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -2547,8 +2547,8 @@ packages: peerDependencies: typescript: '*' - typescript@5.8.2: - resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} hasBin: true @@ -3089,10 +3089,10 @@ snapshots: - acorn - supports-color - '@mdx-js/react@3.1.0(@types/react@19.0.12)(react@19.0.0)': + '@mdx-js/react@3.1.0(@types/react@19.1.8)(react@19.0.0)': dependencies: '@types/mdx': 2.0.13 - '@types/react': 19.0.12 + '@types/react': 19.1.8 react: 19.0.0 '@mdx-js/rollup@3.1.0(acorn@8.14.1)(rollup@4.37.0)': @@ -3127,336 +3127,336 @@ snapshots: '@radix-ui/primitive@1.1.1': {} - '@radix-ui/react-accordion@1.2.3(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-accordion@1.2.3(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-collapsible': 1.1.3(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-direction': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-id': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-collapsible': 1.1.3(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-direction': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-arrow@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-arrow@1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-collapsible@1.1.3(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-collapsible@1.1.3(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-id': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-collection@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-collection@1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-slot': 1.1.2(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.1.2(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-compose-refs@1.1.1(@types/react@19.1.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-context@1.1.1(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-context@1.1.1(@types/react@19.1.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-dialog@1.1.6(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-dialog@1.1.6(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-id': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-slot': 1.1.2(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.1.2(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.8)(react@19.0.0) aria-hidden: 1.2.4 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - react-remove-scroll: 2.6.3(@types/react@19.0.12)(react@19.0.0) + react-remove-scroll: 2.6.3(@types/react@19.1.8)(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-direction@1.1.0(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-direction@1.1.0(@types/react@19.1.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-dismissable-layer@1.1.5(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-dismissable-layer@1.1.5(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-focus-guards@1.1.1(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-focus-guards@1.1.1(@types/react@19.1.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-focus-scope@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-focus-scope@1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) '@radix-ui/react-icons@1.3.2(react@19.0.0)': dependencies: react: 19.0.0 - '@radix-ui/react-id@1.1.0(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-id@1.1.0(@types/react@19.1.8)(react@19.0.0)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-label@2.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-label@2.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-navigation-menu@1.2.5(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-navigation-menu@1.2.5(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-direction': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-id': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-use-previous': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-visually-hidden': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-direction': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-use-previous': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-visually-hidden': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-popover@1.1.6(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-popover@1.1.6(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-id': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-popper': 1.2.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-slot': 1.1.2(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-popper': 1.2.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.1.2(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.8)(react@19.0.0) aria-hidden: 1.2.4 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - react-remove-scroll: 2.6.3(@types/react@19.0.12)(react@19.0.0) + react-remove-scroll: 2.6.3(@types/react@19.1.8)(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-popper@1.2.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-popper@1.2.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-arrow': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-use-rect': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-use-size': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-arrow': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-use-rect': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-use-size': 1.1.0(@types/react@19.1.8)(react@19.0.0) '@radix-ui/rect': 1.1.0 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-portal@1.1.4(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-portal@1.1.4(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-presence@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-presence@1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-primitive@2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-primitive@2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@radix-ui/react-slot': 1.1.2(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-slot': 1.1.2(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-roving-focus@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-roving-focus@1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-direction': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-id': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-direction': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-slot@1.1.2(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-slot@1.1.2(@types/react@19.1.8)(react@19.0.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-tabs@1.1.3(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-tabs@1.1.3(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-context': 1.1.1(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-direction': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-id': 1.1.0(@types/react@19.0.12)(react@19.0.0) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-roving-focus': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-direction': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.1.8)(react@19.0.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-roving-focus': 1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) - '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.1.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.1.8)(react@19.0.0)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.1.8)(react@19.0.0)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.1.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-use-previous@1.1.0(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-use-previous@1.1.0(@types/react@19.1.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-use-rect@1.1.0(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-use-rect@1.1.0(@types/react@19.1.8)(react@19.0.0)': dependencies: '@radix-ui/rect': 1.1.0 react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-use-size@1.1.0(@types/react@19.0.12)(react@19.0.0)': + '@radix-ui/react-use-size@1.1.0(@types/react@19.1.8)(react@19.0.0)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.8)(react@19.0.0) react: 19.0.0 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@radix-ui/react-visually-hidden@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-visually-hidden@1.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 - '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@types/react': 19.1.8 + '@types/react-dom': 19.0.4(@types/react@19.1.8) '@radix-ui/rect@1.1.0': {} @@ -3563,11 +3563,11 @@ snapshots: dependencies: shiki: 1.23.1 - '@shikijs/twoslash@1.23.1(typescript@5.8.2)': + '@shikijs/twoslash@1.23.1(typescript@5.8.3)': dependencies: '@shikijs/core': 1.23.1 '@shikijs/types': 1.23.1 - twoslash: 0.2.12(typescript@5.8.2) + twoslash: 0.2.12(typescript@5.8.3) transitivePeerDependencies: - supports-color - typescript @@ -3630,11 +3630,11 @@ snapshots: dependencies: undici-types: 6.20.0 - '@types/react-dom@19.0.4(@types/react@19.0.12)': + '@types/react-dom@19.0.4(@types/react@19.1.8)': dependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - '@types/react@19.0.12': + '@types/react@19.1.8': dependencies: csstype: 3.1.3 @@ -3642,10 +3642,10 @@ snapshots: '@types/unist@3.0.3': {} - '@typescript/vfs@1.6.1(typescript@5.8.2)': + '@typescript/vfs@1.6.1(typescript@5.8.3)': dependencies: debug: 4.4.0 - typescript: 5.8.2 + typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -5207,24 +5207,24 @@ snapshots: react-refresh@0.14.2: {} - react-remove-scroll-bar@2.3.8(@types/react@19.0.12)(react@19.0.0): + react-remove-scroll-bar@2.3.8(@types/react@19.1.8)(react@19.0.0): dependencies: react: 19.0.0 - react-style-singleton: 2.2.3(@types/react@19.0.12)(react@19.0.0) + react-style-singleton: 2.2.3(@types/react@19.1.8)(react@19.0.0) tslib: 2.8.1 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - react-remove-scroll@2.6.3(@types/react@19.0.12)(react@19.0.0): + react-remove-scroll@2.6.3(@types/react@19.1.8)(react@19.0.0): dependencies: react: 19.0.0 - react-remove-scroll-bar: 2.3.8(@types/react@19.0.12)(react@19.0.0) - react-style-singleton: 2.2.3(@types/react@19.0.12)(react@19.0.0) + react-remove-scroll-bar: 2.3.8(@types/react@19.1.8)(react@19.0.0) + react-style-singleton: 2.2.3(@types/react@19.1.8)(react@19.0.0) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.0.12)(react@19.0.0) - use-sidecar: 1.1.3(@types/react@19.0.12)(react@19.0.0) + use-callback-ref: 1.3.3(@types/react@19.1.8)(react@19.0.0) + use-sidecar: 1.1.3(@types/react@19.1.8)(react@19.0.0) optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 react-router-dom@6.30.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: @@ -5242,13 +5242,13 @@ snapshots: dependencies: react: 19.0.0 - react-style-singleton@2.2.3(@types/react@19.0.12)(react@19.0.0): + react-style-singleton@2.2.3(@types/react@19.1.8)(react@19.0.0): dependencies: get-nonce: 1.0.1 react: 19.0.0 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 react@19.0.0: {} @@ -5654,15 +5654,15 @@ snapshots: twoslash-protocol@0.2.12: {} - twoslash@0.2.12(typescript@5.8.2): + twoslash@0.2.12(typescript@5.8.3): dependencies: - '@typescript/vfs': 1.6.1(typescript@5.8.2) + '@typescript/vfs': 1.6.1(typescript@5.8.3) twoslash-protocol: 0.2.12 - typescript: 5.8.2 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - typescript@5.8.2: {} + typescript@5.8.3: {} ua-parser-js@1.0.40: {} @@ -5739,20 +5739,20 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - use-callback-ref@1.3.3(@types/react@19.0.12)(react@19.0.0): + use-callback-ref@1.3.3(@types/react@19.1.8)(react@19.0.0): dependencies: react: 19.0.0 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 - use-sidecar@1.1.3(@types/react@19.0.12)(react@19.0.0): + use-sidecar@1.1.3(@types/react@19.1.8)(react@19.0.0): dependencies: detect-node-es: 1.1.0 react: 19.0.0 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.8 util-deprecate@1.0.2: {} @@ -5812,24 +5812,24 @@ snapshots: '@types/node': 22.13.13 fsevents: 2.3.3 - vocs@1.0.0-alpha.62(patch_hash=7wumpnts656yvepr4seo2mjn34)(@types/node@22.13.13)(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(acorn@8.14.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.37.0)(typescript@5.8.2): + vocs@1.0.0-alpha.62(patch_hash=472ea4771ea28176fd7a35b8f83fe164ce160c07b9b50111ae749eb8da92176d)(@types/node@22.13.13)(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(acorn@8.14.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.37.0)(typescript@5.8.3): dependencies: '@floating-ui/react': 0.26.28(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@hono/node-server': 1.14.0(hono@3.12.12) - '@mdx-js/react': 3.1.0(@types/react@19.0.12)(react@19.0.0) + '@mdx-js/react': 3.1.0(@types/react@19.1.8)(react@19.0.0) '@mdx-js/rollup': 3.1.0(acorn@8.14.1)(rollup@4.37.0) '@noble/hashes': 1.7.1 '@radix-ui/colors': 3.0.0 - '@radix-ui/react-accordion': 1.2.3(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-dialog': 1.1.6(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-accordion': 1.2.3(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-dialog': 1.1.6(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@radix-ui/react-icons': 1.3.2(react@19.0.0) - '@radix-ui/react-label': 2.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-navigation-menu': 1.2.5(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-popover': 1.1.6(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-tabs': 1.1.3(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-label': 2.1.2(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-navigation-menu': 1.2.5(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-popover': 1.1.6(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-tabs': 1.1.3(@types/react-dom@19.0.4(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@shikijs/rehype': 1.23.1 '@shikijs/transformers': 1.23.1 - '@shikijs/twoslash': 1.23.1(typescript@5.8.2) + '@shikijs/twoslash': 1.23.1(typescript@5.8.3) '@vanilla-extract/css': 1.17.1 '@vanilla-extract/dynamic': 2.1.2 '@vanilla-extract/vite-plugin': 3.9.5(@types/node@22.13.13)(vite@5.4.15(@types/node@22.13.13)) @@ -5872,7 +5872,7 @@ snapshots: shiki: 1.23.1 tailwindcss: 3.4.17 toml: 3.0.0 - twoslash: 0.2.12(typescript@5.8.2) + twoslash: 0.2.12(typescript@5.8.3) ua-parser-js: 1.0.40 unified: 11.0.5 unist-util-visit: 5.0.0 diff --git a/client/routes.ts b/client/routes.ts index 1680a4c..2cb5a96 100644 --- a/client/routes.ts +++ b/client/routes.ts @@ -95,6 +95,10 @@ const config: Sidebar = [ text: "Full Starter React", link: "/starters/full-react-starter", }, + { + text: "Full Bevy Starter", + link: "/starters/full-bevy-starter", + }, ], }, { @@ -112,81 +116,81 @@ const config: Sidebar = [ ], }, { - text: "Dojo Integrations", - collapsed: true, - items: [ - { - text: "React", - collapsed: true, - items: [ - { - text: "Overview", - link: "/integrations/react/overview", - }, - { - text: "Configuration", - items: [ - { - text: "Dojo Config", - link: "/integrations/react/dojo-config", - }, - { - text: "Manifest", - link: "/integrations/react/manifest", - }, - { - text: "Main Setup", - link: "/integrations/react/main", - }, - ], - }, - { - text: "Providers", - items: [ - { - text: "Starknet Provider", - link: "/integrations/react/starknet-provider", - }, - { - text: "Controller Connector", - link: "/integrations/react/controller-connector", - }, - ], - }, - { - text: "Bindings", - items: [ - { - text: "Models Bindings", - link: "/integrations/react/bindings/models-bindings", - }, - { - text: "Contracts Bindings", - link: "/integrations/react/bindings/contracts-bindings", - }, - ], - }, - ], - }, - { - text: "Unity", - link: "/integrations/unity", - }, - { - text: "AI Agents", - items: [ - { - text: "Daydreams", - link: "/integrations/ai/daydreams", - }, - { - text: "Eliza", - link: "/integrations/ai/eliza", - }, - ], - }, - ], -}, + text: "Dojo Integrations", + collapsed: true, + items: [ + { + text: "React", + collapsed: true, + items: [ + { + text: "Overview", + link: "/integrations/react/overview", + }, + { + text: "Configuration", + items: [ + { + text: "Dojo Config", + link: "/integrations/react/dojo-config", + }, + { + text: "Manifest", + link: "/integrations/react/manifest", + }, + { + text: "Main Setup", + link: "/integrations/react/main", + }, + ], + }, + { + text: "Providers", + items: [ + { + text: "Starknet Provider", + link: "/integrations/react/starknet-provider", + }, + { + text: "Controller Connector", + link: "/integrations/react/controller-connector", + }, + ], + }, + { + text: "Bindings", + items: [ + { + text: "Models Bindings", + link: "/integrations/react/bindings/models-bindings", + }, + { + text: "Contracts Bindings", + link: "/integrations/react/bindings/contracts-bindings", + }, + ], + }, + ], + }, + { + text: "Unity", + link: "/integrations/unity", + }, + { + text: "AI Agents", + items: [ + { + text: "Daydreams", + link: "/integrations/ai/daydreams", + }, + { + text: "Eliza", + link: "/integrations/ai/eliza", + }, + ], + }, + ], + }, { text: "Dojo Use Cases", collapsed: true, @@ -243,7 +247,7 @@ const generateSidebarConfig = (sidebar: SidebarItem[]): Sidebar => { const sidebarFocusOn = ( sidebar: SidebarItem[], target: string, - closeOther: boolean = false + closeOther: boolean = false, ): SidebarItem[] => sidebar.map((item) => item.items && item.items.length > 0 @@ -255,7 +259,7 @@ const sidebarFocusOn = ( : { ...item, collapsed: item.text === target ? item.collapsed : true, - } + }, ); export const routes = generateSidebarConfig(config); From d9d5f4ce690db0243423052dacb03a5df19390e5 Mon Sep 17 00:00:00 2001 From: Tony Stark Date: Sat, 26 Jul 2025 17:51:20 -0500 Subject: [PATCH 2/3] Upgrade Dojo to v1.6.1 and Scarb to v2.10.1 Updates project dependencies and CI workflow to use latest Dojo and Scarb versions. Switches from asdf to direct binary installation in CI. --- .github/workflows/ci.yml | 66 +++++++++---------- .../dojo_examples/combat_game/.tool-versions | 4 +- backend/dojo_examples/combat_game/Scarb.lock | 14 ++-- backend/dojo_examples/combat_game/Scarb.toml | 18 ++--- .../combat_game/src/models/skill.cairo | 47 ++++++++----- .../combat_game/src/systems/battle.cairo | 2 +- .../combat_game/src/systems/beast.cairo | 3 +- .../combat_game/src/systems/player.cairo | 3 +- .../combat_game/src/types/beast_type.cairo | 4 +- 9 files changed, 86 insertions(+), 75 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b12bcc..f6c8591 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,57 +2,53 @@ name: Cairo-Dojo CI on: push: - branches: [ main, master ] + branches: [main] pull_request: - branches: [ main, master ] + branches: [main] + +env: + DOJO_VERSION: 1.6.1 + SCARB_VERSION: 2.10.1 + WORKING_DIRECTORY: ./backend/dojo_examples/combat_game jobs: build-and-test: name: Build and Test runs-on: ubuntu-latest - + steps: - name: Checkout code - uses: actions/checkout@v3 - - - name: Install asdf - uses: asdf-vm/actions/setup@v2 - - - name: Verify asdf installation - run: asdf --version + uses: actions/checkout@v4 - - name: Install Dojo plugin + - name: Download Dojo release artifact run: | - asdf plugin add dojo https://github.com/dojoengine/asdf-dojo - asdf install dojo 1.2.1 - asdf global dojo 1.2.1 - asdf list dojo - which sozo || echo "sozo not found" - ls -la /home/runner/.config/.dojo/bin/ || echo "Directory not found" + curl -L -o dojo-linux-x86_64.tar.gz https://github.com/dojoengine/dojo/releases/download/v${{ env.DOJO_VERSION }}/dojo_v${{ env.DOJO_VERSION }}_linux_amd64.tar.gz + tar -xzf dojo-linux-x86_64.tar.gz + sudo mv sozo /usr/local/bin/ - - name: Update PATH - run: echo "$HOME/.asdf/shims" >> $GITHUB_PATH - - - name: Install Scarb plugin - run: | - asdf plugin add scarb - asdf install scarb 2.9.2 - asdf global scarb 2.9.2 + - name: Setup Scarb + uses: software-mansion/setup-scarb@v1 + with: + scarb-version: ${{ env.SCARB_VERSION }} - name: Build contracts - working-directory: backend/dojo_examples/combat_game + working-directory: ${{ env.WORKING_DIRECTORY }} run: | sozo build - if [[ `git status --porcelain` ]]; then - echo "The git repo is dirty" - echo "Make sure to run 'sozo build' after changing Scarb.toml" - exit 1 - fi - name: Run tests - working-directory: backend/dojo_examples/combat_game + working-directory: ${{ env.WORKING_DIRECTORY }} run: sozo test - - name: Check formatting - working-directory: backend/dojo_examples/combat_game - run: scarb fmt + check: + runs-on: ubuntu-latest + name: Check format + steps: + - uses: actions/checkout@v4 + - uses: software-mansion/setup-scarb@v1 + with: + scarb-version: ${{ env.SCARB_VERSION }} + - name: Format + working-directory: ${{ env.WORKING_DIRECTORY }} + run: scarb fmt --check + shell: bash diff --git a/backend/dojo_examples/combat_game/.tool-versions b/backend/dojo_examples/combat_game/.tool-versions index 2ae4f76..c65b0fa 100644 --- a/backend/dojo_examples/combat_game/.tool-versions +++ b/backend/dojo_examples/combat_game/.tool-versions @@ -1,2 +1,2 @@ -dojo 1.2.1 -scarb 2.9.2 +dojo 1.6.1 +scarb 2.10.1 diff --git a/backend/dojo_examples/combat_game/Scarb.lock b/backend/dojo_examples/combat_game/Scarb.lock index fd7b434..4d0982c 100644 --- a/backend/dojo_examples/combat_game/Scarb.lock +++ b/backend/dojo_examples/combat_game/Scarb.lock @@ -4,7 +4,7 @@ version = 1 [[package]] name = "achievement" version = "0.0.0" -source = "git+https://github.com/cartridge-gg/arcade?tag=v1.2.1#8b8ccea5ec85ae7f903903ced9cd16e16b8e47cb" +source = "git+https://github.com/cartridge-gg/arcade?tag=v1.6.1#6438a74b589c3cac19b9782709e3845215ec67d6" dependencies = [ "dojo", ] @@ -20,21 +20,21 @@ dependencies = [ [[package]] name = "dojo" -version = "1.2.1" -source = "git+https://github.com/dojoengine/dojo?tag=v1.2.1#3d4b1a3e662f70679813f9fb65c0b5c7fa5d6f0a" +version = "1.6.1" +source = "git+https://github.com/dojoengine/dojo?tag=v1.6.1#a4f9445cf925e999d97038f596806ec307981a9b" dependencies = [ "dojo_plugin", ] [[package]] name = "dojo_cairo_test" -version = "1.0.12" -source = "git+https://github.com/dojoengine/dojo?tag=v1.2.1#3d4b1a3e662f70679813f9fb65c0b5c7fa5d6f0a" +version = "1.6.1" +source = "git+https://github.com/dojoengine/dojo?tag=v1.6.1#a4f9445cf925e999d97038f596806ec307981a9b" dependencies = [ "dojo", ] [[package]] name = "dojo_plugin" -version = "2.9.2" -source = "git+https://github.com/dojoengine/dojo?tag=v1.2.1#3d4b1a3e662f70679813f9fb65c0b5c7fa5d6f0a" +version = "2.10.1" +source = "git+https://github.com/dojoengine/dojo?tag=v1.6.1#a4f9445cf925e999d97038f596806ec307981a9b" diff --git a/backend/dojo_examples/combat_game/Scarb.toml b/backend/dojo_examples/combat_game/Scarb.toml index 860a7c3..0998f11 100644 --- a/backend/dojo_examples/combat_game/Scarb.toml +++ b/backend/dojo_examples/combat_game/Scarb.toml @@ -1,8 +1,8 @@ [package] -cairo-version = "2.9.2" +cairo-version = "2.10.1" name = "combat_game" version = "0.1.0" -edition = "2023_11" +edition = "2024_07" [cairo] sierra-replace-ids = true @@ -11,18 +11,18 @@ sierra-replace-ids = true sepolia = "sozo --profile sepolia clean && sozo --profile sepolia build && sozo --profile sepolia migrate --account-address $DEPLOYER_ACCOUNT_ADDRESS --private-key $DEPLOYER_PRIVATE_KEY --fee strk" [dependencies] -dojo = { git = "https://github.com/dojoengine/dojo", tag = "v1.2.1" } -achievement = { git = "https://github.com/cartridge-gg/arcade", tag = "v1.2.1" } +dojo = { git = "https://github.com/dojoengine/dojo", tag = "v1.6.1" } +achievement = { git = "https://github.com/cartridge-gg/arcade", tag = "v1.6.1" } [[target.starknet-contract]] build-external-contracts = [ "dojo::world::world_contract::world", - "achievement::events::index::e_TrophyCreation", - "achievement::events::index::e_TrophyProgression", + "achievement::events::index::e_TrophyCreation", + "achievement::events::index::e_TrophyProgression", ] [dev-dependencies] -cairo_test = "2.9.2" -dojo_cairo_test = { git = "https://github.com/dojoengine/dojo", tag = "v1.2.1" } +cairo_test = "2.10.1" +dojo_cairo_test = { git = "https://github.com/dojoengine/dojo", tag = "v1.6.1" } -[profile.sepolia] \ No newline at end of file +[profile.sepolia] diff --git a/backend/dojo_examples/combat_game/src/models/skill.cairo b/backend/dojo_examples/combat_game/src/models/skill.cairo index 69fcbd8..091e30b 100644 --- a/backend/dojo_examples/combat_game/src/models/skill.cairo +++ b/backend/dojo_examples/combat_game/src/models/skill.cairo @@ -67,14 +67,12 @@ pub impl SkillImpl of SkillTrait { #[cfg(test)] mod tests { use super::{ - SkillImpl, SkillType, - SLASH_SKILL_ID, BEAM_SKILL_ID, WAVE_SKILL_ID, PUNCH_SKILL_ID, KICK_SKILL_ID, - BLAST_SKILL_ID, CRUSH_SKILL_ID, PIERCE_SKILL_ID, SMASH_SKILL_ID, BURN_SKILL_ID, - FREEZE_SKILL_ID, SHOCK_SKILL_ID, DEFAULT_SKILL_ID, - SLASH_SKILL_DAMAGE, BEAM_SKILL_DAMAGE, WAVE_SKILL_DAMAGE, PUNCH_SKILL_DAMAGE, - KICK_SKILL_DAMAGE, BLAST_SKILL_DAMAGE, CRUSH_SKILL_DAMAGE, PIERCE_SKILL_DAMAGE, - SMASH_SKILL_DAMAGE, BURN_SKILL_DAMAGE, FREEZE_SKILL_DAMAGE, SHOCK_SKILL_DAMAGE, - DEFAULT_SKILL_DAMAGE, + SkillImpl, SkillType, SLASH_SKILL_ID, BEAM_SKILL_ID, WAVE_SKILL_ID, PUNCH_SKILL_ID, + KICK_SKILL_ID, BLAST_SKILL_ID, CRUSH_SKILL_ID, PIERCE_SKILL_ID, SMASH_SKILL_ID, + BURN_SKILL_ID, FREEZE_SKILL_ID, SHOCK_SKILL_ID, DEFAULT_SKILL_ID, SLASH_SKILL_DAMAGE, + BEAM_SKILL_DAMAGE, WAVE_SKILL_DAMAGE, PUNCH_SKILL_DAMAGE, KICK_SKILL_DAMAGE, + BLAST_SKILL_DAMAGE, CRUSH_SKILL_DAMAGE, PIERCE_SKILL_DAMAGE, SMASH_SKILL_DAMAGE, + BURN_SKILL_DAMAGE, FREEZE_SKILL_DAMAGE, SHOCK_SKILL_DAMAGE, DEFAULT_SKILL_DAMAGE, }; #[test] @@ -248,10 +246,19 @@ mod tests { fn test_all_skill_constants() { // Test that all skill ID constants are unique let skill_ids = array![ - SLASH_SKILL_ID, BEAM_SKILL_ID, WAVE_SKILL_ID, PUNCH_SKILL_ID, - KICK_SKILL_ID, BLAST_SKILL_ID, CRUSH_SKILL_ID, PIERCE_SKILL_ID, - SMASH_SKILL_ID, BURN_SKILL_ID, FREEZE_SKILL_ID, SHOCK_SKILL_ID, - DEFAULT_SKILL_ID + SLASH_SKILL_ID, + BEAM_SKILL_ID, + WAVE_SKILL_ID, + PUNCH_SKILL_ID, + KICK_SKILL_ID, + BLAST_SKILL_ID, + CRUSH_SKILL_ID, + PIERCE_SKILL_ID, + SMASH_SKILL_ID, + BURN_SKILL_ID, + FREEZE_SKILL_ID, + SHOCK_SKILL_ID, + DEFAULT_SKILL_ID, ]; // Test that each ID is within expected range @@ -262,12 +269,18 @@ mod tests { assert!(KICK_SKILL_ID >= 1 && KICK_SKILL_ID <= 13, "Kick skill ID should be in range"); assert!(BLAST_SKILL_ID >= 1 && BLAST_SKILL_ID <= 13, "Blast skill ID should be in range"); assert!(CRUSH_SKILL_ID >= 1 && CRUSH_SKILL_ID <= 13, "Crush skill ID should be in range"); - assert!(PIERCE_SKILL_ID >= 1 && PIERCE_SKILL_ID <= 13, "Pierce skill ID should be in range"); + assert!( + PIERCE_SKILL_ID >= 1 && PIERCE_SKILL_ID <= 13, "Pierce skill ID should be in range", + ); assert!(SMASH_SKILL_ID >= 1 && SMASH_SKILL_ID <= 13, "Smash skill ID should be in range"); assert!(BURN_SKILL_ID >= 1 && BURN_SKILL_ID <= 13, "Burn skill ID should be in range"); - assert!(FREEZE_SKILL_ID >= 1 && FREEZE_SKILL_ID <= 13, "Freeze skill ID should be in range"); + assert!( + FREEZE_SKILL_ID >= 1 && FREEZE_SKILL_ID <= 13, "Freeze skill ID should be in range", + ); assert!(SHOCK_SKILL_ID >= 1 && SHOCK_SKILL_ID <= 13, "Shock skill ID should be in range"); - assert!(DEFAULT_SKILL_ID >= 1 && DEFAULT_SKILL_ID <= 13, "Default skill ID should be in range"); + assert!( + DEFAULT_SKILL_ID >= 1 && DEFAULT_SKILL_ID <= 13, "Default skill ID should be in range", + ); } #[test] @@ -276,7 +289,7 @@ mod tests { // Test that base damage matches what would be set when creating skills let slash_skill = SkillImpl::new(SLASH_SKILL_ID, SLASH_SKILL_DAMAGE, SkillType::Slash, 1); let calculated_damage = SkillImpl::base_damage(SkillType::Slash); - + assert_eq!(slash_skill.power, calculated_damage, "Skill power should match base damage"); } -} \ No newline at end of file +} diff --git a/backend/dojo_examples/combat_game/src/systems/battle.cairo b/backend/dojo_examples/combat_game/src/systems/battle.cairo index 2c1178e..8a3ce2a 100644 --- a/backend/dojo_examples/combat_game/src/systems/battle.cairo +++ b/backend/dojo_examples/combat_game/src/systems/battle.cairo @@ -15,6 +15,7 @@ pub mod battle_system { use combat_game::achievements::achievement::{Achievement, AchievementTrait}; use starknet::{get_caller_address, get_block_timestamp, ContractAddress}; + use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; use core::num::traits::zero::Zero; use achievement::components::achievable::AchievableComponent; @@ -316,4 +317,3 @@ pub mod battle_system { } } } - diff --git a/backend/dojo_examples/combat_game/src/systems/beast.cairo b/backend/dojo_examples/combat_game/src/systems/beast.cairo index 38bb40f..dffc9d0 100644 --- a/backend/dojo_examples/combat_game/src/systems/beast.cairo +++ b/backend/dojo_examples/combat_game/src/systems/beast.cairo @@ -12,6 +12,7 @@ pub trait IBeast { pub mod beast_system { use super::{IBeast, BeastType, BeastStats}; use starknet::get_block_timestamp; + use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; use combat_game::store::{StoreTrait}; use combat_game::models::beast_stats::BeastStatsActionTrait; @@ -38,7 +39,7 @@ pub mod beast_system { store.init_beast_skills(beast_id); let beast_stats = BeastStatsActionTrait::new_beast_stats( - beast_id, beast_type, beast.level, get_block_timestamp() + beast_id, beast_type, beast.level, get_block_timestamp(), ); store.write_beast_stats(beast_stats); beast_id diff --git a/backend/dojo_examples/combat_game/src/systems/player.cairo b/backend/dojo_examples/combat_game/src/systems/player.cairo index 99ffc41..fdb8dcb 100644 --- a/backend/dojo_examples/combat_game/src/systems/player.cairo +++ b/backend/dojo_examples/combat_game/src/systems/player.cairo @@ -9,6 +9,7 @@ pub mod player_system { use super::IPlayer; use combat_game::models::player::{Player, PlayerAssert}; + use starknet::storage::{StoragePointerWriteAccess}; use combat_game::store::{StoreTrait}; use starknet::{get_caller_address, get_block_timestamp}; @@ -18,7 +19,7 @@ pub mod player_system { player_counter: u256, } - // Constructor + // Constructor fn dojo_init(ref self: ContractState) { self.player_counter.write(1); } diff --git a/backend/dojo_examples/combat_game/src/types/beast_type.cairo b/backend/dojo_examples/combat_game/src/types/beast_type.cairo index d06f1cd..5e9185f 100644 --- a/backend/dojo_examples/combat_game/src/types/beast_type.cairo +++ b/backend/dojo_examples/combat_game/src/types/beast_type.cairo @@ -35,7 +35,7 @@ pub impl Intou8BeastType of Into { 0 => BeastType::Light, 1 => BeastType::Magic, 2 => BeastType::Shadow, - _ => BeastType::Light, // Default fallback + _ => BeastType::Light // Default fallback } } } @@ -153,4 +153,4 @@ mod tests { let display_string = format!("{}", beast_type); assert_eq!(display_string, "Shadow"); } -} \ No newline at end of file +} From 93cc742d650e137c94168116f2ff34e521f6ebb9 Mon Sep 17 00:00:00 2001 From: Tony Stark Date: Mon, 4 Aug 2025 23:01:38 -0500 Subject: [PATCH 3/3] fmt ci fix --- .../combat_game/src/tests/test_beast.cairo | 84 +++-- .../combat_game/src/tests/test_player.cairo | 339 ++++++++++-------- 2 files changed, 248 insertions(+), 175 deletions(-) diff --git a/backend/dojo_examples/combat_game/src/tests/test_beast.cairo b/backend/dojo_examples/combat_game/src/tests/test_beast.cairo index 62a8a6c..8105074 100644 --- a/backend/dojo_examples/combat_game/src/tests/test_beast.cairo +++ b/backend/dojo_examples/combat_game/src/tests/test_beast.cairo @@ -1,15 +1,8 @@ #[cfg(test)] mod beast_integration_tests { use combat_game::{ - models::{ - beast::{BeastTrait}, - beast_stats::{BeastStatsActionTrait}, - }, - types::{ - beast_type::BeastType, - skill::SkillType, - status_condition::StatusCondition, - }, + models::{beast::{BeastTrait}, beast_stats::{BeastStatsActionTrait}}, + types::{beast_type::BeastType, skill::SkillType, status_condition::StatusCondition}, }; use starknet::{contract_address_const, ContractAddress}; @@ -46,15 +39,23 @@ mod beast_integration_tests { #[available_gas(250000)] fn test_beast_type_effectiveness_integration() { // Test type effectiveness calculations (pure calculations) - let light_vs_shadow = BeastTrait::calculate_effectiveness(BeastType::Light, BeastType::Shadow); - let light_vs_magic = BeastTrait::calculate_effectiveness(BeastType::Light, BeastType::Magic); - let light_vs_light = BeastTrait::calculate_effectiveness(BeastType::Light, BeastType::Light); + let light_vs_shadow = BeastTrait::calculate_effectiveness( + BeastType::Light, BeastType::Shadow, + ); + let light_vs_magic = BeastTrait::calculate_effectiveness( + BeastType::Light, BeastType::Magic, + ); + let light_vs_light = BeastTrait::calculate_effectiveness( + BeastType::Light, BeastType::Light, + ); assert_eq!(light_vs_shadow, 150, "Light should be super effective against Shadow"); assert_eq!(light_vs_magic, 50, "Light should be not very effective against Magic"); assert_eq!(light_vs_light, 100, "Light should be normally effective against Light"); - let magic_vs_light = BeastTrait::calculate_effectiveness(BeastType::Magic, BeastType::Light); + let magic_vs_light = BeastTrait::calculate_effectiveness( + BeastType::Magic, BeastType::Light, + ); assert_eq!(magic_vs_light, 150, "Magic should be super effective against Light"); } @@ -65,12 +66,26 @@ mod beast_integration_tests { let magic_beast = BeastTrait::new(PLAYER1(), 2, BeastType::Magic); // Test skill type favoring - assert!(light_beast.is_favored_attack(SkillType::Beam), "Light beast should favor Beam attacks"); - assert!(light_beast.is_favored_attack(SkillType::Slash), "Light beast should favor Slash attacks"); - assert!(!light_beast.is_favored_attack(SkillType::Blast), "Light beast should NOT favor Blast attacks"); + assert!( + light_beast.is_favored_attack(SkillType::Beam), "Light beast should favor Beam attacks", + ); + assert!( + light_beast.is_favored_attack(SkillType::Slash), + "Light beast should favor Slash attacks", + ); + assert!( + !light_beast.is_favored_attack(SkillType::Blast), + "Light beast should NOT favor Blast attacks", + ); - assert!(magic_beast.is_favored_attack(SkillType::Blast), "Magic beast should favor Blast attacks"); - assert!(!magic_beast.is_favored_attack(SkillType::Beam), "Magic beast should NOT favor Beam attacks"); + assert!( + magic_beast.is_favored_attack(SkillType::Blast), + "Magic beast should favor Blast attacks", + ); + assert!( + !magic_beast.is_favored_attack(SkillType::Beam), + "Magic beast should NOT favor Beam attacks", + ); } #[test] @@ -79,22 +94,16 @@ mod beast_integration_tests { let light_beast = BeastTrait::new(PLAYER1(), 1, BeastType::Light); // Test attack calculation with type effectiveness - let (damage, is_favored, is_effective) = light_beast.attack( - BeastType::Shadow, - SkillType::Beam, - 1 - ); + let (damage, is_favored, is_effective) = light_beast + .attack(BeastType::Shadow, SkillType::Beam, 1); assert!(damage > 0, "Attack should deal damage"); assert!(is_favored, "Beam should be favored by Light beast"); assert!(is_effective, "Light should be effective against Shadow"); // Test non-effective attack - let (damage2, is_favored2, is_effective2) = light_beast.attack( - BeastType::Magic, - SkillType::Beam, - 1 - ); + let (damage2, is_favored2, is_effective2) = light_beast + .attack(BeastType::Magic, SkillType::Beam, 1); assert!(damage2 > 0, "Attack should still deal damage"); assert!(is_favored2, "Beam should still be favored by Light beast"); @@ -115,7 +124,9 @@ mod beast_integration_tests { // Validate initial state assert_eq!(beast_stats.current_hp, beast_stats.max_hp, "Current HP should equal max HP"); - assert_eq!(beast_stats.status_condition, StatusCondition::None, "Should start with no status"); + assert_eq!( + beast_stats.status_condition, StatusCondition::None, "Should start with no status", + ); } #[test] @@ -141,13 +152,20 @@ mod beast_integration_tests { let mut beast_stats = BeastStatsActionTrait::new_beast_stats(1, BeastType::Light, 1, 1000); // Test initial state - assert_eq!(beast_stats.status_condition, StatusCondition::None, "Should start with no status"); + assert_eq!( + beast_stats.status_condition, StatusCondition::None, "Should start with no status", + ); assert!(beast_stats.can_attack(), "Should be able to attack initially"); // Test applying status condition beast_stats.apply_status(StatusCondition::Poisoned); - assert_eq!(beast_stats.status_condition, StatusCondition::Poisoned, "Should have poisoned status"); - assert!(beast_stats.can_attack(), "Should still be able to attack when poisoned (only Stunned prevents attacking)"); + assert_eq!( + beast_stats.status_condition, StatusCondition::Poisoned, "Should have poisoned status", + ); + assert!( + beast_stats.can_attack(), + "Should still be able to attack when poisoned (only Stunned prevents attacking)", + ); // Test clearing status condition beast_stats.clear_status(); @@ -175,7 +193,7 @@ mod beast_integration_tests { // Each type should have different total stats due to modifiers let light_total = light_stats.max_hp + light_stats.attack; let magic_total = magic_stats.max_hp + magic_stats.attack; - + // At least one comparison should be different due to type modifiers assert!(light_total != magic_total, "Beast types should have different stat totals"); } diff --git a/backend/dojo_examples/combat_game/src/tests/test_player.cairo b/backend/dojo_examples/combat_game/src/tests/test_player.cairo index 18028d8..ff501a6 100644 --- a/backend/dojo_examples/combat_game/src/tests/test_player.cairo +++ b/backend/dojo_examples/combat_game/src/tests/test_player.cairo @@ -12,17 +12,13 @@ mod player_integration_tests { battle::{battle_system, IBattleDispatcher, IBattleDispatcherTrait}, }; use combat_game::models::{ - player::{Player, m_Player, PlayerAssert}, - beast::{Beast, m_Beast}, - beast_stats::{BeastStats, m_BeastStats, BeastStatsActionTrait}, - beast_skill::{BeastSkill, m_BeastSkill}, - skill::{Skill, m_Skill}, + player::{Player, m_Player, PlayerAssert}, beast::{Beast, m_Beast}, + beast_stats::{BeastStats, m_BeastStats, BeastStatsActionTrait}, + beast_skill::{BeastSkill, m_BeastSkill}, skill::{Skill, m_Skill}, battle::{Battle, m_Battle, BattleTrait}, }; use combat_game::types::{ - beast_type::BeastType, - battle_status::BattleStatus, - status_condition::StatusCondition, + beast_type::BeastType, battle_status::BattleStatus, status_condition::StatusCondition, }; use combat_game::store::{StoreTrait}; use combat_game::constants::{SECONDS_PER_DAY}; @@ -38,11 +34,11 @@ mod player_integration_tests { fn PLAYER1() -> ContractAddress { contract_address_const::<0x1234>() } - + fn PLAYER2() -> ContractAddress { contract_address_const::<0x5678>() } - + fn PLAYER3() -> ContractAddress { contract_address_const::<0x9abc>() } @@ -64,11 +60,14 @@ mod player_integration_tests { TestResource::Event(battle_system::e_AttackExecuted::TEST_CLASS_HASH), TestResource::Event(battle_system::e_BattleEnded::TEST_CLASS_HASH), TestResource::Event(achievement::events::index::e_TrophyCreation::TEST_CLASS_HASH), - TestResource::Event(achievement::events::index::e_TrophyProgression::TEST_CLASS_HASH), + TestResource::Event( + achievement::events::index::e_TrophyProgression::TEST_CLASS_HASH, + ), TestResource::Contract(player_system::TEST_CLASS_HASH), TestResource::Contract(beast_system::TEST_CLASS_HASH), TestResource::Contract(battle_system::TEST_CLASS_HASH), - ].span(), + ] + .span(), }; ndef } @@ -81,7 +80,8 @@ mod player_integration_tests { .with_writer_of([dojo::utils::bytearray_hash(@"combat_game")].span()), ContractDefTrait::new(@"combat_game", @"battle_system") .with_writer_of([dojo::utils::bytearray_hash(@"combat_game")].span()), - ].span() + ] + .span() } pub fn setup() -> (WorldStorage, IPlayerDispatcher, IBeastDispatcher, IBattleDispatcher) { @@ -106,10 +106,10 @@ mod player_integration_tests { } fn setup_beast_for_player( - mut world: WorldStorage, - beast_system: IBeastDispatcher, - player_address: ContractAddress, - beast_type: BeastType + mut world: WorldStorage, + beast_system: IBeastDispatcher, + player_address: ContractAddress, + beast_type: BeastType, ) -> u16 { testing::set_caller_address(player_address); beast_system.spawn_beast(beast_type) @@ -123,17 +123,17 @@ mod player_integration_tests { #[available_gas(3000000)] fn test_player_creation_and_initialization() { let (mut world, player_system, beast_system, _) = setup(); - + // Set caller to player 1 testing::set_caller_address(PLAYER1()); - + // Spawn player with initial beast player_system.spawn_player(INITIAL_BEAST_ID); - + // Verify player was created with correct values let store = StoreTrait::new(world); let player = store.read_player_from_address(PLAYER1()); - + player.assert_exists(); assert_eq!(player.address, PLAYER1(), "Player address should match"); assert_eq!(player.current_beast_id, INITIAL_BEAST_ID, "Current beast ID should be set"); @@ -141,7 +141,11 @@ mod player_integration_tests { assert_eq!(player.battles_lost, 0, "Initial battles lost should be 0"); assert!(player.creation_day > 0, "Creation day should be set"); assert!(player.last_active_day > 0, "Last active day should be set"); - assert_eq!(player.creation_day, player.last_active_day, "Creation and last active should be same initially"); + assert_eq!( + player.creation_day, + player.last_active_day, + "Creation and last active should be same initially", + ); } #[test] @@ -149,12 +153,12 @@ mod player_integration_tests { #[should_panic(expected: ('Player: Already exist',))] fn test_player_creation_duplicate_should_fail() { let (mut world, player_system, _, _) = setup(); - + testing::set_caller_address(PLAYER1()); - + // Create player first time player_system.spawn_player(INITIAL_BEAST_ID); - + // Try to create same player again - should panic player_system.spawn_player(INITIAL_BEAST_ID); } @@ -163,23 +167,26 @@ mod player_integration_tests { #[available_gas(3000000)] fn test_player_unique_addresses() { let (mut world, player_system, _, _) = setup(); - + // Create player 1 testing::set_caller_address(PLAYER1()); player_system.spawn_player(1); - + // Create player 2 testing::set_caller_address(PLAYER2()); player_system.spawn_player(2); - + let store = StoreTrait::new(world); let player1 = store.read_player_from_address(PLAYER1()); let player2 = store.read_player_from_address(PLAYER2()); - + player1.assert_exists(); player2.assert_exists(); assert!(player1.address != player2.address, "Players should have unique addresses"); - assert!(player1.current_beast_id != player2.current_beast_id, "Players should have different beast IDs"); + assert!( + player1.current_beast_id != player2.current_beast_id, + "Players should have different beast IDs", + ); } // ================================ @@ -190,19 +197,19 @@ mod player_integration_tests { #[available_gas(5000000)] fn test_player_beast_assignment_integration() { let (mut world, player_system, beast_system, _) = setup(); - + testing::set_caller_address(PLAYER1()); - + // Create beast first let beast_id = beast_system.spawn_beast(BeastType::Light); - + // Create player with this beast player_system.spawn_player(beast_id); - + let store = StoreTrait::new(world); let player = store.read_player_from_address(PLAYER1()); let beast = store.read_beast(beast_id); - + // Verify integration assert_eq!(player.current_beast_id, beast_id, "Player should have correct beast ID"); assert_eq!(beast.player, PLAYER1(), "Beast should belong to player"); @@ -213,22 +220,22 @@ mod player_integration_tests { #[available_gas(5000000)] fn test_player_beast_update_integration() { let (mut world, player_system, beast_system, _) = setup(); - + testing::set_caller_address(PLAYER1()); - + // Create initial setup let initial_beast_id = beast_system.spawn_beast(BeastType::Light); player_system.spawn_player(initial_beast_id); - + // Create a new beast let new_beast_id = beast_system.spawn_beast(BeastType::Shadow); - + // Update player profile with new beast player_system.update_profile(true, new_beast_id); - + let store = StoreTrait::new(world); let player = store.read_player_from_address(PLAYER1()); - + assert_eq!(player.current_beast_id, new_beast_id, "Player should have updated beast ID"); assert_eq!(player.battles_won, 1, "Player should have 1 battle won from update"); } @@ -241,37 +248,41 @@ mod player_integration_tests { #[available_gas(8000000)] fn test_battle_statistics_tracking_integration() { let (mut world, player_system, beast_system, battle_system) = setup(); - + // Setup two players with beasts testing::set_caller_address(PLAYER1()); let beast1_id = beast_system.spawn_beast(BeastType::Light); player_system.spawn_player(beast1_id); - + testing::set_caller_address(PLAYER2()); let beast2_id = beast_system.spawn_beast(BeastType::Shadow); player_system.spawn_player(beast2_id); - + // Setup beast stats for both let mut store = StoreTrait::new(world); - let beast1_stats = BeastStatsActionTrait::new_beast_stats(beast1_id, BeastType::Light, 1, get_block_timestamp()); - let beast2_stats = BeastStatsActionTrait::new_beast_stats(beast2_id, BeastType::Shadow, 1, get_block_timestamp()); + let beast1_stats = BeastStatsActionTrait::new_beast_stats( + beast1_id, BeastType::Light, 1, get_block_timestamp(), + ); + let beast2_stats = BeastStatsActionTrait::new_beast_stats( + beast2_id, BeastType::Shadow, 1, get_block_timestamp(), + ); store.write_beast_stats(beast1_stats); store.write_beast_stats(beast2_stats); - + // Simulate battle wins and losses testing::set_caller_address(PLAYER1()); - player_system.update_profile(true, beast1_id); // Win + player_system.update_profile(true, beast1_id); // Win player_system.update_profile(false, beast1_id); // Loss - player_system.update_profile(true, beast1_id); // Win - + player_system.update_profile(true, beast1_id); // Win + testing::set_caller_address(PLAYER2()); player_system.update_profile(false, beast2_id); // Loss player_system.update_profile(false, beast2_id); // Loss - + // Verify statistics let player1 = store.read_player_from_address(PLAYER1()); let player2 = store.read_player_from_address(PLAYER2()); - + assert_eq!(player1.battles_won, 2, "Player1 should have 2 wins"); assert_eq!(player1.battles_lost, 1, "Player1 should have 1 loss"); assert_eq!(player2.battles_won, 0, "Player2 should have 0 wins"); @@ -282,23 +293,23 @@ mod player_integration_tests { #[available_gas(8000000)] fn test_battle_statistics_persistence() { let (mut world, player_system, beast_system, _) = setup(); - + testing::set_caller_address(PLAYER1()); let beast_id = beast_system.spawn_beast(BeastType::Magic); player_system.spawn_player(beast_id); - + // Initial state verification let mut store = StoreTrait::new(world); let initial_player = store.read_player_from_address(PLAYER1()); assert_eq!(initial_player.battles_won, 0, "Initial wins should be 0"); assert_eq!(initial_player.battles_lost, 0, "Initial losses should be 0"); - + // Simulate multiple battle outcomes - player_system.update_profile(true, beast_id); // Win 1 - player_system.update_profile(true, beast_id); // Win 2 - player_system.update_profile(false, beast_id); // Loss 1 - player_system.update_profile(true, beast_id); // Win 3 - + player_system.update_profile(true, beast_id); // Win 1 + player_system.update_profile(true, beast_id); // Win 2 + player_system.update_profile(false, beast_id); // Loss 1 + player_system.update_profile(true, beast_id); // Win 3 + // Verify persistence across multiple transactions let final_player = store.read_player_from_address(PLAYER1()); assert_eq!(final_player.battles_won, 3, "Should have 3 total wins"); @@ -313,59 +324,85 @@ mod player_integration_tests { #[available_gas(5000000)] fn test_player_activity_tracking() { let (mut world, player_system, beast_system, _) = setup(); - + testing::set_caller_address(PLAYER1()); let beast_id = beast_system.spawn_beast(BeastType::Light); - + // Record creation time let creation_timestamp = get_block_timestamp(); player_system.spawn_player(beast_id); - + let store = StoreTrait::new(world); let player = store.read_player_from_address(PLAYER1()); - + let expected_day = creation_timestamp / SECONDS_PER_DAY; - assert_eq!(player.creation_day, expected_day.try_into().unwrap(), "Creation day should match"); - assert_eq!(player.last_active_day, expected_day.try_into().unwrap(), "Last active should match creation initially"); - + assert_eq!( + player.creation_day, expected_day.try_into().unwrap(), "Creation day should match", + ); + assert_eq!( + player.last_active_day, + expected_day.try_into().unwrap(), + "Last active should match creation initially", + ); + // Simulate time passage and activity - testing::set_block_timestamp(creation_timestamp + SECONDS_PER_DAY + 3600); // Next day + 1 hour + testing::set_block_timestamp( + creation_timestamp + SECONDS_PER_DAY + 3600, + ); // Next day + 1 hour player_system.update_profile(true, beast_id); - + let updated_player = store.read_player_from_address(PLAYER1()); let new_expected_day = (creation_timestamp + SECONDS_PER_DAY + 3600) / SECONDS_PER_DAY; - - assert_eq!(updated_player.creation_day, expected_day.try_into().unwrap(), "Creation day should not change"); - assert_eq!(updated_player.last_active_day, new_expected_day.try_into().unwrap(), "Last active should update"); - assert!(updated_player.last_active_day > updated_player.creation_day, "Last active should be after creation"); + + assert_eq!( + updated_player.creation_day, + expected_day.try_into().unwrap(), + "Creation day should not change", + ); + assert_eq!( + updated_player.last_active_day, + new_expected_day.try_into().unwrap(), + "Last active should update", + ); + assert!( + updated_player.last_active_day > updated_player.creation_day, + "Last active should be after creation", + ); } #[test] #[available_gas(5000000)] fn test_multiple_activity_updates() { let (mut world, player_system, beast_system, _) = setup(); - + testing::set_caller_address(PLAYER1()); let beast_id = beast_system.spawn_beast(BeastType::Shadow); player_system.spawn_player(beast_id); - + let store = StoreTrait::new(world); let initial_player = store.read_player_from_address(PLAYER1()); let initial_last_active = initial_player.last_active_day; - + // Multiple activities on same day should update last_active to same day player_system.update_profile(true, beast_id); player_system.update_profile(false, beast_id); - + let same_day_player = store.read_player_from_address(PLAYER1()); - assert_eq!(same_day_player.last_active_day, initial_last_active, "Same day activities should not change day"); - + assert_eq!( + same_day_player.last_active_day, + initial_last_active, + "Same day activities should not change day", + ); + // Activity on different day should update testing::set_block_timestamp(get_block_timestamp() + SECONDS_PER_DAY * 2); player_system.update_profile(true, beast_id); - + let different_day_player = store.read_player_from_address(PLAYER1()); - assert!(different_day_player.last_active_day > initial_last_active, "Different day activity should update last_active_day"); + assert!( + different_day_player.last_active_day > initial_last_active, + "Different day activity should update last_active_day", + ); } // ================================ @@ -376,42 +413,46 @@ mod player_integration_tests { #[available_gas(10000000)] fn test_player_beast_battle_full_integration() { let (mut world, player_system, beast_system, battle_system) = setup(); - + // Setup Player 1 testing::set_caller_address(PLAYER1()); let beast1_id = beast_system.spawn_beast(BeastType::Light); player_system.spawn_player(beast1_id); - + // Setup Player 2 testing::set_caller_address(PLAYER2()); let beast2_id = beast_system.spawn_beast(BeastType::Shadow); player_system.spawn_player(beast2_id); - + // Setup beast stats let mut store = StoreTrait::new(world); - let beast1_stats = BeastStatsActionTrait::new_beast_stats(beast1_id, BeastType::Light, 1, get_block_timestamp()); - let beast2_stats = BeastStatsActionTrait::new_beast_stats(beast2_id, BeastType::Shadow, 1, get_block_timestamp()); + let beast1_stats = BeastStatsActionTrait::new_beast_stats( + beast1_id, BeastType::Light, 1, get_block_timestamp(), + ); + let beast2_stats = BeastStatsActionTrait::new_beast_stats( + beast2_id, BeastType::Shadow, 1, get_block_timestamp(), + ); store.write_beast_stats(beast1_stats); store.write_beast_stats(beast2_stats); - + // Initialize beast skills store.init_beast_skills(beast1_id); store.init_beast_skills(beast2_id); - + // Create and join battle testing::set_caller_address(PLAYER1()); let battle_id = battle_system.create_battle(PLAYER2(), BATTLE_TYPE); - + testing::set_caller_address(PLAYER2()); battle_system.join_battle(battle_id); - + // Verify cross-system state let battle = store.read_battle(battle_id); let player1 = store.read_player_from_address(PLAYER1()); let player2 = store.read_player_from_address(PLAYER2()); let beast1 = store.read_beast(beast1_id); let beast2 = store.read_beast(beast2_id); - + assert_eq!(battle.player1, PLAYER1(), "Battle player1 should match"); assert_eq!(battle.player2, PLAYER2(), "Battle player2 should match"); assert_eq!(battle.status, BattleStatus::Active, "Battle should be active"); @@ -425,27 +466,27 @@ mod player_integration_tests { #[available_gas(8000000)] fn test_player_beast_switching_integration() { let (mut world, player_system, beast_system, _) = setup(); - + testing::set_caller_address(PLAYER1()); - + // Create multiple beasts let beast1_id = beast_system.spawn_beast(BeastType::Light); let beast2_id = beast_system.spawn_beast(BeastType::Magic); let beast3_id = beast_system.spawn_beast(BeastType::Shadow); - + // Start with beast1 player_system.spawn_player(beast1_id); - + let store = StoreTrait::new(world); let initial_player = store.read_player_from_address(PLAYER1()); assert_eq!(initial_player.current_beast_id, beast1_id, "Should start with beast1"); - + // Switch to beast2 player_system.update_profile(true, beast2_id); let updated_player = store.read_player_from_address(PLAYER1()); assert_eq!(updated_player.current_beast_id, beast2_id, "Should switch to beast2"); assert_eq!(updated_player.battles_won, 1, "Should increment wins"); - + // Switch to beast3 player_system.update_profile(false, beast3_id); let final_player = store.read_player_from_address(PLAYER1()); @@ -462,34 +503,34 @@ mod player_integration_tests { #[available_gas(8000000)] fn test_multiple_players_simultaneous_creation() { let (mut world, player_system, beast_system, _) = setup(); - + // Create multiple players simultaneously testing::set_caller_address(PLAYER1()); let beast1_id = beast_system.spawn_beast(BeastType::Light); player_system.spawn_player(beast1_id); - + testing::set_caller_address(PLAYER2()); let beast2_id = beast_system.spawn_beast(BeastType::Magic); player_system.spawn_player(beast2_id); - + testing::set_caller_address(PLAYER3()); let beast3_id = beast_system.spawn_beast(BeastType::Shadow); player_system.spawn_player(beast3_id); - + // Verify all players exist independently let store = StoreTrait::new(world); let player1 = store.read_player_from_address(PLAYER1()); let player2 = store.read_player_from_address(PLAYER2()); let player3 = store.read_player_from_address(PLAYER3()); - + player1.assert_exists(); player2.assert_exists(); player3.assert_exists(); - + assert_eq!(player1.current_beast_id, beast1_id, "Player1 should have correct beast"); assert_eq!(player2.current_beast_id, beast2_id, "Player2 should have correct beast"); assert_eq!(player3.current_beast_id, beast3_id, "Player3 should have correct beast"); - + // Verify they're all unique assert!(player1.address != player2.address, "Player1 and Player2 should be different"); assert!(player1.address != player3.address, "Player1 and Player3 should be different"); @@ -500,39 +541,39 @@ mod player_integration_tests { #[available_gas(10000000)] fn test_multiple_players_battle_interactions() { let (mut world, player_system, beast_system, _) = setup(); - + // Setup three players testing::set_caller_address(PLAYER1()); let beast1_id = beast_system.spawn_beast(BeastType::Light); player_system.spawn_player(beast1_id); - + testing::set_caller_address(PLAYER2()); let beast2_id = beast_system.spawn_beast(BeastType::Magic); player_system.spawn_player(beast2_id); - + testing::set_caller_address(PLAYER3()); let beast3_id = beast_system.spawn_beast(BeastType::Shadow); player_system.spawn_player(beast3_id); - + // Simulate battle outcomes between different players testing::set_caller_address(PLAYER1()); - player_system.update_profile(true, beast1_id); // Player1 wins vs someone - + player_system.update_profile(true, beast1_id); // Player1 wins vs someone + testing::set_caller_address(PLAYER2()); - player_system.update_profile(false, beast2_id); // Player2 loses vs Player1 - + player_system.update_profile(false, beast2_id); // Player2 loses vs Player1 + testing::set_caller_address(PLAYER1()); - player_system.update_profile(false, beast1_id); // Player1 loses vs Player3 - + player_system.update_profile(false, beast1_id); // Player1 loses vs Player3 + testing::set_caller_address(PLAYER3()); - player_system.update_profile(true, beast3_id); // Player3 wins vs Player1 - + player_system.update_profile(true, beast3_id); // Player3 wins vs Player1 + // Verify statistics let store = StoreTrait::new(world); let player1 = store.read_player_from_address(PLAYER1()); let player2 = store.read_player_from_address(PLAYER2()); let player3 = store.read_player_from_address(PLAYER3()); - + assert_eq!(player1.battles_won, 1, "Player1 should have 1 win"); assert_eq!(player1.battles_lost, 1, "Player1 should have 1 loss"); assert_eq!(player2.battles_won, 0, "Player2 should have 0 wins"); @@ -550,9 +591,9 @@ mod player_integration_tests { #[should_panic(expected: ('Player: Does not exist',))] fn test_update_nonexistent_player() { let (mut world, player_system, _, _) = setup(); - + testing::set_caller_address(PLAYER1()); - + // Try to update profile without creating player first player_system.update_profile(true, 1); } @@ -561,15 +602,15 @@ mod player_integration_tests { #[available_gas(3000000)] fn test_player_with_zero_beast_id() { let (mut world, player_system, _, _) = setup(); - + testing::set_caller_address(PLAYER1()); - + // Create player with zero beast ID (should be allowed) player_system.spawn_player(0); - + let store = StoreTrait::new(world); let player = store.read_player_from_address(PLAYER1()); - + player.assert_exists(); assert_eq!(player.current_beast_id, 0, "Player should have zero beast ID"); } @@ -578,21 +619,21 @@ mod player_integration_tests { #[available_gas(5000000)] fn test_player_battle_statistics_overflow_prevention() { let (mut world, player_system, beast_system, _) = setup(); - + testing::set_caller_address(PLAYER1()); let beast_id = beast_system.spawn_beast(BeastType::Light); player_system.spawn_player(beast_id); - + // Simulate many wins (test large numbers) let mut i: u16 = 0; while i < 100 { player_system.update_profile(true, beast_id); i += 1; }; - + let store = StoreTrait::new(world); let player = store.read_player_from_address(PLAYER1()); - + assert_eq!(player.battles_won, 100, "Should handle 100 wins correctly"); assert_eq!(player.battles_lost, 0, "Should still have 0 losses"); } @@ -601,34 +642,42 @@ mod player_integration_tests { #[available_gas(5000000)] fn test_player_state_consistency_across_operations() { let (mut world, player_system, beast_system, _) = setup(); - + testing::set_caller_address(PLAYER1()); let beast_id = beast_system.spawn_beast(BeastType::Magic); player_system.spawn_player(beast_id); - + let store = StoreTrait::new(world); - + // Perform multiple operations and verify consistency let initial_player = store.read_player_from_address(PLAYER1()); let initial_creation_day = initial_player.creation_day; - + player_system.update_profile(true, beast_id); let after_win = store.read_player_from_address(PLAYER1()); - assert_eq!(after_win.creation_day, initial_creation_day, "Creation day should never change"); + assert_eq!( + after_win.creation_day, initial_creation_day, "Creation day should never change", + ); assert_eq!(after_win.battles_won, 1, "Wins should increment"); - + player_system.update_profile(false, beast_id); let after_loss = store.read_player_from_address(PLAYER1()); - assert_eq!(after_loss.creation_day, initial_creation_day, "Creation day should never change"); + assert_eq!( + after_loss.creation_day, initial_creation_day, "Creation day should never change", + ); assert_eq!(after_loss.battles_won, 1, "Wins should stay same"); assert_eq!(after_loss.battles_lost, 1, "Losses should increment"); - + // Change beast and verify consistency let new_beast_id = beast_system.spawn_beast(BeastType::Shadow); player_system.update_profile(true, new_beast_id); let after_beast_change = store.read_player_from_address(PLAYER1()); - - assert_eq!(after_beast_change.creation_day, initial_creation_day, "Creation day should never change"); + + assert_eq!( + after_beast_change.creation_day, + initial_creation_day, + "Creation day should never change", + ); assert_eq!(after_beast_change.current_beast_id, new_beast_id, "Beast ID should update"); assert_eq!(after_beast_change.battles_won, 2, "Wins should increment"); assert_eq!(after_beast_change.battles_lost, 1, "Losses should stay same"); @@ -638,20 +687,26 @@ mod player_integration_tests { #[available_gas(3000000)] fn test_player_zero_state_validation() { let (mut world, _, _, _) = setup(); - + // Test Zero player state let store = StoreTrait::new(world); let nonexistent_player = store.read_player_from_address(PLAYER1()); - + assert!(nonexistent_player.is_zero(), "Non-existent player should be zero"); - + // Verify zero player structure use combat_game::constants; - assert_eq!(nonexistent_player.address, constants::ZERO_ADDRESS(), "Zero player should have zero address"); + assert_eq!( + nonexistent_player.address, + constants::ZERO_ADDRESS(), + "Zero player should have zero address", + ); assert_eq!(nonexistent_player.current_beast_id, 0, "Zero player should have zero beast ID"); assert_eq!(nonexistent_player.battles_won, 0, "Zero player should have zero wins"); assert_eq!(nonexistent_player.battles_lost, 0, "Zero player should have zero losses"); - assert_eq!(nonexistent_player.last_active_day, 0, "Zero player should have zero last active"); + assert_eq!( + nonexistent_player.last_active_day, 0, "Zero player should have zero last active", + ); assert_eq!(nonexistent_player.creation_day, 1, "Zero player should have creation day 1"); } }