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://discord.gg/wT8XjrjKkf)
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](https://opensource.org/licenses/MIT)
|
||||||

|
|
||||||
|
|
||||||
</div>
|
</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_event;
|
||||||
mod game_rules;
|
mod game_rules;
|
||||||
mod item;
|
mod item;
|
||||||
|
mod jukebox_song;
|
||||||
pub mod loot;
|
pub mod loot;
|
||||||
mod message_type;
|
mod message_type;
|
||||||
mod meta_data_type;
|
mod meta_data_type;
|
||||||
@ -71,6 +72,7 @@ pub fn main() {
|
|||||||
(game_rules::build, "game_rules.rs"),
|
(game_rules::build, "game_rules.rs"),
|
||||||
(registry::build, "registry.rs"),
|
(registry::build, "registry.rs"),
|
||||||
(dimension::build, "dimension.rs"),
|
(dimension::build, "dimension.rs"),
|
||||||
|
(jukebox_song::build, "jukebox_song.rs"),
|
||||||
(sound_category::build, "sound_category.rs"),
|
(sound_category::build, "sound_category.rs"),
|
||||||
(entity_pose::build, "entity_pose.rs"),
|
(entity_pose::build, "entity_pose.rs"),
|
||||||
(scoreboard_slot::build, "scoreboard_slot.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)]
|
#[derive(Deserialize)]
|
||||||
pub struct Packets {
|
pub struct Packets {
|
||||||
version: u32,
|
version: u32,
|
||||||
serverbound: BTreeMap<String, Vec<String>>,
|
serverbound: BTreeMap<String, BTreeMap<String, i32>>,
|
||||||
clientbound: BTreeMap<String, Vec<String>>,
|
clientbound: BTreeMap<String, BTreeMap<String, i32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn build() -> TokenStream {
|
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 =
|
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");
|
.expect("Failed to parse packets.json");
|
||||||
|
|
||||||
let version = packets.version;
|
let version = packets.version;
|
||||||
let serverbound_consts = parse_packets(packets.serverbound);
|
let serverbound_consts = parse_packets(packets.serverbound);
|
||||||
let clientbound_consts = parse_packets(packets.clientbound);
|
let clientbound_consts = parse_packets(packets.clientbound);
|
||||||
|
|
||||||
quote!(
|
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 const CURRENT_MC_PROTOCOL: u32 = #version;
|
||||||
|
|
||||||
pub mod serverbound {
|
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();
|
let mut consts = TokenStream::new();
|
||||||
|
|
||||||
for packet in packets {
|
for (phase_name, packets) in phases {
|
||||||
let phase = packet.0;
|
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 const_name = format_ident!("{}_{}", phase_name.to_uppercase(), sanitized_name);
|
||||||
let packet_id = id as i32;
|
|
||||||
let packet_name = packet_name.replace("/", "_");
|
consts.extend(quote! {
|
||||||
let name = format!("{phase}_{packet_name}").to_uppercase();
|
pub const #const_name: i32 = #packet_id;
|
||||||
let name = format_ident!("{}", name);
|
});
|
||||||
consts.extend([quote! {
|
|
||||||
pub const #name: i32 = #packet_id;
|
|
||||||
}]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
consts
|
consts
|
||||||
|
|||||||
@ -5,83 +5,64 @@ use serde_json::Value;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
pub(crate) fn build() -> TokenStream {
|
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")
|
let process_version = |path: &str| -> TokenStream {
|
||||||
.expect("Failed to read synced_registries.json");
|
let json_str =
|
||||||
let mut data: IndexMap<String, IndexMap<String, Value>> =
|
fs::read_to_string(path).unwrap_or_else(|_| panic!("Failed to read {}", path));
|
||||||
serde_json::from_str(&json_str).expect("Failed to parse synced_registries.json");
|
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") {
|
// Inject "raw" chat type for vanilla parity
|
||||||
data.get_mut("minecraft:chat_type")
|
if let Some(chat) = data.get_mut("minecraft:chat_type") {
|
||||||
} else {
|
chat.insert("raw".to_string(), serde_json::json!({
|
||||||
data.get_mut("chat_type")
|
"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 {
|
let v1_21_9_registries = process_version("../assets/registry/1_21_9_synced_registries.json");
|
||||||
chat_type.insert(
|
let v1_21_11_registries = process_version("../assets/registry/1_21_11_synced_registries.json");
|
||||||
"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();
|
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
use pumpkin_util::resource_location::ResourceLocation;
|
use pumpkin_util::resource_location::ResourceLocation;
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
|
|
||||||
pub struct StaticRegistryEntry {
|
pub struct StaticRegistryEntry {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub nbt_bytes: &'static [u8],
|
pub data: &'static [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StaticRegistry {
|
pub struct StaticRegistry {
|
||||||
@ -89,10 +70,6 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
pub entries: &'static [StaticRegistryEntry],
|
pub entries: &'static [StaticRegistryEntry],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static SYNCED_REGISTRIES: &[StaticRegistry] = &[
|
|
||||||
#(#registries_tokens),*
|
|
||||||
];
|
|
||||||
|
|
||||||
pub struct RegistryEntryData {
|
pub struct RegistryEntryData {
|
||||||
pub entry_id: ResourceLocation,
|
pub entry_id: ResourceLocation,
|
||||||
pub data: Option<Box<[u8]>>,
|
pub data: Option<Box<[u8]>>,
|
||||||
@ -103,20 +80,17 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
pub registry_entries: Vec<RegistryEntryData>,
|
pub registry_entries: Vec<RegistryEntryData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SyncedRegistry;
|
pub static REGISTRIES_1_21_9: &[StaticRegistry] = #v1_21_9_registries;
|
||||||
|
pub static REGISTRIES_1_21_11: &[StaticRegistry] = #v1_21_11_registries;
|
||||||
impl SyncedRegistry {
|
|
||||||
pub fn get_jukebox_song_index(song_key: &str) -> Option<usize> {
|
|
||||||
match song_key {
|
|
||||||
#jukebox_index_arms
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Registry {
|
impl Registry {
|
||||||
pub fn get_synced() -> Vec<Self> {
|
pub fn get_synced(version: MinecraftVersion) -> Vec<Self> {
|
||||||
SYNCED_REGISTRIES.iter().map(|static_reg| {
|
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(':') {
|
let registry_id = if static_reg.registry_id.contains(':') {
|
||||||
ResourceLocation::from(static_reg.registry_id)
|
ResourceLocation::from(static_reg.registry_id)
|
||||||
} else {
|
} else {
|
||||||
@ -124,24 +98,17 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let registry_entries = static_reg.entries.iter().map(|entry| {
|
let registry_entries = static_reg.entries.iter().map(|entry| {
|
||||||
let entry_id = if entry.name.contains(':') {
|
let entry_id =
|
||||||
ResourceLocation::from(entry.name)
|
ResourceLocation::vanilla(entry.name);
|
||||||
} else {
|
|
||||||
ResourceLocation::vanilla(entry.name)
|
|
||||||
};
|
|
||||||
|
|
||||||
let data = Some(entry.nbt_bytes.to_vec().into_boxed_slice());
|
|
||||||
|
|
||||||
RegistryEntryData {
|
RegistryEntryData {
|
||||||
entry_id,
|
entry_id,
|
||||||
data,
|
// Data is now sourced directly from the entry
|
||||||
|
data: Some(entry.data.to_vec().into_boxed_slice()),
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
Self {
|
Self { registry_id, registry_entries }
|
||||||
registry_id,
|
|
||||||
registry_entries,
|
|
||||||
}
|
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
use std::{collections::BTreeMap, fs};
|
use std::{
|
||||||
|
collections::{BTreeMap, HashSet},
|
||||||
|
fs,
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::biome::Biome;
|
use crate::biome::Biome;
|
||||||
use crate::block::BlockAssets;
|
use crate::block::BlockAssets;
|
||||||
@ -10,73 +14,87 @@ use heck::ToPascalCase;
|
|||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{ToTokens, format_ident, quote};
|
use quote::{ToTokens, format_ident, quote};
|
||||||
|
|
||||||
|
// --- EnumCreator with from_string support ---
|
||||||
pub struct EnumCreator {
|
pub struct EnumCreator {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub value: Vec<String>,
|
pub values: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTokens for EnumCreator {
|
impl ToTokens for EnumCreator {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let name = format_ident!("{}", self.name.to_pascal_case());
|
let name = format_ident!("{}", self.name.to_pascal_case());
|
||||||
let values = self
|
|
||||||
.value
|
let variants = self.values.iter().map(|v| {
|
||||||
.iter()
|
let variant_name = format_ident!("{}", v.to_pascal_case());
|
||||||
.map(|value| {
|
quote! { #variant_name }
|
||||||
let name = format_ident!("{}", value.to_pascal_case());
|
});
|
||||||
name
|
|
||||||
})
|
let from_string_arms = self.values.iter().map(|v| {
|
||||||
.collect::<Vec<_>>();
|
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! {
|
tokens.extend(quote! {
|
||||||
|
#[derive(Eq, PartialEq, Hash, Debug, Clone, Copy)]
|
||||||
pub enum #name {
|
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 {
|
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/blocks.json");
|
||||||
println!("cargo:rerun-if-changed=../assets/items.json");
|
println!("cargo:rerun-if-changed=../assets/items.json");
|
||||||
println!("cargo:rerun-if-changed=../assets/biome.json");
|
println!("cargo:rerun-if-changed=../assets/biome.json");
|
||||||
println!("cargo:rerun-if-changed=../assets/fluids.json");
|
println!("cargo:rerun-if-changed=../assets/fluids.json");
|
||||||
println!("cargo:rerun-if-changed=../assets/entities.json");
|
println!("cargo:rerun-if-changed=../assets/entities.json");
|
||||||
|
|
||||||
let tags: BTreeMap<String, BTreeMap<String, Vec<String>>> =
|
// Watch specific tag versions
|
||||||
serde_json::from_str(&fs::read_to_string("../assets/tags.json").unwrap())
|
println!("cargo:rerun-if-changed=../assets/tags/1_21_11_tags.json");
|
||||||
.expect("Failed to parse tags.json");
|
println!("cargo:rerun-if-changed=../assets/tags/1_21_9_tags.json");
|
||||||
|
|
||||||
|
// --- Load Global Assets ---
|
||||||
let blocks_assets: BlockAssets =
|
let blocks_assets: BlockAssets =
|
||||||
serde_json::from_str(&fs::read_to_string("../assets/blocks.json").unwrap())
|
serde_json::from_str(&fs::read_to_string("../assets/blocks.json").unwrap())
|
||||||
.expect("Failed to parse blocks.json");
|
.expect("Failed to parse blocks.json");
|
||||||
|
|
||||||
let items: BTreeMap<String, Item> =
|
let items: BTreeMap<String, Item> =
|
||||||
serde_json::from_str(&fs::read_to_string("../assets/items.json").unwrap())
|
serde_json::from_str(&fs::read_to_string("../assets/items.json").unwrap())
|
||||||
.expect("Failed to parse items.json");
|
.expect("Failed to parse items.json");
|
||||||
|
|
||||||
let biomes: BTreeMap<String, Biome> =
|
let biomes: BTreeMap<String, Biome> =
|
||||||
serde_json::from_str(&fs::read_to_string("../assets/biome.json").unwrap())
|
serde_json::from_str(&fs::read_to_string("../assets/biome.json").unwrap())
|
||||||
.expect("Failed to parse biome.json");
|
.expect("Failed to parse biome.json");
|
||||||
|
|
||||||
let fluids: Vec<Fluid> =
|
let fluids: Vec<Fluid> =
|
||||||
match serde_json::from_str(&fs::read_to_string("../assets/fluids.json").unwrap()) {
|
serde_json::from_str(&fs::read_to_string("../assets/fluids.json").unwrap())
|
||||||
Ok(fluids) => fluids,
|
.expect("Failed to parse fluids.json");
|
||||||
Err(e) => panic!("Failed to parse fluids.json: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let enchantments: BTreeMap<String, Enchantment> =
|
let enchantments: BTreeMap<String, Enchantment> =
|
||||||
serde_json::from_str(&fs::read_to_string("../assets/enchantments.json").unwrap())
|
serde_json::from_str(&fs::read_to_string("../assets/enchantments.json").unwrap())
|
||||||
.expect("Failed to parse enchantments.json");
|
.expect("Failed to parse enchantments.json");
|
||||||
|
|
||||||
let entities: BTreeMap<String, EntityType> =
|
let entities: BTreeMap<String, EntityType> =
|
||||||
serde_json::from_str(&fs::read_to_string("../assets/entities.json").unwrap())
|
serde_json::from_str(&fs::read_to_string("../assets/entities.json").unwrap())
|
||||||
.expect("Failed to parse entities.json");
|
.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
|
let block_id_map: BTreeMap<String, u16> = blocks_assets
|
||||||
.blocks
|
.blocks
|
||||||
.iter()
|
.iter()
|
||||||
@ -85,115 +103,143 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let fluid_id_map: BTreeMap<String, u16> =
|
let fluid_id_map: BTreeMap<String, u16> =
|
||||||
fluids.iter().map(|f| (f.name.clone(), f.id)).collect();
|
fluids.iter().map(|f| (f.name.clone(), f.id)).collect();
|
||||||
|
|
||||||
// Generate tag arrays for each registry key
|
let latest_version_key = "1_21_11";
|
||||||
let mut tag_dicts = Vec::new();
|
let legacy_version_key = "1_21_9";
|
||||||
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();
|
|
||||||
|
|
||||||
for (key, tag_map) in tags {
|
let mut all_registry_keys = HashSet::new();
|
||||||
let key_pascal = format_ident!("{}", key.to_pascal_case());
|
let mut latest_modules = Vec::new();
|
||||||
let dict_name = format_ident!("{}_TAGS", key.to_pascal_case().to_uppercase());
|
let mut legacy_modules = Vec::new();
|
||||||
|
|
||||||
let mut tag_entries = Vec::new();
|
let mut match_get_map = Vec::new();
|
||||||
let mut tag_map_entries = Vec::new();
|
|
||||||
|
|
||||||
for (tag_name, values) in tag_map {
|
let versions = vec![latest_version_key, legacy_version_key];
|
||||||
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! {
|
for version in versions {
|
||||||
pub const #tag_const_name: Tag = (&[#(#values),*], &[#(#ids),*]);
|
let file_path = format!("../assets/tags/{}_tags.json", version);
|
||||||
});
|
if !Path::new(&file_path).exists() {
|
||||||
|
continue;
|
||||||
tag_map_entries.push(quote! {
|
|
||||||
#tag_name => &#key_pascal::#tag_const_name
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tag_dicts.push(quote! {
|
let tags: BTreeMap<String, BTreeMap<String, Vec<String>>> =
|
||||||
#[allow(non_snake_case)]
|
serde_json::from_str(&fs::read_to_string(&file_path).unwrap()).unwrap();
|
||||||
pub mod #key_pascal {
|
|
||||||
use super::Tag;
|
let is_latest = version == latest_version_key;
|
||||||
#(#tag_entries)*
|
let mut tag_dicts = Vec::new();
|
||||||
}
|
let mut match_local_map = Vec::new();
|
||||||
static #dict_name: phf::Map<&'static str, &'static Tag> = phf::phf_map! {
|
|
||||||
#(#tag_map_entries),*
|
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
|
for (tag_name, values) in tag_map {
|
||||||
match_arms_value.push(quote! {
|
let ids: Vec<u16> = values
|
||||||
RegistryKey::#key_pascal => {
|
.iter()
|
||||||
#dict_name.get(tag).map(|i| i.0)
|
.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! {
|
let tag_type_path = if is_latest {
|
||||||
RegistryKey::#key_pascal => {
|
quote!(Tag)
|
||||||
#dict_name.get(tag).map(|i| i.1 )
|
} else {
|
||||||
}
|
quote!(super::Tag)
|
||||||
});
|
};
|
||||||
|
|
||||||
match_arms_tags_all.push(quote! {
|
tag_dicts.push(quote! {
|
||||||
RegistryKey::#key_pascal => {
|
#[allow(non_snake_case)]
|
||||||
&#dict_name
|
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! {
|
match_local_map.push(quote! { RegistryKey::#key_pascal => Some(&#dict_name) });
|
||||||
Self::#key_pascal => #key
|
}
|
||||||
});
|
|
||||||
|
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! {
|
// --- Generate RegistryKey Enum ---
|
||||||
#[derive(Eq, PartialEq, Hash, Debug)]
|
let registry_key_enum = EnumCreator {
|
||||||
#registry_key_enum
|
name: "RegistryKey".to_string(),
|
||||||
|
values: all_registry_keys.into_iter().collect(),
|
||||||
|
}
|
||||||
|
.to_token_stream();
|
||||||
|
|
||||||
impl RegistryKey {
|
quote! {
|
||||||
// IDK why the linter is saying this isn't used
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn identifier_string(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
#(#tag_identifiers),*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Tag = (&'static [&'static str], &'static [u16]);
|
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]> {
|
pub fn get_tag_values(tag_category: RegistryKey, tag: &str) -> Option<&'static [&'static str]> {
|
||||||
match tag_category {
|
get_latest_map(tag_category).and_then(|m| m.get(tag)).map(|t| t.0)
|
||||||
#(#match_arms_value),*
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tag_ids(tag_category: RegistryKey, tag: &str) -> Option<&'static [u16]> {
|
pub fn get_tag_ids(tag_category: RegistryKey, tag: &str) -> Option<&'static [u16]> {
|
||||||
match tag_category {
|
get_latest_map(tag_category).and_then(|m| m.get(tag)).map(|t| t.1)
|
||||||
#(#match_arms_id),*
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_registry_key_tags(tag_category: &RegistryKey) -> &phf::Map<&'static str, &'static Tag> {
|
pub fn get_registry_key_tags(version: MinecraftVersion, tag_category: RegistryKey) -> Option<&'static phf::Map<&'static str, &'static Tag>> {
|
||||||
match tag_category {
|
match version {
|
||||||
#(#match_arms_tags_all),*
|
#(#match_get_map),*,
|
||||||
|
_ => get_latest_map(tag_category)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,8 +248,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
fn registry_key(&self) -> &str;
|
fn registry_key(&self) -> &str;
|
||||||
fn registry_id(&self) -> u16;
|
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 tag = tag.strip_prefix("#").unwrap_or(tag);
|
||||||
let items = get_tag_ids(Self::tag_key(), tag)?;
|
let items = get_tag_ids(Self::tag_key(), tag)?;
|
||||||
Some(items.contains(&self.registry_id()))
|
Some(items.contains(&self.registry_id()))
|
||||||
|
|||||||
@ -8,6 +8,10 @@ pub mod item;
|
|||||||
#[path = "generated/packet.rs"]
|
#[path = "generated/packet.rs"]
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[path = "generated/jukebox_song.rs"]
|
||||||
|
pub mod jukebox_song;
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[path = "generated/registry.rs"]
|
#[path = "generated/registry.rs"]
|
||||||
pub mod registry;
|
pub mod registry;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ use pumpkin_data::{
|
|||||||
};
|
};
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
use pumpkin_util::resource_location::ResourceLocation;
|
use pumpkin_util::resource_location::ResourceLocation;
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
|
|
||||||
#[packet(CONFIG_UPDATE_TAGS)]
|
#[packet(CONFIG_UPDATE_TAGS)]
|
||||||
pub struct CUpdateTags<'a> {
|
pub struct CUpdateTags<'a> {
|
||||||
@ -22,14 +23,18 @@ impl<'a> CUpdateTags<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ClientPacket for CUpdateTags<'_> {
|
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;
|
let mut write = write;
|
||||||
write.write_list(self.tags, |p, registry_key| {
|
write.write_list(self.tags, |p, registry_key| {
|
||||||
p.write_resource_location(&ResourceLocation::vanilla(
|
p.write_resource_location(&ResourceLocation::vanilla(
|
||||||
registry_key.identifier_string(),
|
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(|_| {
|
p.write_var_int(&values.len().try_into().map_err(|_| {
|
||||||
WritingError::Message(format!("{} isn't representable as a VarInt", values.len()))
|
WritingError::Message(format!("{} isn't representable as a VarInt", values.len()))
|
||||||
})?)?;
|
})?)?;
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use crate::ser::NetworkWriteExt;
|
|||||||
use crate::{ClientPacket, WritingError};
|
use crate::{ClientPacket, WritingError};
|
||||||
use pumpkin_data::packet::clientbound::PLAY_BOSS_EVENT;
|
use pumpkin_data::packet::clientbound::PLAY_BOSS_EVENT;
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
|
|
||||||
#[packet(PLAY_BOSS_EVENT)]
|
#[packet(PLAY_BOSS_EVENT)]
|
||||||
pub struct CBossEvent<'a> {
|
pub struct CBossEvent<'a> {
|
||||||
@ -19,7 +20,11 @@ impl<'a> CBossEvent<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ClientPacket for CBossEvent<'_> {
|
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;
|
let mut write = write;
|
||||||
|
|
||||||
write.write_uuid(self.uuid)?;
|
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_macros::packet;
|
||||||
use pumpkin_nbt::END_ID;
|
use pumpkin_nbt::END_ID;
|
||||||
use pumpkin_util::math::position::get_local_cord;
|
use pumpkin_util::math::position::get_local_cord;
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
use pumpkin_world::chunk::format::LightContainer;
|
use pumpkin_world::chunk::format::LightContainer;
|
||||||
use pumpkin_world::chunk::{ChunkData, palette::NetworkPalette};
|
use pumpkin_world::chunk::{ChunkData, palette::NetworkPalette};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@ -13,7 +14,11 @@ use std::io::Write;
|
|||||||
pub struct CChunkData<'a>(pub &'a ChunkData);
|
pub struct CChunkData<'a>(pub &'a ChunkData);
|
||||||
|
|
||||||
impl ClientPacket for CChunkData<'_> {
|
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;
|
let mut write = write;
|
||||||
|
|
||||||
// Chunk X
|
// Chunk X
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use std::io::Write;
|
|||||||
|
|
||||||
use pumpkin_data::packet::clientbound::PLAY_COMMANDS;
|
use pumpkin_data::packet::clientbound::PLAY_COMMANDS;
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
|
|
||||||
use crate::{ClientPacket, VarInt, WritingError, ser::NetworkWriteExt};
|
use crate::{ClientPacket, VarInt, WritingError, ser::NetworkWriteExt};
|
||||||
|
|
||||||
@ -21,7 +22,11 @@ impl<'a> CCommands<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ClientPacket for CCommands<'_> {
|
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;
|
let mut write = write;
|
||||||
write.write_list(&self.nodes, |bytebuf, node: &ProtoNode| {
|
write.write_list(&self.nodes, |bytebuf, node: &ProtoNode| {
|
||||||
node.write_to(bytebuf)
|
node.write_to(bytebuf)
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use std::io::Write;
|
|||||||
|
|
||||||
use pumpkin_data::packet::clientbound::PLAY_PLAYER_CHAT;
|
use pumpkin_data::packet::clientbound::PLAY_PLAYER_CHAT;
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
use pumpkin_util::text::TextComponent;
|
use pumpkin_util::{text::TextComponent, version::MinecraftVersion};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ClientPacket, WritingError,
|
ClientPacket, WritingError,
|
||||||
@ -67,7 +67,11 @@ impl CPlayerChatMessage {
|
|||||||
|
|
||||||
//TODO: Check if we need this custom impl
|
//TODO: Check if we need this custom impl
|
||||||
impl ClientPacket for CPlayerChatMessage {
|
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;
|
let mut write = write;
|
||||||
|
|
||||||
write.write_var_int(&self.global_index)?;
|
write.write_var_int(&self.global_index)?;
|
||||||
|
|||||||
@ -3,6 +3,7 @@ use std::io::Write;
|
|||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use pumpkin_data::packet::clientbound::PLAY_PLAYER_INFO_UPDATE;
|
use pumpkin_data::packet::clientbound::PLAY_PLAYER_INFO_UPDATE;
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
|
|
||||||
use crate::{ClientPacket, Property, WritingError, ser::NetworkWriteExt};
|
use crate::{ClientPacket, Property, WritingError, ser::NetworkWriteExt};
|
||||||
|
|
||||||
@ -41,7 +42,11 @@ impl<'a> CPlayerInfoUpdate<'a> {
|
|||||||
|
|
||||||
// TODO: Check if we need this custom impl
|
// TODO: Check if we need this custom impl
|
||||||
impl ClientPacket for CPlayerInfoUpdate<'_> {
|
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;
|
let mut write = write;
|
||||||
|
|
||||||
write.write_u8(self.actions)?;
|
write.write_u8(self.actions)?;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use std::io::Write;
|
|||||||
|
|
||||||
use pumpkin_data::packet::clientbound::PLAY_PLAYER_POSITION;
|
use pumpkin_data::packet::clientbound::PLAY_PLAYER_POSITION;
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
use pumpkin_util::math::vector3::Vector3;
|
use pumpkin_util::{math::vector3::Vector3, version::MinecraftVersion};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ClientPacket, PositionFlag, ServerPacket, VarInt, WritingError, ser::NetworkReadExt,
|
ClientPacket, PositionFlag, ServerPacket, VarInt, WritingError, ser::NetworkReadExt,
|
||||||
@ -41,7 +41,11 @@ impl CPlayerPosition {
|
|||||||
|
|
||||||
// TODO: Do we need a custom impl?
|
// TODO: Do we need a custom impl?
|
||||||
impl ClientPacket for CPlayerPosition {
|
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;
|
let mut write = write;
|
||||||
|
|
||||||
write.write_var_int(&self.teleport_id)?;
|
write.write_var_int(&self.teleport_id)?;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use pumpkin_data::packet::clientbound::PLAY_SET_EQUIPMENT;
|
use pumpkin_data::packet::clientbound::PLAY_SET_EQUIPMENT;
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -29,7 +30,11 @@ impl CSetEquipment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ClientPacket for 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;
|
let mut write = write;
|
||||||
|
|
||||||
write.write_var_int(&self.entity_id)?;
|
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_data::{packet::clientbound::PLAY_STOP_SOUND, sound::SoundCategory};
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
use pumpkin_util::resource_location::ResourceLocation;
|
use pumpkin_util::resource_location::ResourceLocation;
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
|
|
||||||
#[packet(PLAY_STOP_SOUND)]
|
#[packet(PLAY_STOP_SOUND)]
|
||||||
pub struct CStopSound {
|
pub struct CStopSound {
|
||||||
@ -20,7 +21,11 @@ impl CStopSound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ClientPacket for 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;
|
let mut write = write;
|
||||||
|
|
||||||
const NO_CATEGORY_NO_SOUND: u8 = 0;
|
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_data::packet::clientbound::PLAY_TELEPORT_ENTITY;
|
||||||
use pumpkin_macros::packet;
|
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};
|
use crate::{ClientPacket, PositionFlag, VarInt, WritingError, ser::NetworkWriteExt};
|
||||||
|
|
||||||
@ -42,7 +42,11 @@ impl<'a> CTeleportEntity<'a> {
|
|||||||
|
|
||||||
// TODO: Do we need a custom impl?
|
// TODO: Do we need a custom impl?
|
||||||
impl ClientPacket for CTeleportEntity<'_> {
|
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;
|
let mut write = write;
|
||||||
|
|
||||||
write.write_var_int(&self.entity_id)?;
|
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_data::packet::clientbound::PLAY_SET_OBJECTIVE;
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
use pumpkin_util::text::TextComponent;
|
use pumpkin_util::{text::TextComponent, version::MinecraftVersion};
|
||||||
|
|
||||||
use crate::{ClientPacket, NumberFormat, VarInt, WritingError, ser::NetworkWriteExt};
|
use crate::{ClientPacket, NumberFormat, VarInt, WritingError, ser::NetworkWriteExt};
|
||||||
|
|
||||||
@ -34,7 +34,11 @@ impl CUpdateObjectives {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ClientPacket for 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;
|
let mut write = write;
|
||||||
|
|
||||||
write.write_string(&self.objective_name)?;
|
write.write_string(&self.objective_name)?;
|
||||||
|
|||||||
@ -284,6 +284,7 @@ mod tests {
|
|||||||
use flate2::read::ZlibDecoder;
|
use flate2::read::ZlibDecoder;
|
||||||
use pumpkin_data::packet::clientbound::STATUS_STATUS_RESPONSE;
|
use pumpkin_data::packet::clientbound::STATUS_STATUS_RESPONSE;
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
/// Define a custom packet for testing maximum packet size
|
/// Define a custom packet for testing maximum packet size
|
||||||
@ -339,7 +340,9 @@ mod tests {
|
|||||||
let mut packet_buf = Vec::new();
|
let mut packet_buf = Vec::new();
|
||||||
let writer = &mut packet_buf;
|
let writer = &mut packet_buf;
|
||||||
writer.write_var_int(&VarInt(T::PACKET_ID)).unwrap();
|
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();
|
encoder.write_packet(packet_buf.into()).await.unwrap();
|
||||||
|
|
||||||
@ -374,7 +377,9 @@ mod tests {
|
|||||||
// Remaining buffer is the payload
|
// Remaining buffer is the payload
|
||||||
// We need to obtain the expected payload
|
// We need to obtain the expected payload
|
||||||
let mut expected_payload = Vec::new();
|
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);
|
assert_eq!(buffer, expected_payload);
|
||||||
}
|
}
|
||||||
@ -402,7 +407,9 @@ mod tests {
|
|||||||
// Read data length VarInt (uncompressed data length)
|
// Read data length VarInt (uncompressed data length)
|
||||||
let data_length = decode_varint(&mut buffer).expect("Failed to decode data length");
|
let data_length = decode_varint(&mut buffer).expect("Failed to decode data length");
|
||||||
let mut expected_payload = Vec::new();
|
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 =
|
let uncompressed_data_length =
|
||||||
VarInt(CStatusResponse::PACKET_ID).written_size() + expected_payload.len();
|
VarInt(CStatusResponse::PACKET_ID).written_size() + expected_payload.len();
|
||||||
assert_eq!(data_length as usize, uncompressed_data_length);
|
assert_eq!(data_length as usize, uncompressed_data_length);
|
||||||
@ -458,7 +465,9 @@ mod tests {
|
|||||||
|
|
||||||
// Remaining buffer is the payload
|
// Remaining buffer is the payload
|
||||||
let mut expected_payload = Vec::new();
|
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);
|
assert_eq!(buffer, expected_payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,7 +501,9 @@ mod tests {
|
|||||||
// Read data length VarInt (uncompressed data length)
|
// Read data length VarInt (uncompressed data length)
|
||||||
let data_length = decode_varint(&mut buffer).expect("Failed to decode data length");
|
let data_length = decode_varint(&mut buffer).expect("Failed to decode data length");
|
||||||
let mut expected_payload = Vec::new();
|
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 =
|
let uncompressed_data_length =
|
||||||
VarInt(CStatusResponse::PACKET_ID).written_size() + expected_payload.len();
|
VarInt(CStatusResponse::PACKET_ID).written_size() + expected_payload.len();
|
||||||
assert_eq!(data_length as usize, uncompressed_data_length);
|
assert_eq!(data_length as usize, uncompressed_data_length);
|
||||||
@ -542,7 +553,9 @@ mod tests {
|
|||||||
|
|
||||||
// Remaining buffer is the payload (empty)
|
// Remaining buffer is the payload (empty)
|
||||||
let mut expected_payload = Vec::new();
|
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!(
|
assert_eq!(
|
||||||
buffer.len(),
|
buffer.len(),
|
||||||
@ -587,7 +600,9 @@ mod tests {
|
|||||||
|
|
||||||
// Remaining buffer is the payload
|
// Remaining buffer is the payload
|
||||||
let mut expected_payload = Vec::new();
|
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);
|
assert_eq!(buffer, expected_payload);
|
||||||
}
|
}
|
||||||
@ -639,7 +654,9 @@ mod tests {
|
|||||||
|
|
||||||
// Remaining buffer is the payload
|
// Remaining buffer is the payload
|
||||||
let mut expected_payload = Vec::new();
|
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);
|
assert_eq!(buffer, expected_payload);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use pumpkin_data::packet::serverbound::HANDSHAKE_INTENTION;
|
use pumpkin_data::packet::serverbound::HANDSHAKE_INTENTION;
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
|
|
||||||
#[packet(HANDSHAKE_INTENTION)]
|
#[packet(HANDSHAKE_INTENTION)]
|
||||||
pub struct SHandShake {
|
pub struct SHandShake {
|
||||||
@ -34,6 +35,7 @@ impl ClientPacket for SHandShake {
|
|||||||
fn write_packet_data(
|
fn write_packet_data(
|
||||||
&self,
|
&self,
|
||||||
mut write: impl std::io::Write,
|
mut write: impl std::io::Write,
|
||||||
|
_version: &MinecraftVersion,
|
||||||
) -> Result<(), crate::ser::WritingError> {
|
) -> Result<(), crate::ser::WritingError> {
|
||||||
write.write_var_int(&self.protocol_version)?;
|
write.write_var_int(&self.protocol_version)?;
|
||||||
write.write_string(&self.server_address)?;
|
write.write_string(&self.server_address)?;
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use std::io::Read;
|
|||||||
|
|
||||||
use pumpkin_data::packet::serverbound::PLAY_CHAT;
|
use pumpkin_data::packet::serverbound::PLAY_CHAT;
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ClientPacket, ServerPacket,
|
ClientPacket, ServerPacket,
|
||||||
@ -40,6 +41,7 @@ impl ClientPacket for SChatMessage {
|
|||||||
fn write_packet_data(
|
fn write_packet_data(
|
||||||
&self,
|
&self,
|
||||||
mut write: impl std::io::Write,
|
mut write: impl std::io::Write,
|
||||||
|
_version: &MinecraftVersion,
|
||||||
) -> Result<(), crate::ser::WritingError> {
|
) -> Result<(), crate::ser::WritingError> {
|
||||||
write.write_string(&self.message)?;
|
write.write_string(&self.message)?;
|
||||||
write.write_i64_be(self.timestamp)?;
|
write.write_i64_be(self.timestamp)?;
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use codec::var_int::VarInt;
|
|||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
resource_location::ResourceLocation,
|
resource_location::ResourceLocation,
|
||||||
text::{TextComponent, style::Style},
|
text::{TextComponent, style::Style},
|
||||||
|
version::MinecraftVersion,
|
||||||
};
|
};
|
||||||
use ser::{ReadingError, WritingError};
|
use ser::{ReadingError, WritingError};
|
||||||
use serde::{
|
use serde::{
|
||||||
@ -311,7 +312,11 @@ pub struct RawPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait ClientPacket: Packet {
|
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 {
|
pub trait ServerPacket: Packet + Sized {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use std::io::{Error, Read, Write};
|
use std::io::{Error, Read, Write};
|
||||||
|
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
use serde::{Serialize, de::DeserializeOwned};
|
use serde::{Serialize, de::DeserializeOwned};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -14,7 +15,11 @@ pub trait Packet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Packet + Serialize> ClientPacket for P {
|
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);
|
let mut serializer = serializer::Serializer::new(write);
|
||||||
self.serialize(&mut serializer)
|
self.serialize(&mut serializer)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ pub mod resource_location;
|
|||||||
pub mod serde_enum_as_integer;
|
pub mod serde_enum_as_integer;
|
||||||
pub mod text;
|
pub mod text;
|
||||||
pub mod translation;
|
pub mod translation;
|
||||||
|
pub mod version;
|
||||||
pub mod world_seed;
|
pub mod world_seed;
|
||||||
|
|
||||||
pub mod jwt;
|
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 type BlockStateId = u16;
|
||||||
|
|
||||||
pub const CURRENT_MC_VERSION: &str = "1.21.11";
|
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_VERSION: &str = "1.21.32";
|
||||||
pub const CURRENT_BEDROCK_MC_PROTOCOL: u32 = 898;
|
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::block::{BlockBehaviour, BlockFuture, BrokenArgs, UseWithItemArgs};
|
||||||
use crate::world::World;
|
use crate::world::World;
|
||||||
use pumpkin_data::data_component_impl::JukeboxPlayableImpl;
|
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::world::WorldEvent;
|
||||||
use pumpkin_data::{
|
use pumpkin_data::{
|
||||||
Block,
|
Block,
|
||||||
@ -73,7 +73,7 @@ impl BlockBehaviour for JukeboxBlock {
|
|||||||
return BlockActionResult::Pass;
|
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!");
|
log::error!("Jukebox playable song not registered!");
|
||||||
return BlockActionResult::Pass;
|
return BlockActionResult::Pass;
|
||||||
};
|
};
|
||||||
@ -86,7 +86,7 @@ impl BlockBehaviour for JukeboxBlock {
|
|||||||
.sync_world_event(
|
.sync_world_event(
|
||||||
WorldEvent::JukeboxStartsPlaying,
|
WorldEvent::JukeboxStartsPlaying,
|
||||||
*args.position,
|
*args.position,
|
||||||
jukebox_song as i32,
|
jukebox_song.get_id() as i32,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use crate::{
|
|||||||
server::Server,
|
server::Server,
|
||||||
};
|
};
|
||||||
use core::str;
|
use core::str;
|
||||||
|
use pumpkin_data::{registry::Registry, tag::RegistryKey};
|
||||||
use pumpkin_protocol::{
|
use pumpkin_protocol::{
|
||||||
ConnectionState,
|
ConnectionState,
|
||||||
java::{
|
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");
|
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
|
let entries: Vec<RegistryEntry> = registry
|
||||||
.registry_entries
|
.registry_entries
|
||||||
.iter()
|
.iter()
|
||||||
@ -159,18 +162,13 @@ impl JavaClient {
|
|||||||
.collect();
|
.collect();
|
||||||
self.send_packet_now(&CRegistryData::new(®istry.registry_id, &entries))
|
self.send_packet_now(&CRegistryData::new(®istry.registry_id, &entries))
|
||||||
.await;
|
.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(&[
|
self.send_packet_now(&CUpdateTags::new(&tags_to_send)).await;
|
||||||
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;
|
|
||||||
|
|
||||||
// We are done with configuring
|
// We are done with configuring
|
||||||
log::debug!("Finished config");
|
log::debug!("Finished config");
|
||||||
|
|||||||
@ -1,36 +1,33 @@
|
|||||||
use pumpkin_data::packet::CURRENT_MC_PROTOCOL;
|
use pumpkin_data::packet::CURRENT_MC_PROTOCOL;
|
||||||
use pumpkin_protocol::{ConnectionState, java::server::handshake::SHandShake};
|
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;
|
use crate::net::java::JavaClient;
|
||||||
|
|
||||||
impl JavaClient {
|
impl JavaClient {
|
||||||
pub async fn handle_handshake(&self, handshake: SHandShake) {
|
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.server_address.lock().await = handshake.server_address;
|
||||||
|
self.version.store(MinecraftVersion::from_protocol(version));
|
||||||
|
|
||||||
log::debug!("Handshake: next state is {:?}", &handshake.next_state);
|
log::debug!("Handshake: next state is {:?}", &handshake.next_state);
|
||||||
self.connection_state.store(handshake.next_state);
|
self.connection_state.store(handshake.next_state);
|
||||||
if self.connection_state.load() != ConnectionState::Status {
|
if self.connection_state.load() != ConnectionState::Status {
|
||||||
let protocol = version;
|
let protocol = version;
|
||||||
match protocol.cmp(&(CURRENT_MC_PROTOCOL as i32)) {
|
if protocol < LOWEST_SUPPRORTED_PROTOCOL_VERSION {
|
||||||
std::cmp::Ordering::Less => {
|
self.kick(TextComponent::translate(
|
||||||
self.kick(TextComponent::translate(
|
"multiplayer.disconnect.outdated_client",
|
||||||
"multiplayer.disconnect.outdated_client",
|
[TextComponent::text(CURRENT_MC_VERSION.to_string())],
|
||||||
[TextComponent::text(CURRENT_MC_VERSION.to_string())],
|
))
|
||||||
))
|
.await;
|
||||||
.await;
|
} else if protocol > CURRENT_MC_PROTOCOL {
|
||||||
}
|
self.kick(TextComponent::translate(
|
||||||
std::cmp::Ordering::Equal => {}
|
"multiplayer.disconnect.incompatible",
|
||||||
std::cmp::Ordering::Greater => {
|
[TextComponent::text(CURRENT_MC_VERSION.to_string())],
|
||||||
self.kick(TextComponent::translate(
|
))
|
||||||
"multiplayer.disconnect.incompatible",
|
.await;
|
||||||
[TextComponent::text(CURRENT_MC_VERSION.to_string())],
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ use std::{io::Write, sync::Arc};
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use crossbeam::atomic::AtomicCell;
|
use crossbeam::atomic::AtomicCell;
|
||||||
use pumpkin_config::networking::compression::CompressionInfo;
|
use pumpkin_config::networking::compression::CompressionInfo;
|
||||||
|
use pumpkin_data::packet::CURRENT_MC_PROTOCOL;
|
||||||
use pumpkin_protocol::java::server::play::{
|
use pumpkin_protocol::java::server::play::{
|
||||||
SChangeGameMode, SChatCommand, SChatMessage, SChunkBatch, SClickSlot, SClientCommand,
|
SChangeGameMode, SChatCommand, SChatMessage, SChunkBatch, SClickSlot, SClientCommand,
|
||||||
SClientInformationPlay, SClientTickEnd, SCloseContainer, SCommandSuggestion, SConfirmTeleport,
|
SClientInformationPlay, SClientTickEnd, SCloseContainer, SCommandSuggestion, SConfirmTeleport,
|
||||||
@ -36,6 +37,7 @@ use pumpkin_protocol::{
|
|||||||
ser::{NetworkWriteExt, ReadingError, WritingError},
|
ser::{NetworkWriteExt, ReadingError, WritingError},
|
||||||
};
|
};
|
||||||
use pumpkin_util::text::TextComponent;
|
use pumpkin_util::text::TextComponent;
|
||||||
|
use pumpkin_util::version::MinecraftVersion;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{BufReader, BufWriter},
|
io::{BufReader, BufWriter},
|
||||||
net::{
|
net::{
|
||||||
@ -55,6 +57,7 @@ pub mod config;
|
|||||||
pub mod handshake;
|
pub mod handshake;
|
||||||
pub mod login;
|
pub mod login;
|
||||||
pub mod play;
|
pub mod play;
|
||||||
|
pub mod remapper;
|
||||||
pub mod status;
|
pub mod status;
|
||||||
|
|
||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
@ -63,6 +66,7 @@ use crate::{error::PumpkinError, net::EncryptionError, server::Server};
|
|||||||
|
|
||||||
pub struct JavaClient {
|
pub struct JavaClient {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
|
pub version: AtomicCell<MinecraftVersion>,
|
||||||
/// The client's game profile information.
|
/// The client's game profile information.
|
||||||
pub gameprofile: Mutex<Option<GameProfile>>,
|
pub gameprofile: Mutex<Option<GameProfile>>,
|
||||||
/// The client's configuration settings, Optional
|
/// The client's configuration settings, Optional
|
||||||
@ -106,7 +110,7 @@ impl JavaClient {
|
|||||||
tasks: TaskTracker::new(),
|
tasks: TaskTracker::new(),
|
||||||
outgoing_packet_queue_send: send,
|
outgoing_packet_queue_send: send,
|
||||||
outgoing_packet_queue_recv: Some(recv),
|
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_writer: Arc::new(Mutex::new(TCPNetworkEncoder::new(BufWriter::new(write)))),
|
||||||
network_reader: Mutex::new(TCPNetworkDecoder::new(BufReader::new(read))),
|
network_reader: Mutex::new(TCPNetworkDecoder::new(BufReader::new(read))),
|
||||||
brand: Mutex::new(None),
|
brand: Mutex::new(None),
|
||||||
@ -193,7 +197,7 @@ impl JavaClient {
|
|||||||
pub async fn enqueue_packet<P: ClientPacket>(&self, packet: &P) {
|
pub async fn enqueue_packet<P: ClientPacket>(&self, packet: &P) {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
let writer = &mut buf;
|
let writer = &mut buf;
|
||||||
Self::write_packet(packet, writer).unwrap();
|
self.write_packet(packet, writer).unwrap();
|
||||||
self.enqueue_packet_data(buf.into()).await;
|
self.enqueue_packet_data(buf.into()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +270,7 @@ impl JavaClient {
|
|||||||
pub async fn send_packet_now<P: ClientPacket>(&self, packet: &P) {
|
pub async fn send_packet_now<P: ClientPacket>(&self, packet: &P) {
|
||||||
let mut packet_buf = Vec::new();
|
let mut packet_buf = Vec::new();
|
||||||
let writer = &mut packet_buf;
|
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;
|
self.send_packet_now_data(packet_buf).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,12 +293,13 @@ impl JavaClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_packet<P: ClientPacket>(
|
pub fn write_packet<P: ClientPacket>(
|
||||||
|
&self,
|
||||||
packet: &P,
|
packet: &P,
|
||||||
write: impl Write,
|
write: impl Write,
|
||||||
) -> Result<(), WritingError> {
|
) -> Result<(), WritingError> {
|
||||||
let mut write = write;
|
let mut write = write;
|
||||||
write.write_var_int(&VarInt(P::PACKET_ID))?;
|
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.
|
/// 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;
|
self.handle_config_acknowledged(server).await;
|
||||||
}
|
}
|
||||||
SKnownPacks::PACKET_ID => {
|
SKnownPacks::PACKET_ID => {
|
||||||
self.handle_known_packs(server, SKnownPacks::read(payload)?)
|
self.handle_known_packs(SKnownPacks::read(payload)?).await;
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
SConfigCookieResponse::PACKET_ID => {
|
SConfigCookieResponse::PACKET_ID => {
|
||||||
self.handle_config_cookie_response(&SConfigCookieResponse::read(payload)?);
|
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 key_store::KeyStore;
|
||||||
use pumpkin_config::{AdvancedConfiguration, BasicConfiguration};
|
use pumpkin_config::{AdvancedConfiguration, BasicConfiguration};
|
||||||
use pumpkin_data::dimension::Dimension;
|
use pumpkin_data::dimension::Dimension;
|
||||||
use pumpkin_data::registry::Registry;
|
|
||||||
use pumpkin_world::dimension::into_level;
|
use pumpkin_world::dimension::into_level;
|
||||||
|
|
||||||
use crate::command::CommandSender;
|
use crate::command::CommandSender;
|
||||||
@ -74,8 +73,6 @@ pub struct Server {
|
|||||||
pub worlds: RwLock<Vec<Arc<World>>>,
|
pub worlds: RwLock<Vec<Arc<World>>>,
|
||||||
/// All the dimensions that exist on the server.
|
/// All the dimensions that exist on the server.
|
||||||
pub dimensions: Vec<Dimension>,
|
pub dimensions: Vec<Dimension>,
|
||||||
/// Caches game registries for efficient access.
|
|
||||||
pub cached_registry: Vec<Registry>,
|
|
||||||
/// Assigns unique IDs to containers.
|
/// Assigns unique IDs to containers.
|
||||||
container_id: AtomicU32,
|
container_id: AtomicU32,
|
||||||
/// Mojang's public keys, used for chat session signing
|
/// Mojang's public keys, used for chat session signing
|
||||||
@ -178,8 +175,6 @@ impl Server {
|
|||||||
let server = Self {
|
let server = Self {
|
||||||
basic_config,
|
basic_config,
|
||||||
advanced_config,
|
advanced_config,
|
||||||
|
|
||||||
cached_registry: Registry::get_synced(),
|
|
||||||
container_id: 0.into(),
|
container_id: 0.into(),
|
||||||
worlds: RwLock::new(vec![]),
|
worlds: RwLock::new(vec![]),
|
||||||
dimensions: vec![
|
dimensions: vec![
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user