mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'clean-all-code' into 'master'
Ran fmt on codebase See merge request veloren/veloren!95 Former-commit-id: 9a847a63c0b69dd3a969c3829986032972f00325
This commit is contained in:
commit
a0a628ee97
@ -1,10 +1,7 @@
|
||||
use std::time::Duration;
|
||||
use client::{Client, Event, Input};
|
||||
use common::{clock::Clock, comp};
|
||||
use log::info;
|
||||
use client::{Input, Client, Event};
|
||||
use common::{
|
||||
comp,
|
||||
clock::Clock,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
const FPS: u64 = 60;
|
||||
|
||||
@ -18,8 +15,8 @@ fn main() {
|
||||
let mut clock = Clock::new();
|
||||
|
||||
// Create client
|
||||
let mut client = Client::new(([127, 0, 0, 1], 59003), 300)
|
||||
.expect("Failed to create client instance");
|
||||
let mut client =
|
||||
Client::new(([127, 0, 0, 1], 59003), 300).expect("Failed to create client instance");
|
||||
|
||||
client.register(comp::Player::new("test".to_string()));
|
||||
|
||||
@ -31,7 +28,7 @@ fn main() {
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
break;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
for event in events {
|
||||
|
@ -249,9 +249,18 @@ impl Client {
|
||||
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
|
||||
ServerMsg::Pong => {}
|
||||
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::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) {
|
||||
ServerMsg::SetPlayerEntity(uid) => {
|
||||
self.entity = self.state.ecs().entity_from_uid(uid).unwrap()
|
||||
} // 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) => {
|
||||
self.state.write_component(entity, pos);
|
||||
self.state.write_component(entity, vel);
|
||||
@ -259,7 +268,10 @@ impl Client {
|
||||
}
|
||||
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) => {
|
||||
self.state.write_component(entity, animation_history);
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::fs::File;
|
||||
|
||||
fn try_load(name: &str) -> Option<File> {
|
||||
let basepaths = [
|
||||
@ -22,25 +22,28 @@ fn try_load(name: &str) -> Option<File> {
|
||||
Ok(f) => {
|
||||
debug!("loading {} succedeed", filename);
|
||||
return Some(f);
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("loading {} did not work with error: {}", filename, e);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn load(name: &str) -> Result<Vec<u8>, ()> {
|
||||
return match try_load(name) {
|
||||
Some(mut f) => {
|
||||
let mut content: Vec<u8> = vec!();
|
||||
let mut content: Vec<u8> = vec![];
|
||||
f.read_to_end(&mut content);
|
||||
info!("loaded asset successful: {}", name);
|
||||
Ok(content)
|
||||
},
|
||||
}
|
||||
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(())
|
||||
}
|
||||
};
|
||||
|
@ -23,13 +23,19 @@ impl Clock {
|
||||
}
|
||||
|
||||
#[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)]
|
||||
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)]
|
||||
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)]
|
||||
pub fn tick(&mut self, tgt: Duration) {
|
||||
@ -44,7 +50,9 @@ impl Clock {
|
||||
} else {
|
||||
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()
|
||||
@ -56,8 +64,8 @@ impl Clock {
|
||||
self.running_tps_average = if self.running_tps_average == 0.0 {
|
||||
delta.as_secs_f64()
|
||||
} else {
|
||||
CLOCK_SMOOTHING * self.running_tps_average +
|
||||
(1.0 - CLOCK_SMOOTHING) * delta.as_secs_f64()
|
||||
CLOCK_SMOOTHING * self.running_tps_average
|
||||
+ (1.0 - CLOCK_SMOOTHING) * delta.as_secs_f64()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use specs::{Component, VecStorage, FlaggedStorage};
|
||||
use vek::*;
|
||||
use rand::prelude::*;
|
||||
use specs::{Component, FlaggedStorage, VecStorage};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Race {
|
||||
@ -60,14 +60,14 @@ pub enum Weapon {
|
||||
Staff,
|
||||
}
|
||||
|
||||
use Race::*;
|
||||
use Gender::*;
|
||||
use Head::*;
|
||||
use Chest::*;
|
||||
use Belt::*;
|
||||
use Pants::*;
|
||||
use Hand::*;
|
||||
use Chest::*;
|
||||
use Foot::*;
|
||||
use Gender::*;
|
||||
use Hand::*;
|
||||
use Head::*;
|
||||
use Pants::*;
|
||||
use Race::*;
|
||||
use Weapon::*;
|
||||
|
||||
const ALL_RACES: [Race; 6] = [Danari, Dwarf, Elf, Human, Orc, Undead];
|
||||
|
@ -1,11 +1,11 @@
|
||||
pub mod agent;
|
||||
pub mod character;
|
||||
pub mod player;
|
||||
pub mod phys;
|
||||
pub mod player;
|
||||
|
||||
// Reexports
|
||||
pub use agent::{Agent, Control};
|
||||
pub use character::Animation;
|
||||
pub use character::AnimationHistory;
|
||||
pub use character::Character;
|
||||
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::*;
|
||||
|
||||
// Pos
|
||||
|
@ -1,4 +1,4 @@
|
||||
use specs::{Component, VecStorage, FlaggedStorage};
|
||||
use specs::{Component, FlaggedStorage, VecStorage};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Player {
|
||||
@ -7,9 +7,7 @@ pub struct Player {
|
||||
|
||||
impl Player {
|
||||
pub fn new(alias: String) -> Self {
|
||||
Self {
|
||||
alias,
|
||||
}
|
||||
Self { alias }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
pub mod cell;
|
||||
|
||||
// Library
|
||||
use vek::*;
|
||||
use dot_vox::DotVoxData;
|
||||
use vek::*;
|
||||
|
||||
// Crate
|
||||
use crate::{
|
||||
@ -28,11 +28,7 @@ impl From<DotVoxData> for Segment {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut segment = Segment::filled(
|
||||
Vec3::new(
|
||||
model.size.x,
|
||||
model.size.y,
|
||||
model.size.z,
|
||||
),
|
||||
Vec3::new(model.size.x, model.size.y, model.size.z),
|
||||
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]
|
||||
extern crate serde_derive;
|
||||
@ -10,13 +15,13 @@ pub mod clock;
|
||||
pub mod comp;
|
||||
pub mod figure;
|
||||
pub mod msg;
|
||||
pub mod ray;
|
||||
pub mod state;
|
||||
pub mod sys;
|
||||
pub mod terrain;
|
||||
pub mod util;
|
||||
pub mod volumes;
|
||||
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
|
||||
/// 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 crate::comp;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ClientMsg {
|
||||
Register { player: comp::Player },
|
||||
Register {
|
||||
player: comp::Player,
|
||||
},
|
||||
Character(comp::Character),
|
||||
RequestState(ClientState),
|
||||
Ping,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::marker::PhantomData;
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
use crate::comp;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// Automatically derive From<T> for Packet for each variant Packet::T(T)
|
||||
sphynx::sum_type! {
|
||||
|
@ -1,11 +1,11 @@
|
||||
pub mod client;
|
||||
pub mod ecs_packet;
|
||||
pub mod server;
|
||||
pub mod client;
|
||||
|
||||
// Reexports
|
||||
pub use self::server::{ServerMsg, RequestStateError};
|
||||
pub use self::client::ClientMsg;
|
||||
pub use self::ecs_packet::EcsPacket;
|
||||
pub use self::server::{RequestStateError, ServerMsg};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ClientState {
|
||||
|
@ -1,9 +1,6 @@
|
||||
use super::{ClientState, EcsPacket};
|
||||
use crate::{comp, terrain::TerrainChunk};
|
||||
use vek::*;
|
||||
use crate::{
|
||||
comp,
|
||||
terrain::TerrainChunk,
|
||||
};
|
||||
use super::{EcsPacket, ClientState};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum RequestStateError {
|
||||
|
@ -7,11 +7,7 @@ pub use post2 as post;
|
||||
// Reexports
|
||||
pub use self::{
|
||||
data::{ClientMsg, ServerMsg},
|
||||
post::{
|
||||
Error as PostError,
|
||||
PostBox,
|
||||
PostOffice,
|
||||
},
|
||||
post::{Error as PostError, PostBox, PostOffice},
|
||||
};
|
||||
|
||||
pub trait PostSend = 'static + serde::Serialize + std::marker::Send + std::fmt::Debug;
|
||||
|
@ -1,14 +1,17 @@
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
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,
|
||||
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)]
|
||||
pub enum Error {
|
||||
@ -73,11 +76,11 @@ impl<S: PostMsg, R: PostMsg> PostOffice<S, R> {
|
||||
match self.listener.accept() {
|
||||
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::Interrupted => {},
|
||||
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||
Err(e) => {
|
||||
self.error = Some(e.into());
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +139,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
Err(e) => {
|
||||
self.error = Some(e);
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,18 +157,23 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
Err(e) => {
|
||||
self.error = Some(e.into());
|
||||
break;
|
||||
},
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
self.error = Some(e);
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 incoming_buf = Vec::new();
|
||||
|
||||
@ -176,8 +184,8 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
Ok(Some(e)) | Err(e) => {
|
||||
recv_tx.send(Err(e.into())).unwrap();
|
||||
break 'work;
|
||||
},
|
||||
Ok(None) => {},
|
||||
}
|
||||
Ok(None) => {}
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// Assemble into packet
|
||||
let mut packet_bytes = msg_bytes
|
||||
.len()
|
||||
.to_le_bytes()
|
||||
.as_ref()
|
||||
.to_vec();
|
||||
let mut packet_bytes = msg_bytes.len().to_le_bytes().as_ref().to_vec();
|
||||
packet_bytes.append(&mut msg_bytes);
|
||||
|
||||
// Split packet into chunks
|
||||
@ -200,13 +204,13 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
.chunks(4096)
|
||||
.map(|chunk| chunk.to_vec())
|
||||
.for_each(|chunk| outgoing_chunks.push_back(chunk))
|
||||
},
|
||||
}
|
||||
Err(mpsc::TryRecvError::Empty) => break,
|
||||
// Worker error
|
||||
Err(e) => {
|
||||
let _ = recv_tx.send(Err(e.into()));
|
||||
break 'work;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,17 +222,17 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
Ok(n) => {
|
||||
outgoing_chunks.push_front(chunk.split_off(n));
|
||||
break;
|
||||
},
|
||||
}
|
||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
// Return chunk to the queue to try again later
|
||||
outgoing_chunks.push_front(chunk);
|
||||
break;
|
||||
},
|
||||
}
|
||||
// Worker error
|
||||
Err(e) => {
|
||||
recv_tx.send(Err(e.into())).unwrap();
|
||||
break 'work;
|
||||
},
|
||||
}
|
||||
},
|
||||
None => break,
|
||||
}
|
||||
@ -241,12 +245,12 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
match stream.read(&mut buf) {
|
||||
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::Interrupted => {},
|
||||
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||
// Worker error
|
||||
Err(e) => {
|
||||
recv_tx.send(Err(e.into())).unwrap();
|
||||
break 'work;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,16 +266,14 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
} else if incoming_buf.len() >= len + 8 {
|
||||
match bincode::deserialize(&incoming_buf[8..len + 8]) {
|
||||
Ok(msg) => recv_tx.send(Ok(msg)).unwrap(),
|
||||
Err(err) => {
|
||||
recv_tx.send(Err(err.into())).unwrap()
|
||||
},
|
||||
Err(err) => recv_tx.send(Err(err.into())).unwrap(),
|
||||
}
|
||||
|
||||
incoming_buf = incoming_buf.split_off(len + 8);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
@ -295,7 +297,9 @@ impl<S: PostMsg, R: PostMsg> Drop for PostBox<S, R> {
|
||||
mod tests {
|
||||
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();
|
||||
Ok((PostOffice::bind(sock)?, sock))
|
||||
}
|
||||
@ -353,9 +357,9 @@ mod tests {
|
||||
}
|
||||
|
||||
let mut recv_msgs = Vec::new();
|
||||
loop_for(Duration::from_millis(250), || server
|
||||
.new_messages()
|
||||
.for_each(|msg| recv_msgs.push(msg)));
|
||||
loop_for(Duration::from_millis(250), || {
|
||||
server.new_messages().for_each(|msg| recv_msgs.push(msg))
|
||||
});
|
||||
|
||||
assert_eq!(test_msgs, recv_msgs);
|
||||
}
|
||||
@ -363,7 +367,9 @@ mod tests {
|
||||
#[test]
|
||||
fn send_recv_huge() {
|
||||
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();
|
||||
loop_for(Duration::from_millis(250), || ());
|
||||
@ -374,9 +380,9 @@ mod tests {
|
||||
}
|
||||
|
||||
let mut recv_msgs = Vec::new();
|
||||
loop_for(Duration::from_millis(3000), || server
|
||||
.new_messages()
|
||||
.for_each(|msg| recv_msgs.push(msg)));
|
||||
loop_for(Duration::from_millis(3000), || {
|
||||
server.new_messages().for_each(|msg| recv_msgs.push(msg))
|
||||
});
|
||||
|
||||
assert_eq!(test_msgs.len(), recv_msgs.len());
|
||||
assert!(test_msgs == recv_msgs);
|
||||
|
@ -1,8 +1,5 @@
|
||||
use crate::vol::{ReadVol, Vox};
|
||||
use vek::*;
|
||||
use crate::vol::{
|
||||
Vox,
|
||||
ReadVol,
|
||||
};
|
||||
|
||||
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> {
|
||||
Ray {
|
||||
until: f,
|
||||
..self
|
||||
}
|
||||
Ray { until: f, ..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;
|
||||
ipos = pos.map(|e| e as i32);
|
||||
|
||||
match self.vol
|
||||
.get(ipos)
|
||||
.map(|vox| (vox, (self.until)(vox)))
|
||||
{
|
||||
match self.vol.get(ipos).map(|vox| (vox, (self.until)(vox))) {
|
||||
Ok((vox, true)) => return (dist, Ok(Some(vox))),
|
||||
Ok((_, false)) => {},
|
||||
Ok((_, false)) => {}
|
||||
Err(err) => return (dist, Err(err)),
|
||||
}
|
||||
|
||||
let deltas = (
|
||||
dir.map(|e| if e < 0.0 { 0.0 } else { 1.0 }) -
|
||||
pos.map(|e| e.fract())
|
||||
) / dir;
|
||||
let deltas =
|
||||
(dir.map(|e| if e < 0.0 { 0.0 } else { 1.0 }) - pos.map(|e| e.fract())) / dir;
|
||||
|
||||
dist += deltas.reduce(f32::min).max(PLANCK);
|
||||
}
|
||||
|
@ -1,34 +1,21 @@
|
||||
// Reexports
|
||||
pub use sphynx::Uid;
|
||||
|
||||
use std::{
|
||||
time::Duration,
|
||||
collections::HashSet,
|
||||
use crate::{
|
||||
comp,
|
||||
msg::EcsPacket,
|
||||
sys,
|
||||
terrain::{TerrainChunk, TerrainMap},
|
||||
};
|
||||
use shred::{Fetch, FetchMut};
|
||||
use specs::{
|
||||
Builder,
|
||||
Component,
|
||||
DispatcherBuilder,
|
||||
EntityBuilder as EcsEntityBuilder,
|
||||
Entity as EcsEntity,
|
||||
storage::{
|
||||
Storage as EcsStorage,
|
||||
MaskedStorage as EcsMaskedStorage,
|
||||
},
|
||||
saveload::{MarkedBuilder, MarkerAllocator},
|
||||
storage::{MaskedStorage as EcsMaskedStorage, Storage as EcsStorage},
|
||||
Builder, Component, DispatcherBuilder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder,
|
||||
};
|
||||
use sphynx;
|
||||
use std::{collections::HashSet, time::Duration};
|
||||
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?
|
||||
// TODO: Don't hard-code this
|
||||
@ -85,7 +72,11 @@ impl State {
|
||||
/// Create a new `State` from an ECS state package
|
||||
pub fn from_state_package(state_package: sphynx::StatePackage<EcsPacket>) -> 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(),
|
||||
}
|
||||
}
|
||||
@ -113,7 +104,8 @@ impl State {
|
||||
|
||||
/// Register a component with the state's ECS
|
||||
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
|
||||
@ -166,13 +158,13 @@ impl State {
|
||||
|
||||
/// Get a reference to this state's terrain.
|
||||
pub fn terrain(&self) -> Fetch<TerrainMap> {
|
||||
self.ecs
|
||||
.read_resource::<TerrainMap>()
|
||||
self.ecs.read_resource::<TerrainMap>()
|
||||
}
|
||||
|
||||
/// Insert the provided chunk into this state's terrain.
|
||||
pub fn insert_chunk(&mut self, key: Vec3<i32>, chunk: TerrainChunk) {
|
||||
if self.ecs
|
||||
if self
|
||||
.ecs
|
||||
.write_resource::<TerrainMap>()
|
||||
.insert(key, chunk)
|
||||
.is_some()
|
||||
@ -185,7 +177,8 @@ impl State {
|
||||
|
||||
/// Remove the chunk with the given key from this state's terrain, if it exists
|
||||
pub fn remove_chunk(&mut self, key: Vec3<i32>) {
|
||||
if self.ecs
|
||||
if self
|
||||
.ecs
|
||||
.write_resource::<TerrainMap>()
|
||||
.remove(key)
|
||||
.is_some()
|
||||
|
@ -3,7 +3,7 @@ use specs::{Join, Read, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
// Crate
|
||||
use crate::comp::{Agent, Control, phys::Pos};
|
||||
use crate::comp::{phys::Pos, Agent, Control};
|
||||
|
||||
// Basic ECS AI agent system
|
||||
pub struct Sys;
|
||||
@ -22,12 +22,14 @@ impl<'a> System<'a> for Sys {
|
||||
*bearing += Vec2::new(
|
||||
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 {
|
||||
control.move_dir = bearing.normalized();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
// Library
|
||||
use specs::{Join, Read, ReadStorage, System, WriteStorage, Entities};
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
// 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
|
||||
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) {
|
||||
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
|
||||
// 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;
|
||||
|
||||
let animation =
|
||||
if control.move_dir.magnitude() > 0.01 {
|
||||
let animation = if control.move_dir.magnitude() > 0.01 {
|
||||
dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
|
||||
Animation::Run
|
||||
} else {
|
||||
@ -33,10 +37,13 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
let last_animation = anims.get_mut(entity).map(|h| h.current);
|
||||
|
||||
anims.insert(entity, AnimationHistory {
|
||||
anims.insert(
|
||||
entity,
|
||||
AnimationHistory {
|
||||
last: last_animation,
|
||||
current: animation,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
use vek::*;
|
||||
use specs::{Join, Read, ReadStorage, System, WriteStorage, ReadExpect};
|
||||
use crate::{
|
||||
comp::phys::{Pos, Vel},
|
||||
state::DeltaTime,
|
||||
terrain::TerrainMap,
|
||||
vol::{Vox, ReadVol},
|
||||
vol::{ReadVol, Vox},
|
||||
};
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
// Basic ECS physics system
|
||||
pub struct Sys;
|
||||
@ -33,8 +33,8 @@ impl<'a> System<'a> for Sys {
|
||||
while terrain
|
||||
.get(pos.0.map(|e| e.floor() as i32))
|
||||
.map(|vox| !vox.is_empty())
|
||||
.unwrap_or(false) &&
|
||||
i < 80
|
||||
.unwrap_or(false)
|
||||
&& i < 80
|
||||
{
|
||||
pos.0.z += 0.005;
|
||||
vel.0.z = 0.0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum BiomeKind {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
|
||||
// Crate
|
||||
use crate::vol::Vox;
|
||||
|
@ -1,21 +1,15 @@
|
||||
pub mod block;
|
||||
pub mod biome;
|
||||
pub mod block;
|
||||
|
||||
// Reexports
|
||||
pub use self::{
|
||||
block::Block,
|
||||
biome::BiomeKind,
|
||||
};
|
||||
pub use self::{biome::BiomeKind, block::Block};
|
||||
|
||||
use vek::*;
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
use crate::{
|
||||
vol::VolSize,
|
||||
volumes::{
|
||||
vol_map::VolMap,
|
||||
chunk::Chunk,
|
||||
},
|
||||
volumes::{chunk::Chunk, vol_map::VolMap},
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
|
||||
// TerrainChunkSize
|
||||
|
||||
@ -23,7 +17,11 @@ use crate::{
|
||||
pub struct 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
|
||||
|
@ -1,5 +1,5 @@
|
||||
use vek::*;
|
||||
use crate::ray::{Ray, RayUntil};
|
||||
use vek::*;
|
||||
|
||||
/// A voxel
|
||||
pub trait Vox {
|
||||
@ -66,14 +66,18 @@ pub trait ReadVol: BaseVol {
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Err>;
|
||||
|
||||
fn ray(&self, from: Vec3<f32>, to: Vec3<f32>) -> Ray<Self, fn(&Self::Vox) -> bool>
|
||||
where Self: Sized
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Ray::new(self, from, to, |vox| !vox.is_empty())
|
||||
}
|
||||
}
|
||||
|
||||
/// A volume that provides the ability to sample (i.e: clone a section of) its voxel data.
|
||||
pub trait SampleVol: BaseVol where Self::Vox: Clone {
|
||||
pub trait SampleVol: BaseVol
|
||||
where
|
||||
Self::Vox: Clone,
|
||||
{
|
||||
type Sample: BaseVol + ReadVol;
|
||||
/// Take a sample of the volume by cloning voxels within the provided range.
|
||||
///
|
||||
|
@ -2,18 +2,11 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// Library
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
|
||||
// Local
|
||||
use crate::vol::{
|
||||
Vox,
|
||||
BaseVol,
|
||||
SizedVol,
|
||||
ReadVol,
|
||||
WriteVol,
|
||||
VolSize,
|
||||
};
|
||||
use crate::vol::{BaseVol, ReadVol, SizedVol, VolSize, Vox, WriteVol};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ChunkErr {
|
||||
@ -36,15 +29,13 @@ impl<V: Vox, S: VolSize, M> Chunk<V, S, M> {
|
||||
// array.
|
||||
#[inline(always)]
|
||||
fn idx_for(pos: Vec3<i32>) -> Option<usize> {
|
||||
if
|
||||
pos.map(|e| e >= 0).reduce_and() &&
|
||||
pos.map2(S::SIZE, |e, lim| e < lim as i32).reduce_and()
|
||||
if pos.map(|e| e >= 0).reduce_and()
|
||||
&& pos.map2(S::SIZE, |e, lim| e < lim as i32).reduce_and()
|
||||
{
|
||||
Some((
|
||||
pos.x * S::SIZE.y as i32 * S::SIZE.z as i32 +
|
||||
pos.y * S::SIZE.z as i32 +
|
||||
pos.z
|
||||
) as usize)
|
||||
Some(
|
||||
(pos.x * S::SIZE.y as i32 * S::SIZE.z as i32 + pos.y * S::SIZE.z as i32 + pos.z)
|
||||
as usize,
|
||||
)
|
||||
} else {
|
||||
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> {
|
||||
#[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> {
|
||||
|
@ -2,13 +2,7 @@
|
||||
use vek::*;
|
||||
|
||||
// Local
|
||||
use crate::vol::{
|
||||
Vox,
|
||||
BaseVol,
|
||||
SizedVol,
|
||||
ReadVol,
|
||||
WriteVol,
|
||||
};
|
||||
use crate::vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DynaErr {
|
||||
@ -30,15 +24,8 @@ impl<V: Vox, M> Dyna<V, M> {
|
||||
// array.
|
||||
#[inline(always)]
|
||||
fn idx_for(sz: Vec3<u32>, pos: Vec3<i32>) -> Option<usize> {
|
||||
if
|
||||
pos.map(|e| e >= 0).reduce_and() &&
|
||||
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)
|
||||
if pos.map(|e| e >= 0).reduce_and() && 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 {
|
||||
None
|
||||
}
|
||||
@ -52,7 +39,9 @@ impl<V: Vox, M> BaseVol for Dyna<V, M> {
|
||||
|
||||
impl<V: Vox, M> SizedVol for Dyna<V, M> {
|
||||
#[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> {
|
||||
|
@ -1,3 +1,3 @@
|
||||
pub mod dyna;
|
||||
pub mod chunk;
|
||||
pub mod dyna;
|
||||
pub mod vol_map;
|
||||
|
@ -6,15 +6,7 @@ use vek::*;
|
||||
|
||||
// Crate
|
||||
use crate::{
|
||||
vol::{
|
||||
Vox,
|
||||
BaseVol,
|
||||
SizedVol,
|
||||
ReadVol,
|
||||
SampleVol,
|
||||
WriteVol,
|
||||
VolSize,
|
||||
},
|
||||
vol::{BaseVol, ReadVol, SampleVol, SizedVol, VolSize, Vox, WriteVol},
|
||||
volumes::{
|
||||
chunk::{Chunk, ChunkErr},
|
||||
dyna::{Dyna, DynaErr},
|
||||
@ -56,7 +48,8 @@ impl<V: Vox, S: VolSize, M> ReadVol for VolMap<V, S, M> {
|
||||
#[inline(always)]
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&V, VolMapErr> {
|
||||
let ck = Self::chunk_key(pos);
|
||||
self.chunks.get(&ck)
|
||||
self.chunks
|
||||
.get(&ck)
|
||||
.ok_or(VolMapErr::NoSuchChunk)
|
||||
.and_then(|chunk| {
|
||||
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(
|
||||
range.size().map(|e| e as u32).into(),
|
||||
V::empty(),
|
||||
(),
|
||||
);
|
||||
let mut sample = Dyna::filled(range.size().map(|e| e as u32).into(), V::empty(), ());
|
||||
|
||||
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))?;
|
||||
}
|
||||
|
||||
@ -106,7 +101,8 @@ impl<V: Vox, S: VolSize, M> WriteVol for VolMap<V, S, M> {
|
||||
#[inline(always)]
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: V) -> Result<(), VolMapErr> {
|
||||
let ck = Self::chunk_key(pos);
|
||||
self.chunks.get_mut(&ck)
|
||||
self.chunks
|
||||
.get_mut(&ck)
|
||||
.ok_or(VolMapErr::NoSuchChunk)
|
||||
.and_then(|chunk| {
|
||||
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>> {
|
||||
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 log::info;
|
||||
use server::{Event, Input, Server};
|
||||
use std::time::Duration;
|
||||
|
||||
const TPS: u64 = 30;
|
||||
|
||||
@ -15,11 +15,11 @@ fn main() {
|
||||
let mut clock = Clock::new();
|
||||
|
||||
// Create server
|
||||
let mut server = Server::new()
|
||||
.expect("Failed to create server instance");
|
||||
let mut server = Server::new().expect("Failed to create server instance");
|
||||
|
||||
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");
|
||||
|
||||
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)
|
||||
{
|
||||
Some(current_pos) => {
|
||||
server.state.write_component(entity, comp::phys::Pos(current_pos.0 + Vec3::new(x, y, z)));
|
||||
server.state.write_component(entity, comp::phys::ForceUpdate);
|
||||
},
|
||||
server.state.write_component(
|
||||
entity,
|
||||
comp::phys::Pos(current_pos.0 + Vec3::new(x, y, z)),
|
||||
);
|
||||
server
|
||||
.state
|
||||
.write_component(entity, comp::phys::ForceUpdate);
|
||||
}
|
||||
None => server.clients.notify(
|
||||
entity,
|
||||
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);
|
||||
match (opt_x, opt_y, opt_z) {
|
||||
(Some(x), Some(y), Some(z)) => {
|
||||
server.state.write_component(entity, comp::phys::Pos(Vec3::new(x, y, z)));
|
||||
server.state.write_component(entity, comp::phys::ForceUpdate);
|
||||
},
|
||||
server
|
||||
.state
|
||||
.write_component(entity, comp::phys::Pos(Vec3::new(x, y, z)));
|
||||
server
|
||||
.state
|
||||
.write_component(entity, comp::phys::ForceUpdate);
|
||||
}
|
||||
_ => server
|
||||
.clients
|
||||
.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) => {
|
||||
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(
|
||||
entity,
|
||||
ServerMsg::Chat(format!("Unable to teleport to player '{}'", alias)),
|
||||
|
@ -8,20 +8,10 @@ pub mod input;
|
||||
// Reexports
|
||||
pub use crate::{error::Error, input::Input};
|
||||
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
net::SocketAddr,
|
||||
sync::mpsc,
|
||||
time::Duration,
|
||||
i32,
|
||||
use crate::{
|
||||
client::{Client, Clients},
|
||||
cmd::CHAT_COMMANDS,
|
||||
};
|
||||
use specs::{
|
||||
join::Join, saveload::MarkedBuilder, world::EntityBuilder as EcsEntityBuilder, Builder,
|
||||
Entity as EcsEntity,
|
||||
};
|
||||
use threadpool::ThreadPool;
|
||||
use vek::*;
|
||||
use world::World;
|
||||
use common::{
|
||||
comp,
|
||||
comp::character::Animation,
|
||||
@ -30,10 +20,14 @@ use common::{
|
||||
state::{State, Uid},
|
||||
terrain::TerrainChunk,
|
||||
};
|
||||
use crate::{
|
||||
client::{Client, Clients},
|
||||
cmd::CHAT_COMMANDS,
|
||||
use specs::{
|
||||
join::Join, saveload::MarkedBuilder, world::EntityBuilder as EcsEntityBuilder, Builder,
|
||||
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
|
||||
|
||||
@ -193,15 +187,20 @@ impl Server {
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<comp::Player>(),
|
||||
&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 dist = (chunk_pos - key).map(|e| e.abs()).reduce_max();
|
||||
|
||||
if dist < 4 {
|
||||
self.clients.notify(entity, ServerMsg::TerrainChunkUpdate {
|
||||
self.clients.notify(
|
||||
entity,
|
||||
ServerMsg::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Box::new(chunk.clone()),
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,7 +217,9 @@ impl Server {
|
||||
for (_, pos) in (
|
||||
&self.state.ecs().read_storage::<comp::Player>(),
|
||||
&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 dist = (chunk_pos - key).map(|e| e.abs()).reduce_max();
|
||||
min_dist = min_dist.min(dist);
|
||||
@ -297,44 +298,69 @@ impl Server {
|
||||
ClientState::Connected => disconnect = true, // Default state
|
||||
ClientState::Registered => match client.client_state {
|
||||
// Use ClientMsg::Register instead
|
||||
ClientState::Connected => client.error_state(RequestStateError::WrongMessage),
|
||||
ClientState::Registered => client.error_state(RequestStateError::Already),
|
||||
ClientState::Spectator | ClientState::Character
|
||||
=> client.allow_state(ClientState::Registered),
|
||||
ClientState::Connected => {
|
||||
client.error_state(RequestStateError::WrongMessage)
|
||||
}
|
||||
ClientState::Registered => {
|
||||
client.error_state(RequestStateError::Already)
|
||||
}
|
||||
ClientState::Spectator | ClientState::Character => {
|
||||
client.allow_state(ClientState::Registered)
|
||||
}
|
||||
},
|
||||
ClientState::Spectator => match requested_state {
|
||||
// Become Registered first
|
||||
ClientState::Connected => client.error_state(RequestStateError::Impossible),
|
||||
ClientState::Spectator => client.error_state(RequestStateError::Already),
|
||||
ClientState::Registered | ClientState::Character
|
||||
=> client.allow_state(ClientState::Spectator),
|
||||
ClientState::Connected => {
|
||||
client.error_state(RequestStateError::Impossible)
|
||||
}
|
||||
ClientState::Spectator => {
|
||||
client.error_state(RequestStateError::Already)
|
||||
}
|
||||
ClientState::Registered | ClientState::Character => {
|
||||
client.allow_state(ClientState::Spectator)
|
||||
}
|
||||
},
|
||||
// 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 {
|
||||
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)
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
},
|
||||
ClientMsg::Character(character) => match client.client_state {
|
||||
// Become Registered first
|
||||
ClientState::Connected => client.error_state(RequestStateError::Impossible),
|
||||
ClientState::Registered | ClientState::Spectator =>
|
||||
Self::create_player_character(state, entity, client, character),
|
||||
ClientState::Character => client.error_state(RequestStateError::Already),
|
||||
ClientState::Connected => {
|
||||
client.error_state(RequestStateError::Impossible)
|
||||
}
|
||||
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 {
|
||||
ClientState::Connected => client.error_state(RequestStateError::Impossible),
|
||||
ClientState::Connected => {
|
||||
client.error_state(RequestStateError::Impossible)
|
||||
}
|
||||
ClientState::Registered
|
||||
| ClientState::Spectator
|
||||
| ClientState::Character => new_chat_msgs.push((entity, msg)),
|
||||
},
|
||||
ClientMsg::PlayerAnimation(animation_history) => match client.client_state {
|
||||
ClientState::Character => state.write_component(entity, animation_history),
|
||||
ClientMsg::PlayerAnimation(animation_history) => {
|
||||
match client.client_state {
|
||||
ClientState::Character => {
|
||||
state.write_component(entity, animation_history)
|
||||
}
|
||||
// Only characters can send animations
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
}
|
||||
}
|
||||
ClientMsg::PlayerPhysics { pos, vel, dir } => match client.client_state {
|
||||
ClientState::Character => {
|
||||
state.write_component(entity, pos);
|
||||
@ -350,10 +376,12 @@ impl Server {
|
||||
}
|
||||
ClientState::Spectator | ClientState::Character => {
|
||||
match state.terrain().get_key(key) {
|
||||
Some(chunk) => client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
|
||||
Some(chunk) => {
|
||||
client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Box::new(chunk.clone()),
|
||||
}),
|
||||
})
|
||||
}
|
||||
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::Vel>(),
|
||||
&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()
|
||||
{
|
||||
@ -508,7 +539,10 @@ impl Server {
|
||||
}
|
||||
|
||||
// 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>) {
|
||||
|
@ -5,11 +5,7 @@ use std::f32::consts::PI;
|
||||
use vek::*;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
CharacterSkeleton,
|
||||
super::Animation,
|
||||
SCALE,
|
||||
};
|
||||
use super::{super::Animation, CharacterSkeleton, SCALE};
|
||||
|
||||
pub struct IdleAnimation;
|
||||
|
||||
@ -17,10 +13,7 @@ impl Animation for IdleAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = f64;
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
time: f64,
|
||||
) -> Self::Skeleton {
|
||||
fn update_skeleton(skeleton: &Self::Skeleton, time: f64) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
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.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.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.scale = Vec3::one();
|
||||
|
||||
|
@ -1,18 +1,15 @@
|
||||
pub mod run;
|
||||
pub mod idle;
|
||||
pub mod run;
|
||||
|
||||
// Reexports
|
||||
pub use self::run::RunAnimation;
|
||||
pub use self::idle::IdleAnimation;
|
||||
pub use self::run::RunAnimation;
|
||||
|
||||
// Crate
|
||||
use crate::render::FigureBoneData;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
Skeleton,
|
||||
Bone,
|
||||
};
|
||||
use super::{Bone, Skeleton};
|
||||
|
||||
const SCALE: f32 = 11.0;
|
||||
|
||||
@ -47,7 +44,6 @@ impl CharacterSkeleton {
|
||||
torso: Bone::default(),
|
||||
l_shoulder: Bone::default(),
|
||||
r_shoulder: Bone::default(),
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,7 +71,6 @@ impl Skeleton for CharacterSkeleton {
|
||||
FigureBoneData::default(),
|
||||
FigureBoneData::default(),
|
||||
FigureBoneData::default(),
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
@ -92,6 +87,5 @@ impl Skeleton for CharacterSkeleton {
|
||||
self.torso.interpolate(&target.torso);
|
||||
self.l_shoulder.interpolate(&target.l_shoulder);
|
||||
self.r_shoulder.interpolate(&target.r_shoulder);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,7 @@ use std::f32::consts::PI;
|
||||
use vek::*;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
CharacterSkeleton,
|
||||
super::Animation,
|
||||
SCALE
|
||||
};
|
||||
use super::{super::Animation, CharacterSkeleton, SCALE};
|
||||
|
||||
pub struct RunAnimation;
|
||||
|
||||
@ -17,10 +13,7 @@ impl Animation for RunAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = f64;
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
time: f64,
|
||||
) -> Self::Skeleton {
|
||||
fn update_skeleton(skeleton: &Self::Skeleton, time: f64) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
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.scale = Vec3::one();
|
||||
|
||||
|
||||
next
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,9 @@ impl Bone {
|
||||
}
|
||||
|
||||
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`
|
||||
@ -48,8 +50,5 @@ pub trait Animation {
|
||||
type Dependency;
|
||||
|
||||
/// Returns a new skeleton that is generated by the animation
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
dependency: Self::Dependency,
|
||||
) -> Self::Skeleton;
|
||||
fn update_skeleton(skeleton: &Self::Skeleton, dependency: Self::Dependency) -> Self::Skeleton;
|
||||
}
|
||||
|
@ -85,7 +85,11 @@ impl Chat {
|
||||
|
||||
// Only show if it has the keyboard captured
|
||||
// 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 {
|
||||
let text_edit = TextEdit::new(&self.input)
|
||||
.w(460.0)
|
||||
@ -114,10 +118,12 @@ impl Chat {
|
||||
// Message box
|
||||
Rectangle::fill([470.0, 174.0])
|
||||
.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)
|
||||
} else {
|
||||
r.bottom_left_with_margins_on(ui_widgets.window, 10.0, 10.0)
|
||||
}
|
||||
})
|
||||
.set(self.ids.message_box_bg, ui_widgets);
|
||||
let (mut items, _) = List::flow_down(self.messages.len() + 1)
|
||||
|
@ -176,7 +176,6 @@ pub(self) struct Imgs {
|
||||
inv_slot: ImgId,
|
||||
|
||||
// Buttons
|
||||
|
||||
mmap_closed: ImgId,
|
||||
mmap_closed_hover: ImgId,
|
||||
mmap_closed_press: ImgId,
|
||||
@ -670,18 +669,29 @@ impl Hud {
|
||||
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)
|
||||
.set(self.ids.mmap_frame_bg, ui_widgets);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Image::new(self.imgs.mmap_frame_closed)
|
||||
.w_h(100.0 * 2.0, 11.0 * 2.0)
|
||||
.top_right_with_margins_on(ui_widgets.window, 5.0, 5.0)
|
||||
.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)
|
||||
.hover_image(if self.mmap_open {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})
|
||||
.hover_image(if self.mmap_open {
|
||||
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)
|
||||
.set(self.ids.mmap_button, ui_widgets)
|
||||
.was_clicked()
|
||||
@ -1590,7 +1600,6 @@ impl Hud {
|
||||
.w_h(412.0, 488.0)
|
||||
.set(self.ids.map_frame_bl, ui_widgets);
|
||||
|
||||
|
||||
// Icon
|
||||
Image::new(self.imgs.map_icon)
|
||||
.w_h(224.0 / 3.0, 224.0 / 3.0)
|
||||
|
@ -10,22 +10,18 @@ pub mod mesh;
|
||||
pub mod render;
|
||||
pub mod scene;
|
||||
pub mod session;
|
||||
pub mod ui;
|
||||
pub mod window;
|
||||
pub mod settings;
|
||||
pub mod singleplayer;
|
||||
pub mod ui;
|
||||
pub mod window;
|
||||
|
||||
// Reexports
|
||||
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 simplelog::{CombinedLogger, TermLogger, WriteLogger, Config};
|
||||
use crate::{
|
||||
menu::main::MainMenuState,
|
||||
window::Window,
|
||||
settings::Settings,
|
||||
};
|
||||
use simplelog::{CombinedLogger, Config, TermLogger, WriteLogger};
|
||||
use std::{fs::File, mem, panic, str::FromStr, thread};
|
||||
|
||||
/// The URL of the default public server that Voxygen will connect to
|
||||
const DEFAULT_PUBLIC_SERVER: &'static str = "server.veloren.net";
|
||||
@ -82,7 +78,7 @@ fn main() {
|
||||
let settings = Settings::default();
|
||||
settings.save_to_file();
|
||||
settings
|
||||
},
|
||||
}
|
||||
};
|
||||
let window = Window::new(&settings).expect("Failed to create window");
|
||||
|
||||
@ -93,8 +89,13 @@ fn main() {
|
||||
.unwrap_or(log::LevelFilter::Warn);
|
||||
CombinedLogger::init(vec![
|
||||
TermLogger::new(term_log_level, Config::default()).unwrap(),
|
||||
WriteLogger::new(log::LevelFilter::Info, Config::default(), File::create(&settings.log.file).unwrap()),
|
||||
]).unwrap();
|
||||
WriteLogger::new(
|
||||
log::LevelFilter::Info,
|
||||
Config::default(),
|
||||
File::create(&settings.log.file).unwrap(),
|
||||
),
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
// Set up panic handler to relay swish panic messages to the user
|
||||
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);
|
||||
}));
|
||||
|
||||
let mut global_state = GlobalState {
|
||||
settings,
|
||||
window,
|
||||
};
|
||||
let mut global_state = GlobalState { settings, window };
|
||||
|
||||
// Set up the initial play state
|
||||
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(
|
||||
&mut global_state,
|
||||
))];
|
||||
states.last().map(|current_state| {
|
||||
log::info!("Started game with state '{}'", current_state.name())
|
||||
});
|
||||
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(&mut global_state))];
|
||||
states
|
||||
.last()
|
||||
.map(|current_state| log::info!("Started game with state '{}'", current_state.name()));
|
||||
|
||||
// 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
|
||||
// re-engineer it for each menu we decide to add to the game.
|
||||
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
|
||||
match state_result {
|
||||
PlayStateResult::Shutdown => {
|
||||
@ -160,28 +159,32 @@ The information below is intended for developers and testers.
|
||||
global_state.on_play_state_changed();
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
PlayStateResult::Pop => {
|
||||
direction = Direction::Backwards;
|
||||
states.pop().map(|old_state| {
|
||||
log::info!("Popped state '{}'", old_state.name());
|
||||
global_state.on_play_state_changed();
|
||||
});
|
||||
},
|
||||
}
|
||||
PlayStateResult::Push(new_state) => {
|
||||
direction = Direction::Forwards;
|
||||
log::info!("Pushed state '{}'", new_state.name());
|
||||
states.push(new_state);
|
||||
global_state.on_play_state_changed();
|
||||
},
|
||||
}
|
||||
PlayStateResult::Switch(mut new_state) => {
|
||||
direction = Direction::Forwards;
|
||||
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);
|
||||
global_state.on_play_state_changed();
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
mod ui;
|
||||
|
||||
use crate::{
|
||||
window::{Event, Window},
|
||||
session::SessionState,
|
||||
window::{Event, Window},
|
||||
Direction, GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::{
|
||||
clock::Clock,
|
||||
msg::ClientMsg,
|
||||
};
|
||||
use common::{clock::Clock, msg::ClientMsg};
|
||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
use ui::CharSelectionUi;
|
||||
use vek::*;
|
||||
@ -50,7 +47,7 @@ impl PlayState for CharSelectionState {
|
||||
match event {
|
||||
Event::Close => {
|
||||
return PlayStateResult::Shutdown;
|
||||
},
|
||||
}
|
||||
// Pass events to ui
|
||||
Event::Ui(event) => {
|
||||
self.char_selection_ui.handle_event(event);
|
||||
@ -63,23 +60,35 @@ impl PlayState for CharSelectionState {
|
||||
global_state.window.renderer_mut().clear(BG_COLOR);
|
||||
|
||||
// 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 {
|
||||
ui::Event::Logout => {
|
||||
return PlayStateResult::Pop;
|
||||
},
|
||||
}
|
||||
ui::Event::Play => {
|
||||
self.client.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())));
|
||||
self.client
|
||||
.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
|
||||
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)
|
||||
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");
|
||||
self.client.borrow_mut().cleanup();
|
||||
|
||||
|
@ -5,19 +5,8 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
assets,
|
||||
comp::character::{Belt, Character, Chest, Foot, Gender, Hand, Head, Pants, Race, Weapon},
|
||||
figure::Segment,
|
||||
comp::character::{
|
||||
Character,
|
||||
Race,
|
||||
Gender,
|
||||
Head,
|
||||
Chest,
|
||||
Belt,
|
||||
Pants,
|
||||
Hand,
|
||||
Foot,
|
||||
Weapon,
|
||||
}
|
||||
};
|
||||
use conrod_core::{
|
||||
color,
|
||||
@ -381,10 +370,12 @@ impl CharSelectionUi {
|
||||
// Load fonts
|
||||
let load_font = |filename, ui: &mut Ui| {
|
||||
let fullpath: String = ["/voxygen/font", filename].concat();
|
||||
ui.new_font(conrod_core::text::Font::from_bytes(
|
||||
assets::load(fullpath.as_str())
|
||||
.expect("Error loading file")
|
||||
).unwrap())
|
||||
ui.new_font(
|
||||
conrod_core::text::Font::from_bytes(
|
||||
assets::load(fullpath.as_str()).expect("Error loading file"),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
};
|
||||
let font_opensans = load_font("/OpenSans-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>>,
|
||||
}
|
||||
impl ClientInit {
|
||||
pub fn new(
|
||||
connection_args: (String, u16, bool),
|
||||
client_args: (comp::Player, u64),
|
||||
) -> Self {
|
||||
pub fn new(connection_args: (String, u16, bool), client_args: (comp::Player, u64)) -> Self {
|
||||
let (server_address, default_port, prefer_ipv6) = connection_args;
|
||||
let (player, view_distance) = client_args;
|
||||
|
||||
|
@ -2,7 +2,6 @@ mod client_init;
|
||||
mod start_singleplayer;
|
||||
mod ui;
|
||||
|
||||
use start_singleplayer::StartSingleplayerState;
|
||||
use super::char_selection::CharSelectionState;
|
||||
use crate::{
|
||||
window::{Event, Window},
|
||||
@ -10,6 +9,7 @@ use crate::{
|
||||
};
|
||||
use client_init::{ClientInit, Error as InitError};
|
||||
use common::{clock::Clock, comp};
|
||||
use start_singleplayer::StartSingleplayerState;
|
||||
use std::time::Duration;
|
||||
use ui::{Event as MainMenuEvent, MainMenuUi};
|
||||
use vek::*;
|
||||
@ -86,10 +86,7 @@ impl PlayState for MainMenuState {
|
||||
}
|
||||
|
||||
// Maintain the UI
|
||||
for event in self
|
||||
.main_menu_ui
|
||||
.maintain(global_state)
|
||||
{
|
||||
for event in self.main_menu_ui.maintain(global_state) {
|
||||
match event {
|
||||
MainMenuEvent::LoginAttempt {
|
||||
username,
|
||||
@ -104,15 +101,12 @@ impl PlayState for MainMenuState {
|
||||
// Don't try to connect if there is already a connection in progress
|
||||
client_init = client_init.or(Some(ClientInit::new(
|
||||
(server_address, DEFAULT_PORT, false),
|
||||
(
|
||||
comp::Player::new(username.clone()),
|
||||
300,
|
||||
),
|
||||
(comp::Player::new(username.clone()), 300),
|
||||
)));
|
||||
},
|
||||
}
|
||||
MainMenuEvent::StartSingleplayer => {
|
||||
return PlayStateResult::Push(Box::new(StartSingleplayerState::new()));
|
||||
},
|
||||
}
|
||||
MainMenuEvent::Quit => return PlayStateResult::Shutdown,
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
use common::comp;
|
||||
use super::{DEFAULT_PORT, client_init::ClientInit};
|
||||
use super::{client_init::ClientInit, DEFAULT_PORT};
|
||||
use crate::{
|
||||
menu::char_selection::CharSelectionState,
|
||||
singleplayer::Singleplayer,
|
||||
Direction, GlobalState, PlayState, PlayStateResult,
|
||||
menu::char_selection::CharSelectionState, singleplayer::Singleplayer, Direction, GlobalState,
|
||||
PlayState, PlayStateResult,
|
||||
};
|
||||
use common::comp;
|
||||
|
||||
pub struct StartSingleplayerState {
|
||||
singleplayer: Singleplayer,
|
||||
@ -28,10 +27,7 @@ impl PlayState for StartSingleplayerState {
|
||||
|
||||
let client_init = ClientInit::new(
|
||||
(server_address.clone(), DEFAULT_PORT, false),
|
||||
(
|
||||
comp::Player::new(username.clone()),
|
||||
300,
|
||||
),
|
||||
(comp::Player::new(username.clone()), 300),
|
||||
);
|
||||
|
||||
// Client creation
|
||||
@ -40,7 +36,7 @@ impl PlayState for StartSingleplayerState {
|
||||
Some(Ok(client)) => break client,
|
||||
// Should always work
|
||||
Some(Err(err)) => unreachable!(),
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
|
||||
@ -55,7 +51,7 @@ impl PlayState for StartSingleplayerState {
|
||||
&mut global_state.window,
|
||||
std::rc::Rc::new(std::cell::RefCell::new(client)),
|
||||
)))
|
||||
},
|
||||
}
|
||||
Direction::Backwards => PlayStateResult::Pop,
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
mod vol;
|
||||
pub mod segment;
|
||||
pub mod terrain;
|
||||
mod vol;
|
||||
|
||||
// Crate
|
||||
use crate::render::{self, Mesh};
|
||||
|
@ -1,14 +1,8 @@
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
traits::FactoryExt,
|
||||
};
|
||||
use gfx::{self, traits::FactoryExt};
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
RenderError,
|
||||
gfx_backend,
|
||||
};
|
||||
use super::{gfx_backend, RenderError};
|
||||
|
||||
/// 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.
|
||||
@ -31,7 +25,8 @@ impl<T: Copy + gfx::traits::Pod> Consts<T> {
|
||||
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
||||
vals: &[T],
|
||||
) -> Result<(), RenderError> {
|
||||
encoder.update_buffer(&self.buf, vals, 0)
|
||||
encoder
|
||||
.update_buffer(&self.buf, vals, 0)
|
||||
.map_err(|err| RenderError::UpdateError(err))
|
||||
}
|
||||
}
|
||||
|
@ -75,11 +75,7 @@ pub struct Tri<P: Pipeline> {
|
||||
}
|
||||
|
||||
impl<P: Pipeline> Tri<P> {
|
||||
pub fn new(
|
||||
a: P::Vertex,
|
||||
b: P::Vertex,
|
||||
c: P::Vertex,
|
||||
) -> Self {
|
||||
pub fn new(a: P::Vertex, b: P::Vertex, c: P::Vertex) -> Self {
|
||||
Self { a, b, c }
|
||||
}
|
||||
}
|
||||
@ -93,12 +89,7 @@ pub struct Quad<P: Pipeline> {
|
||||
}
|
||||
|
||||
impl<P: Pipeline> Quad<P> {
|
||||
pub fn new(
|
||||
a: P::Vertex,
|
||||
b: P::Vertex,
|
||||
c: P::Vertex,
|
||||
d: P::Vertex,
|
||||
) -> Self {
|
||||
pub fn new(a: P::Vertex, b: P::Vertex, c: P::Vertex, d: P::Vertex) -> Self {
|
||||
Self { a, b, c, d }
|
||||
}
|
||||
}
|
||||
|
@ -9,33 +9,19 @@ mod util;
|
||||
// Reexports
|
||||
pub use self::{
|
||||
consts::Consts,
|
||||
mesh::{Mesh, Tri, Quad},
|
||||
mesh::{Mesh, Quad, Tri},
|
||||
model::Model,
|
||||
texture::Texture,
|
||||
renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
|
||||
pipelines::{
|
||||
Globals,
|
||||
figure::{
|
||||
FigurePipeline,
|
||||
Locals as FigureLocals,
|
||||
BoneData as FigureBoneData,
|
||||
},
|
||||
skybox::{
|
||||
create_mesh as create_skybox_mesh,
|
||||
SkyboxPipeline,
|
||||
Locals as SkyboxLocals,
|
||||
},
|
||||
terrain::{
|
||||
TerrainPipeline,
|
||||
Locals as TerrainLocals,
|
||||
},
|
||||
figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals},
|
||||
skybox::{create_mesh as create_skybox_mesh, Locals as SkyboxLocals, SkyboxPipeline},
|
||||
terrain::{Locals as TerrainLocals, TerrainPipeline},
|
||||
ui::{
|
||||
create_quad as create_ui_quad,
|
||||
create_tri as create_ui_tri,
|
||||
Mode as UiMode,
|
||||
UiPipeline,
|
||||
create_quad as create_ui_quad, create_tri as create_ui_tri, Mode as UiMode, UiPipeline,
|
||||
},
|
||||
Globals,
|
||||
},
|
||||
renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
|
||||
texture::Texture,
|
||||
};
|
||||
|
||||
#[cfg(feature = "gl")]
|
||||
@ -64,8 +50,5 @@ pub enum RenderError {
|
||||
/// - `SkyboxPipeline`
|
||||
/// - `FigurePipeline`
|
||||
pub trait Pipeline {
|
||||
type Vertex:
|
||||
Clone +
|
||||
gfx::traits::Pod +
|
||||
gfx::pso::buffer::Structure<gfx::format::Format>;
|
||||
type Vertex: Clone + gfx::traits::Pod + gfx::pso::buffer::Structure<gfx::format::Format>;
|
||||
}
|
||||
|
@ -1,15 +1,8 @@
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
traits::FactoryExt,
|
||||
};
|
||||
use gfx::{self, traits::FactoryExt};
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
mesh::Mesh,
|
||||
Pipeline,
|
||||
gfx_backend,
|
||||
};
|
||||
use super::{gfx_backend, mesh::Mesh, Pipeline};
|
||||
|
||||
/// Represents a mesh that has been sent to the GPU.
|
||||
pub struct Model<P: Pipeline> {
|
||||
@ -18,10 +11,7 @@ pub struct Model<P: Pipeline> {
|
||||
}
|
||||
|
||||
impl<P: Pipeline> Model<P> {
|
||||
pub fn new(
|
||||
factory: &mut gfx_backend::Factory,
|
||||
mesh: &Mesh<P>,
|
||||
) -> Self {
|
||||
pub fn new(factory: &mut gfx_backend::Factory, mesh: &Mesh<P>) -> Self {
|
||||
Self {
|
||||
vbuf: factory.create_vertex_buffer(mesh.vertices()),
|
||||
slice: gfx::Slice {
|
||||
|
@ -1,25 +1,20 @@
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
gfx_constant_struct_meta,
|
||||
// Macros
|
||||
gfx_defines,
|
||||
gfx_vertex_struct_meta,
|
||||
gfx_constant_struct_meta,
|
||||
gfx_impl_struct_meta,
|
||||
gfx_pipeline,
|
||||
gfx_pipeline_inner,
|
||||
gfx_vertex_struct_meta,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
super::{util::arr_to_mat, Pipeline, TgtColorFmt, TgtDepthFmt},
|
||||
Globals,
|
||||
super::{
|
||||
Pipeline,
|
||||
TgtColorFmt,
|
||||
TgtDepthFmt,
|
||||
util::arr_to_mat,
|
||||
},
|
||||
};
|
||||
|
||||
gfx_defines! {
|
||||
|
@ -6,9 +6,9 @@ pub mod ui;
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
gfx_constant_struct_meta,
|
||||
// Macros
|
||||
gfx_defines,
|
||||
gfx_constant_struct_meta,
|
||||
gfx_impl_struct_meta,
|
||||
};
|
||||
use vek::*;
|
||||
|
@ -1,25 +1,19 @@
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
gfx_constant_struct_meta,
|
||||
// Macros
|
||||
gfx_defines,
|
||||
gfx_vertex_struct_meta,
|
||||
gfx_constant_struct_meta,
|
||||
gfx_impl_struct_meta,
|
||||
gfx_pipeline,
|
||||
gfx_pipeline_inner,
|
||||
gfx_vertex_struct_meta,
|
||||
};
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
super::{Mesh, Pipeline, Quad, TgtColorFmt, TgtDepthFmt},
|
||||
Globals,
|
||||
super::{
|
||||
Pipeline,
|
||||
TgtColorFmt,
|
||||
TgtDepthFmt,
|
||||
Mesh,
|
||||
Quad,
|
||||
},
|
||||
};
|
||||
|
||||
gfx_defines! {
|
||||
|
@ -1,24 +1,20 @@
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
gfx_constant_struct_meta,
|
||||
// Macros
|
||||
gfx_defines,
|
||||
gfx_vertex_struct_meta,
|
||||
gfx_constant_struct_meta,
|
||||
gfx_impl_struct_meta,
|
||||
gfx_pipeline,
|
||||
gfx_pipeline_inner,
|
||||
gfx_vertex_struct_meta,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
super::{Pipeline, TgtColorFmt, TgtDepthFmt},
|
||||
Globals,
|
||||
super::{
|
||||
Pipeline,
|
||||
TgtColorFmt,
|
||||
TgtDepthFmt,
|
||||
},
|
||||
};
|
||||
|
||||
gfx_defines! {
|
||||
|
@ -1,20 +1,14 @@
|
||||
use super::super::{Pipeline, Quad, TgtColorFmt, TgtDepthFmt, Tri};
|
||||
use gfx::{
|
||||
self,
|
||||
// Macros
|
||||
gfx_defines,
|
||||
gfx_vertex_struct_meta,
|
||||
gfx_impl_struct_meta,
|
||||
gfx_pipeline,
|
||||
gfx_pipeline_inner,
|
||||
gfx_vertex_struct_meta,
|
||||
};
|
||||
use vek::*;
|
||||
use super::super::{
|
||||
Pipeline,
|
||||
TgtColorFmt,
|
||||
TgtDepthFmt,
|
||||
Quad,
|
||||
Tri,
|
||||
};
|
||||
|
||||
gfx_defines! {
|
||||
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 v = |pos, uv| {
|
||||
Vertex {
|
||||
let v = |pos, uv| Vertex {
|
||||
pos,
|
||||
uv,
|
||||
color: color.into_array(),
|
||||
mode: mode_val,
|
||||
}
|
||||
};
|
||||
let aabr_to_lbrt = |aabr: Aabr<f32>| (
|
||||
aabr.min.x, aabr.min.y,
|
||||
aabr.max.x, aabr.max.y,
|
||||
);
|
||||
let aabr_to_lbrt = |aabr: Aabr<f32>| (aabr.min.x, aabr.min.y, aabr.max.x, aabr.max.y);
|
||||
|
||||
let (l, b, r, t) = aabr_to_lbrt(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 v = |pos, uv| {
|
||||
Vertex {
|
||||
let v = |pos, uv| Vertex {
|
||||
pos,
|
||||
uv,
|
||||
color: color.into_array(),
|
||||
mode: mode_val,
|
||||
}
|
||||
};
|
||||
Tri::new(
|
||||
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::{
|
||||
self,
|
||||
traits::{Device, FactoryExt},
|
||||
};
|
||||
use image;
|
||||
use super::{
|
||||
consts::Consts,
|
||||
mesh::Mesh,
|
||||
model::Model,
|
||||
texture::Texture,
|
||||
Pipeline,
|
||||
RenderError,
|
||||
gfx_backend,
|
||||
pipelines::{
|
||||
Globals,
|
||||
figure,
|
||||
skybox,
|
||||
terrain,
|
||||
ui,
|
||||
},
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
/// Represents the format of the window's color target.
|
||||
pub type TgtColorFmt = gfx::format::Rgba8;
|
||||
@ -149,37 +142,30 @@ impl Renderer {
|
||||
pub fn update_consts<T: Copy + gfx::traits::Pod>(
|
||||
&mut self,
|
||||
consts: &mut Consts<T>,
|
||||
vals: &[T]
|
||||
vals: &[T],
|
||||
) -> Result<(), RenderError> {
|
||||
consts.update(&mut self.encoder, vals)
|
||||
}
|
||||
|
||||
/// Create a new model from the provided mesh.
|
||||
pub fn create_model<P: Pipeline>(&mut self, mesh: &Mesh<P>) -> Result<Model<P>, RenderError> {
|
||||
Ok(Model::new(
|
||||
&mut self.factory,
|
||||
mesh,
|
||||
))
|
||||
Ok(Model::new(&mut self.factory, mesh))
|
||||
}
|
||||
|
||||
/// Create a new texture from the provided image.
|
||||
pub fn create_texture<P: Pipeline>(&mut self, image: &image::DynamicImage) -> Result<Texture<P>, RenderError> {
|
||||
Texture::new(
|
||||
&mut self.factory,
|
||||
image,
|
||||
)
|
||||
pub fn create_texture<P: Pipeline>(
|
||||
&mut self,
|
||||
image: &image::DynamicImage,
|
||||
) -> Result<Texture<P>, RenderError> {
|
||||
Texture::new(&mut self.factory, image)
|
||||
}
|
||||
|
||||
/// Create a new dynamic texture (gfx::memory::Usage::Dynamic) with the specified dimensions
|
||||
pub fn create_dynamic_texture<P: Pipeline>(
|
||||
&mut self,
|
||||
dims: Vec2<u16>
|
||||
dims: Vec2<u16>,
|
||||
) -> Result<Texture<P>, RenderError> {
|
||||
Texture::new_dynamic(
|
||||
&mut self.factory,
|
||||
dims.x,
|
||||
dims.y,
|
||||
)
|
||||
Texture::new_dynamic(&mut self.factory, dims.x, dims.y)
|
||||
}
|
||||
|
||||
/// Update a texture with the provided offset, size, and data
|
||||
@ -188,14 +174,9 @@ impl Renderer {
|
||||
texture: &Texture<P>,
|
||||
offset: [u16; 2],
|
||||
size: [u16; 2],
|
||||
data: &[[u8; 4]]
|
||||
data: &[[u8; 4]],
|
||||
) -> Result<(), RenderError> {
|
||||
texture.update(
|
||||
&mut self.encoder,
|
||||
offset,
|
||||
size,
|
||||
data,
|
||||
)
|
||||
texture.update(&mut self.encoder, offset, size, data)
|
||||
}
|
||||
|
||||
/// Queue the rendering of the provided skybox model in the upcoming frame.
|
||||
@ -273,7 +254,12 @@ impl Renderer {
|
||||
&self.ui_pipeline.pso,
|
||||
&ui::pipe::Data {
|
||||
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()),
|
||||
tgt_color: self.tgt_color_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)))?;
|
||||
|
||||
Ok(GfxPipeline {
|
||||
pso: factory.create_pipeline_from_program(
|
||||
pso: factory
|
||||
.create_pipeline_from_program(
|
||||
&program,
|
||||
gfx::Primitive::TriangleList,
|
||||
gfx::state::Rasterizer {
|
||||
@ -311,13 +298,16 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>(
|
||||
pipe,
|
||||
)
|
||||
// Do some funky things to work around an oddity in gfx's error ownership rules
|
||||
.map_err(|err| RenderError::PipelineError(match err {
|
||||
gfx::PipelineStateError::Program(err) =>
|
||||
gfx::PipelineStateError::Program(err),
|
||||
gfx::PipelineStateError::DescriptorInit(err) =>
|
||||
gfx::PipelineStateError::DescriptorInit(err.into()),
|
||||
gfx::PipelineStateError::DeviceCreate(err) =>
|
||||
gfx::PipelineStateError::DeviceCreate(err),
|
||||
}))?,
|
||||
.map_err(|err| {
|
||||
RenderError::PipelineError(match err {
|
||||
gfx::PipelineStateError::Program(err) => gfx::PipelineStateError::Program(err),
|
||||
gfx::PipelineStateError::DescriptorInit(err) => {
|
||||
gfx::PipelineStateError::DescriptorInit(err.into())
|
||||
}
|
||||
gfx::PipelineStateError::DeviceCreate(err) => {
|
||||
gfx::PipelineStateError::DeviceCreate(err)
|
||||
}
|
||||
})
|
||||
})?,
|
||||
})
|
||||
}
|
||||
|
@ -2,29 +2,25 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
traits::Factory,
|
||||
};
|
||||
use image::{
|
||||
DynamicImage,
|
||||
GenericImageView,
|
||||
};
|
||||
use gfx::{self, traits::Factory};
|
||||
use image::{DynamicImage, GenericImageView};
|
||||
use vek::Vec2;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
RenderError,
|
||||
Pipeline,
|
||||
gfx_backend,
|
||||
};
|
||||
use super::{gfx_backend, Pipeline, RenderError};
|
||||
|
||||
type ShaderFormat = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb);
|
||||
|
||||
/// Represents an image that has been uploaded to the GPU.
|
||||
pub struct Texture<P: Pipeline> {
|
||||
pub tex: gfx::handle::Texture<gfx_backend::Resources, <ShaderFormat as gfx::format::Formatted>::Surface>,
|
||||
pub srv: gfx::handle::ShaderResourceView<gfx_backend::Resources, <ShaderFormat as gfx::format::Formatted>::View>,
|
||||
pub tex: gfx::handle::Texture<
|
||||
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>,
|
||||
_phantom: PhantomData<P>,
|
||||
}
|
||||
@ -34,7 +30,8 @@ impl<P: Pipeline> Texture<P> {
|
||||
factory: &mut gfx_backend::Factory,
|
||||
image: &DynamicImage,
|
||||
) -> 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(
|
||||
image.width() as u16,
|
||||
image.height() as u16,
|
||||
@ -73,8 +70,12 @@ impl<P: Pipeline> Texture<P> {
|
||||
)
|
||||
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?;
|
||||
|
||||
let srv =
|
||||
factory.view_texture_as_shader_resource::<ShaderFormat>(&tex, (0, 0), gfx::format::Swizzle::new())
|
||||
let srv = factory
|
||||
.view_texture_as_shader_resource::<ShaderFormat>(
|
||||
&tex,
|
||||
(0, 0),
|
||||
gfx::format::Swizzle::new(),
|
||||
)
|
||||
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Resource(err)))?;
|
||||
|
||||
Ok(Self {
|
||||
@ -107,7 +108,9 @@ impl<P: Pipeline> Texture<P> {
|
||||
mipmap: 0,
|
||||
};
|
||||
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))
|
||||
}
|
||||
/// Get dimensions of the represented image
|
||||
|
@ -38,12 +38,7 @@ impl Camera {
|
||||
* Mat4::rotation_3d(PI / 2.0, -Vec4::unit_x())
|
||||
* Mat4::translation_3d(-self.focus);
|
||||
|
||||
let proj_mat = Mat4::perspective_rh_no(
|
||||
self.fov,
|
||||
self.aspect,
|
||||
NEAR_PLANE,
|
||||
FAR_PLANE,
|
||||
);
|
||||
let proj_mat = Mat4::perspective_rh_no(self.fov, self.aspect, NEAR_PLANE, FAR_PLANE);
|
||||
|
||||
// TODO: Make this more efficient
|
||||
let cam_pos = Vec3::from(view_mat.inverted() * Vec4::unit_w());
|
||||
@ -56,9 +51,7 @@ impl Camera {
|
||||
// Wrap camera yaw
|
||||
self.ori.x = (self.ori.x + delta.x) % (2.0 * PI);
|
||||
// Clamp camera pitch to the vertical limits
|
||||
self.ori.y = (self.ori.y + delta.y)
|
||||
.min(PI / 2.0)
|
||||
.max(-PI / 2.0);
|
||||
self.ori.y = (self.ori.y + delta.y).min(PI / 2.0).max(-PI / 2.0);
|
||||
// Wrap camera roll
|
||||
self.ori.z = (self.ori.z + delta.z) % (2.0 * PI);
|
||||
}
|
||||
@ -70,15 +63,25 @@ impl 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.
|
||||
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.
|
||||
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.
|
||||
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
|
||||
pub fn get_orientation(&self) -> Vec3<f32> { self.ori }
|
||||
pub fn get_orientation(&self) -> Vec3<f32> {
|
||||
self.ori
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +1,27 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
f32,
|
||||
use crate::{
|
||||
anim::{
|
||||
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 common::{
|
||||
assets,
|
||||
comp::{
|
||||
self,
|
||||
character::{
|
||||
Character,
|
||||
Head,
|
||||
Chest,
|
||||
Belt,
|
||||
Pants,
|
||||
Hand,
|
||||
Foot,
|
||||
Weapon,
|
||||
}
|
||||
character::{Belt, Character, Chest, Foot, Hand, Head, Pants, Weapon},
|
||||
},
|
||||
figure::Segment,
|
||||
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 {
|
||||
models: HashMap<Character, (Model<FigurePipeline>, u64)>,
|
||||
@ -64,14 +40,17 @@ impl FigureCache {
|
||||
models: &'a mut HashMap<Character, (Model<FigurePipeline>, u64)>,
|
||||
renderer: &mut Renderer,
|
||||
tick: u64,
|
||||
character: Character)
|
||||
-> &'a (Model<FigurePipeline>, u64) {
|
||||
character: Character,
|
||||
) -> &'a (Model<FigurePipeline>, u64) {
|
||||
match models.get_mut(&character) {
|
||||
Some((model, last_used)) => {
|
||||
*last_used = tick;
|
||||
}
|
||||
None => {
|
||||
models.insert(character, ({
|
||||
models.insert(
|
||||
character,
|
||||
(
|
||||
{
|
||||
let bone_meshes = [
|
||||
Some(Self::load_head(character.head)),
|
||||
Some(Self::load_chest(character.chest)),
|
||||
@ -91,18 +70,22 @@ impl FigureCache {
|
||||
None,
|
||||
];
|
||||
|
||||
|
||||
let mut mesh = Mesh::new();
|
||||
bone_meshes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm)))
|
||||
.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()
|
||||
}, tick));
|
||||
},
|
||||
tick,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,76 +94,106 @@ impl FigureCache {
|
||||
|
||||
pub fn clean(&mut self, tick: u64) {
|
||||
// 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> {
|
||||
let fullpath: String = ["/voxygen/voxel/", filename].concat();
|
||||
Segment::from(dot_vox::load_bytes(
|
||||
Segment::from(
|
||||
dot_vox::load_bytes(
|
||||
assets::load(fullpath.as_str())
|
||||
.expect("Error loading file")
|
||||
.as_slice(),
|
||||
).unwrap())
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.generate_mesh(position)
|
||||
}
|
||||
|
||||
fn load_head(head: Head) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(match head {
|
||||
Self::load_mesh(
|
||||
match head {
|
||||
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> {
|
||||
Self::load_mesh(match chest {
|
||||
Self::load_mesh(
|
||||
match chest {
|
||||
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> {
|
||||
Self::load_mesh(match belt {
|
||||
Self::load_mesh(
|
||||
match belt {
|
||||
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> {
|
||||
Self::load_mesh(match pants {
|
||||
Self::load_mesh(
|
||||
match pants {
|
||||
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> {
|
||||
Self::load_mesh(match hand {
|
||||
Self::load_mesh(
|
||||
match hand {
|
||||
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> {
|
||||
Self::load_mesh(match hand {
|
||||
Self::load_mesh(
|
||||
match hand {
|
||||
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> {
|
||||
Self::load_mesh(match foot {
|
||||
Self::load_mesh(
|
||||
match foot {
|
||||
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> {
|
||||
Self::load_mesh(match foot {
|
||||
Self::load_mesh(
|
||||
match foot {
|
||||
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> {
|
||||
Self::load_mesh(match weapon {
|
||||
Self::load_mesh(
|
||||
match weapon {
|
||||
Weapon::Sword => "sword.vox",
|
||||
// TODO actually match against other weapons and set the right model
|
||||
_ => "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) {
|
||||
let time = client.state().get_time();
|
||||
let ecs = client.state_mut().ecs_mut();
|
||||
@ -190,14 +203,21 @@ impl FigureCache {
|
||||
&ecs.read_storage::<comp::phys::Dir>(),
|
||||
&ecs.read_storage::<comp::Character>(),
|
||||
&ecs.read_storage::<comp::AnimationHistory>(),
|
||||
).join() {
|
||||
let state = self.states
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let state = self
|
||||
.states
|
||||
.entry(entity)
|
||||
.or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
|
||||
|
||||
let target_skeleton = match animation_history.current {
|
||||
comp::character::Animation::Idle => IdleAnimation::update_skeleton(&mut state.skeleton, time),
|
||||
comp::character::Animation::Run => RunAnimation::update_skeleton(&mut state.skeleton, time),
|
||||
comp::character::Animation::Idle => {
|
||||
IdleAnimation::update_skeleton(&mut state.skeleton, time)
|
||||
}
|
||||
comp::character::Animation::Run => {
|
||||
RunAnimation::update_skeleton(&mut state.skeleton, time)
|
||||
}
|
||||
};
|
||||
|
||||
state.skeleton.interpolate(&target_skeleton);
|
||||
@ -205,26 +225,25 @@ impl FigureCache {
|
||||
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 ecs = client.state().ecs();
|
||||
let models = &mut self.models;
|
||||
|
||||
for (entity, &character) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<comp::Character>(),
|
||||
).join() {
|
||||
for (entity, &character) in (&ecs.entities(), &ecs.read_storage::<comp::Character>()).join()
|
||||
{
|
||||
let model = Self::get_or_create_model(models, renderer, tick, character);
|
||||
let state = self.states.get(&entity).unwrap();
|
||||
renderer.render_figure(
|
||||
&model.0,
|
||||
globals,
|
||||
&state.locals,
|
||||
&state.bone_consts,
|
||||
);
|
||||
renderer.render_figure(&model.0, globals, &state.locals, &state.bone_consts);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -238,21 +257,24 @@ pub struct FigureState<S: Skeleton> {
|
||||
impl<S: Skeleton> FigureState<S> {
|
||||
pub fn new(renderer: &mut Renderer, skeleton: S) -> 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(),
|
||||
skeleton,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, renderer: &mut Renderer, pos: Vec3<f32>, dir: Vec3<f32>) {
|
||||
let mat =
|
||||
Mat4::<f32>::identity() *
|
||||
Mat4::translation_3d(pos) *
|
||||
Mat4::rotation_z(-dir.x.atan2(dir.y) + f32::consts::PI / 2.0);
|
||||
let mat = Mat4::<f32>::identity()
|
||||
* Mat4::translation_3d(pos)
|
||||
* Mat4::rotation_z(-dir.x.atan2(dir.y) + f32::consts::PI / 2.0);
|
||||
|
||||
let locals = FigureLocals::new(mat);
|
||||
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 terrain;
|
||||
|
||||
use vek::*;
|
||||
use dot_vox;
|
||||
use common::{
|
||||
comp,
|
||||
figure::Segment,
|
||||
};
|
||||
use client::Client;
|
||||
use self::{camera::Camera, figure::FigureCache, terrain::Terrain};
|
||||
use crate::{
|
||||
anim::{
|
||||
character::{CharacterSkeleton, RunAnimation},
|
||||
Animation,
|
||||
},
|
||||
mesh::Meshable,
|
||||
render::{
|
||||
Consts,
|
||||
Globals,
|
||||
Model,
|
||||
Renderer,
|
||||
create_skybox_mesh, Consts, FigureLocals, Globals, Model, Renderer, SkyboxLocals,
|
||||
SkyboxPipeline,
|
||||
SkyboxLocals,
|
||||
FigureLocals,
|
||||
create_skybox_mesh,
|
||||
},
|
||||
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
|
||||
const CURSOR_PAN_SCALE: f32 = 0.005;
|
||||
@ -56,18 +44,12 @@ impl Scene {
|
||||
let resolution = renderer.get_resolution().map(|e| e as f32);
|
||||
|
||||
Self {
|
||||
globals: renderer
|
||||
.create_consts(&[Globals::default()])
|
||||
.unwrap(),
|
||||
globals: renderer.create_consts(&[Globals::default()]).unwrap(),
|
||||
camera: Camera::new(resolution.x / resolution.y),
|
||||
|
||||
skybox: Skybox {
|
||||
model: renderer
|
||||
.create_model(&create_skybox_mesh())
|
||||
.unwrap(),
|
||||
locals: renderer
|
||||
.create_consts(&[SkyboxLocals::default()])
|
||||
.unwrap(),
|
||||
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
|
||||
locals: renderer.create_consts(&[SkyboxLocals::default()]).unwrap(),
|
||||
},
|
||||
terrain: Terrain::new(),
|
||||
figure_cache: FigureCache::new(),
|
||||
@ -75,10 +57,14 @@ impl Scene {
|
||||
}
|
||||
|
||||
/// 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.
|
||||
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.).
|
||||
///
|
||||
@ -89,17 +75,17 @@ impl Scene {
|
||||
Event::Resize(dims) => {
|
||||
self.camera.set_aspect_ratio(dims.x as f32 / dims.y as f32);
|
||||
true
|
||||
},
|
||||
}
|
||||
// Panning the cursor makes the camera rotate
|
||||
Event::CursorPan(delta) => {
|
||||
self.camera.rotate_by(Vec3::from(delta) * CURSOR_PAN_SCALE);
|
||||
true
|
||||
},
|
||||
}
|
||||
// Zoom the camera when a zoom event occurs
|
||||
Event::Zoom(delta) => {
|
||||
self.camera.zoom_by(delta * 0.3);
|
||||
true
|
||||
},
|
||||
}
|
||||
// All other events are unhandled
|
||||
_ => false,
|
||||
}
|
||||
@ -123,7 +109,10 @@ impl Scene {
|
||||
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents();
|
||||
|
||||
// Update global constants
|
||||
renderer.update_consts(&mut self.globals, &[Globals::new(
|
||||
renderer
|
||||
.update_consts(
|
||||
&mut self.globals,
|
||||
&[Globals::new(
|
||||
view_mat,
|
||||
proj_mat,
|
||||
cam_pos,
|
||||
@ -131,7 +120,8 @@ impl Scene {
|
||||
10.0,
|
||||
client.state().get_time_of_day(),
|
||||
client.state().get_time(),
|
||||
)])
|
||||
)],
|
||||
)
|
||||
.expect("Failed to update global constants");
|
||||
|
||||
// Maintain the terrain
|
||||
@ -147,11 +137,7 @@ impl Scene {
|
||||
/// Render the scene using the provided `Renderer`
|
||||
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)
|
||||
renderer.render_skybox(
|
||||
&self.skybox.model,
|
||||
&self.globals,
|
||||
&self.skybox.locals,
|
||||
);
|
||||
renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
|
||||
|
||||
// Render terrain and figures
|
||||
self.terrain.render(renderer, &self.globals);
|
||||
|
@ -10,24 +10,12 @@ use vek::*;
|
||||
|
||||
// Project
|
||||
use client::Client;
|
||||
use common::{
|
||||
terrain::TerrainMap,
|
||||
volumes::vol_map::VolMapErr,
|
||||
vol::SampleVol,
|
||||
};
|
||||
use common::{terrain::TerrainMap, vol::SampleVol, volumes::vol_map::VolMapErr};
|
||||
|
||||
// Crate
|
||||
use crate::{
|
||||
render::{
|
||||
Consts,
|
||||
Globals,
|
||||
Mesh,
|
||||
Model,
|
||||
Renderer,
|
||||
TerrainPipeline,
|
||||
TerrainLocals,
|
||||
},
|
||||
mesh::Meshable,
|
||||
render::{Consts, Globals, Mesh, Model, Renderer, TerrainLocals, TerrainPipeline},
|
||||
};
|
||||
|
||||
struct TerrainChunk {
|
||||
@ -92,7 +80,11 @@ impl Terrain {
|
||||
let current_tick = client.get_tick();
|
||||
|
||||
// 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())
|
||||
{
|
||||
// TODO: ANOTHER PROBLEM HERE!
|
||||
@ -139,8 +131,12 @@ impl Terrain {
|
||||
// ambient occlusion and edge elision, we also need to borders of the chunk's
|
||||
// neighbours too (hence the `- 1` and `+ 1`).
|
||||
let aabb = Aabb {
|
||||
min: todo.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),
|
||||
min: todo
|
||||
.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
|
||||
@ -173,27 +169,35 @@ impl Terrain {
|
||||
// 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)
|
||||
Some(todo) if response.started_tick == todo.started_tick => {
|
||||
self.chunks.insert(response.pos, TerrainChunk {
|
||||
model: renderer.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"),
|
||||
});
|
||||
self.chunks.insert(
|
||||
response.pos,
|
||||
TerrainChunk {
|
||||
model: renderer
|
||||
.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
|
||||
// since it's either out of date or no longer needed
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) {
|
||||
for (_, chunk) in &self.chunks {
|
||||
renderer.render_terrain_chunk(
|
||||
&chunk.model,
|
||||
globals,
|
||||
&chunk.locals,
|
||||
);
|
||||
renderer.render_terrain_chunk(&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::{
|
||||
Direction,
|
||||
Error,
|
||||
PlayState,
|
||||
PlayStateResult,
|
||||
GlobalState,
|
||||
hud::{Event as HudEvent, Hud},
|
||||
key_state::KeyState,
|
||||
window::{Event, Key, Window},
|
||||
render::Renderer,
|
||||
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;
|
||||
|
||||
@ -27,7 +20,6 @@ pub struct SessionState {
|
||||
hud: Hud,
|
||||
}
|
||||
|
||||
|
||||
/// Represents an active game session (i.e: one that is being played)
|
||||
impl SessionState {
|
||||
/// Create a new `SessionState`
|
||||
@ -43,7 +35,6 @@ impl SessionState {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The background colour
|
||||
const BG_COLOR: Rgba<f32> = Rgba {
|
||||
r: 0.0,
|
||||
@ -64,7 +55,11 @@ impl SessionState {
|
||||
let dir_vec = self.key_state.dir_vec();
|
||||
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 {
|
||||
client::Event::Chat(msg) => {
|
||||
self.hud.new_message(msg);
|
||||
@ -123,7 +118,6 @@ impl PlayState for SessionState {
|
||||
loop {
|
||||
// Handle window events
|
||||
for event in global_state.window.fetch_events() {
|
||||
|
||||
// Pass all events to the ui first
|
||||
if self.hud.handle_event(event.clone(), global_state) {
|
||||
continue;
|
||||
@ -131,7 +125,7 @@ impl PlayState for SessionState {
|
||||
let _handled = match event {
|
||||
Event::Close => {
|
||||
return PlayStateResult::Shutdown;
|
||||
},
|
||||
}
|
||||
// Toggle cursor grabbing
|
||||
Event::KeyDown(Key::ToggleCursor) => {
|
||||
global_state
|
||||
@ -161,18 +155,24 @@ impl PlayState for SessionState {
|
||||
.expect("Failed to tick 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
|
||||
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 {
|
||||
HudEvent::SendMessage(msg) => {
|
||||
// TODO: Handle result
|
||||
self.client.borrow_mut().send_chat(msg);
|
||||
},
|
||||
}
|
||||
HudEvent::Logout => return PlayStateResult::Pop,
|
||||
HudEvent::Quit => {
|
||||
return PlayStateResult::Shutdown;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,9 @@
|
||||
use std::time::Duration;
|
||||
use log::info;
|
||||
use server::{Input, Event, Server};
|
||||
use common::clock::Clock;
|
||||
use std::{
|
||||
thread,
|
||||
thread::JoinHandle
|
||||
};
|
||||
use std::sync::mpsc::{
|
||||
channel, Receiver, Sender, TryRecvError,
|
||||
};
|
||||
use log::info;
|
||||
use server::{Event, Input, Server};
|
||||
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
|
||||
use std::time::Duration;
|
||||
use std::{thread, thread::JoinHandle};
|
||||
|
||||
const TPS: u64 = 30;
|
||||
|
||||
@ -49,11 +44,11 @@ fn run_server(rec: Receiver<Msg>) {
|
||||
let mut clock = Clock::new();
|
||||
|
||||
// Create server
|
||||
let mut server = Server::new()
|
||||
.expect("Failed to create server instance");
|
||||
let mut server = Server::new().expect("Failed to create server instance");
|
||||
|
||||
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");
|
||||
|
||||
for event in events {
|
||||
|
@ -1,46 +1,30 @@
|
||||
mod widgets;
|
||||
mod graphic;
|
||||
mod util;
|
||||
mod widgets;
|
||||
|
||||
pub use widgets::toggle_button::ToggleButton;
|
||||
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::{
|
||||
Error,
|
||||
render::{
|
||||
RenderError,
|
||||
Renderer,
|
||||
Model,
|
||||
Mesh,
|
||||
Texture,
|
||||
create_ui_quad, create_ui_tri, Mesh, Model, RenderError, Renderer, Texture, UiMode,
|
||||
UiPipeline,
|
||||
UiMode,
|
||||
create_ui_quad,
|
||||
create_ui_tri,
|
||||
},
|
||||
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)]
|
||||
pub enum UiError {
|
||||
@ -66,19 +50,23 @@ impl Event {
|
||||
winit::Window::get_hidpi_factor(&self.0) as _
|
||||
}
|
||||
}
|
||||
convert_event!(event, &WindowRef(window.window())).map(|input| {
|
||||
Self(input)
|
||||
})
|
||||
convert_event!(event, &WindowRef(window.window())).map(|input| Self(input))
|
||||
}
|
||||
pub fn is_keyboard_or_mouse(&self) -> bool {
|
||||
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,
|
||||
}
|
||||
}
|
||||
pub fn is_keyboard(&self) -> bool {
|
||||
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,
|
||||
}
|
||||
}
|
||||
@ -113,11 +101,21 @@ impl Cache {
|
||||
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_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture<UiPipeline>) { (&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 glyph_cache_tex(&self) -> &Texture<UiPipeline> {
|
||||
&self.glyph_cache_tex
|
||||
}
|
||||
pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture<UiPipeline>) {
|
||||
(&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>) {
|
||||
self.graphic_cache.clear_cache(new_size);
|
||||
self.graphic_cache_tex = renderer.create_dynamic_texture(new_size).unwrap();
|
||||
@ -190,7 +188,9 @@ impl Scale {
|
||||
match self.mode {
|
||||
ScaleMode::Absolute(scale) => scale / self.dpi_factor,
|
||||
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
|
||||
@ -277,20 +277,22 @@ impl Ui {
|
||||
|
||||
// Get whether a widget besides the window is capturing the mouse
|
||||
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) {
|
||||
match event.0 {
|
||||
Input::Resize(w, h) => self.window_resized = Some(Vec2::new(w, h)),
|
||||
Input::Touch(touch) => self.ui.handle_event(
|
||||
Input::Touch(Touch {
|
||||
Input::Touch(touch) => self.ui.handle_event(Input::Touch(Touch {
|
||||
xy: self.scale.scale_point(touch.xy.into()).into_array(),
|
||||
..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 } => {
|
||||
let (x, y) = self.scale.scale_point(Vec2::new(x, y)).into_tuple();
|
||||
Motion::MouseCursor { x, y }
|
||||
@ -304,8 +306,7 @@ impl Ui {
|
||||
Motion::Scroll { x, y }
|
||||
}
|
||||
_ => motion,
|
||||
})
|
||||
),
|
||||
})),
|
||||
_ => self.ui.handle_event(event.0),
|
||||
}
|
||||
}
|
||||
@ -338,7 +339,8 @@ impl Ui {
|
||||
macro_rules! switch_to_plain_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();
|
||||
current_state = State::Plain;
|
||||
}
|
||||
@ -348,7 +350,12 @@ impl Ui {
|
||||
let p_scale_factor = self.scale.scale_factor_physical();
|
||||
|
||||
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
|
||||
let new_scizzor = {
|
||||
@ -366,17 +373,15 @@ impl Ui {
|
||||
max: Vec2 {
|
||||
x: ((min_x + w) * p_scale_factor) as u16,
|
||||
y: ((min_y + h) * p_scale_factor) as u16,
|
||||
}
|
||||
},
|
||||
}
|
||||
.intersection(window_scizzor)
|
||||
};
|
||||
if new_scizzor != current_scizzor {
|
||||
// Finish the current command
|
||||
self.draw_commands.push(match current_state {
|
||||
State::Plain =>
|
||||
DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
||||
State::Image =>
|
||||
DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
||||
State::Plain => DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
||||
State::Image => DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
||||
});
|
||||
mesh.clear();
|
||||
|
||||
@ -398,8 +403,15 @@ impl Ui {
|
||||
|
||||
use conrod_core::render::PrimitiveKind;
|
||||
match kind {
|
||||
PrimitiveKind::Image { image_id, color, source_rect } => {
|
||||
let graphic_id = self.image_map.get(&image_id).expect("Image does not exist in image map");
|
||||
PrimitiveKind::Image {
|
||||
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();
|
||||
|
||||
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.
|
||||
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();
|
||||
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(
|
||||
(rect.w() * p_scale_factor) as u16,
|
||||
@ -439,17 +453,29 @@ impl Ui {
|
||||
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
|
||||
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 size = aabr.size().into_array();
|
||||
renderer.update_texture(cache_tex, offset, size, &data);
|
||||
}) {
|
||||
},
|
||||
) {
|
||||
Some(aabr) => Aabr {
|
||||
min: Vec2::new(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),
|
||||
min: Vec2::new(
|
||||
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,
|
||||
};
|
||||
@ -460,12 +486,16 @@ impl Ui {
|
||||
color,
|
||||
UiMode::Image,
|
||||
));
|
||||
|
||||
}
|
||||
PrimitiveKind::Text { color, text, font_id } => {
|
||||
PrimitiveKind::Text {
|
||||
color,
|
||||
text,
|
||||
font_id,
|
||||
} => {
|
||||
switch_to_plain_state!();
|
||||
// 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
|
||||
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.cache_queued(|rect, data| {
|
||||
glyph_cache
|
||||
.cache_queued(|rect, data| {
|
||||
let offset = [rect.min.x as u16, rect.min.y 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);
|
||||
}).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let color = srgb_to_linear(color.to_fsa().into());
|
||||
|
||||
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 {
|
||||
min: Vec2::new(uv_rect.min.x, uv_rect.max.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,
|
||||
),
|
||||
};
|
||||
mesh.push_quad(create_ui_quad(
|
||||
rect,
|
||||
uv,
|
||||
color,
|
||||
UiMode::Text,
|
||||
));
|
||||
mesh.push_quad(create_ui_quad(rect, uv, color, UiMode::Text));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -545,16 +577,13 @@ impl Ui {
|
||||
let p2 = Vec2::new(vx(tri[1][0]), vy(tri[1][1]));
|
||||
let p3 = Vec2::new(vx(tri[2][0]), vy(tri[2][1]));
|
||||
// If triangle is clockwise reverse it
|
||||
let (v1, v2): (Vec3<f32>, Vec3<f32>) = ((p2 - p1).into(), (p3 - p1).into());
|
||||
let triangle = if v1.cross(v2).z > 0.0 {[
|
||||
p1.into_array(),
|
||||
p2.into_array(),
|
||||
p3.into_array(),
|
||||
]} else {[
|
||||
p2.into_array(),
|
||||
p1.into_array(),
|
||||
p3.into_array(),
|
||||
]};
|
||||
let (v1, v2): (Vec3<f32>, Vec3<f32>) =
|
||||
((p2 - p1).into(), (p3 - p1).into());
|
||||
let triangle = if v1.cross(v2).z > 0.0 {
|
||||
[p1.into_array(), p2.into_array(), p3.into_array()]
|
||||
} else {
|
||||
[p2.into_array(), p1.into_array(), p3.into_array()]
|
||||
};
|
||||
mesh.push_tri(create_ui_tri(
|
||||
triangle,
|
||||
[[0.0; 2]; 3],
|
||||
@ -562,10 +591,8 @@ impl Ui {
|
||||
UiMode::Geometry,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
_ => {}
|
||||
// TODO: Add this
|
||||
_ => {} // TODO: Add this
|
||||
//PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);}
|
||||
// Other uneeded for now
|
||||
//PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);}
|
||||
@ -573,10 +600,8 @@ impl Ui {
|
||||
}
|
||||
// Enter the final command
|
||||
self.draw_commands.push(match current_state {
|
||||
State::Plain =>
|
||||
DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
||||
State::Image =>
|
||||
DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
||||
State::Plain => DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
||||
State::Image => DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
||||
});
|
||||
|
||||
// Handle window resizing
|
||||
@ -584,7 +609,8 @@ impl Ui {
|
||||
self.scale.window_resized(new_dims, renderer);
|
||||
let (w, h) = self.scale.scaled_window_size().into_tuple();
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -599,12 +625,8 @@ impl Ui {
|
||||
}
|
||||
DrawCommand::Draw { kind, model } => {
|
||||
let tex = match kind {
|
||||
DrawKind::Image => {
|
||||
self.cache.graphic_cache_tex()
|
||||
}
|
||||
DrawKind::Plain => {
|
||||
self.cache.glyph_cache_tex()
|
||||
}
|
||||
DrawKind::Image => self.cache.graphic_cache_tex(),
|
||||
DrawKind::Plain => self.cache.glyph_cache_tex(),
|
||||
};
|
||||
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();
|
||||
Aabr {
|
||||
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::{
|
||||
widget::{self, button},
|
||||
image,
|
||||
WidgetCommon,
|
||||
Widget,
|
||||
Sizeable,
|
||||
Color,
|
||||
Rect,
|
||||
Positionable,
|
||||
widget_ids,
|
||||
widget::{self, button},
|
||||
widget_ids, Color, Positionable, Rect, Sizeable, Widget, WidgetCommon,
|
||||
};
|
||||
|
||||
#[derive(Clone, WidgetCommon)]
|
||||
@ -88,7 +82,9 @@ impl Widget for ToggleButton {
|
||||
type Event = bool;
|
||||
|
||||
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 {
|
||||
@ -96,8 +92,19 @@ impl Widget for ToggleButton {
|
||||
}
|
||||
|
||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let widget::UpdateArgs{ id, state, ui, rect, .. } = args;
|
||||
let ToggleButton { mut value, f_image, t_image, .. } = self;
|
||||
let widget::UpdateArgs {
|
||||
id,
|
||||
state,
|
||||
ui,
|
||||
rect,
|
||||
..
|
||||
} = args;
|
||||
let ToggleButton {
|
||||
mut value,
|
||||
f_image,
|
||||
t_image,
|
||||
..
|
||||
} = self;
|
||||
// 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)
|
||||
if ui.widget_input(state.ids.button).clicks().left().count() % 2 == 1 {
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::{
|
||||
render::{Renderer, TgtColorFmt, TgtDepthFmt},
|
||||
ui, Error, settings::Settings,
|
||||
settings::Settings,
|
||||
ui, Error,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use vek::*;
|
||||
|
@ -1,15 +1,11 @@
|
||||
// Library
|
||||
use vek::*;
|
||||
use noise::{NoiseFn, Perlin};
|
||||
use vek::*;
|
||||
|
||||
// Project
|
||||
use common::{
|
||||
vol::{Vox, SizedVol, WriteVol},
|
||||
terrain::{
|
||||
Block,
|
||||
TerrainChunk,
|
||||
TerrainChunkMeta,
|
||||
},
|
||||
terrain::{Block, TerrainChunk, TerrainChunkMeta},
|
||||
vol::{SizedVol, Vox, WriteVol},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -47,12 +43,14 @@ impl World {
|
||||
let small_freq = 1.0 / 32.0;
|
||||
let small_ampl = 6.0;
|
||||
let offs = 32.0;
|
||||
let height =
|
||||
perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl
|
||||
let height = perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl
|
||||
+ perlin_nz.get(Vec2::from(wposf * small_freq).into_array()) * small_ampl
|
||||
+ offs;
|
||||
|
||||
chunk.set(lpos, if wposf.z < height - 4.0 {
|
||||
chunk
|
||||
.set(
|
||||
lpos,
|
||||
if wposf.z < height - 4.0 {
|
||||
stone
|
||||
} else if wposf.z < height - 1.0 {
|
||||
dirt
|
||||
@ -60,7 +58,9 @@ impl World {
|
||||
grass
|
||||
} else {
|
||||
air
|
||||
}).unwrap();
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
chunk
|
||||
|
Loading…
Reference in New Issue
Block a user