diff --git a/Cargo.lock b/Cargo.lock index cae5cbf..9ad250c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,7 +94,7 @@ dependencies = [ "accesskit_consumer", "hashbrown", "static_assertions", - "windows 0.61.1", + "windows 0.61.3", "windows-core 0.61.2", ] @@ -114,9 +114,9 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" @@ -143,9 +143,12 @@ dependencies = [ [[package]] name = "aligned-vec" -version = "0.5.0" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] [[package]] name = "allocator-api2" @@ -235,7 +238,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -360,7 +363,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -395,7 +398,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -564,7 +567,7 @@ checksum = "42b6b4cb608b8282dc3b53d0f4c9ab404655d562674c682db7e6c0458cc83c23" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -645,15 +648,15 @@ checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "bytemuck" -version = "1.23.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" dependencies = [ "bytemuck_derive", ] @@ -666,7 +669,7 @@ checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -715,9 +718,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.24" +version = "1.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" +checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" dependencies = [ "jobserver", "libc", @@ -742,9 +745,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cfg_aliases" @@ -787,7 +790,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b92ffcacae7b226114b0cbd2b6c1bd9d5ac3435d977f3827b44c20be00e7315" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -1024,7 +1027,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1051,7 +1054,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -1087,15 +1090,17 @@ checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "ecolor" version = "0.31.1" +source = "git+https://github.com/BloodStainedCrow/egui?branch=removeProfiling#4e11a02615078f509d9acc474ae13a66b411eaf7" dependencies = [ "bytemuck", - "emath 0.31.1", + "emath 0.31.1 (git+https://github.com/BloodStainedCrow/egui?branch=removeProfiling)", "serde", ] [[package]] name = "eframe" version = "0.31.1" +source = "git+https://github.com/BloodStainedCrow/egui?branch=removeProfiling#4e11a02615078f509d9acc474ae13a66b411eaf7" dependencies = [ "ahash", "bytemuck", @@ -1132,11 +1137,12 @@ dependencies = [ [[package]] name = "egui" version = "0.31.1" +source = "git+https://github.com/BloodStainedCrow/egui?branch=removeProfiling#4e11a02615078f509d9acc474ae13a66b411eaf7" dependencies = [ "accesskit", "ahash", "bitflags 2.9.1", - "emath 0.31.1", + "emath 0.31.1 (git+https://github.com/BloodStainedCrow/egui?branch=removeProfiling)", "epaint", "log", "nohash-hasher", @@ -1148,6 +1154,7 @@ dependencies = [ [[package]] name = "egui-wgpu" version = "0.31.1" +source = "git+https://github.com/BloodStainedCrow/egui?branch=removeProfiling#4e11a02615078f509d9acc474ae13a66b411eaf7" dependencies = [ "ahash", "bytemuck", @@ -1166,6 +1173,7 @@ dependencies = [ [[package]] name = "egui-winit" version = "0.31.1" +source = "git+https://github.com/BloodStainedCrow/egui?branch=removeProfiling#4e11a02615078f509d9acc474ae13a66b411eaf7" dependencies = [ "accesskit_winit", "ahash", @@ -1199,6 +1207,7 @@ dependencies = [ [[package]] name = "egui_glow" version = "0.31.1" +source = "git+https://github.com/BloodStainedCrow/egui?branch=removeProfiling#4e11a02615078f509d9acc474ae13a66b411eaf7" dependencies = [ "ahash", "bytemuck", @@ -1232,16 +1241,17 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "emath" version = "0.31.1" -dependencies = [ - "bytemuck", - "serde", -] +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b" [[package]] name = "emath" version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b" +source = "git+https://github.com/BloodStainedCrow/egui?branch=removeProfiling#4e11a02615078f509d9acc474ae13a66b411eaf7" +dependencies = [ + "bytemuck", + "serde", +] [[package]] name = "embedded-io" @@ -1279,14 +1289,14 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] name = "enumflags2" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" dependencies = [ "enumflags2_derive", "serde", @@ -1294,13 +1304,13 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -1311,18 +1321,19 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] name = "epaint" version = "0.31.1" +source = "git+https://github.com/BloodStainedCrow/egui?branch=removeProfiling#4e11a02615078f509d9acc474ae13a66b411eaf7" dependencies = [ "ab_glyph", "ahash", "bytemuck", "ecolor", - "emath 0.31.1", + "emath 0.31.1 (git+https://github.com/BloodStainedCrow/egui?branch=removeProfiling)", "epaint_default_fonts", "log", "nohash-hasher", @@ -1334,6 +1345,27 @@ dependencies = [ [[package]] name = "epaint_default_fonts" version = "0.31.1" +source = "git+https://github.com/BloodStainedCrow/egui?branch=removeProfiling#4e11a02615078f509d9acc474ae13a66b411eaf7" + +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.102", +] [[package]] name = "equivalent" @@ -1420,7 +1452,7 @@ dependencies = [ "proptest", "puffin", "puffin_egui", - "rand", + "rand 0.8.5", "rayon", "ron", "rstest", @@ -1458,9 +1490,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "libz-rs-sys", @@ -1535,7 +1567,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -1592,7 +1624,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -1679,7 +1711,7 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] @@ -1717,9 +1749,9 @@ dependencies = [ [[package]] name = "glam" -version = "0.30.3" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b46b9ca4690308844c644e7c634d68792467260e051c8543e0c7871662b3ba7" +checksum = "50a99dbe56b72736564cfa4b85bf9a33079f16ae8b74983ab06af3b1a3696b11" [[package]] name = "glob" @@ -1878,9 +1910,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "allocator-api2", "equivalent", @@ -1909,9 +1941,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -2066,9 +2098,9 @@ dependencies = [ [[package]] name = "image-webp" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" +checksum = "14d75c7014ddab93c232bc6bb9f64790d3dfd1d605199acd4b40b6d69e691e9f" dependencies = [ "byteorder-lite", "quick-error 2.0.1", @@ -2106,7 +2138,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -2252,7 +2284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.0", + "windows-targets 0.53.2", ] [[package]] @@ -2269,14 +2301,14 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.9.1", "libc", - "redox_syscall 0.5.12", + "redox_syscall 0.5.13", ] [[package]] name = "libz-rs-sys" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a" +checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221" dependencies = [ "zlib-rs", ] @@ -2357,9 +2389,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" @@ -2420,9 +2452,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", "simd-adler32", @@ -2563,7 +2595,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -2614,7 +2646,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -2979,7 +3011,7 @@ checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.12", + "redox_syscall 0.5.13", "smallvec", "windows-targets 0.52.6", ] @@ -3026,7 +3058,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", - "rand", + "rand 0.8.5", ] [[package]] @@ -3039,7 +3071,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", "unicase", ] @@ -3076,7 +3108,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -3144,9 +3176,9 @@ checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "postcard" @@ -3258,22 +3290,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] name = "proptest" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" +checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" dependencies = [ "bit-set", "bit-vec", "bitflags 2.9.1", "lazy_static", "num-traits", - "rand", - "rand_chacha", + "rand 0.9.1", + "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", "rusty-fork", @@ -3382,8 +3414,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -3393,7 +3435,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -3405,13 +3457,22 @@ dependencies = [ "getrandom 0.2.16", ] +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + [[package]] name = "rand_xorshift" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core", + "rand_core 0.9.3", ] [[package]] @@ -3446,8 +3507,8 @@ dependencies = [ "once_cell", "paste", "profiling", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "simd_helpers", "system-deps", "thiserror 1.0.69", @@ -3507,9 +3568,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ "bitflags 2.9.1", ] @@ -3633,7 +3694,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.101", + "syn 2.0.102", "unicode-ident", ] @@ -3783,7 +3844,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -3806,14 +3867,14 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -3906,9 +3967,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smithay-client-toolkit" @@ -3973,7 +4034,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -4061,7 +4122,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -4074,7 +4135,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -4109,9 +4170,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.101" +version = "2.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462" dependencies = [ "proc-macro2", "quote", @@ -4137,7 +4198,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -4219,7 +4280,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -4230,7 +4291,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -4247,7 +4308,7 @@ dependencies = [ [[package]] name = "tilelib" version = "0.1.0" -source = "git+https://github.com/BloodStainedCrow/tilelib.git#899c454a87342375518a5ed7021e1e62a6ccbcea" +source = "git+https://github.com/BloodStainedCrow/tilelib.git#d6c1448f8e77af7929ea72c1bf54b42fce5609cb" dependencies = [ "bytemuck", "egui", @@ -4347,9 +4408,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toml" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -4359,18 +4420,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", @@ -4392,20 +4453,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", ] @@ -4513,9 +4574,9 @@ checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" [[package]] name = "unicode-width" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" [[package]] name = "url" @@ -4563,9 +4624,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "v_frame" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" dependencies = [ "aligned-vec", "num-traits", @@ -4611,9 +4672,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -4646,7 +4707,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", "wasm-bindgen-shared", ] @@ -4681,7 +4742,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5047,9 +5108,9 @@ dependencies = [ [[package]] name = "windows" -version = "0.61.1" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ "windows-collections", "windows-core 0.61.2", @@ -5112,7 +5173,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -5123,7 +5184,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -5134,7 +5195,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -5145,14 +5206,14 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-numerics" @@ -5237,6 +5298,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -5285,9 +5355,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" dependencies = [ "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", @@ -5542,9 +5612,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] @@ -5662,7 +5732,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", "synstructure", ] @@ -5717,7 +5787,7 @@ checksum = "100ffec29ed51859052f4563061abe35557acb56ba574510571f8398efc70a29" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", "zbus-lockstep", "zbus_xml", "zvariant", @@ -5732,7 +5802,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", "zbus_names", "zvariant", "zvariant_utils", @@ -5780,7 +5850,7 @@ checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] @@ -5800,7 +5870,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", "synstructure", ] @@ -5834,14 +5904,14 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", ] [[package]] name = "zlib-rs" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8" +checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a" [[package]] name = "zune-core" @@ -5860,9 +5930,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +checksum = "0f6fe2e33d02a98ee64423802e16df3de99c43e5cf5ff983767e1128b394c8ac" dependencies = [ "zune-core", ] @@ -5890,7 +5960,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.102", "zvariant_utils", ] @@ -5904,6 +5974,6 @@ dependencies = [ "quote", "serde", "static_assertions", - "syn 2.0.101", + "syn 2.0.102", "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index ade6fd4..9db012c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,9 +46,9 @@ puffin = "0.19" [patch.crates-io] puffin_egui = { git = "https://github.com/BloodStainedCrow/puffin" } puffin = { git = "https://github.com/BloodStainedCrow/puffin" } -egui = { path = "../egui/crates/egui" } -eframe = { path = "../egui/crates/eframe" } -egui-wgpu = { path = "../egui/crates/egui-wgpu" } +egui = { git = "https://github.com/BloodStainedCrow/egui", branch = "removeProfiling" } +eframe = { git = "https://github.com/BloodStainedCrow/egui", branch = "removeProfiling" } +egui-wgpu = { git = "https://github.com/BloodStainedCrow/egui", branch = "removeProfiling" } [lints.rust] # TODO: @@ -62,6 +62,8 @@ unwrap_used = { level = "deny", priority = -1 } wildcard_enum_match_arm = { level = "deny", priority = -1 } match_same_arms = { level = "deny", priority = -1 } + +redundant_closure_for_method_calls = { level = "allow", priority = 1 } suboptimal_flops = { level = "allow", priority = 1 } module_name_repetitions = { level = "allow", priority = 1 } @@ -82,3 +84,7 @@ incremental = true [profile.release] lto = true # codegen-units = 1 + +[features] +# Use Krastorio2 graphics. Since I have not properly added licensing information, I currently do not push them, therefore this feature is broken +graphics = [] \ No newline at end of file diff --git a/codium.nix b/codium.nix index 3e548a8..e0a8573 100644 --- a/codium.nix +++ b/codium.nix @@ -5,6 +5,7 @@ in pkgs.mkShell { buildInputs = [ ] ++ (with pkgs; [ + bacon (vscode-with-extensions.override { vscode = vscodium; diff --git a/crash_replays/001.rep b/crash_replays/001.rep index 659590c..05a3275 100644 Binary files a/crash_replays/001.rep and b/crash_replays/001.rep differ diff --git a/crash_replays/002.rep b/crash_replays/002.rep deleted file mode 100644 index 78b5a68..0000000 Binary files a/crash_replays/002.rep and /dev/null differ diff --git a/crash_replays/003.rep b/crash_replays/003.rep deleted file mode 100644 index 7fa32f0..0000000 Binary files a/crash_replays/003.rep and /dev/null differ diff --git a/crash_replays/004.rep b/crash_replays/004.rep deleted file mode 100644 index 225b674..0000000 Binary files a/crash_replays/004.rep and /dev/null differ diff --git a/crash_replays/005.rep b/crash_replays/005.rep deleted file mode 100644 index 6e5aff8..0000000 Binary files a/crash_replays/005.rep and /dev/null differ diff --git a/crash_replays/006.rep b/crash_replays/006.rep deleted file mode 100644 index 5a8c2f9..0000000 Binary files a/crash_replays/006.rep and /dev/null differ diff --git a/crash_replays/007.rep b/crash_replays/007.rep deleted file mode 100644 index c4805cf..0000000 Binary files a/crash_replays/007.rep and /dev/null differ diff --git a/crash_replays/008.rep b/crash_replays/008.rep deleted file mode 100644 index bbfa073..0000000 Binary files a/crash_replays/008.rep and /dev/null differ diff --git a/crash_replays/009.rep b/crash_replays/009.rep deleted file mode 100644 index e84b905..0000000 Binary files a/crash_replays/009.rep and /dev/null differ diff --git a/crash_replays/010.rep b/crash_replays/010.rep deleted file mode 100644 index 07e4db2..0000000 Binary files a/crash_replays/010.rep and /dev/null differ diff --git a/crash_replays/011.rep b/crash_replays/011.rep deleted file mode 100644 index 28d7661..0000000 Binary files a/crash_replays/011.rep and /dev/null differ diff --git a/crash_replays/012.rep b/crash_replays/012.rep deleted file mode 100644 index 7c9eb53..0000000 Binary files a/crash_replays/012.rep and /dev/null differ diff --git a/src/assembler.rs b/src/assembler.rs index 3fc0d2a..36aa0f4 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -589,7 +589,7 @@ impl fn get_info( &self, - index: u16, + index: u32, data_store: &DataStore, ) -> AssemblerOnclickInfo { let items = data_store.recipe_to_items.get(&self.recipe).unwrap(); @@ -790,23 +790,12 @@ impl // TODO: I don't think this holds anymore, now that we cannot bail early at 0 power_mult // debug_assert!(increase > 0); - let ings_arr = ZipArray { - array: self.ings.each_mut().map(|r| r.iter_mut()), - }; - - let outputs_arr = ZipArray { - array: self.outputs.each_mut().map(|r| r.iter_mut()), - }; - let mut power = Watt(0); - // TODO: Benchmark if this is okay - for ( - mut outputs, - (mut ings, (timer, (prod_timer, (speed_mod, (bonus_prod, (base_power, power_mod)))))), - ) in outputs_arr.zip( - ings_arr.zip( - self.timers.iter_mut().zip( + for (index, (timer, (prod_timer, (speed_mod, (bonus_prod, (base_power, power_mod)))))) in + self.timers + .iter_mut() + .zip( self.prod_timers.iter_mut().zip( self.combined_speed_mod.iter().copied().zip( self.bonus_productivity.iter().copied().zip( @@ -817,34 +806,32 @@ impl ), ), ), - ), - ), - ) { - // FIXME: Remove the items from the ings at the start of the crafting process + ) + .enumerate() + { + // ~~Remove the items from the ings at the start of the crafting process~~ + // We will do this as part of the frontend ui! let increase = (u32::from(increase) * u32::from(speed_mod) / 20) as u16; - let ing_mul: u8 = ings - .iter() - .zip(our_ings.iter()) - .fold(1, |acc, (have, want)| acc * u8::from(**have >= *want)); - let ing_mul_for_two_crafts: u16 = ings - .iter() - .zip(our_ings.iter()) - .fold(1, |acc, (have, want)| { - acc * u16::from(**have >= (*want * 2)) - }); + let mut ing_mul: u8 = 1; + for i in 0..NUM_INGS { + ing_mul *= u8::from(self.ings[i][index] >= our_ings[i]); + } + + let mut ing_mul_for_two_crafts: u16 = 1; + for i in 0..NUM_INGS { + ing_mul_for_two_crafts *= u16::from(self.ings[i][index] >= our_ings[i] * 2); + } + let new_timer_output_space = timer.wrapping_add(increase * u16::from(ing_mul)); let new_timer_output_full = timer.saturating_add(increase * u16::from(ing_mul)); - let space_mul: u8 = - outputs - .iter() - .zip(our_outputs.iter()) - .fold(1, |acc, (have, new_from_recipe)| { - // TODO: 100 output amount hardcoded!!!! - acc * u8::from((have.saturating_add(*new_from_recipe)) <= 100) - }); + let mut space_mul: u8 = 1; + for i in 0..NUM_OUTPUTS { + space_mul *= + u8::from((self.outputs[i][index].saturating_add(our_outputs[i])) <= 100); + } let new_timer = new_timer_output_space * u16::from(space_mul) + new_timer_output_full * (1 - u16::from(space_mul)); @@ -867,13 +854,12 @@ impl *timer = new_timer; *prod_timer = new_prod_timer; - outputs - .iter_mut() - .zip(our_outputs.iter()) - .for_each(|(output, new)| **output += (timer_mul + prod_timer_mul) * new); - ings.iter_mut() - .zip(our_ings.iter()) - .for_each(|(ing, used)| **ing -= timer_mul * used); + for i in 0..NUM_OUTPUTS { + self.outputs[i][index] += (timer_mul + prod_timer_mul) * our_outputs[i]; + } + for i in 0..NUM_INGS { + self.ings[i][index] -= timer_mul * our_ings[i]; + } times_ings_used += u32::from(timer_mul); num_finished_crafts += u32::from(timer_mul + prod_timer_mul); } @@ -907,44 +893,41 @@ impl self.ings.each_mut().map(|b| &mut **b) } - pub fn get_outputs_mut(&mut self, idx: usize) -> &mut [ITEMCOUNTTYPE] { - &mut self.outputs[idx] + pub fn get_outputs_mut(&mut self, idx: u32) -> &mut [ITEMCOUNTTYPE] { + &mut self.outputs[idx as usize] } - pub fn get_ings_mut(&mut self, idx: usize) -> &mut [ITEMCOUNTTYPE] { - &mut self.ings[idx] + pub fn get_ings_mut(&mut self, idx: u32) -> &mut [ITEMCOUNTTYPE] { + &mut self.ings[idx as usize] } - pub fn get_output_mut( - &mut self, - output_idx: usize, - index: usize, - ) -> Option<&mut ITEMCOUNTTYPE> { - if index < self.len { - Some(&mut self.outputs[output_idx][index]) + pub fn get_output_mut(&mut self, output_idx: usize, index: u32) -> Option<&mut ITEMCOUNTTYPE> { + if (index as usize) < self.len { + Some(&mut self.outputs[output_idx][index as usize]) } else { None } } - pub fn get_output(&self, output_idx: usize, index: usize) -> Option<&ITEMCOUNTTYPE> { - if index < self.len { - Some(&self.outputs[output_idx][index]) + pub fn get_output(&self, output_idx: usize, index: u32) -> Option<&ITEMCOUNTTYPE> { + if (index as usize) < self.len { + Some(&self.outputs[output_idx][index as usize]) } else { None } } - pub fn get_ing_mut(&mut self, input_idx: usize, index: usize) -> Option<&mut ITEMCOUNTTYPE> { - if index < self.len { - Some(&mut self.ings[input_idx][index]) + pub fn get_ing_mut(&mut self, input_idx: usize, index: u32) -> Option<&mut ITEMCOUNTTYPE> { + if (index as usize) < self.len { + Some(&mut self.ings[input_idx][index as usize]) } else { None } } /// The caller must make sure, that this index is not used in any other machine, since it will either crash/work on a nonexistant Assembler or be reused for another machine! - pub fn remove_assembler(&mut self, index: usize) -> AssemblerRemovalInfo { + pub fn remove_assembler(&mut self, index: u32) -> AssemblerRemovalInfo { + let index = index as usize; debug_assert!(!self.holes.contains(&index)); self.holes.push(index); @@ -966,7 +949,7 @@ impl pub fn remove_assembler_data( &mut self, - index: usize, + index: u32, ) -> ( Vec, Vec, @@ -1001,7 +984,7 @@ impl fn remove_assembler_data_inner( &mut self, - index: usize, + index: u32, ) -> ( [ITEMCOUNTTYPE; NUM_INGS], [ITEMCOUNTTYPE; NUM_INGS], @@ -1016,6 +999,7 @@ impl u8, Position, ) { + let index = index as usize; debug_assert!(!self.holes.contains(&index)); self.holes.push(index); @@ -1061,7 +1045,7 @@ impl modules: &[Option], position: Position, data_store: &DataStore, - ) -> usize { + ) -> u32 { assert_eq!( modules.len(), data_store.assembler_info[usize::from(ty)].num_module_slots as usize @@ -1114,10 +1098,10 @@ impl pub fn move_assembler( &mut self, - index: usize, + index: u32, dest: &mut Self, data_store: &DataStore, - ) -> usize { + ) -> u32 { let data = self.remove_assembler_data_inner(index); dest.add_assembler_with_data( @@ -1141,7 +1125,7 @@ impl ty: u8, position: Position, data_store: &DataStore, - ) -> usize { + ) -> u32 { let len = self.timers.len(); // debug_assert!(len % Simdtype::LEN == 0); @@ -1188,7 +1172,7 @@ impl self.types[hole_index] = ty; self.positions[hole_index] = position; - return hole_index; + return hole_index.try_into().unwrap(); } if self.len == self.timers.len() { @@ -1357,17 +1341,18 @@ impl self.types.push(ty); self.len += 1; - self.len - 1 + (self.len - 1).try_into().unwrap() } pub fn modify_modifiers( &mut self, - index: u16, + index: u32, speed: i16, prod: i16, power: i16, data_store: &DataStore, ) { + let index = index as usize; self.raw_speed_mod[usize::from(index)] = self.raw_speed_mod[usize::from(index)] .checked_add(speed) .expect("Over/Underflowed"); diff --git a/src/belt/mod.rs b/src/belt/mod.rs index c414c4e..00c8dad 100644 --- a/src/belt/mod.rs +++ b/src/belt/mod.rs @@ -13,6 +13,7 @@ use std::{ mem, usize, }; +use crate::inserter::FakeUnionStorage; use crate::{ data::DataStore, inserter::{ @@ -45,9 +46,9 @@ enum FreeIndex { } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -enum Inserter { - Out(BeltStorageInserter), - In(BeltStorageInserter), +enum Inserter { + Out(BeltStorageInserter<{ Dir::BeltToStorage }>), + In(BeltStorageInserter<{ Dir::StorageToBelt }>), } #[derive( @@ -87,8 +88,8 @@ fn do_update_test_bools(items: &mut [bool]) { } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -pub struct BeltStore { - pub inner: InnerBeltStore, +pub struct BeltStore { + pub inner: InnerBeltStore, any_belts: Vec>, any_belt_holes: Vec, @@ -115,11 +116,11 @@ enum BeltGraphConnection { } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -pub struct InnerBeltStore { - sushi_belts: Vec>, +pub struct InnerBeltStore { + sushi_belts: Vec>, sushi_belt_holes: Vec, - smart_belts: Box<[MultiBeltStore]>, + smart_belts: Box<[MultiBeltStore]>, pub belt_belt_inserters: BeltBeltInserterStore, @@ -232,11 +233,8 @@ pub struct BreakBeltResultInfo { pub new_belt: Option<(BeltTileId, Side)>, } -impl InnerBeltStore { - fn remove_smart_belt( - &mut self, - id: BeltId, - ) -> SmartBelt { +impl InnerBeltStore { + fn remove_smart_belt(&mut self, id: BeltId) -> SmartBelt { self.smart_belts[usize_from(id.item.id)].remove_belt(id.index) } @@ -244,8 +242,7 @@ impl InnerBeltStore, id: usize, - ) -> [impl IntoIterator> + use<'a, ItemIdxType, RecipeIdxType>; 2] - { + ) -> [impl IntoIterator> + use<'a, ItemIdxType>; 2] { let index_to_id = move |index| BeltId { item, index }; let [input, output] = self.pure_splitters[usize_from(item.id)].get_splitter_belt_ids(id); @@ -259,30 +256,25 @@ impl InnerBeltStore( &'a self, id: usize, - ) -> [impl IntoIterator + use<'a, ItemIdxType, RecipeIdxType>; 2] { + ) -> [impl IntoIterator + use<'a, ItemIdxType>; 2] { [ self.sushi_splitters[id].input_belts.iter().copied(), self.sushi_splitters[id].output_belts.iter().copied(), ] } - fn remove_sushi_belt(&mut self, id: usize) -> SushiBelt { + fn remove_sushi_belt(&mut self, id: usize) -> SushiBelt { let mut temp = SushiBelt::new(1); mem::swap(&mut temp, &mut self.sushi_belts[id]); + self.sushi_belt_holes.push(id); temp } - fn get_smart( - &self, - smart_belt_id: BeltId, - ) -> &SmartBelt { + fn get_smart(&self, smart_belt_id: BeltId) -> &SmartBelt { &self.smart_belts[usize_from(smart_belt_id.item.id)].belts[smart_belt_id.index] } - fn get_smart_mut( - &mut self, - smart_belt_id: BeltId, - ) -> &mut SmartBelt { + fn get_smart_mut(&mut self, smart_belt_id: BeltId) -> &mut SmartBelt { &mut self.smart_belts[usize_from(smart_belt_id.item.id)].belts[smart_belt_id.index] } @@ -290,21 +282,18 @@ impl InnerBeltStore, indices: [usize; N], - ) -> [&mut SmartBelt; N] { + ) -> [&mut SmartBelt; N] { self.smart_belts[usize_from(item.id)] .belts .get_disjoint_mut(indices) .unwrap() } - fn get_sushi(&self, sushi_belt_id: usize) -> &SushiBelt { + fn get_sushi(&self, sushi_belt_id: usize) -> &SushiBelt { &self.sushi_belts[sushi_belt_id] } - fn get_sushi_mut( - &mut self, - sushi_belt_id: usize, - ) -> &mut SushiBelt { + fn get_sushi_mut(&mut self, sushi_belt_id: usize) -> &mut SushiBelt { &mut self.sushi_belts[sushi_belt_id] } @@ -670,7 +659,7 @@ impl InnerBeltStore) -> usize { + fn add_sushi_belt(&mut self, belt: SushiBelt) -> usize { let sushi_idx = if let Some(hole) = self.sushi_belt_holes.pop() { self.sushi_belts[hole] = belt; hole @@ -682,7 +671,7 @@ impl InnerBeltStore) -> BeltId { + fn add_belt(&mut self, belt: SmartBelt) -> BeltId { let item = belt.item; let smart_idx = self.smart_belts[usize_from(belt.item.id)].add_belt(belt); @@ -918,8 +907,10 @@ enum MakePureError { ErrorSushi, } -impl BeltStore { - pub fn new(data_store: &DataStore) -> Self { +impl BeltStore { + pub fn new( + data_store: &DataStore, + ) -> Self { Self { inner: InnerBeltStore { sushi_belts: vec![], @@ -978,8 +969,8 @@ impl BeltStore( - store: &mut BeltStore, + fn check_incoming_edges( + store: &mut BeltStore, tile_id: BeltTileId, mut goal_item: Option>, incoming_edges: &[(NodeIndex, BeltGraphConnection)], @@ -1459,7 +1450,7 @@ impl BeltStore( + pub fn update<'a, 'b, RecipeIdxType: IdxTrait>( &mut self, num_grids_total: usize, storages_by_item: impl IndexedParallelIterator>, @@ -1651,7 +1642,7 @@ impl BeltStore) -> BeltTileId { + fn add_belt(&mut self, belt: SmartBelt) -> BeltTileId { let id = self.inner.add_belt(belt); let new_id = self.add_smart_to_any_list(id); @@ -1673,10 +1664,7 @@ impl BeltStore, - ) -> BeltTileId { + fn add_sushi_belt(&mut self, belt: SushiBelt) -> BeltTileId { let sushi_idx = self.inner.add_sushi_belt(belt); let new_id = self.add_sushi_to_any_list(sushi_idx); @@ -1776,11 +1764,10 @@ impl BeltStore, id: BeltTileId, pos: BeltLenType, - storage_id: Storage, + storage_id: FakeUnionStorage, ) -> Result<(), SpaceOccupiedError> { - let handle_sushi_belt = |belt: &mut SushiBelt| { - belt.add_in_inserter(filter, pos, storage_id) - }; + let handle_sushi_belt = + |belt: &mut SushiBelt| belt.add_in_inserter(filter, pos, storage_id); match id { BeltTileId::AnyBelt(index, _) => { @@ -1839,11 +1826,10 @@ impl BeltStore, id: BeltTileId, pos: BeltLenType, - storage_id: Storage, + storage_id: FakeUnionStorage, ) -> Result<(), SpaceOccupiedError> { - let handle_sushi_belt = |belt: &mut SushiBelt| { - belt.add_out_inserter(filter, pos, storage_id) - }; + let handle_sushi_belt = + |belt: &mut SushiBelt| belt.add_out_inserter(filter, pos, storage_id); match id { BeltTileId::AnyBelt(index, _) => { @@ -1972,8 +1958,8 @@ impl BeltStore, ) -> ( - impl IntoIterator> + Clone + use<'a, ItemIdxType, RecipeIdxType>, - impl IntoIterator> + Clone + use<'a, ItemIdxType, RecipeIdxType>, + impl IntoIterator> + Clone + use<'a, ItemIdxType>, + impl IntoIterator> + Clone + use<'a, ItemIdxType>, ) { // FIXME: Consider splitters!!!! ( @@ -2194,7 +2180,7 @@ impl BeltStore( &mut self, front_tile_id: BeltTileId, back_tile_id: BeltTileId, @@ -2388,15 +2374,13 @@ impl BeltStore { - pub belts: Vec>, +pub struct MultiBeltStore { + pub belts: Vec>, pub holes: Vec, } -impl Default - for MultiBeltStore -{ +impl Default for MultiBeltStore { fn default() -> Self { Self { belts: vec![], @@ -2405,17 +2389,15 @@ impl Default } } -impl MultiBeltStore { - pub fn belts_mut( - &mut self, - ) -> impl IntoIterator> { +impl MultiBeltStore { + pub fn belts_mut(&mut self) -> impl IntoIterator> { self.belts .iter_mut() .enumerate() .filter_map(|(i, b)| (!self.holes.contains(&i)).then_some(b)) } - pub fn add_belt(&mut self, belt: SmartBelt) -> usize { + pub fn add_belt(&mut self, belt: SmartBelt) -> usize { if let Some(hole) = self.holes.pop() { self.belts[hole] = belt; hole @@ -2425,7 +2407,7 @@ impl MultiBeltStore SmartBelt { + pub fn remove_belt(&mut self, belt: usize) -> SmartBelt { self.holes.push(belt); let mut temp = SmartBelt::new(1, self.belts[belt].item); diff --git a/src/belt/smart.rs b/src/belt/smart.rs index 4f0fff9..1998a57 100644 --- a/src/belt/smart.rs +++ b/src/belt/smart.rs @@ -8,6 +8,8 @@ use crate::{ storage_list::SingleItemStorages, }; +use crate::inserter::FakeUnionStorage; + use super::{ belt::{Belt, BeltLenType, ItemInfo, NoSpaceError}, sushi::{SushiBelt, SushiInserterStore}, @@ -16,13 +18,13 @@ use super::{ #[allow(clippy::module_name_repetitions)] #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -pub struct SmartBelt { +pub struct SmartBelt { pub(super) is_circular: bool, pub(super) first_free_index: FreeIndex, /// Important, zero_index must ALWAYS be used using mod len pub(super) zero_index: BeltLenType, pub(super) locs: Box<[bool]>, - pub(super) inserters: InserterStore, + pub(super) inserters: InserterStore, pub(super) item: Item, } @@ -34,16 +36,16 @@ pub struct EmptyBelt { } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -pub struct InserterStore { - pub(super) inserters: Vec>, +pub struct InserterStore { + pub(super) inserters: Vec, pub(super) offsets: Vec, } #[derive(Debug)] -pub struct BeltInserterInfo { +pub struct BeltInserterInfo { pub outgoing: bool, pub state: InserterState, - pub connection: Storage, + pub connection: FakeUnionStorage, } const MIN_INSERTER_SPACING: usize = 8; @@ -56,7 +58,7 @@ pub(super) enum InserterAdditionError { ItemMismatch, } -impl SmartBelt { +impl SmartBelt { #[must_use] pub fn new(len: u16, item: Item) -> Self { Self { @@ -77,7 +79,7 @@ impl SmartBelt SushiBelt { + pub(super) fn into_sushi_belt(self) -> SushiBelt { let Self { is_circular, first_free_index, @@ -182,11 +184,7 @@ impl SmartBelt, - new: Storage, - ) { + pub fn change_inserter_storage_id(&mut self, old: FakeUnionStorage, new: FakeUnionStorage) { for inserter in &mut self.inserters.inserters { match inserter { Inserter::Out(inserter) => { @@ -203,7 +201,7 @@ impl SmartBelt) { + pub fn set_inserter_storage_id(&mut self, belt_pos: u16, new: FakeUnionStorage) { let mut pos = 0; for (offset, inserter) in self @@ -229,7 +227,7 @@ impl SmartBelt Option> { + pub fn get_inserter_info_at(&self, belt_pos: u16) -> Option { let mut pos = 0; for (offset, inserter) in self @@ -261,7 +259,7 @@ impl SmartBelt Storage { + pub fn remove_inserter(&mut self, pos: BeltLenType) -> FakeUnionStorage { assert!( usize::from(pos) < self.locs.len(), "Bounds check {pos} >= {}", @@ -308,7 +306,7 @@ impl SmartBelt, index: u16, - storage_id: Storage, + storage_id: FakeUnionStorage, ) -> Result<(), InserterAdditionError> { assert!( usize::from(index) < self.locs.len(), @@ -361,7 +359,7 @@ impl SmartBelt, index: u16, - storage_id: Storage, + storage_id: FakeUnionStorage, ) -> Result<(), InserterAdditionError> { assert!( usize::from(index) < self.locs.len(), @@ -408,7 +406,7 @@ impl SmartBelt Option<&Inserter> { + fn get_inserter(&self, index: u16) -> Option<&Inserter> { let mut pos_after_last_inserter = 0; for (i, offset) in self.inserters.offsets.iter().enumerate() { @@ -859,10 +857,10 @@ impl EmptyBelt { } } - pub fn into_smart_belt( + pub fn into_smart_belt( self, item: Item, - ) -> SmartBelt { + ) -> SmartBelt { SmartBelt::new(self.len.into(), item) } @@ -895,9 +893,7 @@ pub enum Side { BACK, } -impl Belt - for SmartBelt -{ +impl Belt for SmartBelt { fn add_length(&mut self, amount: BeltLenType, side: Side) -> BeltLenType { assert!(!self.is_circular); take_mut::take(self, |s| s.join_with_empty(EmptyBelt::new(amount), side)); diff --git a/src/belt/splitter.rs b/src/belt/splitter.rs index 9a384d7..38e55cf 100644 --- a/src/belt/splitter.rs +++ b/src/belt/splitter.rs @@ -74,10 +74,7 @@ pub struct Splitter { impl Splitter { // TODO: Test this - pub fn update( - &mut self, - belts: &mut MultiBeltStore, - ) { + pub fn update(&mut self, belts: &mut MultiBeltStore) { // FIXME: Handle the case where an input and output are the same belt! let [input_1, input_2, output_1, output_2] = belts .belts @@ -88,8 +85,7 @@ impl Splitter { self.output_belts[1], ]) .expect("Inputs or outputs overlap (or something is out of bounds)"); - let mut inputs: [&mut super::smart::SmartBelt; 2] = - [input_1, input_2]; + let mut inputs: [&mut super::smart::SmartBelt; 2] = [input_1, input_2]; let mut outputs = [output_1, output_2]; let num_items_possible_to_input = inputs @@ -183,7 +179,7 @@ impl SushiSplitter { // TODO: Test this pub fn update( &mut self, - belts: &mut [SushiBelt], + belts: &mut [SushiBelt], ) { // FIXME: Handle the case where an input and output are the same belt! let [input_1, input_2, output_1, output_2] = belts @@ -194,8 +190,8 @@ impl SushiSplitter { self.output_belts[1], ]) .expect("Inputs or outputs overlap (or something is out of bounds)"); - let mut inputs: [&mut SushiBelt; 2] = [input_1, input_2]; - let mut outputs: [&mut SushiBelt; 2] = [output_1, output_2]; + let mut inputs: [&mut SushiBelt; 2] = [input_1, input_2]; + let mut outputs: [&mut SushiBelt; 2] = [output_1, output_2]; let num_items_possible_to_input = inputs .iter() diff --git a/src/belt/sushi.rs b/src/belt/sushi.rs index b352e20..4665cf6 100644 --- a/src/belt/sushi.rs +++ b/src/belt/sushi.rs @@ -13,20 +13,21 @@ use super::{ smart::{InserterStore, Side, SmartBelt, SpaceOccupiedError}, FreeIndex, Inserter, }; +use crate::inserter::FakeUnionStorage; #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -pub(super) struct SushiBelt { +pub(super) struct SushiBelt { pub(super) is_circular: bool, pub(super) locs: Box<[Option>]>, pub(super) first_free_index: FreeIndex, /// Important, zero_index must ALWAYS be used using mod len pub(super) zero_index: BeltLenType, - pub(super) inserters: SushiInserterStore, + pub(super) inserters: SushiInserterStore, } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -pub(super) struct SushiInserterStore { - pub(super) inserters: Vec<(Inserter, Item)>, +pub(super) struct SushiInserterStore { + pub(super) inserters: Vec<(Inserter, Item)>, pub(super) offsets: Vec, } @@ -36,7 +37,7 @@ pub(super) enum SushiInfo { Pure(Option>), } -impl SushiBelt { +impl SushiBelt { pub fn new(len: BeltLenType) -> Self { Self { is_circular: false, @@ -54,7 +55,7 @@ impl SushiBelt, pos: BeltLenType, - storage_id: Storage, + storage_id: FakeUnionStorage, ) -> Result<(), SpaceOccupiedError> { assert!( usize::from(pos) < self.locs.len(), @@ -100,7 +101,7 @@ impl SushiBelt, pos: BeltLenType, - storage_id: Storage, + storage_id: FakeUnionStorage, ) -> Result<(), SpaceOccupiedError> { assert!( usize::from(pos) < self.locs.len(), @@ -234,7 +235,7 @@ impl SushiBelt) -> SmartBelt { + pub fn into_smart_belt(self, item: Item) -> SmartBelt { let found_item = match self.locs.iter().copied().flatten().all_equal_value() { Ok(found_item) => { assert_eq!(found_item, item); @@ -452,9 +453,7 @@ impl SushiBelt Belt - for SushiBelt -{ +impl Belt for SushiBelt { fn query_item( &self, pos: super::belt::BeltLenType, @@ -508,6 +507,7 @@ impl Belt BeltLenType::try_from(self.locs.len()).expect("Belt too long!") } + #[profiling::function] fn update(&mut self) { if self.query_item(0).is_none() { // Correctness: Since we always % len whenever we access using self.zero_index, we do not need to % len here diff --git a/src/chest.rs b/src/chest.rs index ce03e73..65fb34a 100644 --- a/src/chest.rs +++ b/src/chest.rs @@ -47,6 +47,7 @@ pub struct MultiChestStore { } impl MultiChestStore { + #[must_use] pub fn new( item: Item, data_store: &DataStore, @@ -66,7 +67,7 @@ impl MultiChestStore { ty: u8, slot_limit: u8, data_store: &DataStore, - ) -> usize { + ) -> u32 { let stack_size = data_store.item_stack_sizes[usize_from(self.item.id)]; assert!(slot_limit <= data_store.chest_num_slots[usize::from(ty)]); let num_stacks = slot_limit; @@ -78,7 +79,7 @@ impl MultiChestStore { self.max_insert[hole] = max_items.try_into().unwrap_or(ITEMCOUNTTYPE::MAX); self.max_items[hole] = max_items.saturating_sub(u16::from(ITEMCOUNTTYPE::MAX)); - hole + hole.try_into().unwrap() } else { self.inout.push(0); self.storage.push(0); @@ -87,28 +88,29 @@ impl MultiChestStore { self.max_items .push(max_items.saturating_sub(u16::from(ITEMCOUNTTYPE::MAX))); - self.inout.len() - 1 + (self.inout.len() - 1).try_into().unwrap() } } pub fn remove_chest( &mut self, - index: usize, + index: u32, data_store: &DataStore, ) -> u16 { + let index = index as usize; self.holes.push(index); - let items = self.inout[index] as u16 + self.storage[index]; + let items = u16::from(self.inout[index]) + self.storage[index]; self.inout[index] = 0; self.storage[index] = 0; self.max_items[index] = 0; items } - pub fn get_chest(&self, index: usize) -> (u16, u16) { + pub fn get_chest(&self, index: u32) -> (u16, u16) { ( - self.storage[index] + u16::from(self.inout[index]), - self.max_items[index], + self.storage[index as usize] + u16::from(self.inout[index as usize]), + self.max_items[index as usize], ) } @@ -121,19 +123,19 @@ impl MultiChestStore { let to_move = inout.abs_diff(CHEST_GOAL_AMOUNT); if *inout >= CHEST_GOAL_AMOUNT { - let moved: ITEMCOUNTTYPE = min(to_move as u16, max_items - *storage) + let moved: ITEMCOUNTTYPE = min(u16::from(to_move), max_items - *storage) .try_into() .expect("since to_move was a ITEMCOUNTTYPE, this always fits"); *inout -= moved; - *storage += moved as u16; + *storage += u16::from(to_move); debug_assert!(*storage <= max_items); } else { - let moved: ITEMCOUNTTYPE = min(to_move as u16, *storage) + let moved: ITEMCOUNTTYPE = min(u16::from(to_move), *storage) .try_into() .expect("since to_move was a ITEMCOUNTTYPE, this always fits"); *inout += moved; - *storage -= moved as u16; + *storage -= u16::from(to_move); } } } @@ -150,11 +152,11 @@ impl MultiChestStore { let moved: i16 = (switch as i16 + (1 - switch as i16) * -1) * (min( - to_move as u16, + u16::from(to_move), (max_items - *storage) * switch + (1 - switch) * *storage, ) as i16); - *inout = (*inout as u16).wrapping_sub_signed(moved) as u8; + *inout = (u16::from(*inout)).wrapping_sub_signed(moved) as u8; *storage = (*storage).wrapping_add_signed(moved) as u16; debug_assert!(*storage <= max_items); @@ -162,7 +164,9 @@ impl MultiChestStore { } /// Returns the number of items no longer part of the box - pub fn change_chest_size(&mut self, index: usize, new_size: u16) -> u16 { + pub fn change_chest_size(&mut self, index: u32, new_size: u16) -> u16 { + let index = index as usize; + let removed_items = if new_size < max(self.max_items[index], self.max_insert[index] as u16) { let current_items = self.inout[index] as u16 + self.storage[index]; @@ -171,7 +175,7 @@ impl MultiChestStore { let items_to_remove = current_items - new_size; if self.storage[index] >= items_to_remove { - self.storage[index] -= items_to_remove + self.storage[index] -= items_to_remove; } else { self.inout[index] = self.inout[index] .checked_sub( @@ -231,19 +235,19 @@ mod test { let mut inout_naive = inout; if inout_naive >= CHEST_GOAL_AMOUNT { - let moved: ITEMCOUNTTYPE = min(to_move as u16, max_items - storage) + let moved: ITEMCOUNTTYPE = min(u16::from(to_move), max_items - storage) .try_into() .expect("since to_move was a ITEMCOUNTTYPE, this always fits"); inout_naive -= moved; - storage_naive += moved as u16; + storage_naive += u16::from(moved); debug_assert!(storage_naive <= max_items); } else { - let moved: ITEMCOUNTTYPE = min(to_move as u16, storage) + let moved: ITEMCOUNTTYPE = min(u16::from(to_move), storage) .try_into() .expect("since to_move was a ITEMCOUNTTYPE, this always fits"); inout_naive += moved; - storage_naive -= moved as u16; + storage_naive -= u16::from(moved); } let mut storage_simd = storage; diff --git a/src/data/factorio_1_1.fgmod b/src/data/factorio_1_1.fgmod index b8e58d9..e4281cd 100644 --- a/src/data/factorio_1_1.fgmod +++ b/src/data/factorio_1_1.fgmod @@ -497,4 +497,19 @@ precursors: [], ), ], + solar_panels: [ + ( + name: "factory_game::infinity_battery", + display_name: "Infinity Battery", + tile_size: (2, 2), + output: (100000000000), + ), + ( + name: "factory_game::solar_panel", + display_name: "Solar Panel", + tile_size: (3, 3), + output: (60000), + ), + ], + accumulators: [], ) \ No newline at end of file diff --git a/src/data/factorio_1_1.rs b/src/data/factorio_1_1.rs index afb7564..3b6a6ca 100644 --- a/src/data/factorio_1_1.rs +++ b/src/data/factorio_1_1.rs @@ -2,7 +2,7 @@ use crate::power::Watt; use super::{ AllowedIn, RawAssemblingMachine, RawBeacon, RawChest, RawDataStore, RawEntity, RawItem, - RawItemStack, RawLab, RawModule, RawPowerPole, RawRecipeData, RawTechnology, + RawItemStack, RawLab, RawModule, RawPowerPole, RawRecipeData, RawSolarPanel, RawTechnology, }; const RAW_DATA_STR: &'static str = include_str!("factorio_1_1.fgmod"); @@ -10,6 +10,7 @@ const RAW_DATA_STR: &'static str = include_str!("factorio_1_1.fgmod"); #[must_use] pub fn get_raw_data_test() -> RawDataStore { ron::from_str(RAW_DATA_STR).expect("RAW_DATA_STR invalid") + // get_raw_data_fn() } #[must_use] @@ -232,7 +233,7 @@ pub fn get_raw_data_fn() -> RawDataStore { amount: 1, }] .into_boxed_slice(), - time_to_craft: 300, + time_to_craft: 360, is_intermediate: true, }, @@ -369,6 +370,16 @@ pub fn get_raw_data_fn() -> RawDataStore { base_speed: 25, num_module_slots: 4, }, + RawAssemblingMachine { + name: "factory_game::electric_furnace".to_string(), + display_name: "Electric Furnace".to_string(), + tile_size: (3, 3), + working_power_draw: Watt(180000), + fluid_connection_offsets: [].to_vec(), + num_module_slots: 2, + base_bonus_prod: 0, + base_speed: 40, + }, ], labs: vec![RawLab { name: "factory_game::lab".to_string(), @@ -475,5 +486,22 @@ pub fn get_raw_data_fn() -> RawDataStore { num_units: 10, precursors: vec![], }], + solar_panels: vec![ + RawSolarPanel { + name: "factory_game::infinity_battery".to_string(), + display_name: "Infinity Battery".to_string(), + tile_size: (2, 2), + // 1 Terrawatt should be enough for now + output: Watt(1_000_000_000_000), + }, + RawSolarPanel { + name: "factory_game::solar_panel".to_string(), + display_name: "Solar Panel".to_string(), + tile_size: (3, 3), + // TODO: Non constant output + output: Watt(60_000), + }, + ], + accumulators: vec![], } } diff --git a/src/data/mod.rs b/src/data/mod.rs index 29bc5ca..61d00b5 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -93,6 +93,27 @@ struct RawBeacon { effect_size: (u8, u8), } +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +struct RawSolarPanel { + name: String, + display_name: String, + tile_size: (u8, u8), + + // TODO: + output: Watt, +} + +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +struct RawAccumulator { + name: String, + display_name: String, + tile_size: (u8, u8), + + charge: Joule, + max_charge_rate: Watt, + max_discharge_rate: Watt, +} + #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] struct RawFluidConnection { fluid_dir: ItemRecipeDir, @@ -122,6 +143,8 @@ pub struct RawDataStore { modules: Vec, chests: Vec, technologies: Vec, + solar_panels: Vec, + accumulators: Vec, } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] @@ -233,6 +256,30 @@ pub struct ModuleInfo { pub power_mod: i8, } +#[derive(Debug, Clone, serde::Serialize, serde:: Deserialize)] +pub struct SolarPanelInfo { + pub name: String, + pub size: [u16; 2], + + pub power_output: SolarPanelOutputFunction, +} + +#[derive(Debug, Clone, serde::Serialize, serde:: Deserialize)] +pub enum SolarPanelOutputFunction { + Constant(Watt), + Lookup(Vec), +} + +#[derive(Debug, Clone, serde::Serialize, serde:: Deserialize)] +pub struct AccumulatorInfo { + pub name: String, + pub size: [u16; 2], + + pub max_charge: Joule, + pub max_charge_rate: Watt, + pub max_discharge_rate: Watt, +} + #[derive(Debug, Clone, serde::Serialize, serde:: Deserialize)] pub struct DataStore { pub checksum: String, @@ -244,6 +291,8 @@ pub struct DataStore { pub beacon_info: Vec, pub max_beacon_range: (u16, u16), pub module_info: Vec, + pub solar_panel_info: Vec, + pub accumulator_info: Vec, /// In 5% steps pub min_power_mod: u8, @@ -710,7 +759,7 @@ impl RawDataStore { .power_poles .iter() .map(|p| PowerPoleData { - size: (p.tile_size.0 as u16, p.tile_size.1 as u16), + size: (u16::from(p.tile_size.0), u16::from(p.tile_size.1)), power_range: p.power_range, connection_range: p.connection_range, }) @@ -788,6 +837,31 @@ impl RawDataStore { }) .collect(), + solar_panel_info: self + .solar_panels + .iter() + .map(|raw| { + SolarPanelInfo { + name: raw.display_name.clone(), + size: [raw.tile_size.0.into(), raw.tile_size.1.into()], + // FIXME: + power_output: SolarPanelOutputFunction::Constant(raw.output), + } + }) + .collect(), + + accumulator_info: self + .accumulators + .iter() + .map(|raw| AccumulatorInfo { + name: raw.display_name.clone(), + size: [raw.tile_size.0.into(), raw.tile_size.1.into()], + max_charge: raw.charge, + max_charge_rate: raw.max_charge_rate, + max_discharge_rate: raw.max_discharge_rate, + }) + .collect(), + beacon_info: self .beacons .iter() @@ -888,7 +962,7 @@ impl RawDataStore { chest_tile_sizes: self .chests .iter() - .map(|chest| (chest.tile_size.0 as u16, chest.tile_size.1 as u16)) + .map(|chest| (u16::from(chest.tile_size.0), u16::from(chest.tile_size.1))) .collect(), recipe_to_translated_index: (0..self.recipes.len()) diff --git a/src/frontend/action/action_state_machine.rs b/src/frontend/action/action_state_machine.rs index ba0bdd0..9e6f327 100644 --- a/src/frontend/action/action_state_machine.rs +++ b/src/frontend/action/action_state_machine.rs @@ -31,6 +31,8 @@ pub struct ActionStateMachine, + pub consumption_filters: Vec, current_mouse_pos: (f32, f32), current_held_keys: HashSet, @@ -72,13 +74,19 @@ impl ActionStateMachine { #[must_use] - pub fn new(my_player_id: PLAYERID, local_player_pos: (f32, f32)) -> Self { + pub fn new( + my_player_id: PLAYERID, + local_player_pos: (f32, f32), + data_store: &DataStore, + ) -> Self { Self { my_player_id, local_player_pos, statistics_panel_open: false, statistics_panel: StatisticsPanel::default(), + production_filters: vec![true; data_store.item_names.len()], + consumption_filters: vec![true; data_store.item_names.len()], current_mouse_pos: (0.0, 0.0), current_held_keys: HashSet::new(), @@ -535,9 +543,9 @@ impl mouse_pos: (f32, f32), ) -> Position { let mouse_pos = ( - ((mouse_pos.0 - 0.5) * (WIDTH_PER_LEVEL as f32)) + ((mouse_pos.0) * (WIDTH_PER_LEVEL as f32)) .mul_add(zoom_level * zoom_level, player_pos.0), - ((mouse_pos.1 - 0.5) * (WIDTH_PER_LEVEL as f32)) + ((mouse_pos.1) * (WIDTH_PER_LEVEL as f32)) .mul_add(zoom_level * zoom_level, player_pos.1), ); diff --git a/src/frontend/world/tile.rs b/src/frontend/world/tile.rs index 281b632..50f5e41 100644 --- a/src/frontend/world/tile.rs +++ b/src/frontend/world/tile.rs @@ -10,6 +10,7 @@ use strum::EnumIter; use itertools::Itertools; +use crate::inserter::FakeUnionStorage; use crate::{ belt::{ splitter::SplitterDistributionMode, BeltBeltInserterAdditionInfo, BeltTileId, @@ -45,7 +46,7 @@ pub enum FloorTile { #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct Chunk { - pub floor_tiles: Option<[[FloorTile; CHUNK_SIZE as usize]; CHUNK_SIZE as usize]>, + pub floor_tiles: Option>, entities: Vec>, } @@ -1198,7 +1199,7 @@ impl World Some(InserterConnectionPossibility { conn: InserterConnection::Storage(Static::Done(Storage::Static { - static_id: StaticID::Chest, + static_id: StaticID::Chest as u16, index: *index, })), inserter_item_hint: None, @@ -1299,7 +1300,7 @@ impl World Some(InserterConnectionPossibility { conn: InserterConnection::Storage(Static::Done(Storage::Static { - static_id: StaticID::Chest, + static_id: StaticID::Chest as u16, index: *index, })), inserter_item_hint: None, @@ -1441,7 +1442,7 @@ impl World unreachable!(), @@ -1459,7 +1460,11 @@ impl World {}, Err(_) => { @@ -1510,7 +1515,7 @@ impl World unreachable!(), @@ -1528,7 +1533,11 @@ impl World {}, Err(_) => { @@ -1580,7 +1589,7 @@ impl World unreachable!(), @@ -1610,7 +1619,7 @@ impl World unreachable!(), @@ -1630,6 +1639,7 @@ impl World { // This means at most 256 different types of Chest can exist, should be fine :) ty: u8, pos: Position, - item: Option<(Item, usize)>, + item: Option<(Item, u32)>, slot_limit: u8, }, Roboport { @@ -2734,7 +2744,7 @@ pub enum Entity { ty: u8, /// List of all the module slots of this assembler modules: Box<[Option]>, - pole_position: Option<(Position, WeakIndex, u16)>, + pole_position: Option<(Position, WeakIndex, u32)>, }, Beacon { ty: u8, @@ -2776,9 +2786,12 @@ impl Entity (2, 1), Dir::West => (1, 2), }, - Self::Chest { ty, .. } => data_store.chest_tile_sizes[*ty as usize], + Self::Chest { ty, .. } => data_store.chest_tile_sizes[usize::from(*ty)], Self::Roboport { .. } => (4, 4), - Self::SolarPanel { .. } => (3, 3), + Self::SolarPanel { ty, .. } => ( + data_store.solar_panel_info[usize::from(*ty)].size[0], + data_store.solar_panel_info[usize::from(*ty)].size[1], + ), Self::Lab { ty, .. } => data_store.lab_info[usize::from(*ty)].size, Self::Beacon { ty, .. } => data_store.beacon_info[usize::from(*ty)].size, } @@ -2903,7 +2916,7 @@ impl Dir { pub struct AssemblerID { pub recipe: Recipe, pub grid: PowerGridIdentifier, - pub assembler_index: u16, + pub assembler_index: u32, } #[derive( Debug, Clone, Copy, serde::Deserialize, serde::Serialize, PartialEq, Eq, PartialOrd, Ord, Hash, diff --git a/src/inserter/belt_storage_inserter.rs b/src/inserter/belt_storage_inserter.rs index ac912b8..db855b8 100644 --- a/src/inserter/belt_storage_inserter.rs +++ b/src/inserter/belt_storage_inserter.rs @@ -1,11 +1,8 @@ use std::marker::ConstParamTy; -use crate::{ - item::{IdxTrait, WeakIdxTrait}, - storage_list::{index, SingleItemStorages}, -}; +use crate::storage_list::{index, index_fake_union, SingleItemStorages}; -use super::{InserterState, Storage}; +use super::{FakeUnionStorage, InserterState}; #[derive(Debug, ConstParamTy, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] pub enum Dir { @@ -14,8 +11,8 @@ pub enum Dir { } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -pub struct BeltStorageInserter { - pub storage_id: Storage, +pub struct BeltStorageInserter { + pub storage_id: FakeUnionStorage, pub state: InserterState, } @@ -27,9 +24,9 @@ pub struct BeltStorageInserter { // Luckily since inserter only have limited range (3 tiles or whatever) there is inherent locality in the accesses, if the MultiStores are somewhat spacially aligned. // Though this could also lead to particularly poor access patterns if the belt/line of inserters is perpendicular to the stride pattern of the Multistore // (maybe some quadtree weirdness could help?) -impl BeltStorageInserter { +impl BeltStorageInserter { #[must_use] - pub const fn new(id: Storage) -> Self { + pub const fn new(id: FakeUnionStorage) -> Self { Self { storage_id: id, state: InserterState::WaitingForSourceItems, @@ -37,7 +34,7 @@ impl BeltStorageInserter BeltStorageInserter { +impl BeltStorageInserter<{ Dir::BeltToStorage }> { pub fn update( &mut self, loc: &mut bool, @@ -58,7 +55,7 @@ impl BeltStorageInserter { - let (max_insert, old) = index( + let (max_insert, old) = index_fake_union( storages, self.storage_id, num_grids_total, @@ -93,7 +90,7 @@ impl BeltStorageInserter BeltStorageInserter { +impl BeltStorageInserter<{ Dir::StorageToBelt }> { pub fn update( &mut self, loc: &mut bool, @@ -109,7 +106,7 @@ impl BeltStorageInserter { - let (_max_insert, old) = index( + let (_max_insert, old) = index_fake_union( storages, self.storage_id, num_grids_total, diff --git a/src/inserter/mod.rs b/src/inserter/mod.rs index 326cec2..5d01786 100644 --- a/src/inserter/mod.rs +++ b/src/inserter/mod.rs @@ -66,8 +66,8 @@ pub const MAX_GRID_COUNT: usize = u16::MAX as usize - 1; pub const MAX_TIMES_AN_ITEM_CAN_APPEAR_IN_RECIPES: usize = u16::MAX as usize; pub const MAX_RECIPE_COUNT: usize = u16::MAX as usize; -#[derive(Debug, Clone, Copy, serde::Deserialize, serde::Serialize)] -struct FakeUnionStorage { +#[derive(Debug, Clone, Copy, PartialEq, serde::Deserialize, serde::Serialize)] +pub struct FakeUnionStorage { index: u32, grid_or_static_flag: u16, recipe_idx_with_this_item: u16, @@ -75,7 +75,7 @@ struct FakeUnionStorage { impl FakeUnionStorage { #[inline(always)] - fn into_inner_and_outer_indices( + pub fn into_inner_and_outer_indices( self, num_grids_total: usize, grid_size: usize, @@ -93,7 +93,10 @@ impl FakeUnionStorage { } #[inline(always)] - fn into_inner_and_outer_indices_with_statics_at_zero(self, grid_size: usize) -> (usize, usize) { + pub fn into_inner_and_outer_indices_with_statics_at_zero( + self, + grid_size: usize, + ) -> (usize, usize) { let grid_offs = usize::from(self.grid_or_static_flag); let recipe_idx_with_this_item_or_single_kind_power_grid_kind = usize::from(self.recipe_idx_with_this_item); @@ -104,7 +107,7 @@ impl FakeUnionStorage { ) } - fn from_storage( + pub fn from_storage( item: Item, storage: Storage, data_store: &DataStore, @@ -136,13 +139,13 @@ impl FakeUnionStorage { } } - fn from_storage_with_statics_at_zero( + pub fn from_storage_with_statics_at_zero( item: Item, storage: Storage, data_store: &DataStore, ) -> Self { let grid_size: usize = grid_size(item, data_store); - let static_size: usize = static_size(data_store); + let static_size: usize = static_size(item, data_store); let grid_offset = static_size.div_ceil(grid_size); @@ -172,7 +175,7 @@ impl FakeUnionStorage { Storage::Static { index, static_id } => Self { index: u32::try_from(index).unwrap(), grid_or_static_flag: 0, - recipe_idx_with_this_item: static_id as u16, + recipe_idx_with_this_item: static_id, }, } } @@ -185,16 +188,15 @@ pub enum Storage { Assembler { grid: PowerGridIdentifier, recipe_idx_with_this_item: RecipeIdxType, - // TODO: - index: u16, + index: u32, }, Lab { grid: PowerGridIdentifier, - index: u16, + index: u32, }, Static { - index: usize, - static_id: StaticID, + static_id: u16, + index: u32, }, } @@ -260,16 +262,16 @@ impl Storage { ); let outer = Into::::into(grid) * grid_size + Into::::into(recipe_idx_with_this_item); - (outer, Into::::into(index)) + (outer, index.try_into().unwrap()) }, Storage::Lab { grid, index } => { let outer = Into::::into(grid) * grid_size + num_recipes; - (outer, Into::::into(index)) + (outer, index.try_into().unwrap()) }, Storage::Static { static_id, index } => { // debug_assert!(usize::from(static_id) < data_store.num_different_static_containers); let outer = num_grids_total * grid_size + Into::::into(static_id as u8); - (outer, Into::::into(index)) + (outer, index.try_into().unwrap()) }, } } @@ -295,16 +297,16 @@ impl Storage { ); let outer = (Into::::into(grid) + grid_offset) * grid_size + Into::::into(recipe_idx_with_this_item); - (outer, Into::::into(index)) + (outer, index.try_into().unwrap()) }, Storage::Lab { grid, index } => { let outer = (Into::::into(grid) + grid_offset) * grid_size + num_recipes; - (outer, Into::::into(index)) + (outer, index.try_into().unwrap()) }, Storage::Static { static_id, index } => { // debug_assert!(usize::from(static_id) < data_store.num_different_static_containers); let outer = Into::::into(static_id as u8); - (outer, Into::::into(index)) + (outer, index.try_into().unwrap()) }, } } @@ -345,7 +347,7 @@ mod test { fn random_storage(num_grids: u16, num_recipes: u8) -> impl Strategy> { prop_oneof![ - (0..num_grids, 0..num_recipes, 0..u16::MAX).prop_map( + (0..num_grids, 0..num_recipes, 0..u32::MAX).prop_map( |(grid, recipe_idx_with_this_item, index)| { Storage::Assembler { grid: grid.try_into().unwrap_or(PowerGridIdentifier::MAX), @@ -354,7 +356,7 @@ mod test { } } ), - (0..num_grids, 0..u16::MAX).prop_map(|(grid, index)| { + (0..num_grids, 0..u32::MAX).prop_map(|(grid, index)| { Storage::Lab { grid: grid.try_into().unwrap_or(PowerGridIdentifier::MAX), index, @@ -362,7 +364,7 @@ mod test { }), (random_static(), 0..u16::MAX).prop_map(|(static_id, index)| { Storage::Static { - static_id, + static_id: static_id as u16, index: index.into(), } }) @@ -414,7 +416,7 @@ mod test { let union_indices = storage_union.into_inner_and_outer_indices_with_statics_at_zero(grid_size); - let storage_indices = storage.into_inner_and_outer_indices_with_statics_at_zero(num_grids.into(), DATA_STORE.num_recipes_with_item[usize_from(item.id)], grid_size, static_size(&DATA_STORE)); + let storage_indices = storage.into_inner_and_outer_indices_with_statics_at_zero(num_grids.into(), DATA_STORE.num_recipes_with_item[usize_from(item.id)], grid_size, static_size(item, &DATA_STORE)); prop_assert_eq!(union_indices, storage_indices); } diff --git a/src/inserter/storage_storage_inserter.rs b/src/inserter/storage_storage_inserter.rs index 179e78e..f610906 100644 --- a/src/inserter/storage_storage_inserter.rs +++ b/src/inserter/storage_storage_inserter.rs @@ -1,16 +1,16 @@ use crate::{ item::{IdxTrait, WeakIdxTrait}, - storage_list::{index, SingleItemStorages}, + storage_list::{index, index_fake_union, SingleItemStorages}, }; -use super::{InserterState, Storage}; +use super::{FakeUnionStorage, InserterState, Storage}; // FIXME: the storage_id cannot properly represent an index into multiple slices (which I have here, since // there are multiple lists of storages in the different MultiAssemblerStores (since multiple different recipes take for example Iron Plates)) #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -pub struct StorageStorageInserter { - storage_id_in: Storage, - storage_id_out: Storage, +pub struct StorageStorageInserter { + storage_id_in: FakeUnionStorage, + storage_id_out: FakeUnionStorage, state: InserterState, } @@ -23,9 +23,9 @@ pub struct StorageStorageInserter { // Luckily since inserter only have limited range (3 tiles or whatever) there is inherent locality in the accesses, if the MultiStores are somewhat spacially aligned. // Though this could also lead to particularly poor access patterns if the belt/line of inserters is perpendicular to the stride pattern of the Multistore // (maybe some weird quadtree weirdness could help?) -impl StorageStorageInserter { +impl StorageStorageInserter { #[must_use] - pub const fn new(in_id: Storage, out_id: Storage) -> Self { + pub const fn new(in_id: FakeUnionStorage, out_id: FakeUnionStorage) -> Self { Self { storage_id_in: in_id, storage_id_out: out_id, @@ -46,7 +46,7 @@ impl StorageStorageInserter { match self.state { InserterState::WaitingForSourceItems => { - let (_max_insert, old) = index( + let (_max_insert, old) = index_fake_union( storages, self.storage_id_in, num_grids_total, @@ -62,7 +62,7 @@ impl StorageStorageInserter { } }, InserterState::WaitingForSpaceInDestination => { - let (max_insert, old) = index( + let (max_insert, old) = index_fake_union( storages, self.storage_id_out, num_grids_total, diff --git a/src/lab.rs b/src/lab.rs index adee760..1eae736 100644 --- a/src/lab.rs +++ b/src/lab.rs @@ -325,7 +325,7 @@ impl MultiLabStore { position: Position, modules: &[Option], data_store: &DataStore, - ) -> u16 { + ) -> u32 { let base_speed = data_store.lab_info[usize::from(ty)].base_speed; let base_prod = data_store.lab_info[usize::from(ty)].base_prod; let base_power = data_store.lab_info[usize::from(ty)].base_power_consumption; @@ -409,10 +409,10 @@ impl MultiLabStore { self.positions.len() - 1 }; - idx.try_into().expect("More than u16::MAX Labs in a grid") + idx.try_into().expect("More than u32::MAX Labs in a grid") } - pub fn remove_lab(&mut self, index: u16) -> Box<[ITEMCOUNTTYPE]> { + pub fn remove_lab(&mut self, index: u32) -> Box<[ITEMCOUNTTYPE]> { let index = index as usize; self.holes.push(index); @@ -434,7 +434,7 @@ impl MultiLabStore { ret } - pub fn move_lab(&mut self, index: u16, other: &mut Self) -> u16 { + pub fn move_lab(&mut self, index: u32, other: &mut Self) -> u32 { todo!(); let index = index as usize; self.holes.push(index); @@ -479,17 +479,18 @@ impl MultiLabStore { }); idx.try_into() - .expect("More than u16::MAX Labs in a single grid") + .expect("More than u32::MAX Labs in a single grid") } pub fn modify_modifiers( &mut self, - index: u16, + index: u32, speed: i16, prod: i16, power: i16, data_store: &DataStore, ) { + let index = index as usize; self.raw_speed_mod[usize::from(index)] = self.raw_speed_mod[usize::from(index)] .checked_add(speed) .expect("Over/Underflowed"); diff --git a/src/lib.rs b/src/lib.rs index fbe3194..d6c7b8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -142,7 +142,10 @@ pub fn main() { eframe::run_native( "FactoryGame", - NativeOptions::default(), + NativeOptions { + // depth_buffer: 32, + ..Default::default() + }, Box::new(|cc| { let mut app = eframe_app::App::new(cc, sender); @@ -176,9 +179,12 @@ fn run_integrated_server( match data_store { data::DataStoreOptions::ItemU8RecipeU8(data_store) => { let (send, recv) = channel(); - let state_machine: Arc>> = Arc::new(Mutex::new( - ActionStateMachine::new(0, (100.0 * CHUNK_SIZE_FLOAT, 100.0 * CHUNK_SIZE_FLOAT)), - )); + let state_machine: Arc>> = + Arc::new(Mutex::new(ActionStateMachine::new( + 0, + (100.0 * CHUNK_SIZE_FLOAT, 100.0 * CHUNK_SIZE_FLOAT), + &data_store, + ))); let game_state = Arc::new(Mutex::new( load().map(|save| save.game_state).unwrap_or_else(|| { @@ -275,9 +281,12 @@ fn run_client(start_game_info: StartGameInfo) -> (LoadedGame, Arc, Se match data_store { data::DataStoreOptions::ItemU8RecipeU8(data_store) => { let (send, recv) = channel(); - let state_machine: Arc>> = Arc::new(Mutex::new( - ActionStateMachine::new(1, (100.0 * CHUNK_SIZE_FLOAT, 100.0 * CHUNK_SIZE_FLOAT)), - )); + let state_machine: Arc>> = + Arc::new(Mutex::new(ActionStateMachine::new( + 1, + (100.0 * CHUNK_SIZE_FLOAT, 100.0 * CHUNK_SIZE_FLOAT), + &data_store, + ))); let game_state = Arc::new(Mutex::new( load() diff --git a/src/multiplayer/mod.rs b/src/multiplayer/mod.rs index 3639f82..0c77d6d 100644 --- a/src/multiplayer/mod.rs +++ b/src/multiplayer/mod.rs @@ -153,15 +153,15 @@ impl Game {}, ControlFlow::Break(e) => return e, } + + { + profiling::scope!("Wait"); + update_interval.tick(); + } } } diff --git a/src/multiplayer/server.rs b/src/multiplayer/server.rs index 4300ea3..cb5b688 100644 --- a/src/multiplayer/server.rs +++ b/src/multiplayer/server.rs @@ -6,7 +6,6 @@ use std::{ time::Instant, }; - use crate::{ data::DataStore, frontend::{action::ActionType, world::tile::World}, diff --git a/src/power/mod.rs b/src/power/mod.rs index 293ddab..18aa74f 100644 --- a/src/power/mod.rs +++ b/src/power/mod.rs @@ -48,6 +48,20 @@ pub mod power_grid; )] pub struct Joule(pub u64); +impl Display for Joule { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.0 > 1_000_000_000 { + write!(f, "{:.1}GJ", self.0 as f64 / 1_000_000_000.0) + } else if self.0 > 1_000_000 { + write!(f, "{:.1}MJ", self.0 as f64 / 1_000_000.0) + } else if self.0 > 1_000 { + write!(f, "{:.1}KJ", self.0 as f64 / 1_000.0) + } else { + write!(f, "{:.1}J", self.0 as f64) + } + } +} + impl Sum for Joule { fn sum>(iter: I) -> Self { Self(iter.map(|mj| mj.0).sum()) @@ -606,7 +620,7 @@ impl PowerGridStorage PowerGridStorage PowerGridStorage, ) -> (ResearchProgress, RecipeTickInfo) { let (research_progress, production_info, beacon_updates) = self .power_grids .par_iter_mut() - .map(|grid| grid.update(Watt(u64::MAX / (u16::MAX as u64)), tech_state, data_store)) + .map(|grid| { + grid.update( + &data_store + .solar_panel_info + .iter() + .map(|info| match &info.power_output { + crate::data::SolarPanelOutputFunction::Constant(output) => *output, + crate::data::SolarPanelOutputFunction::Lookup(output) => { + output[usize::try_from(current_time).unwrap()] + }, + }) + .collect::>(), + tech_state, + data_store, + ) + }) .reduce( || (0, RecipeTickInfo::new(data_store), vec![]), |(acc_progress, infos, mut old_updates), (rhs_progress, info, new_updates)| { diff --git a/src/power/power_grid.rs b/src/power/power_grid.rs index 0e05fee..a1761a0 100644 --- a/src/power/power_grid.rs +++ b/src/power/power_grid.rs @@ -4,13 +4,14 @@ use std::{ mem, }; +use itertools::Itertools; use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator}; use crate::{ assembler::{AssemblerOnclickInfo, AssemblerRemovalInfo, FullAssemblerStore}, data::{DataStore, LazyPowerMachineInfo}, frontend::world::{tile::AssemblerID, Position}, - item::{IdxTrait, Item, Recipe, WeakIdxTrait, ITEMCOUNTTYPE}, + item::{usize_from, IdxTrait, Item, Recipe, WeakIdxTrait, ITEMCOUNTTYPE}, lab::MultiLabStore, network_graph::{Network, WeakIndex}, power::Joule, @@ -38,15 +39,15 @@ pub enum PowerGridEntity Assembler { ty: u8, recipe: Recipe, - index: u16, + index: u32, }, Lab { ty: u8, - index: u16, + index: u32, }, LazyPowerProducer { item: Item, - index: usize, + index: u32, }, SolarPanel { ty: u8, @@ -68,7 +69,7 @@ pub enum BeaconAffectedEntity { }, Lab { grid: PowerGridIdentifier, - index: usize, + index: u32, }, } @@ -81,16 +82,24 @@ pub struct PowerGrid { steam_power_producers: SteamPowerProducerStore, // TODO: Currently there can only be a single type of solar panel and accumulator - num_solar_panels: u64, - main_accumulator_count: u64, - main_accumulator_charge: Joule, + num_solar_panels: Box<[u64]>, + pub main_accumulator_count: Box<[u64]>, + pub main_accumulator_charge: Box<[Joule]>, // unique_accumulators: Vec, use_burnable_fuel_to_charge_accumulators: Option, pub last_power_consumption: Watt, + pub last_produced_power: Watt, + + pub last_ticks_max_power_production: Watt, + + max_lazy_power: Watt, pub last_power_mult: u8, - pub power_history: Timeline, + pub power_mult_history: Timeline, + // FIXME: Not actually storing where the power consumption/production originates is not very useful :/ + // pub power_consumption_history: Timeline, + // pub power_production_history: Timeline, pub is_placeholder: bool, pub num_assemblers_of_type: Box<[usize]>, @@ -150,16 +159,21 @@ impl PowerGrid PowerGrid PowerGrid 0 - { - (self.main_accumulator_charge * self.main_accumulator_count - + other.main_accumulator_charge * other.main_accumulator_count) - / (self.main_accumulator_count + other.main_accumulator_count) - } else { - assert_eq!(Joule(0), self.main_accumulator_charge); - assert_eq!(Joule(0), other.main_accumulator_charge); - Joule(0) - }, + num_solar_panels: self.num_solar_panels, + main_accumulator_count: self.main_accumulator_count, + main_accumulator_charge: self.main_accumulator_charge, use_burnable_fuel_to_charge_accumulators: match ( self.use_burnable_fuel_to_charge_accumulators, other.use_burnable_fuel_to_charge_accumulators, @@ -322,6 +361,10 @@ impl PowerGrid= other.last_power_consumption { @@ -330,11 +373,11 @@ impl PowerGrid= other.last_power_consumption { - self.power_history + self.power_mult_history } else { - other.power_history + other.power_mult_history } }, is_placeholder: false, @@ -366,8 +409,7 @@ impl PowerGrid WeakIndex { assert!(!self.is_placeholder); - // FIXME: Respect the solar panel type - self.num_solar_panels += 1; + self.num_solar_panels[usize::from(ty)] += 1; self.grid_graph.add_weak_element( pole_connection, @@ -383,11 +425,14 @@ impl PowerGrid PowerGrid], pole_connection: Position, data_store: &DataStore, - ) -> (WeakIndex, u16) { + ) -> (WeakIndex, u32) { assert!(!self.is_placeholder); self.num_labs_of_type[usize::from(ty)] += 1; @@ -603,12 +648,10 @@ impl PowerGrid { - // FIXME: Respect ty - self.num_solar_panels -= 1; + self.num_solar_panels[usize::from(*ty)] -= 1; }, PowerGridEntity::Accumulator { ty } => { - // FIXME: Respect ty - self.main_accumulator_count -= 1; + self.main_accumulator_count[usize::from(*ty)] -= 1; }, PowerGridEntity::Beacon { ty, @@ -725,8 +768,8 @@ impl PowerGrid { // FIXME: Respect ty - self.num_solar_panels -= 1; - other.num_solar_panels += 1; + self.num_solar_panels[usize::from(*ty)] -= 1; + other.num_solar_panels[usize::from(*ty)] += 1; ( connected_entity.0, @@ -736,8 +779,8 @@ impl PowerGrid { // FIXME: Respect ty - self.main_accumulator_count -= 1; - other.main_accumulator_count += 1; + self.main_accumulator_count[usize::from(*ty)] -= 1; + other.main_accumulator_count[usize::from(*ty)] += 1; ( connected_entity.0, @@ -955,7 +998,7 @@ impl PowerGrid, ) { @@ -976,7 +1019,7 @@ impl PowerGrid, ) { @@ -1074,7 +1117,7 @@ impl PowerGrid, ) { @@ -1183,19 +1226,19 @@ impl PowerGrid self.stores.assemblers_0_1 [data_store.recipe_to_ing_out_combo_idx[old_assembler_id.recipe.id.into()]] - .remove_assembler_data(old_assembler_id.assembler_index as usize), + .remove_assembler_data(old_assembler_id.assembler_index), (1, 1) => self.stores.assemblers_1_1 [data_store.recipe_to_ing_out_combo_idx[old_assembler_id.recipe.id.into()]] - .remove_assembler_data(old_assembler_id.assembler_index as usize), + .remove_assembler_data(old_assembler_id.assembler_index), (2, 1) => self.stores.assemblers_2_1 [data_store.recipe_to_ing_out_combo_idx[old_assembler_id.recipe.id.into()]] - .remove_assembler_data(old_assembler_id.assembler_index as usize), + .remove_assembler_data(old_assembler_id.assembler_index), (3, 1) => self.stores.assemblers_3_1 [data_store.recipe_to_ing_out_combo_idx[old_assembler_id.recipe.id.into()]] - .remove_assembler_data(old_assembler_id.assembler_index as usize), + .remove_assembler_data(old_assembler_id.assembler_index), (4, 1) => self.stores.assemblers_4_1 [data_store.recipe_to_ing_out_combo_idx[old_assembler_id.recipe.id.into()]] - .remove_assembler_data(old_assembler_id.assembler_index as usize), + .remove_assembler_data(old_assembler_id.assembler_index), _ => unreachable!(), }; @@ -1349,19 +1392,19 @@ impl PowerGrid self.stores.assemblers_0_1 [data_store.recipe_to_ing_out_combo_idx[assembler_id.recipe.id.into()]] - .remove_assembler(assembler_id.assembler_index as usize), + .remove_assembler(assembler_id.assembler_index), (1, 1) => self.stores.assemblers_1_1 [data_store.recipe_to_ing_out_combo_idx[assembler_id.recipe.id.into()]] - .remove_assembler(assembler_id.assembler_index as usize), + .remove_assembler(assembler_id.assembler_index), (2, 1) => self.stores.assemblers_2_1 [data_store.recipe_to_ing_out_combo_idx[assembler_id.recipe.id.into()]] - .remove_assembler(assembler_id.assembler_index as usize), + .remove_assembler(assembler_id.assembler_index), (3, 1) => self.stores.assemblers_3_1 [data_store.recipe_to_ing_out_combo_idx[assembler_id.recipe.id.into()]] - .remove_assembler(assembler_id.assembler_index as usize), + .remove_assembler(assembler_id.assembler_index), (4, 1) => self.stores.assemblers_4_1 [data_store.recipe_to_ing_out_combo_idx[assembler_id.recipe.id.into()]] - .remove_assembler(assembler_id.assembler_index as usize), + .remove_assembler(assembler_id.assembler_index), _ => unreachable!(), }; @@ -1373,9 +1416,9 @@ impl PowerGrid, recipe: Recipe, - index: u16, + index: u32, data_store: &DataStore, - ) -> usize { + ) -> u32 { match ( data_store.recipe_num_ing_lookup[recipe.id.into()], data_store.recipe_num_out_lookup[recipe.id.into()], @@ -1383,7 +1426,7 @@ impl PowerGrid self.stores.assemblers_0_1 [data_store.recipe_to_ing_out_combo_idx[recipe.id.into()]] .move_assembler( - index.into(), + index, &mut other_stores.assemblers_0_1 [data_store.recipe_to_ing_out_combo_idx[recipe.id.into()]], data_store, @@ -1391,7 +1434,7 @@ impl PowerGrid self.stores.assemblers_1_1 [data_store.recipe_to_ing_out_combo_idx[recipe.id.into()]] .move_assembler( - index.into(), + index, &mut other_stores.assemblers_1_1 [data_store.recipe_to_ing_out_combo_idx[recipe.id.into()]], data_store, @@ -1399,7 +1442,7 @@ impl PowerGrid self.stores.assemblers_2_1 [data_store.recipe_to_ing_out_combo_idx[recipe.id.into()]] .move_assembler( - index.into(), + index, &mut other_stores.assemblers_2_1 [data_store.recipe_to_ing_out_combo_idx[recipe.id.into()]], data_store, @@ -1407,7 +1450,7 @@ impl PowerGrid self.stores.assemblers_3_1 [data_store.recipe_to_ing_out_combo_idx[recipe.id.into()]] .move_assembler( - index.into(), + index, &mut other_stores.assemblers_3_1 [data_store.recipe_to_ing_out_combo_idx[recipe.id.into()]], data_store, @@ -1415,7 +1458,7 @@ impl PowerGrid self.stores.assemblers_4_1 [data_store.recipe_to_ing_out_combo_idx[recipe.id.into()]] .move_assembler( - index.into(), + index, &mut other_stores.assemblers_4_1 [data_store.recipe_to_ing_out_combo_idx[recipe.id.into()]], data_store, @@ -1428,45 +1471,66 @@ impl PowerGrid, - ) -> u16 { + ) -> u32 { self.lab_stores.move_lab(index, other_stores) } - // TODO: Currently impossible because of Ing Generics - // fn do_for_assembler( - // &mut self, - // recipe: Recipe, - // data_store: &DataStore, - // f: impl Fn(&mut MultiAssemblerStore) -> T, - // ) -> T { - // match ( - // data_store.recipe_num_ing_lookup[recipe.id.into()], - // data_store.recipe_num_out_lookup[recipe.id.into()], - // ) { - // (0, 1) => f(&mut self.stores.assemblers_0_1 - // [data_store.recipe_to_ing_out_combo_idx[recipe.id.into()]]), - - // _ => unreachable!(), - // } - // } - // FIXME: This is a huge, high branching function. // Make it simpler and more readable, and reduce repetition #[profiling::function] fn extract_power( &mut self, goal_amount: Joule, - solar_panel_production_amount: Watt, + solar_panel_production_amounts: &[Watt], data_store: &DataStore, - ) -> u8 { - let solar_power = (solar_panel_production_amount * self.num_solar_panels).joules_per_tick(); + ) -> Joule { + assert_eq!( + solar_panel_production_amounts.len(), + self.num_solar_panels.len() + ); + let solar_power = self + .num_solar_panels + .iter() + .zip(solar_panel_production_amounts) + .map(|(a, b)| *b * *a) + .sum::() + .joules_per_tick(); + + self.last_ticks_max_power_production = solar_power.watt_from_tick() + self.max_lazy_power; + + if goal_amount == Joule(0) { + return Joule(0); + } + + let max_charge_amount_per: Box<[Joule]> = self + .main_accumulator_count + .iter() + .zip(self.main_accumulator_charge.iter().copied()) + .zip( + data_store + .accumulator_info + .iter() + .map(|info| info.max_charge_rate), + ) + .zip( + data_store + .accumulator_info + .iter() + .map(|info| info.max_charge), + ) + .map( + |(((count, charge), max_charge_rate), max_charge): ( + ((&u64, Joule), Watt), + Joule, + )| { + min(max_charge_rate.joules_per_tick(), max_charge - charge) * *count + }, + ) + .collect(); + let max_charge_amount = max_charge_amount_per.iter().copied().sum(); - let max_charge_amount: Joule = max( - MAX_ACCUMULATOR_CHARGE_RATE.joules_per_tick(), - MAX_ACCUMULATOR_CHARGE - self.main_accumulator_charge, - ) * self.main_accumulator_count; // + self // .unique_accumulators // .iter() @@ -1484,7 +1548,7 @@ impl PowerGrid= max_charge_amount { // We already have enough power, without using burnables. - self.charge_by(max_charge_amount); + self.charge_by(max_charge_amount, &max_charge_amount_per); } else if self .use_burnable_fuel_to_charge_accumulators .unwrap_or_default() @@ -1499,12 +1563,12 @@ impl PowerGrid PowerGrid return MAX_POWER_MULT, + std::cmp::Ordering::Equal => return goal_amount, std::cmp::Ordering::Greater => { // Use remaining power for charging let charge_amount = goal_amount - actually_extracted; // This will never underflow - self.charge_by(charge_amount); + self.charge_by(charge_amount, &max_charge_amount_per); - return MAX_POWER_MULT; + return goal_amount; }, } } @@ -1566,20 +1626,16 @@ impl PowerGrid MAX_POWER_MULT, + std::cmp::Ordering::Equal => goal_amount, std::cmp::Ordering::Greater => { unreachable!( "We extracted more power than needed from burners, while disallowing charging?!" @@ -1589,15 +1645,30 @@ impl PowerGrid= amount + max_charge_amount_per.iter().copied().sum::() >= amount, + "Tried to charge the accumulators more than max amount" ); - self.main_accumulator_charge = min( - self.main_accumulator_charge + amount, - MAX_ACCUMULATOR_CHARGE, - ); + debug_assert!(max_charge_amount_per.is_sorted()); + + // Since we sort, we can simply go through the list sequentially + for ((charge, max_rate), num_left) in self + .main_accumulator_charge + .iter_mut() + .zip(max_charge_amount_per) + .zip((1..=max_charge_amount_per.len()).rev()) + .sorted_by_key(|((_charge, max_rate), _num_left)| *max_rate) + { + // FIXME: This is integer division, so we lose some power here. + let charge_here: Joule = min(*max_rate, amount / u64::try_from(num_left).unwrap()); + *charge = *charge + charge_here; + amount = amount - charge_here; + } + + // Due to the integer div, this assert could fail + assert!(amount == Joule(0)); // This is an algorithm for (kindof) handling accumulators with different charge from the "main pack" // while amount > MegaJoule(0) { @@ -1644,28 +1715,52 @@ impl PowerGrid Joule { - // only extract at most MAX_ACCUMULATOR_DISCHARGE_RATE - let to_extract = min( - power_needed, - (MAX_ACCUMULATOR_DISCHARGE_RATE * self.main_accumulator_count).joules_per_tick(), - ); - assert!( - (MAX_ACCUMULATOR_DISCHARGE_RATE * self.main_accumulator_count).joules_per_tick() - >= to_extract - ); + fn extract_from_accumulators( + &mut self, + mut power_needed: Joule, + data_store: &DataStore, + ) -> Joule { + let originally_needed = power_needed; + let discharge_amount_per: Box<[Joule]> = self + .main_accumulator_count + .iter() + .zip(self.main_accumulator_charge.iter().copied()) + .zip( + data_store + .accumulator_info + .iter() + .map(|info| info.max_discharge_rate), + ) + .map( + |((count, charge), max_discharge_rate): ((&u64, Joule), Watt)| { + min(max_discharge_rate.joules_per_tick(), charge) * *count + }, + ) + .collect(); - let old = self.main_accumulator_charge; - self.main_accumulator_charge = - Joule(self.main_accumulator_charge.0.saturating_sub(to_extract.0)); + // Since we sort, we can simply go through the list sequentially + for ((charge, max_rate), num_left) in self + .main_accumulator_charge + .iter_mut() + .zip(discharge_amount_per) + .zip((1..=data_store.accumulator_info.len()).rev()) + .sorted_by_key(|((charge, max_rate), num_left)| *max_rate) + { + // FIXME: This is integer division, so we lose some power here. + let discharge_from_here: Joule = + min(max_rate, power_needed / u64::try_from(num_left).unwrap()); + assert!(*charge >= discharge_from_here); + *charge = *charge - discharge_from_here; + power_needed = power_needed - discharge_from_here; + } - min(old, to_extract) + originally_needed - power_needed } #[profiling::function] pub fn update( &mut self, - solar_panel_production_amount: Watt, + solar_panel_production_amounts: &[Watt], tech_state: &TechState, data_store: &DataStore, ) -> ( @@ -1689,10 +1784,12 @@ impl PowerGrid( self.last_power_mult, &data_store.recipe_index_lookups, @@ -1720,10 +1817,12 @@ impl PowerGrid( self.last_power_mult, &data_store.recipe_index_lookups, @@ -1751,10 +1850,12 @@ impl PowerGrid( self.last_power_mult, &data_store.recipe_index_lookups, @@ -1782,10 +1883,12 @@ impl PowerGrid( self.last_power_mult, &data_store.recipe_index_lookups, @@ -1811,10 +1914,12 @@ impl PowerGrid( self.last_power_mult, &data_store.recipe_index_lookups, @@ -1848,6 +1953,7 @@ impl PowerGrid PowerGrid, (_, _, _))> = if next_power_mult @@ -1896,7 +2013,7 @@ impl PowerGrid { } impl GameState { + #[must_use] pub fn new(data_store: &DataStore) -> Self { Self { current_tick: 0, @@ -60,6 +61,7 @@ impl GameState) -> Self { let mut ret = Self { current_tick: 0, @@ -84,10 +86,12 @@ impl GameState) -> Self { Self::new_with_beacon_red_green_production(data_store) } + #[must_use] pub fn new_with_beacon_red_green_production( data_store: &DataStore, ) -> Self { @@ -104,6 +108,9 @@ impl GameState() < u16::MAX / 200 { + ret.update(data_store); + } bp.apply( Position { x: x_pos, @@ -119,6 +126,7 @@ impl GameState, ) -> Self { @@ -154,6 +162,7 @@ impl GameState, ) -> Self { @@ -167,7 +176,7 @@ impl GameState = ron::de::from_reader(file).unwrap(); - for y_start in (0..10_000).step_by(6_000) { + for y_start in (0..60_000).step_by(6_000) { for y_pos in (1590..6000).step_by(10) { for x_pos in (1590..3000).step_by(60) { if rand::random::() == 0 { @@ -189,6 +198,7 @@ impl GameState) -> Self { let mut ret = Self { current_tick: 0, @@ -200,7 +210,7 @@ impl GameState = ron::de::from_reader(file).unwrap(); - for y_pos in (1600..3_000).step_by(3) { + for y_pos in (1600..84_000).step_by(3) { ret.update(data_store); for x_pos in (1600..3000).step_by(50) { bp.apply(Position { x: x_pos, y: y_pos }, &mut ret, data_store); @@ -257,6 +267,7 @@ pub struct SimulationState SimulationState { + #[must_use] pub fn new(data_store: &DataStore) -> Self { Self { tech_state: TechState { @@ -270,19 +281,21 @@ impl SimulationState { pub power_grids: PowerGridStorage, - pub belts: BeltStore, - pub storage_storage_inserters: StorageStorageInserterStore, + pub belts: BeltStore, + pub storage_storage_inserters: StorageStorageInserterStore, pub chests: FullChestStore, } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -pub struct StorageStorageInserterStore { - pub inserters: Box<[Vec>]>, +pub struct StorageStorageInserterStore { + pub inserters: Box<[Vec]>, holes: Box<[Vec]>, } -impl StorageStorageInserterStore { - fn new(data_store: &DataStore) -> Self { +impl StorageStorageInserterStore { + fn new( + data_store: &DataStore, + ) -> Self { Self { inserters: vec![vec![]; data_store.item_names.len()].into_boxed_slice(), holes: vec![vec![]; data_store.item_names.len()].into_boxed_slice(), @@ -290,7 +303,7 @@ impl StorageStorageInserterStore { } #[profiling::function] - fn update<'a, 'b, ItemIdxType: IdxTrait>( + fn update<'a, 'b, ItemIdxType: IdxTrait, RecipeIdxType: IdxTrait>( &mut self, full_storages: impl IndexedParallelIterator>, num_grids_total: usize, @@ -322,24 +335,30 @@ impl StorageStorageInserterStore { // Ideally we could replace inserter holes with placeholder that do not do anything, but I don't quite know how those would work. .filter_map(|(i, v)| (!holes.contains(&i)).then_some(v)) .for_each(|ins| { - ins.update(storages, MOVETIME, num_grids_total, num_recipes, grid_size) + ins.update(storages, MOVETIME, num_grids_total, num_recipes, grid_size); }); }); } - pub fn add_ins( + pub fn add_ins( &mut self, item: Item, start: Storage, dest: Storage, + data_store: &DataStore, ) -> usize { let idx = if let Some(hole_idx) = self.holes[usize_from(item.id)].pop() { - self.inserters[usize_from(item.id)][hole_idx] = - StorageStorageInserter::new(start, dest); + self.inserters[usize_from(item.id)][hole_idx] = StorageStorageInserter::new( + FakeUnionStorage::from_storage_with_statics_at_zero(item, start, data_store), + FakeUnionStorage::from_storage_with_statics_at_zero(item, dest, data_store), + ); hole_idx } else { - self.inserters[usize_from(item.id)].push(StorageStorageInserter::new(start, dest)); + self.inserters[usize_from(item.id)].push(StorageStorageInserter::new( + FakeUnionStorage::from_storage_with_statics_at_zero(item, start, data_store), + FakeUnionStorage::from_storage_with_statics_at_zero(item, dest, data_store), + )); self.inserters[usize_from(item.id)].len() - 1 }; @@ -704,17 +723,18 @@ impl GameState { info!("Trying to place solar_panel at {pos:?}"); - // TODO: get size dynamically - if !self.world.can_fit(pos, (3, 3), data_store) { + let size = data_store.solar_panel_info[usize::from(ty)].size; + let size = size.into(); + + if !self.world.can_fit(pos, size, data_store) { warn!("Tried to place solar_panel where it does not fit"); continue; } - // FIXME: Hardcoded let powered_by = self.world.is_powered_by( &self.simulation_state, pos, - (3, 3), + size, data_store, ); @@ -1157,7 +1177,7 @@ impl GameState (Position, Posit #[cfg(test)] mod tests { - use std::{fs::File, sync::LazyLock}; + use std::fs::File; use crate::{ - assembler::AssemblerOnclickInfo, blueprint::{random_blueprint_strategy, random_position, Blueprint}, data::{factorio_1_1::get_raw_data_test, DataStore}, frontend::{ diff --git a/src/rendering/eframe_app.rs b/src/rendering/eframe_app.rs index 9412b7f..3236607 100644 --- a/src/rendering/eframe_app.rs +++ b/src/rendering/eframe_app.rs @@ -42,6 +42,7 @@ pub struct App { } impl App { + #[must_use] pub fn new(cc: &eframe::CreationContext, input_sender: Sender) -> Self { let render_state = cc.wgpu_render_state.as_ref().unwrap(); let atlas = Arc::new(texture_atlas()); @@ -70,6 +71,8 @@ impl eframe::App for App { CentralPanel::default().show(ctx, |ui| { let painter = ui.painter(); + let game_graphics_area = painter.clip_rect(); + if let Some(game) = &self.currently_loaded_game { // Only create game input actions if the ui does not currently want input let wants_pointer = ctx.wants_pointer_input(); @@ -101,9 +104,21 @@ impl eframe::App for App { _ => {}, } let input = if let Event::PointerMoved(dest) = event { + let pos_normalized = [dest.x / size.width(), dest.y / size.height()]; + + let ar = size.width() / size.height(); + + if pos_normalized[0] < 0.0 + || pos_normalized[0] > 1.0 + || pos_normalized[1] < 0.0 + || pos_normalized[1] > 1.0 + { + continue; + } + Ok(Input::MouseMove( - dest.x / size.width(), - dest.y / size.height(), + (pos_normalized[0] - 0.5), + (pos_normalized[1] - 0.5) / ar, )) } else { event.clone().try_into() @@ -213,7 +228,13 @@ impl CallbackTrait render_pass: &mut eframe::wgpu::RenderPass<'static>, callback_resources: &egui_wgpu::CallbackResources, ) { - let mut rend = self.raw_renderer.start_draw(render_pass); + let mut rend = self.raw_renderer.start_draw( + render_pass, + [ + info.viewport_in_pixels().width_px as f32, + info.viewport_in_pixels().height_px as f32, + ], + ); let gamestate = self.game_state.lock(); diff --git a/src/rendering/mod.rs b/src/rendering/mod.rs index 5be60c6..f4e1101 100644 --- a/src/rendering/mod.rs +++ b/src/rendering/mod.rs @@ -1,5 +1,5 @@ use image::GenericImageView; -use tilelib::types::{Sprite, Texture}; +use tilelib::types::{DrawInstance, Layer, Sprite, Texture}; use crate::frontend::world::tile::Dir; @@ -8,14 +8,100 @@ pub mod eframe_app; mod render_world; pub mod window; +#[derive(Debug)] +struct EntitySprite { + pub sprite: Sprite, + pub aspect_ratio: f32, + pub offset: (f32, f32), + pub scaling: (f32, f32), +} + +impl EntitySprite { + const fn new_tiling(sprite: Sprite) -> Self { + Self { + sprite, + aspect_ratio: 1.0, + offset: (0.0, 0.0), + scaling: (1.0, 1.0), + } + } + + const fn new_scaled(sprite: Sprite, size: f32) -> Self { + Self { + sprite, + aspect_ratio: 1.0, + offset: (0.0, 0.0), + scaling: (size, size), + } + } + + fn new_tall(sprite: Sprite, aspect_ratio: f32) -> Self { + assert!(aspect_ratio < 1.0); + let height = 1.0 / aspect_ratio; + Self { + sprite, + aspect_ratio, + offset: (0.0, -(height - 1.0)), + scaling: (1.0, height), + } + } + + fn draw(&self, pos: [f32; 2], tile_size: [u16; 2], animation_frame: u32, layer: &mut Layer) { + layer.draw_sprite( + &self.sprite, + DrawInstance { + position: [pos[0] + self.offset.0, pos[1] + self.offset.1], + size: [ + f32::from(tile_size[0]) * self.scaling.0, + f32::from(tile_size[1]) * self.scaling.1, + ], + animation_frame, + }, + ); + } + + fn draw_centered_on( + &self, + underlying: &Self, + pos: [f32; 2], + tile_size: [u16; 2], + animation_frame: u32, + layer: &mut Layer, + ) { + let other_pos = [pos[0] + underlying.offset.0, pos[1] + underlying.offset.1]; + let other_size = [ + f32::from(tile_size[0]) * underlying.scaling.0, + f32::from(tile_size[1]) * underlying.scaling.1, + ]; + let self_size = [self.scaling.0, self.scaling.1]; + + let unused_space = [other_size[0] - self_size[0], other_size[1] - self_size[1]]; + let self_pos = [ + other_pos[0] + unused_space[0] / 2.0, + other_pos[1] + unused_space[1] / 2.0, + ]; + + layer.draw_sprite( + &self.sprite, + DrawInstance { + position: self_pos, + size: self_size, + animation_frame, + }, + ); + } +} + #[derive(Debug)] pub struct TextureAtlas { outside_world: Sprite, blue: Sprite, - assembler: Sprite, - no_power: Sprite, - not_connected: Sprite, + chest: EntitySprite, + + assembler: EntitySprite, + no_power: EntitySprite, + not_connected: EntitySprite, belt: enum_map::EnumMap, inserter: enum_map::EnumMap, @@ -23,11 +109,15 @@ pub struct TextureAtlas { items: Box<[Sprite]>, - beacon: Sprite, + beacon: EntitySprite, + power_pole: EntitySprite, + + lab: EntitySprite, default: Sprite, } +#[cfg(not(feature = "graphics"))] fn texture_atlas() -> TextureAtlas { let black = include_bytes!("temp_assets/outside_world.png"); let black = image::load_from_memory(black).unwrap(); @@ -126,13 +216,200 @@ fn texture_atlas() -> TextureAtlas { let beacon = beacon.to_rgba8().into_vec(); TextureAtlas { - outside_world: Sprite::new(Texture::new(1, black, black_dimensions)), - assembler: Sprite::new(Texture::new(1, assembler, assembler_dimensions)), + outside_world: Sprite::new(Texture::new(1, black.clone(), black_dimensions)), + blue: Sprite::new(Texture::new(1, blue, blue_dimensions)), + + not_connected: EntitySprite::new_scaled( + Sprite::new(Texture::new(1, not_connected, not_connected_dimensions)), + 3.0, + ), + + no_power: EntitySprite::new_scaled( + Sprite::new(Texture::new(1, no_power, no_power_dimensions)), + 3.0, + ), + + assembler: EntitySprite::new_tiling(Sprite::new(Texture::new( + 1, + assembler.clone(), + assembler_dimensions, + ))), + chest: EntitySprite::new_tiling(Sprite::new(Texture::new(1, black, black_dimensions))), + + items: vec![ + Sprite::new(Texture::new(1, plate.clone(), plate_dimensions)), + Sprite::new(Texture::new(1, plate, plate_dimensions)), + ] + .into_boxed_slice(), + + player: Sprite::new(Texture::new(1, player, player_dimensions)), + belt: enum_map::EnumMap::from_array([ + Sprite::new(Texture::new(1, belt_north.clone(), belt_north_dimensions)), + Sprite::new(Texture::new(1, belt_east, belt_east_dimensions)), + Sprite::new(Texture::new(1, belt_south, belt_south_dimensions)), + Sprite::new(Texture::new(1, belt_west, belt_west_dimensions)), + ]), + + inserter: enum_map::EnumMap::from_array([ + Sprite::new(Texture::new(1, inserter_north, inserter_north_dimensions)), + Sprite::new(Texture::new(1, inserter_east, inserter_east_dimensions)), + Sprite::new(Texture::new(1, inserter_south, inserter_south_dimensions)), + Sprite::new(Texture::new(1, inserter_west, inserter_west_dimensions)), + ]), + + beacon: EntitySprite::new_tiling(Sprite::new(Texture::new(1, beacon, beacon_dimensions))), + power_pole: EntitySprite::new_tiling(Sprite::new(Texture::new( + 1, + assembler, + assembler_dimensions, + ))), + + lab: EntitySprite::new_tiling(Sprite::new(Texture::new( + 1, + belt_north, + belt_north_dimensions, + ))), + + default: Sprite::new(Texture::default()), + } +} + +#[cfg(feature = "graphics")] +fn texture_atlas() -> TextureAtlas { + let black = include_bytes!("temp_assets/outside_world.png"); + let black = image::load_from_memory(black).unwrap(); + + let black_dimensions = black.dimensions(); + let black = black.to_rgba8().into_vec(); + + let blue = include_bytes!("temp_assets/blue.png"); + let blue = image::load_from_memory(blue).unwrap(); + + let blue_dimensions = blue.dimensions(); + let blue = blue.to_rgba8().into_vec(); + + let assembler = include_bytes!("temp_assets/krastorio/furnace.png"); + let assembler = image::load_from_memory(assembler).unwrap(); + + let assembler_dimensions = assembler.dimensions(); + let assembler = assembler.to_rgba8().into_vec(); + + let power_pole = include_bytes!("temp_assets/krastorio/PowerPole.png"); + let power_pole = image::load_from_memory(power_pole).unwrap(); + + let power_pole_dimensions = power_pole.dimensions(); + let power_pole = power_pole.to_rgba8().into_vec(); + + let lab = include_bytes!("temp_assets/krastorio/advanced-lab.png"); + let lab = image::load_from_memory(lab).unwrap(); + + let lab_dimensions = lab.dimensions(); + let lab = lab.to_rgba8().into_vec(); + + let chest = include_bytes!("temp_assets/krastorio/chest.png"); + let chest: image::DynamicImage = image::load_from_memory(chest).unwrap(); + + let chest_dimensions = chest.dimensions(); + let chest = chest.to_rgba8().into_vec(); + + let belt_north = include_bytes!("temp_assets/belt_north.png"); + let belt_north = image::load_from_memory(belt_north).unwrap(); + + let belt_north_dimensions = belt_north.dimensions(); + let belt_north = belt_north.to_rgba8().into_vec(); + + let belt_south = include_bytes!("temp_assets/belt_south.png"); + let belt_south = image::load_from_memory(belt_south).unwrap(); + + let belt_south_dimensions = belt_south.dimensions(); + let belt_south = belt_south.to_rgba8().into_vec(); + + let belt_west = include_bytes!("temp_assets/belt_west.png"); + let belt_west = image::load_from_memory(belt_west).unwrap(); + + let belt_west_dimensions = belt_west.dimensions(); + let belt_west = belt_west.to_rgba8().into_vec(); + + let belt_east = include_bytes!("temp_assets/belt_east.png"); + let belt_east = image::load_from_memory(belt_east).unwrap(); + + let belt_east_dimensions = belt_east.dimensions(); + let belt_east = belt_east.to_rgba8().into_vec(); + + let inserter_north = include_bytes!("temp_assets/inserter_north.png"); + let inserter_north = image::load_from_memory(inserter_north).unwrap(); + + let inserter_north_dimensions = inserter_north.dimensions(); + let inserter_north = inserter_north.to_rgba8().into_vec(); + + let inserter_south = include_bytes!("temp_assets/inserter_south.png"); + let inserter_south = image::load_from_memory(inserter_south).unwrap(); + + let inserter_south_dimensions = inserter_south.dimensions(); + let inserter_south = inserter_south.to_rgba8().into_vec(); + + let inserter_west = include_bytes!("temp_assets/inserter_west.png"); + let inserter_west = image::load_from_memory(inserter_west).unwrap(); + + let inserter_west_dimensions = inserter_west.dimensions(); + let inserter_west = inserter_west.to_rgba8().into_vec(); + + let inserter_east = include_bytes!("temp_assets/inserter_east.png"); + let inserter_east = image::load_from_memory(inserter_east).unwrap(); + + let inserter_east_dimensions = inserter_east.dimensions(); + let inserter_east = inserter_east.to_rgba8().into_vec(); + + let plate = include_bytes!("temp_assets/plate.png"); + let plate = image::load_from_memory(plate).unwrap(); + + let plate_dimensions = plate.dimensions(); + let plate = plate.to_rgba8().into_vec(); + + let player = include_bytes!("temp_assets/player.png"); + let player = image::load_from_memory(player).unwrap(); + + let player_dimensions = player.dimensions(); + let player = player.to_rgba8().into_vec(); + + let not_connected = include_bytes!("temp_assets/not_connected.png"); + let not_connected = image::load_from_memory(not_connected).unwrap(); + + let not_connected_dimensions = not_connected.dimensions(); + let not_connected = not_connected.to_rgba8().into_vec(); + + let no_power = include_bytes!("temp_assets/no_power.png"); + let no_power = image::load_from_memory(no_power).unwrap(); + + let no_power_dimensions = no_power.dimensions(); + let no_power = no_power.to_rgba8().into_vec(); + + let beacon = include_bytes!("temp_assets/beacon.png"); + let beacon = image::load_from_memory(beacon).unwrap(); + + let beacon_dimensions = beacon.dimensions(); + let beacon = beacon.to_rgba8().into_vec(); + + TextureAtlas { + outside_world: Sprite::new(Texture::new(1, black.clone(), black_dimensions)), blue: Sprite::new(Texture::new(1, blue, blue_dimensions)), - not_connected: Sprite::new(Texture::new(1, not_connected, not_connected_dimensions)), + not_connected: EntitySprite::new_scaled( + Sprite::new(Texture::new(1, not_connected, not_connected_dimensions)), + 3.0, + ), - no_power: Sprite::new(Texture::new(1, no_power, no_power_dimensions)), + no_power: EntitySprite::new_scaled( + Sprite::new(Texture::new(1, no_power, no_power_dimensions)), + 3.0, + ), + + assembler: EntitySprite::new_tiling(Sprite::new(Texture::new( + 7 * 4, + assembler, + assembler_dimensions, + ))), + chest: EntitySprite::new_tiling(Sprite::new(Texture::new(1, chest, chest_dimensions))), items: vec![ Sprite::new(Texture::new(1, plate.clone(), plate_dimensions)), @@ -155,7 +432,13 @@ fn texture_atlas() -> TextureAtlas { Sprite::new(Texture::new(1, inserter_west, inserter_west_dimensions)), ]), - beacon: Sprite::new(Texture::new(1, beacon, beacon_dimensions)), + beacon: EntitySprite::new_tiling(Sprite::new(Texture::new(1, beacon, beacon_dimensions))), + power_pole: EntitySprite::new_tall( + Sprite::new(Texture::new(1, power_pole, power_pole_dimensions)), + 1.0 / 2.0, + ), + + lab: EntitySprite::new_tiling(Sprite::new(Texture::new(1, lab, lab_dimensions))), default: Sprite::new(Texture::default()), } diff --git a/src/rendering/render_world.rs b/src/rendering/render_world.rs index e28a34f..37a1268 100644 --- a/src/rendering/render_world.rs +++ b/src/rendering/render_world.rs @@ -1,8 +1,11 @@ -use std::{cmp::min, iter::successors}; +use std::{ + cmp::{min, Ordering}, + iter::successors, +}; use crate::{ assembler::AssemblerOnclickInfo, - belt::{belt::Belt, splitter::SPLITTER_BELT_LEN, BeltTileId}, + belt::{splitter::SPLITTER_BELT_LEN, BeltTileId}, blueprint::Blueprint, data::{factorio_1_1::get_raw_data_test, DataStore, ItemRecipeDir}, frontend::{ @@ -13,20 +16,20 @@ use crate::{ set_recipe::SetRecipeInfo, ActionType, }, - world::tile::{ - AssemblerID, AssemblerInfo, Dir, Entity, BELT_LEN_PER_TILE, CHUNK_SIZE_FLOAT, - }, + world::tile::{AssemblerInfo, Dir, Entity, BELT_LEN_PER_TILE, CHUNK_SIZE_FLOAT}, }, item::{usize_from, IdxTrait, Item, Recipe}, - power::{power_grid::MAX_POWER_MULT, Watt}, + power::{power_grid::MAX_POWER_MULT, Joule, Watt}, statistics::{ NUM_SAMPLES_AT_INTERVALS, NUM_X_AXIS_TICKS, RELATIVE_INTERVAL_MULTS, TIMESCALE_LEGEND, }, + TICKS_PER_SECOND_LOGIC, }; use eframe::egui::{ self, Align2, Color32, ComboBox, Context, CornerRadius, Label, Layout, ProgressBar, Stroke, Ui, Window, }; +use egui::{RichText, ScrollArea, Sense, UiBuilder}; use egui_extras::{Column, TableBuilder}; use egui_plot::{AxisHints, GridMark, Line, Plot, PlotPoints}; use log::{info, trace, warn}; @@ -46,20 +49,23 @@ pub fn render_world( state_machine: &ActionStateMachine, data_store: &DataStore, ) { - let num_tiles_across_screen = + let ar = renderer.get_aspect_ratio(); + + let num_tiles_across_screen_horizontal = WIDTH_PER_LEVEL as f32 * state_machine.zoom_level * state_machine.zoom_level; - let tilesize: f32 = 1.0 / num_tiles_across_screen; + let num_tiles_across_screen_vertical = num_tiles_across_screen_horizontal / ar; + let tilesize: f32 = 1.0 / num_tiles_across_screen_horizontal; - let mut tile_layer = Layer::square_tile_grid(tilesize); - let mut entity_layer = Layer::square_tile_grid(tilesize); + let mut tile_layer = Layer::square_tile_grid(tilesize, ar); + let mut entity_layer = Layer::square_tile_grid(tilesize, ar); - let mut item_layer = Layer::square_tile_grid(tilesize); + let mut item_layer = Layer::square_tile_grid(tilesize, ar); - let mut player_layer = Layer::square_tile_grid(tilesize); + let mut player_layer = Layer::square_tile_grid(tilesize, ar); - let mut warning_layer = Layer::square_tile_grid(tilesize); + let mut warning_layer = Layer::square_tile_grid(tilesize, ar); - let range_layer = Layer::square_tile_grid(tilesize); + let range_layer = Layer::square_tile_grid(tilesize, ar); let player_pos = state_machine.local_player_pos; @@ -68,18 +74,18 @@ pub fn render_world( (player_pos.1 / CHUNK_SIZE_FLOAT) as i32, ); - for x_offs in -((num_tiles_across_screen / CHUNK_SIZE_FLOAT / 2.0).ceil() as i32) - ..=((num_tiles_across_screen / CHUNK_SIZE_FLOAT / 2.0).ceil() as i32) + for x_offs in -((num_tiles_across_screen_horizontal / CHUNK_SIZE_FLOAT / 2.0).ceil() as i32) + ..=((num_tiles_across_screen_horizontal / CHUNK_SIZE_FLOAT / 2.0).ceil() as i32) { // TODO: Use different height (aspect ratio!) - for y_offs in -((num_tiles_across_screen / CHUNK_SIZE_FLOAT / 2.0).ceil() as i32) - ..=((num_tiles_across_screen / CHUNK_SIZE_FLOAT / 2.0).ceil() as i32) + for y_offs in -((num_tiles_across_screen_vertical / CHUNK_SIZE_FLOAT / 2.0).ceil() as i32) + ..=((num_tiles_across_screen_vertical / CHUNK_SIZE_FLOAT / 2.0).ceil() as i32) { let chunk_draw_offs = ( x_offs as f32 * CHUNK_SIZE_FLOAT - player_pos.0 % CHUNK_SIZE_FLOAT - + (0.5 * num_tiles_across_screen), + + (0.5 * num_tiles_across_screen_horizontal), y_offs as f32 * CHUNK_SIZE_FLOAT - player_pos.1 % CHUNK_SIZE_FLOAT - + (0.5 * num_tiles_across_screen), + + (0.5 * num_tiles_across_screen_vertical), ); match game_state.world.get_chunk( @@ -93,7 +99,13 @@ pub fn render_world( .unwrap(), ) { Some(chunk) => { - for (x, row) in chunk.floor_tiles.unwrap_or_default().iter().enumerate() { + for (x, row) in chunk + .floor_tiles + .as_ref() + .unwrap_or(&Box::new(Default::default())) + .iter() + .enumerate() + { for (y, tile) in row.iter().enumerate() { match tile { crate::frontend::world::tile::FloorTile::Empty => tile_layer @@ -108,17 +120,19 @@ pub fn render_world( animation_frame: 0, }, ), - _ => tile_layer.draw_sprite( - &texture_atlas.default, - DrawInstance { - position: [ - chunk_draw_offs.0 + x as f32, - chunk_draw_offs.1 + y as f32, - ], - size: [1.0, 1.0], - animation_frame: 0, - }, - ), + _ => { + tile_layer.draw_sprite( + &texture_atlas.default, + DrawInstance { + position: [ + chunk_draw_offs.0 + x as f32, + chunk_draw_offs.1 + y as f32, + ], + size: [1.0, 1.0], + animation_frame: 0, + }, + ); + }, } } } @@ -126,45 +140,81 @@ pub fn render_world( for entity in chunk.get_entities() { match entity { crate::frontend::world::tile::Entity::Assembler { - pos, info, .. + ty, + pos, + info, + .. } => { - entity_layer.draw_sprite( - &texture_atlas.assembler, - DrawInstance { - position: [ - chunk_draw_offs.0 + (pos.x % 16) as f32, - chunk_draw_offs.1 + (pos.y % 16) as f32, - ], - size: [3.0, 3.0], - animation_frame: 0, - }, - ); + let size: [u16; 2] = [ + data_store.assembler_info[usize::from(*ty)].size.0, + data_store.assembler_info[usize::from(*ty)].size.1, + ]; match info { AssemblerInfo::UnpoweredNoRecipe | AssemblerInfo::Unpowered(_) => { - warning_layer.draw_sprite( - &texture_atlas.not_connected, - DrawInstance { - position: [ + texture_atlas.not_connected.draw_centered_on( + &texture_atlas.assembler, + [ + chunk_draw_offs.0 + (pos.x % 16) as f32, + chunk_draw_offs.1 + (pos.y % 16) as f32, + ], + size, + 0, + &mut warning_layer, + ); + + texture_atlas.assembler.draw( + [ + chunk_draw_offs.0 + (pos.x % 16) as f32, + chunk_draw_offs.1 + (pos.y % 16) as f32, + ], + size, + 0, + &mut entity_layer, + ); + }, + AssemblerInfo::PoweredNoRecipe(pole_position) => { + let grid = game_state + .simulation_state + .factory + .power_grids + .pole_pos_to_grid_id[pole_position]; + + let last_power = game_state + .simulation_state + .factory + .power_grids + .power_grids[usize::from(grid)] + .last_power_mult; + + if last_power == 0 { + texture_atlas.no_power.draw_centered_on( + &texture_atlas.assembler, + [ chunk_draw_offs.0 + (pos.x % 16) as f32, chunk_draw_offs.1 + (pos.y % 16) as f32, ], - size: [3.0, 3.0], - animation_frame: 0, - }, + size, + 0, + &mut warning_layer, + ); + } + + texture_atlas.assembler.draw( + [ + chunk_draw_offs.0 + (pos.x % 16) as f32, + chunk_draw_offs.1 + (pos.y % 16) as f32, + ], + size, + 0, + &mut entity_layer, ); }, - AssemblerInfo::PoweredNoRecipe(pole_position) - | AssemblerInfo::Powered { - id: - AssemblerID { - recipe: _, - grid: _, - assembler_index: _, - }, + AssemblerInfo::Powered { + id, pole_position, - weak_index: _, + weak_index, } => { let grid = game_state .simulation_state @@ -180,18 +230,56 @@ pub fn render_world( .last_power_mult; if last_power == 0 { - warning_layer.draw_sprite( - &texture_atlas.no_power, - DrawInstance { - position: [ - chunk_draw_offs.0 + (pos.x % 16) as f32, - chunk_draw_offs.1 + (pos.y % 16) as f32, - ], - size: [3.0, 3.0], - animation_frame: 0, - }, + texture_atlas.no_power.draw_centered_on( + &texture_atlas.assembler, + [ + chunk_draw_offs.0 + (pos.x % 16) as f32, + chunk_draw_offs.1 + (pos.y % 16) as f32, + ], + size, + 0, + &mut warning_layer, ); } + + let AssemblerOnclickInfo { + inputs, + outputs, + timer_percentage, + prod_timer_percentage, + base_speed, + speed_mod, + prod_mod, + power_consumption_mod, + base_power_consumption, + } = game_state + .simulation_state + .factory + .power_grids + .get_assembler_info(*id, data_store); + + texture_atlas.assembler.draw( + [ + chunk_draw_offs.0 + (pos.x % 16) as f32, + chunk_draw_offs.1 + (pos.y % 16) as f32, + ], + size, + (timer_percentage + * (texture_atlas + .assembler + .sprite + .texture + .number_anim_frames + as f32)) + .floor() + as u32 + % texture_atlas + .assembler + .sprite + .texture + .number_anim_frames, + &mut entity_layer, + ); }, } }, @@ -276,7 +364,12 @@ pub fn render_world( } }, - Entity::Inserter { pos, direction, .. } => { + Entity::Inserter { + pos, + direction, + info, + .. + } => { entity_layer.draw_sprite( &texture_atlas.inserter[*direction], DrawInstance { @@ -288,6 +381,27 @@ pub fn render_world( animation_frame: 0, }, ); + + match info { + crate::frontend::world::tile::InserterInfo::NotAttached { + start_pos, + end_pos, + } => {}, + crate::frontend::world::tile::InserterInfo::Attached { + start_pos, + end_pos, + info, + } => { + // match info { + // crate::frontend::world::tile::AttachedInserter::BeltStorage { id, belt_pos } => todo!(), + // crate::frontend::world::tile::AttachedInserter::BeltBelt { item, inserter } => todo!(), + // crate::frontend::world::tile::AttachedInserter::StorageStorage { item, inserter } => { + // // let info = game_state.simulation_state.factory.storage_storage_inserters + + // }, + // } + }, + } }, Entity::PowerPole { @@ -297,16 +411,16 @@ pub fn render_world( } => { // TODO: // println!("Pole at {pos:?}, with grid: {grid_id}"); - entity_layer.draw_sprite( - &texture_atlas.assembler, - DrawInstance { - position: [ - chunk_draw_offs.0 + (pos.x % 16) as f32, - chunk_draw_offs.1 + (pos.y % 16) as f32, - ], - size: [1.0, 1.0], - animation_frame: 0, - }, + let size = data_store.power_pole_data[usize::from(*ty)].size; + let size = [size.0, size.1]; + texture_atlas.power_pole.draw( + [ + chunk_draw_offs.0 + (pos.x % 16) as f32, + chunk_draw_offs.1 + (pos.y % 16) as f32, + ], + size, + 0, + &mut entity_layer, ); }, @@ -391,19 +505,19 @@ pub fn render_world( item, slot_limit: _, } => { - entity_layer.draw_sprite( - &texture_atlas.default, - DrawInstance { - position: [ - chunk_draw_offs.0 + (pos.x % 16) as f32, - chunk_draw_offs.1 + (pos.y % 16) as f32, - ], - size: [1.0, 1.0], - animation_frame: 0, - }, + let size = data_store.chest_tile_sizes[usize::from(*ty)]; + let size = [size.0, size.1]; + texture_atlas.chest.draw( + [ + chunk_draw_offs.0 + (pos.x % 16) as f32, + chunk_draw_offs.1 + (pos.y % 16) as f32, + ], + size, + 0, + &mut entity_layer, ); }, - Entity::SolarPanel { pos, .. } => { + Entity::SolarPanel { ty, pos, .. } => { entity_layer.draw_sprite( &texture_atlas.default, DrawInstance { @@ -411,24 +525,69 @@ pub fn render_world( chunk_draw_offs.0 + (pos.x % 16) as f32, chunk_draw_offs.1 + (pos.y % 16) as f32, ], - size: [3.0, 3.0], + size: data_store.solar_panel_info[usize::from(*ty)] + .size + .map(|v| v as f32), animation_frame: 0, }, ); }, // TODO: Render if a lab is working! - Entity::Lab { pos, .. } => { - entity_layer.draw_sprite( - &texture_atlas.belt[Dir::North], - DrawInstance { - position: [ + Entity::Lab { + ty, + pos, + pole_position, + .. + } => { + let size = data_store.lab_info[usize::from(*ty)].size; + let size = [size.0, size.1]; + + texture_atlas.lab.draw( + [ + chunk_draw_offs.0 + (pos.x % 16) as f32, + chunk_draw_offs.1 + (pos.y % 16) as f32, + ], + size, + 0, + &mut entity_layer, + ); + + if let Some((pole_pos, _, _)) = pole_position { + let grid = game_state + .simulation_state + .factory + .power_grids + .pole_pos_to_grid_id[pole_pos]; + + let last_power = + game_state.simulation_state.factory.power_grids.power_grids + [usize::from(grid)] + .last_power_mult; + + if last_power == 0 { + texture_atlas.no_power.draw_centered_on( + &texture_atlas.lab, + [ + chunk_draw_offs.0 + (pos.x % 16) as f32, + chunk_draw_offs.1 + (pos.y % 16) as f32, + ], + size, + 0, + &mut warning_layer, + ); + } + } else { + texture_atlas.not_connected.draw_centered_on( + &texture_atlas.lab, + [ chunk_draw_offs.0 + (pos.x % 16) as f32, chunk_draw_offs.1 + (pos.y % 16) as f32, ], - size: [3.0, 3.0], - animation_frame: 0, - }, - ); + size, + 0, + &mut warning_layer, + ); + } }, Entity::Beacon { @@ -437,19 +596,17 @@ pub fn render_world( modules, pole_position, } => { - let (size_x, size_y) = - data_store.beacon_info[usize::from(*ty)].size; + let size = data_store.beacon_info[usize::from(*ty)].size; + let size = [size.0, size.1]; - entity_layer.draw_sprite( - &texture_atlas.beacon, - DrawInstance { - position: [ - chunk_draw_offs.0 + (pos.x % 16) as f32, - chunk_draw_offs.1 + (pos.y % 16) as f32, - ], - size: [size_x.into(), size_y.into()], - animation_frame: 0, - }, + texture_atlas.beacon.draw( + [ + chunk_draw_offs.0 + (pos.x % 16) as f32, + chunk_draw_offs.1 + (pos.y % 16) as f32, + ], + size, + 0, + &mut entity_layer, ); if let Some((pole_pos, _)) = pole_position { @@ -465,29 +622,27 @@ pub fn render_world( .last_power_mult; if last_power == 0 { - warning_layer.draw_sprite( - &texture_atlas.no_power, - DrawInstance { - position: [ - chunk_draw_offs.0 + (pos.x % 16) as f32, - chunk_draw_offs.1 + (pos.y % 16) as f32, - ], - size: [size_x.into(), size_y.into()], - animation_frame: 0, - }, - ); - } - } else { - warning_layer.draw_sprite( - &texture_atlas.not_connected, - DrawInstance { - position: [ + texture_atlas.no_power.draw_centered_on( + &texture_atlas.beacon, + [ chunk_draw_offs.0 + (pos.x % 16) as f32, chunk_draw_offs.1 + (pos.y % 16) as f32, ], - size: [size_x.into(), size_y.into()], - animation_frame: 0, - }, + size, + 0, + &mut warning_layer, + ); + } + } else { + texture_atlas.not_connected.draw_centered_on( + &texture_atlas.beacon, + [ + chunk_draw_offs.0 + (pos.x % 16) as f32, + chunk_draw_offs.1 + (pos.y % 16) as f32, + ], + size, + 0, + &mut warning_layer, ); } @@ -531,19 +686,21 @@ pub fn render_world( ) => match place_entity_type { // TODO: crate::frontend::world::tile::PlaceEntityType::Assembler { ty, pos } => { - entity_layer.draw_sprite( - &texture_atlas.assembler, - DrawInstance { - position: [ - pos.x as f32 - state_machine.local_player_pos.0 - + num_tiles_across_screen / 2.0, - pos.y as f32 - state_machine.local_player_pos.1 - + num_tiles_across_screen / 2.0, - ], - size: [3.0, 3.0], - animation_frame: 0, - }, - ) + let size: [u16; 2] = [ + data_store.assembler_info[usize::from(*ty)].size.0, + data_store.assembler_info[usize::from(*ty)].size.1, + ]; + texture_atlas.assembler.draw( + [ + pos.x as f32 - state_machine.local_player_pos.0 + + num_tiles_across_screen_horizontal / 2.0, + pos.y as f32 - state_machine.local_player_pos.1 + + num_tiles_across_screen_vertical / 2.0, + ], + size, + 0, + &mut entity_layer, + ); }, crate::frontend::world::tile::PlaceEntityType::Inserter { pos, @@ -588,8 +745,10 @@ pub fn render_world( &texture_atlas.player, DrawInstance { position: [ - player.pos.0 - state_machine.local_player_pos.0 + num_tiles_across_screen / 2.0, - player.pos.1 - state_machine.local_player_pos.1 + num_tiles_across_screen / 2.0, + player.pos.0 - state_machine.local_player_pos.0 + + num_tiles_across_screen_horizontal / 2.0, + player.pos.1 - state_machine.local_player_pos.1 + + num_tiles_across_screen_vertical / 2.0, ], size: [1.0, 2.0], animation_frame: 0, @@ -609,7 +768,10 @@ pub fn render_world( &texture_atlas.player, DrawInstance { // Always in the middle - position: [num_tiles_across_screen / 2.0, num_tiles_across_screen / 2.0], + position: [ + num_tiles_across_screen_horizontal / 2.0, + num_tiles_across_screen_vertical / 2.0, + ], size: [1.0, 2.0], animation_frame: 0, }, @@ -808,14 +970,36 @@ pub fn render_ui( ui.label(format!("Power Grid number: {}", grid_id)); - let pb = ProgressBar::new(pg.last_power_mult as f32 / 64.0); - ui.add(pb); + ui.columns_const(|[ui_consumption, ui_production, ui_storage]| { + // Power Consumption + ui_consumption.add(Label::new(RichText::new("Satisfaction").heading()).wrap_mode(egui::TextWrapMode::Extend)); + ui_consumption.add(ProgressBar::new(pg.last_produced_power.0 as f32 / pg.last_power_consumption.0 as f32).corner_radius(CornerRadius::ZERO).fill(if pg.last_power_mult == MAX_POWER_MULT { + Color32::GREEN + } else if pg.last_power_mult > MAX_POWER_MULT / 2 { + Color32::YELLOW + } else { + Color32::RED + }).text(RichText::new(format!("{}/{}", pg.last_produced_power, pg.last_power_consumption)).color(Color32::BLACK))); + + + // Power Production + ui_production.add(Label::new(RichText::new("Production").heading()).wrap_mode(egui::TextWrapMode::Extend)); + ui_production.add(ProgressBar::new(pg.last_produced_power.0 as f32 / pg.last_ticks_max_power_production.0 as f32).corner_radius(CornerRadius::ZERO).text(RichText::new(format!("{}/{}", pg.last_produced_power, pg.last_ticks_max_power_production)).color(Color32::BLACK))); + + + // Power Storage + let max_charge: Joule = pg.main_accumulator_count.iter().copied().zip(data_store.accumulator_info.iter().map(|info| info.max_charge)).map(|(count, charge)| charge * count).sum(); + let current_charge: Joule = pg.main_accumulator_count.iter().copied().zip(pg.main_accumulator_charge.iter().copied()).map(|(count, charge)| charge * count).sum(); + + ui_storage.add(Label::new(RichText::new("Accumulator charge").heading()).wrap_mode(egui::TextWrapMode::Extend)); + ui_storage.add(ProgressBar::new(current_charge.0 as f32 / max_charge.0 as f32).corner_radius(CornerRadius::ZERO).text(RichText::new(format!("{}/{}", current_charge, max_charge)).color(Color32::BLACK))); + }); let timescale = 1; let max_value_at_timescale = (MAX_POWER_MULT as f64) * (RELATIVE_INTERVAL_MULTS[..=timescale].iter().copied().product::() as f64); let num_samples = NUM_SAMPLES_AT_INTERVALS[timescale]; - let points = pg.power_history.get_series(timescale, data_store, Some(|_| true)).into_iter().map(|series| (series.name, series.data.into_iter() + let points = pg.power_mult_history.get_series(timescale, data_store, Some(|_| true)).into_iter().map(|(_, series)| (series.name, series.data.into_iter() .enumerate() .map(|(i, v)| [i as f64, v.into()]) .collect::>())); @@ -1024,6 +1208,8 @@ pub fn render_ui( ui.radio_value(time_scale, 2, "1 Hour"); }); + let time_scale = *time_scale; + match state_machine.statistics_panel { StatisticsPanel::Items(scale) | StatisticsPanel::Fluids(scale) => { let take_fluids = @@ -1035,7 +1221,7 @@ pub fn render_ui( ui_consumption.heading("Consumption"); ui_consumption.separator(); - let prod_points: Vec<(String, usize, PlotPoints)> = game_state + let prod_points: Vec<(String, usize, f32, PlotPoints)> = game_state .statistics .production .get_series( @@ -1046,27 +1232,54 @@ pub fn render_ui( }), ) .into_iter() - .enumerate() - .map(|(i, series)| (series.name, i, series.data)) + .map(|(item_id, series)| (series.name, item_id, series.data)) .map(|(name, i, data)| { ( name, i, + data.iter().copied().sum(), data.into_iter() .enumerate() .map(|(i, v)| [i as f64, v.into()]) .collect(), ) }) - .filter(|(_, _, points): &(_, _, PlotPoints)| { - points.points().iter().any(|p| p.y > 0.0) + .filter(|(_, _, sum, _): &(_, _, f32, _)| *sum > 0.0) + .collect(); + + let max_prod = prod_points + .iter() + .map(|v| v.2) + .max_by(|a, b| { + if a < b { + Ordering::Less + } else { + Ordering::Greater + } }) + .unwrap_or(0.0); + + let mut sum_list_prod: Vec<_> = prod_points + .iter() + .map(|v| (v.0.clone(), v.1, v.2)) .collect(); - let lines = prod_points.into_iter().map(|(name, id, points)| { - Line::new(name, points) - .stroke(Stroke::new(2.0, data_store.item_to_colour[id])) + + sum_list_prod.sort_by(|a, b| { + if a.2 < b.2 { + Ordering::Greater + } else { + Ordering::Less + } }); + let lines = prod_points + .into_iter() + .filter(|(_, id, _, _)| state_machine.production_filters[*id]) + .map(|(name, id, _sum, points)| { + Line::new(name, points) + .stroke(Stroke::new(2.0, data_store.item_to_colour[id])) + }); + let ticks_per_value = RELATIVE_INTERVAL_MULTS[..=scale] .iter() .copied() @@ -1127,13 +1340,94 @@ pub fn render_ui( .allow_zoom([false, false]) .allow_drag([false, false]) .allow_scroll([false, false]) + .view_aspect(3.0) .show(ui_production, |ui| { for line in lines { ui.line(line); } }); - let cons_points: Vec<(String, usize, PlotPoints)> = game_state + let ticks_total = (RELATIVE_INTERVAL_MULTS[..=time_scale] + .iter() + .copied() + .product::() + * NUM_SAMPLES_AT_INTERVALS[time_scale]) + as f32; + + let row_height = ui_production.spacing().interact_size.y; + ScrollArea::vertical().id_salt("Prod List Scroll").show( + ui_production, + |ui| { + TableBuilder::new(ui) + .id_salt("Production List") + .sense(Sense::click()) + .column(Column::auto()) + .column(Column::remainder()) + .column(Column::auto()) + .body(|body| { + body.rows(row_height, sum_list_prod.len(), |mut row| { + let idx = row.index(); + row.col(|ui| { + if state_machine.production_filters + [sum_list_prod[idx].1] + { + ui.add( + Label::new(egui::RichText::new( + sum_list_prod[idx].0.as_str(), + )) + .extend(), + ); + } else { + ui.add( + Label::new( + egui::RichText::new( + sum_list_prod[idx].0.as_str(), + ) + .strikethrough(), + ) + .extend(), + ); + } + }); + row.col(|ui| { + ui.add( + ProgressBar::new( + sum_list_prod[idx].2 / max_prod, + ) + .fill( + data_store.item_to_colour + [sum_list_prod[idx].1], + ) + .corner_radius(CornerRadius::ZERO), + ); + }); + row.col(|ui| { + ui.with_layout( + Layout::right_to_left(egui::Align::Center), + |ui| { + ui.add( + Label::new(format!( + "{:.0}/m", + sum_list_prod[idx].2 / ticks_total + * TICKS_PER_SECOND_LOGIC as f32 + * 60.0 + )) + .extend(), + ); + }, + ); + }); + if row.response().clicked() { + state_machine.production_filters + [sum_list_prod[idx].1] = !state_machine + .production_filters[sum_list_prod[idx].1]; + } + }); + }); + }, + ); + + let cons_points: Vec<(String, usize, f32, PlotPoints)> = game_state .statistics .consumption .get_series( @@ -1144,27 +1438,54 @@ pub fn render_ui( }), ) .into_iter() - .enumerate() - .map(|(i, series)| (series.name, i, series.data)) + .map(|(item_id, series)| (series.name, item_id, series.data)) .map(|(name, i, data)| { ( name, i, + data.iter().copied().sum(), data.into_iter() .enumerate() .map(|(i, v)| [i as f64, v.into()]) .collect(), ) }) - .filter(|(_, _, points): &(_, _, PlotPoints)| { - points.points().iter().any(|p| p.y > 0.0) + .filter(|(_, _, sum, _): &(_, _, f32, _)| *sum > 0.0) + .collect(); + + let max_cons = cons_points + .iter() + .map(|v| v.2) + .max_by(|a, b| { + if a < b { + Ordering::Less + } else { + Ordering::Greater + } }) + .unwrap_or(0.0); + + let mut sum_list_cons: Vec<_> = cons_points + .iter() + .map(|v| (v.0.clone(), v.1, v.2)) .collect(); - let lines = cons_points.into_iter().map(|(name, id, points)| { - Line::new(name, points) - .stroke(Stroke::new(2.0, data_store.item_to_colour[id])) + + sum_list_cons.sort_by(|a, b| { + if a.2 < b.2 { + Ordering::Greater + } else { + Ordering::Less + } }); + let lines = cons_points + .into_iter() + .filter(|(_, id, _, _)| state_machine.consumption_filters[*id]) + .map(|(name, id, _sum, points)| { + Line::new(name, points) + .stroke(Stroke::new(2.0, data_store.item_to_colour[id])) + }); + let ticks_per_value = RELATIVE_INTERVAL_MULTS[..=scale] .iter() .copied() @@ -1225,11 +1546,84 @@ pub fn render_ui( .allow_zoom([false, false]) .allow_drag([false, false]) .allow_scroll([false, false]) + .view_aspect(3.0) .show(ui_consumption, |ui| { for line in lines { ui.line(line); } }); + + ScrollArea::vertical().id_salt("Cons List Scroll").show( + ui_consumption, + |ui| { + TableBuilder::new(ui) + .id_salt("Consumption List") + .sense(Sense::click()) + .column(Column::auto()) + .column(Column::remainder()) + .column(Column::auto()) + .body(|body| { + body.rows(row_height, sum_list_cons.len(), |mut row| { + let idx = row.index(); + row.col(|ui| { + if state_machine.consumption_filters + [sum_list_cons[idx].1] + { + ui.add( + Label::new(egui::RichText::new( + sum_list_cons[idx].0.as_str(), + )) + .extend(), + ); + } else { + ui.add( + Label::new( + egui::RichText::new( + sum_list_cons[idx].0.as_str(), + ) + .strikethrough(), + ) + .extend(), + ); + } + }); + row.col(|ui| { + ui.add( + ProgressBar::new( + sum_list_cons[idx].2 / max_cons, + ) + .fill( + data_store.item_to_colour + [sum_list_cons[idx].1], + ) + .corner_radius(CornerRadius::ZERO), + ); + }); + row.col(|ui| { + ui.with_layout( + Layout::right_to_left(egui::Align::Center), + |ui| { + ui.add( + Label::new(format!( + "{:.0}/m", + sum_list_cons[idx].2 / ticks_total + * TICKS_PER_SECOND_LOGIC as f32 + * 60.0 + )) + .extend(), + ); + }, + ); + }); + if row.response().clicked() { + state_machine.consumption_filters + [sum_list_cons[idx].1] = !state_machine + .consumption_filters[sum_list_cons[idx].1]; + } + }); + }); + }, + ); }); }, } diff --git a/src/rendering/temp_assets/.gitignore b/src/rendering/temp_assets/.gitignore new file mode 100644 index 0000000..dd6abf6 --- /dev/null +++ b/src/rendering/temp_assets/.gitignore @@ -0,0 +1 @@ +krastorio \ No newline at end of file diff --git a/src/rendering/temp_assets/no_power.png b/src/rendering/temp_assets/no_power.png index 9a254b0..6d1d5d5 100644 Binary files a/src/rendering/temp_assets/no_power.png and b/src/rendering/temp_assets/no_power.png differ diff --git a/src/rendering/temp_assets/not_connected.png b/src/rendering/temp_assets/not_connected.png index 2f5d026..524ab1c 100644 Binary files a/src/rendering/temp_assets/not_connected.png and b/src/rendering/temp_assets/not_connected.png differ diff --git a/src/statistics/consumption.rs b/src/statistics/consumption.rs index 34a92ab..750067b 100644 --- a/src/statistics/consumption.rs +++ b/src/statistics/consumption.rs @@ -78,7 +78,7 @@ impl values: &[Self], filter: Option) -> bool>, data_store: &DataStore, - ) -> impl IntoIterator { + ) -> impl IntoIterator { BTreeMap::from_iter( values .iter() @@ -104,8 +104,13 @@ impl .into_iter() .map(|(k, v)| (k.0, (k.1, v))), ) - .into_values() - .map(|a| (a.0.as_str(), a.1.into_iter().map(|v| v as f32).collect()).into()) + .into_iter() + .map(|(item_id, a)| { + ( + item_id.try_into().unwrap(), + (a.0.as_str(), a.1.into_iter().map(|v| v as f32).collect()).into(), + ) + }) } } diff --git a/src/statistics/mod.rs b/src/statistics/mod.rs index 284e35b..5beee40 100644 --- a/src/statistics/mod.rs +++ b/src/statistics/mod.rs @@ -69,6 +69,7 @@ impl GenStatistics { .production .get_series(timescale, data_store, filter) .into_iter() + .map(|v| v.1) .collect(); LineChart::new( @@ -83,7 +84,7 @@ pub trait IntoSeries: Sized { values: &[Self], filter: Option bool>, data_store: &DataStore, - ) -> impl IntoIterator; + ) -> impl IntoIterator; } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] @@ -165,7 +166,8 @@ impl AddAssign<&'a T>> Timeline { timescale: usize, data_store: &'b DataStore, filter: Option, - ) -> impl IntoIterator + use<'a, 'b, T, Item, ItemIdxType, RecipeIdxType, Filter> + ) -> impl IntoIterator + + use<'a, 'b, T, Item, ItemIdxType, RecipeIdxType, Filter> where T: IntoSeries, { diff --git a/src/statistics/power.rs b/src/statistics/power.rs index 3aebabc..7c5ae89 100644 --- a/src/statistics/power.rs +++ b/src/statistics/power.rs @@ -16,8 +16,9 @@ impl values: &[Self], filter: Option) -> bool>, data_store: &DataStore, - ) -> impl IntoIterator { - iter::once( + ) -> impl IntoIterator { + iter::once(( + 0, ( "Power Satisfaction", values @@ -26,6 +27,6 @@ impl .collect::>(), ) .into(), - ) + )) } } diff --git a/src/statistics/production.rs b/src/statistics/production.rs index 8f0c2fe..da1d27c 100644 --- a/src/statistics/production.rs +++ b/src/statistics/production.rs @@ -79,7 +79,7 @@ impl values: &[Self], filter: Option) -> bool>, data_store: &DataStore, - ) -> impl IntoIterator { + ) -> impl IntoIterator { BTreeMap::from_iter( values .iter() @@ -105,8 +105,13 @@ impl .into_iter() .map(|(k, v)| (k.0, (k.1, v))), ) - .into_values() - .map(|a| (a.0.as_str(), a.1.into_iter().map(|v| v as f32).collect()).into()) + .into_iter() + .map(|(item_id, a)| { + ( + item_id.try_into().unwrap(), + (a.0.as_str(), a.1.into_iter().map(|v| v as f32).collect()).into(), + ) + }) } } diff --git a/src/statistics/research.rs b/src/statistics/research.rs index 86d8870..1c2f286 100644 --- a/src/statistics/research.rs +++ b/src/statistics/research.rs @@ -25,8 +25,9 @@ impl IntoSeries<(), ItemIdxType, values: &[Self], filter: Option bool>, _data_store: &crate::data::DataStore, - ) -> impl IntoIterator { - iter::once( + ) -> impl IntoIterator { + iter::once(( + 0, ( "Research", values @@ -36,6 +37,6 @@ impl IntoSeries<(), ItemIdxType, .collect(), ) .into(), - ) + )) } } diff --git a/src/storage_list.rs b/src/storage_list.rs index d36cc4c..ac057ff 100644 --- a/src/storage_list.rs +++ b/src/storage_list.rs @@ -1,6 +1,7 @@ use std::u16; use itertools::Itertools; +use petgraph::data; use rayon::iter::IndexedParallelIterator; use strum::IntoEnumIterator; @@ -8,15 +9,17 @@ use crate::{ assembler::FullAssemblerStore, chest::FullChestStore, data::{DataStore, ItemRecipeDir}, - inserter::{StaticID, Storage}, + inserter::{FakeUnionStorage, StaticID, Storage}, item::{usize_from, IdxTrait, Item, ITEMCOUNTTYPE}, lab::MultiLabStore, power::{power_grid::PowerGridIdentifier, PowerGridStorage}, split_arbitrary::split_arbitrary_mut_slice, }; -pub const ALWAYS_FULL: &'static [ITEMCOUNTTYPE] = &[0; u16::MAX as usize]; +// FIXME: We just yeet 10MB of RAM into the wind here :/ +pub const ALWAYS_FULL: &'static [ITEMCOUNTTYPE] = &[0; 10_000_000]; pub const PANIC_ON_INSERT: &'static [ITEMCOUNTTYPE] = &[0; 0]; +pub const PANIC_ON_INSERT_DATA: &'static [ITEMCOUNTTYPE] = &[0; 0]; type SingleGridStorage<'a, 'b> = (&'a [ITEMCOUNTTYPE], &'b mut [ITEMCOUNTTYPE]); pub type SingleItemStorages<'a, 'b> = &'a mut [SingleGridStorage<'b, 'b>]; //[SingleGridStorage; NUM_RECIPES * NUM_GRIDS]; @@ -42,13 +45,15 @@ pub fn num_recipes( } pub fn static_size( + item: Item, data_store: &DataStore, ) -> usize { - StaticID::iter() - .map(|s| match s { - StaticID::Chest => data_store.item_names.len(), - }) - .sum() + let mut size = 0; + + // Chests + size += 1; + + size } pub fn grid_size( @@ -67,7 +72,11 @@ fn size_of_single_item_slice( ) -> usize { let num_different_static_containers = data_store.num_different_static_containers; let grid_size = grid_size(item, data_store); - num_grids_total * grid_size + num_different_static_containers + let static_size = static_size(item, data_store); + + let first_grid_offs = static_size.div_ceil(grid_size); + + (first_grid_offs + num_grids_total) * grid_size } pub fn index<'a, 'b, RecipeIdxType: IdxTrait>( @@ -76,7 +85,10 @@ pub fn index<'a, 'b, RecipeIdxType: IdxTrait>( num_grids_total: usize, num_recipes: usize, grid_size: usize, + static_size: usize, ) -> (&'a ITEMCOUNTTYPE, &'a mut ITEMCOUNTTYPE) { + let first_grid_offs_in_grids = static_size.div_ceil(grid_size); + match storage_id { Storage::Assembler { grid, @@ -87,32 +99,46 @@ pub fn index<'a, 'b, RecipeIdxType: IdxTrait>( usize_from(recipe_idx_with_this_item) < num_recipes, "The recipe stored in an inserter needs to be translated!" ); - let outer = &mut slice[Into::::into(grid) * grid_size + let outer = &mut slice[(first_grid_offs_in_grids + Into::::into(grid)) + * grid_size + Into::::into(recipe_idx_with_this_item)]; ( - &outer.0[Into::::into(index)], - &mut outer.1[Into::::into(index)], + &outer.0[usize::try_from(index).unwrap()], + &mut outer.1[usize::try_from(index).unwrap()], ) }, Storage::Lab { grid, index } => { - let outer = &mut slice[Into::::into(grid) * grid_size + num_recipes]; + let outer = &mut slice + [(first_grid_offs_in_grids + Into::::into(grid)) * grid_size + num_recipes]; ( - &outer.0[Into::::into(index)], - &mut outer.1[Into::::into(index)], + &outer.0[usize::try_from(index).unwrap()], + &mut outer.1[usize::try_from(index).unwrap()], ) }, Storage::Static { static_id, index } => { // debug_assert!(usize::from(static_id) < data_store.num_different_static_containers); - let outer = - &mut slice[num_grids_total * grid_size + Into::::into(static_id as u8)]; + let outer = &mut slice[Into::::into(static_id)]; ( - &outer.0[Into::::into(index)], - &mut outer.1[Into::::into(index)], + &outer.0[usize::try_from(index).unwrap()], + &mut outer.1[usize::try_from(index).unwrap()], ) }, } } +pub fn index_fake_union<'a, 'b>( + slice: SingleItemStorages<'a, 'b>, + storage_id: FakeUnionStorage, + num_grids_total: usize, + num_recipes: usize, + grid_size: usize, +) -> (&'a ITEMCOUNTTYPE, &'a mut ITEMCOUNTTYPE) { + let (outer, inner) = storage_id.into_inner_and_outer_indices_with_statics_at_zero(grid_size); + + let subslice = &mut slice[outer]; + (&subslice.0[inner], &mut subslice.1[inner]) +} + #[profiling::function] pub fn sizes<'a, ItemIdxType: IdxTrait, RecipeIdxType: IdxTrait>( data_store: &'a DataStore, @@ -157,18 +183,23 @@ fn get_full_storage_index( let num_recipes = num_recipes(item, data_store); let num_labs = num_labs(item, data_store); let grid_size = grid_size(item, data_store); + let static_size = static_size(item, data_store); + + let first_grid_offs = static_size.div_ceil(grid_size); let ret = match storage { Storage::Assembler { grid, recipe_idx_with_this_item: recipe, index: _, - } => item_offs + usize::from(grid) * grid_size + usize_from(recipe), - Storage::Lab { grid, index: _ } => item_offs + usize::from(grid) * grid_size + num_recipes, + } => item_offs + (first_grid_offs + usize::from(grid)) * grid_size + usize_from(recipe), + Storage::Lab { grid, index: _ } => { + item_offs + (first_grid_offs + usize::from(grid)) * grid_size + num_recipes + }, Storage::Static { static_id, index: _, - } => item_offs + num_power_grids * grid_size + usize::from(static_id as u8), + } => item_offs + usize::from(static_id), }; ret @@ -262,7 +293,7 @@ fn all_storages<'a, 'b, ItemIdxType: IdxTrait, RecipeIdxType: IdxTrait>( .into_iter() .chain(all_lab_storages(grid_id, &mut grid.lab_stores, data_store)) }) - .chain(all_chest_storages(chest_store)); + .chain(all_static_storages(chest_store, data_store)); all_storages } @@ -689,6 +720,64 @@ fn all_lab_storages<'a, 'b, ItemIdxType: IdxTrait, RecipeIdxType: IdxTrait>( #[profiling::function] fn all_lazy_power_machine_storages() {} +#[profiling::function] +fn all_static_storages<'a, 'b, ItemIdxType: IdxTrait, RecipeIdxType: IdxTrait>( + chest_store: &'a mut FullChestStore, + data_store: &'b DataStore, +) -> impl IntoIterator< + Item = ( + Item, + Storage, + &'a [ITEMCOUNTTYPE], + &'a mut [ITEMCOUNTTYPE], + ), +> + use<'a, 'b, ItemIdxType, RecipeIdxType> { + (0..data_store.item_names.len()) + .zip(chest_store.stores.iter_mut()) + .flat_map(|(id, chest)| { + let item = Item { + id: id.try_into().unwrap(), + }; + + let grid_size = grid_size(item, data_store); + let static_size = static_size(item, data_store); + + let first_grid_offs_in_grids = static_size.div_ceil(grid_size); + + let first_grid_offs = grid_size * first_grid_offs_in_grids; + + let (max_insert, data) = chest.storage_list_slices(); + + std::iter::repeat(item) + .zip( + std::iter::once(( + Storage::Static { + static_id: crate::inserter::StaticID::Chest as u16, + index: 0, + }, + max_insert, + data, + )) + .chain( + std::iter::repeat_with(|| (PANIC_ON_INSERT, [].as_mut_slice())) + .zip(StaticID::iter().count()..) + .map(|((max, data), static_id)| { + ( + Storage::Static { + static_id: static_id.try_into().unwrap(), + index: 0, + }, + max, + data, + ) + }), + ) + .take(first_grid_offs), + ) + .map(|(item, (a, b, c))| (item, a, b, c)) + }) +} + #[profiling::function] fn all_chest_storages<'a, ItemIdxType: IdxTrait, RecipeIdxType: IdxTrait>( chest_store: &'a mut FullChestStore, @@ -714,7 +803,7 @@ fn all_chest_storages<'a, ItemIdxType: IdxTrait, RecipeIdxType: IdxTrait>( ( item, Storage::Static { - static_id: crate::inserter::StaticID::Chest, + static_id: crate::inserter::StaticID::Chest as u16, index: 0, }, max_insert, diff --git a/tested_ideas/storage_list_statics_at_zero.md b/tested_ideas/storage_list_statics_at_zero.md new file mode 100644 index 0000000..4c36b3c --- /dev/null +++ b/tested_ideas/storage_list_statics_at_zero.md @@ -0,0 +1 @@ +Placing the static storages at the start of the storage list, we an skip some calculations in the inserter indexing. I have tested this, and it seems to save ~300us on a full factory. \ No newline at end of file diff --git a/tests/visual_test.rs b/tests/visual_test.rs index 80fde6b..59abc22 100644 --- a/tests/visual_test.rs +++ b/tests/visual_test.rs @@ -40,7 +40,11 @@ fn start_ui() -> ( let ds_move = ds.clone(); spawn(move || { let (send, recv) = channel(); - let sm = Arc::new(Mutex::new(ActionStateMachine::new(0, (1600.0, 1600.0)))); + let sm = Arc::new(Mutex::new(ActionStateMachine::new( + 0, + (1600.0, 1600.0), + &DATA_STORE, + ))); let sm_move = sm.clone(); let gs_move_move = gs_move.clone();