Block entity support, implement signs
This commit is contained in:
parent
3fb58a1b2c
commit
c117f28b2a
|
@ -1303,7 +1303,7 @@ define_blocks! {
|
|||
],
|
||||
},
|
||||
data Some(rotation.data()),
|
||||
material material::NON_SOLID,
|
||||
material material::INVISIBLE,
|
||||
model { ("minecraft", "standing_sign") },
|
||||
collision vec![],
|
||||
}
|
||||
|
@ -1412,7 +1412,7 @@ define_blocks! {
|
|||
_ => 2,
|
||||
})
|
||||
},
|
||||
material material::NON_SOLID,
|
||||
material material::INVISIBLE,
|
||||
model { ("minecraft", "wall_sign") },
|
||||
variant format!("facing={}", facing.as_string()),
|
||||
collision vec![],
|
||||
|
@ -5344,7 +5344,7 @@ impl Rotation {
|
|||
}
|
||||
}
|
||||
|
||||
fn data(&self) -> usize {
|
||||
pub fn data(&self) -> usize {
|
||||
match *self {
|
||||
Rotation::South => 0,
|
||||
Rotation::SouthSouthWest => 1,
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::fmt;
|
|||
use direction::Direction;
|
||||
use std::ops;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Position {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
|
|
|
@ -170,7 +170,13 @@ impl Manager {
|
|||
let changes = self.changed_entity_components.clone();
|
||||
self.changed_entity_components = HashSet::with_hasher(BuildHasherDefault::default());
|
||||
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_render_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 {
|
||||
self.free_entities.push(entity.id);
|
||||
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() {
|
||||
set.components = BSet::new(self.components.len());
|
||||
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 block_entity;
|
||||
|
||||
use ecs;
|
||||
use cgmath::Vector3;
|
||||
|
@ -17,6 +18,8 @@ pub fn add_systems(m: &mut ecs::Manager) {
|
|||
m.add_system(sys);
|
||||
let sys = systems::ApplyGravity::new(m);
|
||||
m.add_system(sys);
|
||||
|
||||
block_entity::add_systems(m);
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
2
|
||||
} else {
|
||||
|
@ -359,7 +359,7 @@ pub fn append_box_texture_scale(
|
|||
z: vert.z * d + z,
|
||||
texture: tex.clone(),
|
||||
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,
|
||||
g: gg,
|
||||
b: bb,
|
||||
|
|
|
@ -306,7 +306,7 @@ impl Server {
|
|||
sun_model.tick(renderer, self.world_time, self.world_age);
|
||||
}
|
||||
|
||||
self.world.tick();
|
||||
self.world.tick(&mut self.entities);
|
||||
|
||||
// Copy to camera
|
||||
if let Some(player) = self.player {
|
||||
|
@ -340,6 +340,7 @@ impl Server {
|
|||
TeleportPlayer => on_teleport,
|
||||
TimeUpdate => on_time_update,
|
||||
ChangeGameState => on_game_state_change,
|
||||
UpdateSign => on_sign_update,
|
||||
}
|
||||
},
|
||||
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) {
|
||||
self.world.load_chunk(
|
||||
chunk_data.chunk_x,
|
||||
|
@ -531,7 +542,7 @@ impl Server {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Set {
|
||||
data: Vec<u64>,
|
||||
}
|
||||
|
@ -65,4 +65,10 @@ impl Set {
|
|||
}
|
||||
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 cgmath;
|
||||
use chunk_builder;
|
||||
use ecs;
|
||||
use entity::block_entity;
|
||||
use format;
|
||||
|
||||
pub mod biome;
|
||||
|
||||
|
@ -34,6 +37,15 @@ pub struct World {
|
|||
render_list: Vec<(i32, i32, i32)>,
|
||||
|
||||
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)]
|
||||
|
@ -68,6 +80,7 @@ impl World {
|
|||
chunks: HashMap::with_hasher(BuildHasherDefault::default()),
|
||||
render_list: vec![],
|
||||
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 {
|
||||
let cpos = CPos(pos.x >> 4, pos.z >> 4);
|
||||
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) {
|
||||
|
@ -133,7 +156,7 @@ impl World {
|
|||
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)) {
|
||||
Some(ref chunk) => chunk.get_block_light(pos.x & 0xF, pos.y, pos.z & 0xF),
|
||||
None => 0,
|
||||
|
@ -146,7 +169,7 @@ impl World {
|
|||
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)) {
|
||||
Some(ref chunk) => chunk.get_sky_light(pos.x & 0xF, pos.y, pos.z & 0xF),
|
||||
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;
|
||||
let start = time::precise_time_ns();
|
||||
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) {
|
||||
|
@ -471,8 +540,12 @@ impl World {
|
|||
snapshot
|
||||
}
|
||||
|
||||
pub fn unload_chunk(&mut self, x: i32, z: i32) {
|
||||
self.chunks.remove(&CPos(x, z));
|
||||
pub fn unload_chunk(&mut self, x: i32, z: i32, m: &mut ecs::Manager) {
|
||||
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> {
|
||||
|
@ -529,8 +602,8 @@ impl World {
|
|||
let m = bit::Map::from_raw(bits, bit_size as usize);
|
||||
|
||||
section.blocks = m;
|
||||
for i in 0 .. 4096 {
|
||||
let bl_id = section.blocks.get(i);
|
||||
for bi in 0 .. 4096 {
|
||||
let bl_id = section.blocks.get(bi);
|
||||
if bit_size == 13 {
|
||||
if section.block_map.get(bl_id)
|
||||
.map(|v| v.1)
|
||||
|
@ -543,7 +616,19 @@ impl World {
|
|||
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 {
|
||||
|
@ -675,6 +760,8 @@ pub struct Chunk {
|
|||
|
||||
heightmap: [u8; 16 * 16],
|
||||
heightmap_dirty: bool,
|
||||
|
||||
block_entities: HashMap<Position, ecs::Entity, BuildHasherDefault<FNVHash>>,
|
||||
}
|
||||
|
||||
impl Chunk {
|
||||
|
@ -691,6 +778,7 @@ impl Chunk {
|
|||
biomes: [0; 16 * 16],
|
||||
heightmap: [0; 16 * 16],
|
||||
heightmap_dirty: true,
|
||||
block_entities: HashMap::with_hasher(BuildHasherDefault::default()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue