feat: 1.21.9-1.21.11 support
more versions will come
This commit is contained in:
parent
5ed0e57843
commit
142296a9b2
@ -5,7 +5,6 @@
|
||||

|
||||
[](https://discord.gg/wT8XjrjKkf)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
|
||||
1
assets/jukebox_song.json
Normal file
1
assets/jukebox_song.json
Normal file
@ -0,0 +1 @@
|
||||
{"11":0,"13":1,"5":2,"blocks":3,"cat":4,"chirp":5,"creator":6,"creator_music_box":7,"far":8,"lava_chicken":9,"mall":10,"mellohi":11,"otherside":12,"pigstep":13,"precipice":14,"relic":15,"stal":16,"strad":17,"tears":18,"wait":19,"ward":20}
|
||||
1
assets/packet/1_21_11_packets.json
Normal file
1
assets/packet/1_21_11_packets.json
Normal file
File diff suppressed because one or more lines are too long
@ -1,276 +0,0 @@
|
||||
{
|
||||
"version": 774,
|
||||
"serverbound": {
|
||||
"handshake": [
|
||||
"intention"
|
||||
],
|
||||
"status": [
|
||||
"status_request",
|
||||
"ping_request"
|
||||
],
|
||||
"login": [
|
||||
"hello",
|
||||
"key",
|
||||
"custom_query_answer",
|
||||
"login_acknowledged",
|
||||
"cookie_response"
|
||||
],
|
||||
"config": [
|
||||
"client_information",
|
||||
"cookie_response",
|
||||
"custom_payload",
|
||||
"finish_configuration",
|
||||
"keep_alive",
|
||||
"pong",
|
||||
"resource_pack",
|
||||
"select_known_packs",
|
||||
"custom_click_action",
|
||||
"accept_code_of_conduct"
|
||||
],
|
||||
"play": [
|
||||
"accept_teleportation",
|
||||
"block_entity_tag_query",
|
||||
"bundle_item_selected",
|
||||
"change_difficulty",
|
||||
"change_game_mode",
|
||||
"chat_ack",
|
||||
"chat_command",
|
||||
"chat_command_signed",
|
||||
"chat",
|
||||
"chat_session_update",
|
||||
"chunk_batch_received",
|
||||
"client_command",
|
||||
"client_tick_end",
|
||||
"client_information",
|
||||
"command_suggestion",
|
||||
"configuration_acknowledged",
|
||||
"container_button_click",
|
||||
"container_click",
|
||||
"container_close",
|
||||
"container_slot_state_changed",
|
||||
"cookie_response",
|
||||
"custom_payload",
|
||||
"debug_subscription_request",
|
||||
"edit_book",
|
||||
"entity_tag_query",
|
||||
"interact",
|
||||
"jigsaw_generate",
|
||||
"keep_alive",
|
||||
"lock_difficulty",
|
||||
"move_player_pos",
|
||||
"move_player_pos_rot",
|
||||
"move_player_rot",
|
||||
"move_player_status_only",
|
||||
"move_vehicle",
|
||||
"paddle_boat",
|
||||
"pick_item_from_block",
|
||||
"pick_item_from_entity",
|
||||
"ping_request",
|
||||
"place_recipe",
|
||||
"player_abilities",
|
||||
"player_action",
|
||||
"player_command",
|
||||
"player_input",
|
||||
"player_loaded",
|
||||
"pong",
|
||||
"recipe_book_change_settings",
|
||||
"recipe_book_seen_recipe",
|
||||
"rename_item",
|
||||
"resource_pack",
|
||||
"seen_advancements",
|
||||
"select_trade",
|
||||
"set_beacon",
|
||||
"set_carried_item",
|
||||
"set_command_block",
|
||||
"set_command_minecart",
|
||||
"set_creative_mode_slot",
|
||||
"set_jigsaw_block",
|
||||
"set_structure_block",
|
||||
"set_test_block",
|
||||
"sign_update",
|
||||
"swing",
|
||||
"teleport_to_entity",
|
||||
"test_instance_block_action",
|
||||
"use_item_on",
|
||||
"use_item",
|
||||
"custom_click_action"
|
||||
]
|
||||
},
|
||||
"clientbound": {
|
||||
"status": [
|
||||
"status_response",
|
||||
"pong_response"
|
||||
],
|
||||
"login": [
|
||||
"login_disconnect",
|
||||
"hello",
|
||||
"login_finished",
|
||||
"login_compression",
|
||||
"custom_query",
|
||||
"cookie_request"
|
||||
],
|
||||
"config": [
|
||||
"cookie_request",
|
||||
"custom_payload",
|
||||
"disconnect",
|
||||
"finish_configuration",
|
||||
"keep_alive",
|
||||
"ping",
|
||||
"reset_chat",
|
||||
"registry_data",
|
||||
"resource_pack_pop",
|
||||
"resource_pack_push",
|
||||
"store_cookie",
|
||||
"transfer",
|
||||
"update_enabled_features",
|
||||
"update_tags",
|
||||
"select_known_packs",
|
||||
"custom_report_details",
|
||||
"server_links",
|
||||
"clear_dialog",
|
||||
"show_dialog",
|
||||
"code_of_conduct"
|
||||
],
|
||||
"play": [
|
||||
"bundle_delimiter",
|
||||
"add_entity",
|
||||
"animate",
|
||||
"award_stats",
|
||||
"block_changed_ack",
|
||||
"block_destruction",
|
||||
"block_entity_data",
|
||||
"block_event",
|
||||
"block_update",
|
||||
"boss_event",
|
||||
"change_difficulty",
|
||||
"chunk_batch_finished",
|
||||
"chunk_batch_start",
|
||||
"chunks_biomes",
|
||||
"clear_titles",
|
||||
"command_suggestions",
|
||||
"commands",
|
||||
"container_close",
|
||||
"container_set_content",
|
||||
"container_set_data",
|
||||
"container_set_slot",
|
||||
"cookie_request",
|
||||
"cooldown",
|
||||
"custom_chat_completions",
|
||||
"custom_payload",
|
||||
"damage_event",
|
||||
"debug/block_value",
|
||||
"debug/chunk_value",
|
||||
"debug/entity_value",
|
||||
"debug/event",
|
||||
"debug_sample",
|
||||
"delete_chat",
|
||||
"disconnect",
|
||||
"disguised_chat",
|
||||
"entity_event",
|
||||
"entity_position_sync",
|
||||
"explode",
|
||||
"forget_level_chunk",
|
||||
"game_event",
|
||||
"game_test_highlight_pos",
|
||||
"mount_screen_open",
|
||||
"hurt_animation",
|
||||
"initialize_border",
|
||||
"keep_alive",
|
||||
"level_chunk_with_light",
|
||||
"level_event",
|
||||
"level_particles",
|
||||
"light_update",
|
||||
"login",
|
||||
"map_item_data",
|
||||
"merchant_offers",
|
||||
"move_entity_pos",
|
||||
"move_entity_pos_rot",
|
||||
"move_minecart_along_track",
|
||||
"move_entity_rot",
|
||||
"move_vehicle",
|
||||
"open_book",
|
||||
"open_screen",
|
||||
"open_sign_editor",
|
||||
"ping",
|
||||
"pong_response",
|
||||
"place_ghost_recipe",
|
||||
"player_abilities",
|
||||
"player_chat",
|
||||
"player_combat_end",
|
||||
"player_combat_enter",
|
||||
"player_combat_kill",
|
||||
"player_info_remove",
|
||||
"player_info_update",
|
||||
"player_look_at",
|
||||
"player_position",
|
||||
"player_rotation",
|
||||
"recipe_book_add",
|
||||
"recipe_book_remove",
|
||||
"recipe_book_settings",
|
||||
"remove_entities",
|
||||
"remove_mob_effect",
|
||||
"reset_score",
|
||||
"resource_pack_pop",
|
||||
"resource_pack_push",
|
||||
"respawn",
|
||||
"rotate_head",
|
||||
"section_blocks_update",
|
||||
"select_advancements_tab",
|
||||
"server_data",
|
||||
"set_action_bar_text",
|
||||
"set_border_center",
|
||||
"set_border_lerp_size",
|
||||
"set_border_size",
|
||||
"set_border_warning_delay",
|
||||
"set_border_warning_distance",
|
||||
"set_camera",
|
||||
"set_chunk_cache_center",
|
||||
"set_chunk_cache_radius",
|
||||
"set_cursor_item",
|
||||
"set_default_spawn_position",
|
||||
"set_display_objective",
|
||||
"set_entity_data",
|
||||
"set_entity_link",
|
||||
"set_entity_motion",
|
||||
"set_equipment",
|
||||
"set_experience",
|
||||
"set_health",
|
||||
"set_held_slot",
|
||||
"set_objective",
|
||||
"set_passengers",
|
||||
"set_player_inventory",
|
||||
"set_player_team",
|
||||
"set_score",
|
||||
"set_simulation_distance",
|
||||
"set_subtitle_text",
|
||||
"set_time",
|
||||
"set_title_text",
|
||||
"set_titles_animation",
|
||||
"sound_entity",
|
||||
"sound",
|
||||
"start_configuration",
|
||||
"stop_sound",
|
||||
"store_cookie",
|
||||
"system_chat",
|
||||
"tab_list",
|
||||
"tag_query",
|
||||
"take_item_entity",
|
||||
"teleport_entity",
|
||||
"test_instance_block_status",
|
||||
"ticking_state",
|
||||
"ticking_step",
|
||||
"transfer",
|
||||
"update_advancements",
|
||||
"update_attributes",
|
||||
"update_mob_effect",
|
||||
"update_recipes",
|
||||
"update_tags",
|
||||
"projectile_power",
|
||||
"custom_report_details",
|
||||
"server_links",
|
||||
"waypoint",
|
||||
"clear_dialog",
|
||||
"show_dialog"
|
||||
]
|
||||
}
|
||||
}
|
||||
1
assets/registry/1_21_11_synced_registries.json
Normal file
1
assets/registry/1_21_11_synced_registries.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/registry/1_21_9_synced_registries.json
Normal file
1
assets/registry/1_21_9_synced_registries.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
12656
assets/tags.json
12656
assets/tags.json
File diff suppressed because it is too large
Load Diff
1
assets/tags/1_21_11_tags.json
Normal file
1
assets/tags/1_21_11_tags.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/tags/1_21_9_tags.json
Normal file
1
assets/tags/1_21_9_tags.json
Normal file
File diff suppressed because one or more lines are too long
@ -29,6 +29,7 @@ mod fuels;
|
||||
mod game_event;
|
||||
mod game_rules;
|
||||
mod item;
|
||||
mod jukebox_song;
|
||||
pub mod loot;
|
||||
mod message_type;
|
||||
mod meta_data_type;
|
||||
@ -71,6 +72,7 @@ pub fn main() {
|
||||
(game_rules::build, "game_rules.rs"),
|
||||
(registry::build, "registry.rs"),
|
||||
(dimension::build, "dimension.rs"),
|
||||
(jukebox_song::build, "jukebox_song.rs"),
|
||||
(sound_category::build, "sound_category.rs"),
|
||||
(entity_pose::build, "entity_pose.rs"),
|
||||
(scoreboard_slot::build, "scoreboard_slot.rs"),
|
||||
|
||||
88
pumpkin-data/build/jukebox_song.rs
Normal file
88
pumpkin-data/build/jukebox_song.rs
Normal file
@ -0,0 +1,88 @@
|
||||
use heck::ToPascalCase;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs;
|
||||
|
||||
pub(crate) fn build() -> TokenStream {
|
||||
println!("cargo:rerun-if-changed=../assets/jukebox_song.json");
|
||||
|
||||
let songs: BTreeMap<String, u32> = serde_json::from_str(
|
||||
&fs::read_to_string("../assets/jukebox_song.json").expect("Missing jukebox_song.json"),
|
||||
)
|
||||
.expect("Failed to parse jukebox_song.json");
|
||||
|
||||
// Helper to handle numeric keys like "11" -> "Id11"
|
||||
let make_variant_ident = |name: &str| {
|
||||
let pascal = name.to_pascal_case();
|
||||
if pascal.chars().next().is_some_and(|c| c.is_ascii_digit()) {
|
||||
format_ident!("Id{}", pascal)
|
||||
} else {
|
||||
format_ident!("{}", pascal)
|
||||
}
|
||||
};
|
||||
|
||||
let variants = songs
|
||||
.keys()
|
||||
.map(|name| {
|
||||
let variant_name = make_variant_ident(name);
|
||||
quote! { #variant_name, }
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
let type_from_name = songs
|
||||
.keys()
|
||||
.map(|name| {
|
||||
let variant_name = make_variant_ident(name);
|
||||
quote! { #name => Some(Self::#variant_name), }
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
let type_to_name = songs
|
||||
.keys()
|
||||
.map(|name| {
|
||||
let variant_name = make_variant_ident(name);
|
||||
quote! { Self::#variant_name => #name, }
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
let type_to_id = songs
|
||||
.iter()
|
||||
.map(|(name, id)| {
|
||||
let variant_name = make_variant_ident(name);
|
||||
quote! { Self::#variant_name => #id, }
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
quote! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[repr(u32)]
|
||||
pub enum JukeboxSong {
|
||||
#variants
|
||||
}
|
||||
|
||||
impl JukeboxSong {
|
||||
#[doc = r" Returns the JukeboxSong from the string name (e.g., 'pigstep')."]
|
||||
pub fn from_name(name: &str) -> Option<Self> {
|
||||
match name {
|
||||
#type_from_name
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = r" Returns the string name of the song."]
|
||||
pub const fn to_name(&self) -> &'static str {
|
||||
match self {
|
||||
#type_to_name
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = r" Returns the numeric ID associated with the song."]
|
||||
pub const fn get_id(&self) -> u32 {
|
||||
match self {
|
||||
#type_to_id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,22 +7,23 @@ use serde::Deserialize;
|
||||
#[derive(Deserialize)]
|
||||
pub struct Packets {
|
||||
version: u32,
|
||||
serverbound: BTreeMap<String, Vec<String>>,
|
||||
clientbound: BTreeMap<String, Vec<String>>,
|
||||
serverbound: BTreeMap<String, BTreeMap<String, i32>>,
|
||||
clientbound: BTreeMap<String, BTreeMap<String, i32>>,
|
||||
}
|
||||
|
||||
pub(crate) fn build() -> TokenStream {
|
||||
println!("cargo:rerun-if-changed=../assets/packets.json");
|
||||
println!("cargo:rerun-if-changed=../assets/packet/1_21_11_packets.json");
|
||||
|
||||
let packets: Packets =
|
||||
serde_json::from_str(&fs::read_to_string("../assets/packets.json").unwrap())
|
||||
serde_json::from_str(&fs::read_to_string("../assets/packet/1_21_11_packets.json").unwrap())
|
||||
.expect("Failed to parse packets.json");
|
||||
|
||||
let version = packets.version;
|
||||
let serverbound_consts = parse_packets(packets.serverbound);
|
||||
let clientbound_consts = parse_packets(packets.clientbound);
|
||||
|
||||
quote!(
|
||||
/// The current Minecraft protocol version. This changes only when the protocol itself is modified.
|
||||
/// The current Minecraft protocol version.
|
||||
pub const CURRENT_MC_PROTOCOL: u32 = #version;
|
||||
|
||||
pub mod serverbound {
|
||||
@ -35,20 +36,21 @@ pub(crate) fn build() -> TokenStream {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn parse_packets(packets: BTreeMap<String, Vec<String>>) -> proc_macro2::TokenStream {
|
||||
pub(crate) fn parse_packets(phases: BTreeMap<String, BTreeMap<String, i32>>) -> TokenStream {
|
||||
let mut consts = TokenStream::new();
|
||||
|
||||
for packet in packets {
|
||||
let phase = packet.0;
|
||||
for (phase_name, packets) in phases {
|
||||
for (packet_name, packet_id) in packets {
|
||||
let sanitized_name = packet_name
|
||||
.replace("/", "_")
|
||||
.replace("-", "_")
|
||||
.to_uppercase();
|
||||
|
||||
for (id, packet_name) in packet.1.iter().enumerate() {
|
||||
let packet_id = id as i32;
|
||||
let packet_name = packet_name.replace("/", "_");
|
||||
let name = format!("{phase}_{packet_name}").to_uppercase();
|
||||
let name = format_ident!("{}", name);
|
||||
consts.extend([quote! {
|
||||
pub const #name: i32 = #packet_id;
|
||||
}]);
|
||||
let const_name = format_ident!("{}_{}", phase_name.to_uppercase(), sanitized_name);
|
||||
|
||||
consts.extend(quote! {
|
||||
pub const #const_name: i32 = #packet_id;
|
||||
});
|
||||
}
|
||||
}
|
||||
consts
|
||||
|
||||
@ -5,83 +5,64 @@ use serde_json::Value;
|
||||
use std::fs;
|
||||
|
||||
pub(crate) fn build() -> TokenStream {
|
||||
println!("cargo:rerun-if-changed=../assets/synced_registries.json");
|
||||
println!("cargo:rerun-if-changed=../assets/registry/1_21_9_synced_registries.json");
|
||||
println!("cargo:rerun-if-changed=../assets/registry/1_21_11_synced_registries.json");
|
||||
|
||||
let json_str = fs::read_to_string("../assets/synced_registries.json")
|
||||
.expect("Failed to read synced_registries.json");
|
||||
let mut data: IndexMap<String, IndexMap<String, Value>> =
|
||||
serde_json::from_str(&json_str).expect("Failed to parse synced_registries.json");
|
||||
let process_version = |path: &str| -> TokenStream {
|
||||
let json_str =
|
||||
fs::read_to_string(path).unwrap_or_else(|_| panic!("Failed to read {}", path));
|
||||
let mut data: IndexMap<String, IndexMap<String, Value>> =
|
||||
serde_json::from_str(&json_str).expect("Failed to parse JSON");
|
||||
|
||||
let chat_type = if data.contains_key("minecraft:chat_type") {
|
||||
data.get_mut("minecraft:chat_type")
|
||||
} else {
|
||||
data.get_mut("chat_type")
|
||||
// Inject "raw" chat type for vanilla parity
|
||||
if let Some(chat) = data.get_mut("minecraft:chat_type") {
|
||||
chat.insert("raw".to_string(), serde_json::json!({
|
||||
"chat": { "translation_key": "%s", "parameters": ["content"] },
|
||||
"narration": { "translation_key": "%s says %s", "parameters": ["sender", "content"] }
|
||||
}));
|
||||
}
|
||||
|
||||
let reg_tokens: Vec<TokenStream> = data
|
||||
.iter()
|
||||
.map(|(reg_name, entries)| {
|
||||
let entry_tokens: Vec<TokenStream> = entries
|
||||
.iter()
|
||||
.map(|(entry_name, entry_data)| {
|
||||
let mut bytes = Vec::new();
|
||||
pumpkin_nbt::serializer::to_bytes_unnamed(entry_data, &mut bytes).unwrap();
|
||||
let byte_literal = Literal::byte_string(&bytes);
|
||||
|
||||
quote! {
|
||||
StaticRegistryEntry {
|
||||
name: #entry_name,
|
||||
data: #byte_literal
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
quote! {
|
||||
StaticRegistry {
|
||||
registry_id: #reg_name,
|
||||
entries: &[#(#entry_tokens),*],
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
quote! { &[#(#reg_tokens),*] }
|
||||
};
|
||||
|
||||
if let Some(chat_type) = chat_type {
|
||||
chat_type.insert(
|
||||
"raw".to_string(),
|
||||
serde_json::json!({
|
||||
"chat": {
|
||||
"translation_key": "%s",
|
||||
"parameters": ["content"],
|
||||
"style": null
|
||||
},
|
||||
"narration": {
|
||||
"translation_key": "%s says %s",
|
||||
"parameters": ["sender", "content"],
|
||||
"style": null
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
let registries_tokens = data.iter().map(|(reg_name, entries)| {
|
||||
let entry_tokens = entries.iter().map(|(entry_name, entry_data)| {
|
||||
let mut nbt_bytes = Vec::new();
|
||||
pumpkin_nbt::serializer::to_bytes_unnamed(entry_data, &mut nbt_bytes)
|
||||
.expect("Failed to serialize NBT at build time");
|
||||
|
||||
let nbt_literal = Literal::byte_string(&nbt_bytes);
|
||||
|
||||
quote! {
|
||||
StaticRegistryEntry {
|
||||
name: #entry_name,
|
||||
nbt_bytes: #nbt_literal,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
StaticRegistry {
|
||||
registry_id: #reg_name,
|
||||
entries: &[#(#entry_tokens),*],
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let jukebox_entries = data
|
||||
.get("minecraft:jukebox_song")
|
||||
.or_else(|| data.get("jukebox_song"));
|
||||
|
||||
let jukebox_index_arms = jukebox_entries
|
||||
.map(|entries| {
|
||||
entries
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, (name, _))| {
|
||||
quote! { #name => Some(#index), }
|
||||
})
|
||||
.collect::<TokenStream>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let v1_21_9_registries = process_version("../assets/registry/1_21_9_synced_registries.json");
|
||||
let v1_21_11_registries = process_version("../assets/registry/1_21_11_synced_registries.json");
|
||||
|
||||
quote! {
|
||||
use pumpkin_util::resource_location::ResourceLocation;
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
|
||||
pub struct StaticRegistryEntry {
|
||||
pub name: &'static str,
|
||||
pub nbt_bytes: &'static [u8],
|
||||
pub data: &'static [u8],
|
||||
}
|
||||
|
||||
pub struct StaticRegistry {
|
||||
@ -89,10 +70,6 @@ pub(crate) fn build() -> TokenStream {
|
||||
pub entries: &'static [StaticRegistryEntry],
|
||||
}
|
||||
|
||||
pub static SYNCED_REGISTRIES: &[StaticRegistry] = &[
|
||||
#(#registries_tokens),*
|
||||
];
|
||||
|
||||
pub struct RegistryEntryData {
|
||||
pub entry_id: ResourceLocation,
|
||||
pub data: Option<Box<[u8]>>,
|
||||
@ -103,20 +80,17 @@ pub(crate) fn build() -> TokenStream {
|
||||
pub registry_entries: Vec<RegistryEntryData>,
|
||||
}
|
||||
|
||||
pub struct SyncedRegistry;
|
||||
|
||||
impl SyncedRegistry {
|
||||
pub fn get_jukebox_song_index(song_key: &str) -> Option<usize> {
|
||||
match song_key {
|
||||
#jukebox_index_arms
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
pub static REGISTRIES_1_21_9: &[StaticRegistry] = #v1_21_9_registries;
|
||||
pub static REGISTRIES_1_21_11: &[StaticRegistry] = #v1_21_11_registries;
|
||||
|
||||
impl Registry {
|
||||
pub fn get_synced() -> Vec<Self> {
|
||||
SYNCED_REGISTRIES.iter().map(|static_reg| {
|
||||
pub fn get_synced(version: MinecraftVersion) -> Vec<Self> {
|
||||
let static_regs = match version {
|
||||
MinecraftVersion::V_1_21_9 => REGISTRIES_1_21_9,
|
||||
_ => REGISTRIES_1_21_11,
|
||||
};
|
||||
|
||||
static_regs.iter().map(|static_reg| {
|
||||
let registry_id = if static_reg.registry_id.contains(':') {
|
||||
ResourceLocation::from(static_reg.registry_id)
|
||||
} else {
|
||||
@ -124,24 +98,17 @@ pub(crate) fn build() -> TokenStream {
|
||||
};
|
||||
|
||||
let registry_entries = static_reg.entries.iter().map(|entry| {
|
||||
let entry_id = if entry.name.contains(':') {
|
||||
ResourceLocation::from(entry.name)
|
||||
} else {
|
||||
ResourceLocation::vanilla(entry.name)
|
||||
};
|
||||
|
||||
let data = Some(entry.nbt_bytes.to_vec().into_boxed_slice());
|
||||
let entry_id =
|
||||
ResourceLocation::vanilla(entry.name);
|
||||
|
||||
RegistryEntryData {
|
||||
entry_id,
|
||||
data,
|
||||
// Data is now sourced directly from the entry
|
||||
data: Some(entry.data.to_vec().into_boxed_slice()),
|
||||
}
|
||||
}).collect();
|
||||
|
||||
Self {
|
||||
registry_id,
|
||||
registry_entries,
|
||||
}
|
||||
Self { registry_id, registry_entries }
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
use std::{collections::BTreeMap, fs};
|
||||
use std::{
|
||||
collections::{BTreeMap, HashSet},
|
||||
fs,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use crate::biome::Biome;
|
||||
use crate::block::BlockAssets;
|
||||
@ -10,73 +14,87 @@ use heck::ToPascalCase;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, format_ident, quote};
|
||||
|
||||
// --- EnumCreator with from_string support ---
|
||||
pub struct EnumCreator {
|
||||
pub name: String,
|
||||
pub value: Vec<String>,
|
||||
pub values: Vec<String>,
|
||||
}
|
||||
|
||||
impl ToTokens for EnumCreator {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let name = format_ident!("{}", self.name.to_pascal_case());
|
||||
let values = self
|
||||
.value
|
||||
.iter()
|
||||
.map(|value| {
|
||||
let name = format_ident!("{}", value.to_pascal_case());
|
||||
name
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let variants = self.values.iter().map(|v| {
|
||||
let variant_name = format_ident!("{}", v.to_pascal_case());
|
||||
quote! { #variant_name }
|
||||
});
|
||||
|
||||
let from_string_arms = self.values.iter().map(|v| {
|
||||
let variant_name = format_ident!("{}", v.to_pascal_case());
|
||||
quote! { #v => Some(Self::#variant_name) }
|
||||
});
|
||||
|
||||
let to_string_arms = self.values.iter().map(|v| {
|
||||
let variant_name = format_ident!("{}", v.to_pascal_case());
|
||||
quote! { Self::#variant_name => #v }
|
||||
});
|
||||
|
||||
tokens.extend(quote! {
|
||||
#[derive(Eq, PartialEq, Hash, Debug, Clone, Copy)]
|
||||
pub enum #name {
|
||||
#(#values),*
|
||||
#(#variants),*
|
||||
}
|
||||
|
||||
impl #name {
|
||||
pub fn from_string(s: &str) -> Option<Self> {
|
||||
match s {
|
||||
#(#from_string_arms,)*
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn identifier_string(&self) -> &str {
|
||||
match self {
|
||||
#(#to_string_arms),*
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build() -> TokenStream {
|
||||
println!("cargo:rerun-if-changed=../assets/tags.json");
|
||||
// --- Rerun Triggers ---
|
||||
println!("cargo:rerun-if-changed=../assets/blocks.json");
|
||||
println!("cargo:rerun-if-changed=../assets/items.json");
|
||||
println!("cargo:rerun-if-changed=../assets/biome.json");
|
||||
println!("cargo:rerun-if-changed=../assets/fluids.json");
|
||||
println!("cargo:rerun-if-changed=../assets/entities.json");
|
||||
|
||||
let tags: BTreeMap<String, BTreeMap<String, Vec<String>>> =
|
||||
serde_json::from_str(&fs::read_to_string("../assets/tags.json").unwrap())
|
||||
.expect("Failed to parse tags.json");
|
||||
// Watch specific tag versions
|
||||
println!("cargo:rerun-if-changed=../assets/tags/1_21_11_tags.json");
|
||||
println!("cargo:rerun-if-changed=../assets/tags/1_21_9_tags.json");
|
||||
|
||||
// --- Load Global Assets ---
|
||||
let blocks_assets: BlockAssets =
|
||||
serde_json::from_str(&fs::read_to_string("../assets/blocks.json").unwrap())
|
||||
.expect("Failed to parse blocks.json");
|
||||
|
||||
let items: BTreeMap<String, Item> =
|
||||
serde_json::from_str(&fs::read_to_string("../assets/items.json").unwrap())
|
||||
.expect("Failed to parse items.json");
|
||||
|
||||
let biomes: BTreeMap<String, Biome> =
|
||||
serde_json::from_str(&fs::read_to_string("../assets/biome.json").unwrap())
|
||||
.expect("Failed to parse biome.json");
|
||||
|
||||
let fluids: Vec<Fluid> =
|
||||
match serde_json::from_str(&fs::read_to_string("../assets/fluids.json").unwrap()) {
|
||||
Ok(fluids) => fluids,
|
||||
Err(e) => panic!("Failed to parse fluids.json: {e}"),
|
||||
};
|
||||
|
||||
serde_json::from_str(&fs::read_to_string("../assets/fluids.json").unwrap())
|
||||
.expect("Failed to parse fluids.json");
|
||||
let enchantments: BTreeMap<String, Enchantment> =
|
||||
serde_json::from_str(&fs::read_to_string("../assets/enchantments.json").unwrap())
|
||||
.expect("Failed to parse enchantments.json");
|
||||
|
||||
let entities: BTreeMap<String, EntityType> =
|
||||
serde_json::from_str(&fs::read_to_string("../assets/entities.json").unwrap())
|
||||
.expect("Failed to parse entities.json");
|
||||
|
||||
let registry_key_enum = EnumCreator {
|
||||
name: "RegistryKey".to_string(),
|
||||
value: tags.keys().map(|key| key.to_string()).collect(),
|
||||
}
|
||||
.to_token_stream();
|
||||
|
||||
let block_id_map: BTreeMap<String, u16> = blocks_assets
|
||||
.blocks
|
||||
.iter()
|
||||
@ -85,115 +103,143 @@ pub(crate) fn build() -> TokenStream {
|
||||
let fluid_id_map: BTreeMap<String, u16> =
|
||||
fluids.iter().map(|f| (f.name.clone(), f.id)).collect();
|
||||
|
||||
// Generate tag arrays for each registry key
|
||||
let mut tag_dicts = Vec::new();
|
||||
let mut match_arms_value = Vec::new();
|
||||
let mut match_arms_id = Vec::new();
|
||||
let mut match_arms_tags_all = Vec::new();
|
||||
let mut tag_identifiers = Vec::new();
|
||||
let latest_version_key = "1_21_11";
|
||||
let legacy_version_key = "1_21_9";
|
||||
|
||||
for (key, tag_map) in tags {
|
||||
let key_pascal = format_ident!("{}", key.to_pascal_case());
|
||||
let dict_name = format_ident!("{}_TAGS", key.to_pascal_case().to_uppercase());
|
||||
let mut all_registry_keys = HashSet::new();
|
||||
let mut latest_modules = Vec::new();
|
||||
let mut legacy_modules = Vec::new();
|
||||
|
||||
let mut tag_entries = Vec::new();
|
||||
let mut tag_map_entries = Vec::new();
|
||||
let mut match_get_map = Vec::new();
|
||||
|
||||
for (tag_name, values) in tag_map {
|
||||
let ids: Vec<u16> = values
|
||||
.iter()
|
||||
.filter_map(|v| match key.as_str() {
|
||||
"worldgen/biome" => biomes.get(v).map(|b| b.id as u16),
|
||||
"fluid" => fluid_id_map.get(v).copied(),
|
||||
"item" => items.get(v).map(|i| i.id),
|
||||
"block" => block_id_map.get(v).copied(),
|
||||
"enchantment" => enchantments
|
||||
.get(&format!("minecraft:{}", v))
|
||||
.map(|e| e.id as u16),
|
||||
"entity_type" => entities.get(v).map(|e| e.id),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let tag_const_name =
|
||||
format_ident!("{}", tag_name.replace([':', '/'], "_").to_uppercase());
|
||||
let versions = vec![latest_version_key, legacy_version_key];
|
||||
|
||||
tag_entries.push(quote! {
|
||||
pub const #tag_const_name: Tag = (&[#(#values),*], &[#(#ids),*]);
|
||||
});
|
||||
|
||||
tag_map_entries.push(quote! {
|
||||
#tag_name => &#key_pascal::#tag_const_name
|
||||
});
|
||||
for version in versions {
|
||||
let file_path = format!("../assets/tags/{}_tags.json", version);
|
||||
if !Path::new(&file_path).exists() {
|
||||
continue;
|
||||
}
|
||||
|
||||
tag_dicts.push(quote! {
|
||||
#[allow(non_snake_case)]
|
||||
pub mod #key_pascal {
|
||||
use super::Tag;
|
||||
#(#tag_entries)*
|
||||
}
|
||||
static #dict_name: phf::Map<&'static str, &'static Tag> = phf::phf_map! {
|
||||
#(#tag_map_entries),*
|
||||
let tags: BTreeMap<String, BTreeMap<String, Vec<String>>> =
|
||||
serde_json::from_str(&fs::read_to_string(&file_path).unwrap()).unwrap();
|
||||
|
||||
let is_latest = version == latest_version_key;
|
||||
let mut tag_dicts = Vec::new();
|
||||
let mut match_local_map = Vec::new();
|
||||
|
||||
for (key, tag_map) in tags {
|
||||
all_registry_keys.insert(key.clone());
|
||||
let key_pascal = format_ident!("{}", key.to_pascal_case());
|
||||
let dict_name = format_ident!("{}_TAGS", key.to_pascal_case().to_uppercase());
|
||||
|
||||
let mut tag_entries = Vec::new();
|
||||
let mut tag_map_entries = Vec::new();
|
||||
let tag_type_path = if is_latest {
|
||||
quote!(super::Tag)
|
||||
} else {
|
||||
quote!(super::super::Tag)
|
||||
};
|
||||
});
|
||||
|
||||
// Add match arm for this registry key
|
||||
match_arms_value.push(quote! {
|
||||
RegistryKey::#key_pascal => {
|
||||
#dict_name.get(tag).map(|i| i.0)
|
||||
for (tag_name, values) in tag_map {
|
||||
let ids: Vec<u16> = values
|
||||
.iter()
|
||||
.filter_map(|v| match key.as_str() {
|
||||
"worldgen/biome" => biomes.get(v).map(|b| b.id as u16),
|
||||
"fluid" => fluid_id_map.get(v).copied(),
|
||||
"item" => items.get(v).map(|i| i.id),
|
||||
"block" => block_id_map.get(v).copied(),
|
||||
"enchantment" => enchantments
|
||||
.get(&format!("minecraft:{}", v))
|
||||
.map(|e| e.id as u16),
|
||||
"entity_type" => entities.get(v).map(|e| e.id),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let tag_const_name =
|
||||
format_ident!("{}", tag_name.replace([':', '/'], "_").to_uppercase());
|
||||
|
||||
tag_entries.push(quote! {
|
||||
pub const #tag_const_name: #tag_type_path = (&[#(#values),*], &[#(#ids),*]);
|
||||
});
|
||||
tag_map_entries.push(quote! { #tag_name => &#key_pascal::#tag_const_name });
|
||||
}
|
||||
});
|
||||
|
||||
match_arms_id.push(quote! {
|
||||
RegistryKey::#key_pascal => {
|
||||
#dict_name.get(tag).map(|i| i.1 )
|
||||
}
|
||||
});
|
||||
let tag_type_path = if is_latest {
|
||||
quote!(Tag)
|
||||
} else {
|
||||
quote!(super::Tag)
|
||||
};
|
||||
|
||||
match_arms_tags_all.push(quote! {
|
||||
RegistryKey::#key_pascal => {
|
||||
&#dict_name
|
||||
}
|
||||
});
|
||||
tag_dicts.push(quote! {
|
||||
#[allow(non_snake_case)]
|
||||
pub mod #key_pascal {
|
||||
#(#tag_entries)* }
|
||||
pub(crate) static #dict_name: phf::Map<&'static str, &'static #tag_type_path> = phf::phf_map! {
|
||||
#(#tag_map_entries),* };
|
||||
});
|
||||
|
||||
tag_identifiers.push(quote! {
|
||||
Self::#key_pascal => #key
|
||||
});
|
||||
match_local_map.push(quote! { RegistryKey::#key_pascal => Some(&#dict_name) });
|
||||
}
|
||||
|
||||
if is_latest {
|
||||
latest_modules.push(quote! {
|
||||
#(#tag_dicts)*
|
||||
#[allow(unreachable_patterns)]
|
||||
pub fn get_latest_map(key: RegistryKey) -> Option<&'static phf::Map<&'static str, &'static Tag>> {
|
||||
match key { #(#match_local_map,)* _ => None }
|
||||
}
|
||||
});
|
||||
match_get_map
|
||||
.push(quote! { MinecraftVersion::V_1_21_11 => get_latest_map(tag_category) });
|
||||
} else {
|
||||
let mod_name = format_ident!("tags_{}", version);
|
||||
legacy_modules.push(quote! {
|
||||
mod #mod_name {
|
||||
use super::RegistryKey;
|
||||
#(#tag_dicts)*
|
||||
pub fn get_map(key: RegistryKey) -> Option<&'static phf::Map<&'static str, &'static super::Tag>> {
|
||||
match key { #(#match_local_map,)* _ => None }
|
||||
}
|
||||
}
|
||||
});
|
||||
match_get_map
|
||||
.push(quote! { MinecraftVersion::V_1_21_9 => tags_1_21_9::get_map(tag_category) });
|
||||
}
|
||||
}
|
||||
|
||||
quote! {
|
||||
#[derive(Eq, PartialEq, Hash, Debug)]
|
||||
#registry_key_enum
|
||||
// --- Generate RegistryKey Enum ---
|
||||
let registry_key_enum = EnumCreator {
|
||||
name: "RegistryKey".to_string(),
|
||||
values: all_registry_keys.into_iter().collect(),
|
||||
}
|
||||
.to_token_stream();
|
||||
|
||||
impl RegistryKey {
|
||||
// IDK why the linter is saying this isn't used
|
||||
#[allow(dead_code)]
|
||||
pub fn identifier_string(&self) -> &str {
|
||||
match self {
|
||||
#(#tag_identifiers),*
|
||||
}
|
||||
}
|
||||
}
|
||||
quote! {
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
|
||||
pub type Tag = (&'static [&'static str], &'static [u16]);
|
||||
|
||||
#(#tag_dicts)*
|
||||
#registry_key_enum
|
||||
|
||||
// Latest tags are exported directly here
|
||||
#(#latest_modules)*
|
||||
|
||||
// Legacy tags are hidden in their own module
|
||||
#(#legacy_modules)*
|
||||
|
||||
pub fn get_tag_values(tag_category: RegistryKey, tag: &str) -> Option<&'static [&'static str]> {
|
||||
match tag_category {
|
||||
#(#match_arms_value),*
|
||||
}
|
||||
get_latest_map(tag_category).and_then(|m| m.get(tag)).map(|t| t.0)
|
||||
}
|
||||
|
||||
pub fn get_tag_ids(tag_category: RegistryKey, tag: &str) -> Option<&'static [u16]> {
|
||||
match tag_category {
|
||||
#(#match_arms_id),*
|
||||
}
|
||||
get_latest_map(tag_category).and_then(|m| m.get(tag)).map(|t| t.1)
|
||||
}
|
||||
|
||||
pub fn get_registry_key_tags(tag_category: &RegistryKey) -> &phf::Map<&'static str, &'static Tag> {
|
||||
match tag_category {
|
||||
#(#match_arms_tags_all),*
|
||||
pub fn get_registry_key_tags(version: MinecraftVersion, tag_category: RegistryKey) -> Option<&'static phf::Map<&'static str, &'static Tag>> {
|
||||
match version {
|
||||
#(#match_get_map),*,
|
||||
_ => get_latest_map(tag_category)
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,8 +248,7 @@ pub(crate) fn build() -> TokenStream {
|
||||
fn registry_key(&self) -> &str;
|
||||
fn registry_id(&self) -> u16;
|
||||
|
||||
/// Returns `None` if the tag does not exist.
|
||||
fn is_tagged_with(&self, tag: &str) -> Option<bool> {
|
||||
fn is_tagged_with(&self, tag: &str) -> Option<bool> {
|
||||
let tag = tag.strip_prefix("#").unwrap_or(tag);
|
||||
let items = get_tag_ids(Self::tag_key(), tag)?;
|
||||
Some(items.contains(&self.registry_id()))
|
||||
|
||||
@ -8,6 +8,10 @@ pub mod item;
|
||||
#[path = "generated/packet.rs"]
|
||||
pub mod packet;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[path = "generated/jukebox_song.rs"]
|
||||
pub mod jukebox_song;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[path = "generated/registry.rs"]
|
||||
pub mod registry;
|
||||
|
||||
@ -9,6 +9,7 @@ use pumpkin_data::{
|
||||
};
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::resource_location::ResourceLocation;
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
|
||||
#[packet(CONFIG_UPDATE_TAGS)]
|
||||
pub struct CUpdateTags<'a> {
|
||||
@ -22,14 +23,18 @@ impl<'a> CUpdateTags<'a> {
|
||||
}
|
||||
|
||||
impl ClientPacket for CUpdateTags<'_> {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
write.write_list(self.tags, |p, registry_key| {
|
||||
p.write_resource_location(&ResourceLocation::vanilla(
|
||||
registry_key.identifier_string(),
|
||||
))?;
|
||||
|
||||
let values = get_registry_key_tags(registry_key);
|
||||
let values = get_registry_key_tags(*version, *registry_key).unwrap();
|
||||
p.write_var_int(&values.len().try_into().map_err(|_| {
|
||||
WritingError::Message(format!("{} isn't representable as a VarInt", values.len()))
|
||||
})?)?;
|
||||
|
||||
@ -5,6 +5,7 @@ use crate::ser::NetworkWriteExt;
|
||||
use crate::{ClientPacket, WritingError};
|
||||
use pumpkin_data::packet::clientbound::PLAY_BOSS_EVENT;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
|
||||
#[packet(PLAY_BOSS_EVENT)]
|
||||
pub struct CBossEvent<'a> {
|
||||
@ -19,7 +20,11 @@ impl<'a> CBossEvent<'a> {
|
||||
}
|
||||
|
||||
impl ClientPacket for CBossEvent<'_> {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
write.write_uuid(self.uuid)?;
|
||||
|
||||
@ -5,6 +5,7 @@ use pumpkin_data::packet::clientbound::PLAY_LEVEL_CHUNK_WITH_LIGHT;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_nbt::END_ID;
|
||||
use pumpkin_util::math::position::get_local_cord;
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
use pumpkin_world::chunk::format::LightContainer;
|
||||
use pumpkin_world::chunk::{ChunkData, palette::NetworkPalette};
|
||||
use std::io::Write;
|
||||
@ -13,7 +14,11 @@ use std::io::Write;
|
||||
pub struct CChunkData<'a>(pub &'a ChunkData);
|
||||
|
||||
impl ClientPacket for CChunkData<'_> {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
// Chunk X
|
||||
|
||||
@ -2,6 +2,7 @@ use std::io::Write;
|
||||
|
||||
use pumpkin_data::packet::clientbound::PLAY_COMMANDS;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
|
||||
use crate::{ClientPacket, VarInt, WritingError, ser::NetworkWriteExt};
|
||||
|
||||
@ -21,7 +22,11 @@ impl<'a> CCommands<'a> {
|
||||
}
|
||||
|
||||
impl ClientPacket for CCommands<'_> {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
write.write_list(&self.nodes, |bytebuf, node: &ProtoNode| {
|
||||
node.write_to(bytebuf)
|
||||
|
||||
@ -2,7 +2,7 @@ use std::io::Write;
|
||||
|
||||
use pumpkin_data::packet::clientbound::PLAY_PLAYER_CHAT;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::text::TextComponent;
|
||||
use pumpkin_util::{text::TextComponent, version::MinecraftVersion};
|
||||
|
||||
use crate::{
|
||||
ClientPacket, WritingError,
|
||||
@ -67,7 +67,11 @@ impl CPlayerChatMessage {
|
||||
|
||||
//TODO: Check if we need this custom impl
|
||||
impl ClientPacket for CPlayerChatMessage {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
write.write_var_int(&self.global_index)?;
|
||||
|
||||
@ -3,6 +3,7 @@ use std::io::Write;
|
||||
use bitflags::bitflags;
|
||||
use pumpkin_data::packet::clientbound::PLAY_PLAYER_INFO_UPDATE;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
|
||||
use crate::{ClientPacket, Property, WritingError, ser::NetworkWriteExt};
|
||||
|
||||
@ -41,7 +42,11 @@ impl<'a> CPlayerInfoUpdate<'a> {
|
||||
|
||||
// TODO: Check if we need this custom impl
|
||||
impl ClientPacket for CPlayerInfoUpdate<'_> {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
write.write_u8(self.actions)?;
|
||||
|
||||
@ -2,7 +2,7 @@ use std::io::Write;
|
||||
|
||||
use pumpkin_data::packet::clientbound::PLAY_PLAYER_POSITION;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
use pumpkin_util::{math::vector3::Vector3, version::MinecraftVersion};
|
||||
|
||||
use crate::{
|
||||
ClientPacket, PositionFlag, ServerPacket, VarInt, WritingError, ser::NetworkReadExt,
|
||||
@ -41,7 +41,11 @@ impl CPlayerPosition {
|
||||
|
||||
// TODO: Do we need a custom impl?
|
||||
impl ClientPacket for CPlayerPosition {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
write.write_var_int(&self.teleport_id)?;
|
||||
|
||||
@ -6,6 +6,7 @@ use crate::{
|
||||
};
|
||||
use pumpkin_data::packet::clientbound::PLAY_SET_EQUIPMENT;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
@ -29,7 +30,11 @@ impl CSetEquipment {
|
||||
}
|
||||
|
||||
impl ClientPacket for CSetEquipment {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
write.write_var_int(&self.entity_id)?;
|
||||
|
||||
@ -6,6 +6,7 @@ use crate::{ClientPacket, WritingError};
|
||||
use pumpkin_data::{packet::clientbound::PLAY_STOP_SOUND, sound::SoundCategory};
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::resource_location::ResourceLocation;
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
|
||||
#[packet(PLAY_STOP_SOUND)]
|
||||
pub struct CStopSound {
|
||||
@ -20,7 +21,11 @@ impl CStopSound {
|
||||
}
|
||||
|
||||
impl ClientPacket for CStopSound {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
const NO_CATEGORY_NO_SOUND: u8 = 0;
|
||||
|
||||
@ -2,7 +2,7 @@ use std::io::Write;
|
||||
|
||||
use pumpkin_data::packet::clientbound::PLAY_TELEPORT_ENTITY;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
use pumpkin_util::{math::vector3::Vector3, version::MinecraftVersion};
|
||||
|
||||
use crate::{ClientPacket, PositionFlag, VarInt, WritingError, ser::NetworkWriteExt};
|
||||
|
||||
@ -42,7 +42,11 @@ impl<'a> CTeleportEntity<'a> {
|
||||
|
||||
// TODO: Do we need a custom impl?
|
||||
impl ClientPacket for CTeleportEntity<'_> {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
write.write_var_int(&self.entity_id)?;
|
||||
|
||||
@ -2,7 +2,7 @@ use std::io::Write;
|
||||
|
||||
use pumpkin_data::packet::clientbound::PLAY_SET_OBJECTIVE;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::text::TextComponent;
|
||||
use pumpkin_util::{text::TextComponent, version::MinecraftVersion};
|
||||
|
||||
use crate::{ClientPacket, NumberFormat, VarInt, WritingError, ser::NetworkWriteExt};
|
||||
|
||||
@ -34,7 +34,11 @@ impl CUpdateObjectives {
|
||||
}
|
||||
|
||||
impl ClientPacket for CUpdateObjectives {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
write.write_string(&self.objective_name)?;
|
||||
|
||||
@ -284,6 +284,7 @@ mod tests {
|
||||
use flate2::read::ZlibDecoder;
|
||||
use pumpkin_data::packet::clientbound::STATUS_STATUS_RESPONSE;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
use serde::Serialize;
|
||||
|
||||
/// Define a custom packet for testing maximum packet size
|
||||
@ -339,7 +340,9 @@ mod tests {
|
||||
let mut packet_buf = Vec::new();
|
||||
let writer = &mut packet_buf;
|
||||
writer.write_var_int(&VarInt(T::PACKET_ID)).unwrap();
|
||||
packet.write_packet_data(writer).unwrap();
|
||||
packet
|
||||
.write_packet_data(writer, &MinecraftVersion::V_1_21_11)
|
||||
.unwrap();
|
||||
|
||||
encoder.write_packet(packet_buf.into()).await.unwrap();
|
||||
|
||||
@ -374,7 +377,9 @@ mod tests {
|
||||
// Remaining buffer is the payload
|
||||
// We need to obtain the expected payload
|
||||
let mut expected_payload = Vec::new();
|
||||
packet.write_packet_data(&mut expected_payload).unwrap();
|
||||
packet
|
||||
.write_packet_data(&mut expected_payload, &MinecraftVersion::V_1_21_11)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(buffer, expected_payload);
|
||||
}
|
||||
@ -402,7 +407,9 @@ mod tests {
|
||||
// Read data length VarInt (uncompressed data length)
|
||||
let data_length = decode_varint(&mut buffer).expect("Failed to decode data length");
|
||||
let mut expected_payload = Vec::new();
|
||||
packet.write_packet_data(&mut expected_payload).unwrap();
|
||||
packet
|
||||
.write_packet_data(&mut expected_payload, &MinecraftVersion::V_1_21_11)
|
||||
.unwrap();
|
||||
let uncompressed_data_length =
|
||||
VarInt(CStatusResponse::PACKET_ID).written_size() + expected_payload.len();
|
||||
assert_eq!(data_length as usize, uncompressed_data_length);
|
||||
@ -458,7 +465,9 @@ mod tests {
|
||||
|
||||
// Remaining buffer is the payload
|
||||
let mut expected_payload = Vec::new();
|
||||
packet.write_packet_data(&mut expected_payload).unwrap();
|
||||
packet
|
||||
.write_packet_data(&mut expected_payload, &MinecraftVersion::V_1_21_11)
|
||||
.unwrap();
|
||||
assert_eq!(buffer, expected_payload);
|
||||
}
|
||||
|
||||
@ -492,7 +501,9 @@ mod tests {
|
||||
// Read data length VarInt (uncompressed data length)
|
||||
let data_length = decode_varint(&mut buffer).expect("Failed to decode data length");
|
||||
let mut expected_payload = Vec::new();
|
||||
packet.write_packet_data(&mut expected_payload).unwrap();
|
||||
packet
|
||||
.write_packet_data(&mut expected_payload, &MinecraftVersion::V_1_21_11)
|
||||
.unwrap();
|
||||
let uncompressed_data_length =
|
||||
VarInt(CStatusResponse::PACKET_ID).written_size() + expected_payload.len();
|
||||
assert_eq!(data_length as usize, uncompressed_data_length);
|
||||
@ -542,7 +553,9 @@ mod tests {
|
||||
|
||||
// Remaining buffer is the payload (empty)
|
||||
let mut expected_payload = Vec::new();
|
||||
packet.write_packet_data(&mut expected_payload).unwrap();
|
||||
packet
|
||||
.write_packet_data(&mut expected_payload, &MinecraftVersion::V_1_21_11)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
buffer.len(),
|
||||
@ -587,7 +600,9 @@ mod tests {
|
||||
|
||||
// Remaining buffer is the payload
|
||||
let mut expected_payload = Vec::new();
|
||||
packet.write_packet_data(&mut expected_payload).unwrap();
|
||||
packet
|
||||
.write_packet_data(&mut expected_payload, &MinecraftVersion::V_1_21_11)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(buffer, expected_payload);
|
||||
}
|
||||
@ -639,7 +654,9 @@ mod tests {
|
||||
|
||||
// Remaining buffer is the payload
|
||||
let mut expected_payload = Vec::new();
|
||||
packet.write_packet_data(&mut expected_payload).unwrap();
|
||||
packet
|
||||
.write_packet_data(&mut expected_payload, &MinecraftVersion::V_1_21_11)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(buffer, expected_payload);
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ use crate::{
|
||||
};
|
||||
use pumpkin_data::packet::serverbound::HANDSHAKE_INTENTION;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
|
||||
#[packet(HANDSHAKE_INTENTION)]
|
||||
pub struct SHandShake {
|
||||
@ -34,6 +35,7 @@ impl ClientPacket for SHandShake {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
write.write_var_int(&self.protocol_version)?;
|
||||
write.write_string(&self.server_address)?;
|
||||
|
||||
@ -2,6 +2,7 @@ use std::io::Read;
|
||||
|
||||
use pumpkin_data::packet::serverbound::PLAY_CHAT;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
|
||||
use crate::{
|
||||
ClientPacket, ServerPacket,
|
||||
@ -40,6 +41,7 @@ impl ClientPacket for SChatMessage {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
write.write_string(&self.message)?;
|
||||
write.write_i64_be(self.timestamp)?;
|
||||
|
||||
@ -11,6 +11,7 @@ use codec::var_int::VarInt;
|
||||
use pumpkin_util::{
|
||||
resource_location::ResourceLocation,
|
||||
text::{TextComponent, style::Style},
|
||||
version::MinecraftVersion,
|
||||
};
|
||||
use ser::{ReadingError, WritingError};
|
||||
use serde::{
|
||||
@ -311,7 +312,11 @@ pub struct RawPacket {
|
||||
}
|
||||
|
||||
pub trait ClientPacket: Packet {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError>;
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError>;
|
||||
}
|
||||
|
||||
pub trait ServerPacket: Packet + Sized {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use std::io::{Error, Read, Write};
|
||||
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
|
||||
use crate::{
|
||||
@ -14,7 +15,11 @@ pub trait Packet {
|
||||
}
|
||||
|
||||
impl<P: Packet + Serialize> ClientPacket for P {
|
||||
fn write_packet_data(&self, write: impl Write) -> Result<(), WritingError> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
_version: &MinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut serializer = serializer::Serializer::new(write);
|
||||
self.serialize(&mut serializer)
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ pub mod resource_location;
|
||||
pub mod serde_enum_as_integer;
|
||||
pub mod text;
|
||||
pub mod translation;
|
||||
pub mod version;
|
||||
pub mod world_seed;
|
||||
|
||||
pub mod jwt;
|
||||
|
||||
166
pumpkin-util/src/version.rs
Normal file
166
pumpkin-util/src/version.rs
Normal file
@ -0,0 +1,166 @@
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum MinecraftVersion {
|
||||
V_1_7_2,
|
||||
V_1_7_6,
|
||||
V_1_8,
|
||||
V_1_9,
|
||||
V_1_9_1,
|
||||
V_1_9_2,
|
||||
V_1_9_3,
|
||||
V_1_10,
|
||||
V_1_11,
|
||||
V_1_11_1,
|
||||
V_1_12,
|
||||
V_1_12_1,
|
||||
V_1_12_2,
|
||||
V_1_13,
|
||||
V_1_13_1,
|
||||
V_1_13_2,
|
||||
V_1_14,
|
||||
V_1_14_1,
|
||||
V_1_14_2,
|
||||
V_1_14_3,
|
||||
V_1_14_4,
|
||||
V_1_15,
|
||||
V_1_15_1,
|
||||
V_1_15_2,
|
||||
V_1_16,
|
||||
V_1_16_1,
|
||||
V_1_16_2,
|
||||
V_1_16_3,
|
||||
V_1_16_4,
|
||||
V_1_17,
|
||||
V_1_17_1,
|
||||
V_1_18,
|
||||
V_1_18_2,
|
||||
V_1_19,
|
||||
V_1_19_1,
|
||||
V_1_19_3,
|
||||
V_1_19_4,
|
||||
V_1_20,
|
||||
V_1_20_2,
|
||||
V_1_20_3,
|
||||
V_1_20_5,
|
||||
V_1_21,
|
||||
V_1_21_2,
|
||||
V_1_21_4,
|
||||
V_1_21_5,
|
||||
V_1_21_6,
|
||||
V_1_21_7,
|
||||
V_1_21_9,
|
||||
V_1_21_11,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl MinecraftVersion {
|
||||
pub fn protocol_version(&self) -> i32 {
|
||||
match self {
|
||||
Self::V_1_7_2 => 4,
|
||||
Self::V_1_7_6 => 5,
|
||||
Self::V_1_8 => 47,
|
||||
Self::V_1_9 => 107,
|
||||
Self::V_1_9_1 => 108,
|
||||
Self::V_1_9_2 => 109,
|
||||
Self::V_1_9_3 => 110,
|
||||
Self::V_1_10 => 210,
|
||||
Self::V_1_11 => 315,
|
||||
Self::V_1_11_1 => 316,
|
||||
Self::V_1_12 => 335,
|
||||
Self::V_1_12_1 => 338,
|
||||
Self::V_1_12_2 => 340,
|
||||
Self::V_1_13 => 393,
|
||||
Self::V_1_13_1 => 401,
|
||||
Self::V_1_13_2 => 404,
|
||||
Self::V_1_14 => 477,
|
||||
Self::V_1_14_1 => 480,
|
||||
Self::V_1_14_2 => 485,
|
||||
Self::V_1_14_3 => 490,
|
||||
Self::V_1_14_4 => 498,
|
||||
Self::V_1_15 => 573,
|
||||
Self::V_1_15_1 => 575,
|
||||
Self::V_1_15_2 => 578,
|
||||
Self::V_1_16 => 735,
|
||||
Self::V_1_16_1 => 736,
|
||||
Self::V_1_16_2 => 751,
|
||||
Self::V_1_16_3 => 753,
|
||||
Self::V_1_16_4 => 754,
|
||||
Self::V_1_17 => 755,
|
||||
Self::V_1_17_1 => 756,
|
||||
Self::V_1_18 => 757,
|
||||
Self::V_1_18_2 => 758,
|
||||
Self::V_1_19 => 759,
|
||||
Self::V_1_19_1 => 760,
|
||||
Self::V_1_19_3 => 761,
|
||||
Self::V_1_19_4 => 762,
|
||||
Self::V_1_20 => 763,
|
||||
Self::V_1_20_2 => 764,
|
||||
Self::V_1_20_3 => 765,
|
||||
Self::V_1_20_5 => 766,
|
||||
Self::V_1_21 => 767,
|
||||
Self::V_1_21_2 => 768,
|
||||
Self::V_1_21_4 => 769,
|
||||
Self::V_1_21_5 => 770,
|
||||
Self::V_1_21_6 => 771,
|
||||
Self::V_1_21_7 => 772,
|
||||
Self::V_1_21_9 => 773,
|
||||
Self::V_1_21_11 => 774,
|
||||
Self::Unknown => -1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_protocol(protocol: u32) -> Self {
|
||||
match protocol {
|
||||
4 => Self::V_1_7_2,
|
||||
5 => Self::V_1_7_6,
|
||||
47 => Self::V_1_8,
|
||||
107 => Self::V_1_9,
|
||||
108 => Self::V_1_9_1,
|
||||
109 => Self::V_1_9_2,
|
||||
110 => Self::V_1_9_3,
|
||||
210 => Self::V_1_10,
|
||||
315 => Self::V_1_11,
|
||||
316 => Self::V_1_11_1,
|
||||
335 => Self::V_1_12,
|
||||
338 => Self::V_1_12_1,
|
||||
340 => Self::V_1_12_2,
|
||||
393 => Self::V_1_13,
|
||||
401 => Self::V_1_13_1,
|
||||
404 => Self::V_1_13_2,
|
||||
477 => Self::V_1_14,
|
||||
480 => Self::V_1_14_1,
|
||||
485 => Self::V_1_14_2,
|
||||
490 => Self::V_1_14_3,
|
||||
498 => Self::V_1_14_4,
|
||||
573 => Self::V_1_15,
|
||||
575 => Self::V_1_15_1,
|
||||
578 => Self::V_1_15_2,
|
||||
735 => Self::V_1_16,
|
||||
736 => Self::V_1_16_1,
|
||||
751 => Self::V_1_16_2,
|
||||
753 => Self::V_1_16_3,
|
||||
754 => Self::V_1_16_4,
|
||||
755 => Self::V_1_17,
|
||||
756 => Self::V_1_17_1,
|
||||
757 => Self::V_1_18,
|
||||
758 => Self::V_1_18_2,
|
||||
759 => Self::V_1_19,
|
||||
760 => Self::V_1_19_1,
|
||||
761 => Self::V_1_19_3,
|
||||
762 => Self::V_1_19_4,
|
||||
763 => Self::V_1_20,
|
||||
764 => Self::V_1_20_2,
|
||||
765 => Self::V_1_20_3,
|
||||
766 => Self::V_1_20_5,
|
||||
767 => Self::V_1_21,
|
||||
768 => Self::V_1_21_2,
|
||||
769 => Self::V_1_21_4,
|
||||
770 => Self::V_1_21_5,
|
||||
771 => Self::V_1_21_6,
|
||||
772 => Self::V_1_21_7,
|
||||
773 => Self::V_1_21_9,
|
||||
774 => Self::V_1_21_11,
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,6 +22,8 @@ pub type BlockId = u16;
|
||||
pub type BlockStateId = u16;
|
||||
|
||||
pub const CURRENT_MC_VERSION: &str = "1.21.11";
|
||||
pub const LOWEST_SUPPRORTED_PROTOCOL_VERSION: u32 = 773;
|
||||
|
||||
pub const CURRENT_BEDROCK_MC_VERSION: &str = "1.21.32";
|
||||
pub const CURRENT_BEDROCK_MC_PROTOCOL: u32 = 898;
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ use crate::block::registry::BlockActionResult;
|
||||
use crate::block::{BlockBehaviour, BlockFuture, BrokenArgs, UseWithItemArgs};
|
||||
use crate::world::World;
|
||||
use pumpkin_data::data_component_impl::JukeboxPlayableImpl;
|
||||
use pumpkin_data::registry::SyncedRegistry;
|
||||
use pumpkin_data::jukebox_song::JukeboxSong;
|
||||
use pumpkin_data::world::WorldEvent;
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
@ -73,7 +73,7 @@ impl BlockBehaviour for JukeboxBlock {
|
||||
return BlockActionResult::Pass;
|
||||
};
|
||||
|
||||
let Some(jukebox_song) = SyncedRegistry::get_jukebox_song_index(song) else {
|
||||
let Some(jukebox_song) = JukeboxSong::from_name(song) else {
|
||||
log::error!("Jukebox playable song not registered!");
|
||||
return BlockActionResult::Pass;
|
||||
};
|
||||
@ -86,7 +86,7 @@ impl BlockBehaviour for JukeboxBlock {
|
||||
.sync_world_event(
|
||||
WorldEvent::JukeboxStartsPlaying,
|
||||
*args.position,
|
||||
jukebox_song as i32,
|
||||
jukebox_song.get_id() as i32,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ use crate::{
|
||||
server::Server,
|
||||
};
|
||||
use core::str;
|
||||
use pumpkin_data::{registry::Registry, tag::RegistryKey};
|
||||
use pumpkin_protocol::{
|
||||
ConnectionState,
|
||||
java::{
|
||||
@ -149,9 +150,11 @@ impl JavaClient {
|
||||
);
|
||||
}
|
||||
|
||||
pub async fn handle_known_packs(&self, server: &Server, _config_acknowledged: SKnownPacks) {
|
||||
pub async fn handle_known_packs(&self, _config_acknowledged: SKnownPacks) {
|
||||
log::debug!("Handling known packs");
|
||||
for registry in &server.cached_registry {
|
||||
let mut tags_to_send = Vec::new();
|
||||
let registry = Registry::get_synced(self.version.load());
|
||||
for registry in registry {
|
||||
let entries: Vec<RegistryEntry> = registry
|
||||
.registry_entries
|
||||
.iter()
|
||||
@ -159,18 +162,13 @@ impl JavaClient {
|
||||
.collect();
|
||||
self.send_packet_now(&CRegistryData::new(®istry.registry_id, &entries))
|
||||
.await;
|
||||
if let Some(tag) = RegistryKey::from_string(®istry.registry_id.path)
|
||||
&& pumpkin_data::tag::get_registry_key_tags(self.version.load(), tag).is_some()
|
||||
{
|
||||
tags_to_send.push(tag);
|
||||
}
|
||||
}
|
||||
self.send_packet_now(&CUpdateTags::new(&[
|
||||
pumpkin_data::tag::RegistryKey::Block,
|
||||
pumpkin_data::tag::RegistryKey::Fluid,
|
||||
pumpkin_data::tag::RegistryKey::Enchantment,
|
||||
pumpkin_data::tag::RegistryKey::WorldgenBiome,
|
||||
pumpkin_data::tag::RegistryKey::Item,
|
||||
pumpkin_data::tag::RegistryKey::EntityType,
|
||||
pumpkin_data::tag::RegistryKey::Dialog,
|
||||
pumpkin_data::tag::RegistryKey::Timeline,
|
||||
]))
|
||||
.await;
|
||||
self.send_packet_now(&CUpdateTags::new(&tags_to_send)).await;
|
||||
|
||||
// We are done with configuring
|
||||
log::debug!("Finished config");
|
||||
|
||||
@ -1,36 +1,33 @@
|
||||
use pumpkin_data::packet::CURRENT_MC_PROTOCOL;
|
||||
use pumpkin_protocol::{ConnectionState, java::server::handshake::SHandShake};
|
||||
use pumpkin_util::text::TextComponent;
|
||||
use pumpkin_util::{text::TextComponent, version::MinecraftVersion};
|
||||
|
||||
use pumpkin_world::CURRENT_MC_VERSION;
|
||||
use pumpkin_world::{CURRENT_MC_VERSION, LOWEST_SUPPRORTED_PROTOCOL_VERSION};
|
||||
|
||||
use crate::net::java::JavaClient;
|
||||
|
||||
impl JavaClient {
|
||||
pub async fn handle_handshake(&self, handshake: SHandShake) {
|
||||
let version = handshake.protocol_version.0;
|
||||
let version = handshake.protocol_version.0 as u32;
|
||||
*self.server_address.lock().await = handshake.server_address;
|
||||
self.version.store(MinecraftVersion::from_protocol(version));
|
||||
|
||||
log::debug!("Handshake: next state is {:?}", &handshake.next_state);
|
||||
self.connection_state.store(handshake.next_state);
|
||||
if self.connection_state.load() != ConnectionState::Status {
|
||||
let protocol = version;
|
||||
match protocol.cmp(&(CURRENT_MC_PROTOCOL as i32)) {
|
||||
std::cmp::Ordering::Less => {
|
||||
self.kick(TextComponent::translate(
|
||||
"multiplayer.disconnect.outdated_client",
|
||||
[TextComponent::text(CURRENT_MC_VERSION.to_string())],
|
||||
))
|
||||
.await;
|
||||
}
|
||||
std::cmp::Ordering::Equal => {}
|
||||
std::cmp::Ordering::Greater => {
|
||||
self.kick(TextComponent::translate(
|
||||
"multiplayer.disconnect.incompatible",
|
||||
[TextComponent::text(CURRENT_MC_VERSION.to_string())],
|
||||
))
|
||||
.await;
|
||||
}
|
||||
if protocol < LOWEST_SUPPRORTED_PROTOCOL_VERSION {
|
||||
self.kick(TextComponent::translate(
|
||||
"multiplayer.disconnect.outdated_client",
|
||||
[TextComponent::text(CURRENT_MC_VERSION.to_string())],
|
||||
))
|
||||
.await;
|
||||
} else if protocol > CURRENT_MC_PROTOCOL {
|
||||
self.kick(TextComponent::translate(
|
||||
"multiplayer.disconnect.incompatible",
|
||||
[TextComponent::text(CURRENT_MC_VERSION.to_string())],
|
||||
))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ use std::{io::Write, sync::Arc};
|
||||
use bytes::Bytes;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use pumpkin_config::networking::compression::CompressionInfo;
|
||||
use pumpkin_data::packet::CURRENT_MC_PROTOCOL;
|
||||
use pumpkin_protocol::java::server::play::{
|
||||
SChangeGameMode, SChatCommand, SChatMessage, SChunkBatch, SClickSlot, SClientCommand,
|
||||
SClientInformationPlay, SClientTickEnd, SCloseContainer, SCommandSuggestion, SConfirmTeleport,
|
||||
@ -36,6 +37,7 @@ use pumpkin_protocol::{
|
||||
ser::{NetworkWriteExt, ReadingError, WritingError},
|
||||
};
|
||||
use pumpkin_util::text::TextComponent;
|
||||
use pumpkin_util::version::MinecraftVersion;
|
||||
use tokio::{
|
||||
io::{BufReader, BufWriter},
|
||||
net::{
|
||||
@ -55,6 +57,7 @@ pub mod config;
|
||||
pub mod handshake;
|
||||
pub mod login;
|
||||
pub mod play;
|
||||
pub mod remapper;
|
||||
pub mod status;
|
||||
|
||||
use crate::entity::player::Player;
|
||||
@ -63,6 +66,7 @@ use crate::{error::PumpkinError, net::EncryptionError, server::Server};
|
||||
|
||||
pub struct JavaClient {
|
||||
pub id: u64,
|
||||
pub version: AtomicCell<MinecraftVersion>,
|
||||
/// The client's game profile information.
|
||||
pub gameprofile: Mutex<Option<GameProfile>>,
|
||||
/// The client's configuration settings, Optional
|
||||
@ -106,7 +110,7 @@ impl JavaClient {
|
||||
tasks: TaskTracker::new(),
|
||||
outgoing_packet_queue_send: send,
|
||||
outgoing_packet_queue_recv: Some(recv),
|
||||
|
||||
version: AtomicCell::new(MinecraftVersion::from_protocol(CURRENT_MC_PROTOCOL)),
|
||||
network_writer: Arc::new(Mutex::new(TCPNetworkEncoder::new(BufWriter::new(write)))),
|
||||
network_reader: Mutex::new(TCPNetworkDecoder::new(BufReader::new(read))),
|
||||
brand: Mutex::new(None),
|
||||
@ -193,7 +197,7 @@ impl JavaClient {
|
||||
pub async fn enqueue_packet<P: ClientPacket>(&self, packet: &P) {
|
||||
let mut buf = Vec::new();
|
||||
let writer = &mut buf;
|
||||
Self::write_packet(packet, writer).unwrap();
|
||||
self.write_packet(packet, writer).unwrap();
|
||||
self.enqueue_packet_data(buf.into()).await;
|
||||
}
|
||||
|
||||
@ -266,7 +270,7 @@ impl JavaClient {
|
||||
pub async fn send_packet_now<P: ClientPacket>(&self, packet: &P) {
|
||||
let mut packet_buf = Vec::new();
|
||||
let writer = &mut packet_buf;
|
||||
Self::write_packet(packet, writer).unwrap();
|
||||
self.write_packet(packet, writer).unwrap();
|
||||
self.send_packet_now_data(packet_buf).await;
|
||||
}
|
||||
|
||||
@ -289,12 +293,13 @@ impl JavaClient {
|
||||
}
|
||||
|
||||
pub fn write_packet<P: ClientPacket>(
|
||||
&self,
|
||||
packet: &P,
|
||||
write: impl Write,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
write.write_var_int(&VarInt(P::PACKET_ID))?;
|
||||
packet.write_packet_data(write)
|
||||
packet.write_packet_data(write, &self.version.load())
|
||||
}
|
||||
|
||||
/// Handles an incoming packet, routing it to the appropriate handler based on the current connection state.
|
||||
@ -503,8 +508,7 @@ impl JavaClient {
|
||||
self.handle_config_acknowledged(server).await;
|
||||
}
|
||||
SKnownPacks::PACKET_ID => {
|
||||
self.handle_known_packs(server, SKnownPacks::read(payload)?)
|
||||
.await;
|
||||
self.handle_known_packs(SKnownPacks::read(payload)?).await;
|
||||
}
|
||||
SConfigCookieResponse::PACKET_ID => {
|
||||
self.handle_config_cookie_response(&SConfigCookieResponse::read(payload)?);
|
||||
|
||||
1
pumpkin/src/net/java/remapper/mod.rs
Normal file
1
pumpkin/src/net/java/remapper/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod registry;
|
||||
1
pumpkin/src/net/java/remapper/registry.rs
Normal file
1
pumpkin/src/net/java/remapper/registry.rs
Normal file
@ -0,0 +1 @@
|
||||
|
||||
@ -14,7 +14,6 @@ use connection_cache::{CachedBranding, CachedStatus};
|
||||
use key_store::KeyStore;
|
||||
use pumpkin_config::{AdvancedConfiguration, BasicConfiguration};
|
||||
use pumpkin_data::dimension::Dimension;
|
||||
use pumpkin_data::registry::Registry;
|
||||
use pumpkin_world::dimension::into_level;
|
||||
|
||||
use crate::command::CommandSender;
|
||||
@ -74,8 +73,6 @@ pub struct Server {
|
||||
pub worlds: RwLock<Vec<Arc<World>>>,
|
||||
/// All the dimensions that exist on the server.
|
||||
pub dimensions: Vec<Dimension>,
|
||||
/// Caches game registries for efficient access.
|
||||
pub cached_registry: Vec<Registry>,
|
||||
/// Assigns unique IDs to containers.
|
||||
container_id: AtomicU32,
|
||||
/// Mojang's public keys, used for chat session signing
|
||||
@ -178,8 +175,6 @@ impl Server {
|
||||
let server = Self {
|
||||
basic_config,
|
||||
advanced_config,
|
||||
|
||||
cached_registry: Registry::get_synced(),
|
||||
container_id: 0.into(),
|
||||
worlds: RwLock::new(vec![]),
|
||||
dimensions: vec![
|
||||
|
||||
Loading…
Reference in New Issue
Block a user