├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src ├── core ├── logger.rs └── mod.rs ├── io ├── mod.rs ├── network │ ├── game_connection.rs │ ├── mod.rs │ └── packet │ │ ├── incoming │ │ ├── handshake.rs │ │ ├── mod.rs │ │ └── status.rs │ │ ├── mod.rs │ │ └── outgoing │ │ ├── mod.rs │ │ └── status.rs └── operations │ ├── mod.rs │ ├── reader.rs │ └── writer.rs ├── lib.rs ├── main.rs └── universe ├── mod.rs └── world └── mod.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | sudo: false 3 | addons: 4 | apt: 5 | packages: 6 | - libcurl4-openssl-dev 7 | - libelf-dev 8 | - libdw-dev 9 | rust: 10 | - nightly 11 | - beta 12 | - stable 13 | before_script: 14 | - | 15 | pip install 'travis-cargo<0.2' --user && 16 | export PATH=$HOME/.local/bin:$PATH 17 | script: 18 | - | 19 | travis-cargo build && 20 | travis-cargo test && 21 | travis-cargo --only nightly bench && 22 | travis-cargo --only stable doc 23 | after_success: 24 | - travis-cargo --only stable doc-upload 25 | # measure code coverage and upload to coveralls.io 26 | - travis-cargo coveralls --no-sudo 27 | env: 28 | global: 29 | - TRAVIS_CARGO_NIGHTLY_FEATURE="" 30 | - secure: TT+AOeCeDeI7x7cVxQl+PeaXIJlrdEgqU38k6W9uhlFcsD60ulr52nzkbrkf01O7xeBZ4Fanei61xc1FQlOmPeyM+GktN3jc4+B4NN/YStZEaZnmk7bl7vX7Rqw7b1bucHgkqYee6S5vK2LrFrNYnxs9fz0ruK1FRfNXi/iGPGPMBv/Dm/bz/HBAJDpPxrTbb0VU9XsbYeXZekWa7/SaRQEnJmETrg5XkSJm4ZHxsV0V5dSxNO7MZ149Gv4sNLMGlHWfXkyCfTSvc8V/7dqTkXUqa5GBXLCR1LMBJ2yF/LNMtrnyAnKPU80mybjFqfqd1m2/D1u1briZGJgMvg35d1H1nbXYoXlxoTDxLbD5t9AQ0VwL6FLMr/a3SMh8HOBTXMUtX0sbT6igm9WH+FP1rrG3RGKsG0jkMT9sqQWDr5BjRpkkSLqJ0iLqgp3kmM6iYvN8Y+1f6qawNAhSgCMHlccmVV3F1X7wxtMp5b7gMhQhlYNzNXhmmXd/b4KwG7j9TSEJ/tm7KFDFv+ww3Ri3ALbV3HF17EOCRAKdRW7q0O/v6XzgSKJkfsRI+d0LjdDOuz1SOXmBBvvR5z4jQwb1QTdFH9vzCzAQaYRVYRfEoA6FMZaAT7iPSSug5r61f7725pU8ElDwkA5uQuGVHqMghu4UpD+Ru6HT2ADUCYR/Rcc= 31 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "netherrack" 3 | version = "0.0.2-pre" 4 | authors = ["Cruz Julian Bishop "] 5 | description = "A Minecraft server programmed in Rust" 6 | 7 | repository = "https://github.com/Techern/Netherrack" 8 | documentation = "http://techern.github.io/Netherrack" 9 | readme = "README.md" 10 | keywords = ["Minecraft", "Server"] 11 | license = "MIT OR Apache-2.0" 12 | 13 | [dependencies] 14 | semver = "0.1.20" 15 | log = "0.3.1" 16 | integral_square_root = "1.0.0" 17 | chrono = "0.2.15" 18 | uuid = "0.1.17" 19 | varint = "0.2.0" 20 | bit_utils = "0.1.0" 21 | rustc-serialize = "0.3.16" 22 | io_operations = "0.1.0" 23 | lazy_static = "0.1.14" 24 | 25 | [lib] 26 | name = "netherrack" 27 | path = "src/lib.rs" 28 | test = true 29 | doctest = true 30 | bench = true 31 | doc = true 32 | plugin = false 33 | harness = true 34 | 35 | [[bin]] 36 | name = "netherrack_executable" 37 | path = "src/main.rs" 38 | test = false 39 | doctest = false 40 | bench = false 41 | doc = false 42 | plugin = false 43 | harness = false 44 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 The Netherrack Developers 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Netherrack (Server) 2 | ## A Minecraft server implementation programmed in Rust 3 | 4 | [![Build Status](https://travis-ci.org/Techern/Netherrack.svg?branch=master)](https://travis-ci.org/Techern/Netherrack) [![Crates.io](https://img.shields.io/crates/v/netherrack.svg)](https://crates.io/crates/netherrack) 5 | [![Coverage Status](https://coveralls.io/repos/Techern/Netherrack/badge.svg?branch=master&service=github)](https://coveralls.io/github/Techern/Netherrack?branch=master) [![Minecraft target](https://img.shields.io/badge/MC%20Target-1.8-green.svg)]() 6 | 7 | ## About Netherrack 8 | 9 | ### What is Netherrack? 10 | 11 | Netherrack started as a project to recreate Minecraft's server using Java (and later D 2.0), but was ultimately cancelled. 12 | 13 | Prismarine was started in 2014 for the same reason, but due to personal issues, it never got off the ground. 14 | 15 | Netherrack has now been resurrected as a recreation of the Minecraft server using Rust, and is required to gain the experience required to create a new generation of sandbox utilities and games. 16 | 17 | ### Can I use it? 18 | 19 | You can certainly try! Prepare to be disappointed, though, as most functionality is not yet implemented. 20 | 21 | By the time v0.0.5 is released, it should be playable. From there, we will keep growing bigger and better! 22 | 23 | #### I want to use Netherrack as an embedded server. Can I do that? 24 | 25 | Sure! Netherrack will fully support starting an embedded server. All you have to do is set the global logger and then run it :) 26 | 27 | You may eventually have to set more options, but for now it will be nice and simple 28 | 29 | ### Are there plugins? 30 | 31 | Not yet, but we're drafting a process that will allow a Netherrack server with plugins to interact with both vanilla and modified (with Forge, initially) clients without losing support for either. 32 | 33 | Of course, some plugins will require a Forge client (for example, an IronChests port), which will disable vanilla clients. 34 | 35 | ### Can I help out... 36 | 37 | #### As a programmer? 38 | 39 | Yes, please! There is still a **lot** of work required, and even a tiny bit helps immensely. 40 | 41 | #### As a sponsor? 42 | 43 | Wow, I'm flattered, but we're not quite at that stage yet. 44 | 45 | #### As a beta tester? 46 | 47 | Of course! All versions in the 0.x.y range can be considered pre-release, but official alpha and beta builds will be introduced before 1.0.0. 48 | 49 | ## License 50 | 51 | Licensed under either of 52 | 53 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 54 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 55 | 56 | at your option. 57 | 58 | ### Contribution 59 | 60 | Unless you explicitly state otherwise, any contribution intentionally 61 | submitted for inclusion in the work by you, as defined in the Apache-2.0 62 | license, shall be dual licensed as above, without any additional terms or 63 | conditions. 64 | -------------------------------------------------------------------------------- /src/core/logger.rs: -------------------------------------------------------------------------------- 1 | use ::log::{LogRecord, LogMetadata}; 2 | 3 | ///The Logger used by Netherrack 4 | /// 5 | ///For now, it simply logs to standard output. In future versions, it will be extended 6 | pub struct NetherrackLogger; 7 | 8 | impl ::log::Log for NetherrackLogger { 9 | 10 | ///Checks to see if a LogRecord can be accepted based on LogMetadata 11 | #[allow(unused_variables)] 12 | fn enabled(&self, metadata: &LogMetadata) -> bool { 13 | true //Before 0.1, change dynamically based on if we're a prerelease version 14 | } 15 | 16 | ///Attempts to log a LogRecord 17 | fn log(&self, record: &LogRecord) { 18 | //First, check to see if logging is enabled for the metadata 19 | if self.enabled(record.metadata()) { 20 | println!("[{}] {}: {}", record.level(), record.target(), record.args()); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/core/mod.rs: -------------------------------------------------------------------------------- 1 | //! Core functionality for Netherrack 2 | //! 3 | //! Will be expanded dramatically in the future 4 | 5 | pub mod logger; 6 | -------------------------------------------------------------------------------- /src/io/mod.rs: -------------------------------------------------------------------------------- 1 | //! Access to various I/O operations and features 2 | //! 3 | //! To be expanded "soon" 4 | 5 | // Include network operations 6 | pub mod network; 7 | 8 | // Include I/O operations 9 | pub mod operations; 10 | 11 | pub use self::operations::reader::NetherrackReader; 12 | 13 | pub use self::operations::writer::NetherrackWriter; 14 | -------------------------------------------------------------------------------- /src/io/network/game_connection.rs: -------------------------------------------------------------------------------- 1 | //! Utilities to do with connections between a Minecraft or Forge client and Netherrack 2 | 3 | extern crate chrono; 4 | use self::chrono::duration::Duration; 5 | 6 | /*use super::packet::{ PacketHeader, 7 | ID_HANDSHAKE_CTS_HANDSHAKING, 8 | ID_STATUS_CTS_REQUEST, ID_STATUS_CTS_PING 9 | };*/ 10 | 11 | use std::net::{Shutdown, TcpStream}; 12 | 13 | use ::io_operations::reader::Reader; 14 | 15 | /// An enum describing the current connection's state 16 | #[derive(PartialEq, Clone, Copy, Debug)] 17 | pub enum ConnectionState { 18 | 19 | /// Connection is in handshake mode 20 | HANDSHAKE, 21 | 22 | /// Connection is in login mode 23 | LOGIN, 24 | 25 | /// Connection is in status mode 26 | STATUS, 27 | 28 | /// Connection is in play mode 29 | PLAY 30 | 31 | } 32 | 33 | /// A struct defining a game connection 34 | #[derive(Debug)] 35 | pub struct GameConnection { 36 | 37 | /// The TCP stream bound to this GameConnection 38 | pub stream: TcpStream, 39 | 40 | /// The state of this GameConnection 41 | pub state: ConnectionState, 42 | 43 | /// Whether the client has the Forge Mod Loader injected into it 44 | /// 45 | /// This may change in 1.9 as FML is being destroyed and Forge is becoming the norm 46 | pub forge_enabled: bool, 47 | 48 | /// A boolean declaring if this GameConnection is connected 49 | pub connected: bool 50 | 51 | } 52 | 53 | impl GameConnection { 54 | 55 | /// Creates a new GameConnection 56 | pub fn new(stream: TcpStream) -> GameConnection { 57 | GameConnection { 58 | stream: stream, 59 | state: ConnectionState::HANDSHAKE, 60 | forge_enabled: false, 61 | connected: true //HURR DURR 62 | } 63 | } 64 | 65 | pub fn disconnect(&mut self) { 66 | //TODO: Check to see if in ConnectionState::PLAY, otherwise 67 | let result = self.stream.shutdown(Shutdown::Both); 68 | 69 | if result.is_ok() == false { 70 | error!("Error disconnecting: {:?}", result); 71 | } 72 | 73 | self.connected = false; 74 | 75 | ::std::thread::yield_now(); 76 | 77 | } 78 | 79 | /// Starts listening on the connection 80 | pub fn start_listening(&mut self) { 81 | 82 | trace!("Got a new client from {}!", self.stream.peer_addr().unwrap()); 83 | 84 | let mut timeout_duration = Duration::zero(); 85 | 86 | loop { 87 | 88 | //First, let's start off the timeout timer. 89 | timeout_duration = timeout_duration + Duration::milliseconds(2); 90 | ::std::thread::sleep(::std::time::Duration::from_millis(2)); 91 | 92 | if timeout_duration.num_seconds() >= 1 { 93 | info!("Client at {} timed out, dropping connection", self.stream.peer_addr().unwrap()); 94 | self.disconnect(); 95 | break; 96 | } 97 | 98 | if !self.connected { 99 | debug!("Client at {} was forcibly disconnected, maybe for a good reason", self.stream.peer_addr().unwrap()); 100 | break; 101 | } 102 | 103 | match self.stream.read_unsigned_byte() { 104 | Err(error) => { 105 | 106 | if error != "Could not read one byte" { 107 | error!("Error: {}", error); 108 | self.disconnect(); 109 | } 110 | } 111 | 112 | Ok(value) => { 113 | timeout_duration = Duration::zero(); 114 | info!("Value is {}", value); 115 | } 116 | } 117 | 118 | /* 119 | let mut raw_buffer = vec![0u8; 512]; 120 | 121 | match self.stream.read(&mut raw_buffer) { 122 | 123 | Err(error) => { 124 | // Connection dropped out or something broke 125 | // In the future, we use the customized NetherrackStream to see if we're in GAME mode, and if so, get the attached player and start saving their information and get rid of them 126 | // For now, we just exit the loop 127 | error!("Got an error! {}", error); 128 | 129 | self.disconnect(); 130 | break; 131 | } 132 | Ok(count) => { 133 | if count == 0 { 134 | //Nothing in stream, let's sleep for a few milliseconds and try again 135 | timeout_duration = timeout_duration + Duration::milliseconds(2); 136 | ::std::thread::sleep_ms(2); 137 | } else { 138 | 139 | timeout_duration = Duration::zero(); 140 | 141 | // Now truncate the raw buffer - Don't worry, it will reallocate to 512 on the next networking loop 142 | raw_buffer.truncate(count); 143 | 144 | let mut backing: VecDeque = VecDeque::::with_capacity(count); 145 | 146 | for b in raw_buffer { 147 | 148 | backing.push_back(b); 149 | } 150 | 151 | let mut buffer = DequeBuffer::from(backing); 152 | 153 | //drop(raw_buffer); 154 | 155 | let length_result = buffer.read_unsigned_varint_32(); 156 | let id_result = buffer.read_unsigned_varint_32(); 157 | 158 | if length_result.is_err() || id_result.is_err() { 159 | error!("Error while reading packet ID or length! Oh no, dropping connection"); 160 | 161 | self.disconnect(); 162 | break; 163 | } 164 | 165 | let packet_header = PacketHeader::new(length_result.unwrap(), id_result.unwrap()); 166 | 167 | if self.state == ConnectionState::HANDSHAKE { 168 | 169 | match packet_header.id { 170 | 171 | ID_HANDSHAKE_CTS_HANDSHAKING => { 172 | super::packet::incoming::handshake::HandshakePacket::decode(packet_header, self, &mut buffer).handle(self); 173 | }, 174 | _ => debug!("Incoming handshake packet unhandled; ID: {}, Length: {}", packet_header.id, packet_header.length) 175 | 176 | } 177 | 178 | } else if self.state == ConnectionState::LOGIN { 179 | 180 | match packet_header.id { 181 | 182 | _ => debug!("Incoming login packet unhandled; ID: {}, Length: {}", packet_header.id, packet_header.length) 183 | 184 | } 185 | 186 | } else if self.state == ConnectionState::STATUS { 187 | 188 | match packet_header.id { 189 | 190 | ID_STATUS_CTS_REQUEST => { 191 | super::packet::incoming::status::StatusRequestPacket::decode(packet_header, self, &mut buffer).handle(self); 192 | }, 193 | ID_STATUS_CTS_PING => { 194 | super::packet::incoming::status::ListPingPacket::decode(packet_header, self, &mut buffer).handle(self); 195 | }, 196 | _ => debug!("Incoming play packet unhandled; ID: {}, Length: {}", packet_header.id, packet_header.length) 197 | 198 | } 199 | 200 | } else if self.state == ConnectionState::PLAY { 201 | 202 | match packet_header.id { 203 | 204 | _ => debug!("Incoming play packet unhandled; ID: {}, Length: {}", packet_header.id, packet_header.length) 205 | 206 | } 207 | 208 | } 209 | 210 | // This is a memory leak. We need to get the time of last packet and check to see if it's more than 20 seconds ago 211 | } 212 | } 213 | 214 | }*/ 215 | 216 | } 217 | 218 | } 219 | 220 | } 221 | -------------------------------------------------------------------------------- /src/io/network/mod.rs: -------------------------------------------------------------------------------- 1 | //! Functions relating to network operations. 2 | //! 3 | //! This will eventually be moved 4 | 5 | pub mod game_connection; 6 | use self::game_connection::GameConnection; 7 | 8 | pub mod packet; 9 | 10 | use std::net::TcpListener; 11 | 12 | use std::thread; 13 | 14 | 15 | fn start_listening(port: u16) -> Result { 16 | 17 | let listener = TcpListener::bind(("0.0.0.0", port)); 18 | 19 | if listener.is_ok() { 20 | return Ok(listener.unwrap()); 21 | } else { 22 | return Err("Could not listen on requested port"); 23 | } 24 | 25 | } 26 | 27 | pub fn start_network() { 28 | 29 | let listener = start_listening(25565); 30 | 31 | if listener.is_err() { 32 | error!("Could not start listening on port {}", 25565); 33 | } 34 | 35 | let listener = listener.unwrap(); 36 | 37 | for stream in listener.incoming() { 38 | 39 | match stream { 40 | Ok(stream) => { 41 | thread::spawn(move || { 42 | // New connection succeeded 43 | //TODO: Add this connection to a list of connections 44 | GameConnection::new(stream).start_listening() 45 | }); 46 | } 47 | Err(e) => { 48 | error!("Could not accept a new stream: {}", e); 49 | } 50 | } 51 | 52 | } 53 | 54 | drop(listener); 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/io/network/packet/incoming/handshake.rs: -------------------------------------------------------------------------------- 1 | //! Defines all handshake packets 2 | //! 3 | //! Thankfully, there's only one packet so far :) 4 | 5 | /*use super::super::super::deque_buffer::DequeBuffer; 6 | use super::super::super::game_connection::{ConnectionState, GameConnection}; //It's super super super effective! 7 | use super::super::PacketHeader; 8 | 9 | /// A packet sent from the client to initiate a handshake 10 | pub struct HandshakePacket { 11 | 12 | /// The header of this HandshakePacket 13 | pub header: PacketHeader, 14 | 15 | /// The protocol version that the client is using 16 | pub protocol_version: u32, 17 | 18 | /// The address the client is using to connect to the server 19 | pub server_address: String, 20 | 21 | /// The port the client is connecting to the server with 22 | pub server_port: u16, 23 | 24 | /// The next state requested by the client 25 | pub next_state: u32 26 | 27 | } 28 | 29 | impl HandshakePacket { 30 | 31 | /// Decodes this HandshakePacket 32 | pub fn decode(header: PacketHeader, connection: &mut GameConnection, buffer: &mut DequeBuffer) -> HandshakePacket { 33 | 34 | let protocol_result = buffer.read_unsigned_varint_32(); 35 | 36 | if protocol_result.is_err() { 37 | error!("Error reading protocol version"); 38 | connection.disconnect(); 39 | } 40 | 41 | let hostname: String = buffer.read_utf8_string(); 42 | 43 | let port: u16 = buffer.read_unsigned_short(); 44 | 45 | let next_state_result = buffer.read_unsigned_varint_32(); 46 | 47 | if next_state_result.is_err() { 48 | error!("Invalid next state: {:?}", next_state_result); 49 | connection.disconnect(); 50 | } 51 | 52 | HandshakePacket { header: header, protocol_version: protocol_result.unwrap(), server_address: hostname, server_port: port, next_state: next_state_result.unwrap() } 53 | 54 | } 55 | 56 | /// Handles this HandshakePacket 57 | pub fn handle(&self, connection: &mut GameConnection) { 58 | 59 | debug!("Incoming connection using protocol {}", self.protocol_version); 60 | 61 | if self.server_address.ends_with("\0FML\0") { 62 | connection.forge_enabled = true; 63 | } 64 | 65 | match self.next_state { 66 | 67 | 1 => { 68 | connection.state = ConnectionState::STATUS; 69 | }, 70 | 2 => { 71 | connection.state = ConnectionState::LOGIN; 72 | } 73 | _ => { 74 | error!("Invalid handshake next state of {}, disconnecting", self.next_state); 75 | connection.disconnect(); 76 | } 77 | 78 | } 79 | } 80 | 81 | }*/ 82 | -------------------------------------------------------------------------------- /src/io/network/packet/incoming/mod.rs: -------------------------------------------------------------------------------- 1 | //! The module containing all incoming packet implementations 2 | //! 3 | //! Any unimplemented packets currently print out the ID and length for future reference (see game_connection.rs) 4 | 5 | pub mod handshake; 6 | pub mod status; 7 | 8 | /* 9 | use super::super::super::deque_buffer::DequeBuffer; 10 | use super::super::super::game_connection::GameConnection; //It's super super super effective! 11 | use super::super::PacketHeader; 12 | 13 | /// A packet sent from the client to 14 | pub struct Packet { 15 | 16 | /// The header of this Packet 17 | pub header: PacketHeader, 18 | 19 | // Your fields here 20 | 21 | } 22 | 23 | impl Packet { 24 | 25 | /// Decodes this Packet 26 | /// 27 | /// **DO NOT DO ANYTHING EXCEPT DECODING!** 28 | /// 29 | /// Actual functionality will be handled in the handle function 30 | pub fn decode(header: PacketHeader, connection: &mut GameConnection, buffer: &mut DequeBuffer) -> Packet { 31 | 32 | // Decode here 33 | 34 | Packet { header: header /*etc*/ } 35 | 36 | } 37 | 38 | /// Handles this Packet 39 | pub fn handle(&self, connection: &mut GameConnection) { 40 | info!("Got a packet!"); 41 | 42 | // Ooooh, handle the packet 43 | } 44 | 45 | } 46 | */ 47 | -------------------------------------------------------------------------------- /src/io/network/packet/incoming/status.rs: -------------------------------------------------------------------------------- 1 | //! Handles all status packets 2 | /* 3 | use super::super::super::deque_buffer::DequeBuffer; 4 | use super::super::super::game_connection::GameConnection; //It's super super super effective! 5 | 6 | use super::super::PacketHeader; 7 | 8 | use super::super::outgoing::OutgoingPacket; 9 | use super::super::outgoing::status::{StatusResponsePacket, ListPongPacket}; 10 | 11 | /// A packet sent from the client to make the server send a status response packet 12 | pub struct StatusRequestPacket { 13 | 14 | /// The header of this StatusRequestPacket 15 | pub header: PacketHeader 16 | 17 | } 18 | 19 | impl StatusRequestPacket { 20 | 21 | /// Decodes this StatusRequestPacket 22 | /// 23 | /// **DO NOT DO ANYTHING EXCEPT DECODING!** 24 | /// 25 | /// Actual functionality will be handled in the handle function 26 | #[allow(unused_variables)] 27 | pub fn decode(header: PacketHeader, connection: &mut GameConnection, buffer: &mut DequeBuffer) -> StatusRequestPacket { 28 | 29 | // Nothing to do here 30 | 31 | StatusRequestPacket { header: header /*etc*/ } 32 | 33 | } 34 | 35 | /// Handles this StatusRequestPacket 36 | pub fn handle(&self, connection: &mut GameConnection) { 37 | StatusResponsePacket::new().send(connection); 38 | } 39 | 40 | } 41 | 42 | /// A list ping packet sent from the client to the server 43 | pub struct ListPingPacket { 44 | 45 | /// The header of this ListPingPacket 46 | pub header: PacketHeader, 47 | 48 | /// The ping ID (usually the system time in milliseconds) 49 | pub payload: i64 50 | 51 | } 52 | 53 | impl ListPingPacket { 54 | 55 | /// Decodes this Packet 56 | /// 57 | /// **DO NOT DO ANYTHING EXCEPT DECODING!** 58 | /// 59 | /// Actual functionality will be handled in the handle function 60 | #[allow(unused_variables)] 61 | pub fn decode(header: PacketHeader, connection: &mut GameConnection, buffer: &mut DequeBuffer) -> ListPingPacket { 62 | 63 | let id: i64 = buffer.read_signed_long(); 64 | 65 | ListPingPacket { header: header, payload: id } 66 | 67 | } 68 | 69 | /// Handles this ListPingPacket 70 | pub fn handle(&self, connection: &mut GameConnection) { 71 | ListPongPacket::new(self.payload).send(connection); 72 | } 73 | 74 | }*/ 75 | -------------------------------------------------------------------------------- /src/io/network/packet/mod.rs: -------------------------------------------------------------------------------- 1 | //! Functions relating to network packets 2 | 3 | pub mod incoming; 4 | pub mod outgoing; 5 | 6 | pub use super::game_connection::GameConnection; 7 | 8 | /// A struct defining the header of a Packet 9 | #[derive(Clone, Debug)] 10 | pub struct PacketHeader { 11 | 12 | /// The number of bytes contained in the ID and the packet data 13 | pub length: u32, 14 | 15 | /// The ID of this packet 16 | pub id: u32 17 | 18 | } 19 | 20 | impl PacketHeader { 21 | 22 | /// Creates a new PacketHeader 23 | pub fn new(length: u32, id: u32) -> PacketHeader { 24 | PacketHeader { length: length, id: id } 25 | } 26 | 27 | } 28 | 29 | /// The ID of a handshake packet 30 | pub const ID_HANDSHAKE_CTS_HANDSHAKING: u32 = 0x00; 31 | 32 | /// The ID of a legacy server list ping packet 33 | pub const ID_HANDSHAKE_CTS_LEGACY_PING: u32 = 0xFE; 34 | 35 | /// The ID of a keep-alive packet 36 | /// 37 | /// One of these must be sent periodically, and if the client does not receive one at least every 30 seconds, it will disconnect 38 | pub const ID_PLAY_STC_KEEP_ALIVE: u32 = 0x00; 39 | 40 | /// The ID of a "join game" packet packet 41 | pub const ID_PLAY_STC_JOIN_GAME: u32 = 0x01; 42 | 43 | /// The ID of a chat message packet 44 | pub const ID_PLAY_STC_CHAT_MESSAGE: u32 = 0x02; 45 | 46 | /// The ID of a time update packet 47 | pub const ID_PLAY_STC_TIME_UPDATE: u32 = 0x03; 48 | 49 | /// The ID of a entity equipment packet 50 | pub const ID_PLAY_STC_ENTITY_EQUIPMENT: u32 = 0x04; 51 | 52 | /// The ID of a spawn position packet 53 | pub const ID_PLAY_STC_SPAWN_POSITION: u32 = 0x05; 54 | 55 | /// The ID of a health update packet 56 | pub const ID_PLAY_STC_UPDATE_HEALTH: u32 = 0x06; 57 | 58 | /// The ID of a respawn packet 59 | pub const ID_PLAY_STC_RESPAWN: u32 = 0x07; 60 | 61 | /// The ID of a player position **and** look packet 62 | pub const ID_PLAY_STC_PLAYER_POSITION_AND_LOOK: u32 = 0x08; 63 | 64 | /// The ID of a change held item packet 65 | pub const ID_PLAY_STC_CHANGE_HELD_ITEM: u32 = 0x09; 66 | 67 | /// The ID of a use bed packet 68 | pub const ID_PLAY_STC_USE_BED: u32 = 0x0A; 69 | 70 | /// The ID of an animation packet 71 | pub const ID_PLAY_STC_ANIMATION: u32 = 0x0B; 72 | 73 | /// The ID of a spawn player packet 74 | pub const ID_PLAY_STC_SPAWN_PLAYER: u32 = 0x0C; 75 | 76 | /// The ID of a collect item packet 77 | pub const ID_PLAY_STC_COLLECT_ITEM: u32 = 0x0D; 78 | 79 | /// The ID of a spawn object packet 80 | pub const ID_PLAY_STC_SPAWN_OBJECT: u32 = 0x0E; 81 | 82 | /// The ID of a spawn mob packet 83 | pub const ID_PLAY_STC_SPAWN_MOB: u32 = 0x0F; 84 | 85 | /// The ID of a spawn painting packet 86 | pub const ID_PLAY_STC_SPAWN_PAINTING: u32 = 0x10; 87 | 88 | /// The ID of a spawn experience orb packet 89 | pub const ID_PLAY_STC_SPAWN_EXPERIENCE_ORB: u32 = 0x11; 90 | 91 | /// The ID of an entity velocity packet 92 | pub const ID_PLAY_STC_ENTITY_VELOCITY: u32 = 0x12; 93 | 94 | /// The ID of a destroy entities packet 95 | pub const ID_PLAY_STC_DESTROY_ENTITIES: u32 = 0x13; 96 | 97 | /// The ID of an entity packet 98 | pub const ID_PLAY_STC_ENTITY: u32 = 0x14; 99 | 100 | /// The ID of an entity relative move packet 101 | pub const ID_PLAY_STC_ENTITY_RELATIVE_MOVE: u32 = 0x15; 102 | 103 | /// The ID of an entity look packet 104 | pub const ID_PLAY_STC_ENTITY_LOOK: u32 = 0x16; 105 | 106 | /// The ID of an entity look and relative move packet 107 | pub const ID_PLAY_STC_ENTITY_LOOK_AND_RELATIVE_MOVE: u32 = 0x17; 108 | 109 | /// The ID of an entity teleport packet 110 | pub const ID_PLAY_STC_ENTITY_TELEPORT: u32 = 0x18; 111 | 112 | /// The ID of an entity head look packet 113 | pub const ID_PLAY_STC_HEAD_LOOK: u32 = 0x19; 114 | 115 | /// The ID of an entity status packet 116 | pub const ID_PLAY_STC_ENTITY_STATUS: u32 = 0x1A; 117 | 118 | /// The ID of an attach entity packet 119 | pub const ID_PLAY_STC_ATTACH_ENTITY: u32 = 0x1B; 120 | 121 | /// The ID of an entity metadata packet 122 | pub const ID_PLAY_STC_ENTITY_METADATA: u32 = 0x1C; 123 | 124 | /// The ID of an entity effect packet 125 | pub const ID_PLAY_STC_ENTITY_EFFECT: u32 = 0x1D; 126 | 127 | /// The ID of a remove entity effect packet 128 | pub const ID_PLAY_STC_REMOVE_ENTITY_EFFECT: u32 = 0x1E; 129 | 130 | /// The ID of a set experience packet 131 | pub const ID_PLAY_STC_SET_EXPERIENCE: u32 = 0x1F; 132 | 133 | /// The ID of an entity properties packet 134 | pub const ID_PLAY_STC_ENTITY_PROPERTIES: u32 = 0x20; 135 | 136 | /// The ID of a chunk data packet 137 | pub const ID_PLAY_STC_CHUNK_DATA: u32 = 0x21; 138 | 139 | /// The ID of a multi block change packet 140 | pub const ID_PLAY_STC_MULTI_BLOCK_CHANGE: u32 = 0x22; 141 | 142 | /// The ID of a block change packet 143 | pub const ID_PLAY_STC_BLOCK_CHANGE: u32 = 0x23; 144 | 145 | /// The ID of a block action packet 146 | pub const ID_PLAY_STC_BLOCK_ACTION: u32 = 0x24; 147 | 148 | /// The ID of a block break animation packet 149 | pub const ID_PLAY_STC_BLOCK_BREAK_ANIMATION: u32 = 0x25; 150 | 151 | /// The ID of a map chunk bulk packet 152 | pub const ID_PLAY_STC_MAP_CHUNK_BULK: u32 = 0x26; 153 | 154 | /// The ID of an explosion packet 155 | pub const ID_PLAY_STC_EXPLOSION: u32 = 0x27; 156 | 157 | /// The ID of an effect packet 158 | pub const ID_PLAY_STC_EFFECT: u32 = 0x28; 159 | 160 | /// The ID of a sound effect packet 161 | pub const ID_PLAY_STC_SOUND_EFFECT: u32 = 0x29; 162 | 163 | /// The ID of a particle packet 164 | pub const ID_PLAY_STC_PARTICLE: u32 = 0x2A; 165 | 166 | /// The ID of a change game state packet 167 | pub const ID_PLAY_STC_CHANGE_GAME_STATE: u32 = 0x2B; 168 | 169 | /// The ID of a spawn global entity packet 170 | pub const ID_PLAY_STC_SPAWN_GLOBAL_ENTITY: u32 = 0x2C; 171 | 172 | /// The ID of an open window packet 173 | pub const ID_PLAY_STC_OPEN_WINDOW: u32 = 0x2D; 174 | 175 | /// The ID of a close window packet 176 | pub const ID_PLAY_STC_CLOSE_WINDOW: u32 = 0x2E; 177 | 178 | /// The ID of a set slot packet 179 | pub const ID_PLAY_STC_SET_SLOT: u32 = 0x2F; 180 | 181 | /// The ID of a window items packet 182 | pub const ID_PLAY_STC_WINDOW_ITEMS: u32 = 0x30; 183 | 184 | /// The ID of a window property packet 185 | pub const ID_PLAY_STC_WINDOW_PROPERTY: u32 = 0x31; 186 | 187 | /// The ID of a confirm transaction packet 188 | pub const ID_PLAY_STC_CONFIRM_TRANSACTION: u32 = 0x32; 189 | 190 | /// The ID of a sign update packet 191 | pub const ID_PLAY_STC_SIGN_UPDATE: u32 = 0x33; 192 | 193 | /// The ID of a maps packet 194 | pub const ID_PLAY_STC_MAPS: u32 = 0x34; 195 | 196 | /// The ID of a block entity update packet 197 | pub const ID_PLAY_STC_BLOCK_ENTITY_UPDATE: u32 = 0x35; 198 | 199 | /// The ID of an open sign editor packet 200 | pub const ID_PLAY_STC_OPEN_SIGN_EDITOR: u32 = 0x36; 201 | 202 | /// The ID of a statistics packet 203 | pub const ID_PLAY_STC_STATISTICS: u32 = 0x37; 204 | 205 | /// The ID of a player list item packet 206 | pub const ID_PLAY_STC_PLAYER_LIST_ITEM: u32 = 0x38; 207 | 208 | /// The ID of a player abilities packet 209 | pub const ID_PLAY_STC_PLAYER_ABILITIES: u32 = 0x39; 210 | 211 | /// The ID of a tab complete packet 212 | pub const ID_PLAY_STC_TAB_COMPLETE: u32 = 0x3A; 213 | 214 | /// The ID of a scoreboard objective packet 215 | pub const ID_PLAY_STC_SCOREBOARD_OBJECTIVE: u32 = 0x3B; 216 | 217 | /// The ID of an update score packet 218 | pub const ID_PLAY_STC_UPDATE_SCORE: u32 = 0x3C; 219 | 220 | /// The ID of a display scoreboard packet 221 | pub const ID_PLAY_STC_DISPLAY_SCOREBOARD: u32 = 0x3D; 222 | 223 | /// The ID of a teams packet 224 | pub const ID_PLAY_STC_TEAMS: u32 = 0x3E; 225 | 226 | /// The ID of a plugin message packet 227 | pub const ID_PLAY_STC_PLUGIN_MESSAGE: u32 = 0x3F; 228 | 229 | /// The ID of a disconnect packet 230 | pub const ID_PLAY_STC_DISCONNECT: u32 = 0x40; 231 | 232 | /// The ID of a server difficulty packet 233 | pub const ID_PLAY_STC_SERVER_DIFFICULTY: u32 = 0x41; 234 | 235 | /// The ID of a combat event packet 236 | pub const ID_PLAY_STC_COMBAT_EVENT: u32 = 0x42; 237 | 238 | /// The ID of a camera packet 239 | pub const ID_PLAY_STC_CAMERA: u32 = 0x43; 240 | 241 | /// The ID of a world border packet 242 | pub const ID_PLAY_STC_WORLD_BORDER: u32 = 0x44; 243 | 244 | /// The ID of a title packet 245 | pub const ID_PLAY_STC_TITLE: u32 = 0x45; 246 | 247 | /// The ID of a set compression packet 248 | pub const ID_PLAY_STC_SET_COMPRESSION: u32 = 0x46; 249 | 250 | /// The ID of a player list header/footer packet 251 | pub const ID_PLAY_STC_PLAYER_LIST_HEADER_FOOTER: u32 = 0x47; 252 | 253 | /// The ID of a send resource pack packet 254 | pub const ID_PLAY_STC_SEND_RESOURCE_PACK: u32 = 0x48; 255 | 256 | /// The ID of an update entity NBT packet 257 | pub const ID_PLAY_STC_UPDATE_ENTITY_NBT: u32 = 0x49; 258 | 259 | /// The ID of a keep alive packet 260 | pub const ID_PLAY_CTS_KEEP_ALIVE: u32 = 0x00; 261 | 262 | /// The ID of a chat message packet 263 | pub const ID_PLAY_CTS_CHAT_MESSAGE: u32 = 0x01; 264 | 265 | /// The ID of a use entity packet 266 | pub const ID_PLAY_CTS_USE_ENTITY: u32 = 0x02; 267 | 268 | /// The ID of a player packet 269 | pub const ID_PLAY_CTS_PLAYER: u32 = 0x03; 270 | 271 | /// The ID of a player position packet 272 | pub const ID_PLAY_CTS_PLAYER_POSITION: u32 = 0x04; 273 | 274 | /// The ID of a player look packet 275 | pub const ID_PLAY_CTS_PLAYER_LOOK: u32 = 0x05; 276 | 277 | /// The ID of a player position and look packet 278 | pub const ID_PLAY_CTS_PLAYER_POSITION_AND_LOOK: u32 = 0x06; 279 | 280 | /// The ID of a player digging packet 281 | pub const ID_PLAY_CTS_PLAYER_DIGGING: u32 = 0x07; 282 | 283 | /// The ID of a player block placement packet 284 | pub const ID_PLAY_CTS_PLAYER_BLOCK_PLACEMENT: u32 = 0x08; 285 | 286 | /// The ID of a change held item packet 287 | pub const ID_PLAY_CTS_CHANGE_HELD_ITEM: u32 = 0x09; 288 | 289 | /// The ID of an animation packet 290 | pub const ID_PLAY_CTS_ANIMATION: u32 = 0x0A; 291 | 292 | /// The ID of an entity action packet 293 | pub const ID_PLAY_CTS_ENTITY_ACTION: u32 = 0x0B; 294 | 295 | /// The ID of a steer vehicle packet 296 | pub const ID_PLAY_CTS_STEER_VEHICLE: u32 = 0x0C; 297 | 298 | /// The ID of a close window packet 299 | pub const ID_PLAY_CTS_CLOSE_WINDOW: u32 = 0x0D; 300 | 301 | /// The ID of a click window packet 302 | pub const ID_PLAY_CTS_CLICK_WINDOW: u32 = 0x0E; 303 | 304 | /// The ID of a confirm transaction packet 305 | pub const ID_PLAY_CTS_CONFIRM_TRANSACTION: u32 = 0x0F; 306 | 307 | /// The ID of a creative inventory action packet 308 | pub const ID_PLAY_CTS_CREATIVE_INVENTORY_ACTION: u32 = 0x10; 309 | 310 | /// The ID of an enchant item packet 311 | pub const ID_PLAY_CTS_ENCHANT_ITEM: u32 = 0x11; 312 | 313 | /// The ID of a sign update packet 314 | pub const ID_PLAY_CTS_SIGN_UPDATE: u32 = 0x12; 315 | 316 | /// The ID of a player abilities packet 317 | pub const ID_PLAY_CTS_PLAYER_ABILITIES: u32 = 0x13; 318 | 319 | /// The ID of a tab complete packet 320 | pub const ID_PLAY_CTS_TAB_COMPLETE: u32 = 0x14; 321 | 322 | /// The ID of a client settings packet 323 | pub const ID_PLAY_CTS_CLIENT_SETTINGS: u32 = 0x15; 324 | 325 | /// The ID of a client status packet 326 | pub const ID_PLAY_CTS_CLIENT_STATUS: u32 = 0x16; 327 | 328 | /// The ID of a plugin message packet 329 | pub const ID_PLAY_CTS_PLUGIN_MESSAGE: u32 = 0x17; 330 | 331 | /// The ID of a spectate packet 332 | pub const ID_PLAY_CTS_SPECTATE: u32 = 0x18; 333 | 334 | /// The ID of a resource pack status packet 335 | pub const ID_PLAY_CTS_RESOURCE_PACK_STATUS: u32 = 0x19; 336 | 337 | /// The ID of a response packet 338 | pub const ID_STATUS_STC_RESPONSE: u32 = 0x00; 339 | 340 | /// The ID of a pong packet 341 | pub const ID_STATUS_STC_PONG: u32 = 0x01; 342 | 343 | /// The ID of a request packet 344 | pub const ID_STATUS_CTS_REQUEST: u32 = 0x00; 345 | 346 | /// The ID of a ping packet 347 | pub const ID_STATUS_CTS_PING: u32 = 0x01; 348 | 349 | /// The ID of a disconnect packet 350 | pub const ID_LOGIN_STC_DISCONNECT: u32 = 0x00; 351 | 352 | /// The ID of an encryption request packet 353 | pub const ID_LOGIN_STC_ENCRYPTION_REQUEST: u32 = 0x01; 354 | 355 | /// The ID of a login success packet 356 | pub const ID_LOGIN_STC_LOGIN_SUCCESS: u32 = 0x02; 357 | 358 | /// The ID of a set compression packet 359 | pub const ID_LOGIN_STC_SET_COMPRESSION: u32 = 0x03; 360 | 361 | /// The ID of a start login packet 362 | pub const ID_LOGIN_CTS_START_LOGIN: u32 = 0x00; 363 | 364 | /// The ID of an encryption response packet 365 | pub const ID_LOGIN_CTS_ENCRYPTION_RESPONSE: u32 = 0x01; 366 | -------------------------------------------------------------------------------- /src/io/network/packet/outgoing/mod.rs: -------------------------------------------------------------------------------- 1 | //! The module containing all outgoing packet implementations 2 | 3 | /*use super::super::deque_buffer::DequeBuffer; 4 | use super::super::game_connection::GameConnection; //It's super super super effective! 5 | 6 | use std::io::Write; 7 | 8 | //pub mod handshake; No handshake packets (yet)! 9 | pub mod status; 10 | 11 | /// A trait for outgoing packets 12 | pub trait OutgoingPacket { 13 | 14 | /// Gets this Packet's ID 15 | /// 16 | /// One day, this will be replaced with an associated constant 17 | fn get_id(&self) -> u32; 18 | 19 | /// Encodes this Packet's data 20 | fn encode_data(&self, buffer: &mut DequeBuffer); 21 | 22 | /// Encodes this OutgoingPacket 23 | fn encode(&self, buffer: &mut DequeBuffer) { 24 | 25 | buffer.write_unsigned_varint_32(self.get_id()); 26 | 27 | self.encode_data(buffer); 28 | 29 | } 30 | 31 | /// Sends this OutgoingPacket to the client 32 | fn send(&self, connection: &mut GameConnection) { 33 | 34 | let mut data_buffer = DequeBuffer::new(); 35 | 36 | self.encode(&mut data_buffer); 37 | 38 | let mut length_buffer = DequeBuffer::new(); 39 | 40 | length_buffer.write_unsigned_varint_32(data_buffer.remaining() as u32); //TODO: Try to get this as data_buffer.prepend_varint_32 - One day 41 | 42 | let buffer: Vec = length_buffer.data.into_iter().chain(data_buffer.data.into_iter()).collect(); 43 | 44 | let _buffer: &[u8] = &buffer[..]; 45 | 46 | if connection.stream.write(_buffer).is_ok() { 47 | let _ = connection.stream.flush(); 48 | } 49 | 50 | self.post_send(connection); 51 | 52 | } 53 | 54 | #[allow(unused_variables)] 55 | /// Called after the OutgoingPacket is sent 56 | fn post_send(&self, connection: &mut GameConnection) { 57 | // Do nothing, this may be expanded by default later 58 | } 59 | 60 | }*/ 61 | 62 | /* 63 | use super::super::super::deque_buffer::DequeBuffer; 64 | use super::super::super::game_connection::GameConnection; //It's super super super effective! 65 | use super::super::{ PacketHeader, ID_STC_ }; 66 | 67 | /// A packet sent from the server to 68 | pub struct Packet { 69 | 70 | // Your fields here 71 | 72 | } 73 | 74 | impl OutgoingPacket for Packet { 75 | 76 | 77 | /// Gets this Packet's ID 78 | /// 79 | /// One day, this will be replaced with an associated constant 80 | fn get_id(&self) -> u32 { 81 | ID_STC_ 82 | } 83 | 84 | /// Encodes this Packet's data 85 | fn encode_data(&self, buffer: &mut DequeBuffer) { 86 | 87 | } 88 | 89 | } 90 | 91 | impl Packet { 92 | 93 | /// Creates a new Packet 94 | pub fn new() -> Packet { 95 | 96 | Packet { /*etc*/ } 97 | 98 | } 99 | 100 | } 101 | */ 102 | -------------------------------------------------------------------------------- /src/io/network/packet/outgoing/status.rs: -------------------------------------------------------------------------------- 1 | //! Implements all outgoing status packets 2 | /* 3 | use super::super::super::deque_buffer::DequeBuffer; 4 | use super::super::super::game_connection::GameConnection; //It's super super super effective! 5 | use super::super::{ ID_STATUS_STC_RESPONSE, ID_STATUS_STC_PONG }; 6 | 7 | use super::OutgoingPacket; 8 | 9 | use rustc_serialize::json; 10 | 11 | mod response { 12 | 13 | use super::super::super::super::super::super::{get_version, MINECRAFT_PROTOCOL_VERSION}; 14 | use super::super::super::super::super::super::universe::{MAX_PLAYERS}; 15 | 16 | /// A response to be sent by the server list response packet 17 | #[derive(Debug, RustcDecodable, RustcEncodable)] 18 | pub struct Response { 19 | 20 | /// The player data contained in this response 21 | pub players: Players, 22 | 23 | /// The version data contained in this response 24 | pub version: Version, 25 | 26 | /// The description contained in this response 27 | pub description: Description, 28 | 29 | /// The optional / Forge-only mod information 30 | pub modinfo: Option 31 | 32 | } 33 | 34 | impl Response { 35 | 36 | /// Constructs a new Response 37 | pub fn construct() -> Response { 38 | 39 | return Response { players: Players::construct(), version: Version::construct(), description: Description::construct(), modinfo: Some(ModInfo::construct())}; 40 | 41 | } 42 | 43 | } 44 | 45 | /// A struct containing mod (forge) information 46 | #[derive(Debug, RustcDecodable, RustcEncodable)] 47 | #[allow(non_snake_case)] 48 | pub struct ModInfo { 49 | 50 | /// The type of mod loader compatibility being used 51 | pub _type: String, 52 | 53 | /// The list of mods currently in use on the server 54 | pub modList: Vec 55 | 56 | } 57 | 58 | impl ModInfo { 59 | 60 | /// Constructs a new ModInfo struct 61 | pub fn construct() -> ModInfo { 62 | 63 | ModInfo { _type: "FML".to_string(), modList: ModDescriptor::construct() } 64 | 65 | } 66 | 67 | } 68 | 69 | /// A struct containing mod information 70 | #[derive(Debug, RustcDecodable, RustcEncodable)] 71 | pub struct ModDescriptor { 72 | 73 | /// The mod's ID 74 | pub modid: String, 75 | 76 | /// The mod's version 77 | pub version: String 78 | 79 | } 80 | 81 | impl ModDescriptor { 82 | 83 | /// Constructs a new list of ModDescriptors 84 | pub fn construct() -> Vec { 85 | 86 | //TODO: One day, replace this with names of mods added 87 | vec!( 88 | ModDescriptor { modid: "ExampleMod".to_string(), version: "0.0.1-pre".to_string() } 89 | ) 90 | 91 | } 92 | 93 | } 94 | 95 | /// A struct defining the players portion of the StatusResponsePacket 96 | #[derive(Debug, RustcDecodable, RustcEncodable)] 97 | pub struct Players { 98 | 99 | /// The maximum number of players allowed on this server 100 | pub max: i32, //Yes, I know. But Java only supports signed integers 101 | 102 | /// The current number of online players 103 | pub online: i32 104 | 105 | } 106 | 107 | impl Players { 108 | 109 | /// Constructs a new Players struct 110 | /// 111 | /// TODO: Make this use real data for online 112 | pub fn construct() -> Players { 113 | 114 | Players { max: MAX_PLAYERS, online: 0 } 115 | 116 | } 117 | 118 | } 119 | 120 | /// The version part of the response packet 121 | #[derive(Debug, RustcDecodable, RustcEncodable)] 122 | pub struct Version { 123 | 124 | /// The name of the version (This may or may not be ignored) 125 | pub name: String, 126 | 127 | /// The Minecraft protocol number being used 128 | pub protocol: u32 129 | 130 | } 131 | 132 | impl Version { 133 | 134 | /// Constructs a new Version struct 135 | /// 136 | /// TODO: Make name use a defined value 137 | pub fn construct() -> Version { 138 | 139 | Version { name: "1.8.8".to_string(), protocol: MINECRAFT_PROTOCOL_VERSION } 140 | 141 | } 142 | 143 | } 144 | 145 | /// The description part of the response packet 146 | #[derive(Debug, RustcDecodable, RustcEncodable)] 147 | pub struct Description { 148 | 149 | /// The text to display 150 | pub text: String 151 | 152 | } 153 | 154 | impl Description { 155 | 156 | /// Constructs a new Description. 157 | /// 158 | /// In the future, this will get the description from a (cached) file 159 | pub fn construct() -> Description { 160 | Description { text: format!("A Netherrack {} server", get_version()) } 161 | } 162 | 163 | } 164 | 165 | } 166 | 167 | /// A packet sent from the server to 168 | pub struct StatusResponsePacket; 169 | 170 | impl StatusResponsePacket { 171 | 172 | /// Creates a new Packet 173 | pub fn new() -> StatusResponsePacket { 174 | 175 | StatusResponsePacket 176 | 177 | } 178 | 179 | } 180 | 181 | impl OutgoingPacket for StatusResponsePacket { 182 | 183 | /// Gets this StatusResponsePacket's ID 184 | /// 185 | /// One day, this will be replaced with an associated constant 186 | fn get_id(&self) -> u32 { 187 | ID_STATUS_STC_RESPONSE 188 | } 189 | 190 | /// Encodes this StatusResponsePacket's data 191 | fn encode_data(&self, buffer: &mut DequeBuffer) { 192 | buffer.write_utf8_string( 193 | json::encode(&response::Response::construct()).unwrap().replace("_type", "type") 194 | ); 195 | } 196 | 197 | } 198 | 199 | /// A packet sent from the server to the client responding to a ping 200 | pub struct ListPongPacket { 201 | 202 | pub payload: i64 203 | 204 | } 205 | 206 | impl ListPongPacket { 207 | 208 | /// Creates a new ListPongPacket 209 | pub fn new(payload: i64) -> ListPongPacket { 210 | 211 | ListPongPacket { payload: payload } 212 | 213 | } 214 | } 215 | 216 | impl OutgoingPacket for ListPongPacket { 217 | 218 | /// Gets this ListPongPacket's ID 219 | fn get_id(&self) -> u32 { 220 | 221 | ID_STATUS_STC_PONG 222 | 223 | } 224 | 225 | /// Encodes this Packet's data 226 | fn encode_data(&self, buffer: &mut DequeBuffer) { 227 | buffer.write_signed_long(self.payload); 228 | } 229 | 230 | /// Called after the OutgoingPacket is sent 231 | fn post_send(&self, connection: &mut GameConnection) { 232 | // All ListPongPackets are at the end of any packet stream, so we can disconnect the client here 233 | connection.disconnect(); 234 | } 235 | 236 | }*/ 237 | -------------------------------------------------------------------------------- /src/io/operations/mod.rs: -------------------------------------------------------------------------------- 1 | //! Netherrack-specific I/O operations for Rust 2 | 3 | pub mod reader; 4 | 5 | pub mod writer; 6 | 7 | #[cfg(test)] 8 | mod test { 9 | 10 | use super::reader::NetherrackReader; 11 | use super::writer::NetherrackWriter; 12 | 13 | use io_operations::writer::Writer; 14 | use io_operations::reader::Reader; 15 | 16 | 17 | use std::io::{ Read, Cursor }; 18 | 19 | #[test] 20 | fn test_read_write_cursor_changes() { 21 | 22 | let mut vector = Cursor::new(vec![0u8; 0]); 23 | 24 | assert!(vector.write_utf8_string("Hello, cruel world!".to_string()).is_ok()); 25 | 26 | assert!(vector.write_unsigned_byte(13).is_ok()); 27 | 28 | let bytes_written = vector.position() as u32; 29 | 30 | let mut new_vector = Cursor::new(vec![0u8; 0]); 31 | 32 | assert!(new_vector.write_unsigned_varint_32(bytes_written).is_ok()); 33 | 34 | vector.set_position(0); 35 | 36 | let _end = vector.read_to_end(new_vector.get_mut()); 37 | 38 | new_vector.set_position(0); 39 | 40 | assert_eq!(bytes_written, new_vector.read_unsigned_varint_32().unwrap()); 41 | 42 | assert_eq!("Hello, cruel world!", new_vector.read_utf8_string().unwrap()); 43 | 44 | assert_eq!(13, new_vector.read_unsigned_byte().unwrap()); 45 | 46 | } 47 | 48 | #[test] 49 | fn test_read_write_utf8_string() { 50 | 51 | let mut vector = Cursor::new(vec![0u8; 0]); 52 | 53 | assert!(vector.write_utf8_string("Hello, world!".to_string()).is_ok()); 54 | assert!(vector.write_utf8_string("".to_string()).is_ok()); 55 | assert!(vector.write_utf8_string("null".to_string()).is_ok()); 56 | assert!(vector.write_utf8_string("0".to_string()).is_ok()); 57 | assert!(vector.write_utf8_string("And that is why this really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, long string is the Prince of Bel-Air".to_string()).is_ok()); 58 | 59 | vector.set_position(0); 60 | 61 | assert_eq!("Hello, world!", vector.read_utf8_string().unwrap()); 62 | assert_eq!("", vector.read_utf8_string().unwrap()); 63 | assert_eq!("null", vector.read_utf8_string().unwrap()); 64 | assert_eq!("0", vector.read_utf8_string().unwrap()); 65 | assert_eq!("And that is why this really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, long string is the Prince of Bel-Air", vector.read_utf8_string().unwrap()); 66 | 67 | } 68 | 69 | #[test] 70 | fn test_read_write_unsigned_varint_32() { 71 | 72 | let mut vector = Cursor::new(vec![0u8; 0]); 73 | 74 | assert!(vector.write_unsigned_varint_32(15).is_ok()); 75 | assert!(vector.write_unsigned_varint_32(0).is_ok()); 76 | assert!(vector.write_unsigned_varint_32(2111111111).is_ok()); 77 | assert!(vector.write_unsigned_varint_32(3463465).is_ok()); 78 | 79 | vector.set_position(0); 80 | 81 | assert_eq!(15, vector.read_unsigned_varint_32().unwrap()); 82 | assert_eq!(0, vector.read_unsigned_varint_32().unwrap()); 83 | assert_eq!(2111111111, vector.read_unsigned_varint_32().unwrap()); 84 | assert_eq!(3463465, vector.read_unsigned_varint_32().unwrap()); 85 | 86 | 87 | } 88 | 89 | #[test] 90 | fn test_read_write_signed_varint_32() { 91 | 92 | let mut vector = Cursor::new(vec![0u8; 0]); 93 | 94 | assert!(vector.write_signed_varint_32(-4).is_ok()); 95 | assert!(vector.write_signed_varint_32(0).is_ok()); 96 | assert!(vector.write_signed_varint_32(2111111111).is_ok()); 97 | assert!(vector.write_signed_varint_32(-2111111111).is_ok()); 98 | assert!(vector.write_signed_varint_32(-3463465).is_ok()); 99 | 100 | vector.set_position(0); 101 | 102 | assert_eq!(-4, vector.read_signed_varint_32().unwrap()); 103 | assert_eq!(-0, vector.read_signed_varint_32().unwrap()); 104 | assert_eq!(2111111111, vector.read_signed_varint_32().unwrap()); 105 | assert_eq!(-2111111111, vector.read_signed_varint_32().unwrap()); 106 | assert_eq!(-3463465, vector.read_signed_varint_32().unwrap()); 107 | 108 | 109 | } 110 | 111 | #[test] 112 | fn test_read_write_lots_of_unsigned_varint_32() { 113 | 114 | let mut vector = Cursor::new(vec![0u8; 0]); 115 | 116 | let mut index = 0; 117 | 118 | while index < 123456 { 119 | index += 1; 120 | 121 | assert!(vector.write_unsigned_varint_32(index).is_ok()); 122 | } 123 | 124 | vector.set_position(0); 125 | index = 0; 126 | 127 | while index < 123456 { 128 | index += 1; 129 | 130 | assert_eq!(index, vector.read_unsigned_varint_32().unwrap()); 131 | } 132 | 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/io/operations/reader.rs: -------------------------------------------------------------------------------- 1 | //! Netherrack-specific reading I/O operations 2 | 3 | use io_operations::reader::Reader; 4 | 5 | extern crate varint; 6 | 7 | extern crate bit_utils; 8 | use self::bit_utils::BitInformation; 9 | 10 | pub trait NetherrackReader : Reader { 11 | 12 | /// Reads a UTF-8 string from the buffer 13 | #[allow(unused_variables)] //Only for error stuff 14 | fn read_utf8_string(&mut self) -> Result { 15 | 16 | match self.read_unsigned_varint_32() { 17 | 18 | Err(error) => { 19 | return Err("Bad size for utf-8 string"); 20 | } 21 | 22 | Ok(mut size) => { 23 | 24 | let mut bytes: Vec = Vec::::with_capacity(size as usize); 25 | 26 | while size > 0 { 27 | match self.read_unsigned_byte() { 28 | Err(error) => { 29 | return Err("Bad things while reading a UTF-8 string"); 30 | } 31 | 32 | Ok(value) => { 33 | bytes.push(value); 34 | size -= 1; 35 | } 36 | } 37 | } 38 | 39 | match String::from_utf8(bytes) { 40 | 41 | Err(errval) => { 42 | return Err("Error parsing UTF-8 String"); 43 | } 44 | 45 | Ok(string) => { 46 | return Ok(string); 47 | } 48 | 49 | } 50 | 51 | } 52 | 53 | } 54 | 55 | } 56 | 57 | /// Reads a signed 32-bit Varint from this NetherrackReader 58 | #[allow(unused_variables)] //For the error handling as we need to change the string 59 | fn read_signed_varint_32(&mut self) -> Result { 60 | match self.read_unsigned_varint_32() { 61 | Ok(value) => { 62 | return Ok(self::varint::zigzag_unsigned_int(value)); 63 | } 64 | 65 | Err(error) => { 66 | return Err("Could not read a signed varint32"); 67 | } 68 | } 69 | } 70 | 71 | /// Reads an unsigned 32-bit Varint from this NetherrackReader 72 | fn read_unsigned_varint_32(&mut self) -> Result { 73 | 74 | // The number of bits to shift by. <<0, <<7, <<14, etc 75 | let mut shift_amount: u32 = 0; 76 | 77 | // The decoded value 78 | let mut decoded_value: u32 = 0; 79 | 80 | loop { 81 | 82 | match self.read_unsigned_byte() { 83 | Err(error) => { 84 | error!("Got an error while reading a byte for an unsigned varint32: {}", error); 85 | return Err("Could not read an unsigned byte for an unsigned varint32"); 86 | } 87 | 88 | Ok(byte_value) => { 89 | decoded_value |= ((byte_value & 0b01111111) as u32) << shift_amount; 90 | 91 | // See if we're supposed to keep reading 92 | if byte_value.has_most_signifigant_bit() { 93 | shift_amount += 7; 94 | } else { 95 | return Ok(decoded_value); 96 | } 97 | } 98 | } 99 | 100 | } 101 | 102 | } 103 | 104 | } 105 | 106 | impl NetherrackReader for ::std::io::Cursor> { } 107 | impl NetherrackReader for ::std::net::TcpStream { } 108 | -------------------------------------------------------------------------------- /src/io/operations/writer.rs: -------------------------------------------------------------------------------- 1 | //! Netherrack-specific writing I/O operations 2 | 3 | use io_operations::writer::Writer; 4 | 5 | use std::io::Result; 6 | 7 | extern crate varint; 8 | 9 | pub trait NetherrackWriter : Writer { 10 | 11 | /// Writes a UTF-8 string to this NetherrackWriter 12 | fn write_utf8_string(&mut self, value: String) -> Result<()> { 13 | 14 | let bytes = value.as_bytes(); 15 | 16 | let _ = self.write_unsigned_varint_32(bytes.len() as u32); //FIXME: CHECK FOR FAILURE BEFORE 0.1.0 17 | 18 | for &byte in bytes { 19 | let _ = self.write_unsigned_byte(byte); 20 | } 21 | 22 | Ok(()) 23 | 24 | } 25 | 26 | /// Writes a signed varint 32 to this NetherrackWriter 27 | fn write_signed_varint_32(&mut self, value: i32) -> Result<()> { 28 | self.write_unsigned_varint_32(self::varint::zigzag_signed_int(value)) 29 | } 30 | 31 | /// Writes an unsigned 32-bit Varint to this NetherrackWriter 32 | /// 33 | /// TODO: Currently, this returns the Result of the last byte written. We need to roll our own 34 | /// eventually 35 | fn write_unsigned_varint_32(&mut self, value: u32) -> Result<()> { 36 | 37 | let mut _value: u32 = value; 38 | 39 | if value == 0 { 40 | return self.write_unsigned_byte(0) 41 | } else { 42 | 43 | while _value >= 0b10000000 { 44 | 45 | let next_byte: u8 = ((_value & 0b01111111) as u8) | 0b10000000; 46 | 47 | _value = _value >> 7; 48 | 49 | let _ = self.write_unsigned_byte(next_byte); 50 | 51 | } 52 | 53 | return self.write_unsigned_byte((_value & 0b01111111) as u8); 54 | 55 | } 56 | 57 | } 58 | 59 | } 60 | 61 | impl NetherrackWriter for ::std::io::Cursor> { } 62 | impl NetherrackWriter for ::std::net::TcpStream { } 63 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Entry module for the Netherrack project 2 | 3 | // We'll be using serialization a lot 4 | extern crate rustc_serialize; 5 | 6 | // Enable logging and use of logging macros throughout Netherrack 7 | #[macro_use] 8 | extern crate log; 9 | 10 | // Enable global use of lazy_static 11 | #[macro_use] 12 | extern crate lazy_static; 13 | 14 | // Allow use of Semantic Versioning througout Netherrack 15 | extern crate semver; 16 | // Also allow usage of Version through Netherrack 17 | pub use semver::Version; 18 | 19 | // Allow use of the core module 20 | pub mod core; 21 | 22 | // Import I/O operations before Netherrack-specific ones 23 | extern crate io_operations; 24 | // Allow access to I/O operations 25 | pub mod io; 26 | 27 | // Allow access to the universe 28 | pub mod universe; 29 | 30 | 31 | pub use std::sync::mpsc::{ Sender, Receiver, channel }; 32 | 33 | // Okay, this is the start of Netherrack's functions 34 | 35 | /// The version of the Minecraft protocol accepted by Netherrack 36 | pub const MINECRAFT_PROTOCOL_VERSION: u32 = 47; 37 | 38 | /// The version of Netherrack as determined at compile time 39 | pub const NETHERRACK_VERSION_STRING: &'static str = env!("CARGO_PKG_VERSION"); 40 | 41 | /// Gets the current version of Netherrack 42 | pub fn get_version() -> Version { 43 | Version::parse(NETHERRACK_VERSION_STRING).unwrap() 44 | } 45 | 46 | /// Starts a new Netherrack server instance 47 | pub fn start_server() { 48 | 49 | info!("Netherrack startup called"); 50 | 51 | trace!("Starting network in a new thread"); 52 | 53 | std::thread::spawn(move || { 54 | io::network::start_network(); 55 | }); 56 | 57 | debug!("Networking should be set up"); 58 | 59 | loop { 60 | //TODO: In the future, execute a tick. Use Duration's span function to get time taken, sleep the remainder, and go again 61 | std::thread::sleep(std::time::Duration::from_millis(20)); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | //! Placeholder that enables running Netherrack as a standalone executable. 2 | //! 3 | //! Actual logic is in the library itself so that, for example, an embedded server can be created. 4 | //! 5 | //! All you would need to do is set the logger! 6 | 7 | extern crate netherrack; 8 | 9 | pub use netherrack::*; 10 | 11 | #[macro_use] 12 | extern crate log; 13 | 14 | /// Starts a standalone version of Netherrack 15 | /// 16 | /// It actually just sets the loggers, and then starts an embedded server :) 17 | fn main() { 18 | 19 | if set_global_logger() { 20 | info!("Set up logging"); 21 | } else { 22 | error!("Could not set up logging"); 23 | } 24 | 25 | info!("Attempting to load Netherrack {}", get_version()); 26 | 27 | start_server(); 28 | 29 | } 30 | 31 | fn set_global_logger() -> bool { 32 | 33 | let log_setup_result: Result<(), log::SetLoggerError> = log::set_logger(|max_log_level| { 34 | max_log_level.set(log::LogLevelFilter::Trace); 35 | Box::new(core::logger::NetherrackLogger) 36 | }); 37 | 38 | if log_setup_result.is_ok() { 39 | return true; 40 | } else { 41 | return false; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /src/universe/mod.rs: -------------------------------------------------------------------------------- 1 | //! The universe, where everything to do with server-wide functions resides 2 | 3 | pub mod world; 4 | 5 | /// The maximum number of worlds to be hosted per universe 6 | /// 7 | /// This is to be tested and will be increased, decreased, or set to a user-defined value prior to release 8 | pub const MAX_WORLDS: u8 = 16; 9 | 10 | /// The maximum number of players accepted by this universe 11 | /// 12 | /// This is to be tested and will be set to a user-defined value (or perhaps automatically depending on hardware) prior to release 13 | pub const MAX_PLAYERS: i32 = 200; -------------------------------------------------------------------------------- /src/universe/world/mod.rs: -------------------------------------------------------------------------------- 1 | //! A world, where everything ingame happens. 2 | 3 | /// A structure defining a world 4 | /// 5 | /// Will be changed shortly 6 | pub struct World { 7 | 8 | /// The name of this world 9 | pub name: &'static str, 10 | 11 | /// The base seed used by this world to set the seed for chunk generators 12 | pub seed: u64, 13 | 14 | /// The border for this world 15 | /// 16 | /// If set to 0, no world border is available 17 | pub border: u64/*, 18 | 19 | pub chunkcolumns: Vec, 20 | 21 | pub difficulty: Difficulty*/ 22 | 23 | } 24 | 25 | impl World { 26 | 27 | /// Checks to see if this world has a border 28 | pub fn has_border(&self) -> bool { 29 | self.border != 0 30 | } 31 | 32 | } 33 | 34 | #[cfg(test)] 35 | mod test { 36 | 37 | use super::*; 38 | 39 | #[test] 40 | pub fn new_world_has_no_border() { 41 | assert!((World { name: "Hello", seed: 21337420u64, border: 0 }).has_border() == false); 42 | } 43 | 44 | #[test] 45 | pub fn new_world_has_border() { 46 | assert!((World { name: "Hello", seed: 21337420u64, border: 100000 }).has_border() == true); 47 | } 48 | 49 | } --------------------------------------------------------------------------------