mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added raycasting (needs testing) and basic character terrain collision
Former-commit-id: be6bfacfd28e777a64d8157fce129f8072e20b38
This commit is contained in:
parent
61afb98869
commit
f210de09df
@ -194,10 +194,10 @@ impl Client {
|
|||||||
{
|
{
|
||||||
let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
|
let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
|
||||||
|
|
||||||
for i in chunk_pos.x - 2..chunk_pos.x + 2 {
|
for i in chunk_pos.x - 3..chunk_pos.x + 3 {
|
||||||
for j in chunk_pos.y - 2..chunk_pos.y + 2 {
|
for j in chunk_pos.y - 3..chunk_pos.y + 3 {
|
||||||
for k in 0..1 {
|
for k in 0..1 {
|
||||||
let key = chunk_pos + Vec3::new(i, j, k);
|
let key = Vec3::new(i, j, k);
|
||||||
if self.state.terrain().get_key(key).is_none()
|
if self.state.terrain().get_key(key).is_none()
|
||||||
&& !self.pending_chunks.contains(&key)
|
&& !self.pending_chunks.contains(&key)
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,8 @@ pub mod terrain;
|
|||||||
pub mod util;
|
pub mod util;
|
||||||
pub mod volumes;
|
pub mod volumes;
|
||||||
pub mod vol;
|
pub mod vol;
|
||||||
|
pub mod ray;
|
||||||
|
|
||||||
// TODO: unignore the code here, for some reason it refuses to compile here while has no problems copy-pasted elsewhere
|
// TODO: unignore the code here, for some reason it refuses to compile here while has no problems copy-pasted elsewhere
|
||||||
/// The networking module containing high-level wrappers of `TcpListener` and `TcpStream` (`PostOffice` and `PostBox` respectively) and data types used by both the server and client
|
/// The networking module containing high-level wrappers of `TcpListener` and `TcpStream` (`PostOffice` and `PostBox` respectively) and data types used by both the server and client
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -179,7 +179,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try getting messages from the send channel
|
// Try getting messages from the send channel
|
||||||
for _ in 0..10 {
|
for _ in 0..100 {
|
||||||
match send_rx.try_recv() {
|
match send_rx.try_recv() {
|
||||||
Ok(send_msg) => {
|
Ok(send_msg) => {
|
||||||
// Serialize message
|
// Serialize message
|
||||||
@ -209,7 +209,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try sending bytes through the TCP stream
|
// Try sending bytes through the TCP stream
|
||||||
for _ in 0..10 {
|
for _ in 0..100 {
|
||||||
//println!("HERE! Outgoing len: {}", outgoing_chunks.len());
|
//println!("HERE! Outgoing len: {}", outgoing_chunks.len());
|
||||||
match outgoing_chunks.pop_front() {
|
match outgoing_chunks.pop_front() {
|
||||||
Some(chunk) => match stream.write_all(&chunk) {
|
Some(chunk) => match stream.write_all(&chunk) {
|
||||||
@ -230,7 +230,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try receiving bytes from the TCP stream
|
// Try receiving bytes from the TCP stream
|
||||||
for _ in 0..10 {
|
for _ in 0..100 {
|
||||||
let mut buf = [0; 1024];
|
let mut buf = [0; 1024];
|
||||||
|
|
||||||
match stream.read(&mut buf) {
|
match stream.read(&mut buf) {
|
||||||
@ -245,7 +245,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try turning bytes into messages
|
// Try turning bytes into messages
|
||||||
for _ in 0..10 {
|
for _ in 0..100 {
|
||||||
match incoming_buf.get(0..8) {
|
match incoming_buf.get(0..8) {
|
||||||
Some(len_bytes) => {
|
Some(len_bytes) => {
|
||||||
let len = usize::from_le_bytes(<[u8; 8]>::try_from(len_bytes).unwrap()); // Can't fail
|
let len = usize::from_le_bytes(<[u8; 8]>::try_from(len_bytes).unwrap()); // Can't fail
|
||||||
|
77
common/src/ray.rs
Normal file
77
common/src/ray.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use vek::*;
|
||||||
|
use crate::vol::{
|
||||||
|
Vox,
|
||||||
|
ReadVol,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait RayUntil<V: Vox> = FnMut(&V) -> bool;
|
||||||
|
|
||||||
|
pub struct Ray<'a, V: ReadVol, F: RayUntil<V::Vox>> {
|
||||||
|
vol: &'a V,
|
||||||
|
from: Vec3<f32>,
|
||||||
|
to: Vec3<f32>,
|
||||||
|
until: F,
|
||||||
|
max_iter: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
|
||||||
|
pub fn new(vol: &'a V, from: Vec3<f32>, to: Vec3<f32>, until: F) -> Self {
|
||||||
|
Self {
|
||||||
|
vol,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
until,
|
||||||
|
max_iter: 100,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn until<G: RayUntil<V::Vox>>(self, g: G) -> Ray<'a, V, G> {
|
||||||
|
Ray {
|
||||||
|
vol: self.vol,
|
||||||
|
from: self.from,
|
||||||
|
to: self.to,
|
||||||
|
until: g,
|
||||||
|
max_iter: self.max_iter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_iter(mut self, max_iter: usize) -> Self {
|
||||||
|
self.max_iter = max_iter;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cast(mut self) -> (f32, Result<&'a V::Vox, V::Err>) {
|
||||||
|
// TODO: Fully test this!
|
||||||
|
|
||||||
|
const PLANCK: f32 = 0.001;
|
||||||
|
|
||||||
|
let mut dist = 0.0;
|
||||||
|
let dir = (self.to - self.from).normalized();
|
||||||
|
|
||||||
|
let mut pos = self.from;
|
||||||
|
let mut ipos = pos.map(|e| e as i32);
|
||||||
|
|
||||||
|
for _ in 0..self.max_iter {
|
||||||
|
pos = dir * dist;
|
||||||
|
ipos = pos.map(|e| e as i32);
|
||||||
|
|
||||||
|
match self.vol
|
||||||
|
.get(ipos)
|
||||||
|
.map(|vox| (vox, (self.until)(vox)))
|
||||||
|
{
|
||||||
|
Ok((vox, true)) => return (dist, Ok(vox)),
|
||||||
|
Ok((_, false)) => {},
|
||||||
|
Err(err) => return (dist, Err(err)),
|
||||||
|
}
|
||||||
|
|
||||||
|
let deltas = (
|
||||||
|
dir.map(|e| if e < 0.0 { 0.0 } else { 1.0 }) -
|
||||||
|
pos.map(|e| e.fract())
|
||||||
|
) / dir;
|
||||||
|
|
||||||
|
dist += deltas.reduce(f32::min).max(PLANCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
(dist, self.vol.get(ipos))
|
||||||
|
}
|
||||||
|
}
|
@ -1,25 +1,42 @@
|
|||||||
// Library
|
use vek::*;
|
||||||
use specs::{Join, Read, ReadStorage, System, WriteStorage};
|
use specs::{Join, Read, ReadStorage, System, WriteStorage, ReadExpect};
|
||||||
|
|
||||||
// Crate
|
|
||||||
use crate::{
|
use crate::{
|
||||||
comp::phys::{Pos, Vel},
|
comp::phys::{Pos, Vel},
|
||||||
state::DeltaTime,
|
state::DeltaTime,
|
||||||
|
terrain::TerrainMap,
|
||||||
|
vol::{Vox, ReadVol},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Basic ECS physics system
|
// Basic ECS physics system
|
||||||
pub struct Sys;
|
pub struct Sys;
|
||||||
|
|
||||||
|
const GRAVITY: f32 = 9.81;
|
||||||
|
|
||||||
impl<'a> System<'a> for Sys {
|
impl<'a> System<'a> for Sys {
|
||||||
type SystemData = (
|
type SystemData = (
|
||||||
WriteStorage<'a, Pos>,
|
ReadExpect<'a, TerrainMap>,
|
||||||
ReadStorage<'a, Vel>,
|
|
||||||
Read<'a, DeltaTime>,
|
Read<'a, DeltaTime>,
|
||||||
|
WriteStorage<'a, Pos>,
|
||||||
|
WriteStorage<'a, Vel>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, (mut positions, velocities, dt): Self::SystemData) {
|
fn run(&mut self, (terrain, dt, mut positions, mut velocities): Self::SystemData) {
|
||||||
(&mut positions, &velocities)
|
for (pos, vel) in (&mut positions, &mut velocities).join() {
|
||||||
.join() // this can be parallelized with par_join()
|
// Gravity
|
||||||
.for_each(|(pos, vel)| pos.0 += vel.0 * dt.0 as f32);
|
vel.0.z -= GRAVITY * dt.0 as f32;
|
||||||
|
|
||||||
|
// Movement
|
||||||
|
pos.0 += vel.0 * dt.0 as f32;
|
||||||
|
|
||||||
|
// Basic collision with terrain
|
||||||
|
while terrain
|
||||||
|
.get(pos.0.map(|e| e as i32))
|
||||||
|
.map(|vox| !vox.is_empty())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
pos.0.z += 0.05;
|
||||||
|
vel.0.z = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Library
|
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
use crate::ray::{Ray, RayUntil};
|
||||||
|
|
||||||
/// A voxel
|
/// A voxel
|
||||||
pub trait Vox {
|
pub trait Vox {
|
||||||
@ -64,6 +64,12 @@ pub trait ReadVol: BaseVol {
|
|||||||
/// Get a reference to the voxel at the provided position in the volume.
|
/// Get a reference to the voxel at the provided position in the volume.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Err>;
|
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Err>;
|
||||||
|
|
||||||
|
fn ray(&self, from: Vec3<f32>, to: Vec3<f32>) -> Ray<Self, fn(&Self::Vox) -> bool>
|
||||||
|
where Self: Sized
|
||||||
|
{
|
||||||
|
Ray::new(self, from, to, |vox| !vox.is_empty())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A volume that provides the ability to sample (i.e: clone a section of) its voxel data.
|
/// A volume that provides the ability to sample (i.e: clone a section of) its voxel data.
|
||||||
|
@ -112,7 +112,7 @@ impl Server {
|
|||||||
self.state
|
self.state
|
||||||
.ecs_mut()
|
.ecs_mut()
|
||||||
.create_entity_synced()
|
.create_entity_synced()
|
||||||
.with(comp::phys::Pos(Vec3::zero()))
|
.with(comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0)))
|
||||||
.with(comp::phys::Vel(Vec3::zero()))
|
.with(comp::phys::Vel(Vec3::zero()))
|
||||||
.with(comp::phys::Dir(Vec3::unit_y()))
|
.with(comp::phys::Dir(Vec3::unit_y()))
|
||||||
.with(character)
|
.with(character)
|
||||||
@ -125,7 +125,7 @@ impl Server {
|
|||||||
character: comp::Character,
|
character: comp::Character,
|
||||||
) {
|
) {
|
||||||
state.write_component(entity, character);
|
state.write_component(entity, character);
|
||||||
state.write_component(entity, comp::phys::Pos(Vec3::zero()));
|
state.write_component(entity, comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0)));
|
||||||
state.write_component(entity, comp::phys::Vel(Vec3::zero()));
|
state.write_component(entity, comp::phys::Vel(Vec3::zero()));
|
||||||
state.write_component(entity, comp::phys::Dir(Vec3::unit_y()));
|
state.write_component(entity, comp::phys::Dir(Vec3::unit_y()));
|
||||||
// Make sure everything is accepted
|
// Make sure everything is accepted
|
||||||
@ -182,7 +182,6 @@ impl Server {
|
|||||||
// Fetch any generated `TerrainChunk`s and insert them into the terrain
|
// Fetch any generated `TerrainChunk`s and insert them into the terrain
|
||||||
// Also, send the chunk data to anybody that is close by
|
// Also, send the chunk data to anybody that is close by
|
||||||
for (key, chunk) in self.chunk_rx.try_iter() {
|
for (key, chunk) in self.chunk_rx.try_iter() {
|
||||||
println!("Generation finished {:?}", key);
|
|
||||||
// Send the chunk to all nearby players
|
// Send the chunk to all nearby players
|
||||||
for (entity, player, pos) in (
|
for (entity, player, pos) in (
|
||||||
&self.state.ecs().entities(),
|
&self.state.ecs().entities(),
|
||||||
@ -194,7 +193,6 @@ impl Server {
|
|||||||
// TODO: Distance check
|
// TODO: Distance check
|
||||||
// if self.state.terrain().key_pos(key)
|
// if self.state.terrain().key_pos(key)
|
||||||
|
|
||||||
println!("Send to player {:?}", key);
|
|
||||||
self.clients.notify(entity, ServerMsg::TerrainChunkUpdate {
|
self.clients.notify(entity, ServerMsg::TerrainChunkUpdate {
|
||||||
key,
|
key,
|
||||||
chunk: Box::new(chunk.clone()),
|
chunk: Box::new(chunk.clone()),
|
||||||
|
@ -67,7 +67,7 @@ impl<M> Meshable for Dyna<Block, M> {
|
|||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
{
|
{
|
||||||
mesh.push_quad(create_quad(
|
mesh.push_quad(create_quad(
|
||||||
Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_y(),
|
-Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_y(),
|
||||||
-Vec3::unit_y(),
|
-Vec3::unit_y(),
|
||||||
Vec3::unit_z(),
|
Vec3::unit_z(),
|
||||||
-Vec3::unit_x(),
|
-Vec3::unit_x(),
|
||||||
@ -80,7 +80,7 @@ impl<M> Meshable for Dyna<Block, M> {
|
|||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
{
|
{
|
||||||
mesh.push_quad(create_quad(
|
mesh.push_quad(create_quad(
|
||||||
Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_x(),
|
-Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_x(),
|
||||||
Vec3::unit_y(),
|
Vec3::unit_y(),
|
||||||
Vec3::unit_z(),
|
Vec3::unit_z(),
|
||||||
Vec3::unit_x(),
|
Vec3::unit_x(),
|
||||||
@ -93,7 +93,7 @@ impl<M> Meshable for Dyna<Block, M> {
|
|||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
{
|
{
|
||||||
mesh.push_quad(create_quad(
|
mesh.push_quad(create_quad(
|
||||||
Vec3::one() + pos.map(|e| e as f32),
|
-Vec3::one() + pos.map(|e| e as f32),
|
||||||
Vec3::unit_x(),
|
Vec3::unit_x(),
|
||||||
Vec3::unit_z(),
|
Vec3::unit_z(),
|
||||||
-Vec3::unit_y(),
|
-Vec3::unit_y(),
|
||||||
@ -106,7 +106,7 @@ impl<M> Meshable for Dyna<Block, M> {
|
|||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
{
|
{
|
||||||
mesh.push_quad(create_quad(
|
mesh.push_quad(create_quad(
|
||||||
Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_y(),
|
-Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_y(),
|
||||||
Vec3::unit_z(),
|
Vec3::unit_z(),
|
||||||
Vec3::unit_x(),
|
Vec3::unit_x(),
|
||||||
Vec3::unit_y(),
|
Vec3::unit_y(),
|
||||||
@ -119,7 +119,7 @@ impl<M> Meshable for Dyna<Block, M> {
|
|||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
{
|
{
|
||||||
mesh.push_quad(create_quad(
|
mesh.push_quad(create_quad(
|
||||||
Vec3::one() + pos.map(|e| e as f32),
|
-Vec3::one() + pos.map(|e| e as f32),
|
||||||
Vec3::unit_y(),
|
Vec3::unit_y(),
|
||||||
Vec3::unit_x(),
|
Vec3::unit_x(),
|
||||||
-Vec3::unit_z(),
|
-Vec3::unit_z(),
|
||||||
@ -132,7 +132,7 @@ impl<M> Meshable for Dyna<Block, M> {
|
|||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
{
|
{
|
||||||
mesh.push_quad(create_quad(
|
mesh.push_quad(create_quad(
|
||||||
Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_z(),
|
-Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_z(),
|
||||||
Vec3::unit_x(),
|
Vec3::unit_x(),
|
||||||
Vec3::unit_y(),
|
Vec3::unit_y(),
|
||||||
Vec3::unit_z(),
|
Vec3::unit_z(),
|
||||||
|
@ -106,9 +106,9 @@ impl Terrain {
|
|||||||
|
|
||||||
if client.state().terrain().get_key(pos).is_some() {
|
if client.state().terrain().get_key(pos).is_some() {
|
||||||
match self.mesh_todo.iter_mut().find(|todo| todo.pos == pos) {
|
match self.mesh_todo.iter_mut().find(|todo| todo.pos == pos) {
|
||||||
Some(todo) => todo.started_tick = current_tick,
|
//Some(todo) => todo.started_tick = current_tick,
|
||||||
// The chunk it's queued yet, add it to the queue
|
// The chunk it's queued yet, add it to the queue
|
||||||
None => self.mesh_todo.push_back(ChunkMeshState {
|
_ /* None */ => self.mesh_todo.push_back(ChunkMeshState {
|
||||||
pos,
|
pos,
|
||||||
started_tick: current_tick,
|
started_tick: current_tick,
|
||||||
active_worker: false,
|
active_worker: false,
|
||||||
|
@ -40,8 +40,8 @@ impl World {
|
|||||||
let wpos = lpos + chunk_pos * chunk.get_size().map(|e| e as i32);
|
let wpos = lpos + chunk_pos * chunk.get_size().map(|e| e as i32);
|
||||||
let wposf = wpos.map(|e| e as f64);
|
let wposf = wpos.map(|e| e as f64);
|
||||||
|
|
||||||
let freq = 1.0 / 32.0;
|
let freq = 1.0 / 64.0;
|
||||||
let ampl = 16.0;
|
let ampl = 12.0;
|
||||||
let offs = 16.0;
|
let offs = 16.0;
|
||||||
let height = perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl + offs;
|
let height = perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl + offs;
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ impl World {
|
|||||||
if wposf.z < height - 1.0 {
|
if wposf.z < height - 1.0 {
|
||||||
stone
|
stone
|
||||||
} else {
|
} else {
|
||||||
sand
|
grass
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
air
|
air
|
||||||
|
Loading…
Reference in New Issue
Block a user