Skip to content

Commit

Permalink
Added dynamic terrain, added client payloads
Browse files Browse the repository at this point in the history
  • Loading branch information
zesterer committed Jul 2, 2018
1 parent 8b1abf8 commit 70408ca
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 88 deletions.
68 changes: 57 additions & 11 deletions client/src/lib.rs
@@ -1,4 +1,4 @@
#![feature(nll)]
#![feature(nll, euclidean_division)]

// Crates
#[macro_use]
Expand Down Expand Up @@ -28,7 +28,7 @@ use std::net::{ToSocketAddrs};
use coord::prelude::*;

// Project
use region::Entity;
use region::{Entity, Chunk, VolMgr, VolGen, FnPayloadFunc};
use common::{get_version, Uid};
use common::net;
use common::net::{Connection, ServerMessage, ClientMessage, Callback, UdpMgr};
Expand Down Expand Up @@ -57,26 +57,36 @@ pub enum ClientStatus {
Disconnected,
}

pub struct Client {
pub trait Payloads: 'static {
type Chunk: Send + Sync + 'static;
}

pub struct Client<P: Payloads> {
status: RwLock<ClientStatus>,
conn: Arc<Connection<ServerMessage>>,

player: RwLock<Player>,
entities: RwLock<HashMap<Uid, Entity>>,

chunk_mgr: VolMgr<Chunk, <P as Payloads>::Chunk>,

callbacks: RwLock<Callbacks>,

finished: Barrier, // We use this to synchronize client shutdown
}

