fix: nether/end
This commit is contained in:
parent
38a924e6ce
commit
8634d8740f
@ -159,7 +159,7 @@ pub fn get_region_seed(world_seed: u64, region_x: i32, region_z: i32, salt: u32)
|
|||||||
/// A seed value to be used with a legacy random generator.
|
/// A seed value to be used with a legacy random generator.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn seed_slime_chunk(x: i32, z: i32, seed: u64, salt: u64) -> u64 {
|
pub const fn seed_slime_chunk(x: i32, z: i32, seed: u64, salt: u64) -> u64 {
|
||||||
(seed
|
(seed
|
||||||
.wrapping_add((x.wrapping_mul(x).wrapping_mul(4_987_142)) as i64 as u64)
|
.wrapping_add((x.wrapping_mul(x).wrapping_mul(4_987_142)) as i64 as u64)
|
||||||
.wrapping_add((x.wrapping_mul(5_947_611)) as i64 as u64)
|
.wrapping_add((x.wrapping_mul(5_947_611)) as i64 as u64)
|
||||||
|
|||||||
@ -280,6 +280,46 @@ impl TextComponentBase {
|
|||||||
text
|
text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts this component by resolving all translations.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// A new component with all translations resolved.
|
||||||
|
fn translate_hover_event(style: &mut Style) {
|
||||||
|
if let Some(ref hover) = style.hover_event {
|
||||||
|
style.hover_event = match hover {
|
||||||
|
HoverEvent::ShowText { value } => {
|
||||||
|
let mut hover_components = vec![];
|
||||||
|
for hover_component in value {
|
||||||
|
hover_components.push(hover_component.to_owned().to_translated());
|
||||||
|
}
|
||||||
|
Some(HoverEvent::ShowText {
|
||||||
|
value: hover_components,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
HoverEvent::ShowEntity { name, id, uuid } => name.as_ref().map_or_else(
|
||||||
|
|| {
|
||||||
|
Some(HoverEvent::ShowEntity {
|
||||||
|
name: None,
|
||||||
|
id: id.clone(),
|
||||||
|
uuid: uuid.clone(),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|name| {
|
||||||
|
Some(HoverEvent::ShowEntity {
|
||||||
|
name: Some(name.iter().map(|x| x.to_owned().to_translated()).collect()),
|
||||||
|
id: id.clone(),
|
||||||
|
uuid: uuid.clone(),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
),
|
||||||
|
HoverEvent::ShowItem { id, count } => Some(HoverEvent::ShowItem {
|
||||||
|
id: id.clone(),
|
||||||
|
count: count.to_owned(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts this component by resolving all translations.
|
/// Converts this component by resolving all translations.
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
@ -354,52 +394,16 @@ impl TextComponentBase {
|
|||||||
_ => self, // If not a translation, return as is
|
_ => self, // If not a translation, return as is
|
||||||
};
|
};
|
||||||
// Ensure that the extra components are translated
|
// Ensure that the extra components are translated
|
||||||
let mut extra = vec![];
|
let extra = component
|
||||||
for extra_component in component.extra {
|
.extra
|
||||||
let translated = extra_component.to_translated();
|
.into_iter()
|
||||||
extra.push(translated);
|
.map(Self::to_translated)
|
||||||
}
|
.collect();
|
||||||
|
|
||||||
// If the hover event is present, it will also be translated
|
// If the hover event is present, it will also be translated
|
||||||
let style = match component.style.hover_event {
|
let mut style = component.style;
|
||||||
None => component.style,
|
Self::translate_hover_event(&mut style);
|
||||||
Some(ref hover) => {
|
|
||||||
let mut style = component.style.clone();
|
|
||||||
style.hover_event = match hover {
|
|
||||||
HoverEvent::ShowText { value } => {
|
|
||||||
let mut hover_components = vec![];
|
|
||||||
for hover_component in value {
|
|
||||||
hover_components.push(hover_component.to_owned().to_translated());
|
|
||||||
}
|
|
||||||
Some(HoverEvent::ShowText {
|
|
||||||
value: hover_components,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
HoverEvent::ShowEntity { name, id, uuid } => name.as_ref().map_or_else(
|
|
||||||
|| {
|
|
||||||
Some(HoverEvent::ShowEntity {
|
|
||||||
name: None,
|
|
||||||
id: id.clone(),
|
|
||||||
uuid: uuid.clone(),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|name| {
|
|
||||||
Some(HoverEvent::ShowEntity {
|
|
||||||
name: Some(
|
|
||||||
name.iter().map(|x| x.to_owned().to_translated()).collect(),
|
|
||||||
),
|
|
||||||
id: id.clone(),
|
|
||||||
uuid: uuid.clone(),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
),
|
|
||||||
HoverEvent::ShowItem { id, count } => Some(HoverEvent::ShowItem {
|
|
||||||
id: id.clone(),
|
|
||||||
count: count.to_owned(),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
style
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Self {
|
Self {
|
||||||
content: component.content,
|
content: component.content,
|
||||||
style,
|
style,
|
||||||
|
|||||||
@ -13,10 +13,10 @@ pub fn into_level(
|
|||||||
seed: i64,
|
seed: i64,
|
||||||
gen_pool: Option<Arc<rayon::ThreadPool>>,
|
gen_pool: Option<Arc<rayon::ThreadPool>>,
|
||||||
) -> Arc<Level> {
|
) -> Arc<Level> {
|
||||||
if dimension == Dimension::OVERWORLD {
|
if dimension.minecraft_name == Dimension::OVERWORLD.minecraft_name {
|
||||||
} else if dimension == Dimension::THE_NETHER {
|
} else if dimension.minecraft_name == Dimension::THE_NETHER.minecraft_name {
|
||||||
base_directory.push("DIM-1");
|
base_directory.push("DIM-1");
|
||||||
} else if dimension == Dimension::THE_END {
|
} else if dimension.minecraft_name == Dimension::THE_END.minecraft_name {
|
||||||
base_directory.push("DIM1");
|
base_directory.push("DIM1");
|
||||||
}
|
}
|
||||||
Level::from_root_folder(level_config, base_directory, seed, dimension, gen_pool)
|
Level::from_root_folder(level_config, base_directory, seed, dimension, gen_pool)
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use pumpkin_util::{
|
|||||||
math::{block_box::BlockBox, position::BlockPos, vector3::Vector3},
|
math::{block_box::BlockBox, position::BlockPos, vector3::Vector3},
|
||||||
random::{RandomGenerator, RandomImpl, get_carver_seed, xoroshiro128::Xoroshiro},
|
random::{RandomGenerator, RandomImpl, get_carver_seed, xoroshiro128::Xoroshiro},
|
||||||
};
|
};
|
||||||
use tracing::debug;
|
use tracing::trace;
|
||||||
|
|
||||||
use crate::generation::structure::structures::stronghold::StrongholdPieceType;
|
use crate::generation::structure::structures::stronghold::StrongholdPieceType;
|
||||||
pub use crate::world::WorldPortalExt;
|
pub use crate::world::WorldPortalExt;
|
||||||
@ -411,7 +411,7 @@ impl StructurePiece {
|
|||||||
let block_pos = self.offset_pos(x, y, z);
|
let block_pos = self.offset_pos(x, y, z);
|
||||||
|
|
||||||
if !box_limit.contains_pos(&block_pos) {
|
if !box_limit.contains_pos(&block_pos) {
|
||||||
debug!("Structure out of bounds");
|
trace!("Structure out of bounds");
|
||||||
return Block::AIR.default_state;
|
return Block::AIR.default_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,7 +431,7 @@ impl StructurePiece {
|
|||||||
|
|
||||||
// Bounds and logic checks
|
// Bounds and logic checks
|
||||||
if !box_limit.contains_pos(&block_pos) {
|
if !box_limit.contains_pos(&block_pos) {
|
||||||
debug!("Structure out of bounds");
|
trace!("Structure out of bounds");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,14 +14,23 @@ pub struct EndPortalBlock;
|
|||||||
impl BlockBehaviour for EndPortalBlock {
|
impl BlockBehaviour for EndPortalBlock {
|
||||||
fn on_entity_collision<'a>(&'a self, args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> {
|
fn on_entity_collision<'a>(&'a self, args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let world = if args.world.dimension == Dimension::THE_END {
|
let target_world =
|
||||||
|
if args.world.dimension.minecraft_name == Dimension::THE_END.minecraft_name {
|
||||||
args.server.get_world_from_dimension(&Dimension::OVERWORLD)
|
args.server.get_world_from_dimension(&Dimension::OVERWORLD)
|
||||||
} else {
|
} else {
|
||||||
args.server.get_world_from_dimension(&Dimension::THE_END)
|
args.server.get_world_from_dimension(&Dimension::THE_END)
|
||||||
};
|
};
|
||||||
|
if Arc::ptr_eq(&target_world, args.world) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tracing::info!(
|
||||||
|
"End portal collision at {:?}, targeting world {:?}",
|
||||||
|
args.position,
|
||||||
|
target_world.dimension.minecraft_name
|
||||||
|
);
|
||||||
args.entity
|
args.entity
|
||||||
.get_entity()
|
.get_entity()
|
||||||
.try_use_portal(0, world, *args.position)
|
.try_use_portal(0, target_world, *args.position)
|
||||||
.await;
|
.await;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,12 +70,22 @@ impl BlockBehaviour for NetherPortalBlock {
|
|||||||
|
|
||||||
fn on_entity_collision<'a>(&'a self, args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> {
|
fn on_entity_collision<'a>(&'a self, args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let target_world = if args.world.dimension == Dimension::THE_NETHER {
|
let target_world =
|
||||||
|
if args.world.dimension.minecraft_name == Dimension::THE_NETHER.minecraft_name {
|
||||||
args.server.get_world_from_dimension(&Dimension::OVERWORLD)
|
args.server.get_world_from_dimension(&Dimension::OVERWORLD)
|
||||||
} else {
|
} else {
|
||||||
args.server.get_world_from_dimension(&Dimension::THE_NETHER)
|
args.server.get_world_from_dimension(&Dimension::THE_NETHER)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if Arc::ptr_eq(&target_world, args.world) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::info!(
|
||||||
|
"Nether portal collision at {:?}, targeting world {:?}",
|
||||||
|
args.position,
|
||||||
|
target_world.dimension.minecraft_name
|
||||||
|
);
|
||||||
let portal_delay = Self::get_portal_time(args.world, args.entity);
|
let portal_delay = Self::get_portal_time(args.world, args.entity);
|
||||||
|
|
||||||
args.entity
|
args.entity
|
||||||
|
|||||||
@ -44,23 +44,8 @@ impl MoveControlTrait for MoveControl {
|
|||||||
let mob_entity = mob.get_mob_entity();
|
let mob_entity = mob.get_mob_entity();
|
||||||
let living_entity = &mob_entity.living_entity;
|
let living_entity = &mob_entity.living_entity;
|
||||||
let entity = &living_entity.entity;
|
let entity = &living_entity.entity;
|
||||||
|
|
||||||
if self.operation == Operation::Strafe {
|
if self.operation == Operation::Strafe {
|
||||||
let movement_speed = living_entity.get_attribute_value(&Attributes::MOVEMENT_SPEED);
|
|
||||||
let speed_modified = (self.speed_modifier * movement_speed) as f32;
|
|
||||||
let xa = self.strafe_forwards;
|
|
||||||
let za = self.strafe_right;
|
|
||||||
let mut dist = xa.hypot(za);
|
|
||||||
if dist < 1.0 {
|
|
||||||
dist = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let dist_norm = speed_modified / dist;
|
|
||||||
let _xa_norm = xa * dist_norm;
|
|
||||||
let _za_norm = za * dist_norm;
|
|
||||||
|
|
||||||
// TODO: is_walkable check
|
// TODO: is_walkable check
|
||||||
|
|
||||||
living_entity.movement_input.store(Vector3::new(
|
living_entity.movement_input.store(Vector3::new(
|
||||||
self.strafe_right as f64,
|
self.strafe_right as f64,
|
||||||
0.0,
|
0.0,
|
||||||
@ -121,11 +106,13 @@ impl MoveControlTrait for MoveControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MoveControl {
|
impl MoveControl {
|
||||||
|
#[must_use]
|
||||||
pub fn has_wanted(&self) -> bool {
|
pub fn has_wanted(&self) -> bool {
|
||||||
self.operation == Operation::MoveTo
|
self.operation == Operation::MoveTo
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_speed_modifier(&self) -> f64 {
|
#[must_use]
|
||||||
|
pub const fn get_speed_modifier(&self) -> f64 {
|
||||||
self.speed_modifier
|
self.speed_modifier
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +126,7 @@ impl MoveControl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn strafe(&mut self, forwards: f32, right: f32) {
|
pub const fn strafe(&mut self, forwards: f32, right: f32) {
|
||||||
self.operation = Operation::Strafe;
|
self.operation = Operation::Strafe;
|
||||||
self.strafe_forwards = forwards;
|
self.strafe_forwards = forwards;
|
||||||
self.strafe_right = right;
|
self.strafe_right = right;
|
||||||
|
|||||||
@ -42,7 +42,7 @@ impl TrackTargetGoal {
|
|||||||
Self::new(check_visibility, false)
|
Self::new(check_visibility, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_unseen_memory_ticks(mut self, ticks: i32) -> Self {
|
pub const fn set_unseen_memory_ticks(mut self, ticks: i32) -> Self {
|
||||||
self.max_time_without_visibility = ticks;
|
self.max_time_without_visibility = ticks;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|||||||
@ -224,7 +224,7 @@ impl MobEntity {
|
|||||||
let dimension = &world.dimension;
|
let dimension = &world.dimension;
|
||||||
let block_light_limit = dimension.monster_spawn_block_light_limit;
|
let block_light_limit = dimension.monster_spawn_block_light_limit;
|
||||||
|
|
||||||
let block_light = world.get_block_light_level(pos).unwrap();
|
let block_light = world.get_block_light_level(pos).unwrap_or(0);
|
||||||
if block_light_limit < 15 && block_light > block_light_limit {
|
if block_light_limit < 15 && block_light > block_light_limit {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -187,13 +187,12 @@ impl SlimeEntity {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_spawn_chance(moon_phase: i64) -> f32 {
|
const fn get_spawn_chance(moon_phase: i64) -> f32 {
|
||||||
match moon_phase {
|
match moon_phase {
|
||||||
0 => 1.0,
|
0 => 1.0,
|
||||||
1 | 7 => 0.75,
|
1 | 7 => 0.75,
|
||||||
2 | 6 => 0.5,
|
2 | 6 => 0.5,
|
||||||
3 | 5 => 0.25,
|
3 | 5 => 0.25,
|
||||||
4 => 0.0,
|
|
||||||
_ => 0.0,
|
_ => 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,11 +205,11 @@ impl SlimeEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_jump_delay(&self) -> i32 {
|
fn get_jump_delay() -> i32 {
|
||||||
rand::random_range(10..30)
|
rand::random_range(10..30)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rot_lerp(&self, start: f32, end: f32, max_step: f32) -> f32 {
|
fn rot_lerp(start: f32, end: f32, max_step: f32) -> f32 {
|
||||||
let mut diff = (end - start).rem_euclid(360.0);
|
let mut diff = (end - start).rem_euclid(360.0);
|
||||||
if diff > 180.0 {
|
if diff > 180.0 {
|
||||||
diff -= 360.0;
|
diff -= 360.0;
|
||||||
@ -363,7 +362,7 @@ impl Mob for SlimeEntity {
|
|||||||
pos.z + zd as f64,
|
pos.z + zd as f64,
|
||||||
);
|
);
|
||||||
let new_entity = Entity::new(world.clone(), new_pos, &EntityType::SLIME);
|
let new_entity = Entity::new(world.clone(), new_pos, &EntityType::SLIME);
|
||||||
let slime = SlimeEntity::new(new_entity);
|
let slime = Self::new(new_entity);
|
||||||
slime.set_size(half_size, true);
|
slime.set_size(half_size, true);
|
||||||
slime
|
slime
|
||||||
.entity
|
.entity
|
||||||
@ -383,7 +382,8 @@ pub struct SlimeMoveControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SlimeMoveControl {
|
impl SlimeMoveControl {
|
||||||
pub fn new(slime: Weak<SlimeEntity>) -> Self {
|
#[must_use]
|
||||||
|
pub const fn new(slime: Weak<SlimeEntity>) -> Self {
|
||||||
Self { slime }
|
Self { slime }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,7 +400,7 @@ impl MoveControlTrait for SlimeMoveControl {
|
|||||||
let entity = &living_entity.entity;
|
let entity = &living_entity.entity;
|
||||||
|
|
||||||
let current_yaw = entity.yaw.load();
|
let current_yaw = entity.yaw.load();
|
||||||
let new_yaw = slime.rot_lerp(current_yaw, slime.target_yaw.load(), 90.0);
|
let new_yaw = SlimeEntity::rot_lerp(current_yaw, slime.target_yaw.load(), 90.0);
|
||||||
entity.yaw.store(new_yaw);
|
entity.yaw.store(new_yaw);
|
||||||
entity.head_yaw.store(new_yaw);
|
entity.head_yaw.store(new_yaw);
|
||||||
entity.body_yaw.store(new_yaw);
|
entity.body_yaw.store(new_yaw);
|
||||||
@ -415,7 +415,7 @@ impl MoveControlTrait for SlimeMoveControl {
|
|||||||
let current_delay = slime.jump_delay.load(Ordering::Relaxed);
|
let current_delay = slime.jump_delay.load(Ordering::Relaxed);
|
||||||
if current_delay <= 0 {
|
if current_delay <= 0 {
|
||||||
// Start jump
|
// Start jump
|
||||||
let mut next_delay = slime.get_jump_delay();
|
let mut next_delay = SlimeEntity::get_jump_delay();
|
||||||
if slime.is_aggressive.load(Ordering::Relaxed) {
|
if slime.is_aggressive.load(Ordering::Relaxed) {
|
||||||
next_delay /= 3;
|
next_delay /= 3;
|
||||||
}
|
}
|
||||||
@ -455,7 +455,7 @@ pub struct SlimeFloatGoal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SlimeFloatGoal {
|
impl SlimeFloatGoal {
|
||||||
pub fn new(slime: Arc<SlimeEntity>) -> Self {
|
pub const fn new(slime: Arc<SlimeEntity>) -> Self {
|
||||||
Self { slime }
|
Self { slime }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -497,7 +497,7 @@ pub struct SlimeAttackGoal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SlimeAttackGoal {
|
impl SlimeAttackGoal {
|
||||||
pub fn new(slime: Arc<SlimeEntity>) -> Self {
|
pub const fn new(slime: Arc<SlimeEntity>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
slime,
|
slime,
|
||||||
grow_tired_timer: 0,
|
grow_tired_timer: 0,
|
||||||
@ -558,7 +558,7 @@ pub struct SlimeRandomDirectionGoal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SlimeRandomDirectionGoal {
|
impl SlimeRandomDirectionGoal {
|
||||||
pub fn new(slime: Arc<SlimeEntity>) -> Self {
|
pub const fn new(slime: Arc<SlimeEntity>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
slime,
|
slime,
|
||||||
chosen_degrees: 0.0,
|
chosen_degrees: 0.0,
|
||||||
@ -618,7 +618,7 @@ pub struct SlimeKeepOnJumpingGoal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SlimeKeepOnJumpingGoal {
|
impl SlimeKeepOnJumpingGoal {
|
||||||
pub fn new(slime: Arc<SlimeEntity>) -> Self {
|
pub const fn new(slime: Arc<SlimeEntity>) -> Self {
|
||||||
Self { slime }
|
Self { slime }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -221,6 +221,24 @@ impl Server {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let dimensions = {
|
||||||
|
let mut dimensions = vec![Dimension::OVERWORLD];
|
||||||
|
if basic_config.allow_nether {
|
||||||
|
dimensions.push(Dimension::THE_NETHER);
|
||||||
|
}
|
||||||
|
if basic_config.allow_end {
|
||||||
|
dimensions.push(Dimension::THE_END);
|
||||||
|
}
|
||||||
|
dimensions
|
||||||
|
};
|
||||||
|
info!(
|
||||||
|
"Enabled dimensions: {:?}",
|
||||||
|
dimensions
|
||||||
|
.iter()
|
||||||
|
.map(|d| d.minecraft_name)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
|
||||||
let server = Self {
|
let server = Self {
|
||||||
basic_config,
|
basic_config,
|
||||||
advanced_config,
|
advanced_config,
|
||||||
@ -234,11 +252,7 @@ impl Server {
|
|||||||
recipe_manager: Arc::new(recipe::RecipeManager::new()),
|
recipe_manager: Arc::new(recipe::RecipeManager::new()),
|
||||||
map_id: level_info.load().map_id.into(),
|
map_id: level_info.load().map_id.into(),
|
||||||
worlds: ArcSwap::from_pointee(vec![]),
|
worlds: ArcSwap::from_pointee(vec![]),
|
||||||
dimensions: vec![
|
dimensions,
|
||||||
Dimension::OVERWORLD,
|
|
||||||
Dimension::THE_NETHER,
|
|
||||||
Dimension::THE_END,
|
|
||||||
],
|
|
||||||
command_dispatcher,
|
command_dispatcher,
|
||||||
block_registry: block_registry.clone(),
|
block_registry: block_registry.clone(),
|
||||||
item_registry: super::item::items::default_registry(),
|
item_registry: super::item::items::default_registry(),
|
||||||
@ -305,18 +319,19 @@ impl Server {
|
|||||||
};
|
};
|
||||||
|
|
||||||
info!("Starting parallel world load...");
|
info!("Starting parallel world load...");
|
||||||
let (overworld, nether, end, keys) = tokio::join!(
|
let mut world_futures = Vec::new();
|
||||||
world_loader(Dimension::OVERWORLD),
|
for dim in &server.dimensions {
|
||||||
world_loader(Dimension::THE_NETHER),
|
world_futures.push(world_loader(dim.clone()));
|
||||||
world_loader(Dimension::THE_END),
|
}
|
||||||
mojang_keys_task
|
|
||||||
);
|
let (worlds_results, keys) =
|
||||||
|
tokio::join!(futures::future::join_all(world_futures), mojang_keys_task);
|
||||||
|
|
||||||
|
let mut worlds_vec = Vec::new();
|
||||||
|
for world_result in worlds_results {
|
||||||
|
worlds_vec.push(world_result.expect("World loading panicked"));
|
||||||
|
}
|
||||||
|
|
||||||
let worlds_vec = vec![
|
|
||||||
overworld.expect("Overworld panicked"),
|
|
||||||
nether.expect("Nether panicked"),
|
|
||||||
end.expect("End panicked"),
|
|
||||||
];
|
|
||||||
server.worlds.store(Arc::new(worlds_vec));
|
server.worlds.store(Arc::new(worlds_vec));
|
||||||
if let Ok(k) = keys {
|
if let Ok(k) = keys {
|
||||||
server.mojang_public_keys.store(Arc::new(k));
|
server.mojang_public_keys.store(Arc::new(k));
|
||||||
@ -354,18 +369,18 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_world_from_dimension(&self, dimension: &Dimension) -> Arc<World> {
|
pub fn get_world_from_dimension(&self, dimension: &Dimension) -> Arc<World> {
|
||||||
// TODO: this is really bad
|
self.worlds
|
||||||
let world_guard = self.worlds.load();
|
.load()
|
||||||
|
.iter()
|
||||||
if dimension == &Dimension::OVERWORLD {
|
.find(|w| w.dimension.minecraft_name == dimension.minecraft_name)
|
||||||
world_guard.first()
|
|
||||||
} else if dimension == &Dimension::THE_NETHER {
|
|
||||||
world_guard.get(1)
|
|
||||||
} else {
|
|
||||||
world_guard.get(2)
|
|
||||||
}
|
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap()
|
.unwrap_or_else(|| {
|
||||||
|
self.worlds
|
||||||
|
.load()
|
||||||
|
.first()
|
||||||
|
.expect("Default world should exist")
|
||||||
|
.clone()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_world(self: &Arc<Self>, name: String, dimension: Dimension) -> Arc<World> {
|
pub async fn create_world(self: &Arc<Self>, name: String, dimension: Dimension) -> Arc<World> {
|
||||||
|
|||||||
@ -232,6 +232,45 @@ impl PartialEq for World {
|
|||||||
impl Eq for World {}
|
impl Eq for World {}
|
||||||
|
|
||||||
impl World {
|
impl World {
|
||||||
|
pub async fn get_block_state_id_async(&self, position: &BlockPos) -> BlockStateId {
|
||||||
|
if !self.is_in_build_limit(*position) {
|
||||||
|
return Block::AIR.default_state.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (chunk_coordinate, relative) = position.chunk_and_chunk_relative_position();
|
||||||
|
self.level
|
||||||
|
.get_or_fetch_chunk(chunk_coordinate, |chunk| {
|
||||||
|
chunk
|
||||||
|
.section
|
||||||
|
.get_block_absolute_y(relative.x as usize, relative.y, relative.z as usize)
|
||||||
|
.unwrap_or(Block::AIR.default_state.id)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_block_state_async(&self, position: &BlockPos) -> &'static BlockState {
|
||||||
|
let id = self.get_block_state_id_async(position).await;
|
||||||
|
BlockState::from_id(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_heightmap_height_async(
|
||||||
|
&self,
|
||||||
|
height_map: ChunkHeightmapType,
|
||||||
|
x: i32,
|
||||||
|
z: i32,
|
||||||
|
) -> i32 {
|
||||||
|
let chunk_pos = Vector2::new(x >> 4, z >> 4);
|
||||||
|
self.level
|
||||||
|
.get_or_fetch_chunk(chunk_pos, |chunk| {
|
||||||
|
chunk
|
||||||
|
.heightmap
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.get(height_map, x, z, self.min_y)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn load(
|
pub fn load(
|
||||||
level: Arc<Level>,
|
level: Arc<Level>,
|
||||||
@ -245,8 +284,8 @@ impl World {
|
|||||||
|
|
||||||
// Load portal POI from disk (PoiStorage::new automatically loads from disk if files exist)
|
// Load portal POI from disk (PoiStorage::new automatically loads from disk if files exist)
|
||||||
let portal_poi = portal::PortalPoiStorage::new(&level.level_folder.root_folder);
|
let portal_poi = portal::PortalPoiStorage::new(&level.level_folder.root_folder);
|
||||||
let dragon_fight =
|
let dragon_fight = (dimension.minecraft_name == Dimension::THE_END.minecraft_name)
|
||||||
(dimension == Dimension::THE_END).then(|| Mutex::new(dragon_fight::DragonFight::new()));
|
.then(|| Mutex::new(dragon_fight::DragonFight::new()));
|
||||||
Self {
|
Self {
|
||||||
uuid: Uuid::new_v4(),
|
uuid: Uuid::new_v4(),
|
||||||
level,
|
level,
|
||||||
|
|||||||
@ -12,7 +12,7 @@ use pumpkin_world::{chunk::ChunkHeightmapType, world::BlockFlags};
|
|||||||
|
|
||||||
use crate::world::World;
|
use crate::world::World;
|
||||||
|
|
||||||
const SEARCH_RADIUS_NETHER: i32 = 16;
|
const SEARCH_RADIUS_NETHER: i32 = 128;
|
||||||
const SEARCH_RADIUS_OVERWORLD: i32 = 128;
|
const SEARCH_RADIUS_OVERWORLD: i32 = 128;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -467,6 +467,11 @@ impl NetherPortal {
|
|||||||
world: &Arc<World>,
|
world: &Arc<World>,
|
||||||
target_pos: BlockPos,
|
target_pos: BlockPos,
|
||||||
) -> Option<PortalSearchResult> {
|
) -> Option<PortalSearchResult> {
|
||||||
|
tracing::debug!(
|
||||||
|
"Searching for portal in {:?} around {:?}",
|
||||||
|
world.dimension.minecraft_name,
|
||||||
|
target_pos
|
||||||
|
);
|
||||||
let min_y = world.min_y;
|
let min_y = world.min_y;
|
||||||
let max_y = min_y + world.dimension.height - 1;
|
let max_y = min_y + world.dimension.height - 1;
|
||||||
let worldborder = world.worldborder.lock().await;
|
let worldborder = world.worldborder.lock().await;
|
||||||
@ -545,6 +550,11 @@ impl NetherPortal {
|
|||||||
target_pos: BlockPos,
|
target_pos: BlockPos,
|
||||||
axis: HorizontalAxis,
|
axis: HorizontalAxis,
|
||||||
) -> Option<(BlockPos, HorizontalAxis, bool)> {
|
) -> Option<(BlockPos, HorizontalAxis, bool)> {
|
||||||
|
tracing::debug!(
|
||||||
|
"Finding safe location for portal in {:?} around {:?}",
|
||||||
|
world.dimension.minecraft_name,
|
||||||
|
target_pos
|
||||||
|
);
|
||||||
let min_y = world.min_y;
|
let min_y = world.min_y;
|
||||||
let max_y = min_y + world.dimension.height - 1;
|
let max_y = min_y + world.dimension.height - 1;
|
||||||
let worldborder = world.worldborder.lock().await;
|
let worldborder = world.worldborder.lock().await;
|
||||||
@ -564,8 +574,8 @@ impl NetherPortal {
|
|||||||
let mut ideal_pos: Option<(BlockPos, HorizontalAxis, f64)> = None;
|
let mut ideal_pos: Option<(BlockPos, HorizontalAxis, f64)> = None;
|
||||||
let mut acceptable_pos: Option<(BlockPos, HorizontalAxis, f64)> = None;
|
let mut acceptable_pos: Option<(BlockPos, HorizontalAxis, f64)> = None;
|
||||||
|
|
||||||
for offset_x in -16..=16 {
|
for offset_x in -32..=32 {
|
||||||
for offset_z in -16..=16 {
|
for offset_z in -32..=32 {
|
||||||
let check_x = target_pos.0.x + offset_x;
|
let check_x = target_pos.0.x + offset_x;
|
||||||
let check_z = target_pos.0.z + offset_z;
|
let check_z = target_pos.0.z + offset_z;
|
||||||
|
|
||||||
@ -579,23 +589,25 @@ impl NetherPortal {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let heightmap_y = world.get_heightmap_height(
|
let heightmap_y = world
|
||||||
|
.get_heightmap_height_async(
|
||||||
ChunkHeightmapType::MotionBlocking,
|
ChunkHeightmapType::MotionBlocking,
|
||||||
check_x,
|
check_x,
|
||||||
check_z,
|
check_z,
|
||||||
);
|
)
|
||||||
|
.await;
|
||||||
let start_y = heightmap_y.min(top_y_limit);
|
let start_y = heightmap_y.min(top_y_limit);
|
||||||
|
|
||||||
let mut y = start_y;
|
let mut y = start_y;
|
||||||
while y >= min_y {
|
while y >= min_y {
|
||||||
let pos = BlockPos(Vector3::new(check_x, y, check_z));
|
let pos = BlockPos(Vector3::new(check_x, y, check_z));
|
||||||
let state = world.get_block_state(&pos);
|
let state = world.get_block_state_async(&pos).await;
|
||||||
|
|
||||||
if Self::is_valid_portal_air(state) {
|
if Self::is_valid_portal_air(state) {
|
||||||
let mut bottom_y = y;
|
let mut bottom_y = y;
|
||||||
while bottom_y > min_y {
|
while bottom_y > min_y {
|
||||||
let below = BlockPos(Vector3::new(check_x, bottom_y - 1, check_z));
|
let below = BlockPos(Vector3::new(check_x, bottom_y - 1, check_z));
|
||||||
let below_state = world.get_block_state(&below);
|
let below_state = world.get_block_state_async(&below).await;
|
||||||
if !Self::is_valid_portal_air(below_state) {
|
if !Self::is_valid_portal_air(below_state) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -607,18 +619,23 @@ impl NetherPortal {
|
|||||||
let floor_pos = BlockPos(Vector3::new(check_x, bottom_y, check_z));
|
let floor_pos = BlockPos(Vector3::new(check_x, bottom_y, check_z));
|
||||||
|
|
||||||
for check_axis in [HorizontalAxis::X, HorizontalAxis::Z] {
|
for check_axis in [HorizontalAxis::X, HorizontalAxis::Z] {
|
||||||
if Self::is_valid_portal_pos(world, floor_pos, check_axis, 0) {
|
if Self::is_valid_portal_pos_async(world, floor_pos, check_axis, 0)
|
||||||
|
.await
|
||||||
|
{
|
||||||
let dist = f64::from(target_pos.0.squared_distance_to(
|
let dist = f64::from(target_pos.0.squared_distance_to(
|
||||||
floor_pos.0.x,
|
floor_pos.0.x,
|
||||||
floor_pos.0.y,
|
floor_pos.0.y,
|
||||||
floor_pos.0.z,
|
floor_pos.0.z,
|
||||||
));
|
));
|
||||||
|
|
||||||
let is_ideal =
|
let is_ideal = Self::is_valid_portal_pos_async(
|
||||||
Self::is_valid_portal_pos(world, floor_pos, check_axis, -1)
|
world, floor_pos, check_axis, -1,
|
||||||
&& Self::is_valid_portal_pos(
|
)
|
||||||
|
.await
|
||||||
|
&& Self::is_valid_portal_pos_async(
|
||||||
world, floor_pos, check_axis, 1,
|
world, floor_pos, check_axis, 1,
|
||||||
);
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
if is_ideal {
|
if is_ideal {
|
||||||
if ideal_pos.is_none()
|
if ideal_pos.is_none()
|
||||||
@ -669,7 +686,7 @@ impl NetherPortal {
|
|||||||
state.replaceable() && !state.is_liquid()
|
state.replaceable() && !state.is_liquid()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_valid_portal_pos(
|
async fn is_valid_portal_pos_async(
|
||||||
world: &Arc<World>,
|
world: &Arc<World>,
|
||||||
floor_pos: BlockPos,
|
floor_pos: BlockPos,
|
||||||
axis: HorizontalAxis,
|
axis: HorizontalAxis,
|
||||||
@ -693,7 +710,7 @@ impl NetherPortal {
|
|||||||
.offset_dir(perpendicular.to_offset(), perpendicular_offset)
|
.offset_dir(perpendicular.to_offset(), perpendicular_offset)
|
||||||
.offset_dir(BlockDirection::Up.to_offset(), height);
|
.offset_dir(BlockDirection::Up.to_offset(), height);
|
||||||
|
|
||||||
let state = world.get_block_state(&pos);
|
let state = world.get_block_state_async(&pos).await;
|
||||||
|
|
||||||
if height < 0 {
|
if height < 0 {
|
||||||
if !state.is_solid_block() {
|
if !state.is_solid_block() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user