Block entity support, implement signs
This commit is contained in:
parent
3fb58a1b2c
commit
c117f28b2a
|
@ -1303,7 +1303,7 @@ define_blocks! {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
data Some(rotation.data()),
|
data Some(rotation.data()),
|
||||||
material material::NON_SOLID,
|
material material::INVISIBLE,
|
||||||
model { ("minecraft", "standing_sign") },
|
model { ("minecraft", "standing_sign") },
|
||||||
collision vec![],
|
collision vec![],
|
||||||
}
|
}
|
||||||
|
@ -1412,7 +1412,7 @@ define_blocks! {
|
||||||
_ => 2,
|
_ => 2,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
material material::NON_SOLID,
|
material material::INVISIBLE,
|
||||||
model { ("minecraft", "wall_sign") },
|
model { ("minecraft", "wall_sign") },
|
||||||
variant format!("facing={}", facing.as_string()),
|
variant format!("facing={}", facing.as_string()),
|
||||||
collision vec![],
|
collision vec![],
|
||||||
|
@ -5344,7 +5344,7 @@ impl Rotation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn data(&self) -> usize {
|
pub fn data(&self) -> usize {
|
||||||
match *self {
|
match *self {
|
||||||
Rotation::South => 0,
|
Rotation::South => 0,
|
||||||
Rotation::SouthSouthWest => 1,
|
Rotation::SouthSouthWest => 1,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::fmt;
|
||||||
use direction::Direction;
|
use direction::Direction;
|
||||||
use std::ops;
|
use std::ops;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct Position {
|
pub struct Position {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
|
|
|
@ -170,7 +170,13 @@ impl Manager {
|
||||||
let changes = self.changed_entity_components.clone();
|
let changes = self.changed_entity_components.clone();
|
||||||
self.changed_entity_components = HashSet::with_hasher(BuildHasherDefault::default());
|
self.changed_entity_components = HashSet::with_hasher(BuildHasherDefault::default());
|
||||||
for entity in changes {
|
for entity in changes {
|
||||||
let state = self.entities[entity.id].0.as_mut().unwrap().clone();
|
let (cur, state) = {
|
||||||
|
let state = self.entities[entity.id].0.as_mut().unwrap();
|
||||||
|
let cur = state.components.clone();
|
||||||
|
let orig = state.clone();
|
||||||
|
state.components.or(&state.last_components);
|
||||||
|
(cur, orig)
|
||||||
|
};
|
||||||
self.trigger_add_for_systems(entity, &state.last_components, &state.components, world, renderer);
|
self.trigger_add_for_systems(entity, &state.last_components, &state.components, world, renderer);
|
||||||
self.trigger_add_for_render_systems(entity, &state.last_components, &state.components, world, renderer);
|
self.trigger_add_for_render_systems(entity, &state.last_components, &state.components, world, renderer);
|
||||||
self.trigger_remove_for_systems(entity, &state.last_components, &state.components, world, renderer);
|
self.trigger_remove_for_systems(entity, &state.last_components, &state.components, world, renderer);
|
||||||
|
@ -182,12 +188,14 @@ impl Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let state = self.entities[entity.id].0.as_mut().unwrap();
|
||||||
|
state.components = cur;
|
||||||
|
state.last_components = state.components.clone();
|
||||||
|
}
|
||||||
if state.removed {
|
if state.removed {
|
||||||
self.free_entities.push(entity.id);
|
self.free_entities.push(entity.id);
|
||||||
self.entities[entity.id].0 = None;
|
self.entities[entity.id].0 = None;
|
||||||
} else {
|
|
||||||
let state = self.entities[entity.id].0.as_mut().unwrap();
|
|
||||||
state.last_components = state.components.clone();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,6 +252,7 @@ impl Manager {
|
||||||
if let Some(set) = self.entities[e.id].0.as_mut() {
|
if let Some(set) = self.entities[e.id].0.as_mut() {
|
||||||
set.components = BSet::new(self.components.len());
|
set.components = BSet::new(self.components.len());
|
||||||
set.removed = true;
|
set.removed = true;
|
||||||
|
self.changed_entity_components.insert(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
pub mod sign;
|
||||||
|
|
||||||
|
use world::block::Block;
|
||||||
|
use shared::Position;
|
||||||
|
use ecs;
|
||||||
|
|
||||||
|
pub fn add_systems(m: &mut ecs::Manager) {
|
||||||
|
sign::add_systems(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum BlockEntityType {
|
||||||
|
Sign
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntityType {
|
||||||
|
pub fn get_block_entity(bl: Block) -> Option<BlockEntityType> {
|
||||||
|
match bl {
|
||||||
|
Block::StandingSign{..} | Block::WallSign{..} => Some(BlockEntityType::Sign),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_entity(&self, m: &mut ecs::Manager, pos: Position) -> ecs::Entity {
|
||||||
|
let e = m.create_entity();
|
||||||
|
m.add_component_direct(e, pos);
|
||||||
|
match *self {
|
||||||
|
BlockEntityType::Sign => sign::init_entity(m, e),
|
||||||
|
}
|
||||||
|
e
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,263 @@
|
||||||
|
|
||||||
|
use ecs;
|
||||||
|
use format::{self, Component};
|
||||||
|
use shared::{Direction, Position};
|
||||||
|
use world;
|
||||||
|
use world::block::Block;
|
||||||
|
use render;
|
||||||
|
use render::model;
|
||||||
|
|
||||||
|
pub fn add_systems(m: &mut ecs::Manager) {
|
||||||
|
let sys = SignRenderer::new(m);
|
||||||
|
m.add_render_system(sys);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_entity(m: &mut ecs::Manager, e: ecs::Entity) {
|
||||||
|
m.add_component_direct(e, SignInfo {
|
||||||
|
model: None,
|
||||||
|
lines: [
|
||||||
|
Component::Text(format::TextComponent::new("")),
|
||||||
|
Component::Text(format::TextComponent::new("")),
|
||||||
|
Component::Text(format::TextComponent::new("")),
|
||||||
|
Component::Text(format::TextComponent::new("")),
|
||||||
|
],
|
||||||
|
offset_x: 0.0,
|
||||||
|
offset_y: 0.0,
|
||||||
|
offset_z: 0.0,
|
||||||
|
has_stand: false,
|
||||||
|
rotation: 0.0,
|
||||||
|
dirty: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SignInfo {
|
||||||
|
model: Option<model::ModelKey>,
|
||||||
|
|
||||||
|
pub lines: [format::Component; 4],
|
||||||
|
pub dirty: bool,
|
||||||
|
|
||||||
|
offset_x: f64,
|
||||||
|
offset_y: f64,
|
||||||
|
offset_z: f64,
|
||||||
|
has_stand: bool,
|
||||||
|
rotation: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SignRenderer {
|
||||||
|
filter: ecs::Filter,
|
||||||
|
position: ecs::Key<Position>,
|
||||||
|
sign_info: ecs::Key<SignInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SignRenderer {
|
||||||
|
fn new(m: &mut ecs::Manager) -> SignRenderer {
|
||||||
|
let sign_info = m.get_key();
|
||||||
|
let position = m.get_key();
|
||||||
|
SignRenderer {
|
||||||
|
filter: ecs::Filter::new()
|
||||||
|
.with(position)
|
||||||
|
.with(sign_info),
|
||||||
|
position: position,
|
||||||
|
sign_info: sign_info,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ecs::System for SignRenderer {
|
||||||
|
|
||||||
|
fn filter(&self) -> &ecs::Filter {
|
||||||
|
&self.filter
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, m: &mut ecs::Manager, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||||
|
for e in m.find(&self.filter) {
|
||||||
|
let position = *m.get_component(e, self.position).unwrap();
|
||||||
|
let info = m.get_component_mut(e, self.sign_info).unwrap();
|
||||||
|
if info.dirty {
|
||||||
|
self.entity_removed(m, e, world, renderer);
|
||||||
|
self.entity_added(m, e, world, renderer);
|
||||||
|
}
|
||||||
|
if let Some(model) = info.model {
|
||||||
|
let mdl = renderer.model.get_model(model).unwrap();
|
||||||
|
mdl.block_light = world.get_block_light(position) as f32;
|
||||||
|
mdl.sky_light = world.get_sky_light(position) as f32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn entity_added(&mut self, m: &mut ecs::Manager, e: ecs::Entity, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||||
|
use std::f64::consts::PI;
|
||||||
|
use cgmath::{Vector3, Matrix4, Decomposed, Rotation3, Rad, Angle, Quaternion};
|
||||||
|
let position = *m.get_component(e, self.position).unwrap();
|
||||||
|
let info = m.get_component_mut(e, self.sign_info).unwrap();
|
||||||
|
info.dirty = false;
|
||||||
|
match world.get_block(position) {
|
||||||
|
Block::WallSign{facing} => {
|
||||||
|
info.offset_z = 7.5 / 16.0;
|
||||||
|
match facing {
|
||||||
|
Direction::North => {},
|
||||||
|
Direction::South => info.rotation = PI,
|
||||||
|
Direction::West => info.rotation = PI / 2.0,
|
||||||
|
Direction::East => info.rotation = -PI / 2.0,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Block::StandingSign{rotation} => {
|
||||||
|
info.offset_z = 5.0 / 16.0;
|
||||||
|
info.has_stand = true;
|
||||||
|
info.rotation = -(rotation.data() as f64 / 16.0) * PI * 2.0 + PI;
|
||||||
|
}
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
let wood = render::Renderer::get_texture(renderer.get_textures_ref(), "blocks/planks_oak");
|
||||||
|
|
||||||
|
macro_rules! rel {
|
||||||
|
($tex:expr, $x:expr, $y:expr, $w:expr, $h:expr) => (
|
||||||
|
Some($tex.relative(($x) / 16.0, ($y) / 16.0, ($w) / 16.0, ($h) / 16.0))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut verts = vec![];
|
||||||
|
// Backboard
|
||||||
|
model::append_box_texture_scale(&mut verts, -0.5, -4.0/16.0, -0.5/16.0, 1.0, 8.0/16.0, 1.0/16.0, [
|
||||||
|
rel!(wood, 0.0, 0.0, 16.0, 2.0), // Up
|
||||||
|
rel!(wood, 0.0, 0.0, 16.0, 2.0), // Down
|
||||||
|
rel!(wood, 0.0, 4.0, 16.0, 12.0), // North
|
||||||
|
rel!(wood, 0.0, 4.0, 16.0, 12.0), // South
|
||||||
|
rel!(wood, 0.0, 0.0, 2.0, 12.0), // West
|
||||||
|
rel!(wood, 0.0, 0.0, 2.0, 12.0), // East
|
||||||
|
], [
|
||||||
|
[1.5, 1.0], // Up
|
||||||
|
[1.5, 1.0], // Down
|
||||||
|
[1.5, 1.0], // North
|
||||||
|
[1.5, 1.0], // South
|
||||||
|
[1.0, 1.0], // West
|
||||||
|
[1.0, 1.0], // East
|
||||||
|
]);
|
||||||
|
for vert in &mut verts[8..12] {
|
||||||
|
vert.r = 183;
|
||||||
|
vert.g = 183;
|
||||||
|
vert.b = 196;
|
||||||
|
}
|
||||||
|
if info.has_stand {
|
||||||
|
let log = render::Renderer::get_texture(renderer.get_textures_ref(), "blocks/log_oak");
|
||||||
|
model::append_box(&mut verts, -0.5/16.0, -0.25-9.0/16.0, -0.5/16.0, 1.0/16.0, 9.0/16.0, 1.0/16.0, [
|
||||||
|
rel!(log, 0.0, 0.0, 2.0, 2.0), // Up
|
||||||
|
rel!(log, 0.0, 0.0, 2.0, 2.0), // Down
|
||||||
|
rel!(log, 0.0, 4.0, 2.0, 12.0), // North
|
||||||
|
rel!(log, 0.0, 4.0, 2.0, 12.0), // South
|
||||||
|
rel!(log, 0.0, 0.0, 2.0, 12.0), // West
|
||||||
|
rel!(log, 0.0, 0.0, 2.0, 12.0), // East
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, line) in info.lines.iter().enumerate() {
|
||||||
|
let mut state = FormatState {
|
||||||
|
line: i as f32,
|
||||||
|
width: 0.0,
|
||||||
|
offset: 0.0,
|
||||||
|
text: Vec::new(),
|
||||||
|
renderer: renderer,
|
||||||
|
};
|
||||||
|
state.build(line, format::Color::Black);
|
||||||
|
let width = state.width;
|
||||||
|
// Center align text
|
||||||
|
for vert in &mut state.text {
|
||||||
|
vert.x += width * 0.5;
|
||||||
|
}
|
||||||
|
verts.extend_from_slice(&state.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
let model = renderer.model.create_model(
|
||||||
|
model::DEFAULT,
|
||||||
|
vec![verts]
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mdl = renderer.model.get_model(model).unwrap();
|
||||||
|
mdl.radius = 2.0;
|
||||||
|
mdl.x = position.x as f32 + 0.5;
|
||||||
|
mdl.y = position.y as f32 + 0.5;
|
||||||
|
mdl.z = position.z as f32 + 0.5;
|
||||||
|
mdl.matrix[0] = Matrix4::from(Decomposed {
|
||||||
|
scale: 1.0,
|
||||||
|
rot: Quaternion::from_angle_y(Rad::new(info.rotation as f32)),
|
||||||
|
disp: Vector3::new(position.x as f32 + 0.5, -position.y as f32 - 0.5, position.z as f32 + 0.5),
|
||||||
|
}) * Matrix4::from_translation(Vector3::new(info.offset_x as f32, -info.offset_y as f32, info.offset_z as f32));
|
||||||
|
}
|
||||||
|
|
||||||
|
info.model = Some(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn entity_removed(&mut self, m: &mut ecs::Manager, e: ecs::Entity, _: &mut world::World, renderer: &mut render::Renderer) {
|
||||||
|
let info = m.get_component_mut(e, self.sign_info).unwrap();
|
||||||
|
if let Some(model) = info.model {
|
||||||
|
renderer.model.remove_model(model);
|
||||||
|
}
|
||||||
|
info.model = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FormatState<'a> {
|
||||||
|
line: f32,
|
||||||
|
offset: f32,
|
||||||
|
width: f32,
|
||||||
|
text: Vec<model::Vertex>,
|
||||||
|
renderer: &'a mut render::Renderer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a> FormatState<'a> {
|
||||||
|
fn build(&mut self, c: &Component, color: format::Color) {
|
||||||
|
match c {
|
||||||
|
&format::Component::Text(ref txt) => {
|
||||||
|
let col = FormatState::get_color(&txt.modifier, color);
|
||||||
|
self.append_text(&txt.text, col);
|
||||||
|
let modi = &txt.modifier;
|
||||||
|
if let Some(ref extra) = modi.extra {
|
||||||
|
for e in extra {
|
||||||
|
self.build(e, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append_text(&mut self, txt: &str, color: format::Color) {
|
||||||
|
const Y_SCALE: f32 = (6.0 / 16.0) / 4.0;
|
||||||
|
const X_SCALE: f32 = Y_SCALE / 16.0;
|
||||||
|
|
||||||
|
let (rr, gg, bb) = color.to_rgb();
|
||||||
|
for ch in txt.chars() {
|
||||||
|
if ch == ' ' {
|
||||||
|
self.offset += 6.0 * X_SCALE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let texture = self.renderer.ui.character_texture(ch);
|
||||||
|
let w = self.renderer.ui.size_of_char(ch) as f32;
|
||||||
|
|
||||||
|
for vert in ::model::BlockVertex::face_by_direction(Direction::North) {
|
||||||
|
self.text.push(model::Vertex {
|
||||||
|
x: vert.x * X_SCALE * w - (self.offset + w * X_SCALE),
|
||||||
|
y: vert.y * Y_SCALE - (Y_SCALE + 0.4/16.0) * self.line + 2.1 / 16.0,
|
||||||
|
z: -0.6 / 16.0,
|
||||||
|
texture: texture.clone(),
|
||||||
|
texture_x: vert.toffsetx as f64,
|
||||||
|
texture_y: vert.toffsety as f64,
|
||||||
|
r: rr,
|
||||||
|
g: gg,
|
||||||
|
b: bb,
|
||||||
|
a: 255,
|
||||||
|
id: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
self.offset += (w + 2.0) * X_SCALE;
|
||||||
|
}
|
||||||
|
if self.offset > self.width {
|
||||||
|
self.width = self.offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_color(modi: &format::Modifier, color: format::Color) -> format::Color {
|
||||||
|
modi.color.unwrap_or(color)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
pub mod player;
|
pub mod player;
|
||||||
|
pub mod block_entity;
|
||||||
|
|
||||||
use ecs;
|
use ecs;
|
||||||
use cgmath::Vector3;
|
use cgmath::Vector3;
|
||||||
|
@ -17,6 +18,8 @@ pub fn add_systems(m: &mut ecs::Manager) {
|
||||||
m.add_system(sys);
|
m.add_system(sys);
|
||||||
let sys = systems::ApplyGravity::new(m);
|
let sys = systems::ApplyGravity::new(m);
|
||||||
m.add_system(sys);
|
m.add_system(sys);
|
||||||
|
|
||||||
|
block_entity::add_systems(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Location of an entity in the world.
|
/// Location of an entity in the world.
|
||||||
|
|
|
@ -204,7 +204,7 @@ impl Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&mut self, frustum: &Frustum<f32>, perspective_matrix: &Matrix4<f32>, camera_matrix: &Matrix4<f32>, sky_offset: f32, light_level: f32) {
|
pub fn draw(&mut self, frustum: &Frustum<f32>, perspective_matrix: &Matrix4<f32>, camera_matrix: &Matrix4<f32>, light_level: f32, sky_offset: f32) {
|
||||||
let m = if self.index_type == gl::UNSIGNED_SHORT {
|
let m = if self.index_type == gl::UNSIGNED_SHORT {
|
||||||
2
|
2
|
||||||
} else {
|
} else {
|
||||||
|
@ -359,7 +359,7 @@ pub fn append_box_texture_scale(
|
||||||
z: vert.z * d + z,
|
z: vert.z * d + z,
|
||||||
texture: tex.clone(),
|
texture: tex.clone(),
|
||||||
texture_x: (vert.toffsetx as f64) * texture_scale[dir.index()][0],
|
texture_x: (vert.toffsetx as f64) * texture_scale[dir.index()][0],
|
||||||
texture_y: (vert.toffsety as f64) * texture_scale[dir.index()][0],
|
texture_y: (vert.toffsety as f64) * texture_scale[dir.index()][1],
|
||||||
r: rr,
|
r: rr,
|
||||||
g: gg,
|
g: gg,
|
||||||
b: bb,
|
b: bb,
|
||||||
|
|
|
@ -306,7 +306,7 @@ impl Server {
|
||||||
sun_model.tick(renderer, self.world_time, self.world_age);
|
sun_model.tick(renderer, self.world_time, self.world_age);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.world.tick();
|
self.world.tick(&mut self.entities);
|
||||||
|
|
||||||
// Copy to camera
|
// Copy to camera
|
||||||
if let Some(player) = self.player {
|
if let Some(player) = self.player {
|
||||||
|
@ -340,6 +340,7 @@ impl Server {
|
||||||
TeleportPlayer => on_teleport,
|
TeleportPlayer => on_teleport,
|
||||||
TimeUpdate => on_time_update,
|
TimeUpdate => on_time_update,
|
||||||
ChangeGameState => on_game_state_change,
|
ChangeGameState => on_game_state_change,
|
||||||
|
UpdateSign => on_sign_update,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(err) => panic!("Err: {:?}", err),
|
Err(err) => panic!("Err: {:?}", err),
|
||||||
|
@ -520,6 +521,16 @@ impl Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_sign_update(&mut self, update_sign: packet::play::clientbound::UpdateSign) {
|
||||||
|
self.world.add_block_entity_action(world::BlockEntityAction::UpdateSignText(
|
||||||
|
update_sign.location,
|
||||||
|
update_sign.line1,
|
||||||
|
update_sign.line2,
|
||||||
|
update_sign.line3,
|
||||||
|
update_sign.line4,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
fn on_chunk_data(&mut self, chunk_data: packet::play::clientbound::ChunkData) {
|
fn on_chunk_data(&mut self, chunk_data: packet::play::clientbound::ChunkData) {
|
||||||
self.world.load_chunk(
|
self.world.load_chunk(
|
||||||
chunk_data.chunk_x,
|
chunk_data.chunk_x,
|
||||||
|
@ -531,7 +542,7 @@ impl Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_chunk_unload(&mut self, chunk_unload: packet::play::clientbound::ChunkUnload) {
|
fn on_chunk_unload(&mut self, chunk_unload: packet::play::clientbound::ChunkUnload) {
|
||||||
self.world.unload_chunk(chunk_unload.x, chunk_unload.z);
|
self.world.unload_chunk(chunk_unload.x, chunk_unload.z, &mut self.entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_block_change(&mut self, block_change: packet::play::clientbound::BlockChange) {
|
fn on_block_change(&mut self, block_change: packet::play::clientbound::BlockChange) {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Set {
|
pub struct Set {
|
||||||
data: Vec<u64>,
|
data: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
@ -65,4 +65,10 @@ impl Set {
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn or(&mut self, other: &Set) {
|
||||||
|
for (a, b) in self.data.iter_mut().zip(&other.data) {
|
||||||
|
*a = (*a) | *b;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
106
src/world/mod.rs
106
src/world/mod.rs
|
@ -25,6 +25,9 @@ use render;
|
||||||
use collision;
|
use collision;
|
||||||
use cgmath;
|
use cgmath;
|
||||||
use chunk_builder;
|
use chunk_builder;
|
||||||
|
use ecs;
|
||||||
|
use entity::block_entity;
|
||||||
|
use format;
|
||||||
|
|
||||||
pub mod biome;
|
pub mod biome;
|
||||||
|
|
||||||
|
@ -34,6 +37,15 @@ pub struct World {
|
||||||
render_list: Vec<(i32, i32, i32)>,
|
render_list: Vec<(i32, i32, i32)>,
|
||||||
|
|
||||||
light_updates: VecDeque<LightUpdate>,
|
light_updates: VecDeque<LightUpdate>,
|
||||||
|
|
||||||
|
block_entity_actions: VecDeque<BlockEntityAction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum BlockEntityAction {
|
||||||
|
Create(Position),
|
||||||
|
Remove(Position),
|
||||||
|
UpdateSignText(Position, format::Component, format::Component, format::Component, format::Component),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
@ -68,6 +80,7 @@ impl World {
|
||||||
chunks: HashMap::with_hasher(BuildHasherDefault::default()),
|
chunks: HashMap::with_hasher(BuildHasherDefault::default()),
|
||||||
render_list: vec![],
|
render_list: vec![],
|
||||||
light_updates: VecDeque::new(),
|
light_updates: VecDeque::new(),
|
||||||
|
block_entity_actions: VecDeque::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +97,17 @@ impl World {
|
||||||
fn set_block_raw(&mut self, pos: Position, b: block::Block) -> bool {
|
fn set_block_raw(&mut self, pos: Position, b: block::Block) -> bool {
|
||||||
let cpos = CPos(pos.x >> 4, pos.z >> 4);
|
let cpos = CPos(pos.x >> 4, pos.z >> 4);
|
||||||
let chunk = self.chunks.entry(cpos).or_insert_with(|| Chunk::new(cpos));
|
let chunk = self.chunks.entry(cpos).or_insert_with(|| Chunk::new(cpos));
|
||||||
chunk.set_block(pos.x & 0xF, pos.y, pos.z & 0xF, b)
|
if chunk.set_block(pos.x & 0xF, pos.y, pos.z & 0xF, b) {
|
||||||
|
if chunk.block_entities.contains_key(&pos) {
|
||||||
|
self.block_entity_actions.push_back(BlockEntityAction::Remove(pos));
|
||||||
|
}
|
||||||
|
if block_entity::BlockEntityType::get_block_entity(b).is_some() {
|
||||||
|
self.block_entity_actions.push_back(BlockEntityAction::Create(pos));
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_block(&mut self, pos: Position) {
|
pub fn update_block(&mut self, pos: Position) {
|
||||||
|
@ -133,7 +156,7 @@ impl World {
|
||||||
chunk.set_block_light(pos.x & 0xF, pos.y, pos.z & 0xF, light);
|
chunk.set_block_light(pos.x & 0xF, pos.y, pos.z & 0xF, light);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_block_light(&self, pos: Position) -> u8 {
|
pub fn get_block_light(&self, pos: Position) -> u8 {
|
||||||
match self.chunks.get(&CPos(pos.x >> 4, pos.z >> 4)) {
|
match self.chunks.get(&CPos(pos.x >> 4, pos.z >> 4)) {
|
||||||
Some(ref chunk) => chunk.get_block_light(pos.x & 0xF, pos.y, pos.z & 0xF),
|
Some(ref chunk) => chunk.get_block_light(pos.x & 0xF, pos.y, pos.z & 0xF),
|
||||||
None => 0,
|
None => 0,
|
||||||
|
@ -146,7 +169,7 @@ impl World {
|
||||||
chunk.set_sky_light(pos.x & 0xF, pos.y, pos.z & 0xF, light);
|
chunk.set_sky_light(pos.x & 0xF, pos.y, pos.z & 0xF, light);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_sky_light(&self, pos: Position) -> u8 {
|
pub fn get_sky_light(&self, pos: Position) -> u8 {
|
||||||
match self.chunks.get(&CPos(pos.x >> 4, pos.z >> 4)) {
|
match self.chunks.get(&CPos(pos.x >> 4, pos.z >> 4)) {
|
||||||
Some(ref chunk) => chunk.get_sky_light(pos.x & 0xF, pos.y, pos.z & 0xF),
|
Some(ref chunk) => chunk.get_sky_light(pos.x & 0xF, pos.y, pos.z & 0xF),
|
||||||
None => 15,
|
None => 15,
|
||||||
|
@ -160,7 +183,11 @@ impl World {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self) {
|
pub fn add_block_entity_action(&mut self, action: BlockEntityAction) {
|
||||||
|
self.block_entity_actions.push_back(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(&mut self, m: &mut ecs::Manager) {
|
||||||
use time;
|
use time;
|
||||||
let start = time::precise_time_ns();
|
let start = time::precise_time_ns();
|
||||||
let mut updates_performed = 0;
|
let mut updates_performed = 0;
|
||||||
|
@ -174,6 +201,48 @@ impl World {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let sign_info: ecs::Key<block_entity::sign::SignInfo> = m.get_key();
|
||||||
|
|
||||||
|
while let Some(action) = self.block_entity_actions.pop_front() {
|
||||||
|
match action {
|
||||||
|
BlockEntityAction::Remove(pos) => {
|
||||||
|
if let Some(chunk) = self.chunks.get_mut(&CPos(pos.x >> 4, pos.z >> 4)) {
|
||||||
|
if let Some(entity) = chunk.block_entities.remove(&pos) {
|
||||||
|
m.remove_entity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BlockEntityAction::Create(pos) => {
|
||||||
|
if let Some(chunk) = self.chunks.get_mut(&CPos(pos.x >> 4, pos.z >> 4)) {
|
||||||
|
// Remove existing entity
|
||||||
|
if let Some(entity) = chunk.block_entities.remove(&pos) {
|
||||||
|
m.remove_entity(entity);
|
||||||
|
}
|
||||||
|
let block = chunk.get_block(pos.x & 0xF, pos.y, pos.z & 0xF);
|
||||||
|
if let Some(entity_type) = block_entity::BlockEntityType::get_block_entity(block) {
|
||||||
|
let entity = entity_type.create_entity(m, pos);
|
||||||
|
chunk.block_entities.insert(pos, entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BlockEntityAction::UpdateSignText(pos, line1, line2, line3, line4) => {
|
||||||
|
if let Some(chunk) = self.chunks.get(&CPos(pos.x >> 4, pos.z >> 4)) {
|
||||||
|
if let Some(entity) = chunk.block_entities.get(&pos) {
|
||||||
|
if let Some(sign) = m.get_component_mut(*entity, sign_info) {
|
||||||
|
sign.lines = [
|
||||||
|
line1,
|
||||||
|
line2,
|
||||||
|
line3,
|
||||||
|
line4,
|
||||||
|
];
|
||||||
|
sign.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_light_update(&mut self) {
|
fn do_light_update(&mut self) {
|
||||||
|
@ -471,8 +540,12 @@ impl World {
|
||||||
snapshot
|
snapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unload_chunk(&mut self, x: i32, z: i32) {
|
pub fn unload_chunk(&mut self, x: i32, z: i32, m: &mut ecs::Manager) {
|
||||||
self.chunks.remove(&CPos(x, z));
|
if let Some(chunk) = self.chunks.remove(&CPos(x, z)) {
|
||||||
|
for entity in chunk.block_entities.values() {
|
||||||
|
m.remove_entity(*entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_chunk(&mut self, x: i32, z: i32, new: bool, mask: u16, data: Vec<u8>) -> Result<(), protocol::Error> {
|
pub fn load_chunk(&mut self, x: i32, z: i32, new: bool, mask: u16, data: Vec<u8>) -> Result<(), protocol::Error> {
|
||||||
|
@ -529,8 +602,8 @@ impl World {
|
||||||
let m = bit::Map::from_raw(bits, bit_size as usize);
|
let m = bit::Map::from_raw(bits, bit_size as usize);
|
||||||
|
|
||||||
section.blocks = m;
|
section.blocks = m;
|
||||||
for i in 0 .. 4096 {
|
for bi in 0 .. 4096 {
|
||||||
let bl_id = section.blocks.get(i);
|
let bl_id = section.blocks.get(bi);
|
||||||
if bit_size == 13 {
|
if bit_size == 13 {
|
||||||
if section.block_map.get(bl_id)
|
if section.block_map.get(bl_id)
|
||||||
.map(|v| v.1)
|
.map(|v| v.1)
|
||||||
|
@ -543,7 +616,19 @@ impl World {
|
||||||
section.rev_block_map.insert(bl, bl_id);
|
section.rev_block_map.insert(bl, bl_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
section.block_map.get_mut(bl_id).unwrap().1 += 1;
|
let bmap = section.block_map.get_mut(bl_id).unwrap();
|
||||||
|
bmap.1 += 1;
|
||||||
|
if block_entity::BlockEntityType::get_block_entity(bmap.0).is_some() {
|
||||||
|
let pos = Position::new(
|
||||||
|
(bi & 0xF) as i32,
|
||||||
|
(bi >> 8) as i32,
|
||||||
|
((bi >> 4) & 0xF) as i32
|
||||||
|
) + (chunk.position.0 << 4, (i << 4) as i32, chunk.position.1 << 4);
|
||||||
|
if chunk.block_entities.contains_key(&pos) {
|
||||||
|
self.block_entity_actions.push_back(BlockEntityAction::Remove(pos))
|
||||||
|
}
|
||||||
|
self.block_entity_actions.push_back(BlockEntityAction::Create(pos))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for entry in §ion.block_map {
|
for entry in §ion.block_map {
|
||||||
|
@ -675,6 +760,8 @@ pub struct Chunk {
|
||||||
|
|
||||||
heightmap: [u8; 16 * 16],
|
heightmap: [u8; 16 * 16],
|
||||||
heightmap_dirty: bool,
|
heightmap_dirty: bool,
|
||||||
|
|
||||||
|
block_entities: HashMap<Position, ecs::Entity, BuildHasherDefault<FNVHash>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chunk {
|
impl Chunk {
|
||||||
|
@ -691,6 +778,7 @@ impl Chunk {
|
||||||
biomes: [0; 16 * 16],
|
biomes: [0; 16 * 16],
|
||||||
heightmap: [0; 16 * 16],
|
heightmap: [0; 16 * 16],
|
||||||
heightmap_dirty: true,
|
heightmap_dirty: true,
|
||||||
|
block_entities: HashMap::with_hasher(BuildHasherDefault::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue