Prepare chunk entity generation
Also switch to strip_prefix instead of replace, much more efficient
This commit is contained in:
parent
25e3286476
commit
1a736267ba
File diff suppressed because it is too large
Load Diff
@ -14,9 +14,39 @@ struct Biome {
|
|||||||
temperature_modifier: Option<TemperatureModifier>,
|
temperature_modifier: Option<TemperatureModifier>,
|
||||||
//carvers: Vec<String>,
|
//carvers: Vec<String>,
|
||||||
features: Vec<Vec<String>>,
|
features: Vec<Vec<String>>,
|
||||||
|
creature_spawn_probability: Option<f32>,
|
||||||
|
spawners: SpawnGroups,
|
||||||
id: u8,
|
id: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, PartialEq, Eq, Hash)]
|
||||||
|
struct SpawnGroups {
|
||||||
|
monster: Vec<Spawner>,
|
||||||
|
ambient: Vec<Spawner>,
|
||||||
|
axolotls: Vec<Spawner>,
|
||||||
|
creature: Vec<Spawner>,
|
||||||
|
misc: Vec<Spawner>,
|
||||||
|
underground_water_creature: Vec<Spawner>,
|
||||||
|
water_ambient: Vec<Spawner>,
|
||||||
|
water_creature: Vec<Spawner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Hash, PartialEq, Eq)]
|
||||||
|
struct Spawner {
|
||||||
|
r#type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Spawner {
|
||||||
|
pub fn to_tokens(&self) -> TokenStream {
|
||||||
|
let r#type = &self.r#type;
|
||||||
|
quote! {
|
||||||
|
Spawner {
|
||||||
|
r#type: #r#type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone)]
|
#[derive(Deserialize, Clone)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
enum TemperatureModifier {
|
enum TemperatureModifier {
|
||||||
@ -123,11 +153,70 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let downfall = biome.downfall;
|
let downfall = biome.downfall;
|
||||||
// let carvers = &biome.carvers;
|
// let carvers = &biome.carvers;
|
||||||
let features = &biome.features;
|
let features = &biome.features;
|
||||||
|
let creature_spawn_probability = &biome.creature_spawn_probability.unwrap_or(0.1);
|
||||||
|
|
||||||
let temperature_modifier = biome
|
let temperature_modifier = biome
|
||||||
.temperature_modifier
|
.temperature_modifier
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or(TemperatureModifier::None);
|
.unwrap_or(TemperatureModifier::None);
|
||||||
|
|
||||||
|
let monster: Vec<_> = biome
|
||||||
|
.spawners
|
||||||
|
.monster
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_tokens())
|
||||||
|
.collect();
|
||||||
|
let ambient: Vec<_> = biome
|
||||||
|
.spawners
|
||||||
|
.ambient
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_tokens())
|
||||||
|
.collect();
|
||||||
|
let axolotls: Vec<_> = biome
|
||||||
|
.spawners
|
||||||
|
.axolotls
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_tokens())
|
||||||
|
.collect();
|
||||||
|
let creature: Vec<_> = biome
|
||||||
|
.spawners
|
||||||
|
.creature
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_tokens())
|
||||||
|
.collect();
|
||||||
|
let misc: Vec<_> = biome.spawners.misc.iter().map(|s| s.to_tokens()).collect();
|
||||||
|
let underground_water_creature: Vec<_> = biome
|
||||||
|
.spawners
|
||||||
|
.underground_water_creature
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_tokens())
|
||||||
|
.collect();
|
||||||
|
let water_ambient: Vec<_> = biome
|
||||||
|
.spawners
|
||||||
|
.water_ambient
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_tokens())
|
||||||
|
.collect();
|
||||||
|
let water_creature: Vec<_> = biome
|
||||||
|
.spawners
|
||||||
|
.water_creature
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_tokens())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let spawners = quote! {
|
||||||
|
SpawnGroups {
|
||||||
|
monster: &[#(#monster),*],
|
||||||
|
ambient: &[#(#ambient),*],
|
||||||
|
axolotls: &[#(#axolotls),*],
|
||||||
|
creature: &[#(#creature),*],
|
||||||
|
misc: &[#(#misc),*],
|
||||||
|
underground_water_creature: &[#(#underground_water_creature),*],
|
||||||
|
water_ambient: &[#(#water_ambient),*],
|
||||||
|
water_creature: &[#(#water_creature),*],
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let temperature_modifier = match temperature_modifier {
|
let temperature_modifier = match temperature_modifier {
|
||||||
TemperatureModifier::Frozen => quote! { TemperatureModifier::Frozen },
|
TemperatureModifier::Frozen => quote! { TemperatureModifier::Frozen },
|
||||||
TemperatureModifier::None => quote! { TemperatureModifier::None },
|
TemperatureModifier::None => quote! { TemperatureModifier::None },
|
||||||
@ -144,7 +233,9 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
#temperature_modifier,
|
#temperature_modifier,
|
||||||
#downfall
|
#downfall
|
||||||
),
|
),
|
||||||
features: &[#(&[#(#features),*]),*]
|
features: &[#(&[#(#features),*]),*],
|
||||||
|
creature_spawn_probability: #creature_spawn_probability,
|
||||||
|
spawners: #spawners,
|
||||||
};
|
};
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
@ -154,188 +245,207 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
|
|
||||||
let overworld_tree = biome_trees.overworld.into_token_stream();
|
let overworld_tree = biome_trees.overworld.into_token_stream();
|
||||||
let nether_tree = biome_trees.nether.into_token_stream();
|
let nether_tree = biome_trees.nether.into_token_stream();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
use pumpkin_util::biome::{TemperatureModifier, Weather};
|
|
||||||
use serde::{Deserializer, de};
|
|
||||||
use crate::biome::de::Deserialize;
|
|
||||||
use std::{fmt, hash::{Hasher, Hash}};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
use pumpkin_util::biome::{TemperatureModifier, Weather};
|
||||||
pub struct Biome {
|
use serde::{Deserializer, de};
|
||||||
pub id: u8,
|
use crate::biome::de::Deserialize;
|
||||||
pub registry_id: &'static str,
|
use std::{fmt, hash::{Hasher, Hash}};
|
||||||
pub weather: Weather,
|
|
||||||
// carvers: &'static [&str],
|
|
||||||
pub features: &'static [&'static [&'static str]]
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Biome {
|
#[derive(Debug)]
|
||||||
fn eq(&self, other: &Biome) -> bool {
|
pub struct Biome {
|
||||||
self.id == other.id
|
pub id: u8,
|
||||||
|
pub registry_id: &'static str,
|
||||||
|
pub weather: Weather,
|
||||||
|
// carvers: &'static [&str],
|
||||||
|
pub features: &'static [&'static [&'static str]],
|
||||||
|
pub creature_spawn_probability: f32,
|
||||||
|
pub spawners: SpawnGroups,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for Biome {}
|
#[derive(Debug)]
|
||||||
|
pub struct SpawnGroups {
|
||||||
impl Hash for Biome {
|
pub monster: &'static [Spawner],
|
||||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
pub ambient: &'static [Spawner],
|
||||||
self.id.hash(state);
|
pub axolotls: &'static [Spawner],
|
||||||
|
pub creature: &'static [Spawner],
|
||||||
|
pub misc: &'static [Spawner],
|
||||||
|
pub underground_water_creature: &'static [Spawner],
|
||||||
|
pub water_ambient: &'static [Spawner],
|
||||||
|
pub water_creature: &'static [Spawner],
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for &'static Biome {
|
#[derive(Debug)]
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
pub struct Spawner {
|
||||||
where
|
pub r#type: &'static str,
|
||||||
D: Deserializer<'de>,
|
}
|
||||||
{
|
|
||||||
struct BiomeVisitor;
|
|
||||||
|
|
||||||
impl de::Visitor<'_> for BiomeVisitor {
|
impl PartialEq for Biome {
|
||||||
type Value = &'static Biome;
|
fn eq(&self, other: &Biome) -> bool {
|
||||||
|
self.id == other.id
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
formatter.write_str("a biome name as a string")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: serde::de::Error,
|
|
||||||
{
|
|
||||||
self.visit_str(&v)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
let biome = Biome::from_name(value.strip_prefix("minecraft:").unwrap_or(value));
|
|
||||||
biome.ok_or_else(|| E::unknown_variant(value, &["unknown biome"]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_str(BiomeVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Biome {
|
|
||||||
#variants
|
|
||||||
|
|
||||||
pub fn from_name(name: &str) -> Option<&'static Self> {
|
|
||||||
match name {
|
|
||||||
#name_to_type
|
|
||||||
_ => None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn from_id(id: u8) -> Option<&'static Self> {
|
impl Eq for Biome {}
|
||||||
match id {
|
|
||||||
#id_to_type
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
impl Hash for Biome {
|
||||||
pub struct ParameterRange {
|
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
||||||
min: i64,
|
self.id.hash(state);
|
||||||
max: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParameterRange {
|
|
||||||
fn calc_distance(&self, noise: i64) -> i64 {
|
|
||||||
if noise > self.max {
|
|
||||||
noise - self.max
|
|
||||||
} else if noise < self.min {
|
|
||||||
self.min - noise
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
pub enum BiomeTree {
|
|
||||||
Leaf {
|
|
||||||
parameters: [ParameterRange; 7],
|
|
||||||
biome: &'static Biome,
|
|
||||||
},
|
|
||||||
Branch {
|
|
||||||
parameters: [ParameterRange; 7],
|
|
||||||
nodes: &'static [BiomeTree],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl BiomeTree {
|
|
||||||
pub fn get(
|
|
||||||
&'static self,
|
|
||||||
point_list: &[i64; 7],
|
|
||||||
previous_result_node: &mut Option<&'static BiomeTree>,
|
|
||||||
) -> &'static Biome {
|
|
||||||
let result_node = self.get_resulting_node(point_list, *previous_result_node);
|
|
||||||
match result_node {
|
|
||||||
BiomeTree::Leaf { biome, .. } => {
|
|
||||||
*previous_result_node = Some(result_node);
|
|
||||||
biome
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_resulting_node(
|
impl<'de> Deserialize<'de> for &'static Biome {
|
||||||
&'static self,
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
point_list: &[i64; 7],
|
where
|
||||||
previous_result_node: Option<&'static BiomeTree>,
|
D: Deserializer<'de>,
|
||||||
) -> &'static BiomeTree {
|
{
|
||||||
match self {
|
struct BiomeVisitor;
|
||||||
Self::Leaf { .. } => self,
|
|
||||||
Self::Branch { nodes, .. } => {
|
|
||||||
let mut distance = previous_result_node
|
|
||||||
.map(|node| node.get_squared_distance(point_list))
|
|
||||||
.unwrap_or(i64::MAX);
|
|
||||||
let mut best_node = previous_result_node;
|
|
||||||
|
|
||||||
for node in *nodes {
|
impl de::Visitor<'_> for BiomeVisitor {
|
||||||
let node_distance = node.get_squared_distance(point_list);
|
type Value = &'static Biome;
|
||||||
if distance > node_distance {
|
|
||||||
let node2 = node.get_resulting_node(point_list, best_node);
|
|
||||||
let node2_distance = if node == node2 {
|
|
||||||
node_distance
|
|
||||||
} else {
|
|
||||||
node2.get_squared_distance(point_list)
|
|
||||||
};
|
|
||||||
|
|
||||||
if distance > node2_distance {
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
distance = node2_distance;
|
formatter.write_str("a biome name as a string")
|
||||||
best_node = Some(node2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
best_node.expect("This should be populated after traversing the tree")
|
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
self.visit_str(&v)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
let biome = Biome::from_name(value.strip_prefix("minecraft:").unwrap_or(value));
|
||||||
|
biome.ok_or_else(|| E::unknown_variant(value, &["unknown biome"]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_str(BiomeVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Biome {
|
||||||
|
#variants
|
||||||
|
|
||||||
|
pub fn from_name(name: &str) -> Option<&'static Self> {
|
||||||
|
match name {
|
||||||
|
#name_to_type
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn from_id(id: u8) -> Option<&'static Self> {
|
||||||
|
match id {
|
||||||
|
#id_to_type
|
||||||
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_squared_distance(&self, point_list: &[i64; 7]) -> i64 {
|
#[derive(PartialEq)]
|
||||||
let parameters = match self {
|
pub struct ParameterRange {
|
||||||
Self::Leaf { parameters, .. } => parameters,
|
min: i64,
|
||||||
Self::Branch { parameters, .. } => parameters,
|
max: i64,
|
||||||
};
|
|
||||||
|
|
||||||
parameters
|
|
||||||
.iter()
|
|
||||||
.zip(point_list)
|
|
||||||
.map(|(bound, value)| {
|
|
||||||
let distance = bound.calc_distance(*value);
|
|
||||||
distance * distance
|
|
||||||
})
|
|
||||||
.sum()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub const OVERWORLD_BIOME_SOURCE: BiomeTree = #overworld_tree;
|
impl ParameterRange {
|
||||||
pub const NETHER_BIOME_SOURCE: BiomeTree = #nether_tree;
|
fn calc_distance(&self, noise: i64) -> i64 {
|
||||||
}
|
if noise > self.max {
|
||||||
|
noise - self.max
|
||||||
|
} else if noise < self.min {
|
||||||
|
self.min - noise
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub enum BiomeTree {
|
||||||
|
Leaf {
|
||||||
|
parameters: [ParameterRange; 7],
|
||||||
|
biome: &'static Biome,
|
||||||
|
},
|
||||||
|
Branch {
|
||||||
|
parameters: [ParameterRange; 7],
|
||||||
|
nodes: &'static [BiomeTree],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl BiomeTree {
|
||||||
|
pub fn get(
|
||||||
|
&'static self,
|
||||||
|
point_list: &[i64; 7],
|
||||||
|
previous_result_node: &mut Option<&'static BiomeTree>,
|
||||||
|
) -> &'static Biome {
|
||||||
|
let result_node = self.get_resulting_node(point_list, *previous_result_node);
|
||||||
|
match result_node {
|
||||||
|
BiomeTree::Leaf { biome, .. } => {
|
||||||
|
*previous_result_node = Some(result_node);
|
||||||
|
biome
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_resulting_node(
|
||||||
|
&'static self,
|
||||||
|
point_list: &[i64; 7],
|
||||||
|
previous_result_node: Option<&'static BiomeTree>,
|
||||||
|
) -> &'static BiomeTree {
|
||||||
|
match self {
|
||||||
|
Self::Leaf { .. } => self,
|
||||||
|
Self::Branch { nodes, .. } => {
|
||||||
|
let mut distance = previous_result_node
|
||||||
|
.map(|node| node.get_squared_distance(point_list))
|
||||||
|
.unwrap_or(i64::MAX);
|
||||||
|
let mut best_node = previous_result_node;
|
||||||
|
|
||||||
|
for node in *nodes {
|
||||||
|
let node_distance = node.get_squared_distance(point_list);
|
||||||
|
if distance > node_distance {
|
||||||
|
let node2 = node.get_resulting_node(point_list, best_node);
|
||||||
|
let node2_distance = if node == node2 {
|
||||||
|
node_distance
|
||||||
|
} else {
|
||||||
|
node2.get_squared_distance(point_list)
|
||||||
|
};
|
||||||
|
|
||||||
|
if distance > node2_distance {
|
||||||
|
distance = node2_distance;
|
||||||
|
best_node = Some(node2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
best_node.expect("This should be populated after traversing the tree")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_squared_distance(&self, point_list: &[i64; 7]) -> i64 {
|
||||||
|
let parameters = match self {
|
||||||
|
Self::Leaf { parameters, .. } => parameters,
|
||||||
|
Self::Branch { parameters, .. } => parameters,
|
||||||
|
};
|
||||||
|
|
||||||
|
parameters
|
||||||
|
.iter()
|
||||||
|
.zip(point_list)
|
||||||
|
.map(|(bound, value)| {
|
||||||
|
let distance = bound.calc_distance(*value);
|
||||||
|
distance * distance
|
||||||
|
})
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const OVERWORLD_BIOME_SOURCE: BiomeTree = #overworld_tree;
|
||||||
|
pub const NETHER_BIOME_SOURCE: BiomeTree = #nether_tree;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1368,8 +1368,8 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
];
|
];
|
||||||
|
|
||||||
pub fn get_block(registry_id: &str) -> Option<Block> {
|
pub fn get_block(registry_id: &str) -> Option<Block> {
|
||||||
let key = registry_id.replace("minecraft:", "");
|
let key = registry_id.strip_prefix("minecraft:").unwrap_or(registry_id);
|
||||||
Block::from_registry_key(key.as_str())
|
Block::from_registry_key(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_block_by_id(id: u16) -> Option<Block> {
|
pub fn get_block_by_id(id: u16) -> Option<Block> {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use std::{collections::HashMap, fs};
|
use std::{collections::HashMap, fs};
|
||||||
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
|
use pumpkin_util::HeightMap;
|
||||||
use quote::{ToTokens, format_ident, quote};
|
use quote::{ToTokens, format_ident, quote};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use syn::LitInt;
|
use syn::LitInt;
|
||||||
@ -14,6 +15,22 @@ pub struct EntityType {
|
|||||||
pub fire_immune: bool,
|
pub fire_immune: bool,
|
||||||
pub dimension: [f32; 2],
|
pub dimension: [f32; 2],
|
||||||
pub eye_height: f32,
|
pub eye_height: f32,
|
||||||
|
pub spawn_restriction: SpawnRestriction,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct SpawnRestriction {
|
||||||
|
location: SpawnLocation,
|
||||||
|
heightmap: HeightMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum SpawnLocation {
|
||||||
|
InLava,
|
||||||
|
InWater,
|
||||||
|
OnGround,
|
||||||
|
Unrestricted,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NamedEntityType<'a>(&'a str, &'a EntityType);
|
pub struct NamedEntityType<'a>(&'a str, &'a EntityType);
|
||||||
@ -34,6 +51,27 @@ impl ToTokens for NamedEntityType<'_> {
|
|||||||
None => quote! { None },
|
None => quote! { None },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let spawn_restriction_location = match entity.spawn_restriction.location {
|
||||||
|
SpawnLocation::InLava => quote! {SpawnLocation::InLava},
|
||||||
|
SpawnLocation::InWater => quote! {SpawnLocation::InWater},
|
||||||
|
SpawnLocation::OnGround => quote! {SpawnLocation::OnGround},
|
||||||
|
SpawnLocation::Unrestricted => quote! {SpawnLocation::Unrestricted},
|
||||||
|
};
|
||||||
|
|
||||||
|
let spawn_restriction_heightmap = match entity.spawn_restriction.heightmap {
|
||||||
|
HeightMap::WorldSurfaceWg => quote! { HeightMap::WorldSurfaceWg },
|
||||||
|
HeightMap::WorldSurface => quote! { HeightMap::WorldSurface },
|
||||||
|
HeightMap::OceanFloorWg => quote! { HeightMap::OceanFloorWg },
|
||||||
|
HeightMap::OceanFloor => quote! { HeightMap::OceanFloor },
|
||||||
|
HeightMap::MotionBlocking => quote! { HeightMap::MotionBlocking },
|
||||||
|
HeightMap::MotionBlockingNoLeaves => quote! { HeightMap::MotionBlockingNoLeaves },
|
||||||
|
};
|
||||||
|
|
||||||
|
let spawn_restriction = quote! { SpawnRestriction {
|
||||||
|
location: #spawn_restriction_location,
|
||||||
|
heightmap: #spawn_restriction_heightmap,
|
||||||
|
}};
|
||||||
|
|
||||||
let summonable = entity.summonable;
|
let summonable = entity.summonable;
|
||||||
let fire_immune = entity.fire_immune;
|
let fire_immune = entity.fire_immune;
|
||||||
let eye_height = entity.eye_height;
|
let eye_height = entity.eye_height;
|
||||||
@ -50,6 +88,7 @@ impl ToTokens for NamedEntityType<'_> {
|
|||||||
fire_immune: #fire_immune,
|
fire_immune: #fire_immune,
|
||||||
dimension: [#dimension0, #dimension1], // Correctly construct the array
|
dimension: [#dimension0, #dimension1], // Correctly construct the array
|
||||||
eye_height: #eye_height,
|
eye_height: #eye_height,
|
||||||
|
spawn_restriction: #spawn_restriction,
|
||||||
resource_name: #name,
|
resource_name: #name,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -87,6 +126,8 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
quote! {
|
quote! {
|
||||||
|
use pumpkin_util::HeightMap;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct EntityType {
|
pub struct EntityType {
|
||||||
pub id: u16,
|
pub id: u16,
|
||||||
@ -96,9 +137,24 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
pub fire_immune: bool,
|
pub fire_immune: bool,
|
||||||
pub dimension: [f32; 2],
|
pub dimension: [f32; 2],
|
||||||
pub eye_height: f32,
|
pub eye_height: f32,
|
||||||
|
pub spawn_restriction: SpawnRestriction,
|
||||||
pub resource_name: &'static str,
|
pub resource_name: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct SpawnRestriction {
|
||||||
|
location: SpawnLocation,
|
||||||
|
heightmap: HeightMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum SpawnLocation {
|
||||||
|
InLava,
|
||||||
|
InWater,
|
||||||
|
OnGround,
|
||||||
|
Unrestricted
|
||||||
|
}
|
||||||
|
|
||||||
impl EntityType {
|
impl EntityType {
|
||||||
#consts
|
#consts
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,17 @@ pub mod serde_enum_as_integer;
|
|||||||
pub mod text;
|
pub mod text;
|
||||||
pub mod translation;
|
pub mod translation;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Copy, Debug, PartialEq)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum HeightMap {
|
||||||
|
WorldSurfaceWg,
|
||||||
|
WorldSurface,
|
||||||
|
OceanFloorWg,
|
||||||
|
OceanFloor,
|
||||||
|
MotionBlocking,
|
||||||
|
MotionBlockingNoLeaves,
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! global_path {
|
macro_rules! global_path {
|
||||||
($path:expr) => {{
|
($path:expr) => {{
|
||||||
|
|||||||
@ -144,7 +144,9 @@ impl ChunkData {
|
|||||||
delay: tick.delay as u16,
|
delay: tick.delay as u16,
|
||||||
priority: TickPriority::from(tick.priority),
|
priority: TickPriority::from(tick.priority),
|
||||||
target_block_id: Block::from_registry_key(
|
target_block_id: Block::from_registry_key(
|
||||||
&tick.target_block.replace("minecraft:", ""),
|
tick.target_block
|
||||||
|
.strip_prefix("minecraft:")
|
||||||
|
.unwrap_or(&tick.target_block),
|
||||||
)
|
)
|
||||||
.unwrap_or(Block::AIR)
|
.unwrap_or(Block::AIR)
|
||||||
.id,
|
.id,
|
||||||
@ -158,7 +160,9 @@ impl ChunkData {
|
|||||||
delay: tick.delay as u16,
|
delay: tick.delay as u16,
|
||||||
priority: TickPriority::from(tick.priority),
|
priority: TickPriority::from(tick.priority),
|
||||||
target_block_id: Block::from_registry_key(
|
target_block_id: Block::from_registry_key(
|
||||||
&tick.target_block.replace("minecraft:", ""),
|
tick.target_block
|
||||||
|
.strip_prefix("minecraft:")
|
||||||
|
.unwrap_or(&tick.target_block),
|
||||||
)
|
)
|
||||||
.unwrap_or(Block::AIR)
|
.unwrap_or(Block::AIR)
|
||||||
.id,
|
.id,
|
||||||
|
|||||||
@ -84,11 +84,11 @@ impl MatchingBlocksBlockPredicate {
|
|||||||
let block = self.offset.get_block(chunk, pos);
|
let block = self.offset.get_block(chunk, pos);
|
||||||
match &self.blocks {
|
match &self.blocks {
|
||||||
MatchingBlocksWrapper::Single(single_block) => {
|
MatchingBlocksWrapper::Single(single_block) => {
|
||||||
single_block.replace("minecraft:", "") == block.name
|
single_block.strip_prefix("minecraft:").unwrap() == block.name
|
||||||
}
|
}
|
||||||
MatchingBlocksWrapper::Multiple(blocks) => blocks
|
MatchingBlocksWrapper::Multiple(blocks) => blocks
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.replace("minecraft:", ""))
|
.map(|s| s.strip_prefix("minecraft:").unwrap())
|
||||||
.contains(block.name),
|
.contains(block.name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use pumpkin_data::BlockDirection;
|
use pumpkin_data::BlockDirection;
|
||||||
|
use pumpkin_util::HeightMap;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
@ -13,12 +14,12 @@ use pumpkin_util::math::vector2::Vector2;
|
|||||||
use pumpkin_util::math::vector3::Vector3;
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
use pumpkin_util::random::{RandomGenerator, RandomImpl};
|
use pumpkin_util::random::{RandomGenerator, RandomImpl};
|
||||||
|
|
||||||
|
use crate::ProtoChunk;
|
||||||
use crate::generation::block_predicate::BlockPredicate;
|
use crate::generation::block_predicate::BlockPredicate;
|
||||||
use crate::generation::height_limit::HeightLimitView;
|
use crate::generation::height_limit::HeightLimitView;
|
||||||
use crate::generation::height_provider::HeightProvider;
|
use crate::generation::height_provider::HeightProvider;
|
||||||
use crate::level::Level;
|
use crate::level::Level;
|
||||||
use crate::world::BlockRegistryExt;
|
use crate::world::BlockRegistryExt;
|
||||||
use crate::{HeightMap, ProtoChunk};
|
|
||||||
|
|
||||||
use super::configured_features::{CONFIGURED_FEATURES, ConfiguredFeature};
|
use super::configured_features::{CONFIGURED_FEATURES, ConfiguredFeature};
|
||||||
|
|
||||||
|
|||||||
@ -12,12 +12,12 @@ use pumpkin_data::{
|
|||||||
};
|
};
|
||||||
use pumpkin_macros::default_block_state;
|
use pumpkin_macros::default_block_state;
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
|
HeightMap,
|
||||||
math::{position::BlockPos, vector2::Vector2, vector3::Vector3},
|
math::{position::BlockPos, vector2::Vector2, vector3::Vector3},
|
||||||
random::{RandomGenerator, get_decorator_seed, xoroshiro128::Xoroshiro},
|
random::{RandomGenerator, get_decorator_seed, xoroshiro128::Xoroshiro},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
HeightMap,
|
|
||||||
biome::{BiomeSupplier, MultiNoiseBiomeSupplier, end::TheEndBiomeSupplier, hash_seed},
|
biome::{BiomeSupplier, MultiNoiseBiomeSupplier, end::TheEndBiomeSupplier, hash_seed},
|
||||||
block::RawBlockState,
|
block::RawBlockState,
|
||||||
chunk::CHUNK_AREA,
|
chunk::CHUNK_AREA,
|
||||||
@ -547,6 +547,24 @@ impl<'a> ProtoChunk<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_entities(&self) {
|
||||||
|
let start_x = self.start_block_x();
|
||||||
|
let start_z = self.start_block_z();
|
||||||
|
|
||||||
|
let population_seed =
|
||||||
|
Xoroshiro::get_population_seed(self.random_config.seed, start_x, start_z);
|
||||||
|
let _random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(population_seed));
|
||||||
|
let _biome = self.get_biome(&Vector3::new(
|
||||||
|
start_x,
|
||||||
|
self.bottom_section_coord() as i32 + self.height() as i32 - 1,
|
||||||
|
start_z,
|
||||||
|
));
|
||||||
|
// while random.next_f32() < biome.creature_spawn_probability {
|
||||||
|
|
||||||
|
// }
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_biome_for_terrain_gen(&self, global_block_pos: &Vector3<i32>) -> &'static Biome {
|
pub fn get_biome_for_terrain_gen(&self, global_block_pos: &Vector3<i32>) -> &'static Biome {
|
||||||
let seed_biome_pos = biome::get_biome_blend(
|
let seed_biome_pos = biome::get_biome_blend(
|
||||||
self.bottom_y(),
|
self.bottom_y(),
|
||||||
|
|||||||
@ -327,7 +327,7 @@ impl NoiseThresholdMaterialCondition {
|
|||||||
pub fn test(&self, context: &mut MaterialRuleContext) -> bool {
|
pub fn test(&self, context: &mut MaterialRuleContext) -> bool {
|
||||||
let sampler = context
|
let sampler = context
|
||||||
.noise_builder
|
.noise_builder
|
||||||
.get_noise_sampler_for_id(&self.noise.replace("minecraft:", ""));
|
.get_noise_sampler_for_id(self.noise.strip_prefix("minecraft:").unwrap());
|
||||||
let value = sampler.sample(context.block_pos.x as f64, 0.0, context.block_pos.z as f64);
|
let value = sampler.sample(context.block_pos.x as f64, 0.0, context.block_pos.z as f64);
|
||||||
value >= self.min_threshold && value <= self.max_threshold
|
value >= self.min_threshold && value <= self.max_threshold
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,17 +20,6 @@ pub mod world_info;
|
|||||||
pub type BlockId = u16;
|
pub type BlockId = u16;
|
||||||
pub type BlockStateId = u16;
|
pub type BlockStateId = u16;
|
||||||
|
|
||||||
#[derive(Deserialize, Clone)]
|
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
|
||||||
pub enum HeightMap {
|
|
||||||
WorldSurfaceWg,
|
|
||||||
WorldSurface,
|
|
||||||
OceanFloorWg,
|
|
||||||
OceanFloor,
|
|
||||||
MotionBlocking,
|
|
||||||
MotionBlockingNoLeaves,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! global_path {
|
macro_rules! global_path {
|
||||||
($path:expr) => {{
|
($path:expr) => {{
|
||||||
@ -60,8 +49,6 @@ pub use generation::{
|
|||||||
GlobalRandomConfig, noise_router::proto_noise_router::ProtoNoiseRouters,
|
GlobalRandomConfig, noise_router::proto_noise_router::ProtoNoiseRouters,
|
||||||
proto_chunk::ProtoChunk, settings::GENERATION_SETTINGS, settings::GeneratorSetting,
|
proto_chunk::ProtoChunk, settings::GENERATION_SETTINGS, settings::GeneratorSetting,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
pub fn bench_create_and_populate_noise(
|
pub fn bench_create_and_populate_noise(
|
||||||
base_router: &ProtoNoiseRouters,
|
base_router: &ProtoNoiseRouters,
|
||||||
random_config: &GlobalRandomConfig,
|
random_config: &GlobalRandomConfig,
|
||||||
|
|||||||
@ -114,7 +114,7 @@ impl LootPoolEntryTypesExt for LootPoolEntryTypes {
|
|||||||
match self {
|
match self {
|
||||||
Self::Empty => Vec::new(),
|
Self::Empty => Vec::new(),
|
||||||
Self::Item(item_entry) => {
|
Self::Item(item_entry) => {
|
||||||
let key = &item_entry.name.replace("minecraft:", "");
|
let key = &item_entry.name.strip_prefix("minecraft:").unwrap();
|
||||||
vec![ItemStack::new(1, Item::from_registry_key(key).unwrap())]
|
vec![ItemStack::new(1, Item::from_registry_key(key).unwrap())]
|
||||||
}
|
}
|
||||||
Self::LootTable => todo!(),
|
Self::LootTable => todo!(),
|
||||||
|
|||||||
@ -38,7 +38,7 @@ impl ArgumentConsumer for EffectTypeArgumentConsumer {
|
|||||||
let name = args.pop()?;
|
let name = args.pop()?;
|
||||||
|
|
||||||
// Create a static damage type first
|
// Create a static damage type first
|
||||||
let damage_type = EffectType::from_name(&name.replace("minecraft:", ""))?;
|
let damage_type = EffectType::from_name(name.strip_prefix("minecraft:").unwrap_or(name))?;
|
||||||
// Find matching static damage type from values array
|
// Find matching static damage type from values array
|
||||||
Some(Arg::Effect(damage_type))
|
Some(Arg::Effect(damage_type))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,15 +58,17 @@ impl<'a> FindArg<'a> for ItemArgumentConsumer {
|
|||||||
|
|
||||||
fn find_arg(args: &'a ConsumedArgs, name: &str) -> Result<Self::Data, CommandError> {
|
fn find_arg(args: &'a ConsumedArgs, name: &str) -> Result<Self::Data, CommandError> {
|
||||||
match args.get(name) {
|
match args.get(name) {
|
||||||
Some(Arg::Item(name)) => Item::from_registry_key(&name.replace("minecraft:", ""))
|
Some(Arg::Item(name)) => {
|
||||||
.map_or_else(
|
Item::from_registry_key(name.strip_prefix("minecraft:").unwrap_or(name))
|
||||||
|| {
|
.map_or_else(
|
||||||
Err(CommandError::GeneralCommandIssue(format!(
|
|| {
|
||||||
"Item {name} does not exist."
|
Err(CommandError::GeneralCommandIssue(format!(
|
||||||
)))
|
"Item {name} does not exist."
|
||||||
},
|
)))
|
||||||
|item| Ok((*name, item)),
|
},
|
||||||
),
|
|item| Ok((*name, item)),
|
||||||
|
)
|
||||||
|
}
|
||||||
_ => Err(CommandError::InvalidConsumption(Some(name.to_string()))),
|
_ => Err(CommandError::InvalidConsumption(Some(name.to_string()))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,7 @@ impl ArgumentConsumer for ParticleArgumentConsumer {
|
|||||||
let name = args.pop()?;
|
let name = args.pop()?;
|
||||||
|
|
||||||
// Create a static damage type first
|
// Create a static damage type first
|
||||||
let particle = Particle::from_name(&name.replace("minecraft:", ""))?;
|
let particle = Particle::from_name(name.strip_prefix("minecraft:").unwrap_or(name))?;
|
||||||
// Find matching static damage type from values array
|
// Find matching static damage type from values array
|
||||||
Some(Arg::Particle(particle))
|
Some(Arg::Particle(particle))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,15 +57,16 @@ impl<'a> FindArg<'a> for SoundArgumentConsumer {
|
|||||||
|
|
||||||
fn find_arg(args: &'a super::ConsumedArgs, name: &str) -> Result<Self::Data, CommandError> {
|
fn find_arg(args: &'a super::ConsumedArgs, name: &str) -> Result<Self::Data, CommandError> {
|
||||||
match args.get(name) {
|
match args.get(name) {
|
||||||
Some(Arg::Block(name)) => Sound::from_name(&name.replace("minecraft:", ""))
|
Some(Arg::Block(name)) => {
|
||||||
.map_or_else(
|
Sound::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else(
|
||||||
|| {
|
|| {
|
||||||
Err(CommandError::GeneralCommandIssue(format!(
|
Err(CommandError::GeneralCommandIssue(format!(
|
||||||
"Sound {name} does not exist."
|
"Sound {name} does not exist."
|
||||||
)))
|
)))
|
||||||
},
|
},
|
||||||
Result::Ok,
|
Result::Ok,
|
||||||
),
|
)
|
||||||
|
}
|
||||||
_ => Err(CommandError::InvalidConsumption(Some(name.to_string()))),
|
_ => Err(CommandError::InvalidConsumption(Some(name.to_string()))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,15 +57,16 @@ impl<'a> FindArg<'a> for SummonableEntitiesArgumentConsumer {
|
|||||||
|
|
||||||
fn find_arg(args: &'a super::ConsumedArgs, name: &str) -> Result<Self::Data, CommandError> {
|
fn find_arg(args: &'a super::ConsumedArgs, name: &str) -> Result<Self::Data, CommandError> {
|
||||||
match args.get(name) {
|
match args.get(name) {
|
||||||
Some(Arg::Block(name)) => EntityType::from_name(&name.replace("minecraft:", ""))
|
Some(Arg::Block(name)) => {
|
||||||
.map_or_else(
|
EntityType::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else(
|
||||||
|| {
|
|| {
|
||||||
Err(CommandError::GeneralCommandIssue(format!(
|
Err(CommandError::GeneralCommandIssue(format!(
|
||||||
"Entity {name} does not exist."
|
"Entity {name} does not exist."
|
||||||
)))
|
)))
|
||||||
},
|
},
|
||||||
Result::Ok,
|
Result::Ok,
|
||||||
),
|
)
|
||||||
|
}
|
||||||
_ => Err(CommandError::InvalidConsumption(Some(name.to_string()))),
|
_ => Err(CommandError::InvalidConsumption(Some(name.to_string()))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user