diff --git a/.gitignore b/.gitignore index 7b273b1..2f7896d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -*.lock target/ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..cafdac8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,384 @@ +[root] +name = "steven" +version = "0.0.1" +dependencies = [ + "byteorder 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "glfw 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "steven_gl 0.0.1", + "steven_openssl 0.0.1", +] + +[[package]] +name = "advapi32-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cookie" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "openssl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "enum_primitive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "flate2" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gcc" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gl_common" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gl_generator" +version = "0.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "khronos_api 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "xml-rs 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glfw" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "enum_primitive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glfw-sys 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glfw-sys" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hpack" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "httparse" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hyper" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cookie 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "language-tags 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "khronos_api" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "language-tags" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libressl-pnacl-sys" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "matches" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "mime" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz-sys" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-sys" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pkg-config" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pnacl-build-helper" +version = "1.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tempdir 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-serialize" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "solicit" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "steven_gl" +version = "0.0.1" +dependencies = [ + "gl_common 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "gl_generator 0.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "khronos_api 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "steven_openssl" +version = "0.0.1" +dependencies = [ + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tempdir" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "traitobject" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "typeable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicase" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "url" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "xml-rs" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + diff --git a/Cargo.toml b/Cargo.toml index eb0514f..4f0ce64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [package] - -name = "steven_rust" +name = "steven" version = "0.0.1" authors = [ "Thinkofdeath " ] @@ -20,3 +19,6 @@ version = "0" [dependencies.steven_openssl] path = "./openssl" version = "0" + +[[bin]] +name = "steven" diff --git a/log.log b/log.log new file mode 100644 index 0000000..407d775 --- /dev/null +++ b/log.log @@ -0,0 +1,210 @@ +Compression: 256 +Login: Think b1184d43-1684-41cf-a212-8b9a3df3b6ab +JoinGame(JoinGame { entity_id: 47, gamemode: 1, dimension: 0, difficulty: 1, max_players: 20, level_type: "default", reduced_debug_info: false }) +PluginMessageClientbound(PluginMessageClientbound { channel: "REGISTER", data: [87, 69, 67, 85, 73, 0] }) +PluginMessageClientbound(PluginMessageClientbound { channel: "MC|Brand", data: [11, 67, 114, 97, 102, 116, 66, 117, 107, 107, 105, 116] }) +ServerDifficulty(ServerDifficulty { difficulty: 1 }) +SpawnPosition(SpawnPosition { location: <202,64,-93> }) +PlayerAbilities(PlayerAbilities { flags: 13, flying_speed: 0.05, walking_speed: 0.1 }) +SetCurrentHotbarSlot(SetCurrentHotbarSlot { slot: 5 }) +EntityAction(EntityAction { entity_id: 47, action_id: 28 }) +Statistics(Statistics { statistices: [] }) +MSG: Think joined the game +PlayerInfo(PlayerInfo { inner: PlayerInfoData { action: 0, players: [Add { uuid: UUID(5000938010188400878, 10192164627100470560), name: "Thinkofdeath", properties: [PlayerProperty { name: "textures", value: "eyJ0aW1lc3RhbXAiOjE0NDIwODM5NDgxMjMsInByb2ZpbGVJZCI6IjQ1NjZlNjlmYzkwNzQ4ZWU4ZDcxZDdiYTVhYTAwZDIwIiwicHJvZmlsZU5hbWUiOiJUaGlua29mZGVhdGgiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTNlODFiOWUxOWFiMWVmMTdhOTBjMGFhNGUxMDg1ZmMxM2NkNDdjZWQ1YTdhMWE0OTI4MDNiMzU2MWU0YTE1YiJ9LCJDQVBFIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTc4OTMyNzBmN2RmNjdhMjBlYTljOGFiNTJkN2FmZjIzMjcwZmM0M2ExMWZiM2RhZTYyMjkxNjM0YWY0MjQifX19", signature: Some("FUTqRMhKeZkCsFVBXlK5qJfB+7lxHBpHT0mHx1sZO32ml3TObw6ZLSqkOJvgj8lSstV3Zg248Ld08z+mEsVPR9qFjibQeFU2S1YKgEglfZOIlIWLrFmlpi2QEEAiUg43a/KpZh8ydNPiNrrhgz7LoHoKHg+lQFeuwqc/Q+pgIMCXsKTqVMOR36LMkMYDuoyhyJs2kop7JxYLE2puibwhki6RwLjU93I+UenVEtBygcu0Eo5FXM0s4kshwS97o6NsvkVq0n4QDLDm9pCVNQ//krLtrrdaq4ZmINBVroOy6XBiMy5Yct8H2EK7KXua1QTeihQwWYg2eWi6Wrjs11gzb9t0OaTv0deB9nljdjIl1ee2bpY320/OcOfFCtmPjb6baDUb34Gl0ZZEK4jQC1JXPpNGXoFPD7iYHYfIR2uqyWCvFqJufNx6XHYjFWFnk4nFJmalDliz3vRPzWC/X1m+1k25HNom+xY88NPGZPSsybBwa/DgunToQxSfy3W1cYti0RVCsAThW25OTZ32ZmRuRswcA9RAifAKa9B0uzrmh5jBJiYVLMM7uP2D6vMB6G4PEczwM56VsEs9eppiPYR9EQ+AKqR7wWPDeQck0n4SVOAYy0gLCgJqayg5xwMQikh8RdhVaNW1nfNRxiAaCs6WZoYmot/YRsTxB3aEw088YmI=") }], gamemode: 1, ping: 0, display: None }] } }) +PlayerInfo(PlayerInfo { inner: PlayerInfoData { action: 0, players: [Add { uuid: UUID(12761034494690214351, 11678550278305724075), name: "Think", properties: [PlayerProperty { name: "textures", value: "eyJ0aW1lc3RhbXAiOjE0NDIwODM5NTk4NTMsInByb2ZpbGVJZCI6ImIxMTg0ZDQzMTY4NDQxY2ZhMjEyOGI5YTNkZjNiNmFiIiwicHJvZmlsZU5hbWUiOiJUaGluayIsInRleHR1cmVzIjp7fX0=", signature: Some("c8KfMdq65VLdsBVrW1dtnIJM+OtCFXk5uCKvUZ7aTeBeQVQh2gSRNe303hbLkYNGtbY64nHcB1Pm2NF0P85Sl3S7MZDxWJmrGIQbnsS4Ptd+Y90Ub51eQxUy5EG78xYPvmTC6UBqVkQfhLfCQBkKLaYFb6ec8pMdmGubfttp0FTOIyQ6HU9x+kfx7K53McumV8P1LCzsjNGfm9tB1zg698LoPJHn5srSvUCAA1OLGsXpw/Zo8j8BwPpdHwq4KhSe0OYQD0xdw7EF3ih7eSPnBgfWADzCYsUC6AReAvbKo5uBtEtI+DGT33YGmJFhXCEo7B9EyXGZHQ+Yn+RXmXF4+l+e2A7I0GhvdjOi+REZvCksH5U9Ac8jqVr8BgtlJCPJD1xa3WteCngmovCyGb8ldeb0Ni27l0UqW0v6RbB9TQGfktwxJE7zZjU5pV2wV8XQq2VCwFzRy7KGyF4TFGoQtq2o9Spw6VWsT1rDQuJXJ8/XaSq624Sj8UkRm2RpJ6LesM6j+N8Q/ISetXHwreiR0SYHgoWCQuznAsELsSWcV7Af/7XfNEu5YmkWqzquEjx/LAlLWfLo5KwvlXjj9FOhcQXMqdNLJeoEsvlndtVUtY6yTfwZbLF7mG3UO06iRxP2GsO3rIFDmAqgD4iztcXW8wZASFsllPh9BN4+KhhkKDQ=") }], gamemode: 1, ping: 0, display: None }] } }) +PlayerInfo(PlayerInfo { inner: PlayerInfoData { action: 0, players: [Add { uuid: UUID(12761034494690214351, 11678550278305724075), name: "Think", properties: [PlayerProperty { name: "textures", value: "eyJ0aW1lc3RhbXAiOjE0NDIwODM5NTk4NTMsInByb2ZpbGVJZCI6ImIxMTg0ZDQzMTY4NDQxY2ZhMjEyOGI5YTNkZjNiNmFiIiwicHJvZmlsZU5hbWUiOiJUaGluayIsInRleHR1cmVzIjp7fX0=", signature: Some("c8KfMdq65VLdsBVrW1dtnIJM+OtCFXk5uCKvUZ7aTeBeQVQh2gSRNe303hbLkYNGtbY64nHcB1Pm2NF0P85Sl3S7MZDxWJmrGIQbnsS4Ptd+Y90Ub51eQxUy5EG78xYPvmTC6UBqVkQfhLfCQBkKLaYFb6ec8pMdmGubfttp0FTOIyQ6HU9x+kfx7K53McumV8P1LCzsjNGfm9tB1zg698LoPJHn5srSvUCAA1OLGsXpw/Zo8j8BwPpdHwq4KhSe0OYQD0xdw7EF3ih7eSPnBgfWADzCYsUC6AReAvbKo5uBtEtI+DGT33YGmJFhXCEo7B9EyXGZHQ+Yn+RXmXF4+l+e2A7I0GhvdjOi+REZvCksH5U9Ac8jqVr8BgtlJCPJD1xa3WteCngmovCyGb8ldeb0Ni27l0UqW0v6RbB9TQGfktwxJE7zZjU5pV2wV8XQq2VCwFzRy7KGyF4TFGoQtq2o9Spw6VWsT1rDQuJXJ8/XaSq624Sj8UkRm2RpJ6LesM6j+N8Q/ISetXHwreiR0SYHgoWCQuznAsELsSWcV7Af/7XfNEu5YmkWqzquEjx/LAlLWfLo5KwvlXjj9FOhcQXMqdNLJeoEsvlndtVUtY6yTfwZbLF7mG3UO06iRxP2GsO3rIFDmAqgD4iztcXW8wZASFsllPh9BN4+KhhkKDQ=") }], gamemode: 1, ping: 0, display: None }] } }) +UpdateBlockEntity(UpdateBlockEntity { location: <31,95,-116>, action: 5, nbt: Some(NamedTag("", Compound({"y": Int(95), "x": Int(31), "z": Int(-116), "Item": Int(38), "Data": Int(1), "id": String("FlowerPot")}))) }) +UpdateBlockEntity(UpdateBlockEntity { location: <31,95,-117>, action: 5, nbt: Some(NamedTag("", Compound({"z": Int(-117), "id": String("FlowerPot"), "y": Int(95), "Item": Int(38), "x": Int(31), "Data": Int(0)}))) }) +UpdateBlockEntity(UpdateBlockEntity { location: <30,95,-116>, action: 5, nbt: Some(NamedTag("", Compound({"Data": Int(2), "id": String("FlowerPot"), "Item": Int(38), "z": Int(-116), "y": Int(95), "x": Int(30)}))) }) +UpdateBlockEntity(UpdateBlockEntity { location: <28,92,-119>, action: 3, nbt: Some(NamedTag("", Compound({"Lock": String(""), "x": Int(28), "z": Int(-119), "Secondary": Int(0), "Primary": Int(0), "id": String("Beacon"), "y": Int(92), "Levels": Int(0)}))) }) +UpdateBlockEntity(UpdateBlockEntity { location: <28,95,-116>, action: 3, nbt: Some(NamedTag("", Compound({"Primary": Int(1), "Levels": Int(1), "y": Int(95), "id": String("Beacon"), "Lock": String(""), "z": Int(-116), "Secondary": Int(0), "x": Int(28)}))) }) +SpawnMob(SpawnMob { entity_id: 0, uuid: UUID(8318773244061304819, 12224757210753227758), ty: 90, x: 782, y: 3008, z: -3601, yaw: -126, pitch: -28, head_pitch: 125, velocity_x: 0, velocity_y: -627, velocity_z: 0, metadata: Metadata[ 3=Bool(false), 6=Float(10), 10=Byte(0), 1=Int(300), 11=Bool(false), 5=Byte(0), 9=Int(0), 8=Bool(false), 0=Byte(0), 12=Bool(false), 7=Int(0), 4=Bool(false), 2=String(""), ] }) +EntityMetadata(EntityMetadata { entity_id: 0, metadata: Metadata[ 2=String(""), 10=Byte(0), 4=Bool(false), 5=Byte(0), 8=Bool(false), 9=Int(0), 6=Float(10), 3=Bool(false), 11=Bool(false), 12=Bool(false), 1=Int(300), 7=Int(0), 0=Byte(0), ] }) +StatusRequest(StatusRequest { empty: () }) +EntityHeadLook(EntityHeadLook { entity_id: 0, head_yaw: 125 }) +SpawnMob(SpawnMob { entity_id: 1, uuid: UUID(15638293629224504267, 10167566484811300374), ty: 91, x: 817, y: 3008, z: -3634, yaw: 61, pitch: -28, head_pitch: 101, velocity_x: 0, velocity_y: -627, velocity_z: 0, metadata: Metadata[ 6=Float(8), 7=Int(0), 0=Byte(0), 1=Int(300), 9=Int(0), 3=Bool(false), 8=Bool(false), 4=Bool(false), 10=Byte(0), 11=Bool(false), 2=String("Steven The Sheep"), 12=Byte(0), 5=Byte(0), ] }) +EntityMetadata(EntityMetadata { entity_id: 1, metadata: Metadata[ 8=Bool(false), 9=Int(0), 10=Byte(0), 0=Byte(0), 11=Bool(false), 2=String("Steven The Sheep"), 12=Byte(0), 4=Bool(false), 3=Bool(false), 5=Byte(0), 1=Int(300), 7=Int(0), 6=Float(8), ] }) +StatusRequest(StatusRequest { empty: () }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 101 }) +SpawnPlayer(SpawnPlayer { entity_id: 46, uuid: UUID(5000938010188400878, 10192164627100470560), x: 777, y: 3072, z: -3686, yaw: -26, pitch: 25, metadata: Metadata[ 5=Byte(0), 3=Bool(false), 4=Bool(false), 0=Byte(0), 1=Int(300), 8=Bool(true), 10=Float(0), 7=Int(8171462), 9=Int(0), 13=Byte(1), 6=Float(20), 11=Int(0), 2=String(""), 12=Byte(127), ] }) +EntityMetadata(EntityMetadata { entity_id: 46, metadata: Metadata[ 6=Float(20), 3=Bool(false), 12=Byte(127), 1=Int(300), 0=Byte(0), 5=Byte(0), 7=Int(8171462), 13=Byte(1), 10=Float(0), 11=Int(0), 8=Bool(true), 2=String(""), 9=Int(0), 4=Bool(false), ] }) +StatusRequest(StatusRequest { empty: () }) +EntityEquipment(EntityEquipment { entity_id: 46, slot: 0, item: Some(Stack { id: 165, count: 64, damage: 0, tag: None }) }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -27 }) +StatusRequest(StatusRequest { empty: () }) +MSG: Hello world +TeleportPlayer(TeleportPlayer { x: 28.4464725021921, y: 95, z: -116.30000001192093, yaw: -178.90189, pitch: 37.049976, flags: 0 }) +WorldBorder(WorldBorder { action: 3, old_radius: Some(0), new_radius: Some(0), speed: Some(65), x: Some(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063061072628375414), z: Some(-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000630610726283749), portal_boundary: Some(29999984), warning_time: Some(5), warning_blocks: Some(15) }) +TimeUpdate(TimeUpdate { world_age: 7683709, time_of_day: 7872174 }) +StatusRequest(StatusRequest { empty: () }) +WindowItems(WindowItems { id: 0, items: [None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, Some(Stack { id: 50, count: 64, damage: 0, tag: None }), Some(Stack { id: 1, count: 64, damage: 0, tag: None }), Some(Stack { id: 1, count: 64, damage: 0, tag: None }), Some(Stack { id: 12, count: 64, damage: 0, tag: None }), Some(Stack { id: 2, count: 64, damage: 0, tag: None }), Some(Stack { id: 276, count: 64, damage: 0, tag: None }), None, None, None, None] }) +WindowSetSlot(WindowSetSlot { id: 255, property: -1, item: None }) +WindowSetSlot(WindowSetSlot { id: 0, property: 36, item: Some(Stack { id: 50, count: 64, damage: 0, tag: None }) }) +WindowSetSlot(WindowSetSlot { id: 0, property: 37, item: Some(Stack { id: 1, count: 64, damage: 0, tag: None }) }) +WindowSetSlot(WindowSetSlot { id: 0, property: 38, item: Some(Stack { id: 1, count: 64, damage: 0, tag: None }) }) +WindowSetSlot(WindowSetSlot { id: 0, property: 39, item: Some(Stack { id: 12, count: 64, damage: 0, tag: None }) }) +WindowSetSlot(WindowSetSlot { id: 0, property: 40, item: Some(Stack { id: 2, count: 64, damage: 0, tag: None }) }) +WindowSetSlot(WindowSetSlot { id: 0, property: 41, item: Some(Stack { id: 276, count: 64, damage: 0, tag: None }) }) +EntityMetadata(EntityMetadata { entity_id: 47, metadata: Metadata[ 1=Int(300), 8=Bool(false), 9=Int(0), 7=Int(0), 10=Float(0), 3=Bool(false), 5=Byte(0), 12=Byte(0), 0=Byte(0), 11=Int(0), 13=Byte(1), 4=Bool(false), 6=Float(20), 2=String(""), ] }) +StatusRequest(StatusRequest { empty: () }) +MSG: Welcome, Think! +MSG: Type /help for a list of commands. +MSG: Type /list to see who else is online. +MSG: Players online: 2 - World time: 6:10 AM +MSG: You have no new mail. +TimeUpdate(TimeUpdate { world_age: 7683712, time_of_day: 7872177 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityLook(EntityLook { entity_id: 0, yaw: -126, pitch: 0, on_ground: true }) +EntityMove(EntityMove { entity_id: 46, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +EntityLook(EntityLook { entity_id: 1, yaw: 61, pitch: 0, on_ground: true }) +TimeUpdate(TimeUpdate { world_age: 7683732, time_of_day: 7872197 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityMove(EntityMove { entity_id: 0, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +EntityMove(EntityMove { entity_id: 1, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +KeepAliveClientbound(KeepAliveClientbound { id: 37196518 }) +TimeUpdate(TimeUpdate { world_age: 7683752, time_of_day: 7872217 }) +BlockChange(BlockChange { location: <-9,85,-235>, block_id: 624 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityLook(EntityLook { entity_id: 0, yaw: -126, pitch: -29, on_ground: true }) +StatusRequest(StatusRequest { empty: () }) +StatusRequest(StatusRequest { empty: () }) +StatusRequest(StatusRequest { empty: () }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 79 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 58 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 37 }) +TimeUpdate(TimeUpdate { world_age: 7683772, time_of_day: 7872237 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 23 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityMove(EntityMove { entity_id: 46, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 39 }) +KeepAliveClientbound(KeepAliveClientbound { id: 37198568 }) +TimeUpdate(TimeUpdate { world_age: 7683792, time_of_day: 7872257 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityMove(EntityMove { entity_id: 0, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +EntityMove(EntityMove { entity_id: 1, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +SoundEffect(SoundEffect { name: "mob.sheep.say", x: 204, y: 752, z: -908, volume: 1, pitch: 58 }) +TimeUpdate(TimeUpdate { world_age: 7683812, time_of_day: 7872277 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityLook(EntityLook { entity_id: 0, yaw: -126, pitch: 0, on_ground: true }) +KeepAliveClientbound(KeepAliveClientbound { id: 37200618 }) +TimeUpdate(TimeUpdate { world_age: 7683832, time_of_day: 7872297 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityMove(EntityMove { entity_id: 46, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +StatusRequest(StatusRequest { empty: () }) +StatusRequest(StatusRequest { empty: () }) +StatusRequest(StatusRequest { empty: () }) +EntityLook(EntityLook { entity_id: 0, yaw: -126, pitch: -29, on_ground: true }) +TimeUpdate(TimeUpdate { world_age: 7683852, time_of_day: 7872317 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityMove(EntityMove { entity_id: 0, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +EntityMove(EntityMove { entity_id: 1, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +EntityLook(EntityLook { entity_id: 46, yaw: -46, pitch: 17, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -35 }) +EntityLook(EntityLook { entity_id: 46, yaw: -58, pitch: 9, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -53 }) +EntityLook(EntityLook { entity_id: 46, yaw: -71, pitch: 5, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -67 }) +EntityLook(EntityLook { entity_id: 46, yaw: -90, pitch: 5, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -77 }) +EntityLookAndMove(EntityLookAndMove { entity_id: 46, delta_x: 0, delta_y: 0, delta_z: -10, yaw: -95, pitch: 4, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -95 }) +SoundEffect(SoundEffect { name: "mob.pig.say", x: 195, y: 752, z: -900, volume: 1, pitch: 57 }) +EntityMove(EntityMove { entity_id: 46, delta_x: 7, delta_y: 0, delta_z: -9, on_ground: true }) +SoundEffect(SoundEffect { name: "step.grass", x: 197, y: 768, z: -927, volume: 0.15, pitch: 63 }) +TimeUpdate(TimeUpdate { world_age: 7683872, time_of_day: 7872337 }) +KeepAliveClientbound(KeepAliveClientbound { id: 37202669 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityLookAndMove(EntityLookAndMove { entity_id: 46, delta_x: 12, delta_y: 0, delta_z: -8, yaw: -85, pitch: 8, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -89 }) +EntityHeadLook(EntityHeadLook { entity_id: 0, head_yaw: -122 }) +EntityLookAndMove(EntityLookAndMove { entity_id: 46, delta_x: 5, delta_y: 0, delta_z: -4, yaw: -78, pitch: 11, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -83 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 60 }) +EntityLook(EntityLook { entity_id: 46, yaw: -52, pitch: 18, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -66 }) +EntityLookAndMove(EntityLookAndMove { entity_id: 46, delta_x: -4, delta_y: 0, delta_z: 14, yaw: -46, pitch: 19, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -47 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 82 }) +EntityMove(EntityMove { entity_id: 46, delta_x: -2, delta_y: 0, delta_z: 6, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 103 }) +EntityLook(EntityLook { entity_id: 46, yaw: -39, pitch: 22, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -42 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 124 }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -37 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: -115 }) +EntityLook(EntityLook { entity_id: 46, yaw: -32, pitch: 23, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -32 }) +TimeUpdate(TimeUpdate { world_age: 7683892, time_of_day: 7872357 }) +EntityLook(EntityLook { entity_id: 0, yaw: -126, pitch: 0, on_ground: true }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityMove(EntityMove { entity_id: 46, delta_x: -1, delta_y: 0, delta_z: 2, on_ground: true }) +EntityLook(EntityLook { entity_id: 46, yaw: 13, pitch: 18, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: -20 }) +EntityLook(EntityLook { entity_id: 46, yaw: 29, pitch: 19, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: 29 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 120 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 109 }) +TimeUpdate(TimeUpdate { world_age: 7683912, time_of_day: 7872377 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityMove(EntityMove { entity_id: 0, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +EntityMove(EntityMove { entity_id: 1, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +KeepAliveClientbound(KeepAliveClientbound { id: 37204718 }) +StatusRequest(StatusRequest { empty: () }) +StatusRequest(StatusRequest { empty: () }) +StatusRequest(StatusRequest { empty: () }) +TimeUpdate(TimeUpdate { world_age: 7683932, time_of_day: 7872397 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 88 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 67 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 59 }) +TimeUpdate(TimeUpdate { world_age: 7683952, time_of_day: 7872417 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +KeepAliveClientbound(KeepAliveClientbound { id: 37206768 }) +SoundEffect(SoundEffect { name: "mob.sheep.say", x: 204, y: 752, z: -908, volume: 1, pitch: 66 }) +EntityMove(EntityMove { entity_id: 46, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: -653, velocity_y: -627, velocity_z: 502 }) +EntityLook(EntityLook { entity_id: 0, yaw: -105, pitch: 0, on_ground: true }) +EntityVelocity(EntityVelocity { entity_id: 1, velocity_x: 399, velocity_y: -627, velocity_z: -363 }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: -597, velocity_y: -627, velocity_z: 879 }) +EntityLook(EntityLook { entity_id: 0, yaw: -63, pitch: 0, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 0, head_yaw: -109 }) +BlockChange(BlockChange { location: <-72,10,-189>, block_id: 624 }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: -647, velocity_y: -627, velocity_z: 607 }) +EntityLook(EntityLook { entity_id: 0, yaw: -97, pitch: 0, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 0, head_yaw: -95 }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: -166, velocity_y: -627, velocity_z: 140 }) +EntityVelocity(EntityVelocity { entity_id: 1, velocity_x: 0, velocity_y: -627, velocity_z: 0 }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: -695, velocity_y: -627, velocity_z: 686 }) +EntityVelocity(EntityVelocity { entity_id: 1, velocity_x: 396, velocity_y: -627, velocity_z: -399 }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: -141, velocity_y: -627, velocity_z: 0 }) +EntityVelocity(EntityVelocity { entity_id: 1, velocity_x: 0, velocity_y: -627, velocity_z: 0 }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: -689, velocity_y: -627, velocity_z: 604 }) +EntityVelocity(EntityVelocity { entity_id: 1, velocity_x: 400, velocity_y: -627, velocity_z: -397 }) +TimeUpdate(TimeUpdate { world_age: 7683972, time_of_day: 7872437 }) +BlockAction(BlockAction { location: <26,95,-117>, byte1: 1, byte2: 0, block_type: 130 }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: 0, velocity_y: -627, velocity_z: 141 }) +EntityMove(EntityMove { entity_id: 0, delta_x: 0, delta_y: 0, delta_z: 2, on_ground: true }) +EntityVelocity(EntityVelocity { entity_id: 1, velocity_x: 0, velocity_y: -627, velocity_z: 0 }) +EntityMove(EntityMove { entity_id: 1, delta_x: 0, delta_y: 0, delta_z: 0, on_ground: true }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: -604, velocity_y: -627, velocity_z: 689 }) +EntityVelocity(EntityVelocity { entity_id: 1, velocity_x: 397, velocity_y: -627, velocity_z: -400 }) +SoundEffect(SoundEffect { name: "mob.pig.step", x: 195, y: 752, z: -899, volume: 0.15, pitch: 63 }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: -141, velocity_y: -627, velocity_z: 0 }) +EntityVelocity(EntityVelocity { entity_id: 1, velocity_x: 0, velocity_y: -627, velocity_z: 0 }) +EntityLook(EntityLook { entity_id: 46, yaw: 26, pitch: 27, on_ground: true }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: -689, velocity_y: -627, velocity_z: 604 }) +EntityVelocity(EntityVelocity { entity_id: 1, velocity_x: 399, velocity_y: -627, velocity_z: -397 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 51 }) +EntityLook(EntityLook { entity_id: 46, yaw: 21, pitch: 31, on_ground: true }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: 24 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 37 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 23 }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: 0, velocity_y: -627, velocity_z: 141 }) +EntityVelocity(EntityVelocity { entity_id: 1, velocity_x: 0, velocity_y: -627, velocity_z: 0 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 16 }) +EntityHeadLook(EntityHeadLook { entity_id: 46, head_yaw: 20 }) +EntityVelocity(EntityVelocity { entity_id: 0, velocity_x: -604, velocity_y: -627, velocity_z: 689 }) +EntityVelocity(EntityVelocity { entity_id: 1, velocity_x: 397, velocity_y: -627, velocity_z: -400 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: 9 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: -5 }) +EntityHeadLook(EntityHeadLook { entity_id: 1, head_yaw: -20 }) diff --git a/openssl/Cargo.lock b/openssl/Cargo.lock new file mode 100644 index 0000000..827b76c --- /dev/null +++ b/openssl/Cargo.lock @@ -0,0 +1,12 @@ +[root] +name = "steven_openssl" +version = "0.0.1" +dependencies = [ + "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + diff --git a/src/main.rs b/src/bin/steven.rs similarity index 95% rename from src/main.rs rename to src/bin/steven.rs index 561f09e..56ccb89 100644 --- a/src/main.rs +++ b/src/bin/steven.rs @@ -1,10 +1,7 @@ extern crate glfw; +extern crate steven; -pub mod bit; -pub mod protocol; -pub mod format; - -mod gl; +use steven::*; use glfw::{Action, Context, Key}; fn main() { diff --git a/src/format.rs b/src/format.rs index 7928967..26ec1e7 100644 --- a/src/format.rs +++ b/src/format.rs @@ -4,8 +4,7 @@ use std::fmt; #[derive(Debug)] pub enum Component { - Text(TextComponent), - None + Text(TextComponent) } impl Component { @@ -16,7 +15,7 @@ impl Component { } else if v.find("text").is_some(){ Component::Text(TextComponent::from_value(v, modifier)) } else { - Component::None + Component::Text(TextComponent{text: "".to_owned(), modifier: modifier}) } } @@ -29,18 +28,17 @@ impl fmt::Display for Component { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Component::Text(ref txt) => write!(f, "{}", txt), - Component::None => Result::Ok(()), } } } impl Default for Component { fn default() -> Self { - Component::None + Component::Text(TextComponent{text: "".to_owned(), modifier: Default::default()}) } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Modifier { pub extra: Option>, pub bold: Option, diff --git a/src/item.rs b/src/item.rs new file mode 100644 index 0000000..27661f2 --- /dev/null +++ b/src/item.rs @@ -0,0 +1,54 @@ +extern crate byteorder; + +use nbt; +use protocol::{Serializable}; +use std::io; +use std::io::{Read, Write}; +use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; + +#[derive(Debug)] +pub struct Stack { + id: isize, + count: isize, + damage: isize, + tag: Option, +} + + +impl Default for Stack { + fn default() -> Stack { + Stack { + id: -1, + count: 0, + damage: 0, + tag: None, + } + } +} + +impl Serializable for Option { + fn read_from(buf: &mut io::Read) -> Result, io::Error> { + let id = try!(buf.read_i16::()); + if id == -1 { + return Ok(None); + } + Ok(Some(Stack{ + id: id as isize, + count: try!(buf.read_u8()) as isize, + damage: try!(buf.read_i16::()) as isize, + tag: try!(Serializable::read_from(buf)), + })) + } + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + match *self { + Some(ref val) => { + try!(buf.write_i16::(val.id as i16)); + try!(buf.write_u8(val.count as u8)); + try!(buf.write_i16::(val.damage as i16)); + try!(val.tag.write_to(buf)); + }, + None => try!(buf.write_i16::(-1)), + } + Result::Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..4653127 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,8 @@ +#![cfg_attr(test, allow(dead_code))] +pub mod bit; +pub mod protocol; +pub mod format; +pub mod nbt; +pub mod item; +pub mod gl; +pub mod types; diff --git a/src/nbt/mod.rs b/src/nbt/mod.rs new file mode 100644 index 0000000..7abfd9e --- /dev/null +++ b/src/nbt/mod.rs @@ -0,0 +1,274 @@ +extern crate byteorder; + +use std::collections::HashMap; +use std::io; +use std::io::{Read, Write}; + +use super::protocol::{Serializable}; +use super::protocol; +use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; + +#[derive(Debug)] +pub enum Tag { + End, + Byte(i8), + Short(i16), + Int(i32), + Long(i64), + Float(f32), + Double(f64), + ByteArray(Vec), + String(String), + List(Vec), + Compound(HashMap), + IntArray(Vec), +} + +#[derive(Debug)] +pub struct NamedTag(pub String, pub Tag); + +impl Tag { + + pub fn new_compound() -> Tag { + Tag::Compound(HashMap::new()) + } + + pub fn new_list() -> Tag { + Tag::List(Vec::new()) + } + + /// Returns the tag with the given name from the compound. + /// + /// # Panics + /// Panics when the tag isn't a compound. + pub fn get(&self, name: &str) -> Option<&Tag> { + match *self { + Tag::Compound(ref val) => val.get(name), + _ => panic!("not a compound tag"), + } + } + + /// Places the tag into the compound using the given name. + /// + /// # Panics + /// Panics when the tag isn't a compound. + pub fn put(&mut self, name: &str, tag: Tag) { + match *self { + Tag::Compound(ref mut val) => val.insert(name.to_owned(), tag), + _ => panic!("not a compound tag"), + }; + } + + pub fn is_compound(&self) -> bool { + match *self { + Tag::Compound(_) => true, + _ => false, + } + } + + pub fn as_byte(&self) -> Option { + match *self { + Tag::Byte(val) => Some(val), + _ => None, + } + } + + pub fn as_short(&self) -> Option { + match *self { + Tag::Short(val) => Some(val), + _ => None, + } + } + + pub fn as_int(&self) -> Option { + match *self { + Tag::Int(val) => Some(val), + _ => None, + } + } + + pub fn as_long(&self) -> Option { + match *self { + Tag::Long(val) => Some(val), + _ => None, + } + } + + pub fn as_float(&self) -> Option { + match *self { + Tag::Float(val) => Some(val), + _ => None, + } + } + + pub fn as_double(&self) -> Option { + match *self { + Tag::Double(val) => Some(val), + _ => None, + } + } + + pub fn as_byte_array(&self) -> Option<&[u8]> { + match *self { + Tag::ByteArray(ref val) => Some(&val[..]), + _ => None, + } + } + + pub fn as_string(&self) -> Option<&str> { + match *self { + Tag::String(ref val) => Some(&val[..]), + _ => None, + } + } + + pub fn as_list(&self) -> Option<&[Tag]> { + match *self { + Tag::List(ref val) => Some(&val[..]), + _ => None, + } + } + + pub fn as_compound(&self) -> Option<&HashMap> { + match *self { + Tag::Compound(ref val) => Some(val), + _ => None, + } + } + + pub fn as_int_array(&self) -> Option<&[i32]> { + match *self { + Tag::IntArray(ref val) => Some(&val[..]), + _ => None, + } + } + + fn internal_id(&self) -> u8 { + match *self { + Tag::End => 0, + Tag::Byte(_) => 1, + Tag::Short(_) => 2, + Tag::Int(_) => 3, + Tag::Long(_) => 4, + Tag::Float(_) => 5, + Tag::Double(_) => 6, + Tag::ByteArray(_) => 7, + Tag::String(_) => 8, + Tag::List(_) => 9, + Tag::Compound(_) => 10, + Tag::IntArray(_) => 11, + } + } + + fn read_type(id: u8, buf: &mut io::Read) -> Result { + match id { + 0 => unreachable!(), + 1 => Ok(Tag::Byte(try!(buf.read_i8()))), + 2 => Ok(Tag::Short(try!(buf.read_i16::()))), + 3 => Ok(Tag::Int(try!(buf.read_i32::()))), + 4 => Ok(Tag::Long(try!(buf.read_i64::()))), + 5 => Ok(Tag::Float(try!(buf.read_f32::()))), + 6 => Ok(Tag::Double(try!(buf.read_f64::()))), + 7 => Ok(Tag::ByteArray({ + let len : i32 = try!(Serializable::read_from(buf)); + let mut data = Vec::with_capacity(len as usize); + try!(buf.take(len as u64).read_to_end(&mut data)); + data + })), + 8 => Ok(Tag::String(try!(read_string(buf)))), + 9 => { + let mut l = Vec::new(); + let ty = try!(buf.read_u8()); + let len : i32 = try!(Serializable::read_from(buf)); + for _ in 0 .. len { + l.push(try!(Tag::read_type(ty, buf))); + } + Ok(Tag::List(l)) + }, + 10 => { + let mut c = Tag::new_compound(); + loop { + let ty = try!(buf.read_u8()); + if ty == 0 { + break; + } + let name: String = try!(read_string(buf)); + c.put(&name[..], try!(Tag::read_type(ty, buf))); + } + Ok(c) + }, + 11 => Ok(Tag::IntArray({ + let len : i32 = try!(Serializable::read_from(buf)); + let mut data = Vec::with_capacity(len as usize); + for _ in 0 .. len { + data.push(try!(buf.read_i32::())); + } + data + })), + _ => Err(io::Error::new(io::ErrorKind::InvalidData, protocol::Error::Err("invalid tag".to_owned()))), + } + } +} + +impl Serializable for Tag { + fn read_from(buf: &mut io::Read) -> Result { + Tag::read_type(10, buf) + } + + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + match *self { + Tag::End => {}, + Tag::Byte(val) => try!(buf.write_i8(val)), + Tag::Short(val) => try!(buf.write_i16::(val)), + Tag::Int(val) => try!(buf.write_i32::(val)), + Tag::Long(val) => try!(buf.write_i64::(val)), + Tag::Float(val) => try!(buf.write_f32::(val)), + Tag::Double(val) => try!(buf.write_f64::(val)), + Tag::ByteArray(ref val) => { + try!((val.len() as i32).write_to(buf)); + try!(buf.write_all(val)); + }, + Tag::String(ref val) => try!(write_string(buf, val)), + Tag::List(ref val) => { + if val.is_empty() { + try!(buf.write_u8(0)); + try!(buf.write_i32::(0)); + } else { + try!(buf.write_u8(val[0].internal_id())); + try!(buf.write_i32::(val.len() as i32)); + for e in val { + try!(e.write_to(buf)); + } + } + }, + Tag::Compound(ref val) => { + for (k, v) in val { + try!(v.internal_id().write_to(buf)); + try!(write_string(buf, k)); + try!(v.write_to(buf)); + } + try!(buf.write_u8(0)); + }, + Tag::IntArray(ref val) => { + try!((val.len() as i32).write_to(buf)); + for v in val { + try!(v.write_to(buf)); + } + }, + } + Result::Ok(()) + } +} + +pub fn write_string(buf: &mut io::Write, s: &String)-> io::Result<()> { + let data = s.as_bytes(); + try!((data.len() as i16).write_to(buf)); + buf.write_all(data) +} + +pub fn read_string(buf: &mut io::Read) -> io::Result { + let len: i16 = try!(buf.read_i16::()); + let mut ret = String::new(); + try!(buf.take(len as u64).read_to_string(&mut ret)); + Result::Ok(ret) +} diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index ace9268..2f7496e 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -7,7 +7,9 @@ extern crate serde_json; pub mod mojang; +use nbt; use format; +use std::fmt; use std::default; use std::net::TcpStream; use std::io; @@ -21,7 +23,8 @@ use self::flate2::read::{ZlibDecoder, ZlibEncoder}; macro_rules! state_packets { ($($state:ident $stateName:ident { $($dir:ident $dirName:ident { - $($name:ident => $id:expr { + $( + $name:ident => $id:expr { $($field:ident: $field_type:ty = $(when ($cond:expr))*, )+ })* })+ @@ -29,6 +32,7 @@ macro_rules! state_packets { use protocol::*; use std::io; + #[derive(Debug)] pub enum Packet { $( $( @@ -47,9 +51,12 @@ macro_rules! state_packets { use protocol::*; use std::io; use format; + use nbt; + use types; + use item; $( - #[derive(Default)] + #[derive(Default, Debug)] pub struct $name { $(pub $field: $field_type),+, } @@ -58,7 +65,7 @@ macro_rules! state_packets { fn packet_id(&self) -> i32{ $id } - fn write(self, buf: &mut Vec) -> Result<(), io::Error> { + fn write(self, buf: &mut io::Write) -> Result<(), io::Error> { $( if true $(&& ($cond(&self)))* { try!(self.$field.write_to(buf)); @@ -76,7 +83,7 @@ macro_rules! state_packets { /// Returns the packet for the given state, direction and id after parsing the fields /// from the buffer. - pub fn packet_by_id(state: State, dir: Direction, id: i32, mut buf: &mut io::Cursor>) -> Result, io::Error> { + pub fn packet_by_id(state: State, dir: Direction, id: i32, mut buf: &mut io::Read) -> Result, io::Error> { match state { $( State::$stateName => { @@ -115,6 +122,42 @@ pub trait Serializable { fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error>; } +impl Serializable for Vec { + fn read_from(buf: &mut io::Read) -> Result , io::Error> { + let mut v = Vec::new(); + try!(buf.read_to_end(&mut v)); + Ok(v) + } + + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + buf.write_all(&self[..]) + } +} + +impl Serializable for Option{ + fn read_from(buf: &mut io::Read) -> Result, io::Error> { + let ty = try!(buf.read_u8()); + if ty == 0 { + Result::Ok(None) + } else { + let name = try!(nbt::read_string(buf)); + let tag = try!(nbt::Tag::read_from(buf)); + Result::Ok(Some(nbt::NamedTag(name, tag))) + } + } + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + match *self { + Some(ref val) => { + try!(buf.write_u8(10)); + try!(nbt::write_string(buf, &val.0)); + try!(val.1.write_to(buf)); + } + None => try!(buf.write_u8(0)), + } + Result::Ok(()) + } +} + impl Serializable for Option where T : Serializable { fn read_from(buf: &mut io::Read) -> Result, io::Error> { Result::Ok(Some(try!(T::read_from(buf)))) @@ -159,46 +202,6 @@ impl Serializable for format::Component { } } -pub struct Position(u64); - -impl Position { - fn new(x: i32, y: i32, z: i32) -> Position { - Position( - (((x as u64) & 0x3FFFFFF) << 38) | - (((y as u64) & 0xFFF) << 26) | - ((z as u64) & 0x3FFFFFF) - ) - } - - fn get_x(&self) -> i32 { - ((self.0 as i64) >> 38) as i32 - } - - fn get_y(&self) -> i32 { - (((self.0 as i64) >> 26) & 0xFFF) as i32 - } - - fn get_z(&self) -> i32 { - ((self.0 as i64) << 38 >> 38) as i32 - } -} - -impl Default for Position { - fn default() -> Position { - Position(0) - } -} - -impl Serializable for Position { - fn read_from(buf: &mut io::Read) -> Result { - Result::Ok(Position(try!(buf.read_u64::()))) - } - fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { - try!(buf.write_u64::(self.0)); - Result::Ok(()) - } -} - impl Serializable for () { fn read_from(_: &mut io::Read) -> Result<(), io::Error> { Result::Ok(()) @@ -218,6 +221,16 @@ impl Serializable for bool { } } +impl Serializable for i8 { + fn read_from(buf: &mut io::Read) -> Result { + Result::Ok(try!(buf.read_i8())) + } + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + try!(buf.write_i8(*self)); + Result::Ok(()) + } +} + impl Serializable for i16 { fn read_from(buf: &mut io::Read) -> Result { Result::Ok(try!(buf.read_i16::())) @@ -268,7 +281,54 @@ impl Serializable for u16 { } } -pub trait Lengthable : Serializable + Into + From + Copy + Default {} +impl Serializable for f32 { + fn read_from(buf: &mut io::Read) -> Result { + Result::Ok(try!(buf.read_f32::())) + } + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + try!(buf.write_f32::(*self)); + Result::Ok(()) + } +} + +impl Serializable for f64 { + fn read_from(buf: &mut io::Read) -> Result { + Result::Ok(try!(buf.read_f64::())) + } + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + try!(buf.write_f64::(*self)); + Result::Ok(()) + } +} + +#[derive(Debug)] +pub struct UUID(u64, u64); + +impl Default for UUID { + fn default() -> Self { UUID(0, 0) } +} + +impl Serializable for UUID { + fn read_from(buf: &mut io::Read) -> Result { + Result::Ok( + UUID( + try!(buf.read_u64::()), + try!(buf.read_u64::()), + ) + ) + } + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + try!(buf.write_u64::(self.0)); + try!(buf.write_u64::(self.1)); + Result::Ok(()) + } +} + + +pub trait Lengthable : Serializable + Copy + Default { + fn into(self) -> usize; + fn from(usize) -> Self; +} pub struct LenPrefixed { len: L, @@ -296,7 +356,7 @@ impl Serializable for LenPrefixed { } fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { - let len_data : L = self.data.len().into(); + let len_data : L = L::from(self.data.len()); try!(len_data.write_to(buf)); let ref data = self.data; for val in data { @@ -306,6 +366,7 @@ impl Serializable for LenPrefixed { } } + impl Default for LenPrefixed { fn default() -> Self { LenPrefixed { @@ -315,12 +376,94 @@ impl Default for LenPrefixed { } } +impl fmt::Debug for LenPrefixed { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.data.fmt(f) + } +} + +// Optimization +pub struct LenPrefixedBytes { + len: L, + pub data: Vec +} + +impl LenPrefixedBytes { + fn new(data: Vec) -> LenPrefixedBytes { + return LenPrefixedBytes { + len: Default::default(), + data: data, + } + } +} + +impl Serializable for LenPrefixedBytes { + fn read_from(buf: &mut io::Read) -> Result, io::Error> { + let len_data : L = try!(Serializable::read_from(buf)); + let len : usize = len_data.into(); + let mut data : Vec = Vec::with_capacity(len); + try!(buf.take(len as u64).read_to_end(&mut data)); + Result::Ok(LenPrefixedBytes{len: len_data, data: data}) + } + + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + let len_data : L = L::from(self.data.len()); + try!(len_data.write_to(buf)); + try!(buf.write_all(&self.data[..])); + Result::Ok(()) + } +} + + +impl Default for LenPrefixedBytes { + fn default() -> Self { + LenPrefixedBytes { + len: default::Default::default(), + data: default::Default::default() + } + } +} + +impl fmt::Debug for LenPrefixedBytes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.data.fmt(f) + } +} + +impl Lengthable for i16 { + fn into(self) -> usize { + self as usize + } + + fn from(u: usize) -> i16 { + u as i16 + } +} + +impl Lengthable for i32 { + fn into(self) -> usize { + self as usize + } + + fn from(u: usize) -> i32 { + u as i32 + } +} + /// VarInt have a variable size (between 1 and 5 bytes) when encoded based /// on the size of the number #[derive(Clone, Copy)] -pub struct VarInt(i32); +pub struct VarInt(pub i32); -impl Lengthable for VarInt {} +impl Lengthable for VarInt { + fn into(self) -> usize { + self.0 as usize + } + + fn from(u: usize) -> VarInt { + VarInt(u as i32) + } +} impl Serializable for VarInt { /// Decodes a VarInt from the Reader @@ -333,7 +476,7 @@ impl Serializable for VarInt { val |= (b & PART) << (size * 7); size+=1; if size > 5 { - return Result::Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Err("VarInt too big".to_string()))) + return Result::Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Err("VarInt too big".to_owned()))) } if (b & 0x80) == 0 { break @@ -362,15 +505,70 @@ impl default::Default for VarInt { fn default() -> VarInt { VarInt(0) } } -impl convert::Into for VarInt { - fn into(self) -> usize { - self.0 as usize +impl fmt::Debug for VarInt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) } } -impl convert::From for VarInt { - fn from(u: usize) -> VarInt { - VarInt(u as i32) +/// VarLong have a variable size (between 1 and 10 bytes) when encoded based +/// on the size of the number +#[derive(Clone, Copy)] +pub struct VarLong(pub i64); + +impl Lengthable for VarLong { + fn into(self) -> usize { + self.0 as usize + } + + fn from(u: usize) -> VarLong { + VarLong(u as i64) + } +} + +impl Serializable for VarLong { + /// Decodes a VarLong from the Reader + fn read_from(buf: &mut io::Read) -> Result { + const PART : u64 = 0x7F; + let mut size = 0; + let mut val = 0u64; + loop { + let b = try!(buf.read_u8()) as u64; + val |= (b & PART) << (size * 7); + size+=1; + if size > 10 { + return Result::Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Err("VarLong too big".to_owned()))) + } + if (b & 0x80) == 0 { + break + } + } + + Result::Ok(VarLong(val as i64)) + } + + /// Encodes a VarLong into the Writer + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + const PART : u64 = 0x7F; + let mut val = self.0 as u64; + loop { + if (val & !PART) == 0 { + try!(buf.write_u8(val as u8)); + return Result::Ok(()); + } + try!(buf.write_u8(((val & PART) | 0x80) as u8)); + val >>= 7; + } + } +} + +impl default::Default for VarLong { + fn default() -> VarLong { VarLong(0) } +} + +impl fmt::Debug for VarLong { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) } } @@ -516,13 +714,12 @@ impl Conn { Some(val) => { let pos = buf.position() as usize; let ibuf = buf.into_inner(); - if ibuf.len() < pos { + if ibuf.len() != pos { return Result::Err(Error::Err(format!("Failed to read all of packet 0x{:X}, had {} bytes left", id, ibuf.len() - pos))) } Result::Ok(val) }, - // FIXME - None => Result::Ok(packet::Packet::StatusRequest(packet::status::serverbound::StatusRequest{empty:()}))//Result::Err(Error::Err("missing packet".to_string())) + None => Result::Err(Error::Err("missing packet".to_owned())) } } @@ -592,25 +789,25 @@ impl Clone for Conn { pub trait PacketType { fn packet_id(&self) -> i32; - fn write(self, buf: &mut Vec) -> Result<(), io::Error>; + fn write(self, buf: &mut io::Write) -> Result<(), io::Error>; } -#[test] -fn test() { +// #[test] +pub fn test() { let mut c = Conn::new("localhost:25565").unwrap(); c.write_packet(packet::handshake::serverbound::Handshake{ - protocol_version: VarInt(69), - host: "localhost".to_string(), + protocol_version: VarInt(71), + host: "localhost".to_owned(), port: 25565, next: VarInt(2), }).unwrap(); c.state = State::Login; - c.write_packet(packet::login::serverbound::LoginStart{username: "Think".to_string()}).unwrap(); + c.write_packet(packet::login::serverbound::LoginStart{username: "Think".to_owned()}).unwrap(); let packet = match c.read_packet().unwrap() { packet::Packet::EncryptionRequest(val) => val, - _ => panic!("Wrong packet"), + val => panic!("Wrong packet: {:?}", val), }; let mut key = openssl::PublicKey::new(&packet.public_key.data); @@ -620,17 +817,17 @@ fn test() { let token_e = key.encrypt(&packet.verify_token.data); let profile = mojang::Profile{ - username: "Think".to_string(), - id: "b1184d43168441cfa2128b9a3df3b6ab".to_string(), - access_token: "".to_string() + username: "Think".to_owned(), + id: "b1184d43168441cfa2128b9a3df3b6ab".to_owned(), + access_token: "".to_owned() }; profile.join_server(&packet.server_id, &shared, &packet.public_key.data); c.write_packet(packet::login::serverbound::EncryptionResponse{ - shared_secret: LenPrefixed::new(shared_e), - verify_token: LenPrefixed::new(token_e), - }); + shared_secret: LenPrefixedBytes::new(shared_e), + verify_token: LenPrefixedBytes::new(token_e), + }).unwrap(); let mut read = c.clone(); let mut write = c.clone(); @@ -660,12 +857,13 @@ fn test() { let mut count = 0; loop { match read.read_packet().unwrap() { packet::Packet::ServerMessage(val) => println!("MSG: {}", val.message), - _ => { + packet::Packet::ChunkData(_) => {}, + val => { + println!("{:?}", val); if first { - println!("got packet"); write.write_packet(packet::play::serverbound::ChatMessage{ - message: "Hello world".to_string(), - }); + message: "Hello world".to_owned(), + }).unwrap(); first = false; } count += 1; diff --git a/src/protocol/packet.rs b/src/protocol/packet.rs index fcc07e1..f201ba6 100644 --- a/src/protocol/packet.rs +++ b/src/protocol/packet.rs @@ -1,3 +1,4 @@ +use format; state_packets!( handshake Handshaking { @@ -38,7 +39,7 @@ state_packets!( TabComplete => 0x00 { text: String =, has_target: bool =, - target: Option = when(|p: &TabComplete| p.has_target == true), + target: Option = when(|p: &TabComplete| p.has_target == true), } // ChatMessage is sent by the client when it sends a chat message or // executes a command (prefixed by '/'). @@ -76,14 +77,712 @@ state_packets!( button: u8 =, action_number: u16 =, mode: u8 =, - clicked_item: ()=, // TODO + clicked_item: Option =, // TODO + } + // CloseWindow is sent when the client closes a window. + CloseWindow => 0x07 { + id: u8 =, + } + // PluginMessageServerbound is used for custom messages between the client + // and server. This is mainly for plugins/mods but vanilla has a few channels + // registered too. + PluginMessageServerbound => 0x08 { + channel: String =, + data: Vec =, + } + // UseEntity is sent when the user interacts (right clicks) or attacks + // (left clicks) an entity. + UseEntity => 0x09 { + target_id: VarInt =, + ty: VarInt =, + target_x: f32 = when(|p: &UseEntity| p.ty.0 == 2), + target_y: f32 = when(|p: &UseEntity| p.ty.0 == 2), + target_z: f32 = when(|p: &UseEntity| p.ty.0 == 2), + hand: VarInt = when(|p: &UseEntity| p.ty.0 == 0 || p.ty.0 == 2), + } + // KeepAliveServerbound is sent by a client as a response to a + // KeepAliveClientbound. If the client doesn't reply the server + // may disconnect the client. + KeepAliveServerbound => 0x0A { + id: VarInt =, + } + // PlayerPosition is used to update the player's position. + PlayerPosition => 0x0B { + x: f64 =, + y: f64 =, + z: f64 =, + on_ground: bool =, + } + // PlayerPositionLook is a combination of PlayerPosition and + // PlayerLook. + PlayerPositionLook => 0x0C { + x: f64 =, + y: f64 =, + z: f64 =, + yaw: f32 =, + pitch: f32 =, + on_ground: bool =, + } + // PlayerLook is used to update the player's rotation. + PlayerLook => 0x0D { + yaw: f32 =, + pitch: f32 =, + on_ground: bool =, + } + // Player is used to update whether the player is on the ground or not. + Player => 0x0E { + on_ground: bool =, + } + // ClientAbilities is used to modify the players current abilities. + // Currently flying is the only one + ClientAbilities => 0x0F { + flags: u8 =, + flying_speed: f32 =, + walking_speed: f32 =, + } + // PlayerDigging is sent when the client starts/stops digging a block. + // It also can be sent for droppping items and eating/shooting. + PlayerDigging => 0x10 { + status: u8 =, + location: types::Position =, + face: u8 =, + } + // PlayerAction is sent when a player preforms various actions. + PlayerAction => 0x11 { + entity_id: VarInt =, + action_id: VarInt =, + jump_boost: VarInt =, + } + // SteerVehicle is sent by the client when steers or preforms an action + // on a vehicle. + SteerVehicle => 0x12 { + sideways: f32 =, + forward: f32 =, + flags: u8 =, + } + // ResourcePackStatus informs the server of the client's current progress + // in activating the requested resource pack + ResourcePackStatus => 0x13 { + hash: String =, + result: VarInt =, + } + // HeldItemChange is sent when the player changes the currently active + // hotbar slot. + HeldItemChange => 0x14 { + slot: i16 =, + } + // CreativeInventoryAction is sent when the client clicks in the creative + // inventory. This is used to spawn items in creative. + CreativeInventoryAction => 0x15 { + slot: i16 =, + clicked_item: Option =, + } + // SetSign sets the text on a sign after placing it. + SetSign => 0x16 { + location: types::Position =, + line1: String =, + line2: String =, + line3: String =, + line4: String =, + } + // ArmSwing is sent by the client when the player left clicks (to swing their + // arm). + ArmSwing => 0x17 { + hand: VarInt =, + } + // SpectateTeleport is sent by clients in spectator mode to teleport to a player. + SpectateTeleport => 0x18 { + target: UUID =, + } + // PlayerBlockPlacement is sent when the client tries to place a block. + PlayerBlockPlacement => 0x19 { + location: types::Position =, + face: VarInt =, + hand: VarInt =, + cursor_x: u8 =, + cursor_y: u8 =, + cursor_z: u8 =, + } + // UseItem is sent when the client tries to use an item. + UseItem => 0x1A { + hand: VarInt =, } } clientbound Clientbound { - ServerMessage => 15 { + // SpawnObject is used to spawn an object or vehicle into the world when it + // is in range of the client. + SpawnObject => 0x00 { + entity_id: VarInt =, + uuid: UUID =, + ty: u8 =, + x: i32 =, + y: i32 =, + z: i32 =, + pitch: i8 =, + yaw: i8 =, + data: i32 =, + velocity_x: i16 =, + velocity_y: i16 =, + velocity_z: i16 =, + } + // SpawnExperienceOrb spawns a single experience orb into the world when + // it is in range of the client. The count controls the amount of experience + // gained when collected. + SpawnExperienceOrb => 0x01 { + entity_id: VarInt =, + x: i32 =, + y: i32 =, + z: i32 =, + count: i16 =, + } + // SpawnGlobalEntity spawns an entity which is visible from anywhere in the + // world. Currently only used for lightning. + SpawnGlobalEntity => 0x02 { + entity_id: VarInt =, + ty: u8 =, + x: i32 =, + y: i32 =, + z: i32 =, + } + // SpawnMob is used to spawn a living entity into the world when it is in + // range of the client. + SpawnMob => 0x03 { + entity_id: VarInt =, + uuid: UUID =, + ty: u8 =, + x: i32 =, + y: i32 =, + z: i32 =, + yaw: i8 =, + pitch: i8 =, + head_pitch: i8 =, + velocity_x: i16 =, + velocity_y: i16 =, + velocity_z: i16 =, + metadata: types::Metadata =, + } + // SpawnPainting spawns a painting into the world when it is in range of + // the client. The title effects the size and the texture of the painting. + SpawnPainting => 0x04 { + entity_id: VarInt =, + title: String =, + location: types::Position =, + direction: u8 =, + } + // SpawnPlayer is used to spawn a player when they are in range of the client. + // This packet alone isn't enough to display the player as the skin and username + // information is in the player information packet. + SpawnPlayer => 0x05 { + entity_id: VarInt =, + uuid: UUID =, + x: i32 =, + y: i32 =, + z: i32 =, + yaw: i8 =, + pitch: i8 =, + metadata: types::Metadata =, + } + // Animation is sent by the server to play an animation on a specific entity. + Animation => 0x06 { + entity_id: VarInt =, + animation_id: u8 =, + } + // Statistics is used to update the statistics screen for the client. + Statistics => 0x07 { + statistices: LenPrefixed =, + } + // BlockBreakAnimation is used to create and update the block breaking + // animation played when a player starts digging a block. + BlockBreakAnimation => 0x08 { + entity_id: VarInt =, + location: types::Position =, + stage: i8 =, + } + // UpdateBlockEntity updates the nbt tag of a block entity in the + // world. + UpdateBlockEntity => 0x09 { + location: types::Position =, + action: u8 =, + nbt: Option =, + } + // BlockAction triggers different actions depending on the target block. + BlockAction => 0x0A { + location: types::Position =, + byte1: u8 =, + byte2: u8 =, + block_type: VarInt =, + } + // BlockChange is used to update a single block on the client. + BlockChange => 0x0B { + location: types::Position =, + block_id: VarInt =, + } + // BossBar displays and/or changes a boss bar that is displayed on the + // top of the client's screen. This is normally used for bosses such as + // the ender dragon or the wither. + BossBar => 0x0C { + uuid: UUID =, + action: VarInt =, + title: format::Component = when(|p: &BossBar| p.action.0 == 0 || p.action.0 == 3), + health: f32 = when(|p: &BossBar| p.action.0 == 0 || p.action.0 == 2), + color: VarInt = when(|p: &BossBar| p.action.0 == 0 || p.action.0 == 4), + style: VarInt = when(|p: &BossBar| p.action.0 == 0 || p.action.0 == 4), + flags: u8 = when(|p: &BossBar| p.action.0 == 0 || p.action.0 == 5), + } + // ServerDifficulty changes the displayed difficulty in the client's menu + // as well as some ui changes for hardcore. + ServerDifficulty => 0x0D { + difficulty: u8 =, + } + // TabCompleteReply is sent as a reply to a tab completion request. + // The matches should be possible completions for the command/chat the + // player sent. + TabCompleteReply => 0x0E { + matches: LenPrefixed =, + } + // ServerMessage is a message sent by the server. It could be from a player + // or just a system message. The Type field controls the location the + // message is displayed at and when the message is displayed. + ServerMessage => 0x0F { message: format::Component =, + // 0 - Chat message, 1 - System message, 2 - Action bar message position: u8 =, } + // MultiBlockChange is used to update a batch of blocks in a single packet. + MultiBlockChange => 0x10 { + chunk_x: i32 =, + chunk_y: i32 =, + records: LenPrefixed =, + } + // ConfirmTransaction notifies the client whether a transaction was successful + // or failed (e.g. due to lag). + ConfirmTransaction => 0x11 { + id: u8 =, + action_number: i16 =, + accepted: bool =, + } + // WindowClose forces the client to close the window with the given id, + // e.g. a chest getting destroyed. + WindowClose => 0x12 { + id: u8 =, + } + // WindowOpen tells the client to open the inventory window of the given + // type. The ID is used to reference the instance of the window in + // other packets. + WindowOpen => 0x13 { + id: u8 =, + ty: String =, + title: format::Component =, + slot_count: u8 =, + entity_id: i32 = when(|p: &WindowOpen| p.ty == "EntityHorse"), + } + // WindowItems sets every item in a window. + WindowItems => 0x14 { + id: u8 =, + items: LenPrefixed> =, + } + // WindowProperty changes the value of a property of a window. Properties + // vary depending on the window type. + WindowProperty => 0x15 { + id: u8 =, + property: i16 =, + value: i16 =, + } + // WindowSetSlot changes an itemstack in one of the slots in a window. + WindowSetSlot => 0x16 { + id: u8 =, + property: i16 =, + item: Option =, + } + // SetCooldown disables a set item (by id) for the set number of ticks + SetCooldown => 0x17 { + item_id: VarInt =, + ticks: VarInt =, + } + // PluginMessageClientbound is used for custom messages between the client + // and server. This is mainly for plugins/mods but vanilla has a few channels + // registered too. + PluginMessageClientbound => 0x18 { + channel: String =, + data: Vec =, + } + // Disconnect causes the client to disconnect displaying the passed reason. + Disconnect => 0x19 { + reason: format::Component =, + } + // EntityAction causes an entity to preform an action based on the passed + // id. + EntityAction => 0x1A { + entity_id: i32 =, + action_id: u8 =, + } + // Explosion is sent when an explosion is triggered (tnt, creeper etc). + // This plays the effect and removes the effected blocks. + Explosion => 0x1B { + x: f32 =, + y: f32 =, + z: f32 =, + radius: f32 =, + records: LenPrefixed =, + velocity_x: f32 =, + velocity_y: f32 =, + velocity_z: f32 =, + } + // ChunkUnload tells the client to unload the chunk at the specified + // position. + ChunkUnload => 0x1C { + x: i32 =, + z: i32 =, + } + // SetCompression updates the compression threshold. + SetCompression => 0x1D { + threshold: VarInt =, + } + // ChangeGameState is used to modify the game's state like gamemode or + // weather. + ChangeGameState => 0x1E { + reason: u8 =, + value: f32 =, + } + // KeepAliveClientbound is sent by a server to check if the + // client is still responding and keep the connection open. + // The client should reply with the KeepAliveServerbound + // packet setting ID to the same as this one. + KeepAliveClientbound => 0x1F { + id: VarInt =, + } + // ChunkData sends or updates a single chunk on the client. If New is set + // then biome data should be sent too. + ChunkData => 0x20 { + chunk_x: i32 =, + chunk_z: i32 =, + new: bool =, + bitmask: VarInt =, + data: LenPrefixedBytes =, + } + // Effect plays a sound effect or particle at the target location with the + // volume (of sounds) being relative to the player's position unless + // DisableRelative is set to true. + Effect => 0x21 { + effect_id: i32 =, + location: types::Position =, + data: i32 =, + disable_relative: bool =, + } + // Particle spawns particles at the target location with the various + // modifiers. + Particle => 0x22 { + particle_id: i32 =, + long_distance: bool =, + x: f32 =, + y: f32 =, + z: f32 =, + offset_x: f32 =, + offset_y: f32 =, + offset_z: f32 =, + speed: f32 =, + count: i32 =, + data1: VarInt = when(|p: &Particle| p.particle_id == 36 || p.particle_id == 37 || p.particle_id == 38), + data2: VarInt = when(|p: &Particle| p.particle_id == 36), + } + // SoundEffect plays the named sound at the target location. + SoundEffect => 0x23 { + name: String =, + x: i32 =, + y: i32 =, + z: i32 =, + volume: f32 =, + pitch: u8 =, + } + // JoinGame is sent after completing the login process. This + // sets the initial state for the client. + JoinGame => 0x24 { + // The entity id the client will be referenced by + entity_id: i32 =, + // The starting gamemode of the client + gamemode: u8 =, + // The dimension the client is starting in + dimension: i8 =, + // The difficuilty setting for the server + difficulty: u8 =, + // The max number of players on the server + max_players: u8 =, + // The level type of the server + level_type: String =, + // Whether the client should reduce the amount of debug + // information it displays in F3 mode + reduced_debug_info: bool =, + } + // Maps updates a single map's contents + Maps => 0x25 { + item_damage: VarInt =, + scale: i8 =, + tracking_position: bool =, + icons: LenPrefixed =, + columns: u8 =, + rows: Option = when(|p: &Maps| p.columns > 0), + x: Option = when(|p: &Maps| p.columns > 0), + z: Option = when(|p: &Maps| p.columns > 0), + data: Option> = when(|p: &Maps| p.columns > 0), + } + // EntityMove moves the entity with the id by the offsets provided. + EntityMove => 0x26 { + entity_id: VarInt =, + delta_x: i8 =, + delta_y: i8 =, + delta_z: i8 =, + on_ground: bool =, + } + // EntityLookAndMove is a combination of EntityMove and EntityLook. + EntityLookAndMove => 0x27 { + entity_id: VarInt =, + delta_x: i8 =, + delta_y: i8 =, + delta_z: i8 =, + yaw: i8 =, + pitch: i8 =, + on_ground: bool =, + } + // EntityLook rotates the entity to the new angles provided. + EntityLook => 0x28 { + entity_id: VarInt =, + yaw: i8 =, + pitch: i8 =, + on_ground: bool =, + } + // Entity does nothing. It is a result of subclassing used in Minecraft. + Entity => 0x29 { + entity_id: VarInt =, + } + // SignEditorOpen causes the client to open the editor for a sign so that + // it can write to it. Only sent in vanilla when the player places a sign. + SignEditorOpen => 0x2A { + location: types::Position =, + } + // PlayerAbilities is used to modify the players current abilities. Flying, + // creative, god mode etc. + PlayerAbilities => 0x2B { + flags: u8 =, + flying_speed: f32 =, + walking_speed: f32 =, + } + // CombatEvent is used for... you know, I never checked. I have no + // clue. + CombatEvent => 0x2C { + event: VarInt =, + direction: Option = when(|p: &CombatEvent| p.event.0 == 1), + player_id: Option = when(|p: &CombatEvent| p.event.0 == 2), + entity_id: Option = when(|p: &CombatEvent| p.event.0 == 1 || p.event.0 == 2), + message: Option = when(|p: &CombatEvent| p.event.0 == 2), + } + // PlayerInfo is sent by the server for every player connected to the server + // to provide skin and username information as well as ping and gamemode info. + PlayerInfo => 0x2D { + inner: packet::PlayerInfoData =, // Ew but watcha gonna do? + } + // TeleportPlayer is sent to change the player's position. The client is expected + // to reply to the server with the same positions as contained in this packet + // otherwise will reject future packets. + TeleportPlayer => 0x2E { + x: f64 =, + y: f64 =, + z: f64 =, + yaw: f32 =, + pitch: f32 =, + flags: u8 =, + } + // EntityUsedBed is sent by the server when a player goes to bed. + EntityUsedBed => 0x2F { + entity_id: VarInt =, + location: types::Position =, + } + // EntityDestroy destroys the entities with the ids in the provided slice. + EntityDestroy => 0x30 { + entity_ids: LenPrefixed =, + } + // EntityRemoveEffect removes an effect from an entity. + EntityRemoveEffect => 0x31 { + entity_id: VarInt =, + effect_id: i8 =, + } + // ResourcePackSend causes the client to check its cache for the requested + // resource packet and download it if its missing. Once the resource pack + // is obtained the client will use it. + ResourcePackSend => 0x32 { + url: String =, + hash: String =, + } + // Respawn is sent to respawn the player after death or when they move worlds. + Respawn => 0x33 { + dimension: i32 =, + difficulty: u8 =, + gamemode: u8 =, + level_type: String =, + } + // EntityHeadLook rotates an entity's head to the new angle. + EntityHeadLook => 0x34 { + entity_id: VarInt =, + head_yaw: i8 =, + } + // WorldBorder configures the world's border. + WorldBorder => 0x35 { + action: VarInt =, + old_radius: Option = when(|p: &WorldBorder| p.action.0 == 3 || p.action.0 == 1), + new_radius: Option = when(|p: &WorldBorder| p.action.0 == 3 || p.action.0 == 1 || p.action.0 == 0), + speed: Option = when(|p: &WorldBorder| p.action.0 == 3 || p.action.0 == 1), + x: Option = when(|p: &WorldBorder| p.action.0 == 3 || p.action.0 == 2), + z: Option = when(|p: &WorldBorder| p.action.0 == 3 || p.action.0 == 2), + portal_boundary: Option = when(|p: &WorldBorder| p.action.0 == 3), + warning_time: Option = when(|p: &WorldBorder| p.action.0 == 3 || p.action.0 == 4), + warning_blocks: Option = when(|p: &WorldBorder| p.action.0 == 3 || p.action.0 == 5), + } + // Camera causes the client to spectate the entity with the passed id. + // Use the player's id to de-spectate. + Camera => 0x36 { + target_id: VarInt =, + } + // SetCurrentHotbarSlot changes the player's currently selected hotbar item. + SetCurrentHotbarSlot => 0x37 { + slot: u8 =, + } + // ScoreboardDisplay is used to set the display position of a scoreboard. + ScoreboardDisplay => 0x38 { + position: u8 =, + name: String =, + } + // EntityMetadata updates the metadata for an entity. + EntityMetadata => 0x39 { + entity_id: VarInt =, + metadata: types::Metadata =, + } + // EntityAttach attaches to entities together, either by mounting or leashing. + // -1 can be used at the EntityID to deattach. + EntityAttach => 0x3A { + entity_id: i32 =, + vehicle: i32 =, + leash: bool =, + } + // EntityVelocity sets the velocity of an entity in 1/8000 of a block + // per a tick. + EntityVelocity => 0x3B { + entity_id: VarInt =, + velocity_x: i16 =, + velocity_y: i16 =, + velocity_z: i16 =, + } + // EntityEquipment is sent to display an item on an entity, like a sword + // or armor. Slot 0 is the held item and slots 1 to 4 are boots, leggings + // chestplate and helmet respectively. + EntityEquipment => 0x3C { + entity_id: VarInt =, + slot: VarInt =, + item: Option =, + } + // SetExperience updates the experience bar on the client. + SetExperience => 0x3D { + experience_bar: f32 =, + level: VarInt =, + total_experience: VarInt =, + } + // UpdateHealth is sent by the server to update the player's health and food. + UpdateHealth => 0x3E { + health: f32 =, + food: VarInt =, + food_saturation: f32 =, + } + // ScoreboardObjective creates/updates a scoreboard objective. + ScoreboardObjective => 0x3F { + name: String =, + mode: u8 =, + value: String = when(|p: &ScoreboardObjective| p.mode == 0 || p.mode == 2), + ty: String = when(|p: &ScoreboardObjective| p.mode == 0 || p.mode == 2), + } + // Teams creates and updates teams + Teams => 0x40 { + name: String =, + mode: u8 =, + display_name: Option = when(|p: &Teams| p.mode == 0 || p.mode == 2), + prefix: Option = when(|p: &Teams| p.mode == 0 || p.mode == 2), + suffix: Option = when(|p: &Teams| p.mode == 0 || p.mode == 2), + flags: Option = when(|p: &Teams| p.mode == 0 || p.mode == 2), + name_tag_visibility: Option = when(|p: &Teams| p.mode == 0 || p.mode == 2), + collision_rule: Option = when(|p: &Teams| p.mode == 0 || p.mode == 2), + color: Option = when(|p: &Teams| p.mode == 0 || p.mode == 2), + players: Option> = when(|p: &Teams| p.mode == 0 || p.mode == 3 || p.mode == 4), + } + // UpdateScore is used to update or remove an item from a scoreboard + // objective. + UpdateScore => 0x41 { + name: String =, + action: u8 =, + object_name: String =, + value: Option = when(|p: &UpdateScore| p.action != 1), + } + // SpawnPosition is sent to change the player's current spawn point. Currently + // only used by the client for the compass. + SpawnPosition => 0x42 { + location: types::Position =, + } + // TimeUpdate is sent to sync the world's time to the client, the client + // will manually tick the time itself so this doesn't need to sent repeatedly + // but if the server or client has issues keeping up this can fall out of sync + // so it is a good idea to sent this now and again + TimeUpdate => 0x43 { + world_age: i64 =, + time_of_day: i64 =, + } + // Title configures an on-screen title. + Title => 0x44 { + action: VarInt =, + title: Option = when(|p: &Title| p.action.0 == 0), + sub_title: Option = when(|p: &Title| p.action.0 == 1), + fade_in: Option = when(|p: &Title| p.action.0 == 2), + fade_stay: Option = when(|p: &Title| p.action.0 == 2), + fade_out: Option = when(|p: &Title| p.action.0 == 2), + } + // UpdateSign sets or changes the text on a sign. + UpdateSign => 0x45 { + location: types::Position =, + line1: format::Component =, + line2: format::Component =, + line3: format::Component =, + line4: format::Component =, + } + // PlayerListHeaderFooter updates the header/footer of the player list. + PlayerListHeaderFooter => 0x46 { + header: format::Component =, + footer: format::Component =, + } + // CollectItem causes the collected item to fly towards the collector. This + // does not destroy the entity. + CollectItem => 0x47 { + collected_entity_id: VarInt =, + collector_entity_id: VarInt =, + } + // EntityTeleport teleports the entity to the target location. This is + // sent if the entity moves further than EntityMove allows. + EntityTeleport => 0x48 { + entity_id: VarInt =, + x: i32 =, + y: i32 =, + z: i32 =, + yaw: i8 =, + pitch: i8 =, + on_ground: bool =, + } + // EntityProperties updates the properties for an entity. + EntityProperties => 0x49 { + entity_id: VarInt =, + properties: LenPrefixed =, + } + // EntityEffect applies a status effect to an entity for a given duration. + EntityEffect => 0x4A { + entity_id: VarInt =, + effect_id: i8 =, + amplifier: i8 =, + duration: VarInt =, + hide_particles: bool =, + } } } login Login { @@ -91,52 +790,52 @@ state_packets!( // LoginStart is sent immeditately after switching into the login // state. The passed username is used by the server to authenticate // the player in online mode. - LoginStart => 0 { + LoginStart => 0x00 { username: String =, } // EncryptionResponse is sent as a reply to EncryptionRequest. All // packets following this one must be encrypted with AES/CFB8 // encryption. - EncryptionResponse => 1 { + EncryptionResponse => 0x01 { // The key for the AES/CFB8 cipher encrypted with the // public key - shared_secret: LenPrefixed =, + shared_secret: LenPrefixedBytes =, // The verify token from the request encrypted with the // public key - verify_token: LenPrefixed =, + verify_token: LenPrefixedBytes =, } } clientbound Clientbound { // LoginDisconnect is sent by the server if there was any issues // authenticating the player during login or the general server // issues (e.g. too many players). - LoginDisconnect => 0 { + LoginDisconnect => 0x00 { reason: format::Component =, } // EncryptionRequest is sent by the server if the server is in // online mode. If it is not sent then its assumed the server is // in offline mode. - EncryptionRequest => 1 { + EncryptionRequest => 0x01 { // Generally empty, left in from legacy auth // but is still used by the client if provided server_id: String =, // A RSA Public key serialized in x.509 PRIX format - public_key: LenPrefixed =, + public_key: LenPrefixedBytes =, // Token used by the server to verify encryption is working // correctly - verify_token: LenPrefixed =, + verify_token: LenPrefixedBytes =, } // LoginSuccess is sent by the server if the player successfully // authenicates with the session servers (online mode) or straight // after LoginStart (offline mode). - LoginSuccess => 2 { + LoginSuccess => 0x02 { // String encoding of a uuid (with hyphens) uuid: String =, username: String =, } // SetInitialCompression sets the compression threshold during the // login state. - SetInitialCompression => 3 { + SetInitialCompression => 0x03 { // Threshold where a packet should be sent compressed threshold: VarInt =, } @@ -148,14 +847,14 @@ state_packets!( // switching to the Status protocol state and is used // to signal the server to send a StatusResponse to the // client - StatusRequest => 0 { + StatusRequest => 0x00 { empty: () =, } // StatusPing is sent by the client after recieving a // StatusResponse. The client uses the time from sending // the ping until the time of recieving a pong to measure // the latency between the client and the server. - StatusPing => 1 { + StatusPing => 0x01 { ping: i64 =, } } @@ -181,15 +880,268 @@ state_packets!( // "description": "Hello world", // "favicon": "data:image/png;base64," // } - StatusResponse => 0 { + StatusResponse => 0x00 { status: String =, } // StatusPong is sent as a reply to a StatusPing. // The Time field should be exactly the same as the // one sent by the client. - StatusPong => 1 { + StatusPong => 0x01 { ping: i64 =, } } } ); + +#[derive(Debug, Default)] +pub struct Statistic { + pub name: String, + pub value: VarInt, +} + +impl Serializable for Statistic { + fn read_from(buf: &mut io::Read) -> Result { + Ok(Statistic { + name: try!(Serializable::read_from(buf)), + value: try!(Serializable::read_from(buf)), + }) + } + + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + try!(self.name.write_to(buf)); + self.value.write_to(buf) + } +} + +#[derive(Debug, Default)] +pub struct BlockChangeRecord { + pub xz: u8, + pub y: u8, + pub block_id: VarInt, +} + +impl Serializable for BlockChangeRecord { + fn read_from(buf: &mut io::Read) -> Result { + Ok(BlockChangeRecord{ + xz: try!(Serializable::read_from(buf)), + y: try!(Serializable::read_from(buf)), + block_id: try!(Serializable::read_from(buf)), + }) + } + + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + try!(self.xz.write_to(buf)); + try!(self.y.write_to(buf)); + self.block_id.write_to(buf) + } +} + +#[derive(Debug, Default)] +pub struct ExplosionRecord { + pub x: i8, + pub y: i8, + pub z: i8, +} + +impl Serializable for ExplosionRecord { + fn read_from(buf: &mut io::Read) -> Result { + Ok(ExplosionRecord{ + x: try!(Serializable::read_from(buf)), + y: try!(Serializable::read_from(buf)), + z: try!(Serializable::read_from(buf)), + }) + } + + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + try!(self.x.write_to(buf)); + try!(self.y.write_to(buf)); + self.z.write_to(buf) + } +} + +#[derive(Debug)] +pub struct MapIcon { + pub direction_type: i8, + pub x: i8, + pub z: i8, +} + +impl Serializable for MapIcon { + fn read_from(buf: &mut io::Read) -> Result { + Ok(MapIcon{ + direction_type: try!(Serializable::read_from(buf)), + x: try!(Serializable::read_from(buf)), + z: try!(Serializable::read_from(buf)), + }) + } + + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + try!(self.direction_type.write_to(buf)); + try!(self.x.write_to(buf)); + self.z.write_to(buf) + } +} + +impl Default for MapIcon { + fn default() -> Self { + MapIcon { .. Default::default() } + } +} + +#[derive(Debug, Default)] +pub struct EntityProperty { + pub key: String, + pub value: f64, + pub modifiers: LenPrefixed, +} + +impl Serializable for EntityProperty { + fn read_from(buf: &mut io::Read) -> Result { + Ok(EntityProperty{ + key: try!(Serializable::read_from(buf)), + value: try!(Serializable::read_from(buf)), + modifiers: try!(Serializable::read_from(buf)), + }) + } + + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + try!(self.key.write_to(buf)); + try!(self.value.write_to(buf)); + self.modifiers.write_to(buf) + } +} + +#[derive(Debug, Default)] +pub struct PropertyModifier { + pub uuid: UUID, + pub amount: f64, + pub operation: i8, +} + +impl Serializable for PropertyModifier { + fn read_from(buf: &mut io::Read) -> Result { + Ok(PropertyModifier{ + uuid: try!(Serializable::read_from(buf)), + amount: try!(Serializable::read_from(buf)), + operation: try!(Serializable::read_from(buf)), + }) + } + + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + try!(self.uuid.write_to(buf)); + try!(self.amount.write_to(buf)); + self.operation.write_to(buf) + } +} + +#[derive(Debug)] +pub struct PlayerInfoData { + pub action: VarInt, + pub players: Vec, +} + +impl Serializable for PlayerInfoData { + fn read_from(buf: &mut io::Read) -> Result { + let mut m = PlayerInfoData{ + action: try!(Serializable::read_from(buf)), + players: Vec::new(), + }; + let len = try!(VarInt::read_from(buf)); + for _ in 0 .. len.0 { + let uuid = try!(UUID::read_from(buf)); + match m.action.0 { + 0 => { + let name = try!(String::read_from(buf)); + let mut props = Vec::new(); + let plen = try!(VarInt::read_from(buf)).0; + for _ in 0 .. plen { + let mut prop = PlayerProperty { + name: try!(String::read_from(buf)), + value: try!(String::read_from(buf)), + signature: Default::default(), + }; + if try!(bool::read_from(buf)) { + prop.signature = Some(try!(String::read_from(buf))); + } + props.push(prop); + } + let p = PlayerDetail::Add { + uuid: uuid, + name: name, + properties: props, + gamemode: try!(Serializable::read_from(buf)), + ping: try!(Serializable::read_from(buf)), + display: { + if try!(bool::read_from(buf)) { + Some(try!(Serializable::read_from(buf))) + } else { + None + } + }, + }; + m.players.push(p); + }, + 1 => { + m.players.push(PlayerDetail::UpdateGamemode{ + uuid: uuid, + gamemode: try!(Serializable::read_from(buf)), + }) + }, + 2 => { + m.players.push(PlayerDetail::UpdateLatency{ + uuid: uuid, + ping: try!(Serializable::read_from(buf)), + }) + }, + 3 => { + m.players.push(PlayerDetail::UpdateDisplayName{ + uuid: uuid, + display: { + if try!(bool::read_from(buf)) { + Some(try!(Serializable::read_from(buf))) + } else { + None + } + }, + }) + }, + 4 => { + m.players.push(PlayerDetail::Remove{ + uuid: uuid, + }) + }, + _ => panic!(), + } + } + Ok(m) + } + + fn write_to(&self, _: &mut io::Write) -> Result<(), io::Error> { + unimplemented!() // I'm lazy + } +} + +impl Default for PlayerInfoData { + fn default() -> Self { + PlayerInfoData { + action: VarInt(0), + players: Vec::new(), + } + } +} + +#[derive(Debug)] +pub enum PlayerDetail { + Add{uuid: UUID, name: String, properties: Vec, gamemode: VarInt, ping: VarInt, display: Option}, + UpdateGamemode{uuid: UUID, gamemode: VarInt}, + UpdateLatency{uuid: UUID, ping: VarInt}, + UpdateDisplayName{uuid: UUID, display: Option}, + Remove{uuid: UUID}, +} + +#[derive(Debug)] +pub struct PlayerProperty { + pub name: String, + pub value: String, + pub signature: Option, +} diff --git a/src/type/mod.rs b/src/type/mod.rs new file mode 100644 index 0000000..082cb1a --- /dev/null +++ b/src/type/mod.rs @@ -0,0 +1,6 @@ + +mod blockpos; +pub use self::blockpos::*; + +mod metadata; +pub use self::metadata::*; diff --git a/src/types/blockpos.rs b/src/types/blockpos.rs new file mode 100644 index 0000000..5f71af0 --- /dev/null +++ b/src/types/blockpos.rs @@ -0,0 +1,54 @@ +extern crate byteorder; + +use std::fmt; +use protocol::{Serializable}; +use std::io; +use std::io::{Read, Write}; +use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; + +#[derive(Clone, Copy)] +pub struct Position(u64); + +impl Position { + fn new(x: i32, y: i32, z: i32) -> Position { + Position( + (((x as u64) & 0x3FFFFFF) << 38) | + (((y as u64) & 0xFFF) << 26) | + ((z as u64) & 0x3FFFFFF) + ) + } + + fn get_x(&self) -> i32 { + ((self.0 as i64) >> 38) as i32 + } + + fn get_y(&self) -> i32 { + (((self.0 as i64) >> 26) & 0xFFF) as i32 + } + + fn get_z(&self) -> i32 { + ((self.0 as i64) << 38 >> 38) as i32 + } +} + +impl Default for Position { + fn default() -> Position { + Position(0) + } +} + +impl fmt::Debug for Position { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "<{},{},{}>", self.get_x(), self.get_y(), self.get_z()) + } +} + +impl Serializable for Position { + fn read_from(buf: &mut io::Read) -> Result { + Result::Ok(Position(try!(buf.read_u64::()))) + } + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + try!(buf.write_u64::(self.0)); + Result::Ok(()) + } +} diff --git a/src/types/metadata.rs b/src/types/metadata.rs new file mode 100644 index 0000000..3b78b42 --- /dev/null +++ b/src/types/metadata.rs @@ -0,0 +1,380 @@ + +use std::collections::HashMap; +use std::marker::PhantomData; +use std::io; +use std::io::{Read, Write}; +use std::fmt; +use protocol; +use protocol::{Serializable}; +use format; +use item; + +pub struct MetadataKey { + index: i32, + ty: PhantomData, +} + +impl MetadataKey { + // TODO: Make const later when possible + /*const*/ fn new(index: i32) -> MetadataKey { + MetadataKey { + index: index, + ty: PhantomData, + } + } +} + +pub struct Metadata { + map: HashMap, +} + +impl Metadata { + pub fn new() -> Metadata { + Metadata { map: HashMap::new() } + } + + pub fn get(&self, key: &MetadataKey) -> Option<&T> { + self.map.get(&key.index).map(T::unwrap) + } + + pub fn put(&mut self, key: &MetadataKey, val: T) { + self.map.insert(key.index, val.wrap()); + } + + fn put_raw(&mut self, index: i32, val: T) { + self.map.insert(index, val.wrap()); + } +} + +impl Serializable for Metadata { + + fn read_from(buf: &mut io::Read) -> Result { + let mut m = Metadata::new(); + loop { + let index = try!(u8::read_from(buf)) as i32; + if index == 0xFF { + break; + } + let ty = try!(u8::read_from(buf)); + match ty { + 0 => m.put_raw(index, try!(i8::read_from(buf))), + 1 => m.put_raw(index, try!(protocol::VarInt::read_from(buf)).0), + 2 => m.put_raw(index, try!(f32::read_from(buf))), + 3 => m.put_raw(index, try!(String::read_from(buf))), + 4 => m.put_raw(index, try!(format::Component::read_from(buf))), + 5 => m.put_raw(index, try!(Option::::read_from(buf))), + 6 => m.put_raw(index, try!(bool::read_from(buf))), + 7 => m.put_raw(index, [ + try!(f32::read_from(buf)), + try!(f32::read_from(buf)), + try!(f32::read_from(buf)) + ]), + 8 => m.put_raw(index, try!(super::Position::read_from(buf))), + 9 => { + if try!(bool::read_from(buf)) { + m.put_raw(index, try!(Option::::read_from(buf))); + } else { + m.put_raw::>(index, None); + } + }, + 10 => m.put_raw(index, try!(protocol::VarInt::read_from(buf))), + 11 => { + if try!(bool::read_from(buf)) { + m.put_raw(index, try!(Option::::read_from(buf))); + } else { + m.put_raw::>(index, None); + } + }, + 12 => m.put_raw(index, try!(protocol::VarInt::read_from(buf)).0 as u16), + _ => return Err(io::Error::new(io::ErrorKind::InvalidInput, protocol::Error::Err("unknown metadata type".to_owned()))), + } + } + Ok(m) + } + + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + for (k, v) in &self.map { + try!((*k as u8).write_to(buf)); + match *v { + Value::Byte(ref val) => { + try!(u8::write_to(&0, buf)); + try!(val.write_to(buf)); + }, + Value::Int(ref val) => { + try!(u8::write_to(&1, buf)); + try!(protocol::VarInt(*val).write_to(buf)); + }, + Value::Float(ref val) => { + try!(u8::write_to(&2, buf)); + try!(val.write_to(buf)); + }, + Value::String(ref val) => { + try!(u8::write_to(&3, buf)); + try!(val.write_to(buf)); + }, + Value::FormatComponent(ref val) => { + try!(u8::write_to(&4, buf)); + try!(val.write_to(buf)); + }, + Value::OptionalItemStack(ref val) => { + try!(u8::write_to(&5, buf)); + try!(val.write_to(buf)); + }, + Value::Bool(ref val) => { + try!(u8::write_to(&6, buf)); + try!(val.write_to(buf)); + }, + Value::Vector(ref val) => { + try!(u8::write_to(&7, buf)); + try!(val[0].write_to(buf)); + try!(val[1].write_to(buf)); + try!(val[2].write_to(buf)); + }, + Value::Position(ref val) => { + try!(u8::write_to(&8, buf)); + try!(val.write_to(buf)); + }, + Value::OptionalPosition(ref val) => { + try!(u8::write_to(&9, buf)); + try!(val.is_some().write_to(buf)); + try!(val.write_to(buf)); + }, + Value::Direction(ref val) => { + try!(u8::write_to(&10, buf)); + try!(val.write_to(buf)); + } + Value::OptionalUUID(ref val) => { + try!(u8::write_to(&11, buf)); + try!(val.is_some().write_to(buf)); + try!(val.write_to(buf)); + }, + Value::Block(ref val) => { + try!(u8::write_to(&11, buf)); + try!(protocol::VarInt(*val as i32).write_to(buf)); + } + } + } + try!(u8::write_to(&0xFF, buf)); + Ok(()) + } +} + +impl fmt::Debug for Metadata { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "Metadata[ ")); + for (k, v) in &self.map { + try!(write!(f, "{:?}={:?}, ", k, v)); + } + write!(f, "]") + } +} + +impl Default for Metadata { + fn default() -> Metadata { + Metadata::new() + } +} + +#[derive(Debug)] +enum Value { + Byte(i8), + Int(i32), + Float(f32), + String(String), + FormatComponent(format::Component), + OptionalItemStack(Option), + Bool(bool), + Vector([f32; 3]), + Position(super::Position), + OptionalPosition(Option), + Direction(protocol::VarInt), // TODO: Proper type + OptionalUUID(Option), + Block(u16), // TODO: Proper type +} + +pub trait MetaValue { + fn unwrap(&Value) -> &Self; + fn wrap(self) -> Value; +} + +impl MetaValue for i8 { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::Byte(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::Byte(self) + } +} + +impl MetaValue for i32 { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::Int(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::Int(self) + } +} + +impl MetaValue for f32 { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::Float(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::Float(self) + } +} + +impl MetaValue for String { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::String(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::String(self) + } +} + +impl MetaValue for format::Component { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::FormatComponent(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::FormatComponent(self) + } +} + +impl MetaValue for Option { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::OptionalItemStack(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::OptionalItemStack(self) + } +} + +impl MetaValue for bool { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::Bool(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::Bool(self) + } +} + +impl MetaValue for [f32; 3] { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::Vector(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::Vector(self) + } +} + +impl MetaValue for super::Position { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::Position(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::Position(self) + } +} + +impl MetaValue for Option { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::OptionalPosition(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::OptionalPosition(self) + } +} + +impl MetaValue for protocol::VarInt { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::Direction(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::Direction(self) + } +} + +impl MetaValue for Option { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::OptionalUUID(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::OptionalUUID(self) + } +} + +impl MetaValue for u16 { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::Block(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::Block(self) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::marker::PhantomData; + + const TEST: MetadataKey = + MetadataKey { + index: 0, + ty: PhantomData, + }; + + #[test] + fn basic() { + let mut m = Metadata::new(); + + m.put(&TEST, "Hello world".to_owned()); + + match m.get(&TEST) { + Some(val) => { + assert!(val == "Hello world"); + } + None => panic!("failed"), + } + } +} diff --git a/src/types/mod.rs b/src/types/mod.rs new file mode 100644 index 0000000..082cb1a --- /dev/null +++ b/src/types/mod.rs @@ -0,0 +1,6 @@ + +mod blockpos; +pub use self::blockpos::*; + +mod metadata; +pub use self::metadata::*;