mirror of
https://github.com/G2-Games/minecraft_alpha_server.git
synced 2025-04-19 23:32:57 -05:00
Compare commits
No commits in common. "a9677205ddfaf538af2e02857d5bc78993dd38da" and "81dc4ec3d9208af06b25c9649e43cd714dfc376e" have entirely different histories.
a9677205dd
...
81dc4ec3d9
13 changed files with 246 additions and 385 deletions
|
@ -1,4 +1,4 @@
|
|||
# Alpha Server
|
||||
A server written in rust or something idk
|
||||
|
||||
Targeting Minecraft Beta `1.1_02`, protocol version `8`.
|
||||
Targeting Minecraft Alpha `1.2.6`, server version `0.2.8`.
|
||||
|
|
|
@ -1,54 +1,6 @@
|
|||
use num_derive::FromPrimitive;
|
||||
use num_traits::FromPrimitive;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// A trait to unify [`Block`]s and [`Item`]s.
|
||||
pub trait BlockItemID: Debug + Clone + PartialEq {
|
||||
/// The ID of the Block/Item
|
||||
fn id(&self) -> i16;
|
||||
|
||||
/// The Block/Item corresponding to an ID
|
||||
fn from_id(id: i16) -> Self;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum BlockItem {
|
||||
Unknown,
|
||||
Block(Block),
|
||||
Item(Item),
|
||||
}
|
||||
|
||||
impl BlockItemID for BlockItem {
|
||||
fn id(&self) -> i16 {
|
||||
match self {
|
||||
Self::Unknown => -1,
|
||||
BlockItem::Block(b) => *b as i16,
|
||||
BlockItem::Item(i) => *i as i16 + 255,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_id(id: i16) -> Self {
|
||||
if id <= 255 {
|
||||
if let Some(b) = Block::from_i16(id) {
|
||||
Self::Block(b)
|
||||
} else {
|
||||
Self::Unknown
|
||||
}
|
||||
} else {
|
||||
if let Some(b) = Item::from_i16(id - 255) {
|
||||
Self::Item(b)
|
||||
} else {
|
||||
Self::Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(i16)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(FromPrimitive)]
|
||||
pub enum Block {
|
||||
Air = 0,
|
||||
Unknown = -1,
|
||||
Stone = 1,
|
||||
Grass = 2,
|
||||
Dirt = 3,
|
||||
|
@ -127,126 +79,110 @@ pub enum Block {
|
|||
PumpkinLantern = 91,
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[repr(i16)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(FromPrimitive)]
|
||||
pub enum Item {
|
||||
ShovelSteel = 0,
|
||||
PickaxeSteel = 1,
|
||||
AxeSteel = 2,
|
||||
FlintAndSteel = 3,
|
||||
AppleRed = 4,
|
||||
Bow = 5,
|
||||
Arrow = 6,
|
||||
Coal = 7,
|
||||
Diamond = 8,
|
||||
IngotIron = 9,
|
||||
IngotGold = 10,
|
||||
SwordSteel = 11,
|
||||
SwordWood = 12,
|
||||
ShovelWood = 13,
|
||||
PickaxeWood = 14,
|
||||
AxeWood = 15,
|
||||
SwordStone = 16,
|
||||
ShovelStone = 17,
|
||||
PickaxeStone = 18,
|
||||
AxeStone = 19,
|
||||
SwordDiamond = 20,
|
||||
ShovelDiamond = 21,
|
||||
PickaxeDiamond = 22,
|
||||
AxeDiamond = 23,
|
||||
Stick = 24,
|
||||
BowlEmpty = 25,
|
||||
BowlSoup = 26,
|
||||
SwordGold = 27,
|
||||
ShovelGold = 28,
|
||||
PickaxeGold = 29,
|
||||
AxeGold = 30,
|
||||
Silk = 31,
|
||||
Feather = 32,
|
||||
Gunpowder = 33,
|
||||
HoeWood = 34,
|
||||
HoeStone = 35,
|
||||
HoeSteel = 36,
|
||||
HoeDiamond = 37,
|
||||
HoeGold = 38,
|
||||
Seeds = 39,
|
||||
Wheat = 40,
|
||||
Bread = 41,
|
||||
HelmetLeather = 42,
|
||||
PlateLeather = 43,
|
||||
LegsLeather = 44,
|
||||
BootsLeather = 45,
|
||||
HelmetChain = 46,
|
||||
PlateChain = 47,
|
||||
LegsChain = 48,
|
||||
BootsChain = 49,
|
||||
HelmetSteel = 50,
|
||||
PlateSteel = 51,
|
||||
LegsSteel = 52,
|
||||
BootsSteel = 53,
|
||||
HelmetDiamond = 54,
|
||||
PlateDiamond = 55,
|
||||
LegsDiamond = 56,
|
||||
BootsDiamond = 57,
|
||||
HelmetGold = 58,
|
||||
PlateGold = 59,
|
||||
LegsGold = 60,
|
||||
BootsGold = 61,
|
||||
Flint = 62,
|
||||
PorkRaw = 63,
|
||||
PorkCooked = 64,
|
||||
Painting = 65,
|
||||
AppleGold = 66,
|
||||
Sign = 67,
|
||||
DoorWood = 68,
|
||||
BucketEmpty = 69,
|
||||
BucketWater = 70,
|
||||
BucketLava = 71,
|
||||
MinecartEmpty = 72,
|
||||
Saddle = 73,
|
||||
DoorSteel = 74,
|
||||
Redstone = 75,
|
||||
Snowball = 76,
|
||||
Boat = 77,
|
||||
Leather = 78,
|
||||
BucketMilk = 79,
|
||||
Brick = 80,
|
||||
Clay = 81,
|
||||
Reed = 82,
|
||||
Paper = 83,
|
||||
Book = 84,
|
||||
SlimeBall = 85,
|
||||
MinecartCrate = 86,
|
||||
MinecartPowered = 87,
|
||||
Egg = 88,
|
||||
Compass = 89,
|
||||
FishingRod = 90,
|
||||
PocketSundial = 91,
|
||||
LightStoneDust = 92,
|
||||
FishRaw = 93,
|
||||
FishCooked = 94,
|
||||
Unknown = -1,
|
||||
ShovelSteel = 256,
|
||||
PickaxeSteel = 257,
|
||||
AxeSteel = 258,
|
||||
FlintAndSteel = 259,
|
||||
AppleRed = 260,
|
||||
Bow = 261,
|
||||
Arrow = 262,
|
||||
Coal = 263,
|
||||
Diamond = 264,
|
||||
IngotIron = 265,
|
||||
IngotGold = 266,
|
||||
SwordSteel = 267,
|
||||
SwordWood = 268,
|
||||
ShovelWood = 269,
|
||||
PickaxeWood = 270,
|
||||
AxeWood = 271,
|
||||
SwordStone = 272,
|
||||
ShovelStone = 273,
|
||||
PickaxeStone = 274,
|
||||
AxeStone = 275,
|
||||
SwordDiamond = 276,
|
||||
ShovelDiamond = 277,
|
||||
PickaxeDiamond = 278,
|
||||
AxeDiamond = 279,
|
||||
Stick = 280,
|
||||
BowlEmpty = 281,
|
||||
BowlSoup = 282,
|
||||
SwordGold = 283,
|
||||
ShovelGold = 284,
|
||||
PickaxeGold = 285,
|
||||
AxeGold = 286,
|
||||
Silk = 287,
|
||||
Feather = 288,
|
||||
Gunpowder = 289,
|
||||
HoeWood = 290,
|
||||
HoeStone = 291,
|
||||
HoeSteel = 292,
|
||||
HoeDiamond = 293,
|
||||
HoeGold = 294,
|
||||
Seeds = 295,
|
||||
Wheat = 296,
|
||||
Bread = 297,
|
||||
HelmetLeather = 298,
|
||||
PlateLeather = 299,
|
||||
LegsLeather = 300,
|
||||
BootsLeather = 301,
|
||||
HelmetChain = 302,
|
||||
PlateChain = 303,
|
||||
LegsChain = 304,
|
||||
BootsChain = 305,
|
||||
HelmetSteel = 306,
|
||||
PlateSteel = 307,
|
||||
LegsSteel = 308,
|
||||
BootsSteel = 309,
|
||||
HelmetDiamond = 310,
|
||||
PlateDiamond = 311,
|
||||
LegsDiamond = 312,
|
||||
BootsDiamond = 313,
|
||||
HelmetGold = 314,
|
||||
PlateGold = 315,
|
||||
LegsGold = 316,
|
||||
BootsGold = 317,
|
||||
Flint = 318,
|
||||
PorkRaw = 319,
|
||||
PorkCooked = 320,
|
||||
Painting = 321,
|
||||
AppleGold = 322,
|
||||
Sign = 323,
|
||||
DoorWood = 324,
|
||||
BucketEmpty = 325,
|
||||
BucketWater = 326,
|
||||
BucketLava = 327,
|
||||
MinecartEmpty = 328,
|
||||
Saddle = 329,
|
||||
DoorSteel = 330,
|
||||
Redstone = 331,
|
||||
Snowball = 332,
|
||||
Boat = 333,
|
||||
Leather = 334,
|
||||
BucketMilk = 335,
|
||||
Brick = 336,
|
||||
Clay = 337,
|
||||
Reed = 338,
|
||||
Paper = 339,
|
||||
Book = 340,
|
||||
SlimeBall = 341,
|
||||
MinecartCrate = 342,
|
||||
MinecartPowered = 343,
|
||||
Egg = 344,
|
||||
Compass = 345,
|
||||
FishingRod = 346,
|
||||
PocketSundial = 347,
|
||||
LightStoneDust = 348,
|
||||
FishRaw = 349,
|
||||
FishCooked = 350,
|
||||
Record13 = 2000,
|
||||
RecordCat = 2001,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ItemStack {
|
||||
pub stack_size: i32,
|
||||
pub animations_to_go: i32,
|
||||
pub item_id: BlockItem,
|
||||
pub item_damage: i32,
|
||||
}
|
||||
|
||||
impl ItemStack {
|
||||
pub fn new(item_id: i32, stack_size: i32, item_damage: i32) -> Self {
|
||||
Self {
|
||||
stack_size,
|
||||
item_id: BlockItem::from_id(item_id as i16),
|
||||
item_damage,
|
||||
animations_to_go: -1,
|
||||
}
|
||||
impl Item {
|
||||
fn index() -> i16 {
|
||||
256
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{io::Read, ops};
|
||||
use std::ops;
|
||||
|
||||
pub trait ToBytes: Sized {
|
||||
/// A byte array which can store a packed representation of this type.
|
||||
|
@ -7,12 +7,6 @@ pub trait ToBytes: Sized {
|
|||
fn to_bytes(self) -> Self::Bytes;
|
||||
}
|
||||
|
||||
pub trait FromBytes: Sized {
|
||||
type Bytes: ByteArray;
|
||||
|
||||
fn from_bytes<R: Read>(stream: &mut R) -> Self;
|
||||
}
|
||||
|
||||
mod private {
|
||||
pub trait ByteArray {}
|
||||
|
||||
|
|
28
src/chunk.rs
28
src/chunk.rs
|
@ -1,8 +1,9 @@
|
|||
use byteorder::{WriteBytesExt, BE};
|
||||
use flate2::{Compression, write::ZlibEncoder};
|
||||
use flate2::write::ZlibEncoder;
|
||||
use flate2::Compression;
|
||||
use num_derive::FromPrimitive;
|
||||
use std::io::prelude::*;
|
||||
|
||||
use crate::blocks_items::Block;
|
||||
use crate::byte_ops::ToBytes;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -70,13 +71,13 @@ impl BlockArray {
|
|||
for z in 0..CHUNK_WIDTH_Z {
|
||||
let pos = y + (z * (CHUNK_HEIGHT_Y)) + (x * (CHUNK_HEIGHT_Y) * (CHUNK_WIDTH_X));
|
||||
if y == 7 {
|
||||
blocks[pos] = Block::Grass as u8;
|
||||
blocks[pos] = BlockType::Grass as u8;
|
||||
} else if y > 0 && y < 7 {
|
||||
blocks[pos] = Block::Dirt as u8;
|
||||
blocks[pos] = BlockType::Dirt as u8;
|
||||
} else if y == 0 {
|
||||
blocks[pos] = Block::Bedrock as u8;
|
||||
blocks[pos] = BlockType::Bedrock as u8;
|
||||
} else {
|
||||
blocks[pos] = Block::Air as u8;
|
||||
blocks[pos] = BlockType::Air as u8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,6 +92,21 @@ impl BlockArray {
|
|||
}
|
||||
}
|
||||
|
||||
#[repr(i16)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(FromPrimitive)]
|
||||
pub enum BlockType {
|
||||
None = -1,
|
||||
Air,
|
||||
Stone,
|
||||
Grass,
|
||||
Dirt,
|
||||
Cobblestone,
|
||||
Planks,
|
||||
Sapling,
|
||||
Bedrock,
|
||||
}
|
||||
|
||||
impl ToBytes for MapChunk {
|
||||
type Bytes = Vec<u8>;
|
||||
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
use std::sync::atomic::{self, AtomicI32};
|
||||
|
||||
/// The current Entity ID. Incremented by one every time there is a new entity.
|
||||
///
|
||||
/// This value should rarely be accessed directly, and definitely never updated.
|
||||
pub static ENTITY_ID: EntityID = EntityID::new(0);
|
||||
|
||||
pub struct EntityID {
|
||||
id: AtomicI32
|
||||
}
|
||||
|
||||
impl EntityID {
|
||||
/// Create a new entity ID
|
||||
const fn new(id: i32) -> Self {
|
||||
Self {
|
||||
id: AtomicI32::new(id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a new Entity ID and increment the global value by 1.
|
||||
#[inline]
|
||||
pub fn get(&self) -> i32 {
|
||||
let eid = self.id.load(atomic::Ordering::Relaxed);
|
||||
self.id.store(eid + 1, atomic::Ordering::Relaxed);
|
||||
|
||||
eid
|
||||
}
|
||||
}
|
120
src/main.rs
120
src/main.rs
|
@ -1,45 +1,49 @@
|
|||
mod mcstring;
|
||||
mod utils;
|
||||
mod byte_ops;
|
||||
mod chunk;
|
||||
mod position;
|
||||
mod state;
|
||||
mod player;
|
||||
mod blocks_items;
|
||||
mod entity_id;
|
||||
mod packets;
|
||||
|
||||
use std::{io::{self, Write}, net::{TcpListener, TcpStream}, process::exit, sync::{Arc, RwLock}, thread};
|
||||
use std::{io::{self, Write}, net::{TcpListener, TcpStream}, sync::{atomic::{self, AtomicI32}, Arc, RwLock}, thread};
|
||||
|
||||
use base16ct::lower::encode_string;
|
||||
use chunk::{BlockArray, MapChunk, PreChunk};
|
||||
use entity_id::ENTITY_ID;
|
||||
use log::{debug, error, info};
|
||||
use log::{error, info, warn};
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt, BE};
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::FromPrimitive;
|
||||
use byte_ops::ToBytes;
|
||||
use packets::{packet15_place::Packet15Place, packet1_login, Packet};
|
||||
use player::DiggingStatus;
|
||||
use player::{DiggingStatus, PlayerBlockPlacement};
|
||||
use position::{PlayerLook, PlayerPosition, PlayerPositionLook};
|
||||
use state::{GameState, PlayerState};
|
||||
use mcstring::{MCString, ReadMCString, WriteMCString};
|
||||
use utils::{MCString, ReadMCString, WriteMCString};
|
||||
use rand::random;
|
||||
|
||||
/// The current Entity ID. Incremented by one every time there is a new entity.
|
||||
///
|
||||
/// This value should rarely be accessed directly, and definitely never updated.
|
||||
static ENTITY_ID: AtomicI32 = AtomicI32::new(0);
|
||||
|
||||
/// Get an Entity ID and increment the global value by 1.
|
||||
#[inline]
|
||||
fn get_eid() -> i32 {
|
||||
let eid = ENTITY_ID.load(atomic::Ordering::Relaxed);
|
||||
ENTITY_ID.store(eid + 1, atomic::Ordering::Relaxed);
|
||||
|
||||
eid
|
||||
}
|
||||
|
||||
fn main() {
|
||||
colog::default_builder()
|
||||
.filter_level(log::LevelFilter::Debug)
|
||||
.init();
|
||||
|
||||
info!("Starting Minecraft server version Beta 1.1_02");
|
||||
info!("Setting up game state");
|
||||
let game_state: Arc<RwLock<GameState>> = Arc::new(RwLock::new(GameState::new()));
|
||||
|
||||
let listener = match TcpListener::bind("0.0.0.0:25565") {
|
||||
Ok(l) => l,
|
||||
Err(e) => {
|
||||
error!("Starting server failed: {e}");
|
||||
exit(1)
|
||||
},
|
||||
};
|
||||
let listener = TcpListener::bind("0.0.0.0:25565").unwrap();
|
||||
info!("Server started and listening on {}", listener.local_addr().unwrap());
|
||||
|
||||
for mut connection in listener.incoming().filter_map(|c| c.ok()) {
|
||||
|
@ -78,17 +82,17 @@ fn player_loop(
|
|||
break;
|
||||
}
|
||||
|
||||
if player_state.is_valid()
|
||||
&& (game_state.read().unwrap().player_list().get(player_state.username()).is_some_and(|p| *p != player_state)
|
||||
|| game_state.read().unwrap().player_list().get(player_state.username()).is_none())
|
||||
{
|
||||
game_state.write()
|
||||
.unwrap()
|
||||
.player_list_mut()
|
||||
.insert(player_state.username().clone(), player_state.clone());
|
||||
if player_state.is_valid() {
|
||||
if game_state.read().unwrap().player_list().get(player_state.username()).is_some_and(|p| *p != player_state)
|
||||
|| game_state.read().unwrap().player_list().get(player_state.username()).is_none()
|
||||
{
|
||||
game_state.write()
|
||||
.unwrap()
|
||||
.player_list_mut()
|
||||
.insert(player_state.username().clone(), player_state.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -111,19 +115,22 @@ fn handle_command(
|
|||
info!("Handshake with {username} successful");
|
||||
},
|
||||
Command::Login => {
|
||||
let login_info = packet1_login::Packet1Login::read_from(&mut connection)?;
|
||||
let protocol_version = connection.read_u32::<BE>()?;
|
||||
let username = connection.read_mcstring()?;
|
||||
// These are mostly useless
|
||||
let _password = connection.read_mcstring()?;
|
||||
let _map_seed = connection.read_i64::<BE>()?;
|
||||
let _dimension = connection.read_i8()?;
|
||||
|
||||
// Return a successful login packet to the client
|
||||
let eid = ENTITY_ID.get();
|
||||
let login_packet = packet1_login::Packet1Login::new(eid, 0, 0);
|
||||
connection.write_u8(Command::Login as u8)?;
|
||||
login_packet.write_into(&mut connection)?;
|
||||
let eid = get_eid();
|
||||
let login_packet = ServerLoginPacket::new(eid, 0, 0);
|
||||
connection.write_u8(Command::Login as u8).unwrap();
|
||||
connection.write_all(&login_packet.to_bytes())?;
|
||||
|
||||
info!("{} [{}] logged in with entity id {}", login_info.username, connection.peer_addr().unwrap(), eid);
|
||||
info!("{username} logged in. Protocol version {protocol_version}");
|
||||
*player_state = PlayerState::new(username.to_string(), eid);
|
||||
|
||||
*player_state = PlayerState::new(login_info.username.to_string(), eid);
|
||||
|
||||
// Send "chunks" to the player. This simulates a flat-world of 20 by 20 chunks.
|
||||
for i in -10..10 {
|
||||
for o in -10..10 {
|
||||
let x = i * 16;
|
||||
|
@ -179,7 +186,7 @@ fn handle_command(
|
|||
}
|
||||
Command::HoldingChange => {
|
||||
let _unused = connection.read_i32::<BE>()?;
|
||||
let _block_id = connection.read_i16::<BE>()?;
|
||||
let block_id = connection.read_i16::<BE>()?;
|
||||
}
|
||||
Command::PlayerDigging => {
|
||||
let _status = DiggingStatus::from_u8(connection.read_u8()?).unwrap();
|
||||
|
@ -189,8 +196,7 @@ fn handle_command(
|
|||
let _face = connection.read_u8()?;
|
||||
}
|
||||
Command::PlayerBlockPlacement => {
|
||||
let status = Packet15Place::read_from(&mut connection)?;
|
||||
dbg!(status);
|
||||
let _status = PlayerBlockPlacement::from_bytes(&mut connection);
|
||||
}
|
||||
Command::Animation => {
|
||||
let _eid = connection.read_i32::<BE>()?;
|
||||
|
@ -203,7 +209,6 @@ fn handle_command(
|
|||
}
|
||||
Command::KeepAlive => {
|
||||
connection.write_u8(Command::KeepAlive as u8)?;
|
||||
info!("Keepalive!");
|
||||
}
|
||||
Command::UpdateHealth => {
|
||||
connection.read_u8()?;
|
||||
|
@ -211,8 +216,6 @@ fn handle_command(
|
|||
c => unimplemented!("This command ({c:?}) is probably `Server -> Client` only; thus it is unimplemented for the other way around!")
|
||||
}
|
||||
|
||||
connection.write_u8(Command::KeepAlive as u8)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -257,3 +260,38 @@ enum Command {
|
|||
ComplexEntities = 0x3B,
|
||||
Disconnect = 0xFF,
|
||||
}
|
||||
|
||||
struct ServerLoginPacket {
|
||||
entity_id: i32,
|
||||
unknown1: MCString,
|
||||
unknown2: MCString,
|
||||
map_seed: i64,
|
||||
dimension: i8,
|
||||
}
|
||||
|
||||
impl ServerLoginPacket {
|
||||
pub fn new(entity_id: i32, map_seed: i64, dimension: i8) -> Self {
|
||||
Self {
|
||||
entity_id,
|
||||
unknown1: MCString::default(),
|
||||
unknown2: MCString::default(),
|
||||
map_seed,
|
||||
dimension,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToBytes for ServerLoginPacket {
|
||||
type Bytes = Vec<u8>;
|
||||
|
||||
fn to_bytes(self) -> Self::Bytes {
|
||||
let mut out_buf = Vec::new();
|
||||
out_buf.write_i32::<BE>(self.entity_id).unwrap();
|
||||
out_buf.write_mcstring(&self.unknown1).unwrap();
|
||||
out_buf.write_mcstring(&self.unknown2).unwrap();
|
||||
out_buf.write_i64::<BE>(self.map_seed).unwrap();
|
||||
out_buf.write_i8(self.dimension).unwrap();
|
||||
|
||||
out_buf
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
use std::io::{self, Read, Write};
|
||||
|
||||
pub mod packet1_login;
|
||||
pub mod packet15_place;
|
||||
pub mod packet101;
|
||||
|
||||
/// A packet for communicating across the network.
|
||||
pub trait Packet
|
||||
where Self: Sized
|
||||
{
|
||||
/// Read the packet in from a stream
|
||||
fn read_from<R: Read>(input: &mut R) -> Result<Self, io::Error>;
|
||||
|
||||
/// Write the packet out to a stream
|
||||
fn write_into<W: Write>(&self, output: &mut W) -> Result<(), io::Error>;
|
||||
|
||||
/// The size of the packet in bytes
|
||||
fn size(&self) -> usize;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
use byteorder::{ReadBytesExt, WriteBytesExt, BE};
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use super::Packet;
|
||||
|
||||
pub struct Packet101 {
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
use crate::{blocks_items::{BlockItem, BlockItemID, ItemStack}, player::Direction};
|
||||
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt, BE};
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use super::Packet;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Packet15Place {
|
||||
id: BlockItem,
|
||||
x_position: i32,
|
||||
y_position: u8,
|
||||
z_position: i32,
|
||||
direction: u8,
|
||||
amount: Option<u8>,
|
||||
health: Option<i16>,
|
||||
}
|
||||
|
||||
impl Packet for Packet15Place {
|
||||
fn read_from<R: std::io::Read>(input: &mut R) -> Result<Self, std::io::Error> {
|
||||
let id = BlockItem::from_id(input.read_i16::<BE>()?);
|
||||
Ok(Self {
|
||||
id,
|
||||
x_position: input.read_i32::<BE>()?,
|
||||
y_position: input.read_u8()?,
|
||||
z_position: input.read_i32::<BE>()?,
|
||||
direction: input.read_u8()?,
|
||||
amount: if id.id() <= 0 { None } else { Some(input.read_u8()?) },
|
||||
health: if id.id() <= 0 { None } else { Some(input.read_i16::<BE>()?) }
|
||||
})
|
||||
}
|
||||
|
||||
fn write_into<W: std::io::Write>(&self, output: &mut W) -> Result<(), std::io::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
use byteorder::{ReadBytesExt, WriteBytesExt, BE};
|
||||
|
||||
use crate::mcstring::{MCString, WriteMCString, ReadMCString};
|
||||
|
||||
use super::Packet;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Packet1Login {
|
||||
pub username: MCString,
|
||||
pub password: MCString,
|
||||
pub protocol_version: i32,
|
||||
pub world_seed: i64,
|
||||
pub dimension: i8,
|
||||
}
|
||||
|
||||
impl Packet1Login {
|
||||
pub fn new(protocol_version: i32, world_seed: i64, dimension: i8) -> Self {
|
||||
Self {
|
||||
username: MCString::default(),
|
||||
password: MCString::default(),
|
||||
protocol_version,
|
||||
world_seed,
|
||||
dimension,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Packet for Packet1Login {
|
||||
fn read_from<R: std::io::Read>(input: &mut R) -> Result<Self, std::io::Error> {
|
||||
let protocol_version = input.read_i32::<BE>()?;
|
||||
let username = input.read_mcstring()?.into();
|
||||
let password = input.read_mcstring()?.into();
|
||||
let world_seed = input.read_i64::<BE>()?;
|
||||
let dimension = input.read_i8()?;
|
||||
|
||||
Ok(Packet1Login {
|
||||
username,
|
||||
password,
|
||||
protocol_version,
|
||||
world_seed,
|
||||
dimension,
|
||||
})
|
||||
}
|
||||
|
||||
fn write_into<W: std::io::Write>(&self, output: &mut W) -> Result<(), std::io::Error> {
|
||||
output.write_i32::<BE>(self.protocol_version).unwrap();
|
||||
output.write_mcstring(&self.username).unwrap();
|
||||
output.write_mcstring(&self.password).unwrap();
|
||||
output.write_i64::<BE>(self.world_seed).unwrap();
|
||||
output.write_i8(self.dimension).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
4 + self.username.len() + self.password.len() + 8 + 1
|
||||
}
|
||||
}
|
|
@ -1,4 +1,10 @@
|
|||
use std::io::Read;
|
||||
|
||||
use byteorder::{ReadBytesExt, BE};
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use crate::chunk::BlockType;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
@ -31,3 +37,32 @@ pub struct PlayerDigging {
|
|||
position_z: i32,
|
||||
face: Direction,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PlayerBlockPlacement {
|
||||
block_id: BlockType,
|
||||
position_x: i32,
|
||||
position_y: u8,
|
||||
position_z: i32,
|
||||
direction: Direction,
|
||||
//amount: u8,
|
||||
//health: u8,
|
||||
}
|
||||
|
||||
impl PlayerBlockPlacement {
|
||||
pub fn from_bytes<R: Read>(stream: &mut R) -> Self {
|
||||
let block_id = BlockType::from_i16(stream.read_i16::<BE>().unwrap()).unwrap();
|
||||
let position_x = stream.read_i32::<BE>().unwrap();
|
||||
let position_y = stream.read_u8().unwrap();
|
||||
let position_z = stream.read_i32::<BE>().unwrap();
|
||||
let direction = Direction::from_u8(stream.read_u8().unwrap()).unwrap();
|
||||
|
||||
Self {
|
||||
block_id,
|
||||
position_x,
|
||||
position_y,
|
||||
position_z,
|
||||
direction,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
13
src/state.rs
13
src/state.rs
|
@ -1,7 +1,8 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::{
|
||||
blocks_items::BlockItem, chunk::MapChunk, position::{PlayerLook, PlayerPosition, PlayerPositionLook}
|
||||
chunk::{BlockType, MapChunk},
|
||||
position::{PlayerLook, PlayerPosition, PlayerPositionLook},
|
||||
};
|
||||
|
||||
pub struct GameState {
|
||||
|
@ -28,7 +29,7 @@ impl GameState {
|
|||
pub struct PlayerState {
|
||||
eid: i32,
|
||||
username: String,
|
||||
holding: BlockItem,
|
||||
holding: i16,
|
||||
position_look: PlayerPositionLook,
|
||||
}
|
||||
|
||||
|
@ -38,7 +39,7 @@ impl PlayerState {
|
|||
Self {
|
||||
eid,
|
||||
username,
|
||||
holding: BlockItem::Unknown,
|
||||
holding: -1,
|
||||
position_look: PlayerPositionLook::default(),
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +48,7 @@ impl PlayerState {
|
|||
Self {
|
||||
eid: -1,
|
||||
username: String::new(),
|
||||
holding: BlockItem::Unknown,
|
||||
holding: -1,
|
||||
position_look: PlayerPositionLook::default(),
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +77,7 @@ impl PlayerState {
|
|||
&self.position_look
|
||||
}
|
||||
|
||||
pub fn holding(&self) -> &BlockItem {
|
||||
pub fn holding(&self) -> &BlockType {
|
||||
&self.holding
|
||||
}
|
||||
|
||||
|
@ -88,7 +89,7 @@ impl PlayerState {
|
|||
self.position_look.look = look
|
||||
}
|
||||
|
||||
pub fn set_holding(&mut self, holding: BlockItem) {
|
||||
pub fn set_holding(&mut self, holding: i16) {
|
||||
self.holding = holding
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,18 +2,12 @@ use std::{fmt::Display, io::{self, Read, Write}};
|
|||
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt, BE};
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct MCString {
|
||||
len: u16,
|
||||
chars: Vec<u8>,
|
||||
}
|
||||
|
||||
impl MCString {
|
||||
pub fn len(&self) -> usize {
|
||||
self.len as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for MCString {
|
||||
type Error = ();
|
||||
|
Loading…
Reference in a new issue