mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Ran fmt on codebase
Former-commit-id: 7fecffa1dc66fffba4f07d45fb80960dc5178f4f
This commit is contained in:
parent
2bcd6b6295
commit
993388e56a
@ -1,10 +1,7 @@
|
|||||||
use std::time::Duration;
|
use client::{Client, Event, Input};
|
||||||
|
use common::{clock::Clock, comp};
|
||||||
use log::info;
|
use log::info;
|
||||||
use client::{Input, Client, Event};
|
use std::time::Duration;
|
||||||
use common::{
|
|
||||||
comp,
|
|
||||||
clock::Clock,
|
|
||||||
};
|
|
||||||
|
|
||||||
const FPS: u64 = 60;
|
const FPS: u64 = 60;
|
||||||
|
|
||||||
@ -18,8 +15,8 @@ fn main() {
|
|||||||
let mut clock = Clock::new();
|
let mut clock = Clock::new();
|
||||||
|
|
||||||
// Create client
|
// Create client
|
||||||
let mut client = Client::new(([127, 0, 0, 1], 59003), 300)
|
let mut client =
|
||||||
.expect("Failed to create client instance");
|
Client::new(([127, 0, 0, 1], 59003), 300).expect("Failed to create client instance");
|
||||||
|
|
||||||
client.register(comp::Player::new("test".to_string()));
|
client.register(comp::Player::new("test".to_string()));
|
||||||
|
|
||||||
@ -31,7 +28,7 @@ fn main() {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("Error: {:?}", err);
|
println!("Error: {:?}", err);
|
||||||
break;
|
break;
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for event in events {
|
for event in events {
|
||||||
|
@ -249,9 +249,18 @@ impl Client {
|
|||||||
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
|
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
|
||||||
ServerMsg::Pong => {}
|
ServerMsg::Pong => {}
|
||||||
ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
|
ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
|
||||||
ServerMsg::SetPlayerEntity(uid) => self.entity = self.state.ecs().entity_from_uid(uid).unwrap(), // TODO: Don't unwrap here!
|
ServerMsg::SetPlayerEntity(uid) => {
|
||||||
ServerMsg::EcsSync(sync_package) => self.state.ecs_mut().sync_with_package(sync_package),
|
self.entity = self.state.ecs().entity_from_uid(uid).unwrap()
|
||||||
ServerMsg::EntityPhysics { entity, pos, vel, dir } => match self.state.ecs().entity_from_uid(entity) {
|
} // TODO: Don't unwrap here!
|
||||||
|
ServerMsg::EcsSync(sync_package) => {
|
||||||
|
self.state.ecs_mut().sync_with_package(sync_package)
|
||||||
|
}
|
||||||
|
ServerMsg::EntityPhysics {
|
||||||
|
entity,
|
||||||
|
pos,
|
||||||
|
vel,
|
||||||
|
dir,
|
||||||
|
} => match self.state.ecs().entity_from_uid(entity) {
|
||||||
Some(entity) => {
|
Some(entity) => {
|
||||||
self.state.write_component(entity, pos);
|
self.state.write_component(entity, pos);
|
||||||
self.state.write_component(entity, vel);
|
self.state.write_component(entity, vel);
|
||||||
@ -259,7 +268,10 @@ impl Client {
|
|||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
},
|
},
|
||||||
ServerMsg::EntityAnimation { entity, animation_history } => match self.state.ecs().entity_from_uid(entity) {
|
ServerMsg::EntityAnimation {
|
||||||
|
entity,
|
||||||
|
animation_history,
|
||||||
|
} => match self.state.ecs().entity_from_uid(entity) {
|
||||||
Some(entity) => {
|
Some(entity) => {
|
||||||
self.state.write_component(entity, animation_history);
|
self.state.write_component(entity, animation_history);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::fs::File;
|
|
||||||
|
|
||||||
fn try_load(name: &str) -> Option<File> {
|
fn try_load(name: &str) -> Option<File> {
|
||||||
let basepaths = [
|
let basepaths = [
|
||||||
@ -22,25 +22,28 @@ fn try_load(name: &str) -> Option<File> {
|
|||||||
Ok(f) => {
|
Ok(f) => {
|
||||||
debug!("loading {} succedeed", filename);
|
debug!("loading {} succedeed", filename);
|
||||||
return Some(f);
|
return Some(f);
|
||||||
},
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!("loading {} did not work with error: {}", filename, e);
|
debug!("loading {} did not work with error: {}", filename, e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(name: &str) -> Result<Vec<u8>, ()> {
|
pub fn load(name: &str) -> Result<Vec<u8>, ()> {
|
||||||
return match try_load(name) {
|
return match try_load(name) {
|
||||||
Some(mut f) => {
|
Some(mut f) => {
|
||||||
let mut content: Vec<u8> = vec!();
|
let mut content: Vec<u8> = vec![];
|
||||||
f.read_to_end(&mut content);
|
f.read_to_end(&mut content);
|
||||||
info!("loaded asset successful: {}", name);
|
info!("loaded asset successful: {}", name);
|
||||||
Ok(content)
|
Ok(content)
|
||||||
},
|
}
|
||||||
None => {
|
None => {
|
||||||
warn!("Loading asset failed, wanted to load {} but could not load it, check debug log!", name);
|
warn!(
|
||||||
|
"Loading asset failed, wanted to load {} but could not load it, check debug log!",
|
||||||
|
name
|
||||||
|
);
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -23,13 +23,19 @@ impl Clock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn get_tps(&self) -> f64 { 1.0 / self.running_tps_average }
|
pub fn get_tps(&self) -> f64 {
|
||||||
|
1.0 / self.running_tps_average
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn get_last_delta(&self) -> Duration { self.last_delta.unwrap_or(Duration::new(0, 0)) }
|
pub fn get_last_delta(&self) -> Duration {
|
||||||
|
self.last_delta.unwrap_or(Duration::new(0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn get_avg_delta(&self) -> Duration { Duration::from_secs_f64(self.running_tps_average) }
|
pub fn get_avg_delta(&self) -> Duration {
|
||||||
|
Duration::from_secs_f64(self.running_tps_average)
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn tick(&mut self, tgt: Duration) {
|
pub fn tick(&mut self, tgt: Duration) {
|
||||||
@ -44,7 +50,9 @@ impl Clock {
|
|||||||
} else {
|
} else {
|
||||||
tgt.as_secs_f64() / self.running_tps_average
|
tgt.as_secs_f64() / self.running_tps_average
|
||||||
};
|
};
|
||||||
thread::sleep(Duration::from_secs_f64(sleep_dur.as_secs_f64() * adjustment));
|
thread::sleep(Duration::from_secs_f64(
|
||||||
|
sleep_dur.as_secs_f64() * adjustment,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let delta = SystemTime::now()
|
let delta = SystemTime::now()
|
||||||
@ -56,8 +64,8 @@ impl Clock {
|
|||||||
self.running_tps_average = if self.running_tps_average == 0.0 {
|
self.running_tps_average = if self.running_tps_average == 0.0 {
|
||||||
delta.as_secs_f64()
|
delta.as_secs_f64()
|
||||||
} else {
|
} else {
|
||||||
CLOCK_SMOOTHING * self.running_tps_average +
|
CLOCK_SMOOTHING * self.running_tps_average
|
||||||
(1.0 - CLOCK_SMOOTHING) * delta.as_secs_f64()
|
+ (1.0 - CLOCK_SMOOTHING) * delta.as_secs_f64()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use specs::{Component, VecStorage, FlaggedStorage};
|
|
||||||
use vek::*;
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
use specs::{Component, FlaggedStorage, VecStorage};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub enum Race {
|
pub enum Race {
|
||||||
@ -60,14 +60,14 @@ pub enum Weapon {
|
|||||||
Staff,
|
Staff,
|
||||||
}
|
}
|
||||||
|
|
||||||
use Race::*;
|
|
||||||
use Gender::*;
|
|
||||||
use Head::*;
|
|
||||||
use Chest::*;
|
|
||||||
use Belt::*;
|
use Belt::*;
|
||||||
use Pants::*;
|
use Chest::*;
|
||||||
use Hand::*;
|
|
||||||
use Foot::*;
|
use Foot::*;
|
||||||
|
use Gender::*;
|
||||||
|
use Hand::*;
|
||||||
|
use Head::*;
|
||||||
|
use Pants::*;
|
||||||
|
use Race::*;
|
||||||
use Weapon::*;
|
use Weapon::*;
|
||||||
|
|
||||||
const ALL_RACES: [Race; 6] = [Danari, Dwarf, Elf, Human, Orc, Undead];
|
const ALL_RACES: [Race; 6] = [Danari, Dwarf, Elf, Human, Orc, Undead];
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
pub mod agent;
|
pub mod agent;
|
||||||
pub mod character;
|
pub mod character;
|
||||||
pub mod player;
|
|
||||||
pub mod phys;
|
pub mod phys;
|
||||||
|
pub mod player;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
pub use agent::{Agent, Control};
|
pub use agent::{Agent, Control};
|
||||||
|
pub use character::Animation;
|
||||||
|
pub use character::AnimationHistory;
|
||||||
pub use character::Character;
|
pub use character::Character;
|
||||||
pub use player::Player;
|
pub use player::Player;
|
||||||
pub use character::AnimationHistory;
|
|
||||||
pub use character::Animation;
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use specs::{Component, VecStorage, FlaggedStorage, NullStorage};
|
use specs::{Component, FlaggedStorage, NullStorage, VecStorage};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
// Pos
|
// Pos
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use specs::{Component, VecStorage, FlaggedStorage};
|
use specs::{Component, FlaggedStorage, VecStorage};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
@ -7,9 +7,7 @@ pub struct Player {
|
|||||||
|
|
||||||
impl Player {
|
impl Player {
|
||||||
pub fn new(alias: String) -> Self {
|
pub fn new(alias: String) -> Self {
|
||||||
Self {
|
Self { alias }
|
||||||
alias,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
pub mod cell;
|
pub mod cell;
|
||||||
|
|
||||||
// Library
|
// Library
|
||||||
use vek::*;
|
|
||||||
use dot_vox::DotVoxData;
|
use dot_vox::DotVoxData;
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -28,11 +28,7 @@ impl From<DotVoxData> for Segment {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let mut segment = Segment::filled(
|
let mut segment = Segment::filled(
|
||||||
Vec3::new(
|
Vec3::new(model.size.x, model.size.y, model.size.z),
|
||||||
model.size.x,
|
|
||||||
model.size.y,
|
|
||||||
model.size.z,
|
|
||||||
),
|
|
||||||
Cell::empty(),
|
Cell::empty(),
|
||||||
(),
|
(),
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
#![feature(euclidean_division, duration_float, trait_alias, bind_by_move_pattern_guards)]
|
#![feature(
|
||||||
|
euclidean_division,
|
||||||
|
duration_float,
|
||||||
|
trait_alias,
|
||||||
|
bind_by_move_pattern_guards
|
||||||
|
)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
@ -10,13 +15,13 @@ pub mod clock;
|
|||||||
pub mod comp;
|
pub mod comp;
|
||||||
pub mod figure;
|
pub mod figure;
|
||||||
pub mod msg;
|
pub mod msg;
|
||||||
|
pub mod ray;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
pub mod sys;
|
pub mod sys;
|
||||||
pub mod terrain;
|
pub mod terrain;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
pub mod volumes;
|
|
||||||
pub mod vol;
|
pub mod vol;
|
||||||
pub mod ray;
|
pub mod volumes;
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use vek::*;
|
|
||||||
use super::ClientState;
|
use super::ClientState;
|
||||||
use crate::comp;
|
use crate::comp;
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum ClientMsg {
|
pub enum ClientMsg {
|
||||||
Register { player: comp::Player },
|
Register {
|
||||||
|
player: comp::Player,
|
||||||
|
},
|
||||||
Character(comp::Character),
|
Character(comp::Character),
|
||||||
RequestState(ClientState),
|
RequestState(ClientState),
|
||||||
Ping,
|
Ping,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::marker::PhantomData;
|
|
||||||
use serde_derive::{Serialize, Deserialize};
|
|
||||||
use crate::comp;
|
use crate::comp;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
// Automatically derive From<T> for Packet for each variant Packet::T(T)
|
// Automatically derive From<T> for Packet for each variant Packet::T(T)
|
||||||
sphynx::sum_type! {
|
sphynx::sum_type! {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
|
pub mod client;
|
||||||
pub mod ecs_packet;
|
pub mod ecs_packet;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod client;
|
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
pub use self::server::{ServerMsg, RequestStateError};
|
|
||||||
pub use self::client::ClientMsg;
|
pub use self::client::ClientMsg;
|
||||||
pub use self::ecs_packet::EcsPacket;
|
pub use self::ecs_packet::EcsPacket;
|
||||||
|
pub use self::server::{RequestStateError, ServerMsg};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum ClientState {
|
pub enum ClientState {
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
|
use super::{ClientState, EcsPacket};
|
||||||
|
use crate::{comp, terrain::TerrainChunk};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
use crate::{
|
|
||||||
comp,
|
|
||||||
terrain::TerrainChunk,
|
|
||||||
};
|
|
||||||
use super::{EcsPacket, ClientState};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum RequestStateError {
|
pub enum RequestStateError {
|
||||||
|
@ -7,11 +7,7 @@ pub use post2 as post;
|
|||||||
// Reexports
|
// Reexports
|
||||||
pub use self::{
|
pub use self::{
|
||||||
data::{ClientMsg, ServerMsg},
|
data::{ClientMsg, ServerMsg},
|
||||||
post::{
|
post::{Error as PostError, PostBox, PostOffice},
|
||||||
Error as PostError,
|
|
||||||
PostBox,
|
|
||||||
PostOffice,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait PostSend = 'static + serde::Serialize + std::marker::Send + std::fmt::Debug;
|
pub trait PostSend = 'static + serde::Serialize + std::marker::Send + std::fmt::Debug;
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
io::{self, Read, Write},
|
|
||||||
net::{TcpListener, TcpStream, SocketAddr, Shutdown},
|
|
||||||
time::{Instant, Duration},
|
|
||||||
marker::PhantomData,
|
|
||||||
sync::{mpsc, Arc, atomic::{AtomicBool, Ordering}},
|
|
||||||
thread,
|
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
|
io::{self, Read, Write},
|
||||||
|
marker::PhantomData,
|
||||||
|
net::{Shutdown, SocketAddr, TcpListener, TcpStream},
|
||||||
|
sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
mpsc, Arc,
|
||||||
|
},
|
||||||
|
thread,
|
||||||
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use serde::{Serialize, de::DeserializeOwned};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@ -73,11 +76,11 @@ impl<S: PostMsg, R: PostMsg> PostOffice<S, R> {
|
|||||||
match self.listener.accept() {
|
match self.listener.accept() {
|
||||||
Ok((stream, sock)) => new.push(PostBox::from_stream(stream).unwrap()),
|
Ok((stream, sock)) => new.push(PostBox::from_stream(stream).unwrap()),
|
||||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
|
Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
|
||||||
Err(e) if e.kind() == io::ErrorKind::Interrupted => {},
|
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.error = Some(e.into());
|
self.error = Some(e.into());
|
||||||
break;
|
break;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +139,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.error = Some(e);
|
self.error = Some(e);
|
||||||
None
|
None
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,18 +157,23 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.error = Some(e.into());
|
self.error = Some(e.into());
|
||||||
break;
|
break;
|
||||||
},
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
self.error = Some(e);
|
self.error = Some(e);
|
||||||
break;
|
break;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new.into_iter()
|
new.into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn worker(mut stream: TcpStream, send_rx: mpsc::Receiver<S>, recv_tx: mpsc::Sender<Result<R, Error>>, running: Arc<AtomicBool>) {
|
fn worker(
|
||||||
|
mut stream: TcpStream,
|
||||||
|
send_rx: mpsc::Receiver<S>,
|
||||||
|
recv_tx: mpsc::Sender<Result<R, Error>>,
|
||||||
|
running: Arc<AtomicBool>,
|
||||||
|
) {
|
||||||
let mut outgoing_chunks = VecDeque::new();
|
let mut outgoing_chunks = VecDeque::new();
|
||||||
let mut incoming_buf = Vec::new();
|
let mut incoming_buf = Vec::new();
|
||||||
|
|
||||||
@ -176,8 +184,8 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
|||||||
Ok(Some(e)) | Err(e) => {
|
Ok(Some(e)) | Err(e) => {
|
||||||
recv_tx.send(Err(e.into())).unwrap();
|
recv_tx.send(Err(e.into())).unwrap();
|
||||||
break 'work;
|
break 'work;
|
||||||
},
|
}
|
||||||
Ok(None) => {},
|
Ok(None) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try getting messages from the send channel
|
// Try getting messages from the send channel
|
||||||
@ -188,11 +196,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
|||||||
let mut msg_bytes = bincode::serialize(&send_msg).unwrap();
|
let mut msg_bytes = bincode::serialize(&send_msg).unwrap();
|
||||||
|
|
||||||
// Assemble into packet
|
// Assemble into packet
|
||||||
let mut packet_bytes = msg_bytes
|
let mut packet_bytes = msg_bytes.len().to_le_bytes().as_ref().to_vec();
|
||||||
.len()
|
|
||||||
.to_le_bytes()
|
|
||||||
.as_ref()
|
|
||||||
.to_vec();
|
|
||||||
packet_bytes.append(&mut msg_bytes);
|
packet_bytes.append(&mut msg_bytes);
|
||||||
|
|
||||||
// Split packet into chunks
|
// Split packet into chunks
|
||||||
@ -200,13 +204,13 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
|||||||
.chunks(4096)
|
.chunks(4096)
|
||||||
.map(|chunk| chunk.to_vec())
|
.map(|chunk| chunk.to_vec())
|
||||||
.for_each(|chunk| outgoing_chunks.push_back(chunk))
|
.for_each(|chunk| outgoing_chunks.push_back(chunk))
|
||||||
},
|
}
|
||||||
Err(mpsc::TryRecvError::Empty) => break,
|
Err(mpsc::TryRecvError::Empty) => break,
|
||||||
// Worker error
|
// Worker error
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let _ = recv_tx.send(Err(e.into()));
|
let _ = recv_tx.send(Err(e.into()));
|
||||||
break 'work;
|
break 'work;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,17 +222,17 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
|||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
outgoing_chunks.push_front(chunk.split_off(n));
|
outgoing_chunks.push_front(chunk.split_off(n));
|
||||||
break;
|
break;
|
||||||
},
|
}
|
||||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||||
// Return chunk to the queue to try again later
|
// Return chunk to the queue to try again later
|
||||||
outgoing_chunks.push_front(chunk);
|
outgoing_chunks.push_front(chunk);
|
||||||
break;
|
break;
|
||||||
},
|
}
|
||||||
// Worker error
|
// Worker error
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
recv_tx.send(Err(e.into())).unwrap();
|
recv_tx.send(Err(e.into())).unwrap();
|
||||||
break 'work;
|
break 'work;
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
@ -241,12 +245,12 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
|||||||
match stream.read(&mut buf) {
|
match stream.read(&mut buf) {
|
||||||
Ok(n) => incoming_buf.extend_from_slice(&buf[0..n]),
|
Ok(n) => incoming_buf.extend_from_slice(&buf[0..n]),
|
||||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
|
Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
|
||||||
Err(e) if e.kind() == io::ErrorKind::Interrupted => {},
|
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||||
// Worker error
|
// Worker error
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
recv_tx.send(Err(e.into())).unwrap();
|
recv_tx.send(Err(e.into())).unwrap();
|
||||||
break 'work;
|
break 'work;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,16 +266,14 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
|||||||
} else if incoming_buf.len() >= len + 8 {
|
} else if incoming_buf.len() >= len + 8 {
|
||||||
match bincode::deserialize(&incoming_buf[8..len + 8]) {
|
match bincode::deserialize(&incoming_buf[8..len + 8]) {
|
||||||
Ok(msg) => recv_tx.send(Ok(msg)).unwrap(),
|
Ok(msg) => recv_tx.send(Ok(msg)).unwrap(),
|
||||||
Err(err) => {
|
Err(err) => recv_tx.send(Err(err.into())).unwrap(),
|
||||||
recv_tx.send(Err(err.into())).unwrap()
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
incoming_buf = incoming_buf.split_off(len + 8);
|
incoming_buf = incoming_buf.split_off(len + 8);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,7 +297,9 @@ impl<S: PostMsg, R: PostMsg> Drop for PostBox<S, R> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn create_postoffice<S: PostMsg, R: PostMsg>(id: u16) -> Result<(PostOffice<S, R>, SocketAddr), Error> {
|
fn create_postoffice<S: PostMsg, R: PostMsg>(
|
||||||
|
id: u16,
|
||||||
|
) -> Result<(PostOffice<S, R>, SocketAddr), Error> {
|
||||||
let sock = ([0; 4], 12345 + id).into();
|
let sock = ([0; 4], 12345 + id).into();
|
||||||
Ok((PostOffice::bind(sock)?, sock))
|
Ok((PostOffice::bind(sock)?, sock))
|
||||||
}
|
}
|
||||||
@ -353,9 +357,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut recv_msgs = Vec::new();
|
let mut recv_msgs = Vec::new();
|
||||||
loop_for(Duration::from_millis(250), || server
|
loop_for(Duration::from_millis(250), || {
|
||||||
.new_messages()
|
server.new_messages().for_each(|msg| recv_msgs.push(msg))
|
||||||
.for_each(|msg| recv_msgs.push(msg)));
|
});
|
||||||
|
|
||||||
assert_eq!(test_msgs, recv_msgs);
|
assert_eq!(test_msgs, recv_msgs);
|
||||||
}
|
}
|
||||||
@ -363,7 +367,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn send_recv_huge() {
|
fn send_recv_huge() {
|
||||||
let (mut postoffice, sock) = create_postoffice::<(), Vec<i32>>(3).unwrap();
|
let (mut postoffice, sock) = create_postoffice::<(), Vec<i32>>(3).unwrap();
|
||||||
let test_msgs: Vec<Vec<i32>> = (0..5).map(|i| (0..100000).map(|j| i * 2 + j).collect()).collect();
|
let test_msgs: Vec<Vec<i32>> = (0..5)
|
||||||
|
.map(|i| (0..100000).map(|j| i * 2 + j).collect())
|
||||||
|
.collect();
|
||||||
|
|
||||||
let mut client = PostBox::<Vec<i32>, ()>::to(sock).unwrap();
|
let mut client = PostBox::<Vec<i32>, ()>::to(sock).unwrap();
|
||||||
loop_for(Duration::from_millis(250), || ());
|
loop_for(Duration::from_millis(250), || ());
|
||||||
@ -374,9 +380,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut recv_msgs = Vec::new();
|
let mut recv_msgs = Vec::new();
|
||||||
loop_for(Duration::from_millis(3000), || server
|
loop_for(Duration::from_millis(3000), || {
|
||||||
.new_messages()
|
server.new_messages().for_each(|msg| recv_msgs.push(msg))
|
||||||
.for_each(|msg| recv_msgs.push(msg)));
|
});
|
||||||
|
|
||||||
assert_eq!(test_msgs.len(), recv_msgs.len());
|
assert_eq!(test_msgs.len(), recv_msgs.len());
|
||||||
assert!(test_msgs == recv_msgs);
|
assert!(test_msgs == recv_msgs);
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
|
use crate::vol::{ReadVol, Vox};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
use crate::vol::{
|
|
||||||
Vox,
|
|
||||||
ReadVol,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub trait RayUntil<V: Vox> = FnMut(&V) -> bool;
|
pub trait RayUntil<V: Vox> = FnMut(&V) -> bool;
|
||||||
|
|
||||||
@ -26,10 +23,7 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn until(self, f: F) -> Ray<'a, V, F> {
|
pub fn until(self, f: F) -> Ray<'a, V, F> {
|
||||||
Ray {
|
Ray { until: f, ..self }
|
||||||
until: f,
|
|
||||||
..self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_iter(mut self, max_iter: usize) -> Self {
|
pub fn max_iter(mut self, max_iter: usize) -> Self {
|
||||||
@ -52,19 +46,14 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
|
|||||||
pos = self.from + dir * dist;
|
pos = self.from + dir * dist;
|
||||||
ipos = pos.map(|e| e as i32);
|
ipos = pos.map(|e| e as i32);
|
||||||
|
|
||||||
match self.vol
|
match self.vol.get(ipos).map(|vox| (vox, (self.until)(vox))) {
|
||||||
.get(ipos)
|
|
||||||
.map(|vox| (vox, (self.until)(vox)))
|
|
||||||
{
|
|
||||||
Ok((vox, true)) => return (dist, Ok(Some(vox))),
|
Ok((vox, true)) => return (dist, Ok(Some(vox))),
|
||||||
Ok((_, false)) => {},
|
Ok((_, false)) => {}
|
||||||
Err(err) => return (dist, Err(err)),
|
Err(err) => return (dist, Err(err)),
|
||||||
}
|
}
|
||||||
|
|
||||||
let deltas = (
|
let deltas =
|
||||||
dir.map(|e| if e < 0.0 { 0.0 } else { 1.0 }) -
|
(dir.map(|e| if e < 0.0 { 0.0 } else { 1.0 }) - pos.map(|e| e.fract())) / dir;
|
||||||
pos.map(|e| e.fract())
|
|
||||||
) / dir;
|
|
||||||
|
|
||||||
dist += deltas.reduce(f32::min).max(PLANCK);
|
dist += deltas.reduce(f32::min).max(PLANCK);
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,21 @@
|
|||||||
// Reexports
|
// Reexports
|
||||||
pub use sphynx::Uid;
|
pub use sphynx::Uid;
|
||||||
|
|
||||||
use std::{
|
use crate::{
|
||||||
time::Duration,
|
comp,
|
||||||
collections::HashSet,
|
msg::EcsPacket,
|
||||||
|
sys,
|
||||||
|
terrain::{TerrainChunk, TerrainMap},
|
||||||
};
|
};
|
||||||
use shred::{Fetch, FetchMut};
|
use shred::{Fetch, FetchMut};
|
||||||
use specs::{
|
use specs::{
|
||||||
Builder,
|
|
||||||
Component,
|
|
||||||
DispatcherBuilder,
|
|
||||||
EntityBuilder as EcsEntityBuilder,
|
|
||||||
Entity as EcsEntity,
|
|
||||||
storage::{
|
|
||||||
Storage as EcsStorage,
|
|
||||||
MaskedStorage as EcsMaskedStorage,
|
|
||||||
},
|
|
||||||
saveload::{MarkedBuilder, MarkerAllocator},
|
saveload::{MarkedBuilder, MarkerAllocator},
|
||||||
|
storage::{MaskedStorage as EcsMaskedStorage, Storage as EcsStorage},
|
||||||
|
Builder, Component, DispatcherBuilder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder,
|
||||||
};
|
};
|
||||||
use sphynx;
|
use sphynx;
|
||||||
|
use std::{collections::HashSet, time::Duration};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
use crate::{
|
|
||||||
comp,
|
|
||||||
sys,
|
|
||||||
terrain::{
|
|
||||||
TerrainMap,
|
|
||||||
TerrainChunk,
|
|
||||||
},
|
|
||||||
msg::EcsPacket,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// How much faster should an in-game day be compared to a real day?
|
/// How much faster should an in-game day be compared to a real day?
|
||||||
// TODO: Don't hard-code this
|
// TODO: Don't hard-code this
|
||||||
@ -85,7 +72,11 @@ impl State {
|
|||||||
/// Create a new `State` from an ECS state package
|
/// Create a new `State` from an ECS state package
|
||||||
pub fn from_state_package(state_package: sphynx::StatePackage<EcsPacket>) -> Self {
|
pub fn from_state_package(state_package: sphynx::StatePackage<EcsPacket>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ecs: sphynx::World::from_state_package(specs::World::new(), Self::setup_sphynx_world, state_package),
|
ecs: sphynx::World::from_state_package(
|
||||||
|
specs::World::new(),
|
||||||
|
Self::setup_sphynx_world,
|
||||||
|
state_package,
|
||||||
|
),
|
||||||
changes: Changes::default(),
|
changes: Changes::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,7 +104,8 @@ impl State {
|
|||||||
|
|
||||||
/// Register a component with the state's ECS
|
/// Register a component with the state's ECS
|
||||||
pub fn with_component<T: Component>(mut self) -> Self
|
pub fn with_component<T: Component>(mut self) -> Self
|
||||||
where <T as Component>::Storage: Default
|
where
|
||||||
|
<T as Component>::Storage: Default,
|
||||||
{
|
{
|
||||||
self.ecs.register::<T>();
|
self.ecs.register::<T>();
|
||||||
self
|
self
|
||||||
@ -166,13 +158,13 @@ impl State {
|
|||||||
|
|
||||||
/// Get a reference to this state's terrain.
|
/// Get a reference to this state's terrain.
|
||||||
pub fn terrain(&self) -> Fetch<TerrainMap> {
|
pub fn terrain(&self) -> Fetch<TerrainMap> {
|
||||||
self.ecs
|
self.ecs.read_resource::<TerrainMap>()
|
||||||
.read_resource::<TerrainMap>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert the provided chunk into this state's terrain.
|
/// Insert the provided chunk into this state's terrain.
|
||||||
pub fn insert_chunk(&mut self, key: Vec3<i32>, chunk: TerrainChunk) {
|
pub fn insert_chunk(&mut self, key: Vec3<i32>, chunk: TerrainChunk) {
|
||||||
if self.ecs
|
if self
|
||||||
|
.ecs
|
||||||
.write_resource::<TerrainMap>()
|
.write_resource::<TerrainMap>()
|
||||||
.insert(key, chunk)
|
.insert(key, chunk)
|
||||||
.is_some()
|
.is_some()
|
||||||
@ -185,7 +177,8 @@ impl State {
|
|||||||
|
|
||||||
/// Remove the chunk with the given key from this state's terrain, if it exists
|
/// Remove the chunk with the given key from this state's terrain, if it exists
|
||||||
pub fn remove_chunk(&mut self, key: Vec3<i32>) {
|
pub fn remove_chunk(&mut self, key: Vec3<i32>) {
|
||||||
if self.ecs
|
if self
|
||||||
|
.ecs
|
||||||
.write_resource::<TerrainMap>()
|
.write_resource::<TerrainMap>()
|
||||||
.remove(key)
|
.remove(key)
|
||||||
.is_some()
|
.is_some()
|
||||||
|
@ -3,7 +3,7 @@ use specs::{Join, Read, ReadStorage, System, WriteStorage};
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::comp::{Agent, Control, phys::Pos};
|
use crate::comp::{phys::Pos, Agent, Control};
|
||||||
|
|
||||||
// Basic ECS AI agent system
|
// Basic ECS AI agent system
|
||||||
pub struct Sys;
|
pub struct Sys;
|
||||||
@ -22,12 +22,14 @@ impl<'a> System<'a> for Sys {
|
|||||||
*bearing += Vec2::new(
|
*bearing += Vec2::new(
|
||||||
rand::random::<f32>().fract() - 0.5,
|
rand::random::<f32>().fract() - 0.5,
|
||||||
rand::random::<f32>().fract() - 0.5,
|
rand::random::<f32>().fract() - 0.5,
|
||||||
) * 0.1 - *bearing * 0.01 - pos.0 * 0.0002;
|
) * 0.1
|
||||||
|
- *bearing * 0.01
|
||||||
|
- pos.0 * 0.0002;
|
||||||
|
|
||||||
if bearing.magnitude_squared() != 0.0 {
|
if bearing.magnitude_squared() != 0.0 {
|
||||||
control.move_dir = bearing.normalized();
|
control.move_dir = bearing.normalized();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
// Library
|
// Library
|
||||||
use specs::{Join, Read, ReadStorage, System, WriteStorage, Entities};
|
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::comp::{Control, Animation, AnimationHistory, phys::{Pos, Vel, Dir}};
|
use crate::comp::{
|
||||||
|
phys::{Dir, Pos, Vel},
|
||||||
|
Animation, AnimationHistory, Control,
|
||||||
|
};
|
||||||
|
|
||||||
// Basic ECS AI agent system
|
// Basic ECS AI agent system
|
||||||
pub struct Sys;
|
pub struct Sys;
|
||||||
@ -18,13 +21,14 @@ impl<'a> System<'a> for Sys {
|
|||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, (entities, mut vels, mut dirs, mut anims, controls): Self::SystemData) {
|
fn run(&mut self, (entities, mut vels, mut dirs, mut anims, controls): Self::SystemData) {
|
||||||
for (entity, mut vel, mut dir, control) in (&entities, &mut vels, &mut dirs, &controls).join() {
|
for (entity, mut vel, mut dir, control) in
|
||||||
|
(&entities, &mut vels, &mut dirs, &controls).join()
|
||||||
|
{
|
||||||
// TODO: Don't hard-code this
|
// TODO: Don't hard-code this
|
||||||
// Apply physics to the player: acceleration and non-linear decceleration
|
// Apply physics to the player: acceleration and non-linear decceleration
|
||||||
vel.0 += control.move_dir * 2.0 - vel.0.map(|e| e * e.abs() + e) * 0.03;
|
vel.0 += control.move_dir * 2.0 - vel.0.map(|e| e * e.abs() + e) * 0.03;
|
||||||
|
|
||||||
let animation =
|
let animation = if control.move_dir.magnitude() > 0.01 {
|
||||||
if control.move_dir.magnitude() > 0.01 {
|
|
||||||
dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
|
dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
|
||||||
Animation::Run
|
Animation::Run
|
||||||
} else {
|
} else {
|
||||||
@ -33,10 +37,13 @@ impl<'a> System<'a> for Sys {
|
|||||||
|
|
||||||
let last_animation = anims.get_mut(entity).map(|h| h.current);
|
let last_animation = anims.get_mut(entity).map(|h| h.current);
|
||||||
|
|
||||||
anims.insert(entity, AnimationHistory {
|
anims.insert(
|
||||||
|
entity,
|
||||||
|
AnimationHistory {
|
||||||
last: last_animation,
|
last: last_animation,
|
||||||
current: animation,
|
current: animation,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use vek::*;
|
|
||||||
use specs::{Join, Read, ReadStorage, System, WriteStorage, ReadExpect};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
comp::phys::{Pos, Vel},
|
comp::phys::{Pos, Vel},
|
||||||
state::DeltaTime,
|
state::DeltaTime,
|
||||||
terrain::TerrainMap,
|
terrain::TerrainMap,
|
||||||
vol::{Vox, ReadVol},
|
vol::{ReadVol, Vox},
|
||||||
};
|
};
|
||||||
|
use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
// Basic ECS physics system
|
// Basic ECS physics system
|
||||||
pub struct Sys;
|
pub struct Sys;
|
||||||
@ -33,8 +33,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
while terrain
|
while terrain
|
||||||
.get(pos.0.map(|e| e.floor() as i32))
|
.get(pos.0.map(|e| e.floor() as i32))
|
||||||
.map(|vox| !vox.is_empty())
|
.map(|vox| !vox.is_empty())
|
||||||
.unwrap_or(false) &&
|
.unwrap_or(false)
|
||||||
i < 80
|
&& i < 80
|
||||||
{
|
{
|
||||||
pos.0.z += 0.005;
|
pos.0.z += 0.005;
|
||||||
vel.0.z = 0.0;
|
vel.0.z = 0.0;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use serde_derive::{Serialize, Deserialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum BiomeKind {
|
pub enum BiomeKind {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
use serde_derive::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::vol::Vox;
|
use crate::vol::Vox;
|
||||||
|
@ -1,21 +1,15 @@
|
|||||||
pub mod block;
|
|
||||||
pub mod biome;
|
pub mod biome;
|
||||||
|
pub mod block;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
pub use self::{
|
pub use self::{biome::BiomeKind, block::Block};
|
||||||
block::Block,
|
|
||||||
biome::BiomeKind,
|
|
||||||
};
|
|
||||||
|
|
||||||
use vek::*;
|
|
||||||
use serde_derive::{Serialize, Deserialize};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
vol::VolSize,
|
vol::VolSize,
|
||||||
volumes::{
|
volumes::{chunk::Chunk, vol_map::VolMap},
|
||||||
vol_map::VolMap,
|
|
||||||
chunk::Chunk,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
// TerrainChunkSize
|
// TerrainChunkSize
|
||||||
|
|
||||||
@ -23,7 +17,11 @@ use crate::{
|
|||||||
pub struct TerrainChunkSize;
|
pub struct TerrainChunkSize;
|
||||||
|
|
||||||
impl VolSize for TerrainChunkSize {
|
impl VolSize for TerrainChunkSize {
|
||||||
const SIZE: Vec3<u32> = Vec3 { x: 32, y: 32, z: 32 };
|
const SIZE: Vec3<u32> = Vec3 {
|
||||||
|
x: 32,
|
||||||
|
y: 32,
|
||||||
|
z: 32,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TerrainChunkMeta
|
// TerrainChunkMeta
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use vek::*;
|
|
||||||
use crate::ray::{Ray, RayUntil};
|
use crate::ray::{Ray, RayUntil};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
/// A voxel
|
/// A voxel
|
||||||
pub trait Vox {
|
pub trait Vox {
|
||||||
@ -66,14 +66,18 @@ pub trait ReadVol: BaseVol {
|
|||||||
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>
|
fn ray(&self, from: Vec3<f32>, to: Vec3<f32>) -> Ray<Self, fn(&Self::Vox) -> bool>
|
||||||
where Self: Sized
|
where
|
||||||
|
Self: Sized,
|
||||||
{
|
{
|
||||||
Ray::new(self, from, to, |vox| !vox.is_empty())
|
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.
|
||||||
pub trait SampleVol: BaseVol where Self::Vox: Clone {
|
pub trait SampleVol: BaseVol
|
||||||
|
where
|
||||||
|
Self::Vox: Clone,
|
||||||
|
{
|
||||||
type Sample: BaseVol + ReadVol;
|
type Sample: BaseVol + ReadVol;
|
||||||
/// Take a sample of the volume by cloning voxels within the provided range.
|
/// Take a sample of the volume by cloning voxels within the provided range.
|
||||||
///
|
///
|
||||||
|
@ -2,18 +2,11 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
// Library
|
// Library
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
use serde_derive::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use crate::vol::{
|
use crate::vol::{BaseVol, ReadVol, SizedVol, VolSize, Vox, WriteVol};
|
||||||
Vox,
|
|
||||||
BaseVol,
|
|
||||||
SizedVol,
|
|
||||||
ReadVol,
|
|
||||||
WriteVol,
|
|
||||||
VolSize,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ChunkErr {
|
pub enum ChunkErr {
|
||||||
@ -36,15 +29,13 @@ impl<V: Vox, S: VolSize, M> Chunk<V, S, M> {
|
|||||||
// array.
|
// array.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn idx_for(pos: Vec3<i32>) -> Option<usize> {
|
fn idx_for(pos: Vec3<i32>) -> Option<usize> {
|
||||||
if
|
if pos.map(|e| e >= 0).reduce_and()
|
||||||
pos.map(|e| e >= 0).reduce_and() &&
|
&& pos.map2(S::SIZE, |e, lim| e < lim as i32).reduce_and()
|
||||||
pos.map2(S::SIZE, |e, lim| e < lim as i32).reduce_and()
|
|
||||||
{
|
{
|
||||||
Some((
|
Some(
|
||||||
pos.x * S::SIZE.y as i32 * S::SIZE.z as i32 +
|
(pos.x * S::SIZE.y as i32 * S::SIZE.z as i32 + pos.y * S::SIZE.z as i32 + pos.z)
|
||||||
pos.y * S::SIZE.z as i32 +
|
as usize,
|
||||||
pos.z
|
)
|
||||||
) as usize)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -58,7 +49,9 @@ impl<V: Vox, S: VolSize, M> BaseVol for Chunk<V, S, M> {
|
|||||||
|
|
||||||
impl<V: Vox, S: VolSize, M> SizedVol for Chunk<V, S, M> {
|
impl<V: Vox, S: VolSize, M> SizedVol for Chunk<V, S, M> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn get_size(&self) -> Vec3<u32> { S::SIZE }
|
fn get_size(&self) -> Vec3<u32> {
|
||||||
|
S::SIZE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: Vox, S: VolSize, M> ReadVol for Chunk<V, S, M> {
|
impl<V: Vox, S: VolSize, M> ReadVol for Chunk<V, S, M> {
|
||||||
|
@ -2,13 +2,7 @@
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use crate::vol::{
|
use crate::vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol};
|
||||||
Vox,
|
|
||||||
BaseVol,
|
|
||||||
SizedVol,
|
|
||||||
ReadVol,
|
|
||||||
WriteVol,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DynaErr {
|
pub enum DynaErr {
|
||||||
@ -30,15 +24,8 @@ impl<V: Vox, M> Dyna<V, M> {
|
|||||||
// array.
|
// array.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn idx_for(sz: Vec3<u32>, pos: Vec3<i32>) -> Option<usize> {
|
fn idx_for(sz: Vec3<u32>, pos: Vec3<i32>) -> Option<usize> {
|
||||||
if
|
if pos.map(|e| e >= 0).reduce_and() && pos.map2(sz, |e, lim| e < lim as i32).reduce_and() {
|
||||||
pos.map(|e| e >= 0).reduce_and() &&
|
Some((pos.x * sz.y as i32 * sz.z as i32 + pos.y * sz.z as i32 + pos.z) as usize)
|
||||||
pos.map2(sz, |e, lim| e < lim as i32).reduce_and()
|
|
||||||
{
|
|
||||||
Some((
|
|
||||||
pos.x * sz.y as i32 * sz.z as i32 +
|
|
||||||
pos.y * sz.z as i32 +
|
|
||||||
pos.z
|
|
||||||
) as usize)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -52,7 +39,9 @@ impl<V: Vox, M> BaseVol for Dyna<V, M> {
|
|||||||
|
|
||||||
impl<V: Vox, M> SizedVol for Dyna<V, M> {
|
impl<V: Vox, M> SizedVol for Dyna<V, M> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn get_size(&self) -> Vec3<u32> { self.sz }
|
fn get_size(&self) -> Vec3<u32> {
|
||||||
|
self.sz
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: Vox, M> ReadVol for Dyna<V, M> {
|
impl<V: Vox, M> ReadVol for Dyna<V, M> {
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
pub mod dyna;
|
|
||||||
pub mod chunk;
|
pub mod chunk;
|
||||||
|
pub mod dyna;
|
||||||
pub mod vol_map;
|
pub mod vol_map;
|
||||||
|
@ -6,15 +6,7 @@ use vek::*;
|
|||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::{
|
use crate::{
|
||||||
vol::{
|
vol::{BaseVol, ReadVol, SampleVol, SizedVol, VolSize, Vox, WriteVol},
|
||||||
Vox,
|
|
||||||
BaseVol,
|
|
||||||
SizedVol,
|
|
||||||
ReadVol,
|
|
||||||
SampleVol,
|
|
||||||
WriteVol,
|
|
||||||
VolSize,
|
|
||||||
},
|
|
||||||
volumes::{
|
volumes::{
|
||||||
chunk::{Chunk, ChunkErr},
|
chunk::{Chunk, ChunkErr},
|
||||||
dyna::{Dyna, DynaErr},
|
dyna::{Dyna, DynaErr},
|
||||||
@ -56,7 +48,8 @@ impl<V: Vox, S: VolSize, M> ReadVol for VolMap<V, S, M> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn get(&self, pos: Vec3<i32>) -> Result<&V, VolMapErr> {
|
fn get(&self, pos: Vec3<i32>) -> Result<&V, VolMapErr> {
|
||||||
let ck = Self::chunk_key(pos);
|
let ck = Self::chunk_key(pos);
|
||||||
self.chunks.get(&ck)
|
self.chunks
|
||||||
|
.get(&ck)
|
||||||
.ok_or(VolMapErr::NoSuchChunk)
|
.ok_or(VolMapErr::NoSuchChunk)
|
||||||
.and_then(|chunk| {
|
.and_then(|chunk| {
|
||||||
let co = Self::chunk_offs(pos);
|
let co = Self::chunk_offs(pos);
|
||||||
@ -87,14 +80,16 @@ impl<V: Vox + Clone, S: VolSize, M> SampleVol for VolMap<V, S, M> {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let mut sample = Dyna::filled(
|
let mut sample = Dyna::filled(range.size().map(|e| e as u32).into(), V::empty(), ());
|
||||||
range.size().map(|e| e as u32).into(),
|
|
||||||
V::empty(),
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
|
|
||||||
for pos in sample.iter_positions() {
|
for pos in sample.iter_positions() {
|
||||||
sample.set(pos, self.get(range.min + pos).map(|v| v.clone()).unwrap_or(V::empty()))
|
sample
|
||||||
|
.set(
|
||||||
|
pos,
|
||||||
|
self.get(range.min + pos)
|
||||||
|
.map(|v| v.clone())
|
||||||
|
.unwrap_or(V::empty()),
|
||||||
|
)
|
||||||
.map_err(|err| VolMapErr::DynaErr(err))?;
|
.map_err(|err| VolMapErr::DynaErr(err))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +101,8 @@ impl<V: Vox, S: VolSize, M> WriteVol for VolMap<V, S, M> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set(&mut self, pos: Vec3<i32>, vox: V) -> Result<(), VolMapErr> {
|
fn set(&mut self, pos: Vec3<i32>, vox: V) -> Result<(), VolMapErr> {
|
||||||
let ck = Self::chunk_key(pos);
|
let ck = Self::chunk_key(pos);
|
||||||
self.chunks.get_mut(&ck)
|
self.chunks
|
||||||
|
.get_mut(&ck)
|
||||||
.ok_or(VolMapErr::NoSuchChunk)
|
.ok_or(VolMapErr::NoSuchChunk)
|
||||||
.and_then(|chunk| {
|
.and_then(|chunk| {
|
||||||
let co = Self::chunk_offs(pos);
|
let co = Self::chunk_offs(pos);
|
||||||
@ -122,7 +118,9 @@ impl<V: Vox, S: VolSize, M> VolMap<V, S, M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chunk_size() -> Vec3<u32> { S::SIZE }
|
pub fn chunk_size() -> Vec3<u32> {
|
||||||
|
S::SIZE
|
||||||
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, key: Vec3<i32>, chunk: Chunk<V, S, M>) -> Option<Chunk<V, S, M>> {
|
pub fn insert(&mut self, key: Vec3<i32>, chunk: Chunk<V, S, M>) -> Option<Chunk<V, S, M>> {
|
||||||
self.chunks.insert(key, chunk)
|
self.chunks.insert(key, chunk)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::time::Duration;
|
|
||||||
use log::info;
|
|
||||||
use server::{Input, Event, Server};
|
|
||||||
use common::clock::Clock;
|
use common::clock::Clock;
|
||||||
|
use log::info;
|
||||||
|
use server::{Event, Input, Server};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
const TPS: u64 = 30;
|
const TPS: u64 = 30;
|
||||||
|
|
||||||
@ -15,11 +15,11 @@ fn main() {
|
|||||||
let mut clock = Clock::new();
|
let mut clock = Clock::new();
|
||||||
|
|
||||||
// Create server
|
// Create server
|
||||||
let mut server = Server::new()
|
let mut server = Server::new().expect("Failed to create server instance");
|
||||||
.expect("Failed to create server instance");
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let events = server.tick(Input::default(), clock.get_last_delta())
|
let events = server
|
||||||
|
.tick(Input::default(), clock.get_last_delta())
|
||||||
.expect("Failed to tick server");
|
.expect("Failed to tick server");
|
||||||
|
|
||||||
for event in events {
|
for event in events {
|
||||||
|
@ -88,9 +88,14 @@ fn handle_jump(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
|
|||||||
.read_component_cloned::<comp::phys::Pos>(entity)
|
.read_component_cloned::<comp::phys::Pos>(entity)
|
||||||
{
|
{
|
||||||
Some(current_pos) => {
|
Some(current_pos) => {
|
||||||
server.state.write_component(entity, comp::phys::Pos(current_pos.0 + Vec3::new(x, y, z)));
|
server.state.write_component(
|
||||||
server.state.write_component(entity, comp::phys::ForceUpdate);
|
entity,
|
||||||
},
|
comp::phys::Pos(current_pos.0 + Vec3::new(x, y, z)),
|
||||||
|
);
|
||||||
|
server
|
||||||
|
.state
|
||||||
|
.write_component(entity, comp::phys::ForceUpdate);
|
||||||
|
}
|
||||||
None => server.clients.notify(
|
None => server.clients.notify(
|
||||||
entity,
|
entity,
|
||||||
ServerMsg::Chat(String::from("Command 'jump' invalid in current state")),
|
ServerMsg::Chat(String::from("Command 'jump' invalid in current state")),
|
||||||
@ -107,9 +112,13 @@ fn handle_goto(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
|
|||||||
let (opt_x, opt_y, opt_z) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32);
|
let (opt_x, opt_y, opt_z) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32);
|
||||||
match (opt_x, opt_y, opt_z) {
|
match (opt_x, opt_y, opt_z) {
|
||||||
(Some(x), Some(y), Some(z)) => {
|
(Some(x), Some(y), Some(z)) => {
|
||||||
server.state.write_component(entity, comp::phys::Pos(Vec3::new(x, y, z)));
|
server
|
||||||
server.state.write_component(entity, comp::phys::ForceUpdate);
|
.state
|
||||||
},
|
.write_component(entity, comp::phys::Pos(Vec3::new(x, y, z)));
|
||||||
|
server
|
||||||
|
.state
|
||||||
|
.write_component(entity, comp::phys::ForceUpdate);
|
||||||
|
}
|
||||||
_ => server
|
_ => server
|
||||||
.clients
|
.clients
|
||||||
.notify(entity, ServerMsg::Chat(String::from(action.help_string))),
|
.notify(entity, ServerMsg::Chat(String::from(action.help_string))),
|
||||||
@ -144,8 +153,10 @@ fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &Chat
|
|||||||
{
|
{
|
||||||
Some(pos) => {
|
Some(pos) => {
|
||||||
server.state.write_component(entity, pos);
|
server.state.write_component(entity, pos);
|
||||||
server.state.write_component(entity, comp::phys::ForceUpdate);
|
server
|
||||||
},
|
.state
|
||||||
|
.write_component(entity, comp::phys::ForceUpdate);
|
||||||
|
}
|
||||||
None => server.clients.notify(
|
None => server.clients.notify(
|
||||||
entity,
|
entity,
|
||||||
ServerMsg::Chat(format!("Unable to teleport to player '{}'", alias)),
|
ServerMsg::Chat(format!("Unable to teleport to player '{}'", alias)),
|
||||||
|
@ -8,20 +8,10 @@ pub mod input;
|
|||||||
// Reexports
|
// Reexports
|
||||||
pub use crate::{error::Error, input::Input};
|
pub use crate::{error::Error, input::Input};
|
||||||
|
|
||||||
use std::{
|
use crate::{
|
||||||
collections::HashSet,
|
client::{Client, Clients},
|
||||||
net::SocketAddr,
|
cmd::CHAT_COMMANDS,
|
||||||
sync::mpsc,
|
|
||||||
time::Duration,
|
|
||||||
i32,
|
|
||||||
};
|
};
|
||||||
use specs::{
|
|
||||||
join::Join, saveload::MarkedBuilder, world::EntityBuilder as EcsEntityBuilder, Builder,
|
|
||||||
Entity as EcsEntity,
|
|
||||||
};
|
|
||||||
use threadpool::ThreadPool;
|
|
||||||
use vek::*;
|
|
||||||
use world::World;
|
|
||||||
use common::{
|
use common::{
|
||||||
comp,
|
comp,
|
||||||
comp::character::Animation,
|
comp::character::Animation,
|
||||||
@ -30,10 +20,14 @@ use common::{
|
|||||||
state::{State, Uid},
|
state::{State, Uid},
|
||||||
terrain::TerrainChunk,
|
terrain::TerrainChunk,
|
||||||
};
|
};
|
||||||
use crate::{
|
use specs::{
|
||||||
client::{Client, Clients},
|
join::Join, saveload::MarkedBuilder, world::EntityBuilder as EcsEntityBuilder, Builder,
|
||||||
cmd::CHAT_COMMANDS,
|
Entity as EcsEntity,
|
||||||
};
|
};
|
||||||
|
use std::{collections::HashSet, i32, net::SocketAddr, sync::mpsc, time::Duration};
|
||||||
|
use threadpool::ThreadPool;
|
||||||
|
use vek::*;
|
||||||
|
use world::World;
|
||||||
|
|
||||||
const CLIENT_TIMEOUT: f64 = 20.0; // Seconds
|
const CLIENT_TIMEOUT: f64 = 20.0; // Seconds
|
||||||
|
|
||||||
@ -193,15 +187,20 @@ impl Server {
|
|||||||
&self.state.ecs().entities(),
|
&self.state.ecs().entities(),
|
||||||
&self.state.ecs().read_storage::<comp::Player>(),
|
&self.state.ecs().read_storage::<comp::Player>(),
|
||||||
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
||||||
).join() {
|
)
|
||||||
|
.join()
|
||||||
|
{
|
||||||
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));
|
||||||
let dist = (chunk_pos - key).map(|e| e.abs()).reduce_max();
|
let dist = (chunk_pos - key).map(|e| e.abs()).reduce_max();
|
||||||
|
|
||||||
if dist < 4 {
|
if dist < 4 {
|
||||||
self.clients.notify(entity, ServerMsg::TerrainChunkUpdate {
|
self.clients.notify(
|
||||||
|
entity,
|
||||||
|
ServerMsg::TerrainChunkUpdate {
|
||||||
key,
|
key,
|
||||||
chunk: Box::new(chunk.clone()),
|
chunk: Box::new(chunk.clone()),
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +217,9 @@ impl Server {
|
|||||||
for (_, pos) in (
|
for (_, pos) in (
|
||||||
&self.state.ecs().read_storage::<comp::Player>(),
|
&self.state.ecs().read_storage::<comp::Player>(),
|
||||||
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
||||||
).join() {
|
)
|
||||||
|
.join()
|
||||||
|
{
|
||||||
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));
|
||||||
let dist = (chunk_pos - key).map(|e| e.abs()).reduce_max();
|
let dist = (chunk_pos - key).map(|e| e.abs()).reduce_max();
|
||||||
min_dist = min_dist.min(dist);
|
min_dist = min_dist.min(dist);
|
||||||
@ -297,44 +298,69 @@ impl Server {
|
|||||||
ClientState::Connected => disconnect = true, // Default state
|
ClientState::Connected => disconnect = true, // Default state
|
||||||
ClientState::Registered => match client.client_state {
|
ClientState::Registered => match client.client_state {
|
||||||
// Use ClientMsg::Register instead
|
// Use ClientMsg::Register instead
|
||||||
ClientState::Connected => client.error_state(RequestStateError::WrongMessage),
|
ClientState::Connected => {
|
||||||
ClientState::Registered => client.error_state(RequestStateError::Already),
|
client.error_state(RequestStateError::WrongMessage)
|
||||||
ClientState::Spectator | ClientState::Character
|
}
|
||||||
=> client.allow_state(ClientState::Registered),
|
ClientState::Registered => {
|
||||||
|
client.error_state(RequestStateError::Already)
|
||||||
|
}
|
||||||
|
ClientState::Spectator | ClientState::Character => {
|
||||||
|
client.allow_state(ClientState::Registered)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ClientState::Spectator => match requested_state {
|
ClientState::Spectator => match requested_state {
|
||||||
// Become Registered first
|
// Become Registered first
|
||||||
ClientState::Connected => client.error_state(RequestStateError::Impossible),
|
ClientState::Connected => {
|
||||||
ClientState::Spectator => client.error_state(RequestStateError::Already),
|
client.error_state(RequestStateError::Impossible)
|
||||||
ClientState::Registered | ClientState::Character
|
}
|
||||||
=> client.allow_state(ClientState::Spectator),
|
ClientState::Spectator => {
|
||||||
|
client.error_state(RequestStateError::Already)
|
||||||
|
}
|
||||||
|
ClientState::Registered | ClientState::Character => {
|
||||||
|
client.allow_state(ClientState::Spectator)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// Use ClientMsg::Character instead
|
// Use ClientMsg::Character instead
|
||||||
ClientState::Character => client.error_state(RequestStateError::WrongMessage),
|
ClientState::Character => {
|
||||||
|
client.error_state(RequestStateError::WrongMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ClientMsg::Register { player } => match client.client_state {
|
ClientMsg::Register { player } => match client.client_state {
|
||||||
ClientState::Connected => Self::initialize_player(state, entity, client, player),
|
ClientState::Connected => {
|
||||||
|
Self::initialize_player(state, entity, client, player)
|
||||||
|
}
|
||||||
// Use RequestState instead (No need to send `player` again)
|
// Use RequestState instead (No need to send `player` again)
|
||||||
_ => client.error_state(RequestStateError::Impossible),
|
_ => client.error_state(RequestStateError::Impossible),
|
||||||
},
|
},
|
||||||
ClientMsg::Character(character) => match client.client_state {
|
ClientMsg::Character(character) => match client.client_state {
|
||||||
// Become Registered first
|
// Become Registered first
|
||||||
ClientState::Connected => client.error_state(RequestStateError::Impossible),
|
ClientState::Connected => {
|
||||||
ClientState::Registered | ClientState::Spectator =>
|
client.error_state(RequestStateError::Impossible)
|
||||||
Self::create_player_character(state, entity, client, character),
|
}
|
||||||
ClientState::Character => client.error_state(RequestStateError::Already),
|
ClientState::Registered | ClientState::Spectator => {
|
||||||
|
Self::create_player_character(state, entity, client, character)
|
||||||
|
}
|
||||||
|
ClientState::Character => {
|
||||||
|
client.error_state(RequestStateError::Already)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ClientMsg::Chat(msg) => match client.client_state {
|
ClientMsg::Chat(msg) => match client.client_state {
|
||||||
ClientState::Connected => client.error_state(RequestStateError::Impossible),
|
ClientState::Connected => {
|
||||||
|
client.error_state(RequestStateError::Impossible)
|
||||||
|
}
|
||||||
ClientState::Registered
|
ClientState::Registered
|
||||||
| ClientState::Spectator
|
| ClientState::Spectator
|
||||||
| ClientState::Character => new_chat_msgs.push((entity, msg)),
|
| ClientState::Character => new_chat_msgs.push((entity, msg)),
|
||||||
},
|
},
|
||||||
ClientMsg::PlayerAnimation(animation_history) => match client.client_state {
|
ClientMsg::PlayerAnimation(animation_history) => {
|
||||||
ClientState::Character => state.write_component(entity, animation_history),
|
match client.client_state {
|
||||||
|
ClientState::Character => {
|
||||||
|
state.write_component(entity, animation_history)
|
||||||
|
}
|
||||||
// Only characters can send animations
|
// Only characters can send animations
|
||||||
_ => client.error_state(RequestStateError::Impossible),
|
_ => client.error_state(RequestStateError::Impossible),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ClientMsg::PlayerPhysics { pos, vel, dir } => match client.client_state {
|
ClientMsg::PlayerPhysics { pos, vel, dir } => match client.client_state {
|
||||||
ClientState::Character => {
|
ClientState::Character => {
|
||||||
state.write_component(entity, pos);
|
state.write_component(entity, pos);
|
||||||
@ -350,10 +376,12 @@ impl Server {
|
|||||||
}
|
}
|
||||||
ClientState::Spectator | ClientState::Character => {
|
ClientState::Spectator | ClientState::Character => {
|
||||||
match state.terrain().get_key(key) {
|
match state.terrain().get_key(key) {
|
||||||
Some(chunk) => client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
|
Some(chunk) => {
|
||||||
|
client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
|
||||||
key,
|
key,
|
||||||
chunk: Box::new(chunk.clone()),
|
chunk: Box::new(chunk.clone()),
|
||||||
}),
|
})
|
||||||
|
}
|
||||||
None => requested_chunks.push(key),
|
None => requested_chunks.push(key),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -458,7 +486,10 @@ impl Server {
|
|||||||
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
||||||
&self.state.ecs().read_storage::<comp::phys::Vel>(),
|
&self.state.ecs().read_storage::<comp::phys::Vel>(),
|
||||||
&self.state.ecs().read_storage::<comp::phys::Dir>(),
|
&self.state.ecs().read_storage::<comp::phys::Dir>(),
|
||||||
self.state.ecs().read_storage::<comp::phys::ForceUpdate>().maybe(),
|
self.state
|
||||||
|
.ecs()
|
||||||
|
.read_storage::<comp::phys::ForceUpdate>()
|
||||||
|
.maybe(),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
{
|
{
|
||||||
@ -508,7 +539,10 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove all force flags
|
// Remove all force flags
|
||||||
self.state.ecs_mut().write_storage::<comp::phys::ForceUpdate>().clear();
|
self.state
|
||||||
|
.ecs_mut()
|
||||||
|
.write_storage::<comp::phys::ForceUpdate>()
|
||||||
|
.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_chunk(&mut self, key: Vec3<i32>) {
|
pub fn generate_chunk(&mut self, key: Vec3<i32>) {
|
||||||
|
@ -5,11 +5,7 @@ use std::f32::consts::PI;
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use super::{
|
use super::{super::Animation, CharacterSkeleton, SCALE};
|
||||||
CharacterSkeleton,
|
|
||||||
super::Animation,
|
|
||||||
SCALE,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct IdleAnimation;
|
pub struct IdleAnimation;
|
||||||
|
|
||||||
@ -17,10 +13,7 @@ impl Animation for IdleAnimation {
|
|||||||
type Skeleton = CharacterSkeleton;
|
type Skeleton = CharacterSkeleton;
|
||||||
type Dependency = f64;
|
type Dependency = f64;
|
||||||
|
|
||||||
fn update_skeleton(
|
fn update_skeleton(skeleton: &Self::Skeleton, time: f64) -> Self::Skeleton {
|
||||||
skeleton: &Self::Skeleton,
|
|
||||||
time: f64,
|
|
||||||
) -> Self::Skeleton {
|
|
||||||
let mut next = (*skeleton).clone();
|
let mut next = (*skeleton).clone();
|
||||||
|
|
||||||
let wave = (time as f32 * 12.0).sin();
|
let wave = (time as f32 * 12.0).sin();
|
||||||
@ -47,11 +40,19 @@ impl Animation for IdleAnimation {
|
|||||||
next.shorts.ori = Quaternion::rotation_y(0.0);
|
next.shorts.ori = Quaternion::rotation_y(0.0);
|
||||||
next.shorts.scale = Vec3::one();
|
next.shorts.scale = Vec3::one();
|
||||||
|
|
||||||
next.l_hand.offset = Vec3::new(2.0 + waveultracos_slow * 0.3, 7.5, 12.5 + waveultra_slow * 1.1);
|
next.l_hand.offset = Vec3::new(
|
||||||
|
2.0 + waveultracos_slow * 0.3,
|
||||||
|
7.5,
|
||||||
|
12.5 + waveultra_slow * 1.1,
|
||||||
|
);
|
||||||
next.l_hand.ori = Quaternion::rotation_y(0.0 + waveultra_slow * 0.06);
|
next.l_hand.ori = Quaternion::rotation_y(0.0 + waveultra_slow * 0.06);
|
||||||
next.l_hand.scale = Vec3::one();
|
next.l_hand.scale = Vec3::one();
|
||||||
|
|
||||||
next.r_hand.offset = Vec3::new(2.0 + waveultracos_slow * 0.3 , - 7.5, 12.5 + waveultra_slow * 1.1);
|
next.r_hand.offset = Vec3::new(
|
||||||
|
2.0 + waveultracos_slow * 0.3,
|
||||||
|
-7.5,
|
||||||
|
12.5 + waveultra_slow * 1.1,
|
||||||
|
);
|
||||||
next.r_hand.ori = Quaternion::rotation_y(0.0 + waveultra_slow * 0.06);
|
next.r_hand.ori = Quaternion::rotation_y(0.0 + waveultra_slow * 0.06);
|
||||||
next.r_hand.scale = Vec3::one();
|
next.r_hand.scale = Vec3::one();
|
||||||
|
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
pub mod run;
|
|
||||||
pub mod idle;
|
pub mod idle;
|
||||||
|
pub mod run;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
pub use self::run::RunAnimation;
|
|
||||||
pub use self::idle::IdleAnimation;
|
pub use self::idle::IdleAnimation;
|
||||||
|
pub use self::run::RunAnimation;
|
||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::render::FigureBoneData;
|
use crate::render::FigureBoneData;
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use super::{
|
use super::{Bone, Skeleton};
|
||||||
Skeleton,
|
|
||||||
Bone,
|
|
||||||
};
|
|
||||||
|
|
||||||
const SCALE: f32 = 11.0;
|
const SCALE: f32 = 11.0;
|
||||||
|
|
||||||
@ -47,7 +44,6 @@ impl CharacterSkeleton {
|
|||||||
torso: Bone::default(),
|
torso: Bone::default(),
|
||||||
l_shoulder: Bone::default(),
|
l_shoulder: Bone::default(),
|
||||||
r_shoulder: Bone::default(),
|
r_shoulder: Bone::default(),
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,7 +71,6 @@ impl Skeleton for CharacterSkeleton {
|
|||||||
FigureBoneData::default(),
|
FigureBoneData::default(),
|
||||||
FigureBoneData::default(),
|
FigureBoneData::default(),
|
||||||
FigureBoneData::default(),
|
FigureBoneData::default(),
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +87,5 @@ impl Skeleton for CharacterSkeleton {
|
|||||||
self.torso.interpolate(&target.torso);
|
self.torso.interpolate(&target.torso);
|
||||||
self.l_shoulder.interpolate(&target.l_shoulder);
|
self.l_shoulder.interpolate(&target.l_shoulder);
|
||||||
self.r_shoulder.interpolate(&target.r_shoulder);
|
self.r_shoulder.interpolate(&target.r_shoulder);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,7 @@ use std::f32::consts::PI;
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use super::{
|
use super::{super::Animation, CharacterSkeleton, SCALE};
|
||||||
CharacterSkeleton,
|
|
||||||
super::Animation,
|
|
||||||
SCALE
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct RunAnimation;
|
pub struct RunAnimation;
|
||||||
|
|
||||||
@ -17,10 +13,7 @@ impl Animation for RunAnimation {
|
|||||||
type Skeleton = CharacterSkeleton;
|
type Skeleton = CharacterSkeleton;
|
||||||
type Dependency = f64;
|
type Dependency = f64;
|
||||||
|
|
||||||
fn update_skeleton(
|
fn update_skeleton(skeleton: &Self::Skeleton, time: f64) -> Self::Skeleton {
|
||||||
skeleton: &Self::Skeleton,
|
|
||||||
time: f64,
|
|
||||||
) -> Self::Skeleton {
|
|
||||||
let mut next = (*skeleton).clone();
|
let mut next = (*skeleton).clone();
|
||||||
|
|
||||||
let wave = (time as f32 * 14.0).sin();
|
let wave = (time as f32 * 14.0).sin();
|
||||||
@ -79,8 +72,6 @@ impl Animation for RunAnimation {
|
|||||||
next.r_shoulder.ori = Quaternion::rotation_y(0.0);
|
next.r_shoulder.ori = Quaternion::rotation_y(0.0);
|
||||||
next.r_shoulder.scale = Vec3::one();
|
next.r_shoulder.scale = Vec3::one();
|
||||||
|
|
||||||
|
|
||||||
next
|
next
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@ impl Bone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_base_matrix(&self) -> Mat4<f32> {
|
pub fn compute_base_matrix(&self) -> Mat4<f32> {
|
||||||
Mat4::<f32>::translation_3d(self.offset) * Mat4::scaling_3d(self.scale) * Mat4::from(self.ori)
|
Mat4::<f32>::translation_3d(self.offset)
|
||||||
|
* Mat4::scaling_3d(self.scale)
|
||||||
|
* Mat4::from(self.ori)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the current bone to be more like `target`
|
/// Change the current bone to be more like `target`
|
||||||
@ -48,8 +50,5 @@ pub trait Animation {
|
|||||||
type Dependency;
|
type Dependency;
|
||||||
|
|
||||||
/// Returns a new skeleton that is generated by the animation
|
/// Returns a new skeleton that is generated by the animation
|
||||||
fn update_skeleton(
|
fn update_skeleton(skeleton: &Self::Skeleton, dependency: Self::Dependency) -> Self::Skeleton;
|
||||||
skeleton: &Self::Skeleton,
|
|
||||||
dependency: Self::Dependency,
|
|
||||||
) -> Self::Skeleton;
|
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,11 @@ impl Chat {
|
|||||||
|
|
||||||
// Only show if it has the keyboard captured
|
// Only show if it has the keyboard captured
|
||||||
// Chat input with rectangle as background
|
// Chat input with rectangle as background
|
||||||
let keyboard_captured = ui_widgets.global_input().current.widget_capturing_keyboard.map_or(false, |id| id == self.ids.input);
|
let keyboard_captured = ui_widgets
|
||||||
|
.global_input()
|
||||||
|
.current
|
||||||
|
.widget_capturing_keyboard
|
||||||
|
.map_or(false, |id| id == self.ids.input);
|
||||||
if keyboard_captured {
|
if keyboard_captured {
|
||||||
let text_edit = TextEdit::new(&self.input)
|
let text_edit = TextEdit::new(&self.input)
|
||||||
.w(460.0)
|
.w(460.0)
|
||||||
@ -114,10 +118,12 @@ impl Chat {
|
|||||||
// Message box
|
// Message box
|
||||||
Rectangle::fill([470.0, 174.0])
|
Rectangle::fill([470.0, 174.0])
|
||||||
.rgba(0.0, 0.0, 0.0, 0.4)
|
.rgba(0.0, 0.0, 0.0, 0.4)
|
||||||
.and(|r| if keyboard_captured {
|
.and(|r| {
|
||||||
|
if keyboard_captured {
|
||||||
r.up_from(self.ids.input_bg, 0.0)
|
r.up_from(self.ids.input_bg, 0.0)
|
||||||
} else {
|
} else {
|
||||||
r.bottom_left_with_margins_on(ui_widgets.window, 10.0, 10.0)
|
r.bottom_left_with_margins_on(ui_widgets.window, 10.0, 10.0)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.set(self.ids.message_box_bg, ui_widgets);
|
.set(self.ids.message_box_bg, ui_widgets);
|
||||||
let (mut items, _) = List::flow_down(self.messages.len() + 1)
|
let (mut items, _) = List::flow_down(self.messages.len() + 1)
|
||||||
|
@ -176,7 +176,6 @@ pub(self) struct Imgs {
|
|||||||
inv_slot: ImgId,
|
inv_slot: ImgId,
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
|
|
||||||
mmap_closed: ImgId,
|
mmap_closed: ImgId,
|
||||||
mmap_closed_hover: ImgId,
|
mmap_closed_hover: ImgId,
|
||||||
mmap_closed_press: ImgId,
|
mmap_closed_press: ImgId,
|
||||||
@ -670,18 +669,29 @@ impl Hud {
|
|||||||
Rectangle::fill_with([92.0 * 2.0, 82.0 * 2.0], color::TRANSPARENT)
|
Rectangle::fill_with([92.0 * 2.0, 82.0 * 2.0], color::TRANSPARENT)
|
||||||
.mid_top_with_margin_on(self.ids.mmap_frame, 13.0 * 2.0 + 2.0)
|
.mid_top_with_margin_on(self.ids.mmap_frame, 13.0 * 2.0 + 2.0)
|
||||||
.set(self.ids.mmap_frame_bg, ui_widgets);
|
.set(self.ids.mmap_frame_bg, ui_widgets);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Image::new(self.imgs.mmap_frame_closed)
|
Image::new(self.imgs.mmap_frame_closed)
|
||||||
.w_h(100.0 * 2.0, 11.0 * 2.0)
|
.w_h(100.0 * 2.0, 11.0 * 2.0)
|
||||||
.top_right_with_margins_on(ui_widgets.window, 5.0, 5.0)
|
.top_right_with_margins_on(ui_widgets.window, 5.0, 5.0)
|
||||||
.set(self.ids.mmap_frame, ui_widgets);
|
.set(self.ids.mmap_frame, ui_widgets);
|
||||||
};
|
};
|
||||||
|
|
||||||
if Button::image(if self.mmap_open {self.imgs.mmap_open} else {self.imgs.mmap_closed})
|
if Button::image(if self.mmap_open {
|
||||||
|
self.imgs.mmap_open
|
||||||
|
} else {
|
||||||
|
self.imgs.mmap_closed
|
||||||
|
})
|
||||||
.w_h(100.0 * 0.2, 100.0 * 0.2)
|
.w_h(100.0 * 0.2, 100.0 * 0.2)
|
||||||
.hover_image(if self.mmap_open {self.imgs.mmap_open_hover} else {self.imgs.mmap_closed_hover})
|
.hover_image(if self.mmap_open {
|
||||||
.press_image(if self.mmap_open {self.imgs.mmap_open_press} else {self.imgs.mmap_closed_press})
|
self.imgs.mmap_open_hover
|
||||||
|
} else {
|
||||||
|
self.imgs.mmap_closed_hover
|
||||||
|
})
|
||||||
|
.press_image(if self.mmap_open {
|
||||||
|
self.imgs.mmap_open_press
|
||||||
|
} else {
|
||||||
|
self.imgs.mmap_closed_press
|
||||||
|
})
|
||||||
.top_right_with_margins_on(self.ids.mmap_frame, 0.0, 0.0)
|
.top_right_with_margins_on(self.ids.mmap_frame, 0.0, 0.0)
|
||||||
.set(self.ids.mmap_button, ui_widgets)
|
.set(self.ids.mmap_button, ui_widgets)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
@ -1590,7 +1600,6 @@ impl Hud {
|
|||||||
.w_h(412.0, 488.0)
|
.w_h(412.0, 488.0)
|
||||||
.set(self.ids.map_frame_bl, ui_widgets);
|
.set(self.ids.map_frame_bl, ui_widgets);
|
||||||
|
|
||||||
|
|
||||||
// Icon
|
// Icon
|
||||||
Image::new(self.imgs.map_icon)
|
Image::new(self.imgs.map_icon)
|
||||||
.w_h(224.0 / 3.0, 224.0 / 3.0)
|
.w_h(224.0 / 3.0, 224.0 / 3.0)
|
||||||
|
@ -10,22 +10,18 @@ pub mod mesh;
|
|||||||
pub mod render;
|
pub mod render;
|
||||||
pub mod scene;
|
pub mod scene;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
pub mod ui;
|
|
||||||
pub mod window;
|
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod singleplayer;
|
pub mod singleplayer;
|
||||||
|
pub mod ui;
|
||||||
|
pub mod window;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
pub use crate::error::Error;
|
pub use crate::error::Error;
|
||||||
|
|
||||||
use std::{mem, thread, panic, fs::File, str::FromStr};
|
use crate::{menu::main::MainMenuState, settings::Settings, window::Window};
|
||||||
use log;
|
use log;
|
||||||
use simplelog::{CombinedLogger, TermLogger, WriteLogger, Config};
|
use simplelog::{CombinedLogger, Config, TermLogger, WriteLogger};
|
||||||
use crate::{
|
use std::{fs::File, mem, panic, str::FromStr, thread};
|
||||||
menu::main::MainMenuState,
|
|
||||||
window::Window,
|
|
||||||
settings::Settings,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The URL of the default public server that Voxygen will connect to
|
/// The URL of the default public server that Voxygen will connect to
|
||||||
const DEFAULT_PUBLIC_SERVER: &'static str = "server.veloren.net";
|
const DEFAULT_PUBLIC_SERVER: &'static str = "server.veloren.net";
|
||||||
@ -82,7 +78,7 @@ fn main() {
|
|||||||
let settings = Settings::default();
|
let settings = Settings::default();
|
||||||
settings.save_to_file();
|
settings.save_to_file();
|
||||||
settings
|
settings
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
let window = Window::new(&settings).expect("Failed to create window");
|
let window = Window::new(&settings).expect("Failed to create window");
|
||||||
|
|
||||||
@ -93,8 +89,13 @@ fn main() {
|
|||||||
.unwrap_or(log::LevelFilter::Warn);
|
.unwrap_or(log::LevelFilter::Warn);
|
||||||
CombinedLogger::init(vec![
|
CombinedLogger::init(vec![
|
||||||
TermLogger::new(term_log_level, Config::default()).unwrap(),
|
TermLogger::new(term_log_level, Config::default()).unwrap(),
|
||||||
WriteLogger::new(log::LevelFilter::Info, Config::default(), File::create(&settings.log.file).unwrap()),
|
WriteLogger::new(
|
||||||
]).unwrap();
|
log::LevelFilter::Info,
|
||||||
|
Config::default(),
|
||||||
|
File::create(&settings.log.file).unwrap(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Set up panic handler to relay swish panic messages to the user
|
// Set up panic handler to relay swish panic messages to the user
|
||||||
let settings_clone = settings.clone();
|
let settings_clone = settings.clone();
|
||||||
@ -127,18 +128,13 @@ The information below is intended for developers and testers.
|
|||||||
msgbox::create("Voxygen has panicked", &msg, msgbox::IconType::ERROR);
|
msgbox::create("Voxygen has panicked", &msg, msgbox::IconType::ERROR);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let mut global_state = GlobalState {
|
let mut global_state = GlobalState { settings, window };
|
||||||
settings,
|
|
||||||
window,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set up the initial play state
|
// Set up the initial play state
|
||||||
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(
|
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(&mut global_state))];
|
||||||
&mut global_state,
|
states
|
||||||
))];
|
.last()
|
||||||
states.last().map(|current_state| {
|
.map(|current_state| log::info!("Started game with state '{}'", current_state.name()));
|
||||||
log::info!("Started game with state '{}'", current_state.name())
|
|
||||||
});
|
|
||||||
|
|
||||||
// What's going on here?
|
// What's going on here?
|
||||||
// ---------------------
|
// ---------------------
|
||||||
@ -148,7 +144,10 @@ The information below is intended for developers and testers.
|
|||||||
// The code below manages the state transfer logic automatically so that we don't have to
|
// The code below manages the state transfer logic automatically so that we don't have to
|
||||||
// re-engineer it for each menu we decide to add to the game.
|
// re-engineer it for each menu we decide to add to the game.
|
||||||
let mut direction = Direction::Forwards;
|
let mut direction = Direction::Forwards;
|
||||||
while let Some(state_result) = states.last_mut().map(|last| last.play(direction, &mut global_state)){
|
while let Some(state_result) = states
|
||||||
|
.last_mut()
|
||||||
|
.map(|last| last.play(direction, &mut global_state))
|
||||||
|
{
|
||||||
// Implement state transfer logic
|
// Implement state transfer logic
|
||||||
match state_result {
|
match state_result {
|
||||||
PlayStateResult::Shutdown => {
|
PlayStateResult::Shutdown => {
|
||||||
@ -160,28 +159,32 @@ The information below is intended for developers and testers.
|
|||||||
global_state.on_play_state_changed();
|
global_state.on_play_state_changed();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
PlayStateResult::Pop => {
|
PlayStateResult::Pop => {
|
||||||
direction = Direction::Backwards;
|
direction = Direction::Backwards;
|
||||||
states.pop().map(|old_state| {
|
states.pop().map(|old_state| {
|
||||||
log::info!("Popped state '{}'", old_state.name());
|
log::info!("Popped state '{}'", old_state.name());
|
||||||
global_state.on_play_state_changed();
|
global_state.on_play_state_changed();
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
PlayStateResult::Push(new_state) => {
|
PlayStateResult::Push(new_state) => {
|
||||||
direction = Direction::Forwards;
|
direction = Direction::Forwards;
|
||||||
log::info!("Pushed state '{}'", new_state.name());
|
log::info!("Pushed state '{}'", new_state.name());
|
||||||
states.push(new_state);
|
states.push(new_state);
|
||||||
global_state.on_play_state_changed();
|
global_state.on_play_state_changed();
|
||||||
},
|
}
|
||||||
PlayStateResult::Switch(mut new_state) => {
|
PlayStateResult::Switch(mut new_state) => {
|
||||||
direction = Direction::Forwards;
|
direction = Direction::Forwards;
|
||||||
states.last_mut().map(|old_state| {
|
states.last_mut().map(|old_state| {
|
||||||
log::info!("Switching to state '{}' from state '{}'", new_state.name(), old_state.name());
|
log::info!(
|
||||||
|
"Switching to state '{}' from state '{}'",
|
||||||
|
new_state.name(),
|
||||||
|
old_state.name()
|
||||||
|
);
|
||||||
mem::swap(old_state, &mut new_state);
|
mem::swap(old_state, &mut new_state);
|
||||||
global_state.on_play_state_changed();
|
global_state.on_play_state_changed();
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
window::{Event, Window},
|
|
||||||
session::SessionState,
|
session::SessionState,
|
||||||
|
window::{Event, Window},
|
||||||
Direction, GlobalState, PlayState, PlayStateResult,
|
Direction, GlobalState, PlayState, PlayStateResult,
|
||||||
};
|
};
|
||||||
use client::{self, Client};
|
use client::{self, Client};
|
||||||
use common::{
|
use common::{clock::Clock, msg::ClientMsg};
|
||||||
clock::Clock,
|
|
||||||
msg::ClientMsg,
|
|
||||||
};
|
|
||||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||||
use ui::CharSelectionUi;
|
use ui::CharSelectionUi;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -50,7 +47,7 @@ impl PlayState for CharSelectionState {
|
|||||||
match event {
|
match event {
|
||||||
Event::Close => {
|
Event::Close => {
|
||||||
return PlayStateResult::Shutdown;
|
return PlayStateResult::Shutdown;
|
||||||
},
|
}
|
||||||
// Pass events to ui
|
// Pass events to ui
|
||||||
Event::Ui(event) => {
|
Event::Ui(event) => {
|
||||||
self.char_selection_ui.handle_event(event);
|
self.char_selection_ui.handle_event(event);
|
||||||
@ -63,23 +60,35 @@ impl PlayState for CharSelectionState {
|
|||||||
global_state.window.renderer_mut().clear(BG_COLOR);
|
global_state.window.renderer_mut().clear(BG_COLOR);
|
||||||
|
|
||||||
// Maintain the UI
|
// Maintain the UI
|
||||||
for event in self.char_selection_ui.maintain(global_state.window.renderer_mut()) {
|
for event in self
|
||||||
|
.char_selection_ui
|
||||||
|
.maintain(global_state.window.renderer_mut())
|
||||||
|
{
|
||||||
match event {
|
match event {
|
||||||
ui::Event::Logout => {
|
ui::Event::Logout => {
|
||||||
return PlayStateResult::Pop;
|
return PlayStateResult::Pop;
|
||||||
},
|
}
|
||||||
ui::Event::Play => {
|
ui::Event::Play => {
|
||||||
self.client.borrow_mut().postbox.send_message(ClientMsg::Character(self.char_selection_ui.character));
|
self.client
|
||||||
return PlayStateResult::Switch( Box::new(SessionState::new(&mut global_state.window, self.client.clone())));
|
.borrow_mut()
|
||||||
|
.postbox
|
||||||
|
.send_message(ClientMsg::Character(self.char_selection_ui.character));
|
||||||
|
return PlayStateResult::Switch(Box::new(SessionState::new(
|
||||||
|
&mut global_state.window,
|
||||||
|
self.client.clone(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the UI to the screen
|
// Draw the UI to the screen
|
||||||
self.char_selection_ui.render(global_state.window.renderer_mut());
|
self.char_selection_ui
|
||||||
|
.render(global_state.window.renderer_mut());
|
||||||
|
|
||||||
// Tick the client (currently only to keep the connection alive)
|
// Tick the client (currently only to keep the connection alive)
|
||||||
self.client.borrow_mut().tick(client::Input::default(), clock.get_last_delta())
|
self.client
|
||||||
|
.borrow_mut()
|
||||||
|
.tick(client::Input::default(), clock.get_last_delta())
|
||||||
.expect("Failed to tick the client");
|
.expect("Failed to tick the client");
|
||||||
self.client.borrow_mut().cleanup();
|
self.client.borrow_mut().cleanup();
|
||||||
|
|
||||||
|
@ -5,19 +5,8 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
assets,
|
assets,
|
||||||
|
comp::character::{Belt, Character, Chest, Foot, Gender, Hand, Head, Pants, Race, Weapon},
|
||||||
figure::Segment,
|
figure::Segment,
|
||||||
comp::character::{
|
|
||||||
Character,
|
|
||||||
Race,
|
|
||||||
Gender,
|
|
||||||
Head,
|
|
||||||
Chest,
|
|
||||||
Belt,
|
|
||||||
Pants,
|
|
||||||
Hand,
|
|
||||||
Foot,
|
|
||||||
Weapon,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
color,
|
color,
|
||||||
@ -381,10 +370,12 @@ impl CharSelectionUi {
|
|||||||
// Load fonts
|
// Load fonts
|
||||||
let load_font = |filename, ui: &mut Ui| {
|
let load_font = |filename, ui: &mut Ui| {
|
||||||
let fullpath: String = ["/voxygen/font", filename].concat();
|
let fullpath: String = ["/voxygen/font", filename].concat();
|
||||||
ui.new_font(conrod_core::text::Font::from_bytes(
|
ui.new_font(
|
||||||
assets::load(fullpath.as_str())
|
conrod_core::text::Font::from_bytes(
|
||||||
.expect("Error loading file")
|
assets::load(fullpath.as_str()).expect("Error loading file"),
|
||||||
).unwrap())
|
)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let font_opensans = load_font("/OpenSans-Regular.ttf", &mut ui);
|
let font_opensans = load_font("/OpenSans-Regular.ttf", &mut ui);
|
||||||
let font_metamorph = load_font("/Metamorphous-Regular.ttf", &mut ui);
|
let font_metamorph = load_font("/Metamorphous-Regular.ttf", &mut ui);
|
||||||
|
@ -20,10 +20,7 @@ pub struct ClientInit {
|
|||||||
rx: Receiver<Result<Client, Error>>,
|
rx: Receiver<Result<Client, Error>>,
|
||||||
}
|
}
|
||||||
impl ClientInit {
|
impl ClientInit {
|
||||||
pub fn new(
|
pub fn new(connection_args: (String, u16, bool), client_args: (comp::Player, u64)) -> Self {
|
||||||
connection_args: (String, u16, bool),
|
|
||||||
client_args: (comp::Player, u64),
|
|
||||||
) -> Self {
|
|
||||||
let (server_address, default_port, prefer_ipv6) = connection_args;
|
let (server_address, default_port, prefer_ipv6) = connection_args;
|
||||||
let (player, view_distance) = client_args;
|
let (player, view_distance) = client_args;
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ mod client_init;
|
|||||||
mod start_singleplayer;
|
mod start_singleplayer;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
use start_singleplayer::StartSingleplayerState;
|
|
||||||
use super::char_selection::CharSelectionState;
|
use super::char_selection::CharSelectionState;
|
||||||
use crate::{
|
use crate::{
|
||||||
window::{Event, Window},
|
window::{Event, Window},
|
||||||
@ -10,6 +9,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use client_init::{ClientInit, Error as InitError};
|
use client_init::{ClientInit, Error as InitError};
|
||||||
use common::{clock::Clock, comp};
|
use common::{clock::Clock, comp};
|
||||||
|
use start_singleplayer::StartSingleplayerState;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use ui::{Event as MainMenuEvent, MainMenuUi};
|
use ui::{Event as MainMenuEvent, MainMenuUi};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -86,10 +86,7 @@ impl PlayState for MainMenuState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Maintain the UI
|
// Maintain the UI
|
||||||
for event in self
|
for event in self.main_menu_ui.maintain(global_state) {
|
||||||
.main_menu_ui
|
|
||||||
.maintain(global_state)
|
|
||||||
{
|
|
||||||
match event {
|
match event {
|
||||||
MainMenuEvent::LoginAttempt {
|
MainMenuEvent::LoginAttempt {
|
||||||
username,
|
username,
|
||||||
@ -104,15 +101,12 @@ impl PlayState for MainMenuState {
|
|||||||
// Don't try to connect if there is already a connection in progress
|
// Don't try to connect if there is already a connection in progress
|
||||||
client_init = client_init.or(Some(ClientInit::new(
|
client_init = client_init.or(Some(ClientInit::new(
|
||||||
(server_address, DEFAULT_PORT, false),
|
(server_address, DEFAULT_PORT, false),
|
||||||
(
|
(comp::Player::new(username.clone()), 300),
|
||||||
comp::Player::new(username.clone()),
|
|
||||||
300,
|
|
||||||
),
|
|
||||||
)));
|
)));
|
||||||
},
|
}
|
||||||
MainMenuEvent::StartSingleplayer => {
|
MainMenuEvent::StartSingleplayer => {
|
||||||
return PlayStateResult::Push(Box::new(StartSingleplayerState::new()));
|
return PlayStateResult::Push(Box::new(StartSingleplayerState::new()));
|
||||||
},
|
}
|
||||||
MainMenuEvent::Quit => return PlayStateResult::Shutdown,
|
MainMenuEvent::Quit => return PlayStateResult::Shutdown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
use common::comp;
|
use super::{client_init::ClientInit, DEFAULT_PORT};
|
||||||
use super::{DEFAULT_PORT, client_init::ClientInit};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
menu::char_selection::CharSelectionState,
|
menu::char_selection::CharSelectionState, singleplayer::Singleplayer, Direction, GlobalState,
|
||||||
singleplayer::Singleplayer,
|
PlayState, PlayStateResult,
|
||||||
Direction, GlobalState, PlayState, PlayStateResult,
|
|
||||||
};
|
};
|
||||||
|
use common::comp;
|
||||||
|
|
||||||
pub struct StartSingleplayerState {
|
pub struct StartSingleplayerState {
|
||||||
singleplayer: Singleplayer,
|
singleplayer: Singleplayer,
|
||||||
@ -28,10 +27,7 @@ impl PlayState for StartSingleplayerState {
|
|||||||
|
|
||||||
let client_init = ClientInit::new(
|
let client_init = ClientInit::new(
|
||||||
(server_address.clone(), DEFAULT_PORT, false),
|
(server_address.clone(), DEFAULT_PORT, false),
|
||||||
(
|
(comp::Player::new(username.clone()), 300),
|
||||||
comp::Player::new(username.clone()),
|
|
||||||
300,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Client creation
|
// Client creation
|
||||||
@ -40,7 +36,7 @@ impl PlayState for StartSingleplayerState {
|
|||||||
Some(Ok(client)) => break client,
|
Some(Ok(client)) => break client,
|
||||||
// Should always work
|
// Should always work
|
||||||
Some(Err(err)) => unreachable!(),
|
Some(Err(err)) => unreachable!(),
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -55,7 +51,7 @@ impl PlayState for StartSingleplayerState {
|
|||||||
&mut global_state.window,
|
&mut global_state.window,
|
||||||
std::rc::Rc::new(std::cell::RefCell::new(client)),
|
std::rc::Rc::new(std::cell::RefCell::new(client)),
|
||||||
)))
|
)))
|
||||||
},
|
}
|
||||||
Direction::Backwards => PlayStateResult::Pop,
|
Direction::Backwards => PlayStateResult::Pop,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
mod vol;
|
|
||||||
pub mod segment;
|
pub mod segment;
|
||||||
pub mod terrain;
|
pub mod terrain;
|
||||||
|
mod vol;
|
||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::render::{self, Mesh};
|
use crate::render::{self, Mesh};
|
||||||
|
@ -1,14 +1,8 @@
|
|||||||
// Library
|
// Library
|
||||||
use gfx::{
|
use gfx::{self, traits::FactoryExt};
|
||||||
self,
|
|
||||||
traits::FactoryExt,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use super::{
|
use super::{gfx_backend, RenderError};
|
||||||
RenderError,
|
|
||||||
gfx_backend,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A handle to a series of constants sitting on the GPU. This is used to hold information used in
|
/// A handle to a series of constants sitting on the GPU. This is used to hold information used in
|
||||||
/// the rendering process that does not change throughout a single render pass.
|
/// the rendering process that does not change throughout a single render pass.
|
||||||
@ -31,7 +25,8 @@ impl<T: Copy + gfx::traits::Pod> Consts<T> {
|
|||||||
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
||||||
vals: &[T],
|
vals: &[T],
|
||||||
) -> Result<(), RenderError> {
|
) -> Result<(), RenderError> {
|
||||||
encoder.update_buffer(&self.buf, vals, 0)
|
encoder
|
||||||
|
.update_buffer(&self.buf, vals, 0)
|
||||||
.map_err(|err| RenderError::UpdateError(err))
|
.map_err(|err| RenderError::UpdateError(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,11 +75,7 @@ pub struct Tri<P: Pipeline> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Pipeline> Tri<P> {
|
impl<P: Pipeline> Tri<P> {
|
||||||
pub fn new(
|
pub fn new(a: P::Vertex, b: P::Vertex, c: P::Vertex) -> Self {
|
||||||
a: P::Vertex,
|
|
||||||
b: P::Vertex,
|
|
||||||
c: P::Vertex,
|
|
||||||
) -> Self {
|
|
||||||
Self { a, b, c }
|
Self { a, b, c }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,12 +89,7 @@ pub struct Quad<P: Pipeline> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Pipeline> Quad<P> {
|
impl<P: Pipeline> Quad<P> {
|
||||||
pub fn new(
|
pub fn new(a: P::Vertex, b: P::Vertex, c: P::Vertex, d: P::Vertex) -> Self {
|
||||||
a: P::Vertex,
|
|
||||||
b: P::Vertex,
|
|
||||||
c: P::Vertex,
|
|
||||||
d: P::Vertex,
|
|
||||||
) -> Self {
|
|
||||||
Self { a, b, c, d }
|
Self { a, b, c, d }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,33 +9,19 @@ mod util;
|
|||||||
// Reexports
|
// Reexports
|
||||||
pub use self::{
|
pub use self::{
|
||||||
consts::Consts,
|
consts::Consts,
|
||||||
mesh::{Mesh, Tri, Quad},
|
mesh::{Mesh, Quad, Tri},
|
||||||
model::Model,
|
model::Model,
|
||||||
texture::Texture,
|
|
||||||
renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
|
|
||||||
pipelines::{
|
pipelines::{
|
||||||
Globals,
|
figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals},
|
||||||
figure::{
|
skybox::{create_mesh as create_skybox_mesh, Locals as SkyboxLocals, SkyboxPipeline},
|
||||||
FigurePipeline,
|
terrain::{Locals as TerrainLocals, TerrainPipeline},
|
||||||
Locals as FigureLocals,
|
|
||||||
BoneData as FigureBoneData,
|
|
||||||
},
|
|
||||||
skybox::{
|
|
||||||
create_mesh as create_skybox_mesh,
|
|
||||||
SkyboxPipeline,
|
|
||||||
Locals as SkyboxLocals,
|
|
||||||
},
|
|
||||||
terrain::{
|
|
||||||
TerrainPipeline,
|
|
||||||
Locals as TerrainLocals,
|
|
||||||
},
|
|
||||||
ui::{
|
ui::{
|
||||||
create_quad as create_ui_quad,
|
create_quad as create_ui_quad, create_tri as create_ui_tri, Mode as UiMode, UiPipeline,
|
||||||
create_tri as create_ui_tri,
|
|
||||||
Mode as UiMode,
|
|
||||||
UiPipeline,
|
|
||||||
},
|
},
|
||||||
|
Globals,
|
||||||
},
|
},
|
||||||
|
renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
|
||||||
|
texture::Texture,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "gl")]
|
#[cfg(feature = "gl")]
|
||||||
@ -64,8 +50,5 @@ pub enum RenderError {
|
|||||||
/// - `SkyboxPipeline`
|
/// - `SkyboxPipeline`
|
||||||
/// - `FigurePipeline`
|
/// - `FigurePipeline`
|
||||||
pub trait Pipeline {
|
pub trait Pipeline {
|
||||||
type Vertex:
|
type Vertex: Clone + gfx::traits::Pod + gfx::pso::buffer::Structure<gfx::format::Format>;
|
||||||
Clone +
|
|
||||||
gfx::traits::Pod +
|
|
||||||
gfx::pso::buffer::Structure<gfx::format::Format>;
|
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
// Library
|
// Library
|
||||||
use gfx::{
|
use gfx::{self, traits::FactoryExt};
|
||||||
self,
|
|
||||||
traits::FactoryExt,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use super::{
|
use super::{gfx_backend, mesh::Mesh, Pipeline};
|
||||||
mesh::Mesh,
|
|
||||||
Pipeline,
|
|
||||||
gfx_backend,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Represents a mesh that has been sent to the GPU.
|
/// Represents a mesh that has been sent to the GPU.
|
||||||
pub struct Model<P: Pipeline> {
|
pub struct Model<P: Pipeline> {
|
||||||
@ -18,10 +11,7 @@ pub struct Model<P: Pipeline> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Pipeline> Model<P> {
|
impl<P: Pipeline> Model<P> {
|
||||||
pub fn new(
|
pub fn new(factory: &mut gfx_backend::Factory, mesh: &Mesh<P>) -> Self {
|
||||||
factory: &mut gfx_backend::Factory,
|
|
||||||
mesh: &Mesh<P>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
vbuf: factory.create_vertex_buffer(mesh.vertices()),
|
vbuf: factory.create_vertex_buffer(mesh.vertices()),
|
||||||
slice: gfx::Slice {
|
slice: gfx::Slice {
|
||||||
|
@ -1,25 +1,20 @@
|
|||||||
// Library
|
// Library
|
||||||
use gfx::{
|
use gfx::{
|
||||||
self,
|
self,
|
||||||
|
gfx_constant_struct_meta,
|
||||||
// Macros
|
// Macros
|
||||||
gfx_defines,
|
gfx_defines,
|
||||||
gfx_vertex_struct_meta,
|
|
||||||
gfx_constant_struct_meta,
|
|
||||||
gfx_impl_struct_meta,
|
gfx_impl_struct_meta,
|
||||||
gfx_pipeline,
|
gfx_pipeline,
|
||||||
gfx_pipeline_inner,
|
gfx_pipeline_inner,
|
||||||
|
gfx_vertex_struct_meta,
|
||||||
};
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use super::{
|
use super::{
|
||||||
|
super::{util::arr_to_mat, Pipeline, TgtColorFmt, TgtDepthFmt},
|
||||||
Globals,
|
Globals,
|
||||||
super::{
|
|
||||||
Pipeline,
|
|
||||||
TgtColorFmt,
|
|
||||||
TgtDepthFmt,
|
|
||||||
util::arr_to_mat,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
gfx_defines! {
|
gfx_defines! {
|
||||||
|
@ -6,9 +6,9 @@ pub mod ui;
|
|||||||
// Library
|
// Library
|
||||||
use gfx::{
|
use gfx::{
|
||||||
self,
|
self,
|
||||||
|
gfx_constant_struct_meta,
|
||||||
// Macros
|
// Macros
|
||||||
gfx_defines,
|
gfx_defines,
|
||||||
gfx_constant_struct_meta,
|
|
||||||
gfx_impl_struct_meta,
|
gfx_impl_struct_meta,
|
||||||
};
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
@ -1,25 +1,19 @@
|
|||||||
// Library
|
// Library
|
||||||
use gfx::{
|
use gfx::{
|
||||||
self,
|
self,
|
||||||
|
gfx_constant_struct_meta,
|
||||||
// Macros
|
// Macros
|
||||||
gfx_defines,
|
gfx_defines,
|
||||||
gfx_vertex_struct_meta,
|
|
||||||
gfx_constant_struct_meta,
|
|
||||||
gfx_impl_struct_meta,
|
gfx_impl_struct_meta,
|
||||||
gfx_pipeline,
|
gfx_pipeline,
|
||||||
gfx_pipeline_inner,
|
gfx_pipeline_inner,
|
||||||
|
gfx_vertex_struct_meta,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use super::{
|
use super::{
|
||||||
|
super::{Mesh, Pipeline, Quad, TgtColorFmt, TgtDepthFmt},
|
||||||
Globals,
|
Globals,
|
||||||
super::{
|
|
||||||
Pipeline,
|
|
||||||
TgtColorFmt,
|
|
||||||
TgtDepthFmt,
|
|
||||||
Mesh,
|
|
||||||
Quad,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
gfx_defines! {
|
gfx_defines! {
|
||||||
|
@ -1,24 +1,20 @@
|
|||||||
// Library
|
// Library
|
||||||
use gfx::{
|
use gfx::{
|
||||||
self,
|
self,
|
||||||
|
gfx_constant_struct_meta,
|
||||||
// Macros
|
// Macros
|
||||||
gfx_defines,
|
gfx_defines,
|
||||||
gfx_vertex_struct_meta,
|
|
||||||
gfx_constant_struct_meta,
|
|
||||||
gfx_impl_struct_meta,
|
gfx_impl_struct_meta,
|
||||||
gfx_pipeline,
|
gfx_pipeline,
|
||||||
gfx_pipeline_inner,
|
gfx_pipeline_inner,
|
||||||
|
gfx_vertex_struct_meta,
|
||||||
};
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use super::{
|
use super::{
|
||||||
|
super::{Pipeline, TgtColorFmt, TgtDepthFmt},
|
||||||
Globals,
|
Globals,
|
||||||
super::{
|
|
||||||
Pipeline,
|
|
||||||
TgtColorFmt,
|
|
||||||
TgtDepthFmt,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
gfx_defines! {
|
gfx_defines! {
|
||||||
|
@ -1,20 +1,14 @@
|
|||||||
|
use super::super::{Pipeline, Quad, TgtColorFmt, TgtDepthFmt, Tri};
|
||||||
use gfx::{
|
use gfx::{
|
||||||
self,
|
self,
|
||||||
// Macros
|
// Macros
|
||||||
gfx_defines,
|
gfx_defines,
|
||||||
gfx_vertex_struct_meta,
|
|
||||||
gfx_impl_struct_meta,
|
gfx_impl_struct_meta,
|
||||||
gfx_pipeline,
|
gfx_pipeline,
|
||||||
gfx_pipeline_inner,
|
gfx_pipeline_inner,
|
||||||
|
gfx_vertex_struct_meta,
|
||||||
};
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
use super::super::{
|
|
||||||
Pipeline,
|
|
||||||
TgtColorFmt,
|
|
||||||
TgtDepthFmt,
|
|
||||||
Quad,
|
|
||||||
Tri,
|
|
||||||
};
|
|
||||||
|
|
||||||
gfx_defines! {
|
gfx_defines! {
|
||||||
vertex Vertex {
|
vertex Vertex {
|
||||||
@ -65,20 +59,20 @@ impl Mode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_quad(rect: Aabr<f32>, uv_rect: Aabr<f32>, color: Rgba<f32>, mode: Mode) -> Quad<UiPipeline> {
|
pub fn create_quad(
|
||||||
|
rect: Aabr<f32>,
|
||||||
|
uv_rect: Aabr<f32>,
|
||||||
|
color: Rgba<f32>,
|
||||||
|
mode: Mode,
|
||||||
|
) -> Quad<UiPipeline> {
|
||||||
let mode_val = mode.value();
|
let mode_val = mode.value();
|
||||||
let v = |pos, uv| {
|
let v = |pos, uv| Vertex {
|
||||||
Vertex {
|
|
||||||
pos,
|
pos,
|
||||||
uv,
|
uv,
|
||||||
color: color.into_array(),
|
color: color.into_array(),
|
||||||
mode: mode_val,
|
mode: mode_val,
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let aabr_to_lbrt = |aabr: Aabr<f32>| (
|
let aabr_to_lbrt = |aabr: Aabr<f32>| (aabr.min.x, aabr.min.y, aabr.max.x, aabr.max.y);
|
||||||
aabr.min.x, aabr.min.y,
|
|
||||||
aabr.max.x, aabr.max.y,
|
|
||||||
);
|
|
||||||
|
|
||||||
let (l, b, r, t) = aabr_to_lbrt(rect);
|
let (l, b, r, t) = aabr_to_lbrt(rect);
|
||||||
let (uv_l, uv_b, uv_r, uv_t) = aabr_to_lbrt(uv_rect);
|
let (uv_l, uv_b, uv_r, uv_t) = aabr_to_lbrt(uv_rect);
|
||||||
@ -90,15 +84,18 @@ pub fn create_quad(rect: Aabr<f32>, uv_rect: Aabr<f32>, color: Rgba<f32>, mode:
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_tri(tri: [[f32; 2]; 3], uv_tri: [[f32; 2]; 3], color: Rgba<f32>, mode: Mode) -> Tri<UiPipeline> {
|
pub fn create_tri(
|
||||||
|
tri: [[f32; 2]; 3],
|
||||||
|
uv_tri: [[f32; 2]; 3],
|
||||||
|
color: Rgba<f32>,
|
||||||
|
mode: Mode,
|
||||||
|
) -> Tri<UiPipeline> {
|
||||||
let mode_val = mode.value();
|
let mode_val = mode.value();
|
||||||
let v = |pos, uv| {
|
let v = |pos, uv| Vertex {
|
||||||
Vertex {
|
|
||||||
pos,
|
pos,
|
||||||
uv,
|
uv,
|
||||||
color: color.into_array(),
|
color: color.into_array(),
|
||||||
mode: mode_val,
|
mode: mode_val,
|
||||||
}
|
|
||||||
};
|
};
|
||||||
Tri::new(
|
Tri::new(
|
||||||
v([tri[0][0], tri[0][1]], [uv_tri[0][0], uv_tri[0][1]]),
|
v([tri[0][0], tri[0][1]], [uv_tri[0][0], uv_tri[0][1]]),
|
||||||
|
@ -1,25 +1,18 @@
|
|||||||
use vek::*;
|
use super::{
|
||||||
|
consts::Consts,
|
||||||
|
gfx_backend,
|
||||||
|
mesh::Mesh,
|
||||||
|
model::Model,
|
||||||
|
pipelines::{figure, skybox, terrain, ui, Globals},
|
||||||
|
texture::Texture,
|
||||||
|
Pipeline, RenderError,
|
||||||
|
};
|
||||||
use gfx::{
|
use gfx::{
|
||||||
self,
|
self,
|
||||||
traits::{Device, FactoryExt},
|
traits::{Device, FactoryExt},
|
||||||
};
|
};
|
||||||
use image;
|
use image;
|
||||||
use super::{
|
use vek::*;
|
||||||
consts::Consts,
|
|
||||||
mesh::Mesh,
|
|
||||||
model::Model,
|
|
||||||
texture::Texture,
|
|
||||||
Pipeline,
|
|
||||||
RenderError,
|
|
||||||
gfx_backend,
|
|
||||||
pipelines::{
|
|
||||||
Globals,
|
|
||||||
figure,
|
|
||||||
skybox,
|
|
||||||
terrain,
|
|
||||||
ui,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Represents the format of the window's color target.
|
/// Represents the format of the window's color target.
|
||||||
pub type TgtColorFmt = gfx::format::Rgba8;
|
pub type TgtColorFmt = gfx::format::Rgba8;
|
||||||
@ -149,37 +142,30 @@ impl Renderer {
|
|||||||
pub fn update_consts<T: Copy + gfx::traits::Pod>(
|
pub fn update_consts<T: Copy + gfx::traits::Pod>(
|
||||||
&mut self,
|
&mut self,
|
||||||
consts: &mut Consts<T>,
|
consts: &mut Consts<T>,
|
||||||
vals: &[T]
|
vals: &[T],
|
||||||
) -> Result<(), RenderError> {
|
) -> Result<(), RenderError> {
|
||||||
consts.update(&mut self.encoder, vals)
|
consts.update(&mut self.encoder, vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new model from the provided mesh.
|
/// Create a new model from the provided mesh.
|
||||||
pub fn create_model<P: Pipeline>(&mut self, mesh: &Mesh<P>) -> Result<Model<P>, RenderError> {
|
pub fn create_model<P: Pipeline>(&mut self, mesh: &Mesh<P>) -> Result<Model<P>, RenderError> {
|
||||||
Ok(Model::new(
|
Ok(Model::new(&mut self.factory, mesh))
|
||||||
&mut self.factory,
|
|
||||||
mesh,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new texture from the provided image.
|
/// Create a new texture from the provided image.
|
||||||
pub fn create_texture<P: Pipeline>(&mut self, image: &image::DynamicImage) -> Result<Texture<P>, RenderError> {
|
pub fn create_texture<P: Pipeline>(
|
||||||
Texture::new(
|
&mut self,
|
||||||
&mut self.factory,
|
image: &image::DynamicImage,
|
||||||
image,
|
) -> Result<Texture<P>, RenderError> {
|
||||||
)
|
Texture::new(&mut self.factory, image)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new dynamic texture (gfx::memory::Usage::Dynamic) with the specified dimensions
|
/// Create a new dynamic texture (gfx::memory::Usage::Dynamic) with the specified dimensions
|
||||||
pub fn create_dynamic_texture<P: Pipeline>(
|
pub fn create_dynamic_texture<P: Pipeline>(
|
||||||
&mut self,
|
&mut self,
|
||||||
dims: Vec2<u16>
|
dims: Vec2<u16>,
|
||||||
) -> Result<Texture<P>, RenderError> {
|
) -> Result<Texture<P>, RenderError> {
|
||||||
Texture::new_dynamic(
|
Texture::new_dynamic(&mut self.factory, dims.x, dims.y)
|
||||||
&mut self.factory,
|
|
||||||
dims.x,
|
|
||||||
dims.y,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update a texture with the provided offset, size, and data
|
/// Update a texture with the provided offset, size, and data
|
||||||
@ -188,14 +174,9 @@ impl Renderer {
|
|||||||
texture: &Texture<P>,
|
texture: &Texture<P>,
|
||||||
offset: [u16; 2],
|
offset: [u16; 2],
|
||||||
size: [u16; 2],
|
size: [u16; 2],
|
||||||
data: &[[u8; 4]]
|
data: &[[u8; 4]],
|
||||||
) -> Result<(), RenderError> {
|
) -> Result<(), RenderError> {
|
||||||
texture.update(
|
texture.update(&mut self.encoder, offset, size, data)
|
||||||
&mut self.encoder,
|
|
||||||
offset,
|
|
||||||
size,
|
|
||||||
data,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queue the rendering of the provided skybox model in the upcoming frame.
|
/// Queue the rendering of the provided skybox model in the upcoming frame.
|
||||||
@ -273,7 +254,12 @@ impl Renderer {
|
|||||||
&self.ui_pipeline.pso,
|
&self.ui_pipeline.pso,
|
||||||
&ui::pipe::Data {
|
&ui::pipe::Data {
|
||||||
vbuf: model.vbuf.clone(),
|
vbuf: model.vbuf.clone(),
|
||||||
scissor: gfx::Rect { x: min.x, y: min.y, w: max.x - min.x, h: max.y - min.y },
|
scissor: gfx::Rect {
|
||||||
|
x: min.x,
|
||||||
|
y: min.y,
|
||||||
|
w: max.x - min.x,
|
||||||
|
h: max.y - min.y,
|
||||||
|
},
|
||||||
tex: (tex.srv.clone(), tex.sampler.clone()),
|
tex: (tex.srv.clone(), tex.sampler.clone()),
|
||||||
tgt_color: self.tgt_color_view.clone(),
|
tgt_color: self.tgt_color_view.clone(),
|
||||||
tgt_depth: self.tgt_depth_view.clone(),
|
tgt_depth: self.tgt_depth_view.clone(),
|
||||||
@ -298,7 +284,8 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>(
|
|||||||
.map_err(|err| RenderError::PipelineError(gfx::PipelineStateError::Program(err)))?;
|
.map_err(|err| RenderError::PipelineError(gfx::PipelineStateError::Program(err)))?;
|
||||||
|
|
||||||
Ok(GfxPipeline {
|
Ok(GfxPipeline {
|
||||||
pso: factory.create_pipeline_from_program(
|
pso: factory
|
||||||
|
.create_pipeline_from_program(
|
||||||
&program,
|
&program,
|
||||||
gfx::Primitive::TriangleList,
|
gfx::Primitive::TriangleList,
|
||||||
gfx::state::Rasterizer {
|
gfx::state::Rasterizer {
|
||||||
@ -311,13 +298,16 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>(
|
|||||||
pipe,
|
pipe,
|
||||||
)
|
)
|
||||||
// Do some funky things to work around an oddity in gfx's error ownership rules
|
// Do some funky things to work around an oddity in gfx's error ownership rules
|
||||||
.map_err(|err| RenderError::PipelineError(match err {
|
.map_err(|err| {
|
||||||
gfx::PipelineStateError::Program(err) =>
|
RenderError::PipelineError(match err {
|
||||||
gfx::PipelineStateError::Program(err),
|
gfx::PipelineStateError::Program(err) => gfx::PipelineStateError::Program(err),
|
||||||
gfx::PipelineStateError::DescriptorInit(err) =>
|
gfx::PipelineStateError::DescriptorInit(err) => {
|
||||||
gfx::PipelineStateError::DescriptorInit(err.into()),
|
gfx::PipelineStateError::DescriptorInit(err.into())
|
||||||
gfx::PipelineStateError::DeviceCreate(err) =>
|
}
|
||||||
gfx::PipelineStateError::DeviceCreate(err),
|
gfx::PipelineStateError::DeviceCreate(err) => {
|
||||||
}))?,
|
gfx::PipelineStateError::DeviceCreate(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2,29 +2,25 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
// Library
|
// Library
|
||||||
use gfx::{
|
use gfx::{self, traits::Factory};
|
||||||
self,
|
use image::{DynamicImage, GenericImageView};
|
||||||
traits::Factory,
|
|
||||||
};
|
|
||||||
use image::{
|
|
||||||
DynamicImage,
|
|
||||||
GenericImageView,
|
|
||||||
};
|
|
||||||
use vek::Vec2;
|
use vek::Vec2;
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use super::{
|
use super::{gfx_backend, Pipeline, RenderError};
|
||||||
RenderError,
|
|
||||||
Pipeline,
|
|
||||||
gfx_backend,
|
|
||||||
};
|
|
||||||
|
|
||||||
type ShaderFormat = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb);
|
type ShaderFormat = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb);
|
||||||
|
|
||||||
/// Represents an image that has been uploaded to the GPU.
|
/// Represents an image that has been uploaded to the GPU.
|
||||||
pub struct Texture<P: Pipeline> {
|
pub struct Texture<P: Pipeline> {
|
||||||
pub tex: gfx::handle::Texture<gfx_backend::Resources, <ShaderFormat as gfx::format::Formatted>::Surface>,
|
pub tex: gfx::handle::Texture<
|
||||||
pub srv: gfx::handle::ShaderResourceView<gfx_backend::Resources, <ShaderFormat as gfx::format::Formatted>::View>,
|
gfx_backend::Resources,
|
||||||
|
<ShaderFormat as gfx::format::Formatted>::Surface,
|
||||||
|
>,
|
||||||
|
pub srv: gfx::handle::ShaderResourceView<
|
||||||
|
gfx_backend::Resources,
|
||||||
|
<ShaderFormat as gfx::format::Formatted>::View,
|
||||||
|
>,
|
||||||
pub sampler: gfx::handle::Sampler<gfx_backend::Resources>,
|
pub sampler: gfx::handle::Sampler<gfx_backend::Resources>,
|
||||||
_phantom: PhantomData<P>,
|
_phantom: PhantomData<P>,
|
||||||
}
|
}
|
||||||
@ -34,7 +30,8 @@ impl<P: Pipeline> Texture<P> {
|
|||||||
factory: &mut gfx_backend::Factory,
|
factory: &mut gfx_backend::Factory,
|
||||||
image: &DynamicImage,
|
image: &DynamicImage,
|
||||||
) -> Result<Self, RenderError> {
|
) -> Result<Self, RenderError> {
|
||||||
let (tex, srv) = factory.create_texture_immutable_u8::<ShaderFormat>(
|
let (tex, srv) = factory
|
||||||
|
.create_texture_immutable_u8::<ShaderFormat>(
|
||||||
gfx::texture::Kind::D2(
|
gfx::texture::Kind::D2(
|
||||||
image.width() as u16,
|
image.width() as u16,
|
||||||
image.height() as u16,
|
image.height() as u16,
|
||||||
@ -73,8 +70,12 @@ impl<P: Pipeline> Texture<P> {
|
|||||||
)
|
)
|
||||||
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?;
|
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?;
|
||||||
|
|
||||||
let srv =
|
let srv = factory
|
||||||
factory.view_texture_as_shader_resource::<ShaderFormat>(&tex, (0, 0), gfx::format::Swizzle::new())
|
.view_texture_as_shader_resource::<ShaderFormat>(
|
||||||
|
&tex,
|
||||||
|
(0, 0),
|
||||||
|
gfx::format::Swizzle::new(),
|
||||||
|
)
|
||||||
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Resource(err)))?;
|
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Resource(err)))?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@ -107,7 +108,9 @@ impl<P: Pipeline> Texture<P> {
|
|||||||
mipmap: 0,
|
mipmap: 0,
|
||||||
};
|
};
|
||||||
encoder
|
encoder
|
||||||
.update_texture::<<ShaderFormat as gfx::format::Formatted>::Surface, ShaderFormat>(&self.tex, None, info, data)
|
.update_texture::<<ShaderFormat as gfx::format::Formatted>::Surface, ShaderFormat>(
|
||||||
|
&self.tex, None, info, data,
|
||||||
|
)
|
||||||
.map_err(|err| RenderError::TexUpdateError(err))
|
.map_err(|err| RenderError::TexUpdateError(err))
|
||||||
}
|
}
|
||||||
/// Get dimensions of the represented image
|
/// Get dimensions of the represented image
|
||||||
|
@ -38,12 +38,7 @@ impl Camera {
|
|||||||
* Mat4::rotation_3d(PI / 2.0, -Vec4::unit_x())
|
* Mat4::rotation_3d(PI / 2.0, -Vec4::unit_x())
|
||||||
* Mat4::translation_3d(-self.focus);
|
* Mat4::translation_3d(-self.focus);
|
||||||
|
|
||||||
let proj_mat = Mat4::perspective_rh_no(
|
let proj_mat = Mat4::perspective_rh_no(self.fov, self.aspect, NEAR_PLANE, FAR_PLANE);
|
||||||
self.fov,
|
|
||||||
self.aspect,
|
|
||||||
NEAR_PLANE,
|
|
||||||
FAR_PLANE,
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: Make this more efficient
|
// TODO: Make this more efficient
|
||||||
let cam_pos = Vec3::from(view_mat.inverted() * Vec4::unit_w());
|
let cam_pos = Vec3::from(view_mat.inverted() * Vec4::unit_w());
|
||||||
@ -56,9 +51,7 @@ impl Camera {
|
|||||||
// Wrap camera yaw
|
// Wrap camera yaw
|
||||||
self.ori.x = (self.ori.x + delta.x) % (2.0 * PI);
|
self.ori.x = (self.ori.x + delta.x) % (2.0 * PI);
|
||||||
// Clamp camera pitch to the vertical limits
|
// Clamp camera pitch to the vertical limits
|
||||||
self.ori.y = (self.ori.y + delta.y)
|
self.ori.y = (self.ori.y + delta.y).min(PI / 2.0).max(-PI / 2.0);
|
||||||
.min(PI / 2.0)
|
|
||||||
.max(-PI / 2.0);
|
|
||||||
// Wrap camera roll
|
// Wrap camera roll
|
||||||
self.ori.z = (self.ori.z + delta.z) % (2.0 * PI);
|
self.ori.z = (self.ori.z + delta.z) % (2.0 * PI);
|
||||||
}
|
}
|
||||||
@ -70,15 +63,25 @@ impl Camera {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the focus position of the camera.
|
/// Get the focus position of the camera.
|
||||||
pub fn get_focus_pos(&self) -> Vec3<f32> { self.focus }
|
pub fn get_focus_pos(&self) -> Vec3<f32> {
|
||||||
|
self.focus
|
||||||
|
}
|
||||||
/// Set the focus position of the camera.
|
/// Set the focus position of the camera.
|
||||||
pub fn set_focus_pos(&mut self, focus: Vec3<f32>) { self.focus = focus; }
|
pub fn set_focus_pos(&mut self, focus: Vec3<f32>) {
|
||||||
|
self.focus = focus;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the aspect ratio of the camera.
|
/// Get the aspect ratio of the camera.
|
||||||
pub fn get_aspect_ratio(&self) -> f32 { self.aspect }
|
pub fn get_aspect_ratio(&self) -> f32 {
|
||||||
|
self.aspect
|
||||||
|
}
|
||||||
/// Set the aspect ratio of the camera.
|
/// Set the aspect ratio of the camera.
|
||||||
pub fn set_aspect_ratio(&mut self, aspect: f32) { self.aspect = aspect; }
|
pub fn set_aspect_ratio(&mut self, aspect: f32) {
|
||||||
|
self.aspect = aspect;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the orientation of the camera
|
/// Get the orientation of the camera
|
||||||
pub fn get_orientation(&self) -> Vec3<f32> { self.ori }
|
pub fn get_orientation(&self) -> Vec3<f32> {
|
||||||
|
self.ori
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,51 +1,27 @@
|
|||||||
use std::{
|
use crate::{
|
||||||
collections::HashMap,
|
anim::{
|
||||||
f32,
|
character::{CharacterSkeleton, IdleAnimation, RunAnimation},
|
||||||
|
Animation, Skeleton,
|
||||||
|
},
|
||||||
|
mesh::Meshable,
|
||||||
|
render::{
|
||||||
|
Consts, FigureBoneData, FigureLocals, FigurePipeline, Globals, Mesh, Model, Renderer,
|
||||||
|
},
|
||||||
|
Error,
|
||||||
};
|
};
|
||||||
use specs::{Entity as EcsEntity, Component, VecStorage, Join};
|
|
||||||
use vek::*;
|
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use common::{
|
use common::{
|
||||||
|
assets,
|
||||||
comp::{
|
comp::{
|
||||||
self,
|
self,
|
||||||
character::{
|
character::{Belt, Character, Chest, Foot, Hand, Head, Pants, Weapon},
|
||||||
Character,
|
|
||||||
Head,
|
|
||||||
Chest,
|
|
||||||
Belt,
|
|
||||||
Pants,
|
|
||||||
Hand,
|
|
||||||
Foot,
|
|
||||||
Weapon,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
figure::Segment,
|
figure::Segment,
|
||||||
msg,
|
msg,
|
||||||
assets,
|
|
||||||
};
|
|
||||||
use crate::{
|
|
||||||
Error,
|
|
||||||
render::{
|
|
||||||
Consts,
|
|
||||||
Globals,
|
|
||||||
Mesh,
|
|
||||||
Model,
|
|
||||||
Renderer,
|
|
||||||
FigurePipeline,
|
|
||||||
FigureBoneData,
|
|
||||||
FigureLocals,
|
|
||||||
},
|
|
||||||
anim::{
|
|
||||||
Animation,
|
|
||||||
Skeleton,
|
|
||||||
character::{
|
|
||||||
CharacterSkeleton,
|
|
||||||
RunAnimation,
|
|
||||||
IdleAnimation,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mesh::Meshable,
|
|
||||||
};
|
};
|
||||||
|
use specs::{Component, Entity as EcsEntity, Join, VecStorage};
|
||||||
|
use std::{collections::HashMap, f32};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
pub struct FigureCache {
|
pub struct FigureCache {
|
||||||
models: HashMap<Character, (Model<FigurePipeline>, u64)>,
|
models: HashMap<Character, (Model<FigurePipeline>, u64)>,
|
||||||
@ -64,14 +40,17 @@ impl FigureCache {
|
|||||||
models: &'a mut HashMap<Character, (Model<FigurePipeline>, u64)>,
|
models: &'a mut HashMap<Character, (Model<FigurePipeline>, u64)>,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
tick: u64,
|
tick: u64,
|
||||||
character: Character)
|
character: Character,
|
||||||
-> &'a (Model<FigurePipeline>, u64) {
|
) -> &'a (Model<FigurePipeline>, u64) {
|
||||||
match models.get_mut(&character) {
|
match models.get_mut(&character) {
|
||||||
Some((model, last_used)) => {
|
Some((model, last_used)) => {
|
||||||
*last_used = tick;
|
*last_used = tick;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
models.insert(character, ({
|
models.insert(
|
||||||
|
character,
|
||||||
|
(
|
||||||
|
{
|
||||||
let bone_meshes = [
|
let bone_meshes = [
|
||||||
Some(Self::load_head(character.head)),
|
Some(Self::load_head(character.head)),
|
||||||
Some(Self::load_chest(character.chest)),
|
Some(Self::load_chest(character.chest)),
|
||||||
@ -91,18 +70,22 @@ impl FigureCache {
|
|||||||
None,
|
None,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
let mut mesh = Mesh::new();
|
let mut mesh = Mesh::new();
|
||||||
bone_meshes
|
bone_meshes
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm)))
|
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm)))
|
||||||
.for_each(|(i, bone_mesh)| {
|
.for_each(|(i, bone_mesh)| {
|
||||||
mesh.push_mesh_map(bone_mesh, |vert| vert.with_bone_idx(i as u8))
|
mesh.push_mesh_map(bone_mesh, |vert| {
|
||||||
|
vert.with_bone_idx(i as u8)
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
renderer.create_model(&mesh).unwrap()
|
renderer.create_model(&mesh).unwrap()
|
||||||
}, tick));
|
},
|
||||||
|
tick,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,76 +94,106 @@ impl FigureCache {
|
|||||||
|
|
||||||
pub fn clean(&mut self, tick: u64) {
|
pub fn clean(&mut self, tick: u64) {
|
||||||
// TODO: Don't hard-code this
|
// TODO: Don't hard-code this
|
||||||
self.models.retain(|_, (_, last_used)| *last_used + 60 > tick);
|
self.models
|
||||||
|
.retain(|_, (_, last_used)| *last_used + 60 > tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_mesh(filename: &'static str, position: Vec3<f32>) -> Mesh<FigurePipeline> {
|
fn load_mesh(filename: &'static str, position: Vec3<f32>) -> Mesh<FigurePipeline> {
|
||||||
let fullpath: String = ["/voxygen/voxel/", filename].concat();
|
let fullpath: String = ["/voxygen/voxel/", filename].concat();
|
||||||
Segment::from(dot_vox::load_bytes(
|
Segment::from(
|
||||||
|
dot_vox::load_bytes(
|
||||||
assets::load(fullpath.as_str())
|
assets::load(fullpath.as_str())
|
||||||
.expect("Error loading file")
|
.expect("Error loading file")
|
||||||
.as_slice(),
|
.as_slice(),
|
||||||
).unwrap())
|
)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
.generate_mesh(position)
|
.generate_mesh(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_head(head: Head) -> Mesh<FigurePipeline> {
|
fn load_head(head: Head) -> Mesh<FigurePipeline> {
|
||||||
Self::load_mesh(match head {
|
Self::load_mesh(
|
||||||
|
match head {
|
||||||
Head::DefaultHead => "head.vox",
|
Head::DefaultHead => "head.vox",
|
||||||
}, Vec3::new(-5.5, -7.0, -6.0))
|
},
|
||||||
|
Vec3::new(-5.5, -7.0, -6.0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_chest(chest: Chest) -> Mesh<FigurePipeline> {
|
fn load_chest(chest: Chest) -> Mesh<FigurePipeline> {
|
||||||
Self::load_mesh(match chest {
|
Self::load_mesh(
|
||||||
|
match chest {
|
||||||
Chest::DefaultChest => "chest.vox",
|
Chest::DefaultChest => "chest.vox",
|
||||||
}, Vec3::new(-2.5, -6.0, 0.0))
|
},
|
||||||
|
Vec3::new(-2.5, -6.0, 0.0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_belt(belt: Belt) -> Mesh<FigurePipeline> {
|
fn load_belt(belt: Belt) -> Mesh<FigurePipeline> {
|
||||||
Self::load_mesh(match belt {
|
Self::load_mesh(
|
||||||
|
match belt {
|
||||||
Belt::DefaultBelt => "belt.vox",
|
Belt::DefaultBelt => "belt.vox",
|
||||||
}, Vec3::new(-2.5, -5.0, 0.0))
|
},
|
||||||
|
Vec3::new(-2.5, -5.0, 0.0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_pants(pants: Pants) -> Mesh<FigurePipeline> {
|
fn load_pants(pants: Pants) -> Mesh<FigurePipeline> {
|
||||||
Self::load_mesh(match pants {
|
Self::load_mesh(
|
||||||
|
match pants {
|
||||||
Pants::DefaultPants => "pants.vox",
|
Pants::DefaultPants => "pants.vox",
|
||||||
}, Vec3::new(-2.5, -5.0, 0.0))
|
},
|
||||||
|
Vec3::new(-2.5, -5.0, 0.0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_left_hand(hand: Hand) -> Mesh<FigurePipeline> {
|
fn load_left_hand(hand: Hand) -> Mesh<FigurePipeline> {
|
||||||
Self::load_mesh(match hand {
|
Self::load_mesh(
|
||||||
|
match hand {
|
||||||
Hand::DefaultHand => "hand.vox",
|
Hand::DefaultHand => "hand.vox",
|
||||||
}, Vec3::new(0.0, -2.0, -7.0))
|
},
|
||||||
|
Vec3::new(0.0, -2.0, -7.0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_right_hand(hand: Hand) -> Mesh<FigurePipeline> {
|
fn load_right_hand(hand: Hand) -> Mesh<FigurePipeline> {
|
||||||
Self::load_mesh(match hand {
|
Self::load_mesh(
|
||||||
|
match hand {
|
||||||
Hand::DefaultHand => "hand.vox",
|
Hand::DefaultHand => "hand.vox",
|
||||||
}, Vec3::new(0.0, -2.0, -7.0))
|
},
|
||||||
|
Vec3::new(0.0, -2.0, -7.0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_left_foot(foot: Foot) -> Mesh<FigurePipeline> {
|
fn load_left_foot(foot: Foot) -> Mesh<FigurePipeline> {
|
||||||
Self::load_mesh(match foot {
|
Self::load_mesh(
|
||||||
|
match foot {
|
||||||
Foot::DefaultFoot => "foot.vox",
|
Foot::DefaultFoot => "foot.vox",
|
||||||
}, Vec3::new(-3.5, -2.5, -8.0))
|
},
|
||||||
|
Vec3::new(-3.5, -2.5, -8.0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_right_foot(foot: Foot) -> Mesh<FigurePipeline> {
|
fn load_right_foot(foot: Foot) -> Mesh<FigurePipeline> {
|
||||||
Self::load_mesh(match foot {
|
Self::load_mesh(
|
||||||
|
match foot {
|
||||||
Foot::DefaultFoot => "foot.vox",
|
Foot::DefaultFoot => "foot.vox",
|
||||||
}, Vec3::new(-3.5, -2.5, -8.0))
|
},
|
||||||
|
Vec3::new(-3.5, -2.5, -8.0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_weapon(weapon: Weapon) -> Mesh<FigurePipeline> {
|
fn load_weapon(weapon: Weapon) -> Mesh<FigurePipeline> {
|
||||||
Self::load_mesh(match weapon {
|
Self::load_mesh(
|
||||||
|
match weapon {
|
||||||
Weapon::Sword => "sword.vox",
|
Weapon::Sword => "sword.vox",
|
||||||
// TODO actually match against other weapons and set the right model
|
// TODO actually match against other weapons and set the right model
|
||||||
_ => "sword.vox",
|
_ => "sword.vox",
|
||||||
}, Vec3::new(0.0, 0.0, -4.0))
|
},
|
||||||
|
Vec3::new(0.0, 0.0, -4.0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) {
|
pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) {
|
||||||
let time = client.state().get_time();
|
let time = client.state().get_time();
|
||||||
let ecs = client.state_mut().ecs_mut();
|
let ecs = client.state_mut().ecs_mut();
|
||||||
@ -190,14 +203,21 @@ impl FigureCache {
|
|||||||
&ecs.read_storage::<comp::phys::Dir>(),
|
&ecs.read_storage::<comp::phys::Dir>(),
|
||||||
&ecs.read_storage::<comp::Character>(),
|
&ecs.read_storage::<comp::Character>(),
|
||||||
&ecs.read_storage::<comp::AnimationHistory>(),
|
&ecs.read_storage::<comp::AnimationHistory>(),
|
||||||
).join() {
|
)
|
||||||
let state = self.states
|
.join()
|
||||||
|
{
|
||||||
|
let state = self
|
||||||
|
.states
|
||||||
.entry(entity)
|
.entry(entity)
|
||||||
.or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
|
.or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
|
||||||
|
|
||||||
let target_skeleton = match animation_history.current {
|
let target_skeleton = match animation_history.current {
|
||||||
comp::character::Animation::Idle => IdleAnimation::update_skeleton(&mut state.skeleton, time),
|
comp::character::Animation::Idle => {
|
||||||
comp::character::Animation::Run => RunAnimation::update_skeleton(&mut state.skeleton, time),
|
IdleAnimation::update_skeleton(&mut state.skeleton, time)
|
||||||
|
}
|
||||||
|
comp::character::Animation::Run => {
|
||||||
|
RunAnimation::update_skeleton(&mut state.skeleton, time)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
state.skeleton.interpolate(&target_skeleton);
|
state.skeleton.interpolate(&target_skeleton);
|
||||||
@ -205,26 +225,25 @@ impl FigureCache {
|
|||||||
state.update(renderer, pos.0, dir.0);
|
state.update(renderer, pos.0, dir.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.states.retain(|entity, _| ecs.entities().is_alive(*entity));
|
self.states
|
||||||
|
.retain(|entity, _| ecs.entities().is_alive(*entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client, globals: &Consts<Globals>) {
|
pub fn render(
|
||||||
|
&mut self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
client: &mut Client,
|
||||||
|
globals: &Consts<Globals>,
|
||||||
|
) {
|
||||||
let tick = client.get_tick();
|
let tick = client.get_tick();
|
||||||
let ecs = client.state().ecs();
|
let ecs = client.state().ecs();
|
||||||
let models = &mut self.models;
|
let models = &mut self.models;
|
||||||
|
|
||||||
for (entity, &character) in (
|
for (entity, &character) in (&ecs.entities(), &ecs.read_storage::<comp::Character>()).join()
|
||||||
&ecs.entities(),
|
{
|
||||||
&ecs.read_storage::<comp::Character>(),
|
|
||||||
).join() {
|
|
||||||
let model = Self::get_or_create_model(models, renderer, tick, character);
|
let model = Self::get_or_create_model(models, renderer, tick, character);
|
||||||
let state = self.states.get(&entity).unwrap();
|
let state = self.states.get(&entity).unwrap();
|
||||||
renderer.render_figure(
|
renderer.render_figure(&model.0, globals, &state.locals, &state.bone_consts);
|
||||||
&model.0,
|
|
||||||
globals,
|
|
||||||
&state.locals,
|
|
||||||
&state.bone_consts,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,21 +257,24 @@ pub struct FigureState<S: Skeleton> {
|
|||||||
impl<S: Skeleton> FigureState<S> {
|
impl<S: Skeleton> FigureState<S> {
|
||||||
pub fn new(renderer: &mut Renderer, skeleton: S) -> Self {
|
pub fn new(renderer: &mut Renderer, skeleton: S) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bone_consts: renderer.create_consts(&skeleton.compute_matrices()).unwrap(),
|
bone_consts: renderer
|
||||||
|
.create_consts(&skeleton.compute_matrices())
|
||||||
|
.unwrap(),
|
||||||
locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(),
|
locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(),
|
||||||
skeleton,
|
skeleton,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, renderer: &mut Renderer, pos: Vec3<f32>, dir: Vec3<f32>) {
|
fn update(&mut self, renderer: &mut Renderer, pos: Vec3<f32>, dir: Vec3<f32>) {
|
||||||
let mat =
|
let mat = Mat4::<f32>::identity()
|
||||||
Mat4::<f32>::identity() *
|
* Mat4::translation_3d(pos)
|
||||||
Mat4::translation_3d(pos) *
|
* Mat4::rotation_z(-dir.x.atan2(dir.y) + f32::consts::PI / 2.0);
|
||||||
Mat4::rotation_z(-dir.x.atan2(dir.y) + f32::consts::PI / 2.0);
|
|
||||||
|
|
||||||
let locals = FigureLocals::new(mat);
|
let locals = FigureLocals::new(mat);
|
||||||
renderer.update_consts(&mut self.locals, &[locals]).unwrap();
|
renderer.update_consts(&mut self.locals, &[locals]).unwrap();
|
||||||
|
|
||||||
renderer.update_consts(&mut self.bone_consts, &self.skeleton.compute_matrices()).unwrap();
|
renderer
|
||||||
|
.update_consts(&mut self.bone_consts, &self.skeleton.compute_matrices())
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,35 +2,23 @@ pub mod camera;
|
|||||||
pub mod figure;
|
pub mod figure;
|
||||||
pub mod terrain;
|
pub mod terrain;
|
||||||
|
|
||||||
use vek::*;
|
use self::{camera::Camera, figure::FigureCache, terrain::Terrain};
|
||||||
use dot_vox;
|
|
||||||
use common::{
|
|
||||||
comp,
|
|
||||||
figure::Segment,
|
|
||||||
};
|
|
||||||
use client::Client;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
anim::{
|
||||||
|
character::{CharacterSkeleton, RunAnimation},
|
||||||
|
Animation,
|
||||||
|
},
|
||||||
|
mesh::Meshable,
|
||||||
render::{
|
render::{
|
||||||
Consts,
|
create_skybox_mesh, Consts, FigureLocals, Globals, Model, Renderer, SkyboxLocals,
|
||||||
Globals,
|
|
||||||
Model,
|
|
||||||
Renderer,
|
|
||||||
SkyboxPipeline,
|
SkyboxPipeline,
|
||||||
SkyboxLocals,
|
|
||||||
FigureLocals,
|
|
||||||
create_skybox_mesh,
|
|
||||||
},
|
},
|
||||||
window::Event,
|
window::Event,
|
||||||
mesh::Meshable, anim::{
|
|
||||||
Animation,
|
|
||||||
character::{CharacterSkeleton, RunAnimation},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use self::{
|
|
||||||
camera::Camera,
|
|
||||||
figure::FigureCache,
|
|
||||||
terrain::Terrain,
|
|
||||||
};
|
};
|
||||||
|
use client::Client;
|
||||||
|
use common::{comp, figure::Segment};
|
||||||
|
use dot_vox;
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
// TODO: Don't hard-code this
|
// TODO: Don't hard-code this
|
||||||
const CURSOR_PAN_SCALE: f32 = 0.005;
|
const CURSOR_PAN_SCALE: f32 = 0.005;
|
||||||
@ -56,18 +44,12 @@ impl Scene {
|
|||||||
let resolution = renderer.get_resolution().map(|e| e as f32);
|
let resolution = renderer.get_resolution().map(|e| e as f32);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
globals: renderer
|
globals: renderer.create_consts(&[Globals::default()]).unwrap(),
|
||||||
.create_consts(&[Globals::default()])
|
|
||||||
.unwrap(),
|
|
||||||
camera: Camera::new(resolution.x / resolution.y),
|
camera: Camera::new(resolution.x / resolution.y),
|
||||||
|
|
||||||
skybox: Skybox {
|
skybox: Skybox {
|
||||||
model: renderer
|
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
|
||||||
.create_model(&create_skybox_mesh())
|
locals: renderer.create_consts(&[SkyboxLocals::default()]).unwrap(),
|
||||||
.unwrap(),
|
|
||||||
locals: renderer
|
|
||||||
.create_consts(&[SkyboxLocals::default()])
|
|
||||||
.unwrap(),
|
|
||||||
},
|
},
|
||||||
terrain: Terrain::new(),
|
terrain: Terrain::new(),
|
||||||
figure_cache: FigureCache::new(),
|
figure_cache: FigureCache::new(),
|
||||||
@ -75,10 +57,14 @@ impl Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to the scene's camera.
|
/// Get a reference to the scene's camera.
|
||||||
pub fn camera(&self) -> &Camera { &self.camera }
|
pub fn camera(&self) -> &Camera {
|
||||||
|
&self.camera
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a mutable reference to the scene's camera.
|
/// Get a mutable reference to the scene's camera.
|
||||||
pub fn camera_mut(&mut self) -> &mut Camera { &mut self.camera }
|
pub fn camera_mut(&mut self) -> &mut Camera {
|
||||||
|
&mut self.camera
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle an incoming user input event (i.e: cursor moved, key pressed, window closed, etc.).
|
/// Handle an incoming user input event (i.e: cursor moved, key pressed, window closed, etc.).
|
||||||
///
|
///
|
||||||
@ -89,17 +75,17 @@ impl Scene {
|
|||||||
Event::Resize(dims) => {
|
Event::Resize(dims) => {
|
||||||
self.camera.set_aspect_ratio(dims.x as f32 / dims.y as f32);
|
self.camera.set_aspect_ratio(dims.x as f32 / dims.y as f32);
|
||||||
true
|
true
|
||||||
},
|
}
|
||||||
// Panning the cursor makes the camera rotate
|
// Panning the cursor makes the camera rotate
|
||||||
Event::CursorPan(delta) => {
|
Event::CursorPan(delta) => {
|
||||||
self.camera.rotate_by(Vec3::from(delta) * CURSOR_PAN_SCALE);
|
self.camera.rotate_by(Vec3::from(delta) * CURSOR_PAN_SCALE);
|
||||||
true
|
true
|
||||||
},
|
}
|
||||||
// Zoom the camera when a zoom event occurs
|
// Zoom the camera when a zoom event occurs
|
||||||
Event::Zoom(delta) => {
|
Event::Zoom(delta) => {
|
||||||
self.camera.zoom_by(delta * 0.3);
|
self.camera.zoom_by(delta * 0.3);
|
||||||
true
|
true
|
||||||
},
|
}
|
||||||
// All other events are unhandled
|
// All other events are unhandled
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@ -123,7 +109,10 @@ impl Scene {
|
|||||||
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents();
|
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents();
|
||||||
|
|
||||||
// Update global constants
|
// Update global constants
|
||||||
renderer.update_consts(&mut self.globals, &[Globals::new(
|
renderer
|
||||||
|
.update_consts(
|
||||||
|
&mut self.globals,
|
||||||
|
&[Globals::new(
|
||||||
view_mat,
|
view_mat,
|
||||||
proj_mat,
|
proj_mat,
|
||||||
cam_pos,
|
cam_pos,
|
||||||
@ -131,7 +120,8 @@ impl Scene {
|
|||||||
10.0,
|
10.0,
|
||||||
client.state().get_time_of_day(),
|
client.state().get_time_of_day(),
|
||||||
client.state().get_time(),
|
client.state().get_time(),
|
||||||
)])
|
)],
|
||||||
|
)
|
||||||
.expect("Failed to update global constants");
|
.expect("Failed to update global constants");
|
||||||
|
|
||||||
// Maintain the terrain
|
// Maintain the terrain
|
||||||
@ -147,11 +137,7 @@ impl Scene {
|
|||||||
/// Render the scene using the provided `Renderer`
|
/// Render the scene using the provided `Renderer`
|
||||||
pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client) {
|
pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client) {
|
||||||
// Render the skybox first (it appears over everything else so must be rendered first)
|
// Render the skybox first (it appears over everything else so must be rendered first)
|
||||||
renderer.render_skybox(
|
renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
|
||||||
&self.skybox.model,
|
|
||||||
&self.globals,
|
|
||||||
&self.skybox.locals,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Render terrain and figures
|
// Render terrain and figures
|
||||||
self.terrain.render(renderer, &self.globals);
|
self.terrain.render(renderer, &self.globals);
|
||||||
|
@ -10,24 +10,12 @@ use vek::*;
|
|||||||
|
|
||||||
// Project
|
// Project
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use common::{
|
use common::{terrain::TerrainMap, vol::SampleVol, volumes::vol_map::VolMapErr};
|
||||||
terrain::TerrainMap,
|
|
||||||
volumes::vol_map::VolMapErr,
|
|
||||||
vol::SampleVol,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::{
|
use crate::{
|
||||||
render::{
|
|
||||||
Consts,
|
|
||||||
Globals,
|
|
||||||
Mesh,
|
|
||||||
Model,
|
|
||||||
Renderer,
|
|
||||||
TerrainPipeline,
|
|
||||||
TerrainLocals,
|
|
||||||
},
|
|
||||||
mesh::Meshable,
|
mesh::Meshable,
|
||||||
|
render::{Consts, Globals, Mesh, Model, Renderer, TerrainLocals, TerrainPipeline},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TerrainChunk {
|
struct TerrainChunk {
|
||||||
@ -92,7 +80,11 @@ impl Terrain {
|
|||||||
let current_tick = client.get_tick();
|
let current_tick = client.get_tick();
|
||||||
|
|
||||||
// Add any recently created or changed chunks to the list of chunks to be meshed
|
// Add any recently created or changed chunks to the list of chunks to be meshed
|
||||||
for pos in client.state().changes().new_chunks.iter()
|
for pos in client
|
||||||
|
.state()
|
||||||
|
.changes()
|
||||||
|
.new_chunks
|
||||||
|
.iter()
|
||||||
.chain(client.state().changes().changed_chunks.iter())
|
.chain(client.state().changes().changed_chunks.iter())
|
||||||
{
|
{
|
||||||
// TODO: ANOTHER PROBLEM HERE!
|
// TODO: ANOTHER PROBLEM HERE!
|
||||||
@ -139,8 +131,12 @@ impl Terrain {
|
|||||||
// ambient occlusion and edge elision, we also need to borders of the chunk's
|
// ambient occlusion and edge elision, we also need to borders of the chunk's
|
||||||
// neighbours too (hence the `- 1` and `+ 1`).
|
// neighbours too (hence the `- 1` and `+ 1`).
|
||||||
let aabb = Aabb {
|
let aabb = Aabb {
|
||||||
min: todo.pos.map2(TerrainMap::chunk_size(), |e, sz| e * sz as i32 - 1),
|
min: todo
|
||||||
max: todo.pos.map2(TerrainMap::chunk_size(), |e, sz| (e + 1) * sz as i32 + 1),
|
.pos
|
||||||
|
.map2(TerrainMap::chunk_size(), |e, sz| e * sz as i32 - 1),
|
||||||
|
max: todo
|
||||||
|
.pos
|
||||||
|
.map2(TerrainMap::chunk_size(), |e, sz| (e + 1) * sz as i32 + 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Copy out the chunk data we need to perform the meshing. We do this by taking a
|
// Copy out the chunk data we need to perform the meshing. We do this by taking a
|
||||||
@ -173,27 +169,35 @@ impl Terrain {
|
|||||||
// It's the mesh we want, insert the newly finished model into the terrain model
|
// It's the mesh we want, insert the newly finished model into the terrain model
|
||||||
// data structure (convert the mesh to a model first of course)
|
// data structure (convert the mesh to a model first of course)
|
||||||
Some(todo) if response.started_tick == todo.started_tick => {
|
Some(todo) if response.started_tick == todo.started_tick => {
|
||||||
self.chunks.insert(response.pos, TerrainChunk {
|
self.chunks.insert(
|
||||||
model: renderer.create_model(&response.mesh).expect("Failed to upload chunk mesh to the GPU"),
|
response.pos,
|
||||||
locals: renderer.create_consts(&[TerrainLocals {
|
TerrainChunk {
|
||||||
model_offs: response.pos.map2(TerrainMap::chunk_size(), |e, sz| e as f32 * sz as f32).into_array(),
|
model: renderer
|
||||||
}]).expect("Failed to upload chunk locals to the GPU"),
|
.create_model(&response.mesh)
|
||||||
});
|
.expect("Failed to upload chunk mesh to the GPU"),
|
||||||
|
locals: renderer
|
||||||
|
.create_consts(&[TerrainLocals {
|
||||||
|
model_offs: response
|
||||||
|
.pos
|
||||||
|
.map2(TerrainMap::chunk_size(), |e, sz| {
|
||||||
|
e as f32 * sz as f32
|
||||||
|
})
|
||||||
|
.into_array(),
|
||||||
|
}])
|
||||||
|
.expect("Failed to upload chunk locals to the GPU"),
|
||||||
},
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
// Chunk must have been removed, or it was spawned on an old tick. Drop the mesh
|
// Chunk must have been removed, or it was spawned on an old tick. Drop the mesh
|
||||||
// since it's either out of date or no longer needed
|
// since it's either out of date or no longer needed
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) {
|
pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) {
|
||||||
for (_, chunk) in &self.chunks {
|
for (_, chunk) in &self.chunks {
|
||||||
renderer.render_terrain_chunk(
|
renderer.render_terrain_chunk(&chunk.model, globals, &chunk.locals);
|
||||||
&chunk.model,
|
|
||||||
globals,
|
|
||||||
&chunk.locals,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,15 @@
|
|||||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
|
||||||
use vek::*;
|
|
||||||
use common::clock::Clock;
|
|
||||||
use client::{
|
|
||||||
self,
|
|
||||||
Client,
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Direction,
|
hud::{Event as HudEvent, Hud},
|
||||||
Error,
|
|
||||||
PlayState,
|
|
||||||
PlayStateResult,
|
|
||||||
GlobalState,
|
|
||||||
key_state::KeyState,
|
key_state::KeyState,
|
||||||
window::{Event, Key, Window},
|
|
||||||
render::Renderer,
|
render::Renderer,
|
||||||
scene::Scene,
|
scene::Scene,
|
||||||
hud::{Hud, Event as HudEvent},
|
window::{Event, Key, Window},
|
||||||
|
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
||||||
};
|
};
|
||||||
|
use client::{self, Client};
|
||||||
|
use common::clock::Clock;
|
||||||
|
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
const FPS: u64 = 60;
|
const FPS: u64 = 60;
|
||||||
|
|
||||||
@ -27,7 +20,6 @@ pub struct SessionState {
|
|||||||
hud: Hud,
|
hud: Hud,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Represents an active game session (i.e: one that is being played)
|
/// Represents an active game session (i.e: one that is being played)
|
||||||
impl SessionState {
|
impl SessionState {
|
||||||
/// Create a new `SessionState`
|
/// Create a new `SessionState`
|
||||||
@ -43,7 +35,6 @@ impl SessionState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The background colour
|
// The background colour
|
||||||
const BG_COLOR: Rgba<f32> = Rgba {
|
const BG_COLOR: Rgba<f32> = Rgba {
|
||||||
r: 0.0,
|
r: 0.0,
|
||||||
@ -64,7 +55,11 @@ impl SessionState {
|
|||||||
let dir_vec = self.key_state.dir_vec();
|
let dir_vec = self.key_state.dir_vec();
|
||||||
let move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1];
|
let move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1];
|
||||||
|
|
||||||
for event in self.client.borrow_mut().tick(client::Input { move_dir }, dt)? {
|
for event in self
|
||||||
|
.client
|
||||||
|
.borrow_mut()
|
||||||
|
.tick(client::Input { move_dir }, dt)?
|
||||||
|
{
|
||||||
match event {
|
match event {
|
||||||
client::Event::Chat(msg) => {
|
client::Event::Chat(msg) => {
|
||||||
self.hud.new_message(msg);
|
self.hud.new_message(msg);
|
||||||
@ -123,7 +118,6 @@ impl PlayState for SessionState {
|
|||||||
loop {
|
loop {
|
||||||
// Handle window events
|
// Handle window events
|
||||||
for event in global_state.window.fetch_events() {
|
for event in global_state.window.fetch_events() {
|
||||||
|
|
||||||
// Pass all events to the ui first
|
// Pass all events to the ui first
|
||||||
if self.hud.handle_event(event.clone(), global_state) {
|
if self.hud.handle_event(event.clone(), global_state) {
|
||||||
continue;
|
continue;
|
||||||
@ -131,7 +125,7 @@ impl PlayState for SessionState {
|
|||||||
let _handled = match event {
|
let _handled = match event {
|
||||||
Event::Close => {
|
Event::Close => {
|
||||||
return PlayStateResult::Shutdown;
|
return PlayStateResult::Shutdown;
|
||||||
},
|
}
|
||||||
// Toggle cursor grabbing
|
// Toggle cursor grabbing
|
||||||
Event::KeyDown(Key::ToggleCursor) => {
|
Event::KeyDown(Key::ToggleCursor) => {
|
||||||
global_state
|
global_state
|
||||||
@ -161,18 +155,24 @@ impl PlayState for SessionState {
|
|||||||
.expect("Failed to tick the scene");
|
.expect("Failed to tick the scene");
|
||||||
|
|
||||||
// Maintain the scene
|
// Maintain the scene
|
||||||
self.scene.maintain(global_state.window.renderer_mut(), &mut self.client.borrow_mut());
|
self.scene.maintain(
|
||||||
|
global_state.window.renderer_mut(),
|
||||||
|
&mut self.client.borrow_mut(),
|
||||||
|
);
|
||||||
// Maintain the UI
|
// Maintain the UI
|
||||||
for event in self.hud.maintain(global_state.window.renderer_mut(), clock.get_tps()) {
|
for event in self
|
||||||
|
.hud
|
||||||
|
.maintain(global_state.window.renderer_mut(), clock.get_tps())
|
||||||
|
{
|
||||||
match event {
|
match event {
|
||||||
HudEvent::SendMessage(msg) => {
|
HudEvent::SendMessage(msg) => {
|
||||||
// TODO: Handle result
|
// TODO: Handle result
|
||||||
self.client.borrow_mut().send_chat(msg);
|
self.client.borrow_mut().send_chat(msg);
|
||||||
},
|
}
|
||||||
HudEvent::Logout => return PlayStateResult::Pop,
|
HudEvent::Logout => return PlayStateResult::Pop,
|
||||||
HudEvent::Quit => {
|
HudEvent::Quit => {
|
||||||
return PlayStateResult::Shutdown;
|
return PlayStateResult::Shutdown;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
use std::time::Duration;
|
|
||||||
use log::info;
|
|
||||||
use server::{Input, Event, Server};
|
|
||||||
use common::clock::Clock;
|
use common::clock::Clock;
|
||||||
use std::{
|
use log::info;
|
||||||
thread,
|
use server::{Event, Input, Server};
|
||||||
thread::JoinHandle
|
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
|
||||||
};
|
use std::time::Duration;
|
||||||
use std::sync::mpsc::{
|
use std::{thread, thread::JoinHandle};
|
||||||
channel, Receiver, Sender, TryRecvError,
|
|
||||||
};
|
|
||||||
|
|
||||||
const TPS: u64 = 30;
|
const TPS: u64 = 30;
|
||||||
|
|
||||||
@ -49,11 +44,11 @@ fn run_server(rec: Receiver<Msg>) {
|
|||||||
let mut clock = Clock::new();
|
let mut clock = Clock::new();
|
||||||
|
|
||||||
// Create server
|
// Create server
|
||||||
let mut server = Server::new()
|
let mut server = Server::new().expect("Failed to create server instance");
|
||||||
.expect("Failed to create server instance");
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let events = server.tick(Input::default(), clock.get_last_delta())
|
let events = server
|
||||||
|
.tick(Input::default(), clock.get_last_delta())
|
||||||
.expect("Failed to tick server");
|
.expect("Failed to tick server");
|
||||||
|
|
||||||
for event in events {
|
for event in events {
|
||||||
|
@ -1,46 +1,30 @@
|
|||||||
mod widgets;
|
|
||||||
mod graphic;
|
mod graphic;
|
||||||
mod util;
|
mod util;
|
||||||
|
mod widgets;
|
||||||
|
|
||||||
pub use widgets::toggle_button::ToggleButton;
|
|
||||||
pub use graphic::Graphic;
|
pub use graphic::Graphic;
|
||||||
pub(self) use util::{srgb_to_linear, linear_to_srgb};
|
pub(self) use util::{linear_to_srgb, srgb_to_linear};
|
||||||
|
pub use widgets::toggle_button::ToggleButton;
|
||||||
|
|
||||||
use graphic::{
|
|
||||||
GraphicCache,
|
|
||||||
Id as GraphicId,
|
|
||||||
};
|
|
||||||
use conrod_core::{
|
|
||||||
Ui as CrUi,
|
|
||||||
UiBuilder,
|
|
||||||
UiCell,
|
|
||||||
text::{
|
|
||||||
Font,
|
|
||||||
GlyphCache,
|
|
||||||
font::Id as FontId,
|
|
||||||
},
|
|
||||||
image::{Map, Id as ImgId},
|
|
||||||
widget::{Id as WidgId, id::Generator},
|
|
||||||
render::Primitive,
|
|
||||||
event::Input,
|
|
||||||
input::{touch::Touch, Widget, Motion, Button},
|
|
||||||
};
|
|
||||||
use vek::*;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Error,
|
|
||||||
render::{
|
render::{
|
||||||
RenderError,
|
create_ui_quad, create_ui_tri, Mesh, Model, RenderError, Renderer, Texture, UiMode,
|
||||||
Renderer,
|
|
||||||
Model,
|
|
||||||
Mesh,
|
|
||||||
Texture,
|
|
||||||
UiPipeline,
|
UiPipeline,
|
||||||
UiMode,
|
|
||||||
create_ui_quad,
|
|
||||||
create_ui_tri,
|
|
||||||
},
|
},
|
||||||
window::Window,
|
window::Window,
|
||||||
|
Error,
|
||||||
};
|
};
|
||||||
|
use conrod_core::{
|
||||||
|
event::Input,
|
||||||
|
image::{Id as ImgId, Map},
|
||||||
|
input::{touch::Touch, Button, Motion, Widget},
|
||||||
|
render::Primitive,
|
||||||
|
text::{font::Id as FontId, Font, GlyphCache},
|
||||||
|
widget::{id::Generator, Id as WidgId},
|
||||||
|
Ui as CrUi, UiBuilder, UiCell,
|
||||||
|
};
|
||||||
|
use graphic::{GraphicCache, Id as GraphicId};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum UiError {
|
pub enum UiError {
|
||||||
@ -66,19 +50,23 @@ impl Event {
|
|||||||
winit::Window::get_hidpi_factor(&self.0) as _
|
winit::Window::get_hidpi_factor(&self.0) as _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
convert_event!(event, &WindowRef(window.window())).map(|input| {
|
convert_event!(event, &WindowRef(window.window())).map(|input| Self(input))
|
||||||
Self(input)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
pub fn is_keyboard_or_mouse(&self) -> bool {
|
pub fn is_keyboard_or_mouse(&self) -> bool {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Input::Press(_) | Input::Release(_) | Input::Motion(_) | Input::Touch(_) | Input::Text(_) => true,
|
Input::Press(_)
|
||||||
|
| Input::Release(_)
|
||||||
|
| Input::Motion(_)
|
||||||
|
| Input::Touch(_)
|
||||||
|
| Input::Text(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_keyboard(&self) -> bool {
|
pub fn is_keyboard(&self) -> bool {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Input::Press(Button::Keyboard(_)) | Input::Release(Button::Keyboard(_)) | Input::Text(_) => true,
|
Input::Press(Button::Keyboard(_))
|
||||||
|
| Input::Release(Button::Keyboard(_))
|
||||||
|
| Input::Text(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,11 +101,21 @@ impl Cache {
|
|||||||
graphic_cache_tex: renderer.create_dynamic_texture(graphic_cache_dims)?,
|
graphic_cache_tex: renderer.create_dynamic_texture(graphic_cache_dims)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn glyph_cache_tex(&self) -> &Texture<UiPipeline> { &self.glyph_cache_tex }
|
pub fn glyph_cache_tex(&self) -> &Texture<UiPipeline> {
|
||||||
pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture<UiPipeline>) { (&mut self.glyph_cache, &self.glyph_cache_tex) }
|
&self.glyph_cache_tex
|
||||||
pub fn graphic_cache_tex(&self) -> &Texture<UiPipeline> { &self.graphic_cache_tex }
|
}
|
||||||
pub fn graphic_cache_mut_and_tex(&mut self) -> (&mut GraphicCache, &Texture<UiPipeline>) { (&mut self.graphic_cache, &self.graphic_cache_tex) }
|
pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture<UiPipeline>) {
|
||||||
pub fn new_graphic(&mut self, graphic: Graphic) -> GraphicId { self.graphic_cache.new_graphic(graphic) }
|
(&mut self.glyph_cache, &self.glyph_cache_tex)
|
||||||
|
}
|
||||||
|
pub fn graphic_cache_tex(&self) -> &Texture<UiPipeline> {
|
||||||
|
&self.graphic_cache_tex
|
||||||
|
}
|
||||||
|
pub fn graphic_cache_mut_and_tex(&mut self) -> (&mut GraphicCache, &Texture<UiPipeline>) {
|
||||||
|
(&mut self.graphic_cache, &self.graphic_cache_tex)
|
||||||
|
}
|
||||||
|
pub fn new_graphic(&mut self, graphic: Graphic) -> GraphicId {
|
||||||
|
self.graphic_cache.new_graphic(graphic)
|
||||||
|
}
|
||||||
pub fn clear_graphic_cache(&mut self, renderer: &mut Renderer, new_size: Vec2<u16>) {
|
pub fn clear_graphic_cache(&mut self, renderer: &mut Renderer, new_size: Vec2<u16>) {
|
||||||
self.graphic_cache.clear_cache(new_size);
|
self.graphic_cache.clear_cache(new_size);
|
||||||
self.graphic_cache_tex = renderer.create_dynamic_texture(new_size).unwrap();
|
self.graphic_cache_tex = renderer.create_dynamic_texture(new_size).unwrap();
|
||||||
@ -190,7 +188,9 @@ impl Scale {
|
|||||||
match self.mode {
|
match self.mode {
|
||||||
ScaleMode::Absolute(scale) => scale / self.dpi_factor,
|
ScaleMode::Absolute(scale) => scale / self.dpi_factor,
|
||||||
ScaleMode::DpiFactor => 1.0,
|
ScaleMode::DpiFactor => 1.0,
|
||||||
ScaleMode::RelativeToWindow(dims) => (self.window_dims.x / dims.x).min(self.window_dims.y / dims.y),
|
ScaleMode::RelativeToWindow(dims) => {
|
||||||
|
(self.window_dims.x / dims.x).min(self.window_dims.y / dims.y)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Calculate factor to transform between physical coordinates and our scaled coordinates
|
// Calculate factor to transform between physical coordinates and our scaled coordinates
|
||||||
@ -277,20 +277,22 @@ impl Ui {
|
|||||||
|
|
||||||
// Get whether a widget besides the window is capturing the mouse
|
// Get whether a widget besides the window is capturing the mouse
|
||||||
pub fn no_widget_capturing_mouse(&self) -> bool {
|
pub fn no_widget_capturing_mouse(&self) -> bool {
|
||||||
self.ui.global_input().current.widget_capturing_mouse.filter(|id| id != &self.ui.window ).is_none()
|
self.ui
|
||||||
|
.global_input()
|
||||||
|
.current
|
||||||
|
.widget_capturing_mouse
|
||||||
|
.filter(|id| id != &self.ui.window)
|
||||||
|
.is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_event(&mut self, event: Event) {
|
pub fn handle_event(&mut self, event: Event) {
|
||||||
match event.0 {
|
match event.0 {
|
||||||
Input::Resize(w, h) => self.window_resized = Some(Vec2::new(w, h)),
|
Input::Resize(w, h) => self.window_resized = Some(Vec2::new(w, h)),
|
||||||
Input::Touch(touch) => self.ui.handle_event(
|
Input::Touch(touch) => self.ui.handle_event(Input::Touch(Touch {
|
||||||
Input::Touch(Touch {
|
|
||||||
xy: self.scale.scale_point(touch.xy.into()).into_array(),
|
xy: self.scale.scale_point(touch.xy.into()).into_array(),
|
||||||
..touch
|
..touch
|
||||||
})
|
})),
|
||||||
),
|
Input::Motion(motion) => self.ui.handle_event(Input::Motion(match motion {
|
||||||
Input::Motion(motion) => self.ui.handle_event(
|
|
||||||
Input::Motion( match motion {
|
|
||||||
Motion::MouseCursor { x, y } => {
|
Motion::MouseCursor { x, y } => {
|
||||||
let (x, y) = self.scale.scale_point(Vec2::new(x, y)).into_tuple();
|
let (x, y) = self.scale.scale_point(Vec2::new(x, y)).into_tuple();
|
||||||
Motion::MouseCursor { x, y }
|
Motion::MouseCursor { x, y }
|
||||||
@ -304,8 +306,7 @@ impl Ui {
|
|||||||
Motion::Scroll { x, y }
|
Motion::Scroll { x, y }
|
||||||
}
|
}
|
||||||
_ => motion,
|
_ => motion,
|
||||||
})
|
})),
|
||||||
),
|
|
||||||
_ => self.ui.handle_event(event.0),
|
_ => self.ui.handle_event(event.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -338,7 +339,8 @@ impl Ui {
|
|||||||
macro_rules! switch_to_plain_state {
|
macro_rules! switch_to_plain_state {
|
||||||
() => {
|
() => {
|
||||||
if let State::Image = current_state {
|
if let State::Image = current_state {
|
||||||
self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap()));
|
self.draw_commands
|
||||||
|
.push(DrawCommand::image(renderer.create_model(&mesh).unwrap()));
|
||||||
mesh.clear();
|
mesh.clear();
|
||||||
current_state = State::Plain;
|
current_state = State::Plain;
|
||||||
}
|
}
|
||||||
@ -348,7 +350,12 @@ impl Ui {
|
|||||||
let p_scale_factor = self.scale.scale_factor_physical();
|
let p_scale_factor = self.scale.scale_factor_physical();
|
||||||
|
|
||||||
while let Some(prim) = primitives.next() {
|
while let Some(prim) = primitives.next() {
|
||||||
let Primitive {kind, scizzor, id: _id, rect} = prim;
|
let Primitive {
|
||||||
|
kind,
|
||||||
|
scizzor,
|
||||||
|
id: _id,
|
||||||
|
rect,
|
||||||
|
} = prim;
|
||||||
|
|
||||||
// Check for a change in the scizzor
|
// Check for a change in the scizzor
|
||||||
let new_scizzor = {
|
let new_scizzor = {
|
||||||
@ -366,17 +373,15 @@ impl Ui {
|
|||||||
max: Vec2 {
|
max: Vec2 {
|
||||||
x: ((min_x + w) * p_scale_factor) as u16,
|
x: ((min_x + w) * p_scale_factor) as u16,
|
||||||
y: ((min_y + h) * p_scale_factor) as u16,
|
y: ((min_y + h) * p_scale_factor) as u16,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
.intersection(window_scizzor)
|
.intersection(window_scizzor)
|
||||||
};
|
};
|
||||||
if new_scizzor != current_scizzor {
|
if new_scizzor != current_scizzor {
|
||||||
// Finish the current command
|
// Finish the current command
|
||||||
self.draw_commands.push(match current_state {
|
self.draw_commands.push(match current_state {
|
||||||
State::Plain =>
|
State::Plain => DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
||||||
DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
State::Image => DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
||||||
State::Image =>
|
|
||||||
DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
|
||||||
});
|
});
|
||||||
mesh.clear();
|
mesh.clear();
|
||||||
|
|
||||||
@ -398,8 +403,15 @@ impl Ui {
|
|||||||
|
|
||||||
use conrod_core::render::PrimitiveKind;
|
use conrod_core::render::PrimitiveKind;
|
||||||
match kind {
|
match kind {
|
||||||
PrimitiveKind::Image { image_id, color, source_rect } => {
|
PrimitiveKind::Image {
|
||||||
let graphic_id = self.image_map.get(&image_id).expect("Image does not exist in image map");
|
image_id,
|
||||||
|
color,
|
||||||
|
source_rect,
|
||||||
|
} => {
|
||||||
|
let graphic_id = self
|
||||||
|
.image_map
|
||||||
|
.get(&image_id)
|
||||||
|
.expect("Image does not exist in image map");
|
||||||
let (graphic_cache, cache_tex) = self.cache.graphic_cache_mut_and_tex();
|
let (graphic_cache, cache_tex) = self.cache.graphic_cache_mut_and_tex();
|
||||||
|
|
||||||
match graphic_cache.get_graphic(*graphic_id) {
|
match graphic_cache.get_graphic(*graphic_id) {
|
||||||
@ -409,13 +421,15 @@ impl Ui {
|
|||||||
|
|
||||||
// Switch to the `Image` state for this image if we're not in it already.
|
// Switch to the `Image` state for this image if we're not in it already.
|
||||||
if let State::Plain = current_state {
|
if let State::Plain = current_state {
|
||||||
self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap()));
|
self.draw_commands
|
||||||
|
.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap()));
|
||||||
mesh.clear();
|
mesh.clear();
|
||||||
current_state = State::Image;
|
current_state = State::Image;
|
||||||
}
|
}
|
||||||
|
|
||||||
let color = srgb_to_linear(color.unwrap_or(conrod_core::color::WHITE).to_fsa().into());
|
let color = srgb_to_linear(
|
||||||
|
color.unwrap_or(conrod_core::color::WHITE).to_fsa().into(),
|
||||||
|
);
|
||||||
|
|
||||||
let resolution = Vec2::new(
|
let resolution = Vec2::new(
|
||||||
(rect.w() * p_scale_factor) as u16,
|
(rect.w() * p_scale_factor) as u16,
|
||||||
@ -439,17 +453,29 @@ impl Ui {
|
|||||||
max: Vec2::new(uv_r, uv_t),
|
max: Vec2::new(uv_r, uv_t),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (cache_w, cache_h) = cache_tex.get_dimensions().map(|e| e as f32).into_tuple();
|
let (cache_w, cache_h) =
|
||||||
|
cache_tex.get_dimensions().map(|e| e as f32).into_tuple();
|
||||||
|
|
||||||
// Cache graphic at particular resolution
|
// Cache graphic at particular resolution
|
||||||
let uv_aabr = match graphic_cache.cache_res(*graphic_id, resolution, source_aabr, |aabr, data| {
|
let uv_aabr = match graphic_cache.cache_res(
|
||||||
|
*graphic_id,
|
||||||
|
resolution,
|
||||||
|
source_aabr,
|
||||||
|
|aabr, data| {
|
||||||
let offset = aabr.min.into_array();
|
let offset = aabr.min.into_array();
|
||||||
let size = aabr.size().into_array();
|
let size = aabr.size().into_array();
|
||||||
renderer.update_texture(cache_tex, offset, size, &data);
|
renderer.update_texture(cache_tex, offset, size, &data);
|
||||||
}) {
|
},
|
||||||
|
) {
|
||||||
Some(aabr) => Aabr {
|
Some(aabr) => Aabr {
|
||||||
min: Vec2::new(aabr.min.x as f32 / cache_w, aabr.max.y as f32 / cache_h),
|
min: Vec2::new(
|
||||||
max: Vec2::new(aabr.max.x as f32 / cache_w, aabr.min.y as f32 / cache_h),
|
aabr.min.x as f32 / cache_w,
|
||||||
|
aabr.max.y as f32 / cache_h,
|
||||||
|
),
|
||||||
|
max: Vec2::new(
|
||||||
|
aabr.max.x as f32 / cache_w,
|
||||||
|
aabr.min.y as f32 / cache_h,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
@ -460,12 +486,16 @@ impl Ui {
|
|||||||
color,
|
color,
|
||||||
UiMode::Image,
|
UiMode::Image,
|
||||||
));
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
PrimitiveKind::Text { color, text, font_id } => {
|
PrimitiveKind::Text {
|
||||||
|
color,
|
||||||
|
text,
|
||||||
|
font_id,
|
||||||
|
} => {
|
||||||
switch_to_plain_state!();
|
switch_to_plain_state!();
|
||||||
// Get screen width and height
|
// Get screen width and height
|
||||||
let (screen_w, screen_h) = renderer.get_resolution().map(|e| e as f32).into_tuple();
|
let (screen_w, screen_h) =
|
||||||
|
renderer.get_resolution().map(|e| e as f32).into_tuple();
|
||||||
// Calculate dpi factor
|
// Calculate dpi factor
|
||||||
let dpi_factor = screen_w / ui.win_w as f32;
|
let dpi_factor = screen_w / ui.win_w as f32;
|
||||||
|
|
||||||
@ -476,19 +506,26 @@ impl Ui {
|
|||||||
glyph_cache.queue_glyph(font_id.index(), glyph.clone());
|
glyph_cache.queue_glyph(font_id.index(), glyph.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
glyph_cache.cache_queued(|rect, data| {
|
glyph_cache
|
||||||
|
.cache_queued(|rect, data| {
|
||||||
let offset = [rect.min.x as u16, rect.min.y as u16];
|
let offset = [rect.min.x as u16, rect.min.y as u16];
|
||||||
let size = [rect.width() as u16, rect.height() as u16];
|
let size = [rect.width() as u16, rect.height() as u16];
|
||||||
|
|
||||||
let new_data = data.iter().map(|x| [255, 255, 255, *x]).collect::<Vec<[u8; 4]>>();
|
let new_data = data
|
||||||
|
.iter()
|
||||||
|
.map(|x| [255, 255, 255, *x])
|
||||||
|
.collect::<Vec<[u8; 4]>>();
|
||||||
|
|
||||||
renderer.update_texture(cache_tex, offset, size, &new_data);
|
renderer.update_texture(cache_tex, offset, size, &new_data);
|
||||||
}).unwrap();
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let color = srgb_to_linear(color.to_fsa().into());
|
let color = srgb_to_linear(color.to_fsa().into());
|
||||||
|
|
||||||
for g in positioned_glyphs {
|
for g in positioned_glyphs {
|
||||||
if let Ok(Some((uv_rect, screen_rect))) = glyph_cache.rect_for(font_id.index(), g) {
|
if let Ok(Some((uv_rect, screen_rect))) =
|
||||||
|
glyph_cache.rect_for(font_id.index(), g)
|
||||||
|
{
|
||||||
let uv = Aabr {
|
let uv = Aabr {
|
||||||
min: Vec2::new(uv_rect.min.x, uv_rect.max.y),
|
min: Vec2::new(uv_rect.min.x, uv_rect.max.y),
|
||||||
max: Vec2::new(uv_rect.max.x, uv_rect.min.y),
|
max: Vec2::new(uv_rect.max.x, uv_rect.min.y),
|
||||||
@ -503,12 +540,7 @@ impl Ui {
|
|||||||
(screen_rect.min.y as f32 / screen_h - 0.5) * -2.0,
|
(screen_rect.min.y as f32 / screen_h - 0.5) * -2.0,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
mesh.push_quad(create_ui_quad(
|
mesh.push_quad(create_ui_quad(rect, uv, color, UiMode::Text));
|
||||||
rect,
|
|
||||||
uv,
|
|
||||||
color,
|
|
||||||
UiMode::Text,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -545,16 +577,13 @@ impl Ui {
|
|||||||
let p2 = Vec2::new(vx(tri[1][0]), vy(tri[1][1]));
|
let p2 = Vec2::new(vx(tri[1][0]), vy(tri[1][1]));
|
||||||
let p3 = Vec2::new(vx(tri[2][0]), vy(tri[2][1]));
|
let p3 = Vec2::new(vx(tri[2][0]), vy(tri[2][1]));
|
||||||
// If triangle is clockwise reverse it
|
// If triangle is clockwise reverse it
|
||||||
let (v1, v2): (Vec3<f32>, Vec3<f32>) = ((p2 - p1).into(), (p3 - p1).into());
|
let (v1, v2): (Vec3<f32>, Vec3<f32>) =
|
||||||
let triangle = if v1.cross(v2).z > 0.0 {[
|
((p2 - p1).into(), (p3 - p1).into());
|
||||||
p1.into_array(),
|
let triangle = if v1.cross(v2).z > 0.0 {
|
||||||
p2.into_array(),
|
[p1.into_array(), p2.into_array(), p3.into_array()]
|
||||||
p3.into_array(),
|
} else {
|
||||||
]} else {[
|
[p2.into_array(), p1.into_array(), p3.into_array()]
|
||||||
p2.into_array(),
|
};
|
||||||
p1.into_array(),
|
|
||||||
p3.into_array(),
|
|
||||||
]};
|
|
||||||
mesh.push_tri(create_ui_tri(
|
mesh.push_tri(create_ui_tri(
|
||||||
triangle,
|
triangle,
|
||||||
[[0.0; 2]; 3],
|
[[0.0; 2]; 3],
|
||||||
@ -562,10 +591,8 @@ impl Ui {
|
|||||||
UiMode::Geometry,
|
UiMode::Geometry,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {} // TODO: Add this
|
||||||
// TODO: Add this
|
|
||||||
//PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);}
|
//PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);}
|
||||||
// Other uneeded for now
|
// Other uneeded for now
|
||||||
//PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);}
|
//PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);}
|
||||||
@ -573,10 +600,8 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
// Enter the final command
|
// Enter the final command
|
||||||
self.draw_commands.push(match current_state {
|
self.draw_commands.push(match current_state {
|
||||||
State::Plain =>
|
State::Plain => DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
||||||
DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
State::Image => DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
||||||
State::Image =>
|
|
||||||
DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle window resizing
|
// Handle window resizing
|
||||||
@ -584,7 +609,8 @@ impl Ui {
|
|||||||
self.scale.window_resized(new_dims, renderer);
|
self.scale.window_resized(new_dims, renderer);
|
||||||
let (w, h) = self.scale.scaled_window_size().into_tuple();
|
let (w, h) = self.scale.scaled_window_size().into_tuple();
|
||||||
self.ui.handle_event(Input::Resize(w, h));
|
self.ui.handle_event(Input::Resize(w, h));
|
||||||
self.cache.clear_graphic_cache(renderer, renderer.get_resolution().map(|e| e * 4));
|
self.cache
|
||||||
|
.clear_graphic_cache(renderer, renderer.get_resolution().map(|e| e * 4));
|
||||||
// TODO: probably need to resize glyph cache, see conrod's gfx backend for reference
|
// TODO: probably need to resize glyph cache, see conrod's gfx backend for reference
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -599,12 +625,8 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
DrawCommand::Draw { kind, model } => {
|
DrawCommand::Draw { kind, model } => {
|
||||||
let tex = match kind {
|
let tex = match kind {
|
||||||
DrawKind::Image => {
|
DrawKind::Image => self.cache.graphic_cache_tex(),
|
||||||
self.cache.graphic_cache_tex()
|
DrawKind::Plain => self.cache.glyph_cache_tex(),
|
||||||
}
|
|
||||||
DrawKind::Plain => {
|
|
||||||
self.cache.glyph_cache_tex()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
renderer.render_ui_element(&model, &tex, scissor);
|
renderer.render_ui_element(&model, &tex, scissor);
|
||||||
}
|
}
|
||||||
@ -617,6 +639,9 @@ fn default_scissor(renderer: &mut Renderer) -> Aabr<u16> {
|
|||||||
let (screen_w, screen_h) = renderer.get_resolution().map(|e| e as u16).into_tuple();
|
let (screen_w, screen_h) = renderer.get_resolution().map(|e| e as u16).into_tuple();
|
||||||
Aabr {
|
Aabr {
|
||||||
min: Vec2 { x: 0, y: 0 },
|
min: Vec2 { x: 0, y: 0 },
|
||||||
max: Vec2 { x: screen_w, y: screen_h }
|
max: Vec2 {
|
||||||
|
x: screen_w,
|
||||||
|
y: screen_h,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,13 +1,7 @@
|
|||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
widget::{self, button},
|
|
||||||
image,
|
image,
|
||||||
WidgetCommon,
|
widget::{self, button},
|
||||||
Widget,
|
widget_ids, Color, Positionable, Rect, Sizeable, Widget, WidgetCommon,
|
||||||
Sizeable,
|
|
||||||
Color,
|
|
||||||
Rect,
|
|
||||||
Positionable,
|
|
||||||
widget_ids,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, WidgetCommon)]
|
#[derive(Clone, WidgetCommon)]
|
||||||
@ -88,7 +82,9 @@ impl Widget for ToggleButton {
|
|||||||
type Event = bool;
|
type Event = bool;
|
||||||
|
|
||||||
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
|
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
|
||||||
State { ids: Ids::new(id_gen) }
|
State {
|
||||||
|
ids: Ids::new(id_gen),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Self::Style {
|
fn style(&self) -> Self::Style {
|
||||||
@ -96,8 +92,19 @@ impl Widget for ToggleButton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||||
let widget::UpdateArgs{ id, state, ui, rect, .. } = args;
|
let widget::UpdateArgs {
|
||||||
let ToggleButton { mut value, f_image, t_image, .. } = self;
|
id,
|
||||||
|
state,
|
||||||
|
ui,
|
||||||
|
rect,
|
||||||
|
..
|
||||||
|
} = args;
|
||||||
|
let ToggleButton {
|
||||||
|
mut value,
|
||||||
|
f_image,
|
||||||
|
t_image,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
// Check if button was clicked
|
// Check if button was clicked
|
||||||
// (can't use .set().was_clicked() because we are changing the image and this is after setting the widget which causes flickering as it takes a frame to change after the mouse button is lifted)
|
// (can't use .set().was_clicked() because we are changing the image and this is after setting the widget which causes flickering as it takes a frame to change after the mouse button is lifted)
|
||||||
if ui.widget_input(state.ids.button).clicks().left().count() % 2 == 1 {
|
if ui.widget_input(state.ids.button).clicks().left().count() % 2 == 1 {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
render::{Renderer, TgtColorFmt, TgtDepthFmt},
|
render::{Renderer, TgtColorFmt, TgtDepthFmt},
|
||||||
ui, Error, settings::Settings,
|
settings::Settings,
|
||||||
|
ui, Error,
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
// Library
|
// Library
|
||||||
use vek::*;
|
|
||||||
use noise::{NoiseFn, Perlin};
|
use noise::{NoiseFn, Perlin};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
// Project
|
// Project
|
||||||
use common::{
|
use common::{
|
||||||
vol::{Vox, SizedVol, WriteVol},
|
terrain::{Block, TerrainChunk, TerrainChunkMeta},
|
||||||
terrain::{
|
vol::{SizedVol, Vox, WriteVol},
|
||||||
Block,
|
|
||||||
TerrainChunk,
|
|
||||||
TerrainChunkMeta,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -47,12 +43,14 @@ impl World {
|
|||||||
let small_freq = 1.0 / 32.0;
|
let small_freq = 1.0 / 32.0;
|
||||||
let small_ampl = 6.0;
|
let small_ampl = 6.0;
|
||||||
let offs = 32.0;
|
let offs = 32.0;
|
||||||
let height =
|
let height = perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl
|
||||||
perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl
|
|
||||||
+ perlin_nz.get(Vec2::from(wposf * small_freq).into_array()) * small_ampl
|
+ perlin_nz.get(Vec2::from(wposf * small_freq).into_array()) * small_ampl
|
||||||
+ offs;
|
+ offs;
|
||||||
|
|
||||||
chunk.set(lpos, if wposf.z < height - 4.0 {
|
chunk
|
||||||
|
.set(
|
||||||
|
lpos,
|
||||||
|
if wposf.z < height - 4.0 {
|
||||||
stone
|
stone
|
||||||
} else if wposf.z < height - 1.0 {
|
} else if wposf.z < height - 1.0 {
|
||||||
dirt
|
dirt
|
||||||
@ -60,7 +58,9 @@ impl World {
|
|||||||
grass
|
grass
|
||||||
} else {
|
} else {
|
||||||
air
|
air
|
||||||
}).unwrap();
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk
|
chunk
|
||||||
|
Loading…
Reference in New Issue
Block a user