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
1 change: 1 addition & 0 deletions client/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

4 changes: 1 addition & 3 deletions client/wrapper/console/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
fn main() {

}
fn main() {}
1 change: 1 addition & 0 deletions core/src/network/packet/implementation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ impl Packet for Handshake {
}
}

#[derive(PartialEq, Eq)]
pub enum HandshakeState {
Status,
Login,
Expand Down
2 changes: 1 addition & 1 deletion core/src/prelude.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub use super::{
world::{block::*, BlockPosition, ChunkPosition, Entity, EntityId, Position, World},
world::{block::*, BlockPosition, ChunkPosition, Position, World},
Difficulty, Dimension, Gamemode, PvpStyle,
};
pub use crate::network::cast_packet;
Expand Down
2 changes: 1 addition & 1 deletion core/src/world/block.rs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
pub use feather_blocks::*;
pub use feather_blocks::*;
106 changes: 50 additions & 56 deletions core/src/world/mod.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
use crate::world::block::Block;
use crate::world::chunk::Chunk;
use hashbrown::HashMap;
use std::cell::RefCell;
use std::rc::Rc;

pub mod block;
#[allow(clippy::cast_lossless)]
pub mod chunk;

pub type EntityId = i32;

#[derive(Clone, Copy, Debug, new)]
pub struct Position {
pub x: f64,
Expand Down Expand Up @@ -49,77 +45,69 @@ impl BlockPosition {
}

pub struct World {
generator: RefCell<Box<ChunkGenerator>>,
chunk_map: RefCell<HashMap<ChunkPosition, RefCell<Chunk>>>,
entities: RefCell<HashMap<EntityId, Rc<Entity>>>,
}

pub struct Entity {
pub pos: Position,
pub id: EntityId,
}

impl Entity {
pub fn new(pos: Position, id: EntityId) -> Self {
Self { pos, id }
}
pub generator: Box<ChunkGenerator>,
chunk_map: HashMap<ChunkPosition, Chunk>,
}

impl World {
pub fn new() -> Self {
pub fn new(generator: Box<ChunkGenerator>) -> Self {
Self {
generator: RefCell::new(Box::new(GridChunkGenerator {})),
chunk_map: RefCell::new(HashMap::new()),
entities: RefCell::new(HashMap::new()),
generator,
chunk_map: HashMap::new(),
}
}

pub fn chunk_at(&self, pos: ChunkPosition) -> RefCell<Chunk> {
if let Some(chunk) = self.chunk_map.borrow().get(&pos) {
return chunk.clone();
/// Retrieves the chunk at the specified location.
/// If the chunk is not loaded, `None` will be returned.
pub fn chunk_at(&mut self, pos: ChunkPosition) -> Option<&Chunk> {
if let Some(chunk) = self.chunk_map.get(&pos) {
return Some(chunk);
}
{
self.load_chunk(pos);
self.chunk_map.borrow().get(&pos).unwrap().clone()
}
}

pub fn set_block_at(&self, pos: BlockPosition, block: Block) {
let chunk = self.chunk_at(pos.chunk_pos());
chunk.borrow_mut().set_block_at(
(pos.x % 16) as u16,
pos.y as u16,
(pos.z % 16) as u16,
block,
);
None
}

pub fn block_at(&self, pos: BlockPosition) -> Block {
let _chunk = self.chunk_at(pos.chunk_pos());
let chunk = _chunk.borrow();
chunk.block_at((pos.x % 16) as u16, pos.y as u16, (pos.z % 16) as u16)
}
/// Queues the chunk at the specified
/// position for loading, indicating
/// that the chunk will be loaded at some
/// point in the future. If the chunk is already
/// queued for loading, this function will return.
/// If the chunk is already loaded, this function
/// will do nothing.
pub fn load_chunk(&mut self, pos: ChunkPosition) {
// TODO - in the future this will load chunks
// from the filesystem and insert a future
// into a pending_chunks map

fn load_chunk(&self, pos: ChunkPosition) {
let mut chunk = Chunk::new(pos);
self.generator.borrow_mut().generate(&mut chunk);
self.chunk_map.borrow_mut().insert(pos, RefCell::new(chunk));
self.generator.generate(&mut chunk);
self.chunk_map.insert(pos, chunk);
}

pub fn entity_by_id(&self, id: EntityId) -> Option<Rc<Entity>> {
if let Some(entity) = self.entities.borrow().get(&id) {
Some(Rc::clone(entity))
/// Retrieves the block at the specified
/// location. If the chunk in which the block
/// exists is not laoded, `None` is returned.
pub fn block_at(&mut self, pos: BlockPosition) -> Option<Block> {
let chunk_pos = pos.chunk_pos();

if let Some(chunk) = self.chunk_at(chunk_pos) {
let rpos = chunk_relative_pos(pos);
Some(chunk.block_at(rpos.0, rpos.1, rpos.2))
} else {
None
}
}
}

pub fn add_entity(&self, id: EntityId, entity: Rc<Entity>) {
self.entities.borrow_mut().insert(id, entity);
}
fn chunk_relative_pos(block_pos: BlockPosition) -> (u16, u16, u16) {
(
(block_pos.x % 16) as u16,
block_pos.y as u16,
(block_pos.z % 16) as u16,
)
}

trait ChunkGenerator {
pub trait ChunkGenerator {
fn generate(&self, chunk: &mut Chunk);
}

Expand Down Expand Up @@ -157,10 +145,16 @@ mod tests {

#[test]
fn test_chunk_map() {
let world = World::new();
let mut world = World::new(Box::new(GridChunkGenerator {}));

let chunk = world.chunk_at(ChunkPosition::new(0, 0));
if chunk.is_some() {
panic!();
}

world.load_chunk(ChunkPosition::new(0, 0));

let _chunk = world.chunk_at(ChunkPosition::new(0, 0));
let chunk = _chunk.borrow();
let chunk = world.chunk_at(ChunkPosition::new(0, 0)).unwrap();

for x in 0..15 {
for y in 0..64 {
Expand Down
193 changes: 193 additions & 0 deletions server/src/genindex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
use std::ops::{Index, IndexMut};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GenerationalIndex {
index: usize,
generation: u32,
}

impl GenerationalIndex {
pub fn index(&self) -> usize {
self.index
}
}

struct AllocatorEntry {
is_live: bool,
generation: u32,
}

pub struct GenerationalIndexAllocator {
entries: Vec<AllocatorEntry>,
free: Vec<usize>,
}

impl GenerationalIndexAllocator {
pub fn new() -> Self {
Self {
entries: vec![],
free: vec![],
}
}
pub fn allocate(&mut self) -> GenerationalIndex {
if self.free.is_empty() {
self.entries.push(AllocatorEntry {
is_live: true,
generation: 0,
});

GenerationalIndex {
index: self.entries.len() - 1,
generation: 0,
}
} else {
let index = self.free.pop().unwrap();
let entry = &mut self.entries[index];

entry.is_live = true;
entry.generation += 1;

GenerationalIndex {
index,
generation: entry.generation,
}
}
}

pub fn deallocate(&mut self, genindex: GenerationalIndex) {
let index = genindex.index;

assert_eq!(self.entries[index].generation, genindex.generation);

self.free.push(index);
self.entries[index].is_live = false;
}
}

struct ArrayEntry<T> {
value: T,
generation: u32,
}

pub struct GenerationalArray<T>(Vec<Option<ArrayEntry<T>>>);

impl<T> GenerationalArray<T> {
pub fn new() -> Self {
Self(vec![])
}

pub fn set(&mut self, index: GenerationalIndex, value: T) {
if self.0.len() >= index.index() {
self.0.push(None);
}

self.0[index.index()] = Some(ArrayEntry {
value,
generation: index.generation,
});
}

pub fn remove(&mut self, index: GenerationalIndex) -> Option<T> {
let entry = &mut self.0[index.index()];
if let Some(entry) = entry {
if entry.generation == index.generation {
let entry = self.0.get_mut(index.index()).unwrap().take().unwrap();
return Some(entry.value);
}
}

None
}

pub fn get(&self, index: GenerationalIndex) -> Option<&T> {
let entry = self.0.get(index.index());

if entry.is_none() {
return None;
}

let entry = entry.unwrap();
if let Some(entry) = entry {
if entry.generation != index.generation {
return None;
}

Some(&entry.value)
} else {
None
}
}

pub fn get_mut(&mut self, index: GenerationalIndex) -> Option<&mut T> {
let entry = self.0.get_mut(index.index());

if entry.is_none() {
return None;
}

let entry = entry.unwrap();
if let Some(entry) = entry {
if entry.generation != index.generation {
return None;
}

Some(&mut entry.value)
} else {
None
}
}
}

impl<T> Index<GenerationalIndex> for GenerationalArray<T> {
type Output = T;

fn index(&self, index: GenerationalIndex) -> &Self::Output {
self.get(index).unwrap()
}
}

impl<T> IndexMut<GenerationalIndex> for GenerationalArray<T> {
fn index_mut(&mut self, index: GenerationalIndex) -> &mut Self::Output {
self.get_mut(index).unwrap()
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_allocator() {
let mut allocator = GenerationalIndexAllocator::new();

let index = allocator.allocate();
assert_eq!(index.generation, 0);
assert_eq!(index.index(), 0);

let index2 = allocator.allocate();
assert_eq!(index2.generation, 0);
assert_eq!(index2.index(), 1);

allocator.deallocate(index);
let index3 = allocator.allocate();
assert_eq!(index.index(), index3.index());
assert_eq!(index3.generation, 1);
}

#[test]
fn test_array() {
let mut arr = GenerationalArray::new();
let mut alloc = GenerationalIndexAllocator::new();

let index1 = alloc.allocate();
arr.set(index1, "test");
assert_eq!(arr.get(index1), Some(&"test"));

alloc.deallocate(index1);

let index2 = alloc.allocate();
arr.set(index2, "test2");
assert_eq!(arr.get(index2), Some(&"test2"));
assert_eq!(arr.get(index1), None);
}
}
Loading