+345
-91
Cargo.lock
+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
Cargo.toml
+1
crawlspace/Cargo.toml
+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
+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
+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
-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
-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
-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
-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
-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
-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
-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
+1
-1
crawlspace/src/protocol/packets/login/registry/biome.rs
+1
-1
crawlspace/src/protocol/packets/login/registry/dimension.rs
+1
-1
crawlspace/src/protocol/packets/login/registry/dimension.rs
+183
crawlspace/src/protocol/packets/play/world.rs
+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
+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
+1
-1
crawlspace/src/world/block_entity.rs
+13
crawlspace/src/world/blocks.rs
+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
+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
+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
+11
crawlspace-proto/Cargo.toml
+245
crawlspace-proto/src/datatypes/impls.rs
+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
+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
+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
+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
+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
+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
+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
+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
+10
crawlspace-proto-1_8/src/handshake.rs
+138
crawlspace-proto-1_8/src/lib.rs
+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
hub.slime
This is a binary file and will not be displayed.