yog_registry/entities.rs
1//! Entities: what a mod declares an entity type as.
2
3/// What kind of entity a type is.
4#[derive(yog_data::Schema, Debug, Clone, Copy, PartialEq, Eq, Default)]
5pub enum EntityKind {
6 /// Not alive: a thing in the world (a scroll on a wall, a vehicle, a
7 /// display) — no health, no AI.
8 #[default]
9 Object,
10 /// Alive: health, attributes, hurt and death, but no AI of its own.
11 Living,
12 /// A creature with AI: `goals`, and walking about.
13 Mob,
14 /// Hangs on a block's side, as a painting: `width`×`height` whole
15 /// blocks of wall (the item it's placed from may say another size —
16 /// [`ItemDef::hangs`]); it stays while the blocks behind hold it, and
17 /// breaking it, or losing its wall, drops the item it was placed from.
18 Hanging,
19}
20
21/// An entity type to register (`.yentity`). Its look is a body model
22/// (`model`, `.ymodel`) with clips by state; what it does beyond `goals` is
23/// the mod's code (entity events, a tick of its own).
24#[derive(yog_data::Schema, Debug, Clone)]
25pub struct EntityDef {
26 /// Its id; a source may leave it out: the file's name, the build fills it in.
27 #[data(default)]
28 pub id: String,
29 /// Its name (a text or a `@Set.key` resource); default: the id's lang key.
30 pub name: Option<String>,
31 #[data(default)]
32 pub kind: EntityKind,
33 /// Its spawn group (`MobCategory`): `misc`, `monster`, `creature`,
34 /// `ambient`, `water_creature`, `water_ambient`, `underground_water_creature`.
35 #[data(default = "misc")]
36 pub category: String,
37 /// Hitbox, blocks.
38 pub width: f32,
39 pub height: f32,
40 /// Eye height, blocks; default 85% of the height.
41 pub eye_height: Option<f32>,
42 /// Lava and fire don't hurt it.
43 #[data(default)]
44 pub fire_immune: bool,
45 /// It doesn't fall.
46 #[data(default)]
47 pub no_gravity: bool,
48 /// Others push it (living things by default).
49 pub pushable: Option<bool>,
50 /// Others stand on and bump into it as into a block (a boat).
51 #[data(default)]
52 pub solid: bool,
53 /// How far players see it, chunks.
54 #[data(default = "eight")]
55 pub tracking_range: u32,
56 /// How often its movement is sent, ticks.
57 #[data(default = "three")]
58 pub update_interval: u32,
59 /// Living and mob attributes by id: `max_health`, `movement_speed`,
60 /// `attack_damage`, `follow_range`, `armor`, `knockback_resistance`… (the
61 /// game's, `minecraft:` optional, or a mod's).
62 #[data(default)]
63 pub attributes: yog_data::Ordered<f64>,
64 /// Its body model (`.ymodel` id); none: the mod draws it (`on_body`).
65 pub model: Option<String>,
66 /// Its clips (`.yanim` id).
67 pub animations: Option<String>,
68 /// Clip by state: `idle`, `walk`, `attack`, `hurt`, `death`, or the mod's
69 /// own states (entity data `yog:state`).
70 #[data(default)]
71 pub clips: yog_data::Ordered<String>,
72 /// Spawn egg colors `[base, spots]` (`0xRRGGBB`); none: no egg.
73 pub spawn_egg: Option<[u32; 2]>,
74 /// Mobs' AI goals, in priority order — the game's by name: `float`,
75 /// `panic`, `melee_attack`, `wander`, `look_at_player`,
76 /// `look_around`, `target_player`, `avoid_player`.
77 #[data(default)]
78 pub goals: Vec<String>,
79 /// The mod handles each tick of every entity of this type
80 /// (`yog_event::entity::game::Tick`, keyed by the type).
81 #[data(default)]
82 pub ticks: bool,
83 /// A hanging thing's sound events when it's placed and when it breaks;
84 /// default: a painting's.
85 pub place_sound: Option<String>,
86 pub break_sound: Option<String>,
87}
88
89/// A hanging thing's sounds when it names none: a painting's.
90pub const HANGING_PLACE_SOUND: &str = yog_ids::id!(yog_ids::ns::MINECRAFT, "entity.painting.place");
91pub const HANGING_BREAK_SOUND: &str = yog_ids::id!(yog_ids::ns::MINECRAFT, "entity.painting.break");
92
93fn eight() -> u32 {
94 8
95}
96
97fn three() -> u32 {
98 3
99}
100
101fn misc() -> String {
102 "misc".into()
103}
104
105impl EntityDef {
106 pub fn new(id: impl Into<String>, kind: EntityKind, width: f32, height: f32) -> Self {
107 Self {
108 id: id.into(),
109 name: None,
110 kind,
111 category: misc(),
112 width,
113 height,
114 eye_height: None,
115 fire_immune: false,
116 no_gravity: false,
117 pushable: None,
118 solid: false,
119 tracking_range: eight(),
120 update_interval: three(),
121 attributes: yog_data::Ordered::default(),
122 model: None,
123 animations: None,
124 clips: yog_data::Ordered::default(),
125 spawn_egg: None,
126 goals: Vec::new(),
127 ticks: false,
128 place_sound: None,
129 break_sound: None,
130 }
131 }
132
133 /// Itself with the sounds it doesn't name: a painting's.
134 pub fn with_default_sounds(mut self) -> Self {
135 self.place_sound
136 .get_or_insert_with(|| HANGING_PLACE_SOUND.into());
137 self.break_sound
138 .get_or_insert_with(|| HANGING_BREAK_SOUND.into());
139 self
140 }
141}