feat: add bedrock forms
This commit is contained in:
parent
f383c88c76
commit
5aafff35e8
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -2965,6 +2965,8 @@ name = "pumpkin-plugin-api"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"postcard",
|
"postcard",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-serde-structured",
|
"tracing-serde-structured",
|
||||||
"wit-bindgen 0.57.1",
|
"wit-bindgen 0.57.1",
|
||||||
|
|||||||
@ -393,7 +393,7 @@ impl ToTokens for BlockPropertyStruct {
|
|||||||
|
|
||||||
fn to_state_id(&self, block: &Block) -> u16 {
|
fn to_state_id(&self, block: &Block) -> u16 {
|
||||||
if !Self::handles_block_id(block.id) {
|
if !Self::handles_block_id(block.id) {
|
||||||
panic!("{} is not a valid block for {}", &block.name, #struct_name);
|
panic!("{} is not a valid block for {}", block.name, #struct_name);
|
||||||
}
|
}
|
||||||
block.states[0].id + self.to_index()
|
block.states[0].id + self.to_index()
|
||||||
}
|
}
|
||||||
@ -401,7 +401,7 @@ impl ToTokens for BlockPropertyStruct {
|
|||||||
fn from_state_id(state_id: u16, block: &Block) -> Self {
|
fn from_state_id(state_id: u16, block: &Block) -> Self {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
Self::handles_block_id(block.id),
|
Self::handles_block_id(block.id),
|
||||||
"{} is not a valid block for {}", &block.name, #struct_name
|
"{} is not a valid block for {}", block.name, #struct_name
|
||||||
);
|
);
|
||||||
|
|
||||||
let min_id = block.states[0].id;
|
let min_id = block.states[0].id;
|
||||||
@ -420,7 +420,7 @@ impl ToTokens for BlockPropertyStruct {
|
|||||||
|
|
||||||
fn default(block: &Block) -> Self {
|
fn default(block: &Block) -> Self {
|
||||||
if !Self::handles_block_id(block.id) {
|
if !Self::handles_block_id(block.id) {
|
||||||
panic!("{} is not a valid block for {}", &block.name, #struct_name);
|
panic!("{} is not a valid block for {}", block.name, #struct_name);
|
||||||
}
|
}
|
||||||
Self::from_state_id(block.default_state.id, block)
|
Self::from_state_id(block.default_state.id, block)
|
||||||
}
|
}
|
||||||
@ -433,7 +433,7 @@ impl ToTokens for BlockPropertyStruct {
|
|||||||
fn from_props(props: &[(&str, &str)], block: &Block) -> Self {
|
fn from_props(props: &[(&str, &str)], block: &Block) -> Self {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
if !matches!(block.id, #(#block_ids)|*) {
|
if !matches!(block.id, #(#block_ids)|*) {
|
||||||
panic!("{} is not a valid block for {}", &block.name, #struct_name);
|
panic!("{} is not a valid block for {}", block.name, #struct_name);
|
||||||
}
|
}
|
||||||
let mut block_props = Self::default(block);
|
let mut block_props = Self::default(block);
|
||||||
for (key, value) in props {
|
for (key, value) in props {
|
||||||
|
|||||||
@ -13,9 +13,6 @@ uuid.workspace = true
|
|||||||
|
|
||||||
toml.workspace = true
|
toml.workspace = true
|
||||||
|
|
||||||
[features]
|
|
||||||
# Adds helper to change the config at runtime
|
|
||||||
test_helper = []
|
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -907,7 +907,7 @@ impl FluidProperties for WaterLikeFluidProperties {
|
|||||||
if !["water", "lava"].contains(&fluid.name) {
|
if !["water", "lava"].contains(&fluid.name) {
|
||||||
panic!(
|
panic!(
|
||||||
"{} is not a valid fluid for {}",
|
"{} is not a valid fluid for {}",
|
||||||
&fluid.name, "WaterLikeFluidProperties"
|
fluid.name, "WaterLikeFluidProperties"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let prop_index = self.to_index();
|
let prop_index = self.to_index();
|
||||||
@ -921,7 +921,7 @@ impl FluidProperties for WaterLikeFluidProperties {
|
|||||||
if !["water", "lava"].contains(&fluid.name) {
|
if !["water", "lava"].contains(&fluid.name) {
|
||||||
panic!(
|
panic!(
|
||||||
"{} is not a valid fluid for {}",
|
"{} is not a valid fluid for {}",
|
||||||
&fluid.name, "WaterLikeFluidProperties"
|
fluid.name, "WaterLikeFluidProperties"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for (idx, state) in fluid.states.iter().enumerate() {
|
for (idx, state) in fluid.states.iter().enumerate() {
|
||||||
@ -935,7 +935,7 @@ impl FluidProperties for WaterLikeFluidProperties {
|
|||||||
if !["water", "lava"].contains(&fluid.name) {
|
if !["water", "lava"].contains(&fluid.name) {
|
||||||
panic!(
|
panic!(
|
||||||
"{} is not a valid fluid for {}",
|
"{} is not a valid fluid for {}",
|
||||||
&fluid.name, "WaterLikeFluidProperties"
|
fluid.name, "WaterLikeFluidProperties"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Self::from_state_id(fluid.default_state_index, fluid)
|
Self::from_state_id(fluid.default_state_index, fluid)
|
||||||
@ -947,7 +947,7 @@ impl FluidProperties for WaterLikeFluidProperties {
|
|||||||
if !["water", "lava"].contains(&fluid.name) {
|
if !["water", "lava"].contains(&fluid.name) {
|
||||||
panic!(
|
panic!(
|
||||||
"{} is not a valid fluid for {}",
|
"{} is not a valid fluid for {}",
|
||||||
&fluid.name, "WaterLikeFluidProperties"
|
fluid.name, "WaterLikeFluidProperties"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let mut fluid_props = Self::default(fluid);
|
let mut fluid_props = Self::default(fluid);
|
||||||
@ -995,7 +995,7 @@ impl FluidProperties for FlowingWaterLikeFluidProperties {
|
|||||||
if !["flowing_water", "flowing_lava"].contains(&fluid.name) {
|
if !["flowing_water", "flowing_lava"].contains(&fluid.name) {
|
||||||
panic!(
|
panic!(
|
||||||
"{} is not a valid fluid for {}",
|
"{} is not a valid fluid for {}",
|
||||||
&fluid.name, "FlowingWaterLikeFluidProperties"
|
fluid.name, "FlowingWaterLikeFluidProperties"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let prop_index = self.to_index();
|
let prop_index = self.to_index();
|
||||||
@ -1009,7 +1009,7 @@ impl FluidProperties for FlowingWaterLikeFluidProperties {
|
|||||||
if !["flowing_water", "flowing_lava"].contains(&fluid.name) {
|
if !["flowing_water", "flowing_lava"].contains(&fluid.name) {
|
||||||
panic!(
|
panic!(
|
||||||
"{} is not a valid fluid for {}",
|
"{} is not a valid fluid for {}",
|
||||||
&fluid.name, "FlowingWaterLikeFluidProperties"
|
fluid.name, "FlowingWaterLikeFluidProperties"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for (idx, state) in fluid.states.iter().enumerate() {
|
for (idx, state) in fluid.states.iter().enumerate() {
|
||||||
@ -1023,7 +1023,7 @@ impl FluidProperties for FlowingWaterLikeFluidProperties {
|
|||||||
if !["flowing_water", "flowing_lava"].contains(&fluid.name) {
|
if !["flowing_water", "flowing_lava"].contains(&fluid.name) {
|
||||||
panic!(
|
panic!(
|
||||||
"{} is not a valid fluid for {}",
|
"{} is not a valid fluid for {}",
|
||||||
&fluid.name, "FlowingWaterLikeFluidProperties"
|
fluid.name, "FlowingWaterLikeFluidProperties"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Self::from_state_id(fluid.default_state_index, fluid)
|
Self::from_state_id(fluid.default_state_index, fluid)
|
||||||
@ -1038,7 +1038,7 @@ impl FluidProperties for FlowingWaterLikeFluidProperties {
|
|||||||
if !["flowing_water", "flowing_lava"].contains(&fluid.name) {
|
if !["flowing_water", "flowing_lava"].contains(&fluid.name) {
|
||||||
panic!(
|
panic!(
|
||||||
"{} is not a valid fluid for {}",
|
"{} is not a valid fluid for {}",
|
||||||
&fluid.name, "FlowingWaterLikeFluidProperties"
|
fluid.name, "FlowingWaterLikeFluidProperties"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let mut fluid_props = Self::default(fluid);
|
let mut fluid_props = Self::default(fluid);
|
||||||
|
|||||||
@ -10,6 +10,8 @@ wit-bindgen = { workspace = true }
|
|||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
postcard = { workspace = true }
|
postcard = { workspace = true }
|
||||||
tracing-serde-structured = { workspace = true }
|
tracing-serde-structured = { workspace = true }
|
||||||
|
serde = { workspace = true }
|
||||||
|
serde_json = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.component]
|
[package.metadata.component]
|
||||||
target = { path = "../pumpkin-plugin-wit" }
|
target = { path = "../pumpkin-plugin-wit" }
|
||||||
|
|||||||
@ -0,0 +1,21 @@
|
|||||||
|
use crate::wit::pumpkin::plugin::event::{BedrockFormResponseEventData, Event, EventType};
|
||||||
|
|
||||||
|
use super::super::FromIntoEvent;
|
||||||
|
|
||||||
|
/// An event that occurs when a player responds to a Bedrock custom form.
|
||||||
|
pub struct BedrockFormResponseEvent;
|
||||||
|
impl FromIntoEvent for BedrockFormResponseEvent {
|
||||||
|
const EVENT_TYPE: EventType = EventType::BedrockFormResponseEvent;
|
||||||
|
type Data = BedrockFormResponseEventData;
|
||||||
|
|
||||||
|
fn data_from_event(event: Event) -> Self::Data {
|
||||||
|
match event {
|
||||||
|
Event::BedrockFormResponseEvent(data) => data,
|
||||||
|
_ => panic!("unexpected event"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn data_into_event(data: Self::Data) -> Event {
|
||||||
|
Event::BedrockFormResponseEvent(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
pub mod bedrock_form_response;
|
||||||
pub mod changed_main_hand;
|
pub mod changed_main_hand;
|
||||||
pub mod egg_throw;
|
pub mod egg_throw;
|
||||||
pub mod exp_change;
|
pub mod exp_change;
|
||||||
|
|||||||
218
pumpkin-plugin-api/src/forms.rs
Normal file
218
pumpkin-plugin-api/src/forms.rs
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
use crate::player::Player;
|
||||||
|
use crate::text::TextComponent;
|
||||||
|
use crate::wit::pumpkin::plugin::forms::{
|
||||||
|
self as wit_forms, CustomForm, CustomFormElement, Form, FormImage, ImageType, ModalForm,
|
||||||
|
SimpleForm, SimpleFormButton,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct SimpleFormBuilder {
|
||||||
|
title: TextComponent,
|
||||||
|
content: TextComponent,
|
||||||
|
buttons: Vec<SimpleFormButton>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleFormBuilder {
|
||||||
|
pub fn new(title: impl Into<TextComponent>, content: impl Into<TextComponent>) -> Self {
|
||||||
|
Self {
|
||||||
|
title: title.into(),
|
||||||
|
content: content.into(),
|
||||||
|
buttons: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn button(mut self, text: impl Into<TextComponent>, image: Option<FormImage>) -> Self {
|
||||||
|
self.buttons.push(SimpleFormButton {
|
||||||
|
text: text.into(),
|
||||||
|
image,
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Form {
|
||||||
|
Form::Simple(SimpleForm {
|
||||||
|
title: self.title,
|
||||||
|
content: self.content,
|
||||||
|
buttons: self.buttons,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ModalFormBuilder {
|
||||||
|
title: TextComponent,
|
||||||
|
content: TextComponent,
|
||||||
|
button1: TextComponent,
|
||||||
|
button2: TextComponent,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModalFormBuilder {
|
||||||
|
pub fn new(title: impl Into<TextComponent>, content: impl Into<TextComponent>) -> Self {
|
||||||
|
Self {
|
||||||
|
title: title.into(),
|
||||||
|
content: content.into(),
|
||||||
|
button1: TextComponent::text("Yes"),
|
||||||
|
button2: TextComponent::text("No"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn button1(mut self, text: impl Into<TextComponent>) -> Self {
|
||||||
|
self.button1 = text.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn button2(mut self, text: impl Into<TextComponent>) -> Self {
|
||||||
|
self.button2 = text.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Form {
|
||||||
|
Form::Modal(ModalForm {
|
||||||
|
title: self.title,
|
||||||
|
content: self.content,
|
||||||
|
button1: self.button1,
|
||||||
|
button2: self.button2,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CustomFormBuilder {
|
||||||
|
title: TextComponent,
|
||||||
|
elements: Vec<CustomFormElement>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CustomFormBuilder {
|
||||||
|
pub fn new(title: impl Into<TextComponent>) -> Self {
|
||||||
|
Self {
|
||||||
|
title: title.into(),
|
||||||
|
elements: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn label(mut self, text: impl Into<TextComponent>) -> Self {
|
||||||
|
self.elements.push(CustomFormElement::Label(text.into()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle(mut self, text: impl Into<TextComponent>, default: bool) -> Self {
|
||||||
|
self.elements
|
||||||
|
.push(CustomFormElement::Toggle((text.into(), default)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn slider(
|
||||||
|
mut self,
|
||||||
|
text: impl Into<TextComponent>,
|
||||||
|
min: f32,
|
||||||
|
max: f32,
|
||||||
|
step: f32,
|
||||||
|
default: f32,
|
||||||
|
) -> Self {
|
||||||
|
self.elements.push(CustomFormElement::Slider((
|
||||||
|
text.into(),
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
step,
|
||||||
|
default,
|
||||||
|
)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn step_slider(
|
||||||
|
mut self,
|
||||||
|
text: impl Into<TextComponent>,
|
||||||
|
steps: Vec<String>,
|
||||||
|
default: u32,
|
||||||
|
) -> Self {
|
||||||
|
self.elements
|
||||||
|
.push(CustomFormElement::StepSlider((text.into(), steps, default)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dropdown(
|
||||||
|
mut self,
|
||||||
|
text: impl Into<TextComponent>,
|
||||||
|
options: Vec<String>,
|
||||||
|
default: u32,
|
||||||
|
) -> Self {
|
||||||
|
self.elements
|
||||||
|
.push(CustomFormElement::Dropdown((text.into(), options, default)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn input(
|
||||||
|
mut self,
|
||||||
|
text: impl Into<TextComponent>,
|
||||||
|
placeholder: impl Into<String>,
|
||||||
|
default: impl Into<String>,
|
||||||
|
) -> Self {
|
||||||
|
self.elements.push(CustomFormElement::Input((
|
||||||
|
text.into(),
|
||||||
|
placeholder.into(),
|
||||||
|
default.into(),
|
||||||
|
)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Form {
|
||||||
|
Form::Custom(CustomForm {
|
||||||
|
title: self.title,
|
||||||
|
elements: self.elements,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_form(player: Player, form: Form) -> u32 {
|
||||||
|
wit_forms::send_form(player, form)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn url_image(url: impl Into<String>) -> FormImage {
|
||||||
|
FormImage {
|
||||||
|
type_: ImageType::Url,
|
||||||
|
data: url.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_image(path: impl Into<String>) -> FormImage {
|
||||||
|
FormImage {
|
||||||
|
type_: ImageType::Path,
|
||||||
|
data: path.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum FormResponse {
|
||||||
|
Simple(u32),
|
||||||
|
Modal(bool),
|
||||||
|
Custom(Vec<serde_json::Value>),
|
||||||
|
Closed,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FormResponse {
|
||||||
|
pub fn parse(data: Option<String>) -> Self {
|
||||||
|
match data {
|
||||||
|
None => Self::Closed,
|
||||||
|
Some(s) => {
|
||||||
|
if let Ok(val) = serde_json::from_str::<serde_json::Value>(&s) {
|
||||||
|
if val.is_u64() {
|
||||||
|
Self::Simple(val.as_u64().unwrap() as u32)
|
||||||
|
} else if val.is_boolean() {
|
||||||
|
Self::Modal(val.as_bool().unwrap())
|
||||||
|
} else if val.is_array() {
|
||||||
|
Self::Custom(val.as_array().unwrap().clone())
|
||||||
|
} else {
|
||||||
|
Self::Closed // Or some error state
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Fallback for some clients that might send raw strings for simple/modal
|
||||||
|
if s == "true" {
|
||||||
|
Self::Modal(true)
|
||||||
|
} else if s == "false" {
|
||||||
|
Self::Modal(false)
|
||||||
|
} else if let Ok(idx) = s.parse::<u32>() {
|
||||||
|
Self::Simple(idx)
|
||||||
|
} else {
|
||||||
|
Self::Closed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -35,6 +35,7 @@ use crate::{
|
|||||||
|
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
|
pub mod forms;
|
||||||
/// Constants for plugin permissions.
|
/// Constants for plugin permissions.
|
||||||
///
|
///
|
||||||
/// Use these in your `PluginMetadata` to request access to specific host features.
|
/// Use these in your `PluginMetadata` to request access to specific host features.
|
||||||
|
|||||||
@ -258,6 +258,13 @@ interface event {
|
|||||||
can-build: bool,
|
can-build: bool,
|
||||||
cancelled: bool
|
cancelled: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record bedrock-form-response-event-data {
|
||||||
|
player: player,
|
||||||
|
form-id: u32,
|
||||||
|
response-data: option<string>,
|
||||||
|
}
|
||||||
|
|
||||||
record server-command-event-data {
|
record server-command-event-data {
|
||||||
command: string,
|
command: string,
|
||||||
cancelled: bool
|
cancelled: bool
|
||||||
@ -321,6 +328,7 @@ interface event {
|
|||||||
block-can-build-event,
|
block-can-build-event,
|
||||||
block-grow-event,
|
block-grow-event,
|
||||||
block-place-event,
|
block-place-event,
|
||||||
|
bedrock-form-response-event,
|
||||||
server-command-event,
|
server-command-event,
|
||||||
spawn-change-event,
|
spawn-change-event,
|
||||||
server-broadcast-event,
|
server-broadcast-event,
|
||||||
@ -358,6 +366,7 @@ interface event {
|
|||||||
block-can-build-event(block-can-build-event-data),
|
block-can-build-event(block-can-build-event-data),
|
||||||
block-grow-event(block-grow-event-data),
|
block-grow-event(block-grow-event-data),
|
||||||
block-place-event(block-place-event-data),
|
block-place-event(block-place-event-data),
|
||||||
|
bedrock-form-response-event(bedrock-form-response-event-data),
|
||||||
server-command-event(server-command-event-data),
|
server-command-event(server-command-event-data),
|
||||||
spawn-change-event(spawn-change-event-data),
|
spawn-change-event(spawn-change-event-data),
|
||||||
server-broadcast-event(server-broadcast-event-data),
|
server-broadcast-event(server-broadcast-event-data),
|
||||||
|
|||||||
54
pumpkin-plugin-wit/v0.1/forms.wit
Normal file
54
pumpkin-plugin-wit/v0.1/forms.wit
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
interface forms {
|
||||||
|
use player.{player};
|
||||||
|
use text.{text-component};
|
||||||
|
|
||||||
|
enum image-type {
|
||||||
|
url,
|
||||||
|
path,
|
||||||
|
}
|
||||||
|
|
||||||
|
record form-image {
|
||||||
|
%type: image-type,
|
||||||
|
data: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
record simple-form-button {
|
||||||
|
text: text-component,
|
||||||
|
image: option<form-image>,
|
||||||
|
}
|
||||||
|
|
||||||
|
record simple-form {
|
||||||
|
title: text-component,
|
||||||
|
content: text-component,
|
||||||
|
buttons: list<simple-form-button>,
|
||||||
|
}
|
||||||
|
|
||||||
|
record modal-form {
|
||||||
|
title: text-component,
|
||||||
|
content: text-component,
|
||||||
|
button1: text-component,
|
||||||
|
button2: text-component,
|
||||||
|
}
|
||||||
|
|
||||||
|
variant custom-form-element {
|
||||||
|
label(text-component),
|
||||||
|
toggle(tuple<text-component, bool>),
|
||||||
|
slider(tuple<text-component, f32, f32, f32, f32>), // text, min, max, step, default
|
||||||
|
step-slider(tuple<text-component, list<string>, u32>), // text, steps, default
|
||||||
|
dropdown(tuple<text-component, list<string>, u32>), // text, options, default
|
||||||
|
input(tuple<text-component, string, string>), // text, placeholder, default
|
||||||
|
}
|
||||||
|
|
||||||
|
record custom-form {
|
||||||
|
title: text-component,
|
||||||
|
elements: list<custom-form-element>,
|
||||||
|
}
|
||||||
|
|
||||||
|
variant form {
|
||||||
|
simple(simple-form),
|
||||||
|
modal(modal-form),
|
||||||
|
custom(custom-form),
|
||||||
|
}
|
||||||
|
|
||||||
|
send-form: func(player: player, form: form) -> u32;
|
||||||
|
}
|
||||||
@ -35,6 +35,8 @@ world plugin {
|
|||||||
import entity;
|
import entity;
|
||||||
/// Provides boss bar creation and management.
|
/// Provides boss bar creation and management.
|
||||||
import boss-bar;
|
import boss-bar;
|
||||||
|
/// Provides Bedrock custom forms.
|
||||||
|
import forms;
|
||||||
|
|
||||||
// --- Plugin-provided exports ---
|
// --- Plugin-provided exports ---
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ pub mod handshake;
|
|||||||
pub mod inventory_content;
|
pub mod inventory_content;
|
||||||
pub mod level_chunk;
|
pub mod level_chunk;
|
||||||
pub mod level_event;
|
pub mod level_event;
|
||||||
|
pub mod modal_form_request;
|
||||||
pub mod move_player;
|
pub mod move_player;
|
||||||
pub mod network_chunk_publisher_update;
|
pub mod network_chunk_publisher_update;
|
||||||
pub mod network_settings;
|
pub mod network_settings;
|
||||||
@ -38,6 +39,7 @@ pub use handshake::*;
|
|||||||
pub use inventory_content::*;
|
pub use inventory_content::*;
|
||||||
pub use level_chunk::*;
|
pub use level_chunk::*;
|
||||||
pub use level_event::*;
|
pub use level_event::*;
|
||||||
|
pub use modal_form_request::*;
|
||||||
pub use move_player::*;
|
pub use move_player::*;
|
||||||
pub use network_chunk_publisher_update::*;
|
pub use network_chunk_publisher_update::*;
|
||||||
pub use network_settings::*;
|
pub use network_settings::*;
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
use crate::{codec::var_int::VarInt, serial::PacketWrite};
|
||||||
|
use pumpkin_macros::packet;
|
||||||
|
|
||||||
|
#[packet(100)]
|
||||||
|
#[derive(PacketWrite)]
|
||||||
|
pub struct CModalFormRequest {
|
||||||
|
pub form_id: VarInt,
|
||||||
|
pub form_data: String,
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ pub mod container_close;
|
|||||||
pub mod interaction;
|
pub mod interaction;
|
||||||
pub mod loading_screen;
|
pub mod loading_screen;
|
||||||
pub mod login;
|
pub mod login;
|
||||||
|
pub mod modal_form_response;
|
||||||
pub mod player_action;
|
pub mod player_action;
|
||||||
pub mod player_auth_input;
|
pub mod player_auth_input;
|
||||||
pub mod raknet;
|
pub mod raknet;
|
||||||
|
|||||||
18
pumpkin-protocol/src/bedrock/server/modal_form_response.rs
Normal file
18
pumpkin-protocol/src/bedrock/server/modal_form_response.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use crate::codec::var_int::VarInt;
|
||||||
|
use crate::serial::PacketRead;
|
||||||
|
use pumpkin_macros::packet;
|
||||||
|
use std::io::{Error, Read};
|
||||||
|
|
||||||
|
#[packet(101)]
|
||||||
|
pub struct SModalFormResponse {
|
||||||
|
pub form_id: VarInt,
|
||||||
|
pub form_data: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PacketRead for SModalFormResponse {
|
||||||
|
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||||
|
let form_id = VarInt::read(reader)?;
|
||||||
|
let form_data = Option::<String>::read(reader)?;
|
||||||
|
Ok(Self { form_id, form_data })
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -110,7 +110,7 @@ impl<'de, T: Deserialize<'de>> Visitor<'de> for IdOrVisitor<T> {
|
|||||||
})?);
|
})?);
|
||||||
}
|
}
|
||||||
IdOrStateDeserializer::Id(id) => {
|
IdOrStateDeserializer::Id(id) => {
|
||||||
debug_assert!(*id == 0);
|
debug_assert_eq!(*id, 0);
|
||||||
// Get the data
|
// Get the data
|
||||||
let value = T::deserialize(deserializer)?;
|
let value = T::deserialize(deserializer)?;
|
||||||
*self = IdOrStateDeserializer::Value(value);
|
*self = IdOrStateDeserializer::Value(value);
|
||||||
|
|||||||
@ -226,7 +226,6 @@ impl PerlinNoiseSampler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Data for a single octave in an octave Perlin noise sampler.
|
/// Data for a single octave in an octave Perlin noise sampler.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct SamplerData {
|
pub struct SamplerData {
|
||||||
/// The Perlin noise sampler for this octave.
|
/// The Perlin noise sampler for this octave.
|
||||||
pub sampler: PerlinNoiseSampler,
|
pub sampler: PerlinNoiseSampler,
|
||||||
@ -243,7 +242,6 @@ pub struct SamplerData {
|
|||||||
/// Octave noise, also known as fractal noise, combines multiple octaves of Perlin noise
|
/// Octave noise, also known as fractal noise, combines multiple octaves of Perlin noise
|
||||||
/// with different frequencies and amplitudes to create more complex, natural-looking patterns.
|
/// with different frequencies and amplitudes to create more complex, natural-looking patterns.
|
||||||
/// Each octave adds finer detail to the overall noise.
|
/// Each octave adds finer detail to the overall noise.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct OctavePerlinNoiseSampler {
|
pub struct OctavePerlinNoiseSampler {
|
||||||
/// The list of samplers for each octave, with their associated parameters.
|
/// The list of samplers for each octave, with their associated parameters.
|
||||||
pub samplers: Box<[SamplerData]>,
|
pub samplers: Box<[SamplerData]>,
|
||||||
|
|||||||
@ -216,7 +216,6 @@ impl RandomImpl for Xoroshiro {
|
|||||||
/// This struct allows for deterministic creation of multiple independent
|
/// This struct allows for deterministic creation of multiple independent
|
||||||
/// random generators from a single seed, which is essential for
|
/// random generators from a single seed, which is essential for
|
||||||
/// parallelizable world generation.
|
/// parallelizable world generation.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct XoroshiroSplitter {
|
pub struct XoroshiroSplitter {
|
||||||
/// Lower 64 bits of the splitter state.
|
/// Lower 64 bits of the splitter state.
|
||||||
lo: u64,
|
lo: u64,
|
||||||
|
|||||||
@ -79,8 +79,6 @@ harness = false
|
|||||||
name = "noise_router"
|
name = "noise_router"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[features]
|
|
||||||
tokio_taskdump = []
|
|
||||||
|
|
||||||
# [lints]
|
# [lints]
|
||||||
# workspace = true
|
# workspace = true
|
||||||
|
|||||||
@ -19,7 +19,6 @@ pub trait BiomeSupplier {
|
|||||||
fn biome(&self, x: i32, y: i32, z: i32, noise: &mut MultiNoiseSampler<'_>) -> &'static Biome;
|
fn biome(&self, x: i32, y: i32, z: i32, noise: &mut MultiNoiseSampler<'_>) -> &'static Biome;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct MultiNoiseBiomeSupplier {
|
pub struct MultiNoiseBiomeSupplier {
|
||||||
source: &'static BiomeTree,
|
source: &'static BiomeTree,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ pub const fn to_long(float: f32) -> i64 {
|
|||||||
(float * 10000f32) as i64
|
(float * 10000f32) as i64
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||||
pub struct NoiseValuePoint {
|
pub struct NoiseValuePoint {
|
||||||
pub temperature: i64,
|
pub temperature: i64,
|
||||||
pub humidity: i64,
|
pub humidity: i64,
|
||||||
|
|||||||
@ -586,42 +586,42 @@ impl GenerationSchedule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_all_chunk(&self, save_proto_chunk: bool) {
|
fn save_all_chunk(&mut self, save_proto_chunk: bool) {
|
||||||
let mut chunks = Vec::with_capacity(self.chunk_map.len());
|
let mut chunks = Vec::with_capacity(self.chunk_map.len());
|
||||||
for (pos, holder) in &self.chunk_map {
|
|
||||||
if let Some(chunk) = &holder.chunk {
|
for (pos, holder) in self.chunk_map.iter_mut() {
|
||||||
match chunk {
|
if let Some(chunk) = holder.chunk.take() {
|
||||||
Chunk::Level(sync_chunk) => {
|
let should_save = match &chunk {
|
||||||
if sync_chunk.is_dirty() {
|
Chunk::Level(sync_chunk) => sync_chunk.is_dirty(),
|
||||||
chunks.push((*pos, Chunk::Level(sync_chunk.clone())));
|
Chunk::Proto(_) => save_proto_chunk,
|
||||||
}
|
};
|
||||||
}
|
|
||||||
Chunk::Proto(proto) => {
|
if should_save {
|
||||||
if save_proto_chunk {
|
chunks.push((*pos, chunk));
|
||||||
chunks.push((*pos, Chunk::Proto(proto.clone())));
|
} else {
|
||||||
}
|
holder.chunk = Some(chunk);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if chunks.is_empty() {
|
if chunks.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Saving {} chunks (collected from {} holders)...",
|
"Saving {} chunks (collected from {} holders)...",
|
||||||
chunks.len(),
|
chunks.len(),
|
||||||
self.chunk_map.len()
|
self.chunk_map.len()
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut data = self.io_lock.0.lock().unwrap();
|
let mut data = self.io_lock.0.lock().unwrap();
|
||||||
for (pos, _chunk) in &chunks {
|
for (pos, _) in &chunks {
|
||||||
*data.entry(*pos).or_insert(0) += 1;
|
*data.entry(*pos).or_insert(0) += 1;
|
||||||
}
|
}
|
||||||
drop(data);
|
drop(data);
|
||||||
|
|
||||||
if let Err(e) = self.io_write.send(chunks) {
|
if let Err(e) = self.io_write.send(chunks) {
|
||||||
error!(
|
error!("Failed to send chunks to io write thread: {:?}", e);
|
||||||
"Failed to send chunks to io write thread during unload (may have shut down): {:?}",
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
#[derive(Clone)]
|
|
||||||
pub struct CarvingMask {
|
pub struct CarvingMask {
|
||||||
min_y: i32,
|
min_y: i32,
|
||||||
mask: Vec<u64>,
|
mask: Vec<u64>,
|
||||||
|
|||||||
@ -12,7 +12,6 @@ pub struct SpringFeatureFeature {
|
|||||||
pub valid_blocks: BlockWrapper,
|
pub valid_blocks: BlockWrapper,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum BlockWrapper {
|
pub enum BlockWrapper {
|
||||||
Single(String),
|
Single(String),
|
||||||
Multi(Vec<String>),
|
Multi(Vec<String>),
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
use pumpkin_data::chunk::DoublePerlinNoiseParameters;
|
use pumpkin_data::chunk::DoublePerlinNoiseParameters;
|
||||||
use pumpkin_util::{noise::perlin::OctavePerlinNoiseSampler, random::RandomImpl};
|
use pumpkin_util::{noise::perlin::OctavePerlinNoiseSampler, random::RandomImpl};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct DoublePerlinNoiseSampler {
|
pub struct DoublePerlinNoiseSampler {
|
||||||
first_sampler: OctavePerlinNoiseSampler,
|
first_sampler: OctavePerlinNoiseSampler,
|
||||||
second_sampler: OctavePerlinNoiseSampler,
|
second_sampler: OctavePerlinNoiseSampler,
|
||||||
|
|||||||
@ -472,7 +472,6 @@ impl FlatCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Cache2D {
|
pub struct Cache2D {
|
||||||
pub(crate) input_index: usize,
|
pub(crate) input_index: usize,
|
||||||
last_sample_column: u64,
|
last_sample_column: u64,
|
||||||
|
|||||||
@ -10,7 +10,6 @@ use super::{
|
|||||||
IndexToNoisePos, NoiseFunctionComponentRange, StaticIndependentChunkNoiseFunctionComponentImpl,
|
IndexToNoisePos, NoiseFunctionComponentRange, StaticIndependentChunkNoiseFunctionComponentImpl,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Constant {
|
pub struct Constant {
|
||||||
value: f64,
|
value: f64,
|
||||||
}
|
}
|
||||||
@ -43,7 +42,6 @@ impl StaticIndependentChunkNoiseFunctionComponentImpl for Constant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Linear {
|
pub struct Linear {
|
||||||
pub(crate) input_index: usize,
|
pub(crate) input_index: usize,
|
||||||
min_value: f64,
|
min_value: f64,
|
||||||
@ -95,7 +93,6 @@ impl Linear {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Binary {
|
pub struct Binary {
|
||||||
pub(crate) input1_index: usize,
|
pub(crate) input1_index: usize,
|
||||||
pub(crate) input2_index: usize,
|
pub(crate) input2_index: usize,
|
||||||
@ -275,7 +272,6 @@ impl Binary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Unary {
|
pub struct Unary {
|
||||||
pub(crate) input_index: usize,
|
pub(crate) input_index: usize,
|
||||||
min_value: f64,
|
min_value: f64,
|
||||||
@ -345,7 +341,6 @@ impl Unary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Clamp {
|
pub struct Clamp {
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
data: &'static ClampData,
|
data: &'static ClampData,
|
||||||
|
|||||||
@ -21,7 +21,6 @@ use super::{
|
|||||||
IndexToNoisePos, NoiseFunctionComponentRange, StaticIndependentChunkNoiseFunctionComponentImpl,
|
IndexToNoisePos, NoiseFunctionComponentRange, StaticIndependentChunkNoiseFunctionComponentImpl,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct EndIsland {
|
pub struct EndIsland {
|
||||||
sampler: Arc<SimplexNoiseSampler>,
|
sampler: Arc<SimplexNoiseSampler>,
|
||||||
}
|
}
|
||||||
@ -170,7 +169,6 @@ impl NoiseFunctionComponentRange for WeirdScaled {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ClampedYGradient {
|
pub struct ClampedYGradient {
|
||||||
data: &'static ClampedYGradientData,
|
data: &'static ClampedYGradientData,
|
||||||
}
|
}
|
||||||
@ -205,7 +203,6 @@ impl StaticIndependentChunkNoiseFunctionComponentImpl for ClampedYGradient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct RangeChoice {
|
pub struct RangeChoice {
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
pub(crate) when_in_index: usize,
|
pub(crate) when_in_index: usize,
|
||||||
|
|||||||
@ -43,7 +43,6 @@ pub trait StaticIndependentChunkNoiseFunctionComponentImpl: NoiseFunctionCompone
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Wrapper {
|
pub struct Wrapper {
|
||||||
pub input_index: usize,
|
pub input_index: usize,
|
||||||
pub wrapper_type: WrapperType,
|
pub wrapper_type: WrapperType,
|
||||||
|
|||||||
@ -8,7 +8,6 @@ use crate::generation::noise::router::{
|
|||||||
|
|
||||||
use super::NoiseFunctionComponentRange;
|
use super::NoiseFunctionComponentRange;
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum SplineValue {
|
pub enum SplineValue {
|
||||||
Spline(Spline),
|
Spline(Spline),
|
||||||
Fixed(f32),
|
Fixed(f32),
|
||||||
@ -37,7 +36,6 @@ impl SplineValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct SplinePoint {
|
pub struct SplinePoint {
|
||||||
pub location: f32,
|
pub location: f32,
|
||||||
pub value: SplineValue,
|
pub value: SplineValue,
|
||||||
@ -67,7 +65,6 @@ pub enum Range {
|
|||||||
Below,
|
Below,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Spline {
|
pub struct Spline {
|
||||||
pub input_index: usize,
|
pub input_index: usize,
|
||||||
pub points: Box<[SplinePoint]>,
|
pub points: Box<[SplinePoint]>,
|
||||||
@ -201,7 +198,6 @@ impl Spline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct SplineFunction {
|
pub struct SplineFunction {
|
||||||
spline: Spline,
|
spline: Spline,
|
||||||
min_value: f64,
|
min_value: f64,
|
||||||
|
|||||||
@ -7,7 +7,6 @@ use crate::generation::noise::router::{
|
|||||||
density_function::NoiseFunctionComponentRange,
|
density_function::NoiseFunctionComponentRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct FindTopSurface {
|
pub struct FindTopSurface {
|
||||||
density_index: usize,
|
density_index: usize,
|
||||||
upper_bound_index: usize,
|
upper_bound_index: usize,
|
||||||
|
|||||||
@ -150,7 +150,6 @@ impl FluidLevelSamplerImpl for StandardChunkFluidLevelSampler {
|
|||||||
///
|
///
|
||||||
/// 12. full: Generation is done and a chunk can now be loaded. The proto-chunk is now converted to a level chunk and all block updates deferred in the above steps are executed.
|
/// 12. full: Generation is done and a chunk can now be loaded. The proto-chunk is now converted to a level chunk and all block updates deferred in the above steps are executed.
|
||||||
///
|
///
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ProtoChunk {
|
pub struct ProtoChunk {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub z: i32,
|
pub z: i32,
|
||||||
@ -162,10 +161,10 @@ pub struct ProtoChunk {
|
|||||||
/// HEIGHTMAPS
|
/// HEIGHTMAPS
|
||||||
///
|
///
|
||||||
/// Top block that is not air
|
/// Top block that is not air
|
||||||
pub flat_surface_height_map: Box<[i16]>,
|
pub flat_surface_height_map: [i16; CHUNK_AREA],
|
||||||
flat_ocean_floor_height_map: Box<[i16]>,
|
flat_ocean_floor_height_map: [i16; CHUNK_AREA],
|
||||||
pub flat_motion_blocking_height_map: Box<[i16]>,
|
pub flat_motion_blocking_height_map: [i16; CHUNK_AREA],
|
||||||
pub flat_motion_blocking_no_leaves_height_map: Box<[i16]>,
|
pub flat_motion_blocking_no_leaves_height_map: [i16; CHUNK_AREA],
|
||||||
structure_starts: FxHashMap<StructureKeys, StructureInstance>,
|
structure_starts: FxHashMap<StructureKeys, StructureInstance>,
|
||||||
|
|
||||||
// Height of the chunk for indexing
|
// Height of the chunk for indexing
|
||||||
@ -214,7 +213,7 @@ impl ProtoChunk {
|
|||||||
let height = dimension.logical_height as u16;
|
let height = dimension.logical_height as u16;
|
||||||
let section_count = (height as usize) / 16;
|
let section_count = (height as usize) / 16;
|
||||||
|
|
||||||
let default_heightmap = vec![i16::MIN; CHUNK_AREA].into_boxed_slice();
|
let default_heightmap = [i16::MIN; CHUNK_AREA];
|
||||||
Self {
|
Self {
|
||||||
x,
|
x,
|
||||||
z,
|
z,
|
||||||
@ -228,9 +227,9 @@ impl ProtoChunk {
|
|||||||
* biome_coords::from_block(height as i32) as usize
|
* biome_coords::from_block(height as i32) as usize
|
||||||
]
|
]
|
||||||
.into_boxed_slice(),
|
.into_boxed_slice(),
|
||||||
flat_surface_height_map: default_heightmap.clone(),
|
flat_surface_height_map: default_heightmap,
|
||||||
flat_ocean_floor_height_map: default_heightmap.clone(),
|
flat_ocean_floor_height_map: default_heightmap,
|
||||||
flat_motion_blocking_height_map: default_heightmap.clone(),
|
flat_motion_blocking_height_map: default_heightmap,
|
||||||
flat_motion_blocking_no_leaves_height_map: default_heightmap,
|
flat_motion_blocking_no_leaves_height_map: default_heightmap,
|
||||||
structure_starts: FxHashMap::default(),
|
structure_starts: FxHashMap::default(),
|
||||||
height,
|
height,
|
||||||
|
|||||||
@ -10,7 +10,6 @@ use crate::{
|
|||||||
|
|
||||||
pub const DEFAULT_H_POS: i32 = -1;
|
pub const DEFAULT_H_POS: i32 = -1;
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ShiftableStructurePiece {
|
pub struct ShiftableStructurePiece {
|
||||||
pub piece: StructurePiece,
|
pub piece: StructurePiece,
|
||||||
h_pos: i32,
|
h_pos: i32,
|
||||||
|
|||||||
@ -46,16 +46,11 @@ impl StructureGenerator for BuriedTreasureGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct BuriedTreasurePiece {
|
pub struct BuriedTreasurePiece {
|
||||||
piece: StructurePiece,
|
piece: StructurePiece,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructurePieceBase for BuriedTreasurePiece {
|
impl StructurePieceBase for BuriedTreasurePiece {
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn place(
|
fn place(
|
||||||
&mut self,
|
&mut self,
|
||||||
chunk: &mut ProtoChunk,
|
chunk: &mut ProtoChunk,
|
||||||
|
|||||||
@ -62,7 +62,6 @@ impl StructureGenerator for DesertPyramidGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct DesertPyramidPiece {
|
pub struct DesertPyramidPiece {
|
||||||
piece: StructurePiece,
|
piece: StructurePiece,
|
||||||
height_adjusted: bool,
|
height_adjusted: bool,
|
||||||
@ -446,10 +445,6 @@ impl DesertPyramidPiece {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StructurePieceBase for DesertPyramidPiece {
|
impl StructurePieceBase for DesertPyramidPiece {
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_structure_piece(&self) -> &StructurePiece {
|
fn get_structure_piece(&self) -> &StructurePiece {
|
||||||
&self.piece
|
&self.piece
|
||||||
}
|
}
|
||||||
|
|||||||
@ -129,7 +129,6 @@ impl StructureGenerator for IglooGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Single igloo structure piece containing dome and optional basement.
|
/// Single igloo structure piece containing dome and optional basement.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct IglooPiece {
|
pub struct IglooPiece {
|
||||||
shiftable_structure_piece: ShiftableStructurePiece,
|
shiftable_structure_piece: ShiftableStructurePiece,
|
||||||
top_template: Arc<StructureTemplate>,
|
top_template: Arc<StructureTemplate>,
|
||||||
@ -141,10 +140,6 @@ pub struct IglooPiece {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StructurePieceBase for IglooPiece {
|
impl StructurePieceBase for IglooPiece {
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn place(
|
fn place(
|
||||||
&mut self,
|
&mut self,
|
||||||
chunk: &mut ProtoChunk,
|
chunk: &mut ProtoChunk,
|
||||||
|
|||||||
@ -68,7 +68,6 @@ impl StructureGenerator for JungleTempleGenerator {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct JungleTemplePiece {
|
pub struct JungleTemplePiece {
|
||||||
// Composition: Rust uses a base struct to mimic the ScatteredFeaturePiece inheritance
|
// Composition: Rust uses a base struct to mimic the ScatteredFeaturePiece inheritance
|
||||||
piece: StructurePiece,
|
piece: StructurePiece,
|
||||||
@ -79,10 +78,6 @@ pub struct JungleTemplePiece {
|
|||||||
placed_trap_2: bool,
|
placed_trap_2: bool,
|
||||||
}
|
}
|
||||||
impl StructurePieceBase for JungleTemplePiece {
|
impl StructurePieceBase for JungleTemplePiece {
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_structure_piece(&self) -> &StructurePiece {
|
fn get_structure_piece(&self) -> &StructurePiece {
|
||||||
&self.piece
|
&self.piece
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,8 +47,6 @@ pub trait StructurePieceBase: Send + Sync {
|
|||||||
self.get_structure_piece_mut().translate(x, y, z);
|
self.get_structure_piece_mut().translate(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase>;
|
|
||||||
|
|
||||||
/// Places the blocks for this piece into the chunk.
|
/// Places the blocks for this piece into the chunk.
|
||||||
fn place(
|
fn place(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -449,10 +447,6 @@ impl StructurePiece {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StructurePieceBase for StructurePiece {
|
impl StructurePieceBase for StructurePiece {
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn place(
|
fn place(
|
||||||
&mut self,
|
&mut self,
|
||||||
_chunk: &mut ProtoChunk,
|
_chunk: &mut ProtoChunk,
|
||||||
@ -623,7 +617,6 @@ pub fn create_chunk_random(seed: i64, chunk_x: i32, chunk_z: i32) -> RandomGener
|
|||||||
RandomGenerator::Xoroshiro(Xoroshiro::from_seed(carver_seed))
|
RandomGenerator::Xoroshiro(Xoroshiro::from_seed(carver_seed))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum StructureInstance {
|
pub enum StructureInstance {
|
||||||
/// This chunk is the "owner" of the structure.
|
/// This chunk is the "owner" of the structure.
|
||||||
Start(StructurePosition),
|
Start(StructurePosition),
|
||||||
|
|||||||
@ -20,7 +20,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Straight exterior bridge segment (5 × 10 × 19).
|
/// Straight exterior bridge segment (5 × 10 × 19).
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct BridgePiece {
|
pub struct BridgePiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
}
|
}
|
||||||
@ -148,8 +147,4 @@ impl StructurePieceBase for BridgePiece {
|
|||||||
chunk, &bb, false, 4, 1, 17, 4, 4, 17, fence_west, fence_west,
|
chunk, &bb, false, 4, 1, 17, 4, 4, 17, fence_west, fence_west,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,6 @@ use crate::{
|
|||||||
|
|
||||||
/// 4-way exterior bridge crossing (19 × 10 × 19).
|
/// 4-way exterior bridge crossing (19 × 10 × 19).
|
||||||
/// Also serves as the generation start piece.
|
/// Also serves as the generation start piece.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct BridgeCrossingPiece {
|
pub struct BridgeCrossingPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
}
|
}
|
||||||
@ -182,8 +181,4 @@ impl StructurePieceBase for BridgeCrossingPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,6 @@ use crate::{
|
|||||||
/// Dead-end / terminator piece for the exterior bridge (5 × 10 × 8).
|
/// Dead-end / terminator piece for the exterior bridge (5 × 10 × 8).
|
||||||
/// Generated randomly on each side and used as a fallback when no valid piece
|
/// Generated randomly on each side and used as a fallback when no valid piece
|
||||||
/// can be placed.
|
/// can be placed.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct BridgeEndPiece {
|
pub struct BridgeEndPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
/// Seed used so the crumbling geometry is deterministic per world seed.
|
/// Seed used so the crumbling geometry is deterministic per world seed.
|
||||||
@ -113,8 +112,4 @@ impl StructurePieceBase for BridgeEndPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Exterior platform with a Blaze mob-spawner (7 × 8 × 9).
|
/// Exterior platform with a Blaze mob-spawner (7 × 8 × 9).
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct BridgePlatformPiece {
|
pub struct BridgePlatformPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
pub has_blaze_spawner: bool,
|
pub has_blaze_spawner: bool,
|
||||||
@ -163,8 +162,4 @@ impl StructurePieceBase for BridgePlatformPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Small 3-way crossing for the exterior bridge network (7 × 9 × 7).
|
/// Small 3-way crossing for the exterior bridge network (7 × 9 × 7).
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct BridgeSmallCrossingPiece {
|
pub struct BridgeSmallCrossingPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
}
|
}
|
||||||
@ -156,8 +155,4 @@ impl StructurePieceBase for BridgeSmallCrossingPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Stairway that transitions from bridge level to interior level (7 × 11 × 7).
|
/// Stairway that transitions from bridge level to interior level (7 × 11 × 7).
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct BridgeStairsPiece {
|
pub struct BridgeStairsPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
}
|
}
|
||||||
@ -142,8 +141,4 @@ impl StructurePieceBase for BridgeStairsPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Interior corridor piece with a balcony overlook (9 × 7 × 9).
|
/// Interior corridor piece with a balcony overlook (9 × 7 × 9).
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CorridorBalconyPiece {
|
pub struct CorridorBalconyPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
}
|
}
|
||||||
@ -164,8 +163,4 @@ impl StructurePieceBase for CorridorBalconyPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// 4-way interior corridor crossing (5 × 7 × 5).
|
/// 4-way interior corridor crossing (5 × 7 × 5).
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CorridorCrossingPiece {
|
pub struct CorridorCrossingPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
}
|
}
|
||||||
@ -130,8 +129,4 @@ impl StructurePieceBase for CorridorCrossingPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Large entrance tower connecting the bridge network to the interior (13 × 14 × 13).
|
/// Large entrance tower connecting the bridge network to the interior (13 × 14 × 13).
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CorridorExitPiece {
|
pub struct CorridorExitPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
}
|
}
|
||||||
@ -229,8 +228,4 @@ impl StructurePieceBase for CorridorExitPiece {
|
|||||||
// chunk.schedule_fluid_tick(&lava_pos, 0);
|
// chunk.schedule_fluid_tick(&lava_pos, 0);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Interior corridor that turns left (NW), optionally containing a chest (5 × 7 × 5).
|
/// Interior corridor that turns left (NW), optionally containing a chest (5 × 7 × 5).
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CorridorLeftTurnPiece {
|
pub struct CorridorLeftTurnPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
pub contains_chest: bool,
|
pub contains_chest: bool,
|
||||||
@ -154,8 +153,4 @@ impl StructurePieceBase for CorridorLeftTurnPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Large interior room with nether wart crops (13 × 14 × 13).
|
/// Large interior room with nether wart crops (13 × 14 × 13).
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CorridorNetherWartsRoomPiece {
|
pub struct CorridorNetherWartsRoomPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
}
|
}
|
||||||
@ -274,8 +273,4 @@ impl StructurePieceBase for CorridorNetherWartsRoomPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Interior corridor that turns right (SE), optionally containing a chest (5 × 7 × 5).
|
/// Interior corridor that turns right (SE), optionally containing a chest (5 × 7 × 5).
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CorridorRightTurnPiece {
|
pub struct CorridorRightTurnPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
pub contains_chest: bool,
|
pub contains_chest: bool,
|
||||||
@ -154,8 +153,4 @@ impl StructurePieceBase for CorridorRightTurnPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Descending interior corridor staircase (5 × 14 × 10).
|
/// Descending interior corridor staircase (5 × 14 × 10).
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CorridorStairsPiece {
|
pub struct CorridorStairsPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
}
|
}
|
||||||
@ -145,8 +144,4 @@ impl StructurePieceBase for CorridorStairsPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,8 +46,8 @@ impl StructureGenerator for NetherFortressGenerator {
|
|||||||
let start_z = section_coords::section_to_block(context.chunk_z) + 2;
|
let start_z = section_coords::section_to_block(context.chunk_z) + 2;
|
||||||
|
|
||||||
let start_piece = BridgeCrossingPiece::new_start(&mut random, start_x, start_z);
|
let start_piece = BridgeCrossingPiece::new_start(&mut random, start_x, start_z);
|
||||||
let start_box: Box<dyn crate::generation::structure::structures::StructurePieceBase> =
|
|
||||||
Box::new(start_piece.clone());
|
let base_piece = start_piece.piece.piece.clone();
|
||||||
|
|
||||||
let mut pieces_to_process: Vec<
|
let mut pieces_to_process: Vec<
|
||||||
Box<dyn crate::generation::structure::structures::StructurePieceBase>,
|
Box<dyn crate::generation::structure::structures::StructurePieceBase>,
|
||||||
@ -56,10 +56,8 @@ impl StructureGenerator for NetherFortressGenerator {
|
|||||||
let mut bridge_pieces = get_bridge_piece_weights();
|
let mut bridge_pieces = get_bridge_piece_weights();
|
||||||
let mut corridor_pieces = get_corridor_piece_weights();
|
let mut corridor_pieces = get_corridor_piece_weights();
|
||||||
|
|
||||||
collector.add_piece(start_box);
|
|
||||||
|
|
||||||
start_piece.fill_openings(
|
start_piece.fill_openings(
|
||||||
&start_piece.piece.piece,
|
&base_piece,
|
||||||
&mut random,
|
&mut random,
|
||||||
&mut bridge_pieces,
|
&mut bridge_pieces,
|
||||||
&mut corridor_pieces,
|
&mut corridor_pieces,
|
||||||
@ -67,17 +65,22 @@ impl StructureGenerator for NetherFortressGenerator {
|
|||||||
&mut pieces_to_process,
|
&mut pieces_to_process,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
collector.add_piece(Box::new(start_piece));
|
||||||
|
|
||||||
while !pieces_to_process.is_empty() {
|
while !pieces_to_process.is_empty() {
|
||||||
let idx = random.next_bounded_i32(pieces_to_process.len() as i32) as usize;
|
let idx = random.next_bounded_i32(pieces_to_process.len() as i32) as usize;
|
||||||
let piece = pieces_to_process.remove(idx);
|
let piece = pieces_to_process.remove(idx);
|
||||||
|
|
||||||
piece.fill_openings_nether(
|
piece.fill_openings_nether(
|
||||||
&start_piece.piece.piece,
|
&base_piece,
|
||||||
&mut random,
|
&mut random,
|
||||||
&mut bridge_pieces,
|
&mut bridge_pieces,
|
||||||
&mut corridor_pieces,
|
&mut corridor_pieces,
|
||||||
&mut collector,
|
&mut collector,
|
||||||
&mut pieces_to_process,
|
&mut pieces_to_process,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
collector.add_piece(piece);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(StructurePosition {
|
Some(StructurePosition {
|
||||||
@ -619,7 +622,6 @@ impl NetherFortressPiece {
|
|||||||
orientation,
|
orientation,
|
||||||
self.piece.chain_length + 1,
|
self.piece.chain_length + 1,
|
||||||
) {
|
) {
|
||||||
collector.add_piece(p.clone_box());
|
|
||||||
pieces_to_process.push(p);
|
pieces_to_process.push(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,6 @@ use crate::{
|
|||||||
|
|
||||||
/// Straight interior corridor segment (5 × 7 × 5).
|
/// Straight interior corridor segment (5 × 7 × 5).
|
||||||
/// This is also the fallback piece returned by the generation logic.
|
/// This is also the fallback piece returned by the generation logic.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct SmallCorridorPiece {
|
pub struct SmallCorridorPiece {
|
||||||
pub piece: NetherFortressPiece,
|
pub piece: NetherFortressPiece,
|
||||||
}
|
}
|
||||||
@ -122,8 +121,4 @@ impl StructurePieceBase for SmallCorridorPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -106,7 +106,6 @@ impl StructureGenerator for NetherFossilGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct NetherFossilPiece {
|
struct NetherFossilPiece {
|
||||||
shiftable_structure_piece: ShiftableStructurePiece,
|
shiftable_structure_piece: ShiftableStructurePiece,
|
||||||
template: Arc<StructureTemplate>,
|
template: Arc<StructureTemplate>,
|
||||||
@ -156,10 +155,6 @@ impl NetherFossilPiece {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StructurePieceBase for NetherFossilPiece {
|
impl StructurePieceBase for NetherFossilPiece {
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn place(
|
fn place(
|
||||||
&mut self,
|
&mut self,
|
||||||
chunk: &mut ProtoChunk,
|
chunk: &mut ProtoChunk,
|
||||||
|
|||||||
@ -19,7 +19,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ChestCorridorPiece {
|
pub struct ChestCorridorPiece {
|
||||||
pub piece: StrongholdPiece,
|
pub piece: StrongholdPiece,
|
||||||
pub chest_generated: bool,
|
pub chest_generated: bool,
|
||||||
@ -159,8 +158,4 @@ impl StructurePieceBase for ChestCorridorPiece {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CorridorPiece {
|
pub struct CorridorPiece {
|
||||||
piece: StrongholdPiece,
|
piece: StrongholdPiece,
|
||||||
left_exit: bool,
|
left_exit: bool,
|
||||||
@ -164,13 +163,8 @@ impl StructurePieceBase for CorridorPiece {
|
|||||||
inner.fill_with_outline(chunk, &box_limit, false, 4, 1, 2, 4, 3, 4, air, air);
|
inner.fill_with_outline(chunk, &box_limit, false, 4, 1, 2, 4, 3, 4, air, air);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct SmallCorridorPiece {
|
pub struct SmallCorridorPiece {
|
||||||
pub piece: StrongholdPiece,
|
pub piece: StrongholdPiece,
|
||||||
pub length: i32,
|
pub length: i32,
|
||||||
@ -238,10 +232,6 @@ impl SmallCorridorPiece {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StructurePieceBase for SmallCorridorPiece {
|
impl StructurePieceBase for SmallCorridorPiece {
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_structure_piece(&self) -> &crate::generation::structure::structures::StructurePiece {
|
fn get_structure_piece(&self) -> &crate::generation::structure::structures::StructurePiece {
|
||||||
&self.piece.piece
|
&self.piece.piece
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct FiveWayCrossingPiece {
|
pub struct FiveWayCrossingPiece {
|
||||||
pub piece: StrongholdPiece,
|
pub piece: StrongholdPiece,
|
||||||
pub lower_left_exists: bool,
|
pub lower_left_exists: bool,
|
||||||
@ -313,8 +312,4 @@ impl StructurePieceBase for FiveWayCrossingPiece {
|
|||||||
// let torch = Block::WALL_TORCH.default_state.with("facing", "south");
|
// let torch = Block::WALL_TORCH.default_state.with("facing", "south");
|
||||||
// inner.add_block(chunk, &torch, 6, 5, 6, &box_limit);
|
// inner.add_block(chunk, &torch, 6, 5, 6, &box_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct LeftTurnPiece {
|
pub struct LeftTurnPiece {
|
||||||
pub piece: StrongholdPiece,
|
pub piece: StrongholdPiece,
|
||||||
}
|
}
|
||||||
@ -138,8 +137,4 @@ impl StructurePieceBase for LeftTurnPiece {
|
|||||||
inner.fill_with_outline(chunk, &box_limit, false, 4, 1, 1, 4, 3, 3, air, air);
|
inner.fill_with_outline(chunk, &box_limit, false, 4, 1, 1, 4, 3, 3, air, air);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct LibraryPiece {
|
pub struct LibraryPiece {
|
||||||
pub piece: StrongholdPiece,
|
pub piece: StrongholdPiece,
|
||||||
pub tall: bool,
|
pub tall: bool,
|
||||||
@ -237,8 +236,4 @@ impl StructurePieceBase for LibraryPiece {
|
|||||||
// inner.add_chest(chunk, &box_limit, random, 12, 8, 1, "stronghold_library");
|
// inner.add_chest(chunk, &box_limit, random, 12, 8, 1, "stronghold_library");
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,27 +71,19 @@ impl StructureGenerator for StrongholdGenerator {
|
|||||||
let mut last_piece_type: Option<StrongholdPieceType> = None;
|
let mut last_piece_type: Option<StrongholdPieceType> = None;
|
||||||
let mut has_portal_room = false;
|
let mut has_portal_room = false;
|
||||||
|
|
||||||
// let attempt_seed = get_carver_seed(
|
|
||||||
// &mut context.random,
|
|
||||||
// context.seed as u64,
|
|
||||||
// context.chunk_x,
|
|
||||||
// context.chunk_z,
|
|
||||||
// );
|
|
||||||
|
|
||||||
let start_x = section_coords::section_to_block(context.chunk_x) + 2;
|
let start_x = section_coords::section_to_block(context.chunk_x) + 2;
|
||||||
let start_z = section_coords::section_to_block(context.chunk_z) + 2;
|
let start_z = section_coords::section_to_block(context.chunk_z) + 2;
|
||||||
|
|
||||||
let start_piece = SpiralStaircasePiece::new_start(&mut random, start_x, start_z);
|
let start_piece = SpiralStaircasePiece::new_start(&mut random, start_x, start_z);
|
||||||
let start_box: Box<dyn StructurePieceBase> = Box::new(start_piece.clone());
|
|
||||||
|
let base_piece = start_piece.piece.piece.clone();
|
||||||
|
|
||||||
// In Vanilla, pieces_to_process is 'start.pieces'
|
// In Vanilla, pieces_to_process is 'start.pieces'
|
||||||
let mut pieces_to_process: Vec<Box<dyn StructurePieceBase>> = Vec::new();
|
let mut pieces_to_process: Vec<Box<dyn StructurePieceBase>> = Vec::new();
|
||||||
|
|
||||||
collector.add_piece(start_box);
|
|
||||||
|
|
||||||
// Initial Fill
|
// Initial Fill
|
||||||
start_piece.fill_openings(
|
start_piece.fill_openings(
|
||||||
&start_piece.piece.piece,
|
&base_piece,
|
||||||
&mut random,
|
&mut random,
|
||||||
&mut weights,
|
&mut weights,
|
||||||
&mut last_piece_type,
|
&mut last_piece_type,
|
||||||
@ -100,12 +92,15 @@ impl StructureGenerator for StrongholdGenerator {
|
|||||||
&mut pieces_to_process,
|
&mut pieces_to_process,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
collector.add_piece(Box::new(start_piece));
|
||||||
|
|
||||||
// Growth Loop
|
// Growth Loop
|
||||||
while !pieces_to_process.is_empty() {
|
while !pieces_to_process.is_empty() {
|
||||||
let idx = random.next_bounded_i32(pieces_to_process.len() as i32) as usize;
|
let idx = random.next_bounded_i32(pieces_to_process.len() as i32) as usize;
|
||||||
let piece = pieces_to_process.remove(idx);
|
let piece = pieces_to_process.remove(idx);
|
||||||
|
|
||||||
piece.fill_openings(
|
piece.fill_openings(
|
||||||
&start_piece.piece.piece,
|
&base_piece,
|
||||||
&mut random,
|
&mut random,
|
||||||
&mut weights,
|
&mut weights,
|
||||||
&mut last_piece_type,
|
&mut last_piece_type,
|
||||||
@ -113,6 +108,9 @@ impl StructureGenerator for StrongholdGenerator {
|
|||||||
&mut collector,
|
&mut collector,
|
||||||
&mut pieces_to_process,
|
&mut pieces_to_process,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Move into collector AFTER processing its children
|
||||||
|
collector.add_piece(piece);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift height
|
// Shift height
|
||||||
@ -252,7 +250,6 @@ fn get_initial_weights() -> Vec<PieceWeight> {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct StrongholdPiece {
|
pub struct StrongholdPiece {
|
||||||
pub piece: StructurePiece,
|
pub piece: StructurePiece,
|
||||||
pub entry_door: EntranceType,
|
pub entry_door: EntranceType,
|
||||||
@ -617,7 +614,6 @@ impl StrongholdPiece {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(p) = next_piece {
|
if let Some(p) = next_piece {
|
||||||
collector.add_piece(p.clone_box());
|
|
||||||
return Some(p);
|
return Some(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct PortalRoomPiece {
|
pub struct PortalRoomPiece {
|
||||||
pub piece: StrongholdPiece,
|
pub piece: StrongholdPiece,
|
||||||
pub spawner_placed: bool,
|
pub spawner_placed: bool,
|
||||||
@ -372,8 +371,4 @@ impl StructurePieceBase for PortalRoomPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct PrisonHallPiece {
|
pub struct PrisonHallPiece {
|
||||||
piece: StrongholdPiece,
|
piece: StrongholdPiece,
|
||||||
}
|
}
|
||||||
@ -222,8 +221,4 @@ impl StructurePieceBase for PrisonHallPiece {
|
|||||||
// inner.add_block(chunk, &door_bottom, 4, 1, 8, &box_limit);
|
// inner.add_block(chunk, &door_bottom, 4, 1, 8, &box_limit);
|
||||||
// inner.add_block(chunk, &door_top, 4, 2, 8, &box_limit);
|
// inner.add_block(chunk, &door_top, 4, 2, 8, &box_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct RightTurnPiece {
|
pub struct RightTurnPiece {
|
||||||
pub piece: StrongholdPiece,
|
pub piece: StrongholdPiece,
|
||||||
}
|
}
|
||||||
@ -143,8 +142,4 @@ impl StructurePieceBase for RightTurnPiece {
|
|||||||
inner.fill_with_outline(chunk, &box_limit, false, 0, 1, 1, 0, 3, 3, air, air);
|
inner.fill_with_outline(chunk, &box_limit, false, 0, 1, 1, 0, 3, 3, air, air);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,20 +28,6 @@ pub struct SpiralStaircasePiece {
|
|||||||
pub portal_room_exists: bool,
|
pub portal_room_exists: bool,
|
||||||
pub pieces: Vec<Box<dyn StructurePieceBase>>,
|
pub pieces: Vec<Box<dyn StructurePieceBase>>,
|
||||||
}
|
}
|
||||||
impl Clone for SpiralStaircasePiece {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
// StrongholdPiece and other types must derive Clone
|
|
||||||
piece: self.piece.clone(),
|
|
||||||
orientation: self.orientation,
|
|
||||||
is_structure_start: self.is_structure_start,
|
|
||||||
last_piece_data_idx: self.last_piece_data_idx,
|
|
||||||
portal_room_exists: self.portal_room_exists,
|
|
||||||
// Use the clone_box helper we added to the trait!
|
|
||||||
pieces: self.pieces.iter().map(|p| p.clone_box()).collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SpiralStaircasePiece {
|
impl SpiralStaircasePiece {
|
||||||
/// Matches Start(Random random, int i, int j)
|
/// Matches Start(Random random, int i, int j)
|
||||||
@ -102,10 +88,6 @@ impl SpiralStaircasePiece {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StructurePieceBase for SpiralStaircasePiece {
|
impl StructurePieceBase for SpiralStaircasePiece {
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_structure_piece(&self) -> &StructurePiece {
|
fn get_structure_piece(&self) -> &StructurePiece {
|
||||||
&self.piece.piece
|
&self.piece.piece
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct SquareRoomPiece {
|
pub struct SquareRoomPiece {
|
||||||
piece: StrongholdPiece,
|
piece: StrongholdPiece,
|
||||||
room_type: u32,
|
room_type: u32,
|
||||||
@ -273,8 +272,4 @@ impl StructurePieceBase for SquareRoomPiece {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct StairsPiece {
|
pub struct StairsPiece {
|
||||||
pub piece: StrongholdPiece,
|
pub piece: StrongholdPiece,
|
||||||
}
|
}
|
||||||
@ -144,8 +143,4 @@ impl StructurePieceBase for StairsPiece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,16 +55,11 @@ impl StructureGenerator for SwampHutGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct SwampHutPiece {
|
pub struct SwampHutPiece {
|
||||||
shiftable_structure_piece: ShiftableStructurePiece,
|
shiftable_structure_piece: ShiftableStructurePiece,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructurePieceBase for SwampHutPiece {
|
impl StructurePieceBase for SwampHutPiece {
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn place(
|
fn place(
|
||||||
&mut self,
|
&mut self,
|
||||||
chunk: &mut ProtoChunk,
|
chunk: &mut ProtoChunk,
|
||||||
|
|||||||
@ -28,7 +28,6 @@ use super::{BlockMirror, BlockRotation, BlockStateResolver, StructureTemplate};
|
|||||||
/// - Applying rotation and mirror transformations
|
/// - Applying rotation and mirror transformations
|
||||||
/// - Placing blocks at world coordinates
|
/// - Placing blocks at world coordinates
|
||||||
/// - Skipping structure void blocks
|
/// - Skipping structure void blocks
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TemplatePiece {
|
pub struct TemplatePiece {
|
||||||
/// The underlying structure piece metadata.
|
/// The underlying structure piece metadata.
|
||||||
pub piece: StructurePiece,
|
pub piece: StructurePiece,
|
||||||
@ -159,10 +158,6 @@ impl TemplatePiece {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StructurePieceBase for TemplatePiece {
|
impl StructurePieceBase for TemplatePiece {
|
||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn place(
|
fn place(
|
||||||
&mut self,
|
&mut self,
|
||||||
chunk: &mut ProtoChunk,
|
chunk: &mut ProtoChunk,
|
||||||
|
|||||||
@ -61,7 +61,7 @@ pub type SyncEntityChunk = Arc<ChunkEntityData>;
|
|||||||
pub struct Level {
|
pub struct Level {
|
||||||
pub seed: Seed,
|
pub seed: Seed,
|
||||||
pub world_portal: ArcSwap<Option<Arc<dyn WorldPortalExt>>>,
|
pub world_portal: ArcSwap<Option<Arc<dyn WorldPortalExt>>>,
|
||||||
pub level_folder: LevelFolder,
|
pub level_folder: Arc<LevelFolder>,
|
||||||
pub lighting_config: LightingEngineConfig,
|
pub lighting_config: LightingEngineConfig,
|
||||||
|
|
||||||
/// Counts the number of ticks that have been scheduled for this world
|
/// Counts the number of ticks that have been scheduled for this world
|
||||||
@ -117,26 +117,12 @@ pub struct RandomTickSample {
|
|||||||
pub tick_fluid: bool,
|
pub tick_fluid: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct LevelFolder {
|
pub struct LevelFolder {
|
||||||
pub root_folder: PathBuf,
|
pub root_folder: PathBuf,
|
||||||
pub region_folder: PathBuf,
|
pub region_folder: PathBuf,
|
||||||
pub entities_folder: PathBuf,
|
pub entities_folder: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[cfg(feature = "tokio_taskdump")]
|
|
||||||
pub async fn dump() {
|
|
||||||
// let handle = Handle::current();
|
|
||||||
// if let Ok(dump) = timeout(Duration::from_secs(100), handle.dump()).await {
|
|
||||||
// for (i, task) in dump.tasks().iter().enumerate() {
|
|
||||||
// let trace = task.trace();
|
|
||||||
// log::error!("TASK {i}:");
|
|
||||||
// log::error!("{trace}\n");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Level {
|
impl Level {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_root_folder(
|
pub fn from_root_folder(
|
||||||
@ -152,11 +138,11 @@ impl Level {
|
|||||||
std::fs::create_dir_all(®ion_folder).expect("Failed to create Region folder");
|
std::fs::create_dir_all(®ion_folder).expect("Failed to create Region folder");
|
||||||
std::fs::create_dir_all(&entities_folder).expect("Failed to create Entities folder");
|
std::fs::create_dir_all(&entities_folder).expect("Failed to create Entities folder");
|
||||||
|
|
||||||
let level_folder = LevelFolder {
|
let level_folder = Arc::new(LevelFolder {
|
||||||
root_folder,
|
root_folder,
|
||||||
region_folder,
|
region_folder,
|
||||||
entities_folder,
|
entities_folder,
|
||||||
};
|
});
|
||||||
|
|
||||||
let seed = Seed(seed as u64);
|
let seed = Seed(seed as u64);
|
||||||
let world_gen = get_world_gen(seed, dimension).into();
|
let world_gen = get_world_gen(seed, dimension).into();
|
||||||
@ -766,12 +752,6 @@ impl Level {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_get_chunk(&self, coordinates: &Vector2<i32>) -> Option<Arc<ChunkData>> {
|
|
||||||
self.loaded_chunks
|
|
||||||
.get(coordinates)
|
|
||||||
.map(|x| x.value().clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_chunk_loaded(&self, coordinates: &Vector2<i32>) -> bool {
|
pub fn is_chunk_loaded(&self, coordinates: &Vector2<i32>) -> bool {
|
||||||
self.loaded_chunks.contains_key(coordinates)
|
self.loaded_chunks.contains_key(coordinates)
|
||||||
}
|
}
|
||||||
@ -784,6 +764,16 @@ impl Level {
|
|||||||
self.loaded_chunks.get(coordinates).map(|x| f(x.value()))
|
self.loaded_chunks.get(coordinates).map(|x| f(x.value()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_entity_chunk_sync<R, F: Fn(&SyncEntityChunk) -> R>(
|
||||||
|
&self,
|
||||||
|
coordinates: &Vector2<i32>,
|
||||||
|
f: F,
|
||||||
|
) -> Option<R> {
|
||||||
|
self.loaded_entity_chunks
|
||||||
|
.get(coordinates)
|
||||||
|
.map(|x| f(x.value()))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_rough_biome(&self, position: &BlockPos) -> &'static Biome {
|
pub fn get_rough_biome(&self, position: &BlockPos) -> &'static Biome {
|
||||||
let (chunk_coordinate, relative) = position.chunk_and_chunk_relative_position();
|
let (chunk_coordinate, relative) = position.chunk_and_chunk_relative_position();
|
||||||
let id = self.read_chunk_sync(&chunk_coordinate, |chunk| {
|
let id = self.read_chunk_sync(&chunk_coordinate, |chunk| {
|
||||||
@ -796,16 +786,6 @@ impl Level {
|
|||||||
Biome::from_id(id.flatten().unwrap_or(0)).unwrap_or(&Biome::THE_VOID)
|
Biome::from_id(id.flatten().unwrap_or(0)).unwrap_or(&Biome::THE_VOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_entity_chunk_sync<R, F: Fn(&SyncEntityChunk) -> R>(
|
|
||||||
&self,
|
|
||||||
coordinates: &Vector2<i32>,
|
|
||||||
f: F,
|
|
||||||
) -> Option<R> {
|
|
||||||
self.loaded_entity_chunks
|
|
||||||
.get(coordinates)
|
|
||||||
.map(|x| f(x.value()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_entity_chunk_sync(&self, pos: &Vector2<i32>) -> Option<SyncEntityChunk> {
|
pub fn get_entity_chunk_sync(&self, pos: &Vector2<i32>) -> Option<SyncEntityChunk> {
|
||||||
self.loaded_entity_chunks
|
self.loaded_entity_chunks
|
||||||
.get(pos)
|
.get(pos)
|
||||||
|
|||||||
@ -115,7 +115,6 @@ tempfile.workspace = true
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
console-subscriber = ["dep:console-subscriber"]
|
console-subscriber = ["dep:console-subscriber"]
|
||||||
tokio_taskdump = ["pumpkin-world/tokio_taskdump"]
|
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
@ -155,7 +155,7 @@ impl CrashReport {
|
|||||||
eprintln!(
|
eprintln!(
|
||||||
"{}\n{}",
|
"{}\n{}",
|
||||||
RED.console_color("Backtrace:"),
|
RED.console_color("Backtrace:"),
|
||||||
&self.captured_backtrace
|
self.captured_backtrace
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2165,7 +2165,7 @@ impl Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_fall_flying(&self, fall_flying: bool) {
|
pub async fn set_fall_flying(&self, fall_flying: bool) {
|
||||||
assert!(self.fall_flying.load(Relaxed) != fall_flying);
|
assert_ne!(self.fall_flying.load(Relaxed), fall_flying);
|
||||||
self.fall_flying.store(fall_flying, Relaxed);
|
self.fall_flying.store(fall_flying, Relaxed);
|
||||||
self.set_flag(Flag::FallFlying, fall_flying).await;
|
self.set_flag(Flag::FallFlying, fall_flying).await;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,16 +62,14 @@ impl ItemBehaviour for EnderEyeItem {
|
|||||||
|
|
||||||
let new_state_id = block.from_properties(&props).to_state_id(block);
|
let new_state_id = block.from_properties(&props).to_state_id(block);
|
||||||
world
|
world
|
||||||
.set_block_state(&location, new_state_id, BlockFlags::empty())
|
.set_block_state(&location, new_state_id, BlockFlags::NOTIFY_LISTENERS)
|
||||||
.await;
|
.await;
|
||||||
|
// Consume one item.
|
||||||
|
item.decrement(1);
|
||||||
world.sync_world_event(WorldEvent::EndPortalFrameFill, location, 0);
|
world.sync_world_event(WorldEvent::EndPortalFrameFill, location, 0);
|
||||||
|
|
||||||
// Try to complete the portal.
|
// Try to complete the portal.
|
||||||
EndPortal::get_new_portal(&world, location).await;
|
EndPortal::get_new_portal(&world, location).await;
|
||||||
|
|
||||||
// Consume one item.
|
|
||||||
item.decrement(1);
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -47,9 +47,9 @@ impl Ignition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn can_be_lit(block: &Block, state_id: u16) -> Option<u16> {
|
fn can_be_lit(block: &Block, state_id: u16) -> Option<u16> {
|
||||||
let mut props = match &block.properties(state_id) {
|
let mut props = {
|
||||||
Some(props) => props.to_props(),
|
let props = &block.properties(state_id)?;
|
||||||
None => return None,
|
props.to_props()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((_, value)) = props.iter_mut().find(|(k, _)| *k == "extinguished") {
|
if let Some((_, value)) = props.iter_mut().find(|(k, _)| *k == "extinguished") {
|
||||||
|
|||||||
@ -94,6 +94,8 @@ pub struct BedrockClient {
|
|||||||
output_split_number: AtomicU16,
|
output_split_number: AtomicU16,
|
||||||
output_sequenced_index: AtomicU32,
|
output_sequenced_index: AtomicU32,
|
||||||
output_ordered_index: AtomicU32,
|
output_ordered_index: AtomicU32,
|
||||||
|
/// The next form ID to use for custom forms.
|
||||||
|
pub next_form_id: AtomicU32,
|
||||||
/// An notifier that is triggered when this client is closed.
|
/// An notifier that is triggered when this client is closed.
|
||||||
close_token: CancellationToken,
|
close_token: CancellationToken,
|
||||||
last_seen: Arc<AtomicCell<std::time::Instant>>,
|
last_seen: Arc<AtomicCell<std::time::Instant>>,
|
||||||
@ -133,6 +135,7 @@ impl BedrockClient {
|
|||||||
output_split_number: AtomicU16::new(0),
|
output_split_number: AtomicU16::new(0),
|
||||||
output_sequenced_index: AtomicU32::new(0),
|
output_sequenced_index: AtomicU32::new(0),
|
||||||
output_ordered_index: AtomicU32::new(0),
|
output_ordered_index: AtomicU32::new(0),
|
||||||
|
next_form_id: AtomicU32::new(0),
|
||||||
compounds: Arc::new(Mutex::new(HashMap::new())),
|
compounds: Arc::new(Mutex::new(HashMap::new())),
|
||||||
close_token: CancellationToken::new(),
|
close_token: CancellationToken::new(),
|
||||||
last_seen: Arc::new(AtomicCell::new(std::time::Instant::now())),
|
last_seen: Arc::new(AtomicCell::new(std::time::Instant::now())),
|
||||||
@ -789,6 +792,16 @@ impl BedrockClient {
|
|||||||
SAnimate::PACKET_ID => {
|
SAnimate::PACKET_ID => {
|
||||||
self.handle_animate(player, server, &SAnimate::read(reader)?);
|
self.handle_animate(player, server, &SAnimate::read(reader)?);
|
||||||
}
|
}
|
||||||
|
pumpkin_protocol::bedrock::server::modal_form_response::SModalFormResponse::PACKET_ID => {
|
||||||
|
self.handle_modal_form_response(
|
||||||
|
player,
|
||||||
|
server,
|
||||||
|
pumpkin_protocol::bedrock::server::modal_form_response::SModalFormResponse::read(
|
||||||
|
reader,
|
||||||
|
)?,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
SLoadingScreen::PACKET_ID => {
|
SLoadingScreen::PACKET_ID => {
|
||||||
// Ignore for now
|
// Ignore for now
|
||||||
}
|
}
|
||||||
|
|||||||
@ -411,4 +411,18 @@ impl BedrockClient {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn handle_modal_form_response(
|
||||||
|
&self,
|
||||||
|
player: &Arc<Player>,
|
||||||
|
server: &Server,
|
||||||
|
packet: pumpkin_protocol::bedrock::server::modal_form_response::SModalFormResponse,
|
||||||
|
) {
|
||||||
|
let event = crate::plugin::api::events::player::bedrock_form_response::BedrockFormResponseEvent::new(
|
||||||
|
player.clone(),
|
||||||
|
packet.form_id.0 as u32,
|
||||||
|
packet.form_data,
|
||||||
|
);
|
||||||
|
let _ = server.plugin_manager.fire(event).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,7 @@ impl LANBroadcast {
|
|||||||
|
|
||||||
let mut interval = time::interval(Duration::from_millis(1500));
|
let mut interval = time::interval(Duration::from_millis(1500));
|
||||||
|
|
||||||
let advertisement = format!("[MOTD]{}[/MOTD][AD]{}[/AD]", &self.motd, bound_addr.port());
|
let advertisement = format!("[MOTD]{}[/MOTD][AD]{}[/AD]", self.motd, bound_addr.port());
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"LAN broadcast running on {}",
|
"LAN broadcast running on {}",
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
use pumpkin_macros::Event;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::entity::player::Player;
|
||||||
|
|
||||||
|
use super::PlayerEvent;
|
||||||
|
|
||||||
|
/// An event that occurs when a player responds to a Bedrock custom form.
|
||||||
|
#[derive(Event, Clone)]
|
||||||
|
pub struct BedrockFormResponseEvent {
|
||||||
|
/// The player who responded to the form.
|
||||||
|
pub player: Arc<Player>,
|
||||||
|
|
||||||
|
/// The ID of the form.
|
||||||
|
pub form_id: u32,
|
||||||
|
|
||||||
|
/// The response data as a JSON string. None if the form was closed.
|
||||||
|
pub response_data: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BedrockFormResponseEvent {
|
||||||
|
/// Creates a new instance of `BedrockFormResponseEvent`.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(player: Arc<Player>, form_id: u32, response_data: Option<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
player,
|
||||||
|
form_id,
|
||||||
|
response_data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlayerEvent for BedrockFormResponseEvent {
|
||||||
|
fn get_player(&self) -> &Arc<Player> {
|
||||||
|
&self.player
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
pub mod bedrock_form_response;
|
||||||
pub mod changed_main_hand;
|
pub mod changed_main_hand;
|
||||||
pub mod egg_throw;
|
pub mod egg_throw;
|
||||||
pub mod exp_change;
|
pub mod exp_change;
|
||||||
|
|||||||
@ -11,8 +11,8 @@ use crate::plugin::{
|
|||||||
},
|
},
|
||||||
player::to_wit_item_stack,
|
player::to_wit_item_stack,
|
||||||
pumpkin::plugin::event::{
|
pumpkin::plugin::event::{
|
||||||
Event, InteractAction as WasmInteractAction, InventoryClickEventData,
|
BedrockFormResponseEventData, Event, InteractAction as WasmInteractAction,
|
||||||
InventoryCloseEventData, PlayerChangeWorldEventData,
|
InventoryClickEventData, InventoryCloseEventData, PlayerChangeWorldEventData,
|
||||||
PlayerChangedMainHandEventData, PlayerChatEventData, PlayerCommandSendEventData,
|
PlayerChangedMainHandEventData, PlayerChatEventData, PlayerCommandSendEventData,
|
||||||
PlayerCustomPayloadEventData, PlayerEggThrowEventData, PlayerExpChangeEventData,
|
PlayerCustomPayloadEventData, PlayerEggThrowEventData, PlayerExpChangeEventData,
|
||||||
PlayerFishEventData, PlayerFishState as WasmPlayerFishState,
|
PlayerFishEventData, PlayerFishState as WasmPlayerFishState,
|
||||||
@ -26,6 +26,7 @@ use crate::plugin::{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
player::{
|
player::{
|
||||||
|
bedrock_form_response::BedrockFormResponseEvent,
|
||||||
changed_main_hand::PlayerChangedMainHandEvent,
|
changed_main_hand::PlayerChangedMainHandEvent,
|
||||||
egg_throw::PlayerEggThrowEvent,
|
egg_throw::PlayerEggThrowEvent,
|
||||||
exp_change::PlayerExpChangeEvent,
|
exp_change::PlayerExpChangeEvent,
|
||||||
@ -733,3 +734,28 @@ impl ToFromWasmEvent for PlayerToggleSprintEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToFromWasmEvent for BedrockFormResponseEvent {
|
||||||
|
fn to_wasm_event(&self, state: &mut PluginHostState) -> Event {
|
||||||
|
let player = state
|
||||||
|
.add_player(self.player.clone())
|
||||||
|
.expect("failed to add player resource");
|
||||||
|
|
||||||
|
Event::BedrockFormResponseEvent(BedrockFormResponseEventData {
|
||||||
|
player,
|
||||||
|
form_id: self.form_id,
|
||||||
|
response_data: self.response_data.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_wasm_event(event: Event, state: &mut PluginHostState) -> Self {
|
||||||
|
match event {
|
||||||
|
Event::BedrockFormResponseEvent(data) => Self {
|
||||||
|
player: consume_player(state, &data.player),
|
||||||
|
form_id: data.form_id,
|
||||||
|
response_data: data.response_data,
|
||||||
|
},
|
||||||
|
_ => panic!("unexpected event type"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
129
pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/forms.rs
Normal file
129
pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/forms.rs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
use crate::net::ClientPlatform;
|
||||||
|
use crate::plugin::loader::wasm::wasm_host::state::PluginHostState;
|
||||||
|
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::player::player_from_resource;
|
||||||
|
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::player::text_component_from_resource;
|
||||||
|
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::forms::{
|
||||||
|
CustomForm, CustomFormElement, Form, Host, ImageType, ModalForm, SimpleForm,
|
||||||
|
};
|
||||||
|
use pumpkin_protocol::bedrock::client::modal_form_request::CModalFormRequest;
|
||||||
|
use pumpkin_util::translation::Locale;
|
||||||
|
use serde_json::{Value, json};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
use wasmtime::component::Resource;
|
||||||
|
|
||||||
|
impl Host for PluginHostState {
|
||||||
|
async fn send_form(
|
||||||
|
&mut self,
|
||||||
|
player_res: Resource<
|
||||||
|
crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::player::Player,
|
||||||
|
>,
|
||||||
|
form: Form,
|
||||||
|
) -> wasmtime::Result<u32> {
|
||||||
|
let player = player_from_resource(self, &player_res)?;
|
||||||
|
|
||||||
|
if let ClientPlatform::Bedrock(client) = &player.client {
|
||||||
|
let form_id = client.next_form_id.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
|
let locale_str = player.config.load().locale.clone();
|
||||||
|
let locale = Locale::from_str(&locale_str).unwrap_or(Locale::EnUs);
|
||||||
|
|
||||||
|
let form_json = match form {
|
||||||
|
Form::Simple(simple) => self.serialize_simple_form(simple, locale),
|
||||||
|
Form::Modal(modal) => self.serialize_modal_form(&modal, locale),
|
||||||
|
Form::Custom(custom) => self.serialize_custom_form(custom, locale),
|
||||||
|
};
|
||||||
|
|
||||||
|
client
|
||||||
|
.send_game_packet(&CModalFormRequest {
|
||||||
|
form_id: pumpkin_protocol::codec::var_int::VarInt(form_id as i32),
|
||||||
|
form_data: form_json.to_string(),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(form_id)
|
||||||
|
} else {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginHostState {
|
||||||
|
fn translate_res(
|
||||||
|
&self,
|
||||||
|
res: &Resource<
|
||||||
|
crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::text::TextComponent,
|
||||||
|
>,
|
||||||
|
locale: Locale,
|
||||||
|
) -> String {
|
||||||
|
let component = text_component_from_resource(self, res);
|
||||||
|
component.0.get_text(locale)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_simple_form(&self, form: SimpleForm, locale: Locale) -> Value {
|
||||||
|
let buttons: Vec<Value> = form
|
||||||
|
.buttons
|
||||||
|
.into_iter()
|
||||||
|
.map(|b| {
|
||||||
|
let mut obj = json!({ "text": self.translate_res(&b.text, locale) });
|
||||||
|
if let Some(image) = b.image {
|
||||||
|
obj.as_object_mut().unwrap().insert(
|
||||||
|
"image".to_string(),
|
||||||
|
json!({
|
||||||
|
"type": match image.type_ {
|
||||||
|
ImageType::Url => "url",
|
||||||
|
ImageType::Path => "path",
|
||||||
|
},
|
||||||
|
"data": image.data
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
obj
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
json!({
|
||||||
|
"type": "form",
|
||||||
|
"title": self.translate_res(&form.title, locale),
|
||||||
|
"content": self.translate_res(&form.content, locale),
|
||||||
|
"buttons": buttons
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_modal_form(&self, form: &ModalForm, locale: Locale) -> Value {
|
||||||
|
json!({
|
||||||
|
"type": "modal",
|
||||||
|
"title": self.translate_res(&form.title, locale),
|
||||||
|
"content": self.translate_res(&form.content, locale),
|
||||||
|
"button1": self.translate_res(&form.button1, locale),
|
||||||
|
"button2": self.translate_res(&form.button2, locale)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_custom_form(&self, form: CustomForm, locale: Locale) -> Value {
|
||||||
|
let elements: Vec<Value> = form.elements.into_iter().map(|e| {
|
||||||
|
match e {
|
||||||
|
CustomFormElement::Label(text) => json!({ "type": "label", "text": self.translate_res(&text, locale) }),
|
||||||
|
CustomFormElement::Toggle((text, default)) => json!({ "type": "toggle", "text": self.translate_res(&text, locale), "default": default }),
|
||||||
|
CustomFormElement::Slider((text, min, max, step, default)) => json!({
|
||||||
|
"type": "slider", "text": self.translate_res(&text, locale), "min": min, "max": max, "step": step, "default": default
|
||||||
|
}),
|
||||||
|
CustomFormElement::StepSlider((text, steps, default)) => json!({
|
||||||
|
"type": "step_slider", "text": self.translate_res(&text, locale), "steps": steps, "default": default
|
||||||
|
}),
|
||||||
|
CustomFormElement::Dropdown((text, options, default)) => json!({
|
||||||
|
"type": "dropdown", "text": self.translate_res(&text, locale), "options": options, "default": default
|
||||||
|
}),
|
||||||
|
CustomFormElement::Input((text, placeholder, default)) => json!({
|
||||||
|
"type": "input", "text": self.translate_res(&text, locale), "placeholder": placeholder, "default": default
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
json!({
|
||||||
|
"type": "custom_form",
|
||||||
|
"title": self.translate_res(&form.title, locale),
|
||||||
|
"content": elements
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,6 +13,7 @@ pub mod common;
|
|||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod entity;
|
pub mod entity;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
|
pub mod forms;
|
||||||
pub mod generated_packets;
|
pub mod generated_packets;
|
||||||
pub mod gui;
|
pub mod gui;
|
||||||
pub mod i18n;
|
pub mod i18n;
|
||||||
|
|||||||
@ -424,13 +424,11 @@ impl World {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn flush_synced_block_events(self: &Arc<Self>) {
|
pub async fn flush_synced_block_events(self: &Arc<Self>) {
|
||||||
let events;
|
|
||||||
// THIS IS IMPORTANT
|
// THIS IS IMPORTANT
|
||||||
// it prevents deadlocks and also removes the need to wait for a lock when adding a new synced block
|
// it prevents deadlocks and also removes the need to wait for a lock when adding a new synced block
|
||||||
{
|
let events = {
|
||||||
let mut queue = self.synced_block_event_queue.lock().await;
|
let mut queue = self.synced_block_event_queue.lock().await;
|
||||||
events = queue.clone();
|
std::mem::take(&mut *queue)
|
||||||
queue.clear();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for event in events {
|
for event in events {
|
||||||
@ -1599,6 +1597,8 @@ impl World {
|
|||||||
(position, yaw, pitch)
|
(position, yaw, pitch)
|
||||||
} else {
|
} else {
|
||||||
let spawn_position = Vector2::new(level_info.spawn_x, level_info.spawn_z);
|
let spawn_position = Vector2::new(level_info.spawn_x, level_info.spawn_z);
|
||||||
|
let chunk_pos = Vector2::new(level_info.spawn_x >> 4, level_info.spawn_z >> 4);
|
||||||
|
self.level.get_or_fetch_chunk(chunk_pos, |_| ()).await;
|
||||||
let pos_y = self.get_top_block(spawn_position) + 1; // +1 to spawn on top of the block
|
let pos_y = self.get_top_block(spawn_position) + 1; // +1 to spawn on top of the block
|
||||||
|
|
||||||
let position = Vector3::new(
|
let position = Vector3::new(
|
||||||
@ -1937,6 +1937,8 @@ impl World {
|
|||||||
} else {
|
} else {
|
||||||
let info = &self.level_info.load();
|
let info = &self.level_info.load();
|
||||||
let spawn_position = Vector2::new(info.spawn_x, info.spawn_z);
|
let spawn_position = Vector2::new(info.spawn_x, info.spawn_z);
|
||||||
|
let chunk_pos = Vector2::new(info.spawn_x >> 4, info.spawn_z >> 4);
|
||||||
|
self.level.get_or_fetch_chunk(chunk_pos, |_| ()).await;
|
||||||
let pos_y = self.get_top_block(spawn_position) + 1; // +1 to spawn on top of the block
|
let pos_y = self.get_top_block(spawn_position) + 1; // +1 to spawn on top of the block
|
||||||
|
|
||||||
let position = Vector3::new(
|
let position = Vector3::new(
|
||||||
@ -2428,6 +2430,8 @@ impl World {
|
|||||||
// FIXME: This spawn position calculation is incorrect. Should use vanilla's
|
// FIXME: This spawn position calculation is incorrect. Should use vanilla's
|
||||||
// proper spawn position calculation (see #1381). The y-level calculation
|
// proper spawn position calculation (see #1381). The y-level calculation
|
||||||
// needs to account for spawn radius and find a safe spawn position.
|
// needs to account for spawn radius and find a safe spawn position.
|
||||||
|
let chunk_pos = Vector2::new(spawn_x >> 4, spawn_z >> 4);
|
||||||
|
self.level.get_or_fetch_chunk(chunk_pos, |_| ()).await;
|
||||||
let top = self.get_top_block(Vector2::new(spawn_x, spawn_z));
|
let top = self.get_top_block(Vector2::new(spawn_x, spawn_z));
|
||||||
|
|
||||||
(
|
(
|
||||||
@ -2496,6 +2500,8 @@ impl World {
|
|||||||
);
|
);
|
||||||
// FIXME: This spawn position calculation is incorrect. Should use vanilla's
|
// FIXME: This spawn position calculation is incorrect. Should use vanilla's
|
||||||
// proper spawn position calculation (see #1381).
|
// proper spawn position calculation (see #1381).
|
||||||
|
let chunk_pos = Vector2::new(spawn_x >> 4, spawn_z >> 4);
|
||||||
|
self.level.get_or_fetch_chunk(chunk_pos, |_| ()).await;
|
||||||
let top = self.get_top_block(Vector2::new(spawn_x, spawn_z));
|
let top = self.get_top_block(Vector2::new(spawn_x, spawn_z));
|
||||||
let fallback_pos = Vector3::new(
|
let fallback_pos = Vector3::new(
|
||||||
f64::from(spawn_x) + 0.5,
|
f64::from(spawn_x) + 0.5,
|
||||||
|
|||||||
@ -94,7 +94,7 @@ impl EndPortal {
|
|||||||
.set_block_state(
|
.set_block_state(
|
||||||
&pos.offset(Vector3::new(x, 0, z)),
|
&pos.offset(Vector3::new(x, 0, z)),
|
||||||
Block::END_PORTAL.default_state.id,
|
Block::END_PORTAL.default_state.id,
|
||||||
BlockFlags::empty(),
|
BlockFlags::NOTIFY_LISTENERS,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user