commit 5029a09963b5753c1f9b7f777f28e1c0951343e7 Author: mat Date: Mon Dec 6 00:28:40 2021 -0600 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..3b614348 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.formatOnSave": true +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..916bbaa7 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,704 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "async-recursion" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bot" +version = "0.1.0" +dependencies = [ + "minecraft-client", + "minecraft-protocol", + "tokio", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "data-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" + +[[package]] +name = "enum-as-inner" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" + +[[package]] +name = "futures-io" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" + +[[package]] +name = "futures-sink" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af" + +[[package]] +name = "futures-task" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12" + +[[package]] +name = "futures-util" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipconfig" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" +dependencies = [ + "socket2", + "widestring", + "winapi", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" + +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "minecraft-client" +version = "0.1.0" +dependencies = [ + "minecraft-protocol", +] + +[[package]] +name = "minecraft-protocol" +version = "0.1.0" +dependencies = [ + "async-recursion", + "byteorder", + "bytes", + "thiserror", + "tokio", + "tokio-util", + "trust-dns-resolver", +] + +[[package]] +name = "mio" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project-lite" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" + +[[package]] +name = "proc-macro2" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + +[[package]] +name = "smallvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" + +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if", + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "winapi", +] + +[[package]] +name = "tokio-util" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "trust-dns-proto" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0d7f5db438199a6e2609debe3f69f808d074e0a2888ee0bccb45fe234d03f4" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "lazy_static", + "log", + "rand", + "smallvec", + "thiserror", + "tinyvec", + "tokio", + "url", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ad17b608a64bd0735e67bde16b0636f8aa8591f831a25d18443ed00a699770" +dependencies = [ + "cfg-if", + "futures-util", + "ipconfig", + "lazy_static", + "log", + "lru-cache", + "parking_lot", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "trust-dns-proto", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "widestring" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winreg" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +dependencies = [ + "winapi", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..0b621513 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[workspace] + +members = [ + "bot", + "minecraft-client", + "minecraft-protocol", +] \ No newline at end of file diff --git a/bot/Cargo.toml b/bot/Cargo.toml new file mode 100644 index 00000000..f1c89a99 --- /dev/null +++ b/bot/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "bot" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +minecraft-client = { path = "../minecraft-client" } +minecraft-protocol = { path = "../minecraft-protocol" } +tokio = "^1.14.0" diff --git a/bot/src/main.rs b/bot/src/main.rs new file mode 100644 index 00000000..def38c3d --- /dev/null +++ b/bot/src/main.rs @@ -0,0 +1,17 @@ +use minecraft_client; +use minecraft_protocol::ServerAddress; +use tokio::runtime::Runtime; + +async fn bot() { + let address = ServerAddress::parse(&"play.wynncraft.com".to_string()).unwrap(); + minecraft_protocol::server_status_pinger::ping_server(&address) + .await + .unwrap(); +} + +fn main() { + println!("Hello, world!"); + + let io_loop = Runtime::new().unwrap(); + io_loop.block_on(bot()); +} diff --git a/minecraft-client/Cargo.toml b/minecraft-client/Cargo.toml new file mode 100644 index 00000000..10a0ecbf --- /dev/null +++ b/minecraft-client/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "minecraft-client" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +minecraft-protocol = { path = "../minecraft-protocol" } \ No newline at end of file diff --git a/minecraft-client/src/lib.rs b/minecraft-client/src/lib.rs new file mode 100644 index 00000000..2670101f --- /dev/null +++ b/minecraft-client/src/lib.rs @@ -0,0 +1,10 @@ +use minecraft_protocol; + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + let result = 2 + 2; + assert_eq!(result, 4); + } +} diff --git a/minecraft-protocol/Cargo.toml b/minecraft-protocol/Cargo.toml new file mode 100644 index 00000000..83657153 --- /dev/null +++ b/minecraft-protocol/Cargo.toml @@ -0,0 +1,15 @@ +[package] +edition = "2021" +name = "minecraft-protocol" +version = "0.1.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-recursion = "^0.3.2" +byteorder = "^1.4.3" +bytes = "^1.1.0" +thiserror = "^1.0.30" +tokio = {version = "^1.14.0", features = ["io-util"]} +tokio-util = "^0.6.9" +trust-dns-resolver = "^0.20.3" diff --git a/minecraft-protocol/src/connection.rs b/minecraft-protocol/src/connection.rs new file mode 100644 index 00000000..4fa1cde7 --- /dev/null +++ b/minecraft-protocol/src/connection.rs @@ -0,0 +1,38 @@ +use crate::ServerIpAddress; +use bytes::BytesMut; +use tokio::{io::BufWriter, net::TcpStream}; + +pub enum PacketFlow { + ClientToServer, + ServerToClient, +} + +pub struct Connection { + pub flow: PacketFlow, + pub stream: BufWriter, + /// The read buffer + pub buffer: BytesMut, +} + +impl Connection { + pub async fn new(address: &ServerIpAddress) -> Result { + let ip = address.ip; + let port = address.port; + + let stream = TcpStream::connect(format!("{}:{}", ip, port)) + .await + .map_err(|_| "Failed to connect to server")?; + + // enable tcp_nodelay + stream + .set_nodelay(true) + .expect("Error enabling tcp_nodelay"); + + Ok(Connection { + flow: PacketFlow::ClientToServer, + stream: BufWriter::new(stream), + // 4mb read buffer + buffer: BytesMut::with_capacity(4 * 1024 * 1024), + }) + } +} diff --git a/minecraft-protocol/src/friendly_byte_buf.rs b/minecraft-protocol/src/friendly_byte_buf.rs new file mode 100644 index 00000000..2babe398 --- /dev/null +++ b/minecraft-protocol/src/friendly_byte_buf.rs @@ -0,0 +1,56 @@ +//! Minecraft calls it a "friendly byte buffer". + +use byteorder::{BigEndian, WriteBytesExt}; +// use std::io::Write; + +const MAX_VARINT_SIZE: u32 = 5; +const MAX_VARLONG_SIZE: u32 = 10; +const DEFAULT_NBT_QUOTA: u32 = 2097152; +const MAX_STRING_LENGTH: u16 = 32767; +const MAX_COMPONENT_STRING_LENGTH: u32 = 262144; + +pub struct FriendlyByteBuf<'a> { + source: &'a mut Vec, +} + +impl FriendlyByteBuf<'_> { + pub fn write_byte(&mut self, n: u8) { + self.source.write_u8(n).unwrap(); + println!("write_byte: {}", n); + } + + pub fn write_bytes(&mut self, bytes: &[u8]) { + self.source.extend_from_slice(bytes); + } + + pub fn write_varint(&mut self, mut n: u32) { + loop { + if (n & 0xFFFFFF80) == 0 { + self.write_byte(n as u8); + return (); + } + self.write_byte((n & 0x7F | 0x80) as u8); + n >>= 7; + } + } + + pub fn write_utf_with_len(&mut self, string: &String, len: usize) { + if string.len() > len { + panic!( + "String too big (was {} bytes encoded, max {})", + string.len(), + len + ); + } + self.write_varint(string.len() as u32); + self.write_bytes(string.as_bytes()); + } + + pub fn write_utf(&mut self, string: &String) { + self.write_utf_with_len(string, MAX_STRING_LENGTH as usize); + } + + pub fn write_short(&mut self, n: u16) { + self.source.write_u16::(n).unwrap(); + } +} diff --git a/minecraft-protocol/src/lib.rs b/minecraft-protocol/src/lib.rs new file mode 100644 index 00000000..8c647dc2 --- /dev/null +++ b/minecraft-protocol/src/lib.rs @@ -0,0 +1,53 @@ +use std::net::IpAddr; +use std::net::TcpStream; +use std::str::FromStr; + +use tokio::runtime::Runtime; + +pub mod connection; +pub mod friendly_byte_buf; +pub mod packets; +pub mod resolver; +pub mod server_status_pinger; + +#[derive(Debug)] +pub struct ServerAddress { + pub host: String, + pub port: u16, +} + +#[derive(Debug)] +pub struct ServerIpAddress { + pub ip: IpAddr, + pub port: u16, +} + +impl ServerAddress { + /// Convert a Minecraft server address (host:port, the port is optional) to a ServerAddress + pub fn parse(string: &String) -> Result { + if string.is_empty() { + return Err("Empty string".to_string()); + } + let mut parts = string.split(':'); + let host = parts.next().ok_or("No host specified")?.to_string(); + // default the port to 25565 + let port = parts.next().unwrap_or("25565"); + let port = u16::from_str(port).map_err(|_| "Invalid port specified")?; + Ok(ServerAddress { host, port }) + } +} + +pub async fn connect(address: ServerAddress) -> Result<(), Box> { + let resolved_address = resolver::resolve_address(&address).await; + println!("Resolved address: {:?}", resolved_address); + Ok(()) +} + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + let result = 2 + 2; + assert_eq!(result, 4); + } +} diff --git a/minecraft-protocol/src/packets/client_intention_packet.rs b/minecraft-protocol/src/packets/client_intention_packet.rs new file mode 100644 index 00000000..fdbd9468 --- /dev/null +++ b/minecraft-protocol/src/packets/client_intention_packet.rs @@ -0,0 +1,21 @@ +use crate::friendly_byte_buf::FriendlyByteBuf; + +use super::{ConnectionProtocol, Packet}; + +pub struct ClientIntentionPacket { + protocol_version: u32, + hostname: String, + port: u16, + intention: ConnectionProtocol, +} + +// implement "Packet" for "ClientIntentionPacket" +impl Packet for ClientIntentionPacket { + // implement "from_reader" for "ClientIntentionPacket" + fn write(&self, buf: &mut FriendlyByteBuf) { + buf.write_varint(self.protocol_version); + buf.write_utf(&self.hostname); + buf.write_short(self.port); + buf.write_varint(self.intention.clone() as u32); + } +} diff --git a/minecraft-protocol/src/packets/mod.rs b/minecraft-protocol/src/packets/mod.rs new file mode 100644 index 00000000..530a1b4b --- /dev/null +++ b/minecraft-protocol/src/packets/mod.rs @@ -0,0 +1,27 @@ +pub mod client_intention_packet; + +use crate::friendly_byte_buf::FriendlyByteBuf; + +#[derive(Debug, Clone, PartialEq)] +pub enum ConnectionProtocol { + Handshaking = -1, + Play = 0, + Status = 1, + Login = 2, +} + +pub trait Packet { + fn write(&self, friendly_byte_buf: &mut FriendlyByteBuf) -> (); +} + +struct PacketSet<'a> { + pub packets: Vec<&'a dyn Packet>, +} + +impl<'a> PacketSet<'a> { + fn add_packet(&mut self, packet: &'a dyn Packet) { + self.packets.push(packet); + } +} + +// PacketSet diff --git a/minecraft-protocol/src/resolver.rs b/minecraft-protocol/src/resolver.rs new file mode 100644 index 00000000..5dc6df8b --- /dev/null +++ b/minecraft-protocol/src/resolver.rs @@ -0,0 +1,56 @@ +use std::net::IpAddr; + +use crate::{ServerAddress, ServerIpAddress}; +use async_recursion::async_recursion; +use trust_dns_resolver::{ + config::{ResolverConfig, ResolverOpts}, + TokioAsyncResolver, +}; + +/// Resolve a Minecraft server address into an IP address and port. +/// If it's already an IP address, it's returned as-is. +#[async_recursion] +pub async fn resolve_address(address: &ServerAddress) -> Result { + // If the address.host is already in the format of an ip address, return it. + if let Ok(ip) = address.host.parse::() { + return Ok(ServerIpAddress { + ip: ip, + port: address.port, + }); + } + + // we specify Cloudflare instead of the default resolver because trust_dns_resolver has an issue on Windows where it's really slow using the default resolver + let resolver = + TokioAsyncResolver::tokio(ResolverConfig::cloudflare(), ResolverOpts::default()).unwrap(); + + // first, we do a srv lookup for _minecraft._tcp. + let srv_redirect_result = resolver + .srv_lookup(format!("_minecraft._tcp.{}", address.host).as_str()) + .await; + + // if it resolves that means it's a redirect so we call resolve_address again with the new host + if srv_redirect_result.is_ok() { + let redirect_result = srv_redirect_result.unwrap(); + let redirect_srv = redirect_result + .iter() + .next() + .ok_or_else(|| "No SRV record found".to_string())?; + let redirect_address = ServerAddress { + host: redirect_srv.target().to_utf8(), + port: redirect_srv.port(), + }; + + println!("redirecting to {:?}", redirect_address); + + return resolve_address(&redirect_address).await; + } + + // there's no redirect, try to resolve this as an ip address + let lookup_ip_result = resolver.lookup_ip(address.host.clone()).await; + let lookup_ip = lookup_ip_result.map_err(|_| "No IP found".to_string())?; + + Ok(ServerIpAddress { + ip: lookup_ip.iter().next().unwrap(), + port: address.port, + }) +} diff --git a/minecraft-protocol/src/server_status_pinger.rs b/minecraft-protocol/src/server_status_pinger.rs new file mode 100644 index 00000000..86d0cae9 --- /dev/null +++ b/minecraft-protocol/src/server_status_pinger.rs @@ -0,0 +1,100 @@ +use crate::{connection::Connection, resolver, ServerAddress}; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt, BufWriter}, + net::TcpStream, +}; + +struct ServerStatus {} + +async fn write_byte(buf: &mut Vec, n: u8) { + buf.write_u8(n).await.unwrap(); + println!("write_byte: {}", n); +} + +async fn write_bytes(buf: &mut Vec, bytes: &[u8]) { + buf.write_all(bytes).await.unwrap(); + println!("write_bytes: {:?}", buf); +} + +async fn write_varint(buf: &mut Vec, mut n: u32) { + loop { + if (n & 0xFFFFFF80) == 0 { + write_byte(buf, n as u8).await; + return (); + } + write_byte(buf, (n & 0x7F | 0x80) as u8).await; + n >>= 7; + } +} + +async fn write_utf(buf: &mut Vec, string: &[u8], len: usize) { + if string.len() > len { + panic!( + "String too big (was {} bytes encoded, max {})", + string.len(), + len + ); + } + write_varint(buf, string.len() as u32).await; + write_bytes(buf, string).await; +} + +async fn write_short(buf: &mut Vec, n: u16) { + buf.write_u16(n).await.unwrap(); + println!("write_short: {}", n); +} + +pub async fn ping_server(address: &ServerAddress) -> Result<(), String> { + let resolved_address = resolver::resolve_address(&address).await?; + + let mut conn = Connection::new(&resolved_address).await?; + + // protocol version is 757 + + // client intention packet + // friendlyByteBuf.writeVarInt(this.protocolVersion); + // friendlyByteBuf.writeUtf(this.hostName); + // friendlyByteBuf.writeShort(this.port); + // friendlyByteBuf.writeVarInt(this.intention.getId()); + + println!("resolved_address {}", &resolved_address.ip); + println!("writing intention packet {}", address.host); + + let mut buf: Vec = vec![0x00]; // 0 is the packet id for handshake + write_varint(&mut buf, 757).await; + write_utf(&mut buf, address.host.as_bytes(), 32767).await; + write_short(&mut buf, address.port).await; + write_varint(&mut buf, 1).await; + + let mut full_buffer = vec![]; + write_varint(&mut full_buffer, buf.len() as u32).await; // length of 1st packet id + data as VarInt + full_buffer.append(&mut buf); + full_buffer.extend_from_slice(&[ + 1, // length of 2nd packet id + data as VarInt + 0x00, // 2nd packet id: 0 for request as VarInt + ]); + + conn.stream.write_all(&full_buffer).await.unwrap(); + conn.stream.flush().await.unwrap(); + + // log what the server sends back + loop { + if 0 == conn.stream.read_buf(&mut conn.buffer).await.unwrap() { + // The remote closed the connection. For this to be a clean + // shutdown, there should be no data in the read buffer. If + // there is, this means that the peer closed the socket while + // sending a frame. + + // log conn.buffer + println!("{:?}", conn.buffer); + if conn.buffer.is_empty() { + println!("buffer is empty ok"); + return Ok(()); + } else { + return Err("connection reset by peer".into()); + } + } + } + + Ok(()) +}