Week 09 of 2024
Development log of Otterhide
32 items
- Setup a development environment and CI / CD
- Ensure the assets/ directory exists
- Setup a Bevy application
- Make the canvas fill the viewport
- Setup a ground plane and a camera
- Setup a house (cuboid) and sunlight
- Set the camera in motion
- Remove duplicated web/develop goal from the Makefile
- Use a gltf model for a house and a sculpture
- Update some Cargo dependencies
- Implement basic logic concerning day-month
- Let the time pass but keep an eye on it
- Slow down the camera
- Simulate a horizon
- Move the camera related logic to own module
- Parameterize the camera plugin
- Implement day-night cycle with sunlight
- Format some code
- Separate date logic to a new plugin
- Make the ground material (grass) more rough
- Implement buildings plugin
- Let the houses stand in rows of 6
- Prevent negative luminosity at night
- Prevent initial flash of white before game loads
- Separate ground logic to a plugin
- Code consistency: use unqualified SunPlugin
- Introduce game states: Simulate and Explore
- Decouple construction orders from construction
- Update dependencies (Nix and Cargo)
- The date progression will stop as the sim is done
- Implement POC snapshots and rollback (time travel)
- Set simulation to 15 years
Setup a development environment and CI / CD
On by
It's adapted from https://gitlab.com/tad-lispy/bevy-lion-playground, but all the code is removed. There are some dependencies in Cargo.toml that are not yet used, but I expect to use them later.
new file mode 100644
index 0000000..5330b9c
--- /dev/null
+++ b/.envrc
@@ -0,0 +1,28 @@
+shopt -s globstar
+
+watch_file **/*.nix
+watch_file flake.lock
+watch_file rust-toolchain.toml
+
+use_flake() {
+ mkdir -p "$(direnv_layout_dir)"
+ eval "$(nix print-dev-env --profile "$(direnv_layout_dir)/flake-profile")"
+}
+
+if (nix help flake &> /dev/null)
+then
+ # Nix with flakes support
+ use flake
+
+elif command -v lorri
+then
+ # Lorri is installed
+ eval "$(lorri direnv)"
+
+else
+ # Standard nix - going to be slooow
+ use nix
+
+fi
+
+source_env_if_exists .envrc.privatenew file mode 100644
index 0000000..e426355
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+.direnv/
+/target/
+/result
+/public/
+/dist/
+/web/
+/build-image
+/.cargo-home/new file mode 100644
index 0000000..76bc656
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,88 @@
+variables:
+ project_name: "otterhide" # This has to align with flake.nix
+
+test:
+ stage: test
+ image: nixpkgs/nix-flakes:nixos-23.11
+
+ script:
+ - nix develop --command make test
+
+ artifacts:
+ name: "$CI_COMMIT_REF_SLUG"
+ expire_in: 1 week
+ paths:
+ - dist/
+
+ except:
+ - main
+
+ cache:
+ key: shared-cache
+ paths:
+ - target/
+
+pages:
+ stage: deploy
+ image: $CI_REGISTRY_IMAGE:build
+ variables:
+ CARGO_HOME: ${CI_PROJECT_DIR}/.cargo-home/
+ script:
+ - base_url="/$(cut --delimiter='/' --fields=4- <<< $CI_PAGES_URL)"
+ - make public base_url=${base_url}
+
+ artifacts:
+ paths:
+ - public/
+
+ only:
+ - main
+
+ cache:
+ key: cargo
+ paths:
+ - ${CARGO_HOME}/bin/
+ - ${CARGO_HOME}/registry/index/
+ - ${CARGO_HOME}/registry/cache/
+ - ${CARGO_HOME}/git/db/
+ - target/
+
+
+build-image:
+ stage: build
+ image: nixpkgs/nix-flakes:nixos-23.11
+ script:
+ - nix run nixpkgs#gnumake -- build-image
+ artifacts:
+ paths:
+ - build-image
+ cache:
+ key: build-image
+ paths:
+ - build-image
+ rules:
+ - changes:
+ - flake.nix
+ - flake.lock
+ - rust-toolchain.toml
+ - .gitlab-ci.yml
+
+
+publish-build-image:
+ stage: build
+ needs:
+ - build-image
+ dependencies:
+ - build-image
+ image: quay.io/podman/stable
+ script:
+ - gzip --decompress --to-stdout build-image | podman image load
+ - podman image tag ${project_name}-build-image $CI_REGISTRY_IMAGE:build
+ - podman login --username $CI_REGISTRY_USER --password $CI_REGISTRY_PASSWORD $CI_REGISTRY
+ - podman image push $CI_REGISTRY_IMAGE:build
+ rules:
+ - changes:
+ - flake.nix
+ - flake.lock
+ - rust-toolchain.toml
+ - .gitlab-ci.ymlnew file mode 100644
index 0000000..8bb2117
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,4333 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "ab_glyph"
+version = "0.2.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80179d7dd5d7e8c285d67c4a1e652972a92de7475beddfb92028c76463b13225"
+dependencies = [
+ "ab_glyph_rasterizer",
+ "owned_ttf_parser",
+]
+
+[[package]]
+name = "ab_glyph_rasterizer"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
+
+[[package]]
+name = "accesskit"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6cb10ed32c63247e4e39a8f42e8e30fb9442fbf7878c8e4a9849e7e381619bea"
+
+[[package]]
+name = "accesskit_consumer"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c17cca53c09fbd7288667b22a201274b9becaa27f0b91bf52a526db95de45e6"
+dependencies = [
+ "accesskit",
+]
+
+[[package]]
+name = "accesskit_macos"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd3b6ae1eabbfbced10e840fd3fce8a93ae84f174b3e4ba892ab7bcb42e477a7"
+dependencies = [
+ "accesskit",
+ "accesskit_consumer",
+ "objc2 0.3.0-beta.3.patch-leaks.3",
+ "once_cell",
+]
+
+[[package]]
+name = "accesskit_windows"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afcae27ec0974fc7c3b0b318783be89fd1b2e66dd702179fe600166a38ff4a0b"
+dependencies = [
+ "accesskit",
+ "accesskit_consumer",
+ "once_cell",
+ "paste",
+ "static_assertions",
+ "windows 0.48.0",
+]
+
+[[package]]
+name = "accesskit_winit"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45f8f7c9f66d454d5fd8e344c8c8c7324b57194e1041b955519fc58a01e77a25"
+dependencies = [
+ "accesskit",
+ "accesskit_macos",
+ "accesskit_windows",
+ "raw-window-handle 0.6.0",
+ "winit",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "ahash"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f"
+dependencies = [
+ "cfg-if",
+ "getrandom",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
+
+[[package]]
+name = "alsa"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2562ad8dcf0f789f65c6fdaad8a8a9708ed6b488e649da28c01656ad66b8b47"
+dependencies = [
+ "alsa-sys",
+ "bitflags 1.3.2",
+ "libc",
+ "nix 0.24.3",
+]
+
+[[package]]
+name = "alsa-sys"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527"
+dependencies = [
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "android-activity"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289"
+dependencies = [
+ "android-properties",
+ "bitflags 2.4.2",
+ "cc",
+ "cesu8",
+ "jni 0.21.1",
+ "jni-sys",
+ "libc",
+ "log",
+ "ndk 0.8.0",
+ "ndk-context",
+ "ndk-sys 0.5.0+25.2.9519653",
+ "num_enum 0.7.2",
+ "thiserror",
+]
+
+[[package]]
+name = "android-properties"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
+
+[[package]]
+name = "android_log-sys"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "approx"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "arrayref"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
+
+[[package]]
+name = "as-raw-xcb-connection"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
+
+[[package]]
+name = "ash"
+version = "0.37.3+1.3.251"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a"
+dependencies = [
+ "libloading 0.7.4",
+]
+
+[[package]]
+name = "async-broadcast"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b"
+dependencies = [
+ "event-listener 2.5.3",
+ "futures-core",
+]
+
+[[package]]
+name = "async-channel"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3"
+dependencies = [
+ "concurrent-queue",
+ "event-listener 5.1.0",
+ "event-listener-strategy 0.5.0",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-executor"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c"
+dependencies = [
+ "async-lock",
+ "async-task",
+ "concurrent-queue",
+ "fastrand",
+ "futures-lite",
+ "slab",
+]
+
+[[package]]
+name = "async-fs"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc19683171f287921f2405677dd2ed2549c3b3bda697a563ebc3a121ace2aba1"
+dependencies = [
+ "async-lock",
+ "blocking",
+ "futures-lite",
+]
+
+[[package]]
+name = "async-lock"
+version = "3.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b"
+dependencies = [
+ "event-listener 4.0.3",
+ "event-listener-strategy 0.4.0",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-task"
+version = "4.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799"
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "base64"
+version = "0.21.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
+
+[[package]]
+name = "bevy"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "611dd99f412e862610adb43e2243b16436c6d8009f6d9dbe8ce3d6d840b34029"
+dependencies = [
+ "bevy_internal",
+]
+
+[[package]]
+name = "bevy_a11y"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bf80cd6d0dca4073f9b34b16f1d187a4caa035fd841892519431783bbc9e287"
+dependencies = [
+ "accesskit",
+ "bevy_app",
+ "bevy_derive",
+ "bevy_ecs",
+]
+
+[[package]]
+name = "bevy_animation"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa4ef4c35533df3f0c4e938cf6a831456ea563775bab799336f74331140c7665"
+dependencies = [
+ "bevy_app",
+ "bevy_asset",
+ "bevy_core",
+ "bevy_ecs",
+ "bevy_hierarchy",
+ "bevy_math",
+ "bevy_reflect",
+ "bevy_render",
+ "bevy_time",
+ "bevy_transform",
+ "bevy_utils",
+]
+
+[[package]]
+name = "bevy_app"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8bce3544afc010ffed39c136f6d5a9322d20d38df1394d468ba9106caa0434cb"
+dependencies = [
+ "bevy_derive",
+ "bevy_ecs",
+ "bevy_reflect",
+ "bevy_tasks",
+ "bevy_utils",
+ "downcast-rs",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "bevy_asset"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac185d8e29c7eb0194f8aae7af3f7234f7ca7a448293be1d3d0d8fef435f65ec"
+dependencies = [
+ "async-broadcast",
+ "async-fs",
+ "async-lock",
+ "bevy_app",
+ "bevy_asset_macros",
+ "bevy_ecs",
+ "bevy_log",
+ "bevy_reflect",
+ "bevy_tasks",
+ "bevy_utils",
+ "bevy_winit",
+ "blake3",
+ "crossbeam-channel",
+ "downcast-rs",
+ "futures-io",
+ "futures-lite",
+ "js-sys",
+ "parking_lot",
+ "ron",
+ "serde",
+ "thiserror",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "bevy_asset_macros"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb82d1aac8251378c45a8d0ad788d1bf75f54db28c1750f84f1fd7c00127927a"
+dependencies = [
+ "bevy_macro_utils",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "bevy_audio"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4fe7f952e5e0a343fbde43180db7b8e719ad78594480c91b26876623944a3a1"
+dependencies = [
+ "bevy_app",
+ "bevy_asset",
+ "bevy_derive",
+ "bevy_ecs",
+ "bevy_math",
+ "bevy_reflect",
+ "bevy_transform",
+ "bevy_utils",
+ "oboe",
+ "rodio",
+]
+
+[[package]]
+name = "bevy_core"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7b1b340b8d08f48ecd51b97589d261f5023a7b073d25e300382c49146524103"
+dependencies = [
+ "bevy_app",
+ "bevy_ecs",
+ "bevy_math",
+ "bevy_reflect",
+ "bevy_tasks",
+ "bevy_utils",
+ "bytemuck",
+]
+
+[[package]]
+name = "bevy_core_pipeline"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "626a5aaadbdd69eae020c5856575d2d0113423ae1ae1351377e20956d940052c"
+dependencies = [
+ "bevy_app",
+ "bevy_asset",
+ "bevy_core",
+ "bevy_derive",
+ "bevy_ecs",
+ "bevy_log",
+ "bevy_math",
+ "bevy_reflect",
+ "bevy_render",
+ "bevy_transform",
+ "bevy_utils",
+ "bitflags 2.4.2",
+ "radsort",
+ "serde",
+]
+
+[[package]]
+name = "bevy_derive"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "028ae2a34678055185d7f1beebb1ebe6a8dcf3733e139e4ee1383a7f29ae8ba6"
+dependencies = [
+ "bevy_macro_utils",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "bevy_diagnostic"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01a104acfdc5280accd01a3524810daf3bda72924e3da0c8a9ec816a57eef4e3"
+dependencies = [
+ "bevy_app",
+ "bevy_core",
+ "bevy_ecs",
+ "bevy_log",
+ "bevy_time",
+ "bevy_utils",
+ "const-fnv1a-hash",
+ "sysinfo",
+]
+
+[[package]]
+name = "bevy_ecs"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b85406d5febbbdbcac4444ef61cd9a816f2f025ed692a3fc5439a32153070304"
+dependencies = [
+ "async-channel",
+ "bevy_ecs_macros",
+ "bevy_ptr",
+ "bevy_reflect",
+ "bevy_tasks",
+ "bevy_utils",
+ "downcast-rs",
+ "fixedbitset",
+ "rustc-hash",
+ "serde",
+ "thiserror",
+ "thread_local",
+]
+
+[[package]]
+name = "bevy_ecs_macros"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3ce4b65d7c5f1990e729df75cec2ea6e2241b4a0c37b31c281a04c59c11b7b"
+dependencies = [
+ "bevy_macro_utils",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "bevy_encase_derive"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c3d301922e76b16819e17c8cc43b34e92c13ccd06ad19dfa3e52a91a0e13e5c"
+dependencies = [
+ "bevy_macro_utils",
+ "encase_derive_impl",
+]
+
+[[package]]
+name = "bevy_gilrs"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96364a1875ee4545fcf825c78dc065ddb9a3b2a509083ef11142f9de0eb8aa17"
+dependencies = [
+ "bevy_app",
+ "bevy_ecs",
+ "bevy_input",
+ "bevy_log",
+ "bevy_time",
+ "bevy_utils",
+ "gilrs",
+ "thiserror",
+]
+
+[[package]]
+name = "bevy_gizmos"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdca80b7b4db340eb666d69374a0195b3935759120d0b990fcef8b27d0fb3680"
+dependencies = [
+ "bevy_app",
+ "bevy_asset",
+ "bevy_core",
+ "bevy_core_pipeline",
+ "bevy_ecs",
+ "bevy_gizmos_macros",
+ "bevy_log",
+ "bevy_math",
+ "bevy_pbr",
+ "bevy_reflect",
+ "bevy_render",
+ "bevy_sprite",
+ "bevy_transform",
+ "bevy_utils",
+]
+
+[[package]]
+name = "bevy_gizmos_macros"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a949eb8b4538a6e4d875321cda2b63dc0fb0317cf18c8245ca5a32f24f6d26d"
+dependencies = [
+ "bevy_macro_utils",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "bevy_gltf"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "031d0c2a7c0353bb9ac08a5130e58b9a2de3cdaa3c31b5da00b22a9e4732a155"
+dependencies = [
+ "base64",
+ "bevy_animation",
+ "bevy_app",
+ "bevy_asset",
+ "bevy_core",
+ "bevy_core_pipeline",
+ "bevy_ecs",
+ "bevy_hierarchy",
+ "bevy_log",
+ "bevy_math",
+ "bevy_pbr",
+ "bevy_reflect",
+ "bevy_render",
+ "bevy_scene",
+ "bevy_tasks",
+ "bevy_transform",
+ "bevy_utils",
+ "gltf",
+ "percent-encoding",
+ "serde",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
+name = "bevy_hierarchy"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9f9f843e43d921f07658c24eae74285efc7a335c87998596f3f365155320c69"
+dependencies = [
+ "bevy_app",
+ "bevy_core",
+ "bevy_ecs",
+ "bevy_log",
+ "bevy_reflect",
+ "bevy_utils",
+]
+
+[[package]]
+name = "bevy_input"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9cb5b2f3747ffb00cf7e3d6b52f7384476921cd31f0cfd3d1ddff31f83d9252"
+dependencies = [
+ "bevy_app",
+ "bevy_ecs",
+ "bevy_math",
+ "bevy_reflect",
+ "bevy_utils",
+ "smol_str",
+ "thiserror",
+]
+
+[[package]]
+name = "bevy_internal"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7af89c7083830b1d65fcf0260c3d2537c397fe8ce871471b6e97198a4704f23e"
+dependencies = [
+ "bevy_a11y",
+ "bevy_animation",
+ "bevy_app",
+ "bevy_asset",
+ "bevy_audio",
+ "bevy_core",
+ "bevy_core_pipeline",
+ "bevy_derive",
+ "bevy_diagnostic",
+ "bevy_ecs",
+ "bevy_gilrs",
+ "bevy_gizmos",
+ "bevy_gltf",
+ "bevy_hierarchy",
+ "bevy_input",
+ "bevy_log",
+ "bevy_math",
+ "bevy_pbr",
+ "bevy_ptr",
+ "bevy_reflect",
+ "bevy_render",
+ "bevy_scene",
+ "bevy_sprite",
+ "bevy_tasks",
+ "bevy_text",
+ "bevy_time",
+ "bevy_transform",
+ "bevy_ui",
+ "bevy_utils",
+ "bevy_window",
+ "bevy_winit",
+]
+
+[[package]]
+name = "bevy_log"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfd5bcc3531f8008897fb03cc8751b86d0d29ef94f8fd38b422f9603b7ae80d0"
+dependencies = [
+ "android_log-sys",
+ "bevy_app",
+ "bevy_ecs",
+ "bevy_utils",
+ "console_error_panic_hook",
+ "tracing-log 0.1.4",
+ "tracing-subscriber",
+ "tracing-wasm",
+]
+
+[[package]]
+name = "bevy_macro_utils"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac4401c25b197e7c1455a4875a90b61bba047a9e8d290ce029082c818ab1a21c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rustc-hash",
+ "syn 2.0.50",
+ "toml_edit 0.21.1",
+]
+
+[[package]]
+name = "bevy_math"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f312b1b8aa6d3965b65040b08e33efac030db3071f20b44f9da9c4c3dfcaf76"
+dependencies = [
+ "glam",
+ "serde",
+]
+
+[[package]]
+name = "bevy_mikktspace"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3075c01f2b1799945892d5310fc1836e47c045dfe6af5878a304a475931a0c5f"
+dependencies = [
+ "glam",
+]
+
+[[package]]
+name = "bevy_pbr"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31c72bf12e50ff76c9ed9a7c51ceb88bfea9865d00f24d95b12344fffe1e270"
+dependencies = [
+ "bevy_app",
+ "bevy_asset",
+ "bevy_core_pipeline",
+ "bevy_derive",
+ "bevy_ecs",
+ "bevy_math",
+ "bevy_reflect",
+ "bevy_render",
+ "bevy_transform",
+ "bevy_utils",
+ "bevy_window",
+ "bitflags 2.4.2",
+ "bytemuck",
+ "fixedbitset",
+ "radsort",
+ "smallvec",
+ "thread_local",
+]
+
+[[package]]
+name = "bevy_ptr"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86afa4a88ee06b10fe1e6f28a796ba2eedd16804717cbbb911df0cbb0cd6677b"
+
+[[package]]
+name = "bevy_reflect"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "133dfab8d403d0575eeed9084e85780bbb449dcf75dd687448439117789b40a2"
+dependencies = [
+ "bevy_math",
+ "bevy_ptr",
+ "bevy_reflect_derive",
+ "bevy_utils",
+ "downcast-rs",
+ "erased-serde",
+ "glam",
+ "serde",
+ "smol_str",
+ "thiserror",
+]
+
+[[package]]
+name = "bevy_reflect_derive"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce1679a4dfdb2c9ff24ca590914c3cec119d7c9e1b56fa637776913acc030386"
+dependencies = [
+ "bevy_macro_utils",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+ "uuid",
+]
+
+[[package]]
+name = "bevy_render"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3b194b7029b7541ef9206ac3cb696d3cb37f70bd3260d293fc00d378547e892"
+dependencies = [
+ "async-channel",
+ "bevy_app",
+ "bevy_asset",
+ "bevy_core",
+ "bevy_derive",
+ "bevy_ecs",
+ "bevy_encase_derive",
+ "bevy_hierarchy",
+ "bevy_log",
+ "bevy_math",
+ "bevy_mikktspace",
+ "bevy_reflect",
+ "bevy_render_macros",
+ "bevy_tasks",
+ "bevy_time",
+ "bevy_transform",
+ "bevy_utils",
+ "bevy_window",
+ "bitflags 2.4.2",
+ "bytemuck",
+ "codespan-reporting",
+ "downcast-rs",
+ "encase",
+ "futures-lite",
+ "hexasphere",
+ "image",
+ "js-sys",
+ "ktx2",
+ "naga",
+ "naga_oil",
+ "ruzstd",
+ "serde",
+ "thiserror",
+ "thread_local",
+ "wasm-bindgen",
+ "web-sys",
+ "wgpu",
+]
+
+[[package]]
+name = "bevy_render_macros"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4aa6d99b50375bb7f63be2c3055dfe2f926f7b3c4db108bb0b1181b4f02766aa"
+dependencies = [
+ "bevy_macro_utils",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "bevy_scene"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c3c82eaff0b22949183a75a7e2d7fc4ece808235918b34c5b282aab52c3563a"
+dependencies = [
+ "bevy_app",
+ "bevy_asset",
+ "bevy_derive",
+ "bevy_ecs",
+ "bevy_hierarchy",
+ "bevy_reflect",
+ "bevy_render",
+ "bevy_transform",
+ "bevy_utils",
+ "serde",
+ "thiserror",
+ "uuid",
+]
+
+[[package]]
+name = "bevy_sprite"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ea977d7d7c48fc4ba283d449f09528c4e70db17c9048e32e99ecd9890d72223"
+dependencies = [
+ "bevy_app",
+ "bevy_asset",
+ "bevy_core_pipeline",
+ "bevy_derive",
+ "bevy_ecs",
+ "bevy_log",
+ "bevy_math",
+ "bevy_reflect",
+ "bevy_render",
+ "bevy_transform",
+ "bevy_utils",
+ "bitflags 2.4.2",
+ "bytemuck",
+ "fixedbitset",
+ "guillotiere",
+ "radsort",
+ "rectangle-pack",
+ "thiserror",
+]
+
+[[package]]
+name = "bevy_tasks"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b20f243f6fc4c4ba10c2dbff891e947ddae947bb20b263f43e023558b35294bd"
+dependencies = [
+ "async-channel",
+ "async-executor",
+ "async-task",
+ "concurrent-queue",
+ "futures-lite",
+ "wasm-bindgen-futures",
+]
+
+[[package]]
+name = "bevy_text"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "006990d27551dbc339774178e833290952511621662fd5ca23a4e6e922ab2d9f"
+dependencies = [
+ "ab_glyph",
+ "bevy_app",
+ "bevy_asset",
+ "bevy_ecs",
+ "bevy_math",
+ "bevy_reflect",
+ "bevy_render",
+ "bevy_sprite",
+ "bevy_transform",
+ "bevy_utils",
+ "bevy_window",
+ "glyph_brush_layout",
+ "serde",
+ "thiserror",
+]
+
+[[package]]
+name = "bevy_time"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9738901b6b251d2c9250542af7002d6f671401fc3b74504682697c5ec822f210"
+dependencies = [
+ "bevy_app",
+ "bevy_ecs",
+ "bevy_reflect",
+ "bevy_utils",
+ "crossbeam-channel",
+ "thiserror",
+]
+
+[[package]]
+name = "bevy_transform"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba73744a95bc4b8683e91cea3e79b1ad0844c1d677f31fbbc1814c79a5b4f8f0"
+dependencies = [
+ "bevy_app",
+ "bevy_ecs",
+ "bevy_hierarchy",
+ "bevy_math",
+ "bevy_reflect",
+ "thiserror",
+]
+
+[[package]]
+name = "bevy_ui"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fafe872906bac6d7fc8ecff166f56b4253465b2895ed88801499aa113548ccc6"
+dependencies = [
+ "bevy_a11y",
+ "bevy_app",
+ "bevy_asset",
+ "bevy_core_pipeline",
+ "bevy_derive",
+ "bevy_ecs",
+ "bevy_hierarchy",
+ "bevy_input",
+ "bevy_log",
+ "bevy_math",
+ "bevy_reflect",
+ "bevy_render",
+ "bevy_sprite",
+ "bevy_text",
+ "bevy_transform",
+ "bevy_utils",
+ "bevy_window",
+ "bytemuck",
+ "taffy",
+ "thiserror",
+]
+
+[[package]]
+name = "bevy_utils"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94a06aca1c1863606416b892f4c79e300dbc6211b6690953269051a431c2cca0"
+dependencies = [
+ "ahash",
+ "bevy_utils_proc_macros",
+ "getrandom",
+ "hashbrown",
+ "nonmax",
+ "petgraph",
+ "smallvec",
+ "thiserror",
+ "tracing",
+ "uuid",
+ "web-time",
+]
+
+[[package]]
+name = "bevy_utils_proc_macros"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31ae98e9c0c08b0f5c90e22cd713201f759b98d4fd570b99867a695f8641859a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "bevy_window"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb627efd7622a61398ac0d3674f93c997cffe16f13c59fb8ae8a05c9e28de961"
+dependencies = [
+ "bevy_a11y",
+ "bevy_app",
+ "bevy_ecs",
+ "bevy_input",
+ "bevy_math",
+ "bevy_reflect",
+ "bevy_utils",
+ "raw-window-handle 0.6.0",
+ "smol_str",
+]
+
+[[package]]
+name = "bevy_winit"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55105324a201941ae587790f83f6d9caa327e0baa0205558ec41e5ee05a1f703"
+dependencies = [
+ "accesskit_winit",
+ "approx",
+ "bevy_a11y",
+ "bevy_app",
+ "bevy_derive",
+ "bevy_ecs",
+ "bevy_hierarchy",
+ "bevy_input",
+ "bevy_math",
+ "bevy_tasks",
+ "bevy_utils",
+ "bevy_window",
+ "crossbeam-channel",
+ "raw-window-handle 0.6.0",
+ "wasm-bindgen",
+ "web-sys",
+ "winit",
+]
+
+[[package]]
+name = "bindgen"
+version = "0.69.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
+dependencies = [
+ "bitflags 2.4.2",
+ "cexpr",
+ "clang-sys",
+ "itertools",
+ "lazy_static",
+ "lazycell",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "bit-set"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
+dependencies = [
+ "bit-vec",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "blake3"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "cc",
+ "cfg-if",
+ "constant_time_eq",
+]
+
+[[package]]
+name = "block"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
+
+[[package]]
+name = "block-sys"
+version = "0.1.0-beta.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146"
+dependencies = [
+ "objc-sys 0.2.0-beta.2",
+]
+
+[[package]]
+name = "block-sys"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7"
+dependencies = [
+ "objc-sys 0.3.2",
+]
+
+[[package]]
+name = "block2"
+version = "0.2.0-alpha.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42"
+dependencies = [
+ "block-sys 0.1.0-beta.1",
+ "objc2-encode 2.0.0-pre.2",
+]
+
+[[package]]
+name = "block2"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68"
+dependencies = [
+ "block-sys 0.2.1",
+ "objc2 0.4.1",
+]
+
+[[package]]
+name = "blocking"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118"
+dependencies = [
+ "async-channel",
+ "async-lock",
+ "async-task",
+ "fastrand",
+ "futures-io",
+ "futures-lite",
+ "piper",
+ "tracing",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.15.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b"
+
+[[package]]
+name = "bytemuck"
+version = "1.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
+
+[[package]]
+name = "calloop"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298"
+dependencies = [
+ "bitflags 2.4.2",
+ "log",
+ "polling",
+ "rustix",
+ "slab",
+ "thiserror",
+]
+
+[[package]]
+name = "calloop-wayland-source"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02"
+dependencies = [
+ "calloop",
+ "rustix",
+ "wayland-backend",
+ "wayland-client",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.88"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cesu8"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
+
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+
+[[package]]
+name = "clang-sys"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading 0.8.1",
+]
+
+[[package]]
+name = "codespan-reporting"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
+dependencies = [
+ "termcolor",
+ "unicode-width",
+]
+
+[[package]]
+name = "color_quant"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
+
+[[package]]
+name = "com"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6"
+dependencies = [
+ "com_macros",
+]
+
+[[package]]
+name = "com_macros"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5"
+dependencies = [
+ "com_macros_support",
+ "proc-macro2",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "com_macros_support"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "combine"
+version = "4.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
+dependencies = [
+ "bytes",
+ "memchr",
+]
+
+[[package]]
+name = "concurrent-queue"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "console_error_panic_hook"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "const-fnv1a-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca"
+
+[[package]]
+name = "const_panic"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6051f239ecec86fde3410901ab7860d458d160371533842974fc61f96d15879b"
+
+[[package]]
+name = "const_soft_float"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87ca1caa64ef4ed453e68bb3db612e51cf1b2f5b871337f0fcab1c8f87cc3dff"
+
+[[package]]
+name = "constant_time_eq"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
+
+[[package]]
+name = "constgebra"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edd23e864550e6dafc1e41ac78ce4f1ccddc8672b40c403524a04ff3f0518420"
+dependencies = [
+ "const_soft_float",
+]
+
+[[package]]
+name = "convert_case"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
+
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+
+[[package]]
+name = "core-graphics"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "core-graphics-types",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics-types"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "libc",
+]
+
+[[package]]
+name = "coreaudio-rs"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation-sys",
+ "coreaudio-sys",
+]
+
+[[package]]
+name = "coreaudio-sys"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f01585027057ff5f0a5bf276174ae4c1594a2c5bde93d5f46a016d76270f5a9"
+dependencies = [
+ "bindgen",
+]
+
+[[package]]
+name = "cpal"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d959d90e938c5493000514b446987c07aed46c668faaa7d34d6c7a67b1a578c"
+dependencies = [
+ "alsa",
+ "core-foundation-sys",
+ "coreaudio-rs",
+ "dasp_sample",
+ "jni 0.19.0",
+ "js-sys",
+ "libc",
+ "mach2",
+ "ndk 0.7.0",
+ "ndk-context",
+ "oboe",
+ "once_cell",
+ "parking_lot",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "windows 0.46.0",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
+
+[[package]]
+name = "cursor-icon"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
+
+[[package]]
+name = "d3d12"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e3d747f100290a1ca24b752186f61f6637e1deffe3bf6320de6fcb29510a307"
+dependencies = [
+ "bitflags 2.4.2",
+ "libloading 0.8.1",
+ "winapi",
+]
+
+[[package]]
+name = "dasp_sample"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
+
+[[package]]
+name = "data-encoding"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
+
+[[package]]
+name = "derive_more"
+version = "0.99.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "dispatch"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
+
+[[package]]
+name = "dlib"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
+dependencies = [
+ "libloading 0.8.1",
+]
+
+[[package]]
+name = "downcast-rs"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
+
+[[package]]
+name = "either"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
+
+[[package]]
+name = "encase"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95ed933078d2e659745df651f4c180511cd582e5b9414ff896e7d50d207e3103"
+dependencies = [
+ "const_panic",
+ "encase_derive",
+ "glam",
+ "thiserror",
+]
+
+[[package]]
+name = "encase_derive"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4ce1449c7d19eba6cc0abd231150ad81620a8dce29601d7f8d236e5d431d72a"
+dependencies = [
+ "encase_derive_impl",
+]
+
+[[package]]
+name = "encase_derive_impl"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92959a9e8d13eaa13b8ae8c7b583c3bf1669ca7a8e7708a088d12587ba86effc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "erased-serde"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "388979d208a049ffdfb22fa33b9c81942215b940910bccfe258caeb25d125cb3"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "errno"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "euclid"
+version = "0.22.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f253bc5c813ca05792837a0ff4b3a580336b224512d48f7eda1d7dd9210787"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "event-listener"
+version = "2.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
+
+[[package]]
+name = "event-listener"
+version = "4.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "event-listener"
+version = "5.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7ad6fd685ce13acd6d9541a30f6db6567a7a24c9ffd4ba2955d29e3f22c8b27"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "event-listener-strategy"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
+dependencies = [
+ "event-listener 4.0.3",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "event-listener-strategy"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291"
+dependencies = [
+ "event-listener 5.1.0",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
+
+[[package]]
+name = "fdeflate"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645"
+dependencies = [
+ "simd-adler32",
+]
+
+[[package]]
+name = "fixedbitset"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
+
+[[package]]
+name = "flate2"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foreign-types"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
+dependencies = [
+ "foreign-types-macros",
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-macros"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
+
+[[package]]
+name = "futures-core"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+
+[[package]]
+name = "futures-io"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+
+[[package]]
+name = "futures-lite"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba"
+dependencies = [
+ "fastrand",
+ "futures-core",
+ "futures-io",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "gethostname"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
+dependencies = [
+ "libc",
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "gilrs"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8b2e57a9cb946b5d04ae8638c5f554abb5a9f82c4c950fd5b1fee6d119592fb"
+dependencies = [
+ "fnv",
+ "gilrs-core",
+ "log",
+ "uuid",
+ "vec_map",
+]
+
+[[package]]
+name = "gilrs-core"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0af1827b7dd2f36d740ae804c1b3ea0d64c12533fb61ff91883005143a0e8c5a"
+dependencies = [
+ "core-foundation",
+ "inotify",
+ "io-kit-sys",
+ "js-sys",
+ "libc",
+ "libudev-sys",
+ "log",
+ "nix 0.27.1",
+ "uuid",
+ "vec_map",
+ "wasm-bindgen",
+ "web-sys",
+ "windows 0.52.0",
+]
+
+[[package]]
+name = "gl_generator"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
+dependencies = [
+ "khronos_api",
+ "log",
+ "xml-rs",
+]
+
+[[package]]
+name = "glam"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3"
+dependencies = [
+ "bytemuck",
+ "serde",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "glow"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1"
+dependencies = [
+ "js-sys",
+ "slotmap",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "gltf"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b78f069cf941075835822953c345b9e1edd67ae347b81ace3aea9de38c2ef33"
+dependencies = [
+ "byteorder",
+ "gltf-json",
+ "lazy_static",
+ "serde_json",
+]
+
+[[package]]
+name = "gltf-derive"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "438ffe1a5540d75403feaf23636b164e816e93f6f03131674722b3886ce32a57"
+dependencies = [
+ "inflections",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "gltf-json"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "655951ba557f2bc69ea4b0799446bae281fa78efae6319968bdd2c3e9a06d8e1"
+dependencies = [
+ "gltf-derive",
+ "serde",
+ "serde_derive",
+ "serde_json",
+]
+
+[[package]]
+name = "glutin_wgl_sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead"
+dependencies = [
+ "gl_generator",
+]
+
+[[package]]
+name = "glyph_brush_layout"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc32c2334f00ca5ac3695c5009ae35da21da8c62d255b5b96d56e2597a637a38"
+dependencies = [
+ "ab_glyph",
+ "approx",
+ "xi-unicode",
+]
+
+[[package]]
+name = "gpu-alloc"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171"
+dependencies = [
+ "bitflags 2.4.2",
+ "gpu-alloc-types",
+]
+
+[[package]]
+name = "gpu-alloc-types"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4"
+dependencies = [
+ "bitflags 2.4.2",
+]
+
+[[package]]
+name = "gpu-allocator"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884"
+dependencies = [
+ "log",
+ "presser",
+ "thiserror",
+ "winapi",
+ "windows 0.52.0",
+]
+
+[[package]]
+name = "gpu-descriptor"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c"
+dependencies = [
+ "bitflags 2.4.2",
+ "gpu-descriptor-types",
+ "hashbrown",
+]
+
+[[package]]
+name = "gpu-descriptor-types"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c"
+dependencies = [
+ "bitflags 2.4.2",
+]
+
+[[package]]
+name = "grid"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eec1c01eb1de97451ee0d60de7d81cf1e72aabefb021616027f3d1c3ec1c723c"
+
+[[package]]
+name = "guillotiere"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782"
+dependencies = [
+ "euclid",
+ "svg_fmt",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+dependencies = [
+ "ahash",
+ "allocator-api2",
+ "serde",
+]
+
+[[package]]
+name = "hassle-rs"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890"
+dependencies = [
+ "bitflags 2.4.2",
+ "com",
+ "libc",
+ "libloading 0.8.1",
+ "thiserror",
+ "widestring",
+ "winapi",
+]
+
+[[package]]
+name = "hexasphere"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f33ddb7f7143d9e703c072e88b98cd8b9719f174137a671429351bd2ee43c02a"
+dependencies = [
+ "constgebra",
+ "glam",
+]
+
+[[package]]
+name = "hexf-parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
+
+[[package]]
+name = "icrate"
+version = "0.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319"
+dependencies = [
+ "block2 0.3.0",
+ "dispatch",
+ "objc2 0.4.1",
+]
+
+[[package]]
+name = "image"
+version = "0.24.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
+dependencies = [
+ "bytemuck",
+ "byteorder",
+ "color_quant",
+ "num-traits",
+ "png",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "inflections"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a"
+
+[[package]]
+name = "inotify"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdd168d97690d0b8c412d6b6c10360277f4d7ee495c5d0d5d5fe0854923255cc"
+dependencies = [
+ "bitflags 1.3.2",
+ "inotify-sys",
+ "libc",
+]
+
+[[package]]
+name = "inotify-sys"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "io-kit-sys"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4769cb30e5dcf1710fc6730d3e94f78c47723a014a567de385e113c737394640"
+dependencies = [
+ "core-foundation-sys",
+ "mach2",
+]
+
+[[package]]
+name = "itertools"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
+
+[[package]]
+name = "jni"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec"
+dependencies = [
+ "cesu8",
+ "combine",
+ "jni-sys",
+ "log",
+ "thiserror",
+ "walkdir",
+]
+
+[[package]]
+name = "jni"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c"
+dependencies = [
+ "cesu8",
+ "combine",
+ "jni-sys",
+ "log",
+ "thiserror",
+ "walkdir",
+]
+
+[[package]]
+name = "jni"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
+dependencies = [
+ "cesu8",
+ "cfg-if",
+ "combine",
+ "jni-sys",
+ "log",
+ "thiserror",
+ "walkdir",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
+
+[[package]]
+name = "js-sys"
+version = "0.3.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "khronos-egl"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76"
+dependencies = [
+ "libc",
+ "libloading 0.8.1",
+ "pkg-config",
+]
+
+[[package]]
+name = "khronos_api"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
+
+[[package]]
+name = "ktx2"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87d65e08a9ec02e409d27a0139eaa6b9756b4d81fe7cde71f6941a83730ce838"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
+[[package]]
+name = "lewton"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030"
+dependencies = [
+ "byteorder",
+ "ogg",
+ "tinyvec",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.153"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+
+[[package]]
+name = "libloading"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
+
+[[package]]
+name = "libloading"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
+dependencies = [
+ "cfg-if",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "libredox"
+version = "0.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607"
+dependencies = [
+ "bitflags 2.4.2",
+ "libc",
+ "redox_syscall 0.4.1",
+]
+
+[[package]]
+name = "libudev-sys"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324"
+dependencies = [
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+
+[[package]]
+name = "lock_api"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "mach2"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "malloc_buf"
+version = "0.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "matchers"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
+dependencies = [
+ "regex-automata 0.1.10",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+
+[[package]]
+name = "memmap2"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "metal"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25"
+dependencies = [
+ "bitflags 2.4.2",
+ "block",
+ "core-graphics-types",
+ "foreign-types",
+ "log",
+ "objc",
+ "paste",
+]
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
+dependencies = [
+ "adler",
+ "simd-adler32",
+]
+
+[[package]]
+name = "naga"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8878eb410fc90853da3908aebfe61d73d26d4437ef850b70050461f939509899"
+dependencies = [
+ "bit-set",
+ "bitflags 2.4.2",
+ "codespan-reporting",
+ "hexf-parse",
+ "indexmap",
+ "log",
+ "num-traits",
+ "pp-rs",
+ "rustc-hash",
+ "spirv",
+ "termcolor",
+ "thiserror",
+ "unicode-xid",
+]
+
+[[package]]
+name = "naga_oil"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ea62ae0f2787456afca7209ca180522b41f00cbe159ee369eba1e07d365cd1"
+dependencies = [
+ "bit-set",
+ "codespan-reporting",
+ "data-encoding",
+ "indexmap",
+ "naga",
+ "once_cell",
+ "regex",
+ "regex-syntax 0.8.2",
+ "rustc-hash",
+ "thiserror",
+ "tracing",
+ "unicode-ident",
+]
+
+[[package]]
+name = "ndk"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0"
+dependencies = [
+ "bitflags 1.3.2",
+ "jni-sys",
+ "ndk-sys 0.4.1+23.1.7779620",
+ "num_enum 0.5.11",
+ "raw-window-handle 0.5.2",
+ "thiserror",
+]
+
+[[package]]
+name = "ndk"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7"
+dependencies = [
+ "bitflags 2.4.2",
+ "jni-sys",
+ "log",
+ "ndk-sys 0.5.0+25.2.9519653",
+ "num_enum 0.7.2",
+ "raw-window-handle 0.6.0",
+ "thiserror",
+]
+
+[[package]]
+name = "ndk-context"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
+
+[[package]]
+name = "ndk-sys"
+version = "0.4.1+23.1.7779620"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3"
+dependencies = [
+ "jni-sys",
+]
+
+[[package]]
+name = "ndk-sys"
+version = "0.5.0+25.2.9519653"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691"
+dependencies = [
+ "jni-sys",
+]
+
+[[package]]
+name = "nix"
+version = "0.24.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
+dependencies = [
+ "bitflags 1.3.2",
+ "cfg-if",
+ "libc",
+]
+
+[[package]]
+name = "nix"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
+dependencies = [
+ "bitflags 2.4.2",
+ "cfg-if",
+ "libc",
+]
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "nonmax"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51"
+
+[[package]]
+name = "ntapi"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "nu-ansi-term"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
+dependencies = [
+ "overload",
+ "winapi",
+]
+
+[[package]]
+name = "num-derive"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
+dependencies = [
+ "num_enum_derive 0.5.11",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
+dependencies = [
+ "num_enum_derive 0.7.2",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
+dependencies = [
+ "proc-macro-crate 1.3.1",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
+dependencies = [
+ "proc-macro-crate 3.1.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "objc"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
+dependencies = [
+ "malloc_buf",
+ "objc_exception",
+]
+
+[[package]]
+name = "objc-sys"
+version = "0.2.0-beta.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7"
+
+[[package]]
+name = "objc-sys"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7c71324e4180d0899963fc83d9d241ac39e699609fc1025a850aadac8257459"
+
+[[package]]
+name = "objc2"
+version = "0.3.0-beta.3.patch-leaks.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468"
+dependencies = [
+ "block2 0.2.0-alpha.6",
+ "objc-sys 0.2.0-beta.2",
+ "objc2-encode 2.0.0-pre.2",
+]
+
+[[package]]
+name = "objc2"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d"
+dependencies = [
+ "objc-sys 0.3.2",
+ "objc2-encode 3.0.0",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "2.0.0-pre.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512"
+dependencies = [
+ "objc-sys 0.2.0-beta.2",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666"
+
+[[package]]
+name = "objc_exception"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "oboe"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8868cc237ee02e2d9618539a23a8d228b9bb3fc2e7a5b11eed3831de77c395d0"
+dependencies = [
+ "jni 0.20.0",
+ "ndk 0.7.0",
+ "ndk-context",
+ "num-derive",
+ "num-traits",
+ "oboe-sys",
+]
+
+[[package]]
+name = "oboe-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f44155e7fb718d3cfddcf70690b2b51ac4412f347cd9e4fbe511abe9cd7b5f2"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "ogg"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
+[[package]]
+name = "orbclient"
+version = "0.3.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166"
+dependencies = [
+ "libredox",
+]
+
+[[package]]
+name = "otterhide"
+version = "0.1.0"
+dependencies = [
+ "bevy",
+ "derive_more",
+ "itertools",
+ "js-sys",
+ "rand",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "overload"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
+
+[[package]]
+name = "owned_ttf_parser"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4586edfe4c648c71797a74c84bacb32b52b212eff5dfe2bb9f2c599844023e7"
+dependencies = [
+ "ttf-parser",
+]
+
+[[package]]
+name = "parking"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall 0.4.1",
+ "smallvec",
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "petgraph"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
+dependencies = [
+ "fixedbitset",
+ "indexmap",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
+
+[[package]]
+name = "piper"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4"
+dependencies = [
+ "atomic-waker",
+ "fastrand",
+ "futures-io",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+
+[[package]]
+name = "png"
+version = "0.17.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1"
+dependencies = [
+ "bitflags 1.3.2",
+ "crc32fast",
+ "fdeflate",
+ "flate2",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "polling"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9"
+dependencies = [
+ "cfg-if",
+ "concurrent-queue",
+ "pin-project-lite",
+ "rustix",
+ "tracing",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "pp-rs"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb458bb7f6e250e6eb79d5026badc10a3ebb8f9a15d1fff0f13d17c71f4d6dee"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "presser"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa"
+
+[[package]]
+name = "proc-macro-crate"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
+dependencies = [
+ "once_cell",
+ "toml_edit 0.19.15",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
+dependencies = [
+ "toml_edit 0.21.1",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "profiling"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58"
+
+[[package]]
+name = "quick-xml"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "radsort"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17fd96390ed3feda12e1dfe2645ed587e0bea749e319333f104a33ff62f77a0b"
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "range-alloc"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab"
+
+[[package]]
+name = "raw-window-handle"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
+
+[[package]]
+name = "raw-window-handle"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544"
+
+[[package]]
+name = "rectangle-pack"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0d463f2884048e7153449a55166f91028d5b0ea53c79377099ce4e8cf0cf9bb"
+
+[[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata 0.4.5",
+ "regex-syntax 0.8.2",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
+dependencies = [
+ "regex-syntax 0.6.29",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax 0.8.2",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+
+[[package]]
+name = "renderdoc-sys"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "216080ab382b992234dda86873c18d4c48358f5cfcb70fd693d7f6f2131b628b"
+
+[[package]]
+name = "rodio"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b1bb7b48ee48471f55da122c0044fcc7600cfcc85db88240b89cb832935e611"
+dependencies = [
+ "cpal",
+ "lewton",
+]
+
+[[package]]
+name = "ron"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
+dependencies = [
+ "base64",
+ "bitflags 2.4.2",
+ "serde",
+ "serde_derive",
+]
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
+dependencies = [
+ "bitflags 2.4.2",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "ruzstd"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d"
+dependencies = [
+ "byteorder",
+ "derive_more",
+ "twox-hash",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "scoped-tls"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "sctk-adwaita"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550"
+dependencies = [
+ "ab_glyph",
+ "log",
+ "memmap2",
+ "smithay-client-toolkit",
+ "tiny-skia",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
+
+[[package]]
+name = "serde"
+version = "1.0.197"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.197"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "simd-adler32"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
+
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "slotmap"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "smithay-client-toolkit"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a"
+dependencies = [
+ "bitflags 2.4.2",
+ "calloop",
+ "calloop-wayland-source",
+ "cursor-icon",
+ "libc",
+ "log",
+ "memmap2",
+ "rustix",
+ "thiserror",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-csd-frame",
+ "wayland-cursor",
+ "wayland-protocols",
+ "wayland-protocols-wlr",
+ "wayland-scanner",
+ "xkeysym",
+]
+
+[[package]]
+name = "smol_str"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "spirv"
+version = "0.3.0+sdk-1.3.268.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
+dependencies = [
+ "bitflags 2.4.2",
+]
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "strict-num"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
+
+[[package]]
+name = "svg_fmt"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fb1df15f412ee2e9dfc1c504260fa695c1c3f10fe9f4a6ee2d2184d7d6450e2"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sysinfo"
+version = "0.30.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fb4f3438c8f6389c864e61221cbc97e9bca98b4daf39a5beb7bea660f528bb2"
+dependencies = [
+ "cfg-if",
+ "core-foundation-sys",
+ "libc",
+ "ntapi",
+ "once_cell",
+ "windows 0.52.0",
+]
+
+[[package]]
+name = "taffy"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c2287b6d7f721ada4cddf61ade5e760b2c6207df041cac9bfaa192897362fd3"
+dependencies = [
+ "arrayvec",
+ "grid",
+ "num-traits",
+ "slotmap",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+]
+
+[[package]]
+name = "tiny-skia"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "bytemuck",
+ "cfg-if",
+ "log",
+ "tiny-skia-path",
+]
+
+[[package]]
+name = "tiny-skia-path"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "strict-num",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
+
+[[package]]
+name = "toml_edit"
+version = "0.19.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "regex",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log 0.2.0",
+]
+
+[[package]]
+name = "tracing-wasm"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07"
+dependencies = [
+ "tracing",
+ "tracing-subscriber",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "ttf-parser"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4"
+
+[[package]]
+name = "twox-hash"
+version = "1.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
+dependencies = [
+ "cfg-if",
+ "static_assertions",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
+
+[[package]]
+name = "uuid"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a"
+dependencies = [
+ "getrandom",
+ "serde",
+]
+
+[[package]]
+name = "valuable"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "walkdir"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
+
+[[package]]
+name = "wayland-backend"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40"
+dependencies = [
+ "cc",
+ "downcast-rs",
+ "rustix",
+ "scoped-tls",
+ "smallvec",
+ "wayland-sys",
+]
+
+[[package]]
+name = "wayland-client"
+version = "0.31.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f"
+dependencies = [
+ "bitflags 2.4.2",
+ "rustix",
+ "wayland-backend",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-csd-frame"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
+dependencies = [
+ "bitflags 2.4.2",
+ "cursor-icon",
+ "wayland-backend",
+]
+
+[[package]]
+name = "wayland-cursor"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71ce5fa868dd13d11a0d04c5e2e65726d0897be8de247c0c5a65886e283231ba"
+dependencies = [
+ "rustix",
+ "wayland-client",
+ "xcursor",
+]
+
+[[package]]
+name = "wayland-protocols"
+version = "0.31.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4"
+dependencies = [
+ "bitflags 2.4.2",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols-plasma"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479"
+dependencies = [
+ "bitflags 2.4.2",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols-wlr"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6"
+dependencies = [
+ "bitflags 2.4.2",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-scanner"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283"
+dependencies = [
+ "proc-macro2",
+ "quick-xml",
+ "quote",
+]
+
+[[package]]
+name = "wayland-sys"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af"
+dependencies = [
+ "dlib",
+ "log",
+ "pkg-config",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.67"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-time"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "wgpu"
+version = "0.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bfe9a310dcf2e6b85f00c46059aaeaf4184caa8e29a1ecd4b7a704c3482332d"
+dependencies = [
+ "arrayvec",
+ "cfg-if",
+ "cfg_aliases",
+ "js-sys",
+ "log",
+ "naga",
+ "parking_lot",
+ "profiling",
+ "raw-window-handle 0.6.0",
+ "smallvec",
+ "static_assertions",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "wgpu-core",
+ "wgpu-hal",
+ "wgpu-types",
+]
+
+[[package]]
+name = "wgpu-core"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b15e451d4060ada0d99a64df44e4d590213496da7c4f245572d51071e8e30ed"
+dependencies = [
+ "arrayvec",
+ "bit-vec",
+ "bitflags 2.4.2",
+ "cfg_aliases",
+ "codespan-reporting",
+ "indexmap",
+ "log",
+ "naga",
+ "once_cell",
+ "parking_lot",
+ "profiling",
+ "raw-window-handle 0.6.0",
+ "rustc-hash",
+ "smallvec",
+ "thiserror",
+ "web-sys",
+ "wgpu-hal",
+ "wgpu-types",
+]
+
+[[package]]
+name = "wgpu-hal"
+version = "0.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3bb47856236bfafc0bc591a925eb036ac19cd987624a447ff353e7a7e7e6f72"
+dependencies = [
+ "android_system_properties",
+ "arrayvec",
+ "ash",
+ "bit-set",
+ "bitflags 2.4.2",
+ "block",
+ "cfg_aliases",
+ "core-graphics-types",
+ "d3d12",
+ "glow",
+ "glutin_wgl_sys",
+ "gpu-alloc",
+ "gpu-allocator",
+ "gpu-descriptor",
+ "hassle-rs",
+ "js-sys",
+ "khronos-egl",
+ "libc",
+ "libloading 0.8.1",
+ "log",
+ "metal",
+ "naga",
+ "objc",
+ "once_cell",
+ "parking_lot",
+ "profiling",
+ "range-alloc",
+ "raw-window-handle 0.6.0",
+ "renderdoc-sys",
+ "rustc-hash",
+ "smallvec",
+ "thiserror",
+ "wasm-bindgen",
+ "web-sys",
+ "wgpu-types",
+ "winapi",
+]
+
+[[package]]
+name = "wgpu-types"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "895fcbeb772bfb049eb80b2d6e47f6c9af235284e9703c96fc0218a42ffd5af2"
+dependencies = [
+ "bitflags 2.4.2",
+ "js-sys",
+ "web-sys",
+]
+
+[[package]]
+name = "widestring"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
+dependencies = [
+ "windows-targets 0.42.2",
+]
+
+[[package]]
+name = "windows"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
+dependencies = [
+ "windows-core",
+ "windows-targets 0.52.3",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets 0.52.3",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e2ee588991b9e7e6c8338edf3333fbe4da35dc72092643958ebb43f0ab2c49c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6fb8df20c9bcaa8ad6ab513f7b40104840c8867d5751126e4df3b08388d0cc7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets 0.42.2",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.3",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.3",
+ "windows_aarch64_msvc 0.52.3",
+ "windows_i686_gnu 0.52.3",
+ "windows_i686_msvc 0.52.3",
+ "windows_x86_64_gnu 0.52.3",
+ "windows_x86_64_gnullvm 0.52.3",
+ "windows_x86_64_msvc 0.52.3",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
+
+[[package]]
+name = "winit"
+version = "0.29.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c824f11941eeae66ec71111cc2674373c772f482b58939bb4066b642aa2ffcf"
+dependencies = [
+ "ahash",
+ "android-activity",
+ "atomic-waker",
+ "bitflags 2.4.2",
+ "bytemuck",
+ "calloop",
+ "cfg_aliases",
+ "core-foundation",
+ "core-graphics",
+ "cursor-icon",
+ "icrate",
+ "js-sys",
+ "libc",
+ "log",
+ "memmap2",
+ "ndk 0.8.0",
+ "ndk-sys 0.5.0+25.2.9519653",
+ "objc2 0.4.1",
+ "once_cell",
+ "orbclient",
+ "percent-encoding",
+ "raw-window-handle 0.6.0",
+ "redox_syscall 0.3.5",
+ "rustix",
+ "sctk-adwaita",
+ "smithay-client-toolkit",
+ "smol_str",
+ "unicode-segmentation",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-protocols-plasma",
+ "web-sys",
+ "web-time",
+ "windows-sys 0.48.0",
+ "x11-dl",
+ "x11rb",
+ "xkbcommon-dl",
+]
+
+[[package]]
+name = "winnow"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "x11-dl"
+version = "2.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f"
+dependencies = [
+ "libc",
+ "once_cell",
+ "pkg-config",
+]
+
+[[package]]
+name = "x11rb"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a"
+dependencies = [
+ "as-raw-xcb-connection",
+ "gethostname",
+ "libc",
+ "libloading 0.8.1",
+ "once_cell",
+ "rustix",
+ "x11rb-protocol",
+]
+
+[[package]]
+name = "x11rb-protocol"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34"
+
+[[package]]
+name = "xcursor"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911"
+
+[[package]]
+name = "xi-unicode"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a"
+
+[[package]]
+name = "xkbcommon-dl"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5"
+dependencies = [
+ "bitflags 2.4.2",
+ "dlib",
+ "log",
+ "once_cell",
+ "xkeysym",
+]
+
+[[package]]
+name = "xkeysym"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621"
+
+[[package]]
+name = "xml-rs"
+version = "0.8.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
+
+[[package]]
+name = "zerocopy"
+version = "0.7.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.50",
+]new file mode 100644
index 0000000..cc5a0ff
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "otterhide"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+bevy = { version = "0.13", features = [ "wayland" ] }
+derive_more = "0.99.17"
+itertools = "0.12.1"
+js-sys = "0.3.68"
+rand = "0.8.5"
+wasm-bindgen = "0.2.91"
+
+[profile.dev.package."*"]
+opt-level = "z"new file mode 100644
index 0000000..14ad37a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,147 @@
+include Makefile.d/defaults.mk
+
+all: ## Build the program (DEFAULT)
+all: test build
+.PHONY: all
+
+build: $(shell find src/)
+build: Cargo.lock
+build:
+ cargo build --release
+.PHONY: build
+
+test:
+ cargo test
+.PHONY: test
+
+install: ## Install the program in the ${prefix} directory
+install: prefix ?= $(out)
+install: build
+ test $(prefix)
+ mkdir --parents $(prefix)
+ cp --recursive $</* $(prefix)/
+.PHONY: install
+
+
+### DEVELOPMENT
+
+develop: ## Rebuild and run a development version of the program
+develop:
+ cargo run --features bevy/dynamic_linking
+.PHONY: develop
+
+clean: ## Remove all build artifacts
+clean:
+ git clean -dfX \
+ --exclude='!.envrc.private'
+.PHONY: clean
+
+serve: ## Serve the web version of the program
+serve: web
+ miniserve --interfaces=127.0.0.1 --index=index.html web
+.PHONY: serve
+
+help: ## Print this help message
+help:
+ @
+ echo "Useage: make [ goals ]"
+ echo
+ echo "Available goals:"
+ echo
+ cat $(MAKEFILE_LIST) | awk -f Makefile.d/make-goals.awk
+.PHONY: help
+
+### WEB TARGET
+
+web: ## Build the program for the web
+web: $(shell find src/)
+web: $(shell find web-assets/)
+web: Cargo.lock
+web: index.html
+web: base_url ?= "/"
+web:
+ trunk build \
+ --release \
+ --public-url $(base_url) \
+ --dist $@
+ touch $@
+
+web/develop: ## Rebuild and serve a development version of the in a local server
+web/develop:
+ trunk serve \
+ --address=0.0.0.0 \
+ index.html
+.PHONY: web/develop
+
+web/serve: ## Serve a release version of the program
+web/serve: web
+web/serve:
+ miniserve --index=index.html $<
+.PHONY: web/serve
+
+
+### CONTINUOUS INTEGRATION
+
+public: ## Prepare the web assets (used in CI)
+public: web
+public:
+ rm --recursive --force $@
+ cp --recursive --force $^ $@
+ unset GZIP
+ find $@ -type f -regex '.*\.\(htm\|html\|txt\|text\|js\|css\|wasm\)$$' -exec gzip -9 -f -k {} \;
+ find $@ -type f -regex '.*\.\(htm\|html\|txt\|text\|js\|css\|wasm\)$$' -exec brotli --force --keep {} \;
+ touch $@
+.PHONY: public
+
+
+### NIX SPECIFIC
+
+export nix := nix --experimental-features "nix-command flakes"
+export nix-cache-name := software-garden
+
+result: ## Build the program using Nix
+result:
+ cachix use $(nix-cache-name)
+ $(nix) build --print-build-logs
+
+nix-cache: ## Push Nix binary cache to Cachix
+nix-cache: result
+ $(nix) flake archive --json \
+ | jq --raw-output '.path, (.inputs | to_entries [] .value.path)' \
+ | cachix push $(nix-cache-name)
+
+ $(nix) path-info --recursive \
+ | cachix push $(nix-cache-name)
+
+
+### OCI BUILD IMAGE RELATED
+
+build-image: ## Create an OCI image with build environment (to be used in CI)
+build-image: flake.nix
+build-image: flake.lock
+build-image: rust-toolchain.toml
+build-image:
+ nix build \
+ --print-build-logs \
+ .#docker-image
+ cp --dereference result $@
+
+load-build-image: ## Load the OCI image using Podman
+load-build-image: build-image
+ gzip --decompress $^ --to-stdout | podman image load
+.PHONY: load-build-image
+
+build-inside-container: ## Build the program in an OCI container (e.g. to test CI)
+build-inside-container: load-build-image
+ # We need to know the project name to know which image to load. Can we do better?
+ test $${project_name}
+ podman run \
+ --rm \
+ --interactive \
+ --tty \
+ --volume ${PWD}:/src \
+ --workdir /src \
+ --entrypoint make \
+ localhost/$(project_name)-build-image \
+ public
+.PHONY: build-inside-containernew file mode 100644
index 0000000..1a788da
--- /dev/null
+++ b/Makefile.d/defaults.mk
@@ -0,0 +1,39 @@
+# Default settings for Make
+
+# Always use strict bash
+SHELL := bash
+.SHELLFLAGS := -eu -o pipefail -c
+.ONESHELL:
+
+# If a recipe fails, delete it's targets to avoid broken state
+.DELETE_ON_ERROR:
+
+# Allow $$(variables) to be expanded in a second pass
+.SECONDEXPANSION:
+
+# Warn about undefined variables and
+# TODO: How to make it an error, like in bash strict mode?
+# TODO: Consider https://www.artificialworlds.net/blog/2015/04/22/treat-warnings-as-errors-in-a-gnu-makefile/
+MAKEFLAGS += --warn-undefined-variables
+MAKEFLAGS += --warn-undefined-functions
+
+# Remove implicit rules - no magic please
+# See https://www.gnu.org/software/make/manual/html_node/Catalogue-of-Rules.html
+MAKEFLAGS += --no-builtin-rules
+
+# Helper functions
+
+define slugify
+$(shell \
+ echo $(1) \
+ | tr '[:upper:]' '[:lower:]' \
+ | tr --squeeze-repeats --complement '[:alnum:]\n' '-' \
+)
+endef
+
+# General purpose variables
+
+author = $(shell git config user.name)
+
+timestamp = $(shell date '+%s')
+new file mode 100644
index 0000000..ca79030
--- /dev/null
+++ b/Makefile.d/make-goals.awk
@@ -0,0 +1,4 @@
+# Section header
+match($0, /^### (.+)/, matches) { printf "\n\n%s:\n\n", matches[1] }
+# Goal with description
+match($0, /^(.+):.* ## (.+)/, matches) { printf " %-30s %s\n", matches[1], matches[2]}new file mode 100644
index 0000000..e352084
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,130 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1705309234,
+ "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "flake-utils_2": {
+ "inputs": {
+ "systems": "systems_2"
+ },
+ "locked": {
+ "lastModified": 1705309234,
+ "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1708807242,
+ "narHash": "sha256-sRTRkhMD4delO/hPxxi+XwLqPn8BuUq6nnj4JqLwOu0=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "73de017ef2d18a04ac4bfd0c02650007ccb31c2a",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs_2": {
+ "locked": {
+ "lastModified": 1706487304,
+ "narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "90f456026d284c22b3e3497be980b2e47d0b28ac",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs",
+ "rust-overlay": "rust-overlay"
+ }
+ },
+ "rust-overlay": {
+ "inputs": {
+ "flake-utils": "flake-utils_2",
+ "nixpkgs": "nixpkgs_2"
+ },
+ "locked": {
+ "lastModified": 1708913568,
+ "narHash": "sha256-76PGANC2ADf0h7fe0w2nWpfdGN+bemFs2rvW2EdU/ZY=",
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "rev": "cbdf3e5bb205ff2ca165fe661fbd6d885cbd0106",
+ "type": "github"
+ },
+ "original": {
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "type": "github"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ },
+ "systems_2": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}new file mode 100644
index 0000000..5795f21
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,89 @@
+{
+ description = "Simulate and explore a history of a town";
+
+ inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+ rust-overlay.url = "github:oxalica/rust-overlay";
+ flake-utils.url = "github:numtide/flake-utils";
+ };
+
+ outputs = { self, nixpkgs, rust-overlay, flake-utils }:
+ flake-utils.lib.eachDefaultSystem (system:
+ let
+ project-name = "otterhide";
+ overlays = [ (import rust-overlay) ];
+ pkgs = import nixpkgs {
+ inherit system overlays;
+ };
+ buildInputs = with pkgs; [
+ openssl
+ alsa-lib
+ udev
+ libxkbcommon
+ vulkan-loader
+ wayland
+ libffi
+ ];
+ nativeBuildInputs = with pkgs; [
+ (rust-bin.fromRustupToolchainFile ./rust-toolchain.toml)
+ gcc
+ pkg-config
+ gnumake
+ findutils
+ gzip
+ lld
+ trunk
+ wasm-bindgen-cli
+ brotli
+ rustPlatform.bindgenHook
+ ];
+ in
+ {
+ devShell = pkgs.mkShell {
+ inherit buildInputs nativeBuildInputs;
+ name = "${project-name}-develpoment-shell";
+ packages = with pkgs; [
+ pkgs.rust-analyzer
+ pkgs.miniserve
+ pkgs.jq
+ ];
+ project_name = project-name; # Expose as an environment variable for make
+ LD_LIBRARY_PATH = "$LD_LIBRARY_PATH:${ with pkgs; lib.makeLibraryPath buildInputs }";
+ XCURSOR_THEME = "Adwaita"; # Workaround for https://github.com/bevyengine/bevy/issues/4768
+ };
+ defaultPackage = pkgs.rustPlatform.buildRustPackage {
+ # TODO: Consider using naersk here
+ name = project-name;
+ version = "1.0.0";
+ src = ./.;
+ cargoLock = {
+ lockFile = ./Cargo.lock;
+ };
+ postFixup = ''
+ # See https://discourse.nixos.org/t/rust-bevy-vulkan-loader-and-ld-library-path-variable/25282/2
+ patchelf --add-rpath ${ pkgs.vulkan-loader }/lib $out/bin/*
+ '';
+
+ inherit buildInputs nativeBuildInputs;
+ };
+ packages.docker-image = pkgs.dockerTools.buildLayeredImage {
+ name = "${project-name}-build-image";
+ tag = "latest";
+ created = "now";
+ contents = buildInputs ++ nativeBuildInputs ++ [
+ pkgs.bash
+ pkgs.coreutils
+ pkgs.git
+ pkgs.httpie
+ pkgs.rustup
+ pkgs.cacert
+ ];
+ fakeRootCommands = ''
+ mkdir --parents /tmp
+ '';
+ enableFakechroot = true;
+ config.Cmd = [ "${ pkgs.bash }/bin/bash" ];
+ };
+ }
+ );
+}new file mode 100644
index 0000000..d11a782
--- /dev/null
+++ b/index.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<html class="no-js" lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="x-ua-compatible" content="ie=edge">
+ <title>Otterhide</title>
+ <meta name="description" content="Simulate and explore a history of a town">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+
+ <base data-trunk-public-url />
+
+ <link data-trunk rel="copy-dir" href="./web-assets/" data-target-path="./" />
+ <link rel="apple-touch-icon" sizes="180x180" href="./apple-touch-icon.png" />
+ <link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png" />
+ <link rel="icon" type="image/png" sizes="16x16" href="./favicon-16x16.png" />
+ <link rel="manifest" href="./site.webmanifest" />
+
+ <link data-trunk rel="copy-dir" href="./assets/" />
+
+ <style type="text/css" media="screen">
+ html, body {
+ margin: 0;
+ height: 100%;
+ overflow: hidden;
+ }
+ #game-canvas {
+ width: 100%;
+ height: 100%;
+ }
+ </style>
+ <script type="text/javascript">
+ // Workaround for autofocus not working in Firefox.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=662496
+ document.addEventListener ("DOMContentLoaded", () => {
+ const canvas = document.getElementById ("game-canvas")
+ canvas.focus ()
+ })
+ </script>
+
+ <link data-trunk rel="rust" data-opt="z" />
+
+ </head>
+ <body style="touch-action: none">
+ <canvas id="game-canvas" tabindex="0" autofocus></canvas>
+ </body>
+</html>new file mode 100644
index 0000000..571e68f
--- /dev/null
+++ b/rust-toolchain.toml
@@ -0,0 +1,5 @@
+[toolchain]
+channel = "stable"
+components = [ "rust-src" ]
+targets = [ "wasm32-unknown-unknown" ]
+profile = "default"new file mode 100644
index 0000000..80a1832
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}new file mode 100644
index 0000000..eb8c79a
--- /dev/null
+++ b/web-assets/.gitkeep
@@ -0,0 +1 @@
+Just make sure this directory is checked in, even if empty. Otherwise Trunk will fail to build.new file mode 100644
index 0000000..e694967
--- /dev/null
+++ b/web-assets/about.txt
@@ -0,0 +1,6 @@
+This favicon was generated using the following font:
+
+- Font Title: Leckerli One
+- Font Author: Copyright (c) 2011 Gesine Todt (www.gesine-todt.de hallo@gesine-todt.de), with Reserved Font Names "Leckerli"
+- Font Source: http://fonts.gstatic.com/s/leckerlione/v20/V8mCoQH8VCsNttEnxnGQ-1itLZxcBtItFw.ttf
+- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL))new file mode 100644
index 0000000..6de8fb6
Binary files /dev/null and b/web-assets/android-chrome-192x192.png differnew file mode 100644
index 0000000..5a71519
Binary files /dev/null and b/web-assets/android-chrome-512x512.png differnew file mode 100644
index 0000000..0ea5fb1
Binary files /dev/null and b/web-assets/apple-touch-icon.png differnew file mode 100644
index 0000000..de26fe8
Binary files /dev/null and b/web-assets/favicon-16x16.png differnew file mode 100644
index 0000000..e823849
Binary files /dev/null and b/web-assets/favicon-32x32.png differnew file mode 100644
index 0000000..043fef2
Binary files /dev/null and b/web-assets/favicon.ico differnew file mode 100644
index 0000000..45dc8a2
--- /dev/null
+++ b/web-assets/site.webmanifest
@@ -0,0 +1 @@
+{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
\ No newline at end of fileEnsure the assets/ directory exists
On by
Otherwise Trunk fails to build.
new file mode 100644
index 0000000..eb8c79a
--- /dev/null
+++ b/assets/.gitkeep
@@ -0,0 +1 @@
+Just make sure this directory is checked in, even if empty. Otherwise Trunk will fail to build.Setup a Bevy application
On by
It will only print a log message once. But it's there!
index 14ad37a..477a482 100644
--- a/Makefile
+++ b/Makefile
@@ -30,6 +30,11 @@ develop:
= cargo run --features bevy/dynamic_linking
=.PHONY: develop
=
+web/develop: ## Run a development web server
+web/develop:
+ trunk serve
+.PHONY: web/develop
+
=clean: ## Remove all build artifacts
=clean:
= git clean -dfX \index 80a1832..0ec9c21 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,12 @@
+use bevy::prelude::*;
+
=fn main() {
- println!("Hello, world!");
+ App::new()
+ .add_plugins(DefaultPlugins)
+ .add_systems(Startup, greet)
+ .run()
+}
+
+fn greet() {
+ info!("Let's build the city on rock and roll!")
=}Make the canvas fill the viewport
On by
index 0ec9c21..5f5962a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,7 +2,15 @@ use bevy::prelude::*;
=
=fn main() {
= App::new()
- .add_plugins(DefaultPlugins)
+ .add_plugins(DefaultPlugins.set(WindowPlugin {
+ primary_window: Some(Window {
+ title: "Otterhide".into(),
+ canvas: Some("#game-canvas".into()),
+ mode: bevy::window::WindowMode::Fullscreen,
+ ..default()
+ }),
+ ..default()
+ }))
= .add_systems(Startup, greet)
= .run()
=}Setup a ground plane and a camera
On by
index 5f5962a..3789a71 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -11,10 +11,29 @@ fn main() {
= }),
= ..default()
= }))
- .add_systems(Startup, greet)
+ .add_systems(Startup, (greet, setup_ground, setup_camera))
= .run()
=}
=
=fn greet() {
= info!("Let's build the city on rock and roll!")
=}
+
+fn setup_ground(
+ mut commands: Commands,
+ mut meshes: ResMut<Assets<Mesh>>,
+ mut materials: ResMut<Assets<StandardMaterial>>,
+) {
+ commands.spawn(PbrBundle {
+ mesh: meshes.add(Plane3d::default().mesh().size(20., 20.)),
+ material: materials.add(Color::hsl(120.0, 0.6, 0.8)),
+ ..default()
+ });
+}
+
+fn setup_camera(mut commands: Commands) {
+ commands.spawn(Camera3dBundle {
+ transform: Transform::from_xyz(0., 10., 20.).looking_at(Vec3::ZERO, Vec3::Y),
+ ..default()
+ });
+}Setup a house (cuboid) and sunlight
On by
Tweak parameters to show the perspective and make the ground color darker and less saturated.
index 3789a71..00eefa4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -11,7 +11,16 @@ fn main() {
= }),
= ..default()
= }))
- .add_systems(Startup, (greet, setup_ground, setup_camera))
+ .add_systems(
+ Startup,
+ (
+ greet,
+ setup_ground,
+ setup_house,
+ setup_sunlight,
+ setup_camera,
+ ),
+ )
= .run()
=}
=
@@ -26,14 +35,40 @@ fn setup_ground(
=) {
= commands.spawn(PbrBundle {
= mesh: meshes.add(Plane3d::default().mesh().size(20., 20.)),
- material: materials.add(Color::hsl(120.0, 0.6, 0.8)),
+ material: materials.add(Color::hsl(150.0, 0.3, 0.3)),
+ ..default()
+ });
+}
+
+fn setup_house(
+ mut commands: Commands,
+ mut meshes: ResMut<Assets<Mesh>>,
+ mut materials: ResMut<Assets<StandardMaterial>>,
+) {
+ const SIZE: f32 = 1.;
+
+ commands.spawn(PbrBundle {
+ mesh: meshes.add(Cuboid::new(SIZE, SIZE * 2., SIZE)),
+ material: materials.add(Color::hsl(60.0, 0.8, 0.5)),
+ transform: Transform::from_xyz(0., SIZE, 0.),
= ..default()
= });
=}
=
=fn setup_camera(mut commands: Commands) {
= commands.spawn(Camera3dBundle {
- transform: Transform::from_xyz(0., 10., 20.).looking_at(Vec3::ZERO, Vec3::Y),
+ transform: Transform::from_xyz(5., 10., 20.).looking_at(Vec3::ZERO, Vec3::Y),
+ ..default()
+ });
+}
+
+fn setup_sunlight(mut commands: Commands) {
+ commands.spawn(DirectionalLightBundle {
+ transform: Transform::from_xyz(30., 40., -20.).looking_at(Vec3::ZERO, Vec3::Y),
+ directional_light: DirectionalLight {
+ shadows_enabled: true,
+ ..default()
+ },
= ..default()
= });
=}Set the camera in motion
On by
index 00eefa4..ebc5693 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -21,6 +21,7 @@ fn main() {
= setup_camera,
= ),
= )
+ .add_systems(Update, orbit_camera)
= .run()
=}
=
@@ -72,3 +73,9 @@ fn setup_sunlight(mut commands: Commands) {
= ..default()
= });
=}
+
+fn orbit_camera(mut camera: Query<&mut Transform, With<Camera>>, time: Res<Time>) {
+ let mut transform = camera.single_mut();
+
+ transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(time.delta_seconds() / 5.))
+}Remove duplicated web/develop goal from the Makefile
On by
index 477a482..14ad37a 100644
--- a/Makefile
+++ b/Makefile
@@ -30,11 +30,6 @@ develop:
= cargo run --features bevy/dynamic_linking
=.PHONY: develop
=
-web/develop: ## Run a development web server
-web/develop:
- trunk serve
-.PHONY: web/develop
-
=clean: ## Remove all build artifacts
=clean:
= git clean -dfX \Use a gltf model for a house and a sculpture
On by
The source .blend files sit in the art/ directory. The exported .gltf files go to the assets/ directory, and are loaded from there.
To make loader work it was necessary to disable Trunk's SPA feature. That's because Bevy application will try to fetch .meta file for each resource. If there is no such file, the server should respond with 404 status and the loader will just use default parameters. But with the SPA feature Trunk always responds with status 200 and contents of index.html file. Then Bevy tries to parse this HTML and fails.
index 14ad37a..d2398f5 100644
--- a/Makefile
+++ b/Makefile
@@ -70,6 +70,7 @@ web/develop: ## Rebuild and serve a development version of the in a local server
=web/develop:
= trunk serve \
= --address=0.0.0.0 \
+ --no-spa \
= index.html
=.PHONY: web/develop
=new file mode 100644
index 0000000..7284b65
Binary files /dev/null and b/art/large_buildingB.blend differnew file mode 100644
index 0000000..16a64d8
Binary files /dev/null and b/art/suzanne.blend differnew file mode 100644
index 0000000..0e55573
Binary files /dev/null and b/assets/large_buildingB.glb differnew file mode 100644
index 0000000..8b86589
Binary files /dev/null and b/assets/suzanne.glb differindex ebc5693..b360944 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -17,6 +17,7 @@ fn main() {
= greet,
= setup_ground,
= setup_house,
+ setup_sculpture,
= setup_sunlight,
= setup_camera,
= ),
@@ -41,17 +42,22 @@ fn setup_ground(
= });
=}
=
-fn setup_house(
- mut commands: Commands,
- mut meshes: ResMut<Assets<Mesh>>,
- mut materials: ResMut<Assets<StandardMaterial>>,
-) {
- const SIZE: f32 = 1.;
+fn setup_house(mut commands: Commands, assets: ResMut<AssetServer>) {
+ let model = assets.load("large_buildingB.glb#Scene0");
=
- commands.spawn(PbrBundle {
- mesh: meshes.add(Cuboid::new(SIZE, SIZE * 2., SIZE)),
- material: materials.add(Color::hsl(60.0, 0.8, 0.5)),
- transform: Transform::from_xyz(0., SIZE, 0.),
+ commands.spawn(SceneBundle {
+ scene: model,
+ transform: Transform::from_xyz(0., 0., 0.),
+ ..default()
+ });
+}
+
+fn setup_sculpture(mut commands: Commands, assets: ResMut<AssetServer>) {
+ let model = assets.load("suzanne.glb#Scene0");
+
+ commands.spawn(SceneBundle {
+ scene: model,
+ transform: Transform::from_xyz(3., 0., 3.),
= ..default()
= });
=}Update some Cargo dependencies
On by
index 8bb2117..be9d0ed 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -386,7 +386,7 @@ dependencies = [
= "bevy_macro_utils",
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -452,7 +452,7 @@ checksum = "028ae2a34678055185d7f1beebb1ebe6a8dcf3733e139e4ee1383a7f29ae8ba6"
=dependencies = [
= "bevy_macro_utils",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -500,7 +500,7 @@ dependencies = [
= "bevy_macro_utils",
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -560,7 +560,7 @@ dependencies = [
= "bevy_macro_utils",
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -686,7 +686,7 @@ dependencies = [
= "proc-macro2",
= "quote",
= "rustc-hash",
- "syn 2.0.50",
+ "syn 2.0.51",
= "toml_edit 0.21.1",
=]
=
@@ -767,7 +767,7 @@ dependencies = [
= "bevy_macro_utils",
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
= "uuid",
=]
=
@@ -825,7 +825,7 @@ dependencies = [
= "bevy_macro_utils",
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -993,7 +993,7 @@ checksum = "31ae98e9c0c08b0f5c90e22cd713201f759b98d4fd570b99867a695f8641859a"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -1055,7 +1055,7 @@ dependencies = [
= "regex",
= "rustc-hash",
= "shlex",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -1184,7 +1184,7 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -1594,7 +1594,7 @@ checksum = "92959a9e8d13eaa13b8ae8c7b583c3bf1669ca7a8e7708a088d12587ba86effc"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -1734,7 +1734,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -1885,7 +1885,7 @@ dependencies = [
= "inflections",
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -2575,7 +2575,7 @@ dependencies = [
= "proc-macro-crate 3.1.0",
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -3145,7 +3145,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -3281,9 +3281,9 @@ dependencies = [
=
=[[package]]
=name = "syn"
-version = "2.0.50"
+version = "2.0.51"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
+checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c"
=dependencies = [
= "proc-macro2",
= "quote",
@@ -3342,7 +3342,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -3442,7 +3442,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]
=
=[[package]]
@@ -3611,7 +3611,7 @@ dependencies = [
= "once_cell",
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
= "wasm-bindgen-shared",
=]
=
@@ -3645,7 +3645,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
= "wasm-bindgen-backend",
= "wasm-bindgen-shared",
=]
@@ -4188,9 +4188,9 @@ checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
=
=[[package]]
=name = "winit"
-version = "0.29.10"
+version = "0.29.11"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c824f11941eeae66ec71111cc2674373c772f482b58939bb4066b642aa2ffcf"
+checksum = "272be407f804517512fdf408f0fe6c067bf24659a913c61af97af176bfd5aa92"
=dependencies = [
= "ahash",
= "android-activity",
@@ -4329,5 +4329,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.50",
+ "syn 2.0.51",
=]index cc5a0ff..82a0963 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
=# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
=
=[dependencies]
-bevy = { version = "0.13", features = [ "wayland" ] }
+bevy = { version = "0.13", features = ["wayland"] }
=derive_more = "0.99.17"
=itertools = "0.12.1"
=js-sys = "0.3.68"Implement basic logic concerning day-month
On by
A day-month is an abstraction of a month, where every day is the same, so it collapses into one. There is no day-of-month component. only year, month and time of day. It can be advanced (mutation in place) and displayed. The components can be extracted. A Month value can be converted to and from an i32 with overflowing (1 = January, 0 = 12 = 24 = -12 = December).
index d2398f5..493e07b 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ build:
=.PHONY: build
=
=test:
- cargo test
+ cargo test --features bevy/dynamic_linking
=.PHONY: test
=
=install: ## Install the program in the ${prefix} directorynew file mode 100644
index 0000000..8a58156
--- /dev/null
+++ b/src/day_month.rs
@@ -0,0 +1,167 @@
+use std::fmt::Display;
+
+pub const HOUR: f32 = 1.0 / 24.0;
+pub const MINUTE: f32 = HOUR / 60.0;
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum Month {
+ January = 1,
+ February,
+ March,
+ April,
+ May,
+ June,
+ July,
+ August,
+ September,
+ October,
+ November,
+ December,
+}
+
+impl Display for Month {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{self:?}")
+ }
+}
+
+impl Month {
+ fn new(number: i32) -> Self {
+ match number.rem_euclid(12) {
+ 0 => Self::December,
+ 1 => Self::January,
+ 2 => Self::February,
+ 3 => Self::March,
+ 4 => Self::April,
+ 5 => Self::May,
+ 6 => Self::June,
+ 7 => Self::July,
+ 8 => Self::August,
+ 9 => Self::September,
+ 10 => Self::October,
+ 11 => Self::November,
+ _ => panic!("Euclidian remainder of 12 outside of 0..11 range"),
+ }
+ }
+}
+
+#[cfg(test)]
+mod month_tests {
+ use super::*;
+
+ #[test]
+ fn month_to_number() {
+ assert_eq!(Month::January as i32, 1);
+ assert_eq!(Month::February as i32, 2);
+ assert_eq!(Month::December as i32, 12);
+ }
+
+ #[test]
+ fn number_to_month() {
+ assert_eq!(Month::new(1), Month::January);
+ assert_eq!(Month::new(2), Month::February);
+ assert_eq!(Month::new(12), Month::December);
+
+ // Overflow
+ assert_eq!(Month::new(13), Month::January);
+ assert_eq!(Month::new(14), Month::February);
+
+ // Negative
+ assert_eq!(Month::new(0), Month::December);
+ assert_eq!(Month::new(-1), Month::November);
+ assert_eq!(Month::new(-13), Month::November);
+ }
+}
+
+/// Represents a month in a day
+pub struct DayMonth {
+ /// How many daymonths have passed since the start
+ value: f32,
+ /// The first year when the city was founded
+ start: i32,
+}
+
+impl DayMonth {
+ /// Initialize the day-month. Returns beginning (midnight) of the January of a given start year.
+ pub fn new(year: i32) -> Self {
+ Self {
+ start: year,
+ value: 0.0,
+ }
+ }
+
+ pub fn advance(&mut self, duration: f32) -> &Self {
+ self.value += duration;
+ self
+ }
+
+ pub fn year(&self) -> i32 {
+ self.value.div_euclid(12.0) as i32 + self.start
+ }
+
+ pub fn month(&self) -> Month {
+ Month::new(self.value as i32 + 1)
+ }
+
+ pub fn hour(&self) -> i32 {
+ (self.value.rem_euclid(1.0) * 24.0) as i32
+ }
+
+ pub fn minute(&self) -> f32 {
+ // TODO: Can minutes calculation be simplified for efficiency?
+ (self.value.rem_euclid(1.0) * 24.0).rem_euclid(1.0) * 60.0
+ }
+}
+
+impl Display for DayMonth {
+ /// Should give something like March 2024 13:32
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(
+ f,
+ "{} {} {:02}:{:02.0}",
+ self.month(),
+ self.year(),
+ self.hour(),
+ self.minute()
+ )
+ }
+}
+
+#[cfg(test)]
+mod daymonth_tests {
+ use super::*;
+
+ #[test]
+ fn new() {
+ let daymonth = DayMonth::new(1972);
+
+ assert_eq!(daymonth.year(), 1972);
+ assert_eq!(daymonth.month(), Month::January);
+ assert_eq!(daymonth.hour(), 0);
+ assert_eq!(daymonth.minute(), 0.0);
+ }
+
+ #[test]
+ fn advance_and_format() {
+ let mut daymonth = DayMonth::new(1984);
+ assert_eq!(format!("{daymonth}"), "January 1984 00:00");
+
+ daymonth.advance(1.0);
+ assert_eq!(format!("{daymonth}"), "February 1984 00:00");
+
+ daymonth.advance(45. * MINUTE);
+ assert_eq!(format!("{daymonth}"), "February 1984 00:45");
+
+ daymonth.advance(23. * HOUR);
+ assert_eq!(format!("{daymonth}"), "February 1984 23:45");
+
+ daymonth.advance(30. * MINUTE);
+ assert_eq!(format!("{daymonth}"), "March 1984 00:15");
+
+ daymonth.advance(13.5 * HOUR);
+ assert_eq!(format!("{daymonth}"), "March 1984 13:45");
+
+ daymonth.advance(12. * HOUR);
+ assert_eq!(format!("{daymonth}"), "April 1984 01:45");
+ }
+}index b360944..cd3d051 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,5 @@
+mod day_month;
+
=use bevy::prelude::*;
=
=fn main() {Let the time pass but keep an eye on it
On by
index cd3d051..57b74df 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,7 @@
=mod day_month;
=
=use bevy::prelude::*;
+use day_month::DayMonth;
=
=fn main() {
= App::new()
@@ -13,6 +14,7 @@ fn main() {
= }),
= ..default()
= }))
+ .insert_resource(Date(DayMonth::new(1875)))
= .add_systems(
= Startup,
= (
@@ -21,13 +23,17 @@ fn main() {
= setup_house,
= setup_sculpture,
= setup_sunlight,
+ setup_date_display,
= setup_camera,
= ),
= )
- .add_systems(Update, orbit_camera)
+ .add_systems(Update, (orbit_camera, advance_date, update_date_display))
= .run()
=}
=
+#[derive(Resource)]
+struct Date(DayMonth);
+
=fn greet() {
= info!("Let's build the city on rock and roll!")
=}
@@ -87,3 +93,40 @@ fn orbit_camera(mut camera: Query<&mut Transform, With<Camera>>, time: Res<Time>
=
= transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(time.delta_seconds() / 5.))
=}
+
+fn setup_date_display(mut commands: Commands, date: Res<Date>) {
+ commands
+ .spawn(
+ TextBundle::from_section(
+ date.0.to_string(),
+ TextStyle {
+ font_size: 32.0,
+ color: Color::WHITE,
+ ..default()
+ },
+ )
+ .with_style(Style {
+ justify_self: JustifySelf::Center,
+ margin: UiRect::top(Val::Px(20.0)),
+ ..default()
+ }),
+ )
+ .insert(DateDisplay);
+}
+
+fn advance_date(time: Res<Time>, mut date: ResMut<Date>) {
+ // Simulation day-months per one second of real time
+ const SCALE: f32 = 1.0 / 60.0;
+
+ let delta = time.delta_seconds();
+ let duration = delta * SCALE;
+ date.0.advance(duration);
+}
+
+fn update_date_display(mut display: Query<&mut Text, With<DateDisplay>>, date: Res<Date>) {
+ let mut display = display.single_mut();
+ display.sections[0].value = date.0.to_string();
+}
+
+#[derive(Component)]
+struct DateDisplay;Slow down the camera
On by
index 57b74df..b20ee92 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,6 +2,7 @@ mod day_month;
=
=use bevy::prelude::*;
=use day_month::DayMonth;
+use std::f32::consts::PI;
=
=fn main() {
= App::new()
@@ -89,9 +90,14 @@ fn setup_sunlight(mut commands: Commands) {
=}
=
=fn orbit_camera(mut camera: Query<&mut Transform, With<Camera>>, time: Res<Time>) {
- let mut transform = camera.single_mut();
+ const RPS: f32 = 0.005;
+ const VELOCITY: f32 = PI * 2.0 * RPS;
=
- transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(time.delta_seconds() / 5.))
+ let mut transform = camera.single_mut();
+ transform.rotate_around(
+ Vec3::ZERO,
+ Quat::from_rotation_y(time.delta_seconds() * VELOCITY),
+ )
=}
=
=fn setup_date_display(mut commands: Commands, date: Res<Date>) {Simulate a horizon
On by
With a big circle instead of a small plane for ground and lower camera angle.
index b20ee92..94e13d1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,7 +2,7 @@ mod day_month;
=
=use bevy::prelude::*;
=use day_month::DayMonth;
-use std::f32::consts::PI;
+use std::f32::consts::{FRAC_PI_2, PI};
=
=fn main() {
= App::new()
@@ -44,9 +44,11 @@ fn setup_ground(
= mut meshes: ResMut<Assets<Mesh>>,
= mut materials: ResMut<Assets<StandardMaterial>>,
=) {
+ const SIZE: f32 = 100.;
= commands.spawn(PbrBundle {
- mesh: meshes.add(Plane3d::default().mesh().size(20., 20.)),
+ mesh: meshes.add(Circle::new(SIZE)),
= material: materials.add(Color::hsl(150.0, 0.3, 0.3)),
+ transform: Transform::from_rotation(Quat::from_rotation_x(-FRAC_PI_2)),
= ..default()
= });
=}
@@ -80,7 +82,7 @@ fn setup_camera(mut commands: Commands) {
=
=fn setup_sunlight(mut commands: Commands) {
= commands.spawn(DirectionalLightBundle {
- transform: Transform::from_xyz(30., 40., -20.).looking_at(Vec3::ZERO, Vec3::Y),
+ transform: Transform::from_xyz(20., 25., -20.).looking_at(Vec3::ZERO, Vec3::Y),
= directional_light: DirectionalLight {
= shadows_enabled: true,
= ..default()Move the camera related logic to own module
On by
The new module exposes a plugin.
new file mode 100644
index 0000000..393d63c
--- /dev/null
+++ b/src/camera.rs
@@ -0,0 +1,30 @@
+use std::f32::consts::FRAC_2_PI;
+
+use bevy::prelude::*;
+
+pub struct CameraPlugin {}
+
+impl Plugin for CameraPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_systems(Startup, setup_camera)
+ .add_systems(Update, orbit_camera);
+ }
+}
+
+fn setup_camera(mut commands: Commands) {
+ commands.spawn(Camera3dBundle {
+ transform: Transform::from_xyz(5., 10., 20.).looking_at(Vec3::ZERO, Vec3::Y),
+ ..default()
+ });
+}
+
+fn orbit_camera(mut camera: Query<&mut Transform, With<Camera>>, time: Res<Time>) {
+ const RPS: f32 = 0.005;
+ const VELOCITY: f32 = FRAC_2_PI * RPS;
+
+ let mut transform = camera.single_mut();
+ transform.rotate_around(
+ Vec3::ZERO,
+ Quat::from_rotation_y(time.delta_seconds() * VELOCITY),
+ )
+}index 94e13d1..a12055a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,8 +1,9 @@
+mod camera;
=mod day_month;
=
=use bevy::prelude::*;
=use day_month::DayMonth;
-use std::f32::consts::{FRAC_PI_2, PI};
+use std::f32::consts::FRAC_PI_2;
=
=fn main() {
= App::new()
@@ -16,6 +17,7 @@ fn main() {
= ..default()
= }))
= .insert_resource(Date(DayMonth::new(1875)))
+ .add_plugins(camera::CameraPlugin {})
= .add_systems(
= Startup,
= (
@@ -25,10 +27,9 @@ fn main() {
= setup_sculpture,
= setup_sunlight,
= setup_date_display,
- setup_camera,
= ),
= )
- .add_systems(Update, (orbit_camera, advance_date, update_date_display))
+ .add_systems(Update, (advance_date, update_date_display))
= .run()
=}
=
@@ -73,13 +74,6 @@ fn setup_sculpture(mut commands: Commands, assets: ResMut<AssetServer>) {
= });
=}
=
-fn setup_camera(mut commands: Commands) {
- commands.spawn(Camera3dBundle {
- transform: Transform::from_xyz(5., 10., 20.).looking_at(Vec3::ZERO, Vec3::Y),
- ..default()
- });
-}
-
=fn setup_sunlight(mut commands: Commands) {
= commands.spawn(DirectionalLightBundle {
= transform: Transform::from_xyz(20., 25., -20.).looking_at(Vec3::ZERO, Vec3::Y),
@@ -91,17 +85,6 @@ fn setup_sunlight(mut commands: Commands) {
= });
=}
=
-fn orbit_camera(mut camera: Query<&mut Transform, With<Camera>>, time: Res<Time>) {
- const RPS: f32 = 0.005;
- const VELOCITY: f32 = PI * 2.0 * RPS;
-
- let mut transform = camera.single_mut();
- transform.rotate_around(
- Vec3::ZERO,
- Quat::from_rotation_y(time.delta_seconds() * VELOCITY),
- )
-}
-
=fn setup_date_display(mut commands: Commands, date: Res<Date>) {
= commands
= .spawn(Parameterize the camera plugin
On by
Also fix a bug in angular velocity calculation. It should be 2π * rps, not 2/π * rps.
index 393d63c..f466363 100644
--- a/src/camera.rs
+++ b/src/camera.rs
@@ -1,30 +1,43 @@
-use std::f32::consts::FRAC_2_PI;
-
=use bevy::prelude::*;
+use std::f32::consts::PI;
+
+#[derive(Resource, Clone, Copy)]
+pub struct CameraSettings {
+ pub elevation: f32,
+ pub distance: f32,
+ pub rps: f32,
+}
=
-pub struct CameraPlugin {}
+pub struct CameraPlugin(pub CameraSettings);
=
=impl Plugin for CameraPlugin {
= fn build(&self, app: &mut App) {
- app.add_systems(Startup, setup_camera)
+ let settings = self.0.clone();
+
+ app.insert_resource(settings)
+ .add_systems(Startup, setup_camera)
= .add_systems(Update, orbit_camera);
= }
=}
=
-fn setup_camera(mut commands: Commands) {
+fn setup_camera(mut commands: Commands, settings: Res<CameraSettings>) {
= commands.spawn(Camera3dBundle {
- transform: Transform::from_xyz(5., 10., 20.).looking_at(Vec3::ZERO, Vec3::Y),
+ transform: Transform::from_xyz(settings.distance, settings.elevation, 0.)
+ .looking_at(Vec3::ZERO, Vec3::Y),
= ..default()
= });
=}
=
-fn orbit_camera(mut camera: Query<&mut Transform, With<Camera>>, time: Res<Time>) {
- const RPS: f32 = 0.005;
- const VELOCITY: f32 = FRAC_2_PI * RPS;
+fn orbit_camera(
+ mut camera: Query<&mut Transform, With<Camera>>,
+ time: Res<Time>,
+ settings: Res<CameraSettings>,
+) {
+ let velocity = PI * 2.0 * settings.rps;
=
= let mut transform = camera.single_mut();
= transform.rotate_around(
= Vec3::ZERO,
- Quat::from_rotation_y(time.delta_seconds() * VELOCITY),
+ Quat::from_rotation_y(time.delta_seconds() * velocity),
= )
=}index a12055a..e850684 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -17,7 +17,11 @@ fn main() {
= ..default()
= }))
= .insert_resource(Date(DayMonth::new(1875)))
- .add_plugins(camera::CameraPlugin {})
+ .add_plugins(camera::CameraPlugin(camera::CameraSettings {
+ elevation: 5.,
+ distance: 12.,
+ rps: 0.01,
+ }))
= .add_systems(
= Startup,
= (Implement day-night cycle with sunlight
On by
The sun movement and sunlight intensity are in the sun module now. The implementation is pretty basic, but maybe good enough for now. I left the sun gizmo visible for now.
index 8a58156..76c684e 100644
--- a/src/day_month.rs
+++ b/src/day_month.rs
@@ -111,6 +111,11 @@ impl DayMonth {
= // TODO: Can minutes calculation be simplified for efficiency?
= (self.value.rem_euclid(1.0) * 24.0).rem_euclid(1.0) * 60.0
= }
+
+ /// Return a number between 0.0 and 1.0 representing the fraction of the day that passed
+ pub fn time_of_day(&self) -> f32 {
+ self.value.rem_euclid(1.0)
+ }
=}
=
=impl Display for DayMonth {index e850684..ae7dbd3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,6 @@
=mod camera;
=mod day_month;
+mod sun;
=
=use bevy::prelude::*;
=use day_month::DayMonth;
@@ -22,6 +23,7 @@ fn main() {
= distance: 12.,
= rps: 0.01,
= }))
+ .add_plugins(sun::SunPlugin)
= .add_systems(
= Startup,
= (
@@ -29,7 +31,6 @@ fn main() {
= setup_ground,
= setup_house,
= setup_sculpture,
- setup_sunlight,
= setup_date_display,
= ),
= )
@@ -78,17 +79,6 @@ fn setup_sculpture(mut commands: Commands, assets: ResMut<AssetServer>) {
= });
=}
=
-fn setup_sunlight(mut commands: Commands) {
- commands.spawn(DirectionalLightBundle {
- transform: Transform::from_xyz(20., 25., -20.).looking_at(Vec3::ZERO, Vec3::Y),
- directional_light: DirectionalLight {
- shadows_enabled: true,
- ..default()
- },
- ..default()
- });
-}
-
=fn setup_date_display(mut commands: Commands, date: Res<Date>) {
= commands
= .spawn(new file mode 100644
index 0000000..8e0f612
--- /dev/null
+++ b/src/sun.rs
@@ -0,0 +1,68 @@
+use std::{
+ f32::consts::PI,
+ ops::{Mul, Sub},
+};
+
+use crate::Date;
+use bevy::prelude::*;
+
+const ORBIT: f32 = 100.;
+
+pub struct SunPlugin;
+
+impl Plugin for SunPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_systems(Startup, setup_sunlight)
+ .add_systems(Update, (move_sun, update_sunlight_color, draw_gizmos));
+ }
+}
+
+#[derive(Component)]
+struct Sun;
+
+fn draw_gizmos(mut gizmos: Gizmos, sun: Query<(&Transform, &DirectionalLight), With<Sun>>) {
+ let (position, light) = sun.single();
+
+ gizmos.sphere(position.translation, Quat::default(), 5., light.color);
+}
+
+fn setup_sunlight(mut commands: Commands) {
+ commands
+ .spawn(DirectionalLightBundle {
+ transform: Transform::from_translation(Vec3::NEG_Y * ORBIT)
+ .looking_at(Vec3::ZERO, Vec3::Y),
+ directional_light: DirectionalLight {
+ shadows_enabled: true,
+ color: Color::hsl(0.0, 1.0, 0.9),
+ ..default()
+ },
+ ..default()
+ })
+ .insert(Sun);
+}
+
+fn move_sun(mut sun: Query<&mut Transform, With<Sun>>, date: Res<Date>) {
+ let daytime = date.0.time_of_day();
+ let angle = daytime * 2.0 * PI - PI;
+ let rotation = Quat::from_rotation_x(angle) * Quat::from_rotation_z(1.0);
+ let translation = rotation.mul_vec3(Vec3::Y) * ORBIT;
+
+ let mut transform = sun.single_mut();
+ transform.translation = translation;
+ transform.look_at(Vec3::ZERO, Vec3::Y);
+}
+
+fn update_sunlight_color(mut sun: Query<&mut DirectionalLight, With<Sun>>, date: Res<Date>) {
+ let daytime = date.0.time_of_day();
+ let sine = daytime.sub(0.25).mul(2.0 * PI).sin();
+ let hue = 10.0 + (sine + 0.5) * 30.0;
+ let lightness = (sine + 1.0) * 0.1 + 0.75; // between 0.75 and 0.95
+ let illuminance = (sine + 0.5) / 2.0 * 32_000.0;
+
+ let mut sun = sun.single_mut();
+ sun.color.set_h(hue);
+ sun.color.set_l(lightness);
+ sun.illuminance = illuminance;
+}
+
+// TODO: Add ambient light. As it is, at noon shadows are too dark.Format some code
On by
index 8e0f612..0556e54 100644
--- a/src/sun.rs
+++ b/src/sun.rs
@@ -1,10 +1,7 @@
-use std::{
- f32::consts::PI,
- ops::{Mul, Sub},
-};
-
=use crate::Date;
=use bevy::prelude::*;
+use std::f32::consts::PI;
+use std::ops::{Mul, Sub};
=
=const ORBIT: f32 = 100.;
=Separate date logic to a new plugin
On by
new file mode 100644
index 0000000..e465f96
--- /dev/null
+++ b/src/date.rs
@@ -0,0 +1,56 @@
+use crate::day_month::DayMonth;
+use bevy::prelude::*;
+
+const SCALE: f32 = 1.0 / 60.0;
+
+pub struct DatePlugin {
+ pub start: i32,
+}
+
+impl Plugin for DatePlugin {
+ fn build(&self, app: &mut App) {
+ app.insert_resource(Date(DayMonth::new(self.start)))
+ .add_systems(Startup, setup_date_display)
+ .add_systems(Update, (advance_date, update_date_display));
+ }
+}
+
+#[derive(Resource)]
+pub struct Date(pub DayMonth);
+
+fn advance_date(time: Res<Time>, mut date: ResMut<Date>) {
+ // Simulation day-months per one second of real time
+
+ let delta = time.delta_seconds();
+ let duration = delta * SCALE;
+ date.0.advance(duration);
+}
+
+// TODO: Consider if date display logic should go to a UI module?
+#[derive(Component)]
+struct DateDisplay;
+
+fn setup_date_display(mut commands: Commands, date: Res<Date>) {
+ commands
+ .spawn(
+ TextBundle::from_section(
+ date.0.to_string(),
+ TextStyle {
+ font_size: 32.0,
+ color: Color::WHITE,
+ ..default()
+ },
+ )
+ .with_style(Style {
+ justify_self: JustifySelf::Center,
+ margin: UiRect::top(Val::Px(20.0)),
+ ..default()
+ }),
+ )
+ .insert(DateDisplay);
+}
+
+fn update_date_display(mut display: Query<&mut Text, With<DateDisplay>>, date: Res<Date>) {
+ let mut display = display.single_mut();
+ display.sections[0].value = date.0.to_string();
+}index ae7dbd3..c600def 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,9 +1,10 @@
=mod camera;
+mod date;
=mod day_month;
=mod sun;
=
=use bevy::prelude::*;
-use day_month::DayMonth;
+use date::DatePlugin;
=use std::f32::consts::FRAC_PI_2;
=
=fn main() {
@@ -17,30 +18,17 @@ fn main() {
= }),
= ..default()
= }))
- .insert_resource(Date(DayMonth::new(1875)))
= .add_plugins(camera::CameraPlugin(camera::CameraSettings {
= elevation: 5.,
= distance: 12.,
= rps: 0.01,
= }))
+ .add_plugins(DatePlugin { start: 1850 })
= .add_plugins(sun::SunPlugin)
- .add_systems(
- Startup,
- (
- greet,
- setup_ground,
- setup_house,
- setup_sculpture,
- setup_date_display,
- ),
- )
- .add_systems(Update, (advance_date, update_date_display))
+ .add_systems(Startup, (greet, setup_ground, setup_house, setup_sculpture))
= .run()
=}
=
-#[derive(Resource)]
-struct Date(DayMonth);
-
=fn greet() {
= info!("Let's build the city on rock and roll!")
=}
@@ -78,40 +66,3 @@ fn setup_sculpture(mut commands: Commands, assets: ResMut<AssetServer>) {
= ..default()
= });
=}
-
-fn setup_date_display(mut commands: Commands, date: Res<Date>) {
- commands
- .spawn(
- TextBundle::from_section(
- date.0.to_string(),
- TextStyle {
- font_size: 32.0,
- color: Color::WHITE,
- ..default()
- },
- )
- .with_style(Style {
- justify_self: JustifySelf::Center,
- margin: UiRect::top(Val::Px(20.0)),
- ..default()
- }),
- )
- .insert(DateDisplay);
-}
-
-fn advance_date(time: Res<Time>, mut date: ResMut<Date>) {
- // Simulation day-months per one second of real time
- const SCALE: f32 = 1.0 / 60.0;
-
- let delta = time.delta_seconds();
- let duration = delta * SCALE;
- date.0.advance(duration);
-}
-
-fn update_date_display(mut display: Query<&mut Text, With<DateDisplay>>, date: Res<Date>) {
- let mut display = display.single_mut();
- display.sections[0].value = date.0.to_string();
-}
-
-#[derive(Component)]
-struct DateDisplay;index 0556e54..6edaa37 100644
--- a/src/sun.rs
+++ b/src/sun.rs
@@ -1,4 +1,4 @@
-use crate::Date;
+use crate::date::Date;
=use bevy::prelude::*;
=use std::f32::consts::PI;
=use std::ops::{Mul, Sub};Make the ground material (grass) more rough
On by
It looked too glossy, esp during sunrises and sunsets.
index c600def..4cff36a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -41,7 +41,11 @@ fn setup_ground(
= const SIZE: f32 = 100.;
= commands.spawn(PbrBundle {
= mesh: meshes.add(Circle::new(SIZE)),
- material: materials.add(Color::hsl(150.0, 0.3, 0.3)),
+ material: materials.add(StandardMaterial {
+ base_color: Color::hsl(150.0, 0.3, 0.3),
+ perceptual_roughness: 0.8,
+ ..default()
+ }),
= transform: Transform::from_rotation(Quat::from_rotation_x(-FRAC_PI_2)),
= ..default()
= });Implement buildings plugin
On by
Building a new building every month.
The date plugin will emit NewMonth events on the turn of every month. Every time the new buildings plugin will read such an events it will spawn a new building.
Time is sped up, so we don't have to wait too long for the new buildings to show.
new file mode 100644
index 0000000..4571974
--- /dev/null
+++ b/src/buildings.rs
@@ -0,0 +1,48 @@
+use crate::date::NewMonth;
+use bevy::prelude::*;
+
+pub struct BuildingsPlugin;
+
+impl Plugin for BuildingsPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_systems(Startup, setup_sculpture)
+ .add_systems(Update, build);
+ }
+}
+
+#[derive(Component)]
+struct Building;
+
+fn build(
+ mut commands: Commands,
+ assets: ResMut<AssetServer>,
+ mut new_month: EventReader<NewMonth>,
+ buildings: Query<&Building>,
+) {
+ if new_month.read().count() == 0 {
+ return;
+ }
+
+ info!("New month - new building!");
+
+ let model = assets.load("large_buildingB.glb#Scene0");
+ let count = buildings.into_iter().count();
+
+ commands
+ .spawn(SceneBundle {
+ scene: model,
+ transform: Transform::from_xyz(count as f32 * 2., 0., 0.),
+ ..default()
+ })
+ .insert(Building);
+}
+
+fn setup_sculpture(mut commands: Commands, assets: ResMut<AssetServer>) {
+ let model = assets.load("suzanne.glb#Scene0");
+
+ commands.spawn(SceneBundle {
+ scene: model,
+ transform: Transform::from_xyz(3., 0., 3.),
+ ..default()
+ });
+}index e465f96..96bbdfe 100644
--- a/src/date.rs
+++ b/src/date.rs
@@ -1,7 +1,8 @@
=use crate::day_month::DayMonth;
=use bevy::prelude::*;
=
-const SCALE: f32 = 1.0 / 60.0;
+/// Simulation day-months per one second of real time
+const SCALE: f32 = 1.0 / 3.0;
=
=pub struct DatePlugin {
= pub start: i32,
@@ -10,6 +11,7 @@ pub struct DatePlugin {
=impl Plugin for DatePlugin {
= fn build(&self, app: &mut App) {
= app.insert_resource(Date(DayMonth::new(self.start)))
+ .add_event::<NewMonth>()
= .add_systems(Startup, setup_date_display)
= .add_systems(Update, (advance_date, update_date_display));
= }
@@ -18,12 +20,20 @@ impl Plugin for DatePlugin {
=#[derive(Resource)]
=pub struct Date(pub DayMonth);
=
-fn advance_date(time: Res<Time>, mut date: ResMut<Date>) {
- // Simulation day-months per one second of real time
+#[derive(Event)]
+pub struct NewMonth;
+
+fn advance_date(time: Res<Time>, mut date: ResMut<Date>, mut events: EventWriter<NewMonth>) {
+ let month = date.0.month();
=
= let delta = time.delta_seconds();
= let duration = delta * SCALE;
= date.0.advance(duration);
+
+ if date.0.month() != month {
+ events.send(NewMonth);
+ info!("It's a new month: {month}");
+ }
=}
=
=// TODO: Consider if date display logic should go to a UI module?index 4cff36a..49869dd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,9 +1,11 @@
+mod buildings;
=mod camera;
=mod date;
=mod day_month;
=mod sun;
=
=use bevy::prelude::*;
+use buildings::BuildingsPlugin;
=use date::DatePlugin;
=use std::f32::consts::FRAC_PI_2;
=
@@ -23,9 +25,10 @@ fn main() {
= distance: 12.,
= rps: 0.01,
= }))
+ .add_plugins(BuildingsPlugin)
= .add_plugins(DatePlugin { start: 1850 })
= .add_plugins(sun::SunPlugin)
- .add_systems(Startup, (greet, setup_ground, setup_house, setup_sculpture))
+ .add_systems(Startup, (greet, setup_ground))
= .run()
=}
=
@@ -50,23 +53,3 @@ fn setup_ground(
= ..default()
= });
=}
-
-fn setup_house(mut commands: Commands, assets: ResMut<AssetServer>) {
- let model = assets.load("large_buildingB.glb#Scene0");
-
- commands.spawn(SceneBundle {
- scene: model,
- transform: Transform::from_xyz(0., 0., 0.),
- ..default()
- });
-}
-
-fn setup_sculpture(mut commands: Commands, assets: ResMut<AssetServer>) {
- let model = assets.load("suzanne.glb#Scene0");
-
- commands.spawn(SceneBundle {
- scene: model,
- transform: Transform::from_xyz(3., 0., 3.),
- ..default()
- });
-}Let the houses stand in rows of 6
On by
Just so it looks a bit more like a city :P
index 4571974..9f08152 100644
--- a/src/buildings.rs
+++ b/src/buildings.rs
@@ -23,15 +23,20 @@ fn build(
= return;
= }
=
- info!("New month - new building!");
-
= let model = assets.load("large_buildingB.glb#Scene0");
= let count = buildings.into_iter().count();
=
+ const ROWS: usize = 6;
+ const DISTANCE: usize = 2;
+ let x = (count.rem_euclid(ROWS) * DISTANCE) as f32;
+ let z = (count / ROWS * DISTANCE) as f32;
+
+ info!("New month - new building at ({x:.2}, {z:.2})!");
+
= commands
= .spawn(SceneBundle {
= scene: model,
- transform: Transform::from_xyz(count as f32 * 2., 0., 0.),
+ transform: Transform::from_xyz(x, 0., z),
= ..default()
= })
= .insert(Building);Prevent negative luminosity at night
On by
The night sun was emitting negative light from under the ground :O
index 6edaa37..7d25d8c 100644
--- a/src/sun.rs
+++ b/src/sun.rs
@@ -59,7 +59,7 @@ fn update_sunlight_color(mut sun: Query<&mut DirectionalLight, With<Sun>>, date:
= let mut sun = sun.single_mut();
= sun.color.set_h(hue);
= sun.color.set_l(lightness);
- sun.illuminance = illuminance;
+ sun.illuminance = illuminance.max(0.0);
=}
=
=// TODO: Add ambient light. As it is, at noon shadows are too dark.Prevent initial flash of white before game loads
On by
Make the game canvas' background dark gray. Easier on eyes.
index d11a782..e73b292 100644
--- a/index.html
+++ b/index.html
@@ -26,6 +26,7 @@
= #game-canvas {
= width: 100%;
= height: 100%;
+ background: hsl(0, 0%, 10%);
= }
= </style>
= <script type="text/javascript">Separate ground logic to a plugin
On by
new file mode 100644
index 0000000..f2a6489
--- /dev/null
+++ b/src/ground.rs
@@ -0,0 +1,33 @@
+use bevy::prelude::*;
+use std::f32::consts::FRAC_PI_2;
+
+pub struct GroundPlugin;
+
+impl Plugin for GroundPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_systems(Startup, setup_ground);
+ }
+}
+
+#[derive(Component)]
+struct Ground;
+
+fn setup_ground(
+ mut commands: Commands,
+ mut meshes: ResMut<Assets<Mesh>>,
+ mut materials: ResMut<Assets<StandardMaterial>>,
+) {
+ const SIZE: f32 = 100.;
+ commands
+ .spawn(PbrBundle {
+ mesh: meshes.add(Circle::new(SIZE)),
+ material: materials.add(StandardMaterial {
+ base_color: Color::hsl(150.0, 0.3, 0.3),
+ perceptual_roughness: 0.8,
+ ..default()
+ }),
+ transform: Transform::from_rotation(Quat::from_rotation_x(-FRAC_PI_2)),
+ ..default()
+ })
+ .insert(Ground);
+}index 49869dd..92e8ebd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,12 +2,13 @@ mod buildings;
=mod camera;
=mod date;
=mod day_month;
+mod ground;
=mod sun;
=
=use bevy::prelude::*;
=use buildings::BuildingsPlugin;
=use date::DatePlugin;
-use std::f32::consts::FRAC_PI_2;
+use ground::GroundPlugin;
=
=fn main() {
= App::new()
@@ -25,10 +26,11 @@ fn main() {
= distance: 12.,
= rps: 0.01,
= }))
+ .add_plugins(GroundPlugin)
= .add_plugins(BuildingsPlugin)
= .add_plugins(DatePlugin { start: 1850 })
= .add_plugins(sun::SunPlugin)
- .add_systems(Startup, (greet, setup_ground))
+ .add_systems(Startup, greet)
= .run()
=}
=
@@ -36,20 +38,4 @@ fn greet() {
= info!("Let's build the city on rock and roll!")
=}
=
-fn setup_ground(
- mut commands: Commands,
- mut meshes: ResMut<Assets<Mesh>>,
- mut materials: ResMut<Assets<StandardMaterial>>,
-) {
- const SIZE: f32 = 100.;
- commands.spawn(PbrBundle {
- mesh: meshes.add(Circle::new(SIZE)),
- material: materials.add(StandardMaterial {
- base_color: Color::hsl(150.0, 0.3, 0.3),
- perceptual_roughness: 0.8,
- ..default()
- }),
- transform: Transform::from_rotation(Quat::from_rotation_x(-FRAC_PI_2)),
- ..default()
- });
=}Code consistency: use unqualified SunPlugin
On by
Just so it's consistent with other plugins.
index 92e8ebd..fc88b87 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -9,6 +9,7 @@ use bevy::prelude::*;
=use buildings::BuildingsPlugin;
=use date::DatePlugin;
=use ground::GroundPlugin;
+use sun::SunPlugin;
=
=fn main() {
= App::new()
@@ -29,7 +30,7 @@ fn main() {
= .add_plugins(GroundPlugin)
= .add_plugins(BuildingsPlugin)
= .add_plugins(DatePlugin { start: 1850 })
- .add_plugins(sun::SunPlugin)
+ .add_plugins(SunPlugin)
= .add_systems(Startup, greet)
= .run()
=}Introduce game states: Simulate and Explore
On by
The program starts in Simulate state and switches to Explore after a year. For now the state doesn't influence any systems, but it will.
index 76c684e..135daa4 100644
--- a/src/day_month.rs
+++ b/src/day_month.rs
@@ -74,47 +74,50 @@ mod month_tests {
=}
=
=/// Represents a month in a day
+#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
=pub struct DayMonth {
- /// How many daymonths have passed since the start
- value: f32,
- /// The first year when the city was founded
- start: i32,
+ /// The current year
+ year: i32,
+ /// How many daymonths have passed since the start of the year.
+ ///
+ /// From 0.0 (inclusive) to 12.0 (exclusive).
+ month: f32,
=}
=
=impl DayMonth {
= /// Initialize the day-month. Returns beginning (midnight) of the January of a given start year.
= pub fn new(year: i32) -> Self {
- Self {
- start: year,
- value: 0.0,
- }
+ Self { year, month: 0.0 }
= }
=
= pub fn advance(&mut self, duration: f32) -> &Self {
- self.value += duration;
+ let month = self.month + duration;
+
+ self.month = month.rem_euclid(12.0);
+ self.year += month.div_euclid(12.0).floor() as i32;
= self
= }
=
= pub fn year(&self) -> i32 {
- self.value.div_euclid(12.0) as i32 + self.start
+ self.year
= }
=
= pub fn month(&self) -> Month {
- Month::new(self.value as i32 + 1)
+ Month::new(self.month as i32 + 1)
= }
=
= pub fn hour(&self) -> i32 {
- (self.value.rem_euclid(1.0) * 24.0) as i32
+ (self.month.rem_euclid(1.0) * 24.0) as i32
= }
=
= pub fn minute(&self) -> f32 {
= // TODO: Can minutes calculation be simplified for efficiency?
- (self.value.rem_euclid(1.0) * 24.0).rem_euclid(1.0) * 60.0
+ (self.month.rem_euclid(1.0) * 24.0).rem_euclid(1.0) * 60.0
= }
=
= /// Return a number between 0.0 and 1.0 representing the fraction of the day that passed
= pub fn time_of_day(&self) -> f32 {
- self.value.rem_euclid(1.0)
+ self.month.rem_euclid(1.0)
= }
=}
=
@@ -169,4 +172,15 @@ mod daymonth_tests {
= daymonth.advance(12. * HOUR);
= assert_eq!(format!("{daymonth}"), "April 1984 01:45");
= }
+
+ #[test]
+ fn order_and_compare() {
+ assert_eq!(DayMonth::new(2000), DayMonth::new(2000));
+
+ assert!(DayMonth::new(2000) < DayMonth::new(2001));
+ assert!(DayMonth::new(2001) > DayMonth::new(2000));
+ assert!(DayMonth::new(2000) < DayMonth::new(2000).advance(1.0).to_owned());
+ assert!(DayMonth::new(2001) < DayMonth::new(2000).advance(12.5).to_owned());
+ assert!(DayMonth::new(2000) > DayMonth::new(2000).advance(-0.1).to_owned());
+ }
=}index fc88b87..d64a204 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,7 +7,10 @@ mod sun;
=
=use bevy::prelude::*;
=use buildings::BuildingsPlugin;
+use date::Date;
=use date::DatePlugin;
+use date::NewMonth;
+use day_month::DayMonth;
=use ground::GroundPlugin;
=use sun::SunPlugin;
=
@@ -22,6 +25,7 @@ fn main() {
= }),
= ..default()
= }))
+ .init_state::<GameState>()
= .add_plugins(camera::CameraPlugin(camera::CameraSettings {
= elevation: 5.,
= distance: 12.,
@@ -32,6 +36,8 @@ fn main() {
= .add_plugins(DatePlugin { start: 1850 })
= .add_plugins(SunPlugin)
= .add_systems(Startup, greet)
+ .add_systems(Update, switch_states)
+ .add_systems(OnEnter(GameState::Explore), setup_exploration)
= .run()
=}
=
@@ -39,4 +45,27 @@ fn greet() {
= info!("Let's build the city on rock and roll!")
=}
=
+#[derive(States, Debug, Default, Clone, Copy, Hash, PartialEq, Eq)]
+enum GameState {
+ #[default]
+ Simulate,
+ Explore,
+}
+
+fn switch_states(
+ mut new_month_events: EventReader<NewMonth>,
+ date: Res<Date>,
+ mut state: ResMut<NextState<GameState>>,
+) {
+ if new_month_events.read().count() == 0 {
+ return;
+ }
+
+ if date.0 > DayMonth::new(1851) {
+ state.set(GameState::Explore)
+ }
+}
+
+fn setup_exploration() {
+ info!("Now exploring!")
=}Decouple construction orders from construction
On by
Construction order is a decision to construct a new house. They are only issued in the Simulate state. The spawning of a new building follows the construction order. The goal is to have a history system that will store the orders in Simulate state and re-issue them in Explore state.
Technically ConstructionOrder is an event.
I removed the logic related to the little sculpture. It would need to be updated, but it's not worth the effort. I only added it to get a hand on working with GLTF models in the first place.
index 9f08152..4c6767a 100644
--- a/src/buildings.rs
+++ b/src/buildings.rs
@@ -1,29 +1,43 @@
=use crate::date::NewMonth;
+use crate::GameState;
=use bevy::prelude::*;
=
=pub struct BuildingsPlugin;
=
=impl Plugin for BuildingsPlugin {
= fn build(&self, app: &mut App) {
- app.add_systems(Startup, setup_sculpture)
- .add_systems(Update, build);
+ app.add_event::<ConstructionOrder>()
+ .add_systems(
+ Update,
+ order_construction.run_if(in_state(GameState::Simulate)),
+ )
+ .add_systems(Update, spawn_buildings);
= }
=}
=
+/// This event represents a decision to construct a new building.
+///
+/// It will be stored in the history, and will result in spawning a new building.
+#[derive(Event, Clone, Copy)]
+pub struct ConstructionOrder {
+ pub x: f32,
+ pub z: f32,
+}
+
+/// A tag for building entities
=#[derive(Component)]
=struct Building;
=
-fn build(
- mut commands: Commands,
- assets: ResMut<AssetServer>,
- mut new_month: EventReader<NewMonth>,
+/// Issue a construction order, for the record and effect
+fn order_construction(
+ mut new_month_events: EventReader<NewMonth>,
+ mut build_events: EventWriter<ConstructionOrder>,
= buildings: Query<&Building>,
=) {
- if new_month.read().count() == 0 {
+ if new_month_events.read().count() == 0 {
= return;
= }
=
- let model = assets.load("large_buildingB.glb#Scene0");
= let count = buildings.into_iter().count();
=
= const ROWS: usize = 6;
@@ -31,23 +45,28 @@ fn build(
= let x = (count.rem_euclid(ROWS) * DISTANCE) as f32;
= let z = (count / ROWS * DISTANCE) as f32;
=
- info!("New month - new building at ({x:.2}, {z:.2})!");
+ info!("Ordering a new construction at ({x:.2}, {z:.2})!");
=
- commands
- .spawn(SceneBundle {
- scene: model,
- transform: Transform::from_xyz(x, 0., z),
- ..default()
- })
- .insert(Building);
+ build_events.send(ConstructionOrder { x, z });
=}
=
-fn setup_sculpture(mut commands: Commands, assets: ResMut<AssetServer>) {
- let model = assets.load("suzanne.glb#Scene0");
+/// Implement the construction orders
+fn spawn_buildings(
+ mut commands: Commands,
+ assets: ResMut<AssetServer>,
+ mut construction_orders: EventReader<ConstructionOrder>,
+) {
+ for ConstructionOrder { x, z } in construction_orders.read() {
+ let model = assets.load("large_buildingB.glb#Scene0");
=
- commands.spawn(SceneBundle {
- scene: model,
- transform: Transform::from_xyz(3., 0., 3.),
- ..default()
- });
+ info!("Spawning a new building at ({x:.2}, {z:.2})!");
+
+ commands
+ .spawn(SceneBundle {
+ scene: model,
+ transform: Transform::from_xyz(*x, 0., *z),
+ ..default()
+ })
+ .insert(Building);
+ }
=}Update dependencies (Nix and Cargo)
On by
Mostly I want a new rust-analyzer, as the current version is affected by https://github.com/rust-lang/rust-analyzer/issues/16614. But it's a good hygiene to upgrade the rest too.
index be9d0ed..599fc8b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -80,9 +80,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
=
=[[package]]
=name = "ahash"
-version = "0.8.9"
+version = "0.8.10"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f"
+checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b"
=dependencies = [
= "cfg-if",
= "getrandom",
@@ -223,7 +223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3"
=dependencies = [
= "concurrent-queue",
- "event-listener 5.1.0",
+ "event-listener 5.2.0",
= "event-listener-strategy 0.5.0",
= "futures-core",
= "pin-project-lite",
@@ -386,7 +386,7 @@ dependencies = [
= "bevy_macro_utils",
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -452,7 +452,7 @@ checksum = "028ae2a34678055185d7f1beebb1ebe6a8dcf3733e139e4ee1383a7f29ae8ba6"
=dependencies = [
= "bevy_macro_utils",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -500,7 +500,7 @@ dependencies = [
= "bevy_macro_utils",
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -560,7 +560,7 @@ dependencies = [
= "bevy_macro_utils",
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -686,7 +686,7 @@ dependencies = [
= "proc-macro2",
= "quote",
= "rustc-hash",
- "syn 2.0.51",
+ "syn 2.0.52",
= "toml_edit 0.21.1",
=]
=
@@ -767,7 +767,7 @@ dependencies = [
= "bevy_macro_utils",
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
= "uuid",
=]
=
@@ -825,7 +825,7 @@ dependencies = [
= "bevy_macro_utils",
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -993,7 +993,7 @@ checksum = "31ae98e9c0c08b0f5c90e22cd713201f759b98d4fd570b99867a695f8641859a"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -1055,7 +1055,7 @@ dependencies = [
= "regex",
= "rustc-hash",
= "shlex",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -1184,7 +1184,7 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -1483,9 +1483,9 @@ dependencies = [
=
=[[package]]
=name = "crossbeam-channel"
-version = "0.5.11"
+version = "0.5.12"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"
+checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95"
=dependencies = [
= "crossbeam-utils",
=]
@@ -1594,7 +1594,7 @@ checksum = "92959a9e8d13eaa13b8ae8c7b583c3bf1669ca7a8e7708a088d12587ba86effc"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -1650,9 +1650,9 @@ dependencies = [
=
=[[package]]
=name = "event-listener"
-version = "5.1.0"
+version = "5.2.0"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7ad6fd685ce13acd6d9541a30f6db6567a7a24c9ffd4ba2955d29e3f22c8b27"
+checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91"
=dependencies = [
= "concurrent-queue",
= "parking",
@@ -1675,7 +1675,7 @@ version = "0.5.0"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291"
=dependencies = [
- "event-listener 5.1.0",
+ "event-listener 5.2.0",
= "pin-project-lite",
=]
=
@@ -1734,7 +1734,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -1885,7 +1885,7 @@ dependencies = [
= "inflections",
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -2056,9 +2056,9 @@ dependencies = [
=
=[[package]]
=name = "indexmap"
-version = "2.2.3"
+version = "2.2.5"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
+checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
=dependencies = [
= "equivalent",
= "hashbrown",
@@ -2288,9 +2288,9 @@ dependencies = [
=
=[[package]]
=name = "log"
-version = "0.4.20"
+version = "0.4.21"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
=
=[[package]]
=name = "mach2"
@@ -2367,9 +2367,9 @@ dependencies = [
=
=[[package]]
=name = "naga"
-version = "0.19.0"
+version = "0.19.2"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8878eb410fc90853da3908aebfe61d73d26d4437ef850b70050461f939509899"
+checksum = "50e3524642f53d9af419ab5e8dd29d3ba155708267667c2f3f06c88c9e130843"
=dependencies = [
= "bit-set",
= "bitflags 2.4.2",
@@ -2575,7 +2575,7 @@ dependencies = [
= "proc-macro-crate 3.1.0",
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -3145,7 +3145,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -3281,9 +3281,9 @@ dependencies = [
=
=[[package]]
=name = "syn"
-version = "2.0.51"
+version = "2.0.52"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c"
+checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
=dependencies = [
= "proc-macro2",
= "quote",
@@ -3342,7 +3342,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -3442,7 +3442,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]
=
=[[package]]
@@ -3611,7 +3611,7 @@ dependencies = [
= "once_cell",
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
= "wasm-bindgen-shared",
=]
=
@@ -3645,7 +3645,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
= "wasm-bindgen-backend",
= "wasm-bindgen-shared",
=]
@@ -3786,9 +3786,9 @@ dependencies = [
=
=[[package]]
=name = "wgpu"
-version = "0.19.1"
+version = "0.19.2"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bfe9a310dcf2e6b85f00c46059aaeaf4184caa8e29a1ecd4b7a704c3482332d"
+checksum = "f9274d073bfb0cad6c53c575d3f4815617c9ccc134cba3ead1fa5fa51e71595c"
=dependencies = [
= "arrayvec",
= "cfg-if",
@@ -3811,9 +3811,9 @@ dependencies = [
=
=[[package]]
=name = "wgpu-core"
-version = "0.19.0"
+version = "0.19.2"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b15e451d4060ada0d99a64df44e4d590213496da7c4f245572d51071e8e30ed"
+checksum = "0c8bb6a5c62ad78bd683609d525cde6efb6e7cf39e008ea0b8e42518ce18ea81"
=dependencies = [
= "arrayvec",
= "bit-vec",
@@ -3837,9 +3837,9 @@ dependencies = [
=
=[[package]]
=name = "wgpu-hal"
-version = "0.19.1"
+version = "0.19.2"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3bb47856236bfafc0bc591a925eb036ac19cd987624a447ff353e7a7e7e6f72"
+checksum = "cb7b9a56d44851cc0f51bf2f8b5ed8af5cf6e4bdb178fd5786ea2b4771e2edf0"
=dependencies = [
= "android_system_properties",
= "arrayvec",
@@ -3881,9 +3881,9 @@ dependencies = [
=
=[[package]]
=name = "wgpu-types"
-version = "0.19.0"
+version = "0.19.2"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "895fcbeb772bfb049eb80b2d6e47f6c9af235284e9703c96fc0218a42ffd5af2"
+checksum = "b671ff9fb03f78b46ff176494ee1ebe7d603393f42664be55b64dc8d53969805"
=dependencies = [
= "bitflags 2.4.2",
= "js-sys",
@@ -3954,7 +3954,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
=dependencies = [
= "windows-core",
- "windows-targets 0.52.3",
+ "windows-targets 0.52.4",
=]
=
=[[package]]
@@ -3963,7 +3963,7 @@ version = "0.52.0"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
=dependencies = [
- "windows-targets 0.52.3",
+ "windows-targets 0.52.4",
=]
=
=[[package]]
@@ -4012,7 +4012,7 @@ version = "0.52.0"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
=dependencies = [
- "windows-targets 0.52.3",
+ "windows-targets 0.52.4",
=]
=
=[[package]]
@@ -4047,17 +4047,17 @@ dependencies = [
=
=[[package]]
=name = "windows-targets"
-version = "0.52.3"
+version = "0.52.4"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f"
+checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
=dependencies = [
- "windows_aarch64_gnullvm 0.52.3",
- "windows_aarch64_msvc 0.52.3",
- "windows_i686_gnu 0.52.3",
- "windows_i686_msvc 0.52.3",
- "windows_x86_64_gnu 0.52.3",
- "windows_x86_64_gnullvm 0.52.3",
- "windows_x86_64_msvc 0.52.3",
+ "windows_aarch64_gnullvm 0.52.4",
+ "windows_aarch64_msvc 0.52.4",
+ "windows_i686_gnu 0.52.4",
+ "windows_i686_msvc 0.52.4",
+ "windows_x86_64_gnu 0.52.4",
+ "windows_x86_64_gnullvm 0.52.4",
+ "windows_x86_64_msvc 0.52.4",
=]
=
=[[package]]
@@ -4074,9 +4074,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
=
=[[package]]
=name = "windows_aarch64_gnullvm"
-version = "0.52.3"
+version = "0.52.4"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6"
+checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
=
=[[package]]
=name = "windows_aarch64_msvc"
@@ -4092,9 +4092,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
=
=[[package]]
=name = "windows_aarch64_msvc"
-version = "0.52.3"
+version = "0.52.4"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f"
+checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
=
=[[package]]
=name = "windows_i686_gnu"
@@ -4110,9 +4110,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
=
=[[package]]
=name = "windows_i686_gnu"
-version = "0.52.3"
+version = "0.52.4"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb"
+checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
=
=[[package]]
=name = "windows_i686_msvc"
@@ -4128,9 +4128,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
=
=[[package]]
=name = "windows_i686_msvc"
-version = "0.52.3"
+version = "0.52.4"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58"
+checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
=
=[[package]]
=name = "windows_x86_64_gnu"
@@ -4146,9 +4146,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
=
=[[package]]
=name = "windows_x86_64_gnu"
-version = "0.52.3"
+version = "0.52.4"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614"
+checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
=
=[[package]]
=name = "windows_x86_64_gnullvm"
@@ -4164,9 +4164,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
=
=[[package]]
=name = "windows_x86_64_gnullvm"
-version = "0.52.3"
+version = "0.52.4"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c"
+checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
=
=[[package]]
=name = "windows_x86_64_msvc"
@@ -4182,9 +4182,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
=
=[[package]]
=name = "windows_x86_64_msvc"
-version = "0.52.3"
+version = "0.52.4"
=source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
+checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
=
=[[package]]
=name = "winit"
@@ -4329,5 +4329,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
=dependencies = [
= "proc-macro2",
= "quote",
- "syn 2.0.51",
+ "syn 2.0.52",
=]index e352084..e4f7bad 100644
--- a/flake.lock
+++ b/flake.lock
@@ -5,11 +5,11 @@
= "systems": "systems"
= },
= "locked": {
- "lastModified": 1705309234,
- "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
+ "lastModified": 1709126324,
+ "narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
= "owner": "numtide",
= "repo": "flake-utils",
- "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
+ "rev": "d465f4819400de7c8d874d50b982301f28a84605",
= "type": "github"
= },
= "original": {
@@ -38,11 +38,11 @@
= },
= "nixpkgs": {
= "locked": {
- "lastModified": 1708807242,
- "narHash": "sha256-sRTRkhMD4delO/hPxxi+XwLqPn8BuUq6nnj4JqLwOu0=",
+ "lastModified": 1709150264,
+ "narHash": "sha256-HofykKuisObPUfj0E9CJVfaMhawXkYx3G8UIFR/XQ38=",
= "owner": "NixOS",
= "repo": "nixpkgs",
- "rev": "73de017ef2d18a04ac4bfd0c02650007ccb31c2a",
+ "rev": "9099616b93301d5cf84274b184a3a5ec69e94e08",
= "type": "github"
= },
= "original": {
@@ -81,11 +81,11 @@
= "nixpkgs": "nixpkgs_2"
= },
= "locked": {
- "lastModified": 1708913568,
- "narHash": "sha256-76PGANC2ADf0h7fe0w2nWpfdGN+bemFs2rvW2EdU/ZY=",
+ "lastModified": 1709172595,
+ "narHash": "sha256-0oYeE5VkhnPA7YBl+0Utq2cYoHcfsEhSGwraCa27Vs8=",
= "owner": "oxalica",
= "repo": "rust-overlay",
- "rev": "cbdf3e5bb205ff2ca165fe661fbd6d885cbd0106",
+ "rev": "72fa0217f76020ad3aeb2dd9dd72490905b23b6f",
= "type": "github"
= },
= "original": {The date progression will stop as the sim is done
On by
On the last day-month of the experiment (currently January 1861) the time slows down to a halt at 09:32.
The beginning and duration of the experiment are constants again. Later probably we will want to place them as a resource in the world. But for now it's just easier.
index 96bbdfe..2087dd2 100644
--- a/src/date.rs
+++ b/src/date.rs
@@ -1,16 +1,15 @@
-use crate::day_month::DayMonth;
+use crate::day_month::{DayMonth, HOUR, MINUTE};
+use crate::{GameState, BEGINNING, DURATION};
=use bevy::prelude::*;
=
=/// Simulation day-months per one second of real time
=const SCALE: f32 = 1.0 / 3.0;
=
-pub struct DatePlugin {
- pub start: i32,
-}
+pub struct DatePlugin;
=
=impl Plugin for DatePlugin {
= fn build(&self, app: &mut App) {
- app.insert_resource(Date(DayMonth::new(self.start)))
+ app.insert_resource(Date(DayMonth::new(BEGINNING)))
= .add_event::<NewMonth>()
= .add_systems(Startup, setup_date_display)
= .add_systems(Update, (advance_date, update_date_display));
@@ -24,10 +23,18 @@ pub struct Date(pub DayMonth);
=pub struct NewMonth;
=
=fn advance_date(time: Res<Time>, mut date: ResMut<Date>, mut events: EventWriter<NewMonth>) {
+ // Do not go much over the duration, but gently slow down after
+ const ENDTIME: f32 = (9.0 * HOUR + 32.0 * MINUTE);
+ let scale = if date.0.year() < (BEGINNING + DURATION) {
+ SCALE
+ } else {
+ SCALE * (ENDTIME - date.0.time_of_day()).max(0.0)
+ };
+
= let month = date.0.month();
=
= let delta = time.delta_seconds();
- let duration = delta * SCALE;
+ let duration = delta * scale;
= date.0.advance(duration);
=
= if date.0.month() != month {index d64a204..134d4b0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -14,6 +14,9 @@ use day_month::DayMonth;
=use ground::GroundPlugin;
=use sun::SunPlugin;
=
+const BEGINNING: i32 = 1860;
+const DURATION: i32 = 1;
+
=fn main() {
= App::new()
= .add_plugins(DefaultPlugins.set(WindowPlugin {
@@ -33,7 +36,7 @@ fn main() {
= }))
= .add_plugins(GroundPlugin)
= .add_plugins(BuildingsPlugin)
- .add_plugins(DatePlugin { start: 1850 })
+ .add_plugins(DatePlugin)
= .add_plugins(SunPlugin)
= .add_systems(Startup, greet)
= .add_systems(Update, switch_states)
@@ -61,7 +64,7 @@ fn switch_states(
= return;
= }
=
- if date.0 > DayMonth::new(1851) {
+ if date.0 > DayMonth::new(BEGINNING + DURATION) {
= state.set(GameState::Explore)
= }
=}Implement POC snapshots and rollback (time travel)
On by
The events are stored, but not played back yet.
index 599fc8b..4c1f6cb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -179,6 +179,25 @@ dependencies = [
= "num-traits",
=]
=
+[[package]]
+name = "arboard"
+version = "3.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1faa3c733d9a3dd6fbaf85da5d162a2e03b2e0033a90dceb0e2a90fdd1e5380a"
+dependencies = [
+ "clipboard-win",
+ "core-graphics",
+ "image",
+ "log",
+ "objc",
+ "objc-foundation",
+ "objc_id",
+ "parking_lot",
+ "thiserror",
+ "windows-sys 0.48.0",
+ "x11rb",
+]
+
=[[package]]
=name = "arrayref"
=version = "0.3.7"
@@ -503,6 +522,20 @@ dependencies = [
= "syn 2.0.52",
=]
=
+[[package]]
+name = "bevy_egui"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b84bfb8d4104a1467910cf2090bc6a6d394ebde39c0dbc02397b45aa9ef88e80"
+dependencies = [
+ "arboard",
+ "bevy",
+ "egui",
+ "thread_local",
+ "web-sys",
+ "webbrowser",
+]
+
=[[package]]
=name = "bevy_encase_derive"
=version = "0.13.0"
@@ -1272,6 +1305,15 @@ dependencies = [
= "libloading 0.8.1",
=]
=
+[[package]]
+name = "clipboard-win"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12f9a0700e0127ba15d1d52dd742097f821cd9c65939303a44d970465040a297"
+dependencies = [
+ "error-code",
+]
+
=[[package]]
=name = "codespan-reporting"
=version = "0.11.1"
@@ -1559,12 +1601,41 @@ version = "1.2.0"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
=
+[[package]]
+name = "ecolor"
+version = "0.26.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03cfe80b1890e1a8cdbffc6044d6872e814aaf6011835a2a5e2db0e5c5c4ef4e"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "egui"
+version = "0.26.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "180f595432a5b615fc6b74afef3955249b86cfea72607b40740a4cd60d5297d0"
+dependencies = [
+ "ahash",
+ "epaint",
+ "nohash-hasher",
+]
+
=[[package]]
=name = "either"
=version = "1.10.0"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
=
+[[package]]
+name = "emath"
+version = "0.26.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6916301ecf80448f786cdf3eb51d9dbdd831538732229d49119e2d4312eaaf09"
+dependencies = [
+ "bytemuck",
+]
+
=[[package]]
=name = "encase"
=version = "0.7.0"
@@ -1597,6 +1668,21 @@ dependencies = [
= "syn 2.0.52",
=]
=
+[[package]]
+name = "epaint"
+version = "0.26.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77b9fdf617dd7f58b0c8e6e9e4a1281f730cde0831d40547da446b2bb76a47af"
+dependencies = [
+ "ab_glyph",
+ "ahash",
+ "bytemuck",
+ "ecolor",
+ "emath",
+ "nohash-hasher",
+ "parking_lot",
+]
+
=[[package]]
=name = "equivalent"
=version = "1.0.1"
@@ -1622,6 +1708,12 @@ dependencies = [
= "windows-sys 0.52.0",
=]
=
+[[package]]
+name = "error-code"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b"
+
=[[package]]
=name = "euclid"
=version = "0.22.9"
@@ -1743,6 +1835,15 @@ version = "0.3.1"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
=
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
=[[package]]
=name = "futures-core"
=version = "0.3.30"
@@ -2030,6 +2131,15 @@ version = "0.2.1"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
=
+[[package]]
+name = "home"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
=[[package]]
=name = "icrate"
=version = "0.0.4"
@@ -2041,6 +2151,16 @@ dependencies = [
= "objc2 0.4.1",
=]
=
+[[package]]
+name = "idna"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
=[[package]]
=name = "image"
=version = "0.24.9"
@@ -2052,6 +2172,7 @@ dependencies = [
= "color_quant",
= "num-traits",
= "png",
+ "tiff",
=]
=
=[[package]]
@@ -2165,6 +2286,12 @@ version = "0.3.0"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
=
+[[package]]
+name = "jpeg-decoder"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
+
=[[package]]
=name = "js-sys"
=version = "0.3.68"
@@ -2481,6 +2608,12 @@ dependencies = [
= "libc",
=]
=
+[[package]]
+name = "nohash-hasher"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
+
=[[package]]
=name = "nom"
=version = "7.1.3"
@@ -2588,6 +2721,17 @@ dependencies = [
= "objc_exception",
=]
=
+[[package]]
+name = "objc-foundation"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
+dependencies = [
+ "block",
+ "objc",
+ "objc_id",
+]
+
=[[package]]
=name = "objc-sys"
=version = "0.2.0-beta.2"
@@ -2645,6 +2789,15 @@ dependencies = [
= "cc",
=]
=
+[[package]]
+name = "objc_id"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
+dependencies = [
+ "objc",
+]
+
=[[package]]
=name = "oboe"
=version = "0.5.0"
@@ -2697,6 +2850,7 @@ name = "otterhide"
=version = "0.1.0"
=dependencies = [
= "bevy",
+ "bevy_egui",
= "derive_more",
= "itertools",
= "js-sys",
@@ -3355,6 +3509,17 @@ dependencies = [
= "once_cell",
=]
=
+[[package]]
+name = "tiff"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
+dependencies = [
+ "flate2",
+ "jpeg-decoder",
+ "weezl",
+]
+
=[[package]]
=name = "tiny-skia"
=version = "0.11.4"
@@ -3522,12 +3687,27 @@ dependencies = [
= "static_assertions",
=]
=
+[[package]]
+name = "unicode-bidi"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+
=[[package]]
=name = "unicode-ident"
=version = "1.0.12"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
=
+[[package]]
+name = "unicode-normalization"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
+dependencies = [
+ "tinyvec",
+]
+
=[[package]]
=name = "unicode-segmentation"
=version = "1.11.0"
@@ -3546,6 +3726,17 @@ version = "0.2.4"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
=
+[[package]]
+name = "url"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
=[[package]]
=name = "uuid"
=version = "1.7.0"
@@ -3784,6 +3975,29 @@ dependencies = [
= "wasm-bindgen",
=]
=
+[[package]]
+name = "webbrowser"
+version = "0.8.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82b2391658b02c27719fc5a0a73d6e696285138e8b12fba9d4baa70451023c71"
+dependencies = [
+ "core-foundation",
+ "home",
+ "jni 0.21.1",
+ "log",
+ "ndk-context",
+ "objc",
+ "raw-window-handle 0.5.2",
+ "url",
+ "web-sys",
+]
+
+[[package]]
+name = "weezl"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
+
=[[package]]
=name = "wgpu"
=version = "0.19.2"index 82a0963..6670181 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
=
=[dependencies]
=bevy = { version = "0.13", features = ["wayland"] }
+bevy_egui = "0.25.0"
=derive_more = "0.99.17"
=itertools = "0.12.1"
=js-sys = "0.3.68"index 4c6767a..1abb8c0 100644
--- a/src/buildings.rs
+++ b/src/buildings.rs
@@ -1,4 +1,5 @@
=use crate::date::NewMonth;
+use crate::history::TimeTravelRequest;
=use crate::GameState;
=use bevy::prelude::*;
=
@@ -11,7 +12,8 @@ impl Plugin for BuildingsPlugin {
= Update,
= order_construction.run_if(in_state(GameState::Simulate)),
= )
- .add_systems(Update, spawn_buildings);
+ .add_systems(Update, spawn_buildings)
+ .add_systems(Update, rollback);
= }
=}
=
@@ -26,7 +28,7 @@ pub struct ConstructionOrder {
=
=/// A tag for building entities
=#[derive(Component)]
-struct Building;
+pub struct Building;
=
=/// Issue a construction order, for the record and effect
=fn order_construction(
@@ -70,3 +72,29 @@ fn spawn_buildings(
= .insert(Building);
= }
=}
+
+fn rollback(
+ mut requests: EventReader<TimeTravelRequest>,
+ buildings: Query<Entity, With<Building>>,
+ assets: ResMut<AssetServer>,
+ mut commands: Commands,
+) {
+ for TimeTravelRequest(snapshot) in requests.read() {
+ for entity in buildings.iter() {
+ commands.entity(entity).despawn_recursive();
+ }
+
+ for transform in snapshot.clone().buildings {
+ // TODO: DRY with spawn_buildings
+ let model = assets.load("large_buildingB.glb#Scene0");
+
+ commands
+ .spawn(SceneBundle {
+ scene: model,
+ transform: transform.clone(),
+ ..default()
+ })
+ .insert(Building);
+ }
+ }
+}index 2087dd2..586e532 100644
--- a/src/date.rs
+++ b/src/date.rs
@@ -1,9 +1,10 @@
=use crate::day_month::{DayMonth, HOUR, MINUTE};
+use crate::history::TimeTravelRequest;
=use crate::{GameState, BEGINNING, DURATION};
=use bevy::prelude::*;
=
=/// Simulation day-months per one second of real time
-const SCALE: f32 = 1.0 / 3.0;
+const SCALE: f32 = 1.0 / 60.0;
=
=pub struct DatePlugin;
=
@@ -12,7 +13,8 @@ impl Plugin for DatePlugin {
= app.insert_resource(Date(DayMonth::new(BEGINNING)))
= .add_event::<NewMonth>()
= .add_systems(Startup, setup_date_display)
- .add_systems(Update, (advance_date, update_date_display));
+ .add_systems(Update, (advance_date, update_date_display))
+ .add_systems(Update, rollback);
= }
=}
=
@@ -22,13 +24,22 @@ pub struct Date(pub DayMonth);
=#[derive(Event)]
=pub struct NewMonth;
=
-fn advance_date(time: Res<Time>, mut date: ResMut<Date>, mut events: EventWriter<NewMonth>) {
+fn advance_date(
+ time: Res<Time>,
+ mut date: ResMut<Date>,
+ mut events: EventWriter<NewMonth>,
+ game_state: Res<State<GameState>>,
+) {
= // Do not go much over the duration, but gently slow down after
- const ENDTIME: f32 = (9.0 * HOUR + 32.0 * MINUTE);
- let scale = if date.0.year() < (BEGINNING + DURATION) {
- SCALE
+ const ENDTIME: f32 = 9.0 * HOUR + 32.0 * MINUTE;
+ let mut scale = if game_state.get() == &GameState::Simulate {
+ SCALE * 120.
= } else {
- SCALE * (ENDTIME - date.0.time_of_day()).max(0.0)
+ SCALE
+ };
+
+ if date.0.year() >= (BEGINNING + DURATION) {
+ scale *= (ENDTIME - date.0.time_of_day()).max(0.0)
= };
=
= let month = date.0.month();
@@ -71,3 +82,9 @@ fn update_date_display(mut display: Query<&mut Text, With<DateDisplay>>, date: R
= let mut display = display.single_mut();
= display.sections[0].value = date.0.to_string();
=}
+
+fn rollback(mut requests: EventReader<TimeTravelRequest>, mut date: ResMut<Date>) {
+ for TimeTravelRequest(snapshot) in requests.read() {
+ date.0 = snapshot.date;
+ }
+}index 135daa4..a3c7613 100644
--- a/src/day_month.rs
+++ b/src/day_month.rs
@@ -2,8 +2,9 @@ use std::fmt::Display;
=
=pub const HOUR: f32 = 1.0 / 24.0;
=pub const MINUTE: f32 = HOUR / 60.0;
+pub const MINUTES_PER_DAYMONTH: f32 = (60 * 24) as f32;
=
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
=pub enum Month {
= January = 1,
= February,
@@ -135,6 +136,63 @@ impl Display for DayMonth {
= }
=}
=
+// TODO: Ditch the Timestamp type.
+// If we need keys at all, we can use String from a DayMonth. And maybe keys are not needed at all?
+/// Simplified DayMonth that can be used as a key in a hash map
+#[derive(PartialEq, PartialOrd, Ord, Eq, Hash, Clone, Copy)]
+pub struct Timestamp {
+ pub year: i32,
+ pub month: Month,
+ pub hour: i32,
+ pub minute: i32,
+}
+
+impl From<DayMonth> for Timestamp {
+ fn from(day_month: DayMonth) -> Self {
+ Self {
+ year: day_month.year(),
+ month: day_month.month(),
+ hour: day_month.hour(),
+ minute: day_month.minute() as i32,
+ }
+ }
+}
+
+impl From<Timestamp> for DayMonth {
+ fn from(timestamp: Timestamp) -> Self {
+ let minute = (timestamp.hour * 60 + timestamp.minute) as f32;
+
+ Self {
+ year: timestamp.year,
+ month: (timestamp.month as i32 - 1) as f32 + (minute / MINUTES_PER_DAYMONTH),
+ }
+ }
+}
+
+impl From<&Timestamp> for DayMonth {
+ fn from(timestamp: &Timestamp) -> Self {
+ let minute = (timestamp.hour * 60 + timestamp.minute) as f32;
+
+ Self {
+ year: timestamp.year,
+ month: (timestamp.month as i32 - 1) as f32 + (minute / MINUTES_PER_DAYMONTH),
+ }
+ }
+}
+
+impl Display for Timestamp {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(
+ f,
+ "{yyyy} {mmmm} {hh:02}:{mm:02}",
+ yyyy = self.year,
+ mmmm = self.month,
+ hh = self.hour,
+ mm = self.minute
+ )
+ }
+}
+
=#[cfg(test)]
=mod daymonth_tests {
= use super::*;new file mode 100644
index 0000000..634bf13
--- /dev/null
+++ b/src/explore.rs
@@ -0,0 +1,41 @@
+use crate::history::History;
+use crate::history::TimeTravelRequest;
+use bevy::prelude::*;
+use bevy_egui::egui;
+use bevy_egui::EguiContexts;
+use itertools::Itertools;
+
+pub struct ExplorePlugin;
+
+impl Plugin for ExplorePlugin {
+ fn build(&self, app: &mut App) {
+ app.add_systems(
+ Update, paint_ui, /* .run_if(in_state(GameState::Explore)) */
+ );
+ }
+}
+
+fn paint_ui(
+ mut contexts: EguiContexts,
+ history: Res<History>,
+ mut requests: EventWriter<TimeTravelRequest>,
+) {
+ egui::SidePanel::right("explore_ui").show(contexts.ctx_mut(), |ui| {
+ ui.heading("Explore");
+
+ for (timestamp, snapshot) in history
+ .snapshots
+ .iter()
+ // TODO: Consider using BTreeMap for always sorted snapshots. Or even ditch keys all together and use a vector?
+ .sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
+ {
+ let month = timestamp.month.clone();
+ let year = timestamp.year;
+ let button = ui.button(format!("{month} {year}"));
+ if button.clicked() {
+ info!("Time travel to {timestamp}");
+ requests.send(TimeTravelRequest(snapshot.clone()));
+ }
+ }
+ });
+}new file mode 100644
index 0000000..0c01085
--- /dev/null
+++ b/src/history.rs
@@ -0,0 +1,109 @@
+use crate::buildings::ConstructionOrder;
+use crate::buildings::{self, Building};
+use crate::date::{Date, NewMonth};
+use crate::day_month::{DayMonth, Timestamp};
+use crate::GameState;
+use bevy::prelude::*;
+use bevy::utils::HashMap;
+use std::fmt::Display;
+
+pub struct HistoryPlugin;
+
+impl Plugin for HistoryPlugin {
+ fn build(&self, app: &mut App) {
+ app.init_resource::<History>()
+ .add_event::<TimeTravelRequest>()
+ .add_systems(
+ PreUpdate,
+ take_snapshot.run_if(in_state(GameState::Simulate)),
+ )
+ .add_systems(
+ Update,
+ register_historical_events.run_if(in_state(GameState::Simulate)),
+ )
+ .add_systems(
+ Update,
+ time_travel, /* .run_if(in_state(GameState::Explore)) */
+ );
+ }
+}
+
+#[derive(Resource, Default)]
+pub struct History {
+ pub events: HashMap<Timestamp, Vec<HistoricalEvent>>,
+ pub snapshots: HashMap<Timestamp, Snapshot>,
+}
+
+pub enum HistoricalEvent {
+ ConstructionOrder(buildings::ConstructionOrder),
+}
+
+impl Display for HistoricalEvent {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ HistoricalEvent::ConstructionOrder(ConstructionOrder { x, z }) => {
+ write!(
+ f,
+ "construction of a new building ordered at ({x:.2}, {z:.2})",
+ )
+ }
+ }
+ }
+}
+
+fn register_historical_events(
+ mut history: ResMut<History>,
+ date: Res<Date>,
+ mut construction_orders: EventReader<ConstructionOrder>,
+) {
+ let key: Timestamp = date.0.into();
+ let historical_events = history.events.entry(key).or_insert(Vec::new());
+
+ for event in construction_orders.read() {
+ let historical_event = HistoricalEvent::ConstructionOrder(event.to_owned());
+ info!("Registering a historical event: {historical_event}");
+ historical_events.push(historical_event);
+ }
+}
+
+// TODO: Use hankjordan/bevy_save with a custom pipeline
+// See https://github.com/hankjordan/bevy_save/blob/6fe1d55c822ecd075db9a86d383042c9fa07c192/examples/breakout.rs#L614
+#[derive(Clone)]
+pub struct Snapshot {
+ pub date: DayMonth,
+ pub buildings: Vec<Transform>,
+}
+
+fn take_snapshot(
+ mut new_month: EventReader<NewMonth>,
+ date: Res<Date>,
+ mut history: ResMut<History>,
+ buildings: Query<&Transform, With<Building>>,
+) {
+ if new_month.read().count() == 0 {
+ return;
+ }
+
+ let timestamp: Timestamp = date.0.into();
+ let buildings = buildings.iter().map(|transform| *transform).collect();
+ let snapshot = Snapshot {
+ date: date.0,
+ buildings,
+ };
+ history.snapshots.insert(timestamp.clone(), snapshot);
+
+ let count = history.snapshots.len();
+ info!("Registering snapshot {count} on {timestamp}.")
+}
+
+#[derive(Event)]
+pub struct TimeTravelRequest(pub Snapshot);
+
+fn time_travel(
+ mut requests: EventReader<TimeTravelRequest>,
+ mut game_state: ResMut<NextState<GameState>>,
+) {
+ for _ in requests.read() {
+ game_state.set(GameState::Explore);
+ }
+}index 134d4b0..71dfd1d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,16 +2,21 @@ mod buildings;
=mod camera;
=mod date;
=mod day_month;
+mod explore;
=mod ground;
+mod history;
=mod sun;
=
=use bevy::prelude::*;
+use bevy_egui::EguiPlugin;
=use buildings::BuildingsPlugin;
=use date::Date;
=use date::DatePlugin;
=use date::NewMonth;
=use day_month::DayMonth;
+use explore::ExplorePlugin;
=use ground::GroundPlugin;
+use history::HistoryPlugin;
=use sun::SunPlugin;
=
=const BEGINNING: i32 = 1860;
@@ -38,6 +43,9 @@ fn main() {
= .add_plugins(BuildingsPlugin)
= .add_plugins(DatePlugin)
= .add_plugins(SunPlugin)
+ .add_plugins(HistoryPlugin)
+ .add_plugins(ExplorePlugin)
+ .add_plugins(EguiPlugin)
= .add_systems(Startup, greet)
= .add_systems(Update, switch_states)
= .add_systems(OnEnter(GameState::Explore), setup_exploration)Set simulation to 15 years
On by
Move camera away so more buildings can be seen.
Make sidebar scrollable, so all the snapshots can be accessed.
index 634bf13..ab581f3 100644
--- a/src/explore.rs
+++ b/src/explore.rs
@@ -23,19 +23,21 @@ fn paint_ui(
= egui::SidePanel::right("explore_ui").show(contexts.ctx_mut(), |ui| {
= ui.heading("Explore");
=
- for (timestamp, snapshot) in history
- .snapshots
- .iter()
- // TODO: Consider using BTreeMap for always sorted snapshots. Or even ditch keys all together and use a vector?
- .sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
- {
- let month = timestamp.month.clone();
- let year = timestamp.year;
- let button = ui.button(format!("{month} {year}"));
- if button.clicked() {
- info!("Time travel to {timestamp}");
- requests.send(TimeTravelRequest(snapshot.clone()));
+ egui::ScrollArea::vertical().show(ui, |ui| {
+ for (timestamp, snapshot) in history
+ .snapshots
+ .iter()
+ // TODO: Consider using BTreeMap for always sorted snapshots. Or even ditch keys all together and use a vector?
+ .sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
+ {
+ let month = timestamp.month.clone();
+ let year = timestamp.year;
+ let button = ui.button(format!("{month} {year}"));
+ if button.clicked() {
+ info!("Time travel to {timestamp}");
+ requests.send(TimeTravelRequest(snapshot.clone()));
+ }
= }
- }
+ })
= });
=}index 71dfd1d..021646b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,7 +20,7 @@ use history::HistoryPlugin;
=use sun::SunPlugin;
=
=const BEGINNING: i32 = 1860;
-const DURATION: i32 = 1;
+const DURATION: i32 = 15;
=
=fn main() {
= App::new()
@@ -36,7 +36,7 @@ fn main() {
= .init_state::<GameState>()
= .add_plugins(camera::CameraPlugin(camera::CameraSettings {
= elevation: 5.,
- distance: 12.,
+ distance: 20.,
= rps: 0.01,
= }))
= .add_plugins(GroundPlugin)