не хуйня

This commit is contained in:
GIKExe 2025-05-08 09:40:44 +03:00
parent 8f07ea37e7
commit dfd6f56f76
12 changed files with 1489 additions and 117 deletions

512
Cargo.lock generated
View File

@ -17,6 +17,21 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.4.0" version = "1.4.0"
@ -38,36 +53,250 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.9.0" version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "bumpalo"
version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.10.1" version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cc"
version = "1.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0"
dependencies = [
"shlex",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
dependencies = [
"android-tzdata",
"iana-time-zone",
"num-traits",
"serde",
"windows-link",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "crc32fast"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
[[package]]
name = "darling"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "deranged"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
dependencies = [
"powerfmt",
"serde",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "flate2"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
dependencies = [
"crc32fast",
"libz-sys",
"miniz_oxide",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.31.1" version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "iana-time-zone"
version = "0.1.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
"serde",
]
[[package]]
name = "indexmap"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown 0.15.3",
"serde",
]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "js-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.172" version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "libz-sys"
version = "1.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d"
dependencies = [
"cc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.12" version = "0.4.12"
@ -78,6 +307,12 @@ dependencies = [
"scopeguard", "scopeguard",
] ]
[[package]]
name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"
@ -104,6 +339,21 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "object" name = "object"
version = "0.36.7" version = "0.36.7"
@ -113,6 +363,12 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.3" version = "0.12.3"
@ -142,6 +398,18 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pkg-config"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.95" version = "1.0.95"
@ -173,6 +441,10 @@ dependencies = [
name = "rust_mc_serv" name = "rust_mc_serv"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"flate2",
"serde",
"serde_json",
"serde_with",
"tokio", "tokio",
] ]
@ -182,12 +454,92 @@ version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustversion"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "serde_with"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa"
dependencies = [
"base64",
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.9.0",
"serde",
"serde_derive",
"serde_json",
"serde_with_macros",
"time",
]
[[package]]
name = "serde_with_macros"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.4.5" version = "1.4.5"
@ -213,6 +565,12 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.101" version = "2.0.101"
@ -224,6 +582,37 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "time"
version = "0.3.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
[[package]]
name = "time-macros"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
dependencies = [
"num-conv",
"time-core",
]
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.45.0" version = "1.45.0"
@ -259,12 +648,135 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]]
name = "windows-core"
version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
[[package]]
name = "windows-result"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
dependencies = [
"windows-link",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"

View File

@ -4,8 +4,8 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
# async-trait = {version = "0.1.88", optional = true}
tokio = {version = "1.45.0", features = ["full"]} tokio = {version = "1.45.0", features = ["full"]}
flate2 = {version = "1.1.1", features = ["zlib"]}
# [features] serde = {version = "1.0.219", features = ["derive"]}
# async = ["async-trait"] serde_with = "3.12.0"
serde_json = "1.0.140"

123
src/cycle.rs Normal file
View File

@ -0,0 +1,123 @@
use tokio::net::TcpStream;
use crate::data::{clientbound, serverbound, DataError, AsyncReader, DataWriter, Packet, TextComponentBuilder};
#[derive(Debug)]
pub enum PacketError {
WrongPacketID,
Data(DataError),
NextStateIncorrect,
}
impl From<DataError> for PacketError {
fn from(err: DataError) -> Self {
PacketError::Data(err)
}
}
pub async fn main(mut stream: TcpStream) {
let Ok(addr) = stream.peer_addr() else {
return;
};
println!("Подключение: {addr}");
// читаем первый пакет
match read_first_packet(&mut stream).await {
Ok(_) => {}, Err(e) => println!("Ошибка во время обработки пакета: {e:?}")
}
println!("Отключение: {addr}");
println!();
}
async fn read_first_packet(stream: &mut TcpStream) -> Result<(), PacketError> {
let mut packet = stream.read_packet(None).await?;
if packet.id() != 0 { return Err(PacketError::WrongPacketID);}
let version = packet.read_varint().await?;
let host = packet.read_string().await?;
let port = packet.read_short().await?;
let ns = packet.read_varint().await?;
if version != 770 {
let mut packet = Packet::empty(0x00);
let component =
TextComponentBuilder::new()
.text("Версия игры отличается от 1.21.5")
.color("red")
.build();
packet.write_string(&component.as_json()?).await?;
return Ok(stream.write_packet(packet, None).await?);
}
match ns {
1 => the_status(stream).await,
2 => the_login(stream, (version, host, port)).await,
_ => Err(PacketError::NextStateIncorrect)
}
}
async fn the_status(stream: &mut TcpStream) -> Result<(), PacketError> {
let packet = stream.read_packet(None).await?;
if packet.id() != 0 { return Err(PacketError::WrongPacketID); }
let mut p = Packet::empty(clientbound::status::RESPONSE);
let status = "{
\"version\": {
\"name\": \"1.21.5\",
\"protocol\": 770
},
\"players\": {
\"max\": 0,
\"online\": 1
}
}";
p.write_string(status).await?;
stream.write_packet(p, None).await?;
let mut packet = stream.read_packet(None).await?;
if packet.id() != 1 { return Err(PacketError::WrongPacketID); }
let mut p = Packet::empty(clientbound::status::PONG_RESPONSE);
p.write_long(packet.read_long().await?).await?;
stream.write_packet(p, None).await?;
Ok(())
}
async fn the_login(stream: &mut TcpStream, data: (i32, String, u16)) -> Result<(), PacketError> {
if data.0 != 770 {
let mut packet = Packet::empty(clientbound::login::DISCONNECT);
let component =
TextComponentBuilder::new()
.text("Версия игры отличается от 1.21.5")
.color("red")
.build();
packet.write_string(&component.as_json()?).await?;
return Ok(stream.write_packet(packet, None).await?);
}
// println!("Версия протокола: {}", data.0);
// println!("Адрес сервера: {}:{}", data.1, data.2);
// let mut packet = Packet::empty(clientbound::login::DISCONNECT);
// let component =
// TextComponentBuilder::new()
// .text("Вы кто такие? Я вас не звал. Идите нахуй.")
// .color("red")
// .build();
// packet.write_string(&component.as_json()?).await?;
// return Ok(stream.write_packet(packet, None).await?);
let mut packet = stream.read_packet(None).await?;
if packet.id() != serverbound::login::START { return Err(PacketError::WrongPacketID); }
let username = packet.read_string().await?;
let uuid = packet.read_uuid().await?;
println!("Адрес клиента: {:?}", stream.peer_addr());
println!("Адрес сервера: {}:{}", data.1, data.2);
println!("Username: {username}\n UUID: {:X}", uuid);
let mut packet = Packet::empty(clientbound::login::SET_COMPRESSION);
packet.write_varint(512).await?;
Ok(())
}

View File

@ -1,82 +0,0 @@
use std::io::{Cursor, Read, Write};
use tokio::io::{AsyncRead, AsyncReadExt};
use crate::inet::InetError;
#[derive(Debug)]
pub enum DataError {
ReadError,
WriteError,
VarIntIsSoBig,
StringDecodeError,
Inet(InetError),
}
pub trait DataReader {
async fn read_bytes(&mut self, size: usize) -> Result<Vec<u8>, DataError>;
async fn read_byte(&mut self) -> Result<u8, DataError> {
Ok(self.read_bytes(1).await?[0])
}
async fn read_signed_byte(&mut self) -> Result<i8, DataError> {
Ok(self.read_byte().await? as i8)
}
async fn read_short(&mut self) -> Result<u16, DataError> {
Ok(u16::from_be_bytes(
self.read_bytes(2).await?.try_into().unwrap(),
))
}
async fn read_signed_short(&mut self) -> Result<i16, DataError> {
Ok(self.read_short().await? as i16)
}
async fn read_varint_size(&mut self) -> Result<(i32, usize), DataError> {
let mut value = 0;
let mut position = 0;
loop {
let byte = self.read_byte().await?;
value |= ((byte & 0x7F) as i32) << (position * 7);
if (byte & 0x80) == 0 {
return Ok((value, position as usize));
};
position += 1;
if position >= 5 {
return Err(DataError::VarIntIsSoBig);
};
}
}
async fn read_varint(&mut self) -> Result<i32, DataError> {
Ok(self.read_varint_size().await?.0)
}
// async fn read_packet(&mut self, threshold: Option<usize>) -> Result<Cursor<Vec<u8>>, DataError> {
// let size = self.read_varint().await?;
// let mut buf = self.read_bytes(size).await?;
// }
async fn read_string(&mut self) -> Result<String, DataError> {
let size = self.read_varint().await?;
let vec = self.read_bytes(size as usize).await?;
String::from_utf8(vec).map_err(|_| DataError::StringDecodeError)
}
}
impl<R: AsyncRead + Unpin> DataReader for R {
async fn read_bytes(&mut self, size: usize) -> Result<Vec<u8>, DataError> {
let mut buf = vec![0; size];
let mut read = 0;
while read < size {
match AsyncReadExt::read(self, &mut buf[read..]).await {
Ok(0) => return Err(DataError::Inet(InetError::ConnectionClosed)),
Ok(n) => read += n,
Err(_) => return Err(DataError::ReadError),
}
}
Ok(buf)
}
}

106
src/data/async_reader.rs Normal file
View File

