mirror of
https://github.com/italicsjenga/valence.git
synced 2025-01-11 07:11:30 +11:00
Reorganize modules
This commit is contained in:
parent
34d831f5fd
commit
efc2873908
118
src/biome.rs
Normal file
118
src/biome.rs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
use crate::{ident, Ident};
|
||||||
|
|
||||||
|
/// Identifies a particular [`Biome`].
|
||||||
|
///
|
||||||
|
/// Biome IDs are always valid and are cheap to copy and store.
|
||||||
|
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
|
pub struct BiomeId(pub(crate) u16);
|
||||||
|
|
||||||
|
impl BiomeId {
|
||||||
|
pub fn to_index(self) -> usize {
|
||||||
|
self.0 as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains the configuration for a biome.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Biome {
|
||||||
|
/// The unique name for this biome. The name can be
|
||||||
|
/// seen in the F3 debug menu.
|
||||||
|
pub name: Ident,
|
||||||
|
pub precipitation: BiomePrecipitation,
|
||||||
|
pub sky_color: u32,
|
||||||
|
pub water_fog_color: u32,
|
||||||
|
pub fog_color: u32,
|
||||||
|
pub water_color: u32,
|
||||||
|
pub foliage_color: Option<u32>,
|
||||||
|
pub grass_color_modifier: BiomeGrassColorModifier,
|
||||||
|
pub music: Option<BiomeMusic>,
|
||||||
|
pub ambient_sound: Option<Ident>,
|
||||||
|
pub additions_sound: Option<BiomeAdditionsSound>,
|
||||||
|
pub mood_sound: Option<BiomeMoodSound>,
|
||||||
|
pub particle: Option<BiomeParticle>,
|
||||||
|
// TODO: The following fields should be added if they can affect the appearance of the biome to
|
||||||
|
// clients.
|
||||||
|
// * depth: f32
|
||||||
|
// * temperature: f32
|
||||||
|
// * scale: f32
|
||||||
|
// * downfall: f32
|
||||||
|
// * category
|
||||||
|
// * temperature_modifier
|
||||||
|
// * grass_color (misleading name?)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Biome {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
name: ident!("plains"),
|
||||||
|
precipitation: BiomePrecipitation::Rain,
|
||||||
|
sky_color: 7907327,
|
||||||
|
water_fog_color: 329011,
|
||||||
|
fog_color: 12638463,
|
||||||
|
water_color: 4159204,
|
||||||
|
foliage_color: None,
|
||||||
|
grass_color_modifier: BiomeGrassColorModifier::None,
|
||||||
|
music: None,
|
||||||
|
ambient_sound: None,
|
||||||
|
additions_sound: None,
|
||||||
|
mood_sound: None,
|
||||||
|
particle: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum BiomePrecipitation {
|
||||||
|
Rain,
|
||||||
|
Snow,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BiomePrecipitation {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Rain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Minecraft handles grass colors for swamps and dark oak forests in a special
|
||||||
|
/// way.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum BiomeGrassColorModifier {
|
||||||
|
Swamp,
|
||||||
|
DarkForest,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BiomeGrassColorModifier {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct BiomeMusic {
|
||||||
|
pub replace_current_music: bool,
|
||||||
|
pub sound: Ident,
|
||||||
|
pub min_delay: i32,
|
||||||
|
pub max_delay: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct BiomeAdditionsSound {
|
||||||
|
pub sound: Ident,
|
||||||
|
pub tick_chance: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct BiomeMoodSound {
|
||||||
|
pub sound: Ident,
|
||||||
|
pub tick_delay: i32,
|
||||||
|
pub offset: f64,
|
||||||
|
pub block_search_extent: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct BiomeParticle {
|
||||||
|
pub probability: f32,
|
||||||
|
pub typ: Ident,
|
||||||
|
}
|
|
@ -11,9 +11,9 @@ impl ByteAngle {
|
||||||
ByteAngle((f.rem_euclid(360.0) / 360.0 * 256.0).round() as u8)
|
ByteAngle((f.rem_euclid(360.0) / 360.0 * 256.0).round() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_degrees(self) -> f32 {
|
// pub fn to_degrees(self) -> f32 {
|
||||||
self.0 as f32 / 256.0 * 360.0
|
// self.0 as f32 / 256.0 * 360.0
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for ByteAngle {
|
impl Encode for ByteAngle {
|
||||||
|
|
|
@ -8,11 +8,10 @@ use std::ops::Deref;
|
||||||
use bitvec::vec::BitVec;
|
use bitvec::vec::BitVec;
|
||||||
use num::Integer;
|
use num::Integer;
|
||||||
use rayon::iter::{IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator};
|
||||||
use vek::Vec2;
|
|
||||||
|
|
||||||
use crate::block::BlockState;
|
use crate::block::BlockState;
|
||||||
use crate::packets::play::{
|
use crate::packets::play::s2c::{
|
||||||
BlockChange, ChunkDataAndUpdateLight, ChunkDataHeightmaps, ClientPlayPacket, MultiBlockChange,
|
BlockChange, ChunkDataAndUpdateLight, ChunkDataHeightmaps, MultiBlockChange, S2cPlayPacket,
|
||||||
};
|
};
|
||||||
use crate::protocol::{Encode, Nbt};
|
use crate::protocol::{Encode, Nbt};
|
||||||
use crate::var_int::VarInt;
|
use crate::var_int::VarInt;
|
||||||
|
@ -269,7 +268,7 @@ pub(crate) enum BlockChangePacket {
|
||||||
Multi(MultiBlockChange),
|
Multi(MultiBlockChange),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BlockChangePacket> for ClientPlayPacket {
|
impl From<BlockChangePacket> for S2cPlayPacket {
|
||||||
fn from(p: BlockChangePacket) -> Self {
|
fn from(p: BlockChangePacket) -> Self {
|
||||||
match p {
|
match p {
|
||||||
BlockChangePacket::Single(p) => p.into(),
|
BlockChangePacket::Single(p) => p.into(),
|
||||||
|
|
128
src/client.rs
128
src/client.rs
|
@ -7,24 +7,24 @@ use rayon::iter::ParallelIterator;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use vek::Vec3;
|
use vek::Vec3;
|
||||||
|
|
||||||
|
use crate::biome::{Biome, BiomeGrassColorModifier, BiomePrecipitation};
|
||||||
use crate::block_pos::BlockPos;
|
use crate::block_pos::BlockPos;
|
||||||
use crate::byte_angle::ByteAngle;
|
use crate::byte_angle::ByteAngle;
|
||||||
use crate::config::{
|
use crate::dimension::{Dimension, DimensionEffects};
|
||||||
Biome, BiomeGrassColorModifier, BiomePrecipitation, Dimension, DimensionEffects, DimensionId,
|
|
||||||
};
|
|
||||||
use crate::entity::{velocity_to_packet_units, EntityType};
|
use crate::entity::{velocity_to_packet_units, EntityType};
|
||||||
pub use crate::packets::play::GameMode;
|
use crate::packets::play::c2s::C2sPlayPacket;
|
||||||
use crate::packets::play::{
|
pub use crate::packets::play::s2c::GameMode;
|
||||||
|
use crate::packets::play::s2c::{
|
||||||
Biome as BiomeRegistryBiome, BiomeAdditionsSound, BiomeEffects, BiomeMoodSound, BiomeMusic,
|
Biome as BiomeRegistryBiome, BiomeAdditionsSound, BiomeEffects, BiomeMoodSound, BiomeMusic,
|
||||||
BiomeParticle, BiomeParticleOptions, BiomeProperty, BiomeRegistry, ChangeGameState,
|
BiomeParticle, BiomeParticleOptions, BiomeProperty, BiomeRegistry, ChangeGameState,
|
||||||
ChangeGameStateReason, ClientPlayPacket, DestroyEntities, DimensionCodec, DimensionType,
|
ChangeGameStateReason, DestroyEntities, DimensionCodec, DimensionType, DimensionTypeRegistry,
|
||||||
DimensionTypeRegistry, DimensionTypeRegistryEntry, Disconnect, EntityHeadLook, EntityPosition,
|
DimensionTypeRegistryEntry, Disconnect, EntityHeadLook, EntityPosition,
|
||||||
EntityPositionAndRotation, EntityRotation, EntityTeleport, EntityVelocity, JoinGame,
|
EntityPositionAndRotation, EntityRotation, EntityTeleport, EntityVelocity, JoinGame,
|
||||||
KeepAliveClientbound, PlayerPositionAndLook, PlayerPositionAndLookFlags, ServerPlayPacket,
|
KeepAliveClientbound, PlayerPositionAndLook, PlayerPositionAndLookFlags, S2cPlayPacket,
|
||||||
SpawnPosition, UnloadChunk, UpdateViewDistance, UpdateViewPosition,
|
SpawnPosition, UnloadChunk, UpdateViewDistance, UpdateViewPosition,
|
||||||
};
|
};
|
||||||
use crate::protocol::{BoundedInt, Nbt};
|
use crate::protocol::{BoundedInt, Nbt};
|
||||||
use crate::server::ServerPacketChannels;
|
use crate::server::C2sPacketChannels;
|
||||||
use crate::slotmap::{Key, SlotMap};
|
use crate::slotmap::{Key, SlotMap};
|
||||||
use crate::util::{chunks_in_view_distance, is_chunk_in_view_distance};
|
use crate::util::{chunks_in_view_distance, is_chunk_in_view_distance};
|
||||||
use crate::var_int::VarInt;
|
use crate::var_int::VarInt;
|
||||||
|
@ -113,8 +113,8 @@ pub struct ClientId(Key);
|
||||||
/// Represents a client connected to the server after logging in.
|
/// Represents a client connected to the server after logging in.
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
/// Setting this to `None` disconnects the client.
|
/// Setting this to `None` disconnects the client.
|
||||||
send: Option<Sender<ClientPlayPacket>>,
|
send: Option<Sender<S2cPlayPacket>>,
|
||||||
recv: Receiver<ServerPlayPacket>,
|
recv: Receiver<C2sPlayPacket>,
|
||||||
/// The tick this client was created.
|
/// The tick this client was created.
|
||||||
created_tick: Ticks,
|
created_tick: Ticks,
|
||||||
username: String,
|
username: String,
|
||||||
|
@ -170,7 +170,7 @@ impl<'a> Deref for ClientMut<'a> {
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
packet_channels: ServerPacketChannels,
|
packet_channels: C2sPacketChannels,
|
||||||
username: String,
|
username: String,
|
||||||
uuid: Uuid,
|
uuid: Uuid,
|
||||||
server: &Server,
|
server: &Server,
|
||||||
|
@ -301,7 +301,7 @@ impl<'a> ClientMut<'a> {
|
||||||
|
|
||||||
/// Attempts to enqueue a play packet to be sent to this client. The client
|
/// Attempts to enqueue a play packet to be sent to this client. The client
|
||||||
/// is disconnected if the clientbound packet buffer is full.
|
/// is disconnected if the clientbound packet buffer is full.
|
||||||
pub(crate) fn send_packet(&mut self, packet: impl Into<ClientPlayPacket>) {
|
pub(crate) fn send_packet(&mut self, packet: impl Into<S2cPlayPacket>) {
|
||||||
send_packet(&mut self.0.send, packet);
|
send_packet(&mut self.0.send, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,7 +630,7 @@ impl<'a> ClientMut<'a> {
|
||||||
self.0.old_position = self.0.new_position;
|
self.0.old_position = self.0.new_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_serverbound_packet(&mut self, pkt: ServerPlayPacket) {
|
fn handle_serverbound_packet(&mut self, pkt: C2sPlayPacket) {
|
||||||
let client = &mut self.0;
|
let client = &mut self.0;
|
||||||
|
|
||||||
fn handle_movement_packet(
|
fn handle_movement_packet(
|
||||||
|
@ -658,7 +658,7 @@ impl<'a> ClientMut<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match pkt {
|
match pkt {
|
||||||
ServerPlayPacket::TeleportConfirm(p) => {
|
C2sPlayPacket::TeleportConfirm(p) => {
|
||||||
if client.pending_teleports == 0 {
|
if client.pending_teleports == 0 {
|
||||||
self.disconnect("Unexpected teleport confirmation");
|
self.disconnect("Unexpected teleport confirmation");
|
||||||
return;
|
return;
|
||||||
|
@ -677,11 +677,11 @@ impl<'a> ClientMut<'a> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ServerPlayPacket::QueryBlockNbt(_) => {}
|
C2sPlayPacket::QueryBlockNbt(_) => {}
|
||||||
ServerPlayPacket::SetDifficulty(_) => {}
|
C2sPlayPacket::SetDifficulty(_) => {}
|
||||||
ServerPlayPacket::ChatMessageServerbound(_) => {}
|
C2sPlayPacket::ChatMessageServerbound(_) => {}
|
||||||
ServerPlayPacket::ClientStatus(_) => {}
|
C2sPlayPacket::ClientStatus(_) => {}
|
||||||
ServerPlayPacket::ClientSettings(p) => {
|
C2sPlayPacket::ClientSettings(p) => {
|
||||||
let old = client.settings.replace(Settings {
|
let old = client.settings.replace(Settings {
|
||||||
locale: p.locale.0,
|
locale: p.locale.0,
|
||||||
view_distance: p.view_distance.0,
|
view_distance: p.view_distance.0,
|
||||||
|
@ -694,16 +694,16 @@ impl<'a> ClientMut<'a> {
|
||||||
|
|
||||||
client.events.push(Event::SettingsChanged(old));
|
client.events.push(Event::SettingsChanged(old));
|
||||||
}
|
}
|
||||||
ServerPlayPacket::TabCompleteServerbound(_) => {}
|
C2sPlayPacket::TabCompleteServerbound(_) => {}
|
||||||
ServerPlayPacket::ClickWindowButton(_) => {}
|
C2sPlayPacket::ClickWindowButton(_) => {}
|
||||||
ServerPlayPacket::ClickWindow(_) => {}
|
C2sPlayPacket::ClickWindow(_) => {}
|
||||||
ServerPlayPacket::CloseWindow(_) => {}
|
C2sPlayPacket::CloseWindow(_) => {}
|
||||||
ServerPlayPacket::PluginMessageServerbound(_) => {}
|
C2sPlayPacket::PluginMessageServerbound(_) => {}
|
||||||
ServerPlayPacket::EditBook(_) => {}
|
C2sPlayPacket::EditBook(_) => {}
|
||||||
ServerPlayPacket::QueryEntityNbt(_) => {}
|
C2sPlayPacket::QueryEntityNbt(_) => {}
|
||||||
ServerPlayPacket::InteractEntity(_) => {}
|
C2sPlayPacket::InteractEntity(_) => {}
|
||||||
ServerPlayPacket::GenerateStructure(_) => {}
|
C2sPlayPacket::GenerateStructure(_) => {}
|
||||||
ServerPlayPacket::KeepAliveServerbound(p) => {
|
C2sPlayPacket::KeepAliveServerbound(p) => {
|
||||||
let last_keepalive_id = client.last_keepalive_id;
|
let last_keepalive_id = client.last_keepalive_id;
|
||||||
if client.got_keepalive {
|
if client.got_keepalive {
|
||||||
self.disconnect("Unexpected keepalive");
|
self.disconnect("Unexpected keepalive");
|
||||||
|
@ -716,51 +716,51 @@ impl<'a> ClientMut<'a> {
|
||||||
client.got_keepalive = true;
|
client.got_keepalive = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ServerPlayPacket::LockDifficulty(_) => {}
|
C2sPlayPacket::LockDifficulty(_) => {}
|
||||||
ServerPlayPacket::PlayerPosition(p) => {
|
C2sPlayPacket::PlayerPosition(p) => {
|
||||||
handle_movement_packet(client, p.position, client.yaw, client.pitch, p.on_ground)
|
handle_movement_packet(client, p.position, client.yaw, client.pitch, p.on_ground)
|
||||||
}
|
}
|
||||||
ServerPlayPacket::PlayerPositionAndRotation(p) => {
|
C2sPlayPacket::PlayerPositionAndRotation(p) => {
|
||||||
handle_movement_packet(client, p.position, p.yaw, p.pitch, p.on_ground)
|
handle_movement_packet(client, p.position, p.yaw, p.pitch, p.on_ground)
|
||||||
}
|
}
|
||||||
ServerPlayPacket::PlayerRotation(p) => {
|
C2sPlayPacket::PlayerRotation(p) => {
|
||||||
handle_movement_packet(client, client.new_position, p.yaw, p.pitch, p.on_ground)
|
handle_movement_packet(client, client.new_position, p.yaw, p.pitch, p.on_ground)
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerPlayPacket::PlayerMovement(p) => handle_movement_packet(
|
C2sPlayPacket::PlayerMovement(p) => handle_movement_packet(
|
||||||
client,
|
client,
|
||||||
client.new_position,
|
client.new_position,
|
||||||
client.yaw,
|
client.yaw,
|
||||||
client.pitch,
|
client.pitch,
|
||||||
p.on_ground,
|
p.on_ground,
|
||||||
),
|
),
|
||||||
ServerPlayPacket::VehicleMoveServerbound(_) => {}
|
C2sPlayPacket::VehicleMoveServerbound(_) => {}
|
||||||
ServerPlayPacket::SteerBoat(_) => {}
|
C2sPlayPacket::SteerBoat(_) => {}
|
||||||
ServerPlayPacket::PickItem(_) => {}
|
C2sPlayPacket::PickItem(_) => {}
|
||||||
ServerPlayPacket::CraftRecipeRequest(_) => {}
|
C2sPlayPacket::CraftRecipeRequest(_) => {}
|
||||||
ServerPlayPacket::PlayerAbilitiesServerbound(_) => {}
|
C2sPlayPacket::PlayerAbilitiesServerbound(_) => {}
|
||||||
ServerPlayPacket::PlayerDigging(_) => {}
|
C2sPlayPacket::PlayerDigging(_) => {}
|
||||||
ServerPlayPacket::EntityAction(_) => {}
|
C2sPlayPacket::EntityAction(_) => {}
|
||||||
ServerPlayPacket::SteerVehicle(_) => {}
|
C2sPlayPacket::SteerVehicle(_) => {}
|
||||||
ServerPlayPacket::Pong(_) => {}
|
C2sPlayPacket::Pong(_) => {}
|
||||||
ServerPlayPacket::SetRecipeBookState(_) => {}
|
C2sPlayPacket::SetRecipeBookState(_) => {}
|
||||||
ServerPlayPacket::SetDisplayedRecipe(_) => {}
|
C2sPlayPacket::SetDisplayedRecipe(_) => {}
|
||||||
ServerPlayPacket::NameItem(_) => {}
|
C2sPlayPacket::NameItem(_) => {}
|
||||||
ServerPlayPacket::ResourcePackStatus(_) => {}
|
C2sPlayPacket::ResourcePackStatus(_) => {}
|
||||||
ServerPlayPacket::AdvancementTab(_) => {}
|
C2sPlayPacket::AdvancementTab(_) => {}
|
||||||
ServerPlayPacket::SelectTrade(_) => {}
|
C2sPlayPacket::SelectTrade(_) => {}
|
||||||
ServerPlayPacket::SetBeaconEffect(_) => {}
|
C2sPlayPacket::SetBeaconEffect(_) => {}
|
||||||
ServerPlayPacket::HeldItemChangeServerbound(_) => {}
|
C2sPlayPacket::HeldItemChangeServerbound(_) => {}
|
||||||
ServerPlayPacket::UpdateCommandBlock(_) => {}
|
C2sPlayPacket::UpdateCommandBlock(_) => {}
|
||||||
ServerPlayPacket::UpdateCommandBlockMinecart(_) => {}
|
C2sPlayPacket::UpdateCommandBlockMinecart(_) => {}
|
||||||
ServerPlayPacket::CreativeInventoryAction(_) => {}
|
C2sPlayPacket::CreativeInventoryAction(_) => {}
|
||||||
ServerPlayPacket::UpdateJigsawBlock(_) => {}
|
C2sPlayPacket::UpdateJigsawBlock(_) => {}
|
||||||
ServerPlayPacket::UpdateStructureBlock(_) => {}
|
C2sPlayPacket::UpdateStructureBlock(_) => {}
|
||||||
ServerPlayPacket::UpdateSign(_) => {}
|
C2sPlayPacket::UpdateSign(_) => {}
|
||||||
ServerPlayPacket::PlayerArmSwing(_) => {}
|
C2sPlayPacket::PlayerArmSwing(_) => {}
|
||||||
ServerPlayPacket::Spectate(_) => {}
|
C2sPlayPacket::Spectate(_) => {}
|
||||||
ServerPlayPacket::PlayerBlockPlacement(_) => {}
|
C2sPlayPacket::PlayerBlockPlacement(_) => {}
|
||||||
ServerPlayPacket::UseItem(_) => {}
|
C2sPlayPacket::UseItem(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -803,9 +803,9 @@ pub struct Settings {
|
||||||
pub allow_server_listings: bool,
|
pub allow_server_listings: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use crate::packets::play::{ChatMode, DisplayedSkinParts, MainHand};
|
pub use crate::packets::play::c2s::{ChatMode, DisplayedSkinParts, MainHand};
|
||||||
|
|
||||||
fn send_packet(send_opt: &mut Option<Sender<ClientPlayPacket>>, pkt: impl Into<ClientPlayPacket>) {
|
fn send_packet(send_opt: &mut Option<Sender<S2cPlayPacket>>, pkt: impl Into<S2cPlayPacket>) {
|
||||||
if let Some(send) = send_opt {
|
if let Some(send) = send_opt {
|
||||||
match send.try_send(pkt.into()) {
|
match send.try_send(pkt.into()) {
|
||||||
Err(TrySendError::Full(_)) => {
|
Err(TrySendError::Full(_)) => {
|
||||||
|
|
202
src/config.rs
202
src/config.rs
|
@ -6,7 +6,7 @@ use async_trait::async_trait;
|
||||||
use tokio::runtime::Handle as TokioHandle;
|
use tokio::runtime::Handle as TokioHandle;
|
||||||
|
|
||||||
use crate::client::ClientMut;
|
use crate::client::ClientMut;
|
||||||
use crate::{ident, Identifier, NewClientData, Server, Text, Ticks, WorldId, WorldsMut};
|
use crate::{Biome, Dimension, NewClientData, Server, Text, Ticks, WorldId, WorldsMut};
|
||||||
|
|
||||||
/// A trait containing callbacks which are invoked by the running Minecraft
|
/// A trait containing callbacks which are invoked by the running Minecraft
|
||||||
/// server.
|
/// server.
|
||||||
|
@ -223,203 +223,3 @@ pub enum ServerListPing<'a> {
|
||||||
/// Ignores the query and disconnects from the client.
|
/// Ignores the query and disconnects from the client.
|
||||||
Ignore,
|
Ignore,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A handle to a particular [`Dimension`] on the server.
|
|
||||||
///
|
|
||||||
/// Dimension IDs must only be used on servers from which they originate.
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
|
||||||
pub struct DimensionId(pub(crate) u16);
|
|
||||||
|
|
||||||
impl DimensionId {
|
|
||||||
pub fn to_index(self) -> usize {
|
|
||||||
self.0 as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The default dimension ID corresponds to the first element in the `Vec`
|
|
||||||
/// returned by [`Config::dimensions`].
|
|
||||||
impl Default for DimensionId {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Contains the configuration for a dimension type.
|
|
||||||
///
|
|
||||||
/// In Minecraft, "dimension" and "dimension type" are two different concepts.
|
|
||||||
/// For instance, the Overworld and Nether are dimensions, each with
|
|
||||||
/// their own dimension type. A dimension in this library is analogous to a
|
|
||||||
/// [`World`](crate::World) while [`Dimension`] represents a
|
|
||||||
/// dimension type.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Dimension {
|
|
||||||
/// When false, compases will spin randomly.
|
|
||||||
pub natural: bool,
|
|
||||||
/// Must be between 0.0 and 1.0.
|
|
||||||
pub ambient_light: f32,
|
|
||||||
/// Must be between 0 and 24000.
|
|
||||||
pub fixed_time: Option<u16>,
|
|
||||||
/// Determines what skybox/fog effects to use.
|
|
||||||
pub effects: DimensionEffects,
|
|
||||||
/// The minimum height in which blocks can exist in this dimension.
|
|
||||||
///
|
|
||||||
/// `min_y` must meet the following conditions:
|
|
||||||
/// * `min_y % 16 == 0`
|
|
||||||
/// * `-2032 <= min_y <= 2016`
|
|
||||||
pub min_y: i32,
|
|
||||||
/// The total height in which blocks can exist in this dimension.
|
|
||||||
///
|
|
||||||
/// `height` must meet the following conditions:
|
|
||||||
/// * `height % 16 == 0`
|
|
||||||
/// * `0 <= height <= 4064`
|
|
||||||
/// * `min_y + height <= 2032`
|
|
||||||
pub height: i32,
|
|
||||||
// TODO: The following fields should be added if they can affect the
|
|
||||||
// appearance of the dimension to clients.
|
|
||||||
// * infiniburn
|
|
||||||
// * respawn_anchor_works
|
|
||||||
// * has_skylight
|
|
||||||
// * bed_works
|
|
||||||
// * has_raids
|
|
||||||
// * logical_height
|
|
||||||
// * coordinate_scale
|
|
||||||
// * ultrawarm
|
|
||||||
// * has_ceiling
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Dimension {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
natural: true,
|
|
||||||
ambient_light: 1.0,
|
|
||||||
fixed_time: None,
|
|
||||||
effects: DimensionEffects::Overworld,
|
|
||||||
min_y: -64,
|
|
||||||
height: 384,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
||||||
pub enum DimensionEffects {
|
|
||||||
Overworld,
|
|
||||||
TheNether,
|
|
||||||
TheEnd,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Identifies a particular [`Biome`].
|
|
||||||
///
|
|
||||||
/// Biome IDs are always valid and are cheap to copy and store.
|
|
||||||
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
|
||||||
pub struct BiomeId(pub(crate) u16);
|
|
||||||
|
|
||||||
impl BiomeId {
|
|
||||||
pub fn to_index(self) -> usize {
|
|
||||||
self.0 as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Contains the configuration for a biome.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Biome {
|
|
||||||
/// The unique name for this biome. The name can be
|
|
||||||
/// seen in the F3 debug menu.
|
|
||||||
pub name: Identifier,
|
|
||||||
pub precipitation: BiomePrecipitation,
|
|
||||||
pub sky_color: u32,
|
|
||||||
pub water_fog_color: u32,
|
|
||||||
pub fog_color: u32,
|
|
||||||
pub water_color: u32,
|
|
||||||
pub foliage_color: Option<u32>,
|
|
||||||
pub grass_color_modifier: BiomeGrassColorModifier,
|
|
||||||
pub music: Option<BiomeMusic>,
|
|
||||||
pub ambient_sound: Option<Identifier>,
|
|
||||||
pub additions_sound: Option<BiomeAdditionsSound>,
|
|
||||||
pub mood_sound: Option<BiomeMoodSound>,
|
|
||||||
pub particle: Option<BiomeParticle>,
|
|
||||||
// TODO: The following fields should be added if they can affect the appearance of the biome to
|
|
||||||
// clients.
|
|
||||||
// * depth: f32
|
|
||||||
// * temperature: f32
|
|
||||||
// * scale: f32
|
|
||||||
// * downfall: f32
|
|
||||||
// * category
|
|
||||||
// * temperature_modifier
|
|
||||||
// * grass_color (misleading name?)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Biome {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
name: ident!("plains"),
|
|
||||||
precipitation: BiomePrecipitation::Rain,
|
|
||||||
sky_color: 7907327,
|
|
||||||
water_fog_color: 329011,
|
|
||||||
fog_color: 12638463,
|
|
||||||
water_color: 4159204,
|
|
||||||
foliage_color: None,
|
|
||||||
grass_color_modifier: BiomeGrassColorModifier::None,
|
|
||||||
music: None,
|
|
||||||
ambient_sound: None,
|
|
||||||
additions_sound: None,
|
|
||||||
mood_sound: None,
|
|
||||||
particle: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
||||||
pub enum BiomePrecipitation {
|
|
||||||
Rain,
|
|
||||||
Snow,
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for BiomePrecipitation {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Rain
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Minecraft handles grass colors for swamps and dark oak forests in a special
|
|
||||||
/// way.
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
||||||
pub enum BiomeGrassColorModifier {
|
|
||||||
Swamp,
|
|
||||||
DarkForest,
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for BiomeGrassColorModifier {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct BiomeMusic {
|
|
||||||
pub replace_current_music: bool,
|
|
||||||
pub sound: Identifier,
|
|
||||||
pub min_delay: i32,
|
|
||||||
pub max_delay: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct BiomeAdditionsSound {
|
|
||||||
pub sound: Identifier,
|
|
||||||
pub tick_chance: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct BiomeMoodSound {
|
|
||||||
pub sound: Identifier,
|
|
||||||
pub tick_delay: i32,
|
|
||||||
pub offset: f64,
|
|
||||||
pub block_search_extent: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct BiomeParticle {
|
|
||||||
pub probability: f32,
|
|
||||||
pub typ: Identifier,
|
|
||||||
}
|
|
||||||
|
|
82
src/dimension.rs
Normal file
82
src/dimension.rs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/// A handle to a particular [`Dimension`] on the server.
|
||||||
|
///
|
||||||
|
/// Dimension IDs must only be used on servers from which they originate.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
|
pub struct DimensionId(pub(crate) u16);
|
||||||
|
|
||||||
|
impl DimensionId {
|
||||||
|
pub fn to_index(self) -> usize {
|
||||||
|
self.0 as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default dimension ID corresponds to the first element in the `Vec`
|
||||||
|
/// returned by [`Config::dimensions`].
|
||||||
|
impl Default for DimensionId {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains the configuration for a dimension type.
|
||||||
|
///
|
||||||
|
/// In Minecraft, "dimension" and "dimension type" are two different concepts.
|
||||||
|
/// For instance, the Overworld and Nether are dimensions, each with
|
||||||
|
/// their own dimension type. A dimension in this library is analogous to a
|
||||||
|
/// [`World`](crate::World) while [`Dimension`] represents a
|
||||||
|
/// dimension type.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Dimension {
|
||||||
|
/// When false, compases will spin randomly.
|
||||||
|
pub natural: bool,
|
||||||
|
/// Must be between 0.0 and 1.0.
|
||||||
|
pub ambient_light: f32,
|
||||||
|
/// Must be between 0 and 24000.
|
||||||
|
pub fixed_time: Option<u16>,
|
||||||
|
/// Determines what skybox/fog effects to use.
|
||||||
|
pub effects: DimensionEffects,
|
||||||
|
/// The minimum height in which blocks can exist in this dimension.
|
||||||
|
///
|
||||||
|
/// `min_y` must meet the following conditions:
|
||||||
|
/// * `min_y % 16 == 0`
|
||||||
|
/// * `-2032 <= min_y <= 2016`
|
||||||
|
pub min_y: i32,
|
||||||
|
/// The total height in which blocks can exist in this dimension.
|
||||||
|
///
|
||||||
|
/// `height` must meet the following conditions:
|
||||||
|
/// * `height % 16 == 0`
|
||||||
|
/// * `0 <= height <= 4064`
|
||||||
|
/// * `min_y + height <= 2032`
|
||||||
|
pub height: i32,
|
||||||
|
// TODO: The following fields should be added if they can affect the
|
||||||
|
// appearance of the dimension to clients.
|
||||||
|
// * infiniburn
|
||||||
|
// * respawn_anchor_works
|
||||||
|
// * has_skylight
|
||||||
|
// * bed_works
|
||||||
|
// * has_raids
|
||||||
|
// * logical_height
|
||||||
|
// * coordinate_scale
|
||||||
|
// * ultrawarm
|
||||||
|
// * has_ceiling
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Dimension {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
natural: true,
|
||||||
|
ambient_light: 1.0,
|
||||||
|
fixed_time: None,
|
||||||
|
effects: DimensionEffects::Overworld,
|
||||||
|
min_y: -64,
|
||||||
|
height: 384,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum DimensionEffects {
|
||||||
|
Overworld,
|
||||||
|
TheNether,
|
||||||
|
TheEnd,
|
||||||
|
}
|
|
@ -12,8 +12,8 @@ use uuid::Uuid;
|
||||||
use vek::{Aabb, Vec3};
|
use vek::{Aabb, Vec3};
|
||||||
|
|
||||||
use crate::byte_angle::ByteAngle;
|
use crate::byte_angle::ByteAngle;
|
||||||
use crate::packets::play::{
|
use crate::packets::play::s2c::{
|
||||||
ClientPlayPacket, EntityMetadata, SpawnEntity, SpawnExperienceOrb, SpawnLivingEntity,
|
EntityMetadata, S2cPlayPacket, SpawnEntity, SpawnExperienceOrb, SpawnLivingEntity,
|
||||||
SpawnPainting, SpawnPlayer,
|
SpawnPainting, SpawnPlayer,
|
||||||
};
|
};
|
||||||
use crate::protocol::RawBytes;
|
use crate::protocol::RawBytes;
|
||||||
|
@ -580,7 +580,7 @@ pub(crate) enum EntitySpawnPacket {
|
||||||
SpawnPlayer(SpawnPlayer),
|
SpawnPlayer(SpawnPlayer),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EntitySpawnPacket> for ClientPlayPacket {
|
impl From<EntitySpawnPacket> for S2cPlayPacket {
|
||||||
fn from(pkt: EntitySpawnPacket) -> Self {
|
fn from(pkt: EntitySpawnPacket) -> Self {
|
||||||
match pkt {
|
match pkt {
|
||||||
EntitySpawnPacket::SpawnEntity(pkt) => pkt.into(),
|
EntitySpawnPacket::SpawnEntity(pkt) => pkt.into(),
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::protocol::{encode_string_bounded, BoundedString, Decode, Encode};
|
||||||
///
|
///
|
||||||
/// The entire identifier must match the regex `([a-z0-9_-]+:)?[a-z0-9_\/.-]+`.
|
/// The entire identifier must match the regex `([a-z0-9_-]+:)?[a-z0-9_\/.-]+`.
|
||||||
#[derive(Clone, Eq)]
|
#[derive(Clone, Eq)]
|
||||||
pub struct Identifier {
|
pub struct Ident {
|
||||||
ident: Cow<'static, AsciiStr>,
|
ident: Cow<'static, AsciiStr>,
|
||||||
/// The index of the ':' character in the string.
|
/// The index of the ':' character in the string.
|
||||||
/// If there is no namespace then it is `usize::MAX`.
|
/// If there is no namespace then it is `usize::MAX`.
|
||||||
|
@ -33,12 +33,12 @@ pub struct ParseError {
|
||||||
src: Cow<'static, str>,
|
src: Cow<'static, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Identifier {
|
impl Ident {
|
||||||
/// Parses a new identifier from a string.
|
/// Parses a new identifier from a string.
|
||||||
///
|
///
|
||||||
/// The string must match the regex `([a-z0-9_-]+:)?[a-z0-9_\/.-]+`.
|
/// The string must match the regex `([a-z0-9_-]+:)?[a-z0-9_\/.-]+`.
|
||||||
/// If not, an error is returned.
|
/// If not, an error is returned.
|
||||||
pub fn new(str: impl Into<Cow<'static, str>>) -> Result<Identifier, ParseError> {
|
pub fn new(str: impl Into<Cow<'static, str>>) -> Result<Ident, ParseError> {
|
||||||
#![allow(bindings_with_variant_name)]
|
#![allow(bindings_with_variant_name)]
|
||||||
|
|
||||||
let cow = match str.into() {
|
let cow = match str.into() {
|
||||||
|
@ -125,55 +125,55 @@ impl ParseError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Identifier {
|
impl std::fmt::Debug for Ident {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_tuple("Identifier").field(&self.as_str()).finish()
|
f.debug_tuple("Identifier").field(&self.as_str()).finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Identifier {
|
impl FromStr for Ident {
|
||||||
type Err = ParseError;
|
type Err = ParseError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
Identifier::new(s.to_string())
|
Ident::new(s.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Identifier> for String {
|
impl From<Ident> for String {
|
||||||
fn from(id: Identifier) -> Self {
|
fn from(id: Ident) -> Self {
|
||||||
id.ident.into_owned().into()
|
id.ident.into_owned().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Identifier> for Cow<'static, str> {
|
impl From<Ident> for Cow<'static, str> {
|
||||||
fn from(id: Identifier) -> Self {
|
fn from(id: Ident) -> Self {
|
||||||
ascii_cow_to_str_cow(id.ident)
|
ascii_cow_to_str_cow(id.ident)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<str> for Identifier {
|
impl AsRef<str> for Ident {
|
||||||
fn as_ref(&self) -> &str {
|
fn as_ref(&self) -> &str {
|
||||||
self.as_str()
|
self.as_str()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<String> for Identifier {
|
impl TryFrom<String> for Ident {
|
||||||
type Error = ParseError;
|
type Error = ParseError;
|
||||||
|
|
||||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
Identifier::new(value)
|
Ident::new(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&'static str> for Identifier {
|
impl TryFrom<&'static str> for Ident {
|
||||||
type Error = ParseError;
|
type Error = ParseError;
|
||||||
|
|
||||||
fn try_from(value: &'static str) -> Result<Self, Self::Error> {
|
fn try_from(value: &'static str) -> Result<Self, Self::Error> {
|
||||||
Identifier::new(value)
|
Ident::new(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Identifier {
|
impl std::fmt::Display for Ident {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
write!(f, "{}", self.as_str())
|
write!(f, "{}", self.as_str())
|
||||||
}
|
}
|
||||||
|
@ -181,40 +181,40 @@ impl std::fmt::Display for Identifier {
|
||||||
|
|
||||||
/// Equality for identifiers respects the fact that "minecraft:apple" and
|
/// Equality for identifiers respects the fact that "minecraft:apple" and
|
||||||
/// "apple" have the same meaning.
|
/// "apple" have the same meaning.
|
||||||
impl PartialEq for Identifier {
|
impl PartialEq for Ident {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.namespace().unwrap_or("minecraft") == other.namespace().unwrap_or("minecraft")
|
self.namespace().unwrap_or("minecraft") == other.namespace().unwrap_or("minecraft")
|
||||||
&& self.name() == other.name()
|
&& self.name() == other.name()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::hash::Hash for Identifier {
|
impl std::hash::Hash for Ident {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.namespace().unwrap_or("minecraft").hash(state);
|
self.namespace().unwrap_or("minecraft").hash(state);
|
||||||
self.name().hash(state);
|
self.name().hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for Identifier {
|
impl Encode for Ident {
|
||||||
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
||||||
encode_string_bounded(self.as_str(), 0, 32767, w)
|
encode_string_bounded(self.as_str(), 0, 32767, w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for Identifier {
|
impl Decode for Ident {
|
||||||
fn decode(r: &mut impl Read) -> anyhow::Result<Self> {
|
fn decode(r: &mut impl Read) -> anyhow::Result<Self> {
|
||||||
let string = BoundedString::<0, 32767>::decode(r)?.0;
|
let string = BoundedString::<0, 32767>::decode(r)?.0;
|
||||||
Ok(Identifier::new(string)?)
|
Ok(Ident::new(string)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Identifier {
|
impl Serialize for Ident {
|
||||||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
self.as_str().serialize(serializer)
|
self.as_str().serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Identifier {
|
impl<'de> Deserialize<'de> for Ident {
|
||||||
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||||
deserializer.deserialize_str(IdentifierVisitor)
|
deserializer.deserialize_str(IdentifierVisitor)
|
||||||
}
|
}
|
||||||
|
@ -224,18 +224,18 @@ impl<'de> Deserialize<'de> for Identifier {
|
||||||
struct IdentifierVisitor;
|
struct IdentifierVisitor;
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for IdentifierVisitor {
|
impl<'de> Visitor<'de> for IdentifierVisitor {
|
||||||
type Value = Identifier;
|
type Value = Ident;
|
||||||
|
|
||||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
write!(f, "a valid Minecraft identifier")
|
write!(f, "a valid Minecraft identifier")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
|
fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
|
||||||
Identifier::from_str(s).map_err(E::custom)
|
Ident::from_str(s).map_err(E::custom)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_string<E: serde::de::Error>(self, s: String) -> Result<Self::Value, E> {
|
fn visit_string<E: serde::de::Error>(self, s: String) -> Result<Self::Value, E> {
|
||||||
Identifier::new(s).map_err(E::custom)
|
Ident::new(s).map_err(E::custom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,8 +249,8 @@ macro_rules! ident {
|
||||||
let errmsg = "invalid identifier in `ident` macro";
|
let errmsg = "invalid identifier in `ident` macro";
|
||||||
#[allow(clippy::redundant_closure_call)]
|
#[allow(clippy::redundant_closure_call)]
|
||||||
(|args: ::std::fmt::Arguments| match args.as_str() {
|
(|args: ::std::fmt::Arguments| match args.as_str() {
|
||||||
Some(s) => $crate::Identifier::new(s).expect(errmsg),
|
Some(s) => $crate::Ident::new(s).expect(errmsg),
|
||||||
None => $crate::Identifier::new(args.to_string()).expect(errmsg),
|
None => $crate::Ident::new(args.to_string()).expect(errmsg),
|
||||||
})(format_args!($($arg)*))
|
})(format_args!($($arg)*))
|
||||||
}}
|
}}
|
||||||
}
|
}
|
10
src/lib.rs
10
src/lib.rs
|
@ -7,6 +7,7 @@
|
||||||
// missing_docs
|
// missing_docs
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
pub mod biome;
|
||||||
pub mod block;
|
pub mod block;
|
||||||
mod block_pos;
|
mod block_pos;
|
||||||
mod byte_angle;
|
mod byte_angle;
|
||||||
|
@ -14,8 +15,9 @@ pub mod chunk;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
mod codec;
|
mod codec;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod dimension;
|
||||||
pub mod entity;
|
pub mod entity;
|
||||||
pub mod identifier;
|
pub mod ident;
|
||||||
mod packets;
|
mod packets;
|
||||||
mod protocol;
|
mod protocol;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
@ -27,12 +29,14 @@ mod var_long;
|
||||||
pub mod world;
|
pub mod world;
|
||||||
|
|
||||||
pub use async_trait::async_trait;
|
pub use async_trait::async_trait;
|
||||||
|
pub use biome::{Biome, BiomeId};
|
||||||
pub use block_pos::BlockPos;
|
pub use block_pos::BlockPos;
|
||||||
pub use chunk::{Chunk, ChunkPos, Chunks, ChunksMut};
|
pub use chunk::{Chunk, ChunkPos, Chunks, ChunksMut};
|
||||||
pub use client::{Client, ClientMut, Clients, ClientsMut};
|
pub use client::{Client, ClientMut, Clients, ClientsMut};
|
||||||
pub use config::{Biome, BiomeId, Config, Dimension, DimensionId};
|
pub use config::Config;
|
||||||
|
pub use dimension::{Dimension, DimensionId};
|
||||||
pub use entity::{Entities, EntitiesMut, Entity, EntityId, EntityType};
|
pub use entity::{Entities, EntitiesMut, Entity, EntityId, EntityType};
|
||||||
pub use identifier::Identifier;
|
pub use ident::Ident;
|
||||||
pub use server::{start_server, NewClientData, Server, ShutdownResult};
|
pub use server::{start_server, NewClientData, Server, ShutdownResult};
|
||||||
pub use text::{Text, TextFormat};
|
pub use text::{Text, TextFormat};
|
||||||
pub use uuid::Uuid;
|
pub use uuid::Uuid;
|
||||||
|
|
121
src/packets.rs
121
src/packets.rs
|
@ -17,11 +17,10 @@ use vek::Vec3;
|
||||||
|
|
||||||
use crate::block_pos::BlockPos;
|
use crate::block_pos::BlockPos;
|
||||||
use crate::byte_angle::ByteAngle;
|
use crate::byte_angle::ByteAngle;
|
||||||
use crate::identifier::Identifier;
|
|
||||||
use crate::protocol::{BoundedArray, BoundedInt, BoundedString, Decode, Encode, Nbt, RawBytes};
|
use crate::protocol::{BoundedArray, BoundedInt, BoundedString, Decode, Encode, Nbt, RawBytes};
|
||||||
use crate::var_int::VarInt;
|
use crate::var_int::VarInt;
|
||||||
use crate::var_long::VarLong;
|
use crate::var_long::VarLong;
|
||||||
use crate::Text;
|
use crate::{Ident, Text};
|
||||||
|
|
||||||
/// Trait for types that can be written to the Minecraft protocol as a complete
|
/// Trait for types that can be written to the Minecraft protocol as a complete
|
||||||
/// packet.
|
/// packet.
|
||||||
|
@ -353,9 +352,8 @@ pub mod handshake {
|
||||||
|
|
||||||
/// Packets and types used during the status state.
|
/// Packets and types used during the status state.
|
||||||
pub mod status {
|
pub mod status {
|
||||||
use super::*;
|
pub mod s2c {
|
||||||
|
use super::super::*;
|
||||||
// ==== Clientbound ====
|
|
||||||
|
|
||||||
def_struct! {
|
def_struct! {
|
||||||
Response 0x00 {
|
Response 0x00 {
|
||||||
|
@ -369,8 +367,10 @@ pub mod status {
|
||||||
payload: u64
|
payload: u64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ==== Serverbound ====
|
pub mod c2s {
|
||||||
|
use super::super::*;
|
||||||
|
|
||||||
def_struct! {
|
def_struct! {
|
||||||
Request 0x00 {}
|
Request 0x00 {}
|
||||||
|
@ -381,13 +381,13 @@ pub mod status {
|
||||||
payload: u64
|
payload: u64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Packets and types used during the play state.
|
/// Packets and types used during the play state.
|
||||||
pub mod login {
|
pub mod login {
|
||||||
use super::*;
|
pub mod s2c {
|
||||||
|
use super::super::*;
|
||||||
// ==== Clientbound ====
|
|
||||||
|
|
||||||
def_struct! {
|
def_struct! {
|
||||||
Disconnect 0x00 {
|
Disconnect 0x00 {
|
||||||
|
@ -417,8 +417,10 @@ pub mod login {
|
||||||
threshold: VarInt
|
threshold: VarInt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ==== Serverbound ====
|
pub mod c2s {
|
||||||
|
use super::super::*;
|
||||||
|
|
||||||
def_struct! {
|
def_struct! {
|
||||||
LoginStart 0x00 {
|
LoginStart 0x00 {
|
||||||
|
@ -432,13 +434,13 @@ pub mod login {
|
||||||
verify_token: BoundedArray<u8, 16, 128>,
|
verify_token: BoundedArray<u8, 16, 128>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Packets and types used during the play state.
|
/// Packets and types used during the play state.
|
||||||
pub mod play {
|
pub mod play {
|
||||||
use super::*;
|
pub mod s2c {
|
||||||
|
use super::super::*;
|
||||||
// ==== Clientbound ====
|
|
||||||
|
|
||||||
def_struct! {
|
def_struct! {
|
||||||
SpawnEntity 0x00 {
|
SpawnEntity 0x00 {
|
||||||
|
@ -506,7 +508,7 @@ pub mod play {
|
||||||
def_struct! {
|
def_struct! {
|
||||||
SculkVibrationSignal 0x05 {
|
SculkVibrationSignal 0x05 {
|
||||||
source_position: BlockPos,
|
source_position: BlockPos,
|
||||||
destination_identifier: Identifier, // TODO: destination codec type?
|
destination_identifier: Ident, // TODO: destination codec type?
|
||||||
destination: BlockPos, // TODO: this type varies depending on destination_identifier
|
destination: BlockPos, // TODO: this type varies depending on destination_identifier
|
||||||
arrival_ticks: VarInt,
|
arrival_ticks: VarInt,
|
||||||
}
|
}
|
||||||
|
@ -807,12 +809,12 @@ pub mod play {
|
||||||
/// The previous gamemode for the purpose of the F3+F4 gamemode switcher. (TODO: verify)
|
/// The previous gamemode for the purpose of the F3+F4 gamemode switcher. (TODO: verify)
|
||||||
/// Is `-1` if there was no previous gamemode.
|
/// Is `-1` if there was no previous gamemode.
|
||||||
previous_gamemode: GameMode,
|
previous_gamemode: GameMode,
|
||||||
dimension_names: Vec<Identifier>,
|
dimension_names: Vec<Ident>,
|
||||||
dimension_codec: Nbt<DimensionCodec>,
|
dimension_codec: Nbt<DimensionCodec>,
|
||||||
/// The specification of the dimension being spawned into.
|
/// The specification of the dimension being spawned into.
|
||||||
dimension: Nbt<DimensionType>,
|
dimension: Nbt<DimensionType>,
|
||||||
/// The identifier of the dimension being spawned into.
|
/// The identifier of the dimension being spawned into.
|
||||||
dimension_name: Identifier,
|
dimension_name: Ident,
|
||||||
/// Hash of the world's seed used for client biome noise.
|
/// Hash of the world's seed used for client biome noise.
|
||||||
hashed_seed: i64,
|
hashed_seed: i64,
|
||||||
/// No longer used by the client.
|
/// No longer used by the client.
|
||||||
|
@ -841,13 +843,13 @@ pub mod play {
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct DimensionTypeRegistry {
|
pub struct DimensionTypeRegistry {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub typ: Identifier,
|
pub typ: Ident,
|
||||||
pub value: Vec<DimensionTypeRegistryEntry>,
|
pub value: Vec<DimensionTypeRegistryEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct DimensionTypeRegistryEntry {
|
pub struct DimensionTypeRegistryEntry {
|
||||||
pub name: Identifier,
|
pub name: Ident,
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub element: DimensionType,
|
pub element: DimensionType,
|
||||||
}
|
}
|
||||||
|
@ -862,7 +864,7 @@ pub mod play {
|
||||||
pub respawn_anchor_works: bool,
|
pub respawn_anchor_works: bool,
|
||||||
pub has_skylight: bool,
|
pub has_skylight: bool,
|
||||||
pub bed_works: bool,
|
pub bed_works: bool,
|
||||||
pub effects: Identifier,
|
pub effects: Ident,
|
||||||
pub has_raids: bool,
|
pub has_raids: bool,
|
||||||
pub min_y: i32,
|
pub min_y: i32,
|
||||||
pub height: i32,
|
pub height: i32,
|
||||||
|
@ -875,13 +877,13 @@ pub mod play {
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct BiomeRegistry {
|
pub struct BiomeRegistry {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub typ: Identifier,
|
pub typ: Ident,
|
||||||
pub value: Vec<Biome>,
|
pub value: Vec<Biome>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Biome {
|
pub struct Biome {
|
||||||
pub name: Identifier,
|
pub name: Ident,
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub element: BiomeProperty,
|
pub element: BiomeProperty,
|
||||||
}
|
}
|
||||||
|
@ -909,7 +911,7 @@ pub mod play {
|
||||||
pub grass_color: Option<i32>,
|
pub grass_color: Option<i32>,
|
||||||
pub grass_color_modifier: Option<String>,
|
pub grass_color_modifier: Option<String>,
|
||||||
pub music: Option<BiomeMusic>,
|
pub music: Option<BiomeMusic>,
|
||||||
pub ambient_sound: Option<Identifier>,
|
pub ambient_sound: Option<Ident>,
|
||||||
pub additions_sound: Option<BiomeAdditionsSound>,
|
pub additions_sound: Option<BiomeAdditionsSound>,
|
||||||
pub mood_sound: Option<BiomeMoodSound>,
|
pub mood_sound: Option<BiomeMoodSound>,
|
||||||
}
|
}
|
||||||
|
@ -917,20 +919,20 @@ pub mod play {
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct BiomeMusic {
|
pub struct BiomeMusic {
|
||||||
pub replace_current_music: bool,
|
pub replace_current_music: bool,
|
||||||
pub sound: Identifier,
|
pub sound: Ident,
|
||||||
pub max_delay: i32,
|
pub max_delay: i32,
|
||||||
pub min_delay: i32,
|
pub min_delay: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct BiomeAdditionsSound {
|
pub struct BiomeAdditionsSound {
|
||||||
pub sound: Identifier,
|
pub sound: Ident,
|
||||||
pub tick_chance: f64,
|
pub tick_chance: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct BiomeMoodSound {
|
pub struct BiomeMoodSound {
|
||||||
pub sound: Identifier,
|
pub sound: Ident,
|
||||||
pub tick_delay: i32,
|
pub tick_delay: i32,
|
||||||
pub offset: f64,
|
pub offset: f64,
|
||||||
pub block_search_extent: i32,
|
pub block_search_extent: i32,
|
||||||
|
@ -945,7 +947,7 @@ pub mod play {
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct BiomeParticleOptions {
|
pub struct BiomeParticleOptions {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub typ: Identifier,
|
pub typ: Ident,
|
||||||
}
|
}
|
||||||
|
|
||||||
def_enum! {
|
def_enum! {
|
||||||
|
@ -1094,34 +1096,34 @@ pub mod play {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! def_client_play_packet_enum {
|
macro_rules! def_s2c_play_packet_enum {
|
||||||
{
|
{
|
||||||
$($packet:ident),* $(,)?
|
$($packet:ident),* $(,)?
|
||||||
} => {
|
} => {
|
||||||
/// An enum of all clientbound play packets.
|
/// An enum of all s2c play packets.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ClientPlayPacket {
|
pub enum S2cPlayPacket {
|
||||||
$($packet($packet)),*
|
$($packet($packet)),*
|
||||||
}
|
}
|
||||||
|
|
||||||
impl private::Sealed for ClientPlayPacket {}
|
impl private::Sealed for S2cPlayPacket {}
|
||||||
|
|
||||||
$(
|
$(
|
||||||
impl From<$packet> for ClientPlayPacket {
|
impl From<$packet> for S2cPlayPacket {
|
||||||
fn from(p: $packet) -> ClientPlayPacket {
|
fn from(p: $packet) -> S2cPlayPacket {
|
||||||
ClientPlayPacket::$packet(p)
|
S2cPlayPacket::$packet(p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
|
||||||
impl EncodePacket for ClientPlayPacket {
|
impl EncodePacket for S2cPlayPacket {
|
||||||
fn encode_packet(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
fn encode_packet(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
$(
|
$(
|
||||||
Self::$packet(p) => {
|
Self::$packet(p) => {
|
||||||
VarInt($packet::PACKET_ID)
|
VarInt($packet::PACKET_ID)
|
||||||
.encode(w)
|
.encode(w)
|
||||||
.context(concat!("failed to write play packet ID for `", stringify!($packet), "`"))?;
|
.context(concat!("failed to write s2c play packet ID for `", stringify!($packet), "`"))?;
|
||||||
p.encode(w)
|
p.encode(w)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
@ -1131,7 +1133,7 @@ pub mod play {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_client_play_packet_order() {
|
fn test_s2c_play_packet_order() {
|
||||||
let ids = [
|
let ids = [
|
||||||
$(
|
$(
|
||||||
(stringify!($packet), $packet::PACKET_ID),
|
(stringify!($packet), $packet::PACKET_ID),
|
||||||
|
@ -1139,13 +1141,13 @@ pub mod play {
|
||||||
];
|
];
|
||||||
|
|
||||||
if let Some(w) = ids.windows(2).find(|w| w[0].1 >= w[1].1) {
|
if let Some(w) = ids.windows(2).find(|w| w[0].1 >= w[1].1) {
|
||||||
panic!("the {} and {} variants of the client play packet enum are not properly sorted by their packet ID", w[0].0, w[1].0);
|
panic!("the {} and {} variants of the s2c play packet enum are not properly sorted by their packet ID", w[0].0, w[1].0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def_client_play_packet_enum! {
|
def_s2c_play_packet_enum! {
|
||||||
SpawnEntity,
|
SpawnEntity,
|
||||||
SpawnExperienceOrb,
|
SpawnExperienceOrb,
|
||||||
SpawnLivingEntity,
|
SpawnLivingEntity,
|
||||||
|
@ -1182,8 +1184,10 @@ pub mod play {
|
||||||
EntityTeleport,
|
EntityTeleport,
|
||||||
TimeUpdate,
|
TimeUpdate,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ==== Serverbound ====
|
pub mod c2s {
|
||||||
|
use super::super::*;
|
||||||
|
|
||||||
def_struct! {
|
def_struct! {
|
||||||
TeleportConfirm 0x00 {
|
TeleportConfirm 0x00 {
|
||||||
|
@ -1302,7 +1306,7 @@ pub mod play {
|
||||||
|
|
||||||
def_struct! {
|
def_struct! {
|
||||||
PluginMessageServerbound 0x0a {
|
PluginMessageServerbound 0x0a {
|
||||||
channel: Identifier,
|
channel: Ident,
|
||||||
data: RawBytes,
|
data: RawBytes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1434,7 +1438,7 @@ pub mod play {
|
||||||
def_struct! {
|
def_struct! {
|
||||||
CraftRecipeRequest 0x18 {
|
CraftRecipeRequest 0x18 {
|
||||||
window_id: i8,
|
window_id: i8,
|
||||||
recipe: Identifier,
|
recipe: Ident,
|
||||||
make_all: bool,
|
make_all: bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1545,7 +1549,7 @@ pub mod play {
|
||||||
|
|
||||||
def_struct! {
|
def_struct! {
|
||||||
SetDisplayedRecipe 0x1f {
|
SetDisplayedRecipe 0x1f {
|
||||||
recipe_id: Identifier,
|
recipe_id: Ident,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1566,7 +1570,7 @@ pub mod play {
|
||||||
|
|
||||||
def_enum! {
|
def_enum! {
|
||||||
AdvancementTab 0x22: VarInt {
|
AdvancementTab 0x22: VarInt {
|
||||||
OpenedTab: Identifier = 0,
|
OpenedTab: Ident = 0,
|
||||||
ClosedScreen = 1,
|
ClosedScreen = 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1634,9 +1638,9 @@ pub mod play {
|
||||||
def_struct! {
|
def_struct! {
|
||||||
UpdateJigsawBlock 0x29 {
|
UpdateJigsawBlock 0x29 {
|
||||||
location: BlockPos,
|
location: BlockPos,
|
||||||
name: Identifier,
|
name: Ident,
|
||||||
target: Identifier,
|
target: Ident,
|
||||||
pool: Identifier,
|
pool: Ident,
|
||||||
final_state: String,
|
final_state: String,
|
||||||
joint_type: String,
|
joint_type: String,
|
||||||
}
|
}
|
||||||
|
@ -1737,29 +1741,29 @@ pub mod play {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! def_server_play_packet_enum {
|
macro_rules! def_c2s_play_packet_enum {
|
||||||
{
|
{
|
||||||
$($packet:ident),* $(,)?
|
$($packet:ident),* $(,)?
|
||||||
} => {
|
} => {
|
||||||
/// An enum of all serverbound play packets.
|
/// An enum of all client-to-server play packets.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ServerPlayPacket {
|
pub enum C2sPlayPacket {
|
||||||
$($packet($packet)),*
|
$($packet($packet)),*
|
||||||
}
|
}
|
||||||
|
|
||||||
impl private::Sealed for ServerPlayPacket {}
|
impl private::Sealed for C2sPlayPacket {}
|
||||||
|
|
||||||
impl DecodePacket for ServerPlayPacket {
|
impl DecodePacket for C2sPlayPacket {
|
||||||
fn decode_packet(r: &mut impl Read) -> anyhow::Result<ServerPlayPacket> {
|
fn decode_packet(r: &mut impl Read) -> anyhow::Result<C2sPlayPacket> {
|
||||||
let packet_id = VarInt::decode(r).context("failed to read play packet ID")?.0;
|
let packet_id = VarInt::decode(r).context("failed to read c2s play packet ID")?.0;
|
||||||
match packet_id {
|
match packet_id {
|
||||||
$(
|
$(
|
||||||
$packet::PACKET_ID => {
|
$packet::PACKET_ID => {
|
||||||
let pkt = $packet::decode(r)?;
|
let pkt = $packet::decode(r)?;
|
||||||
Ok(ServerPlayPacket::$packet(pkt))
|
Ok(C2sPlayPacket::$packet(pkt))
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
id => bail!("unknown play packet ID {:#04x}", id)
|
id => bail!("unknown c2s play packet ID {:#04x}", id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1767,7 +1771,7 @@ pub mod play {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_server_play_packet_order() {
|
fn test_c2s_play_packet_order() {
|
||||||
let ids = [
|
let ids = [
|
||||||
$(
|
$(
|
||||||
(stringify!($packet), $packet::PACKET_ID),
|
(stringify!($packet), $packet::PACKET_ID),
|
||||||
|
@ -1775,13 +1779,13 @@ pub mod play {
|
||||||
];
|
];
|
||||||
|
|
||||||
if let Some(w) = ids.windows(2).find(|w| w[0].1 >= w[1].1) {
|
if let Some(w) = ids.windows(2).find(|w| w[0].1 >= w[1].1) {
|
||||||
panic!("the {} and {} variants of the server play packet enum are not properly sorted by their packet ID", w[0].0, w[1].0);
|
panic!("the {} and {} variants of the c2s play packet enum are not properly sorted by their packet ID", w[0].0, w[1].0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def_server_play_packet_enum! {
|
def_c2s_play_packet_enum! {
|
||||||
TeleportConfirm,
|
TeleportConfirm,
|
||||||
QueryBlockNbt,
|
QueryBlockNbt,
|
||||||
SetDifficulty,
|
SetDifficulty,
|
||||||
|
@ -1831,6 +1835,7 @@ pub mod play {
|
||||||
PlayerBlockPlacement,
|
PlayerBlockPlacement,
|
||||||
UseItem,
|
UseItem,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -27,18 +27,23 @@ use tokio::sync::{oneshot, Semaphore};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::codec::{Decoder, Encoder};
|
use crate::codec::{Decoder, Encoder};
|
||||||
use crate::config::{Biome, BiomeId, Config, Dimension, DimensionId, ServerListPing};
|
use crate::config::{Config, ServerListPing};
|
||||||
use crate::packets::handshake::{Handshake, HandshakeNextState};
|
use crate::packets::handshake::{Handshake, HandshakeNextState};
|
||||||
use crate::packets::login::{
|
use crate::packets::login;
|
||||||
self, EncryptionRequest, EncryptionResponse, LoginStart, LoginSuccess, SetCompression,
|
use crate::packets::login::c2s::{EncryptionResponse, LoginStart};
|
||||||
};
|
use crate::packets::login::s2c::{EncryptionRequest, LoginSuccess, SetCompression};
|
||||||
use crate::packets::play::{ClientPlayPacket, ServerPlayPacket};
|
use crate::packets::play::c2s::C2sPlayPacket;
|
||||||
use crate::packets::status::{Ping, Pong, Request, Response};
|
use crate::packets::play::s2c::S2cPlayPacket;
|
||||||
|
use crate::packets::status::c2s::{Ping, Request};
|
||||||
|
use crate::packets::status::s2c::{Pong, Response};
|
||||||
use crate::protocol::{BoundedArray, BoundedString};
|
use crate::protocol::{BoundedArray, BoundedString};
|
||||||
use crate::util::valid_username;
|
use crate::util::valid_username;
|
||||||
use crate::var_int::VarInt;
|
use crate::var_int::VarInt;
|
||||||
use crate::world::Worlds;
|
use crate::world::Worlds;
|
||||||
use crate::{Client, ClientMut, Ticks, WorldsMut, PROTOCOL_VERSION, VERSION_NAME};
|
use crate::{
|
||||||
|
Biome, BiomeId, Client, ClientMut, Dimension, DimensionId, Ticks, WorldsMut, PROTOCOL_VERSION,
|
||||||
|
VERSION_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
/// A handle to a running Minecraft server containing state which is accessible
|
/// A handle to a running Minecraft server containing state which is accessible
|
||||||
/// outside the update loop. Servers are internally refcounted and can be shared
|
/// outside the update loop. Servers are internally refcounted and can be shared
|
||||||
|
@ -89,7 +94,7 @@ pub struct NewClientData {
|
||||||
|
|
||||||
struct NewClientMessage {
|
struct NewClientMessage {
|
||||||
ncd: NewClientData,
|
ncd: NewClientData,
|
||||||
reply: oneshot::Sender<ClientPacketChannels>,
|
reply: oneshot::Sender<S2cPacketChannels>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result type returned from [`ServerConfig::start`] after the server is
|
/// The result type returned from [`ServerConfig::start`] after the server is
|
||||||
|
@ -97,8 +102,8 @@ struct NewClientMessage {
|
||||||
pub type ShutdownResult = Result<(), ShutdownError>;
|
pub type ShutdownResult = Result<(), ShutdownError>;
|
||||||
pub type ShutdownError = Box<dyn Error + Send + Sync + 'static>;
|
pub type ShutdownError = Box<dyn Error + Send + Sync + 'static>;
|
||||||
|
|
||||||
pub(crate) type ClientPacketChannels = (Sender<ServerPlayPacket>, Receiver<ClientPlayPacket>);
|
pub(crate) type S2cPacketChannels = (Sender<C2sPlayPacket>, Receiver<S2cPlayPacket>);
|
||||||
pub(crate) type ServerPacketChannels = (Sender<ClientPlayPacket>, Receiver<ServerPlayPacket>);
|
pub(crate) type C2sPacketChannels = (Sender<S2cPlayPacket>, Receiver<C2sPlayPacket>);
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
pub fn config(&self) -> &(impl Config + ?Sized) {
|
pub fn config(&self) -> &(impl Config + ?Sized) {
|
||||||
|
@ -368,12 +373,7 @@ fn do_update_loop(server: Server, mut worlds: WorldsMut) -> ShutdownResult {
|
||||||
});
|
});
|
||||||
|
|
||||||
world.clients.par_iter_mut().for_each(|(_, mut client)| {
|
world.clients.par_iter_mut().for_each(|(_, mut client)| {
|
||||||
client.update(
|
client.update(&server, &world.entities, &world.chunks, &world.meta);
|
||||||
&server,
|
|
||||||
&world.entities,
|
|
||||||
&world.chunks,
|
|
||||||
&world.meta,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
world.entities.update();
|
world.entities.update();
|
||||||
|
@ -396,8 +396,8 @@ fn join_player(server: &Server, mut worlds: WorldsMut, msg: NewClientMessage) {
|
||||||
let (clientbound_tx, clientbound_rx) = flume::bounded(server.0.outgoing_packet_capacity);
|
let (clientbound_tx, clientbound_rx) = flume::bounded(server.0.outgoing_packet_capacity);
|
||||||
let (serverbound_tx, serverbound_rx) = flume::bounded(server.0.incoming_packet_capacity);
|
let (serverbound_tx, serverbound_rx) = flume::bounded(server.0.incoming_packet_capacity);
|
||||||
|
|
||||||
let client_packet_channels: ClientPacketChannels = (serverbound_tx, clientbound_rx);
|
let client_packet_channels: S2cPacketChannels = (serverbound_tx, clientbound_rx);
|
||||||
let server_packet_channels: ServerPacketChannels = (clientbound_tx, serverbound_rx);
|
let server_packet_channels: C2sPacketChannels = (clientbound_tx, serverbound_rx);
|
||||||
|
|
||||||
let _ = msg.reply.send(client_packet_channels);
|
let _ = msg.reply.send(client_packet_channels);
|
||||||
|
|
||||||
|
@ -674,7 +674,7 @@ async fn handle_login(
|
||||||
|
|
||||||
if let Err(reason) = server.0.cfg.login(server, &npd).await {
|
if let Err(reason) = server.0.cfg.login(server, &npd).await {
|
||||||
log::info!("Disconnect at login: \"{reason}\"");
|
log::info!("Disconnect at login: \"{reason}\"");
|
||||||
c.0.write_packet(&login::Disconnect { reason }).await?;
|
c.0.write_packet(&login::s2c::Disconnect { reason }).await?;
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use serde::de::Visitor;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
use crate::protocol::{BoundedString, Decode, Encode};
|
use crate::protocol::{BoundedString, Decode, Encode};
|
||||||
use crate::Identifier;
|
use crate::Ident;
|
||||||
|
|
||||||
/// Represents formatted text in Minecraft's JSON text format.
|
/// Represents formatted text in Minecraft's JSON text format.
|
||||||
///
|
///
|
||||||
|
@ -308,14 +308,14 @@ enum ClickEvent {
|
||||||
enum HoverEvent {
|
enum HoverEvent {
|
||||||
ShowText(Box<Text>),
|
ShowText(Box<Text>),
|
||||||
ShowItem {
|
ShowItem {
|
||||||
id: Identifier,
|
id: Ident,
|
||||||
count: Option<i32>,
|
count: Option<i32>,
|
||||||
// TODO: tag
|
// TODO: tag
|
||||||
},
|
},
|
||||||
ShowEntity {
|
ShowEntity {
|
||||||
name: Box<Text>,
|
name: Box<Text>,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
typ: Identifier,
|
typ: Ident,
|
||||||
// TODO: id (hyphenated entity UUID as a string)
|
// TODO: id (hyphenated entity UUID as a string)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,8 @@ where
|
||||||
aabb
|
aabb
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes a normalized direction vector and returns a (yaw, pitch) tuple in degrees.
|
/// Takes a normalized direction vector and returns a (yaw, pitch) tuple in
|
||||||
|
/// degrees.
|
||||||
///
|
///
|
||||||
/// This function is the inverse of [`from_yaw_and_pitch`].
|
/// This function is the inverse of [`from_yaw_and_pitch`].
|
||||||
pub fn to_yaw_and_pitch(d: Vec3<f64>) -> (f32, f32) {
|
pub fn to_yaw_and_pitch(d: Vec3<f64>) -> (f32, f32) {
|
||||||
|
@ -65,7 +66,8 @@ pub fn to_yaw_and_pitch(d: Vec3<f64>) -> (f32, f32) {
|
||||||
(yaw, pitch)
|
(yaw, pitch)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes yaw and pitch angles (in degrees) and returns a normalized direction vector.
|
/// Takes yaw and pitch angles (in degrees) and returns a normalized direction
|
||||||
|
/// vector.
|
||||||
///
|
///
|
||||||
/// This function is the inverse of [`to_yaw_and_pitch`].
|
/// This function is the inverse of [`to_yaw_and_pitch`].
|
||||||
pub fn from_yaw_and_pitch(yaw: f32, pitch: f32) -> Vec3<f64> {
|
pub fn from_yaw_and_pitch(yaw: f32, pitch: f32) -> Vec3<f64> {
|
||||||
|
|
|
@ -3,9 +3,8 @@ use std::ops::Deref;
|
||||||
|
|
||||||
use rayon::iter::ParallelIterator;
|
use rayon::iter::ParallelIterator;
|
||||||
|
|
||||||
use crate::config::DimensionId;
|
|
||||||
use crate::slotmap::{Key, SlotMap};
|
use crate::slotmap::{Key, SlotMap};
|
||||||
use crate::{Chunks, ChunksMut, Clients, ClientsMut, Entities, EntitiesMut, Server};
|
use crate::{Chunks, ChunksMut, Clients, ClientsMut, DimensionId, Entities, EntitiesMut, Server};
|
||||||
|
|
||||||
pub struct Worlds {
|
pub struct Worlds {
|
||||||
sm: SlotMap<World>,
|
sm: SlotMap<World>,
|
||||||
|
|
Loading…
Reference in a new issue