Move ResourceLocation to pumpkin-util (#910)

* Rename Identifier to ResourceLocation

* Run cargo fmt

* Move ResourceLocation to pumpkin-util

* Remove redundant as_string function

* Run cargo fmt
This commit is contained in:
Epix
2025-06-17 06:13:47 -07:00
committed by GitHub
parent 39359e35ff
commit d55364d66f
49 changed files with 325 additions and 305 deletions

View File

@@ -1,17 +1,16 @@
use pumpkin_data::packet::clientbound::CONFIG_COOKIE_REQUEST;
use pumpkin_macros::packet;
use crate::codec::identifier::Identifier;
use pumpkin_util::resource_location::ResourceLocation;
#[derive(serde::Serialize)]
#[packet(CONFIG_COOKIE_REQUEST)]
/// Requests a cookie that was previously stored.
pub struct CCookieRequest<'a> {
pub key: &'a Identifier,
pub key: &'a ResourceLocation,
}
impl<'a> CCookieRequest<'a> {
pub fn new(key: &'a Identifier) -> Self {
pub fn new(key: &'a ResourceLocation) -> Self {
Self { key }
}
}

View File

@@ -1,18 +1,19 @@
use pumpkin_data::packet::clientbound::CONFIG_REGISTRY_DATA;
use pumpkin_macros::packet;
use pumpkin_util::resource_location::ResourceLocation;
use serde::Serialize;
use crate::{codec::identifier::Identifier, ser::network_serialize_no_prefix};
use crate::ser::network_serialize_no_prefix;
#[derive(Serialize)]
#[packet(CONFIG_REGISTRY_DATA)]
pub struct CRegistryData<'a> {
pub registry_id: &'a Identifier,
pub registry_id: &'a ResourceLocation,
pub entries: &'a [RegistryEntry],
}
impl<'a> CRegistryData<'a> {
pub fn new(registry_id: &'a Identifier, entries: &'a [RegistryEntry]) -> Self {
pub fn new(registry_id: &'a ResourceLocation, entries: &'a [RegistryEntry]) -> Self {
Self {
registry_id,
entries,
@@ -22,7 +23,7 @@ impl<'a> CRegistryData<'a> {
#[derive(Serialize)]
pub struct RegistryEntry {
pub entry_id: Identifier,
pub entry_id: ResourceLocation,
#[serde(serialize_with = "network_serialize_no_prefix")]
pub data: Option<Box<[u8]>>,
}
@@ -33,7 +34,7 @@ impl RegistryEntry {
let mut data_buf = Vec::new();
pumpkin_nbt::serializer::to_bytes_unnamed(nbt, &mut data_buf).unwrap();
RegistryEntry {
entry_id: Identifier::vanilla(name),
entry_id: ResourceLocation::vanilla(name),
data: Some(data_buf.into_boxed_slice()),
}
}
@@ -41,7 +42,7 @@ impl RegistryEntry {
let mut data_buf = Vec::new();
pumpkin_nbt::serializer::to_bytes_unnamed(nbt, &mut data_buf).unwrap();
RegistryEntry {
entry_id: Identifier::pumpkin(name),
entry_id: ResourceLocation::pumpkin(name),
data: Some(data_buf.into_boxed_slice()),
}
}

View File

@@ -1,18 +1,18 @@
use crate::codec::identifier::Identifier;
use pumpkin_data::packet::clientbound::CONFIG_STORE_COOKIE;
use pumpkin_macros::packet;
use pumpkin_util::resource_location::ResourceLocation;
#[derive(serde::Serialize)]
#[packet(CONFIG_STORE_COOKIE)]
/// Stores some arbitrary data on the client, which persists between server transfers.
/// The Notchian (vanilla) client only accepts cookies of up to 5 KiB in size.
pub struct CStoreCookie<'a> {
key: &'a Identifier,
key: &'a ResourceLocation,
payload: &'a [u8], // 5120,
}
impl<'a> CStoreCookie<'a> {
pub fn new(key: &'a Identifier, payload: &'a [u8]) -> Self {
pub fn new(key: &'a ResourceLocation, payload: &'a [u8]) -> Self {
Self { key, payload }
}
}

View File

@@ -2,7 +2,6 @@ use std::io::Write;
use crate::{
ClientPacket,
codec::identifier::Identifier,
ser::{NetworkWriteExt, WritingError},
};
@@ -13,6 +12,7 @@ use pumpkin_data::{
tag::{RegistryKey, get_registry_key_tags},
};
use pumpkin_macros::packet;
use pumpkin_util::resource_location::ResourceLocation;
#[packet(CONFIG_UPDATE_TAGS)]
pub struct CUpdateTags<'a> {
@@ -29,7 +29,9 @@ impl ClientPacket for CUpdateTags<'_> {
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
let mut write = write;
write.write_list(self.tags, |p, registry_key| {
p.write_identifier(&Identifier::vanilla(registry_key.identifier_string()))?;
p.write_resource_location(&ResourceLocation::vanilla(
registry_key.identifier_string(),
))?;
let values = get_registry_key_tags(registry_key);
p.write_var_int(&values.len().try_into().map_err(|_| {
@@ -37,7 +39,7 @@ impl ClientPacket for CUpdateTags<'_> {
})?)?;
for (key, values) in values.iter() {
// This is technically an `Identifier` but same thing
// This is technically a `ResourceLocation` but same thing
p.write_string_bounded(key, u16::MAX as usize)?;
p.write_list(values, |p, string_id| {
let id = match registry_key {

View File

@@ -1,18 +1,17 @@
use pumpkin_data::packet::clientbound::LOGIN_COOKIE_REQUEST;
use pumpkin_macros::packet;
use pumpkin_util::resource_location::ResourceLocation;
use serde::Serialize;
use crate::codec::identifier::Identifier;
#[derive(Serialize)]
#[packet(LOGIN_COOKIE_REQUEST)]
/// Requests a cookie that was previously stored.
pub struct CLoginCookieRequest<'a> {
key: &'a Identifier,
key: &'a ResourceLocation,
}
impl<'a> CLoginCookieRequest<'a> {
pub fn new(key: &'a Identifier) -> Self {
pub fn new(key: &'a ResourceLocation) -> Self {
Self { key }
}
}

View File

@@ -129,7 +129,7 @@ impl ProtoNode<'_> {
} => {
// suggestion type
let suggestion_type = &override_suggestion_type.expect("ProtoNode::FLAG_HAS_SUGGESTION_TYPE should only be set if override_suggestion_type is not `None`.");
write.write_string(suggestion_type.identifier())?;
write.write_string(suggestion_type.resource_location())?;
}
_ => unimplemented!(
"`ProtoNode::FLAG_HAS_SUGGESTION_TYPE` is only implemented for `ProtoNodeType::Argument`"
@@ -316,7 +316,7 @@ pub enum SuggestionProviders {
}
impl SuggestionProviders {
fn identifier(&self) -> &'static str {
fn resource_location(&self) -> &'static str {
match self {
Self::AskServer => "minecraft:ask_server",
Self::AllRecipes => "minecraft:all_recipes",

View File

@@ -1,18 +1,17 @@
use pumpkin_data::packet::clientbound::PLAY_COOKIE_REQUEST;
use pumpkin_macros::packet;
use pumpkin_util::resource_location::ResourceLocation;
use serde::Serialize;
use crate::codec::identifier::Identifier;
#[derive(Serialize)]
#[packet(PLAY_COOKIE_REQUEST)]
/// Requests a cookie that was previously stored.
pub struct CPlayCookieRequest<'a> {
key: &'a Identifier,
key: &'a ResourceLocation,
}
impl<'a> CPlayCookieRequest<'a> {
pub fn new(key: &'a Identifier) -> Self {
pub fn new(key: &'a ResourceLocation) -> Self {
Self { key }
}
}

View File

@@ -1,17 +1,17 @@
use pumpkin_data::packet::clientbound::PLAY_LOGIN;
use pumpkin_util::math::position::BlockPos;
use pumpkin_util::{math::position::BlockPos, resource_location::ResourceLocation};
use pumpkin_macros::packet;
use serde::Serialize;
use crate::{VarInt, codec::identifier::Identifier};
use crate::VarInt;
#[derive(Serialize)]
#[packet(PLAY_LOGIN)]
pub struct CLogin<'a> {
entity_id: i32,
is_hardcore: bool,
dimension_names: &'a [Identifier],
dimension_names: &'a [ResourceLocation],
max_players: VarInt,
view_distance: VarInt,
simulated_distance: VarInt,
@@ -20,14 +20,14 @@ pub struct CLogin<'a> {
limited_crafting: bool,
// Spawn info
dimension_type: VarInt,
dimension_name: Identifier,
dimension_name: ResourceLocation,
/// First 8 bytes of the SHA-256 hash of the world's seed. Used client side for biome noise
hashed_seed: i64,
game_mode: u8,
previous_gamemode: i8,
debug: bool,
is_flat: bool,
death_dimension_name: Option<(Identifier, BlockPos)>,
death_dimension_name: Option<(ResourceLocation, BlockPos)>,
portal_cooldown: VarInt,
sealevel: VarInt,
enforce_secure_chat: bool,
@@ -38,7 +38,7 @@ impl<'a> CLogin<'a> {
pub fn new(
entity_id: i32,
is_hardcore: bool,
dimension_names: &'a [Identifier],
dimension_names: &'a [ResourceLocation],
max_players: VarInt,
view_distance: VarInt,
simulated_distance: VarInt,
@@ -46,13 +46,13 @@ impl<'a> CLogin<'a> {
enabled_respawn_screen: bool,
limited_crafting: bool,
dimension_type: VarInt,
dimension_name: Identifier,
dimension_name: ResourceLocation,
hashed_seed: i64,
game_mode: u8,
previous_gamemode: i8,
debug: bool,
is_flat: bool,
death_dimension_name: Option<(Identifier, BlockPos)>,
death_dimension_name: Option<(ResourceLocation, BlockPos)>,
portal_cooldown: VarInt,
sealevel: VarInt,
enforce_secure_chat: bool,

View File

@@ -1,21 +1,21 @@
use pumpkin_data::packet::clientbound::PLAY_RESPAWN;
use pumpkin_macros::packet;
use pumpkin_util::math::position::BlockPos;
use pumpkin_util::{math::position::BlockPos, resource_location::ResourceLocation};
use serde::{Deserialize, Serialize};
use crate::{VarInt, codec::identifier::Identifier};
use crate::VarInt;
#[derive(Serialize, Deserialize)]
#[packet(PLAY_RESPAWN)]
pub struct CRespawn {
dimension_type: VarInt,
dimension_name: Identifier,
dimension_name: ResourceLocation,
hashed_seed: i64,
game_mode: u8,
previous_gamemode: i8,
debug: bool,
is_flat: bool,
death_dimension_name: Option<(Identifier, BlockPos)>,
death_dimension_name: Option<(ResourceLocation, BlockPos)>,
portal_cooldown: VarInt,
sealevel: VarInt,
data_kept: u8,
@@ -25,13 +25,13 @@ impl CRespawn {
#[expect(clippy::too_many_arguments)]
pub fn new(
dimension_type: VarInt,
dimension_name: Identifier,
dimension_name: ResourceLocation,
hashed_seed: i64,
game_mode: u8,
previous_gamemode: i8,
debug: bool,
is_flat: bool,
death_dimension_name: Option<(Identifier, BlockPos)>,
death_dimension_name: Option<(ResourceLocation, BlockPos)>,
portal_cooldown: VarInt,
sealevel: VarInt,
data_kept: u8,

View File

@@ -1,19 +1,20 @@
use std::io::Write;
use crate::ClientPacket;
use crate::codec::var_int::VarInt;
use crate::ser::{NetworkWriteExt, WritingError};
use crate::{ClientPacket, codec::identifier::Identifier};
use pumpkin_data::{packet::clientbound::PLAY_STOP_SOUND, sound::SoundCategory};
use pumpkin_macros::packet;
use pumpkin_util::resource_location::ResourceLocation;
#[packet(PLAY_STOP_SOUND)]
pub struct CStopSound {
sound_id: Option<Identifier>,
sound_id: Option<ResourceLocation>,
category: Option<SoundCategory>,
}
impl CStopSound {
pub fn new(sound_id: Option<Identifier>, category: Option<SoundCategory>) -> Self {
pub fn new(sound_id: Option<ResourceLocation>, category: Option<SoundCategory>) -> Self {
Self { sound_id, category }
}
}
@@ -31,7 +32,7 @@ impl ClientPacket for CStopSound {
(Some(category), Some(sound_id)) => {
write.write_u8_be(CATEGORY_AND_SOUND)?;
write.write_var_int(&VarInt(category as i32))?;
write.write_identifier(sound_id)
write.write_resource_location(sound_id)
}
(Some(category), None) => {
write.write_u8_be(CATEGORY_ONLY)?;
@@ -39,7 +40,7 @@ impl ClientPacket for CStopSound {
}
(None, Some(sound_id)) => {
write.write_u8_be(SOUND_ONLY)?;
write.write_identifier(sound_id)
write.write_resource_location(sound_id)
}
(None, None) => write.write_u8_be(NO_CATEGORY_NO_SOUND),
}

View File

@@ -1,6 +1,6 @@
use crate::codec::identifier::Identifier;
use pumpkin_data::packet::clientbound::PLAY_STORE_COOKIE;
use pumpkin_macros::packet;
use pumpkin_util::resource_location::ResourceLocation;
use serde::Serialize;
/// Stores some arbitrary data on the client, which persists between server transfers.
@@ -8,12 +8,12 @@ use serde::Serialize;
#[derive(Serialize)]
#[packet(PLAY_STORE_COOKIE)]
pub struct CStoreCookie<'a> {
key: &'a Identifier,
key: &'a ResourceLocation,
payload: &'a [u8], // 5120,
}
impl<'a> CStoreCookie<'a> {
pub fn new(key: &'a Identifier, payload: &'a [u8]) -> Self {
pub fn new(key: &'a ResourceLocation, payload: &'a [u8]) -> Self {
Self { key, payload }
}
}

View File

@@ -1,104 +0,0 @@
use std::{
io::{Read, Write},
num::NonZeroUsize,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Visitor};
use crate::ser::{NetworkReadExt, NetworkWriteExt, ReadingError, WritingError};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Identifier {
pub namespace: String,
pub path: String,
}
impl Identifier {
pub fn vanilla(path: &str) -> Self {
Self {
namespace: "minecraft".to_string(),
path: path.to_string(),
}
}
pub fn pumpkin(path: &str) -> Self {
Self {
namespace: "pumpkin".to_string(),
path: path.to_string(),
}
}
pub fn get(&self) -> String {
format!("{}:{}", self.namespace, self.path)
}
}
impl Identifier {
/// The maximum number of bytes an `Identifier` is the same as for a normal `String`.
const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(i16::MAX as usize).unwrap();
pub fn encode(&self, write: &mut impl Write) -> Result<(), WritingError> {
write.write_string_bounded(&self.to_string(), Self::MAX_SIZE.get())
}
pub fn decode(read: &mut impl Read) -> Result<Self, ReadingError> {
let identifier = read.get_string_bounded(Self::MAX_SIZE.get())?;
match identifier.split_once(":") {
Some((namespace, path)) => Ok(Identifier {
namespace: namespace.to_string(),
path: path.to_string(),
}),
None => Err(ReadingError::Incomplete("Identifier".to_string())),
}
}
}
impl Serialize for Identifier {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for Identifier {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct IdentifierVisitor;
impl Visitor<'_> for IdentifierVisitor {
type Value = Identifier;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid identifier (namespace:path)")
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(&v)
}
fn visit_str<E>(self, identifier: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match identifier.split_once(":") {
Some((namespace, path)) => Ok(Identifier {
namespace: namespace.to_string(),
path: path.to_string(),
}),
None => Err(serde::de::Error::custom("identifier can't be split")),
}
}
}
deserializer.deserialize_str(IdentifierVisitor)
}
}
impl std::fmt::Display for Identifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.namespace, self.path)
}
}

View File

@@ -1,5 +1,4 @@
pub mod bit_set;
pub mod identifier;
pub mod item_stack_seralizer;
pub mod var_int;
pub mod var_long;

View File

@@ -5,8 +5,11 @@ use std::{
use aes::cipher::{BlockDecryptMut, BlockEncryptMut, BlockSizeUser, generic_array::GenericArray};
use bytes::Bytes;
use codec::{identifier::Identifier, var_int::VarInt};
use pumpkin_util::text::{TextComponent, style::Style};
use codec::var_int::VarInt;
use pumpkin_util::{
resource_location::ResourceLocation,
text::{TextComponent, style::Style},
};
use ser::{NetworkWriteExt, ReadingError, WritingError, packet::Packet};
use serde::{
Deserialize, Serialize, Serializer,
@@ -188,7 +191,7 @@ impl<T: Serialize> Serialize for IdOr<T> {
#[derive(Serialize, Deserialize, Clone, PartialEq)]
pub struct SoundEvent {
pub sound_name: Identifier,
pub sound_name: ResourceLocation,
pub range: Option<f32>,
}
@@ -516,10 +519,8 @@ impl Serialize for LinkType {
#[cfg(test)]
mod test {
use crate::{
codec::identifier::Identifier,
ser::{deserializer::Deserializer, serializer::Serializer},
};
use crate::ser::{deserializer::Deserializer, serializer::Serializer};
use pumpkin_util::resource_location::ResourceLocation;
use serde::{Deserialize, Serialize};
use crate::{IdOr, SoundEvent};
@@ -541,7 +542,7 @@ mod test {
fn test_serde_id_or_value() {
let mut buf = Vec::new();
let event = SoundEvent {
sound_name: Identifier::vanilla("test"),
sound_name: ResourceLocation::vanilla("test"),
range: Some(1.0),
};

View File

@@ -3,11 +3,12 @@ use std::io::{Read, Write};
use crate::{
FixedBitSet,
codec::{bit_set::BitSet, identifier::Identifier, var_int::VarInt, var_long::VarLong},
codec::{bit_set::BitSet, var_int::VarInt, var_long::VarLong},
};
pub mod deserializer;
use pumpkin_nbt::{serializer::WriteAdaptor, tag::NbtTag};
use pumpkin_util::resource_location::ResourceLocation;
use thiserror::Error;
pub mod packet;
pub mod serializer;
@@ -67,7 +68,7 @@ pub trait NetworkReadExt {
fn get_var_long(&mut self) -> Result<VarLong, ReadingError>;
fn get_string_bounded(&mut self, bound: usize) -> Result<String, ReadingError>;
fn get_string(&mut self) -> Result<String, ReadingError>;
fn get_identifier(&mut self) -> Result<Identifier, ReadingError>;
fn get_resource_location(&mut self) -> Result<ResourceLocation, ReadingError>;
fn get_uuid(&mut self) -> Result<uuid::Uuid, ReadingError>;
fn get_fixed_bitset(&mut self, bits: usize) -> Result<FixedBitSet, ReadingError>;
@@ -237,8 +238,15 @@ impl<R: Read> NetworkReadExt for R {
self.get_string_bounded(i16::MAX as usize)
}
fn get_identifier(&mut self) -> Result<Identifier, ReadingError> {
Identifier::decode(self)
fn get_resource_location(&mut self) -> Result<ResourceLocation, ReadingError> {
let resource_location = self.get_string_bounded(ResourceLocation::MAX_SIZE.get())?;
match resource_location.split_once(":") {
Some((namespace, path)) => Ok(ResourceLocation {
namespace: namespace.to_string(),
path: path.to_string(),
}),
None => Err(ReadingError::Incomplete("ResourceLocation".to_string())),
}
}
fn get_uuid(&mut self) -> Result<uuid::Uuid, ReadingError> {
@@ -301,7 +309,7 @@ pub trait NetworkWriteExt {
fn write_var_long(&mut self, data: &VarLong) -> Result<(), WritingError>;
fn write_string_bounded(&mut self, data: &str, bound: usize) -> Result<(), WritingError>;
fn write_string(&mut self, data: &str) -> Result<(), WritingError>;
fn write_identifier(&mut self, data: &Identifier) -> Result<(), WritingError>;
fn write_resource_location(&mut self, data: &ResourceLocation) -> Result<(), WritingError>;
fn write_uuid(&mut self, data: &uuid::Uuid) -> Result<(), WritingError> {
let (first, second) = data.as_u64_pair();
@@ -420,8 +428,8 @@ impl<W: Write> NetworkWriteExt for W {
self.write_string_bounded(data, i16::MAX as usize)
}
fn write_identifier(&mut self, data: &Identifier) -> Result<(), WritingError> {
data.encode(self)
fn write_resource_location(&mut self, data: &ResourceLocation) -> Result<(), WritingError> {
self.write_string_bounded(&data.to_string(), ResourceLocation::MAX_SIZE.get())
}
fn write_bitset(&mut self, data: &BitSet) -> Result<(), WritingError> {

View File

@@ -2,10 +2,10 @@ use std::io::Read;
use pumpkin_data::packet::serverbound::CONFIG_COOKIE_RESPONSE;
use pumpkin_macros::packet;
use pumpkin_util::resource_location::ResourceLocation;
use crate::{
ServerPacket,
codec::identifier::Identifier,
ser::{NetworkReadExt, ReadingError},
};
@@ -13,7 +13,7 @@ use crate::{
/// Response to a `CCookieRequest` (configuration) from the server.
/// The Notchian (vanilla) server only accepts responses of up to 5 KiB in size.
pub struct SConfigCookieResponse {
pub key: Identifier,
pub key: ResourceLocation,
pub has_payload: bool,
pub payload: Option<Box<[u8]>>, // 5120,
}
@@ -24,7 +24,7 @@ impl ServerPacket for SConfigCookieResponse {
fn read(read: impl Read) -> Result<Self, ReadingError> {
let mut read = read;
let key = read.get_identifier()?;
let key = read.get_resource_location()?;
let has_payload = read.get_bool()?;
if !has_payload {

View File

@@ -2,17 +2,17 @@ use std::io::Read;
use pumpkin_data::packet::serverbound::CONFIG_CUSTOM_PAYLOAD;
use pumpkin_macros::packet;
use pumpkin_util::resource_location::ResourceLocation;
use crate::{
ServerPacket,
codec::identifier::Identifier,
ser::{NetworkReadExt, ReadingError},
};
const MAX_PAYLOAD_SIZE: usize = 1048576;
#[packet(CONFIG_CUSTOM_PAYLOAD)]
pub struct SPluginMessage {
pub channel: Identifier,
pub channel: ResourceLocation,
pub data: Box<[u8]>,
}
@@ -21,7 +21,7 @@ impl ServerPacket for SPluginMessage {
let mut read = read;
Ok(Self {
channel: read.get_identifier()?,
channel: read.get_resource_location()?,
data: read.read_remaining_to_boxed_slice(MAX_PAYLOAD_SIZE)?,
})
}

View File

@@ -2,17 +2,17 @@ use std::io::Read;
use crate::{
ServerPacket,
codec::identifier::Identifier,
ser::{NetworkReadExt, ReadingError},
};
use pumpkin_data::packet::serverbound::LOGIN_COOKIE_RESPONSE;
use pumpkin_macros::packet;
use pumpkin_util::resource_location::ResourceLocation;
#[packet(LOGIN_COOKIE_RESPONSE)]
/// Response to a `CCookieRequest` (login) from the server.
/// The Notchian server only accepts responses of up to 5 kiB in size.
pub struct SLoginCookieResponse {
pub key: Identifier,
pub key: ResourceLocation,
pub payload: Option<Box<[u8]>>, // 5120,
}
@@ -22,7 +22,7 @@ impl ServerPacket for SLoginCookieResponse {
fn read(read: impl Read) -> Result<Self, ReadingError> {
let mut read = read;
let key = read.get_identifier()?;
let key = read.get_resource_location()?;
let has_payload = read.get_bool()?;
if !has_payload {

View File

@@ -2,17 +2,17 @@ use std::io::Read;
use crate::{
ServerPacket,
codec::identifier::Identifier,
ser::{NetworkReadExt, ReadingError},
};
use pumpkin_data::packet::serverbound::PLAY_COOKIE_RESPONSE;
use pumpkin_macros::packet;
use pumpkin_util::resource_location::ResourceLocation;
#[packet(PLAY_COOKIE_RESPONSE)]
/// Response to a `CCookieRequest` (play) from the server.
/// The Notchian (vanilla) server only accepts responses of up to 5 KiB in size.
pub struct SCookieResponse {
pub key: Identifier,
pub key: ResourceLocation,
pub payload: Option<Box<[u8]>>, // 5120,
}
@@ -22,7 +22,7 @@ impl ServerPacket for SCookieResponse {
fn read(read: impl Read) -> Result<Self, ReadingError> {
let mut read = read;
let key = read.get_identifier()?;
let key = read.get_resource_location()?;
let has_payload = read.get_bool()?;
if !has_payload {

View File

@@ -1,8 +1,8 @@
use pumpkin_protocol::codec::identifier::Identifier;
use pumpkin_util::resource_location::ResourceLocation;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BannerPattern {
asset_id: Identifier,
asset_id: ResourceLocation,
translation_key: String,
}

View File

@@ -15,7 +15,8 @@ use instrument::Instrument;
use jukebox_song::JukeboxSong;
use paint::Painting;
use pig::PigVariant;
use pumpkin_protocol::{client::config::RegistryEntry, codec::identifier::Identifier};
use pumpkin_protocol::client::config::RegistryEntry;
use pumpkin_util::resource_location::ResourceLocation;
use serde::{Deserialize, Serialize};
use trim_material::TrimMaterial;
use trim_pattern::TrimPattern;
@@ -45,7 +46,7 @@ pub static SYNCED_REGISTRIES: LazyLock<SyncedRegistry> = LazyLock::new(|| {
});
pub struct Registry {
pub registry_id: Identifier,
pub registry_id: ResourceLocation,
pub registry_entries: Vec<RegistryEntry>,
}
@@ -72,32 +73,33 @@ pub struct SyncedRegistry {
instrument: IndexMap<String, Instrument>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DimensionType {
Overworld,
OverworldCaves,
TheEnd,
TheNether,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct DataPool<T> {
data: T,
weight: i32,
}
impl DimensionType {
pub fn name(&self) -> Identifier {
// TODO: remove in favor of numerical registry ids for `minecraft:dimension_type`
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VanillaDimensionType {
Overworld,
OverworldCaves,
TheEnd,
TheNether,
}
impl VanillaDimensionType {
pub fn resource_location(&self) -> ResourceLocation {
match self {
Self::Overworld => Identifier::vanilla("overworld"),
Self::OverworldCaves => Identifier::vanilla("overworld_caves"),
Self::TheEnd => Identifier::vanilla("the_end"),
Self::TheNether => Identifier::vanilla("the_nether"),
Self::Overworld => ResourceLocation::vanilla("overworld"),
Self::OverworldCaves => ResourceLocation::vanilla("overworld_caves"),
Self::TheEnd => ResourceLocation::vanilla("the_end"),
Self::TheNether => ResourceLocation::vanilla("the_nether"),
}
}
pub fn from_name(name: &str) -> Option<Self> {
match name {
pub fn from_resource_location_string(resource_location: &str) -> Option<Self> {
match resource_location {
"minecraft:overworld" => Some(Self::Overworld),
"minecraft:overworld_caves" => Some(Self::OverworldCaves),
"minecraft:the_end" => Some(Self::TheEnd),
@@ -115,7 +117,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let biome = Registry {
registry_id: Identifier::vanilla("worldgen/biome"),
registry_id: ResourceLocation::vanilla("worldgen/biome"),
registry_entries,
};
@@ -143,7 +145,7 @@ impl Registry {
));
let chat_type = Registry {
registry_id: Identifier::vanilla("chat_type"),
registry_id: ResourceLocation::vanilla("chat_type"),
registry_entries,
};
@@ -153,7 +155,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let wolf_variant = Registry {
registry_id: Identifier::vanilla("wolf_variant"),
registry_id: ResourceLocation::vanilla("wolf_variant"),
registry_entries,
};
@@ -163,7 +165,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let cat_variant = Registry {
registry_id: Identifier::vanilla("cat_variant"),
registry_id: ResourceLocation::vanilla("cat_variant"),
registry_entries,
};
let registry_entries = SYNCED_REGISTRIES
@@ -172,7 +174,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let chicken_variant = Registry {
registry_id: Identifier::vanilla("chicken_variant"),
registry_id: ResourceLocation::vanilla("chicken_variant"),
registry_entries,
};
let registry_entries = SYNCED_REGISTRIES
@@ -181,7 +183,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let cow_variant = Registry {
registry_id: Identifier::vanilla("cow_variant"),
registry_id: ResourceLocation::vanilla("cow_variant"),
registry_entries,
};
let registry_entries = SYNCED_REGISTRIES
@@ -190,7 +192,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let frog_variant = Registry {
registry_id: Identifier::vanilla("frog_variant"),
registry_id: ResourceLocation::vanilla("frog_variant"),
registry_entries,
};
let registry_entries = SYNCED_REGISTRIES
@@ -199,7 +201,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let pig_variant = Registry {
registry_id: Identifier::vanilla("pig_variant"),
registry_id: ResourceLocation::vanilla("pig_variant"),
registry_entries,
};
let registry_entries = SYNCED_REGISTRIES
@@ -208,7 +210,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let wolf_sound_variant = Registry {
registry_id: Identifier::vanilla("wolf_sound_variant"),
registry_id: ResourceLocation::vanilla("wolf_sound_variant"),
registry_entries,
};
@@ -218,7 +220,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let painting_variant = Registry {
registry_id: Identifier::vanilla("painting_variant"),
registry_id: ResourceLocation::vanilla("painting_variant"),
registry_entries,
};
@@ -228,7 +230,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let dimension_type = Registry {
registry_id: Identifier::vanilla("dimension_type"),
registry_id: ResourceLocation::vanilla("dimension_type"),
registry_entries,
};
@@ -238,7 +240,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let damage_type = Registry {
registry_id: Identifier::vanilla("damage_type"),
registry_id: ResourceLocation::vanilla("damage_type"),
registry_entries,
};
@@ -248,7 +250,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let banner_pattern = Registry {
registry_id: Identifier::vanilla("banner_pattern"),
registry_id: ResourceLocation::vanilla("banner_pattern"),
registry_entries,
};
@@ -258,7 +260,7 @@ impl Registry {
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();
let jukebox_song = Registry {
registry_id: Identifier::vanilla("jukebox_song"),
registry_id: ResourceLocation::vanilla("jukebox_song"),
registry_entries,
};

View File

@@ -1,9 +1,9 @@
use pumpkin_protocol::codec::identifier::Identifier;
use pumpkin_util::resource_location::ResourceLocation;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Painting {
asset_id: Identifier,
asset_id: ResourceLocation,
// #[serde(skip_serializing_if = "Option::is_none")]
// title: Option<TextComponent<'static>>,
// #[serde(skip_serializing_if = "Option::is_none")]

View File

@@ -1,9 +1,9 @@
use pumpkin_protocol::codec::identifier::Identifier;
use pumpkin_util::resource_location::ResourceLocation;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrimPattern {
asset_id: Identifier,
asset_id: ResourceLocation,
// description: TextComponent<'static>,
decal: bool,
}

View File

@@ -14,6 +14,7 @@ pub mod noise;
pub mod permission;
pub mod random;
pub mod registry;
pub mod resource_location;
pub mod serde_enum_as_integer;
pub mod text;
pub mod translation;

View File

@@ -0,0 +1,81 @@
use std::num::NonZeroUsize;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Visitor};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ResourceLocation {
pub namespace: String,
pub path: String,
}
impl ResourceLocation {
/// The maximum number of bytes for a [`ResourceLocation`] is the same as for a normal [`String`].
pub const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(i16::MAX as usize).unwrap();
pub fn vanilla(path: &str) -> Self {
Self {
namespace: "minecraft".to_string(),
path: path.to_string(),
}
}
pub fn pumpkin(path: &str) -> Self {
Self {
namespace: "pumpkin".to_string(),
path: path.to_string(),
}
}
}
impl std::fmt::Display for ResourceLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.namespace, self.path)
}
}
impl Serialize for ResourceLocation {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for ResourceLocation {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ResourceLocationVisitor;
impl Visitor<'_> for ResourceLocationVisitor {
type Value = ResourceLocation;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid resource location (namespace:path)")
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(&v)
}
fn visit_str<E>(self, resource_location: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match resource_location.split_once(":") {
Some((namespace, path)) => Ok(ResourceLocation {
namespace: namespace.to_string(),
path: path.to_string(),
}),
None => Err(serde::de::Error::custom("resource location can't be split")),
}
}
}
deserializer.deserialize_str(ResourceLocationVisitor)
}
}

View File

@@ -296,8 +296,8 @@ impl TextComponent {
/// Allows you to change the font of the text.
/// Default fonts: `minecraft:default`, `minecraft:uniform`, `minecraft:alt`, `minecraft:illageralt`
pub fn font(mut self, identifier: String) -> Self {
self.0.style.font = Some(identifier);
pub fn font(mut self, resource_location: String) -> Self {
self.0.style.font = Some(resource_location);
self
}

View File

@@ -106,8 +106,8 @@ impl Style {
/// Allows you to change the font of the text.
/// Default fonts: `minecraft:default`, `minecraft:uniform`, `minecraft:alt`, `minecraft:illageralt`
pub fn font(mut self, identifier: String) -> Self {
self.font = Some(identifier);
pub fn font(mut self, resource_location: String) -> Self {
self.font = Some(resource_location);
self
}

View File

@@ -25,7 +25,7 @@ pub struct BarrelBlockEntity {
#[async_trait]
impl BlockEntity for BarrelBlockEntity {
fn identifier(&self) -> &'static str {
fn resource_location(&self) -> &'static str {
Self::ID
}

View File

@@ -9,7 +9,7 @@ pub struct BedBlockEntity {
#[async_trait]
impl BlockEntity for BedBlockEntity {
fn identifier(&self) -> &'static str {
fn resource_location(&self) -> &'static str {
Self::ID
}

View File

@@ -10,7 +10,7 @@ pub struct ChestBlockEntity {
#[async_trait]
impl BlockEntity for ChestBlockEntity {
fn identifier(&self) -> &'static str {
fn resource_location(&self) -> &'static str {
Self::ID
}

View File

@@ -28,7 +28,7 @@ impl CommandBlockEntity {
#[async_trait]
impl BlockEntity for CommandBlockEntity {
fn identifier(&self) -> &'static str {
fn resource_location(&self) -> &'static str {
Self::ID
}
fn get_position(&self) -> BlockPos {

View File

@@ -16,7 +16,7 @@ const OUTPUT_SIGNAL: &str = "OutputSignal";
#[async_trait]
impl BlockEntity for ComparatorBlockEntity {
fn identifier(&self) -> &'static str {
fn resource_location(&self) -> &'static str {
Self::ID
}

View File

@@ -16,7 +16,7 @@ impl EndPortalBlockEntity {
#[async_trait]
impl BlockEntity for EndPortalBlockEntity {
fn identifier(&self) -> &'static str {
fn resource_location(&self) -> &'static str {
Self::ID
}

View File

@@ -31,10 +31,10 @@ pub trait BlockEntity: Send + Sync {
where
Self: Sized;
async fn tick(&self, _world: &Arc<dyn SimpleWorld>) {}
fn identifier(&self) -> &'static str;
fn resource_location(&self) -> &'static str;
fn get_position(&self) -> BlockPos;
async fn write_internal(&self, nbt: &mut NbtCompound) {
nbt.put_string("id", self.identifier().to_string());
nbt.put_string("id", self.resource_location().to_string());
let position = self.get_position();
nbt.put_int("x", position.0.x);
nbt.put_int("y", position.0.y);
@@ -45,7 +45,7 @@ pub trait BlockEntity: Send + Sync {
pumpkin_data::block_properties::BLOCK_ENTITY_TYPES
.iter()
.position(|block_entity_name| {
*block_entity_name == self.identifier().split(":").last().unwrap()
*block_entity_name == self.resource_location().split(":").last().unwrap()
})
.unwrap() as u32
}

View File

@@ -55,7 +55,7 @@ const SOURCE: &str = "source";
#[async_trait]
impl BlockEntity for PistonBlockEntity {
fn identifier(&self) -> &'static str {
fn resource_location(&self) -> &'static str {
Self::ID
}

View File

@@ -144,7 +144,7 @@ impl Text {
#[async_trait]
impl BlockEntity for SignBlockEntity {
fn identifier(&self) -> &'static str {
fn resource_location(&self) -> &'static str {
Self::ID
}

View File

@@ -7,7 +7,7 @@ use pumpkin_data::tag::{RegistryKey, get_tag_values};
use pumpkin_data::{Block, BlockDirection};
use pumpkin_data::{BlockState, block_properties::BedPart};
use pumpkin_protocol::server::play::SUseItemOn;
use pumpkin_registry::DimensionType;
use pumpkin_registry::VanillaDimensionType;
use pumpkin_util::GameMode;
use pumpkin_util::math::position::BlockPos;
use pumpkin_util::text::TextComponent;
@@ -159,7 +159,7 @@ impl PumpkinBlock for BedBlock {
};
// Explode if not in the overworld
if world.dimension_type != DimensionType::Overworld {
if world.dimension_type != VanillaDimensionType::Overworld {
world
.break_block(&bed_head_pos, None, BlockFlags::SKIP_DROPS)
.await;

View File

@@ -64,7 +64,7 @@ impl PumpkinBlock for CommandBlock {
if let Some((nbt, block_entity)) = world.get_block_entity(pos).await {
let command_entity = CommandBlockEntity::from_nbt(&nbt, *pos);
if block_entity.identifier() != command_entity.identifier() {
if block_entity.resource_location() != command_entity.resource_location() {
return;
}
Self::update(
@@ -82,7 +82,7 @@ impl PumpkinBlock for CommandBlock {
if let Some((nbt, block_entity)) = world.get_block_entity(pos).await {
let command_entity = CommandBlockEntity::from_nbt(&nbt, *pos);
if block_entity.identifier() != command_entity.identifier() {
if block_entity.resource_location() != command_entity.resource_location() {
return;
}
// TODO

View File

@@ -7,7 +7,7 @@ use crate::world::World;
use async_trait::async_trait;
use pumpkin_data::{Block, BlockState};
use pumpkin_macros::pumpkin_block;
use pumpkin_registry::DimensionType;
use pumpkin_registry::VanillaDimensionType;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::block::entities::end_portal::EndPortalBlockEntity;
@@ -25,12 +25,14 @@ impl PumpkinBlock for EndPortalBlock {
_state: BlockState,
server: &Server,
) {
let world = if world.dimension_type == DimensionType::TheEnd {
let world = if world.dimension_type == VanillaDimensionType::TheEnd {
server
.get_world_from_dimension(DimensionType::Overworld)
.get_world_from_dimension(VanillaDimensionType::Overworld)
.await
} else {
server.get_world_from_dimension(DimensionType::TheEnd).await
server
.get_world_from_dimension(VanillaDimensionType::TheEnd)
.await
};
entity.get_entity().try_use_portal(0, world, pos).await;
}

View File

@@ -1,6 +1,6 @@
use pumpkin_data::block_properties::HorizontalAxis;
use pumpkin_data::entity::EntityType;
use pumpkin_registry::DimensionType;
use pumpkin_registry::VanillaDimensionType;
use pumpkin_world::world::BlockAccessor;
use rand::Rng;
use std::sync::Arc;
@@ -51,7 +51,9 @@ impl PumpkinBlock for FireBlock {
let dimension = world.dimension_type;
// First lets check if we are in OverWorld or Nether, its not possible to place an Nether portal in other dimensions in Vanilla
if dimension == DimensionType::Overworld || dimension == DimensionType::TheNether {
if dimension == VanillaDimensionType::Overworld
|| dimension == VanillaDimensionType::TheNether
{
if let Some(portal) = NetherPortal::get_new_portal(world, pos, HorizontalAxis::X).await
{
portal.create(world).await;

View File

@@ -10,7 +10,7 @@ use pumpkin_data::block_properties::{Axis, BlockProperties, NetherPortalLikeProp
use pumpkin_data::entity::EntityType;
use pumpkin_data::{Block, BlockDirection, BlockState};
use pumpkin_macros::pumpkin_block;
use pumpkin_registry::DimensionType;
use pumpkin_registry::VanillaDimensionType;
use pumpkin_util::GameMode;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
@@ -70,13 +70,13 @@ impl PumpkinBlock for NetherPortalBlock {
_state: BlockState,
server: &Server,
) {
let target_world = if world.dimension_type == DimensionType::TheNether {
let target_world = if world.dimension_type == VanillaDimensionType::TheNether {
server
.get_world_from_dimension(DimensionType::Overworld)
.get_world_from_dimension(VanillaDimensionType::Overworld)
.await
} else {
server
.get_world_from_dimension(DimensionType::TheNether)
.get_world_from_dimension(VanillaDimensionType::TheNether)
.await
};

View File

@@ -17,7 +17,7 @@ use crate::command::{
/// Command: playsound <sound> [<source>] [<targets>] [<pos>] [<volume>] [<pitch>] [<minVolume>]
///
/// Plays a sound at specified position for target players.
/// - sound: The sound identifier to play
/// - sound: The sound resource location to play
/// - source: Sound category (master, music, record, etc.)
/// - targets: Players who will hear the sound
/// - pos: Position to play the sound from

View File

@@ -8,7 +8,7 @@ use crate::command::{
tree::{CommandTree, builder::argument},
};
use async_trait::async_trait;
use pumpkin_protocol::codec::identifier::Identifier;
use pumpkin_util::resource_location::ResourceLocation;
use pumpkin_util::text::TextComponent;
const NAMES: [&str; 1] = ["stopsound"];
@@ -39,7 +39,7 @@ impl CommandExecutor for Executor {
sound
.as_ref()
.cloned()
.map(|s| Identifier::vanilla(s.to_name()))
.map(|s| ResourceLocation::vanilla(s.to_name()))
.ok(),
category.as_ref().map(|s| **s).ok(),
)

View File

@@ -20,7 +20,7 @@ use pumpkin_protocol::{
codec::var_int::VarInt,
ser::serializer::Serializer,
};
use pumpkin_registry::DimensionType;
use pumpkin_registry::VanillaDimensionType;
use pumpkin_util::math::{
boundingbox::{BoundingBox, EntityDimensions},
get_section_cord,
@@ -324,15 +324,16 @@ impl Entity {
.store(self.default_portal_cooldown(), Ordering::Relaxed);
let pos = self.pos.load();
// TODO: this is bad
let scale_factor_new =
if portal_manager.portal_world.dimension_type == DimensionType::TheNether {
8.0
} else {
1.0
};
let scale_factor_new = if portal_manager.portal_world.dimension_type
== VanillaDimensionType::TheNether
{
8.0
} else {
1.0
};
// TODO: this is bad
let scale_factor_current =
if self.world.read().await.dimension_type == DimensionType::TheNether {
if self.world.read().await.dimension_type == VanillaDimensionType::TheNether {
8.0
} else {
1.0

View File

@@ -44,7 +44,6 @@ use pumpkin_protocol::client::play::{
CSubtitle, CSystemChatMessage, CTitleText, CUnloadChunk, CUpdateMobEffect, CUpdateTime,
GameEvent, MetaDataType, Metadata, PlayerAction, PlayerInfoFlags, PreviousMessage,
};
use pumpkin_protocol::codec::identifier::Identifier;
use pumpkin_protocol::codec::var_int::VarInt;
use pumpkin_protocol::ser::packet::Packet;
use pumpkin_protocol::server::play::{
@@ -56,12 +55,13 @@ use pumpkin_protocol::server::play::{
SSetCreativeSlot, SSetHeldItem, SSetPlayerGround, SSwingArm, SUpdateSign, SUseItem, SUseItemOn,
};
use pumpkin_protocol::{IdOr, RawPacket, ServerPacket};
use pumpkin_registry::DimensionType;
use pumpkin_registry::VanillaDimensionType;
use pumpkin_util::GameMode;
use pumpkin_util::math::{
boundingbox::BoundingBox, experience, position::BlockPos, vector2::Vector2, vector3::Vector3,
};
use pumpkin_util::permission::PermissionLvl;
use pumpkin_util::resource_location::ResourceLocation;
use pumpkin_util::text::TextComponent;
use pumpkin_world::biome;
use pumpkin_world::cylindrical_chunk_iterator::Cylindrical;
@@ -512,7 +512,7 @@ impl Player {
pub async fn set_respawn_point(
&self,
dimension: DimensionType,
dimension: VanillaDimensionType,
block_pos: BlockPos,
yaw: f32,
) -> bool {
@@ -544,12 +544,12 @@ impl Player {
.get_block_and_block_state(&respawn_point.position)
.await;
if respawn_point.dimension == DimensionType::Overworld
if respawn_point.dimension == VanillaDimensionType::Overworld
&& block.is_tagged_with("#minecraft:beds").unwrap()
{
// TODO: calculate respawn position
Some((respawn_point.position.to_f64(), respawn_point.yaw))
} else if respawn_point.dimension == DimensionType::TheNether
} else if respawn_point.dimension == VanillaDimensionType::TheNether
&& block == Block::RESPAWN_ANCHOR
{
// TODO: calculate respawn position
@@ -679,9 +679,13 @@ impl Player {
///
/// # Arguments
///
/// * `sound_id`: An optional `Identifier` specifying the sound to stop. If `None`, all sounds in the specified category (if any) will be stopped.
/// * `category`: An optional `SoundCategory` specifying the sound category to stop. If `None`, all sounds with the specified identifier (if any) will be stopped.
pub async fn stop_sound(&self, sound_id: Option<Identifier>, category: Option<SoundCategory>) {
/// * `sound_id`: An optional [`ResourceLocation`] specifying the sound to stop. If [`None`], all sounds in the specified category (if any) will be stopped.
/// * `category`: An optional [`SoundCategory`] specifying the sound category to stop. If [`None`], all sounds with the specified resource location (if any) will be stopped.
pub async fn stop_sound(
&self,
sound_id: Option<ResourceLocation>,
category: Option<SoundCategory>,
) {
self.client
.enqueue_packet(&CStopSound::new(sound_id, category))
.await;
@@ -1049,7 +1053,7 @@ impl Player {
self.unload_watched_chunks(&current_world).await;
let last_pos = self.living_entity.last_pos.load();
let death_dimension = self.world().await.dimension_type.name();
let death_dimension = self.world().await.dimension_type.resource_location();
let death_location = BlockPos(Vector3::new(
last_pos.x.round() as i32,
last_pos.y.round() as i32,
@@ -1058,7 +1062,7 @@ impl Player {
self.client
.send_packet_now(&CRespawn::new(
(new_world.dimension_type as u8).into(),
new_world.dimension_type.name(),
new_world.dimension_type.resource_location(),
biome::hash_seed(new_world.level.seed.0), // seed
self.gamemode.load() as u8,
self.gamemode.load() as i8,
@@ -1867,7 +1871,14 @@ impl NBTStorage for Player {
// Store food level, saturation, exhaustion, and tick timer
self.hunger_manager.write_nbt(nbt).await;
nbt.put_string("Dimension", self.world().await.dimension_type.name().get());
nbt.put_string(
"Dimension",
self.world()
.await
.dimension_type
.resource_location()
.to_string(),
);
}
async fn read_nbt(&mut self, nbt: &mut NbtCompound) {
@@ -2282,7 +2293,7 @@ impl TryFrom<i32> for Hand {
/// Represents the player's respawn point.
#[derive(Copy, Debug, Clone, PartialEq)]
pub struct RespawnPoint {
pub dimension: DimensionType,
pub dimension: VanillaDimensionType,
pub position: BlockPos,
pub yaw: f32,
pub force: bool,

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use crate::entity::player::Player;
use async_trait::async_trait;
use pumpkin_data::{Block, BlockState, fluid::Fluid, item::Item};
use pumpkin_registry::DimensionType;
use pumpkin_registry::VanillaDimensionType;
use pumpkin_util::{
GameMode,
math::{position::BlockPos, vector3::Vector3},
@@ -211,7 +211,9 @@ impl PumpkinItem for FilledBucketItem {
return;
};
if item.id != Item::LAVA_BUCKET.id && world.dimension_type == DimensionType::TheNether {
if item.id != Item::LAVA_BUCKET.id
&& world.dimension_type == VanillaDimensionType::TheNether
{
return;
}
let (block, state) = world.get_block_and_block_state(&pos).await;

View File

@@ -592,7 +592,7 @@ impl Player {
if let Some((nbt, block_entity)) = self.world().await.get_block_entity(&pos).await {
let command_entity = CommandBlockEntity::from_nbt(&nbt, pos);
if block_entity.identifier() != command_entity.identifier() {
if block_entity.resource_location() != command_entity.resource_location() {
log::warn!(
"Client tried to change Command block but not Command block entity found"
);

View File

@@ -22,7 +22,7 @@ use pumpkin_protocol::client::login::CEncryptionRequest;
use pumpkin_protocol::client::play::CChangeDifficulty;
use pumpkin_protocol::client::play::CSetSelectedSlot;
use pumpkin_protocol::{ClientPacket, client::config::CPluginMessage};
use pumpkin_registry::{DimensionType, Registry};
use pumpkin_registry::{Registry, VanillaDimensionType};
use pumpkin_util::Difficulty;
use pumpkin_util::math::vector2::Vector2;
use pumpkin_util::text::TextComponent;
@@ -70,7 +70,7 @@ pub struct Server {
/// Manages multiple worlds within the server.
pub worlds: RwLock<Vec<Arc<World>>>,
/// All the dimensions that exist on the server.
pub dimensions: Vec<DimensionType>,
pub dimensions: Vec<VanillaDimensionType>,
/// Caches game registries for efficient access.
pub cached_registry: Vec<Registry>,
/// Assigns unique IDs to containers.
@@ -148,21 +148,21 @@ impl Server {
let overworld = World::load(
Dimension::Overworld.into_level(world_path.clone(), block_registry.clone(), seed),
level_info.clone(),
DimensionType::Overworld,
VanillaDimensionType::Overworld,
block_registry.clone(),
);
log::info!("Loading Nether: {seed}");
let nether = World::load(
Dimension::Nether.into_level(world_path.clone(), block_registry.clone(), seed),
level_info.clone(),
DimensionType::TheNether,
VanillaDimensionType::TheNether,
block_registry.clone(),
);
log::info!("Loading End: {seed}");
let end = World::load(
Dimension::End.into_level(world_path.clone(), block_registry.clone(), seed),
level_info.clone(),
DimensionType::TheEnd,
VanillaDimensionType::TheEnd,
block_registry.clone(),
);
@@ -177,10 +177,10 @@ impl Server {
container_id: 0.into(),
worlds: RwLock::new(vec![Arc::new(overworld), Arc::new(nether), Arc::new(end)]),
dimensions: vec![
DimensionType::Overworld,
DimensionType::OverworldCaves,
DimensionType::TheNether,
DimensionType::TheEnd,
VanillaDimensionType::Overworld,
VanillaDimensionType::OverworldCaves,
VanillaDimensionType::TheNether,
VanillaDimensionType::TheEnd,
],
command_dispatcher,
block_registry,
@@ -228,14 +228,14 @@ impl Server {
self.tasks.spawn(task)
}
pub async fn get_world_from_dimension(&self, dimension: DimensionType) -> Arc<World> {
pub async fn get_world_from_dimension(&self, dimension: VanillaDimensionType) -> Arc<World> {
// TODO: this is really bad
let world_guard = self.worlds.read().await;
let world = match dimension {
DimensionType::Overworld => world_guard.first(),
DimensionType::OverworldCaves => todo!(),
DimensionType::TheEnd => world_guard.get(2),
DimensionType::TheNether => world_guard.get(1),
VanillaDimensionType::Overworld => world_guard.first(),
VanillaDimensionType::OverworldCaves => todo!(),
VanillaDimensionType::TheEnd => world_guard.get(2),
VanillaDimensionType::TheNether => world_guard.get(1),
};
world.cloned().unwrap()
}
@@ -272,7 +272,9 @@ impl Server {
let (world, nbt) = if let Ok(Some(data)) = self.player_data_storage.load_data(&uuid) {
if let Some(dimension_key) = data.get_string("Dimension") {
if let Some(dimension) = DimensionType::from_name(dimension_key) {
if let Some(dimension) =
VanillaDimensionType::from_resource_location_string(dimension_key)
{
let world = self.get_world_from_dimension(dimension).await;
(world, Some(data))
} else {

View File

@@ -44,7 +44,6 @@ use pumpkin_data::{BlockDirection, block_properties::get_block_outline_shapes};
use pumpkin_inventory::equipment_slot::EquipmentSlot;
use pumpkin_macros::send_cancellable;
use pumpkin_nbt::{compound::NbtCompound, to_bytes_unnamed};
use pumpkin_protocol::codec::identifier::Identifier;
use pumpkin_protocol::ser::serializer::Serializer;
use pumpkin_protocol::{
ClientPacket, IdOr, SoundEvent,
@@ -68,8 +67,9 @@ use pumpkin_protocol::{
},
codec::var_int::VarInt,
};
use pumpkin_registry::DimensionType;
use pumpkin_registry::VanillaDimensionType;
use pumpkin_util::math::{position::chunk_section_from_pos, vector2::Vector2};
use pumpkin_util::resource_location::ResourceLocation;
use pumpkin_util::text::{TextComponent, color::NamedColor};
use pumpkin_util::{
Difficulty,
@@ -141,7 +141,7 @@ pub struct World {
/// The world's time, including counting ticks for weather, time cycles, and statistics.
pub level_time: Mutex<LevelTime>,
/// The type of dimension the world is in.
pub dimension_type: DimensionType,
pub dimension_type: VanillaDimensionType,
pub sea_level: i32,
/// The world's weather, including rain and thunder levels.
pub weather: Mutex<Weather>,
@@ -157,17 +157,21 @@ impl World {
pub fn load(
level: Level,
level_info: LevelData,
dimension_type: DimensionType,
dimension_type: VanillaDimensionType,
block_registry: Arc<BlockRegistry>,
) -> Self {
// TODO
let generation_settings = match dimension_type {
DimensionType::Overworld => GENERATION_SETTINGS
VanillaDimensionType::Overworld => GENERATION_SETTINGS
.get(&GeneratorSetting::Overworld)
.unwrap(),
DimensionType::OverworldCaves => todo!(),
DimensionType::TheEnd => GENERATION_SETTINGS.get(&GeneratorSetting::End).unwrap(),
DimensionType::TheNether => GENERATION_SETTINGS.get(&GeneratorSetting::Nether).unwrap(),
VanillaDimensionType::OverworldCaves => todo!(),
VanillaDimensionType::TheEnd => {
GENERATION_SETTINGS.get(&GeneratorSetting::End).unwrap()
}
VanillaDimensionType::TheNether => {
GENERATION_SETTINGS.get(&GeneratorSetting::Nether).unwrap()
}
};
Self {
@@ -521,12 +525,16 @@ impl World {
pub async fn get_top_block(&self, position: Vector2<i32>) -> i32 {
// TODO: this is bad
let generation_settings = match self.dimension_type {
DimensionType::Overworld => GENERATION_SETTINGS
VanillaDimensionType::Overworld => GENERATION_SETTINGS
.get(&GeneratorSetting::Overworld)
.unwrap(),
DimensionType::OverworldCaves => todo!(),
DimensionType::TheEnd => GENERATION_SETTINGS.get(&GeneratorSetting::End).unwrap(),
DimensionType::TheNether => GENERATION_SETTINGS.get(&GeneratorSetting::Nether).unwrap(),
VanillaDimensionType::OverworldCaves => todo!(),
VanillaDimensionType::TheEnd => {
GENERATION_SETTINGS.get(&GeneratorSetting::End).unwrap()
}
VanillaDimensionType::TheNether => {
GENERATION_SETTINGS.get(&GeneratorSetting::Nether).unwrap()
}
};
for y in (i32::from(generation_settings.shape.min_y)
..=i32::from(generation_settings.shape.height))
@@ -549,8 +557,11 @@ impl World {
player: Arc<Player>,
server: &Server,
) {
let dimensions: Vec<Identifier> =
server.dimensions.iter().map(DimensionType::name).collect();
let dimensions: Vec<ResourceLocation> = server
.dimensions
.iter()
.map(VanillaDimensionType::resource_location)
.collect();
// This code follows the vanilla packet order
let entity_id = player.entity_id();
@@ -575,7 +586,7 @@ impl World {
true,
false,
(self.dimension_type as u8).into(),
self.dimension_type.name(),
self.dimension_type.resource_location(),
biome::hash_seed(self.level.seed.0), // seed
gamemode as u8,
player
@@ -941,7 +952,7 @@ impl World {
pub async fn respawn_player(&self, player: &Arc<Player>, alive: bool) {
let last_pos = player.living_entity.last_pos.load();
let death_dimension = player.world().await.dimension_type.name();
let death_dimension = player.world().await.dimension_type.resource_location();
let death_location = BlockPos(Vector3::new(
last_pos.x.round() as i32,
last_pos.y.round() as i32,
@@ -956,7 +967,7 @@ impl World {
.client
.enqueue_packet(&CRespawn::new(
(self.dimension_type as u8).into(),
self.dimension_type.name(),
self.dimension_type.resource_location(),
biome::hash_seed(self.level.seed.0), // seed
player.gamemode.load() as u8,
player.gamemode.load() as i8,