use crate::generator::{BlockPosition, Generator};
use bitflags::bitflags;
use cubiomes_sys::enums::{self};
use enums::StructureType;
use std::mem::{transmute, MaybeUninit};
use thiserror::Error;
pub mod strongholds;
#[cfg(test)]
mod test;
#[derive(Error, Debug, PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)]
pub enum StructureGenerationError {
#[error("Underlying library cubiomes returned a bool that is not 0 or 1.")]
CubiomesError,
}
bitflags! {struct StructureFlags: u32{}}
impl Generator {
pub fn try_generate_structure_in_region(
&mut self,
region_pos: StructureRegion,
) -> Option<BlockPosition> {
assert_eq!(self.minecraft_version(), region_pos.minecraft_version);
let pos = self.get_structure_generation_attempt(region_pos)?;
if self
.verify_structure_generation_attempt(pos, region_pos.structure_type)
.ok()?
{
return Some(pos);
}
None
}
pub fn verify_structure_generation_attempt(
&mut self,
pos: BlockPosition,
structure_type: StructureType,
) -> Result<bool, StructureGenerationError> {
match unsafe {
cubiomes_sys::isViableStructurePos(
structure_type as i32,
self.as_mut_ptr(),
pos.x,
pos.z,
StructureFlags::empty().bits(),
)
} {
0 => Ok(false),
1 => Ok(true),
_ => Err(StructureGenerationError::CubiomesError),
}
}
fn get_structure_generation_attempt(
&self,
region_pos: StructureRegion,
) -> Option<BlockPosition> {
let seed = self.seed();
region_pos.get_structure_generation_attempt(seed)
}
}
#[doc = include_str!("../../examples/find_structures.rs")]
#[doc = include_str!("../../examples/efficient_structure_hunting.rs")]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
pub struct StructureRegion {
pub x: i32,
pub z: i32,
region_size: i8,
pub(crate) minecraft_version: enums::MCVersion,
pub(crate) structure_type: enums::StructureType,
}
impl StructureRegion {
pub fn new(
region_x: i32,
region_z: i32,
minecraft_version: enums::MCVersion,
structure_type: enums::StructureType,
) -> Result<Self, StructureGenerationError> {
let region_scale = get_structure_scale(structure_type, minecraft_version)?;
Ok(Self {
x: region_x,
z: region_z,
region_size: region_scale,
minecraft_version,
structure_type,
})
}
pub fn from_block_position(
pos: BlockPosition,
minecraft_version: enums::MCVersion,
structure_type: enums::StructureType,
) -> Result<Self, StructureGenerationError> {
let region_scale = get_structure_scale(structure_type, minecraft_version)?;
let (x, z) = pos.scale_by_num((region_scale as i32) * 16);
Ok(Self {
x,
z,
region_size: region_scale,
minecraft_version,
structure_type,
})
}
#[must_use]
pub fn get_structure_generation_attempt(&self, seed: i64) -> Option<BlockPosition> {
let minecraft_version = self.minecraft_version;
let mut pos: MaybeUninit<cubiomes_sys::Pos> = MaybeUninit::uninit();
if unsafe {
cubiomes_sys::getStructurePos(
self.structure_type as i32,
minecraft_version as i32,
transmute::<i64, u64>(seed),
self.x,
self.z,
pos.as_mut_ptr(),
)
} == 0
{
return None;
}
Some(unsafe { pos.assume_init() }.into())
}
pub fn set_new_minecraft_pos(&mut self, pos: BlockPosition) {
(self.x, self.z) = pos.scale_by_num(self.region_size as i32);
}
#[inline]
#[must_use]
pub const fn region_size_chunks(&self) -> i32 {
self.region_size as i32
}
#[inline]
#[must_use]
pub const fn region_size_blocks(&self) -> i32 {
(self.region_size as i32) * 16
}
#[inline]
#[must_use]
pub const fn minecraft_verions(&self) -> enums::MCVersion {
self.minecraft_version
}
#[inline]
#[must_use]
pub const fn structure_type(&self) -> enums::StructureType {
self.structure_type
}
}
fn get_structure_scale(
structure_type: enums::StructureType,
minecraft_version: enums::MCVersion,
) -> Result<i8, StructureGenerationError> {
let mut sconf: MaybeUninit<cubiomes_sys::StructureConfig> = MaybeUninit::uninit();
unsafe {
match cubiomes_sys::getStructureConfig(
structure_type as i32,
minecraft_version as i32,
sconf.as_mut_ptr(),
) {
0 => Err(StructureGenerationError::CubiomesError),
_ => Ok(sconf.assume_init().regionSize),
}
}
}