From ad6293075f3edb2a1ffd88d013b6e55626c0794c Mon Sep 17 00:00:00 2001 From: G2-Games Date: Sun, 13 Oct 2024 02:21:21 -0500 Subject: [PATCH] Organizing code and figuring things out --- src/blocks_items.rs | 264 +++++++++++++++++++++------------- src/byte_ops.rs | 8 +- src/chunk.rs | 28 +--- src/entity_id.rs | 28 ++++ src/main.rs | 120 ++++++---------- src/{utils.rs => mcstring.rs} | 8 +- src/packets/mod.rs | 19 +++ src/packets/packet101.rs | 8 ++ src/packets/packet15_place.rs | 40 ++++++ src/packets/packet1_login.rs | 58 ++++++++ src/player.rs | 35 ----- src/state.rs | 13 +- 12 files changed, 384 insertions(+), 245 deletions(-) create mode 100644 src/entity_id.rs rename src/{utils.rs => mcstring.rs} (92%) create mode 100644 src/packets/mod.rs create mode 100644 src/packets/packet101.rs create mode 100644 src/packets/packet15_place.rs create mode 100644 src/packets/packet1_login.rs diff --git a/src/blocks_items.rs b/src/blocks_items.rs index 718b8e5..0b62e74 100644 --- a/src/blocks_items.rs +++ b/src/blocks_items.rs @@ -1,6 +1,54 @@ +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 { - Unknown = -1, + Air = 0, Stone = 1, Grass = 2, Dirt = 3, @@ -79,110 +127,126 @@ pub enum Block { PumpkinLantern = 91, } + + #[repr(i16)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(FromPrimitive)] pub enum Item { - 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, + 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, Record13 = 2000, RecordCat = 2001, } -impl Item { - fn index() -> i16 { - 256 +#[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, + } } } diff --git a/src/byte_ops.rs b/src/byte_ops.rs index ca6d949..4b4ea1d 100644 --- a/src/byte_ops.rs +++ b/src/byte_ops.rs @@ -1,4 +1,4 @@ -use std::ops; +use std::{io::Read, ops}; pub trait ToBytes: Sized { /// A byte array which can store a packed representation of this type. @@ -7,6 +7,12 @@ pub trait ToBytes: Sized { fn to_bytes(self) -> Self::Bytes; } +pub trait FromBytes: Sized { + type Bytes: ByteArray; + + fn from_bytes(stream: &mut R) -> Self; +} + mod private { pub trait ByteArray {} diff --git a/src/chunk.rs b/src/chunk.rs index a97ece6..c2797ec 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -1,9 +1,8 @@ use byteorder::{WriteBytesExt, BE}; -use flate2::write::ZlibEncoder; -use flate2::Compression; -use num_derive::FromPrimitive; +use flate2::{Compression, write::ZlibEncoder}; use std::io::prelude::*; +use crate::blocks_items::Block; use crate::byte_ops::ToBytes; #[derive(Debug, Clone)] @@ -71,13 +70,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] = BlockType::Grass as u8; + blocks[pos] = Block::Grass as u8; } else if y > 0 && y < 7 { - blocks[pos] = BlockType::Dirt as u8; + blocks[pos] = Block::Dirt as u8; } else if y == 0 { - blocks[pos] = BlockType::Bedrock as u8; + blocks[pos] = Block::Bedrock as u8; } else { - blocks[pos] = BlockType::Air as u8; + blocks[pos] = Block::Air as u8; } } } @@ -92,21 +91,6 @@ 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; diff --git a/src/entity_id.rs b/src/entity_id.rs new file mode 100644 index 0000000..73719ed --- /dev/null +++ b/src/entity_id.rs @@ -0,0 +1,28 @@ +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 + } +} diff --git a/src/main.rs b/src/main.rs index 0535704..2195a8f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,49 +1,45 @@ -mod utils; +mod mcstring; 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}, sync::{atomic::{self, AtomicI32}, Arc, RwLock}, thread}; +use std::{io::{self, Write}, net::{TcpListener, TcpStream}, process::exit, sync::{Arc, RwLock}, thread}; use base16ct::lower::encode_string; use chunk::{BlockArray, MapChunk, PreChunk}; -use log::{error, info, warn}; +use entity_id::ENTITY_ID; +use log::{debug, error, info}; use byteorder::{ReadBytesExt, WriteBytesExt, BE}; use num_derive::FromPrimitive; use num_traits::FromPrimitive; use byte_ops::ToBytes; -use player::{DiggingStatus, PlayerBlockPlacement}; +use packets::{packet15_place::Packet15Place, packet1_login, Packet}; +use player::DiggingStatus; use position::{PlayerLook, PlayerPosition, PlayerPositionLook}; use state::{GameState, PlayerState}; -use utils::{MCString, ReadMCString, WriteMCString}; +use mcstring::{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!("Setting up game state"); + info!("Starting Minecraft server version Beta 1.1_02"); let game_state: Arc> = Arc::new(RwLock::new(GameState::new())); - let listener = TcpListener::bind("0.0.0.0:25565").unwrap(); + let listener = match TcpListener::bind("0.0.0.0:25565") { + Ok(l) => l, + Err(e) => { + error!("Starting server failed: {e}"); + exit(1) + }, + }; info!("Server started and listening on {}", listener.local_addr().unwrap()); for mut connection in listener.incoming().filter_map(|c| c.ok()) { @@ -82,17 +78,17 @@ fn player_loop( break; } - 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()); - } + 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()); } + } Ok(()) @@ -115,22 +111,19 @@ fn handle_command( info!("Handshake with {username} successful"); }, Command::Login => { - let protocol_version = connection.read_u32::()?; - let username = connection.read_mcstring()?; - // These are mostly useless - let _password = connection.read_mcstring()?; - let _map_seed = connection.read_i64::()?; - let _dimension = connection.read_i8()?; + let login_info = packet1_login::Packet1Login::read_from(&mut connection)?; // Return a successful login packet to the client - 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())?; + 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)?; - info!("{username} logged in. Protocol version {protocol_version}"); - *player_state = PlayerState::new(username.to_string(), eid); + info!("{} [{}] logged in with entity id {}", login_info.username, connection.peer_addr().unwrap(), 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; @@ -186,7 +179,7 @@ fn handle_command( } Command::HoldingChange => { let _unused = connection.read_i32::()?; - let block_id = connection.read_i16::()?; + let _block_id = connection.read_i16::()?; } Command::PlayerDigging => { let _status = DiggingStatus::from_u8(connection.read_u8()?).unwrap(); @@ -196,7 +189,8 @@ fn handle_command( let _face = connection.read_u8()?; } Command::PlayerBlockPlacement => { - let _status = PlayerBlockPlacement::from_bytes(&mut connection); + let status = Packet15Place::read_from(&mut connection)?; + dbg!(status); } Command::Animation => { let _eid = connection.read_i32::()?; @@ -209,6 +203,7 @@ fn handle_command( } Command::KeepAlive => { connection.write_u8(Command::KeepAlive as u8)?; + info!("Keepalive!"); } Command::UpdateHealth => { connection.read_u8()?; @@ -216,6 +211,8 @@ 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(()) } @@ -260,38 +257,3 @@ 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; - - fn to_bytes(self) -> Self::Bytes { - let mut out_buf = Vec::new(); - out_buf.write_i32::(self.entity_id).unwrap(); - out_buf.write_mcstring(&self.unknown1).unwrap(); - out_buf.write_mcstring(&self.unknown2).unwrap(); - out_buf.write_i64::(self.map_seed).unwrap(); - out_buf.write_i8(self.dimension).unwrap(); - - out_buf - } -} diff --git a/src/utils.rs b/src/mcstring.rs similarity index 92% rename from src/utils.rs rename to src/mcstring.rs index 19bad30..3300b6a 100644 --- a/src/utils.rs +++ b/src/mcstring.rs @@ -2,12 +2,18 @@ use std::{fmt::Display, io::{self, Read, Write}}; use byteorder::{ReadBytesExt, WriteBytesExt, BE}; -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct MCString { len: u16, chars: Vec, } +impl MCString { + pub fn len(&self) -> usize { + self.len as usize + } +} + impl TryFrom<&str> for MCString { type Error = (); diff --git a/src/packets/mod.rs b/src/packets/mod.rs new file mode 100644 index 0000000..c80cd08 --- /dev/null +++ b/src/packets/mod.rs @@ -0,0 +1,19 @@ +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(input: &mut R) -> Result; + + /// Write the packet out to a stream + fn write_into(&self, output: &mut W) -> Result<(), io::Error>; + + /// The size of the packet in bytes + fn size(&self) -> usize; +} diff --git a/src/packets/packet101.rs b/src/packets/packet101.rs new file mode 100644 index 0000000..5178b7c --- /dev/null +++ b/src/packets/packet101.rs @@ -0,0 +1,8 @@ +use byteorder::{ReadBytesExt, WriteBytesExt, BE}; +use num_traits::FromPrimitive; + +use super::Packet; + +pub struct Packet101 { + +} diff --git a/src/packets/packet15_place.rs b/src/packets/packet15_place.rs new file mode 100644 index 0000000..b6acabf --- /dev/null +++ b/src/packets/packet15_place.rs @@ -0,0 +1,40 @@ +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, + health: Option, +} + +impl Packet for Packet15Place { + fn read_from(input: &mut R) -> Result { + let id = BlockItem::from_id(input.read_i16::()?); + Ok(Self { + id, + x_position: input.read_i32::()?, + y_position: input.read_u8()?, + z_position: input.read_i32::()?, + 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::()?) } + }) + } + + fn write_into(&self, output: &mut W) -> Result<(), std::io::Error> { + unimplemented!() + } + + fn size(&self) -> usize { + todo!() + } +} diff --git a/src/packets/packet1_login.rs b/src/packets/packet1_login.rs new file mode 100644 index 0000000..710ce3c --- /dev/null +++ b/src/packets/packet1_login.rs @@ -0,0 +1,58 @@ +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(input: &mut R) -> Result { + let protocol_version = input.read_i32::()?; + let username = input.read_mcstring()?.into(); + let password = input.read_mcstring()?.into(); + let world_seed = input.read_i64::()?; + let dimension = input.read_i8()?; + + Ok(Packet1Login { + username, + password, + protocol_version, + world_seed, + dimension, + }) + } + + fn write_into(&self, output: &mut W) -> Result<(), std::io::Error> { + output.write_i32::(self.protocol_version).unwrap(); + output.write_mcstring(&self.username).unwrap(); + output.write_mcstring(&self.password).unwrap(); + output.write_i64::(self.world_seed).unwrap(); + output.write_i8(self.dimension).unwrap(); + + Ok(()) + } + + fn size(&self) -> usize { + 4 + self.username.len() + self.password.len() + 8 + 1 + } +} diff --git a/src/player.rs b/src/player.rs index 5c11d8d..eca1ce5 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,10 +1,4 @@ -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)] @@ -37,32 +31,3 @@ 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(stream: &mut R) -> Self { - let block_id = BlockType::from_i16(stream.read_i16::().unwrap()).unwrap(); - let position_x = stream.read_i32::().unwrap(); - let position_y = stream.read_u8().unwrap(); - let position_z = stream.read_i32::().unwrap(); - let direction = Direction::from_u8(stream.read_u8().unwrap()).unwrap(); - - Self { - block_id, - position_x, - position_y, - position_z, - direction, - } - } -} diff --git a/src/state.rs b/src/state.rs index 389c661..c6df91d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,8 +1,7 @@ use std::collections::BTreeMap; use crate::{ - chunk::{BlockType, MapChunk}, - position::{PlayerLook, PlayerPosition, PlayerPositionLook}, + blocks_items::BlockItem, chunk::MapChunk, position::{PlayerLook, PlayerPosition, PlayerPositionLook} }; pub struct GameState { @@ -29,7 +28,7 @@ impl GameState { pub struct PlayerState { eid: i32, username: String, - holding: i16, + holding: BlockItem, position_look: PlayerPositionLook, } @@ -39,7 +38,7 @@ impl PlayerState { Self { eid, username, - holding: -1, + holding: BlockItem::Unknown, position_look: PlayerPositionLook::default(), } } @@ -48,7 +47,7 @@ impl PlayerState { Self { eid: -1, username: String::new(), - holding: -1, + holding: BlockItem::Unknown, position_look: PlayerPositionLook::default(), } } @@ -77,7 +76,7 @@ impl PlayerState { &self.position_look } - pub fn holding(&self) -> &BlockType { + pub fn holding(&self) -> &BlockItem { &self.holding } @@ -89,7 +88,7 @@ impl PlayerState { self.position_look.look = look } - pub fn set_holding(&mut self, holding: i16) { + pub fn set_holding(&mut self, holding: BlockItem) { self.holding = holding } }