Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion server/src/chunk_logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
//! Also handles unloading chunks when unused.
use crossbeam::channel::{Receiver, Sender};
use shrev::{EventChannel, ReaderId};
use specs::{Component, Entity, Read, ReadStorage, System, World, Write};
use specs::{Component, DispatcherBuilder, Entity, Read, ReadStorage, System, World, Write};
use std::sync::atomic::{AtomicU32, Ordering};

use feather_core::world::{ChunkMap, ChunkPosition};

use rayon::prelude::*;

use crate::entity::EntityDestroyEvent;
use crate::systems::{CHUNK_HOLD_REMOVE, CHUNK_LOAD, CHUNK_OPTIMIZE, CHUNK_UNLOAD};
use crate::{chunkworker, current_time_in_millis, TickCount, TPS};
use hashbrown::HashSet;
use multimap::MultiMap;
Expand Down Expand Up @@ -398,6 +399,16 @@ impl<'a> System<'a> for ChunkOptimizeSystem {
}
}

pub fn init_logic(dispatcher: &mut DispatcherBuilder) {
dispatcher.add(ChunkLoadSystem, CHUNK_LOAD, &[]);
dispatcher.add(ChunkOptimizeSystem, CHUNK_OPTIMIZE, &[]);
}

pub fn init_handlers(dispatcher: &mut DispatcherBuilder) {
dispatcher.add(ChunkUnloadSystem::default(), CHUNK_UNLOAD, &[]);
dispatcher.add(ChunkHoldRemoveSystem::default(), CHUNK_HOLD_REMOVE, &[]);
}

