add working container state and change to fix with latest current branch
This commit is contained in:
parent
c98c0ec6bf
commit
d1c4e59955
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -1901,6 +1901,7 @@ dependencies = [
|
|||||||
"digest 0.11.0-pre.9",
|
"digest 0.11.0-pre.9",
|
||||||
"hmac",
|
"hmac",
|
||||||
"image",
|
"image",
|
||||||
|
"itertools 0.13.0",
|
||||||
"log",
|
"log",
|
||||||
"mio",
|
"mio",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
@ -2806,9 +2807,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.39.2"
|
version = "1.40.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
|
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
use crate::WindowType;
|
|
||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
|
|
||||||
pub struct ClickMode {
|
pub struct ClickMode {
|
||||||
@ -8,8 +7,6 @@ pub struct ClickMode {
|
|||||||
|
|
||||||
pub struct Click {
|
pub struct Click {
|
||||||
pub mode: ClickMode,
|
pub mode: ClickMode,
|
||||||
pub state_id: u32,
|
|
||||||
pub window_type: WindowType,
|
|
||||||
pub changed_items: Vec<ItemChange>,
|
pub changed_items: Vec<ItemChange>,
|
||||||
pub carried_item: Option<ItemStack>,
|
pub carried_item: Option<ItemStack>,
|
||||||
}
|
}
|
||||||
@ -25,7 +22,7 @@ impl ClickMode {
|
|||||||
click_type: ClickType::CreativePickItem,
|
click_type: ClickType::CreativePickItem,
|
||||||
slot: Slot::Normal(slot.try_into().unwrap()),
|
slot: Slot::Normal(slot.try_into().unwrap()),
|
||||||
},
|
},
|
||||||
4 => Self::new_drop_item(button, slot),
|
4 => Self::new_drop_item(button),
|
||||||
5 => Self::new_drag_item(button, slot),
|
5 => Self::new_drag_item(button, slot),
|
||||||
6 => Self {
|
6 => Self {
|
||||||
click_type: ClickType::DoubleClick,
|
click_type: ClickType::DoubleClick,
|
||||||
@ -78,7 +75,7 @@ impl ClickMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_drop_item(button: i8, slot: i16) -> Self {
|
fn new_drop_item(button: i8) -> Self {
|
||||||
let drop_type = match button {
|
let drop_type = match button {
|
||||||
0 => DropType::SingleItem,
|
0 => DropType::SingleItem,
|
||||||
1 => DropType::FullStack,
|
1 => DropType::FullStack,
|
||||||
@ -87,7 +84,7 @@ impl ClickMode {
|
|||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
click_type: ClickType::DropType(drop_type),
|
click_type: ClickType::DropType(drop_type),
|
||||||
slot: Slot::Normal(slot.try_into().unwrap()),
|
slot: Slot::OutsideInventory,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +105,6 @@ impl ClickMode {
|
|||||||
MouseDragState::End,
|
MouseDragState::End,
|
||||||
Slot::OutsideInventory,
|
Slot::OutsideInventory,
|
||||||
),
|
),
|
||||||
|
|
||||||
4 => (
|
4 => (
|
||||||
MouseDragType::Right,
|
MouseDragType::Right,
|
||||||
MouseDragState::Start,
|
MouseDragState::Start,
|
||||||
|
|||||||
@ -76,7 +76,28 @@ pub trait Container: Sync + Send {
|
|||||||
|
|
||||||
fn all_slots_ref(&self) -> Vec<Option<&ItemStack>>;
|
fn all_slots_ref(&self) -> Vec<Option<&ItemStack>>;
|
||||||
|
|
||||||
fn state_id(&mut self) -> i32;
|
fn all_combinable_slots(&self) -> Vec<Option<&ItemStack>> {
|
||||||
|
self.all_slots_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn all_combinable_slots_mut(&mut self) -> Vec<&mut Option<ItemStack>> {
|
||||||
|
self.all_slots()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_state_id(&mut self) -> i32;
|
||||||
|
|
||||||
|
fn reset_state_id(&mut self);
|
||||||
|
fn state_id(&self) -> i32;
|
||||||
|
|
||||||
|
fn print_all_contents(&self) {
|
||||||
|
self.all_slots_ref()
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(slot, item)| item.map(|item| (slot, item)))
|
||||||
|
.for_each(|(slot, item)| {
|
||||||
|
dbg!(slot, item);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_item_take(
|
pub fn handle_item_take(
|
||||||
@ -106,12 +127,6 @@ pub fn handle_item_change(
|
|||||||
current_slot: &mut Option<ItemStack>,
|
current_slot: &mut Option<ItemStack>,
|
||||||
mouse_click: MouseClick,
|
mouse_click: MouseClick,
|
||||||
) {
|
) {
|
||||||
if let Some(carried) = carried_slot.as_ref() {
|
|
||||||
dbg!(carried);
|
|
||||||
}
|
|
||||||
if let Some(current) = current_slot.as_ref() {
|
|
||||||
dbg!(current);
|
|
||||||
}
|
|
||||||
match (current_slot.as_mut(), carried_slot.as_mut()) {
|
match (current_slot.as_mut(), carried_slot.as_mut()) {
|
||||||
// Swap or combine current and carried
|
// Swap or combine current and carried
|
||||||
(Some(current), Some(carried)) => {
|
(Some(current), Some(carried)) => {
|
||||||
@ -170,25 +185,23 @@ pub fn combine_stacks(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OptionallyCombinedContainer<'a> {
|
pub struct OptionallyCombinedContainer<'a, 'b> {
|
||||||
container: Option<&'a mut Box<dyn Container>>,
|
container: Option<&'a mut Box<dyn Container>>,
|
||||||
inventory: &'a mut PlayerInventory,
|
inventory: &'b mut PlayerInventory,
|
||||||
state_id: i32,
|
|
||||||
}
|
}
|
||||||
impl<'a> OptionallyCombinedContainer<'a> {
|
impl<'a, 'b> OptionallyCombinedContainer<'a, 'b> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
player_inventory: &'a mut PlayerInventory,
|
player_inventory: &'b mut PlayerInventory,
|
||||||
container: Option<&'a mut Box<dyn Container>>,
|
container: Option<&'a mut Box<dyn Container>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inventory: player_inventory,
|
inventory: player_inventory,
|
||||||
container,
|
container,
|
||||||
state_id: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Container for OptionallyCombinedContainer<'a> {
|
impl<'a> Container for OptionallyCombinedContainer<'a, 'a> {
|
||||||
fn window_type(&self) -> &'static WindowType {
|
fn window_type(&self) -> &'static WindowType {
|
||||||
if let Some(container) = &self.container {
|
if let Some(container) = &self.container {
|
||||||
container.window_type()
|
container.window_type()
|
||||||
@ -198,27 +211,38 @@ impl<'a> Container for OptionallyCombinedContainer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn all_slots(&mut self) -> Vec<&mut Option<ItemStack>> {
|
fn all_slots(&mut self) -> Vec<&mut Option<ItemStack>> {
|
||||||
let mut slots = if let Some(container) = &mut self.container {
|
let slots = match &mut self.container {
|
||||||
container.all_slots()
|
Some(container) => {
|
||||||
} else {
|
let mut slots = container.all_slots();
|
||||||
vec![]
|
slots.extend(self.inventory.all_combinable_slots_mut());
|
||||||
|
slots
|
||||||
|
}
|
||||||
|
None => self.inventory.all_slots(),
|
||||||
};
|
};
|
||||||
slots.extend(self.inventory.all_slots());
|
dbg!(slots.len());
|
||||||
slots
|
slots
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_slots_ref(&self) -> Vec<Option<&ItemStack>> {
|
fn all_slots_ref(&self) -> Vec<Option<&ItemStack>> {
|
||||||
let mut slots = if let Some(container) = &self.container {
|
match &self.container {
|
||||||
container.all_slots_ref()
|
Some(container) => {
|
||||||
} else {
|
let mut slots = container.all_slots_ref();
|
||||||
vec![]
|
slots.extend(self.inventory.all_combinable_slots());
|
||||||
};
|
|
||||||
slots.extend(self.inventory.all_slots_ref());
|
|
||||||
slots
|
slots
|
||||||
}
|
}
|
||||||
|
None => self.inventory.all_slots_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn state_id(&mut self) -> i32 {
|
fn advance_state_id(&mut self) -> i32 {
|
||||||
self.state_id += 1;
|
self.inventory.advance_state_id()
|
||||||
self.state_id - 1
|
}
|
||||||
|
|
||||||
|
fn reset_state_id(&mut self) {
|
||||||
|
self.inventory.reset_state_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_id(&self) -> i32 {
|
||||||
|
self.inventory.state_id()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ pub struct OpenContainer {
|
|||||||
impl OpenContainer {
|
impl OpenContainer {
|
||||||
pub fn try_open(&self, player_id: i32) -> Option<MutexGuard<Box<dyn Container>>> {
|
pub fn try_open(&self, player_id: i32) -> Option<MutexGuard<Box<dyn Container>>> {
|
||||||
if !self.players.contains(&player_id) {
|
if !self.players.contains(&player_id) {
|
||||||
|
dbg!("couldn't open container");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let container = self.container.lock().unwrap();
|
let container = self.container.lock().unwrap();
|
||||||
@ -31,6 +32,18 @@ impl OpenContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_player(&mut self, player_id: i32) {
|
||||||
|
if let Some(index) = self.players.iter().enumerate().find_map(|(index, id)| {
|
||||||
|
if *id == player_id {
|
||||||
|
Some(index)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
self.players.remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn empty(player_id: i32) -> Self {
|
pub fn empty(player_id: i32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
players: vec![player_id],
|
players: vec![player_id],
|
||||||
@ -58,6 +71,7 @@ impl Container for Chest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn all_slots(&mut self) -> Vec<&mut Option<ItemStack>> {
|
fn all_slots(&mut self) -> Vec<&mut Option<ItemStack>> {
|
||||||
|
dbg!(self.slots.iter().len());
|
||||||
self.slots.iter_mut().collect()
|
self.slots.iter_mut().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,8 +79,16 @@ impl Container for Chest {
|
|||||||
self.slots.iter().map(|slot| slot.as_ref()).collect()
|
self.slots.iter().map(|slot| slot.as_ref()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state_id(&mut self) -> i32 {
|
fn advance_state_id(&mut self) -> i32 {
|
||||||
self.state_id += 1;
|
self.state_id += 1;
|
||||||
self.state_id - 1
|
self.state_id - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reset_state_id(&mut self) {
|
||||||
|
self.state_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_id(&self) -> i32 {
|
||||||
|
self.state_id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ pub struct PlayerInventory {
|
|||||||
// current selected slot in hotbar
|
// current selected slot in hotbar
|
||||||
selected: usize,
|
selected: usize,
|
||||||
state_id: i32,
|
state_id: i32,
|
||||||
|
pub total_opened_containers: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PlayerInventory {
|
impl Default for PlayerInventory {
|
||||||
@ -33,6 +34,7 @@ impl PlayerInventory {
|
|||||||
// TODO: What when player spawns in with an different index ?
|
// TODO: What when player spawns in with an different index ?
|
||||||
selected: 0,
|
selected: 0,
|
||||||
state_id: 0,
|
state_id: 0,
|
||||||
|
total_opened_containers: 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,8 +157,23 @@ impl Container for PlayerInventory {
|
|||||||
self.slots()
|
self.slots()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state_id(&mut self) -> i32 {
|
fn all_combinable_slots(&self) -> Vec<Option<&ItemStack>> {
|
||||||
|
self.items.iter().map(|item| item.as_ref()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn all_combinable_slots_mut(&mut self) -> Vec<&mut Option<ItemStack>> {
|
||||||
|
self.items.iter_mut().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_state_id(&mut self) -> i32 {
|
||||||
self.state_id += 1;
|
self.state_id += 1;
|
||||||
self.state_id - 1
|
self.state_id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_state_id(&mut self) {
|
||||||
|
self.state_id = 0;
|
||||||
|
}
|
||||||
|
fn state_id(&self) -> i32 {
|
||||||
|
self.state_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,3 +64,4 @@ crossbeam-channel = "0.5.13"
|
|||||||
uuid.workspace = true
|
uuid.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
rayon.workspace = true
|
rayon.workspace = true
|
||||||
|
itertools = "0.13.0"
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use num_traits::FromPrimitive;
|
use itertools::Itertools;
|
||||||
use pumpkin_core::text::TextComponent;
|
use pumpkin_core::text::TextComponent;
|
||||||
use pumpkin_inventory::container_click::{KeyClick, MouseClick};
|
use pumpkin_inventory::container_click::{KeyClick, MouseClick};
|
||||||
use pumpkin_inventory::window_property::{WindowProperty, WindowPropertyTrait};
|
use pumpkin_inventory::window_property::{WindowProperty, WindowPropertyTrait};
|
||||||
use pumpkin_inventory::{container_click, handle_item_change, OptionallyCombinedContainer};
|
use pumpkin_inventory::{container_click, OptionallyCombinedContainer};
|
||||||
use pumpkin_inventory::{Container, WindowType};
|
use pumpkin_inventory::{Container, WindowType};
|
||||||
use pumpkin_protocol::client::play::{
|
use pumpkin_protocol::client::play::{
|
||||||
CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerProperty, CSetContainerSlot,
|
CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerProperty, CSetContainerSlot,
|
||||||
@ -10,6 +10,7 @@ use pumpkin_protocol::client::play::{
|
|||||||
use pumpkin_protocol::server::play::SClickContainer;
|
use pumpkin_protocol::server::play::SClickContainer;
|
||||||
use pumpkin_protocol::slot::Slot;
|
use pumpkin_protocol::slot::Slot;
|
||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
|
use std::sync::MutexGuard;
|
||||||
|
|
||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
@ -17,12 +18,12 @@ use crate::server::Server;
|
|||||||
impl Player {
|
impl Player {
|
||||||
pub fn open_container(
|
pub fn open_container(
|
||||||
&mut self,
|
&mut self,
|
||||||
container: &Box<dyn Container>,
|
server: &mut Server,
|
||||||
minecraft_menu_id: &str,
|
minecraft_menu_id: &str,
|
||||||
window_title: Option<&str>,
|
window_title: Option<&str>,
|
||||||
carried_item: Option<&ItemStack>,
|
|
||||||
state_id: i32,
|
|
||||||
) {
|
) {
|
||||||
|
let mut container = self.get_open_container(server);
|
||||||
|
let container = container.as_deref_mut();
|
||||||
let menu_protocol_id = (*pumpkin_world::global_registry::REGISTRY
|
let menu_protocol_id = (*pumpkin_world::global_registry::REGISTRY
|
||||||
.get("minecraft:menu")
|
.get("minecraft:menu")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -32,56 +33,48 @@ impl Player {
|
|||||||
.get("protocol_id")
|
.get("protocol_id")
|
||||||
.unwrap())
|
.unwrap())
|
||||||
.into();
|
.into();
|
||||||
let window_type = container.window_type();
|
let window_type = match &container {
|
||||||
|
Some(container) => container.window_type(),
|
||||||
|
None => &WindowType::Generic9x1,
|
||||||
|
}
|
||||||
|
.to_owned();
|
||||||
let title = TextComponent::text(window_title.unwrap_or(window_type.default_title()));
|
let title = TextComponent::text(window_title.unwrap_or(window_type.default_title()));
|
||||||
|
|
||||||
|
self.inventory.reset_state_id();
|
||||||
|
|
||||||
self.client.send_packet(&COpenScreen::new(
|
self.client.send_packet(&COpenScreen::new(
|
||||||
(*window_type as u8 + 1).into(),
|
self.inventory.total_opened_containers.into(),
|
||||||
menu_protocol_id,
|
menu_protocol_id,
|
||||||
title,
|
title,
|
||||||
));
|
));
|
||||||
|
self.set_container_content(container);
|
||||||
self.set_container_content(Some(container), carried_item, state_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_container_content<'a>(
|
pub fn set_container_content(&mut self, container: Option<&mut Box<dyn Container>>) {
|
||||||
&mut self,
|
let total_opened_containers = self.inventory.total_opened_containers;
|
||||||
container: Option<&Box<dyn Container>>,
|
let container = OptionallyCombinedContainer::new(&mut self.inventory, container);
|
||||||
carried_item: Option<&'a ItemStack>,
|
|
||||||
state_id: i32,
|
let slots = container
|
||||||
) {
|
.all_slots_ref()
|
||||||
let slots: Vec<Slot> = {
|
|
||||||
let items = container.map(|container| container.all_slots_ref());
|
|
||||||
if let Some(mut items) = items {
|
|
||||||
items.extend(self.inventory.all_slots_ref());
|
|
||||||
items
|
|
||||||
} else {
|
|
||||||
self.inventory.all_slots_ref()
|
|
||||||
}
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|item| {
|
.map(Slot::from)
|
||||||
if let Some(item) = item {
|
.collect_vec();
|
||||||
Slot::from(item)
|
|
||||||
} else {
|
|
||||||
Slot::empty()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
};
|
|
||||||
|
|
||||||
let carried_item = {
|
let carried_item = {
|
||||||
if let Some(item) = carried_item {
|
if let Some(item) = self.carried_item.as_ref() {
|
||||||
item.into()
|
item.into()
|
||||||
} else {
|
} else {
|
||||||
Slot::empty()
|
Slot::empty()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let window_type = match container {
|
let packet = CSetContainerContent::new(
|
||||||
Some(container) => *container.window_type() as u8,
|
total_opened_containers,
|
||||||
None => 0,
|
self.inventory.state_id().into(),
|
||||||
};
|
&slots,
|
||||||
|
&carried_item,
|
||||||
let packet = CSetContainerContent::new(window_type, state_id.into(), &slots, &carried_item);
|
);
|
||||||
|
self.inventory.advance_state_id();
|
||||||
self.client.send_packet(&packet);
|
self.client.send_packet(&packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,32 +94,54 @@ impl Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The official Minecraft client is weird, and will always just close *any* window that is opened when this gets sent
|
/// The official Minecraft client is weird, and will always just close *any* window that is opened when this gets sent
|
||||||
pub fn close_container(&mut self, window_type: WindowType) {
|
pub fn close_container(&mut self) {
|
||||||
self.client
|
self.inventory.total_opened_containers += 1;
|
||||||
.send_packet(&CCloseContainer::new(window_type as u8))
|
self.client.send_packet(&CCloseContainer::new(
|
||||||
|
self.inventory.total_opened_containers,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_container_property<T: WindowPropertyTrait>(
|
pub fn set_container_property<T: WindowPropertyTrait>(
|
||||||
&mut self,
|
&mut self,
|
||||||
window_type: WindowType,
|
|
||||||
window_property: WindowProperty<T>,
|
window_property: WindowProperty<T>,
|
||||||
) {
|
) {
|
||||||
let (id, value) = window_property.into_tuple();
|
let (id, value) = window_property.into_tuple();
|
||||||
self.client
|
self.client.send_packet(&CSetContainerProperty::new(
|
||||||
.send_packet(&CSetContainerProperty::new(window_type as u8, id, value));
|
self.inventory.total_opened_containers,
|
||||||
|
id,
|
||||||
|
value,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_click_container(&mut self, server: &mut Server, packet: SClickContainer) {
|
pub fn handle_click_container(&mut self, server: &mut Server, packet: SClickContainer) {
|
||||||
use container_click::*;
|
use container_click::*;
|
||||||
let mut opened_container = if let Some(id) = self.open_container {
|
let mut opened_container = self.get_open_container(server);
|
||||||
server.try_get_container(self.entity_id(), id)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let opened_container = opened_container.as_deref_mut();
|
let opened_container = opened_container.as_deref_mut();
|
||||||
|
|
||||||
|
let current_state_id = if let Some(container) = opened_container.as_ref() {
|
||||||
|
container.state_id()
|
||||||
|
} else {
|
||||||
|
self.inventory.state_id()
|
||||||
|
};
|
||||||
|
if current_state_id != packet.state_id.0 {
|
||||||
|
dbg!(current_state_id, packet.state_id.0);
|
||||||
|
//self.set_container_content(opened_container.as_deref_mut());
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if opened_container.is_some() {
|
||||||
|
if packet.window_id != self.inventory.total_opened_containers {
|
||||||
|
dbg!(
|
||||||
|
self.inventory.total_opened_containers,
|
||||||
|
opened_container.unwrap().window_type()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if packet.window_id != 0 {
|
||||||
|
dbg!("weird");
|
||||||
|
return;
|
||||||
|
}
|
||||||
let click = Click {
|
let click = Click {
|
||||||
state_id: packet.state_id.0.try_into().unwrap(),
|
|
||||||
changed_items: packet
|
changed_items: packet
|
||||||
.array_of_changed_slots
|
.array_of_changed_slots
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -139,12 +154,6 @@ impl Player {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
window_type: WindowType::from_u8(if packet.window_id == 0 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
packet.window_id - 1
|
|
||||||
})
|
|
||||||
.unwrap(),
|
|
||||||
carried_item: packet.carried_item.to_item(),
|
carried_item: packet.carried_item.to_item(),
|
||||||
mode: ClickMode::new(
|
mode: ClickMode::new(
|
||||||
packet
|
packet
|
||||||
@ -157,18 +166,13 @@ impl Player {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
match click.mode.click_type {
|
match click.mode.click_type {
|
||||||
ClickType::MouseClick(mouse_click) => self.mouse_click(
|
ClickType::MouseClick(mouse_click) => {
|
||||||
opened_container,
|
self.mouse_click(opened_container, mouse_click, click.mode.slot)
|
||||||
mouse_click,
|
|
||||||
click.window_type,
|
|
||||||
click.mode.slot,
|
|
||||||
),
|
|
||||||
ClickType::ShiftClick => {
|
|
||||||
self.shift_mouse_click(opened_container, click.window_type, click.mode.slot)
|
|
||||||
}
|
}
|
||||||
|
ClickType::ShiftClick => self.shift_mouse_click(opened_container, click.mode.slot),
|
||||||
ClickType::KeyClick(key_click) => match click.mode.slot {
|
ClickType::KeyClick(key_click) => match click.mode.slot {
|
||||||
container_click::Slot::Normal(slot) => {
|
container_click::Slot::Normal(slot) => {
|
||||||
self.number_button_pressed(opened_container, click.window_type, key_click, slot)
|
self.number_button_pressed(opened_container, key_click, slot)
|
||||||
}
|
}
|
||||||
container_click::Slot::OutsideInventory => {
|
container_click::Slot::OutsideInventory => {
|
||||||
unimplemented!("This is not a valid state")
|
unimplemented!("This is not a valid state")
|
||||||
@ -189,20 +193,16 @@ impl Player {
|
|||||||
drag_type: _,
|
drag_type: _,
|
||||||
} => (),
|
} => (),
|
||||||
ClickType::DropType(_drop_type) => (),
|
ClickType::DropType(_drop_type) => (),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_click(
|
fn mouse_click(
|
||||||
&mut self,
|
&mut self,
|
||||||
opened_container: Option<&mut Box<dyn Container>>,
|
opened_container: Option<&mut Box<dyn Container>>,
|
||||||
mouse_click: MouseClick,
|
mouse_click: MouseClick,
|
||||||
window_type: WindowType,
|
|
||||||
slot: container_click::Slot,
|
slot: container_click::Slot,
|
||||||
) {
|
) {
|
||||||
let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container);
|
let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container);
|
||||||
if container.window_type() != &window_type {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
match slot {
|
match slot {
|
||||||
container_click::Slot::Normal(slot) => {
|
container_click::Slot::Normal(slot) => {
|
||||||
@ -215,41 +215,42 @@ impl Player {
|
|||||||
fn shift_mouse_click(
|
fn shift_mouse_click(
|
||||||
&mut self,
|
&mut self,
|
||||||
opened_container: Option<&mut Box<dyn Container>>,
|
opened_container: Option<&mut Box<dyn Container>>,
|
||||||
window_type: WindowType,
|
|
||||||
slot: container_click::Slot,
|
slot: container_click::Slot,
|
||||||
) {
|
) {
|
||||||
let container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container);
|
let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container);
|
||||||
if container.window_type() != &window_type {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
match slot {
|
match slot {
|
||||||
container_click::Slot::Normal(slot) => {
|
container_click::Slot::Normal(slot) => {
|
||||||
if let Some(item_in_pressed_slot) = self.inventory.slots()[slot] {
|
let all_slots = container.all_slots();
|
||||||
let slots = self.inventory.slots().into_iter().enumerate();
|
if let Some(item_in_pressed_slot) = all_slots[slot].to_owned() {
|
||||||
|
let slots = all_slots.into_iter().enumerate();
|
||||||
// Hotbar
|
// Hotbar
|
||||||
let find_condition = |(_, slot): &(usize, Option<&ItemStack>)| {
|
let find_condition = |(slot_number, slot): (usize, &mut Option<ItemStack>)| {
|
||||||
slot.is_none_or(|item| item.item_id == item_in_pressed_slot.item_id)
|
// TODO: Check for max item count here
|
||||||
|
match slot {
|
||||||
|
Some(item) => {
|
||||||
|
if item.item_id == item_in_pressed_slot.item_id
|
||||||
|
&& item.item_count != 64
|
||||||
|
{
|
||||||
|
Some(slot_number)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Some(slot_number),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let slots = if slot > 35 {
|
let slots = if slot > 35 {
|
||||||
slots
|
slots.skip(9).find_map(find_condition)
|
||||||
.skip(9)
|
|
||||||
.find(find_condition)
|
|
||||||
.map(|(slot_num, _)| slot_num)
|
|
||||||
} else {
|
} else {
|
||||||
slots
|
slots.skip(36).rev().find_map(find_condition)
|
||||||
.skip(36)
|
|
||||||
.rev()
|
|
||||||
.find(find_condition)
|
|
||||||
.map(|(slot_num, _)| slot_num)
|
|
||||||
};
|
};
|
||||||
if let Some(slot) = slots {
|
if let Some(slot) = slots {
|
||||||
let mut item_slot = self.inventory.slots()[slot].map(|i| i.to_owned());
|
let mut item_slot = container.all_slots()[slot].map(|i| i.to_owned());
|
||||||
|
|
||||||
self.inventory
|
container.handle_item_change(&mut item_slot, slot, MouseClick::Left);
|
||||||
.handle_item_change(&mut item_slot, slot, MouseClick::Left);
|
*container.all_slots()[slot] = item_slot;
|
||||||
*self.inventory.slots_mut()[slot] = item_slot;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -260,7 +261,6 @@ impl Player {
|
|||||||
fn number_button_pressed(
|
fn number_button_pressed(
|
||||||
&mut self,
|
&mut self,
|
||||||
opened_container: Option<&mut Box<dyn Container>>,
|
opened_container: Option<&mut Box<dyn Container>>,
|
||||||
window_type: WindowType,
|
|
||||||
key_click: KeyClick,
|
key_click: KeyClick,
|
||||||
slot: usize,
|
slot: usize,
|
||||||
) {
|
) {
|
||||||
@ -270,16 +270,10 @@ impl Player {
|
|||||||
};
|
};
|
||||||
let mut changing_item_slot = self.inventory.get_slot(changing_slot as usize).to_owned();
|
let mut changing_item_slot = self.inventory.get_slot(changing_slot as usize).to_owned();
|
||||||
let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container);
|
let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container);
|
||||||
if container.window_type() != &window_type {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let item_slot = &mut container.all_slots()[slot];
|
container.handle_item_change(&mut changing_item_slot, slot, MouseClick::Left);
|
||||||
if item_slot.is_some() {
|
|
||||||
handle_item_change(&mut changing_item_slot, item_slot, MouseClick::Left);
|
|
||||||
*self.inventory.get_slot(changing_slot as usize) = changing_item_slot
|
*self.inventory.get_slot(changing_slot as usize) = changing_item_slot
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn creative_pick_item(
|
fn creative_pick_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -293,4 +287,15 @@ impl Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn double_click(&mut self, _slot: usize) {}
|
fn double_click(&mut self, _slot: usize) {}
|
||||||
|
|
||||||
|
pub fn get_open_container<'a>(
|
||||||
|
&self,
|
||||||
|
server: &'a Server,
|
||||||
|
) -> Option<MutexGuard<'a, Box<dyn Container>>> {
|
||||||
|
if let Some(id) = self.open_container {
|
||||||
|
server.try_get_container(self.entity_id(), id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -537,8 +537,14 @@ impl Player {
|
|||||||
// TODO:
|
// TODO:
|
||||||
// This function will in the future be used to keep track of if the client is in a valid state.
|
// This function will in the future be used to keep track of if the client is in a valid state.
|
||||||
// But this is not possible yet
|
// But this is not possible yet
|
||||||
pub fn handle_close_container(&mut self, _server: &mut Server, packet: SCloseContainer) {
|
pub fn handle_close_container(&mut self, server: &mut Server, packet: SCloseContainer) {
|
||||||
// window_id 0 represents both 9x1 Generic AND inventory here
|
// window_id 0 represents both 9x1 Generic AND inventory here
|
||||||
|
if let Some(id) = self.open_container {
|
||||||
|
if let Some(container) = server.open_containers.get_mut(&id) {
|
||||||
|
container.remove_player(self.entity_id())
|
||||||
|
}
|
||||||
|
self.open_container = None;
|
||||||
|
}
|
||||||
let Some(_window_type) = WindowType::from_u8(packet.window_id) else {
|
let Some(_window_type) = WindowType::from_u8(packet.window_id) else {
|
||||||
self.kick(TextComponent::text("Invalid window ID"));
|
self.kick(TextComponent::text("Invalid window ID"));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -10,34 +10,18 @@ const DESCRIPTION: &str =
|
|||||||
pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
|
pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
|
||||||
CommandTree::new(NAMES, DESCRIPTION).execute(&|sender, server, _| {
|
CommandTree::new(NAMES, DESCRIPTION).execute(&|sender, server, _| {
|
||||||
if let Some(player) = sender.as_mut_player() {
|
if let Some(player) = sender.as_mut_player() {
|
||||||
let entity_id = player.entity_id().clone();
|
let entity_id = player.entity_id();
|
||||||
player.open_container = Some(0);
|
player.open_container = Some(0);
|
||||||
let mut container = match server.open_containers.get_mut(&0) {
|
match server.open_containers.get_mut(&0) {
|
||||||
Some(ender_chest) => {
|
Some(ender_chest) => {
|
||||||
if ender_chest.try_open(entity_id).is_none() {
|
|
||||||
ender_chest.add_player(entity_id);
|
ender_chest.add_player(entity_id);
|
||||||
}
|
}
|
||||||
ender_chest.try_open(entity_id).unwrap()
|
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
let open_container = OpenContainer::empty(entity_id);
|
let open_container = OpenContainer::empty(entity_id);
|
||||||
server.open_containers.insert(0, open_container);
|
server.open_containers.insert(0, open_container);
|
||||||
server
|
|
||||||
.open_containers
|
|
||||||
.get_mut(&0)
|
|
||||||
.unwrap()
|
|
||||||
.try_open(entity_id)
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
let state_id = container.state_id();
|
player.open_container(server, "minecraft:generic_9x3", Some("Ender Chest"));
|
||||||
player.open_container(
|
|
||||||
&container,
|
|
||||||
"minecraft:generic_9x3",
|
|
||||||
Some("Ender Chest"),
|
|
||||||
None,
|
|
||||||
state_id,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use num_derive::FromPrimitive;
|
||||||
use crate::{client::Client, server::Server};
|
|
||||||
use num_derive::{FromPrimitive, ToPrimitive};
|
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
use pumpkin_core::{
|
use pumpkin_core::{
|
||||||
math::{boundingbox::BoundingBox, position::WorldPosition, vector3::Vector3},
|
math::{boundingbox::BoundingBox, position::WorldPosition, vector3::Vector3},
|
||||||
@ -26,16 +24,13 @@ use pumpkin_protocol::{
|
|||||||
ConnectionState, RawPacket, ServerPacket, VarInt,
|
ConnectionState, RawPacket, ServerPacket, VarInt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use pumpkin_protocol::server::play::SCloseContainer;
|
||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
use pumpkin_world::vector3::Vector3;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
client::{authentication::GameProfile, Client, PlayerConfig},
|
client::{authentication::GameProfile, Client, PlayerConfig},
|
||||||
server::Server,
|
server::Server,
|
||||||
world::World,
|
world::World,
|
||||||
util::boundingbox::BoundingBox
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct PlayerAbilities {
|
pub struct PlayerAbilities {
|
||||||
@ -460,6 +455,10 @@ impl Player {
|
|||||||
self.handle_click_container(server, SClickContainer::read(bytebuf)?);
|
self.handle_click_container(server, SClickContainer::read(bytebuf)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
SCloseContainer::PACKET_ID => {
|
||||||
|
self.handle_close_container(server, SCloseContainer::read(bytebuf)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::error!("Failed to handle player packet id {:#04x}", packet.id.0);
|
log::error!("Failed to handle player packet id {:#04x}", packet.id.0);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -1,13 +1,3 @@
|
|||||||
use std::{
|
|
||||||
io::Cursor,
|
|
||||||
path::Path,
|
|
||||||
sync::{
|
|
||||||
atomic::{AtomicI32, Ordering},
|
|
||||||
Arc, Mutex,
|
|
||||||
},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use base64::{engine::general_purpose, Engine};
|
use base64::{engine::general_purpose, Engine};
|
||||||
use image::GenericImageView;
|
use image::GenericImageView;
|
||||||
use mio::Token;
|
use mio::Token;
|
||||||
@ -20,19 +10,21 @@ use pumpkin_protocol::{
|
|||||||
CURRENT_MC_PROTOCOL,
|
CURRENT_MC_PROTOCOL,
|
||||||
};
|
};
|
||||||
use pumpkin_world::dimension::Dimension;
|
use pumpkin_world::dimension::Dimension;
|
||||||
|
use std::collections::HashMap;
|
||||||
use crate::{
|
use std::{
|
||||||
client::Client,
|
io::Cursor,
|
||||||
config::{AdvancedConfiguration, BasicConfiguration},
|
path::Path,
|
||||||
entity::player::{GameMode, Player},
|
sync::{
|
||||||
world::World,
|
atomic::{AtomicI32, Ordering},
|
||||||
|
Arc, Mutex, MutexGuard,
|
||||||
|
},
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::{client::Client, entity::player::Player, world::World};
|
||||||
use pumpkin_inventory::{Container, OpenContainer};
|
use pumpkin_inventory::{Container, OpenContainer};
|
||||||
use pumpkin_registry::Registry;
|
use pumpkin_registry::Registry;
|
||||||
use rsa::{traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
|
use rsa::{traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use tokio::sync::mpsc;
|
|
||||||
|
|
||||||
|
|
||||||
pub const CURRENT_MC_VERSION: &str = "1.21.1";
|
pub const CURRENT_MC_VERSION: &str = "1.21.1";
|
||||||
|
|
||||||
@ -55,7 +47,6 @@ pub struct Server {
|
|||||||
/// Cache the registry so we don't have to parse it every time a player joins
|
/// Cache the registry so we don't have to parse it every time a player joins
|
||||||
pub cached_registry: Vec<Registry>,
|
pub cached_registry: Vec<Registry>,
|
||||||
|
|
||||||
pub current_players: HashMap<Arc<Token>, Arc<Mutex<Player>>>,
|
|
||||||
pub open_containers: HashMap<u64, OpenContainer>,
|
pub open_containers: HashMap<u64, OpenContainer>,
|
||||||
entity_id: AtomicI32,
|
entity_id: AtomicI32,
|
||||||
|
|
||||||
@ -102,6 +93,7 @@ impl Server {
|
|||||||
Self {
|
Self {
|
||||||
plugin_loader,
|
plugin_loader,
|
||||||
cached_registry: Registry::get_static(),
|
cached_registry: Registry::get_static(),
|
||||||
|
open_containers: HashMap::new(),
|
||||||
// 0 is invalid
|
// 0 is invalid
|
||||||
entity_id: 2.into(),
|
entity_id: 2.into(),
|
||||||
worlds: vec![Arc::new(tokio::sync::Mutex::new(world))],
|
worlds: vec![Arc::new(tokio::sync::Mutex::new(world))],
|
||||||
@ -111,8 +103,6 @@ impl Server {
|
|||||||
status_response,
|
status_response,
|
||||||
status_response_json,
|
status_response_json,
|
||||||
public_key_der,
|
public_key_der,
|
||||||
open_containers: HashMap::new(),
|
|
||||||
base_config: config.0,
|
|
||||||
auth_client,
|
auth_client,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,188 +124,20 @@ impl Server {
|
|||||||
client,
|
client,
|
||||||
world.clone(),
|
world.clone(),
|
||||||
entity_id,
|
entity_id,
|
||||||
self.base_config.hardcore,
|
gamemode,
|
||||||
&["minecraft:overworld"],
|
)));
|
||||||
self.base_config.max_players.into(),
|
world.lock().await.add_player(token, player.clone());
|
||||||
self.base_config.view_distance.into(), // TODO: view distance
|
(player, world)
|
||||||
self.base_config.simulation_distance.into(), // TODO: sim view dinstance
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
0.into(),
|
|
||||||
"minecraft:overworld",
|
|
||||||
0, // seed
|
|
||||||
gamemode.to_u8().unwrap(),
|
|
||||||
self.base_config.default_gamemode.to_i8().unwrap(),
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
None,
|
|
||||||
0.into(),
|
|
||||||
false,
|
|
||||||
));
|
|
||||||
dbg!("sending abilities");
|
|
||||||
// player abilities
|
|
||||||
player
|
|
||||||
.client
|
|
||||||
.send_packet(&CPlayerAbilities::new(0x02, 0.1, 0.1));
|
|
||||||
|
|
||||||
// teleport
|
|
||||||
let x = 10.0;
|
|
||||||
let y = 120.0;
|
|
||||||
let z = 10.0;
|
|
||||||
let yaw = 10.0;
|
|
||||||
let pitch = 10.0;
|
|
||||||
player.teleport(x, y, z, 10.0, 10.0);
|
|
||||||
let gameprofile = &player.gameprofile;
|
|
||||||
// first send info update to our new player, So he can see his Skin
|
|
||||||
// also send his info to everyone else
|
|
||||||
self.broadcast_packet(
|
|
||||||
player,
|
|
||||||
&CPlayerInfoUpdate::new(
|
|
||||||
0x01 | 0x08,
|
|
||||||
&[pumpkin_protocol::client::play::Player {
|
|
||||||
uuid: gameprofile.id,
|
|
||||||
actions: vec![
|
|
||||||
PlayerAction::AddPlayer {
|
|
||||||
name: gameprofile.name.clone(),
|
|
||||||
properties: gameprofile.properties.clone(),
|
|
||||||
},
|
|
||||||
PlayerAction::UpdateListed(true),
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// here we send all the infos of already joined players
|
|
||||||
let mut entries = Vec::new();
|
|
||||||
for (_, playerr) in self
|
|
||||||
.current_players
|
|
||||||
.iter()
|
|
||||||
.filter(|c| c.0 != &player.client.token)
|
|
||||||
{
|
|
||||||
let playerr = playerr.as_ref().lock().unwrap();
|
|
||||||
let gameprofile = &playerr.gameprofile;
|
|
||||||
entries.push(pumpkin_protocol::client::play::Player {
|
|
||||||
uuid: gameprofile.id,
|
|
||||||
actions: vec![
|
|
||||||
PlayerAction::AddPlayer {
|
|
||||||
name: gameprofile.name.clone(),
|
|
||||||
properties: gameprofile.properties.clone(),
|
|
||||||
},
|
|
||||||
PlayerAction::UpdateListed(true),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
player
|
|
||||||
.client
|
|
||||||
.send_packet(&CPlayerInfoUpdate::new(0x01 | 0x08, &entries));
|
|
||||||
|
|
||||||
// Start waiting for level chunks
|
|
||||||
player.client.send_packet(&CGameEvent::new(13, 0.0));
|
|
||||||
|
|
||||||
let gameprofile = &player.gameprofile;
|
|
||||||
|
|
||||||
// spawn player for every client
|
|
||||||
self.broadcast_packet_except(
|
|
||||||
&[&player.client.token],
|
|
||||||
// TODO: add velo
|
|
||||||
&CSpawnEntity::new(
|
|
||||||
entity_id.into(),
|
|
||||||
UUID(gameprofile.id),
|
|
||||||
(EntityType::Player as i32).into(),
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
z,
|
|
||||||
pitch,
|
|
||||||
yaw,
|
|
||||||
yaw,
|
|
||||||
0.into(),
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
// spawn players for our client
|
|
||||||
let token = player.client.token.clone();
|
|
||||||
for (_, existing_player) in self.current_players.iter().filter(|c| c.0 != &token) {
|
|
||||||
let existing_player = existing_player.as_ref().lock().unwrap();
|
|
||||||
let entity = &existing_player.entity;
|
|
||||||
let gameprofile = &existing_player.gameprofile;
|
|
||||||
player.client.send_packet(&CSpawnEntity::new(
|
|
||||||
existing_player.entity_id().into(),
|
|
||||||
UUID(gameprofile.id),
|
|
||||||
EntityType::Player.to_i32().unwrap().into(),
|
|
||||||
entity.x,
|
|
||||||
entity.y,
|
|
||||||
entity.z,
|
|
||||||
entity.yaw,
|
|
||||||
entity.pitch,
|
|
||||||
entity.pitch,
|
|
||||||
0.into(),
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
// entity meta data
|
|
||||||
if let Some(config) = player.client.config.as_ref() {
|
|
||||||
self.broadcast_packet(
|
|
||||||
player,
|
|
||||||
&CSetEntityMetadata::new(
|
|
||||||
entity_id.into(),
|
|
||||||
Metadata::new(17, VarInt(0), config.skin_parts),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.spawn_test_chunk(player, self.base_config.view_distance as u32)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TODO: This definitly should be in world
|
|
||||||
pub fn get_by_entityid(&self, from: &Player, id: EntityId) -> Option<MutexGuard<Player>> {
|
|
||||||
for (_, player) in self
|
|
||||||
.current_players
|
|
||||||
.iter()
|
|
||||||
.filter(|c| c.0 != &from.client.token)
|
|
||||||
{
|
|
||||||
let player = player.lock().unwrap();
|
|
||||||
if player.entity_id() == id {
|
|
||||||
return Some(player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_get_container(
|
pub fn try_get_container(
|
||||||
&self,
|
&self,
|
||||||
player_id: EntityId,
|
player_id: EntityId,
|
||||||
container_id: u64,
|
container_id: u64,
|
||||||
) -> Option<MutexGuard<Box<dyn Container>>> {
|
) -> Option<MutexGuard<'_, Box<dyn Container>>> {
|
||||||
self.open_containers.get(&container_id)?.try_open(player_id)
|
self.open_containers.get(&container_id)?.try_open(player_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a Packet to all Players
|
|
||||||
pub fn broadcast_packet<P>(&self, from: &mut Player, packet: &P)
|
|
||||||
where
|
|
||||||
P: ClientPacket,
|
|
||||||
{
|
|
||||||
// we can't borrow twice at same time
|
|
||||||
from.client.send_packet(packet);
|
|
||||||
for (_, player) in self
|
|
||||||
.current_players
|
|
||||||
.iter()
|
|
||||||
.filter(|c| c.0 != &from.client.token)
|
|
||||||
{
|
|
||||||
let mut player = player.lock().unwrap();
|
|
||||||
player.client.send_packet(packet);
|
|
||||||
}
|
|
||||||
gamemode,
|
|
||||||
)));
|
|
||||||
world.lock().await.add_player(token, player.clone());
|
|
||||||
(player, world)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends a Packet to all Players in all worlds
|
/// Sends a Packet to all Players in all worlds
|
||||||
pub fn broadcast_packet_all<P>(&self, expect: &[&Arc<Token>], packet: &P)
|
pub fn broadcast_packet_all<P>(&self, expect: &[&Arc<Token>], packet: &P)
|
||||||
where
|
where
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user