@ -0,0 +1,106 @@
use std::io::{Cursor, ErrorKind, Read};
use tokio::io::{AsyncRead, AsyncReadExt};
use crate::inet::InetError;
use super::{decompress, packet::Packet, DataError};
pub trait AsyncReader {
async fn read_bytes(&mut self, size: usize) -> Result<Vec<u8>, DataError>;
async fn read_byte(&mut self) -> Result<u8, DataError> {
Ok(self.read_bytes(1).await?[0])
}
async fn read_signed_byte(&mut self) -> Result<i8, DataError> {
Ok(self.read_byte().await? as i8)
}
async fn read_varint_size(&mut self) -> Result<(i32, usize), DataError> {
let mut value = 0;
let mut position = 0;
loop {
let byte = self.read_byte().await?;
value |= ((byte & 0x7F) as i32) << (position * 7);
if (byte & 0x80) == 0 {
return Ok((value, position as usize));
};
position += 1;
if position >= 5 {
return Err(DataError::VarIntIsSoBig);
};
}
}
async fn read_varint(&mut self) -> Result<i32, DataError> {
Ok(self.read_varint_size().await?.0)
}
async fn read_packet(&mut self, threshold: Option<usize>)
-> Result<Packet, DataError> {
let mut data: Vec<u8>;
let packet_lenght = self.read_varint().await? as usize;
if threshold.is_some() {
let data_lenght = self.read_varint_size().await?;
data = self.read_bytes(packet_lenght - data_lenght.1).await?;
if data_lenght.0 != 0 { data = decompress(&data)?; }
} else {
data = self.read_bytes(packet_lenght).await?;
}
let mut cursor = Cursor::new(data);
let id = cursor.read_varint().await?;
Ok(Packet::new(id as u8, cursor))
}
async fn read_short(&mut self) -> Result<u16, DataError> {
Ok(u16::from_be_bytes(
self.read_bytes(2).await?.try_into().unwrap()
))
}
async fn read_signed_short(&mut self) -> Result<i16, DataError> {
Ok(self.read_short().await? as i16)
}
async fn read_string(&mut self) -> Result<String, DataError> {
let size = self.read_varint().await?;
let vec = self.read_bytes(size as usize).await?;
String::from_utf8(vec).or( Err(DataError::StringDecodeError))
}
async fn read_long(&mut self) -> Result<u64, DataError> {
Ok(u64::from_be_bytes(
self.read_bytes(8).await?.try_into().unwrap()
))
}
async fn read_signed_long(&mut self) -> Result<i64, DataError> {
Ok(self.read_long().await? as i64)
}
async fn read_uuid(&mut self) -> Result<u128, DataError> {
Ok(u128::from_be_bytes(
self.read_bytes(16).await?.try_into().unwrap()
))
}
}
impl<R: AsyncRead + Unpin> AsyncReader for R {
async fn read_bytes(&mut self, size: usize) -> Result<Vec<u8>, DataError> {
let mut buf = vec![0; size];
match AsyncReadExt::read_exact(self, &mut buf).await {
Ok(_) => Ok(buf),
Err(e) => match e.kind() {
ErrorKind::UnexpectedEof | ErrorKind::BrokenPipe | ErrorKind::ConnectionReset => {
Err(DataError::Inet(InetError::ConnectionClosed))
}
_ => {
Err(DataError::ReadError)
},
}
}
}
}

212
src/data/component.rs Normal file
View File

@ -0,0 +1,212 @@
use std::io::Read;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use super::DataError;
#[derive(Debug, Serialize, Deserialize, Clone)]
#[skip_serializing_none]
pub struct TextComponent {
pub text: String,
pub color: Option<String>,
pub bold: Option<bool>,
pub italic: Option<bool>,
pub underlined: Option<bool>,
pub strikethrough: Option<bool>,
pub obfuscated: Option<bool>,
pub extra: Option<Vec<TextComponent>>,
}
impl TextComponent {
pub fn new(text: String) -> Self {
Self {
text,
color: None,
bold: None,
italic: None,
underlined: None,
strikethrough: None,
obfuscated: None,
extra: None,
}
}
// pub fn rainbow_offset(text: String, offset: i64) -> TextComponent {
// if text.is_empty() {
// return TextComponent::new(text);
// }
// let children = text
// .char_indices()
// .map(|(i, c)| {
// let hue = (((i as i64 + offset) % text.chars().count() as i64) as f32)
// / (text.chars().count() as f32)
// * 360.0;
// let hsl = Hsl::new(hue, 1.0, 0.5);
// let rgb: Srgb = hsl.into_color();
// let r = (rgb.red * 255.0).round() as u8;
// let g = (rgb.green * 255.0).round() as u8;
// let b = (rgb.blue * 255.0).round() as u8;
// let mut component = TextComponent::new(c.to_string());
// component.color = Some(format!("#{:02X}{:02X}{:02X}", r, g, b));
// component
// })
// .collect::<Vec<TextComponent>>();
// let mut parent = children[0].clone();
// if children.len() > 1 {
// parent.extra = Some(children[1..].to_vec());
// }
// parent
// }
// pub fn rainbow(text: String) -> TextComponent {
// if text.is_empty() {
// return TextComponent::new(text);
// }
// let children = text
// .char_indices()
// .map(|(i, c)| {
// let hue = (i as f32) / (text.chars().count() as f32) * 360.0;
// let hsl = Hsl::new(hue, 1.0, 0.5);
// let rgb: Srgb = hsl.into_color();
// let r = (rgb.red * 255.0).round() as u8;
// let g = (rgb.green * 255.0).round() as u8;
// let b = (rgb.blue * 255.0).round() as u8;
// let mut component = TextComponent::new(c.to_string());
// component.color = Some(format!("#{:02X}{:02X}{:02X}", r, g, b));
// component
// })
// .collect::<Vec<TextComponent>>();
// let mut parent = children[0].clone();
// if children.len() > 1 {
// parent.extra = Some(children[1..].to_vec());
// }
// parent
// }
pub fn builder() -> TextComponentBuilder {
TextComponentBuilder::new()
}
pub fn as_json(self) -> Result<String, DataError> {
serde_json::to_string(&self).or( Err(DataError::SerializationError))
}
pub fn from_json(text: &str) -> Result<TextComponent, DataError> {
serde_json::from_str(text).or( Err(DataError::DeSerializationError))
}
}
impl Default for TextComponent {
fn default() -> Self {
Self::new(String::new())
}
}
pub struct TextComponentBuilder {
text: String,
color: Option<String>,
bold: Option<bool>,
italic: Option<bool>,
underlined: Option<bool>,
strikethrough: Option<bool>,
obfuscated: Option<bool>,
extra: Option<Vec<TextComponent>>,
}
impl TextComponentBuilder {
pub fn new() -> Self {
Self {
text: String::new(),
color: None,
bold: None,
italic: None,
underlined: None,
strikethrough: None,
obfuscated: None,
extra: None,
}
}
pub fn text(mut self, text: &str) -> Self {
self.text = text.to_string();
self
}
pub fn color(mut self, color: &str) -> Self {
self.color = Some(color.to_string());
self
}
pub fn bold(mut self, bold: bool) -> Self {
self.bold = Some(bold);
self
}
pub fn italic(mut self, italic: bool) -> Self {
self.italic = Some(italic);
self
}
pub fn underlined(mut self, underlined: bool) -> Self {
self.underlined = Some(underlined);
self
}
pub fn strikethrough(mut self, strikethrough: bool) -> Self {
self.strikethrough = Some(strikethrough);
self
}
pub fn obfuscated(mut self, obfuscated: bool) -> Self {
self.obfuscated = Some(obfuscated);
self
}
pub fn extra(mut self, extra: Vec<TextComponent>) -> Self {
self.extra = Some(extra);
self
}
pub fn build(self) -> TextComponent {
TextComponent {
text: self.text,
color: self.color,
bold: self.bold,
italic: self.italic,
underlined: self.underlined,
strikethrough: self.strikethrough,
obfuscated: self.obfuscated,
extra: self.extra,
}
}
}
// Реализуем читалку-записывалку текст-компонентов для пакета
// impl ReadWriteNBT<TextComponent> for Packet {
// fn read_nbt(&mut self) -> Result<TextComponent, ServerError> {
// let mut data = Vec::new();
// let pos = self.get_ref().position();
// self
// .get_mut()
// .read_to_end(&mut data)
// .map_err(|_| ServerError::DeTextComponent)?;
// let (remaining, value) =
// craftflow_nbt::from_slice(&data).map_err(|_| ServerError::DeTextComponent)?;
// self
// .get_mut()
// .set_position(pos + (data.len() - remaining.len()) as u64);
// Ok(value)
// }
// fn write_nbt(&mut self, val: &TextComponent) -> Result<(), ServerError> {
// craftflow_nbt::to_writer(self.get_mut(), val).map_err(|_| ServerError::SerTextComponent)?;
// Ok(())
// }
// }

