mirror of
https://github.com/G2-Games/minecraft_alpha_server.git
synced 2025-04-19 15:22:56 -05:00
Worked on state. Added preliminary item and block lists.
This commit is contained in:
parent
e898dfa859
commit
81dc4ec3d9
6 changed files with 386 additions and 65 deletions
188
src/blocks_items.rs
Normal file
188
src/blocks_items.rs
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
#[repr(i16)]
|
||||||
|
pub enum Block {
|
||||||
|
Unknown = -1,
|
||||||
|
Stone = 1,
|
||||||
|
Grass = 2,
|
||||||
|
Dirt = 3,
|
||||||
|
Cobblestone = 4,
|
||||||
|
Planks = 5,
|
||||||
|
Sapling = 6,
|
||||||
|
Bedrock = 7,
|
||||||
|
WaterStill = 8,
|
||||||
|
WaterMoving = 9,
|
||||||
|
LavaStill = 10,
|
||||||
|
LavaMoving = 11,
|
||||||
|
Sand = 12,
|
||||||
|
Gravel = 13,
|
||||||
|
OreGold = 14,
|
||||||
|
OreIron = 15,
|
||||||
|
OreCoal = 16,
|
||||||
|
Wood = 17,
|
||||||
|
Leaves = 18,
|
||||||
|
Sponge = 19,
|
||||||
|
Glass = 20,
|
||||||
|
Cloth = 35,
|
||||||
|
PlantYellow = 37,
|
||||||
|
PlantRed = 38,
|
||||||
|
MushroomBrown = 39,
|
||||||
|
MushroomRed = 40,
|
||||||
|
BlockGold = 41,
|
||||||
|
BlockSteel = 42,
|
||||||
|
StairDouble = 43,
|
||||||
|
StairSingle = 44,
|
||||||
|
Brick = 45,
|
||||||
|
Tnt = 46,
|
||||||
|
BookShelf = 47,
|
||||||
|
CobblestoneMossy = 48,
|
||||||
|
Obsidian = 49,
|
||||||
|
TorchWood = 50,
|
||||||
|
Fire = 51,
|
||||||
|
MobSpawner = 52,
|
||||||
|
StairCompactPlanks = 53,
|
||||||
|
Crate = 54,
|
||||||
|
RedstoneWire = 55,
|
||||||
|
OreDiamond = 56,
|
||||||
|
BlockDiamond = 57,
|
||||||
|
Workbench = 58,
|
||||||
|
Crops = 59,
|
||||||
|
TilledField = 60,
|
||||||
|
StoneOvenIdle = 61,
|
||||||
|
StoneOvenActive = 62,
|
||||||
|
SignPost = 63,
|
||||||
|
DoorWood = 64,
|
||||||
|
Ladder = 65,
|
||||||
|
MinecartTrack = 66,
|
||||||
|
StairCompactCobblestone = 67,
|
||||||
|
SignWall = 68,
|
||||||
|
Lever = 69,
|
||||||
|
PressurePlateStone = 70,
|
||||||
|
DoorSteel = 71,
|
||||||
|
PressurePlatePlanks = 72,
|
||||||
|
OreRedstone = 73,
|
||||||
|
OreRedstoneGlowing = 74,
|
||||||
|
TorchRedstoneIdle = 75,
|
||||||
|
TorchRedstoneActive = 76,
|
||||||
|
Button = 77,
|
||||||
|
Snow = 78,
|
||||||
|
BlockIce = 79,
|
||||||
|
BlockSnow = 80,
|
||||||
|
Cactus = 81,
|
||||||
|
BlockClay = 82,
|
||||||
|
Reed = 83,
|
||||||
|
Jukebox = 84,
|
||||||
|
Fence = 85,
|
||||||
|
Pumpkin = 86,
|
||||||
|
BloodStone = 87,
|
||||||
|
SlowSand = 88,
|
||||||
|
LightStone = 89,
|
||||||
|
Portal = 90,
|
||||||
|
PumpkinLantern = 91,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(i16)]
|
||||||
|
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,
|
||||||
|
Record13 = 2000,
|
||||||
|
RecordCat = 2001,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Item {
|
||||||
|
fn index() -> i16 {
|
||||||
|
256
|
||||||
|
}
|
||||||
|
}
|
11
src/chunk.rs
11
src/chunk.rs
|
@ -47,13 +47,12 @@ const CHUNK_TOTAL_BLOCKS: usize = CHUNK_WIDTH_X * CHUNK_WIDTH_Z * CHUNK_HEIGHT_Y
|
||||||
impl BlockArray {
|
impl BlockArray {
|
||||||
fn compress(self) -> Vec<u8> {
|
fn compress(self) -> Vec<u8> {
|
||||||
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
|
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
|
||||||
encoder.write(&self.blocks).unwrap();
|
encoder.write_all(&self.blocks).unwrap();
|
||||||
encoder.write(&self.metadata).unwrap();
|
encoder.write_all(&self.metadata).unwrap();
|
||||||
encoder.write(&self.block_light).unwrap();
|
encoder.write_all(&self.block_light).unwrap();
|
||||||
encoder.write(&self.sky_light).unwrap();
|
encoder.write_all(&self.sky_light).unwrap();
|
||||||
let output_buf = encoder.finish().unwrap();
|
|
||||||
|
|
||||||
output_buf
|
encoder.finish().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_air() -> Self {
|
pub fn new_air() -> Self {
|
||||||
|
|
157
src/main.rs
157
src/main.rs
|
@ -4,31 +4,33 @@ mod chunk;
|
||||||
mod position;
|
mod position;
|
||||||
mod state;
|
mod state;
|
||||||
mod player;
|
mod player;
|
||||||
|
mod blocks_items;
|
||||||
|
|
||||||
use std::{io::{self, Write}, net::{TcpListener, TcpStream}, sync::RwLock};
|
use std::{io::{self, Write}, net::{TcpListener, TcpStream}, sync::{atomic::{self, AtomicI32}, 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::{info, warn};
|
use log::{error, info, warn};
|
||||||
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 player::{DiggingStatus, PlayerBlockPlacement};
|
||||||
use position::{PlayerLook, PlayerPosition, PlayerPositionAndLook};
|
use position::{PlayerLook, PlayerPosition, PlayerPositionLook};
|
||||||
use state::PlayerState;
|
use state::{GameState, PlayerState};
|
||||||
use utils::{MCString, ReadMCString, WriteMCString};
|
use utils::{MCString, ReadMCString, WriteMCString};
|
||||||
use rand::random;
|
use rand::random;
|
||||||
|
|
||||||
/// List of players.
|
|
||||||
const PLAYER_LIST: RwLock<Vec<PlayerState>> = RwLock::new(Vec::new());
|
|
||||||
|
|
||||||
/// The current Entity ID. Incremented by one every time there is a new entity.
|
/// The current Entity ID. Incremented by one every time there is a new entity.
|
||||||
const ENTITY_ID: RwLock<i32> = RwLock::new(0);
|
///
|
||||||
|
/// 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 {
|
fn get_eid() -> i32 {
|
||||||
let eid = ENTITY_ID.read().unwrap().clone();
|
let eid = ENTITY_ID.load(atomic::Ordering::Relaxed);
|
||||||
*ENTITY_ID.write().unwrap() += 1;
|
ENTITY_ID.store(eid + 1, atomic::Ordering::Relaxed);
|
||||||
|
|
||||||
eid
|
eid
|
||||||
}
|
}
|
||||||
|
@ -38,31 +40,76 @@ fn main() {
|
||||||
.filter_level(log::LevelFilter::Debug)
|
.filter_level(log::LevelFilter::Debug)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
|
info!("Setting up game state");
|
||||||
|
let game_state: Arc<RwLock<GameState>> = Arc::new(RwLock::new(GameState::new()));
|
||||||
|
|
||||||
let listener = TcpListener::bind("0.0.0.0:25565").unwrap();
|
let listener = TcpListener::bind("0.0.0.0:25565").unwrap();
|
||||||
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()) {
|
||||||
info!("Player joined from {}", connection.peer_addr().unwrap());
|
info!("Player joined from {}", connection.peer_addr().unwrap());
|
||||||
while let Some(cmd) = connection.read_u8().ok() {
|
let mut game_state = Arc::clone(&game_state);
|
||||||
let command = Command::from_u8(cmd);
|
thread::spawn(move || {
|
||||||
if command.is_none() {
|
player_loop(
|
||||||
info!("COMMAND: {command:?} (0x{cmd:02X?})");
|
&mut connection,
|
||||||
panic!("This command isn't implemented yet");
|
&mut game_state,
|
||||||
}
|
).unwrap();
|
||||||
handle_command(&mut connection, command.unwrap()).unwrap();
|
|
||||||
}
|
info!("Connection dropped for {}", connection.peer_addr().unwrap());
|
||||||
warn!("Lost connection to client");
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<(), io::Error> {
|
fn player_loop(
|
||||||
|
mut connection: &mut TcpStream,
|
||||||
|
game_state: &mut Arc<RwLock<GameState>>,
|
||||||
|
) -> Result<(), io::Error> {
|
||||||
|
let mut player_state = PlayerState::new_invalid();
|
||||||
|
loop {
|
||||||
|
if let Ok(cmd) = connection.read_u8() {
|
||||||
|
let command = Command::from_u8(cmd);
|
||||||
|
if command.is_none() {
|
||||||
|
error!("COMMAND: {command:?} (0x{cmd:02X?})");
|
||||||
|
panic!("This command isn't implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_command(
|
||||||
|
&mut connection,
|
||||||
|
command.unwrap(),
|
||||||
|
&mut player_state,
|
||||||
|
).unwrap();
|
||||||
|
} else {
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_command(
|
||||||
|
mut connection: &mut TcpStream,
|
||||||
|
command: Command,
|
||||||
|
player_state: &mut PlayerState,
|
||||||
|
) -> Result<(), io::Error> {
|
||||||
match command {
|
match command {
|
||||||
Command::Handshake => {
|
Command::Handshake => {
|
||||||
let username = connection.read_mcstring()?;
|
let username = connection.read_mcstring()?;
|
||||||
let random_number = random::<u128>();
|
let random_number = random::<u128>();
|
||||||
let random_hash = encode_string(md5::compute(random_number.to_le_bytes()).as_slice());
|
let random_hash = encode_string(md5::compute(random_number.to_le_bytes()).as_slice());
|
||||||
|
|
||||||
connection.write_u8(0x02)?;
|
connection.write_u8(Command::Handshake as u8)?;
|
||||||
connection.write_mcstring(&MCString::try_from(random_hash).unwrap())?;
|
connection.write_mcstring(&MCString::try_from(random_hash).unwrap())?;
|
||||||
|
|
||||||
info!("Handshake with {username} successful");
|
info!("Handshake with {username} successful");
|
||||||
|
@ -75,20 +122,14 @@ fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<()
|
||||||
let _map_seed = connection.read_i64::<BE>()?;
|
let _map_seed = connection.read_i64::<BE>()?;
|
||||||
let _dimension = connection.read_i8()?;
|
let _dimension = connection.read_i8()?;
|
||||||
|
|
||||||
|
// Return a successful login packet to the client
|
||||||
let eid = get_eid();
|
let eid = get_eid();
|
||||||
let login_packet = ServerLoginPacket {
|
let login_packet = ServerLoginPacket::new(eid, 0, 0);
|
||||||
entity_id: eid,
|
|
||||||
unknown1: MCString::default(),
|
|
||||||
unknown2: MCString::default(),
|
|
||||||
map_seed: 0,
|
|
||||||
dimension: 0,
|
|
||||||
};
|
|
||||||
connection.write_u8(Command::Login as u8).unwrap();
|
connection.write_u8(Command::Login as u8).unwrap();
|
||||||
connection.write(&login_packet.to_bytes())?;
|
connection.write_all(&login_packet.to_bytes())?;
|
||||||
|
|
||||||
PLAYER_LIST.write().unwrap().push(PlayerState::new(username.to_string(), eid));
|
|
||||||
|
|
||||||
info!("{username} logged in. Protocol version {protocol_version}");
|
info!("{username} logged in. Protocol version {protocol_version}");
|
||||||
|
*player_state = PlayerState::new(username.to_string(), eid);
|
||||||
|
|
||||||
for i in -10..10 {
|
for i in -10..10 {
|
||||||
for o in -10..10 {
|
for o in -10..10 {
|
||||||
|
@ -105,15 +146,15 @@ fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<()
|
||||||
|
|
||||||
connection.write_u8(Command::SpawnPosition as u8)?;
|
connection.write_u8(Command::SpawnPosition as u8)?;
|
||||||
connection.write_u32::<BE>(0)?;
|
connection.write_u32::<BE>(0)?;
|
||||||
connection.write_u32::<BE>(70)?;
|
connection.write_u32::<BE>(0)?;
|
||||||
connection.write_u32::<BE>(0)?;
|
connection.write_u32::<BE>(0)?;
|
||||||
|
|
||||||
let playerpos = PlayerPositionAndLook {
|
let playerpos = PlayerPositionLook {
|
||||||
position: PlayerPosition {
|
position: PlayerPosition {
|
||||||
position_x: 1.0,
|
position_x: 0.5,
|
||||||
stance: 0.0,
|
stance: 0.0,
|
||||||
position_y: 9.63,
|
position_y: 9.63,
|
||||||
position_z: 1.0,
|
position_z: 0.5,
|
||||||
},
|
},
|
||||||
look: PlayerLook {
|
look: PlayerLook {
|
||||||
yaw: 0.0,
|
yaw: 0.0,
|
||||||
|
@ -124,19 +165,28 @@ fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<()
|
||||||
connection.write_all(&playerpos.to_bytes())?;
|
connection.write_all(&playerpos.to_bytes())?;
|
||||||
},
|
},
|
||||||
Command::ChatMessage => {
|
Command::ChatMessage => {
|
||||||
info!("Chat Message Recieved: {}", connection.read_mcstring().unwrap());
|
let message = connection.read_mcstring().unwrap();
|
||||||
|
info!("Chat Message Recieved: {message}");
|
||||||
}
|
}
|
||||||
Command::Player => {
|
Command::Player => {
|
||||||
connection.read_u8()?;
|
connection.read_u8()?;
|
||||||
},
|
},
|
||||||
Command::PlayerLook => {
|
Command::PlayerLook => {
|
||||||
let _look = PlayerLook::from_bytes(&mut connection);
|
let look = PlayerLook::from_bytes(&mut connection);
|
||||||
|
player_state.set_look(look);
|
||||||
}
|
}
|
||||||
Command::PlayerPosition => {
|
Command::PlayerPosition => {
|
||||||
let _pos = PlayerPosition::from_bytes(&mut connection);
|
let pos = PlayerPosition::from_bytes(&mut connection);
|
||||||
|
player_state.set_position(pos);
|
||||||
}
|
}
|
||||||
Command::PlayerPositionAndLook => {
|
Command::PlayerPositionAndLook => {
|
||||||
let _poslook = PlayerPositionAndLook::from_bytes(&mut connection);
|
let poslook = PlayerPositionLook::from_bytes(&mut connection);
|
||||||
|
player_state.set_look(poslook.look);
|
||||||
|
player_state.set_position(poslook.position);
|
||||||
|
}
|
||||||
|
Command::HoldingChange => {
|
||||||
|
let _unused = connection.read_i32::<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();
|
||||||
|
@ -147,12 +197,10 @@ fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<()
|
||||||
}
|
}
|
||||||
Command::PlayerBlockPlacement => {
|
Command::PlayerBlockPlacement => {
|
||||||
let _status = PlayerBlockPlacement::from_bytes(&mut connection);
|
let _status = PlayerBlockPlacement::from_bytes(&mut connection);
|
||||||
dbg!(_status);
|
|
||||||
}
|
}
|
||||||
Command::ArmAnimation => {
|
Command::Animation => {
|
||||||
let _eid = connection.read_i32::<BE>()?;
|
let _eid = connection.read_i32::<BE>()?;
|
||||||
let _animate = connection.read_u8()? != 0;
|
let _animate = connection.read_u8()?;
|
||||||
dbg!(_animate);
|
|
||||||
}
|
}
|
||||||
Command::Disconnect => {
|
Command::Disconnect => {
|
||||||
let disconnect_string = connection.read_mcstring()?;
|
let disconnect_string = connection.read_mcstring()?;
|
||||||
|
@ -160,12 +208,12 @@ fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<()
|
||||||
connection.shutdown(std::net::Shutdown::Both)?;
|
connection.shutdown(std::net::Shutdown::Both)?;
|
||||||
}
|
}
|
||||||
Command::KeepAlive => {
|
Command::KeepAlive => {
|
||||||
let _ = connection.write_u8(0x00);
|
connection.write_u8(Command::KeepAlive as u8)?;
|
||||||
}
|
}
|
||||||
Command::UpdateHealth => {
|
Command::UpdateHealth => {
|
||||||
connection.read_u8()?;
|
connection.read_u8()?;
|
||||||
}
|
}
|
||||||
c => unimplemented!("This command ({c:?}) is probably `Server -> Client` only")
|
c => unimplemented!("This command ({c:?}) is probably `Server -> Client` only; thus it is unimplemented for the other way around!")
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -190,9 +238,26 @@ enum Command {
|
||||||
PlayerPositionAndLook = 0x0D,
|
PlayerPositionAndLook = 0x0D,
|
||||||
PlayerDigging = 0x0E,
|
PlayerDigging = 0x0E,
|
||||||
PlayerBlockPlacement = 0x0F,
|
PlayerBlockPlacement = 0x0F,
|
||||||
ArmAnimation = 0x12,
|
HoldingChange = 0x10,
|
||||||
|
AddToInventory = 0x11,
|
||||||
|
Animation = 0x12,
|
||||||
|
NamedEntitySpawn = 0x14,
|
||||||
|
PickupSpawn = 0x15,
|
||||||
|
CollectItem = 0x16,
|
||||||
|
AddObject = 0x17,
|
||||||
|
MobSpawn = 0x18,
|
||||||
|
EntityVelocity = 0x1C,
|
||||||
|
DestroyEntity = 0x1D,
|
||||||
|
Entity = 0x1E,
|
||||||
|
EntityRelativeMove = 0x1F,
|
||||||
|
EntityLook = 0x20,
|
||||||
|
EntityLookAndRelativeMove = 0x21,
|
||||||
|
EntityTeleport = 0x22,
|
||||||
|
AttachEntity = 0x27,
|
||||||
PreChunk = 0x32,
|
PreChunk = 0x32,
|
||||||
MapChunk = 0x33,
|
MapChunk = 0x33,
|
||||||
|
BlockChange = 0x35,
|
||||||
|
ComplexEntities = 0x3B,
|
||||||
Disconnect = 0xFF,
|
Disconnect = 0xFF,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt, BE};
|
use byteorder::{ReadBytesExt, BE};
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,13 @@ use byteorder::{ReadBytesExt, WriteBytesExt, BE};
|
||||||
|
|
||||||
use crate::byte_ops::ToBytes;
|
use crate::byte_ops::ToBytes;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq)]
|
||||||
pub struct PlayerPositionAndLook {
|
pub struct PlayerPositionLook {
|
||||||
pub position: PlayerPosition,
|
pub position: PlayerPosition,
|
||||||
pub look: PlayerLook,
|
pub look: PlayerLook,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToBytes for PlayerPositionAndLook {
|
impl ToBytes for PlayerPositionLook {
|
||||||
type Bytes = Vec<u8>;
|
type Bytes = Vec<u8>;
|
||||||
|
|
||||||
fn to_bytes(self) -> Self::Bytes {
|
fn to_bytes(self) -> Self::Bytes {
|
||||||
|
@ -27,7 +27,7 @@ impl ToBytes for PlayerPositionAndLook {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlayerPositionAndLook {
|
impl PlayerPositionLook {
|
||||||
pub fn from_bytes<R: Read>(stream: &mut R) -> Self {
|
pub fn from_bytes<R: Read>(stream: &mut R) -> Self {
|
||||||
let position_x = stream.read_f64::<BE>().unwrap();
|
let position_x = stream.read_f64::<BE>().unwrap();
|
||||||
let position_y = stream.read_f64::<BE>().unwrap();
|
let position_y = stream.read_f64::<BE>().unwrap();
|
||||||
|
@ -54,7 +54,7 @@ impl PlayerPositionAndLook {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq)]
|
||||||
pub struct PlayerPosition {
|
pub struct PlayerPosition {
|
||||||
pub position_x: f64,
|
pub position_x: f64,
|
||||||
pub position_y: f64,
|
pub position_y: f64,
|
||||||
|
@ -95,7 +95,7 @@ impl PlayerPosition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq)]
|
||||||
pub struct PlayerLook {
|
pub struct PlayerLook {
|
||||||
pub yaw: f32,
|
pub yaw: f32,
|
||||||
pub pitch: f32,
|
pub pitch: f32,
|
||||||
|
|
81
src/state.rs
81
src/state.rs
|
@ -1,16 +1,36 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
chunk::MapChunk, position::{PlayerLook, PlayerPosition},
|
chunk::{BlockType, MapChunk},
|
||||||
|
position::{PlayerLook, PlayerPosition, PlayerPositionLook},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct GameState {
|
pub struct GameState {
|
||||||
|
player_list: BTreeMap<String, PlayerState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GameState {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
player_list: BTreeMap::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn player_list(&self) -> &BTreeMap<String, PlayerState> {
|
||||||
|
&self.player_list
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn player_list_mut(&mut self) -> &mut BTreeMap<String, PlayerState> {
|
||||||
|
&mut self.player_list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct PlayerState {
|
pub struct PlayerState {
|
||||||
eid: i32,
|
eid: i32,
|
||||||
username: String,
|
username: String,
|
||||||
position: PlayerPosition,
|
holding: i16,
|
||||||
look: PlayerLook,
|
position_look: PlayerPositionLook,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlayerState {
|
impl PlayerState {
|
||||||
|
@ -19,10 +39,59 @@ impl PlayerState {
|
||||||
Self {
|
Self {
|
||||||
eid,
|
eid,
|
||||||
username,
|
username,
|
||||||
position: PlayerPosition::default(),
|
holding: -1,
|
||||||
look: PlayerLook::default(),
|
position_look: PlayerPositionLook::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_invalid() -> Self {
|
||||||
|
Self {
|
||||||
|
eid: -1,
|
||||||
|
username: String::new(),
|
||||||
|
holding: -1,
|
||||||
|
position_look: PlayerPositionLook::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_valid(&self) -> bool {
|
||||||
|
if self.eid >= 0 && self.username != String::new() {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn username(&self) -> &String {
|
||||||
|
&self.username
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn look(&self) -> &PlayerLook {
|
||||||
|
&self.position_look.look
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn position(&self) -> &PlayerPosition {
|
||||||
|
&self.position_look.position
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn position_look(&self) -> &PlayerPositionLook {
|
||||||
|
&self.position_look
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn holding(&self) -> &BlockType {
|
||||||
|
&self.holding
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_position(&mut self, position: PlayerPosition) {
|
||||||
|
self.position_look.position = position
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_look(&mut self, look: PlayerLook) {
|
||||||
|
self.position_look.look = look
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_holding(&mut self, holding: i16) {
|
||||||
|
self.holding = holding
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WorldState {
|
pub struct WorldState {
|
||||||
|
|
Loading…
Reference in a new issue