Add block targeting
This commit is contained in:
parent
d719e117ad
commit
98422678a3
|
@ -27,7 +27,7 @@ use render;
|
|||
use settings::Stevenkey;
|
||||
use ecs;
|
||||
use entity;
|
||||
use cgmath;
|
||||
use cgmath::{self, Point};
|
||||
use collision::Aabb;
|
||||
use types::Gamemode;
|
||||
use shared::{Axis, Position};
|
||||
|
@ -35,6 +35,7 @@ use format;
|
|||
|
||||
mod sun;
|
||||
pub mod plugin_messages;
|
||||
pub mod target;
|
||||
|
||||
pub struct Server {
|
||||
username: String,
|
||||
|
@ -74,6 +75,7 @@ pub struct Server {
|
|||
entity_tick_timer: f64,
|
||||
|
||||
sun_model: Option<sun::SunModel>,
|
||||
target_info: target::Info,
|
||||
}
|
||||
|
||||
pub struct PlayerInfo {
|
||||
|
@ -293,6 +295,8 @@ impl Server {
|
|||
tick_timer: 0.0,
|
||||
entity_tick_timer: 0.0,
|
||||
sun_model: None,
|
||||
|
||||
target_info: target::Info::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,6 +347,12 @@ impl Server {
|
|||
}
|
||||
|
||||
self.world.tick(&mut self.entities);
|
||||
|
||||
if let Some((pos, bl)) = target::trace_ray(&self.world, 4.0, renderer.camera.pos.to_vec(), renderer.view_vector.cast(), target::test_block) {
|
||||
self.target_info.update(renderer, pos, bl);
|
||||
} else {
|
||||
self.target_info.clear(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
fn entity_tick(&mut self, renderer: &mut render::Renderer, delta: f64) {
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
|
||||
use world;
|
||||
use world::block;
|
||||
use shared::Position;
|
||||
use cgmath;
|
||||
use render;
|
||||
use render::model;
|
||||
use collision::{self, Aabb};
|
||||
|
||||
pub struct Info {
|
||||
model: Option<model::ModelKey>,
|
||||
last_block: block::Block,
|
||||
last_pos: Position,
|
||||
}
|
||||
|
||||
impl Info {
|
||||
pub fn new() -> Info {
|
||||
Info {
|
||||
model: None,
|
||||
last_block: block::Air{},
|
||||
last_pos: Position::new(0, 0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self, renderer: &mut render::Renderer) {
|
||||
self.last_block = block::Air{};
|
||||
if let Some(model) = self.model.take() {
|
||||
renderer.model.remove_model(model);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, renderer: &mut render::Renderer, pos: Position, bl: block::Block) {
|
||||
if self.last_block == bl && self.last_pos == pos {
|
||||
return;
|
||||
}
|
||||
self.last_block = bl;
|
||||
self.last_pos = pos;
|
||||
if let Some(model) = self.model.take() {
|
||||
renderer.model.remove_model(model);
|
||||
}
|
||||
let mut parts = vec![];
|
||||
|
||||
const LINE_SIZE: f64 = 1.0 / 128.0;
|
||||
let tex = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid");
|
||||
|
||||
for bound in bl.get_collision_boxes() {
|
||||
let bound = bound.add_v(cgmath::Vector3::new(pos.x as f64, pos.y as f64, pos.z as f64));
|
||||
for point in [
|
||||
(bound.min.x, bound.min.z),
|
||||
(bound.min.x, bound.max.z),
|
||||
(bound.max.x, bound.min.z),
|
||||
(bound.max.x, bound.max.z),
|
||||
].into_iter() {
|
||||
model::append_box(&mut parts,
|
||||
(point.0-LINE_SIZE) as f32, (bound.min.y-LINE_SIZE) as f32, (point.1-LINE_SIZE) as f32,
|
||||
(LINE_SIZE*2.0) as f32, ((bound.max.y-bound.min.y)+LINE_SIZE*2.0) as f32, (LINE_SIZE*2.0) as f32,
|
||||
[
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
]);
|
||||
}
|
||||
|
||||
for point in [
|
||||
(bound.min.x, bound.min.z, bound.max.x, bound.min.z),
|
||||
(bound.min.x, bound.max.z, bound.max.x, bound.max.z),
|
||||
(bound.min.x, bound.min.z, bound.min.x, bound.max.z),
|
||||
(bound.max.x, bound.min.z, bound.max.x, bound.max.z),
|
||||
].into_iter() {
|
||||
model::append_box(&mut parts,
|
||||
(point.0-LINE_SIZE) as f32, (bound.min.y-LINE_SIZE) as f32, (point.1-LINE_SIZE) as f32,
|
||||
((point.2-point.0)+(LINE_SIZE*2.0)) as f32, (LINE_SIZE*2.0) as f32, ((point.3-point.1)+(LINE_SIZE*2.0)) as f32,
|
||||
[
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
]);
|
||||
model::append_box(&mut parts,
|
||||
(point.0-LINE_SIZE) as f32, (bound.max.y-LINE_SIZE) as f32, (point.1-LINE_SIZE) as f32,
|
||||
((point.2-point.0)+(LINE_SIZE*2.0)) as f32, (LINE_SIZE*2.0) as f32, ((point.3-point.1)+(LINE_SIZE*2.0)) as f32,
|
||||
[
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
for part in &mut parts {
|
||||
part.r = 0;
|
||||
part.g = 0;
|
||||
part.b = 0;
|
||||
}
|
||||
|
||||
self.model = Some(renderer.model.create_model(model::DEFAULT, vec![parts]));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_block(world: &world::World, pos: Position, s: cgmath::Vector3<f64>, d: cgmath::Vector3<f64>) -> (bool, Option<(Position, block::Block)>) {
|
||||
let block = world.get_block(pos);
|
||||
for bound in block.get_collision_boxes() {
|
||||
let bound = bound.add_v(cgmath::Vector3::new(pos.x as f64, pos.y as f64, pos.z as f64));
|
||||
if let Some(hit) = intersects_line(bound, s, d) {
|
||||
// TODO: Face/cursor
|
||||
let _ = hit;
|
||||
return (true, Some((pos, block)));
|
||||
}
|
||||
}
|
||||
(false, None)
|
||||
}
|
||||
|
||||
fn intersects_line(bound: collision::Aabb3<f64>, origin: cgmath::Vector3<f64>, dir: cgmath::Vector3<f64>) -> Option<cgmath::Vector3<f64>> {
|
||||
const RIGHT: usize = 0;
|
||||
const LEFT: usize = 1;
|
||||
const MIDDLE: usize = 2;
|
||||
let mut quadrant = [0, 0, 0];
|
||||
let mut candidate_plane = [0.0, 0.0, 0.0];
|
||||
let mut max_t = [0.0, 0.0, 0.0];
|
||||
let mut inside = true;
|
||||
for i in 0 .. 3 {
|
||||
if origin[i] < bound.min[i] {
|
||||
quadrant[i] = LEFT;
|
||||
candidate_plane[i] = bound.min[i];
|
||||
inside = false;
|
||||
} else if origin[i] > bound.max[i] {
|
||||
quadrant[i] = RIGHT;
|
||||
candidate_plane[i] = bound.max[i];
|
||||
inside = false;
|
||||
} else {
|
||||
quadrant[i] = MIDDLE;
|
||||
}
|
||||
}
|
||||
if inside {
|
||||
return Some(origin);
|
||||
}
|
||||
|
||||
for i in 0 .. 3 {
|
||||
if quadrant[i] != MIDDLE && dir[i] != 0.0 {
|
||||
max_t[i] = (candidate_plane[i] - origin[i]) / dir[i];
|
||||
}
|
||||
}
|
||||
let mut which_plane = 0;
|
||||
for i in 1 .. 3 {
|
||||
if max_t[which_plane] < max_t[i] {
|
||||
which_plane = i;
|
||||
}
|
||||
}
|
||||
if max_t[which_plane] < 0.0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut coord = cgmath::Vector3::new(0.0, 0.0, 0.0);
|
||||
for i in 0 .. 3 {
|
||||
if which_plane != i {
|
||||
coord[i] = origin[i] + max_t[which_plane] * dir[i];
|
||||
if coord[i] < bound.min[i] || coord[i] > bound.max[i] {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
coord[i] = candidate_plane[i];
|
||||
}
|
||||
}
|
||||
Some(coord)
|
||||
}
|
||||
|
||||
pub fn trace_ray<F, R>(world: &world::World, max: f64, s: cgmath::Vector3<f64>, d: cgmath::Vector3<f64>, collide_func: F) -> Option<R>
|
||||
where F: Fn(&world::World, Position, cgmath::Vector3<f64>, cgmath::Vector3<f64>,) -> (bool, Option<R>) {
|
||||
struct Gen {
|
||||
count: i32,
|
||||
base: f64,
|
||||
d: f64,
|
||||
}
|
||||
impl Gen {
|
||||
fn new(start: f64, mut d: f64) -> Gen {
|
||||
let base = if d > 0.0 {
|
||||
(start.ceil() - start) / d
|
||||
} else if d < 0.0 {
|
||||
d = d.abs();
|
||||
(start - start.floor()) / d
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
Gen {
|
||||
count: 0,
|
||||
base: base,
|
||||
d: d,
|
||||
}
|
||||
}
|
||||
|
||||
fn next(&mut self) -> f64 {
|
||||
self.count += 1;
|
||||
if self.d == 0.0 {
|
||||
::std::f64::INFINITY
|
||||
} else {
|
||||
self.base + ((self.count as f64 - 1.0) / self.d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut x_gen = Gen::new(s.x, d.x);
|
||||
let mut y_gen = Gen::new(s.y, d.y);
|
||||
let mut z_gen = Gen::new(s.z, d.z);
|
||||
let mut next_nx = x_gen.next();
|
||||
let mut next_ny = y_gen.next();
|
||||
let mut next_nz = z_gen.next();
|
||||
|
||||
let mut x = s.x.floor() as i32;
|
||||
let mut y = s.y.floor() as i32;
|
||||
let mut z = s.z.floor() as i32;
|
||||
|
||||
loop {
|
||||
let (hit, ret) = collide_func(&world, Position::new(x, y, z), s, d);
|
||||
if hit {
|
||||
return ret;
|
||||
}
|
||||
let next_n = if next_nx <= next_ny {
|
||||
if next_nx <= next_nz {
|
||||
let old = next_nx;
|
||||
next_nx = x_gen.next();
|
||||
x += d.x.signum() as i32;
|
||||
old
|
||||
} else {
|
||||
let old = next_nz;
|
||||
next_nz = z_gen.next();
|
||||
z += d.z.signum() as i32;
|
||||
old
|
||||
}
|
||||
} else {
|
||||
if next_ny <= next_nz {
|
||||
let old = next_ny;
|
||||
next_ny = y_gen.next();
|
||||
y += d.y.signum() as i32;
|
||||
old
|
||||
} else {
|
||||
let old = next_nz;
|
||||
next_nz = z_gen.next();
|
||||
z += d.z.signum() as i32;
|
||||
old
|
||||
}
|
||||
};
|
||||
if next_n > max {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
Loading…
Reference in New Issue