Skip to content

Commit 3b9115f

Browse files
committed
Rename Ecs to World and World to Level.
We previously uses World to store blocks and Ecs to store entities. Now, Level contains blocks and World contains entities. This change is motivated by most Rust ECS crates using World as their entity store. Also , Level is the terminoligy used internally in Minecraft from what I know.
1 parent 686b35b commit 3b9115f

39 files changed

+194
-193
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# Cargo build configuration
77
.cargo
88

9-
world/
9+
/world
1010
/config.toml
1111

1212
# Python cache files (libcraft)

feather/base/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ pub mod anvil;
1313
pub mod chunk;
1414
pub mod inventory;
1515
pub mod metadata;
16-
mod world;
1716

1817
pub use blocks::*;
1918
pub use chunk::{Chunk, ChunkSection, CHUNK_HEIGHT, CHUNK_WIDTH};

feather/base/src/world.rs

-1
This file was deleted.

feather/common/src/chunk_entities.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ fn update_chunk_entities(game: &mut Game) -> SysResult {
5353
// Entities that have crossed chunks
5454
let mut events = Vec::new();
5555
for (entity, (old_chunk, &position)) in
56-
game.ecs.query::<(&mut ChunkPosition, &Position)>().iter()
56+
game.world.query::<(&mut ChunkPosition, &Position)>().iter()
5757
{
5858
let new_chunk = position.chunk();
5959
if position.chunk() != *old_chunk {
@@ -71,25 +71,26 @@ fn update_chunk_entities(game: &mut Game) -> SysResult {
7171
}
7272
}
7373
for (entity, event) in events {
74-
game.ecs.insert_entity_event(entity, event)?;
74+
game.world.insert_entity_event(entity, event)?;
7575
}
7676

7777
// Entities that have been created
7878
let mut insertions = Vec::new();
79-
for (entity, (_event, &position)) in game.ecs.query::<(&EntityCreateEvent, &Position)>().iter()
79+
for (entity, (_event, &position)) in
80+
game.world.query::<(&EntityCreateEvent, &Position)>().iter()
8081
{
8182
let chunk = position.chunk();
8283
game.chunk_entities.update(entity, None, chunk);
8384
insertions.push((entity, chunk));
8485
}
8586
// Add ChunkPosition component to new entities
8687
for (entity, chunk) in insertions {
87-
game.ecs.insert(entity, chunk)?;
88+
game.world.insert(entity, chunk)?;
8889
}
8990

9091
// Entities that have been destroyed
9192
for (entity, (_event, &chunk)) in game
92-
.ecs
93+
.world
9394
.query::<(&EntityRemoveEvent, &ChunkPosition)>()
9495
.iter()
9596
{

feather/common/src/chunk_loading.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ struct Ticket(Entity);
117117

118118
/// System to populate chunk tickets based on players' views.
119119
fn update_tickets_for_players(game: &mut Game, state: &mut ChunkLoadState) -> SysResult {
120-
for (player, event) in game.ecs.query::<&ViewUpdateEvent>().iter() {
120+
for (player, event) in game.world.query::<&ViewUpdateEvent>().iter() {
121121
let player_ticket = Ticket(player);
122122

123123
// Remove old tickets
@@ -130,8 +130,8 @@ fn update_tickets_for_players(game: &mut Game, state: &mut ChunkLoadState) -> Sy
130130
state.chunk_tickets.insert_ticket(new_chunk, player_ticket);
131131

132132
// Load if needed
133-
if !game.world.is_chunk_loaded(new_chunk) && !game.world.is_chunk_loading(new_chunk) {
134-
game.world.queue_chunk_load(new_chunk);
133+
if !game.level.is_chunk_loaded(new_chunk) && !game.level.is_chunk_loading(new_chunk) {
134+
game.level.queue_chunk_load(new_chunk);
135135
}
136136
}
137137
}
@@ -155,13 +155,13 @@ fn unload_chunks(game: &mut Game, state: &mut ChunkLoadState) -> SysResult {
155155
continue;
156156
}
157157

158-
game.world.unload_chunk(unload.pos);
158+
game.level.unload_chunk(unload.pos);
159159
}
160160
Ok(())
161161
}
162162

163163
fn remove_dead_entities(game: &mut Game, state: &mut ChunkLoadState) -> SysResult {
164-
for (entity, _event) in game.ecs.query::<&EntityRemoveEvent>().iter() {
164+
for (entity, _event) in game.world.query::<&EntityRemoveEvent>().iter() {
165165
let entity_ticket = Ticket(entity);
166166
for chunk in state.chunk_tickets.take_entity_tickets(entity_ticket) {
167167
state.remove_ticket(chunk, entity_ticket);
@@ -172,6 +172,6 @@ fn remove_dead_entities(game: &mut Game, state: &mut ChunkLoadState) -> SysResul
172172

173173
/// System to call `World::load_chunks` each tick
174174
fn load_chunks(game: &mut Game, _state: &mut ChunkLoadState) -> SysResult {
175-
game.world.load_chunks(&mut game.ecs);
175+
game.level.load_chunks(&mut game.world);
176176
Ok(())
177177
}

feather/common/src/game.rs

+26-30
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ use crate::{
1111
chat::{ChatKind, ChatMessage},
1212
chunk_entities::ChunkEntities,
1313
events::{BlockChangeEvent, EntityCreateEvent, EntityRemoveEvent, PlayerJoinEvent},
14-
ChatBox, World,
14+
ChatBox, Level,
1515
};
1616

1717
type EntitySpawnCallback = Box<dyn FnMut(&mut EntityBuilder, &EntityInit)>;
1818

1919
/// Stores the entire state of a Minecraft game.
2020
///
2121
/// This contains:
22-
/// * A [`World`](base::World) containing chunks and blocks.
23-
/// * An [`Ecs`](ecs::Ecs) containing entities.
22+
/// * A [`World`](vane::Ecs) containing entities.
23+
/// * A [`Level`] containing blocks.
2424
/// * A [`Resources`](ecs::Resources) containing additional, user-defined data.
2525
/// * A [`SystemExecutor`] to run systems.
2626
///
@@ -29,14 +29,9 @@ type EntitySpawnCallback = Box<dyn FnMut(&mut EntityBuilder, &EntityInit)>;
2929
/// should be preferred over raw interaction with the ECS.
3030
pub struct Game {
3131
/// Contains chunks and blocks.
32-
///
33-
/// NB: use methods on `Game` to update
34-
/// blocks, not direct methods on `World`.
35-
/// The `Game` methods will automatically
36-
/// trigger the necessary `BlockChangeEvent`s.
37-
pub world: World,
32+
pub level: Level,
3833
/// Contains entities, including players.
39-
pub ecs: Ecs,
34+
pub world: Ecs,
4035
/// Contains systems.
4136
pub system_executor: Rc<RefCell<SystemExecutor<Game>>>,
4237

@@ -66,8 +61,8 @@ impl Game {
6661
/// Creates a new, empty `Game`.
6762
pub fn new() -> Self {
6863
Self {
69-
world: World::new(),
70-
ecs: Ecs::new(),
64+
level: Level::new(),
65+
world: Ecs::new(),
7166
system_executor: Rc::new(RefCell::new(SystemExecutor::new())),
7267
resources: Arc::new(Resources::new()),
7368
chunk_entities: ChunkEntities::default(),
@@ -123,7 +118,7 @@ impl Game {
123118
///
124119
/// Also triggers necessary events, like `EntitySpawnEvent` and `PlayerJoinEvent`.
125120
pub fn spawn_entity(&mut self, mut builder: EntityBuilder) -> Entity {
126-
let entity = self.ecs.spawn(builder.build());
121+
let entity = self.world.spawn(builder.build());
127122
self.entity_builder = builder;
128123

129124
self.trigger_entity_spawn_events(entity);
@@ -140,11 +135,11 @@ impl Game {
140135
}
141136

142137
fn trigger_entity_spawn_events(&mut self, entity: Entity) {
143-
self.ecs
138+
self.world
144139
.insert_entity_event(entity, EntityCreateEvent)
145140
.unwrap();
146-
if self.ecs.get::<Player>(entity).is_ok() {
147-
self.ecs
141+
if self.world.get::<Player>(entity).is_ok() {
142+
self.world
148143
.insert_entity_event(entity, PlayerJoinEvent)
149144
.unwrap();
150145
}
@@ -153,38 +148,38 @@ impl Game {
153148
/// Causes the given entity to be removed on the next tick.
154149
/// In the meantime, triggers `EntityRemoveEvent`.
155150
pub fn remove_entity(&mut self, entity: Entity) -> Result<(), NoSuchEntity> {
156-
self.ecs.defer_despawn(entity);
157-
self.ecs.insert_entity_event(entity, EntityRemoveEvent)
151+
self.world.defer_despawn(entity);
152+
self.world.insert_entity_event(entity, EntityRemoveEvent)
158153
}
159154

160155
/// Broadcasts a chat message to all entities with
161156
/// a `ChatBox` component (usually just players).
162157
pub fn broadcast_chat(&self, kind: ChatKind, message: impl Into<Text>) {
163158
let message = message.into();
164-
for (_, mailbox) in self.ecs.query::<&mut ChatBox>().iter() {
159+
for (_, mailbox) in self.world.query::<&mut ChatBox>().iter() {
165160
mailbox.send(ChatMessage::new(kind, message.clone()));
166161
}
167162
}
168163

169164
/// Utility method to send a message to an entity.
170165
pub fn send_message(&mut self, entity: Entity, message: ChatMessage) -> SysResult {
171-
let mut mailbox = self.ecs.get_mut::<ChatBox>(entity)?;
166+
let mut mailbox = self.world.get_mut::<ChatBox>(entity)?;
172167
mailbox.send(message);
173168
Ok(())
174169
}
175170

176171
/// Gets the block at the given position.
177172
pub fn block(&self, pos: BlockPosition) -> Option<BlockId> {
178-
self.world.block_at(pos)
173+
self.level.block_at(pos)
179174
}
180175

181176
/// Sets the block at the given position.
182177
///
183178
/// Triggers necessary `BlockChangeEvent`s.
184179
pub fn set_block(&mut self, pos: BlockPosition, block: BlockId) -> bool {
185-
let was_successful = self.world.set_block_at(pos, block);
180+
let was_successful = self.level.set_block_at(pos, block);
186181
if was_successful {
187-
self.ecs.insert_event(BlockChangeEvent::single(pos));
182+
self.world.insert_event(BlockChangeEvent::single(pos));
188183
}
189184
was_successful
190185
}
@@ -198,7 +193,7 @@ impl Game {
198193
section_y: usize,
199194
block: BlockId,
200195
) -> bool {
201-
let mut chunk = match self.world.chunk_map().chunk_at_mut(chunk_pos) {
196+
let mut chunk = match self.level.chunk_map().chunk_at_mut(chunk_pos) {
202197
Some(chunk) => chunk,
203198
None => return false,
204199
};
@@ -209,10 +204,11 @@ impl Game {
209204
return false;
210205
}
211206

212-
self.ecs.insert_event(BlockChangeEvent::fill_chunk_section(
213-
chunk_pos,
214-
section_y as u32,
215-
));
207+
self.world
208+
.insert_event(BlockChangeEvent::fill_chunk_section(
209+
chunk_pos,
210+
section_y as u32,
211+
));
216212

217213
true
218214
}
@@ -232,10 +228,10 @@ impl HasResources for Game {
232228

233229
impl HasEcs for Game {
234230
fn ecs(&self) -> &Ecs {
235-
&self.ecs
231+
&self.world
236232
}
237233

238234
fn ecs_mut(&mut self) -> &mut Ecs {
239-
&mut self.ecs
235+
&mut self.world
240236
}
241237
}

feather/common/src/world.rs renamed to feather/common/src/level.rs

+9-12
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,37 @@ use std::sync::Arc;
77

88
use crate::{
99
events::ChunkLoadEvent,
10-
world_source::{null::NullWorldSource, ChunkLoadResult, WorldSource},
10+
level_source::{null::NullLevelSource, ChunkLoadResult, LevelSource},
1111
};
1212

1313
/// Stores all blocks and chunks in a world,
1414
/// along with global world data like weather, time,
15-
/// and the [`WorldSource`](crate::world_source::WorldSource).
16-
///
17-
/// NB: _not_ what most Rust ECSs call "world."
18-
/// This does not store entities; it only contains blocks.
19-
pub struct World {
15+
/// and the [`LevelSource`](crate::level_source::LevelSource).
16+
pub struct Level {
2017
chunk_map: ChunkMap,
21-
world_source: Box<dyn WorldSource>,
18+
world_source: Box<dyn LevelSource>,
2219
loading_chunks: AHashSet<ChunkPosition>,
2320
canceled_chunk_loads: AHashSet<ChunkPosition>,
2421
}
2522

26-
impl Default for World {
23+
impl Default for Level {
2724
fn default() -> Self {
2825
Self {
2926
chunk_map: ChunkMap::new(),
30-
world_source: Box::new(NullWorldSource::default()),
27+
world_source: Box::new(NullLevelSource::default()),
3128
loading_chunks: AHashSet::new(),
3229
canceled_chunk_loads: AHashSet::new(),
3330
}
3431
}
3532
}
3633

37-
impl World {
34+
impl Level {
3835
pub fn new() -> Self {
3936
Self::default()
4037
}
4138

4239
/// Creates a `World` from a `WorldSource` for loading chunks.
43-
pub fn with_source(world_source: impl WorldSource + 'static) -> Self {
40+
pub fn with_source(world_source: impl LevelSource + 'static) -> Self {
4441
Self {
4542
world_source: Box::new(world_source),
4643
..Default::default()
@@ -228,7 +225,7 @@ mod tests {
228225

229226
#[test]
230227
fn world_out_of_bounds() {
231-
let mut world = World::new();
228+
let mut world = Level::new();
232229
world
233230
.chunk_map_mut()
234231
.insert_chunk(Chunk::new(ChunkPosition::new(0, 0)));

feather/common/src/world_source.rs renamed to feather/common/src/level_source.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub enum ChunkLoadResult {
2222
}
2323

2424
/// Provides methods to load chunks, entities, and global world data.
25-
pub trait WorldSource: 'static {
25+
pub trait LevelSource: 'static {
2626
/// Enqueues the chunk at `pos` to be loaded.
2727
/// A future call to `poll_loaded_chunk` should
2828
/// return this chunk.
@@ -37,7 +37,7 @@ pub trait WorldSource: 'static {
3737

3838
/// Creates a `WorldSource` that falls back to `fallback`
3939
/// if chunks in `self` are missing or corrupt.
40-
fn with_fallback(self, fallback: impl WorldSource) -> FallbackWorldSource
40+
fn with_fallback(self, fallback: impl LevelSource) -> FallbackWorldSource
4141
where
4242
Self: Sized,
4343
{
@@ -51,11 +51,11 @@ pub trait WorldSource: 'static {
5151
/// `WorldSource` wrapping two world sources. Falls back
5252
/// to the second source if the first one is missing a chunk.
5353
pub struct FallbackWorldSource {
54-
first: Box<dyn WorldSource>,
55-
fallback: Box<dyn WorldSource>,
54+
first: Box<dyn LevelSource>,
55+
fallback: Box<dyn LevelSource>,
5656
}
5757

58-
impl WorldSource for FallbackWorldSource {
58+
impl LevelSource for FallbackWorldSource {
5959
fn queue_load(&mut self, pos: ChunkPosition) {
6060
self.first.queue_load(pos);
6161
}

feather/common/src/world_source/flat.rs renamed to feather/common/src/level_source/flat.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
use base::{BlockId, Chunk, ChunkPosition, CHUNK_WIDTH};
22

3-
use super::{ChunkLoadResult, LoadedChunk, WorldSource};
3+
use super::{ChunkLoadResult, LevelSource, LoadedChunk};
44

55
/// A world source used for debugging that emits
66
/// only flat chunks and does no IO.
7-
pub struct FlatWorldSource {
7+
pub struct FlatLevelSource {
88
archetype: Chunk,
99
loaded: Vec<LoadedChunk>,
1010
}
1111

12-
impl Default for FlatWorldSource {
12+
impl Default for FlatLevelSource {
1313
fn default() -> Self {
1414
Self::new()
1515
}
1616
}
1717

18-
impl FlatWorldSource {
18+
impl FlatLevelSource {
1919
pub fn new() -> Self {
2020
let mut archetype = Chunk::new(ChunkPosition::new(0, 0));
2121
for y in 0..64 {
@@ -38,7 +38,7 @@ impl FlatWorldSource {
3838
}
3939
}
4040

41-
impl WorldSource for FlatWorldSource {
41+
impl LevelSource for FlatLevelSource {
4242
fn queue_load(&mut self, pos: base::ChunkPosition) {
4343
let mut chunk = self.archetype.clone();
4444
chunk.set_position(pos);

0 commit comments

Comments
 (0)