Compare commits

...

2 commits

Author SHA1 Message Date
a9677205dd Updated targeted version 2024-10-13 02:22:04 -05:00
ad6293075f Organizing code and figuring things out 2024-10-13 02:21:21 -05:00
13 changed files with 385 additions and 246 deletions

View file

@ -1,4 +1,4 @@
# Alpha Server # Alpha Server
A server written in rust or something idk A server written in rust or something idk
Targeting Minecraft Alpha `1.2.6`, server version `0.2.8`. Targeting Minecraft Beta `1.1_02`, protocol version `8`.

View file

@ -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)] #[repr(i16)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(FromPrimitive)]
pub enum Block { pub enum Block {
Unknown = -1, Air = 0,
Stone = 1, Stone = 1,
Grass = 2, Grass = 2,
Dirt = 3, Dirt = 3,
@ -79,110 +127,126 @@ pub enum Block {
PumpkinLantern = 91, PumpkinLantern = 91,
} }
#[repr(i16)] #[repr(i16)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(FromPrimitive)]
pub enum Item { pub enum Item {
Unknown = -1, ShovelSteel = 0,
ShovelSteel = 256, PickaxeSteel = 1,
PickaxeSteel = 257, AxeSteel = 2,
AxeSteel = 258, FlintAndSteel = 3,
FlintAndSteel = 259, AppleRed = 4,
AppleRed = 260, Bow = 5,
Bow = 261, Arrow = 6,
Arrow = 262, Coal = 7,
Coal = 263, Diamond = 8,
Diamond = 264, IngotIron = 9,
IngotIron = 265, IngotGold = 10,
IngotGold = 266, SwordSteel = 11,
SwordSteel = 267, SwordWood = 12,
SwordWood = 268, ShovelWood = 13,
ShovelWood = 269, PickaxeWood = 14,
PickaxeWood = 270, AxeWood = 15,
AxeWood = 271, SwordStone = 16,
SwordStone = 272, ShovelStone = 17,
ShovelStone = 273, PickaxeStone = 18,
PickaxeStone = 274, AxeStone = 19,
AxeStone = 275, SwordDiamond = 20,
SwordDiamond = 276, ShovelDiamond = 21,
ShovelDiamond = 277, PickaxeDiamond = 22,
PickaxeDiamond = 278, AxeDiamond = 23,
AxeDiamond = 279, Stick = 24,
Stick = 280, BowlEmpty = 25,
BowlEmpty = 281, BowlSoup = 26,
BowlSoup = 282, SwordGold = 27,
SwordGold = 283, ShovelGold = 28,
ShovelGold = 284, PickaxeGold = 29,
PickaxeGold = 285, AxeGold = 30,
AxeGold = 286, Silk = 31,
Silk = 287, Feather = 32,
Feather = 288, Gunpowder = 33,
Gunpowder = 289, HoeWood = 34,
HoeWood = 290, HoeStone = 35,
HoeStone = 291, HoeSteel = 36,
HoeSteel = 292, HoeDiamond = 37,
HoeDiamond = 293, HoeGold = 38,
HoeGold = 294, Seeds = 39,
Seeds = 295, Wheat = 40,
Wheat = 296, Bread = 41,
Bread = 297, HelmetLeather = 42,
HelmetLeather = 298, PlateLeather = 43,
PlateLeather = 299, LegsLeather = 44,
LegsLeather = 300, BootsLeather = 45,
BootsLeather = 301, HelmetChain = 46,
HelmetChain = 302, PlateChain = 47,
PlateChain = 303, LegsChain = 48,
LegsChain = 304, BootsChain = 49,
BootsChain = 305, HelmetSteel = 50,
HelmetSteel = 306, PlateSteel = 51,
PlateSteel = 307, LegsSteel = 52,
LegsSteel = 308, BootsSteel = 53,
BootsSteel = 309, HelmetDiamond = 54,
HelmetDiamond = 310, PlateDiamond = 55,
PlateDiamond = 311, LegsDiamond = 56,
LegsDiamond = 312, BootsDiamond = 57,
BootsDiamond = 313, HelmetGold = 58,
HelmetGold = 314, PlateGold = 59,
PlateGold = 315, LegsGold = 60,
LegsGold = 316, BootsGold = 61,
BootsGold = 317, Flint = 62,
Flint = 318, PorkRaw = 63,
PorkRaw = 319, PorkCooked = 64,
PorkCooked = 320, Painting = 65,
Painting = 321, AppleGold = 66,
AppleGold = 322, Sign = 67,
Sign = 323, DoorWood = 68,
DoorWood = 324, BucketEmpty = 69,
BucketEmpty = 325, BucketWater = 70,
BucketWater = 326, BucketLava = 71,
BucketLava = 327, MinecartEmpty = 72,
MinecartEmpty = 328, Saddle = 73,
Saddle = 329, DoorSteel = 74,
DoorSteel = 330, Redstone = 75,
Redstone = 331, Snowball = 76,
Snowball = 332, Boat = 77,
Boat = 333, Leather = 78,
Leather = 334, BucketMilk = 79,
BucketMilk = 335, Brick = 80,
Brick = 336, Clay = 81,
Clay = 337, Reed = 82,
Reed = 338, Paper = 83,
Paper = 339, Book = 84,
Book = 340, SlimeBall = 85,
SlimeBall = 341, MinecartCrate = 86,
MinecartCrate = 342, MinecartPowered = 87,
MinecartPowered = 343, Egg = 88,
Egg = 344, Compass = 89,
Compass = 345, FishingRod = 90,
FishingRod = 346, PocketSundial = 91,
PocketSundial = 347, LightStoneDust = 92,
LightStoneDust = 348, FishRaw = 93,
FishRaw = 349, FishCooked = 94,
FishCooked = 350,
Record13 = 2000, Record13 = 2000,
RecordCat = 2001, RecordCat = 2001,
} }
impl Item { #[derive(Debug, Clone, Copy, PartialEq, Eq)]
fn index() -> i16 { pub struct ItemStack {
256 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,
}
} }
} }

View file

@ -1,4 +1,4 @@
use std::ops; use std::{io::Read, ops};
pub trait ToBytes: Sized { pub trait ToBytes: Sized {
/// A byte array which can store a packed representation of this type. /// 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; fn to_bytes(self) -> Self::Bytes;
} }
pub trait FromBytes: Sized {
type Bytes: ByteArray;
fn from_bytes<R: Read>(stream: &mut R) -> Self;
}
mod private { mod private {
pub trait ByteArray {} pub trait ByteArray {}

View file

@ -1,9 +1,8 @@
use byteorder::{WriteBytesExt, BE}; use byteorder::{WriteBytesExt, BE};
use flate2::write::ZlibEncoder; use flate2::{Compression, write::ZlibEncoder};
use flate2::Compression;
use num_derive::FromPrimitive;
use std::io::prelude::*; use std::io::prelude::*;
use crate::blocks_items::Block;
use crate::byte_ops::ToBytes; use crate::byte_ops::ToBytes;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -71,13 +70,13 @@ impl BlockArray {
for z in 0..CHUNK_WIDTH_Z { for z in 0..CHUNK_WIDTH_Z {
let pos = y + (z * (CHUNK_HEIGHT_Y)) + (x * (CHUNK_HEIGHT_Y) * (CHUNK_WIDTH_X)); let pos = y + (z * (CHUNK_HEIGHT_Y)) + (x * (CHUNK_HEIGHT_Y) * (CHUNK_WIDTH_X));
if y == 7 { if y == 7 {
blocks[pos] = BlockType::Grass as u8; blocks[pos] = Block::Grass as u8;
} else if y > 0 && y < 7 { } else if y > 0 && y < 7 {
blocks[pos] = BlockType::Dirt as u8; blocks[pos] = Block::Dirt as u8;
} else if y == 0 { } else if y == 0 {
blocks[pos] = BlockType::Bedrock as u8; blocks[pos] = Block::Bedrock as u8;
} else { } 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 { impl ToBytes for MapChunk {
type Bytes = Vec<u8>; type Bytes = Vec<u8>;

28
src/entity_id.rs Normal file
View file

@ -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
}
}

View file

@ -1,49 +1,45 @@
mod utils; mod mcstring;
mod byte_ops; mod byte_ops;
mod chunk; mod chunk;
mod position; mod position;
mod state; mod state;
mod player; mod player;
mod blocks_items; 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 base16ct::lower::encode_string;
use chunk::{BlockArray, MapChunk, PreChunk}; 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 byteorder::{ReadBytesExt, WriteBytesExt, BE};
use num_derive::FromPrimitive; use num_derive::FromPrimitive;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use byte_ops::ToBytes; 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 position::{PlayerLook, PlayerPosition, PlayerPositionLook};
use state::{GameState, PlayerState}; use state::{GameState, PlayerState};
use utils::{MCString, ReadMCString, WriteMCString}; use mcstring::{MCString, ReadMCString, WriteMCString};
use rand::random; 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() { fn main() {
colog::default_builder() colog::default_builder()
.filter_level(log::LevelFilter::Debug) .filter_level(log::LevelFilter::Debug)
.init(); .init();
info!("Setting up game state"); info!("Starting Minecraft server version Beta 1.1_02");
let game_state: Arc<RwLock<GameState>> = Arc::new(RwLock::new(GameState::new())); let game_state: Arc<RwLock<GameState>> = 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()); info!("Server started and listening on {}", listener.local_addr().unwrap());
for mut connection in listener.incoming().filter_map(|c| c.ok()) { for mut connection in listener.incoming().filter_map(|c| c.ok()) {
@ -82,16 +78,16 @@ fn player_loop(
break; break;
} }
if player_state.is_valid() { 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_some_and(|p| *p != player_state)
|| game_state.read().unwrap().player_list().get(player_state.username()).is_none() || game_state.read().unwrap().player_list().get(player_state.username()).is_none())
{ {
game_state.write() game_state.write()
.unwrap() .unwrap()
.player_list_mut() .player_list_mut()
.insert(player_state.username().clone(), player_state.clone()); .insert(player_state.username().clone(), player_state.clone());
} }
}
} }
@ -115,22 +111,19 @@ fn handle_command(
info!("Handshake with {username} successful"); info!("Handshake with {username} successful");
}, },
Command::Login => { Command::Login => {
let protocol_version = connection.read_u32::<BE>()?; let login_info = packet1_login::Packet1Login::read_from(&mut connection)?;
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 // Return a successful login packet to the client
let eid = get_eid(); let eid = ENTITY_ID.get();
let login_packet = ServerLoginPacket::new(eid, 0, 0); let login_packet = packet1_login::Packet1Login::new(eid, 0, 0);
connection.write_u8(Command::Login as u8).unwrap(); connection.write_u8(Command::Login as u8)?;
connection.write_all(&login_packet.to_bytes())?; login_packet.write_into(&mut connection)?;
info!("{username} logged in. Protocol version {protocol_version}"); info!("{} [{}] logged in with entity id {}", login_info.username, connection.peer_addr().unwrap(), eid);
*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 i in -10..10 {
for o in -10..10 { for o in -10..10 {
let x = i * 16; let x = i * 16;
@ -186,7 +179,7 @@ fn handle_command(
} }
Command::HoldingChange => { Command::HoldingChange => {
let _unused = connection.read_i32::<BE>()?; let _unused = connection.read_i32::<BE>()?;
let block_id = connection.read_i16::<BE>()?; let _block_id = connection.read_i16::<BE>()?;
} }
Command::PlayerDigging => { Command::PlayerDigging => {
let _status = DiggingStatus::from_u8(connection.read_u8()?).unwrap(); let _status = DiggingStatus::from_u8(connection.read_u8()?).unwrap();
@ -196,7 +189,8 @@ fn handle_command(
let _face = connection.read_u8()?; let _face = connection.read_u8()?;
} }
Command::PlayerBlockPlacement => { Command::PlayerBlockPlacement => {
let _status = PlayerBlockPlacement::from_bytes(&mut connection); let status = Packet15Place::read_from(&mut connection)?;
dbg!(status);
} }
Command::Animation => { Command::Animation => {
let _eid = connection.read_i32::<BE>()?; let _eid = connection.read_i32::<BE>()?;
@ -209,6 +203,7 @@ fn handle_command(
} }
Command::KeepAlive => { Command::KeepAlive => {
connection.write_u8(Command::KeepAlive as u8)?; connection.write_u8(Command::KeepAlive as u8)?;
info!("Keepalive!");
} }
Command::UpdateHealth => { Command::UpdateHealth => {
connection.read_u8()?; 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!") 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(()) Ok(())
} }
@ -260,38 +257,3 @@ enum Command {
ComplexEntities = 0x3B, ComplexEntities = 0x3B,
Disconnect = 0xFF, 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
}
}

View file

@ -2,12 +2,18 @@ use std::{fmt::Display, io::{self, Read, Write}};
use byteorder::{ReadBytesExt, WriteBytesExt, BE}; use byteorder::{ReadBytesExt, WriteBytesExt, BE};
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct MCString { pub struct MCString {
len: u16, len: u16,
chars: Vec<u8>, chars: Vec<u8>,
} }
impl MCString {
pub fn len(&self) -> usize {
self.len as usize
}
}
impl TryFrom<&str> for MCString { impl TryFrom<&str> for MCString {
type Error = (); type Error = ();

19
src/packets/mod.rs Normal file
View file

@ -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<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;
}

8
src/packets/packet101.rs Normal file
View file

@ -0,0 +1,8 @@
use byteorder::{ReadBytesExt, WriteBytesExt, BE};
use num_traits::FromPrimitive;
use super::Packet;
pub struct Packet101 {
}

View file

@ -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<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!()
}
}

View file

@ -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<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
}
}

View file

@ -1,10 +1,4 @@
use std::io::Read;
use byteorder::{ReadBytesExt, BE};
use num_derive::FromPrimitive; use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use crate::chunk::BlockType;
#[repr(u8)] #[repr(u8)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -37,32 +31,3 @@ pub struct PlayerDigging {
position_z: i32, position_z: i32,
face: Direction, 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,
}
}
}

View file

@ -1,8 +1,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use crate::{ use crate::{
chunk::{BlockType, MapChunk}, blocks_items::BlockItem, chunk::MapChunk, position::{PlayerLook, PlayerPosition, PlayerPositionLook}
position::{PlayerLook, PlayerPosition, PlayerPositionLook},
}; };
pub struct GameState { pub struct GameState {
@ -29,7 +28,7 @@ impl GameState {
pub struct PlayerState { pub struct PlayerState {
eid: i32, eid: i32,
username: String, username: String,
holding: i16, holding: BlockItem,
position_look: PlayerPositionLook, position_look: PlayerPositionLook,
} }
@ -39,7 +38,7 @@ impl PlayerState {
Self { Self {
eid, eid,
username, username,
holding: -1, holding: BlockItem::Unknown,
position_look: PlayerPositionLook::default(), position_look: PlayerPositionLook::default(),
} }
} }
@ -48,7 +47,7 @@ impl PlayerState {
Self { Self {
eid: -1, eid: -1,
username: String::new(), username: String::new(),
holding: -1, holding: BlockItem::Unknown,
position_look: PlayerPositionLook::default(), position_look: PlayerPositionLook::default(),
} }
} }
@ -77,7 +76,7 @@ impl PlayerState {
&self.position_look &self.position_look
} }
pub fn holding(&self) -> &BlockType { pub fn holding(&self) -> &BlockItem {
&self.holding &self.holding
} }
@ -89,7 +88,7 @@ impl PlayerState {
self.position_look.look = look self.position_look.look = look
} }
pub fn set_holding(&mut self, holding: i16) { pub fn set_holding(&mut self, holding: BlockItem) {
self.holding = holding self.holding = holding
} }
} }