mirror of
https://github.com/italicsjenga/valence.git
synced 2024-12-23 22:41:30 +11:00
Make Ident
consistent with vanilla. (#309)
## Description Makes `Ident` consistent with vanilla by prepending the default namespace if none is provided in the constructor. Previously, the constructor did not normalize `foo` to `minecraft:foo`. This could lead to subtle bugs when the ident is eventually unwrapped with `Ident::as_str`. (comparing `foo` with `minecraft:foo` while inside the `Ident` was still handled correctly). ## Test Plan Steps: 1. `cargo test`
This commit is contained in:
parent
ba625b3217
commit
53573642ec
|
@ -221,7 +221,7 @@ impl Client {
|
||||||
|
|
||||||
pub fn send_custom_payload(&mut self, channel: Ident<&str>, data: &[u8]) {
|
pub fn send_custom_payload(&mut self, channel: Ident<&str>, data: &[u8]) {
|
||||||
self.write_packet(&CustomPayloadS2c {
|
self.write_packet(&CustomPayloadS2c {
|
||||||
channel,
|
channel: channel.into(),
|
||||||
data: data.into(),
|
data: data.into(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -682,13 +682,13 @@ fn initial_join(
|
||||||
|
|
||||||
let dimension_names = server
|
let dimension_names = server
|
||||||
.dimensions()
|
.dimensions()
|
||||||
.map(|(_, dim)| dim.name.as_str_ident())
|
.map(|(_, dim)| dim.name.as_str_ident().into())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let dimension_name = server.dimension(instance.dimension()).name.as_str_ident();
|
let dimension_name = server.dimension(instance.dimension()).name.as_str_ident();
|
||||||
|
|
||||||
let last_death_location = q.death_loc.0.map(|(id, pos)| GlobalPos {
|
let last_death_location = q.death_loc.0.map(|(id, pos)| GlobalPos {
|
||||||
dimension_name: server.dimension(id).name.as_str_ident(),
|
dimension_name: server.dimension(id).name.as_str_ident().into(),
|
||||||
position: pos,
|
position: pos,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -701,8 +701,8 @@ fn initial_join(
|
||||||
previous_game_mode: q.prev_game_mode.0.map(|g| g as i8).unwrap_or(-1),
|
previous_game_mode: q.prev_game_mode.0.map(|g| g as i8).unwrap_or(-1),
|
||||||
dimension_names,
|
dimension_names,
|
||||||
registry_codec: Cow::Borrowed(server.registry_codec()),
|
registry_codec: Cow::Borrowed(server.registry_codec()),
|
||||||
dimension_type_name: dimension_name,
|
dimension_type_name: dimension_name.into(),
|
||||||
dimension_name,
|
dimension_name: dimension_name.into(),
|
||||||
hashed_seed: q.hashed_seed.0 as i64,
|
hashed_seed: q.hashed_seed.0 as i64,
|
||||||
max_players: VarInt(0), // Ignored by clients.
|
max_players: VarInt(0), // Ignored by clients.
|
||||||
view_distance: VarInt(q.view_distance.0 as i32),
|
view_distance: VarInt(q.view_distance.0 as i32),
|
||||||
|
@ -756,13 +756,13 @@ fn respawn(
|
||||||
let dimension_name = server.dimension(instance.dimension()).name.as_str_ident();
|
let dimension_name = server.dimension(instance.dimension()).name.as_str_ident();
|
||||||
|
|
||||||
let last_death_location = death_loc.0.map(|(id, pos)| GlobalPos {
|
let last_death_location = death_loc.0.map(|(id, pos)| GlobalPos {
|
||||||
dimension_name: server.dimension(id).name.as_str_ident(),
|
dimension_name: server.dimension(id).name.as_str_ident().into(),
|
||||||
position: pos,
|
position: pos,
|
||||||
});
|
});
|
||||||
|
|
||||||
client.write_packet(&PlayerRespawnS2c {
|
client.write_packet(&PlayerRespawnS2c {
|
||||||
dimension_type_name: dimension_name,
|
dimension_type_name: dimension_name.into(),
|
||||||
dimension_name,
|
dimension_name: dimension_name.into(),
|
||||||
hashed_seed: hashed_seed.0,
|
hashed_seed: hashed_seed.0,
|
||||||
game_mode: (*game_mode).into(),
|
game_mode: (*game_mode).into(),
|
||||||
previous_game_mode: prev_game_mode.0.map(|g| g as i8).unwrap_or(-1),
|
previous_game_mode: prev_game_mode.0.map(|g| g as i8).unwrap_or(-1),
|
||||||
|
|
|
@ -138,7 +138,7 @@ pub struct CloseHandledScreen {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct CustomPayload {
|
pub struct CustomPayload {
|
||||||
pub client: Entity,
|
pub client: Entity,
|
||||||
pub channel: Ident<Box<str>>,
|
pub channel: Ident<String>,
|
||||||
pub data: Box<[u8]>,
|
pub data: Box<[u8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +263,7 @@ pub struct PickFromInventory {
|
||||||
pub struct CraftRequest {
|
pub struct CraftRequest {
|
||||||
pub client: Entity,
|
pub client: Entity,
|
||||||
pub window_id: i8,
|
pub window_id: i8,
|
||||||
pub recipe: Ident<Box<str>>,
|
pub recipe: Ident<String>,
|
||||||
pub make_all: bool,
|
pub make_all: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +354,7 @@ pub struct RecipeCategoryOptions {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct RecipeBookData {
|
pub struct RecipeBookData {
|
||||||
pub client: Entity,
|
pub client: Entity,
|
||||||
pub recipe_id: Ident<Box<str>>,
|
pub recipe_id: Ident<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -395,7 +395,7 @@ pub struct ResourcePackStatusChange {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct OpenAdvancementTab {
|
pub struct OpenAdvancementTab {
|
||||||
pub client: Entity,
|
pub client: Entity,
|
||||||
pub tab_id: Ident<Box<str>>,
|
pub tab_id: Ident<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -452,9 +452,9 @@ pub struct CreativeInventoryAction {
|
||||||
pub struct UpdateJigsaw {
|
pub struct UpdateJigsaw {
|
||||||
pub client: Entity,
|
pub client: Entity,
|
||||||
pub position: BlockPos,
|
pub position: BlockPos,
|
||||||
pub name: Ident<Box<str>>,
|
pub name: Ident<String>,
|
||||||
pub target: Ident<Box<str>>,
|
pub target: Ident<String>,
|
||||||
pub pool: Ident<Box<str>>,
|
pub pool: Ident<String>,
|
||||||
pub final_state: Box<str>,
|
pub final_state: Box<str>,
|
||||||
pub joint_type: Box<str>,
|
pub joint_type: Box<str>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ use tokio::sync::OwnedSemaphorePermit;
|
||||||
use tracing::{error, info, instrument, trace, warn};
|
use tracing::{error, info, instrument, trace, warn};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use valence_protocol::codec::{PacketDecoder, PacketEncoder};
|
use valence_protocol::codec::{PacketDecoder, PacketEncoder};
|
||||||
use valence_protocol::ident::Ident;
|
|
||||||
use valence_protocol::packet::c2s::handshake::handshake::NextState;
|
use valence_protocol::packet::c2s::handshake::handshake::NextState;
|
||||||
use valence_protocol::packet::c2s::handshake::HandshakeC2s;
|
use valence_protocol::packet::c2s::handshake::HandshakeC2s;
|
||||||
use valence_protocol::packet::c2s::login::{LoginHelloC2s, LoginKeyC2s, LoginQueryResponseC2s};
|
use valence_protocol::packet::c2s::login::{LoginHelloC2s, LoginKeyC2s, LoginQueryResponseC2s};
|
||||||
|
@ -35,7 +34,7 @@ use valence_protocol::raw::RawBytes;
|
||||||
use valence_protocol::text::Text;
|
use valence_protocol::text::Text;
|
||||||
use valence_protocol::types::Property;
|
use valence_protocol::types::Property;
|
||||||
use valence_protocol::var_int::VarInt;
|
use valence_protocol::var_int::VarInt;
|
||||||
use valence_protocol::{translation_key, Decode, MINECRAFT_VERSION, PROTOCOL_VERSION};
|
use valence_protocol::{ident_str, translation_key, Decode, MINECRAFT_VERSION, PROTOCOL_VERSION};
|
||||||
|
|
||||||
use crate::config::{AsyncCallbacks, ConnectionMode, ServerListPing};
|
use crate::config::{AsyncCallbacks, ConnectionMode, ServerListPing};
|
||||||
use crate::server::connection::InitialConnection;
|
use crate::server::connection::InitialConnection;
|
||||||
|
@ -440,7 +439,7 @@ pub(super) async fn login_velocity(
|
||||||
// Send Player Info Request into the Plugin Channel
|
// Send Player Info Request into the Plugin Channel
|
||||||
conn.send_packet(&LoginQueryRequestS2c {
|
conn.send_packet(&LoginQueryRequestS2c {
|
||||||
message_id: VarInt(message_id),
|
message_id: VarInt(message_id),
|
||||||
channel: Ident::new("velocity:player_info").unwrap(),
|
channel: ident_str!("velocity:player_info").into(),
|
||||||
data: RawBytes(&[VELOCITY_MIN_SUPPORTED_VERSION]),
|
data: RawBytes(&[VELOCITY_MIN_SUPPORTED_VERSION]),
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use num_integer::{div_ceil, Integer};
|
use num_integer::{div_ceil, Integer};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use valence::biome::BiomeId;
|
use valence::biome::BiomeId;
|
||||||
|
@ -210,11 +212,11 @@ where
|
||||||
converted_biome_palette.clear();
|
converted_biome_palette.clear();
|
||||||
|
|
||||||
for biome_name in palette {
|
for biome_name in palette {
|
||||||
let Ok(ident) = Ident::new(biome_name.as_str()) else {
|
let Ok(ident) = Ident::<Cow<str>>::new(biome_name) else {
|
||||||
return Err(ToValenceError::BadBiomeName)
|
return Err(ToValenceError::BadBiomeName)
|
||||||
};
|
};
|
||||||
|
|
||||||
converted_biome_palette.push(map_biome(ident));
|
converted_biome_palette.push(map_biome(ident.as_str_ident()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if converted_biome_palette.len() == 1 {
|
if converted_biome_palette.len() == 1 {
|
||||||
|
@ -274,7 +276,7 @@ where
|
||||||
let Ok(ident) = Ident::new(&ident[..]) else {
|
let Ok(ident) = Ident::new(&ident[..]) else {
|
||||||
return Err(ToValenceError::UnknownBlockEntityIdent(ident.clone()));
|
return Err(ToValenceError::UnknownBlockEntityIdent(ident.clone()));
|
||||||
};
|
};
|
||||||
let Some(kind) = BlockEntityKind::from_ident(ident) else {
|
let Some(kind) = BlockEntityKind::from_ident(ident.as_str_ident()) else {
|
||||||
return Err(ToValenceError::UnknownBlockEntityIdent(ident.as_str().to_string()));
|
return Err(ToValenceError::UnknownBlockEntityIdent(ident.as_str().to_string()));
|
||||||
};
|
};
|
||||||
let block_entity = BlockEntity {
|
let block_entity = BlockEntity {
|
||||||
|
|
|
@ -58,7 +58,7 @@ pub fn build() -> anyhow::Result<TokenStream> {
|
||||||
let str_name = &sound.name;
|
let str_name = &sound.name;
|
||||||
let name = ident(str_name.to_pascal_case());
|
let name = ident(str_name.to_pascal_case());
|
||||||
quote! {
|
quote! {
|
||||||
Self::#name => #str_name,
|
Self::#name => ident_str!(#str_name),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<TokenStream>();
|
.collect::<TokenStream>();
|
||||||
|
@ -105,8 +105,8 @@ pub fn build() -> anyhow::Result<TokenStream> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the snake_case name of this sound.
|
/// Gets the identifier of this sound.
|
||||||
pub const fn to_str(self) -> &'static str {
|
pub const fn to_ident(self) -> Ident<&'static str> {
|
||||||
match self {
|
match self {
|
||||||
#sound_to_str_arms
|
#sound_to_str_arms
|
||||||
}
|
}
|
||||||
|
|
|
@ -499,6 +499,8 @@ impl PacketDecoder {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::block_pos::BlockPos;
|
use crate::block_pos::BlockPos;
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
|
@ -521,7 +523,7 @@ mod tests {
|
||||||
e: f64,
|
e: f64,
|
||||||
f: BlockPos,
|
f: BlockPos,
|
||||||
g: Hand,
|
g: Hand,
|
||||||
h: Ident<&'a str>,
|
h: Ident<Cow<'a, str>>,
|
||||||
i: Option<ItemStack>,
|
i: Option<ItemStack>,
|
||||||
j: Text,
|
j: Text,
|
||||||
k: VarInt,
|
k: VarInt,
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
//! Resource identifiers.
|
//! Resource identifiers.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::{Borrow, Cow};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Formatter;
|
use std::fmt::Formatter;
|
||||||
use std::hash::{Hash, Hasher};
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
|
||||||
use serde::de::Error as _;
|
use serde::de::Error as _;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{nbt, Decode, Encode};
|
use crate::{nbt, Decode, Encode};
|
||||||
|
|
||||||
|
@ -21,114 +19,230 @@ use crate::{nbt, Decode, Encode};
|
||||||
/// A resource identifier is a string divided into a "namespace" part and a
|
/// A resource identifier is a string divided into a "namespace" part and a
|
||||||
/// "path" part. For instance `minecraft:apple` and `valence:frobnicator` are
|
/// "path" part. For instance `minecraft:apple` and `valence:frobnicator` are
|
||||||
/// both valid identifiers. A string must match the regex
|
/// both valid identifiers. A string must match the regex
|
||||||
/// `^([a-z0-9_.-]+:)?[a-z0-9_.-\/]+$` to be considered valid.
|
/// `^([a-z0-9_.-]+:)?[a-z0-9_.-\/]+$` to be successfully parsed.
|
||||||
///
|
///
|
||||||
/// If the namespace part is left off (the part before and including the colon)
|
/// While parsing, if the namespace part is left off (the part before and
|
||||||
/// the namespace is considered to be "minecraft" for the purposes of equality,
|
/// including the colon) then "minecraft:" is inserted at the beginning of the
|
||||||
/// ordering, and hashing.
|
/// string.
|
||||||
///
|
#[derive(Copy, Clone, Eq, Ord, Hash)]
|
||||||
/// # Contract
|
|
||||||
///
|
|
||||||
/// The type `S` must meet the following criteria:
|
|
||||||
/// - All calls to [`AsRef::as_ref`] and [`Borrow::borrow`][borrow] while the
|
|
||||||
/// string is wrapped in `Ident` must return the same value.
|
|
||||||
///
|
|
||||||
/// [borrow]: std::borrow::Borrow::borrow
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct Ident<S> {
|
pub struct Ident<S> {
|
||||||
string: S,
|
string: S,
|
||||||
path_start: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Ident<S> {
|
/// The error type created when an [`Ident`] cannot be parsed from a
|
||||||
/// Returns an Ident with the given fields
|
/// string. Contains the string that failed to parse.
|
||||||
///
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Error)]
|
||||||
/// # Safety
|
#[error("invalid resource identifier \"{0}\"")]
|
||||||
/// This function does not check for the validity of the Ident.
|
pub struct IdentError(pub String);
|
||||||
/// For a safe version use [`Ident::new`]
|
|
||||||
#[doc(hidden)]
|
impl<'a> Ident<Cow<'a, str>> {
|
||||||
pub const fn new_unchecked(string: S, path_start: usize) -> Self {
|
pub fn new(string: impl Into<Cow<'a, str>>) -> Result<Self, IdentError> {
|
||||||
Self { string, path_start }
|
parse(string.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: AsRef<str>> Ident<S> {
|
impl<S> Ident<S> {
|
||||||
pub fn new(string: S) -> Result<Self, IdentError<S>> {
|
/// Internal API. Do not use.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub const fn new_unchecked(string: S) -> Self {
|
||||||
|
Self { string }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &str
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
self.string.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str_ident(&self) -> Ident<&str>
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
Ident {
|
||||||
|
string: self.as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_inner(self) -> S {
|
||||||
|
self.string
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the namespace part of this resource identifier (the part before
|
||||||
|
/// the colon).
|
||||||
|
pub fn namespace(&self) -> &str
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
self.namespace_and_path().0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the path part of this resource identifier (the part after the
|
||||||
|
/// colon).
|
||||||
|
pub fn path(&self) -> &str
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
self.namespace_and_path().1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn namespace_and_path(&self) -> (&str, &str)
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
self.as_str()
|
||||||
|
.split_once(':')
|
||||||
|
.expect("invalid resource identifier")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(string: Cow<str>) -> Result<Ident<Cow<str>>, IdentError> {
|
||||||
let check_namespace = |s: &str| {
|
let check_namespace = |s: &str| {
|
||||||
!s.is_empty()
|
!s.is_empty()
|
||||||
&& s.chars()
|
&& s.chars()
|
||||||
.all(|c| matches!(c, 'a'..='z' | '0'..='9' | '_' | '.' | '-'))
|
.all(|c| matches!(c, 'a'..='z' | '0'..='9' | '_' | '.' | '-'))
|
||||||
};
|
};
|
||||||
|
|
||||||
let check_path = |s: &str| {
|
let check_path = |s: &str| {
|
||||||
!s.is_empty()
|
!s.is_empty()
|
||||||
&& s.chars()
|
&& s.chars()
|
||||||
.all(|c| matches!(c, 'a'..='z' | '0'..='9' | '_' | '.' | '-' | '/'))
|
.all(|c| matches!(c, 'a'..='z' | '0'..='9' | '_' | '.' | '-' | '/'))
|
||||||
};
|
};
|
||||||
|
|
||||||
let str = string.as_ref();
|
match string.split_once(':') {
|
||||||
|
|
||||||
match str.split_once(':') {
|
|
||||||
Some((namespace, path)) if check_namespace(namespace) && check_path(path) => {
|
Some((namespace, path)) if check_namespace(namespace) && check_path(path) => {
|
||||||
let path_start = namespace.len() + 1;
|
Ok(Ident { string })
|
||||||
Ok(Self { string, path_start })
|
|
||||||
}
|
}
|
||||||
None if check_path(str) => Ok(Self {
|
None if check_path(&string) => Ok(Ident {
|
||||||
string,
|
string: format!("minecraft:{string}").into(),
|
||||||
path_start: 0,
|
|
||||||
}),
|
}),
|
||||||
_ => Err(IdentError(string)),
|
_ => Err(IdentError(string.into())),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the namespace part of this resource identifier.
|
|
||||||
///
|
|
||||||
/// If the underlying string does not contain a namespace followed by a
|
|
||||||
/// ':' character, `"minecraft"` is returned.
|
|
||||||
pub fn namespace(&self) -> &str {
|
|
||||||
if self.path_start == 0 {
|
|
||||||
"minecraft"
|
|
||||||
} else {
|
|
||||||
&self.string.as_ref()[..self.path_start - 1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path(&self) -> &str {
|
|
||||||
&self.string.as_ref()[self.path_start..]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the underlying string as a `str`.
|
|
||||||
pub fn as_str(&self) -> &str {
|
|
||||||
self.string.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Borrows the underlying string and returns it as an `Ident`. This
|
|
||||||
/// operation is infallible and no checks need to be performed.
|
|
||||||
pub fn as_str_ident(&self) -> Ident<&str> {
|
|
||||||
Ident {
|
|
||||||
string: self.string.as_ref(),
|
|
||||||
path_start: self.path_start,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consumes the identifier and returns the underlying string.
|
|
||||||
pub fn into_inner(self) -> S {
|
|
||||||
self.string
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, S: ?Sized> Ident<&'a S> {
|
impl<S: AsRef<str>> AsRef<str> for Ident<S> {
|
||||||
/// Converts the underlying string to its owned representation and returns
|
fn as_ref(&self) -> &str {
|
||||||
/// it as an `Ident`. This operation is infallible and no checks need to be
|
self.string.as_ref()
|
||||||
/// performed.
|
|
||||||
pub fn to_owned_ident(&self) -> Ident<S::Owned>
|
|
||||||
where
|
|
||||||
S: ToOwned,
|
|
||||||
S::Owned: AsRef<str>,
|
|
||||||
{
|
|
||||||
Ident {
|
|
||||||
string: self.string.to_owned(),
|
|
||||||
path_start: self.path_start,
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> AsRef<S> for Ident<S> {
|
||||||
|
fn as_ref(&self) -> &S {
|
||||||
|
&self.string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Borrow<str>> Borrow<str> for Ident<S> {
|
||||||
|
fn borrow(&self) -> &str {
|
||||||
|
self.string.borrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Ident<String>> for String {
|
||||||
|
fn from(value: Ident<String>) -> Self {
|
||||||
|
value.into_inner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Ident<Cow<'a, str>>> for Cow<'a, str> {
|
||||||
|
fn from(value: Ident<Cow<'a, str>>) -> Self {
|
||||||
|
value.into_inner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Ident<Cow<'a, str>>> for Ident<String> {
|
||||||
|
fn from(value: Ident<Cow<'a, str>>) -> Self {
|
||||||
|
Self {
|
||||||
|
string: value.string.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Ident<String>> for Ident<Cow<'a, str>> {
|
||||||
|
fn from(value: Ident<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
string: value.string.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Ident<&'a str>> for Ident<Cow<'a, str>> {
|
||||||
|
fn from(value: Ident<&'a str>) -> Self {
|
||||||
|
Ident {
|
||||||
|
string: value.string.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Ident<&'a str>> for Ident<String> {
|
||||||
|
fn from(value: Ident<&'a str>) -> Self {
|
||||||
|
Ident {
|
||||||
|
string: value.string.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Ident<String> {
|
||||||
|
type Err = IdentError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(Ident::new(s)?.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Ident<Cow<'static, str>> {
|
||||||
|
type Err = IdentError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ident::<String>::try_from(s).map(From::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a str> for Ident<String> {
|
||||||
|
type Error = IdentError;
|
||||||
|
|
||||||
|
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Ident::new(value)?.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<String> for Ident<String> {
|
||||||
|
type Error = IdentError;
|
||||||
|
|
||||||
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Ident::new(value)?.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<Cow<'a, str>> for Ident<String> {
|
||||||
|
type Error = IdentError;
|
||||||
|
|
||||||
|
fn try_from(value: Cow<'a, str>) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Ident::new(value)?.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a str> for Ident<Cow<'a, str>> {
|
||||||
|
type Error = IdentError;
|
||||||
|
|
||||||
|
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||||
|
Self::new(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<String> for Ident<Cow<'a, str>> {
|
||||||
|
type Error = IdentError;
|
||||||
|
|
||||||
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
Self::new(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<Cow<'a, str>> for Ident<Cow<'a, str>> {
|
||||||
|
type Error = IdentError;
|
||||||
|
|
||||||
|
fn try_from(value: Cow<'a, str>) -> Result<Self, Self::Error> {
|
||||||
|
Self::new(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,121 +252,56 @@ impl<S: fmt::Debug> fmt::Debug for Ident<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<Ident<&'a str>> for Ident<String> {
|
impl<S: fmt::Display> fmt::Display for Ident<S> {
|
||||||
fn from(value: Ident<&'a str>) -> Self {
|
|
||||||
value.to_owned_ident()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<Ident<&'a str>> for Ident<Box<str>> {
|
|
||||||
fn from(value: Ident<&'a str>) -> Self {
|
|
||||||
Ident {
|
|
||||||
string: value.string.into(),
|
|
||||||
path_start: value.path_start,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<Ident<&'a str>> for Ident<Cow<'a, str>> {
|
|
||||||
fn from(value: Ident<&'a str>) -> Self {
|
|
||||||
Ident {
|
|
||||||
string: Cow::Borrowed(value.string),
|
|
||||||
path_start: value.path_start,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<Ident<Cow<'a, str>>> for Ident<String> {
|
|
||||||
fn from(value: Ident<Cow<'a, str>>) -> Self {
|
|
||||||
Ident {
|
|
||||||
string: value.string.into_owned(),
|
|
||||||
path_start: value.path_start,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Ident<String> {
|
|
||||||
type Err = IdentError<String>;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
Ident::new(s.to_owned())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<String> for Ident<String> {
|
|
||||||
type Error = IdentError<String>;
|
|
||||||
|
|
||||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
|
||||||
Ident::new(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> From<Ident<S>> for String
|
|
||||||
where
|
|
||||||
S: Into<String> + AsRef<str>,
|
|
||||||
{
|
|
||||||
fn from(id: Ident<S>) -> Self {
|
|
||||||
if id.path_start == 0 {
|
|
||||||
format!("minecraft:{}", id.string.as_ref())
|
|
||||||
} else {
|
|
||||||
id.string.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> fmt::Display for Ident<S>
|
|
||||||
where
|
|
||||||
S: AsRef<str>,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}:{}", self.namespace(), self.path())
|
self.string.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, T> PartialEq<Ident<T>> for Ident<S>
|
impl<S, T> PartialEq<Ident<T>> for Ident<S>
|
||||||
where
|
where
|
||||||
S: AsRef<str>,
|
S: PartialEq<T>,
|
||||||
T: AsRef<str>,
|
|
||||||
{
|
{
|
||||||
fn eq(&self, other: &Ident<T>) -> bool {
|
fn eq(&self, other: &Ident<T>) -> bool {
|
||||||
self.namespace() == other.namespace() && self.path() == other.path()
|
self.string == other.string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Eq for Ident<S> where S: AsRef<str> {}
|
|
||||||
|
|
||||||
impl<S, T> PartialOrd<Ident<T>> for Ident<S>
|
impl<S, T> PartialOrd<Ident<T>> for Ident<S>
|
||||||
where
|
where
|
||||||
S: AsRef<str>,
|
S: PartialOrd<T>,
|
||||||
T: AsRef<str>,
|
|
||||||
{
|
{
|
||||||
fn partial_cmp(&self, other: &Ident<T>) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Ident<T>) -> Option<Ordering> {
|
||||||
(self.namespace(), self.path()).partial_cmp(&(other.namespace(), other.path()))
|
self.string.partial_cmp(&other.string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Ord for Ident<S>
|
impl<S: Encode> Encode for Ident<S> {
|
||||||
where
|
fn encode(&self, w: impl Write) -> anyhow::Result<()> {
|
||||||
S: AsRef<str>,
|
self.as_ref().encode(w)
|
||||||
{
|
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
|
||||||
(self.namespace(), self.path()).cmp(&(other.namespace(), other.path()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Hash for Ident<S>
|
impl<'a, S> Decode<'a> for Ident<S>
|
||||||
where
|
where
|
||||||
S: AsRef<str>,
|
S: Decode<'a>,
|
||||||
|
Ident<S>: TryFrom<S, Error = IdentError>,
|
||||||
{
|
{
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
|
||||||
(self.namespace(), self.path()).hash(state);
|
Ok(Ident::try_from(S::decode(r)?)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Serialize for Ident<T>
|
impl<S> From<Ident<S>> for nbt::Value
|
||||||
where
|
where
|
||||||
T: Serialize,
|
S: Into<nbt::Value>,
|
||||||
{
|
{
|
||||||
|
fn from(value: Ident<S>) -> Self {
|
||||||
|
value.into_inner().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Serialize> Serialize for Ident<T> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
|
@ -261,67 +310,19 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de, T> Deserialize<'de> for Ident<T>
|
impl<'de, S> Deserialize<'de> for Ident<S>
|
||||||
where
|
where
|
||||||
T: Deserialize<'de> + AsRef<str>,
|
S: Deserialize<'de>,
|
||||||
|
Ident<S>: TryFrom<S, Error = IdentError>,
|
||||||
{
|
{
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
Ident::new(T::deserialize(deserializer)?).map_err(D::Error::custom)
|
Ident::try_from(S::deserialize(deserializer)?).map_err(D::Error::custom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Encode> Encode for Ident<S> {
|
|
||||||
fn encode(&self, w: impl Write) -> anyhow::Result<()> {
|
|
||||||
self.string.encode(w)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, S> Decode<'a> for Ident<S>
|
|
||||||
where
|
|
||||||
S: Decode<'a> + AsRef<str>,
|
|
||||||
{
|
|
||||||
fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
|
|
||||||
Ident::new(S::decode(r)?).map_err(|e| anyhow!("{e:#}"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> From<Ident<S>> for nbt::Value
|
|
||||||
where
|
|
||||||
S: Into<nbt::Value>,
|
|
||||||
{
|
|
||||||
fn from(id: Ident<S>) -> Self {
|
|
||||||
id.string.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The error type created when an [`Ident`] cannot be parsed from a
|
|
||||||
/// string. Contains the offending string.
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
pub struct IdentError<S>(pub S);
|
|
||||||
|
|
||||||
impl<S> fmt::Debug for IdentError<S>
|
|
||||||
where
|
|
||||||
S: AsRef<str>,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
f.debug_tuple("IdentError").field(&self.0.as_ref()).finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> fmt::Display for IdentError<S>
|
|
||||||
where
|
|
||||||
S: AsRef<str>,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(f, "invalid resource identifier \"{}\"", self.0.as_ref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> Error for IdentError<S> where S: AsRef<str> {}
|
|
||||||
|
|
||||||
/// Convenience macro for constructing an [`Ident<String>`] from a format
|
/// Convenience macro for constructing an [`Ident<String>`] from a format
|
||||||
/// string.
|
/// string.
|
||||||
///
|
///
|
||||||
|
@ -350,17 +351,12 @@ impl<S> Error for IdentError<S> where S: AsRef<str> {}
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! ident {
|
macro_rules! ident {
|
||||||
($($arg:tt)*) => {{
|
($($arg:tt)*) => {{
|
||||||
$crate::ident::Ident::new(::std::format!($($arg)*)).unwrap()
|
$crate::ident::Ident::<String>::try_from(::std::format!($($arg)*)).unwrap()
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::hash_map::DefaultHasher;
|
|
||||||
use std::hash::Hasher;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_namespace_and_path() {
|
fn check_namespace_and_path() {
|
||||||
let id = ident!("namespace:path");
|
let id = ident!("namespace:path");
|
||||||
|
@ -397,15 +393,4 @@ mod tests {
|
||||||
fn equality() {
|
fn equality() {
|
||||||
assert_eq!(ident!("minecraft:my.identifier"), ident!("my.identifier"));
|
assert_eq!(ident!("minecraft:my.identifier"), ident!("my.identifier"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn equal_hash() {
|
|
||||||
let mut h1 = DefaultHasher::new();
|
|
||||||
ident!("minecraft:my.identifier").hash(&mut h1);
|
|
||||||
|
|
||||||
let mut h2 = DefaultHasher::new();
|
|
||||||
ident!("my.identifier").hash(&mut h2);
|
|
||||||
|
|
||||||
assert_eq!(h1.finish(), h2.finish());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub enum AdvancementTabC2s<'a> {
|
pub enum AdvancementTabC2s<'a> {
|
||||||
OpenedTab { tab_id: Ident<&'a str> },
|
OpenedTab { tab_id: Ident<Cow<'a, str>> },
|
||||||
ClosedScreen,
|
ClosedScreen,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub struct CraftRequestC2s<'a> {
|
pub struct CraftRequestC2s<'a> {
|
||||||
pub window_id: i8,
|
pub window_id: i8,
|
||||||
pub recipe: Ident<&'a str>,
|
pub recipe: Ident<Cow<'a, str>>,
|
||||||
pub make_all: bool,
|
pub make_all: bool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::raw::RawBytes;
|
use crate::raw::RawBytes;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub struct CustomPayloadC2s<'a> {
|
pub struct CustomPayloadC2s<'a> {
|
||||||
pub channel: Ident<&'a str>,
|
pub channel: Ident<Cow<'a, str>>,
|
||||||
pub data: RawBytes<'a>,
|
pub data: RawBytes<'a>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub struct RecipeBookDataC2s<'a> {
|
pub struct RecipeBookDataC2s<'a> {
|
||||||
pub recipe_id: Ident<&'a str>,
|
pub recipe_id: Ident<Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::block_pos::BlockPos;
|
use crate::block_pos::BlockPos;
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub struct UpdateJigsawC2s<'a> {
|
pub struct UpdateJigsawC2s<'a> {
|
||||||
pub position: BlockPos,
|
pub position: BlockPos,
|
||||||
pub name: Ident<&'a str>,
|
pub name: Ident<Cow<'a, str>>,
|
||||||
pub target: Ident<&'a str>,
|
pub target: Ident<Cow<'a, str>>,
|
||||||
pub pool: Ident<&'a str>,
|
pub pool: Ident<Cow<'a, str>>,
|
||||||
pub final_state: &'a str,
|
pub final_state: &'a str,
|
||||||
pub joint_type: &'a str,
|
pub joint_type: &'a str,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::raw::RawBytes;
|
use crate::raw::RawBytes;
|
||||||
use crate::var_int::VarInt;
|
use crate::var_int::VarInt;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub struct LoginQueryRequestS2c<'a> {
|
pub struct LoginQueryRequestS2c<'a> {
|
||||||
pub message_id: VarInt,
|
pub message_id: VarInt,
|
||||||
pub channel: Ident<&'a str>,
|
pub channel: Ident<Cow<'a, str>>,
|
||||||
pub data: RawBytes<'a>,
|
pub data: RawBytes<'a>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,16 @@ use crate::{Decode, Encode};
|
||||||
#[derive(Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub struct AdvancementUpdateS2c<'a> {
|
pub struct AdvancementUpdateS2c<'a> {
|
||||||
pub reset: bool,
|
pub reset: bool,
|
||||||
pub advancement_mapping: Vec<(Ident<&'a str>, Advancement<'a>)>,
|
pub advancement_mapping: Vec<(Ident<Cow<'a, str>>, Advancement<'a>)>,
|
||||||
pub identifiers: Vec<Ident<&'a str>>,
|
pub identifiers: Vec<Ident<Cow<'a, str>>>,
|
||||||
pub progress_mapping: Vec<(Ident<&'a str>, Vec<AdvancementCriteria<'a>>)>,
|
pub progress_mapping: Vec<(Ident<Cow<'a, str>>, Vec<AdvancementCriteria<'a>>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, Encode, Decode)]
|
#[derive(Clone, PartialEq, Debug, Encode, Decode)]
|
||||||
pub struct Advancement<'a> {
|
pub struct Advancement<'a> {
|
||||||
pub parent_id: Option<Ident<&'a str>>,
|
pub parent_id: Option<Ident<Cow<'a, str>>>,
|
||||||
pub display_data: Option<AdvancementDisplay<'a>>,
|
pub display_data: Option<AdvancementDisplay<'a>>,
|
||||||
pub criteria: Vec<(Ident<&'a str>, ())>,
|
pub criteria: Vec<(Ident<Cow<'a, str>>, ())>,
|
||||||
pub requirements: Vec<AdvancementRequirements<'a>>,
|
pub requirements: Vec<AdvancementRequirements<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,14 +35,14 @@ pub struct AdvancementDisplay<'a> {
|
||||||
pub icon: Option<ItemStack>,
|
pub icon: Option<ItemStack>,
|
||||||
pub frame_type: VarInt,
|
pub frame_type: VarInt,
|
||||||
pub flags: i32,
|
pub flags: i32,
|
||||||
pub background_texture: Option<Ident<&'a str>>,
|
pub background_texture: Option<Ident<Cow<'a, str>>>,
|
||||||
pub x_coord: f32,
|
pub x_coord: f32,
|
||||||
pub y_coord: f32,
|
pub y_coord: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||||
pub struct AdvancementCriteria<'a> {
|
pub struct AdvancementCriteria<'a> {
|
||||||
pub criterion_identifier: Ident<&'a str>,
|
pub criterion_identifier: Ident<Cow<'a, str>>,
|
||||||
/// If present, the criteria has been achieved at the
|
/// If present, the criteria has been achieved at the
|
||||||
/// time wrapped; time represented as millis since epoch
|
/// time wrapped; time represented as millis since epoch
|
||||||
pub criterion_progress: Option<i64>,
|
pub criterion_progress: Option<i64>,
|
||||||
|
@ -56,7 +56,7 @@ impl Encode for AdvancementDisplay<'_> {
|
||||||
self.frame_type.encode(&mut w)?;
|
self.frame_type.encode(&mut w)?;
|
||||||
self.flags.encode(&mut w)?;
|
self.flags.encode(&mut w)?;
|
||||||
|
|
||||||
match self.background_texture {
|
match self.background_texture.as_ref() {
|
||||||
None => {}
|
None => {}
|
||||||
Some(texture) => texture.encode(&mut w)?,
|
Some(texture) => texture.encode(&mut w)?,
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ impl<'a> Decode<'a> for AdvancementDisplay<'a> {
|
||||||
let flags = i32::decode(r)?;
|
let flags = i32::decode(r)?;
|
||||||
|
|
||||||
let background_texture = if flags & 1 == 1 {
|
let background_texture = if flags & 1 == 1 {
|
||||||
Some(Ident::<&'a str>::decode(r)?)
|
Some(Ident::decode(r)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
|
@ -86,10 +87,10 @@ pub enum Parser<'a> {
|
||||||
Dimension,
|
Dimension,
|
||||||
GameMode,
|
GameMode,
|
||||||
Time,
|
Time,
|
||||||
ResourceOrTag { registry: Ident<&'a str> },
|
ResourceOrTag { registry: Ident<Cow<'a, str>> },
|
||||||
ResourceOrTagKey { registry: Ident<&'a str> },
|
ResourceOrTagKey { registry: Ident<Cow<'a, str>> },
|
||||||
Resource { registry: Ident<&'a str> },
|
Resource { registry: Ident<Cow<'a, str>> },
|
||||||
ResourceKey { registry: Ident<&'a str> },
|
ResourceKey { registry: Ident<Cow<'a, str>> },
|
||||||
TemplateMirror,
|
TemplateMirror,
|
||||||
TemplateRotation,
|
TemplateRotation,
|
||||||
Uuid,
|
Uuid,
|
||||||
|
@ -182,12 +183,12 @@ impl<'a> Decode<'a> for Node<'a> {
|
||||||
name: <&str>::decode(r)?,
|
name: <&str>::decode(r)?,
|
||||||
parser: Parser::decode(r)?,
|
parser: Parser::decode(r)?,
|
||||||
suggestion: if flags & 0x10 != 0 {
|
suggestion: if flags & 0x10 != 0 {
|
||||||
Some(match Ident::<&str>::decode(r)?.path() {
|
Some(match Ident::<Cow<str>>::decode(r)?.as_str() {
|
||||||
"ask_server" => Suggestion::AskServer,
|
"minecraft:ask_server" => Suggestion::AskServer,
|
||||||
"all_recipes" => Suggestion::AllRecipes,
|
"minecraft:all_recipes" => Suggestion::AllRecipes,
|
||||||
"available_sounds" => Suggestion::AvailableSounds,
|
"minecraft:available_sounds" => Suggestion::AvailableSounds,
|
||||||
"available_biomes" => Suggestion::AvailableBiomes,
|
"minecraft:available_biomes" => Suggestion::AvailableBiomes,
|
||||||
"summonable_entities" => Suggestion::SummonableEntities,
|
"minecraft:summonable_entities" => Suggestion::SummonableEntities,
|
||||||
other => bail!("unknown command suggestion type of \"{other}\""),
|
other => bail!("unknown command suggestion type of \"{other}\""),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub struct CraftFailedResponseS2c<'a> {
|
pub struct CraftFailedResponseS2c<'a> {
|
||||||
pub window_id: u8,
|
pub window_id: u8,
|
||||||
pub recipe: Ident<&'a str>,
|
pub recipe: Ident<Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::raw::RawBytes;
|
use crate::raw::RawBytes;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub struct CustomPayloadS2c<'a> {
|
pub struct CustomPayloadS2c<'a> {
|
||||||
pub channel: Ident<&'a str>,
|
pub channel: Ident<Cow<'a, str>>,
|
||||||
pub data: RawBytes<'a>,
|
pub data: RawBytes<'a>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
|
@ -12,7 +14,7 @@ pub struct EntityAttributesS2c<'a> {
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, Encode, Decode)]
|
#[derive(Clone, PartialEq, Debug, Encode, Decode)]
|
||||||
pub struct AttributeProperty<'a> {
|
pub struct AttributeProperty<'a> {
|
||||||
pub key: Ident<&'a str>,
|
pub key: Ident<Cow<'a, str>>,
|
||||||
pub value: f64,
|
pub value: f64,
|
||||||
pub modifiers: Vec<AttributeModifier>,
|
pub modifiers: Vec<AttributeModifier>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub struct ExplosionS2c<'a> {
|
pub struct ExplosionS2c<'a> {
|
||||||
pub window_id: u8,
|
pub window_id: u8,
|
||||||
pub recipe: Ident<&'a str>,
|
pub recipe: Ident<Cow<'a, str>>,
|
||||||
pub make_all: bool,
|
pub make_all: bool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub struct FeaturesS2c<'a> {
|
pub struct FeaturesS2c<'a> {
|
||||||
pub features: Vec<Ident<&'a str>>,
|
pub features: Vec<Ident<Cow<'a, str>>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,10 @@ pub struct GameJoinS2c<'a> {
|
||||||
pub game_mode: GameMode,
|
pub game_mode: GameMode,
|
||||||
/// Same values as `game_mode` but with -1 to indicate no previous.
|
/// Same values as `game_mode` but with -1 to indicate no previous.
|
||||||
pub previous_game_mode: i8,
|
pub previous_game_mode: i8,
|
||||||
pub dimension_names: Vec<Ident<&'a str>>,
|
pub dimension_names: Vec<Ident<Cow<'a, str>>>,
|
||||||
pub registry_codec: Cow<'a, Compound>,
|
pub registry_codec: Cow<'a, Compound>,
|
||||||
pub dimension_type_name: Ident<&'a str>,
|
pub dimension_type_name: Ident<Cow<'a, str>>,
|
||||||
pub dimension_name: Ident<&'a str>,
|
pub dimension_name: Ident<Cow<'a, str>>,
|
||||||
pub hashed_seed: i64,
|
pub hashed_seed: i64,
|
||||||
pub max_players: VarInt,
|
pub max_players: VarInt,
|
||||||
pub view_distance: VarInt,
|
pub view_distance: VarInt,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
|
@ -5,7 +6,7 @@ use crate::types::SoundCategory;
|
||||||
use crate::var_int::VarInt;
|
use crate::var_int::VarInt;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub struct PlaySoundS2c<'a> {
|
pub struct PlaySoundS2c<'a> {
|
||||||
pub id: SoundId<'a>,
|
pub id: SoundId<'a>,
|
||||||
pub category: SoundCategory,
|
pub category: SoundCategory,
|
||||||
|
@ -15,10 +16,10 @@ pub struct PlaySoundS2c<'a> {
|
||||||
pub seed: i64,
|
pub seed: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum SoundId<'a> {
|
pub enum SoundId<'a> {
|
||||||
Direct {
|
Direct {
|
||||||
id: Ident<&'a str>,
|
id: Ident<Cow<'a, str>>,
|
||||||
range: Option<f32>,
|
range: Option<f32>,
|
||||||
},
|
},
|
||||||
Reference {
|
Reference {
|
||||||
|
@ -47,7 +48,7 @@ impl<'a> Decode<'a> for SoundId<'a> {
|
||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
Ok(SoundId::Direct {
|
Ok(SoundId::Direct {
|
||||||
id: <Ident<&'a str>>::decode(r)?,
|
id: Ident::decode(r)?,
|
||||||
range: <Option<f32>>::decode(r)?,
|
range: <Option<f32>>::decode(r)?,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::types::{GameMode, GlobalPos};
|
use crate::types::{GameMode, GlobalPos};
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, Encode, Decode)]
|
#[derive(Clone, PartialEq, Debug, Encode, Decode)]
|
||||||
pub struct PlayerRespawnS2c<'a> {
|
pub struct PlayerRespawnS2c<'a> {
|
||||||
pub dimension_type_name: Ident<&'a str>,
|
pub dimension_type_name: Ident<Cow<'a, str>>,
|
||||||
pub dimension_name: Ident<&'a str>,
|
pub dimension_name: Ident<Cow<'a, str>>,
|
||||||
pub hashed_seed: u64,
|
pub hashed_seed: u64,
|
||||||
pub game_mode: GameMode,
|
pub game_mode: GameMode,
|
||||||
pub previous_game_mode: i8,
|
pub previous_game_mode: i8,
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Encode, Decode)]
|
#[derive(Clone, Debug, Encode, Decode)]
|
||||||
pub struct SelectAdvancementsTabS2c<'a> {
|
pub struct SelectAdvancementsTabS2c<'a> {
|
||||||
pub identifier: Option<Ident<&'a str>>,
|
pub identifier: Option<Ident<Cow<'a, str>>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
|
@ -7,12 +8,12 @@ use crate::{Decode, Encode};
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct StopSoundS2c<'a> {
|
pub struct StopSoundS2c<'a> {
|
||||||
pub source: Option<SoundCategory>,
|
pub source: Option<SoundCategory>,
|
||||||
pub sound: Option<Ident<&'a str>>,
|
pub sound: Option<Ident<Cow<'a, str>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for StopSoundS2c<'_> {
|
impl Encode for StopSoundS2c<'_> {
|
||||||
fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
|
fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
|
||||||
match (self.source, self.sound) {
|
match (self.source, self.sound.as_ref()) {
|
||||||
(Some(source), Some(sound)) => {
|
(Some(source), Some(sound)) => {
|
||||||
3i8.encode(&mut w)?;
|
3i8.encode(&mut w)?;
|
||||||
source.encode(&mut w)?;
|
source.encode(&mut w)?;
|
||||||
|
@ -38,9 +39,9 @@ impl<'a> Decode<'a> for StopSoundS2c<'a> {
|
||||||
let (source, sound) = match i8::decode(r)? {
|
let (source, sound) = match i8::decode(r)? {
|
||||||
3 => (
|
3 => (
|
||||||
Some(SoundCategory::decode(r)?),
|
Some(SoundCategory::decode(r)?),
|
||||||
Some(<Ident<&'a str>>::decode(r)?),
|
Some(<Ident<Cow<'a, str>>>::decode(r)?),
|
||||||
),
|
),
|
||||||
2 => (None, Some(<Ident<&'a str>>::decode(r)?)),
|
2 => (None, Some(<Ident<Cow<'a, str>>>::decode(r)?)),
|
||||||
1 => (Some(SoundCategory::decode(r)?), None),
|
1 => (Some(SoundCategory::decode(r)?), None),
|
||||||
_ => (None, None),
|
_ => (None, None),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use anyhow::{bail, ensure};
|
use anyhow::{bail, ensure};
|
||||||
|
@ -15,14 +16,14 @@ pub struct SynchronizeRecipesS2c<'a> {
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum Recipe<'a> {
|
pub enum Recipe<'a> {
|
||||||
CraftingShapeless {
|
CraftingShapeless {
|
||||||
recipe_id: Ident<&'a str>,
|
recipe_id: Ident<Cow<'a, str>>,
|
||||||
group: &'a str,
|
group: &'a str,
|
||||||
category: CraftingCategory,
|
category: CraftingCategory,
|
||||||
ingredients: Vec<Ingredient>,
|
ingredients: Vec<Ingredient>,
|
||||||
result: Option<ItemStack>,
|
result: Option<ItemStack>,
|
||||||
},
|
},
|
||||||
CraftingShaped {
|
CraftingShaped {
|
||||||
recipe_id: Ident<&'a str>,
|
recipe_id: Ident<Cow<'a, str>>,
|
||||||
width: VarInt,
|
width: VarInt,
|
||||||
height: VarInt,
|
height: VarInt,
|
||||||
group: &'a str,
|
group: &'a str,
|
||||||
|
@ -32,11 +33,11 @@ pub enum Recipe<'a> {
|
||||||
},
|
},
|
||||||
CraftingSpecial {
|
CraftingSpecial {
|
||||||
kind: SpecialCraftingKind,
|
kind: SpecialCraftingKind,
|
||||||
recipe_id: Ident<&'a str>,
|
recipe_id: Ident<Cow<'a, str>>,
|
||||||
category: CraftingCategory,
|
category: CraftingCategory,
|
||||||
},
|
},
|
||||||
Smelting {
|
Smelting {
|
||||||
recipe_id: Ident<&'a str>,
|
recipe_id: Ident<Cow<'a, str>>,
|
||||||
group: &'a str,
|
group: &'a str,
|
||||||
category: SmeltCategory,
|
category: SmeltCategory,
|
||||||
ingredient: Ingredient,
|
ingredient: Ingredient,
|
||||||
|
@ -45,7 +46,7 @@ pub enum Recipe<'a> {
|
||||||
cooking_time: VarInt,
|
cooking_time: VarInt,
|
||||||
},
|
},
|
||||||
Blasting {
|
Blasting {
|
||||||
recipe_id: Ident<&'a str>,
|
recipe_id: Ident<Cow<'a, str>>,
|
||||||
group: &'a str,
|
group: &'a str,
|
||||||
category: SmeltCategory,
|
category: SmeltCategory,
|
||||||
ingredient: Ingredient,
|
ingredient: Ingredient,
|
||||||
|
@ -54,7 +55,7 @@ pub enum Recipe<'a> {
|
||||||
cooking_time: VarInt,
|
cooking_time: VarInt,
|
||||||
},
|
},
|
||||||
Smoking {
|
Smoking {
|
||||||
recipe_id: Ident<&'a str>,
|
recipe_id: Ident<Cow<'a, str>>,
|
||||||
group: &'a str,
|
group: &'a str,
|
||||||
category: SmeltCategory,
|
category: SmeltCategory,
|
||||||
ingredient: Ingredient,
|
ingredient: Ingredient,
|
||||||
|
@ -63,7 +64,7 @@ pub enum Recipe<'a> {
|
||||||
cooking_time: VarInt,
|
cooking_time: VarInt,
|
||||||
},
|
},
|
||||||
CampfireCooking {
|
CampfireCooking {
|
||||||
recipe_id: Ident<&'a str>,
|
recipe_id: Ident<Cow<'a, str>>,
|
||||||
group: &'a str,
|
group: &'a str,
|
||||||
category: SmeltCategory,
|
category: SmeltCategory,
|
||||||
ingredient: Ingredient,
|
ingredient: Ingredient,
|
||||||
|
@ -72,13 +73,13 @@ pub enum Recipe<'a> {
|
||||||
cooking_time: VarInt,
|
cooking_time: VarInt,
|
||||||
},
|
},
|
||||||
Stonecutting {
|
Stonecutting {
|
||||||
recipe_id: Ident<&'a str>,
|
recipe_id: Ident<Cow<'a, str>>,
|
||||||
group: &'a str,
|
group: &'a str,
|
||||||
ingredient: Ingredient,
|
ingredient: Ingredient,
|
||||||
result: Option<ItemStack>,
|
result: Option<ItemStack>,
|
||||||
},
|
},
|
||||||
Smithing {
|
Smithing {
|
||||||
recipe_id: Ident<&'a str>,
|
recipe_id: Ident<Cow<'a, str>>,
|
||||||
base: Ingredient,
|
base: Ingredient,
|
||||||
addition: Ingredient,
|
addition: Ingredient,
|
||||||
result: Option<ItemStack>,
|
result: Option<ItemStack>,
|
||||||
|
@ -294,16 +295,16 @@ impl<'a> Encode for Recipe<'a> {
|
||||||
|
|
||||||
impl<'a> Decode<'a> for Recipe<'a> {
|
impl<'a> Decode<'a> for Recipe<'a> {
|
||||||
fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
|
fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
|
||||||
Ok(match Ident::<&str>::decode(r)?.path() {
|
Ok(match Ident::<Cow<str>>::decode(r)?.as_str() {
|
||||||
"crafting_shapeless" => Self::CraftingShapeless {
|
"minecraft:crafting_shapeless" => Self::CraftingShapeless {
|
||||||
recipe_id: Decode::decode(r)?,
|
recipe_id: Decode::decode(r)?,
|
||||||
group: Decode::decode(r)?,
|
group: Decode::decode(r)?,
|
||||||
category: Decode::decode(r)?,
|
category: Decode::decode(r)?,
|
||||||
ingredients: Decode::decode(r)?,
|
ingredients: Decode::decode(r)?,
|
||||||
result: Decode::decode(r)?,
|
result: Decode::decode(r)?,
|
||||||
},
|
},
|
||||||
"crafting_shaped" => {
|
"minecraft:crafting_shaped" => {
|
||||||
let recipe_id = Ident::<&str>::decode(r)?;
|
let recipe_id = Ident::decode(r)?;
|
||||||
let width = VarInt::decode(r)?.0;
|
let width = VarInt::decode(r)?.0;
|
||||||
let height = VarInt::decode(r)?.0;
|
let height = VarInt::decode(r)?.0;
|
||||||
let group = <&str>::decode(r)?;
|
let group = <&str>::decode(r)?;
|
||||||
|
@ -324,7 +325,7 @@ impl<'a> Decode<'a> for Recipe<'a> {
|
||||||
result: Decode::decode(r)?,
|
result: Decode::decode(r)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"smelting" => Self::Smelting {
|
"minecraft:smelting" => Self::Smelting {
|
||||||
recipe_id: Decode::decode(r)?,
|
recipe_id: Decode::decode(r)?,
|
||||||
group: Decode::decode(r)?,
|
group: Decode::decode(r)?,
|
||||||
category: Decode::decode(r)?,
|
category: Decode::decode(r)?,
|
||||||
|
@ -333,7 +334,7 @@ impl<'a> Decode<'a> for Recipe<'a> {
|
||||||
experience: Decode::decode(r)?,
|
experience: Decode::decode(r)?,
|
||||||
cooking_time: Decode::decode(r)?,
|
cooking_time: Decode::decode(r)?,
|
||||||
},
|
},
|
||||||
"blasting" => Self::Blasting {
|
"minecraft:blasting" => Self::Blasting {
|
||||||
recipe_id: Decode::decode(r)?,
|
recipe_id: Decode::decode(r)?,
|
||||||
group: Decode::decode(r)?,
|
group: Decode::decode(r)?,
|
||||||
category: Decode::decode(r)?,
|
category: Decode::decode(r)?,
|
||||||
|
@ -342,7 +343,7 @@ impl<'a> Decode<'a> for Recipe<'a> {
|
||||||
experience: Decode::decode(r)?,
|
experience: Decode::decode(r)?,
|
||||||
cooking_time: Decode::decode(r)?,
|
cooking_time: Decode::decode(r)?,
|
||||||
},
|
},
|
||||||
"smoking" => Self::Smoking {
|
"minecraft:smoking" => Self::Smoking {
|
||||||
recipe_id: Decode::decode(r)?,
|
recipe_id: Decode::decode(r)?,
|
||||||
group: Decode::decode(r)?,
|
group: Decode::decode(r)?,
|
||||||
category: Decode::decode(r)?,
|
category: Decode::decode(r)?,
|
||||||
|
@ -351,7 +352,7 @@ impl<'a> Decode<'a> for Recipe<'a> {
|
||||||
experience: Decode::decode(r)?,
|
experience: Decode::decode(r)?,
|
||||||
cooking_time: Decode::decode(r)?,
|
cooking_time: Decode::decode(r)?,
|
||||||
},
|
},
|
||||||
"campfire_cooking" => Self::CampfireCooking {
|
"minecraft:campfire_cooking" => Self::CampfireCooking {
|
||||||
recipe_id: Decode::decode(r)?,
|
recipe_id: Decode::decode(r)?,
|
||||||
group: Decode::decode(r)?,
|
group: Decode::decode(r)?,
|
||||||
category: Decode::decode(r)?,
|
category: Decode::decode(r)?,
|
||||||
|
@ -360,13 +361,13 @@ impl<'a> Decode<'a> for Recipe<'a> {
|
||||||
experience: Decode::decode(r)?,
|
experience: Decode::decode(r)?,
|
||||||
cooking_time: Decode::decode(r)?,
|
cooking_time: Decode::decode(r)?,
|
||||||
},
|
},
|
||||||
"stonecutting" => Self::Stonecutting {
|
"minecraft:stonecutting" => Self::Stonecutting {
|
||||||
recipe_id: Decode::decode(r)?,
|
recipe_id: Decode::decode(r)?,
|
||||||
group: Decode::decode(r)?,
|
group: Decode::decode(r)?,
|
||||||
ingredient: Decode::decode(r)?,
|
ingredient: Decode::decode(r)?,
|
||||||
result: Decode::decode(r)?,
|
result: Decode::decode(r)?,
|
||||||
},
|
},
|
||||||
"smithing" => Self::Smithing {
|
"minecraft:smithing" => Self::Smithing {
|
||||||
recipe_id: Decode::decode(r)?,
|
recipe_id: Decode::decode(r)?,
|
||||||
base: Decode::decode(r)?,
|
base: Decode::decode(r)?,
|
||||||
addition: Decode::decode(r)?,
|
addition: Decode::decode(r)?,
|
||||||
|
@ -374,22 +375,34 @@ impl<'a> Decode<'a> for Recipe<'a> {
|
||||||
},
|
},
|
||||||
other => Self::CraftingSpecial {
|
other => Self::CraftingSpecial {
|
||||||
kind: match other {
|
kind: match other {
|
||||||
"crafting_special_armordye" => SpecialCraftingKind::ArmorDye,
|
"minecraft:crafting_special_armordye" => SpecialCraftingKind::ArmorDye,
|
||||||
"crafting_special_bookcloning" => SpecialCraftingKind::BookCloning,
|
"minecraft:crafting_special_bookcloning" => SpecialCraftingKind::BookCloning,
|
||||||
"crafting_special_mapcloning" => SpecialCraftingKind::MapCloning,
|
"minecraft:crafting_special_mapcloning" => SpecialCraftingKind::MapCloning,
|
||||||
"crafting_special_mapextending" => SpecialCraftingKind::MapExtending,
|
"minecraft:crafting_special_mapextending" => SpecialCraftingKind::MapExtending,
|
||||||
"crafting_special_firework_rocket" => SpecialCraftingKind::FireworkRocket,
|
"minecraft:crafting_special_firework_rocket" => {
|
||||||
"crafting_special_firework_star" => SpecialCraftingKind::FireworkStar,
|
SpecialCraftingKind::FireworkRocket
|
||||||
"crafting_special_firework_star_fade" => SpecialCraftingKind::FireworkStarFade,
|
}
|
||||||
"crafting_special_repairitem" => SpecialCraftingKind::RepairItem,
|
"minecraft:crafting_special_firework_star" => SpecialCraftingKind::FireworkStar,
|
||||||
"crafting_special_tippedarrow" => SpecialCraftingKind::TippedArrow,
|
"minecraft:crafting_special_firework_star_fade" => {
|
||||||
"crafting_special_bannerduplicate" => SpecialCraftingKind::BannerDuplicate,
|
SpecialCraftingKind::FireworkStarFade
|
||||||
"crafting_special_banneraddpattern" => SpecialCraftingKind::BannerAddPattern,
|
}
|
||||||
"crafting_special_shielddecoration" => SpecialCraftingKind::ShieldDecoration,
|
"minecraft:crafting_special_repairitem" => SpecialCraftingKind::RepairItem,
|
||||||
"crafting_special_shulkerboxcoloring" => {
|
"minecraft:crafting_special_tippedarrow" => SpecialCraftingKind::TippedArrow,
|
||||||
|
"minecraft:crafting_special_bannerduplicate" => {
|
||||||
|
SpecialCraftingKind::BannerDuplicate
|
||||||
|
}
|
||||||
|
"minecraft:crafting_special_banneraddpattern" => {
|
||||||
|
SpecialCraftingKind::BannerAddPattern
|
||||||
|
}
|
||||||
|
"minecraft:crafting_special_shielddecoration" => {
|
||||||
|
SpecialCraftingKind::ShieldDecoration
|
||||||
|
}
|
||||||
|
"minecraft:crafting_special_shulkerboxcoloring" => {
|
||||||
SpecialCraftingKind::ShulkerBoxColoring
|
SpecialCraftingKind::ShulkerBoxColoring
|
||||||
}
|
}
|
||||||
"crafting_special_suspiciousstew" => SpecialCraftingKind::SuspiciousStew,
|
"minecraft:crafting_special_suspiciousstew" => {
|
||||||
|
SpecialCraftingKind::SuspiciousStew
|
||||||
|
}
|
||||||
_ => bail!("unknown recipe type \"{other}\""),
|
_ => bail!("unknown recipe type \"{other}\""),
|
||||||
},
|
},
|
||||||
recipe_id: Decode::decode(r)?,
|
recipe_id: Decode::decode(r)?,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::var_int::VarInt;
|
use crate::var_int::VarInt;
|
||||||
use crate::{Decode, Encode};
|
use crate::{Decode, Encode};
|
||||||
|
@ -9,12 +11,12 @@ pub struct SynchronizeTagsS2c<'a> {
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||||
pub struct TagGroup<'a> {
|
pub struct TagGroup<'a> {
|
||||||
pub kind: Ident<&'a str>,
|
pub kind: Ident<Cow<'a, str>>,
|
||||||
pub tags: Vec<Tag<'a>>,
|
pub tags: Vec<Tag<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||||
pub struct Tag<'a> {
|
pub struct Tag<'a> {
|
||||||
pub name: Ident<&'a str>,
|
pub name: Ident<Cow<'a, str>>,
|
||||||
pub entries: Vec<VarInt>,
|
pub entries: Vec<VarInt>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
|
@ -17,12 +18,14 @@ pub struct UnlockRecipesS2c<'a> {
|
||||||
pub blast_furnace_recipe_book_filter_active: bool,
|
pub blast_furnace_recipe_book_filter_active: bool,
|
||||||
pub smoker_recipe_book_open: bool,
|
pub smoker_recipe_book_open: bool,
|
||||||
pub smoker_recipe_book_filter_active: bool,
|
pub smoker_recipe_book_filter_active: bool,
|
||||||
pub recipe_ids: Vec<Ident<&'a str>>,
|
pub recipe_ids: Vec<Ident<Cow<'a, str>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum UpdateRecipeBookAction<'a> {
|
pub enum UpdateRecipeBookAction<'a> {
|
||||||
Init { recipe_ids: Vec<Ident<&'a str>> },
|
Init {
|
||||||
|
recipe_ids: Vec<Ident<Cow<'a, str>>>,
|
||||||
|
},
|
||||||
Add,
|
Add,
|
||||||
Remove,
|
Remove,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
|
use crate::ident_str;
|
||||||
use crate::packet::s2c::play::play_sound::SoundId;
|
use crate::packet::s2c::play::play_sound::SoundId;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/sound.rs"));
|
include!(concat!(env!("OUT_DIR"), "/sound.rs"));
|
||||||
|
@ -6,7 +7,7 @@ include!(concat!(env!("OUT_DIR"), "/sound.rs"));
|
||||||
impl Sound {
|
impl Sound {
|
||||||
pub fn to_id(self) -> SoundId<'static> {
|
pub fn to_id(self) -> SoundId<'static> {
|
||||||
SoundId::Direct {
|
SoundId::Direct {
|
||||||
id: Ident::new(self.to_str()).unwrap(), // TODO: use ident_str.
|
id: self.to_ident().into(),
|
||||||
range: None,
|
range: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1084,8 +1084,7 @@ mod tests {
|
||||||
let txt = Text::storage_nbt(ident!("foo"), "bar", Some(true), Some("baz".into()));
|
let txt = Text::storage_nbt(ident!("foo"), "bar", Some(true), Some("baz".into()));
|
||||||
let serialized = serde_json::to_string(&txt).unwrap();
|
let serialized = serde_json::to_string(&txt).unwrap();
|
||||||
let deserialized: Text = serde_json::from_str(&serialized).unwrap();
|
let deserialized: Text = serde_json::from_str(&serialized).unwrap();
|
||||||
let expected =
|
let expected = r#"{"storage":"minecraft:foo","nbt":"bar","interpret":true,"separator":{"text":"baz"}}"#;
|
||||||
r#"{"storage":"foo","nbt":"bar","interpret":true,"separator":{"text":"baz"}}"#;
|
|
||||||
assert_eq!(serialized, expected);
|
assert_eq!(serialized, expected);
|
||||||
assert_eq!(txt, deserialized);
|
assert_eq!(txt, deserialized);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! Miscellaneous type definitions used in packets.
|
//! Miscellaneous type definitions used in packets.
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -61,9 +62,9 @@ pub enum GameMode {
|
||||||
Spectator,
|
Spectator,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||||
pub struct GlobalPos<'a> {
|
pub struct GlobalPos<'a> {
|
||||||
pub dimension_name: Ident<&'a str>,
|
pub dimension_name: Ident<Cow<'a, str>>,
|
||||||
pub position: BlockPos,
|
pub position: BlockPos,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,26 +16,22 @@ fn check_path(s: &str) -> bool {
|
||||||
|
|
||||||
pub fn ident_str(item: TokenStream) -> Result<TokenStream> {
|
pub fn ident_str(item: TokenStream) -> Result<TokenStream> {
|
||||||
let ident_lit: LitStr = parse2(item)?;
|
let ident_lit: LitStr = parse2(item)?;
|
||||||
let mut ident = &ident_lit.value()[..];
|
let mut ident = ident_lit.value();
|
||||||
|
|
||||||
let path_start = match ident.split_once(':') {
|
match ident.split_once(':') {
|
||||||
Some(("minecraft", path)) if check_path(path) => {
|
Some((namespace, path)) if check_namespace(namespace) && check_path(path) => {}
|
||||||
ident = path;
|
None if check_path(&ident) => {
|
||||||
0
|
ident = format!("minecraft:{ident}");
|
||||||
}
|
}
|
||||||
Some((namespace, path)) if check_namespace(namespace) && check_path(path) => {
|
|
||||||
namespace.len() + 1
|
|
||||||
}
|
|
||||||
None if check_path(ident) => 0,
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
ident_lit.span(),
|
ident_lit.span(),
|
||||||
"string cannot be parsed as ident",
|
"string cannot be parsed as a resource identifier",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
::valence_protocol::ident::Ident::new_unchecked(#ident, #path_start)
|
::valence_protocol::ident::Ident::new_unchecked(#ident)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue