a bare-bones limbo server in rust (mirror of https://github.com/xoogware/crawlspace)

Compare changes

Choose any two refs to compare.

+345 -91
Cargo.lock
··· 1 1 # This file is automatically @generated by Cargo. 2 2 # It is not intended for manual editing. 3 - version = 3 3 + version = 4 4 4 5 5 [[package]] 6 6 name = "addr2line" ··· 39 39 40 40 [[package]] 41 41 name = "anstream" 42 - version = "0.6.19" 42 + version = "0.6.20" 43 43 source = "registry+https://github.com/rust-lang/crates.io-index" 44 - checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" 44 + checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" 45 45 dependencies = [ 46 46 "anstyle", 47 47 "anstyle-parse", ··· 69 69 70 70 [[package]] 71 71 name = "anstyle-query" 72 - version = "1.1.3" 72 + version = "1.1.4" 73 73 source = "registry+https://github.com/rust-lang/crates.io-index" 74 - checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" 74 + checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" 75 75 dependencies = [ 76 - "windows-sys 0.59.0", 76 + "windows-sys 0.60.2", 77 77 ] 78 78 79 79 [[package]] 80 80 name = "anstyle-wincon" 81 - version = "3.0.9" 81 + version = "3.0.10" 82 82 source = "registry+https://github.com/rust-lang/crates.io-index" 83 - checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" 83 + checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" 84 84 dependencies = [ 85 85 "anstyle", 86 86 "once_cell_polyfill", 87 - "windows-sys 0.59.0", 87 + "windows-sys 0.60.2", 88 88 ] 89 89 90 90 [[package]] ··· 105 105 "miniz_oxide", 106 106 "object", 107 107 "rustc-demangle", 108 - "windows-targets", 108 + "windows-targets 0.52.6", 109 109 ] 110 110 111 111 [[package]] ··· 128 128 dependencies = [ 129 129 "proc-macro2", 130 130 "quote", 131 - "syn 2.0.104", 131 + "syn 2.0.106", 132 + ] 133 + 134 + [[package]] 135 + name = "bitfield-struct" 136 + version = "0.11.0" 137 + source = "registry+https://github.com/rust-lang/crates.io-index" 138 + checksum = "d3ca019570363e800b05ad4fd890734f28ac7b72f563ad8a35079efb793616f8" 139 + dependencies = [ 140 + "proc-macro2", 141 + "quote", 142 + "syn 2.0.106", 132 143 ] 133 144 134 145 [[package]] 135 146 name = "bitflags" 136 - version = "2.9.1" 147 + version = "2.9.2" 137 148 source = "registry+https://github.com/rust-lang/crates.io-index" 138 - checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" 149 + checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" 139 150 140 151 [[package]] 141 152 name = "block-buffer" ··· 154 165 155 166 [[package]] 156 167 name = "bytemuck" 157 - version = "1.23.1" 168 + version = "1.23.2" 158 169 source = "registry+https://github.com/rust-lang/crates.io-index" 159 - checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" 170 + checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" 160 171 161 172 [[package]] 162 173 name = "byteorder" ··· 171 182 checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 172 183 173 184 [[package]] 185 + name = "cc" 186 + version = "1.2.33" 187 + source = "registry+https://github.com/rust-lang/crates.io-index" 188 + checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f" 189 + dependencies = [ 190 + "jobserver", 191 + "libc", 192 + "shlex", 193 + ] 194 + 195 + [[package]] 174 196 name = "cesu8" 175 197 version = "1.1.0" 176 198 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 203 225 204 226 [[package]] 205 227 name = "clap" 206 - version = "4.5.40" 228 + version = "4.5.45" 207 229 source = "registry+https://github.com/rust-lang/crates.io-index" 208 - checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" 230 + checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318" 209 231 dependencies = [ 210 232 "clap_builder", 211 233 "clap_derive", ··· 213 235 214 236 [[package]] 215 237 name = "clap_builder" 216 - version = "4.5.40" 238 + version = "4.5.44" 217 239 source = "registry+https://github.com/rust-lang/crates.io-index" 218 - checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" 240 + checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8" 219 241 dependencies = [ 220 242 "anstream", 221 243 "anstyle", ··· 225 247 226 248 [[package]] 227 249 name = "clap_derive" 228 - version = "4.5.40" 250 + version = "4.5.45" 229 251 source = "registry+https://github.com/rust-lang/crates.io-index" 230 - checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" 252 + checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" 231 253 dependencies = [ 232 254 "heck", 233 255 "proc-macro2", 234 256 "quote", 235 - "syn 2.0.104", 257 + "syn 2.0.106", 236 258 ] 237 259 238 260 [[package]] ··· 295 317 dependencies = [ 296 318 "aes", 297 319 "bit-vec", 298 - "bitfield-struct", 320 + "bitfield-struct 0.9.5", 299 321 "byteorder", 300 322 "bytes", 301 323 "cfb8", ··· 309 331 "serde", 310 332 "serde_json", 311 333 "sha2", 312 - "thiserror", 334 + "slimeball-lib", 335 + "thiserror 1.0.69", 313 336 "tokio", 314 337 "tokio-util", 315 338 "tracing", ··· 323 346 dependencies = [ 324 347 "proc-macro2", 325 348 "quote", 326 - "syn 2.0.104", 349 + "syn 2.0.106", 350 + ] 351 + 352 + [[package]] 353 + name = "crawlspace-proto" 354 + version = "0.1.0" 355 + dependencies = [ 356 + "bitfield-struct 0.11.0", 357 + "byteorder", 358 + "serde", 359 + "thiserror 2.0.16", 360 + "uuid", 361 + ] 362 + 363 + [[package]] 364 + name = "crawlspace-proto-1_8" 365 + version = "0.1.0" 366 + dependencies = [ 367 + "bytes", 368 + "crawlspace-macro", 369 + "crawlspace-proto", 370 + "tokio", 371 + "tracing", 327 372 ] 328 373 329 374 [[package]] 330 375 name = "crc32fast" 331 - version = "1.4.2" 376 + version = "1.5.0" 332 377 source = "registry+https://github.com/rust-lang/crates.io-index" 333 - checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 378 + checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" 334 379 dependencies = [ 335 380 "cfg-if", 336 381 ] ··· 484 529 dependencies = [ 485 530 "cfg-if", 486 531 "libc", 487 - "wasi", 532 + "wasi 0.11.1+wasi-snapshot-preview1", 533 + ] 534 + 535 + [[package]] 536 + name = "getrandom" 537 + version = "0.3.3" 538 + source = "registry+https://github.com/rust-lang/crates.io-index" 539 + checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 540 + dependencies = [ 541 + "cfg-if", 542 + "libc", 543 + "r-efi", 544 + "wasi 0.14.2+wasi-0.2.4", 488 545 ] 489 546 490 547 [[package]] ··· 495 552 496 553 [[package]] 497 554 name = "hashbrown" 498 - version = "0.15.4" 555 + version = "0.15.5" 499 556 source = "registry+https://github.com/rust-lang/crates.io-index" 500 - checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" 557 + checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 501 558 502 559 [[package]] 503 560 name = "heck" ··· 521 578 522 579 [[package]] 523 580 name = "indenter" 524 - version = "0.3.3" 581 + version = "0.3.4" 525 582 source = "registry+https://github.com/rust-lang/crates.io-index" 526 - checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" 583 + checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" 527 584 528 585 [[package]] 529 586 name = "indexmap" 530 - version = "2.9.0" 587 + version = "2.10.0" 531 588 source = "registry+https://github.com/rust-lang/crates.io-index" 532 - checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 589 + checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" 533 590 dependencies = [ 534 591 "equivalent", 535 592 "hashbrown", ··· 545 602 ] 546 603 547 604 [[package]] 605 + name = "io-uring" 606 + version = "0.7.9" 607 + source = "registry+https://github.com/rust-lang/crates.io-index" 608 + checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" 609 + dependencies = [ 610 + "bitflags", 611 + "cfg-if", 612 + "libc", 613 + ] 614 + 615 + [[package]] 548 616 name = "is_terminal_polyfill" 549 617 version = "1.70.1" 550 618 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 557 625 checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 558 626 559 627 [[package]] 628 + name = "jobserver" 629 + version = "0.1.33" 630 + source = "registry+https://github.com/rust-lang/crates.io-index" 631 + checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" 632 + dependencies = [ 633 + "getrandom 0.3.3", 634 + "libc", 635 + ] 636 + 637 + [[package]] 560 638 name = "js-sys" 561 639 version = "0.3.77" 562 640 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 574 652 575 653 [[package]] 576 654 name = "libc" 577 - version = "0.2.174" 655 + version = "0.2.175" 578 656 source = "registry+https://github.com/rust-lang/crates.io-index" 579 - checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" 657 + checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" 580 658 581 659 [[package]] 582 660 name = "libredox" 583 - version = "0.1.4" 661 + version = "0.1.9" 584 662 source = "registry+https://github.com/rust-lang/crates.io-index" 585 - checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" 663 + checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" 586 664 dependencies = [ 587 665 "bitflags", 588 666 "libc", ··· 652 730 checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" 653 731 dependencies = [ 654 732 "libc", 655 - "wasi", 733 + "wasi 0.11.1+wasi-snapshot-preview1", 656 734 "windows-sys 0.59.0", 657 735 ] 658 736 ··· 780 858 "libc", 781 859 "redox_syscall", 782 860 "smallvec", 783 - "windows-targets", 861 + "windows-targets 0.52.6", 784 862 ] 785 863 786 864 [[package]] ··· 788 866 version = "0.2.16" 789 867 source = "registry+https://github.com/rust-lang/crates.io-index" 790 868 checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 869 + 870 + [[package]] 871 + name = "pkg-config" 872 + version = "0.3.32" 873 + source = "registry+https://github.com/rust-lang/crates.io-index" 874 + checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 791 875 792 876 [[package]] 793 877 name = "ppv-lite86" ··· 810 894 811 895 [[package]] 812 896 name = "proc-macro2" 813 - version = "1.0.95" 897 + version = "1.0.101" 814 898 source = "registry+https://github.com/rust-lang/crates.io-index" 815 - checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 899 + checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" 816 900 dependencies = [ 817 901 "unicode-ident", 818 902 ] ··· 825 909 dependencies = [ 826 910 "proc-macro2", 827 911 ] 912 + 913 + [[package]] 914 + name = "r-efi" 915 + version = "5.3.0" 916 + source = "registry+https://github.com/rust-lang/crates.io-index" 917 + checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 828 918 829 919 [[package]] 830 920 name = "rand" ··· 853 943 source = "registry+https://github.com/rust-lang/crates.io-index" 854 944 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 855 945 dependencies = [ 856 - "getrandom", 946 + "getrandom 0.2.16", 857 947 ] 858 948 859 949 [[package]] 860 950 name = "rayon" 861 - version = "1.10.0" 951 + version = "1.11.0" 862 952 source = "registry+https://github.com/rust-lang/crates.io-index" 863 - checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" 953 + checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" 864 954 dependencies = [ 865 955 "either", 866 956 "rayon-core", ··· 868 958 869 959 [[package]] 870 960 name = "rayon-core" 871 - version = "1.12.1" 961 + version = "1.13.0" 872 962 source = "registry+https://github.com/rust-lang/crates.io-index" 873 - checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" 963 + checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" 874 964 dependencies = [ 875 965 "crossbeam-deque", 876 966 "crossbeam-utils", ··· 878 968 879 969 [[package]] 880 970 name = "redox_syscall" 881 - version = "0.5.13" 971 + version = "0.5.17" 882 972 source = "registry+https://github.com/rust-lang/crates.io-index" 883 - checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" 973 + checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" 884 974 dependencies = [ 885 975 "bitflags", 886 976 ] ··· 931 1021 932 1022 [[package]] 933 1023 name = "rustc-demangle" 934 - version = "0.1.25" 1024 + version = "0.1.26" 935 1025 source = "registry+https://github.com/rust-lang/crates.io-index" 936 - checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" 1026 + checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" 937 1027 938 1028 [[package]] 939 1029 name = "rustversion" 940 - version = "1.0.21" 1030 + version = "1.0.22" 941 1031 source = "registry+https://github.com/rust-lang/crates.io-index" 942 - checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" 1032 + checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" 943 1033 944 1034 [[package]] 945 1035 name = "ryu" ··· 979 1069 dependencies = [ 980 1070 "proc-macro2", 981 1071 "quote", 982 - "syn 2.0.104", 1072 + "syn 2.0.106", 983 1073 ] 984 1074 985 1075 [[package]] 986 1076 name = "serde_json" 987 - version = "1.0.140" 1077 + version = "1.0.142" 988 1078 source = "registry+https://github.com/rust-lang/crates.io-index" 989 - checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 1079 + checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" 990 1080 dependencies = [ 991 1081 "itoa", 992 1082 "memchr", ··· 1015 1105 ] 1016 1106 1017 1107 [[package]] 1108 + name = "shlex" 1109 + version = "1.3.0" 1110 + source = "registry+https://github.com/rust-lang/crates.io-index" 1111 + checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1112 + 1113 + [[package]] 1018 1114 name = "signal-hook-registry" 1019 - version = "1.4.5" 1115 + version = "1.4.6" 1020 1116 source = "registry+https://github.com/rust-lang/crates.io-index" 1021 - checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" 1117 + checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" 1022 1118 dependencies = [ 1023 1119 "libc", 1024 1120 ] 1025 1121 1026 1122 [[package]] 1123 + name = "slab" 1124 + version = "0.4.11" 1125 + source = "registry+https://github.com/rust-lang/crates.io-index" 1126 + checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" 1127 + 1128 + [[package]] 1129 + name = "slimeball-lib" 1130 + version = "0.1.0" 1131 + source = "git+https://github.com/xoogware/slimeball.git#39ea241ffafc90cde5745257f246bd0dc75c4775" 1132 + dependencies = [ 1133 + "byteorder", 1134 + "fastnbt", 1135 + "serde", 1136 + "thiserror 2.0.16", 1137 + "tracing", 1138 + "zstd", 1139 + ] 1140 + 1141 + [[package]] 1027 1142 name = "smallvec" 1028 1143 version = "1.15.1" 1029 1144 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1031 1146 1032 1147 [[package]] 1033 1148 name = "socket2" 1034 - version = "0.5.10" 1149 + version = "0.6.0" 1035 1150 source = "registry+https://github.com/rust-lang/crates.io-index" 1036 - checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" 1151 + checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" 1037 1152 dependencies = [ 1038 1153 "libc", 1039 - "windows-sys 0.52.0", 1154 + "windows-sys 0.59.0", 1040 1155 ] 1041 1156 1042 1157 [[package]] ··· 1064 1179 1065 1180 [[package]] 1066 1181 name = "syn" 1067 - version = "2.0.104" 1182 + version = "2.0.106" 1068 1183 source = "registry+https://github.com/rust-lang/crates.io-index" 1069 - checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" 1184 + checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" 1070 1185 dependencies = [ 1071 1186 "proc-macro2", 1072 1187 "quote", ··· 1089 1204 source = "registry+https://github.com/rust-lang/crates.io-index" 1090 1205 checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1091 1206 dependencies = [ 1092 - "thiserror-impl", 1207 + "thiserror-impl 1.0.69", 1208 + ] 1209 + 1210 + [[package]] 1211 + name = "thiserror" 1212 + version = "2.0.16" 1213 + source = "registry+https://github.com/rust-lang/crates.io-index" 1214 + checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" 1215 + dependencies = [ 1216 + "thiserror-impl 2.0.16", 1093 1217 ] 1094 1218 1095 1219 [[package]] ··· 1100 1224 dependencies = [ 1101 1225 "proc-macro2", 1102 1226 "quote", 1103 - "syn 2.0.104", 1227 + "syn 2.0.106", 1228 + ] 1229 + 1230 + [[package]] 1231 + name = "thiserror-impl" 1232 + version = "2.0.16" 1233 + source = "registry+https://github.com/rust-lang/crates.io-index" 1234 + checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" 1235 + dependencies = [ 1236 + "proc-macro2", 1237 + "quote", 1238 + "syn 2.0.106", 1104 1239 ] 1105 1240 1106 1241 [[package]] ··· 1114 1249 1115 1250 [[package]] 1116 1251 name = "tokio" 1117 - version = "1.45.1" 1252 + version = "1.47.1" 1118 1253 source = "registry+https://github.com/rust-lang/crates.io-index" 1119 - checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" 1254 + checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" 1120 1255 dependencies = [ 1121 1256 "backtrace", 1122 1257 "bytes", 1258 + "io-uring", 1123 1259 "libc", 1124 1260 "mio", 1125 1261 "parking_lot", 1126 1262 "pin-project-lite", 1127 1263 "signal-hook-registry", 1264 + "slab", 1128 1265 "socket2", 1129 1266 "tokio-macros", 1130 - "windows-sys 0.52.0", 1267 + "windows-sys 0.59.0", 1131 1268 ] 1132 1269 1133 1270 [[package]] ··· 1138 1275 dependencies = [ 1139 1276 "proc-macro2", 1140 1277 "quote", 1141 - "syn 2.0.104", 1278 + "syn 2.0.106", 1142 1279 ] 1143 1280 1144 1281 [[package]] 1145 1282 name = "tokio-util" 1146 - version = "0.7.15" 1283 + version = "0.7.16" 1147 1284 source = "registry+https://github.com/rust-lang/crates.io-index" 1148 - checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" 1285 + checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" 1149 1286 dependencies = [ 1150 1287 "bytes", 1151 1288 "futures-core", ··· 1190 1327 dependencies = [ 1191 1328 "proc-macro2", 1192 1329 "quote", 1193 - "syn 2.0.104", 1330 + "syn 2.0.106", 1194 1331 ] 1195 1332 1196 1333 [[package]] ··· 1272 1409 1273 1410 [[package]] 1274 1411 name = "uuid" 1275 - version = "1.17.0" 1412 + version = "1.18.0" 1276 1413 source = "registry+https://github.com/rust-lang/crates.io-index" 1277 - checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" 1414 + checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" 1278 1415 dependencies = [ 1279 1416 "js-sys", 1280 1417 "wasm-bindgen", ··· 1299 1436 checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 1300 1437 1301 1438 [[package]] 1439 + name = "wasi" 1440 + version = "0.14.2+wasi-0.2.4" 1441 + source = "registry+https://github.com/rust-lang/crates.io-index" 1442 + checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" 1443 + dependencies = [ 1444 + "wit-bindgen-rt", 1445 + ] 1446 + 1447 + [[package]] 1302 1448 name = "wasm-bindgen" 1303 1449 version = "0.2.100" 1304 1450 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1320 1466 "log", 1321 1467 "proc-macro2", 1322 1468 "quote", 1323 - "syn 2.0.104", 1469 + "syn 2.0.106", 1324 1470 "wasm-bindgen-shared", 1325 1471 ] 1326 1472 ··· 1342 1488 dependencies = [ 1343 1489 "proc-macro2", 1344 1490 "quote", 1345 - "syn 2.0.104", 1491 + "syn 2.0.106", 1346 1492 "wasm-bindgen-backend", 1347 1493 "wasm-bindgen-shared", 1348 1494 ] ··· 1379 1525 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1380 1526 1381 1527 [[package]] 1528 + name = "windows-link" 1529 + version = "0.1.3" 1530 + source = "registry+https://github.com/rust-lang/crates.io-index" 1531 + checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" 1532 + 1533 + [[package]] 1382 1534 name = "windows-sys" 1383 - version = "0.52.0" 1535 + version = "0.59.0" 1384 1536 source = "registry+https://github.com/rust-lang/crates.io-index" 1385 - checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1537 + checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1386 1538 dependencies = [ 1387 - "windows-targets", 1539 + "windows-targets 0.52.6", 1388 1540 ] 1389 1541 1390 1542 [[package]] 1391 1543 name = "windows-sys" 1392 - version = "0.59.0" 1544 + version = "0.60.2" 1393 1545 source = "registry+https://github.com/rust-lang/crates.io-index" 1394 - checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1546 + checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 1395 1547 dependencies = [ 1396 - "windows-targets", 1548 + "windows-targets 0.53.3", 1397 1549 ] 1398 1550 1399 1551 [[package]] ··· 1402 1554 source = "registry+https://github.com/rust-lang/crates.io-index" 1403 1555 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1404 1556 dependencies = [ 1405 - "windows_aarch64_gnullvm", 1406 - "windows_aarch64_msvc", 1407 - "windows_i686_gnu", 1408 - "windows_i686_gnullvm", 1409 - "windows_i686_msvc", 1410 - "windows_x86_64_gnu", 1411 - "windows_x86_64_gnullvm", 1412 - "windows_x86_64_msvc", 1557 + "windows_aarch64_gnullvm 0.52.6", 1558 + "windows_aarch64_msvc 0.52.6", 1559 + "windows_i686_gnu 0.52.6", 1560 + "windows_i686_gnullvm 0.52.6", 1561 + "windows_i686_msvc 0.52.6", 1562 + "windows_x86_64_gnu 0.52.6", 1563 + "windows_x86_64_gnullvm 0.52.6", 1564 + "windows_x86_64_msvc 0.52.6", 1565 + ] 1566 + 1567 + [[package]] 1568 + name = "windows-targets" 1569 + version = "0.53.3" 1570 + source = "registry+https://github.com/rust-lang/crates.io-index" 1571 + checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" 1572 + dependencies = [ 1573 + "windows-link", 1574 + "windows_aarch64_gnullvm 0.53.0", 1575 + "windows_aarch64_msvc 0.53.0", 1576 + "windows_i686_gnu 0.53.0", 1577 + "windows_i686_gnullvm 0.53.0", 1578 + "windows_i686_msvc 0.53.0", 1579 + "windows_x86_64_gnu 0.53.0", 1580 + "windows_x86_64_gnullvm 0.53.0", 1581 + "windows_x86_64_msvc 0.53.0", 1413 1582 ] 1414 1583 1415 1584 [[package]] ··· 1417 1586 version = "0.52.6" 1418 1587 source = "registry+https://github.com/rust-lang/crates.io-index" 1419 1588 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1589 + 1590 + [[package]] 1591 + name = "windows_aarch64_gnullvm" 1592 + version = "0.53.0" 1593 + source = "registry+https://github.com/rust-lang/crates.io-index" 1594 + checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" 1420 1595 1421 1596 [[package]] 1422 1597 name = "windows_aarch64_msvc" ··· 1425 1600 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1426 1601 1427 1602 [[package]] 1603 + name = "windows_aarch64_msvc" 1604 + version = "0.53.0" 1605 + source = "registry+https://github.com/rust-lang/crates.io-index" 1606 + checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" 1607 + 1608 + [[package]] 1428 1609 name = "windows_i686_gnu" 1429 1610 version = "0.52.6" 1430 1611 source = "registry+https://github.com/rust-lang/crates.io-index" 1431 1612 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1432 1613 1433 1614 [[package]] 1615 + name = "windows_i686_gnu" 1616 + version = "0.53.0" 1617 + source = "registry+https://github.com/rust-lang/crates.io-index" 1618 + checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" 1619 + 1620 + [[package]] 1434 1621 name = "windows_i686_gnullvm" 1435 1622 version = "0.52.6" 1436 1623 source = "registry+https://github.com/rust-lang/crates.io-index" 1437 1624 checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1438 1625 1439 1626 [[package]] 1627 + name = "windows_i686_gnullvm" 1628 + version = "0.53.0" 1629 + source = "registry+https://github.com/rust-lang/crates.io-index" 1630 + checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" 1631 + 1632 + [[package]] 1440 1633 name = "windows_i686_msvc" 1441 1634 version = "0.52.6" 1442 1635 source = "registry+https://github.com/rust-lang/crates.io-index" 1443 1636 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1444 1637 1445 1638 [[package]] 1639 + name = "windows_i686_msvc" 1640 + version = "0.53.0" 1641 + source = "registry+https://github.com/rust-lang/crates.io-index" 1642 + checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" 1643 + 1644 + [[package]] 1446 1645 name = "windows_x86_64_gnu" 1447 1646 version = "0.52.6" 1448 1647 source = "registry+https://github.com/rust-lang/crates.io-index" 1449 1648 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1450 1649 1451 1650 [[package]] 1651 + name = "windows_x86_64_gnu" 1652 + version = "0.53.0" 1653 + source = "registry+https://github.com/rust-lang/crates.io-index" 1654 + checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" 1655 + 1656 + [[package]] 1452 1657 name = "windows_x86_64_gnullvm" 1453 1658 version = "0.52.6" 1454 1659 source = "registry+https://github.com/rust-lang/crates.io-index" 1455 1660 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1456 1661 1457 1662 [[package]] 1663 + name = "windows_x86_64_gnullvm" 1664 + version = "0.53.0" 1665 + source = "registry+https://github.com/rust-lang/crates.io-index" 1666 + checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" 1667 + 1668 + [[package]] 1458 1669 name = "windows_x86_64_msvc" 1459 1670 version = "0.52.6" 1460 1671 source = "registry+https://github.com/rust-lang/crates.io-index" 1461 1672 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1462 1673 1463 1674 [[package]] 1675 + name = "windows_x86_64_msvc" 1676 + version = "0.53.0" 1677 + source = "registry+https://github.com/rust-lang/crates.io-index" 1678 + checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" 1679 + 1680 + [[package]] 1464 1681 name = "winnow" 1465 1682 version = "0.5.40" 1466 1683 source = "registry+https://github.com/rust-lang/crates.io-index" 1467 1684 checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" 1468 1685 dependencies = [ 1469 1686 "memchr", 1687 + ] 1688 + 1689 + [[package]] 1690 + name = "wit-bindgen-rt" 1691 + version = "0.39.0" 1692 + source = "registry+https://github.com/rust-lang/crates.io-index" 1693 + checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 1694 + dependencies = [ 1695 + "bitflags", 1470 1696 ] 1471 1697 1472 1698 [[package]] ··· 1486 1712 dependencies = [ 1487 1713 "proc-macro2", 1488 1714 "quote", 1489 - "syn 2.0.104", 1715 + "syn 2.0.106", 1716 + ] 1717 + 1718 + [[package]] 1719 + name = "zstd" 1720 + version = "0.13.3" 1721 + source = "registry+https://github.com/rust-lang/crates.io-index" 1722 + checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" 1723 + dependencies = [ 1724 + "zstd-safe", 1725 + ] 1726 + 1727 + [[package]] 1728 + name = "zstd-safe" 1729 + version = "7.2.4" 1730 + source = "registry+https://github.com/rust-lang/crates.io-index" 1731 + checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" 1732 + dependencies = [ 1733 + "zstd-sys", 1734 + ] 1735 + 1736 + [[package]] 1737 + name = "zstd-sys" 1738 + version = "2.0.15+zstd.1.5.7" 1739 + source = "registry+https://github.com/rust-lang/crates.io-index" 1740 + checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" 1741 + dependencies = [ 1742 + "cc", 1743 + "pkg-config", 1490 1744 ]
+1 -1
Cargo.toml
··· 1 1 [workspace] 2 2 resolver = "2" 3 - members = [ "crawlspace-macro","crawlspace"] 3 + members = [ "crawlspace-macro","crawlspace" , "crawlspace-proto", "crawlspace-proto-1_8"] 4 4 5 5 [profile.release-stripped] 6 6 inherits = "release"
+1
crawlspace/Cargo.toml
··· 45 45 tracing = { version = "0.1.40", features = ["max_level_trace", "release_max_level_info"] } 46 46 tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } 47 47 uuid = "1.11.0" 48 + slimeball-lib = { git = "https://github.com/xoogware/slimeball.git" } 48 49 49 50 [features] 50 51 default = []
+1 -1
crawlspace/src/main.rs
··· 77 77 let state = Arc::new(state::State::new(VERSION, VERSION_NUM, args)); 78 78 79 79 info!("Generating world chunk packets"); 80 - let world_cache = WorldCache::from_anvil(state.clone(), &world); 80 + let world_cache = WorldCache::from_slime(state.clone(), world); 81 81 info!("Done."); 82 82 83 83 #[cfg(feature = "lan")]
+75
crawlspace/src/net/cache.rs
··· 41 41 } 42 42 43 43 impl WorldCache { 44 + pub fn from_slime(state: CrawlState, world: slimeball_lib::SlimeWorld) -> Self { 45 + let mut chunks = world.chunks; 46 + chunks.sort_by(|a, b| { 47 + if (a.x + a.z) > (b.x + b.z) { 48 + Ordering::Greater 49 + } else { 50 + Ordering::Less 51 + } 52 + }); 53 + 54 + let block_states = Blocks::new(); 55 + let containers = chunks 56 + .iter() 57 + .flat_map(|c| 58 + c.tile_entities 59 + .iter() 60 + .filter_map(|e| { 61 + let block_entity = BlockEntity::try_parse(e.clone()).map_or_else( 62 + |why| { 63 + warn!( 64 + "failed to parse block entity: {why}, ignoring in container cache for ({}, {})", 65 + c.x, 66 + c.z 67 + ); 68 + None 69 + }, 70 + |e| match e.keep_packed { 71 + true => None, 72 + false => Some(e), 73 + }, 74 + ); 75 + 76 + let block_entity = block_entity?; 77 + 78 + match block_entity.id.as_str() { 79 + "minecraft:chest" | "minecraft:trapped_chest" | "minecraft:barrel" => { 80 + Some(block_entity) 81 + } 82 + _ => None, 83 + } 84 + }) 85 + .map(|container| { 86 + ( 87 + (container.x, container.y, container.z), 88 + Container::try_from(container) 89 + .expect("Failed to convert container from block entity NBT"), 90 + ) 91 + }) 92 + .collect::<Vec<((i32, i32, i32), Container)>>() 93 + ) 94 + .collect(); 95 + 96 + debug!("Containers: {:?}", containers); 97 + 98 + let encoded = chunks 99 + .par_iter() 100 + .map(|chunk| { 101 + let mut encoder = Encoder::new(); 102 + encoder 103 + .append_packet(&ChunkDataUpdateLightC::from_slime( 104 + state.clone(), 105 + chunk, 106 + &block_states, 107 + )) 108 + .expect("Failed to append packet to encoder"); 109 + encoder.take().to_vec() 110 + }) 111 + .collect(); 112 + 113 + Self { 114 + encoded, 115 + containers, 116 + } 117 + } 118 + 44 119 pub fn from_anvil(crawlstate: CrawlState, world: &World) -> Self { 45 120 let mut chunks = world.0.iter().collect::<Vec<_>>(); 46 121
-258
crawlspace/src/protocol/datatypes/impls.rs
··· 1 - /* 2 - * Copyright (c) 2024 Andrew Brower. 3 - * This file is part of Crawlspace. 4 - * 5 - * Crawlspace is free software: you can redistribute it and/or 6 - * modify it under the terms of the GNU Affero General Public 7 - * License as published by the Free Software Foundation, either 8 - * version 3 of the License, or (at your option) any later version. 9 - * 10 - * Crawlspace is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 - * Affero General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Affero General Public 16 - * License along with Crawlspace. If not, see 17 - * <https://www.gnu.org/licenses/>. 18 - */ 19 - 20 - use std::mem; 21 - 22 - use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; 23 - use color_eyre::eyre::{bail, Result}; 24 - use uuid::Uuid; 25 - 26 - use crate::protocol::{Decode, DecodeSized, Encode}; 27 - 28 - impl<'a> Decode<'a> for bool { 29 - fn decode(r: &mut &'a [u8]) -> Result<Self> { 30 - Ok(match r.read_u8()? { 31 - 0x01 => true, 32 - 0x00 => false, 33 - v => bail!("Expected 0x01 or 0x00 for bool, got {v}"), 34 - }) 35 - } 36 - } 37 - 38 - impl Encode for bool { 39 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 40 - let v = match self { 41 - true => 0x01, 42 - false => 0x00, 43 - }; 44 - 45 - Ok(w.write_all(&[v])?) 46 - } 47 - } 48 - 49 - impl<'a> Decode<'a> for i8 { 50 - fn decode(r: &mut &'a [u8]) -> Result<Self> 51 - where 52 - Self: Sized, 53 - { 54 - Ok(r.read_i8()?) 55 - } 56 - } 57 - 58 - impl Encode for i8 { 59 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 60 - Ok(w.write_i8(*self)?) 61 - } 62 - } 63 - 64 - impl<'a> Decode<'a> for u8 { 65 - fn decode(r: &mut &'a [u8]) -> Result<Self> 66 - where 67 - Self: Sized, 68 - { 69 - Ok(r.read_u8()?) 70 - } 71 - } 72 - 73 - impl Encode for u8 { 74 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 75 - Ok(w.write_u8(*self)?) 76 - } 77 - } 78 - 79 - impl<'a> Decode<'a> for i16 { 80 - fn decode(r: &mut &'a [u8]) -> Result<Self> 81 - where 82 - Self: Sized, 83 - { 84 - Ok(r.read_i16::<BigEndian>()?) 85 - } 86 - } 87 - 88 - impl Encode for i16 { 89 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 90 - Ok(w.write_i16::<BigEndian>(*self)?) 91 - } 92 - } 93 - 94 - impl<'a> Decode<'a> for u16 { 95 - fn decode(r: &mut &'a [u8]) -> Result<Self> 96 - where 97 - Self: Sized, 98 - { 99 - Ok(r.read_u16::<BigEndian>()?) 100 - } 101 - } 102 - 103 - impl<'a> Decode<'a> for i32 { 104 - fn decode(r: &mut &'a [u8]) -> Result<Self> 105 - where 106 - Self: Sized, 107 - { 108 - Ok(r.read_i32::<BigEndian>()?) 109 - } 110 - } 111 - 112 - impl Encode for i32 { 113 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 114 - Ok(w.write_i32::<BigEndian>(*self)?) 115 - } 116 - } 117 - 118 - impl<'a> Decode<'a> for i64 { 119 - fn decode(r: &mut &'a [u8]) -> Result<Self> 120 - where 121 - Self: Sized, 122 - { 123 - Ok(r.read_i64::<BigEndian>()?) 124 - } 125 - } 126 - 127 - impl Encode for i64 { 128 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 129 - Ok(w.write_i64::<BigEndian>(*self)?) 130 - } 131 - } 132 - 133 - impl<'a> Decode<'a> for u64 { 134 - fn decode(r: &mut &'a [u8]) -> Result<Self> 135 - where 136 - Self: Sized, 137 - { 138 - Ok(r.read_u64::<BigEndian>()?) 139 - } 140 - } 141 - 142 - impl Encode for u64 { 143 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 144 - Ok(w.write_u64::<BigEndian>(*self)?) 145 - } 146 - } 147 - 148 - impl<'a> Decode<'a> for u128 { 149 - fn decode(r: &mut &'a [u8]) -> Result<Self> 150 - where 151 - Self: Sized, 152 - { 153 - Ok(r.read_u128::<BigEndian>()?) 154 - } 155 - } 156 - 157 - impl Encode for u128 { 158 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 159 - Ok(w.write_u128::<BigEndian>(*self)?) 160 - } 161 - } 162 - 163 - impl<'a> Decode<'a> for f32 { 164 - fn decode(r: &mut &'a [u8]) -> Result<Self> 165 - where 166 - Self: Sized, 167 - { 168 - Ok(r.read_f32::<BigEndian>()?) 169 - } 170 - } 171 - 172 - impl Encode for f32 { 173 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 174 - Ok(w.write_f32::<BigEndian>(*self)?) 175 - } 176 - } 177 - 178 - impl<'a> Decode<'a> for f64 { 179 - fn decode(r: &mut &'a [u8]) -> Result<Self> 180 - where 181 - Self: Sized, 182 - { 183 - Ok(r.read_f64::<BigEndian>()?) 184 - } 185 - } 186 - 187 - impl Encode for f64 { 188 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 189 - Ok(w.write_f64::<BigEndian>(*self)?) 190 - } 191 - } 192 - 193 - impl Encode for Uuid { 194 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 195 - self.as_u128().encode(&mut w) 196 - } 197 - } 198 - 199 - impl<'a> Decode<'a> for Uuid { 200 - fn decode(r: &mut &'a [u8]) -> Result<Self> { 201 - Ok(Uuid::from_u128(r.read_u128::<BigEndian>()?)) 202 - } 203 - } 204 - 205 - impl<T> Encode for Option<T> 206 - where 207 - T: Encode, 208 - { 209 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 210 - match self { 211 - None => Ok(()), 212 - Some(v) => v.encode(&mut w), 213 - } 214 - } 215 - } 216 - 217 - impl<T> Encode for Vec<T> 218 - where 219 - T: Encode, 220 - { 221 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 222 - for item in self { 223 - item.encode(&mut w)?; 224 - } 225 - 226 - Ok(()) 227 - } 228 - } 229 - 230 - impl<'a, T> DecodeSized<'a> for Vec<T> 231 - where 232 - T: Decode<'a>, 233 - { 234 - fn decode(times: usize, r: &mut &'a [u8]) -> Result<Self> { 235 - let mut o = Vec::new(); 236 - 237 - for _ in 0..times { 238 - o.push(T::decode(r)?) 239 - } 240 - 241 - Ok(o) 242 - } 243 - } 244 - 245 - #[derive(Debug)] 246 - pub struct Bytes<'a>(pub &'a [u8]); 247 - 248 - impl<'a> Decode<'a> for Bytes<'a> { 249 - fn decode(r: &mut &'a [u8]) -> Result<Self> { 250 - Ok(Self(mem::take(r))) 251 - } 252 - } 253 - 254 - impl<'a> Encode for Bytes<'a> { 255 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 256 - Ok(w.write_all(self.0)?) 257 - } 258 - }
-109
crawlspace/src/protocol/datatypes/position.rs
··· 1 - /* 2 - * Copyright (c) 2024 Andrew Brower. 3 - * This file is part of Crawlspace. 4 - * 5 - * Crawlspace is free software: you can redistribute it and/or 6 - * modify it under the terms of the GNU Affero General Public 7 - * License as published by the Free Software Foundation, either 8 - * version 3 of the License, or (at your option) any later version. 9 - * 10 - * Crawlspace is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 - * Affero General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Affero General Public 16 - * License along with Crawlspace. If not, see 17 - * <https://www.gnu.org/licenses/>. 18 - */ 19 - 20 - use bitfield_struct::bitfield; 21 - use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; 22 - use color_eyre::eyre::Result; 23 - use thiserror::Error; 24 - 25 - use crate::protocol::{Decode, Encode}; 26 - 27 - #[derive(Debug)] 28 - pub struct Position { 29 - pub x: i32, 30 - pub y: i32, 31 - pub z: i32, 32 - } 33 - 34 - #[bitfield(u64)] 35 - pub struct PackedPosition { 36 - #[bits(26)] 37 - pub x: i32, 38 - #[bits(26)] 39 - pub z: i32, 40 - #[bits(12)] 41 - pub y: i32, 42 - } 43 - 44 - impl Position { 45 - #[must_use] 46 - pub fn new(x: i32, y: i32, z: i32) -> Self { 47 - Self { x, y, z } 48 - } 49 - } 50 - 51 - #[derive(Debug, Error)] 52 - pub enum EncodingError { 53 - #[error("value is out of bounds")] 54 - OutOfBounds, 55 - } 56 - 57 - impl TryFrom<&Position> for PackedPosition { 58 - type Error = EncodingError; 59 - 60 - fn try_from(value: &Position) -> std::result::Result<Self, Self::Error> { 61 - match (value.x, value.y, value.z) { 62 - (-0x2000000..=0x1ffffff, -0x800..=0x7ff, -0x2000000..=0x1ffffff) => { 63 - Ok(PackedPosition::new() 64 - .with_x(value.x) 65 - .with_y(value.y) 66 - .with_z(value.z)) 67 - } 68 - _ => Err(EncodingError::OutOfBounds), 69 - } 70 - } 71 - } 72 - 73 - impl From<PackedPosition> for Position { 74 - fn from(value: PackedPosition) -> Self { 75 - Self { 76 - x: value.x(), 77 - y: value.y(), 78 - z: value.z(), 79 - } 80 - } 81 - } 82 - 83 - impl Encode for Position { 84 - fn encode(&self, w: impl std::io::Write) -> Result<()> { 85 - let encoded: PackedPosition = self.try_into()?; 86 - encoded.encode(w) 87 - } 88 - } 89 - 90 - impl Decode<'_> for Position { 91 - fn decode(r: &mut &'_ [u8]) -> Result<Self> 92 - where 93 - Self: Sized, 94 - { 95 - let bytes = r.read_i64::<BigEndian>()?; 96 - 97 - Ok(Self { 98 - x: (bytes >> 38) as i32, 99 - y: (bytes << 52 >> 52) as i32, 100 - z: (bytes << 26 >> 38) as i32, 101 - }) 102 - } 103 - } 104 - 105 - impl Encode for PackedPosition { 106 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 107 - Ok(w.write_u64::<BigEndian>(self.0)?) 108 - } 109 - }
-97
crawlspace/src/protocol/datatypes/slot.rs
··· 1 - /* 2 - * Copyright (c) 2024 Andrew Brower. 3 - * This file is part of Crawlspace. 4 - * 5 - * Crawlspace is free software: you can redistribute it and/or 6 - * modify it under the terms of the GNU Affero General Public 7 - * License as published by the Free Software Foundation, either 8 - * version 3 of the License, or (at your option) any later version. 9 - * 10 - * Crawlspace is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 - * Affero General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Affero General Public 16 - * License along with Crawlspace. If not, see 17 - * <https://www.gnu.org/licenses/>. 18 - */ 19 - 20 - use crate::{protocol::Encode, server::registries::REGISTRIES, world::Item}; 21 - 22 - use super::VarInt; 23 - 24 - #[derive(Debug, Clone, Default)] 25 - pub struct Slot { 26 - item_count: i8, 27 - item_id: Option<i32>, 28 - components_to_add: Option<Vec<Component>>, 29 - components_to_remove: Option<Vec<i32>>, 30 - } 31 - 32 - #[derive(Debug, Clone)] 33 - pub enum Component {} 34 - 35 - impl From<Item> for Slot { 36 - fn from(value: Item) -> Self { 37 - let item_id = REGISTRIES 38 - .item 39 - .entries 40 - .get(&value.id) 41 - .expect("Couldn't find registry entry for item") 42 - .protocol_id; 43 - 44 - debug!("item id for {}: {item_id}", value.id); 45 - 46 - Self { 47 - item_count: value.count as i8, 48 - item_id: Some(item_id), 49 - components_to_add: None, 50 - components_to_remove: None, 51 - } 52 - } 53 - } 54 - 55 - impl Encode for Slot { 56 - fn encode(&self, mut w: impl std::io::Write) -> color_eyre::eyre::Result<()> { 57 - self.item_count.encode(&mut w)?; 58 - 59 - if self.item_count == 0 { 60 - return Ok(()); 61 - } 62 - 63 - if let Some(item_id) = self.item_id { 64 - VarInt(item_id).encode(&mut w)?; 65 - 66 - VarInt( 67 - self.components_to_add 68 - .as_ref() 69 - .map(|v| v.len()) 70 - .unwrap_or(0) as i32, 71 - ) 72 - .encode(&mut w)?; 73 - 74 - VarInt( 75 - self.components_to_remove 76 - .as_ref() 77 - .map(|v| v.len()) 78 - .unwrap_or(0) as i32, 79 - ) 80 - .encode(&mut w)?; 81 - 82 - if let Some(ref components_to_add) = self.components_to_add { 83 - for _component in components_to_add { 84 - unimplemented!("Encoding components is not implemented"); 85 - } 86 - } 87 - 88 - if let Some(ref components_to_remove) = self.components_to_remove { 89 - for _component in components_to_remove { 90 - unimplemented!("Encoding components is not implemented"); 91 - } 92 - } 93 - } 94 - 95 - Ok(()) 96 - } 97 - }
-165
crawlspace/src/protocol/datatypes/string.rs
··· 1 - /* 2 - * Copyright (c) 2024 Andrew Brower. 3 - * This file is part of Crawlspace. 4 - * 5 - * Crawlspace is free software: you can redistribute it and/or 6 - * modify it under the terms of the GNU Affero General Public 7 - * License as published by the Free Software Foundation, either 8 - * version 3 of the License, or (at your option) any later version. 9 - * 10 - * Crawlspace is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 - * Affero General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Affero General Public 16 - * License along with Crawlspace. If not, see 17 - * <https://www.gnu.org/licenses/>. 18 - */ 19 - 20 - use color_eyre::eyre::{ensure, Result}; 21 - 22 - use crate::protocol::{Decode, Encode}; 23 - 24 - use super::{Bytes, VarInt}; 25 - 26 - #[derive(Debug)] 27 - pub struct Bounded<T, const BOUND: usize = 32767>(pub T); 28 - 29 - impl<'a, const BOUND: usize> Decode<'a> for Bounded<&'a str, BOUND> { 30 - fn decode(r: &mut &'a [u8]) -> Result<Self> { 31 - let len = VarInt::decode(r)?.0; 32 - ensure!(len >= 0, "tried to decode string with negative length"); 33 - 34 - let len = len as usize; 35 - ensure!( 36 - len <= r.len(), 37 - "malformed packet - not enough data to continue decoding (expected {len} got {})", 38 - r.len(), 39 - ); 40 - 41 - let (content, rest) = r.split_at(len); 42 - let content = std::str::from_utf8(content)?; 43 - let utf16_len = content.encode_utf16().count(); 44 - 45 - ensure!( 46 - utf16_len <= BOUND, 47 - "utf-16 encoded string exceeds {BOUND} chars (is {utf16_len})" 48 - ); 49 - 50 - *r = rest; 51 - 52 - Ok(Bounded(content)) 53 - } 54 - } 55 - 56 - impl<'a, const BOUND: usize> Encode for Bounded<&'a str, BOUND> { 57 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 58 - let len = self.0.encode_utf16().count(); 59 - 60 - ensure!(len <= BOUND, "length of string {len} exceeds bound {BOUND}"); 61 - 62 - VarInt(self.0.len() as i32).encode(&mut w)?; 63 - Ok(w.write_all(self.0.as_bytes())?) 64 - } 65 - } 66 - 67 - impl Encode for str { 68 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 69 - VarInt(self.len() as i32).encode(&mut w)?; 70 - Ok(w.write_all(self.as_bytes())?) 71 - } 72 - } 73 - 74 - impl<'a, const BOUND: usize> Encode for Bounded<Bytes<'a>, BOUND> { 75 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 76 - let len = self.0 .0.len(); 77 - ensure!(len <= BOUND, "length of bytes {len} exceeds bound {BOUND}"); 78 - VarInt(len as i32).encode(&mut w)?; 79 - self.0.encode(&mut w) 80 - } 81 - } 82 - 83 - impl<'a, const BOUND: usize> Decode<'a> for Bounded<Bytes<'a>, BOUND> { 84 - fn decode(r: &mut &'a [u8]) -> Result<Self> { 85 - let len = VarInt::decode(r)?.0; 86 - ensure!(len >= 0, "tried to decode string with negative length"); 87 - 88 - let len = len as usize; 89 - ensure!( 90 - len <= r.len(), 91 - "malformed packet - not enough data to continue decoding (expected {len} got {})", 92 - r.len(), 93 - ); 94 - 95 - let (mut content, rest) = r.split_at(len); 96 - let content = Bytes::decode(&mut content)?; 97 - let len = content.0.len(); 98 - 99 - ensure!( 100 - len <= BOUND, 101 - "raw byte length exceeds {BOUND} chars (is {len})" 102 - ); 103 - 104 - *r = rest; 105 - 106 - Ok(Bounded(content)) 107 - } 108 - } 109 - 110 - #[derive(Debug)] 111 - pub struct Rest<T, const BOUND: usize = 32767>(pub T); 112 - 113 - impl<'a, const BOUND: usize> Decode<'a> for Rest<&'a str, BOUND> { 114 - fn decode(r: &mut &'a [u8]) -> Result<Self> { 115 - let (content, rest) = r.split_at(r.len()); 116 - let content = std::str::from_utf8(content)?; 117 - let utf16_len = content.encode_utf16().count(); 118 - 119 - ensure!( 120 - utf16_len <= BOUND, 121 - "utf-16 encoded string exceeds {BOUND} chars (is {utf16_len})" 122 - ); 123 - 124 - *r = rest; 125 - 126 - Ok(Rest(content)) 127 - } 128 - } 129 - 130 - impl<'a, const BOUND: usize> Encode for Rest<&'a str, BOUND> { 131 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 132 - let len = self.0.encode_utf16().count(); 133 - 134 - ensure!(len <= BOUND, "length of string {len} exceeds bound {BOUND}"); 135 - 136 - Ok(w.write_all(self.0.as_bytes())?) 137 - } 138 - } 139 - 140 - impl<'a, const BOUND: usize> Encode for Rest<Bytes<'a>, BOUND> { 141 - fn encode(&self, mut w: impl std::io::Write) -> Result<()> { 142 - let len = self.0.0.len(); 143 - 144 - ensure!(len <= BOUND, "length of bytes {len} exceeds bound {BOUND}"); 145 - 146 - self.0.encode(&mut w) 147 - } 148 - } 149 - 150 - impl<'a, const BOUND: usize> Decode<'a> for Rest<Bytes<'a>, BOUND> { 151 - fn decode(r: &mut &'a [u8]) -> Result<Self> { 152 - let (mut content, rest) = r.split_at(r.len()); 153 - let content = Bytes::decode(&mut content)?; 154 - let len = content.0.len(); 155 - 156 - ensure!( 157 - len <= BOUND, 158 - "raw byte length exceeds {BOUND} chars (is {len})" 159 - ); 160 - 161 - *r = rest; 162 - 163 - Ok(Rest(content)) 164 - } 165 - }
-38
crawlspace/src/protocol/datatypes/text_component.rs
··· 1 - /* 2 - * Copyright (c) 2024 Andrew Brower. 3 - * This file is part of Crawlspace. 4 - * 5 - * Crawlspace is free software: you can redistribute it and/or 6 - * modify it under the terms of the GNU Affero General Public 7 - * License as published by the Free Software Foundation, either 8 - * version 3 of the License, or (at your option) any later version. 9 - * 10 - * Crawlspace is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 - * Affero General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Affero General Public 16 - * License along with Crawlspace. If not, see 17 - * <https://www.gnu.org/licenses/>. 18 - */ 19 - 20 - use serde::Serialize; 21 - 22 - #[derive(Debug, Clone, Serialize)] 23 - pub struct TextComponent { 24 - text: String, 25 - } 26 - 27 - impl From<String> for TextComponent { 28 - fn from(value: String) -> Self { 29 - Self { text: value } 30 - } 31 - } 32 - impl From<&str> for TextComponent { 33 - fn from(value: &str) -> Self { 34 - Self { 35 - text: value.to_owned(), 36 - } 37 - } 38 - }
-304
crawlspace/src/protocol/datatypes/variable.rs
··· 1 - /* 2 - * Copyright (c) 2024 Andrew Brower. 3 - * This file is part of Crawlspace. 4 - * 5 - * Crawlspace is free software: you can redistribute it and/or 6 - * modify it under the terms of the GNU Affero General Public 7 - * License as published by the Free Software Foundation, either 8 - * version 3 of the License, or (at your option) any later version. 9 - * 10 - * Crawlspace is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 - * Affero General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU Affero General Public 16 - * License along with Crawlspace. If not, see 17 - * <https://www.gnu.org/licenses/>. 18 - */ 19 - 20 - use std::fmt::Display; 21 - use std::io::Write; 22 - 23 - use byteorder::ReadBytesExt; 24 - use color_eyre::eyre::Result; 25 - use serde::Deserialize; 26 - 27 - use crate::protocol::{Decode, Encode}; 28 - 29 - #[derive(thiserror::Error, Debug)] 30 - pub enum VariableDecodeError { 31 - #[error("VarNum exceeds 32 bits")] 32 - TooLong, 33 - #[error("VarNum incomplete")] 34 - Incomplete, 35 - } 36 - 37 - pub trait VariableNumber<'a>: Sized + Encode + Decode<'a> { 38 - const SEGMENT_BITS: u8 = 0b01111111; 39 - const CONTINUE_BITS: u8 = 0b10000000; 40 - 41 - const MAX_BYTES: usize; 42 - 43 - fn len(self) -> usize; 44 - } 45 - 46 - macro_rules! make_var_num { 47 - ($name: ident, $type: ty, $max_bytes: expr) => { 48 - #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize)] 49 - #[serde(transparent)] 50 - pub struct $name(pub $type); 51 - 52 - impl VariableNumber<'_> for $name { 53 - const MAX_BYTES: usize = $max_bytes; 54 - 55 - fn len(self) -> usize { 56 - match self.0 { 57 - 0 => 1, 58 - n => (31 - n.leading_zeros() as usize) / 7 + 1, 59 - } 60 - } 61 - } 62 - 63 - impl Display for $name { 64 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 65 - write!(f, "{}", self.0) 66 - } 67 - } 68 - 69 - impl Decode<'_> for $name { 70 - fn decode(r: &mut &[u8]) -> Result<Self> { 71 - let mut v: $type = 0; 72 - 73 - for i in 0..Self::MAX_BYTES { 74 - let byte = r.read_u8().map_err(|_| VariableDecodeError::Incomplete)?; 75 - v |= <$type>::from(byte & Self::SEGMENT_BITS) << (i * 7); 76 - if byte & Self::CONTINUE_BITS == 0 { 77 - return Ok(Self(v)); 78 - } 79 - } 80 - 81 - if r.len() > 0 { 82 - Err(VariableDecodeError::TooLong)?; 83 - } 84 - 85 - Err(VariableDecodeError::Incomplete)? 86 - } 87 - } 88 - }; 89 - } 90 - 91 - make_var_num!(VarInt, i32, 5); 92 - make_var_num!(VarLong, i64, 10); 93 - 94 - impl Encode for VarInt { 95 - // implementation taken from https://github.com/as-com/varint-simd/blob/0f468783da8e181929b01b9c6e9f741c1fe09825/src/encode/mod.rs#L71 96 - // only the first branch is done here because we never need to change varint size 97 - fn encode(&self, mut w: impl Write) -> Result<()> { 98 - let x = self.0 as u64; 99 - let stage1 = (x & 0x000000000000007f) 100 - | ((x & 0x0000000000003f80) << 1) 101 - | ((x & 0x00000000001fc000) << 2) 102 - | ((x & 0x000000000fe00000) << 3) 103 - | ((x & 0x00000000f0000000) << 4); 104 - 105 - let leading = stage1.leading_zeros(); 106 - 107 - let unused_bytes = (leading - 1) / 8; 108 - let bytes_needed = 8 - unused_bytes; 109 - 110 - let msbs = 0x8080808080808080; 111 - let msbmask = 0xFFFFFFFFFFFFFFFF >> ((8 - bytes_needed + 1) * 8 - 1); 112 - 113 - let merged = stage1 | (msbs & msbmask); 114 - let bytes = merged.to_le_bytes(); 115 - 116 - Ok(w.write_all(unsafe { bytes.get_unchecked(..bytes_needed as usize) })?) 117 - } 118 - } 119 - 120 - impl VarLong { 121 - // how cute... 122 - #[inline(always)] 123 - #[cfg(target_feature = "bmi2")] 124 - fn num_to_vector_stage1(self) -> [u8; 16] { 125 - use std::arch::x86_64::*; 126 - let mut res = [0u64; 2]; 127 - 128 - let x = self.0 as u64; 129 - 130 - res[0] = unsafe { _pdep_u64(x, 0x7f7f7f7f7f7f7f7f) }; 131 - res[1] = unsafe { _pdep_u64(x >> 56, 0x000000000000017f) }; 132 - 133 - unsafe { core::mem::transmute(res) } 134 - } 135 - 136 - #[inline(always)] 137 - #[cfg(all(target_feature = "avx2", not(all(target_feature = "bmi2"))))] 138 - fn num_to_vector_stage1(self) -> [u8; 16] { 139 - use std::arch::x86_64::*; 140 - let mut res = [0u64; 2]; 141 - let x = self; 142 - 143 - let b = unsafe { _mm_set1_epi64x(self as i64) }; 144 - let c = unsafe { 145 - _mm_or_si128( 146 - _mm_or_si128( 147 - _mm_sllv_epi64( 148 - _mm_and_si128(b, _mm_set_epi64x(0x00000007f0000000, 0x000003f800000000)), 149 - _mm_set_epi64x(4, 5), 150 - ), 151 - _mm_sllv_epi64( 152 - _mm_and_si128(b, _mm_set_epi64x(0x0001fc0000000000, 0x00fe000000000000)), 153 - _mm_set_epi64x(6, 7), 154 - ), 155 - ), 156 - _mm_or_si128( 157 - _mm_sllv_epi64( 158 - _mm_and_si128(b, _mm_set_epi64x(0x000000000000007f, 0x0000000000003f80)), 159 - _mm_set_epi64x(0, 1), 160 - ), 161 - _mm_sllv_epi64( 162 - _mm_and_si128(b, _mm_set_epi64x(0x00000000001fc000, 0x000000000fe00000)), 163 - _mm_set_epi64x(2, 3), 164 - ), 165 - ), 166 - ) 167 - }; 168 - let d = unsafe { _mm_or_si128(c, _mm_bsrli_si128(c, 8)) }; 169 - 170 - res[0] = unsafe { _mm_extract_epi64(d, 0) as u64 }; 171 - res[1] = ((x & 0x7f00000000000000) >> 56) | ((x & 0x8000000000000000) >> 55); 172 - 173 - unsafe { core::mem::transmute(res) } 174 - } 175 - 176 - // TODO: need to confirm this works. for now it's just a naive translation of avx2, 177 - // but could definitely be improved -- blocking NEON implementation of Encode 178 - // 179 - // #[inline(always)] 180 - // #[cfg(target_feature = "neon")] 181 - // fn num_to_vector_stage1(self) -> [u8; 16] { 182 - // use std::arch::aarch64::*; 183 - // 184 - // let mut res = [0u64; 2]; 185 - // let x = self; 186 - // 187 - // let b = unsafe { vdupq_n_s64(self.0 as i64) }; 188 - // let c = unsafe { 189 - // vorrq_s64( 190 - // vorrq_s64( 191 - // vshlq_s64( 192 - // vandq_s64( 193 - // b, 194 - // vcombine_s64( 195 - // vcreate_s64(0x000003f800000000), 196 - // vcreate_s64(0x00000007f0000000), 197 - // ), 198 - // ), 199 - // vcombine_s64(vcreate_s64(5), vcreate_s64(4)), 200 - // ), 201 - // vshlq_s64( 202 - // vandq_s64( 203 - // b, 204 - // vcombine_s64( 205 - // vcreate_s64(0x00fe000000000000), 206 - // vcreate_s64(0x0001fc0000000000), 207 - // ), 208 - // ), 209 - // vcombine_s64(vcreate_s64(7), vcreate_s64(6)), 210 - // ), 211 - // ), 212 - // vorrq_s64( 213 - // vshlq_s64( 214 - // vandq_s64( 215 - // b, 216 - // vcombine_s64( 217 - // vcreate_s64(0x0000000000003f80), 218 - // vcreate_s64(0x000000000000007f), 219 - // ), 220 - // ), 221 - // vcombine_s64(vcreate_s64(1), vcreate_s64(0)), 222 - // ), 223 - // vshlq_s64( 224 - // vandq_s64( 225 - // b, 226 - // vcombine_s64( 227 - // vcreate_s64(0x000000000fe00000), 228 - // vcreate_s64(0x00000000001fc000), 229 - // ), 230 - // ), 231 - // vcombine_s64(vcreate_s64(3), vcreate_s64(2)), 232 - // ), 233 - // ), 234 - // ) 235 - // }; 236 - // let d = unsafe { vorrq_s64(c, vshrq_n_s64::<8>(c)) }; 237 - // 238 - // res[0] = unsafe { vgetq_lane_s64(d, 0) as u64 }; 239 - // res[1] = 240 - // ((x.0 as u64 & 0x7f00000000000000) >> 56) | ((x.0 as u64 & 0x8000000000000000) >> 55); 241 - // 242 - // unsafe { core::mem::transmute(res) } 243 - // } 244 - } 245 - 246 - impl Encode for VarLong { 247 - // ...and here's the second branch ^_^ 248 - #[cfg(any(target_feature = "bmi2", target_feature = "avx2"))] 249 - fn encode(&self, mut w: impl Write) -> Result<()> { 250 - use std::arch::x86_64::*; 251 - unsafe { 252 - // Break the number into 7-bit parts and spread them out into a vector 253 - let stage1: __m128i = std::mem::transmute(self.num_to_vector_stage1()); 254 - 255 - // Create a mask for where there exist values 256 - // This signed comparison works because all MSBs should be cleared at this point 257 - // Also handle the special case when num == 0 258 - let minimum = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffu8 as i8); 259 - let exists = _mm_or_si128(_mm_cmpgt_epi8(stage1, _mm_setzero_si128()), minimum); 260 - let bits = _mm_movemask_epi8(exists); 261 - 262 - // Count the number of bytes used 263 - let bytes = 32 - bits.leading_zeros() as u8; // lzcnt on supported CPUs 264 - 265 - // Fill that many bytes into a vector 266 - let ascend = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); 267 - let mask = _mm_cmplt_epi8(ascend, _mm_set1_epi8(bytes as i8)); 268 - 269 - // Shift it down 1 byte so the last MSB is the only one set, and make sure only the MSB is set 270 - let shift = _mm_bsrli_si128(mask, 1); 271 - let msbmask = _mm_and_si128(shift, _mm_set1_epi8(128u8 as i8)); 272 - 273 - // Merge the MSB bits into the vector 274 - let merged = _mm_or_si128(stage1, msbmask); 275 - 276 - Ok(w.write_all( 277 - std::mem::transmute::<__m128i, [u8; 16]>(merged).get_unchecked(..bytes as usize), 278 - )?) 279 - } 280 - } 281 - 282 - // TODO: implement this using neon? not likely we'll use arm-based servers but maybe nice for 283 - // local testing? 284 - #[cfg(not(any(target_feature = "bmi2", target_feature = "avx2")))] 285 - fn encode(&self, mut w: impl Write) -> Result<()> { 286 - use byteorder::WriteBytesExt; 287 - 288 - let mut val = self.0 as u64; 289 - loop { 290 - if val & 0b1111111111111111111111111111111111111111111111111111111110000000 == 0 { 291 - w.write_u8(val as u8)?; 292 - return Ok(()); 293 - } 294 - w.write_u8(val as u8 & 0b01111111 | 0b10000000)?; 295 - val >>= 7; 296 - } 297 - } 298 - } 299 - 300 - impl From<VarInt> for i32 { 301 - fn from(value: VarInt) -> Self { 302 - value.0 303 - } 304 - }
-16
crawlspace/src/protocol/mod.rs
··· 17 17 * <https://www.gnu.org/licenses/>. 18 18 */ 19 19 20 - pub mod datatypes { 21 - mod impls; 22 - mod position; 23 - mod slot; 24 - mod string; 25 - mod text_component; 26 - mod variable; 27 - 28 - pub use impls::*; 29 - pub use position::*; 30 - pub use slot::*; 31 - pub use string::*; 32 - pub use text_component::*; 33 - pub use variable::*; 34 - } 35 - 36 20 pub mod packets { 37 21 pub mod login { 38 22 mod config;
+1 -1
crawlspace/src/protocol/packets/login/registry/biome.rs
··· 45 45 mood_sound: Option<MoodSound>, 46 46 additions_sound: Option<AdditionsSound>, 47 47 music: Option<Vec<Music>>, 48 - music_volume: Option<f32> 48 + music_volume: Option<f32>, 49 49 } 50 50 51 51 #[derive(Clone, Debug, Serialize, Deserialize)]
+1 -1
crawlspace/src/protocol/packets/login/registry/dimension.rs
··· 19 19 20 20 use serde::{Deserialize, Serialize}; 21 21 22 - use super::{RegistryItem, deserialize_bool}; 22 + use super::{deserialize_bool, RegistryItem}; 23 23 24 24 #[derive(Clone, Debug, Serialize, Deserialize)] 25 25 pub struct DimensionType {
+19
crawlspace/src/protocol/packets/login/registry/tags.rs
··· 1 + /* 2 + * Copyright (c) 2024 Andrew Brower. 3 + * This file is part of Crawlspace. 4 + * 5 + * Crawlspace is free software: you can redistribute it and/or 6 + * modify it under the terms of the GNU Affero General Public 7 + * License as published by the Free Software Foundation, either 8 + * version 3 of the License, or (at your option) any later version. 9 + * 10 + * Crawlspace is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 + * Affero General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU Affero General Public 16 + * License along with Crawlspace. If not, see 17 + * <https://www.gnu.org/licenses/>. 18 + */ 19 + 1 20 use crawlspace_macro::Packet; 2 21 3 22 use crate::protocol::datatypes::{Bounded, VarInt};
+183
crawlspace/src/protocol/packets/play/world.rs
··· 367 367 }, 368 368 } 369 369 } 370 + 371 + pub fn slime_to_sec( 372 + crawlstate: CrawlState, 373 + value: &slimeball_lib::Section, 374 + block_states: &Blocks, 375 + ) -> Self { 376 + let mut blocks = Vec::new(); 377 + let bit_length = (64 - (value.block_states.palette.len() as u64).leading_zeros()).max(4); 378 + 379 + let blocks_per_long = 64 / bit_length; 380 + 381 + #[cfg(not(feature = "modern_art"))] 382 + let bit_mask = (1 << bit_length) - 1; 383 + 384 + match value.block_states.data { 385 + None => blocks.fill(0), 386 + Some(ref data) => { 387 + trace!("data.len(): {}", data.len()); 388 + trace!("blocks_per_long: {blocks_per_long}"); 389 + blocks.resize(data.len() * blocks_per_long as usize, 0); 390 + let mut i = 0; 391 + for long in data.iter() { 392 + #[cfg(not(feature = "modern_art"))] 393 + { 394 + let long = *long as u64; 395 + for b in 0..blocks_per_long { 396 + blocks[i] = ((long >> (bit_length * b)) & bit_mask) as i16; 397 + i += 1; 398 + } 399 + } 400 + 401 + #[cfg(feature = "modern_art")] 402 + { 403 + let mut long = *long as u64; 404 + while long != 0 { 405 + blocks[i] = (long & ((1 << bit_length) - 1)) as i16; 406 + long >>= bit_length; 407 + i += 1; 408 + } 409 + } 410 + } 411 + } 412 + } 413 + 414 + let palette = value 415 + .block_states 416 + .palette 417 + .iter() 418 + .map(|b| BlockState::parse_state_slime(b, block_states).unwrap_or(BlockState::AIR)) 419 + .collect::<Vec<_>>(); 420 + 421 + let blocks: Vec<u16> = blocks 422 + .iter() 423 + // todo: come up with a better way to do this(?) 424 + .map(|b| palette.get(*b as usize).unwrap_or(&BlockState::AIR).0) 425 + .collect(); 426 + 427 + let block_count = blocks.iter().filter(|b| **b != 0).collect::<Vec<_>>().len(); 428 + 429 + let bit_length = match palette.len() { 430 + 1 => 0, 431 + l => (64 - l.leading_zeros()).max(4) as u8, 432 + }; 433 + 434 + trace!("bit_length: {bit_length}"); 435 + 436 + let palette = { 437 + if bit_length == 15 { 438 + Palette::Direct 439 + } else if bit_length >= 4 { 440 + Palette::Indirect(VarInt(palette.len() as i32), palette) 441 + } else { 442 + Palette::SingleValued(*palette.first().unwrap()) 443 + } 444 + }; 445 + 446 + let blocks = match palette { 447 + Palette::Indirect(_, ref p) => blocks 448 + .iter() 449 + .map(|requested| p.iter().position(|pb| pb.0 == *requested).unwrap() as u16) 450 + .collect::<Vec<_>>(), 451 + _ => blocks, 452 + }; 453 + 454 + trace!("palette: {:?}", palette); 455 + trace!("blocks: {:?}", blocks); 456 + 457 + let data = { 458 + let data = match palette { 459 + Palette::Direct | Palette::Indirect(..) => { 460 + let blocks_per_long = 64 / bit_length; 461 + let mut data = vec![0i64; blocks.len() / blocks_per_long as usize]; 462 + let mut blocks_so_far = 0; 463 + let mut long_index = 0; 464 + 465 + for block in blocks { 466 + if blocks_so_far == blocks_per_long { 467 + blocks_so_far = 0; 468 + long_index += 1; 469 + } 470 + 471 + let block = block as i64; 472 + 473 + data[long_index] |= block << (blocks_so_far * bit_length); 474 + blocks_so_far += 1; 475 + trace!("block: {} ({:b}), long (after appending): {:b}, blocks so far: {blocks_so_far}", block, block, data[long_index]) 476 + } 477 + 478 + data 479 + } 480 + Palette::SingleValued(_) => Vec::with_capacity(0), 481 + }; 482 + 483 + let data = fastnbt::LongArray::new(data.to_vec()); 484 + trace!("data: {:?}", data); 485 + data 486 + }; 487 + 488 + Self { 489 + block_count: block_count as i16, 490 + block_states: PalettedContainer { 491 + bits_per_entry: bit_length, 492 + palette, 493 + data_array: data, 494 + }, 495 + biomes: PalettedContainer { 496 + bits_per_entry: 0, 497 + palette: Palette::SingleValued(BlockState( 498 + crawlstate.registry_cache.the_end_biome_id, 499 + )), 500 + data_array: fastnbt::LongArray::new(vec![]), 501 + }, 502 + } 503 + } 370 504 } 371 505 372 506 impl ChunkDataUpdateLightC<'_> { ··· 403 537 Self { 404 538 x: value.x_pos, 405 539 z: value.z_pos, 540 + heightmaps: HeightMaps(HashMap::new()), 541 + data, 542 + entities: block_entities, 543 + sky_light_mask: BitVec::from_elem(18, false), 544 + block_light_mask: BitVec::from_elem(18, false), 545 + empty_sky_light_mask: BitVec::from_elem(18, true), 546 + empty_block_light_mask: BitVec::from_elem(18, true), 547 + sky_light_arrays: vec![], 548 + block_light_arrays: vec![], 549 + } 550 + } 551 + 552 + pub fn from_slime( 553 + crawlstate: CrawlState, 554 + value: &slimeball_lib::Chunk, 555 + block_states: &Blocks, 556 + ) -> Self { 557 + let data = value 558 + .sections 559 + .iter() 560 + .map(|sec| ChunkSection::slime_to_sec(crawlstate.clone(), sec, block_states)) 561 + .collect::<Vec<_>>(); 562 + 563 + let block_entities = value 564 + .tile_entities 565 + .clone() 566 + .into_iter() 567 + .filter_map(|e| { 568 + world::BlockEntity::try_parse(e).map_or_else( 569 + |why| { 570 + warn!( 571 + "Failed to parse block entity: {why}, ignoring in final chunk packet for ({}, {})", 572 + value.x, 573 + value.z, 574 + ); 575 + None 576 + }, 577 + |e| match e.keep_packed { 578 + true => None, 579 + false => Some(e), 580 + }, 581 + ) 582 + }) 583 + .map(Into::into) 584 + .collect::<Vec<self::BlockEntity>>(); 585 + 586 + Self { 587 + x: value.x, 588 + z: value.z, 406 589 heightmaps: HeightMaps(HashMap::new()), 407 590 data, 408 591 entities: block_entities,
+5 -2
crawlspace/src/state.rs
··· 22 22 use tokio::sync::{mpsc, Mutex, RwLock, Semaphore}; 23 23 use tokio_util::sync::CancellationToken; 24 24 25 + use crate::protocol::packets::login::registry::TAGS; 25 26 use crate::{ 26 27 args::Args, 27 - net::{cache::{TagCache, RegistryCache}, player::SharedPlayer}, 28 + net::{ 29 + cache::{RegistryCache, TagCache}, 30 + player::SharedPlayer, 31 + }, 28 32 protocol::packets::login::registry::ALL_REGISTRIES, 29 33 server::Server, 30 34 }; 31 - use crate::protocol::packets::login::registry::TAGS; 32 35 33 36 #[derive(Debug)] 34 37 pub struct State {
+1 -1
crawlspace/src/world/block_entity.rs
··· 67 67 68 68 Ok(Self { 69 69 id, 70 - keep_packed: get_tag!(data, Value::Byte, "keepPacked") == 1, 70 + keep_packed: data.get("keepPacked").map_or(false, |k| k == 1), 71 71 x: get_tag!(data, Value::Int, "x"), 72 72 y: get_tag!(data, Value::Int, "y"), 73 73 z: get_tag!(data, Value::Int, "z"),
+13
crawlspace/src/world/blocks.rs
··· 50 50 .map(|b| Self(b.id)) 51 51 }) 52 52 } 53 + 54 + pub fn parse_state_slime( 55 + value: &slimeball_lib::BlockState, 56 + block_states: &Blocks, 57 + ) -> Option<Self> { 58 + // TODO: build map lazily to speed up load time? 59 + block_states.0.get(&value.name).and_then(|b| { 60 + b.states 61 + .iter() 62 + .find(|s| value.properties == s.properties) 63 + .map(|b| Self(b.id)) 64 + }) 65 + } 53 66 } 54 67 55 68 #[derive(Debug, Deserialize, Clone)]
+41 -36
crawlspace/src/world/mod.rs
··· 17 17 * <https://www.gnu.org/licenses/>. 18 18 */ 19 19 20 - use std::{collections::HashMap, fs::File, path::Path}; 20 + use std::{collections::HashMap, fs::File, io::BufReader, path::Path}; 21 21 22 22 use color_eyre::eyre::Result; 23 23 use fastanvil::Region; ··· 115 115 pub _data: Option<fastnbt::LongArray>, 116 116 } 117 117 118 - pub fn read_world(path: &str) -> Result<World> { 119 - let folder = Path::new(path).join("region"); 120 - let folder = std::fs::read_dir(folder).unwrap(); 121 - let chunks = std::sync::Mutex::new(HashMap::new()); 118 + pub fn read_world(path: &str) -> Result<slimeball_lib::SlimeWorld> { 119 + let world = File::open(path)?; 120 + let mut reader = BufReader::new(world); 121 + Ok(slimeball_lib::SlimeWorld::deserialize(&mut reader)?) 122 + } 123 + // pub fn read_world(path: &str) -> Result<World> { 124 + // let folder = Path::new(path).join("region"); 125 + // let folder = std::fs::read_dir(folder).unwrap(); 126 + // let chunks = std::sync::Mutex::new(HashMap::new()); 122 127 123 - folder.into_iter().par_bridge().for_each(|path| { 124 - let file = File::open(path.unwrap().path()).expect("Failed to open file"); 125 - let mut region = Region::from_stream(file).expect("Failed to create region from stream"); 128 + // folder.into_iter().par_bridge().for_each(|path| { 129 + // let file = File::open(path.unwrap().path()).expect("Failed to open file"); 130 + // let mut region = Region::from_stream(file).expect("Failed to create region from stream"); 126 131 127 - region.iter().par_bridge().for_each(|chunk| { 128 - let chunk = chunk.unwrap(); 129 - let mut parsed: Chunk = fastnbt::from_bytes(&chunk.data).unwrap_or_else(|e| { 130 - panic!( 131 - "Failed to parse chunk {e}: {}", 132 - &chunk 133 - .data 134 - .iter() 135 - .map(|b| b.to_string()) 136 - .collect::<Vec<String>>() 137 - .join(" ") 138 - ); 139 - }); 132 + // region.iter().par_bridge().for_each(|chunk| { 133 + // let chunk = chunk.unwrap(); 134 + // let mut parsed: Chunk = fastnbt::from_bytes(&chunk.data).unwrap_or_else(|e| { 135 + // panic!( 136 + // "Failed to parse chunk {e}: {}", 137 + // &chunk 138 + // .data 139 + // .iter() 140 + // .map(|b| b.to_string()) 141 + // .collect::<Vec<String>>() 142 + // .join(" ") 143 + // ); 144 + // }); 140 145 141 - if (-10..10).contains(&parsed.x_pos) && (-10..10).contains(&parsed.z_pos) { 142 - parsed.sections.sort_by_key(|c| c.y); 146 + // if (-10..10).contains(&parsed.x_pos) && (-10..10).contains(&parsed.z_pos) { 147 + // parsed.sections.sort_by_key(|c| c.y); 143 148 144 - debug!( 145 - "Successfully parsed chunk at {}, {}", 146 - parsed.x_pos, parsed.z_pos 147 - ); 148 - trace!("{:?}", parsed); 149 + // debug!( 150 + // "Successfully parsed chunk at {}, {}", 151 + // parsed.x_pos, parsed.z_pos 152 + // ); 153 + // trace!("{:?}", parsed); 149 154 150 - let mut chunks = chunks.lock().expect("Failed to lock chunk mutex"); 151 - chunks.insert((parsed.x_pos, parsed.z_pos), parsed); 152 - } 153 - }); 154 - }); 155 + // let mut chunks = chunks.lock().expect("Failed to lock chunk mutex"); 156 + // chunks.insert((parsed.x_pos, parsed.z_pos), parsed); 157 + // } 158 + // }); 159 + // }); 155 160 156 - let chunks = chunks.lock().expect("Failed to lock chunk mutex"); 157 - Ok(World(chunks.clone())) 158 - } 161 + // let chunks = chunks.lock().expect("Failed to lock chunk mutex"); 162 + // Ok(World(chunks.clone())) 163 + // }
+47 -51
crawlspace-macro/src/lib.rs
··· 1 - use proc_macro::{Span, TokenStream}; 1 + /* 2 + * Copyright (c) 2024 Andrew Brower. 3 + * This file is part of Crawlspace. 4 + * 5 + * Crawlspace is free software: you can redistribute it and/or 6 + * modify it under the terms of the GNU Affero General Public 7 + * License as published by the Free Software Foundation, either 8 + * version 3 of the License, or (at your option) any later version. 9 + * 10 + * Crawlspace is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 + * Affero General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU Affero General Public 16 + * License along with Crawlspace. If not, see 17 + * <https://www.gnu.org/licenses/>. 18 + */ 19 + 20 + use proc_macro::TokenStream; 2 21 use quote::quote; 3 22 use syn::{parse_macro_input, parse_quote, DeriveInput, Fields, Ident, Index, Lit, Path}; 4 23 ··· 22 41 attr.parse_nested_meta(|meta| { 23 42 if meta.path.is_ident("id") { 24 43 let lit = meta.value()?.parse()?; 25 - match lit { 26 - Lit::Str(i) => { 27 - id = Some(i); 28 - } 44 + id = match lit { 45 + Lit::Str(i) => Some(quote!(crawlspace_proto::PacketId::String(#i))), 46 + Lit::Int(i) => Some(quote!(crawlspace_proto::PacketId::Numeric(#i))), 29 47 _ => panic!("attribute value `id` must be a string"), 30 48 } 31 49 } else if meta.path.is_ident("state") { ··· 69 87 70 88 let id = id.expect("id must be provided for packet"); 71 89 let state = state.expect("state must be provided for packet"); 72 - let direction = Ident::new( 73 - direction.expect("direction must be provided for packet"), 74 - Span::call_site().into(), 75 - ); 76 90 77 91 let name = input.ident; 78 92 let where_clause = input.generics.where_clause.clone(); 79 93 let generics = input.generics; 80 94 81 95 quote! { 82 - impl #generics Packet for #name #generics #where_clause { 83 - fn id() -> &'static str { 96 + impl #generics crawlspace_proto::Packet for #name #generics #where_clause { 97 + fn packet_id() -> crawlspace_proto::PacketId { 84 98 #id 85 99 } 86 100 87 - fn state() -> PacketState { 101 + fn packet_state() -> crawlspace_proto::ConnectionState { 88 102 #state 89 - } 90 - 91 - fn direction() -> PacketDirection { 92 - PacketDirection::#direction 93 103 } 94 104 } 95 105 } ··· 99 109 /// Automatically implements "straight-across" encoding for the given struct, i.e. fields are 100 110 /// serialized in order as is. Supports #[varint] and #[varlong] attributes on integer types to 101 111 /// serialize as those formats instead. 102 - #[proc_macro_derive(Encode, attributes(varint, varlong))] 103 - pub fn derive_encode(input: TokenStream) -> TokenStream { 112 + #[proc_macro_derive(Write, attributes(varint, varlong))] 113 + pub fn derive_write(input: TokenStream) -> TokenStream { 104 114 let input = parse_macro_input!(input as DeriveInput); 105 115 106 116 let syn::Data::Struct(data) = input.data else { 107 - panic!("Can only derive Encode on a struct"); 117 + panic!("Can only derive Write on a struct"); 108 118 }; 109 119 110 120 let name = input.ident; ··· 124 134 .any(|attr| attr.meta.path().is_ident("varint")) 125 135 { 126 136 fields_encoded.extend(quote! { 127 - VarInt(self.#field_name as i32).encode(&mut w)?; 137 + VarInt(self.#field_name as i32).write(w)?; 128 138 }); 129 139 } else if field 130 140 .attrs ··· 132 142 .any(|attr| attr.meta.path().is_ident("varlong")) 133 143 { 134 144 fields_encoded.extend(quote! { 135 - VarLong(self.#field_name as i64).encode(&mut w)?; 145 + VarLong(self.#field_name as i64).write(w)?; 136 146 }); 137 147 } else { 138 148 fields_encoded.extend(quote! { 139 - self.#field_name.encode(&mut w)?; 149 + self.#field_name.write(w)?; 140 150 }); 141 151 } 142 152 } ··· 151 161 .any(|attr| attr.meta.path().is_ident("varint")) 152 162 { 153 163 fields_encoded.extend(quote! { 154 - VarInt(self.#i as i32).encode(&mut w)?; 164 + VarInt(self.#i as i32).write(w)?; 155 165 }); 156 166 } else if field 157 167 .attrs ··· 159 169 .any(|attr| attr.meta.path().is_ident("varlong")) 160 170 { 161 171 fields_encoded.extend(quote! { 162 - VarLong(self.#i as i64).encode(&mut w)?; 172 + VarLong(self.#i as i64).write(w)?; 163 173 }); 164 174 } else { 165 175 fields_encoded.extend(quote! { 166 - self.#i.encode(&mut w)?; 176 + self.#i.write(w)?; 167 177 }); 168 178 } 169 179 } ··· 172 182 } 173 183 174 184 quote! { 175 - impl #generics Encode for #name #generics #where_clause { 176 - fn encode(&self, mut w: impl std::io::Write) -> color_eyre::Result<()> { 185 + impl #generics Write for #name #generics #where_clause { 186 + fn encode(&self, w: &mut impl std::io::Write) -> crawlspace_proto::Result<()> { 177 187 #fields_encoded 178 188 179 189 Ok(()) ··· 186 196 /// Automatically implements "straight-across" decoding for the given struct, i.e. fields are 187 197 /// deserialized in order as is. Supports #[decode_as(type)] to deserialize according to a different type. 188 198 /// uses TryInto to convert to the expected type where necessary. 189 - #[proc_macro_derive(Decode, attributes(decode_as))] 190 - pub fn derive_decode(input: TokenStream) -> TokenStream { 199 + #[proc_macro_derive(Read, attributes(decode_as))] 200 + pub fn derive_read(input: TokenStream) -> TokenStream { 191 201 let input = parse_macro_input!(input as DeriveInput); 192 202 193 203 let syn::Data::Struct(data) = input.data else { 194 - panic!("Can only derive Decode on a struct"); 204 + panic!("Can only derive Read on a struct"); 195 205 }; 196 206 197 207 let name = input.ident; ··· 204 214 let field_name = field.ident.expect("couldn't get ident for named field"); 205 215 let ty = field.ty; 206 216 207 - let wrapped = format!("for field {field_name} in {name}"); 208 - 209 217 if let Some(attr) = field 210 218 .attrs 211 219 .iter() ··· 216 224 .expect("decode_as value must be a Path"); 217 225 218 226 field_tokens.extend(quote! { 219 - #field_name: <#ty as Decode>::decode(r) 220 - .wrap_err(#wrapped)? 221 - .try_into()?, 227 + #field_name: <#ty as Read>::read(r)?.try_into()?, 222 228 }); 223 229 } else { 224 230 field_tokens.extend(quote! { 225 - #field_name: <#ty as Decode>::decode(r) 226 - .wrap_err(#wrapped)?, 231 + #field_name: <#ty as Read>::read(r)?, 227 232 }); 228 233 } 229 234 } ··· 235 240 } 236 241 Fields::Unnamed(fields) => { 237 242 let mut field_tokens = proc_macro2::TokenStream::new(); 238 - for (i, field) in fields.unnamed.into_iter().enumerate() { 243 + for field in fields.unnamed.into_iter() { 239 244 let ty = field.ty; 240 - 241 - let wrapped = format!("for field {i} in {name}"); 242 245 243 246 if let Some(attr) = field 244 247 .attrs ··· 250 253 .expect("decode_as value must be a Path"); 251 254 252 255 field_tokens.extend(quote! { 253 - <#ty as Decode>::decode(r) 254 - .wrap_err(#wrapped)? 256 + <#ty as Read>::read(r)? 255 257 .try_into()?, 256 258 }); 257 259 } else { 258 260 field_tokens.extend(quote! { 259 - <#ty as Decode>::decode(r).wrap_err(#wrapped)?, 261 + <#ty as Read>::read(r)?, 260 262 }); 261 263 } 262 264 } ··· 270 272 let struct_generics = input.generics; 271 273 let where_clause = struct_generics.where_clause.clone(); 272 274 273 - let mut impl_generics = struct_generics.clone(); 274 - if impl_generics.lifetimes().count() == 0 { 275 - impl_generics.params.push(parse_quote!('a)); 276 - } 277 - 278 275 quote! { 279 - impl #impl_generics Decode #impl_generics for #name #struct_generics #where_clause { 280 - fn decode(r: &mut &'a [u8]) -> color_eyre::Result<Self> 276 + impl #struct_generics crawlspace_proto::Read for #name #struct_generics #where_clause { 277 + fn read(r: &mut impl std::io::Read) -> crawlspace_proto::Result<Self> 281 278 where 282 279 Self: Sized, 283 280 { 284 - use color_eyre::eyre::WrapErr; 285 281 Ok(#struct_tokens) 286 282 } 287 283 }
+11
crawlspace-proto/Cargo.toml
··· 1 + [package] 2 + name = "crawlspace-proto" 3 + version = "0.1.0" 4 + edition = "2024" 5 + 6 + [dependencies] 7 + bitfield-struct = "0.11.0" 8 + byteorder = "1.5.0" 9 + serde = { version = "1.0.219", features = ["derive"] } 10 + thiserror = "2.0.16" 11 + uuid = "1.18.0"
+245
crawlspace-proto/src/datatypes/impls.rs
··· 1 + /* 2 + * Copyright (c) 2024 Andrew Brower. 3 + * This file is part of Crawlspace. 4 + * 5 + * Crawlspace is free software: you can redistribute it and/or 6 + * modify it under the terms of the GNU Affero General Public 7 + * License as published by the Free Software Foundation, either 8 + * version 3 of the License, or (at your option) any later version. 9 + * 10 + * Crawlspace is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 + * Affero General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU Affero General Public 16 + * License along with Crawlspace. If not, see 17 + * <https://www.gnu.org/licenses/>. 18 + */ 19 + 20 + use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; 21 + use uuid::Uuid; 22 + 23 + use crate::{ 24 + ErrorKind::{self, InvalidData}, 25 + Read, Write, 26 + }; 27 + 28 + impl Read for bool { 29 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> { 30 + Ok(match r.read_u8()? { 31 + 0x01 => true, 32 + 0x00 => false, 33 + v => { 34 + return Err(InvalidData(format!( 35 + "Expected 0x01 or 0x00 for bool, got {v}" 36 + ))); 37 + } 38 + }) 39 + } 40 + } 41 + 42 + impl Write for bool { 43 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 44 + let v = match self { 45 + true => 0x01, 46 + false => 0x00, 47 + }; 48 + 49 + Ok(w.write_all(&[v])?) 50 + } 51 + } 52 + 53 + impl Read for i8 { 54 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> { 55 + Ok(r.read_i8()?) 56 + } 57 + } 58 + 59 + impl Write for i8 { 60 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 61 + Ok(w.write_i8(*self)?) 62 + } 63 + } 64 + 65 + impl Read for u8 { 66 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> 67 + where 68 + Self: Sized, 69 + { 70 + Ok(r.read_u8()?) 71 + } 72 + } 73 + 74 + impl Write for u8 { 75 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 76 + Ok(w.write_u8(*self)?) 77 + } 78 + } 79 + 80 + impl Read for i16 { 81 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> 82 + where 83 + Self: Sized, 84 + { 85 + Ok(r.read_i16::<BigEndian>()?) 86 + } 87 + } 88 + 89 + impl Write for i16 { 90 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 91 + Ok(w.write_i16::<BigEndian>(*self)?) 92 + } 93 + } 94 + 95 + impl Read for u16 { 96 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> 97 + where 98 + Self: Sized, 99 + { 100 + Ok(r.read_u16::<BigEndian>()?) 101 + } 102 + } 103 + 104 + impl Read for i32 { 105 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> 106 + where 107 + Self: Sized, 108 + { 109 + Ok(r.read_i32::<BigEndian>()?) 110 + } 111 + } 112 + 113 + impl Write for i32 { 114 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 115 + Ok(w.write_i32::<BigEndian>(*self)?) 116 + } 117 + } 118 + 119 + impl Read for i64 { 120 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> 121 + where 122 + Self: Sized, 123 + { 124 + Ok(r.read_i64::<BigEndian>()?) 125 + } 126 + } 127 + 128 + impl Write for i64 { 129 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 130 + Ok(w.write_i64::<BigEndian>(*self)?) 131 + } 132 + } 133 + 134 + impl Read for u64 { 135 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> 136 + where 137 + Self: Sized, 138 + { 139 + Ok(r.read_u64::<BigEndian>()?) 140 + } 141 + } 142 + 143 + impl Write for u64 { 144 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 145 + Ok(w.write_u64::<BigEndian>(*self)?) 146 + } 147 + } 148 + 149 + impl Read for u128 { 150 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> 151 + where 152 + Self: Sized, 153 + { 154 + Ok(r.read_u128::<BigEndian>()?) 155 + } 156 + } 157 + 158 + impl Write for u128 { 159 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 160 + Ok(w.write_u128::<BigEndian>(*self)?) 161 + } 162 + } 163 + 164 + impl Read for f32 { 165 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> 166 + where 167 + Self: Sized, 168 + { 169 + Ok(r.read_f32::<BigEndian>()?) 170 + } 171 + } 172 + 173 + impl Write for f32 { 174 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 175 + Ok(w.write_f32::<BigEndian>(*self)?) 176 + } 177 + } 178 + 179 + impl Read for f64 { 180 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> 181 + where 182 + Self: Sized, 183 + { 184 + Ok(r.read_f64::<BigEndian>()?) 185 + } 186 + } 187 + 188 + impl Write for f64 { 189 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 190 + Ok(w.write_f64::<BigEndian>(*self)?) 191 + } 192 + } 193 + 194 + impl Write for Uuid { 195 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 196 + self.as_u128().write(w) 197 + } 198 + } 199 + 200 + impl Read for Uuid { 201 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> { 202 + Ok(Uuid::from_u128(r.read_u128::<BigEndian>()?)) 203 + } 204 + } 205 + 206 + impl<T> Write for Option<T> 207 + where 208 + T: Write, 209 + { 210 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 211 + match self { 212 + None => Ok(()), 213 + Some(v) => v.write(w), 214 + } 215 + } 216 + } 217 + 218 + impl<T> Write for Vec<T> 219 + where 220 + T: Write, 221 + { 222 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 223 + for item in self { 224 + item.write(w)?; 225 + } 226 + 227 + Ok(()) 228 + } 229 + } 230 + 231 + impl<T> Read for Vec<T> 232 + where 233 + T: Read, 234 + { 235 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> { 236 + let times = r.read_i32::<BigEndian>()?; 237 + let mut o = Vec::new(); 238 + 239 + for _ in 0..times { 240 + o.push(T::read(r)?) 241 + } 242 + 243 + Ok(o) 244 + } 245 + }
+107
crawlspace-proto/src/datatypes/position.rs
··· 1 + /* 2 + * Copyright (c) 2024 Andrew Brower. 3 + * This file is part of Crawlspace. 4 + * 5 + * Crawlspace is free software: you can redistribute it and/or 6 + * modify it under the terms of the GNU Affero General Public 7 + * License as published by the Free Software Foundation, either 8 + * version 3 of the License, or (at your option) any later version. 9 + * 10 + * Crawlspace is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 + * Affero General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU Affero General Public 16 + * License along with Crawlspace. If not, see 17 + * <https://www.gnu.org/licenses/>. 18 + */ 19 + 20 + use bitfield_struct::bitfield; 21 + use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; 22 + use thiserror::Error; 23 + 24 + use crate::{ErrorKind, Read, Write}; 25 + 26 + #[derive(Debug)] 27 + pub struct Position { 28 + pub x: i32, 29 + pub y: i32, 30 + pub z: i32, 31 + } 32 + 33 + #[bitfield(u64)] 34 + pub struct PackedPosition { 35 + #[bits(26)] 36 + pub x: i32, 37 + #[bits(26)] 38 + pub z: i32, 39 + #[bits(12)] 40 + pub y: i32, 41 + } 42 + 43 + impl Position { 44 + #[must_use] 45 + pub fn new(x: i32, y: i32, z: i32) -> Self { 46 + Self { x, y, z } 47 + } 48 + } 49 + 50 + #[derive(Debug, Error)] 51 + pub enum EncodingError { 52 + #[error("value is out of bounds")] 53 + OutOfBounds, 54 + } 55 + 56 + impl TryFrom<&Position> for PackedPosition { 57 + type Error = EncodingError; 58 + 59 + fn try_from(value: &Position) -> std::result::Result<Self, Self::Error> { 60 + match (value.x, value.y, value.z) { 61 + (-0x2000000..=0x1ffffff, -0x800..=0x7ff, -0x2000000..=0x1ffffff) => { 62 + Ok(PackedPosition::new() 63 + .with_x(value.x) 64 + .with_y(value.y) 65 + .with_z(value.z)) 66 + } 67 + _ => Err(EncodingError::OutOfBounds), 68 + } 69 + } 70 + } 71 + 72 + impl From<PackedPosition> for Position { 73 + fn from(value: PackedPosition) -> Self { 74 + Self { 75 + x: value.x(), 76 + y: value.y(), 77 + z: value.z(), 78 + } 79 + } 80 + } 81 + 82 + impl Write for Position { 83 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 84 + let encoded: PackedPosition = self 85 + .try_into() 86 + .map_err(|_| ErrorKind::InvalidData("Invalid packed position".to_string()))?; 87 + encoded.write(w) 88 + } 89 + } 90 + 91 + impl Read for Position { 92 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> { 93 + let bytes = r.read_i64::<BigEndian>()?; 94 + 95 + Ok(Self { 96 + x: (bytes >> 38) as i32, 97 + y: (bytes << 52 >> 52) as i32, 98 + z: (bytes << 26 >> 38) as i32, 99 + }) 100 + } 101 + } 102 + 103 + impl Write for PackedPosition { 104 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 105 + Ok(w.write_u64::<BigEndian>(self.0)?) 106 + } 107 + }
+89
crawlspace-proto/src/datatypes/slot.rs
··· 1 + /* 2 + * Copyright (c) 2024 Andrew Brower. 3 + * This file is part of Crawlspace. 4 + * 5 + * Crawlspace is free software: you can redistribute it and/or 6 + * modify it under the terms of the GNU Affero General Public 7 + * License as published by the Free Software Foundation, either 8 + * version 3 of the License, or (at your option) any later version. 9 + * 10 + * Crawlspace is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 + * Affero General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU Affero General Public 16 + * License along with Crawlspace. If not, see 17 + * <https://www.gnu.org/licenses/>. 18 + */ 19 + 20 + // use crate::{protocol::Encode, server::registries::REGISTRIES, world::Item}; 21 + use crate::{ErrorKind, Write}; 22 + 23 + use super::VarInt; 24 + 25 + #[derive(Debug, Clone, Default)] 26 + pub struct Slot { 27 + item_count: i8, 28 + item_id: Option<i32>, 29 + components_to_add: Option<Vec<Component>>, 30 + components_to_remove: Option<Vec<i32>>, 31 + } 32 + 33 + #[derive(Debug, Clone)] 34 + pub enum Component {} 35 + 36 + impl Slot { 37 + pub fn new(item_id: i32, item_count: i8) -> Self { 38 + Self { 39 + item_count, 40 + item_id: Some(item_id), 41 + components_to_add: None, 42 + components_to_remove: None, 43 + } 44 + } 45 + } 46 + 47 + impl Write for Slot { 48 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 49 + self.item_count.write(w)?; 50 + 51 + if self.item_count == 0 { 52 + return Ok(()); 53 + } 54 + 55 + if let Some(item_id) = self.item_id { 56 + VarInt(item_id).write(w)?; 57 + 58 + VarInt( 59 + self.components_to_add 60 + .as_ref() 61 + .map(|v| v.len()) 62 + .unwrap_or(0) as i32, 63 + ) 64 + .write(w)?; 65 + 66 + VarInt( 67 + self.components_to_remove 68 + .as_ref() 69 + .map(|v| v.len()) 70 + .unwrap_or(0) as i32, 71 + ) 72 + .write(w)?; 73 + 74 + if let Some(ref components_to_add) = self.components_to_add { 75 + for _component in components_to_add { 76 + unimplemented!("Encoding components is not implemented"); 77 + } 78 + } 79 + 80 + if let Some(ref components_to_remove) = self.components_to_remove { 81 + for _component in components_to_remove { 82 + unimplemented!("Encoding components is not implemented"); 83 + } 84 + } 85 + } 86 + 87 + Ok(()) 88 + } 89 + }
+114
crawlspace-proto/src/datatypes/string.rs
··· 1 + /* 2 + * Copyright (c) 2024 Andrew Brower. 3 + * This file is part of Crawlspace. 4 + * 5 + * Crawlspace is free software: you can redistribute it and/or 6 + * modify it under the terms of the GNU Affero General Public 7 + * License as published by the Free Software Foundation, either 8 + * version 3 of the License, or (at your option) any later version. 9 + * 10 + * Crawlspace is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 + * Affero General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU Affero General Public 16 + * License along with Crawlspace. If not, see 17 + * <https://www.gnu.org/licenses/>. 18 + */ 19 + 20 + use crate::{ 21 + ErrorKind::{self, InvalidData}, 22 + Read, Write, 23 + }; 24 + 25 + use super::VarInt; 26 + 27 + #[derive(Debug)] 28 + pub struct Bounded<T, const BOUND: usize = 32767>(pub T); 29 + 30 + impl<const BOUND: usize> Read for Bounded<String, BOUND> { 31 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> { 32 + let len = VarInt::read(r)?.0; 33 + if len < 0 { 34 + return Err(InvalidData( 35 + "tried to decode string with negative length".to_string(), 36 + )); 37 + } 38 + 39 + let len = len as usize; 40 + 41 + let mut buf = vec![0; len]; 42 + r.read_exact(&mut buf)?; 43 + let content = String::from_utf8(buf) 44 + .map_err(|_| ErrorKind::InvalidData("invalid utf8 string data".to_string()))?; 45 + let utf16_len = content.encode_utf16().count(); 46 + 47 + if utf16_len > BOUND { 48 + return Err(InvalidData(format!( 49 + "utf-16 encoded string exceeds {BOUND} chars (is {utf16_len})" 50 + ))); 51 + } 52 + 53 + Ok(Bounded(content)) 54 + } 55 + } 56 + 57 + impl<'a, const BOUND: usize> Write for Bounded<String, BOUND> { 58 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 59 + let len = self.0.encode_utf16().count(); 60 + 61 + if len > BOUND { 62 + return Err(InvalidData(format!( 63 + "length of string {len} exceeds bound {BOUND}" 64 + ))); 65 + }; 66 + 67 + VarInt(self.0.len() as i32).write(w)?; 68 + Ok(w.write_all(self.0.as_bytes())?) 69 + } 70 + } 71 + 72 + impl Write for str { 73 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 74 + VarInt(self.len() as i32).write(w)?; 75 + Ok(w.write_all(self.as_bytes())?) 76 + } 77 + } 78 + 79 + #[derive(Debug)] 80 + pub struct Rest<T, const BOUND: usize = 32767>(pub T); 81 + 82 + impl<'a, const BOUND: usize> Read for Rest<String, BOUND> { 83 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> { 84 + let mut buf = Vec::new(); 85 + r.read_to_end(&mut buf)?; 86 + 87 + let content = String::from_utf8(buf) 88 + .map_err(|_| InvalidData("Rest was not valid UTF-8".to_string()))?; 89 + 90 + let utf16_len = content.encode_utf16().count(); 91 + 92 + if utf16_len > BOUND { 93 + return Err(InvalidData(format!( 94 + "utf-16 encoded string exceeds {BOUND} chars (is {utf16_len})" 95 + ))); 96 + }; 97 + 98 + Ok(Rest(content)) 99 + } 100 + } 101 + 102 + impl<'a, const BOUND: usize> Write for Rest<String, BOUND> { 103 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 104 + let len = self.0.encode_utf16().count(); 105 + 106 + if len > BOUND { 107 + return Err(InvalidData(format!( 108 + "length of string {len} exceeds bound {BOUND}" 109 + ))); 110 + }; 111 + 112 + Ok(w.write_all(self.0.as_bytes())?) 113 + } 114 + }
+38
crawlspace-proto/src/datatypes/text_component.rs
··· 1 + /* 2 + * Copyright (c) 2024 Andrew Brower. 3 + * This file is part of Crawlspace. 4 + * 5 + * Crawlspace is free software: you can redistribute it and/or 6 + * modify it under the terms of the GNU Affero General Public 7 + * License as published by the Free Software Foundation, either 8 + * version 3 of the License, or (at your option) any later version. 9 + * 10 + * Crawlspace is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 + * Affero General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU Affero General Public 16 + * License along with Crawlspace. If not, see 17 + * <https://www.gnu.org/licenses/>. 18 + */ 19 + 20 + use serde::Serialize; 21 + 22 + #[derive(Debug, Clone, Serialize)] 23 + pub struct TextComponent { 24 + text: String, 25 + } 26 + 27 + impl From<String> for TextComponent { 28 + fn from(value: String) -> Self { 29 + Self { text: value } 30 + } 31 + } 32 + impl From<&str> for TextComponent { 33 + fn from(value: &str) -> Self { 34 + Self { 35 + text: value.to_owned(), 36 + } 37 + } 38 + }
+295
crawlspace-proto/src/datatypes/variable.rs
··· 1 + /* 2 + * Copyright (c) 2024 Andrew Brower. 3 + * This file is part of Crawlspace. 4 + * 5 + * Crawlspace is free software: you can redistribute it and/or 6 + * modify it under the terms of the GNU Affero General Public 7 + * License as published by the Free Software Foundation, either 8 + * version 3 of the License, or (at your option) any later version. 9 + * 10 + * Crawlspace is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 + * Affero General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU Affero General Public 16 + * License along with Crawlspace. If not, see 17 + * <https://www.gnu.org/licenses/>. 18 + */ 19 + 20 + use std::fmt::Display; 21 + 22 + use byteorder::ReadBytesExt; 23 + use serde::Deserialize; 24 + 25 + use crate::{ 26 + ErrorKind::{self, InvalidData}, 27 + Read, Write, 28 + }; 29 + 30 + pub trait VariableNumber: Sized + Write + Read { 31 + const SEGMENT_BITS: u8 = 0b01111111; 32 + const CONTINUE_BITS: u8 = 0b10000000; 33 + 34 + const MAX_BYTES: usize; 35 + 36 + fn len(self) -> usize; 37 + } 38 + 39 + macro_rules! make_var_num { 40 + ($name: ident, $type: ty, $max_bytes: expr) => { 41 + #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize)] 42 + #[serde(transparent)] 43 + pub struct $name(pub $type); 44 + 45 + impl VariableNumber for $name { 46 + const MAX_BYTES: usize = $max_bytes; 47 + 48 + fn len(self) -> usize { 49 + match self.0 { 50 + 0 => 1, 51 + n => (31 - n.leading_zeros() as usize) / 7 + 1, 52 + } 53 + } 54 + } 55 + 56 + impl Display for $name { 57 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 58 + write!(f, "{}", self.0) 59 + } 60 + } 61 + 62 + impl Read for $name { 63 + fn read(r: &mut impl std::io::Read) -> Result<Self, ErrorKind> { 64 + let mut v: $type = 0; 65 + 66 + for i in 0..Self::MAX_BYTES { 67 + let byte = r 68 + .read_u8() 69 + .map_err(|_| InvalidData("Incomplete variable number".to_string()))?; 70 + v |= <$type>::from(byte & Self::SEGMENT_BITS) << (i * 7); 71 + if byte & Self::CONTINUE_BITS == 0 { 72 + return Ok(Self(v)); 73 + } 74 + } 75 + 76 + Err(InvalidData("Malformed variable number".to_string())) 77 + } 78 + } 79 + }; 80 + } 81 + 82 + make_var_num!(VarInt, i32, 5); 83 + make_var_num!(VarLong, i64, 10); 84 + 85 + impl Write for VarInt { 86 + // implementation taken from https://github.com/as-com/varint-simd/blob/0f468783da8e181929b01b9c6e9f741c1fe09825/src/encode/mod.rs#L71 87 + // only the first branch is done here because we never need to change varint size 88 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 89 + let x = self.0 as u64; 90 + let stage1 = (x & 0x000000000000007f) 91 + | ((x & 0x0000000000003f80) << 1) 92 + | ((x & 0x00000000001fc000) << 2) 93 + | ((x & 0x000000000fe00000) << 3) 94 + | ((x & 0x00000000f0000000) << 4); 95 + 96 + let leading = stage1.leading_zeros(); 97 + 98 + let unused_bytes = (leading - 1) / 8; 99 + let bytes_needed = 8 - unused_bytes; 100 + 101 + let msbs = 0x8080808080808080; 102 + let msbmask = 0xFFFFFFFFFFFFFFFF >> ((8 - bytes_needed + 1) * 8 - 1); 103 + 104 + let merged = stage1 | (msbs & msbmask); 105 + let bytes = merged.to_le_bytes(); 106 + 107 + Ok(w.write_all(unsafe { bytes.get_unchecked(..bytes_needed as usize) })?) 108 + } 109 + } 110 + 111 + impl VarLong { 112 + // how cute... 113 + #[inline(always)] 114 + #[cfg(target_feature = "bmi2")] 115 + fn num_to_vector_stage1(self) -> [u8; 16] { 116 + use std::arch::x86_64::*; 117 + let mut res = [0u64; 2]; 118 + 119 + let x = self.0 as u64; 120 + 121 + res[0] = unsafe { _pdep_u64(x, 0x7f7f7f7f7f7f7f7f) }; 122 + res[1] = unsafe { _pdep_u64(x >> 56, 0x000000000000017f) }; 123 + 124 + unsafe { core::mem::transmute(res) } 125 + } 126 + 127 + #[inline(always)] 128 + #[cfg(all(target_feature = "avx2", not(all(target_feature = "bmi2"))))] 129 + fn num_to_vector_stage1(self) -> [u8; 16] { 130 + use std::arch::x86_64::*; 131 + let mut res = [0u64; 2]; 132 + let x = self; 133 + 134 + let b = unsafe { _mm_set1_epi64x(self as i64) }; 135 + let c = unsafe { 136 + _mm_or_si128( 137 + _mm_or_si128( 138 + _mm_sllv_epi64( 139 + _mm_and_si128(b, _mm_set_epi64x(0x00000007f0000000, 0x000003f800000000)), 140 + _mm_set_epi64x(4, 5), 141 + ), 142 + _mm_sllv_epi64( 143 + _mm_and_si128(b, _mm_set_epi64x(0x0001fc0000000000, 0x00fe000000000000)), 144 + _mm_set_epi64x(6, 7), 145 + ), 146 + ), 147 + _mm_or_si128( 148 + _mm_sllv_epi64( 149 + _mm_and_si128(b, _mm_set_epi64x(0x000000000000007f, 0x0000000000003f80)), 150 + _mm_set_epi64x(0, 1), 151 + ), 152 + _mm_sllv_epi64( 153 + _mm_and_si128(b, _mm_set_epi64x(0x00000000001fc000, 0x000000000fe00000)), 154 + _mm_set_epi64x(2, 3), 155 + ), 156 + ), 157 + ) 158 + }; 159 + let d = unsafe { _mm_or_si128(c, _mm_bsrli_si128(c, 8)) }; 160 + 161 + res[0] = unsafe { _mm_extract_epi64(d, 0) as u64 }; 162 + res[1] = ((x & 0x7f00000000000000) >> 56) | ((x & 0x8000000000000000) >> 55); 163 + 164 + unsafe { core::mem::transmute(res) } 165 + } 166 + 167 + // TODO: need to confirm this works. for now it's just a naive translation of avx2, 168 + // but could definitely be improved -- blocking NEON implementation of Encode 169 + // 170 + // #[inline(always)] 171 + // #[cfg(target_feature = "neon")] 172 + // fn num_to_vector_stage1(self) -> [u8; 16] { 173 + // use std::arch::aarch64::*; 174 + // 175 + // let mut res = [0u64; 2]; 176 + // let x = self; 177 + // 178 + // let b = unsafe { vdupq_n_s64(self.0 as i64) }; 179 + // let c = unsafe { 180 + // vorrq_s64( 181 + // vorrq_s64( 182 + // vshlq_s64( 183 + // vandq_s64( 184 + // b, 185 + // vcombine_s64( 186 + // vcreate_s64(0x000003f800000000), 187 + // vcreate_s64(0x00000007f0000000), 188 + // ), 189 + // ), 190 + // vcombine_s64(vcreate_s64(5), vcreate_s64(4)), 191 + // ), 192 + // vshlq_s64( 193 + // vandq_s64( 194 + // b, 195 + // vcombine_s64( 196 + // vcreate_s64(0x00fe000000000000), 197 + // vcreate_s64(0x0001fc0000000000), 198 + // ), 199 + // ), 200 + // vcombine_s64(vcreate_s64(7), vcreate_s64(6)), 201 + // ), 202 + // ), 203 + // vorrq_s64( 204 + // vshlq_s64( 205 + // vandq_s64( 206 + // b, 207 + // vcombine_s64( 208 + // vcreate_s64(0x0000000000003f80), 209 + // vcreate_s64(0x000000000000007f), 210 + // ), 211 + // ), 212 + // vcombine_s64(vcreate_s64(1), vcreate_s64(0)), 213 + // ), 214 + // vshlq_s64( 215 + // vandq_s64( 216 + // b, 217 + // vcombine_s64( 218 + // vcreate_s64(0x000000000fe00000), 219 + // vcreate_s64(0x00000000001fc000), 220 + // ), 221 + // ), 222 + // vcombine_s64(vcreate_s64(3), vcreate_s64(2)), 223 + // ), 224 + // ), 225 + // ) 226 + // }; 227 + // let d = unsafe { vorrq_s64(c, vshrq_n_s64::<8>(c)) }; 228 + // 229 + // res[0] = unsafe { vgetq_lane_s64(d, 0) as u64 }; 230 + // res[1] = 231 + // ((x.0 as u64 & 0x7f00000000000000) >> 56) | ((x.0 as u64 & 0x8000000000000000) >> 55); 232 + // 233 + // unsafe { core::mem::transmute(res) } 234 + // } 235 + } 236 + 237 + impl Write for VarLong { 238 + // ...and here's the second branch ^_^ 239 + #[cfg(any(target_feature = "bmi2", target_feature = "avx2"))] 240 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 241 + use std::arch::x86_64::*; 242 + unsafe { 243 + // Break the number into 7-bit parts and spread them out into a vector 244 + let stage1: __m128i = std::mem::transmute(self.num_to_vector_stage1()); 245 + 246 + // Create a mask for where there exist values 247 + // This signed comparison works because all MSBs should be cleared at this point 248 + // Also handle the special case when num == 0 249 + let minimum = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffu8 as i8); 250 + let exists = _mm_or_si128(_mm_cmpgt_epi8(stage1, _mm_setzero_si128()), minimum); 251 + let bits = _mm_movemask_epi8(exists); 252 + 253 + // Count the number of bytes used 254 + let bytes = 32 - bits.leading_zeros() as u8; // lzcnt on supported CPUs 255 + 256 + // Fill that many bytes into a vector 257 + let ascend = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); 258 + let mask = _mm_cmplt_epi8(ascend, _mm_set1_epi8(bytes as i8)); 259 + 260 + // Shift it down 1 byte so the last MSB is the only one set, and make sure only the MSB is set 261 + let shift = _mm_bsrli_si128(mask, 1); 262 + let msbmask = _mm_and_si128(shift, _mm_set1_epi8(128u8 as i8)); 263 + 264 + // Merge the MSB bits into the vector 265 + let merged = _mm_or_si128(stage1, msbmask); 266 + 267 + Ok(w.write_all( 268 + std::mem::transmute::<__m128i, [u8; 16]>(merged).get_unchecked(..bytes as usize), 269 + )?) 270 + } 271 + } 272 + 273 + // TODO: implement this using neon? not likely we'll use arm-based servers but maybe nice for 274 + // local testing? 275 + #[cfg(not(any(target_feature = "bmi2", target_feature = "avx2")))] 276 + fn write(&self, w: &mut impl std::io::Write) -> Result<(), ErrorKind> { 277 + use byteorder::WriteBytesExt; 278 + 279 + let mut val = self.0 as u64; 280 + loop { 281 + if val & 0b1111111111111111111111111111111111111111111111111111111110000000 == 0 { 282 + w.write_u8(val as u8)?; 283 + return Ok(()); 284 + } 285 + w.write_u8(val as u8 & 0b01111111 | 0b10000000)?; 286 + val >>= 7; 287 + } 288 + } 289 + } 290 + 291 + impl From<VarInt> for i32 { 292 + fn from(value: VarInt) -> Self { 293 + value.0 294 + } 295 + }
+111
crawlspace-proto/src/lib.rs
··· 1 + /* 2 + * Copyright (c) 2024 Andrew Brower. 3 + * This file is part of Crawlspace. 4 + * 5 + * Crawlspace is free software: you can redistribute it and/or 6 + * modify it under the terms of the GNU Affero General Public 7 + * License as published by the Free Software Foundation, either 8 + * version 3 of the License, or (at your option) any later version. 9 + * 10 + * Crawlspace is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 + * Affero General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU Affero General Public 16 + * License along with Crawlspace. If not, see 17 + * <https://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #[allow(unused_imports)] 21 + pub mod datatypes { 22 + mod impls; 23 + mod position; 24 + mod slot; 25 + mod string; 26 + mod text_component; 27 + mod variable; 28 + 29 + pub use impls::*; 30 + pub use position::*; 31 + pub use slot::*; 32 + pub use string::*; 33 + pub use text_component::*; 34 + pub use variable::*; 35 + } 36 + 37 + #[derive(Debug, Clone, Copy, PartialEq)] 38 + pub enum ConnectionState { 39 + Handshake, 40 + Play, 41 + Status, 42 + Login, 43 + } 44 + 45 + #[derive(thiserror::Error, Debug)] 46 + pub enum ErrorKind { 47 + #[error("Not connected to a client")] 48 + Disconnected, 49 + #[error("IO error")] 50 + Io(#[from] std::io::Error), 51 + #[error("Invalid data: {0}")] 52 + InvalidData(String), 53 + #[error("Timed out")] 54 + Timeout, 55 + } 56 + 57 + pub type Result<T> = std::result::Result<T, ErrorKind>; 58 + 59 + pub trait Read { 60 + fn read(reader: &mut impl std::io::Read) -> Result<Self> 61 + where 62 + Self: Sized; 63 + } 64 + 65 + pub trait Write { 66 + fn write(&self, writer: &mut impl std::io::Write) -> Result<()>; 67 + } 68 + 69 + #[derive(Clone, Debug)] 70 + pub enum PacketId { 71 + String(&'static str), 72 + Numeric(i32), 73 + } 74 + 75 + impl PartialEq<i32> for PacketId { 76 + fn eq(&self, other: &i32) -> bool { 77 + match self { 78 + Self::Numeric(i) => i == other, 79 + _ => false, 80 + } 81 + } 82 + } 83 + 84 + impl PartialEq<&'static str> for PacketId { 85 + fn eq(&self, other: &&'static str) -> bool { 86 + match self { 87 + Self::String(s) => s == other, 88 + _ => false, 89 + } 90 + } 91 + } 92 + 93 + pub trait Packet { 94 + fn packet_id() -> PacketId 95 + where 96 + Self: Sized; 97 + fn packet_state() -> ConnectionState 98 + where 99 + Self: Sized; 100 + } 101 + 102 + pub trait ServerboundPacket: Packet + Read {} 103 + impl<T> ServerboundPacket for T where T: Packet + Read {} 104 + 105 + pub trait ClientboundPacket: Packet + Write {} 106 + impl<T> ClientboundPacket for T where T: Packet + Write {} 107 + 108 + pub trait Protocol { 109 + fn handshake_player(&mut self); 110 + // fn login_player(&self); 111 + }
+12
crawlspace-proto-1_8/Cargo.toml
··· 1 + [package] 2 + name = "crawlspace-proto-1_8" 3 + version = "0.1.0" 4 + edition = "2024" 5 + 6 + [dependencies] 7 + crawlspace-macro = { path = "../crawlspace-macro" } 8 + crawlspace-proto = { path = "../crawlspace-proto" } 9 + 10 + bytes = "1.10.1" 11 + tokio = { version = "1.47.1", features = ["io-util", "net", "time"] } 12 + tracing = "0.1.41"
+10
crawlspace-proto-1_8/src/handshake.rs
··· 1 + use crawlspace_macro::{Packet, Read}; 2 + use crawlspace_proto::{ConnectionState, PacketId::Numeric}; 3 + 4 + #[derive(Packet, Read)] 5 + #[packet( 6 + id = "Numeric(0x00)", 7 + state = "ConnectionState::Handshake", 8 + serverbound 9 + )] 10 + pub struct HandshakeS {}
+138
crawlspace-proto-1_8/src/lib.rs
··· 1 + /* 2 + * Copyright (c) 2024 Andrew Brower. 3 + * This file is part of Crawlspace. 4 + * 5 + * Crawlspace is free software: you can redistribute it and/or 6 + * modify it under the terms of the GNU Affero General Public 7 + * License as published by the Free Software Foundation, either 8 + * version 3 of the License, or (at your option) any later version. 9 + * 10 + * Crawlspace is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 + * Affero General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU Affero General Public 16 + * License along with Crawlspace. If not, see 17 + * <https://www.gnu.org/licenses/>. 18 + */ 19 + 20 + use std::time::Duration; 21 + 22 + use bytes::{Buf, BytesMut}; 23 + use crawlspace_proto::{ 24 + ConnectionState, ErrorKind, Packet, Read, ServerboundPacket, 25 + datatypes::{VarInt, VariableNumber}, 26 + }; 27 + use handshake::HandshakeS; 28 + use tokio::{ 29 + io::AsyncReadExt, 30 + net::tcp::{OwnedReadHalf, OwnedWriteHalf}, 31 + }; 32 + use tracing::{debug, warn}; 33 + 34 + mod handshake; 35 + 36 + const BUF_SIZE: usize = 4096; 37 + const MAX_PACKET_SIZE: i32 = 2097152; 38 + 39 + type Frame = (i32, BytesMut); 40 + 41 + /// Minecraft versions 1.8-1.8.9 42 + /// Protocol version 47 43 + pub struct Protocol47 { 44 + connection_state: ConnectionState, 45 + read_half: OwnedReadHalf, 46 + write_half: OwnedWriteHalf, 47 + read_buf: BytesMut, 48 + } 49 + 50 + impl Protocol47 { 51 + pub fn new(read_half: OwnedReadHalf, write_half: OwnedWriteHalf) -> Self { 52 + Self { 53 + connection_state: ConnectionState::Handshake, 54 + read_half, 55 + write_half, 56 + read_buf: BytesMut::new(), 57 + } 58 + } 59 + 60 + pub async fn await_packet<T: ServerboundPacket>(&mut self) -> crawlspace_proto::Result<T> { 61 + // TODO: skip decoding for frames we're not looking for 62 + loop { 63 + let frame = self.read_frame().await?; 64 + 65 + if T::packet_id() == frame.0 { 66 + return Ok(T::read(&mut &frame.1[..])?); 67 + } 68 + 69 + debug!( 70 + "discarding packet with id {} while awaiting {:?}", 71 + frame.0, 72 + T::packet_id() 73 + ); 74 + } 75 + } 76 + 77 + pub async fn read_frame(&mut self) -> crawlspace_proto::Result<Frame> { 78 + // TODO: maybe move this somewhere else? i don't know if a global timeout of 5 seconds per 79 + // packet is realistic but for testing it's chill i suppose 80 + tokio::time::timeout(Duration::from_secs(5), async move { 81 + loop { 82 + if let Some(frame) = self.try_read_next()? { 83 + return Ok(frame); 84 + }; 85 + 86 + // otherwise, keep reading the rest of the packet 87 + // (commented for my own sanity - these method names are awful) 88 + 89 + // reserve more space 90 + self.read_buf.reserve(BUF_SIZE); 91 + // split into two parts - self.read_buf containing already read data 92 + // and a new buf to fill with new data (.len returns number of bytes already held, 93 + // not capacity) 94 + let mut buf = self.read_buf.split_off(self.read_buf.len()); 95 + 96 + // fills the remainder of the buf (just newly allocated space) 97 + if self.read_half.read_buf(&mut buf).await? == 0 { 98 + return Err(std::io::Error::from(std::io::ErrorKind::UnexpectedEof).into()); 99 + } 100 + 101 + // joins "bufs" back together (just moves end pointer) 102 + self.read_buf.unsplit(buf); 103 + } 104 + }) 105 + .await 106 + .map_err(|_| ErrorKind::Timeout)? 107 + } 108 + 109 + /// Ok(None) represents an incomplete but correctly formed packet 110 + fn try_read_next(&mut self) -> crawlspace_proto::Result<Option<Frame>> { 111 + let mut buf = &self.read_buf[..]; 112 + 113 + let len = VarInt::read(&mut buf)?; 114 + 115 + if len.0 < 0 || len.0 > MAX_PACKET_SIZE { 116 + return Err(ErrorKind::InvalidData(format!( 117 + "Packet length {len} is out of bounds (min 0, max {MAX_PACKET_SIZE})" 118 + ))); 119 + }; 120 + 121 + if buf.len() < len.0 as usize { 122 + // packet is incomplete, keep waiting 123 + return Ok(None); 124 + } 125 + 126 + // TODO: use compression here 127 + self.read_buf.advance(len.len()); 128 + let mut data = self.read_buf.split_to(len.0 as usize); 129 + buf = &data[..]; 130 + 131 + let packet_id = VarInt::read(&mut buf)?.0; 132 + 133 + // advance to end of packet id 134 + data.advance(data.len() - buf.len()); 135 + 136 + Ok(Some((packet_id, data))) 137 + } 138 + }
hub.slime

This is a binary file and will not be displayed.

+1 -1
rust-toolchain.toml
··· 16 16 # <https://www.gnu.org/licenses/>. 17 17 18 18 [toolchain] 19 - channel = "1.82.0" 19 + channel = "1.88.0" 20 20 components = [ "rustfmt", "clippy" ]