Base implementation for worlds/blocks
This commit is contained in:
parent
7f10580b67
commit
5f17aead7e
|
@ -0,0 +1,25 @@
|
|||
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! create_ids {
|
||||
($t:ty, ) => ();
|
||||
($t:ty, prev($prev:ident), $name:ident) => (
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $name: $t = $prev + 1;
|
||||
);
|
||||
($t:ty, prev($prev:ident), $name:ident, $($n:ident),+) => (
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $name: $t = $prev + 1;
|
||||
create_ids!($t, prev($name), $($n),+);
|
||||
);
|
||||
($t:ty, $name:ident, $($n:ident),+) => (
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $name: $t = 0;
|
||||
create_ids!($t, prev($name), $($n),+);
|
||||
);
|
||||
($t:ty, $name:ident) => (
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $name: $t = 0;
|
||||
);
|
||||
}
|
10
src/main.rs
10
src/main.rs
|
@ -14,6 +14,8 @@
|
|||
|
||||
#![recursion_limit="200"]
|
||||
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
pub mod ecs;
|
||||
pub mod protocol;
|
||||
pub mod format;
|
||||
|
@ -27,6 +29,8 @@ pub mod ui;
|
|||
pub mod screen;
|
||||
#[macro_use]
|
||||
pub mod console;
|
||||
pub mod server;
|
||||
pub mod world;
|
||||
|
||||
extern crate glutin;
|
||||
extern crate image;
|
||||
|
@ -62,6 +66,8 @@ pub struct Game {
|
|||
console: Arc<Mutex<console::Console>>,
|
||||
should_close: bool,
|
||||
mouse_pos: (i32, i32),
|
||||
|
||||
server: server::Server,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -78,8 +84,7 @@ fn main() {
|
|||
log::set_logger(|max_log_level| {
|
||||
max_log_level.set(log::LogLevelFilter::Trace);
|
||||
Box::new(proxy)
|
||||
})
|
||||
.unwrap();
|
||||
}).unwrap();
|
||||
|
||||
info!("Starting steven");
|
||||
|
||||
|
@ -121,6 +126,7 @@ fn main() {
|
|||
console: con,
|
||||
should_close: false,
|
||||
mouse_pos: (0, 0),
|
||||
server: server::Server::dummy_server(),
|
||||
};
|
||||
|
||||
while !game.should_close {
|
||||
|
|
|
@ -34,29 +34,6 @@ use time;
|
|||
|
||||
pub const SUPPORTED_PROTOCOL: i32 = 74;
|
||||
|
||||
#[doc(hidden)]
|
||||
macro_rules! create_ids {
|
||||
($t:ty, ) => ();
|
||||
($t:ty, prev($prev:ident), $name:ident) => (
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $name: $t = $prev + 1;
|
||||
);
|
||||
($t:ty, prev($prev:ident), $name:ident, $($n:ident),+) => (
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $name: $t = $prev + 1;
|
||||
create_ids!($t, prev($name), $($n),+);
|
||||
);
|
||||
($t:ty, $name:ident, $($n:ident),+) => (
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $name: $t = 0;
|
||||
create_ids!($t, prev($name), $($n),+);
|
||||
);
|
||||
($t:ty, $name:ident) => (
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $name: $t = 0;
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// Helper macro for defining packets
|
||||
#[macro_export]
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2015 Matthew Collins
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use protocol;
|
||||
use world;
|
||||
use world::block;
|
||||
use rand::{self, Rng};
|
||||
|
||||
pub struct Server {
|
||||
conn: Option<protocol::Conn>,
|
||||
world: world::World,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn dummy_server() -> Server {
|
||||
let mut world = world::World::new();
|
||||
let mut rng = rand::thread_rng();
|
||||
for x in -7*16 .. 7*16 {
|
||||
for z in -7*16 .. 7*16 {
|
||||
let h = rng.gen_range(3, 10);
|
||||
for y in 0 .. h {
|
||||
world.set_block(x, y, z, block::MISSING);
|
||||
}
|
||||
}
|
||||
}
|
||||
Server {
|
||||
conn: None,
|
||||
world: world,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
pub struct Map {
|
||||
bits: Vec<u64>,
|
||||
bit_size: usize,
|
||||
pub bit_size: usize,
|
||||
length: usize,
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ impl Map {
|
|||
map
|
||||
}
|
||||
|
||||
pub fn resize(self, size: usize) -> Map {
|
||||
pub fn resize(&self, size: usize) -> Map {
|
||||
let mut n = Map::new(self.length, size);
|
||||
for i in 0..self.length {
|
||||
n.set(i, self.get(i));
|
||||
|
|
|
@ -19,3 +19,4 @@ mod metadata;
|
|||
pub use self::metadata::*;
|
||||
|
||||
pub mod bit;
|
||||
pub mod nibble;
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2015 Matthew Collins
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
pub struct Array {
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Array {
|
||||
pub fn new(size: usize) -> Array {
|
||||
Array {
|
||||
data: vec![0; (size + 1) >> 1],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, idx: usize) -> u8 {
|
||||
let val = self.data[idx>>1];
|
||||
if idx&1 == 0 {
|
||||
val & 0xF
|
||||
} else {
|
||||
val >> 4
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, idx: usize, val: u8) {
|
||||
let i = idx >> 1;
|
||||
let old = self.data[i];
|
||||
if idx&1 == 0 {
|
||||
self.data[i] = (old & 0xF0) | (val & 0xF);
|
||||
} else {
|
||||
self.data[i] = (old & 0x0F) | ((val & 0xF) << 4);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Block {
|
||||
pub render: bool,
|
||||
}
|
||||
|
||||
macro_rules! define_blocks {
|
||||
(
|
||||
$(
|
||||
$name:ident $bl:expr
|
||||
)*
|
||||
) => (
|
||||
const BLOCKS: &'static [Block] = &[
|
||||
$(
|
||||
$bl
|
||||
),*
|
||||
];
|
||||
mod internal_ids { create_ids!(usize, $($name),*); }
|
||||
$(
|
||||
pub const $name: &'static Block = &BLOCKS[internal_ids::$name];
|
||||
)*
|
||||
|
||||
impl Block {
|
||||
pub fn get_id(&self) -> usize {
|
||||
$(
|
||||
if self == $name { return internal_ids::$name; }
|
||||
)*
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
define_blocks! {
|
||||
AIR Block {
|
||||
render: false,
|
||||
}
|
||||
MISSING Block {
|
||||
render: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_block_by_id(id: usize) -> &'static Block {
|
||||
if id >= BLOCKS.len() {
|
||||
return MISSING;
|
||||
}
|
||||
&BLOCKS[id]
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
// Copyright 2015 Matthew Collins
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
pub mod block;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use types::bit;
|
||||
use types::nibble;
|
||||
|
||||
pub struct World {
|
||||
chunks: HashMap<CPos, Chunk>,
|
||||
}
|
||||
|
||||
impl World {
|
||||
pub fn new() -> World {
|
||||
World {
|
||||
chunks: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_block(&mut self, x: i32, y: i32, z: i32, b: &'static block::Block) {
|
||||
let cpos = CPos(x >> 4, z >> 4);
|
||||
if !self.chunks.contains_key(&cpos) {
|
||||
self.chunks.insert(cpos, Chunk::new(cpos));
|
||||
}
|
||||
let chunk = self.chunks.get_mut(&cpos).unwrap();
|
||||
chunk.set_block(x & 0xF, y, z & 0xF, b);
|
||||
}
|
||||
|
||||
pub fn get_block(&self, x: i32, y: i32, z: i32) -> &'static block::Block {
|
||||
match self.chunks.get(&CPos(x >> 4, z >> 4)) {
|
||||
Some(ref chunk) => chunk.get_block(x & 0xF, y, z & 0xF),
|
||||
None => block::AIR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct CPos(i32, i32);
|
||||
|
||||
pub struct Chunk {
|
||||
position: CPos,
|
||||
|
||||
sections: [Option<Section>; 16],
|
||||
biomes: [u8; 16 * 16],
|
||||
}
|
||||
|
||||
impl Chunk {
|
||||
fn new(pos: CPos) -> Chunk {
|
||||
Chunk {
|
||||
position: pos,
|
||||
sections: [
|
||||
None,None,None,None,
|
||||
None,None,None,None,
|
||||
None,None,None,None,
|
||||
None,None,None,None,
|
||||
],
|
||||
biomes: [0; 16 * 16],
|
||||
}
|
||||
}
|
||||
|
||||
fn set_block(&mut self, x: i32, y: i32, z: i32, b: &'static block::Block) {
|
||||
let s_idx = y >> 4;
|
||||
if s_idx < 0 || s_idx > 15 {
|
||||
return;
|
||||
}
|
||||
if self.sections[s_idx as usize].is_none() {
|
||||
if b == block::AIR {
|
||||
return;
|
||||
}
|
||||
self.sections[s_idx as usize] = Some(Section::new(s_idx as u8));
|
||||
}
|
||||
let section = self.sections[s_idx as usize].as_mut().unwrap();
|
||||
section.set_block(x, y & 0xF, z, b);
|
||||
}
|
||||
|
||||
fn get_block(&self, x: i32, y: i32, z: i32) -> &'static block::Block {
|
||||
let s_idx = y >> 4;
|
||||
if s_idx < 0 || s_idx > 15 {
|
||||
return block::AIR;
|
||||
}
|
||||
match self.sections[s_idx as usize].as_ref() {
|
||||
Some(sec) => sec.get_block(x, y & 0xF, z),
|
||||
None => block::AIR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Section {
|
||||
y: u8,
|
||||
|
||||
blocks: bit::Map,
|
||||
block_map: Vec<(&'static block::Block, u32)>,
|
||||
rev_block_map: HashMap<&'static block::Block, usize>,
|
||||
|
||||
block_light: nibble::Array,
|
||||
sky_light: nibble::Array,
|
||||
|
||||
dirty: bool,
|
||||
}
|
||||
|
||||
impl Section {
|
||||
fn new(y: u8) -> Section {
|
||||
let mut section = Section {
|
||||
y: y,
|
||||
|
||||
blocks: bit::Map::new(4096, 4),
|
||||
block_map: vec![
|
||||
(block::AIR, 0xFFFFFFFF)
|
||||
],
|
||||
rev_block_map: HashMap::new(),
|
||||
|
||||
block_light: nibble::Array::new(16 * 16 * 16),
|
||||
sky_light: nibble::Array::new(16 * 16 * 16),
|
||||
|
||||
dirty: false,
|
||||
};
|
||||
for i in 0 .. 16*16*16 {
|
||||
section.sky_light.set(i, 0xF);
|
||||
}
|
||||
section.rev_block_map.insert(block::AIR, 0);
|
||||
section
|
||||
}
|
||||
|
||||
fn get_block(&self, x: i32, y: i32, z: i32) -> &'static block::Block {
|
||||
let idx = self.blocks.get(((y << 8) | (z << 4) | x) as usize);
|
||||
self.block_map[idx].0
|
||||
}
|
||||
|
||||
fn set_block(&mut self, x: i32, y: i32, z: i32, b: &'static block::Block) {
|
||||
let old = self.get_block(x, y, z);
|
||||
if old == b {
|
||||
return;
|
||||
}
|
||||
// Clean up old block
|
||||
{
|
||||
let idx = self.rev_block_map[old];
|
||||
let info = &mut self.block_map[idx];
|
||||
info.1 -= 1;
|
||||
if info.1 == 0 { // None left of this type
|
||||
self.rev_block_map.remove(old);
|
||||
}
|
||||
}
|
||||
|
||||
if !self.rev_block_map.contains_key(b) {
|
||||
let mut found = false;
|
||||
for (i, ref mut info) in self.block_map.iter_mut().enumerate() {
|
||||
if info.1 == 0 {
|
||||
info.0 = b;
|
||||
self.rev_block_map.insert(b, i);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
if self.block_map.len() >= 1 << self.blocks.bit_size {
|
||||
let new_size = self.blocks.bit_size << 1;
|
||||
let new_blocks = self.blocks.resize(new_size);
|
||||
self.blocks = new_blocks;
|
||||
}
|
||||
self.rev_block_map.insert(b, self.block_map.len());
|
||||
self.block_map.push((b, 0));
|
||||
}
|
||||
}
|
||||
|
||||
let idx = self.rev_block_map[b];
|
||||
let info = &mut self.block_map[idx];
|
||||
info.1 += 1;
|
||||
self.blocks.set(((y << 8) | (z << 4) | x) as usize, idx);
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
fn get_block_light(&self, x: i32, y: i32, z: i32) -> u8 {
|
||||
self.block_light.get(((y << 8) | (z << 4) | x) as usize)
|
||||
}
|
||||
|
||||
fn set_block_light(&mut self, x: i32, y: i32, z: i32, l: u8) {
|
||||
self.block_light.set(((y << 8) | (z << 4) | x) as usize, l);
|
||||
}
|
||||
|
||||
fn get_sky_light(&self, x: i32, y: i32, z: i32) -> u8 {
|
||||
self.sky_light.get(((y << 8) | (z << 4) | x) as usize)
|
||||
}
|
||||
|
||||
fn set_sky_light(&mut self, x: i32, y: i32, z: i32, l: u8) {
|
||||
self.sky_light.set(((y << 8) | (z << 4) | x) as usize, l);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue