mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
Add Entity spawning on Chunk generation (#1054)
* Support Spawn * Update natural_spawner.rs * fix distance * fix error * fix * use heigh map * Update living.rs * impl get_rough_biome and merge * fix dropper and entity disappear * merge --------- Co-authored-by: Alexander Medvedev <lilalexmed@proton.me>
This commit is contained in:
@@ -16,6 +16,7 @@ pub struct Biome {
|
||||
features: Vec<Vec<String>>,
|
||||
creature_spawn_probability: Option<f32>,
|
||||
spawners: SpawnGroups,
|
||||
spawn_costs: HashMap<String, SpawnCosts>,
|
||||
pub id: u8,
|
||||
}
|
||||
|
||||
@@ -31,17 +32,43 @@ struct SpawnGroups {
|
||||
water_creature: Vec<Spawner>,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Deserialize, Hash, PartialEq, Eq)]
|
||||
struct Spawner {
|
||||
r#type: String,
|
||||
minCount: i32,
|
||||
maxCount: i32,
|
||||
}
|
||||
|
||||
impl Spawner {
|
||||
pub fn to_tokens(&self) -> TokenStream {
|
||||
let r#type = &self.r#type;
|
||||
let min_count = &self.minCount;
|
||||
let max_count = &self.maxCount;
|
||||
quote! {
|
||||
Spawner {
|
||||
r#type: #r#type,
|
||||
min_count: #min_count,
|
||||
max_count: #max_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq)]
|
||||
struct SpawnCosts {
|
||||
energy_budget: f64,
|
||||
charge: f64,
|
||||
}
|
||||
|
||||
impl SpawnCosts {
|
||||
pub fn to_tokens(&self) -> TokenStream {
|
||||
let energy_budget = &self.energy_budget;
|
||||
let charge = &self.charge;
|
||||
quote! {
|
||||
SpawnCosts {
|
||||
energy_budget: #energy_budget,
|
||||
charge: #charge,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,6 +244,18 @@ pub(crate) fn build() -> TokenStream {
|
||||
}
|
||||
};
|
||||
|
||||
let spawn_costs: Vec<_> = biome
|
||||
.spawn_costs
|
||||
.iter()
|
||||
.map(|(name, cost)| {
|
||||
let cost_token = cost.to_tokens();
|
||||
let entity_type = name.strip_prefix("minecraft:").unwrap();
|
||||
quote! {
|
||||
#entity_type => #cost_token
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let temperature_modifier = match temperature_modifier {
|
||||
TemperatureModifier::Frozen => quote! { TemperatureModifier::Frozen },
|
||||
TemperatureModifier::None => quote! { TemperatureModifier::None },
|
||||
@@ -225,17 +264,20 @@ pub(crate) fn build() -> TokenStream {
|
||||
|
||||
variants.extend([quote! {
|
||||
pub const #format_name: Biome = Biome {
|
||||
id: #index,
|
||||
registry_id: #name,
|
||||
weather: Weather::new(
|
||||
#has_precipitation,
|
||||
#temperature,
|
||||
#temperature_modifier,
|
||||
#downfall
|
||||
),
|
||||
features: &[#(&[#(#features),*]),*],
|
||||
creature_spawn_probability: #creature_spawn_probability,
|
||||
spawners: #spawners,
|
||||
id: #index,
|
||||
registry_id: #name,
|
||||
weather: Weather::new(
|
||||
#has_precipitation,
|
||||
#temperature,
|
||||
#temperature_modifier,
|
||||
#downfall
|
||||
),
|
||||
features: &[#(&[#(#features),*]),*],
|
||||
creature_spawn_probability: #creature_spawn_probability,
|
||||
spawners: #spawners,
|
||||
spawn_costs: phf::phf_map! {
|
||||
#(#spawn_costs),*
|
||||
},
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -246,197 +288,223 @@ pub(crate) fn build() -> TokenStream {
|
||||
let overworld_tree = biome_trees.overworld.into_token_stream();
|
||||
let nether_tree = biome_trees.nether.into_token_stream();
|
||||
quote! {
|
||||
use crate::biome::de::Deserialize;
|
||||
use crate::entity_type::EntityType;
|
||||
use crate::tag::Taggable;
|
||||
use crate::tag::RegistryKey;
|
||||
use pumpkin_util::biome::{TemperatureModifier, Weather};
|
||||
use serde::{Deserializer, de};
|
||||
use std::{fmt, hash::{Hasher, Hash}};
|
||||
|
||||
use pumpkin_util::biome::{TemperatureModifier, Weather};
|
||||
use serde::{Deserializer, de};
|
||||
use crate::biome::de::Deserialize;
|
||||
use std::{fmt, hash::{Hasher, Hash}};
|
||||
#[derive(Debug)]
|
||||
pub struct Biome {
|
||||
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,
|
||||
pub spawn_costs: phf::Map<&'static str, SpawnCosts>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Biome {
|
||||
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,
|
||||
#[derive(Debug)]
|
||||
pub struct SpawnGroups {
|
||||
pub monster: &'static [Spawner],
|
||||
pub ambient: &'static [Spawner],
|
||||
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],
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Spawner {
|
||||
pub r#type: &'static str,
|
||||
pub min_count: i32,
|
||||
pub max_count: i32,
|
||||
}
|
||||
|
||||
impl PartialEq for Biome {
|
||||
fn eq(&self, other: &Biome) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SpawnGroups {
|
||||
pub monster: &'static [Spawner],
|
||||
pub ambient: &'static [Spawner],
|
||||
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 Eq for Biome {}
|
||||
|
||||
impl Hash for Biome {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Spawner {
|
||||
pub r#type: &'static str,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct SpawnCosts {
|
||||
pub energy_budget: f64,
|
||||
pub charge: f64,
|
||||
}
|
||||
|
||||
impl PartialEq for Biome {
|
||||
fn eq(&self, other: &Biome) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
impl<'de> Deserialize<'de> for &'static Biome {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
struct BiomeVisitor;
|
||||
|
||||
impl Eq for Biome {}
|
||||
impl de::Visitor<'_> for BiomeVisitor {
|
||||
type Value = &'static Biome;
|
||||
|
||||
impl Hash for Biome {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for &'static Biome {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
struct BiomeVisitor;
|
||||
|
||||
impl de::Visitor<'_> for BiomeVisitor {
|
||||
type Value = &'static Biome;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a biome name as a string")
|
||||
}
|
||||
|
||||
fn visit_string<E: serde::de::Error>(self, v: String) -> Result<Self::Value, E> {
|
||||
self.visit_str(&v)
|
||||
}
|
||||
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
|
||||
let biome = Biome::from_name(value.strip_prefix("minecraft:").unwrap_or(value));
|
||||
biome.ok_or_else(|| E::unknown_variant(value, &["unknown biome"]))
|
||||
}
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a biome name as a string")
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(BiomeVisitor)
|
||||
}
|
||||
}
|
||||
fn visit_string<E: serde::de::Error>(self, v: String) -> Result<Self::Value, E> {
|
||||
self.visit_str(&v)
|
||||
}
|
||||
|
||||
impl Biome {
|
||||
#variants
|
||||
|
||||
pub fn from_name(name: &str) -> Option<&'static Self> {
|
||||
match name {
|
||||
#name_to_type
|
||||
_ => None
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
|
||||
let biome = Biome::from_name(value.strip_prefix("minecraft:").unwrap_or(value));
|
||||
biome.ok_or_else(|| E::unknown_variant(value, &["unknown biome"]))
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn from_id(id: u8) -> Option<&'static Self> {
|
||||
match id {
|
||||
#id_to_type
|
||||
_ => None
|
||||
}
|
||||
deserializer.deserialize_str(BiomeVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Biome {
|
||||
#variants
|
||||
|
||||
pub fn from_name(name: &str) -> Option<&'static Self> {
|
||||
match name {
|
||||
#name_to_type
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct ParameterRange {
|
||||
min: i64,
|
||||
max: i64,
|
||||
pub const fn from_id(id: u8) -> Option<&'static Self> {
|
||||
match id {
|
||||
#id_to_type
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
impl Taggable for Biome {
|
||||
#[inline]
|
||||
fn registry_id(&self) -> u16 {
|
||||
self.id as u16
|
||||
}
|
||||
#[inline]
|
||||
fn tag_key() -> RegistryKey {
|
||||
RegistryKey::WorldgenBiome
|
||||
}
|
||||
#[inline]
|
||||
fn registry_key(&self) -> &str {
|
||||
self.registry_id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct ParameterRange {
|
||||
min: i64,
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum BiomeTree {
|
||||
Leaf {
|
||||
parameters: [ParameterRange; 7],
|
||||
biome: &'static Biome,
|
||||
},
|
||||
Branch {
|
||||
parameters: [ParameterRange; 7],
|
||||
nodes: &'static [BiomeTree],
|
||||
},
|
||||
}
|
||||
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)
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
if distance > node2_distance {
|
||||
distance = node2_distance;
|
||||
best_node = Some(node2);
|
||||
}
|
||||
}
|
||||
|
||||
best_node.expect("This should be populated after traversing the tree")
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,13 @@ pub struct EntityType {
|
||||
pub id: u16,
|
||||
pub max_health: Option<f32>,
|
||||
pub attackable: Option<bool>,
|
||||
pub mob: Option<bool>,
|
||||
pub limit_per_chunk: Option<i32>,
|
||||
pub loot_table: Option<LootTableStruct>,
|
||||
pub summonable: bool,
|
||||
pub fire_immune: bool,
|
||||
pub category: MobCategory,
|
||||
pub can_spawn_far_from_player: bool,
|
||||
pub dimension: [f32; 2],
|
||||
pub eye_height: f32,
|
||||
pub spawn_restriction: SpawnRestriction,
|
||||
@@ -36,6 +40,20 @@ pub enum SpawnLocation {
|
||||
Unrestricted,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub enum MobCategory {
|
||||
MONSTER,
|
||||
CREATURE,
|
||||
AMBIENT,
|
||||
AXOLOTLS,
|
||||
UNDERGROUND_WATER_CREATURE,
|
||||
WATER_CREATURE,
|
||||
WATER_AMBIENT,
|
||||
MISC,
|
||||
}
|
||||
|
||||
pub struct NamedEntityType<'a>(&'a str, &'a EntityType);
|
||||
|
||||
impl ToTokens for NamedEntityType<'_> {
|
||||
@@ -75,9 +93,31 @@ impl ToTokens for NamedEntityType<'_> {
|
||||
heightmap: #spawn_restriction_heightmap,
|
||||
}};
|
||||
|
||||
let spawn_category = match entity.category {
|
||||
MobCategory::MONSTER => quote! { MobCategory::MONSTER },
|
||||
MobCategory::CREATURE => quote! { MobCategory::CREATURE },
|
||||
MobCategory::AMBIENT => quote! { MobCategory::AMBIENT },
|
||||
MobCategory::AXOLOTLS => quote! { MobCategory::AXOLOTLS },
|
||||
MobCategory::UNDERGROUND_WATER_CREATURE => {
|
||||
quote! { MobCategory::UNDERGROUND_WATER_CREATURE }
|
||||
}
|
||||
MobCategory::WATER_CREATURE => quote! { MobCategory::WATER_CREATURE },
|
||||
MobCategory::WATER_AMBIENT => quote! { MobCategory::WATER_AMBIENT },
|
||||
MobCategory::MISC => quote! { MobCategory::MISC },
|
||||
};
|
||||
|
||||
let summonable = entity.summonable;
|
||||
let fire_immune = entity.fire_immune;
|
||||
let eye_height = entity.eye_height;
|
||||
if entity.mob.is_none() && name != "player" {
|
||||
panic!("missing field 'mob', entity name {name}");
|
||||
}
|
||||
if entity.limit_per_chunk.is_none() && name != "player" {
|
||||
panic!("missing field 'mob', entity name {name}");
|
||||
}
|
||||
let mob = entity.mob.unwrap_or(false);
|
||||
let limit_per_chunk = entity.limit_per_chunk.unwrap_or(0);
|
||||
let can_spawn_far_from_player = entity.can_spawn_far_from_player;
|
||||
|
||||
let dimension0 = entity.dimension[0];
|
||||
let dimension1 = entity.dimension[1];
|
||||
@@ -95,8 +135,12 @@ impl ToTokens for NamedEntityType<'_> {
|
||||
id: #id,
|
||||
max_health: #max_health,
|
||||
attackable: #attackable,
|
||||
mob: #mob,
|
||||
limit_per_chunk: #limit_per_chunk,
|
||||
summonable: #summonable,
|
||||
fire_immune: #fire_immune,
|
||||
category: &#spawn_category,
|
||||
can_spawn_far_from_player: #can_spawn_far_from_player,
|
||||
loot_table: #loot_table,
|
||||
dimension: [#dimension0, #dimension1], // Correctly construct the array
|
||||
eye_height: #eye_height,
|
||||
@@ -130,24 +174,28 @@ pub(crate) fn build() -> TokenStream {
|
||||
});
|
||||
|
||||
type_from_raw_id_arms.extend(quote! {
|
||||
#id_lit => Some(Self::#upper_name),
|
||||
#id_lit => Some(&Self::#upper_name),
|
||||
});
|
||||
|
||||
type_from_name.extend(quote! {
|
||||
#name => Some(Self::#upper_name),
|
||||
#name => Some(&Self::#upper_name),
|
||||
});
|
||||
}
|
||||
quote! {
|
||||
use pumpkin_util::loot_table::*;
|
||||
use pumpkin_util::HeightMap;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Debug)]
|
||||
pub struct EntityType {
|
||||
pub id: u16,
|
||||
pub max_health: Option<f32>,
|
||||
pub attackable: Option<bool>,
|
||||
pub mob: bool,
|
||||
pub limit_per_chunk: i32,
|
||||
pub summonable: bool,
|
||||
pub fire_immune: bool,
|
||||
pub category: &'static MobCategory,
|
||||
pub can_spawn_far_from_player: bool,
|
||||
pub loot_table: Option<LootTable>,
|
||||
pub dimension: [f32; 2],
|
||||
pub eye_height: f32,
|
||||
@@ -155,31 +203,122 @@ pub(crate) fn build() -> TokenStream {
|
||||
pub resource_name: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct SpawnRestriction {
|
||||
location: SpawnLocation,
|
||||
heightmap: HeightMap,
|
||||
impl PartialEq for EntityType {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum SpawnLocation {
|
||||
InLava,
|
||||
InWater,
|
||||
OnGround,
|
||||
Unrestricted
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct SpawnRestriction {
|
||||
pub location: SpawnLocation,
|
||||
pub heightmap: HeightMap,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SpawnLocation {
|
||||
InLava,
|
||||
InWater,
|
||||
OnGround,
|
||||
Unrestricted,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MobCategory {
|
||||
pub id: usize, // mojang don't have this field
|
||||
pub max: i32,
|
||||
pub is_friendly: bool,
|
||||
pub is_persistent: bool,
|
||||
pub despawn_distance: i32,
|
||||
}
|
||||
|
||||
impl PartialEq for MobCategory {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl MobCategory {
|
||||
pub const NO_DESPAWN_DISTANCE: i32 = 32;
|
||||
pub const MONSTER: MobCategory = MobCategory {
|
||||
id: 0,
|
||||
max: 70,
|
||||
is_friendly: false,
|
||||
is_persistent: false,
|
||||
despawn_distance: 128,
|
||||
};
|
||||
pub const CREATURE: MobCategory = MobCategory {
|
||||
id: 1,
|
||||
max: 10,
|
||||
is_friendly: true,
|
||||
is_persistent: true,
|
||||
despawn_distance: 128,
|
||||
};
|
||||
pub const AMBIENT: MobCategory = MobCategory {
|
||||
id: 2,
|
||||
max: 15,
|
||||
is_friendly: true,
|
||||
is_persistent: false,
|
||||
despawn_distance: 128,
|
||||
};
|
||||
pub const AXOLOTLS: MobCategory = MobCategory {
|
||||
id: 3,
|
||||
max: 5,
|
||||
is_friendly: true,
|
||||
is_persistent: false,
|
||||
despawn_distance: 128,
|
||||
};
|
||||
pub const UNDERGROUND_WATER_CREATURE: MobCategory = MobCategory {
|
||||
id: 4,
|
||||
max: 5,
|
||||
is_friendly: true,
|
||||
is_persistent: false,
|
||||
despawn_distance: 128,
|
||||
};
|
||||
pub const WATER_CREATURE: MobCategory = MobCategory {
|
||||
id: 5,
|
||||
max: 5,
|
||||
is_friendly: true,
|
||||
is_persistent: true,
|
||||
despawn_distance: 128,
|
||||
};
|
||||
pub const WATER_AMBIENT: MobCategory = MobCategory {
|
||||
id: 6,
|
||||
max: 20,
|
||||
is_friendly: true,
|
||||
is_persistent: false,
|
||||
despawn_distance: 64,
|
||||
};
|
||||
pub const MISC: MobCategory = MobCategory {
|
||||
id: 7,
|
||||
max: -1,
|
||||
is_friendly: true,
|
||||
is_persistent: true,
|
||||
despawn_distance: 128,
|
||||
};
|
||||
pub const SPAWNING_CATEGORIES: [&'static Self; 8] = [
|
||||
&Self::MONSTER,
|
||||
&Self::CREATURE,
|
||||
&Self::AMBIENT,
|
||||
&Self::AXOLOTLS,
|
||||
&Self::UNDERGROUND_WATER_CREATURE,
|
||||
&Self::WATER_CREATURE,
|
||||
&Self::WATER_AMBIENT,
|
||||
&Self::MISC,
|
||||
];
|
||||
}
|
||||
|
||||
impl EntityType {
|
||||
#consts
|
||||
|
||||
pub const fn from_raw(id: u16) -> Option<Self> {
|
||||
pub const fn from_raw(id: u16) -> Option<&'static Self> {
|
||||
match id {
|
||||
#type_from_raw_id_arms
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_name(name: &str) -> Option<Self> {
|
||||
pub fn from_name(name: &str) -> Option<&'static Self> {
|
||||
match name {
|
||||
#type_from_name
|
||||
_ => None
|
||||
|
||||
@@ -15,12 +15,12 @@ pub(crate) fn build() -> TokenStream {
|
||||
for (egg, entity) in &eggs {
|
||||
let entity = entity.to_shouty_snake_case();
|
||||
let entity = format_ident!("{}", entity);
|
||||
names.extend(quote! { #egg => Some(EntityType::#entity), });
|
||||
names.extend(quote! { #egg => Some(&EntityType::#entity), });
|
||||
}
|
||||
quote! {
|
||||
use crate::entity_type::EntityType;
|
||||
|
||||
pub fn entity_from_egg(id: u16) -> Option<EntityType> {
|
||||
pub fn entity_from_egg(id: u16) -> Option<&'static EntityType> {
|
||||
match id {
|
||||
#names
|
||||
_ => None
|
||||
|
||||
Reference in New Issue
Block a user