diff --git a/.woodpecker/html.yml b/.woodpecker/html.yml index cc7e6b7..64814bf 100644 --- a/.woodpecker/html.yml +++ b/.woodpecker/html.yml @@ -2,16 +2,20 @@ when: - event: [tag] steps: - cache-restore: - image: minio/mc - secrets: [access_key, secret_key] - commands: - - mc alias set minio https://minio.ragarock.moe $access_key $secret_key - - mc cp -quiet --recursive minio/yuno/cache-html/target target - failure: ignore build: image: git.ragarock.moe/silvana/yuno/rust:latest - environment: [CARGO_TERM_COLOR=always, CARGO_HOME=./.cargo-home] + secrets: [access_key, secret_key] + environment: + CARGO_TERM_COLOR: "always" + CARGO_HOME: "./.cargo-home" + RUSTC_WRAPPER: "/usr/bin/sccache" + SCCACHE_ENDPOINT: "https://minio.ragarock.moe" + SCCACHE_BUCKET: "cache" + SCCACHE_REGION: "auto" + AWS_ACCESS_KEY_ID: + from_secret: access_key + AWS_SECRET_ACCESS_KEY: + from_secret: secret_key commands: - rustup default nightly - rustup target add wasm32-unknown-unknown @@ -22,10 +26,3 @@ steps: commands: - mc alias set minio https://minio.ragarock.moe $access_key $secret_key - mc cp -quiet --recursive dist/ minio/yuno/${CI_COMMIT_TAG}/ - cache-upload: - image: minio/mc - secrets: [access_key, secret_key] - commands: - - mc alias set minio https://minio.ragarock.moe $access_key $secret_key - - mc cp -quiet --recursive target/ minio/yuno/cache-html/target - failure: ignore diff --git a/.woodpecker/quality.yml b/.woodpecker/quality.yml index df912d2..3d0f092 100644 --- a/.woodpecker/quality.yml +++ b/.woodpecker/quality.yml @@ -2,38 +2,57 @@ when: - event: [pull_request] steps: - cache-restore: - image: minio/mc - secrets: [access_key, secret_key] - commands: - - mc alias set minio https://minio.ragarock.moe $access_key $secret_key - - mc cp -quiet --recursive minio/yuno/cache-amd64/target target - failure: ignore fmt: image: git.ragarock.moe/silvana/yuno/rust:latest - environment: [CARGO_TERM_COLOR=always, CARGO_HOME=./.cargo-home] + secrets: [access_key, secret_key] + environment: + CARGO_TERM_COLOR: "always" + CARGO_HOME: "./.cargo-home" + RUSTC_WRAPPER: "/usr/bin/sccache" + SCCACHE_ENDPOINT: "https://minio.ragarock.moe" + SCCACHE_BUCKET: "cache" + SCCACHE_REGION: "auto" + AWS_ACCESS_KEY_ID: + from_secret: access_key + AWS_SECRET_ACCESS_KEY: + from_secret: secret_key commands: - rustup default nightly - rustup component add rustfmt - cargo fmt -- --check clippy: image: git.ragarock.moe/silvana/yuno/rust:latest - environment: [CARGO_TERM_COLOR=always, CARGO_HOME=./.cargo-home] + secrets: [access_key, secret_key] + environment: + CARGO_TERM_COLOR: "always" + CARGO_HOME: "./.cargo-home" + RUSTC_WRAPPER: "/usr/bin/sccache" + SCCACHE_ENDPOINT: "https://minio.ragarock.moe" + SCCACHE_BUCKET: "cache" + SCCACHE_REGION: "auto" + AWS_ACCESS_KEY_ID: + from_secret: access_key + AWS_SECRET_ACCESS_KEY: + from_secret: secret_key commands: - rustup default nightly - rustup component add clippy - cargo clippy -- -D warnings test: image: git.ragarock.moe/silvana/yuno/rust:latest - environment: [CARGO_TERM_COLOR=always, CARGO_HOME=./.cargo-home] + secrets: [access_key, secret_key] + environment: + CARGO_TERM_COLOR: "always" + CARGO_HOME: "./.cargo-home" + RUSTC_WRAPPER: "/usr/bin/sccache" + SCCACHE_ENDPOINT: "https://minio.ragarock.moe" + SCCACHE_BUCKET: "cache" + SCCACHE_REGION: "auto" + AWS_ACCESS_KEY_ID: + from_secret: access_key + AWS_SECRET_ACCESS_KEY: + from_secret: secret_key commands: - rustup default nightly - cargo check - cargo test - cache-upload: - image: minio/mc - secrets: [access_key, secret_key] - commands: - - mc alias set minio https://minio.ragarock.moe $access_key $secret_key - - mc cp -quiet --recursive target/ minio/yuno/cache-amd64/target - failure: ignore diff --git a/Cargo.lock b/Cargo.lock index 1599035..bcf43ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,6 +186,24 @@ dependencies = [ "num-traits", ] +[[package]] +name = "arboard" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" +dependencies = [ + "clipboard-win", + "core-graphics", + "image 0.25.2", + "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "parking_lot", + "windows-sys 0.48.0", + "x11rb", +] + [[package]] name = "arrayref" version = "0.3.8" @@ -316,6 +334,50 @@ dependencies = [ "bevy_internal", ] +[[package]] +name = "bevy-inspector-egui" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8d77dbe53c8840aa74b66ea19dac6675d0a1752c989610cbded909d03967bec" +dependencies = [ + "bevy-inspector-egui-derive", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core", + "bevy_core_pipeline", + "bevy_ecs", + "bevy_egui", + "bevy_hierarchy", + "bevy_log", + "bevy_math", + "bevy_pbr", + "bevy_reflect", + "bevy_render", + "bevy_state", + "bevy_time", + "bevy_utils", + "bevy_window", + "bytemuck", + "egui", + "fuzzy-matcher", + "image 0.24.9", + "once_cell", + "pretty-type-name", + "smallvec", +] + +[[package]] +name = "bevy-inspector-egui-derive" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161d93f4b3a9246a87485e30ccf4cc927f204a14f26df42da977e383f0a0ec5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "bevy_a11y" version = "0.14.1" @@ -566,6 +628,39 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "bevy_ecs_tilemap" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d880047f5deaf5166ffc08238125a4ccbd2837f781ca6525fa200fcf5785ba3b" +dependencies = [ + "bevy", + "log", + "regex", +] + +[[package]] +name = "bevy_egui" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4a90f30f2849a07d91e393b10c0cc05df09b5773c010ddde57dd8b583be230" +dependencies = [ + "arboard", + "bevy", + "bytemuck", + "console_log", + "crossbeam-channel", + "egui", + "js-sys", + "log", + "thread_local", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webbrowser", + "winit", +] + [[package]] name = "bevy_encase_derive" version = "0.14.1" @@ -888,7 +983,7 @@ dependencies = [ "encase", "futures-lite", "hexasphere", - "image", + "image 0.25.2", "js-sys", "ktx2", "naga", @@ -1301,6 +1396,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop", + "rustix", + "wayland-backend", + "wayland-client", +] + [[package]] name = "cc" version = "1.1.7" @@ -1355,6 +1462,15 @@ dependencies = [ "libloading 0.8.5", ] +[[package]] +name = "clipboard-win" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" +dependencies = [ + "error-code", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -1365,6 +1481,12 @@ dependencies = [ "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" @@ -1425,6 +1547,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "console_log" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" +dependencies = [ + "log", + "web-sys", +] + [[package]] name = "const-fnv1a-hash" version = "1.1.0" @@ -1630,12 +1762,43 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +[[package]] +name = "ecolor" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e6b451ff1143f6de0f33fc7f1b68fecfd2c7de06e104de96c4514de3f5396f8" +dependencies = [ + "bytemuck", + "emath", +] + +[[package]] +name = "egui" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c97e70a2768de630f161bb5392cbd3874fcf72868f14df0e002e82e06cb798" +dependencies = [ + "ahash", + "emath", + "epaint", + "nohash-hasher", +] + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "emath" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6a21708405ea88f63d8309650b4d77431f4bc28fb9d8e6f77d3963b51249e6" +dependencies = [ + "bytemuck", +] + [[package]] name = "encase" version = "0.8.0" @@ -1677,6 +1840,21 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "epaint" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f0dcc0a0771e7500e94cd1cb797bd13c9f23b9409bdc3c824e2cbc562b7fa01" +dependencies = [ + "ab_glyph", + "ahash", + "bytemuck", + "ecolor", + "emath", + "nohash-hasher", + "parking_lot", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1703,6 +1881,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.10" @@ -1843,6 +2027,15 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "fuzzy-matcher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" +dependencies = [ + "thread_local", +] + [[package]] name = "gethostname" version = "0.4.3" @@ -2140,6 +2333,18 @@ dependencies = [ "unicode-normalization", ] +[[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", +] + [[package]] name = "image" version = "0.25.2" @@ -2150,6 +2355,7 @@ dependencies = [ "byteorder-lite", "num-traits", "png", + "tiff", ] [[package]] @@ -2253,6 +2459,12 @@ dependencies = [ "libc", ] +[[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.69" @@ -2423,6 +2635,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[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.28.0" @@ -2567,6 +2788,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" @@ -3062,6 +3289,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" +[[package]] +name = "pretty-type-name" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f73cdaf19b52e6143685c3606206e114a4dfa969d6b14ec3894c88eb38bd4b" + [[package]] name = "proc-macro-crate" version = "3.1.0" @@ -3086,6 +3319,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +[[package]] +name = "quick-xml" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f24d770aeca0eacb81ac29dfbc55ebcc09312fdd1f8bbecdc7e4a84e000e3b4" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.36" @@ -3282,12 +3524,31 @@ 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.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + [[package]] name = "send_wrapper" version = "0.6.0" @@ -3371,6 +3632,31 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.6.0", + "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.2" @@ -3395,6 +3681,12 @@ 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.3" @@ -3560,6 +3852,54 @@ 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 = "tiled" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad408d366c0e1e7e4e504cabc14c77fdda77176d93b3c6abe5b3b31885df3ad0" +dependencies = [ + "base64 0.22.1", + "flate2", + "xml-rs", + "zstd", +] + +[[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.8.0" @@ -3858,6 +4198,115 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +[[package]] +name = "wayland-backend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90e11ce2ca99c97b940ee83edbae9da2d56a08f9ea8158550fd77fa31722993" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e321577a0a165911bdcfb39cf029302479d7527b517ee58ab0f6ad09edf0943" +dependencies = [ + "bitflags 2.6.0", + "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.6.0", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef9489a8df197ebf3a8ce8a7a7f0a2320035c3743f3c1bd0bdbccf07ce64f95" +dependencies = [ + "rustix", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62989625a776e827cc0f15d41444a3cea5205b963c3a25be48ae1b52d6b4daaa" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79f2d57c7fcc6ab4d602adba364bf59a5c24de57bd194486bf9b8360e06bfc4" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd993de54a40a40fbe5601d9f1fbcaef0aebcc5fda447d7dc8f6dcbaae4f8953" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7b56f89937f1cf2ee1f1259cf2936a17a1f45d8f0aa1019fae6d470d304cfa6" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + [[package]] name = "web-sys" version = "0.3.69" @@ -3896,6 +4345,12 @@ dependencies = [ "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.20.1" @@ -4187,6 +4642,15 @@ 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" @@ -4389,6 +4853,7 @@ version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4225ddd8ab67b8b59a2fee4b34889ebf13c0460c1c3fa297c58e21eb87801b33" dependencies = [ + "ahash", "android-activity", "atomic-waker", "bitflags 2.6.0", @@ -4403,6 +4868,7 @@ dependencies = [ "dpi", "js-sys", "libc", + "memmap2", "ndk 0.9.0", "objc2", "objc2-app-kit", @@ -4414,11 +4880,17 @@ dependencies = [ "raw-window-handle", "redox_syscall 0.4.1", "rustix", + "sctk-adwaita", + "smithay-client-toolkit", "smol_str", "tracing", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", "web-sys", "web-time", "windows-sys 0.52.0", @@ -4477,6 +4949,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" +[[package]] +name = "xcursor" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d491ee231a51ae64a5b762114c3ac2104b967aadba1de45c86ca42cf051513b7" + [[package]] name = "xi-unicode" version = "0.3.0" @@ -4513,10 +4991,14 @@ name = "yuno" version = "0.1.0" dependencies = [ "bevy", + "bevy-inspector-egui", "bevy_asset_loader", + "bevy_ecs_tilemap", "bevy_kira_audio", - "image", + "image 0.25.2", "log", + "thiserror", + "tiled", "webbrowser", "winit", ] @@ -4541,3 +5023,31 @@ dependencies = [ "quote", "syn 2.0.72", ] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 6cbeaac..e50b60d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,3 +70,7 @@ log = { version = "0.4", features = [ "max_level_debug", "release_max_level_warn", ] } +thiserror = "1.0.63" +bevy_ecs_tilemap = { version = "0.14.0" } +tiled = { version = "0.12.0", features = ["wasm"] } +bevy-inspector-egui = "0.25.1" diff --git a/Dockerfile b/Dockerfile index 80d145c..a6f683e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM alpine:edge -RUN apk add curl build-base mold clang gcc libc-dev pkgconf libx11-dev alsa-lib-dev eudev-dev +RUN apk add curl build-base mold clang gcc libc-dev pkgconf libx11-dev alsa-lib-dev eudev-dev sccache WORKDIR /app diff --git a/assets/maps/test.tmx b/assets/maps/test.tmx new file mode 100644 index 0000000..639283f --- /dev/null +++ b/assets/maps/test.tmx @@ -0,0 +1,30 @@ + + + + + + + +1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,3,3,3,1,1,1, +1,3,1,1,1,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,1,3,3,3,1,3,3,1,1, +1,3,1,3,3,3,1,1,1,1,3,3,1,1,1,3,1,1,1,1,1,1,3,3,1,1,1,3,1,1, +1,1,4,3,1,1,1,1,6,1,3,3,1,1,1,1,1,1,1,1,3,3,3,3,3,4,4,3,3,1, +1,1,3,3,4,4,4,4,4,1,1,1,1,1,1,3,1,1,6,1,1,1,1,1,1,4,4,4,3,1, +1,1,3,1,1,1,1,1,4,1,1,1,1,3,3,3,1,1,1,1,1,1,4,4,1,4,4,3,4,1, +1,3,3,1,1,1,1,1,4,1,3,3,3,3,1,1,3,1,5,5,1,1,5,4,1,1,4,3,4,4, +1,4,1,1,1,6,1,4,4,1,3,3,1,1,6,1,3,1,5,5,1,3,3,3,4,1,1,3,1,4, +1,4,4,1,1,1,3,3,1,1,3,3,1,1,1,1,3,3,1,5,5,3,5,1,3,4,4,3,1,4, +1,3,4,1,1,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,5,3,5,5,3,3,4,3,3,4, +1,3,3,1,1,3,4,1,3,1,1,1,3,1,1,1,3,3,3,3,1,3,1,5,1,3,3,4,4,1, +1,4,3,1,1,1,1,1,3,3,1,1,3,3,5,5,3,1,1,3,3,3,1,1,1,1,3,1,1,1, +1,1,3,1,1,1,6,1,1,3,1,1,1,3,3,3,1,1,1,1,6,3,3,1,1,1,3,1,1,1, +1,1,4,3,1,1,1,1,1,1,5,5,5,5,1,3,3,1,1,1,3,1,3,1,1,1,3,1,3,3, +1,1,1,3,3,1,1,1,1,1,5,5,5,1,1,1,3,3,1,1,4,1,3,3,1,1,1,1,3,1, +3,3,1,4,3,1,1,6,1,1,1,3,3,3,3,3,1,1,1,1,4,1,1,3,1,1,1,1,3,1, +1,3,1,1,3,3,1,1,3,3,3,3,1,1,1,1,1,1,1,1,4,4,4,1,1,1,1,3,3,1, +1,3,3,1,1,1,3,3,3,1,1,1,1,1,1,1,6,1,1,3,3,3,4,4,1,1,1,3,1,1, +1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,3,3,3,4,1,1,3,1,1, +1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,3,3,1,1 + + + diff --git a/assets/textures/grass_tiles.png b/assets/textures/grass_tiles.png new file mode 100644 index 0000000..7cf836e --- /dev/null +++ b/assets/textures/grass_tiles.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d90edc82dc2f5dba3642c2d4ed04f7093cd9161643b2e7bc350faf5d1abd9e49 +size 2118 diff --git a/src/lib.rs b/src/lib.rs index 8696068..fbf7829 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,9 +5,14 @@ #[cfg(debug_assertions)] use bevy::diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}; use bevy::prelude::*; +use bevy_ecs_tilemap::TilemapPlugin; +use bevy_inspector_egui::quick::WorldInspectorPlugin; +use map::MapPlugin; use player::PlayerPlugin; +mod loaders; mod loading; +mod map; mod menu; mod player; @@ -25,12 +30,22 @@ pub struct YunoPlugin; impl Plugin for YunoPlugin { fn build(&self, app: &mut App) { - app.init_state::() - .add_plugins((LoadingPlugin, MenuPlugin, PlayerPlugin)); + app.init_state::().add_plugins(( + TilemapPlugin, + loaders::tiled::TiledMapPlugin, + MapPlugin, + LoadingPlugin, + MenuPlugin, + PlayerPlugin, + )); #[cfg(debug_assertions)] { - app.add_plugins((FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin::default())); + app.add_plugins(( + WorldInspectorPlugin::default(), + FrameTimeDiagnosticsPlugin, + LogDiagnosticsPlugin::default(), + )); } } } diff --git a/src/loaders/mod.rs b/src/loaders/mod.rs new file mode 100644 index 0000000..6e4cf69 --- /dev/null +++ b/src/loaders/mod.rs @@ -0,0 +1 @@ +pub(crate) mod tiled; diff --git a/src/loaders/tiled.rs b/src/loaders/tiled.rs new file mode 100644 index 0000000..c98ff2a --- /dev/null +++ b/src/loaders/tiled.rs @@ -0,0 +1,381 @@ +// How to use this: +// You should copy/paste this into your project and use it much like examples/tiles.rs uses this +// file. When you do so you will need to adjust the code based on whether you're using the +// 'atlas` feature in bevy_ecs_tilemap. The bevy_ecs_tilemap uses this as an example of how to +// use both single image tilesets and image collection tilesets. Since your project won't have +// the 'atlas' feature defined in your Cargo config, the expressions prefixed by the #[cfg(...)] +// macro will not compile in your project as-is. If your project depends on the bevy_ecs_tilemap +// 'atlas' feature then move all of the expressions prefixed by #[cfg(not(feature = "atlas"))]. +// Otherwise remove all of the expressions prefixed by #[cfg(feature = "atlas")]. +// +// Functional limitations: +// * When the 'atlas' feature is enabled tilesets using a collection of images will be skipped. +// * Only finite tile layers are loaded. Infinite tile layers and object layers will be skipped. + +use std::io::{Cursor, ErrorKind}; +use std::path::Path; +use std::sync::Arc; + +use bevy::{ + asset::{io::Reader, AssetLoader, AssetPath, AsyncReadExt}, + log, + prelude::{ + Added, Asset, AssetApp, AssetEvent, AssetId, Assets, Bundle, Commands, Component, + DespawnRecursiveExt, Entity, EventReader, GlobalTransform, Handle, Image, Plugin, Query, + Res, Transform, Update, + }, + reflect::TypePath, + utils::HashMap, +}; +use bevy_ecs_tilemap::prelude::*; + +use thiserror::Error; + +#[derive(Default)] +pub struct TiledMapPlugin; + +impl Plugin for TiledMapPlugin { + fn build(&self, app: &mut bevy::prelude::App) { + app.init_asset::() + .register_asset_loader(TiledLoader) + .add_systems(Update, process_loaded_maps); + } +} + +#[derive(TypePath, Asset)] +pub struct TiledMap { + pub map: tiled::Map, + + pub tilemap_textures: HashMap, + + // The offset into the tileset_images for each tile id within each tileset. + pub tile_image_offsets: HashMap<(usize, tiled::TileId), u32>, +} + +// Stores a list of tiled layers. +#[derive(Component, Default)] +pub struct TiledLayersStorage { + pub storage: HashMap, +} + +#[derive(Default, Bundle)] +pub struct TiledMapBundle { + pub tiled_map: Handle, + pub storage: TiledLayersStorage, + pub transform: Transform, + pub global_transform: GlobalTransform, + pub render_settings: TilemapRenderSettings, +} + +struct BytesResourceReader { + bytes: Arc<[u8]>, +} + +impl BytesResourceReader { + fn new(bytes: &[u8]) -> Self { + Self { + bytes: Arc::from(bytes), + } + } +} + +impl tiled::ResourceReader for BytesResourceReader { + type Resource = Cursor>; + type Error = std::io::Error; + + fn read_from(&mut self, _path: &Path) -> std::result::Result { + // In this case, the path is ignored because the byte data is already provided. + Ok(Cursor::new(self.bytes.clone())) + } +} + +pub struct TiledLoader; + +#[derive(Debug, Error)] +pub enum TiledAssetLoaderError { + /// An [IO](std::io) Error + #[error("Could not load Tiled file: {0}")] + Io(#[from] std::io::Error), +} + +impl AssetLoader for TiledLoader { + type Asset = TiledMap; + type Settings = (); + type Error = TiledAssetLoaderError; + + async fn load<'a>( + &'a self, + reader: &'a mut Reader<'_>, + _settings: &'a Self::Settings, + load_context: &'a mut bevy::asset::LoadContext<'_>, + ) -> Result { + let mut bytes = Vec::new(); + reader.read_to_end(&mut bytes).await?; + + let mut loader = tiled::Loader::with_cache_and_reader( + tiled::DefaultResourceCache::new(), + BytesResourceReader::new(&bytes), + ); + let map = loader.load_tmx_map(load_context.path()).map_err(|e| { + std::io::Error::new(ErrorKind::Other, format!("Could not load TMX map: {e}")) + })?; + + let mut tilemap_textures = HashMap::default(); + let mut tile_image_offsets = HashMap::default(); + + for (tileset_index, tileset) in map.tilesets().iter().enumerate() { + let tilemap_texture = match &tileset.image { + None => { + { + let mut tile_images: Vec> = Vec::new(); + for (tile_id, tile) in tileset.tiles() { + if let Some(img) = &tile.image { + // The load context path is the TMX file itself. If the file is at the root of the + // assets/ directory structure then the tmx_dir will be empty, which is fine. + let tmx_dir = load_context + .path() + .parent() + .expect("The asset load context was empty."); + let tile_path = tmx_dir.join(&img.source); + let asset_path = AssetPath::from(tile_path); + log::info!("Loading tile image from {asset_path:?} as image ({tileset_index}, {tile_id})"); + let texture: Handle = load_context.load(asset_path.clone()); + tile_image_offsets + .insert((tileset_index, tile_id), tile_images.len() as u32); + tile_images.push(texture.clone()); + } + } + + TilemapTexture::Vector(tile_images) + } + } + Some(img) => { + // The load context path is the TMX file itself. If the file is at the root of the + // assets/ directory structure then the tmx_dir will be empty, which is fine. + let texture: Handle = load_context.load(img.source.clone()); + + TilemapTexture::Single(texture.clone()) + } + }; + + tilemap_textures.insert(tileset_index, tilemap_texture); + } + + let asset_map = TiledMap { + map, + tilemap_textures, + tile_image_offsets, + }; + + log::info!("Loaded map: {}", load_context.path().display()); + Ok(asset_map) + } + + fn extensions(&self) -> &[&str] { + static EXTENSIONS: &[&str] = &["tmx"]; + EXTENSIONS + } +} + +pub fn process_loaded_maps( + mut commands: Commands, + mut map_events: EventReader>, + maps: Res>, + tile_storage_query: Query<(Entity, &TileStorage)>, + mut map_query: Query<( + &Handle, + &mut TiledLayersStorage, + &TilemapRenderSettings, + )>, + new_maps: Query<&Handle, Added>>, +) { + let mut changed_maps = Vec::>::default(); + for event in map_events.read() { + match event { + AssetEvent::Added { id } => { + log::info!("Map added!"); + changed_maps.push(*id); + } + AssetEvent::Modified { id } => { + log::info!("Map changed!"); + changed_maps.push(*id); + } + AssetEvent::Removed { id } => { + log::info!("Map removed!"); + // if mesh was modified and removed in the same update, ignore the modification + // events are ordered so future modification events are ok + changed_maps.retain(|changed_handle| changed_handle == id); + } + _ => continue, + } + } + + // If we have new map entities add them to the changed_maps list. + for new_map_handle in new_maps.iter() { + changed_maps.push(new_map_handle.id()); + } + + for changed_map in changed_maps.iter() { + for (map_handle, mut layer_storage, render_settings) in map_query.iter_mut() { + // only deal with currently changed map + if map_handle.id() != *changed_map { + continue; + } + if let Some(tiled_map) = maps.get(map_handle) { + // TODO: Create a RemoveMap component.. + for layer_entity in layer_storage.storage.values() { + if let Ok((_, layer_tile_storage)) = tile_storage_query.get(*layer_entity) { + for tile in layer_tile_storage.iter().flatten() { + commands.entity(*tile).despawn_recursive() + } + } + // commands.entity(*layer_entity).despawn_recursive(); + } + + // The TilemapBundle requires that all tile images come exclusively from a single + // tiled texture or from a Vec of independent per-tile images. Furthermore, all of + // the per-tile images must be the same size. Since Tiled allows tiles of mixed + // tilesets on each layer and allows differently-sized tile images in each tileset, + // this means we need to load each combination of tileset and layer separately. + for (tileset_index, tileset) in tiled_map.map.tilesets().iter().enumerate() { + let Some(tilemap_texture) = tiled_map.tilemap_textures.get(&tileset_index) + else { + log::warn!("Skipped creating layer with missing tilemap textures."); + continue; + }; + + let tile_size = TilemapTileSize { + x: tileset.tile_width as f32, + y: tileset.tile_height as f32, + }; + + let tile_spacing = TilemapSpacing { + x: tileset.spacing as f32, + y: tileset.spacing as f32, + }; + + // Once materials have been created/added we need to then create the layers. + for (layer_index, layer) in tiled_map.map.layers().enumerate() { + let offset_x = layer.offset_x; + let offset_y = layer.offset_y; + + let tiled::LayerType::Tiles(tile_layer) = layer.layer_type() else { + log::info!( + "Skipping layer {} because only tile layers are supported.", + layer.id() + ); + continue; + }; + + let tiled::TileLayer::Finite(layer_data) = tile_layer else { + log::info!( + "Skipping layer {} because only finite layers are supported.", + layer.id() + ); + continue; + }; + + let map_size = TilemapSize { + x: tiled_map.map.width, + y: tiled_map.map.height, + }; + + let grid_size = TilemapGridSize { + x: tiled_map.map.tile_width as f32, + y: tiled_map.map.tile_height as f32, + }; + + let map_type = match tiled_map.map.orientation { + tiled::Orientation::Hexagonal => { + TilemapType::Hexagon(HexCoordSystem::Row) + } + tiled::Orientation::Isometric => { + TilemapType::Isometric(IsoCoordSystem::Diamond) + } + tiled::Orientation::Staggered => { + TilemapType::Isometric(IsoCoordSystem::Staggered) + } + tiled::Orientation::Orthogonal => TilemapType::Square, + }; + + let mut tile_storage = TileStorage::empty(map_size); + let layer_entity = commands.spawn_empty().id(); + + for x in 0..map_size.x { + for y in 0..map_size.y { + // Transform TMX coords into bevy coords. + let mapped_y = tiled_map.map.height - 1 - y; + + let mapped_x = x as i32; + let mapped_y = mapped_y as i32; + + let layer_tile = match layer_data.get_tile(mapped_x, mapped_y) { + Some(t) => t, + None => { + continue; + } + }; + if tileset_index != layer_tile.tileset_index() { + continue; + } + let layer_tile_data = + match layer_data.get_tile_data(mapped_x, mapped_y) { + Some(d) => d, + None => { + continue; + } + }; + + let texture_index = match tilemap_texture { + TilemapTexture::Single(_) => layer_tile.id(), + TilemapTexture::Vector(_) => + *tiled_map.tile_image_offsets.get(&(tileset_index, layer_tile.id())) + .expect("The offset into to image vector should have been saved during the initial load."), + _ => unreachable!() + }; + + let tile_pos = TilePos { x, y }; + let tile_entity = commands + .spawn(TileBundle { + position: tile_pos, + tilemap_id: TilemapId(layer_entity), + texture_index: TileTextureIndex(texture_index), + flip: TileFlip { + x: layer_tile_data.flip_h, + y: layer_tile_data.flip_v, + d: layer_tile_data.flip_d, + }, + ..Default::default() + }) + .id(); + tile_storage.set(&tile_pos, tile_entity); + } + } + + commands.entity(layer_entity).insert(TilemapBundle { + grid_size, + size: map_size, + storage: tile_storage, + texture: tilemap_texture.clone(), + tile_size, + spacing: tile_spacing, + transform: get_tilemap_center_transform( + &map_size, + &grid_size, + &map_type, + layer_index as f32, + ) * Transform::from_xyz(offset_x, -offset_y, 0.0), + map_type, + render_settings: *render_settings, + ..Default::default() + }); + + layer_storage + .storage + .insert(layer_index as u32, layer_entity); + } + } + } + } + } +} diff --git a/src/loading.rs b/src/loading.rs index 0caa6f0..aa1e52a 100644 --- a/src/loading.rs +++ b/src/loading.rs @@ -4,7 +4,7 @@ use bevy_asset_loader::{ loading_state::{config::ConfigureLoadingState, LoadingState, LoadingStateAppExt}, }; -use crate::GameState; +use crate::{loaders::tiled::TiledMap, GameState}; pub struct LoadingPlugin; @@ -13,6 +13,7 @@ impl Plugin for LoadingPlugin { app.add_loading_state( LoadingState::new(GameState::Loading) .continue_to_state(GameState::Menu) + .load_collection::() .load_collection::(), ); } @@ -38,3 +39,9 @@ pub struct TextureAssets { #[asset(path = "textures/forgejo.png")] pub forgejo: Handle, } + +#[derive(AssetCollection, Resource)] +pub struct MapAssets { + #[asset(path = "maps/test.tmx")] + pub map: Handle, +} diff --git a/src/map.rs b/src/map.rs new file mode 100644 index 0000000..826cb29 --- /dev/null +++ b/src/map.rs @@ -0,0 +1,18 @@ +use bevy::prelude::*; + +use crate::{loaders::tiled::TiledMapBundle, loading::MapAssets, GameState}; + +pub struct MapPlugin; + +impl Plugin for MapPlugin { + fn build(&self, app: &mut App) { + app.add_systems(OnEnter(GameState::Playing), setup); + } +} + +fn setup(mut commands: Commands, maps: Res) { + commands.spawn(TiledMapBundle { + tiled_map: maps.map.clone(), + ..default() + }); +} diff --git a/src/player.rs b/src/player.rs index 6194d12..68b843e 100644 --- a/src/player.rs +++ b/src/player.rs @@ -47,7 +47,7 @@ impl AnimationConfig { fn spawn(mut commands: Commands, textures: Res) { let mut camera = Camera2dBundle::default(); - camera.projection.scale *= 0.25; + camera.projection.scale *= 0.5; commands.spawn(camera); let animation_config = AnimationConfig::new(0, 3, 10); @@ -55,6 +55,7 @@ fn spawn(mut commands: Commands, textures: Res) { commands.spawn(( SpriteBundle { texture: textures.witch.clone(), + transform: Transform::from_xyz(0.0, 0.0, 100.0), ..default() }, TextureAtlas::from(textures.witch_layout.clone()),