#[cfg(test)]
mod tests {
use specs::{RunNow, World, WorldExt};
Expand Down
40 changes: 22 additions & 18 deletions server/src/entity/broadcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
//! range of a player.

use crate::entity::movement::degrees_to_stops;
use crate::entity::Metadata;
use crate::entity::{EntityComponent, EntityType, VelocityComponent};
use crate::entity::{EntityType, VelocityComponent};
use crate::entity::{Metadata, NamedComponent, PositionComponent};
use crate::network::{send_packet_to_all_players, NetworkComponent};
use crate::util::protocol_velocity;
use feather_core::network::packet::implementation::SpawnObject;
Expand All @@ -12,6 +12,7 @@ use shrev::EventChannel;
use specs::{
Entities, Entity, Read, ReadStorage, ReaderId, System, SystemData, World, WriteStorage,
};
use uuid::Uuid;

//const ITEM_OBJECT_ID: i8 = 2;

Expand All @@ -38,7 +39,8 @@ pub struct EntityBroadcastSystem {

impl<'a> System<'a> for EntityBroadcastSystem {
type SystemData = (
ReadStorage<'a, EntityComponent>,
ReadStorage<'a, PositionComponent>,
ReadStorage<'a, NamedComponent>,
ReadStorage<'a, NetworkComponent>,
ReadStorage<'a, VelocityComponent>,
WriteStorage<'a, Metadata>,
Expand All @@ -47,10 +49,10 @@ impl<'a> System<'a> for EntityBroadcastSystem {
);

fn run(&mut self, data: Self::SystemData) {
let (entity_comps, networks, velocities, mut metadatas, events, entities) = data;
let (positions, nameds, networks, velocities, mut metadatas, events, entities) = data;

for event in events.read(&mut self.reader.as_mut().unwrap()) {
let entity = entity_comps.get(event.entity).unwrap();
let position = positions.get(event.entity).unwrap();
let metadata = metadatas.get_mut(event.entity).unwrap();
let velocity = velocities.get(event.entity).cloned().unwrap_or_default();
let (velocity_x, velocity_y, velocity_z) = protocol_velocity(*velocity);
Expand All @@ -62,14 +64,15 @@ impl<'a> System<'a> for EntityBroadcastSystem {
// The Player Info packet was already sent by `JoinBroadcastSystem`.
match event.ty {
EntityType::Player => {
let named = nameds.get(event.entity).unwrap();
let packet = SpawnPlayer {
entity_id: event.entity.id() as i32,
player_uuid: entity.uuid,
x: entity.position.x,
y: entity.position.y,
z: entity.position.z,
yaw: degrees_to_stops(entity.position.yaw),
pitch: degrees_to_stops(entity.position.pitch),
player_uuid: named.uuid,
x: position.current.x,
y: position.current.y,
z: position.current.z,
yaw: degrees_to_stops(position.current.yaw),
pitch: degrees_to_stops(position.current.pitch),
metadata: metadata.to_raw_metadata(),
};

Expand All @@ -78,13 +81,13 @@ impl<'a> System<'a> for EntityBroadcastSystem {
EntityType::Item => {
let packet = SpawnObject {
entity_id: event.entity.id() as i32,
object_uuid: entity.uuid,
object_uuid: Uuid::new_v4(),
ty: 2, // Type 2 for item stack
x: entity.position.x,
y: entity.position.y,
z: entity.position.z,
pitch: degrees_to_stops(entity.position.pitch),
yaw: degrees_to_stops(entity.position.yaw),
x: position.current.x,
y: position.current.y,
z: position.current.z,
pitch: degrees_to_stops(position.current.pitch),
yaw: degrees_to_stops(position.current.yaw),
data: 1, // Has velocity
velocity_x,
velocity_y,
Expand All @@ -102,7 +105,8 @@ impl<'a> System<'a> for EntityBroadcastSystem {
entity_id: event.entity.id() as i32,
metadata: metadata.to_raw_metadata(),
};
send_packet_to_all_players(&networks, &entities, entity_metadata, None); // Players should know their own metadata
send_packet_to_all_players(&networks, &entities, entity_metadata, None);
// Players should know their own metadata
}
}

Expand Down
66 changes: 45 additions & 21 deletions server/src/entity/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
//! chunk, which allows for more efficient nearby
//! entity queries and packet broadcasting.

use crate::entity::{EntityComponent, EntityDestroyEvent, EntityMoveEvent, EntitySpawnEvent};
use crate::entity::{EntityDestroyEvent, EntitySpawnEvent, PositionComponent};
use feather_core::world::ChunkPosition;
use fnv::FnvHashMap;
use shrev::EventChannel;
use specs::{Entity, Read, ReadStorage, ReaderId, System, Write};
use specs::storage::ComponentEvent;
use specs::{
BitSet, Entities, Entity, Join, Read, ReadStorage, ReaderId, System, World, WorldExt, Write,
};

/// Keeps track of which entities are in which chunk.
#[derive(Debug, Clone, Deref, DerefMut, Default)]
Expand Down Expand Up @@ -57,45 +60,68 @@ impl ChunkEntities {
/// and `EntityDestroyEvent`s.
#[derive(Default)]
pub struct ChunkEntityUpdateSystem {
move_reader: Option<ReaderId<EntityMoveEvent>>,
dirty: BitSet,
move_reader: Option<ReaderId<ComponentEvent>>,
spawn_reader: Option<ReaderId<EntitySpawnEvent>>,
destroy_reader: Option<ReaderId<EntityDestroyEvent>>,
}

impl<'a> System<'a> for ChunkEntityUpdateSystem {
type SystemData = (
ReadStorage<'a, EntityComponent>,
ReadStorage<'a, PositionComponent>,
Write<'a, ChunkEntities>,
Read<'a, EventChannel<EntityMoveEvent>>,
Read<'a, EventChannel<EntitySpawnEvent>>,
Read<'a, EventChannel<EntityDestroyEvent>>,
Entities<'a>,
);

fn run(&mut self, data: Self::SystemData) {
let (entity_comps, mut entity_chunks, move_events, spawn_events, destroy_events) = data;
let (positions, mut entity_chunks, spawn_events, destroy_events, entities) = data;

self.dirty.clear();
for event in positions.channel().read(self.move_reader.as_mut().unwrap()) {
match event {
ComponentEvent::Inserted(id) | ComponentEvent::Modified(id) => {
self.dirty.add(*id);
}
_ => (),
}
}

for event in move_events.read(self.move_reader.as_mut().unwrap()) {
let new_pos = event.new_pos.chunk_pos();
let old_pos = event.old_pos.chunk_pos();
for (position, entity, _) in (&positions, &entities, &self.dirty).join() {
let new_pos = position.current.chunk_pos();
let old_pos = position.previous.chunk_pos();

if new_pos != old_pos {
entity_chunks.remove_from_chunk(old_pos, event.entity);
entity_chunks.add_to_chunk(new_pos, event.entity);
entity_chunks.remove_from_chunk(old_pos, entity);
entity_chunks.add_to_chunk(new_pos, entity);
}
}

for event in spawn_events.read(self.spawn_reader.as_mut().unwrap()) {
let pos = entity_comps.get(event.entity).unwrap().position;
let pos = positions.get(event.entity).unwrap().current;
entity_chunks.add_to_chunk(pos.chunk_pos(), event.entity);
}

for event in destroy_events.read(self.destroy_reader.as_mut().unwrap()) {
let pos = entity_comps.get(event.entity).unwrap().position;
let pos = positions.get(event.entity).unwrap().current;
entity_chunks.remove_from_chunk(pos.chunk_pos(), event.entity);
}
}

setup_impl!(move_reader, spawn_reader, destroy_reader);
fn setup(&mut self, world: &mut World) {
use specs::SystemData;

Self::SystemData::setup(world);

self.move_reader = Some(
world
.write_component::<PositionComponent>()
.register_reader(),
);
self.destroy_reader = Some(world.fetch_mut::<EventChannel<_>>().register_reader());
self.spawn_reader = Some(world.fetch_mut::<EventChannel<_>>().register_reader());
}
}

#[cfg(test)]
Expand Down Expand Up @@ -145,16 +171,14 @@ mod tests {

let entity = t::add_entity_with_pos(&mut w, EntityType::Player, pos, false);

let event = EntityMoveEvent {
entity,
new_pos: pos,
old_pos,
};
t::trigger_event(&w, event);

{
let mut chunk_entities = w.fetch_mut::<ChunkEntities>();
chunk_entities.add_to_chunk(old_pos.chunk_pos(), entity);

w.write_component::<PositionComponent>()
.get_mut(entity)
.unwrap()
.previous = old_pos;
}

d.dispatch(&w);
Expand Down
57 changes: 46 additions & 11 deletions server/src/entity/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use feather_core::world::Position;
use feather_core::Gamemode;
use glm::Vec3;
use specs::storage::BTreeStorage;
use specs::{Component, DenseVecStorage, VecStorage};
use specs::{Component, FlaggedStorage, Join, System, VecStorage, WriteStorage};
use uuid::Uuid;

pub struct PlayerComponent {
Expand All @@ -16,30 +16,65 @@ impl Component for PlayerComponent {
type Storage = BTreeStorage<Self>;
}

pub struct EntityComponent {
pub uuid: Uuid,
pub display_name: String,
pub position: Position,
pub on_ground: bool,
#[derive(Debug, PartialEq)]
pub struct PositionComponent {
/// The current position of this entity.
pub current: Position,
/// The position of this entity on the previous
/// tick. At the end of each tick, `reset` should
/// be called.
pub previous: Position,
}

impl PositionComponent {
/// Resets the current and previous position.
/// Should be called at the end of every tick.
pub fn reset(&mut self) {
self.previous = self.current;
}
}

impl Component for EntityComponent {
type Storage = VecStorage<Self>;
impl Component for PositionComponent {
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
}

/// An entity's velocity, in blocks per tick.
///
/// Entities without this component are assumed
/// to have a velocity of 0.
#[derive(Deref, DerefMut, Clone, Debug, PartialEq)]
#[derive(Deref, DerefMut, Debug, PartialEq, Clone)]
pub struct VelocityComponent(pub Vec3);

impl Component for VelocityComponent {
type Storage = DenseVecStorage<Self>;
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
}

impl Default for VelocityComponent {
fn default() -> Self {
VelocityComponent(glm::vec3(0.0, 0.0, 0.0))
Self(glm::vec3(0.0, 0.0, 0.0))
}
}

#[derive(Clone, Debug)]
pub struct NamedComponent {
pub display_name: String,
pub uuid: Uuid,
}

impl Component for NamedComponent {
type Storage = BTreeStorage<Self>;
}

/// System for resetting an entity's components
/// at the end of the tick.
pub struct ComponentResetSystem;

impl<'a> System<'a> for ComponentResetSystem {
type SystemData = WriteStorage<'a, PositionComponent>;

fn run(&mut self, mut positions: Self::SystemData) {
for position in (&mut positions).join() {
position.reset();
}
}
}
18 changes: 3 additions & 15 deletions server/src/entity/destroy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::network::{send_packet_to_player, NetworkComponent};
use feather_core::network::packet::implementation::DestroyEntities;
use shrev::{EventChannel, ReaderId};
use specs::SystemData;
use specs::{Entities, Entity, Join, Read, ReadStorage, System, World, Write};
use specs::{Entities, Entity, Join, Read, ReadStorage, System, World};

/// Event triggered when an entity
/// of any type is destroyed.
Expand All @@ -28,20 +28,14 @@ pub struct EntityDestroySystem {
reader: Option<ReaderId<EntityDestroyEvent>>,
}

impl EntityDestroySystem {
pub fn new() -> Self {
Self { reader: None }
}
}

impl<'a> System<'a> for EntityDestroySystem {
type SystemData = (Write<'a, EventChannel<EntityDestroyEvent>>, Entities<'a>);
type SystemData = (Read<'a, EventChannel<EntityDestroyEvent>>, Entities<'a>);

fn run(&mut self, data: Self::SystemData) {
let (events, entities) = data;

for event in events.read(&mut self.reader.as_mut().unwrap()) {
entities.delete(event.entity).unwrap();
let _ = entities.delete(event.entity);
}
}

Expand All @@ -62,12 +56,6 @@ pub struct EntityDestroyBroadcastSystem {
reader: Option<ReaderId<EntityDestroyEvent>>,
}

impl EntityDestroyBroadcastSystem {
pub fn new() -> Self {
Self { reader: None }
}
}

impl<'a> System<'a> for EntityDestroyBroadcastSystem {
type SystemData = (
ReadStorage<'a, NetworkComponent>,
Expand Down
Loading