impl Callback<ServerMessage> for Client {
impl<P: Payloads> Callback<ServerMessage> for Client<P> {
fn recv(&self, msg: Result<ServerMessage, common::net::Error>) {
self.handle_packet(msg.unwrap());
}
}

impl Client {
pub fn new<U: ToSocketAddrs>(mode: ClientMode, alias: String, remote_addr: U) -> Result<Arc<Client>, Error> {
fn gen_chunk(pos: Vec2<i64>) -> Chunk {
Chunk::test(vec3!(pos.x * 16, pos.y * 16, 0), vec3!(16, 16, 128))
}

impl<P: Payloads> Client<P> {
pub fn new<U: ToSocketAddrs, GF: FnPayloadFunc<Chunk, P::Chunk, Output=P::Chunk>>(mode: ClientMode, alias: String, remote_addr: U, gen_payload: GF) -> Result<Arc<Client<P>>, Error> {
let mut conn = Connection::new::<U>(&remote_addr, Box::new(|m| {
//
//self.handle_packet(m);
Expand All @@ -91,6 +101,8 @@ impl Client {
player: RwLock::new(Player::new(alias)),
entities: RwLock::new(HashMap::new()),

chunk_mgr: VolMgr::new(16, VolGen::new(gen_chunk, gen_payload)),

callbacks: RwLock::new(Callbacks::new()),

finished: Barrier::new(2),
Expand All @@ -109,15 +121,47 @@ impl Client {

fn tick(&self, dt: f32) {
if let Some(uid) = self.player().entity_uid {
if let Some(player_entry) = self.entities_mut().get_mut(&uid) {
if let Some(player_entity) = self.entities_mut().get_mut(&uid) {
self.conn.send(ClientMessage::PlayerEntityUpdate {
pos: player_entry.pos(),
move_dir: player_entry.move_dir(),
look_dir: player_entry.look_dir(),
pos: player_entity.pos(),
move_dir: player_entity.move_dir(),
look_dir: player_entity.look_dir(),
});
}
}

// Generate terrain around the player
if let Some(uid) = self.player().entity_uid {
if let Some(player_entity) = self.entities_mut().get_mut(&uid) {
let (x, y) = (
(player_entity.pos().x as i64).div_euc(16),
(player_entity.pos().y as i64).div_euc(16)
);

// TODO: define a view distance?!
for i in x - 3 .. x + 4 {
for j in y - 3 .. y + 4 {
if !self.chunk_mgr().contains(vec2!(i, j)) {
self.chunk_mgr().gen(vec2!(i, j));
}
}
}

// This should also be tied to view distance, and could be more efficient
// (maybe? careful: deadlocks)
let chunk_pos = self.chunk_mgr()
.volumes()
.keys()
.map(|p| *p)
.collect::<Vec<_>>();
for pos in chunk_pos {
if (pos - vec2!(x, y)).snake_length() > 10 {
self.chunk_mgr().remove(pos);
}
}
}
}

for (uid, entity) in self.entities_mut().iter_mut() {
let move_dir = entity.move_dir();
*entity.pos_mut() += move_dir * dt;
Expand Down Expand Up @@ -165,7 +209,7 @@ impl Client {
}
}

fn start(client: Arc<Client>) {
fn start(client: Arc<Client<P>>) {

let client_ref = client.clone();
thread::spawn(move || {
Expand Down Expand Up @@ -195,6 +239,8 @@ impl Client {
Ok(self.conn.send(ClientMessage::SendCmd { cmd }))
}

pub fn chunk_mgr<'a>(&'a self) -> &'a VolMgr<Chunk, P::Chunk> { &self.chunk_mgr }

pub fn status<'a>(&'a self) -> RwLockReadGuard<'a, ClientStatus> { self.status.read().unwrap() }

pub fn callbacks<'a>(&'a self) -> RwLockReadGuard<'a, Callbacks> { self.callbacks.read().unwrap() }
Expand Down
1 change: 1 addition & 0 deletions region/src/lib.rs
Expand Up @@ -19,6 +19,7 @@ pub use chunk::Chunk;
pub use cell::{Cell};
pub use model::Model;
pub use entity::Entity;
pub use vol_mgr::{VolMgr, VolGen, VolState, FnGenFunc, FnPayloadFunc};

use coord::vec3::Vec3;

Expand Down
43 changes: 26 additions & 17 deletions region/src/vol_mgr.rs
@@ -1,55 +1,64 @@
// Standard
use std::thread;
use std::sync::{Arc, RwLock};
use std::sync::{Arc, RwLock, RwLockReadGuard};
use std::collections::HashMap;
use std::marker::PhantomData;
use std::any::Any;

// Library
use coord::prelude::*;

// Local
use {Volume, Voxel};

pub trait VolPayload: Send + Sync {}

pub enum VolState<V: Volume> {
pub enum VolState<V: Volume, P> {
Loading,
Exists(V, Box<VolPayload>),
Exists(V, P),
}

pub struct VolGen<V: Volume> {
gen_func: Arc<fn(Vec2<i64>) -> V>,
payload_func: Arc<fn(&V) -> Box<VolPayload>>,
pub trait FnGenFunc<V>: Fn(Vec2<i64>) -> V + Send + Sync + 'static {}
impl<V, T: Fn(Vec2<i64>) -> V + Send + Sync + 'static> FnGenFunc<V> for T {}

pub trait FnPayloadFunc<V, P: Send + Sync + 'static>: Fn(&V) -> P + Send + Sync + 'static {}
impl<V, P: Send + Sync + 'static, T: Fn(&V) -> P + Send + Sync + 'static> FnPayloadFunc<V, P> for T {}

pub struct VolGen<V: Volume, P: Send + Sync + 'static> {
gen_func: Arc<FnGenFunc<V, Output=V>>,
payload_func: Arc<FnPayloadFunc<V, P, Output=P>>,
}

impl <V: Volume> VolGen<V> {
pub fn new(gen_func: fn(Vec2<i64>) -> V, payload_func: fn(&V) -> Box<VolPayload>) -> VolGen<V> {
impl<V: Volume, P: Send + Sync + 'static> VolGen<V, P> {
pub fn new<GF: FnGenFunc<V>, PF: FnPayloadFunc<V, P>>(gen_func: GF, payload_func: PF) -> VolGen<V, P> {
VolGen {
gen_func: Arc::new(gen_func),
payload_func: Arc::new(payload_func),
}
}
}

pub struct VolMgr<V: 'static + Volume> {
pub struct VolMgr<V: 'static + Volume, P: Send + Sync + 'static> {
vol_size: i64,
vols: RwLock<HashMap<Vec2<i64>, Arc<RwLock<VolState<V>>>>>,
gen: VolGen<V>,
vols: RwLock<HashMap<Vec2<i64>, Arc<RwLock<VolState<V, P>>>>>,
gen: VolGen<V, P>,
}

impl<V: 'static + Volume> VolMgr<V> {
pub fn new(vol_size: i64, gen: VolGen<V>) -> VolMgr<V> {
impl<V: 'static + Volume, P: Send + Sync + 'static> VolMgr<V, P> {
pub fn new(vol_size: i64, gen: VolGen<V, P>) -> VolMgr<V, P> {
VolMgr {
vol_size,
vols: RwLock::new(HashMap::new()),
gen,
}
}

pub fn at(&self, pos: Vec2<i64>) -> Option<Arc<RwLock<VolState<V>>>> {
pub fn at(&self, pos: Vec2<i64>) -> Option<Arc<RwLock<VolState<V, P>>>> {
self.vols.read().unwrap().get(&pos).map(|v| v.clone())
}

pub fn volumes<'a>(&'a self) -> RwLockReadGuard<'a, HashMap<Vec2<i64>, Arc<RwLock<VolState<V, P>>>>> {
self.vols.read().unwrap()
}

pub fn contains(&self, pos: Vec2<i64>) -> bool {
self.vols.read().unwrap().contains_key(&pos)
}
Expand All @@ -74,7 +83,7 @@ impl<V: 'static + Volume> VolMgr<V> {
});
}

pub fn set(&self, pos: Vec2<i64>, vol: V, payload: Box<VolPayload>) {
pub fn set(&self, pos: Vec2<i64>, vol: V, payload: P) {
self.vols.write().unwrap().insert(pos, Arc::new(RwLock::new(VolState::Exists(vol, payload))));
}

Expand Down
86 changes: 48 additions & 38 deletions voxygen/src/game.rs
Expand Up @@ -3,6 +3,7 @@ use std::net::ToSocketAddrs;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::f32::consts::PI;
use std::collections::HashMap;
//use std::f32::{sin, cos};

// Library
Expand All @@ -12,21 +13,26 @@ use glutin::{ElementState, VirtualKeyCode};
use dot_vox;

// Project
use client;
use client::{Client, ClientMode};

// Local
use map::Map;
use camera::Camera;
use window::{RenderWindow, Event};
use model_object::{ModelObject, Constants};
use mesh::{Mesh};
use region::Chunk;
use region::{Chunk, VolState};
use key_state::KeyState;
use vox::vox_to_model;

struct Payloads {}
impl client::Payloads for Payloads {
type Chunk = (Mesh, Option<ModelObject>);
}

pub struct Game {
running: AtomicBool,
client: Arc<Client>,
client: Arc<Client<Payloads>>,
window: RenderWindow,
data: Mutex<Data>,
camera: Mutex<Camera>,
Expand All @@ -37,7 +43,10 @@ pub struct Game {
struct Data {
player_model: ModelObject,
other_player_model: ModelObject,
map: Map,
}

fn gen_payload(chunk: &Chunk) -> <Payloads as client::Payloads>::Chunk {
(Mesh::from(chunk), None)
}

impl Game {
Expand All @@ -64,35 +73,13 @@ impl Game {
&other_player_mesh,
);

let chunk = Chunk::test(vec3!(0, 0, 0), vec3!(100,100,100));
let test_mesh = Mesh::from(&chunk);

let test_model = ModelObject::new(
&mut window.renderer_mut(),
&test_mesh,
);

let mut map = Map::new();
map.chunks().insert(Vector3::new(0,0,0), test_model);

let chunk = Chunk::test(Vec3::from((100,0,0)),Vec3::from((100,100,100)));
let test_mesh = Mesh::from(&chunk);

let test_model = ModelObject::new(
&mut window.renderer_mut(),
&test_mesh,
);

map.chunks().insert(Vector3::new(100,0,0), test_model);

Game {
data: Mutex::new(Data {
player_model,
other_player_model,
map,
}),
running: AtomicBool::new(true),
client: Client::new(mode, alias.to_string(), remote_addr)
client: Client::new(mode, alias.to_string(), remote_addr, gen_payload)
.expect("Could not create new client"),
window,
camera: Mutex::new(Camera::new()),
Expand Down Expand Up @@ -176,6 +163,19 @@ impl Game {
self.running.load(Ordering::Relaxed)
}

pub fn mesh_chunks(&self) {
for (pos, vol) in self.client.chunk_mgr().volumes().iter() {
if let VolState::Exists(ref chunk, ref mut payload) = *vol.write().unwrap() {
if let None = payload.1 {
payload.1 = Some(ModelObject::new(
&mut self.window.renderer_mut(),
&payload.0,
));
}
}
}
}

pub fn render_frame(&self) {
let mut renderer = self.window.renderer_mut();
renderer.begin_frame();
Expand All @@ -189,17 +189,26 @@ impl Game {
let camera_mats = self.camera.lock().unwrap().get_mats();
let camera_ori = self.camera.lock().unwrap().ori();

// Render the test model

for (pos, model) in self.data.lock().unwrap().map.chunks() {
renderer.update_model_object(
&model,
Constants::new(//&Matrix4::<f32>::identity(),
&Translation3::<f32>::from_vector(convert(*pos)).to_homogeneous(),
&camera_mats.0,
&camera_mats.1)
);
renderer.render_model_object(&model);
for (pos, vol) in self.client.chunk_mgr().volumes().iter() {
if let VolState::Exists(ref chunk, ref payload) = *vol.read().unwrap() {
if let Some(ref model) = payload.1 {
let model_mat = &Translation3::<f32>::from_vector(Vector3::<f32>::new(
pos.x as f32 * 16.0,
pos.y as f32 * 16.0,
0.0
)).to_homogeneous();

renderer.update_model_object(
&model,
Constants::new(
&model_mat, // TODO: Improve this
&camera_mats.0,
&camera_mats.1,
)
);
renderer.render_model_object(&model);
}
}
}

for (eid, entity) in self.client.entities().iter() {
Expand Down Expand Up @@ -229,6 +238,7 @@ impl Game {

pub fn run(&self) {
while self.handle_window_events() {
self.mesh_chunks();
self.render_frame();
}

Expand Down
1 change: 0 additions & 1 deletion voxygen/src/main.rs
Expand Up @@ -28,7 +28,6 @@ mod pipeline;
mod camera;
mod render_volume;
mod key_state;
mod map;
mod vox;

use std::io;
Expand Down

0 comments on commit 70408ca

Please sign in to comment.