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)
|
||||
}
|
||||
|
||||
pub fn to_degrees(self) -> f32 {
|
||||
self.0 as f32 / 256.0 * 360.0
|
||||
}
|
||||
// pub fn to_degrees(self) -> f32 {
|
||||
// self.0 as f32 / 256.0 * 360.0
|
||||
// }
|
||||
}
|
||||
|
||||
impl Encode for ByteAngle {
|
||||
|
|
|
@ -8,11 +8,10 @@ use std::ops::Deref;
|
|||
use bitvec::vec::BitVec;
|
||||
use num::Integer;
|
||||
use rayon::iter::{IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator};
|
||||
use vek::Vec2;
|
||||
|
||||
use crate::block::BlockState;
|
||||
use crate::packets::play::{
|
||||
BlockChange, ChunkDataAndUpdateLight, ChunkDataHeightmaps, ClientPlayPacket, MultiBlockChange,
|
||||
use crate::packets::play::s2c::{
|
||||
BlockChange, ChunkDataAndUpdateLight, ChunkDataHeightmaps, MultiBlockChange, S2cPlayPacket,
|
||||
};
|
||||
use crate::protocol::{Encode, Nbt};
|
||||
use crate::var_int::VarInt;
|
||||
|
@ -269,7 +268,7 @@ pub(crate) enum BlockChangePacket {
|
|||
Multi(MultiBlockChange),
|
||||
}
|
||||
|
||||
impl From<BlockChangePacket> for ClientPlayPacket {
|
||||
impl From<BlockChangePacket> for S2cPlayPacket {
|
||||
fn from(p: BlockChangePacket) -> Self {
|
||||
match p {
|
||||
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 vek::Vec3;
|
||||
|
||||
use crate::biome::{Biome, BiomeGrassColorModifier, BiomePrecipitation};
|
||||
use crate::block_pos::BlockPos;
|
||||
use crate::byte_angle::ByteAngle;
|
||||
use crate::config::{
|
||||
Biome, BiomeGrassColorModifier, BiomePrecipitation, Dimension, DimensionEffects, DimensionId,
|
||||
};
|
||||
use crate::dimension::{Dimension, DimensionEffects};
|
||||
use crate::entity::{velocity_to_packet_units, EntityType};
|
||||
pub use crate::packets::play::GameMode;
|
||||
use crate::packets::play::{
|
||||
use crate::packets::play::c2s::C2sPlayPacket;
|
||||
pub use crate::packets::play::s2c::GameMode;
|
||||
use crate::packets::play::s2c::{
|
||||
Biome as BiomeRegistryBiome, BiomeAdditionsSound, BiomeEffects, BiomeMoodSound, BiomeMusic,
|
||||
BiomeParticle, BiomeParticleOptions, BiomeProperty, BiomeRegistry, ChangeGameState,
|
||||
ChangeGameStateReason, ClientPlayPacket, DestroyEntities, DimensionCodec, DimensionType,
|
||||
DimensionTypeRegistry, DimensionTypeRegistryEntry, Disconnect, EntityHeadLook, EntityPosition,
|
||||
ChangeGameStateReason, DestroyEntities, DimensionCodec, DimensionType, DimensionTypeRegistry,
|
||||
DimensionTypeRegistryEntry, Disconnect, EntityHeadLook, EntityPosition,
|
||||
EntityPositionAndRotation, EntityRotation, EntityTeleport, EntityVelocity, JoinGame,
|
||||
KeepAliveClientbound, PlayerPositionAndLook, PlayerPositionAndLookFlags, ServerPlayPacket,
|
||||
KeepAliveClientbound, PlayerPositionAndLook, PlayerPositionAndLookFlags, S2cPlayPacket,
|
||||
SpawnPosition, UnloadChunk, UpdateViewDistance, UpdateViewPosition,
|
||||
};
|
||||
use crate::protocol::{BoundedInt, Nbt};
|
||||
use crate::server::ServerPacketChannels;
|
||||
use crate::server::C2sPacketChannels;
|
||||
use crate::slotmap::{Key, SlotMap};
|
||||
use crate::util::{chunks_in_view_distance, is_chunk_in_view_distance};
|
||||
use crate::var_int::VarInt;
|
||||
|
@ -113,8 +113,8 @@ pub struct ClientId(Key);
|
|||
/// Represents a client connected to the server after logging in.
|
||||
pub struct Client {
|
||||
/// Setting this to `None` disconnects the client.
|
||||
send: Option<Sender<ClientPlayPacket>>,
|
||||
recv: Receiver<ServerPlayPacket>,
|
||||
send: Option<Sender<S2cPlayPacket>>,
|
||||
recv: Receiver<C2sPlayPacket>,
|
||||
/// The tick this client was created.
|
||||
created_tick: Ticks,
|
||||
username: String,
|
||||
|
@ -170,7 +170,7 @@ impl<'a> Deref for ClientMut<'a> {
|
|||
|
||||
impl Client {
|
||||
pub(crate) fn new(
|
||||
packet_channels: ServerPacketChannels,
|
||||
packet_channels: C2sPacketChannels,
|
||||
username: String,
|
||||
uuid: Uuid,
|
||||
server: &Server,
|
||||
|
@ -301,7 +301,7 @@ impl<'a> ClientMut<'a> {
|
|||
|
||||
/// Attempts to enqueue a play packet to be sent to this client. The client
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -630,7 +630,7 @@ impl<'a> ClientMut<'a> {
|
|||
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;
|
||||
|
||||
fn handle_movement_packet(
|
||||
|
@ -658,7 +658,7 @@ impl<'a> ClientMut<'a> {
|
|||
}
|
||||
|
||||
match pkt {
|
||||
ServerPlayPacket::TeleportConfirm(p) => {
|
||||
C2sPlayPacket::TeleportConfirm(p) => {
|
||||
if client.pending_teleports == 0 {
|
||||
self.disconnect("Unexpected teleport confirmation");
|
||||
return;
|
||||
|
@ -677,11 +677,11 @@ impl<'a> ClientMut<'a> {
|
|||
));
|
||||
}
|
||||
}
|
||||
ServerPlayPacket::QueryBlockNbt(_) => {}
|
||||
ServerPlayPacket::SetDifficulty(_) => {}
|
||||
ServerPlayPacket::ChatMessageServerbound(_) => {}
|
||||
ServerPlayPacket::ClientStatus(_) => {}
|
||||
ServerPlayPacket::ClientSettings(p) => {
|
||||
C2sPlayPacket::QueryBlockNbt(_) => {}
|
||||
C2sPlayPacket::SetDifficulty(_) => {}
|
||||
C2sPlayPacket::ChatMessageServerbound(_) => {}
|
||||
C2sPlayPacket::ClientStatus(_) => {}
|
||||
C2sPlayPacket::ClientSettings(p) => {
|
||||
let old = client.settings.replace(Settings {
|
||||
locale: p.locale.0,
|
||||
view_distance: p.view_distance.0,
|
||||
|
@ -694,16 +694,16 @@ impl<'a> ClientMut<'a> {
|
|||
|
||||
client.events.push(Event::SettingsChanged(old));
|
||||
}
|
||||
ServerPlayPacket::TabCompleteServerbound(_) => {}
|
||||
ServerPlayPacket::ClickWindowButton(_) => {}
|
||||
ServerPlayPacket::ClickWindow(_) => {}
|
||||
ServerPlayPacket::CloseWindow(_) => {}
|
||||
ServerPlayPacket::PluginMessageServerbound(_) => {}
|
||||
ServerPlayPacket::EditBook(_) => {}
|
||||
ServerPlayPacket::QueryEntityNbt(_) => {}
|
||||
ServerPlayPacket::InteractEntity(_) => {}
|
||||
ServerPlayPacket::GenerateStructure(_) => {}
|
||||
ServerPlayPacket::KeepAliveServerbound(p) => {
|
||||
C2sPlayPacket::TabCompleteServerbound(_) => {}
|
||||
C2sPlayPacket::ClickWindowButton(_) => {}
|
||||
C2sPlayPacket::ClickWindow(_) => {}
|
||||
C2sPlayPacket::CloseWindow(_) => {}
|
||||
C2sPlayPacket::PluginMessageServerbound(_) => {}
|
||||
C2sPlayPacket::EditBook(_) => {}
|
||||
C2sPlayPacket::QueryEntityNbt(_) => {}
|
||||
C2sPlayPacket::InteractEntity(_) => {}
|
||||
C2sPlayPacket::GenerateStructure(_) => {}
|
||||
C2sPlayPacket::KeepAliveServerbound(p) => {
|
||||
let last_keepalive_id = client.last_keepalive_id;
|
||||
if client.got_keepalive {
|
||||
self.disconnect("Unexpected keepalive");
|
||||
|
@ -716,51 +716,51 @@ impl<'a> ClientMut<'a> {
|
|||
client.got_keepalive = true;
|
||||
}
|
||||
}
|
||||
ServerPlayPacket::LockDifficulty(_) => {}
|
||||
ServerPlayPacket::PlayerPosition(p) => {
|
||||
C2sPlayPacket::LockDifficulty(_) => {}
|
||||
C2sPlayPacket::PlayerPosition(p) => {
|
||||
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)
|
||||
}
|
||||
ServerPlayPacket::PlayerRotation(p) => {
|
||||
C2sPlayPacket::PlayerRotation(p) => {
|
||||
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.new_position,
|
||||
client.yaw,
|
||||
client.pitch,
|
||||
p.on_ground,
|
||||
),
|
||||
ServerPlayPacket::VehicleMoveServerbound(_) => {}
|
||||
ServerPlayPacket::SteerBoat(_) => {}
|
||||
ServerPlayPacket::PickItem(_) => {}
|
||||
ServerPlayPacket::CraftRecipeRequest(_) => {}
|
||||
ServerPlayPacket::PlayerAbilitiesServerbound(_) => {}
|
||||
ServerPlayPacket::PlayerDigging(_) => {}
|
||||
ServerPlayPacket::EntityAction(_) => {}
|
||||
ServerPlayPacket::SteerVehicle(_) => {}
|
||||
ServerPlayPacket::Pong(_) => {}
|
||||
ServerPlayPacket::SetRecipeBookState(_) => {}
|
||||
ServerPlayPacket::SetDisplayedRecipe(_) => {}
|
||||
ServerPlayPacket::NameItem(_) => {}
|
||||
ServerPlayPacket::ResourcePackStatus(_) => {}
|
||||
ServerPlayPacket::AdvancementTab(_) => {}
|
||||
ServerPlayPacket::SelectTrade(_) => {}
|
||||
ServerPlayPacket::SetBeaconEffect(_) => {}
|
||||
ServerPlayPacket::HeldItemChangeServerbound(_) => {}
|
||||
ServerPlayPacket::UpdateCommandBlock(_) => {}
|
||||
ServerPlayPacket::UpdateCommandBlockMinecart(_) => {}
|
||||
ServerPlayPacket::CreativeInventoryAction(_) => {}
|
||||
ServerPlayPacket::UpdateJigsawBlock(_) => {}
|
||||
ServerPlayPacket::UpdateStructureBlock(_) => {}
|
||||
ServerPlayPacket::UpdateSign(_) => {}
|
||||
ServerPlayPacket::PlayerArmSwing(_) => {}
|
||||
ServerPlayPacket::Spectate(_) => {}
|
||||
ServerPlayPacket::PlayerBlockPlacement(_) => {}
|
||||
ServerPlayPacket::UseItem(_) => {}
|
||||
C2sPlayPacket::VehicleMoveServerbound(_) => {}
|
||||
C2sPlayPacket::SteerBoat(_) => {}
|
||||
C2sPlayPacket::PickItem(_) => {}
|
||||
C2sPlayPacket::CraftRecipeRequest(_) => {}
|
||||
C2sPlayPacket::PlayerAbilitiesServerbound(_) => {}
|
||||
C2sPlayPacket::PlayerDigging(_) => {}
|
||||
C2sPlayPacket::EntityAction(_) => {}
|
||||
C2sPlayPacket::SteerVehicle(_) => {}
|
||||
C2sPlayPacket::Pong(_) => {}
|
||||
C2sPlayPacket::SetRecipeBookState(_) => {}
|
||||
C2sPlayPacket::SetDisplayedRecipe(_) => {}
|
||||
C2sPlayPacket::NameItem(_) => {}
|
||||
C2sPlayPacket::ResourcePackStatus(_) => {}
|
||||
C2sPlayPacket::AdvancementTab(_) => {}
|
||||
C2sPlayPacket::SelectTrade(_) => {}
|
||||
C2sPlayPacket::SetBeaconEffect(_) => {}
|
||||
C2sPlayPacket::HeldItemChangeServerbound(_) => {}
|
||||
C2sPlayPacket::UpdateCommandBlock(_) => {}
|
||||
C2sPlayPacket::UpdateCommandBlockMinecart(_) => {}
|
||||
C2sPlayPacket::CreativeInventoryAction(_) => {}
|
||||
C2sPlayPacket::UpdateJigsawBlock(_) => {}
|
||||
C2sPlayPacket::UpdateStructureBlock(_) => {}
|
||||
C2sPlayPacket::UpdateSign(_) => {}
|
||||
C2sPlayPacket::PlayerArmSwing(_) => {}
|
||||
C2sPlayPacket::Spectate(_) => {}
|
||||
C2sPlayPacket::PlayerBlockPlacement(_) => {}
|
||||
C2sPlayPacket::UseItem(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -803,9 +803,9 @@ pub struct Settings {
|
|||
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 {
|
||||
match send.try_send(pkt.into()) {
|
||||
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 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
|
||||
/// server.
|
||||
|
@ -223,203 +223,3 @@ pub enum ServerListPing<'a> {
|
|||
/// Ignores the query and disconnects from the client.
|
||||
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 crate::byte_angle::ByteAngle;
|
||||
use crate::packets::play::{
|
||||
ClientPlayPacket, EntityMetadata, SpawnEntity, SpawnExperienceOrb, SpawnLivingEntity,
|
||||
use crate::packets::play::s2c::{
|
||||
EntityMetadata, S2cPlayPacket, SpawnEntity, SpawnExperienceOrb, SpawnLivingEntity,
|
||||
SpawnPainting, SpawnPlayer,
|
||||
};
|
||||
use crate::protocol::RawBytes;
|
||||
|
@ -580,7 +580,7 @@ pub(crate) enum EntitySpawnPacket {
|
|||
SpawnPlayer(SpawnPlayer),
|
||||
}
|
||||
|
||||
impl From<EntitySpawnPacket> for ClientPlayPacket {
|
||||
impl From<EntitySpawnPacket> for S2cPlayPacket {
|
||||
fn from(pkt: EntitySpawnPacket) -> Self {
|
||||
match pkt {
|
||||
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_\/.-]+`.
|
||||
#[derive(Clone, Eq)]
|
||||
pub struct Identifier {
|
||||
pub struct Ident {
|
||||
ident: Cow<'static, AsciiStr>,
|
||||
/// The index of the ':' character in the string.
|
||||
/// If there is no namespace then it is `usize::MAX`.
|
||||
|
@ -33,12 +33,12 @@ pub struct ParseError {
|
|||
src: Cow<'static, str>,
|
||||
}
|
||||
|
||||
impl Identifier {
|
||||
impl Ident {
|
||||
/// Parses a new identifier from a string.
|
||||
///
|
||||
/// The string must match the regex `([a-z0-9_-]+:)?[a-z0-9_\/.-]+`.
|
||||
/// 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)]
|
||||
|
||||
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 {
|
||||
f.debug_tuple("Identifier").field(&self.as_str()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Identifier {
|
||||
impl FromStr for Ident {
|
||||
type Err = ParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Identifier::new(s.to_string())
|
||||
Ident::new(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Identifier> for String {
|
||||
fn from(id: Identifier) -> Self {
|
||||
impl From<Ident> for String {
|
||||
fn from(id: Ident) -> Self {
|
||||
id.ident.into_owned().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Identifier> for Cow<'static, str> {
|
||||
fn from(id: Identifier) -> Self {
|
||||
impl From<Ident> for Cow<'static, str> {
|
||||
fn from(id: Ident) -> Self {
|
||||
ascii_cow_to_str_cow(id.ident)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Identifier {
|
||||
impl AsRef<str> for Ident {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for Identifier {
|
||||
impl TryFrom<String> for Ident {
|
||||
type Error = ParseError;
|
||||
|
||||
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;
|
||||
|
||||
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 {
|
||||
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
|
||||
/// "apple" have the same meaning.
|
||||
impl PartialEq for Identifier {
|
||||
impl PartialEq for Ident {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.namespace().unwrap_or("minecraft") == other.namespace().unwrap_or("minecraft")
|
||||
&& 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) {
|
||||
self.namespace().unwrap_or("minecraft").hash(state);
|
||||
self.name().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode for Identifier {
|
||||
impl Encode for Ident {
|
||||
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
||||
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> {
|
||||
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> {
|
||||
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> {
|
||||
deserializer.deserialize_str(IdentifierVisitor)
|
||||
}
|
||||
|
@ -224,18 +224,18 @@ impl<'de> Deserialize<'de> for Identifier {
|
|||
struct IdentifierVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for IdentifierVisitor {
|
||||
type Value = Identifier;
|
||||
type Value = Ident;
|
||||
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "a valid Minecraft identifier")
|
||||
}
|
||||
|
||||
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> {
|
||||
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";
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
(|args: ::std::fmt::Arguments| match args.as_str() {
|
||||
Some(s) => $crate::Identifier::new(s).expect(errmsg),
|
||||
None => $crate::Identifier::new(args.to_string()).expect(errmsg),
|
||||
Some(s) => $crate::Ident::new(s).expect(errmsg),
|
||||
None => $crate::Ident::new(args.to_string()).expect(errmsg),
|
||||
})(format_args!($($arg)*))
|
||||
}}
|
||||
}
|
10
src/lib.rs
10
src/lib.rs
|
@ -7,6 +7,7 @@
|
|||
// missing_docs
|
||||
)]
|
||||
|
||||
pub mod biome;
|
||||
pub mod block;
|
||||
mod block_pos;
|
||||
mod byte_angle;
|
||||
|
@ -14,8 +15,9 @@ pub mod chunk;
|
|||
pub mod client;
|
||||
mod codec;
|
||||
pub mod config;
|
||||
pub mod dimension;
|
||||
pub mod entity;
|
||||
pub mod identifier;
|
||||
pub mod ident;
|
||||
mod packets;
|
||||
mod protocol;
|
||||
pub mod server;
|
||||
|
@ -27,12 +29,14 @@ mod var_long;
|
|||
pub mod world;
|
||||
|
||||
pub use async_trait::async_trait;
|
||||
pub use biome::{Biome, BiomeId};
|
||||
pub use block_pos::BlockPos;
|
||||
pub use chunk::{Chunk, ChunkPos, Chunks, ChunksMut};
|
||||
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 identifier::Identifier;
|
||||
pub use ident::Ident;
|
||||
pub use server::{start_server, NewClientData, Server, ShutdownResult};
|
||||
pub use text::{Text, TextFormat};
|
||||
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::byte_angle::ByteAngle;
|
||||
use crate::identifier::Identifier;
|
||||
use crate::protocol::{BoundedArray, BoundedInt, BoundedString, Decode, Encode, Nbt, RawBytes};
|
||||
use crate::var_int::VarInt;
|
||||
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
|
||||
/// packet.
|
||||
|
@ -353,9 +352,8 @@ pub mod handshake {
|
|||
|
||||
/// Packets and types used during the status state.
|
||||
pub mod status {
|
||||
use super::*;
|
||||
|
||||
// ==== Clientbound ====
|
||||
pub mod s2c {
|
||||
use super::super::*;
|
||||
|
||||
def_struct! {
|
||||
Response 0x00 {
|
||||
|
@ -369,8 +367,10 @@ pub mod status {
|
|||
payload: u64
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==== Serverbound ====
|
||||
pub mod c2s {
|
||||
use super::super::*;
|
||||
|
||||
def_struct! {
|
||||
Request 0x00 {}
|
||||
|
@ -382,12 +382,12 @@ pub mod status {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Packets and types used during the play state.
|
||||
pub mod login {
|
||||
use super::*;
|
||||
|
||||
// ==== Clientbound ====
|
||||
pub mod s2c {
|
||||
use super::super::*;
|
||||
|
||||
def_struct! {
|
||||
Disconnect 0x00 {
|
||||
|
@ -417,8 +417,10 @@ pub mod login {
|
|||
threshold: VarInt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==== Serverbound ====
|
||||
pub mod c2s {
|
||||
use super::super::*;
|
||||
|
||||
def_struct! {
|
||||
LoginStart 0x00 {
|
||||
|
@ -433,12 +435,12 @@ pub mod login {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Packets and types used during the play state.
|
||||
pub mod play {
|
||||
use super::*;
|
||||
|
||||
// ==== Clientbound ====
|
||||
pub mod s2c {
|
||||
use super::super::*;
|
||||
|
||||
def_struct! {
|
||||
SpawnEntity 0x00 {
|
||||
|
@ -506,7 +508,7 @@ pub mod play {
|
|||
def_struct! {
|
||||
SculkVibrationSignal 0x05 {
|
||||
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
|
||||
arrival_ticks: VarInt,
|
||||
}
|
||||
|
@ -807,12 +809,12 @@ pub mod play {
|
|||
/// The previous gamemode for the purpose of the F3+F4 gamemode switcher. (TODO: verify)
|
||||
/// Is `-1` if there was no previous gamemode.
|
||||
previous_gamemode: GameMode,
|
||||
dimension_names: Vec<Identifier>,
|
||||
dimension_names: Vec<Ident>,
|
||||
dimension_codec: Nbt<DimensionCodec>,
|
||||
/// The specification of the dimension being spawned into.
|
||||
dimension: Nbt<DimensionType>,
|
||||
/// 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.
|
||||
hashed_seed: i64,
|
||||
/// No longer used by the client.
|
||||
|
@ -841,13 +843,13 @@ pub mod play {
|
|||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct DimensionTypeRegistry {
|
||||
#[serde(rename = "type")]
|
||||
pub typ: Identifier,
|
||||
pub typ: Ident,
|
||||
pub value: Vec<DimensionTypeRegistryEntry>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct DimensionTypeRegistryEntry {
|
||||
pub name: Identifier,
|
||||
pub name: Ident,
|
||||
pub id: i32,
|
||||
pub element: DimensionType,
|
||||
}
|
||||
|
@ -862,7 +864,7 @@ pub mod play {
|
|||
pub respawn_anchor_works: bool,
|
||||
pub has_skylight: bool,
|
||||
pub bed_works: bool,
|
||||
pub effects: Identifier,
|
||||
pub effects: Ident,
|
||||
pub has_raids: bool,
|
||||
pub min_y: i32,
|
||||
pub height: i32,
|
||||
|
@ -875,13 +877,13 @@ pub mod play {
|
|||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct BiomeRegistry {
|
||||
#[serde(rename = "type")]
|
||||
pub typ: Identifier,
|
||||
pub typ: Ident,
|
||||
pub value: Vec<Biome>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Biome {
|
||||
pub name: Identifier,
|
||||
pub name: Ident,
|
||||
pub id: i32,
|
||||
pub element: BiomeProperty,
|
||||
}
|
||||
|
@ -909,7 +911,7 @@ pub mod play {
|
|||
pub grass_color: Option<i32>,
|
||||
pub grass_color_modifier: Option<String>,
|
||||
pub music: Option<BiomeMusic>,
|
||||
pub ambient_sound: Option<Identifier>,
|
||||
pub ambient_sound: Option<Ident>,
|
||||
pub additions_sound: Option<BiomeAdditionsSound>,
|
||||
pub mood_sound: Option<BiomeMoodSound>,
|
||||
}
|
||||
|
@ -917,20 +919,20 @@ pub mod play {
|
|||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct BiomeMusic {
|
||||
pub replace_current_music: bool,
|
||||
pub sound: Identifier,
|
||||
pub sound: Ident,
|
||||
pub max_delay: i32,
|
||||
pub min_delay: i32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct BiomeAdditionsSound {
|
||||
pub sound: Identifier,
|
||||
pub sound: Ident,
|
||||
pub tick_chance: f64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct BiomeMoodSound {
|
||||
pub sound: Identifier,
|
||||
pub sound: Ident,
|
||||
pub tick_delay: i32,
|
||||
pub offset: f64,
|
||||
pub block_search_extent: i32,
|
||||
|
@ -945,7 +947,7 @@ pub mod play {
|
|||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct BiomeParticleOptions {
|
||||
#[serde(rename = "type")]
|
||||
pub typ: Identifier,
|
||||
pub typ: Ident,
|
||||
}
|
||||
|
||||
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),* $(,)?
|
||||
} => {
|
||||
/// An enum of all clientbound play packets.
|
||||
/// An enum of all s2c play packets.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ClientPlayPacket {
|
||||
pub enum S2cPlayPacket {
|
||||
$($packet($packet)),*
|
||||
}
|
||||
|
||||
impl private::Sealed for ClientPlayPacket {}
|
||||
impl private::Sealed for S2cPlayPacket {}
|
||||
|
||||
$(
|
||||
impl From<$packet> for ClientPlayPacket {
|
||||
fn from(p: $packet) -> ClientPlayPacket {
|
||||
ClientPlayPacket::$packet(p)
|
||||
impl From<$packet> for S2cPlayPacket {
|
||||
fn from(p: $packet) -> S2cPlayPacket {
|
||||
S2cPlayPacket::$packet(p)
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
impl EncodePacket for ClientPlayPacket {
|
||||
impl EncodePacket for S2cPlayPacket {
|
||||
fn encode_packet(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
||||
match self {
|
||||
$(
|
||||
Self::$packet(p) => {
|
||||
VarInt($packet::PACKET_ID)
|
||||
.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)
|
||||
}
|
||||
)*
|
||||
|
@ -1131,7 +1133,7 @@ pub mod play {
|
|||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_client_play_packet_order() {
|
||||
fn test_s2c_play_packet_order() {
|
||||
let ids = [
|
||||
$(
|
||||
(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) {
|
||||
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,
|
||||
SpawnExperienceOrb,
|
||||
SpawnLivingEntity,
|
||||
|
@ -1182,8 +1184,10 @@ pub mod play {
|
|||
EntityTeleport,
|
||||
TimeUpdate,
|
||||
}
|
||||
}
|
||||
|
||||
// ==== Serverbound ====
|
||||
pub mod c2s {
|
||||
use super::super::*;
|
||||
|
||||
def_struct! {
|
||||
TeleportConfirm 0x00 {
|
||||
|
@ -1302,7 +1306,7 @@ pub mod play {
|
|||
|
||||
def_struct! {
|
||||
PluginMessageServerbound 0x0a {
|
||||
channel: Identifier,
|
||||
channel: Ident,
|
||||
data: RawBytes,
|
||||
}
|
||||
}
|
||||
|
@ -1434,7 +1438,7 @@ pub mod play {
|
|||
def_struct! {
|
||||
CraftRecipeRequest 0x18 {
|
||||
window_id: i8,
|
||||
recipe: Identifier,
|
||||
recipe: Ident,
|
||||
make_all: bool,
|
||||
}
|
||||
}
|
||||
|
@ -1545,7 +1549,7 @@ pub mod play {
|
|||
|
||||
def_struct! {
|
||||
SetDisplayedRecipe 0x1f {
|
||||
recipe_id: Identifier,
|
||||
recipe_id: Ident,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1566,7 +1570,7 @@ pub mod play {
|
|||
|
||||
def_enum! {
|
||||
AdvancementTab 0x22: VarInt {
|
||||
OpenedTab: Identifier = 0,
|
||||
OpenedTab: Ident = 0,
|
||||
ClosedScreen = 1,
|
||||
}
|
||||
}
|
||||
|
@ -1634,9 +1638,9 @@ pub mod play {
|
|||
def_struct! {
|
||||
UpdateJigsawBlock 0x29 {
|
||||
location: BlockPos,
|
||||
name: Identifier,
|
||||
target: Identifier,
|
||||
pool: Identifier,
|
||||
name: Ident,
|
||||
target: Ident,
|
||||
pool: Ident,
|
||||
final_state: 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),* $(,)?
|
||||
} => {
|
||||
/// An enum of all serverbound play packets.
|
||||
/// An enum of all client-to-server play packets.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ServerPlayPacket {
|
||||
pub enum C2sPlayPacket {
|
||||
$($packet($packet)),*
|
||||
}
|
||||
|
||||
impl private::Sealed for ServerPlayPacket {}
|
||||
impl private::Sealed for C2sPlayPacket {}
|
||||
|
||||
impl DecodePacket for ServerPlayPacket {
|
||||
fn decode_packet(r: &mut impl Read) -> anyhow::Result<ServerPlayPacket> {
|
||||
let packet_id = VarInt::decode(r).context("failed to read play packet ID")?.0;
|
||||
impl DecodePacket for C2sPlayPacket {
|
||||
fn decode_packet(r: &mut impl Read) -> anyhow::Result<C2sPlayPacket> {
|
||||
let packet_id = VarInt::decode(r).context("failed to read c2s play packet ID")?.0;
|
||||
match packet_id {
|
||||
$(
|
||||
$packet::PACKET_ID => {
|
||||
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)]
|
||||
#[test]
|
||||
fn test_server_play_packet_order() {
|
||||
fn test_c2s_play_packet_order() {
|
||||
let ids = [
|
||||
$(
|
||||
(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) {
|
||||
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,
|
||||
QueryBlockNbt,
|
||||
SetDifficulty,
|
||||
|
@ -1832,6 +1836,7 @@ pub mod play {
|
|||
UseItem,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
|
|
|
@ -27,18 +27,23 @@ use tokio::sync::{oneshot, Semaphore};
|
|||
use uuid::Uuid;
|
||||
|
||||
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::login::{
|
||||
self, EncryptionRequest, EncryptionResponse, LoginStart, LoginSuccess, SetCompression,
|
||||
};
|
||||
use crate::packets::play::{ClientPlayPacket, ServerPlayPacket};
|
||||
use crate::packets::status::{Ping, Pong, Request, Response};
|
||||
use crate::packets::login;
|
||||
use crate::packets::login::c2s::{EncryptionResponse, LoginStart};
|
||||
use crate::packets::login::s2c::{EncryptionRequest, LoginSuccess, SetCompression};
|
||||
use crate::packets::play::c2s::C2sPlayPacket;
|
||||
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::util::valid_username;
|
||||
use crate::var_int::VarInt;
|
||||
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
|
||||
/// outside the update loop. Servers are internally refcounted and can be shared
|
||||
|
@ -89,7 +94,7 @@ pub struct NewClientData {
|
|||
|
||||
struct NewClientMessage {
|
||||
ncd: NewClientData,
|
||||
reply: oneshot::Sender<ClientPacketChannels>,
|
||||
reply: oneshot::Sender<S2cPacketChannels>,
|
||||
}
|
||||
|
||||
/// The result type returned from [`ServerConfig::start`] after the server is
|
||||
|
@ -97,8 +102,8 @@ struct NewClientMessage {
|
|||
pub type ShutdownResult = Result<(), ShutdownError>;
|
||||
pub type ShutdownError = Box<dyn Error + Send + Sync + 'static>;
|
||||
|
||||
pub(crate) type ClientPacketChannels = (Sender<ServerPlayPacket>, Receiver<ClientPlayPacket>);
|
||||
pub(crate) type ServerPacketChannels = (Sender<ClientPlayPacket>, Receiver<ServerPlayPacket>);
|
||||
pub(crate) type S2cPacketChannels = (Sender<C2sPlayPacket>, Receiver<S2cPlayPacket>);
|
||||
pub(crate) type C2sPacketChannels = (Sender<S2cPlayPacket>, Receiver<C2sPlayPacket>);
|
||||
|
||||
impl Server {
|
||||
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)| {
|
||||
client.update(
|
||||
&server,
|
||||
&world.entities,
|
||||
&world.chunks,
|
||||
&world.meta,
|
||||
);
|
||||
client.update(&server, &world.entities, &world.chunks, &world.meta);
|
||||
});
|
||||
|
||||
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 (serverbound_tx, serverbound_rx) = flume::bounded(server.0.incoming_packet_capacity);
|
||||
|
||||
let client_packet_channels: ClientPacketChannels = (serverbound_tx, clientbound_rx);
|
||||
let server_packet_channels: ServerPacketChannels = (clientbound_tx, serverbound_rx);
|
||||
let client_packet_channels: S2cPacketChannels = (serverbound_tx, clientbound_rx);
|
||||
let server_packet_channels: C2sPacketChannels = (clientbound_tx, serverbound_rx);
|
||||
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ use serde::de::Visitor;
|
|||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::protocol::{BoundedString, Decode, Encode};
|
||||
use crate::Identifier;
|
||||
use crate::Ident;
|
||||
|
||||
/// Represents formatted text in Minecraft's JSON text format.
|
||||
///
|
||||
|
@ -308,14 +308,14 @@ enum ClickEvent {
|
|||
enum HoverEvent {
|
||||
ShowText(Box<Text>),
|
||||
ShowItem {
|
||||
id: Identifier,
|
||||
id: Ident,
|
||||
count: Option<i32>,
|
||||
// TODO: tag
|
||||
},
|
||||
ShowEntity {
|
||||
name: Box<Text>,
|
||||
#[serde(rename = "type")]
|
||||
typ: Identifier,
|
||||
typ: Ident,
|
||||
// TODO: id (hyphenated entity UUID as a string)
|
||||
},
|
||||
}
|
||||
|
|
|
@ -54,7 +54,8 @@ where
|
|||
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`].
|
||||
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)
|
||||
}
|
||||
|
||||
/// 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`].
|
||||
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 crate::config::DimensionId;
|
||||
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 {
|
||||
sm: SlotMap<World>,
|
||||
|
|
Loading…
Reference in a new issue