Add block targeting

This commit is contained in:
Thinkofname 2016-04-21 19:53:47 +01:00
parent d719e117ad
commit 98422678a3
2 changed files with 267 additions and 1 deletions

View File

@ -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) {

256
src/server/target.rs Normal file
View File

@ -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
}