37
src/data/mod.rs Normal file
View File

@ -0,0 +1,37 @@
use std::io::Read;
use crate::inet::InetError;
mod async_reader;
mod reader;
mod writer;
mod packet;
mod packet_id;
mod component;
#[derive(Debug)]
pub enum DataError {
ReadError,
WriteError,
VarIntIsSoBig,
StringDecodeError,
Inet(InetError),
SerializationError,
DeSerializationError,
ZlibError,
}
pub fn decompress(bytes: &[u8]) -> Result<Vec<u8>, DataError> {
let mut decoder = ZlibDecoder::new(bytes);
let mut output = Vec::new();
decoder.read_to_end(&mut output).or(Err(DataError::ZlibError))?;
Ok(output)
}
pub use async_reader::*;
pub use reader::*;
use flate2::bufread::ZlibDecoder;
pub use writer::*;
pub use packet::*;
pub use packet_id::{clientbound, serverbound};
pub use component::*;

97
src/data/packet.rs Normal file
View File

@ -0,0 +1,97 @@
use std::io::Cursor;
use super::{DataError, async_reader::AsyncReader, writer::DataWriter};
#[derive(Debug, Clone)]
pub struct Packet {
id: u8,
cursor: Cursor<Vec<u8>>,
}
impl Packet {
/// Create new packet from id and buffer
pub fn new(id: u8, cursor: Cursor<Vec<u8>>) -> Packet {
Packet { id, cursor }
}
/// Create new packet with id and empty buffer
pub fn empty(id: u8) -> Packet {
Packet {
id,
cursor: Cursor::new(Vec::new()),
}
}
/// Build packet with lambda
pub fn build<F>(id: u8, builder: F) -> Result<Packet, DataError>
where
F: FnOnce(&mut Packet) -> Result<(), DataError>,
{
let mut packet = Self::empty(id);
builder(&mut packet)?;
Ok(packet)
}
/// Get packet id
pub fn id(&self) -> u8 {
self.id
}
/// Set packet id
pub fn set_id(&mut self, id: u8) {
self.id = id;
}
/// Set packet cursor
pub fn set_cursor(&mut self, cursor: Cursor<Vec<u8>>) {
self.cursor = cursor;
}
/// Get cursor length
pub fn len(&self) -> usize {
self.get_bytes().len() - self.cursor.position() as usize
}
/// Is cursor empty
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Get cursor remaining bytes
pub fn get_bytes(&self) -> &[u8] {
self.cursor.get_ref()
}
/// Get mutable reference to cursor
pub fn get_mut(&mut self) -> &mut Cursor<Vec<u8>> {
&mut self.cursor
}
/// Get immutable reference to cursor
pub fn get_ref(&self) -> &Cursor<Vec<u8>> {
&self.cursor
}
/// Get inner cursor
pub fn into_inner(self) -> Cursor<Vec<u8>> {
self.cursor
}
}
impl From<Packet> for Cursor<Vec<u8>> {
fn from(val: Packet) -> Self {
val.cursor
}
}
impl AsyncReader for Packet {
async fn read_bytes(&mut self, size: usize) -> Result<Vec<u8>, DataError> {
self.cursor.read_bytes(size).await
}
}
impl DataWriter for Packet {
async fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), DataError> {
self.cursor.write_bytes(bytes).await
}
}

272
src/data/packet_id.rs Normal file
View File

@ -0,0 +1,272 @@
/*
Generated with parse_ids.py
*/
pub mod clientbound {
pub mod status {
pub const RESPONSE: u8 = 0x00;
pub const PONG_RESPONSE: u8 = 0x01;
}
pub mod login {
pub const DISCONNECT: u8 = 0x00;
pub const ENCRYPTION_REQUEST: u8 = 0x01;
pub const SUCCESS: u8 = 0x02;
pub const SET_COMPRESSION: u8 = 0x03;
pub const PLUGIN_REQUEST: u8 = 0x04;
pub const COOKIE_REQUEST: u8 = 0x05;
}
pub mod configuration {
pub const COOKIE_REQUEST: u8 = 0x00;
pub const PLUGIN_MESSAGE: u8 = 0x01;
pub const DISCONNECT: u8 = 0x02;
pub const FINISH: u8 = 0x03;
pub const KEEP_ALIVE: u8 = 0x04;
pub const PING: u8 = 0x05;
pub const RESET_CHAT: u8 = 0x06;
pub const REGISTRY_DATA: u8 = 0x07;
pub const REMOVE_RESOURCE_PACK: u8 = 0x08;
pub const ADD_RESOURCE_PACK: u8 = 0x09;
pub const STORE_COOKIE: u8 = 0x0A;
pub const TRANSFER: u8 = 0x0B;
pub const FEATURE_FLAGS: u8 = 0x0C;
pub const UPDATE_TAGS: u8 = 0x0D;
pub const KNOWN_PACKS: u8 = 0x0E;
pub const CUSTOM_REPORT_DETAILS: u8 = 0x0F;
pub const SERVER_LINKS: u8 = 0x10;
}
pub mod play {
pub const BUNDLE_DELIMITER: u8 = 0x00;
pub const SPAWN_ENTITY: u8 = 0x01;
pub const ENTITY_ANIMATION: u8 = 0x02;
pub const AWARD_STATISTICS: u8 = 0x03;
pub const ACKNOWLEDGE_BLOCK_CHANGE: u8 = 0x04;
pub const SET_BLOCK_DESTROY_STAGE: u8 = 0x05;
pub const BLOCK_ENTITY_DATA: u8 = 0x06;
pub const BLOCK_ACTION: u8 = 0x07;
pub const BLOCK_UPDATE: u8 = 0x08;
pub const BOSS_BAR: u8 = 0x09;
pub const CHANGE_DIFFICULTY: u8 = 0x0A;
pub const CHUNK_BATCH_FINISHED: u8 = 0x0B;
pub const CHUNK_BATCH_START: u8 = 0x0C;
pub const CHUNK_BIOMES: u8 = 0x0D;
pub const CLEAR_TITLES: u8 = 0x0E;
pub const COMMAND_SUGGESTIONS_RESPONSE: u8 = 0x0F;
pub const COMMANDS: u8 = 0x10;
pub const CLOSE_CONTAINER: u8 = 0x11;
pub const SET_CONTAINER_CONTENT: u8 = 0x12;
pub const SET_CONTAINER_PROPERTY: u8 = 0x13;
pub const SET_CONTAINER_SLOT: u8 = 0x14;
pub const COOKIE_REQUEST: u8 = 0x15;
pub const SET_COOLDOWN: u8 = 0x16;
pub const CHAT_SUGGESTIONS: u8 = 0x17;
pub const PLUGIN_MESSAGE: u8 = 0x18;
pub const DAMAGE_EVENT: u8 = 0x19;
pub const DEBUG_SAMPLE: u8 = 0x1A;
pub const DELETE_MESSAGE: u8 = 0x1B;
pub const DISCONNECT: u8 = 0x1C;
pub const DISGUISED_CHAT_MESSAGE: u8 = 0x1D;
pub const ENTITY_EVENT: u8 = 0x1E;
pub const TELEPORT_ENTITY: u8 = 0x1F;
pub const EXPLOSION: u8 = 0x20;
pub const UNLOAD_CHUNK: u8 = 0x21;
pub const GAME_EVENT: u8 = 0x22;
pub const OPEN_HORSE_SCREEN: u8 = 0x23;
pub const HURT_ANIMATION: u8 = 0x24;
pub const INITIALIZE_WORLD_BORDER: u8 = 0x25;
pub const KEEP_ALIVE: u8 = 0x26;
pub const CHUNK_DATA_AND_UPDATE_LIGHT: u8 = 0x27;
pub const WORLD_EVENT: u8 = 0x28;
pub const PARTICLE: u8 = 0x29;
pub const UPDATE_LIGHT: u8 = 0x2A;
pub const LOGIN: u8 = 0x2B;
pub const MAP_DATA: u8 = 0x2C;
pub const MERCHANT_OFFERS: u8 = 0x2D;
pub const UPDATE_ENTITY_POSITION: u8 = 0x2E;
pub const UPDATE_ENTITY_POSITION_AND_ROTATION: u8 = 0x2F;
pub const MOVE_MINECART_ALONG_TRACK: u8 = 0x30;
pub const UPDATE_ENTITY_ROTATION: u8 = 0x31;
pub const MOVE_VEHICLE: u8 = 0x32;
pub const OPEN_BOOK: u8 = 0x33;
pub const OPEN_SCREEN: u8 = 0x34;
pub const OPEN_SIGN_EDITOR: u8 = 0x35;
pub const PING: u8 = 0x36;
pub const PING_RESPONSE: u8 = 0x37;
pub const PLACE_GHOST_RECIPE: u8 = 0x38;
pub const PLAYER_ABILITIES: u8 = 0x39;
pub const PLAYER_CHAT_MESSAGE: u8 = 0x3A;
pub const END_COMBAT: u8 = 0x3B;
pub const ENTER_COMBAT: u8 = 0x3C;
pub const COMBAT_DEATH: u8 = 0x3D;
pub const PLAYER_INFO_REMOVE: u8 = 0x3E;
pub const PLAYER_INFO_UPDATE: u8 = 0x3F;
pub const LOOK_AT: u8 = 0x40;
pub const SYNCHRONIZE_PLAYER_POSITION: u8 = 0x41;
pub const PLAYER_ROTATION: u8 = 0x42;
pub const RECIPE_BOOK_ADD: u8 = 0x43;
pub const RECIPE_BOOK_REMOVE: u8 = 0x44;
pub const RECIPE_BOOK_SETTINGS: u8 = 0x45;
pub const REMOVE_ENTITIES: u8 = 0x46;
pub const REMOVE_ENTITY_EFFECT: u8 = 0x47;
pub const RESET_SCORE: u8 = 0x48;
pub const REMOVE_RESOURCE_PACK: u8 = 0x49;
pub const ADD_RESOURCE_PACK: u8 = 0x4A;
pub const RESPAWN: u8 = 0x4B;
pub const SET_HEAD_ROTATION: u8 = 0x4C;
pub const UPDATE_SECTION_BLOCKS: u8 = 0x4D;
pub const SELECT_ADVANCEMENTS_TAB: u8 = 0x4E;
pub const SERVER_DATA: u8 = 0x4F;
pub const SET_ACTION_BAR_TEXT: u8 = 0x50;
pub const SET_BORDER_CENTER: u8 = 0x51;
pub const SET_BORDER_LERP_SIZE: u8 = 0x52;
pub const SET_BORDER_SIZE: u8 = 0x53;
pub const SET_BORDER_WARNING_DELAY: u8 = 0x54;
pub const SET_BORDER_WARNING_DISTANCE: u8 = 0x55;
pub const SET_CAMERA: u8 = 0x56;
pub const SET_CENTER_CHUNK: u8 = 0x57;
pub const SET_RENDER_DISTANCE: u8 = 0x58;
pub const SET_CURSOR_ITEM: u8 = 0x59;
pub const SET_DEFAULT_SPAWN_POSITION: u8 = 0x5A;
pub const DISPLAY_OBJECTIVE: u8 = 0x5B;
pub const SET_ENTITY_METADATA: u8 = 0x5C;
pub const LINK_ENTITIES: u8 = 0x5D;
pub const SET_ENTITY_VELOCITY: u8 = 0x5E;
pub const SET_EQUIPMENT: u8 = 0x5F;
pub const SET_EXPERIENCE: u8 = 0x60;
pub const SET_HEALTH: u8 = 0x61;
pub const SET_HELD_ITEM: u8 = 0x62;
pub const UPDATE_OBJECTIVES: u8 = 0x63;
pub const SET_PASSENGERS: u8 = 0x64;
pub const SET_PLAYER_INVENTORY_SLOT: u8 = 0x65;
pub const UPDATE_TEAMS: u8 = 0x66;
pub const UPDATE_SCORE: u8 = 0x67;
pub const SET_SIMULATION_DISTANCE: u8 = 0x68;
pub const SET_SUBTITLE_TEXT: u8 = 0x69;
pub const UPDATE_TIME: u8 = 0x6A;
pub const SET_TITLE_TEXT: u8 = 0x6B;
pub const SET_TITLE_ANIMATION_TIMES: u8 = 0x6C;
pub const ENTITY_SOUND_EFFECT: u8 = 0x6D;
pub const SOUND_EFFECT: u8 = 0x6E;
pub const START_CONFIGURATION: u8 = 0x6F;
pub const STOP_SOUND: u8 = 0x70;
pub const STORE_COOKIE: u8 = 0x71;
pub const SYSTEM_CHAT_MESSAGE: u8 = 0x72;
pub const SET_TAB_LIST_HEADER_AND_FOOTER: u8 = 0x73;
pub const TAG_QUERY_RESPONSE: u8 = 0x74;
pub const PICKUP_ITEM: u8 = 0x75;
pub const SYNCHRONIZE_VEHICLE_POSITION: u8 = 0x76;
pub const TEST_INSTANCE_BLOCK_STATUS: u8 = 0x77;
pub const SET_TICKING_STATE: u8 = 0x78;
pub const STEP_TICK: u8 = 0x79;
pub const TRANSFER: u8 = 0x7A;
pub const UPDATE_ADVANCEMENTS: u8 = 0x7B;
pub const UPDATE_ATTRIBUTES: u8 = 0x7C;
pub const ENTITY_EFFECT: u8 = 0x7D;
pub const UPDATE_RECIPES: u8 = 0x7E;
pub const UPDATE_TAGS: u8 = 0x7F;
pub const PROJECTILE_POWER: u8 = 0x80;
pub const CUSTOM_REPORT_DETAILS: u8 = 0x81;
pub const SERVER_LINKS: u8 = 0x82;
}
}
pub mod serverbound {
pub mod handshake {
pub const HANDSHAKE: u8 = 0x00;
}
pub mod status {
pub const REQUEST: u8 = 0x00;
pub const PING_REQUEST: u8 = 0x01;
}
pub mod login {
pub const START: u8 = 0x00;
pub const ENCRYPTION_RESPONSE: u8 = 0x01;
pub const PLUGIN_RESPONSE: u8 = 0x02;
pub const ACKNOWLEDGED: u8 = 0x03;
pub const COOKIE_RESPONSE: u8 = 0x04;
}
pub mod configuration {
pub const CLIENT_INFORMATION: u8 = 0x00;
pub const COOKIE_RESPONSE: u8 = 0x01;
pub const PLUGIN_MESSAGE: u8 = 0x02;
pub const ACKNOWLEDGE_FINISH: u8 = 0x03;
pub const KEEP_ALIVE: u8 = 0x04;
pub const PONG: u8 = 0x05;
pub const RESOURCE_PACK_RESPONSE: u8 = 0x06;
pub const KNOWN_PACKS: u8 = 0x07;
}
pub mod play {
pub const CONFIRM_TELEPORTATION: u8 = 0x00;
pub const QUERY_BLOCK_ENTITY_TAG: u8 = 0x01;
pub const BUNDLE_ITEM_SELECTED: u8 = 0x02;
pub const CHANGE_DIFFICULTY: u8 = 0x03;
pub const ACKNOWLEDGE_MESSAGE: u8 = 0x04;
pub const CHAT_COMMAND: u8 = 0x05;
pub const SIGNED_CHAT_COMMAND: u8 = 0x06;
pub const CHAT_MESSAGE: u8 = 0x07;
pub const PLAYER_SESSION: u8 = 0x08;
pub const CHUNK_BATCH_RECEIVED: u8 = 0x09;
pub const CLIENT_STATUS: u8 = 0x0A;
pub const CLIENT_TICK_END: u8 = 0x0B;
pub const CLIENT_INFORMATION: u8 = 0x0C;
pub const COMMAND_SUGGESTIONS_REQUEST: u8 = 0x0D;
pub const ACKNOWLEDGE_CONFIGURATION: u8 = 0x0E;
pub const CLICK_CONTAINER_BUTTON: u8 = 0x0F;
pub const CLICK_CONTAINER: u8 = 0x10;
pub const CLOSE_CONTAINER: u8 = 0x11;
pub const CHANGE_CONTAINER_SLOT_STATE: u8 = 0x12;
pub const COOKIE_RESPONSE: u8 = 0x13;
pub const PLUGIN_MESSAGE: u8 = 0x14;
pub const DEBUG_SAMPLE_SUBSCRIPTION: u8 = 0x15;
pub const EDIT_BOOK: u8 = 0x16;
pub const QUERY_ENTITY_TAG: u8 = 0x17;
pub const INTERACT: u8 = 0x18;
pub const JIGSAW_GENERATE: u8 = 0x19;
pub const KEEP_ALIVE: u8 = 0x1A;
pub const LOCK_DIFFICULTY: u8 = 0x1B;
pub const SET_PLAYER_POSITION: u8 = 0x1C;
pub const SET_PLAYER_POSITION_AND_ROTATION: u8 = 0x1D;
pub const SET_PLAYER_ROTATION: u8 = 0x1E;
pub const SET_PLAYER_MOVEMENT_FLAGS: u8 = 0x1F;
pub const MOVE_VEHICLE: u8 = 0x20;
pub const PADDLE_BOAT: u8 = 0x21;
pub const PICK_ITEM_FROM_BLOCK: u8 = 0x22;
pub const PICK_ITEM_FROM_ENTITY: u8 = 0x23;
pub const PING_REQUEST: u8 = 0x24;
pub const PLACE_RECIPE: u8 = 0x25;
pub const PLAYER_ABILITIES: u8 = 0x26;
pub const PLAYER_ACTION: u8 = 0x27;
pub const PLAYER_COMMAND: u8 = 0x28;
pub const PLAYER_INPUT: u8 = 0x29;
pub const PLAYER_LOADED: u8 = 0x2A;
pub const PONG: u8 = 0x2B;
pub const CHANGE_RECIPE_BOOK_SETTINGS: u8 = 0x2C;
pub const SET_SEEN_RECIPE: u8 = 0x2D;
pub const RENAME_ITEM: u8 = 0x2E;
pub const RESOURCE_PACK_RESPONSE: u8 = 0x2F;
pub const SEEN_ADVANCEMENTS: u8 = 0x30;
pub const SELECT_TRADE: u8 = 0x31;
pub const SET_BEACON_EFFECT: u8 = 0x32;
pub const SET_HELD_ITEM: u8 = 0x33;
pub const PROGRAM_COMMAND_BLOCK: u8 = 0x34;
pub const PROGRAM_COMMAND_BLOCK_MINECART: u8 = 0x35;
pub const SET_CREATIVE_MODE_SLOT: u8 = 0x36;
pub const PROGRAM_JIGSAW_BLOCK: u8 = 0x37;
pub const PROGRAM_STRUCTURE_BLOCK: u8 = 0x38;
pub const SET_TEST_BLOCK: u8 = 0x39;
pub const UPDATE_SIGN: u8 = 0x3A;
pub const SWING_ARM: u8 = 0x3B;
pub const TELEPORT_TO_ENTITY: u8 = 0x3C;
pub const TEST_INSTANCE_BLOCK_ACTION: u8 = 0x3D;
pub const USE_ITEM_ON: u8 = 0x3E;
pub const USE_ITEM: u8 = 0x3F;
}
}

20
src/data/reader.rs Normal file
View File

@ -0,0 +1,20 @@
use std::io::Read;
use super::DataError;
pub trait Reader {
fn read_bytes(&mut self, size: usize) -> Result<Vec<u8>, DataError>;
}
impl<R: Read> Reader for R {
fn read_bytes(&mut self, size: usize) -> Result<Vec<u8>, DataError> {
let mut buf = vec![0; size];
match self.read_exact(&mut buf) {
Ok(_) => Ok(buf),
Err(_) => Err(DataError::ReadError)
}
}
}

103
src/data/writer.rs Normal file
View File

@ -0,0 +1,103 @@
use std::io::{Cursor, Seek, SeekFrom, Write};
use flate2::{write::ZlibEncoder, Compression};
use tokio::io::{AsyncWrite, AsyncWriteExt};
use super::{packet::{self, Packet}, DataError};
pub fn compress(bytes: &[u8], compression: u32) -> Result<Vec<u8>, DataError> {
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::new(compression));
encoder.write_all(bytes).or(Err(DataError::ZlibError))?;
encoder.finish().or(Err(DataError::ZlibError))
}
pub trait DataWriter {
async fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), DataError>;
async fn write_byte(&mut self, value: u8) -> Result<(), DataError> {
self.write_bytes(&[value]).await
}
async fn write_signed_byte(&mut self, value: i8) -> Result<(), DataError> {
self.write_byte(value as u8).await
}
async fn write_varint_size(&mut self, value: i32) -> Result<usize, DataError> {
let mut _value = value as u32;
let mut position = 0;
loop {
let mut byte = (_value & 127) as u8;
position += 1; _value >>= 7;
if _value != 0 { byte += 128; };
self.write_byte(byte).await?;
if _value == 0 { return Ok(position) }
}
}
async fn write_varint(&mut self, value: i32) -> Result<(), DataError> {
self.write_varint_size(value).await?; Ok(())
}
async fn write_packet(&mut self, packet: Packet, threshold: Option<usize>)
-> Result<(), DataError> {
let mut buf = Vec::new();
let mut data_buf = Vec::new();
data_buf.write_varint((packet.id() as u32) as i32).await?;
data_buf.write_bytes(packet.get_bytes()).await?;
if let Some(threshold) = threshold {
let mut packet_buf = Vec::new();
if data_buf.len() > threshold {
packet_buf.write_varint(data_buf.len() as i32).await?;
let compressed_data = compress(&data_buf, 5)?;
Write::write_all(&mut packet_buf, &compressed_data).or(Err(DataError::WriteError))?;
} else {
packet_buf.write_varint(0).await?;
packet_buf.write_bytes(&data_buf).await?;
}
buf.write_varint(packet_buf.len() as i32).await?;
buf.write_bytes(&packet_buf).await?;
} else {
buf.write_varint(data_buf.len() as i32).await?;
buf.write_bytes(&data_buf).await?;
}
self.write_bytes(&buf).await?;
Ok(())
}
async fn write_short(&mut self, value: u16) -> Result<(), DataError> {
self.write_bytes(&value.to_be_bytes()).await
}
async fn write_signed_short(&mut self, value: i16) -> Result<(), DataError> {
self.write_short(value as u16).await
}
async fn write_string(&mut self, value: &str) -> Result<(), DataError> {
self.write_varint(value.len() as i32).await?;
self.write_bytes(value.as_bytes()).await?;
Ok(())
}
async fn write_long(&mut self, value: u64) -> Result<(), DataError> {
self.write_bytes(&value.to_be_bytes()).await
}
async fn write_signed_long(&mut self, value: i64) -> Result<(), DataError> {
self.write_long(value as u64).await
}
async fn write_uuid(&mut self, value: u128) -> Result<(), DataError> {
self.write_bytes(&value.to_be_bytes()).await
}
}
impl<W: AsyncWrite + Unpin> DataWriter for W {
async fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), DataError> {
AsyncWriteExt::write_all(self, bytes).await.or(Err(DataError::WriteError))
}
}

