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. "e898dfa85916e26302174b6c73eb1f006ea4bd3f" and "afd0a48527e722badeecd674f1cd1c68b4230e7d" have entirely different histories.
e898dfa859
...
afd0a48527
6 changed files with 98 additions and 203 deletions
|
@ -1,4 +0,0 @@
|
||||||
# Alpha Server
|
|
||||||
A server written in rust or something idk
|
|
||||||
|
|
||||||
Targeting Minecraft Alpha `1.2.6`, server version `0.2.8`.
|
|
94
src/chunk.rs
94
src/chunk.rs
|
@ -1,7 +1,6 @@
|
||||||
use byteorder::{WriteBytesExt, BE};
|
use byteorder::{WriteBytesExt, BE};
|
||||||
use flate2::write::ZlibEncoder;
|
use flate2::write::ZlibEncoder;
|
||||||
use flate2::Compression;
|
use flate2::Compression;
|
||||||
use num_derive::FromPrimitive;
|
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
|
||||||
use crate::byte_ops::ToBytes;
|
use crate::byte_ops::ToBytes;
|
||||||
|
@ -33,71 +32,79 @@ impl MapChunk {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct BlockArray {
|
pub struct BlockArray {
|
||||||
blocks: Vec<u8>,
|
compressed_size: i32,
|
||||||
metadata: Vec<u8>,
|
compressed_data: Vec<u8>,
|
||||||
block_light: Vec<u8>,
|
|
||||||
sky_light: Vec<u8>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const CHUNK_WIDTH_X: usize = 16;
|
|
||||||
const CHUNK_WIDTH_Z: usize = 16;
|
|
||||||
const CHUNK_HEIGHT_Y: usize = 128;
|
|
||||||
const CHUNK_TOTAL_BLOCKS: usize = CHUNK_WIDTH_X * CHUNK_WIDTH_Z * CHUNK_HEIGHT_Y;
|
|
||||||
|
|
||||||
impl BlockArray {
|
impl BlockArray {
|
||||||
fn compress(self) -> Vec<u8> {
|
pub fn new_air() -> Self {
|
||||||
|
let mut block_vec = Vec::new();
|
||||||
|
|
||||||
|
for _ in 0..(16 * 127 * 15) {
|
||||||
|
block_vec.push(0);
|
||||||
|
}
|
||||||
|
for _ in 0..(16 * 127 * 15) / 2 {
|
||||||
|
block_vec.push(0);
|
||||||
|
}
|
||||||
|
for _ in 0..(16 * 127 * 15) / 2 {
|
||||||
|
block_vec.push(0);
|
||||||
|
}
|
||||||
|
for _ in 0..(16 * 127 * 15) / 2 {
|
||||||
|
block_vec.push(0);
|
||||||
|
}
|
||||||
|
|
||||||
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(&block_vec).unwrap();
|
||||||
encoder.write(&self.metadata).unwrap();
|
|
||||||
encoder.write(&self.block_light).unwrap();
|
|
||||||
encoder.write(&self.sky_light).unwrap();
|
|
||||||
let output_buf = encoder.finish().unwrap();
|
let output_buf = encoder.finish().unwrap();
|
||||||
|
|
||||||
output_buf
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_air() -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
blocks: vec![0; CHUNK_TOTAL_BLOCKS],
|
compressed_size: output_buf.len() as i32,
|
||||||
metadata: vec![0; CHUNK_TOTAL_BLOCKS / 2],
|
compressed_data: output_buf,
|
||||||
block_light: vec![0; CHUNK_TOTAL_BLOCKS / 2],
|
|
||||||
sky_light: vec![0xFF; CHUNK_TOTAL_BLOCKS / 2],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_superflat() -> Self {
|
pub fn new_superflat() -> Self {
|
||||||
let mut blocks = vec![0; CHUNK_TOTAL_BLOCKS];
|
let mut block_vec = vec![0; 16 * 16 * 128];
|
||||||
for y in 0..CHUNK_HEIGHT_Y {
|
|
||||||
for x in 0..CHUNK_WIDTH_X {
|
for x in 0..16 {
|
||||||
for z in 0..CHUNK_WIDTH_Z {
|
for y in 0..128 {
|
||||||
let pos = y + (z * (CHUNK_HEIGHT_Y)) + (x * (CHUNK_HEIGHT_Y) * (CHUNK_WIDTH_X));
|
for z in 0..16 {
|
||||||
|
let pos = y + (z * (128)) + (x * (128) * (16));
|
||||||
if y == 7 {
|
if y == 7 {
|
||||||
blocks[pos] = BlockType::Grass as u8;
|
block_vec[pos] = BlockType::Grass as u8;
|
||||||
} else if y > 0 && y < 7 {
|
} else if y > 0 && y < 7 {
|
||||||
blocks[pos] = BlockType::Dirt as u8;
|
block_vec[pos] = BlockType::Dirt as u8;
|
||||||
} else if y == 0 {
|
} else if y == 0 {
|
||||||
blocks[pos] = BlockType::Bedrock as u8;
|
block_vec[pos] = BlockType::Bedrock as u8;
|
||||||
} else {
|
} else {
|
||||||
blocks[pos] = BlockType::Air as u8;
|
block_vec[pos] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _ in 0..(16 * 128 * 16) / 2 {
|
||||||
|
block_vec.push(0);
|
||||||
|
}
|
||||||
|
for _ in 0..(16 * 128 * 16) / 2 {
|
||||||
|
block_vec.push(0);
|
||||||
|
}
|
||||||
|
for _ in 0..(16 * 128 * 16) / 2 {
|
||||||
|
block_vec.push(0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
|
||||||
|
encoder.write(&block_vec).unwrap();
|
||||||
|
let output_buf = encoder.finish().unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
blocks,
|
compressed_size: output_buf.len() as i32,
|
||||||
metadata: vec![0xFF; CHUNK_TOTAL_BLOCKS / 2],
|
compressed_data: output_buf,
|
||||||
block_light: vec![0; CHUNK_TOTAL_BLOCKS / 2],
|
|
||||||
sky_light: vec![0xFF; CHUNK_TOTAL_BLOCKS / 2],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(i16)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
enum BlockType {
|
||||||
#[derive(FromPrimitive)]
|
|
||||||
pub enum BlockType {
|
|
||||||
None = -1,
|
|
||||||
Air,
|
Air,
|
||||||
Stone,
|
Stone,
|
||||||
Grass,
|
Grass,
|
||||||
|
@ -120,9 +127,8 @@ impl ToBytes for MapChunk {
|
||||||
buffer.write_u8(self.size_y).unwrap();
|
buffer.write_u8(self.size_y).unwrap();
|
||||||
buffer.write_u8(self.size_z).unwrap();
|
buffer.write_u8(self.size_z).unwrap();
|
||||||
|
|
||||||
let block_buf = self.compressed_data.compress();
|
buffer.write_i32::<BE>(self.compressed_data.compressed_size).unwrap();
|
||||||
buffer.write_i32::<BE>(block_buf.len() as i32).unwrap();
|
buffer.write_all(&self.compressed_data.compressed_data).unwrap();
|
||||||
buffer.write_all(&block_buf).unwrap();
|
|
||||||
|
|
||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
|
|
101
src/main.rs
101
src/main.rs
|
@ -2,10 +2,8 @@ mod utils;
|
||||||
mod byte_ops;
|
mod byte_ops;
|
||||||
mod chunk;
|
mod chunk;
|
||||||
mod position;
|
mod position;
|
||||||
mod state;
|
|
||||||
mod player;
|
|
||||||
|
|
||||||
use std::{io::{self, Write}, net::{TcpListener, TcpStream}, sync::RwLock};
|
use std::{cell::LazyCell, io::{self, Write}, net::{TcpListener, TcpStream}};
|
||||||
|
|
||||||
use base16ct::lower::encode_string;
|
use base16ct::lower::encode_string;
|
||||||
use chunk::{BlockArray, MapChunk, PreChunk};
|
use chunk::{BlockArray, MapChunk, PreChunk};
|
||||||
|
@ -14,24 +12,23 @@ 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 position::{PlayerLook, PlayerPosition, PlayerPositionAndLook};
|
use position::{PlayerLook, PlayerPosition, PlayerPositionAndLook};
|
||||||
use state::PlayerState;
|
|
||||||
use utils::{MCString, ReadMCString, WriteMCString};
|
use utils::{MCString, ReadMCString, WriteMCString};
|
||||||
use rand::random;
|
use rand::random;
|
||||||
|
|
||||||
/// List of players.
|
const CHUNKS: LazyCell<Vec<MapChunk>> = LazyCell::new(|| {
|
||||||
const PLAYER_LIST: RwLock<Vec<PlayerState>> = RwLock::new(Vec::new());
|
let mut mapchunk = Vec::new();
|
||||||
|
for i in -10..10 {
|
||||||
|
for o in -10..10 {
|
||||||
|
let x = i * 16;
|
||||||
|
let z = o * 16;
|
||||||
|
|
||||||
/// The current Entity ID. Incremented by one every time there is a new entity.
|
mapchunk.push(MapChunk::new(x, z, BlockArray::new_superflat()));
|
||||||
const ENTITY_ID: RwLock<i32> = RwLock::new(0);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_eid() -> i32 {
|
mapchunk
|
||||||
let eid = ENTITY_ID.read().unwrap().clone();
|
});
|
||||||
*ENTITY_ID.write().unwrap() += 1;
|
|
||||||
|
|
||||||
eid
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
colog::default_builder()
|
colog::default_builder()
|
||||||
|
@ -39,15 +36,13 @@ fn main() {
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
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());
|
|
||||||
|
|
||||||
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!("Connected to client @ {}", connection.peer_addr().unwrap());
|
||||||
while let Some(cmd) = connection.read_u8().ok() {
|
while let Some(cmd) = connection.read_u8().ok() {
|
||||||
let command = Command::from_u8(cmd);
|
let command = Command::from_u8(cmd);
|
||||||
if command.is_none() {
|
if command.is_none() {
|
||||||
info!("COMMAND: {command:?} (0x{cmd:02X?})");
|
info!("COMMAND: {command:?} (0x{cmd:02X?})");
|
||||||
panic!("This command isn't implemented yet");
|
|
||||||
}
|
}
|
||||||
handle_command(&mut connection, command.unwrap()).unwrap();
|
handle_command(&mut connection, command.unwrap()).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -62,22 +57,27 @@ fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<()
|
||||||
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());
|
||||||
|
|
||||||
|
info!("Handshake with {username} successful. Providing hash: {random_hash:?}");
|
||||||
|
|
||||||
connection.write_u8(0x02)?;
|
connection.write_u8(0x02)?;
|
||||||
connection.write_mcstring(&MCString::try_from(random_hash).unwrap())?;
|
connection.write_mcstring(&MCString::try_from(random_hash).unwrap())?;
|
||||||
|
|
||||||
info!("Handshake with {username} successful");
|
|
||||||
},
|
},
|
||||||
Command::Login => {
|
Command::Login => {
|
||||||
|
info!("Initiating login");
|
||||||
let protocol_version = connection.read_u32::<BE>()?;
|
let protocol_version = connection.read_u32::<BE>()?;
|
||||||
let username = connection.read_mcstring()?;
|
let username = connection.read_mcstring()?;
|
||||||
// These are mostly useless
|
let password = connection.read_mcstring()?;
|
||||||
let _password = connection.read_mcstring()?;
|
let map_seed = connection.read_i64::<BE>()?;
|
||||||
let _map_seed = connection.read_i64::<BE>()?;
|
let dimension = connection.read_i8()?;
|
||||||
let _dimension = connection.read_i8()?;
|
|
||||||
|
info!("Protocol Version: {protocol_version}");
|
||||||
|
info!("Username: {username}");
|
||||||
|
info!("Password: {password}");
|
||||||
|
info!("Map Seed: {map_seed}");
|
||||||
|
info!("Dimension: {dimension}");
|
||||||
|
|
||||||
let eid = get_eid();
|
|
||||||
let login_packet = ServerLoginPacket {
|
let login_packet = ServerLoginPacket {
|
||||||
entity_id: eid,
|
entity_id: 1,
|
||||||
unknown1: MCString::default(),
|
unknown1: MCString::default(),
|
||||||
unknown2: MCString::default(),
|
unknown2: MCString::default(),
|
||||||
map_seed: 0,
|
map_seed: 0,
|
||||||
|
@ -86,9 +86,7 @@ fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<()
|
||||||
connection.write_u8(Command::Login as u8).unwrap();
|
connection.write_u8(Command::Login as u8).unwrap();
|
||||||
connection.write(&login_packet.to_bytes())?;
|
connection.write(&login_packet.to_bytes())?;
|
||||||
|
|
||||||
PLAYER_LIST.write().unwrap().push(PlayerState::new(username.to_string(), eid));
|
info!("Responded to auth request");
|
||||||
|
|
||||||
info!("{username} logged in. Protocol version {protocol_version}");
|
|
||||||
|
|
||||||
for i in -10..10 {
|
for i in -10..10 {
|
||||||
for o in -10..10 {
|
for o in -10..10 {
|
||||||
|
@ -139,28 +137,24 @@ fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<()
|
||||||
let _poslook = PlayerPositionAndLook::from_bytes(&mut connection);
|
let _poslook = PlayerPositionAndLook::from_bytes(&mut connection);
|
||||||
}
|
}
|
||||||
Command::PlayerDigging => {
|
Command::PlayerDigging => {
|
||||||
let _status = DiggingStatus::from_u8(connection.read_u8()?).unwrap();
|
let status = DiggingStatus::from_u8(connection.read_u8()?).unwrap();
|
||||||
let _pos_x = connection.read_i32::<BE>()?;
|
let pos_x = connection.read_i32::<BE>()?;
|
||||||
let _pos_y = connection.read_u8()?;
|
let pos_y = connection.read_u8()?;
|
||||||
let _pos_z = connection.read_i32::<BE>()?;
|
let pos_z = connection.read_i32::<BE>()?;
|
||||||
let _face = connection.read_u8()?;
|
let face = connection.read_u8()?;
|
||||||
}
|
|
||||||
Command::PlayerBlockPlacement => {
|
|
||||||
let _status = PlayerBlockPlacement::from_bytes(&mut connection);
|
|
||||||
dbg!(_status);
|
|
||||||
}
|
}
|
||||||
Command::ArmAnimation => {
|
Command::ArmAnimation => {
|
||||||
let _eid = connection.read_i32::<BE>()?;
|
let eid = connection.read_i32::<BE>()?;
|
||||||
let _animate = connection.read_u8()? != 0;
|
let animate = connection.read_u8()? != 0;
|
||||||
dbg!(_animate);
|
|
||||||
}
|
}
|
||||||
Command::Disconnect => {
|
Command::Disconnect => {
|
||||||
let disconnect_string = connection.read_mcstring()?;
|
let disconnect_string = connection.read_mcstring()?;
|
||||||
info!("Disconnecting client. Reason: {disconnect_string}");
|
info!("Disconnecting client: {disconnect_string}");
|
||||||
connection.shutdown(std::net::Shutdown::Both)?;
|
connection.shutdown(std::net::Shutdown::Both)?;
|
||||||
}
|
}
|
||||||
Command::KeepAlive => {
|
Command::KeepAlive => {
|
||||||
let _ = connection.write_u8(0x00);
|
let _ = connection.write_u8(0x00);
|
||||||
|
// TODO: Feed keepalive watchdog for client
|
||||||
}
|
}
|
||||||
Command::UpdateHealth => {
|
Command::UpdateHealth => {
|
||||||
connection.read_u8()?;
|
connection.read_u8()?;
|
||||||
|
@ -171,6 +165,16 @@ fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<()
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[derive(FromPrimitive)]
|
||||||
|
enum DiggingStatus {
|
||||||
|
StartedDigging = 0,
|
||||||
|
Digging = 1,
|
||||||
|
StoppedDigging = 2,
|
||||||
|
BlockBroken = 3,
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[derive(FromPrimitive)]
|
#[derive(FromPrimitive)]
|
||||||
|
@ -189,7 +193,6 @@ enum Command {
|
||||||
PlayerLook = 0x0C,
|
PlayerLook = 0x0C,
|
||||||
PlayerPositionAndLook = 0x0D,
|
PlayerPositionAndLook = 0x0D,
|
||||||
PlayerDigging = 0x0E,
|
PlayerDigging = 0x0E,
|
||||||
PlayerBlockPlacement = 0x0F,
|
|
||||||
ArmAnimation = 0x12,
|
ArmAnimation = 0x12,
|
||||||
PreChunk = 0x32,
|
PreChunk = 0x32,
|
||||||
MapChunk = 0x33,
|
MapChunk = 0x33,
|
||||||
|
@ -204,18 +207,6 @@ struct ServerLoginPacket {
|
||||||
dimension: i8,
|
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 {
|
impl ToBytes for ServerLoginPacket {
|
||||||
type Bytes = Vec<u8>;
|
type Bytes = Vec<u8>;
|
||||||
|
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
use std::io::Read;
|
|
||||||
|
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt, BE};
|
|
||||||
use num_derive::FromPrimitive;
|
|
||||||
use num_traits::FromPrimitive;
|
|
||||||
|
|
||||||
use crate::chunk::BlockType;
|
|
||||||
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
#[derive(FromPrimitive)]
|
|
||||||
pub enum DiggingStatus {
|
|
||||||
StartedDigging = 0,
|
|
||||||
Digging = 1,
|
|
||||||
StoppedDigging = 2,
|
|
||||||
BlockBroken = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The face of a block, a direction.
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
#[derive(FromPrimitive)]
|
|
||||||
pub enum Direction {
|
|
||||||
NegY = 0,
|
|
||||||
PosY = 1,
|
|
||||||
NegZ = 2,
|
|
||||||
PosZ = 3,
|
|
||||||
NegX = 4,
|
|
||||||
PosX = 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct PlayerDigging {
|
|
||||||
status: DiggingStatus,
|
|
||||||
position_x: i32,
|
|
||||||
position_y: u8,
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -54,7 +54,7 @@ impl PlayerPositionAndLook {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
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, Clone, Copy)]
|
||||||
pub struct PlayerLook {
|
pub struct PlayerLook {
|
||||||
pub yaw: f32,
|
pub yaw: f32,
|
||||||
pub pitch: f32,
|
pub pitch: f32,
|
||||||
|
|
30
src/state.rs
30
src/state.rs
|
@ -1,30 +0,0 @@
|
||||||
use crate::{
|
|
||||||
chunk::MapChunk, position::{PlayerLook, PlayerPosition},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct GameState {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PlayerState {
|
|
||||||
eid: i32,
|
|
||||||
username: String,
|
|
||||||
position: PlayerPosition,
|
|
||||||
look: PlayerLook,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PlayerState {
|
|
||||||
/// Create a new player when they join
|
|
||||||
pub fn new(username: String, eid: i32,) -> Self {
|
|
||||||
Self {
|
|
||||||
eid,
|
|
||||||
username,
|
|
||||||
position: PlayerPosition::default(),
|
|
||||||
look: PlayerLook::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WorldState {
|
|
||||||
chunks: Vec<MapChunk>,
|
|
||||||
}
|
|
Loading…
Reference in a new issue