View File

@ -1,12 +1,11 @@
use std::{io::Cursor, net::Shutdown};
use data::{DataError, DataReader};
use inet::Server; use inet::Server;
use tokio::{io::AsyncWriteExt, net::TcpStream};
mod data; mod data;
mod inet; mod inet;
mod cycle;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
@ -17,34 +16,7 @@ async fn main() {
loop { loop {
let stream = server.accept().await; let stream = server.accept().await;
tokio::spawn(test(stream)); tokio::spawn(cycle::main(stream));
} }
} }
async fn test(mut stream: TcpStream) {
let Ok(addr) = stream.peer_addr() else {
return;
};
println!("Подключение: {addr}");
// читаем первый пакет
match read_first_packet(&mut stream).await {
Ok(_) => {}, Err(e) => println!("Ошибка во время обработки пакета: {e:?}")
}
println!("Отключение: {addr}");
println!();
}
async fn read_first_packet(stream: &mut TcpStream) -> Result<(), DataError> {
let size = stream.read_varint().await?;
let mut buf = Cursor::new(stream.read_bytes(size as usize).await?);
let id = buf.read_varint().await?;
let version = buf.read_varint().await?;
let host = buf.read_string().await?;
let port = buf.read_short().await?;
let ns = buf.read_varint().await?;
println!("Айди пакета: {id}");
println!("Версия протокола: {version}");
println!("Адрес сервера: {host}:{port}");
println!("Следующее состояние: {ns}");
Ok(())
}