Pedantic comment and language fixes.

Former-commit-id: eb49765c911aaa97a9c8ed351216a7a6f8411213
This commit is contained in:
Cody 2019-05-17 05:22:32 -04:00
parent 96cdbdb881
commit 6b09fd7c53
80 changed files with 835 additions and 816 deletions

View File

@ -4,8 +4,8 @@ stages:
- post-build - post-build
- executable - executable
# our own git fetch command like https://gitlab.com/gitlab-org/gitlab-runner/blob/master/shells/abstract.go # Our own git fetch command like https://gitlab.com/gitlab-org/gitlab-runner/blob/master/shells/abstract.go
# speeds up building because we skip the git clean and dont need any gitlab caches # speeds up building because we skip the git clean and don't need any gitlab caches.
variables: variables:
GIT_STRATEGY: none GIT_STRATEGY: none
before_script: before_script:

View File

@ -6,15 +6,15 @@ use std::time::Duration;
const FPS: u64 = 60; const FPS: u64 = 60;
fn main() { fn main() {
// Init logging // Initialize logging.
pretty_env_logger::init(); pretty_env_logger::init();
info!("Starting chat-cli..."); info!("Starting chat-cli...");
// Set up an fps clock // Set up an fps clock.
let mut clock = Clock::new(); let mut clock = Clock::new();
// Create client // Create a client.
let mut client = let mut client =
Client::new(([127, 0, 0, 1], 59003), 300).expect("Failed to create client instance"); Client::new(([127, 0, 0, 1], 59003), 300).expect("Failed to create client instance");
@ -38,10 +38,10 @@ fn main() {
} }
} }
// Clean up the server after a tick // Clean up the server after a tick.
client.cleanup(); client.cleanup();
// Wait for the next tick // Wait for the next tick.
clock.tick(Duration::from_millis(1000 / FPS)); clock.tick(Duration::from_millis(1000 / FPS));
} }
} }

View File

@ -95,7 +95,7 @@ impl Client {
} }
/// Get a reference to the client's worker thread pool. This pool should be used for any /// Get a reference to the client's worker thread pool. This pool should be used for any
/// computationally expensive operations that run outside of the main thread (i.e: threads that /// computationally expensive operations that run outside of the main thread (i.e., threads that
/// block on I/O operations are exempt). /// block on I/O operations are exempt).
#[allow(dead_code)] #[allow(dead_code)]
pub fn thread_pool(&self) -> &threadpool::ThreadPool { pub fn thread_pool(&self) -> &threadpool::ThreadPool {
@ -114,7 +114,7 @@ impl Client {
&mut self.state &mut self.state
} }
/// Get the player's entity /// Get the player's entity.
#[allow(dead_code)] #[allow(dead_code)]
pub fn entity(&self) -> EcsEntity { pub fn entity(&self) -> EcsEntity {
self.entity self.entity
@ -126,13 +126,13 @@ impl Client {
self.tick self.tick
} }
/// Send a chat message to the server /// Send a chat message to the server.
#[allow(dead_code)] #[allow(dead_code)]
pub fn send_chat(&mut self, msg: String) { pub fn send_chat(&mut self, msg: String) {
self.postbox.send_message(ClientMsg::Chat(msg)) self.postbox.send_message(ClientMsg::Chat(msg))
} }
/// Execute a single client tick, handle input and update the game state by the given duration /// Execute a single client tick, handle input and update the game state by the given duration.
#[allow(dead_code)] #[allow(dead_code)]
pub fn tick(&mut self, input: Input, dt: Duration) -> Result<Vec<Event>, Error> { pub fn tick(&mut self, input: Input, dt: Duration) -> Result<Vec<Event>, Error> {
// This tick function is the centre of the Veloren universe. Most client-side things are // This tick function is the centre of the Veloren universe. Most client-side things are
@ -147,13 +147,13 @@ impl Client {
// 4) Go through the terrain update queue and apply all changes to the terrain // 4) Go through the terrain update queue and apply all changes to the terrain
// 5) Finish the tick, passing control of the main thread back to the frontend // 5) Finish the tick, passing control of the main thread back to the frontend
// Build up a list of events for this frame, to be passed to the frontend // Build up a list of events for this frame, to be passed to the frontend.
let mut frontend_events = Vec::new(); let mut frontend_events = Vec::new();
// Handle new messages from the server // Handle new messages from the server.
frontend_events.append(&mut self.handle_new_messages()?); frontend_events.append(&mut self.handle_new_messages()?);
// Pass character control from frontend input to the player's entity // Pass character control from frontend input to the player's entity.
// TODO: Only do this if the entity already has a Control component! // TODO: Only do this if the entity already has a Control component!
self.state.write_component( self.state.write_component(
self.entity, self.entity,
@ -164,10 +164,10 @@ impl Client {
}, },
); );
// Tick the client's LocalState (step 3) // Tick the client's LocalState (step 3).
self.state.tick(dt); self.state.tick(dt);
// Update the server about the player's physics attributes // Update the server about the player's physics attributes.
match ( match (
self.state.read_storage().get(self.entity).cloned(), self.state.read_storage().get(self.entity).cloned(),
self.state.read_storage().get(self.entity).cloned(), self.state.read_storage().get(self.entity).cloned(),
@ -180,7 +180,7 @@ impl Client {
_ => {} _ => {}
} }
// Update the server about the player's currently playing animation and the previous one // Update the server about the player's currently playing animation and the previous one.
if let Some(animation_history) = self if let Some(animation_history) = self
.state .state
.read_storage::<comp::AnimationHistory>() .read_storage::<comp::AnimationHistory>()
@ -201,7 +201,7 @@ impl Client {
if let Some(pos) = pos { if let Some(pos) = pos {
let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32)); let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
// Remove chunks that are too far from the player // Remove chunks that are too far from the player.
let mut chunks_to_remove = Vec::new(); let mut chunks_to_remove = Vec::new();
self.state.terrain().iter().for_each(|(key, _)| { self.state.terrain().iter().for_each(|(key, _)| {
if (Vec2::from(chunk_pos) - Vec2::from(key)) if (Vec2::from(chunk_pos) - Vec2::from(key))
@ -216,8 +216,8 @@ impl Client {
self.state.remove_chunk(key); self.state.remove_chunk(key);
} }
// Request chunks from the server // Request chunks from the server.
// TODO: This is really not very efficient // TODO: This is really inefficient.
'outer: for dist in 0..10 { 'outer: for dist in 0..10 {
for i in chunk_pos.x - dist..chunk_pos.x + dist + 1 { for i in chunk_pos.x - dist..chunk_pos.x + dist + 1 {
for j in chunk_pos.y - dist..chunk_pos.y + dist + 1 { for j in chunk_pos.y - dist..chunk_pos.y + dist + 1 {
@ -237,25 +237,25 @@ impl Client {
} }
} }
// If chunks are taking too long, assume they're no longer pending // If chunks are taking too long, assume they're no longer pending.
let now = Instant::now(); let now = Instant::now();
self.pending_chunks self.pending_chunks
.retain(|_, created| now.duration_since(*created) < Duration::from_secs(10)); .retain(|_, created| now.duration_since(*created) < Duration::from_secs(10));
} }
// Finish the tick, pass control back to the frontend (step 6) // Finish the tick, pass control back to the frontend (step 6).
self.tick += 1; self.tick += 1;
Ok(frontend_events) Ok(frontend_events)
} }
/// Clean up the client after a tick /// Clean up the client after a tick.
#[allow(dead_code)] #[allow(dead_code)]
pub fn cleanup(&mut self) { pub fn cleanup(&mut self) {
// Cleanup the local state // Cleanup the local state
self.state.cleanup(); self.state.cleanup();
} }
/// Handle new server messages /// Handle new server messages.
fn handle_new_messages(&mut self) -> Result<Vec<Event>, Error> { fn handle_new_messages(&mut self) -> Result<Vec<Event>, Error> {
let mut frontend_events = Vec::new(); let mut frontend_events = Vec::new();
@ -324,7 +324,7 @@ impl Client {
} else if self.state.get_time() - self.last_ping > SERVER_TIMEOUT { } else if self.state.get_time() - self.last_ping > SERVER_TIMEOUT {
return Err(Error::ServerTimeout); return Err(Error::ServerTimeout);
} else if self.state.get_time() - self.last_ping > SERVER_TIMEOUT * 0.5 { } else if self.state.get_time() - self.last_ping > SERVER_TIMEOUT * 0.5 {
// Try pinging the server if the timeout is nearing // Try pinging the server if the timeout is nearing.
self.postbox.send_message(ClientMsg::Ping); self.postbox.send_message(ClientMsg::Ping);
} }

View File

@ -12,9 +12,9 @@ use std::{
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Error { pub enum Error {
/// An asset of a different type has already been loaded with this specifier /// An asset of a different type has already been loaded with this specifier.
InvalidType, InvalidType,
/// Asset does not exist /// Asset does not exist.
NotFound(String), NotFound(String),
} }
@ -35,8 +35,8 @@ lazy_static! {
RwLock::new(HashMap::new()); RwLock::new(HashMap::new());
} }
/// Function used to load assets /// Function used to load assets.
/// loaded assets are cached in a global singleton hashmap /// Loaded assets are cached in a global singleton hashmap.
/// Example usage: /// Example usage:
/// ```no_run /// ```no_run
/// use image::DynamicImage; /// use image::DynamicImage;
@ -54,9 +54,9 @@ pub fn load<A: Asset + 'static>(specifier: &str) -> Result<Arc<A>, Error> {
.downcast()?) .downcast()?)
} }
/// Function used to load assets that will panic if the asset is not found /// Function used to load assets that will panic if the asset is not found.
/// Use this to load essential assets /// Use this to load essential assets.
/// loaded assets are cached in a global singleton hashmap /// Loaded assets are cached in a global singleton hashmap.
/// Example usage: /// Example usage:
/// ```no_run /// ```no_run
/// use image::DynamicImage; /// use image::DynamicImage;
@ -89,11 +89,11 @@ impl Asset for DotVoxData {
} }
} }
// TODO: System to load file from specifiers (eg "core.ui.backgrounds.city") // TODO: System to load file from specifiers (e.g.: "core.ui.backgrounds.city").
fn try_open_with_path(name: &str) -> Option<File> { fn try_open_with_path(name: &str) -> Option<File> {
debug!("Trying to access \"{}\"", name); debug!("Trying to access \"{}\"", name);
// TODO: don't do this? // TODO: Don't do this?
// if it's stupid and it works.., // If it's stupid but it works...
[ [
"assets".to_string(), "assets".to_string(),
"../assets".to_string(), /* optimizations */ "../assets".to_string(), /* optimizations */

View File

@ -43,7 +43,7 @@ impl Clock {
.duration_since(self.last_sys_time) .duration_since(self.last_sys_time)
.expect("Time went backwards!"); .expect("Time went backwards!");
// Attempt to sleep to fill the gap // Attempt to sleep to fill the gap.
if let Some(sleep_dur) = tgt.checked_sub(delta) { if let Some(sleep_dur) = tgt.checked_sub(delta) {
let adjustment = if self.running_tps_average == 0.0 { let adjustment = if self.running_tps_average == 0.0 {
1.0 1.0

View File

@ -71,24 +71,23 @@ pub enum Draw {
} }
//// ////
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Pighead { pub enum PigHead {
Default, Default,
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Pigchest { pub enum PigChest {
Default, Default,
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Pigleg_l { pub enum PigLegL {
Default, Default,
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Pigleg_r { pub enum PigLegR {
Default, Default,
} }
////
const ALL_RACES: [Race; 6] = [ const ALL_RACES: [Race; 6] = [
Race::Danari, Race::Danari,
@ -158,19 +157,19 @@ const ALL_QRACES: [Race; 6] = [
Race::Undead, Race::Undead,
]; ];
const ALL_QBODY_TYPES: [BodyType; 3] = [BodyType::Female, BodyType::Male, BodyType::Unspecified]; const ALL_QBODY_TYPES: [BodyType; 3] = [BodyType::Female, BodyType::Male, BodyType::Unspecified];
const ALL_QHEADS: [Pighead; 1] = [Pighead::Default]; const ALL_QPIG_HEADS: [PigHead; 1] = [PigHead::Default];
const ALL_QCHESTS: [Pigchest; 1] = [Pigchest::Default]; const ALL_QPIG_CHESTS: [PigChest; 1] = [PigChest::Default];
const ALL_QPIGLEG_LS: [Pigleg_l; 1] = [Pigleg_l::Default]; const ALL_QPIG_LEG_LS: [PigLegL; 1] = [PigLegL::Default];
const ALL_QPIGLEG_RS: [Pigleg_r; 1] = [Pigleg_r::Default]; const ALL_QPIG_LEG_RS: [PigLegR; 1] = [PigLegR::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct QuadrupedBody { pub struct QuadrupedBody {
pub race: Race, pub race: Race,
pub body_type: BodyType, pub body_type: BodyType,
pub pighead: Pighead, pub pig_head: PigHead,
pub pigchest: Pigchest, pub pig_chest: PigChest,
pub pigleg_l: Pigleg_l, pub pig_leg_l: PigLegL,
pub pigleg_r: Pigleg_r, pub pig_leg_r: PigLegR,
} }
impl QuadrupedBody { impl QuadrupedBody {
@ -178,10 +177,10 @@ impl QuadrupedBody {
Self { Self {
race: *thread_rng().choose(&ALL_QRACES).unwrap(), race: *thread_rng().choose(&ALL_QRACES).unwrap(),
body_type: *thread_rng().choose(&ALL_QBODY_TYPES).unwrap(), body_type: *thread_rng().choose(&ALL_QBODY_TYPES).unwrap(),
pighead: *thread_rng().choose(&ALL_QHEADS).unwrap(), pig_head: *thread_rng().choose(&ALL_QPIG_HEADS).unwrap(),
pigchest: *thread_rng().choose(&ALL_QCHESTS).unwrap(), pig_chest: *thread_rng().choose(&ALL_QPIG_CHESTS).unwrap(),
pigleg_l: *thread_rng().choose(&ALL_QPIGLEG_LS).unwrap(), pig_leg_l: *thread_rng().choose(&ALL_QPIG_LEG_LS).unwrap(),
pigleg_r: *thread_rng().choose(&ALL_QPIGLEG_RS).unwrap(), pig_leg_r: *thread_rng().choose(&ALL_QPIG_LEG_RS).unwrap(),
} }
} }
} }

View File

@ -1,7 +1,7 @@
use specs::{Component, FlaggedStorage, NullStorage, VecStorage}; use specs::{Component, FlaggedStorage, NullStorage, VecStorage};
use vek::*; use vek::*;
// Pos // Position
#[derive(Copy, Clone, Debug, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct Pos(pub Vec3<f32>); pub struct Pos(pub Vec3<f32>);
@ -10,7 +10,7 @@ impl Component for Pos {
type Storage = VecStorage<Self>; type Storage = VecStorage<Self>;
} }
// Vel // Velocity
#[derive(Copy, Clone, Debug, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct Vel(pub Vec3<f32>); pub struct Vel(pub Vec3<f32>);
@ -19,7 +19,7 @@ impl Component for Vel {
type Storage = VecStorage<Self>; type Storage = VecStorage<Self>;
} }
// Dir // Direction
#[derive(Copy, Clone, Debug, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct Dir(pub Vec3<f32>); pub struct Dir(pub Vec3<f32>);
@ -28,7 +28,7 @@ impl Component for Dir {
type Storage = VecStorage<Self>; type Storage = VecStorage<Self>;
} }
// Dir // Update
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
pub struct ForceUpdate; pub struct ForceUpdate;

View File

@ -4,7 +4,7 @@ use vek::*;
// Crate // Crate
use crate::vol::Vox; use crate::vol::Vox;
/// A type representing a single voxel in a figure /// A type representing a single voxel in a figure.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum Cell { pub enum Cell {
Filled([u8; 3]), Filled([u8; 3]),

View File

@ -23,7 +23,7 @@ pub mod util;
pub mod vol; pub mod vol;
pub mod volumes; pub mod volumes;
/// The networking module containing high-level wrappers of `TcpListener` and `TcpStream` (`PostOffice` and `PostBox` respectively) and data types used by both the server and client /// The networking module containing high-level wrappers of `TcpListener` and `TcpStream` (`PostOffice` and `PostBox` respectively) and data types used by both the server and client.
/// # Examples /// # Examples
/// ``` /// ```
/// use std::net::SocketAddr; /// use std::net::SocketAddr;

View File

@ -2,7 +2,8 @@ use crate::{comp, state};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::marker::PhantomData; use std::marker::PhantomData;
// Automatically derive From<T> for EcsResPacket for each variant EcsResPacket::T(T) // Automatically derive From<T> for EcsResPacket
// for each variant EcsResPacket::T(T).
sphynx::sum_type! { sphynx::sum_type! {
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum EcsResPacket { pub enum EcsResPacket {
@ -11,7 +12,8 @@ sphynx::sum_type! {
} }
} }
impl sphynx::ResPacket for EcsResPacket {} impl sphynx::ResPacket for EcsResPacket {}
// Automatically derive From<T> for EcsCompPacket for each variant EcsCompPacket::T(T) // Automatically derive From<T> for EcsCompPacket
// for each variant EcsCompPacket::T(T.)
sphynx::sum_type! { sphynx::sum_type! {
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum EcsCompPacket { pub enum EcsCompPacket {
@ -23,7 +25,8 @@ sphynx::sum_type! {
Stats(comp::Stats), Stats(comp::Stats),
} }
} }
// Automatically derive From<T> for EcsCompPhantom for each variant EcsCompPhantom::T(PhantomData<T>) // Automatically derive From<T> for EcsCompPhantom
// for each variant EcsCompPhantom::T(PhantomData<T>).
sphynx::sum_type! { sphynx::sum_type! {
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum EcsCompPhantom { pub enum EcsCompPhantom {

View File

@ -1,18 +1,18 @@
/// Messages server sends to client /// Messages server sends to client.
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug)]
pub enum ServerMsg { pub enum ServerMsg {
// VersionInfo MUST always stay first in this struct // VersionInfo MUST always stay first in this struct.
VersionInfo {}, VersionInfo {},
} }
/// Messages client sends to server /// Messages client sends to server.
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug)]
pub enum ClientMsg { pub enum ClientMsg {
// VersionInfo MUST always stay first in this struct // VersionInfo MUST always stay first in this struct.
VersionInfo {}, VersionInfo {},
} }
/// Control message type, used in [PostBox](super::PostBox) and [PostOffice](super::PostOffice) to control threads /// Control message type, used in [PostBox](super::PostBox) and [PostOffice](super::PostOffice) to control threads.
pub enum ControlMsg { pub enum ControlMsg {
Shutdown, Shutdown,
} }

View File

@ -253,7 +253,7 @@ impl<S: PostSend, R: PostRecv> PostBox<S, R> {
let _ = self.send_tx.send(data); let _ = self.send_tx.send(data);
} }
// TODO: This method is super messy // TODO: This method is super messy.
pub fn next_message(&mut self) -> Option<R> { pub fn next_message(&mut self) -> Option<R> {
if self.err.is_some() { if self.err.is_some() {
return None; return None;
@ -528,14 +528,14 @@ fn connect() {
let mut postoffice = PostOffice::<TestMsg<u32>, TestMsg<f32>>::bind(srv_addr).unwrap(); let mut postoffice = PostOffice::<TestMsg<u32>, TestMsg<f32>>::bind(srv_addr).unwrap();
// We should start off with 0 incoming connections // We should start off with 0 incoming connections.
thread::sleep(Duration::from_millis(250)); thread::sleep(Duration::from_millis(250));
assert_eq!(postoffice.new_connections().len(), 0); assert_eq!(postoffice.new_connections().len(), 0);
assert_eq!(postoffice.error(), None); assert_eq!(postoffice.error(), None);
let postbox = PostBox::<TestMsg<f32>, TestMsg<u32>>::to_server(srv_addr).unwrap(); let postbox = PostBox::<TestMsg<f32>, TestMsg<u32>>::to_server(srv_addr).unwrap();
// Now a postbox has been created, we should have 1 new // Now a postbox has been created, we should have 1 new.
thread::sleep(Duration::from_millis(250)); thread::sleep(Duration::from_millis(250));
let incoming = postoffice.new_connections(); let incoming = postoffice.new_connections();
assert_eq!(incoming.len(), 1); assert_eq!(incoming.len(), 1);
@ -549,7 +549,7 @@ fn connect_fail() {
let mut postoffice = PostOffice::<TestMsg<u32>, TestMsg<f32>>::bind(listen_addr).unwrap(); let mut postoffice = PostOffice::<TestMsg<u32>, TestMsg<f32>>::bind(listen_addr).unwrap();
// We should start off with 0 incoming connections // We should start off with 0 incoming connections.
thread::sleep(Duration::from_millis(250)); thread::sleep(Duration::from_millis(250));
assert_eq!(postoffice.new_connections().len(), 0); assert_eq!(postoffice.new_connections().len(), 0);
assert_eq!(postoffice.error(), None); assert_eq!(postoffice.error(), None);
@ -564,7 +564,7 @@ fn connection_count() {
let mut postoffice = PostOffice::<TestMsg<u32>, TestMsg<f32>>::bind(srv_addr).unwrap(); let mut postoffice = PostOffice::<TestMsg<u32>, TestMsg<f32>>::bind(srv_addr).unwrap();
let mut postboxes = Vec::new(); let mut postboxes = Vec::new();
// We should start off with 0 incoming connections // We should start off with 0 incoming connections.
thread::sleep(Duration::from_millis(250)); thread::sleep(Duration::from_millis(250));
assert_eq!(postoffice.new_connections().len(), 0); assert_eq!(postoffice.new_connections().len(), 0);
assert_eq!(postoffice.error(), None); assert_eq!(postoffice.error(), None);
@ -573,7 +573,7 @@ fn connection_count() {
postboxes.push(PostBox::<TestMsg<f32>, TestMsg<u32>>::to_server(srv_addr).unwrap()); postboxes.push(PostBox::<TestMsg<f32>, TestMsg<u32>>::to_server(srv_addr).unwrap());
} }
// 5 postboxes created, we should have 5 // 5 postboxes created, we should have 5.
thread::sleep(Duration::from_millis(3500)); thread::sleep(Duration::from_millis(3500));
let incoming = postoffice.new_connections(); let incoming = postoffice.new_connections();
assert_eq!(incoming.len(), 5); assert_eq!(incoming.len(), 5);
@ -597,7 +597,7 @@ fn disconnect() {
incoming.next().unwrap() incoming.next().unwrap()
}; };
// The client postbox has since been disconnected // The client postbox has since been disconnected.
thread::sleep(Duration::from_millis(2050)); thread::sleep(Duration::from_millis(2050));
let incoming_msgs = server_postbox.new_messages(); let incoming_msgs = server_postbox.new_messages();
assert_eq!(incoming_msgs.len(), 0); assert_eq!(incoming_msgs.len(), 0);

View File

@ -188,7 +188,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
Ok(None) => {} Ok(None) => {}
} }
// Try getting messages from the send channel // Try getting messages from the send channel.
for _ in 0..100 { for _ in 0..100 {
match send_rx.try_recv() { match send_rx.try_recv() {
Ok(send_msg) => { Ok(send_msg) => {
@ -202,12 +202,12 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
} }
*/ */
// Assemble into packet // 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.push(msg_bytes.iter().fold(0, |a, x| a ^ *x)); packet_bytes.push(msg_bytes.iter().fold(0, |a, x| a ^ *x));
packet_bytes.append(&mut msg_bytes); packet_bytes.append(&mut msg_bytes);
// Split packet into chunks // Split packet into chunks.
packet_bytes packet_bytes
.chunks(4096) .chunks(4096)
.map(|chunk| chunk.to_vec()) .map(|chunk| chunk.to_vec())
@ -222,7 +222,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
} }
} }
// Try sending bytes through the TCP stream // Try sending bytes through the TCP stream.
for _ in 0..100 { for _ in 0..100 {
match outgoing_chunks.pop_front() { match outgoing_chunks.pop_front() {
Some(mut chunk) => match stream.write(&chunk) { Some(mut chunk) => match stream.write(&chunk) {
@ -232,7 +232,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
break; break;
} }
Err(e) if e.kind() == io::ErrorKind::WouldBlock => { Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
// Return chunk to the queue to try again later // Return chunk to the queue to try again later.
outgoing_chunks.push_front(chunk); outgoing_chunks.push_front(chunk);
break; break;
} }
@ -246,7 +246,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
} }
} }
// Try receiving bytes from the TCP stream // Try receiving bytes from the TCP stream.
for _ in 0..100 { for _ in 0..100 {
let mut buf = [0; 4096]; let mut buf = [0; 4096];
@ -262,7 +262,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
} }
} }
// Try turning bytes into messages // Try turning bytes into messages.
for _ in 0..100 { for _ in 0..100 {
match incoming_buf.get(0..9) { match incoming_buf.get(0..9) {
Some(len_bytes) => { Some(len_bytes) => {

View File

@ -54,7 +54,7 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
pos = self.from + dir * dist; pos = self.from + dir * dist;
ipos = pos.map(|e| e.floor() as i32); ipos = pos.map(|e| e.floor() as i32);
// Allow one iteration above max // Allow one iteration above max.
if dist > max { if dist > max {
break; break;
} }

View File

@ -20,25 +20,25 @@ use std::{collections::HashSet, sync::Arc, time::Duration};
use vek::*; use vek::*;
/// How much faster should an in-game day be compared to a real day? /// How much faster should an in-game day be compared to a real day?
// TODO: Don't hard-code this // TODO: Don't hard-code this.
const DAY_CYCLE_FACTOR: f64 = 24.0 * 60.0; const DAY_CYCLE_FACTOR: f64 = 24.0 * 60.0;
/// A resource to store the time of day /// A resource that stores the time of day.
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TimeOfDay(f64); pub struct TimeOfDay(f64);
/// A resource to store the tick (i.e: physics) time /// A resource that stores the tick (i.e: physics) time.
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Time(f64); pub struct Time(f64);
/// A resource used to store the time since the last tick /// A resource that stores the time since the previous tick.
#[derive(Default)] #[derive(Default)]
pub struct DeltaTime(pub f32); pub struct DeltaTime(pub f32);
/// At what point should we stop speeding up physics to compensate for lag? If we speed physics up /// At what point should we stop speeding up physics to compensate for lag? If we speed physics up
/// too fast, we'd skip important physics events like collisions. This constant determines what /// too fast, we'd skip important physics events like collisions. This constant determines the
/// the upper limit is. If delta time exceeds this value, the game's physics will begin to produce /// upper limit. If delta time exceeds this value, the game's physics will begin to produce time
/// time lag. Ideally, we'd avoid such a situation. /// lag. Ideally, we'd avoid such a situation.
const MAX_DELTA_TIME: f32 = 0.15; const MAX_DELTA_TIME: f32 = 0.15;
pub struct Changes { pub struct Changes {
@ -64,7 +64,7 @@ impl Changes {
} }
/// A type used to represent game state stored on both the client and the server. This includes /// A type used to represent game state stored on both the client and the server. This includes
/// things like entity components, terrain data, and global state like weather, time of day, etc. /// things like entity components, terrain data, and global states like weather, time of day, etc.
pub struct State { pub struct State {
ecs: sphynx::World<EcsCompPacket, EcsResPacket>, ecs: sphynx::World<EcsCompPacket, EcsResPacket>,
// Avoid lifetime annotation by storing a thread pool instead of the whole dispatcher // Avoid lifetime annotation by storing a thread pool instead of the whole dispatcher
@ -82,7 +82,7 @@ impl State {
} }
} }
/// Create a new `State` from an ECS state package /// Create a new `State` from an ECS state package.
pub fn from_state_package( pub fn from_state_package(
state_package: sphynx::StatePackage<EcsCompPacket, EcsResPacket>, state_package: sphynx::StatePackage<EcsCompPacket, EcsResPacket>,
) -> Self { ) -> Self {
@ -97,14 +97,14 @@ impl State {
} }
} }
// Create a new Sphynx ECS world // Create a new Sphynx ECS world.
fn setup_sphynx_world(ecs: &mut sphynx::World<EcsCompPacket, EcsResPacket>) { fn setup_sphynx_world(ecs: &mut sphynx::World<EcsCompPacket, EcsResPacket>) {
// Register synced components // Register synced components.
ecs.register_synced::<comp::Actor>(); ecs.register_synced::<comp::Actor>();
ecs.register_synced::<comp::Player>(); ecs.register_synced::<comp::Player>();
ecs.register_synced::<comp::Stats>(); ecs.register_synced::<comp::Stats>();
// Register unsynched (or synced by other means) components // Register unsynced (or synced by other means) components.
ecs.register::<comp::phys::Pos>(); ecs.register::<comp::phys::Pos>();
ecs.register::<comp::phys::Vel>(); ecs.register::<comp::phys::Vel>();
ecs.register::<comp::phys::Dir>(); ecs.register::<comp::phys::Dir>();
@ -112,16 +112,16 @@ impl State {
ecs.register::<comp::Agent>(); ecs.register::<comp::Agent>();
ecs.register::<comp::Control>(); ecs.register::<comp::Control>();
// Register synced resources used by the ECS // Register synced resources used by the ECS.
ecs.add_resource_synced(TimeOfDay(0.0)); ecs.add_resource_synced(TimeOfDay(0.0));
// Register unsynced resources used by the ECS // Register unsynced resources used by the ECS.
ecs.add_resource(Time(0.0)); ecs.add_resource(Time(0.0));
ecs.add_resource(DeltaTime(0.0)); ecs.add_resource(DeltaTime(0.0));
ecs.add_resource(TerrainMap::new().unwrap()); ecs.add_resource(TerrainMap::new().unwrap());
} }
/// Register a component with the state's ECS /// Register a component with the state's ECS.
pub fn with_component<T: Component>(mut self) -> Self pub fn with_component<T: Component>(mut self) -> Self
where where
<T as Component>::Storage: Default, <T as Component>::Storage: Default,
@ -130,27 +130,27 @@ impl State {
self self
} }
/// Write a component attributed to a particular entity /// Write a component attributed to a particular entity.
pub fn write_component<C: Component>(&mut self, entity: EcsEntity, comp: C) { pub fn write_component<C: Component>(&mut self, entity: EcsEntity, comp: C) {
let _ = self.ecs.write_storage().insert(entity, comp); let _ = self.ecs.write_storage().insert(entity, comp);
} }
/// Read a component attributed to a particular entity /// Read a component attributed to a particular entity.
pub fn read_component_cloned<C: Component + Clone>(&self, entity: EcsEntity) -> Option<C> { pub fn read_component_cloned<C: Component + Clone>(&self, entity: EcsEntity) -> Option<C> {
self.ecs.read_storage().get(entity).cloned() self.ecs.read_storage().get(entity).cloned()
} }
/// Get a read-only reference to the storage of a particular component type /// Get a read-only reference to the storage of a particular component type.
pub fn read_storage<C: Component>(&self) -> EcsStorage<C, Fetch<EcsMaskedStorage<C>>> { pub fn read_storage<C: Component>(&self) -> EcsStorage<C, Fetch<EcsMaskedStorage<C>>> {
self.ecs.read_storage::<C>() self.ecs.read_storage::<C>()
} }
/// Get a reference to the internal ECS world /// Get a reference to the internal ECS world.
pub fn ecs(&self) -> &sphynx::World<EcsCompPacket, EcsResPacket> { pub fn ecs(&self) -> &sphynx::World<EcsCompPacket, EcsResPacket> {
&self.ecs &self.ecs
} }
/// Get a mutable reference to the internal ECS world /// Get a mutable reference to the internal ECS world.
pub fn ecs_mut(&mut self) -> &mut sphynx::World<EcsCompPacket, EcsResPacket> { pub fn ecs_mut(&mut self) -> &mut sphynx::World<EcsCompPacket, EcsResPacket> {
&mut self.ecs &mut self.ecs
} }
@ -194,7 +194,7 @@ impl State {
} }
} }
/// Remove the chunk with the given key from this state's terrain, if it exists /// Remove the chunk with the given key from this state's terrain, if it exists.
pub fn remove_chunk(&mut self, key: Vec2<i32>) { pub fn remove_chunk(&mut self, key: Vec2<i32>) {
if self if self
.ecs .ecs
@ -208,27 +208,27 @@ impl State {
/// Execute a single tick, simulating the game state by the given duration. /// Execute a single tick, simulating the game state by the given duration.
pub fn tick(&mut self, dt: Duration) { pub fn tick(&mut self, dt: Duration) {
// Change the time accordingly // Change the time accordingly.
self.ecs.write_resource::<TimeOfDay>().0 += dt.as_secs_f64() * DAY_CYCLE_FACTOR; self.ecs.write_resource::<TimeOfDay>().0 += dt.as_secs_f64() * DAY_CYCLE_FACTOR;
self.ecs.write_resource::<Time>().0 += dt.as_secs_f64(); self.ecs.write_resource::<Time>().0 += dt.as_secs_f64();
// Update delta time // Update delta time.
// Above a delta time of MAX_DELTA_TIME, start lagging to avoid skipping important physics events // Beyond a delta time of MAX_DELTA_TIME, start lagging to avoid skipping important physics events.
self.ecs.write_resource::<DeltaTime>().0 = dt.as_secs_f32().min(MAX_DELTA_TIME); self.ecs.write_resource::<DeltaTime>().0 = dt.as_secs_f32().min(MAX_DELTA_TIME);
// Run systems to update the world // Run systems to update the world.
// Create and run dispatcher for ecs systems // Create and run a dispatcher for ecs systems.
let mut dispatch_builder = DispatcherBuilder::new().with_pool(self.thread_pool.clone()); let mut dispatch_builder = DispatcherBuilder::new().with_pool(self.thread_pool.clone());
sys::add_local_systems(&mut dispatch_builder); sys::add_local_systems(&mut dispatch_builder);
// This dispatches all the systems in parallel // This dispatches all the systems in parallel.
dispatch_builder.build().dispatch(&self.ecs.res); dispatch_builder.build().dispatch(&self.ecs.res);
self.ecs.maintain(); self.ecs.maintain();
} }
/// Clean up the state after a tick /// Clean up the state after a tick.
pub fn cleanup(&mut self) { pub fn cleanup(&mut self) {
// Clean up data structures from the last tick // Clean up data structures from the last tick.
self.changes.cleanup(); self.changes.cleanup();
} }
} }

View File

@ -34,10 +34,10 @@ impl<'a> System<'a> for Sys {
Some(tgt_pos) => { Some(tgt_pos) => {
let tgt_pos = tgt_pos.0 + *offset; let tgt_pos = tgt_pos.0 + *offset;
// Jump with target // Jump with target.
control.jumping = tgt_pos.z > pos.0.z + 1.0; control.jumping = tgt_pos.z > pos.0.z + 1.0;
// Move towards the target // Move towards the target.
let dist = tgt_pos.distance(pos.0); let dist = tgt_pos.distance(pos.0);
control.move_dir = if dist > 5.0 { control.move_dir = if dist > 5.0 {
Vec2::from(tgt_pos - pos.0).normalized() Vec2::from(tgt_pos - pos.0).normalized()
@ -50,7 +50,7 @@ impl<'a> System<'a> for Sys {
_ => control.move_dir = Vec2::zero(), _ => control.move_dir = Vec2::zero(),
} }
// Change offset occasionally // Change offset occasionally.
if rand::random::<f32>() < 0.003 { if rand::random::<f32>() < 0.003 {
*offset = *offset =
Vec2::new(rand::random::<f32>() - 0.5, rand::random::<f32>() - 0.5) Vec2::new(rand::random::<f32>() - 0.5, rand::random::<f32>() - 0.5)

View File

@ -42,8 +42,8 @@ impl<'a> System<'a> for Sys {
&& vel.0.z <= 0.0; && vel.0.z <= 0.0;
let (gliding, friction) = if on_ground { let (gliding, friction) = if on_ground {
// TODO: Don't hard-code this // TODO: Don't hard-code this.
// Apply physics to the player: acceleration and non-linear decceleration // Apply physics to the player: acceleration and non-linear deceleration.
vel.0 += Vec2::broadcast(dt.0) * control.move_dir * 200.0; vel.0 += Vec2::broadcast(dt.0) * control.move_dir * 200.0;
if control.jumping { if control.jumping {
@ -52,12 +52,12 @@ impl<'a> System<'a> for Sys {
(false, 0.15) (false, 0.15)
} else { } else {
// TODO: Don't hard-code this // TODO: Don't hard-code this.
// Apply physics to the player: acceleration and non-linear decceleration // Apply physics to the player: acceleration and non-linear deceleration.
vel.0 += Vec2::broadcast(dt.0) * control.move_dir * 10.0; vel.0 += Vec2::broadcast(dt.0) * control.move_dir * 10.0;
if control.gliding && vel.0.z < 0.0 { if control.gliding && vel.0.z < 0.0 {
// TODO: Don't hard-code this // TODO: Don't hard-code this.
let anti_grav = 9.81 * 3.95 + vel.0.z.powf(2.0) * 0.2; let anti_grav = 9.81 * 3.95 + vel.0.z.powf(2.0) * 0.2;
vel.0.z += vel.0.z +=
dt.0 * anti_grav * Vec2::<f32>::from(vel.0 * 0.15).magnitude().min(1.0); dt.0 * anti_grav * Vec2::<f32>::from(vel.0 * 0.15).magnitude().min(1.0);

View File

@ -28,8 +28,8 @@ impl<'a> System<'a> for Sys {
// Movement // Movement
pos.0 += vel.0 * dt.0; pos.0 += vel.0 * dt.0;
// Don't fall into the void // Don't fall into the void.
// TODO: This shouldn't be needed when we have proper physics and chunk loading // TODO: This shouldn't be needed when we have proper physics and chunk loading.
if pos.0.z < 0.0 { if pos.0.z < 0.0 {
pos.0.z = 0.0; pos.0.z = 0.0;
vel.0.z = 0.0; vel.0.z = 0.0;

View File

@ -1,7 +1,7 @@
use crate::ray::{Ray, RayUntil}; use crate::ray::{Ray, RayUntil};
use vek::*; use vek::*;
/// A voxel /// A voxel.
pub trait Vox { pub trait Vox {
fn empty() -> Self; fn empty() -> Self;
fn is_empty(&self) -> bool; fn is_empty(&self) -> bool;
@ -50,7 +50,7 @@ pub trait SizedVol: BaseVol {
#[inline(always)] #[inline(always)]
fn get_size(&self) -> Vec3<u32>; fn get_size(&self) -> Vec3<u32>;
/// Iterate through all potential voxel positions in this volume /// Iterate through all potential voxel positions in this volume.
fn iter_positions(&self) -> VoxPosIter { fn iter_positions(&self) -> VoxPosIter {
VoxPosIter { VoxPosIter {
pos: Vec3::zero(), pos: Vec3::zero(),
@ -73,7 +73,7 @@ pub trait ReadVol: BaseVol {
} }
} }
/// A volume that provides the ability to sample (i.e: clone a section of) its voxel data. /// A volume that provides the ability to sample (i.e., clone a section of) its voxel data.
pub trait SampleVol<I>: BaseVol { pub trait SampleVol<I>: BaseVol {
type Sample: BaseVol + ReadVol; type Sample: BaseVol + ReadVol;
/// Take a sample of the volume by cloning voxels within the provided range. /// Take a sample of the volume by cloning voxels within the provided range.

View File

@ -25,8 +25,8 @@ pub struct Chunk<V: Vox, S: VolSize, M> {
} }
impl<V: Vox, S: VolSize, M> Chunk<V, S, M> { impl<V: Vox, S: VolSize, M> Chunk<V, S, M> {
/// Used to transform a voxel position in the volume into its corresponding index in the voxel /// Used to transform a voxel position in the volume into its corresponding index
// array. /// in the voxel array.
#[inline(always)] #[inline(always)]
fn idx_for(pos: Vec3<i32>) -> Option<usize> { fn idx_for(pos: Vec3<i32>) -> Option<usize> {
if pos.map(|e| e >= 0).reduce_and() if pos.map(|e| e >= 0).reduce_and()

View File

@ -20,8 +20,8 @@ pub struct Dyna<V: Vox, M> {
} }
impl<V: Vox, M> Dyna<V, M> { impl<V: Vox, M> Dyna<V, M> {
/// Used to transform a voxel position in the volume into its corresponding index in the voxel /// Used to transform a voxel position in the volume into its corresponding index
// array. /// in the voxel array.
#[inline(always)] #[inline(always)]
fn idx_for(sz: Vec3<u32>, pos: Vec3<i32>) -> Option<usize> { fn idx_for(sz: Vec3<u32>, pos: Vec3<i32>) -> Option<usize> {
if pos.map(|e| e >= 0).reduce_and() && pos.map2(sz, |e, lim| e < lim as i32).reduce_and() { if pos.map(|e| e >= 0).reduce_and() && pos.map2(sz, |e, lim| e < lim as i32).reduce_and() {

View File

View File

@ -15,7 +15,7 @@ fn main() {
let mut clock = Clock::new(); let mut clock = Clock::new();
// Create server // 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 { loop {
let events = server let events = server
@ -30,10 +30,10 @@ fn main() {
} }
} }
// Clean up the server after a tick // Clean up the server after a tick.
server.cleanup(); server.cleanup();
// Wait for the next tick // Wait for the next tick.
clock.tick(Duration::from_millis(1000 / TPS)); clock.tick(Duration::from_millis(1000 / TPS));
} }
} }

View File

@ -1,4 +1,4 @@
//! # Implementing new commands //! # Implementing new commands.
//! To implement a new command, add an instance of `ChatCommand` to `CHAT_COMMANDS` //! To implement a new command, add an instance of `ChatCommand` to `CHAT_COMMANDS`
//! and provide a handler function. //! and provide a handler function.
@ -9,26 +9,26 @@ use vek::*;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use scan_fmt::scan_fmt; use scan_fmt::scan_fmt;
/// Struct representing a command that a user can run from server chat /// Struct representing a command that a user can run from server chat.
pub struct ChatCommand { pub struct ChatCommand {
/// The keyword used to invoke the command, omitting the leading '/' /// The keyword used to invoke the command, omitting the leading '/'.
pub keyword: &'static str, pub keyword: &'static str,
/// A format string for parsing arguments /// A format string for parsing arguments.
arg_fmt: &'static str, arg_fmt: &'static str,
/// message to explain how the command is used /// A message that explains how the command is used.
help_string: &'static str, help_string: &'static str,
/// Handler function called when the command is executed /// Handler function called when the command is executed.
/// # Arguments /// # Arguments
/// * `&mut Server` - the `Server` instance executing the command /// * `&mut Server` - the `Server` instance executing the command.
/// * `EcsEntity` - an `Entity` corresponding to the player that invoked the command /// * `EcsEntity` - an `Entity` corresponding to the player that invoked the command.
/// * `String` - a `String` containing the part of the command after the keyword /// * `String` - a `String` containing the part of the command after the keyword.
/// * `&ChatCommand` - the command to execute with the above arguments /// * `&ChatCommand` - the command to execute with the above arguments.
/// Handler functions must parse arguments from the the given `String` (`scan_fmt!` is included for this purpose) /// Handler functions must parse arguments from the the given `String` (`scan_fmt!` is included for this purpose).
handler: fn(&mut Server, EcsEntity, String, &ChatCommand), handler: fn(&mut Server, EcsEntity, String, &ChatCommand),
} }
impl ChatCommand { impl ChatCommand {
/// Creates a new chat command /// Creates a new chat command.
pub fn new( pub fn new(
keyword: &'static str, keyword: &'static str,
arg_fmt: &'static str, arg_fmt: &'static str,
@ -42,14 +42,14 @@ impl ChatCommand {
handler, handler,
} }
} }
/// Calls the contained handler function, passing `&self` as the last argument /// Calls the contained handler function, passing `&self` as the last argument.
pub fn execute(&self, server: &mut Server, entity: EcsEntity, args: String) { pub fn execute(&self, server: &mut Server, entity: EcsEntity, args: String) {
(self.handler)(server, entity, args, self); (self.handler)(server, entity, args, self);
} }
} }
lazy_static! { lazy_static! {
/// Static list of chat commands available to the server /// Static list of chat commands available to the server.
pub static ref CHAT_COMMANDS: Vec<ChatCommand> = vec![ pub static ref CHAT_COMMANDS: Vec<ChatCommand> = vec![
ChatCommand::new( ChatCommand::new(
"jump", "jump",
@ -81,7 +81,8 @@ lazy_static! {
"/pet : Spawn a test pet NPC", "/pet : Spawn a test pet NPC",
handle_pet handle_pet
), ),
ChatCommand::new("help", "", "/help: Display this message", handle_help) ChatCommand::new(
"help", "", "/help: Display this message", handle_help)
]; ];
} }
@ -104,7 +105,7 @@ fn handle_jump(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
} }
None => server.clients.notify( None => server.clients.notify(
entity, entity,
ServerMsg::Chat(String::from("Command 'jump' invalid in current state")), ServerMsg::Chat(String::from("Command 'jump' invalid in current state.")),
), ),
} }
} }
@ -165,7 +166,7 @@ fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &Chat
} }
None => server.clients.notify( None => server.clients.notify(
entity, entity,
ServerMsg::Chat(format!("Unable to teleport to player '{}'", alias)), ServerMsg::Chat(format!("Unable to teleport to player '{}'!", alias)),
), ),
}, },
None => { None => {

View File

@ -1,5 +1,5 @@
pub struct Input { pub struct Input {
// TODO: Use this type to manage server input // TODO: Use this type to manage server input.
} }
impl Default for Input { impl Default for Input {

View File

@ -56,7 +56,7 @@ impl Server {
Self::bind(SocketAddr::from(([0; 4], 59003))) Self::bind(SocketAddr::from(([0; 4], 59003)))
} }
/// Create a new server bound to the given socket /// Create a new server bound to the given socket.
#[allow(dead_code)] #[allow(dead_code)]
pub fn bind<A: Into<SocketAddr>>(addrs: A) -> Result<Self, Error> { pub fn bind<A: Into<SocketAddr>>(addrs: A) -> Result<Self, Error> {
let (chunk_tx, chunk_rx) = mpsc::channel(); let (chunk_tx, chunk_rx) = mpsc::channel();
@ -114,7 +114,7 @@ impl Server {
&mut self.world &mut self.world
} }
/// Build a non-player character /// Build a non-player character.
#[allow(dead_code)] #[allow(dead_code)]
pub fn create_npc(&mut self, name: String, body: comp::Body) -> EcsEntityBuilder { pub fn create_npc(&mut self, name: String, body: comp::Body) -> EcsEntityBuilder {
self.state self.state
@ -140,18 +140,18 @@ impl Server {
state.write_component(entity, comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0))); state.write_component(entity, comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0)));
state.write_component(entity, comp::phys::Vel(Vec3::zero())); state.write_component(entity, comp::phys::Vel(Vec3::zero()));
state.write_component(entity, comp::phys::Dir(Vec3::unit_y())); state.write_component(entity, comp::phys::Dir(Vec3::unit_y()));
// Make sure everything is accepted // Make sure everything is accepted.
state.write_component(entity, comp::phys::ForceUpdate); state.write_component(entity, comp::phys::ForceUpdate);
// Set initial animation // Set initial animation.
state.write_component(entity, comp::AnimationHistory::new(comp::Animation::Idle)); state.write_component(entity, comp::AnimationHistory::new(comp::Animation::Idle));
// Tell the client his request was successful // Tell the client its request was successful.
client.notify(ServerMsg::StateAnswer(Ok(ClientState::Character))); client.notify(ServerMsg::StateAnswer(Ok(ClientState::Character)));
client.client_state = ClientState::Character; client.client_state = ClientState::Character;
} }
/// Execute a single server tick, handle input and update the game state by the given duration /// Execute a single server tick, handle input and update the game state by the given duration.
#[allow(dead_code)] #[allow(dead_code)]
pub fn tick(&mut self, input: Input, dt: Duration) -> Result<Vec<Event>, Error> { pub fn tick(&mut self, input: Input, dt: Duration) -> Result<Vec<Event>, Error> {
// This tick function is the centre of the Veloren universe. Most server-side things are // This tick function is the centre of the Veloren universe. Most server-side things are
@ -168,27 +168,27 @@ impl Server {
// 6) Send relevant state updates to all clients // 6) Send relevant state updates to all clients
// 7) Finish the tick, passing control of the main thread back to the frontend // 7) Finish the tick, passing control of the main thread back to the frontend
// Build up a list of events for this frame, to be passed to the frontend // Build up a list of events for this frame, to be passed to the frontend.
let mut frontend_events = Vec::new(); let mut frontend_events = Vec::new();
// If networking has problems, handle them // If networking has problems, handle them.
if let Some(err) = self.postoffice.error() { if let Some(err) = self.postoffice.error() {
return Err(err.into()); return Err(err.into());
} }
// Handle new client connections (step 2) // Handle new client connections (step 2).
frontend_events.append(&mut self.handle_new_connections()?); frontend_events.append(&mut self.handle_new_connections()?);
// Handle new messages from clients // Handle new messages from clients
frontend_events.append(&mut self.handle_new_messages()?); frontend_events.append(&mut self.handle_new_messages()?);
// Tick the client's LocalState (step 3) // Tick the client's LocalState (step 3).
self.state.tick(dt); self.state.tick(dt);
// Fetch any generated `TerrainChunk`s and insert them into the terrain // Fetch any generated `TerrainChunk`s and insert them into the terrain.
// Also, send the chunk data to anybody that is close by // Also, send the chunk data to anybody that is close by.
if let Ok((key, chunk)) = self.chunk_rx.try_recv() { if let Ok((key, chunk)) = self.chunk_rx.try_recv() {
// Send the chunk to all nearby players // Send the chunk to all nearby players.
for (entity, player, pos) in ( for (entity, player, pos) in (
&self.state.ecs().entities(), &self.state.ecs().entities(),
&self.state.ecs().read_storage::<comp::Player>(), &self.state.ecs().read_storage::<comp::Player>(),
@ -216,12 +216,12 @@ impl Server {
self.pending_chunks.remove(&key); self.pending_chunks.remove(&key);
} }
// Remove chunks that are too far from players // Remove chunks that are too far from players.
let mut chunks_to_remove = Vec::new(); let mut chunks_to_remove = Vec::new();
self.state.terrain().iter().for_each(|(key, _)| { self.state.terrain().iter().for_each(|(key, _)| {
let mut min_dist = i32::MAX; let mut min_dist = i32::MAX;
// For each player with a position, calculate the distance // For each player with a position, calculate the distance.
for (_, pos) in ( for (_, pos) in (
&self.state.ecs().read_storage::<comp::Player>(), &self.state.ecs().read_storage::<comp::Player>(),
&self.state.ecs().read_storage::<comp::phys::Pos>(), &self.state.ecs().read_storage::<comp::phys::Pos>(),
@ -243,21 +243,21 @@ impl Server {
self.state.remove_chunk(key); self.state.remove_chunk(key);
} }
// Synchronise clients with the new state of the world // Synchronise clients with the new state of the world.
self.sync_clients(); self.sync_clients();
// Finish the tick, pass control back to the frontend (step 6) // Finish the tick, pass control back to the frontend (step 6).
Ok(frontend_events) Ok(frontend_events)
} }
/// Clean up the server after a tick /// Clean up the server after a tick.
#[allow(dead_code)] #[allow(dead_code)]
pub fn cleanup(&mut self) { pub fn cleanup(&mut self) {
// Cleanup the local state // Cleanup the local state
self.state.cleanup(); self.state.cleanup();
} }
/// Handle new client connections /// Handle new client connections.
fn handle_new_connections(&mut self) -> Result<Vec<Event>, Error> { fn handle_new_connections(&mut self) -> Result<Vec<Event>, Error> {
let mut frontend_events = Vec::new(); let mut frontend_events = Vec::new();
@ -269,11 +269,10 @@ impl Server {
last_ping: self.state.get_time(), last_ping: self.state.get_time(),
}; };
// Return the state of the current world // Return the state of the current world (all of the components that Sphynx tracks).
// (All components Sphynx tracks)
client.notify(ServerMsg::InitialSync { client.notify(ServerMsg::InitialSync {
ecs_state: self.state.ecs().gen_state_package(), ecs_state: self.state.ecs().gen_state_package(),
entity_uid: self.state.ecs().uid_from_entity(entity).unwrap().into(), // Can't fail entity_uid: self.state.ecs().uid_from_entity(entity).unwrap().into(), // Can't fail.
}); });
self.clients.add(entity, client); self.clients.add(entity, client);
@ -284,7 +283,7 @@ impl Server {
Ok(frontend_events) Ok(frontend_events)
} }
/// Handle new client messages /// Handle new client messages.
fn handle_new_messages(&mut self) -> Result<Vec<Event>, Error> { fn handle_new_messages(&mut self) -> Result<Vec<Event>, Error> {
let mut frontend_events = Vec::new(); let mut frontend_events = Vec::new();
@ -297,17 +296,17 @@ impl Server {
let mut disconnect = false; let mut disconnect = false;
let new_msgs = client.postbox.new_messages(); let new_msgs = client.postbox.new_messages();
// Update client ping // Update client ping.
if new_msgs.len() > 0 { if new_msgs.len() > 0 {
client.last_ping = state.get_time(); client.last_ping = state.get_time();
// Process incoming messages // Process incoming messages.
for msg in new_msgs { for msg in new_msgs {
match msg { match msg {
ClientMsg::RequestState(requested_state) => match requested_state { ClientMsg::RequestState(requested_state) => match requested_state {
ClientState::Connected => disconnect = true, // Default state ClientState::Connected => disconnect = true, // Default state
ClientState::Registered => match client.client_state { ClientState::Registered => match client.client_state {
// Use ClientMsg::Register instead // Use ClientMsg::Register instead.
ClientState::Connected => { ClientState::Connected => {
client.error_state(RequestStateError::WrongMessage) client.error_state(RequestStateError::WrongMessage)
} }
@ -319,7 +318,7 @@ impl Server {
} }
}, },
ClientState::Spectator => match requested_state { ClientState::Spectator => match requested_state {
// Become Registered first // Become Registered first.
ClientState::Connected => { ClientState::Connected => {
client.error_state(RequestStateError::Impossible) client.error_state(RequestStateError::Impossible)
} }
@ -330,7 +329,7 @@ impl Server {
client.allow_state(ClientState::Spectator) client.allow_state(ClientState::Spectator)
} }
}, },
// Use ClientMsg::Character instead // Use ClientMsg::Character instead.
ClientState::Character => { ClientState::Character => {
client.error_state(RequestStateError::WrongMessage) client.error_state(RequestStateError::WrongMessage)
} }
@ -339,11 +338,11 @@ impl Server {
ClientState::Connected => { ClientState::Connected => {
Self::initialize_player(state, entity, client, player) Self::initialize_player(state, entity, client, player)
} }
// Use RequestState instead (No need to send `player` again) // Use RequestState instead (No need to send `player` again).
_ => client.error_state(RequestStateError::Impossible), _ => client.error_state(RequestStateError::Impossible),
}, },
ClientMsg::Character { name, body } => match client.client_state { ClientMsg::Character { name, body } => match client.client_state {
// Become Registered first // Become Registered first.
ClientState::Connected => { ClientState::Connected => {
client.error_state(RequestStateError::Impossible) client.error_state(RequestStateError::Impossible)
} }
@ -367,7 +366,7 @@ impl Server {
ClientState::Character => { ClientState::Character => {
state.write_component(entity, animation_history) state.write_component(entity, animation_history)
} }
// Only characters can send animations // Only characters can send animations.
_ => client.error_state(RequestStateError::Impossible), _ => client.error_state(RequestStateError::Impossible),
} }
} }
@ -377,7 +376,7 @@ impl Server {
state.write_component(entity, vel); state.write_component(entity, vel);
state.write_component(entity, dir); state.write_component(entity, dir);
} }
// Only characters send their position // Only characters can send positions.
_ => client.error_state(RequestStateError::Impossible), _ => client.error_state(RequestStateError::Impossible),
}, },
ClientMsg::TerrainChunkRequest { key } => match client.client_state { ClientMsg::TerrainChunkRequest { key } => match client.client_state {
@ -396,7 +395,7 @@ impl Server {
} }
} }
}, },
// Always possible // Always possible.
ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong), ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong),
ClientMsg::Pong => {} ClientMsg::Pong => {}
ClientMsg::Disconnect => disconnect = true, ClientMsg::Disconnect => disconnect = true,
@ -408,7 +407,7 @@ impl Server {
{ {
disconnect = true; disconnect = true;
} else if state.get_time() - client.last_ping > CLIENT_TIMEOUT * 0.5 { } else if state.get_time() - client.last_ping > CLIENT_TIMEOUT * 0.5 {
// Try pinging the client if the timeout is nearing // Try pinging the client if the timeout is nearing.
client.postbox.send_message(ServerMsg::Ping); client.postbox.send_message(ServerMsg::Ping);
} }
@ -421,9 +420,9 @@ impl Server {
} }
}); });
// Handle new chat messages // Handle new chat messages.
for (entity, msg) in new_chat_msgs { for (entity, msg) in new_chat_msgs {
// Handle chat commands // Handle chat commands.
if msg.starts_with("/") && msg.len() > 1 { if msg.starts_with("/") && msg.len() > 1 {
let argv = String::from(&msg[1..]); let argv = String::from(&msg[1..]);
self.process_chat_cmd(entity, argv); self.process_chat_cmd(entity, argv);
@ -439,14 +438,14 @@ impl Server {
} }
} }
// Handle client disconnects // Handle client disconnects.
for entity in disconnected_clients { for entity in disconnected_clients {
self.state.ecs_mut().delete_entity_synced(entity); self.state.ecs_mut().delete_entity_synced(entity);
frontend_events.push(Event::ClientDisconnected { entity }); frontend_events.push(Event::ClientDisconnected { entity });
} }
// Generate requested chunks // Generate requested chunks.
for key in requested_chunks { for key in requested_chunks {
self.generate_chunk(key); self.generate_chunk(key);
} }
@ -454,17 +453,17 @@ impl Server {
Ok(frontend_events) Ok(frontend_events)
} }
/// Initialize a new client states with important information /// Initialize a new client states with important information.
fn initialize_player( fn initialize_player(
state: &mut State, state: &mut State,
entity: specs::Entity, entity: specs::Entity,
client: &mut Client, client: &mut Client,
player: comp::Player, player: comp::Player,
) { ) {
// Save player metadata (for example the username) // Save player metadata (for example the username).
state.write_component(entity, player); state.write_component(entity, player);
// Sync logical information other players have authority over, not the server // Sync logical information other players have authority over, not the server.
for (other_entity, &uid, &animation_history) in ( for (other_entity, &uid, &animation_history) in (
&state.ecs().entities(), &state.ecs().entities(),
&state.ecs().read_storage::<common::state::Uid>(), &state.ecs().read_storage::<common::state::Uid>(),
@ -479,17 +478,17 @@ impl Server {
}); });
} }
// Tell the client his request was successful // Tell the client its request was successful.
client.allow_state(ClientState::Registered); client.allow_state(ClientState::Registered);
} }
/// Sync client states with the most up to date information /// Sync client states with the most up to date information.
fn sync_clients(&mut self) { fn sync_clients(&mut self) {
// Sync 'logical' state using Sphynx // Sync 'logical' state using Sphynx.
self.clients self.clients
.notify_registered(ServerMsg::EcsSync(self.state.ecs_mut().next_sync_package())); .notify_registered(ServerMsg::EcsSync(self.state.ecs_mut().next_sync_package()));
// Sync 'physical' state // Sync 'physical' state.
for (entity, &uid, &pos, &vel, &dir, force_update) in ( for (entity, &uid, &pos, &vel, &dir, force_update) in (
&self.state.ecs().entities(), &self.state.ecs().entities(),
&self.state.ecs().read_storage::<Uid>(), &self.state.ecs().read_storage::<Uid>(),
@ -516,7 +515,7 @@ impl Server {
} }
} }
// Sync animation states // Sync animation states.
for (entity, &uid, &animation_history) in ( for (entity, &uid, &animation_history) in (
&self.state.ecs().entities(), &self.state.ecs().entities(),
&self.state.ecs().read_storage::<Uid>(), &self.state.ecs().read_storage::<Uid>(),
@ -524,7 +523,7 @@ impl Server {
) )
.join() .join()
{ {
// Check if we need to sync // Check if we need to sync.
if Some(animation_history.current) == animation_history.last { if Some(animation_history.current) == animation_history.last {
continue; continue;
} }
@ -538,7 +537,7 @@ impl Server {
); );
} }
// Update animation last/current state // Update animation last/current state.
for (entity, mut animation_history) in ( for (entity, mut animation_history) in (
&self.state.ecs().entities(), &self.state.ecs().entities(),
&mut self.state.ecs().write_storage::<comp::AnimationHistory>(), &mut self.state.ecs().write_storage::<comp::AnimationHistory>(),
@ -548,7 +547,7 @@ impl Server {
animation_history.last = Some(animation_history.current); animation_history.last = Some(animation_history.current);
} }
// Remove all force flags // Remove all force flags.
self.state self.state
.ecs_mut() .ecs_mut()
.write_storage::<comp::phys::ForceUpdate>() .write_storage::<comp::phys::ForceUpdate>()
@ -564,18 +563,18 @@ impl Server {
} }
fn process_chat_cmd(&mut self, entity: EcsEntity, cmd: String) { fn process_chat_cmd(&mut self, entity: EcsEntity, cmd: String) {
// separate string into keyword and arguments // Separate string into keyword and arguments.
let sep = cmd.find(' '); let sep = cmd.find(' ');
let (kwd, args) = match sep { let (kwd, args) = match sep {
Some(i) => (cmd[..i].to_string(), cmd[(i + 1)..].to_string()), Some(i) => (cmd[..i].to_string(), cmd[(i + 1)..].to_string()),
None => (cmd, "".to_string()), None => (cmd, "".to_string()),
}; };
// find command object and run its handler // Find the command object and run its handler.
let action_opt = CHAT_COMMANDS.iter().find(|x| x.keyword == kwd); let action_opt = CHAT_COMMANDS.iter().find(|x| x.keyword == kwd);
match action_opt { match action_opt {
Some(action) => action.execute(self, entity, args), Some(action) => action.execute(self, entity, args),
// unknown command // Unknown command
None => { None => {
self.clients.notify( self.clients.notify(
entity, entity,

View File

@ -6,7 +6,6 @@ use vek::*;
// Local // Local
use super::{super::Animation, CharacterSkeleton, SCALE}; use super::{super::Animation, CharacterSkeleton, SCALE};
//
pub struct GlidingAnimation; pub struct GlidingAnimation;
@ -21,19 +20,19 @@ impl Animation for GlidingAnimation {
) -> Self::Skeleton { ) -> Self::Skeleton {
let mut next = (*skeleton).clone(); let mut next = (*skeleton).clone();
let wave = (anim_time as f32 * 14.0).sin(); let wave = (anim_time as f32 * 14.0).sin();
let waveslow = (anim_time as f32 * 7.0).sin(); let wave_slow = (anim_time as f32 * 7.0).sin();
let wavecos_slow = (anim_time as f32 * 7.0).cos(); let wave_slow_cos = (anim_time as f32 * 7.0).cos();
let arcwave = (1.0f32.ln_1p() - 1.5).abs(); let arc_wave = (1.0f32.ln_1p() - 1.5).abs();
let wavetest = (wave.cbrt()); let wave_test = (wave.cbrt());
let fuzzwave = (anim_time as f32 * 12.0).sin(); let fuzz_wave = (anim_time as f32 * 12.0).sin();
let wavecos = (anim_time as f32 * 14.0).cos(); let wave_cos = (anim_time as f32 * 14.0).cos();
let wave_stop = (anim_time as f32 * 1.5).min(PI / 2.0).sin(); let wave_stop = (anim_time as f32 * 1.5).min(PI / 2.0).sin();
let wave_stopalt = (anim_time as f32 * 5.0).min(PI / 2.0).sin(); let wave_stop_alt = (anim_time as f32 * 5.0).min(PI / 2.0).sin();
let waveveryslow = (anim_time as f32 * 3.0).sin(); let wave_very_slow = (anim_time as f32 * 3.0).sin();
let waveveryslowalt = (anim_time as f32 * 2.5).sin(); let wave_very_slow_alt = (anim_time as f32 * 2.5).sin();
let waveveryslowcos = (anim_time as f32 * 3.0).cos(); let wave_very_slow_cos = (anim_time as f32 * 3.0).cos();
let wave_slowtest = (anim_time as f32).min(PI / 2.0).sin(); let wave_slow_test = (anim_time as f32).min(PI / 2.0).sin();
let head_look = Vec2::new( let head_look = Vec2::new(
((global_time + anim_time) as f32 / 4.0) ((global_time + anim_time) as f32 / 4.0)
@ -48,38 +47,48 @@ impl Animation for GlidingAnimation {
* 0.25, * 0.25,
); );
next.head.offset = Vec3::new(5.5, 2.0, 12.0); next.head.offset = Vec3::new(5.5, 2.0, 12.0);
next.head.ori = Quaternion::rotation_x(0.35 - waveveryslow * 0.10 + head_look.y) next.head.ori = Quaternion::rotation_x(0.35 - wave_very_slow * 0.10 + head_look.y)
* Quaternion::rotation_z(head_look.x + waveveryslowcos * 0.15); * Quaternion::rotation_z(head_look.x + wave_very_slow_cos * 0.15);
next.head.scale = Vec3::one(); next.head.scale = Vec3::one();
next.chest.offset = Vec3::new(5.5, 0.0, 8.0); next.chest.offset = Vec3::new(5.5, 0.0, 8.0);
next.chest.ori = Quaternion::rotation_z(waveveryslowcos * 0.15); next.chest.ori = Quaternion::rotation_z(wave_very_slow_cos * 0.15);
next.chest.scale = Vec3::one(); next.chest.scale = Vec3::one();
next.belt.offset = Vec3::new(5.5, 0.0, 6.0); next.belt.offset = Vec3::new(5.5, 0.0, 6.0);
next.belt.ori = Quaternion::rotation_z(waveveryslowcos * 0.20); next.belt.ori = Quaternion::rotation_z(wave_very_slow_cos * 0.20);
next.belt.scale = Vec3::one(); next.belt.scale = Vec3::one();
next.shorts.offset = Vec3::new(5.5, 0.0, 3.0); next.shorts.offset = Vec3::new(5.5, 0.0, 3.0);
next.shorts.ori = Quaternion::rotation_z(waveveryslowcos * 0.25); next.shorts.ori = Quaternion::rotation_z(wave_very_slow_cos * 0.25);
next.shorts.scale = Vec3::one(); next.shorts.scale = Vec3::one();
next.l_hand.offset = Vec3::new(-8.0, -10.0 + waveveryslow * 2.5, 18.5 + waveveryslow * 1.0); next.l_hand.offset = Vec3::new(
next.l_hand.ori = Quaternion::rotation_x(0.9 - waveveryslow * 0.10); -8.0,
-10.0 + wave_very_slow * 2.5,
18.5 + wave_very_slow * 1.0,
);
next.l_hand.ori = Quaternion::rotation_x(0.9 - wave_very_slow * 0.10);
next.l_hand.scale = Vec3::one(); next.l_hand.scale = Vec3::one();
next.r_hand.offset = Vec3::new(11.0, -10.0 + waveveryslow * 2.5, 18.5 + waveveryslow * 1.0); next.r_hand.offset = Vec3::new(
next.r_hand.ori = Quaternion::rotation_x(0.9 - waveveryslow * 0.10); 11.0,
-10.0 + wave_very_slow * 2.5,
18.5 + wave_very_slow * 1.0,
);
next.r_hand.ori = Quaternion::rotation_x(0.9 - wave_very_slow * 0.10);
next.r_hand.scale = Vec3::one(); next.r_hand.scale = Vec3::one();
next.l_foot.offset = Vec3::new(-3.4, 1.0, 8.0); next.l_foot.offset = Vec3::new(-3.4, 1.0, 8.0);
next.l_foot.ori = next.l_foot.ori = Quaternion::rotation_x(
Quaternion::rotation_x(wave_stop * -0.7 - wavecos_slow * -0.21 + waveveryslow * 0.19); wave_stop * -0.7 - wave_slow_cos * -0.21 + wave_very_slow * 0.19,
);
next.l_foot.scale = Vec3::one(); next.l_foot.scale = Vec3::one();
next.r_foot.offset = Vec3::new(3.4, 1.0, 8.0); next.r_foot.offset = Vec3::new(3.4, 1.0, 8.0);
next.r_foot.ori = next.r_foot.ori = Quaternion::rotation_x(
Quaternion::rotation_x(wave_stop * -0.8 + waveslow * -0.25 + waveveryslowalt * 0.13); wave_stop * -0.8 + wave_slow * -0.25 + wave_very_slow_alt * 0.13,
);
next.r_foot.scale = Vec3::one(); next.r_foot.scale = Vec3::one();
next.weapon.offset = Vec3::new(-5.0, -6.0, 19.0); next.weapon.offset = Vec3::new(-5.0, -6.0, 19.0);
@ -95,11 +104,11 @@ impl Animation for GlidingAnimation {
next.r_shoulder.scale = Vec3::one(); next.r_shoulder.scale = Vec3::one();
next.torso.offset = Vec3::new(-0.5, -0.2, 0.0); next.torso.offset = Vec3::new(-0.5, -0.2, 0.0);
next.torso.ori = Quaternion::rotation_x(-0.8 + waveveryslow * 0.10); next.torso.ori = Quaternion::rotation_x(-0.8 + wave_very_slow * 0.10);
next.torso.scale = Vec3::one() / 11.0; next.torso.scale = Vec3::one() / 11.0;
next.draw.offset = Vec3::new(13.5, 3.0, -1.0); next.draw.offset = Vec3::new(13.5, 3.0, -1.0);
next.draw.ori = Quaternion::rotation_y(waveveryslowcos * 0.05); next.draw.ori = Quaternion::rotation_y(wave_very_slow_cos * 0.05);
next.draw.scale = Vec3::one(); next.draw.scale = Vec3::one();
next next

View File

@ -24,11 +24,11 @@ impl Animation for IdleAnimation {
let mut next = (*skeleton).clone(); let mut next = (*skeleton).clone();
let wave = (anim_time as f32 * 12.0).sin(); let wave = (anim_time as f32 * 12.0).sin();
let wavecos = (anim_time as f32 * 12.0).cos(); let wave_cos = (anim_time as f32 * 12.0).cos();
let wave_slow = (anim_time as f32 * 6.0 + PI).sin(); let wave_slow = (anim_time as f32 * 6.0 + PI).sin();
let wavecos_slow = (anim_time as f32 * 6.0 + PI).cos(); let wave_slow_cos = (anim_time as f32 * 6.0 + PI).cos();
let waveultra_slow = (anim_time as f32 * 1.0 + PI).sin(); let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin();
let waveultracos_slow = (anim_time as f32 * 1.0 + PI).cos(); let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos();
let wave_dip = (wave_slow.abs() - 0.5).abs(); let wave_dip = (wave_slow.abs() - 0.5).abs();
let head_look = Vec2::new( let head_look = Vec2::new(
@ -43,37 +43,37 @@ impl Animation for IdleAnimation {
.sin() .sin()
* 0.25, * 0.25,
); );
next.head.offset = Vec3::new(5.5, 2.0, 11.0 + waveultra_slow * 0.3); next.head.offset = Vec3::new(5.5, 2.0, 11.0 + wave_ultra_slow * 0.3);
next.head.ori = Quaternion::rotation_z(head_look.x) * Quaternion::rotation_x(head_look.y); next.head.ori = Quaternion::rotation_z(head_look.x) * Quaternion::rotation_x(head_look.y);
next.head.scale = Vec3::one(); next.head.scale = Vec3::one();
next.chest.offset = Vec3::new(5.5, 0.0, 7.0 + waveultra_slow * 0.3); next.chest.offset = Vec3::new(5.5, 0.0, 7.0 + wave_ultra_slow * 0.3);
next.chest.ori = Quaternion::rotation_x(0.0); next.chest.ori = Quaternion::rotation_x(0.0);
next.chest.scale = Vec3::one(); next.chest.scale = Vec3::one();
next.belt.offset = Vec3::new(5.5, 0.0, 5.0 + waveultra_slow * 0.3); next.belt.offset = Vec3::new(5.5, 0.0, 5.0 + wave_ultra_slow * 0.3);
next.belt.ori = Quaternion::rotation_x(0.0); next.belt.ori = Quaternion::rotation_x(0.0);
next.belt.scale = Vec3::one(); next.belt.scale = Vec3::one();
next.shorts.offset = Vec3::new(5.5, 0.0, 2.0 + waveultra_slow * 0.3); next.shorts.offset = Vec3::new(5.5, 0.0, 2.0 + wave_ultra_slow * 0.3);
next.shorts.ori = Quaternion::rotation_x(0.0); next.shorts.ori = Quaternion::rotation_x(0.0);
next.shorts.scale = Vec3::one(); next.shorts.scale = Vec3::one();
next.l_hand.offset = Vec3::new( next.l_hand.offset = Vec3::new(
-6.0, -6.0,
-2.0 + waveultracos_slow * 0.15, -2.0 + wave_ultra_slow_cos * 0.15,
11.5 + waveultra_slow * 0.5, 11.5 + wave_ultra_slow * 0.5,
); );
next.l_hand.ori = Quaternion::rotation_x(0.0 + waveultra_slow * 0.06); next.l_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * 0.06);
next.l_hand.scale = Vec3::one(); next.l_hand.scale = Vec3::one();
next.r_hand.offset = Vec3::new( next.r_hand.offset = Vec3::new(
9.0, 9.0,
-2.0 + waveultracos_slow * 0.15, -2.0 + wave_ultra_slow_cos * 0.15,
11.5 + waveultra_slow * 0.5, 11.5 + wave_ultra_slow * 0.5,
); );
next.r_hand.ori = Quaternion::rotation_x(0.0 + waveultra_slow * 0.06); next.r_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * 0.06);
next.r_hand.scale = Vec3::one(); next.r_hand.scale = Vec3::one();
next.l_foot.offset = Vec3::new(-3.3, -0.1, 8.0); next.l_foot.offset = Vec3::new(-3.3, -0.1, 8.0);

View File

@ -6,7 +6,6 @@ use vek::*;
// Local // Local
use super::{super::Animation, CharacterSkeleton, SCALE}; use super::{super::Animation, CharacterSkeleton, SCALE};
//
pub struct JumpAnimation; pub struct JumpAnimation;
@ -21,16 +20,16 @@ impl Animation for JumpAnimation {
) -> Self::Skeleton { ) -> Self::Skeleton {
let mut next = (*skeleton).clone(); let mut next = (*skeleton).clone();
let wave = (anim_time as f32 * 14.0).sin(); let wave = (anim_time as f32 * 14.0).sin();
let waveslow = (anim_time as f32 * 7.0).sin(); let wave_slow = (anim_time as f32 * 7.0).sin();
let arcwave = (1.0f32.ln_1p() - 1.5).abs(); let arc_wave = (1.0f32.ln_1p() - 1.5).abs();
let wavetest = (wave.cbrt()); let wave_test = (wave.cbrt());
let fuzzwave = (anim_time as f32 * 12.0).sin(); let fuzz_wave = (anim_time as f32 * 12.0).sin();
let wavecos = (anim_time as f32 * 14.0).cos(); let wave_cos = (anim_time as f32 * 14.0).cos();
let wave_stop = (anim_time as f32 * 4.5).min(PI / 2.0).sin(); let wave_stop = (anim_time as f32 * 4.5).min(PI / 2.0).sin();
let wave_stopalt = (anim_time as f32 * 5.0).min(PI / 2.0).sin(); let wave_stop_alt = (anim_time as f32 * 5.0).min(PI / 2.0).sin();
let wave_slowtest = (anim_time as f32).min(PI / 2.0).sin(); let wave_slow_test = (anim_time as f32).min(PI / 2.0).sin();
let wavecos_slow = (anim_time as f32 * 8.0 + PI).cos(); let wave_slow_cos = (anim_time as f32 * 8.0 + PI).cos();
next.head.offset = Vec3::new(5.5, 2.0, 12.0); next.head.offset = Vec3::new(5.5, 2.0, 12.0);
next.head.ori = Quaternion::rotation_x(0.25); next.head.ori = Quaternion::rotation_x(0.25);
@ -49,19 +48,19 @@ impl Animation for JumpAnimation {
next.shorts.scale = Vec3::one(); next.shorts.scale = Vec3::one();
next.l_hand.offset = Vec3::new(-6.0, 0.0, 12.0); next.l_hand.offset = Vec3::new(-6.0, 0.0, 12.0);
next.l_hand.ori = Quaternion::rotation_x(wave_stopalt * 1.2 - waveslow * 0.15); next.l_hand.ori = Quaternion::rotation_x(wave_stop_alt * 1.2 - wave_slow * 0.15);
next.l_hand.scale = Vec3::one(); next.l_hand.scale = Vec3::one();
next.r_hand.offset = Vec3::new(9.0, 0.0, 12.0); next.r_hand.offset = Vec3::new(9.0, 0.0, 12.0);
next.r_hand.ori = Quaternion::rotation_x(wave_stopalt * -1.2 + waveslow * 0.15); next.r_hand.ori = Quaternion::rotation_x(wave_stop_alt * -1.2 + wave_slow * 0.15);
next.r_hand.scale = Vec3::one(); next.r_hand.scale = Vec3::one();
next.l_foot.offset = Vec3::new(-3.4, 1.0, 6.0); next.l_foot.offset = Vec3::new(-3.4, 1.0, 6.0);
next.l_foot.ori = Quaternion::rotation_x(wave_stop * -1.2 - waveslow * 0.2); next.l_foot.ori = Quaternion::rotation_x(wave_stop * -1.2 - wave_slow * 0.2);
next.l_foot.scale = Vec3::one(); next.l_foot.scale = Vec3::one();
next.r_foot.offset = Vec3::new(3.4, -1.0, 6.0); next.r_foot.offset = Vec3::new(3.4, -1.0, 6.0);
next.r_foot.ori = Quaternion::rotation_x(wave_stop * 1.2 + waveslow * 0.2); next.r_foot.ori = Quaternion::rotation_x(wave_stop * 1.2 + wave_slow * 0.2);
next.r_foot.scale = Vec3::one(); next.r_foot.scale = Vec3::one();
next.weapon.offset = Vec3::new(-5.0, -6.0, 19.0); next.weapon.offset = Vec3::new(-5.0, -6.0, 19.0);

View File

@ -21,35 +21,35 @@ impl Animation for RunAnimation {
let mut next = (*skeleton).clone(); let mut next = (*skeleton).clone();
let wave = (anim_time as f32 * 14.0).sin(); let wave = (anim_time as f32 * 14.0).sin();
let wavetest = (wave.cbrt()); let wave_test = (wave.cbrt());
let fuzzwave = (anim_time as f32 * 12.0).sin(); let fuzz_wave = (anim_time as f32 * 12.0).sin();
let wavecos = (anim_time as f32 * 14.0).cos(); let wave_cos = (anim_time as f32 * 14.0).cos();
let wave_slow = (anim_time as f32 * 7.0 + PI).sin(); let wave_slow = (anim_time as f32 * 7.0 + PI).sin();
let wavecos_slow = (anim_time as f32 * 8.0 + PI).cos(); let wave_slow_cos = (anim_time as f32 * 8.0 + PI).cos();
let wave_dip = (wave_slow.abs() - 0.5).abs(); let wave_dip = (wave_slow.abs() - 0.5).abs();
next.head.offset = Vec3::new(5.5, 2.0, 11.0 + wavecos * 1.3); next.head.offset = Vec3::new(5.5, 2.0, 11.0 + wave_cos * 1.3);
next.head.ori = Quaternion::rotation_x(0.15); next.head.ori = Quaternion::rotation_x(0.15);
next.head.scale = Vec3::one(); next.head.scale = Vec3::one();
next.chest.offset = Vec3::new(5.5, 0.0, 7.0 + wavecos * 1.1); next.chest.offset = Vec3::new(5.5, 0.0, 7.0 + wave_cos * 1.1);
next.chest.ori = Quaternion::rotation_z(wave * 0.1); next.chest.ori = Quaternion::rotation_z(wave * 0.1);
next.chest.scale = Vec3::one(); next.chest.scale = Vec3::one();
next.belt.offset = Vec3::new(5.5, 0.0, 5.0 + wavecos * 1.1); next.belt.offset = Vec3::new(5.5, 0.0, 5.0 + wave_cos * 1.1);
next.belt.ori = Quaternion::rotation_z(wave * 0.25); next.belt.ori = Quaternion::rotation_z(wave * 0.25);
next.belt.scale = Vec3::one(); next.belt.scale = Vec3::one();
next.shorts.offset = Vec3::new(5.5, 0.0, 2.0 + wavecos * 1.1); next.shorts.offset = Vec3::new(5.5, 0.0, 2.0 + wave_cos * 1.1);
next.shorts.ori = Quaternion::rotation_z(wave * 0.6); next.shorts.ori = Quaternion::rotation_z(wave * 0.6);
next.shorts.scale = Vec3::one(); next.shorts.scale = Vec3::one();
next.l_hand.offset = Vec3::new(-6.0, 0.0 + wavecos * 2.5, 11.0 - wave * 1.5); next.l_hand.offset = Vec3::new(-6.0, 0.0 + wave_cos * 2.5, 11.0 - wave * 1.5);
next.l_hand.ori = Quaternion::rotation_x(wavecos * 0.9); next.l_hand.ori = Quaternion::rotation_x(wave_cos * 0.9);
next.l_hand.scale = Vec3::one(); next.l_hand.scale = Vec3::one();
next.r_hand.offset = Vec3::new(9.0, 0.0 - wavecos * 2.5, 11.0 + wave * 1.5); next.r_hand.offset = Vec3::new(9.0, 0.0 - wave_cos * 2.5, 11.0 + wave * 1.5);
next.r_hand.ori = Quaternion::rotation_x(wavecos * -0.9); next.r_hand.ori = Quaternion::rotation_x(wave_cos * -0.9);
next.r_hand.scale = Vec3::one(); next.r_hand.scale = Vec3::one();
next.l_foot.offset = Vec3::new(-3.4, 0.0 + wave * 1.0, 6.0); next.l_foot.offset = Vec3::new(-3.4, 0.0 + wave * 1.0, 6.0);
@ -73,7 +73,7 @@ impl Animation for RunAnimation {
next.r_shoulder.scale = Vec3::one(); next.r_shoulder.scale = Vec3::one();
next.torso.offset = Vec3::new(-0.5, -0.2, 0.4); next.torso.offset = Vec3::new(-0.5, -0.2, 0.4);
next.torso.ori = Quaternion::rotation_x(-velocity * 0.05 - wavecos * 0.1); next.torso.ori = Quaternion::rotation_x(-velocity * 0.05 - wave_cos * 0.1);
next.torso.scale = Vec3::one() / 11.0; next.torso.scale = Vec3::one() / 11.0;
next.draw.offset = Vec3::new(13.5, 0.0, 0.0); next.draw.offset = Vec3::new(13.5, 0.0, 0.0);

View File

@ -28,9 +28,9 @@ impl Bone {
* Mat4::from(self.ori) * Mat4::from(self.ori)
} }
/// Change the current bone to be more like `target` /// Change the current bone to be more like `target`.
fn interpolate(&mut self, target: &Bone) { fn interpolate(&mut self, target: &Bone) {
// TODO: Make configurable // TODO: Make configurable.
let factor = 0.3; let factor = 0.3;
self.offset += (target.offset - self.offset) * factor; self.offset += (target.offset - self.offset) * factor;
self.ori = vek::ops::Slerp::slerp(self.ori, target.ori, factor); self.ori = vek::ops::Slerp::slerp(self.ori, target.ori, factor);
@ -41,7 +41,7 @@ impl Bone {
pub trait Skeleton: Send + Sync + 'static { pub trait Skeleton: Send + Sync + 'static {
fn compute_matrices(&self) -> [FigureBoneData; 16]; fn compute_matrices(&self) -> [FigureBoneData; 16];
/// Change the current skeleton to be more like `target` /// Change the current skeleton to be more like `target`.
fn interpolate(&mut self, target: &Self); fn interpolate(&mut self, target: &Self);
} }
@ -49,7 +49,7 @@ pub trait Animation {
type Skeleton; type Skeleton;
type Dependency; type Dependency;
/// Returns a new skeleton that is generated by the animation /// Returns a new skeleton that is generated by the animation.
fn update_skeleton( fn update_skeleton(
skeleton: &Self::Skeleton, skeleton: &Self::Skeleton,
dependency: Self::Dependency, dependency: Self::Dependency,

View File

@ -21,16 +21,16 @@ impl Animation for IdleAnimation {
let mut next = (*skeleton).clone(); let mut next = (*skeleton).clone();
let wave = (anim_time as f32 * 14.0).sin(); let wave = (anim_time as f32 * 14.0).sin();
let wavetest = (wave.cbrt()); let wave_test = (wave.cbrt());
let waveultra_slow = (anim_time as f32 * 1.0 + PI).sin(); let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin();
let waveultracos_slow = (anim_time as f32 * 1.0 + PI).cos(); let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos();
let fuzzwave = (anim_time as f32 * 12.0).sin(); let fuzz_wave = (anim_time as f32 * 12.0).sin();
let wavecos = (anim_time as f32 * 14.0).cos(); let wave_cos = (anim_time as f32 * 14.0).cos();
let wave_slow = (anim_time as f32 * 3.5 + PI).sin(); let wave_slow = (anim_time as f32 * 3.5 + PI).sin();
let wavecos_slow = (anim_time as f32 * 3.5 + PI).cos(); let wave_slow_cos = (anim_time as f32 * 3.5 + PI).cos();
let wave_dip = (wave_slow.abs() - 0.5).abs(); let wave_dip = (wave_slow.abs() - 0.5).abs();
let pighead_look = Vec2::new( let pig_head_look = Vec2::new(
((global_time + anim_time) as f32 / 8.0) ((global_time + anim_time) as f32 / 8.0)
.floor() .floor()
.mul(7331.0) .mul(7331.0)
@ -43,30 +43,30 @@ impl Animation for IdleAnimation {
* 0.25, * 0.25,
); );
next.pighead.offset = Vec3::new(0.0, -2.0, -1.5 + wave * 0.2) / 11.0; next.pig_head.offset = Vec3::new(0.0, -2.0, -1.5 + wave * 0.2) / 11.0;
next.pighead.ori = Quaternion::rotation_z(pighead_look.x) next.pig_head.ori = Quaternion::rotation_z(pig_head_look.x)
* Quaternion::rotation_x(pighead_look.y + wavecos_slow * 0.03); * Quaternion::rotation_x(pig_head_look.y + wave_slow_cos * 0.03);
next.pighead.scale = Vec3::one() / 10.5; next.pig_head.scale = Vec3::one() / 10.5;
next.pigchest.offset = Vec3::new(wave_slow * 0.05, -9.0, 1.5 + wavecos_slow * 0.4) / 11.0; next.pig_chest.offset = Vec3::new(wave_slow * 0.05, -9.0, 1.5 + wave_slow_cos * 0.4) / 11.0;
next.pigchest.ori = Quaternion::rotation_y(wave_slow * 0.05); next.pig_chest.ori = Quaternion::rotation_y(wave_slow * 0.05);
next.pigchest.scale = Vec3::one() / 11.0; next.pig_chest.scale = Vec3::one() / 11.0;
next.piglf_leg.offset = Vec3::new(-4.5, 2.0, 1.5) / 11.0; next.pig_leg_lf.offset = Vec3::new(-4.5, 2.0, 1.5) / 11.0;
next.piglf_leg.ori = Quaternion::rotation_x(wave_slow * 0.08); next.pig_leg_lf.ori = Quaternion::rotation_x(wave_slow * 0.08);
next.piglf_leg.scale = Vec3::one() / 11.0; next.pig_leg_lf.scale = Vec3::one() / 11.0;
next.pigrf_leg.offset = Vec3::new(2.5, 2.0, 1.5) / 11.0; next.pig_leg_rf.offset = Vec3::new(2.5, 2.0, 1.5) / 11.0;
next.pigrf_leg.ori = Quaternion::rotation_x(wavecos_slow * 0.08); next.pig_leg_rf.ori = Quaternion::rotation_x(wave_slow_cos * 0.08);
next.pigrf_leg.scale = Vec3::one() / 11.0; next.pig_leg_rf.scale = Vec3::one() / 11.0;
next.piglb_leg.offset = Vec3::new(-4.5, -3.0, 1.5) / 11.0; next.pig_leg_lb.offset = Vec3::new(-4.5, -3.0, 1.5) / 11.0;
next.piglb_leg.ori = Quaternion::rotation_x(wavecos_slow * 0.08); next.pig_leg_lb.ori = Quaternion::rotation_x(wave_slow_cos * 0.08);
next.piglb_leg.scale = Vec3::one() / 11.0; next.pig_leg_lb.scale = Vec3::one() / 11.0;
next.pigrb_leg.offset = Vec3::new(2.5, -3.0, 1.5) / 11.0; next.pig_leg_rb.offset = Vec3::new(2.5, -3.0, 1.5) / 11.0;
next.pigrb_leg.ori = Quaternion::rotation_x(wave_slow * 0.08); next.pig_leg_rb.ori = Quaternion::rotation_x(wave_slow * 0.08);
next.pigrb_leg.scale = Vec3::one() / 11.0; next.pig_leg_rb.scale = Vec3::one() / 11.0;
next next
} }

View File

@ -21,37 +21,37 @@ impl Animation for JumpAnimation {
let mut next = (*skeleton).clone(); let mut next = (*skeleton).clone();
let wave = (anim_time as f32 * 14.0).sin(); let wave = (anim_time as f32 * 14.0).sin();
let wavetest = (wave.cbrt()); let wave_test = (wave.cbrt());
let fuzzwave = (anim_time as f32 * 12.0).sin(); let fuzz_wave = (anim_time as f32 * 12.0).sin();
let wavecos = (anim_time as f32 * 14.0).cos(); let wave_cos = (anim_time as f32 * 14.0).cos();
let wave_slow = (anim_time as f32 * 7.0 + PI).sin(); let wave_slow = (anim_time as f32 * 7.0 + PI).sin();
let wavecos_slow = (anim_time as f32 * 8.0 + PI).cos(); let wave_slow_cos = (anim_time as f32 * 8.0 + PI).cos();
let wave_dip = (wave_slow.abs() - 0.5).abs(); let wave_dip = (wave_slow.abs() - 0.5).abs();
let wave_stop = (anim_time as f32 * 4.5).min(PI / 2.0).sin(); let wave_stop = (anim_time as f32 * 4.5).min(PI / 2.0).sin();
next.pighead.offset = Vec3::new(0.0, 0.0, -1.5) / 11.0; next.pig_head.offset = Vec3::new(0.0, 0.0, -1.5) / 11.0;
next.pighead.ori = Quaternion::rotation_x(wave_stop * 0.4); next.pig_head.ori = Quaternion::rotation_x(wave_stop * 0.4);
next.pighead.scale = Vec3::one() / 10.5; next.pig_head.scale = Vec3::one() / 10.5;
next.pigchest.offset = Vec3::new(0.0, -9.0, 1.5) / 11.0; next.pig_chest.offset = Vec3::new(0.0, -9.0, 1.5) / 11.0;
next.pigchest.ori = Quaternion::rotation_x(0.0); next.pig_chest.ori = Quaternion::rotation_x(0.0);
next.pigchest.scale = Vec3::one() / 11.0; next.pig_chest.scale = Vec3::one() / 11.0;
next.piglf_leg.offset = Vec3::new(-4.5, 3.0, 1.5) / 11.0; next.pig_leg_lf.offset = Vec3::new(-4.5, 3.0, 1.5) / 11.0;
next.piglf_leg.ori = Quaternion::rotation_x(wave_stop * 0.6 - wave_slow * 0.3); next.pig_leg_lf.ori = Quaternion::rotation_x(wave_stop * 0.6 - wave_slow * 0.3);
next.piglf_leg.scale = Vec3::one() / 11.0; next.pig_leg_lf.scale = Vec3::one() / 11.0;
next.pigrf_leg.offset = Vec3::new(2.5, 3.0, 1.5) / 11.0; next.pig_leg_rf.offset = Vec3::new(2.5, 3.0, 1.5) / 11.0;
next.pigrf_leg.ori = Quaternion::rotation_x(wave_stop * 0.6 - wave_slow * 0.3); next.pig_leg_rf.ori = Quaternion::rotation_x(wave_stop * 0.6 - wave_slow * 0.3);
next.pigrf_leg.scale = Vec3::one() / 11.0; next.pig_leg_rf.scale = Vec3::one() / 11.0;
next.piglb_leg.offset = Vec3::new(-4.5, -4.0, 2.0) / 11.0; next.pig_leg_lb.offset = Vec3::new(-4.5, -4.0, 2.0) / 11.0;
next.piglb_leg.ori = Quaternion::rotation_x(wave_stop * -0.6 + wave_slow * 0.3); next.pig_leg_lb.ori = Quaternion::rotation_x(wave_stop * -0.6 + wave_slow * 0.3);
next.piglb_leg.scale = Vec3::one() / 11.0; next.pig_leg_lb.scale = Vec3::one() / 11.0;
next.pigrb_leg.offset = Vec3::new(2.5, -4.0, 2.0) / 11.0; next.pig_leg_rb.offset = Vec3::new(2.5, -4.0, 2.0) / 11.0;
next.pigrb_leg.ori = Quaternion::rotation_x(wave_stop * -0.6 + wave_slow * 0.3); next.pig_leg_rb.ori = Quaternion::rotation_x(wave_stop * -0.6 + wave_slow * 0.3);
next.pigrb_leg.scale = Vec3::one() / 11.0; next.pig_leg_rb.scale = Vec3::one() / 11.0;
next next
} }

View File

@ -17,23 +17,23 @@ const SCALE: f32 = 11.0;
#[derive(Clone)] #[derive(Clone)]
pub struct QuadrupedSkeleton { pub struct QuadrupedSkeleton {
pighead: Bone, pig_head: Bone,
pigchest: Bone, pig_chest: Bone,
piglf_leg: Bone, pig_leg_lf: Bone,
pigrf_leg: Bone, pig_leg_rf: Bone,
piglb_leg: Bone, pig_leg_lb: Bone,
pigrb_leg: Bone, pig_leg_rb: Bone,
} }
impl QuadrupedSkeleton { impl QuadrupedSkeleton {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
pighead: Bone::default(), pig_head: Bone::default(),
pigchest: Bone::default(), pig_chest: Bone::default(),
piglf_leg: Bone::default(), pig_leg_lf: Bone::default(),
pigrf_leg: Bone::default(), pig_leg_rf: Bone::default(),
piglb_leg: Bone::default(), pig_leg_lb: Bone::default(),
pigrb_leg: Bone::default(), pig_leg_rb: Bone::default(),
} }
} }
} }
@ -41,12 +41,12 @@ impl QuadrupedSkeleton {
impl Skeleton for QuadrupedSkeleton { impl Skeleton for QuadrupedSkeleton {
fn compute_matrices(&self) -> [FigureBoneData; 16] { fn compute_matrices(&self) -> [FigureBoneData; 16] {
[ [
FigureBoneData::new(self.pighead.compute_base_matrix()), FigureBoneData::new(self.pig_head.compute_base_matrix()),
FigureBoneData::new(self.pigchest.compute_base_matrix()), FigureBoneData::new(self.pig_chest.compute_base_matrix()),
FigureBoneData::new(self.piglf_leg.compute_base_matrix()), FigureBoneData::new(self.pig_leg_lf.compute_base_matrix()),
FigureBoneData::new(self.pigrf_leg.compute_base_matrix()), FigureBoneData::new(self.pig_leg_rf.compute_base_matrix()),
FigureBoneData::new(self.piglb_leg.compute_base_matrix()), FigureBoneData::new(self.pig_leg_lb.compute_base_matrix()),
FigureBoneData::new(self.pigrb_leg.compute_base_matrix()), FigureBoneData::new(self.pig_leg_rb.compute_base_matrix()),
FigureBoneData::default(), FigureBoneData::default(),
FigureBoneData::default(), FigureBoneData::default(),
FigureBoneData::default(), FigureBoneData::default(),
@ -61,11 +61,11 @@ impl Skeleton for QuadrupedSkeleton {
} }
fn interpolate(&mut self, target: &Self) { fn interpolate(&mut self, target: &Self) {
self.pighead.interpolate(&target.pighead); self.pig_head.interpolate(&target.pig_head);
self.pigchest.interpolate(&target.pigchest); self.pig_chest.interpolate(&target.pig_chest);
self.piglf_leg.interpolate(&target.piglf_leg); self.pig_leg_lf.interpolate(&target.pig_leg_lf);
self.pigrf_leg.interpolate(&target.pigrf_leg); self.pig_leg_rf.interpolate(&target.pig_leg_rf);
self.piglb_leg.interpolate(&target.piglb_leg); self.pig_leg_lb.interpolate(&target.pig_leg_lb);
self.pigrb_leg.interpolate(&target.pigrb_leg); self.pig_leg_rb.interpolate(&target.pig_leg_rb);
} }
} }

View File

@ -21,43 +21,43 @@ impl Animation for RunAnimation {
let mut next = (*skeleton).clone(); let mut next = (*skeleton).clone();
let wave = (anim_time as f32 * 14.0).sin(); let wave = (anim_time as f32 * 14.0).sin();
let wavequick = (anim_time as f32 * 20.0).sin(); let wave_quick = (anim_time as f32 * 20.0).sin();
let wavequickcos = (anim_time as f32 * 20.0).cos(); let wave_quick_cos = (anim_time as f32 * 20.0).cos();
let wavetest = (wave.cbrt()); let wave_test = (wave.cbrt());
let fuzzwave = (anim_time as f32 * 12.0).sin(); let fuzz_wave = (anim_time as f32 * 12.0).sin();
let wavecos = (anim_time as f32 * 14.0).cos(); let wave_cos = (anim_time as f32 * 14.0).cos();
let wave_slow = (anim_time as f32 * 7.0 + PI).sin(); let wave_slow = (anim_time as f32 * 7.0 + PI).sin();
let wavecos_slow = (anim_time as f32 * 8.0 + PI).cos(); let wave_slow_cos = (anim_time as f32 * 8.0 + PI).cos();
let wave_dip = (wave_slow.abs() - 0.5).abs(); let wave_dip = (wave_slow.abs() - 0.5).abs();
next.pighead.offset = Vec3::new(0.0, 0.0, -1.5 + wave * 1.5) / 11.0; next.pig_head.offset = Vec3::new(0.0, 0.0, -1.5 + wave * 1.5) / 11.0;
next.pighead.ori = next.pig_head.ori =
Quaternion::rotation_x(0.2 + wave * 0.05) * Quaternion::rotation_y(wavecos * 0.03); Quaternion::rotation_x(0.2 + wave * 0.05) * Quaternion::rotation_y(wave_cos * 0.03);
next.pighead.scale = Vec3::one() / 10.5; next.pig_head.scale = Vec3::one() / 10.5;
next.pigchest.offset = Vec3::new(0.0, -9.0, 1.5 + wavecos * 1.2) / 11.0; next.pig_chest.offset = Vec3::new(0.0, -9.0, 1.5 + wave_cos * 1.2) / 11.0;
next.pigchest.ori = Quaternion::rotation_x(wave * 0.1); next.pig_chest.ori = Quaternion::rotation_x(wave * 0.1);
next.pigchest.scale = Vec3::one() / 11.0; next.pig_chest.scale = Vec3::one() / 11.0;
next.piglf_leg.offset = next.pig_leg_lf.offset =
Vec3::new(-4.5, 2.0 + wavequick * 0.8, 2.5 + wavequickcos * 1.5) / 11.0; Vec3::new(-4.5, 2.0 + wave_quick * 0.8, 2.5 + wave_quick_cos * 1.5) / 11.0;
next.piglf_leg.ori = Quaternion::rotation_x(wavequick * 0.3); next.pig_leg_lf.ori = Quaternion::rotation_x(wave_quick * 0.3);
next.piglf_leg.scale = Vec3::one() / 11.0; next.pig_leg_lf.scale = Vec3::one() / 11.0;
next.pigrf_leg.offset = next.pig_leg_rf.offset =
Vec3::new(2.5, 2.0 - wavequickcos * 0.8, 2.5 + wavequick * 1.5) / 11.0; Vec3::new(2.5, 2.0 - wave_quick_cos * 0.8, 2.5 + wave_quick * 1.5) / 11.0;
next.pigrf_leg.ori = Quaternion::rotation_x(wavequickcos * -0.3); next.pig_leg_rf.ori = Quaternion::rotation_x(wave_quick_cos * -0.3);
next.pigrf_leg.scale = Vec3::one() / 11.0; next.pig_leg_rf.scale = Vec3::one() / 11.0;
next.piglb_leg.offset = next.pig_leg_lb.offset =
Vec3::new(-4.5, -3.0 - wavequickcos * 0.8, 2.5 + wavequick * 1.5) / 11.0; Vec3::new(-4.5, -3.0 - wave_quick_cos * 0.8, 2.5 + wave_quick * 1.5) / 11.0;
next.piglb_leg.ori = Quaternion::rotation_x(wavequickcos * -0.3); next.pig_leg_lb.ori = Quaternion::rotation_x(wave_quick_cos * -0.3);
next.piglb_leg.scale = Vec3::one() / 11.0; next.pig_leg_lb.scale = Vec3::one() / 11.0;
next.pigrb_leg.offset = next.pig_leg_rb.offset =
Vec3::new(2.5, -3.0 + wavequick * 0.8, 2.5 + wavequickcos * 1.5) / 11.0; Vec3::new(2.5, -3.0 + wave_quick * 0.8, 2.5 + wave_quick_cos * 1.5) / 11.0;
next.pigrb_leg.ori = Quaternion::rotation_x(wavequick * 0.3); next.pig_leg_rb.ori = Quaternion::rotation_x(wave_quick * 0.3);
next.pigrb_leg.scale = Vec3::one() / 11.0; next.pig_leg_rb.scale = Vec3::one() / 11.0;
next next
} }

View File

@ -7,16 +7,16 @@ use client;
// Crate // Crate
use crate::render::RenderError; use crate::render::RenderError;
/// Represents any error that may be triggered by Voxygen /// Represents any error that may be triggered by Voxygen.
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// An error relating to the internal client /// An error relating to the internal client.
ClientError(client::Error), ClientError(client::Error),
/// A miscellaneous error relating to a backend dependency /// A miscellaneous error relating to a backend dependency.
BackendError(Box<any::Any>), BackendError(Box<any::Any>),
/// An error relating the rendering subsystem /// An error relating the rendering subsystem.
RenderError(RenderError), RenderError(RenderError),
// A miscellaneous error with an unknown or unspecified source /// A miscellaneous error with an unknown or unspecified source.
Other(failure::Error), Other(failure::Error),
} }

View File

@ -150,9 +150,9 @@ impl<'a> Widget for Buttons<'a> {
return Some(Event::ToggleMap); return Some(Event::ToggleMap);
}; };
// Other Windows can only be accessed, when Settings are closed. // Other Windows can only be accessed when `Settings` is closed.
// Opening Settings will close all other Windows including the Bag. // Opening `Settings` will close all other Windows, including the `Bag`.
// Opening the Map won't close the windows displayed before. // Opening the `Map` won't close the previously displayed windows.
Image::new(self.imgs.social_button) Image::new(self.imgs.social_button)
.w_h(25.0, 25.0) .w_h(25.0, 25.0)
.left_from(state.ids.settings_button, 10.0) .left_from(state.ids.settings_button, 10.0)

View File

@ -104,7 +104,7 @@ impl<'a> Widget for CharacterWindow<'a> {
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event { fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs { id, state, ui, .. } = args; let widget::UpdateArgs { id, state, ui, .. } = args;
// TODO: Read from parameter / character struct // TODO: Read from parameter/character struct.
let xp_percentage = 0.4; let xp_percentage = 0.4;
// Frame // Frame
@ -133,7 +133,8 @@ impl<'a> Widget for CharacterWindow<'a> {
} }
// Title // Title
Text::new("Character Name") // Add in actual Character Name // TODO: Use an actual character name.
Text::new("Character Name")
.mid_top_with_margin_on(state.charwindow_frame, 6.0) .mid_top_with_margin_on(state.charwindow_frame, 6.0)
.font_id(self.fonts.metamorph) .font_id(self.fonts.metamorph)
.font_size(14) .font_size(14)
@ -153,7 +154,7 @@ impl<'a> Widget for CharacterWindow<'a> {
// Contents // Contents
//Head // Head
Image::new(self.imgs.head_bg) Image::new(self.imgs.head_bg)
.w_h(28.0 * 1.8, 28.0 * 1.8) .w_h(28.0 * 1.8, 28.0 * 1.8)
.mid_top_with_margin_on(state.content_align, 5.0) .mid_top_with_margin_on(state.content_align, 5.0)
@ -319,7 +320,8 @@ impl<'a> Widget for CharacterWindow<'a> {
.top_left_with_margins_on(state.charwindow_tab_bg, 7.0 * 4.0, 4.0 * 4.0) .top_left_with_margins_on(state.charwindow_tab_bg, 7.0 * 4.0, 4.0 * 4.0)
.set(state.charwindow_rectangle, ui); .set(state.charwindow_rectangle, ui);
// Tab Button -> Add that back in when we have multiple tabs // TODO: Add this back in when we have multiple tabs.
// Tab Button ->
// Button::image(self.imgs.charwindow_tab) // Button::image(self.imgs.charwindow_tab)
//.w_h(65.0, 23.0) //.w_h(65.0, 23.0)
//.top_left_with_margins_on(state.charwindow_tab_bg, -18.0, 1.8) //.top_left_with_margins_on(state.charwindow_tab_bg, -18.0, 1.8)
@ -328,7 +330,8 @@ impl<'a> Widget for CharacterWindow<'a> {
//.label_font_size(14) //.label_font_size(14)
//.set(state.charwindow_tab1, ui); //.set(state.charwindow_tab1, ui);
Text::new("1") //Add in actual Character Level // TODO: Use an actual character level.
Text::new("1")
.mid_top_with_margin_on(state.charwindow_rectangle, 10.0) .mid_top_with_margin_on(state.charwindow_rectangle, 10.0)
.font_id(self.fonts.opensans) .font_id(self.fonts.opensans)
.font_size(30) .font_size(30)
@ -352,7 +355,8 @@ impl<'a> Widget for CharacterWindow<'a> {
.set(state.charwindow_tab1_expbar, ui); .set(state.charwindow_tab1_expbar, ui);
// Exp-Text // Exp-Text
Text::new("120/170") // Shows the Exp / Exp to reach the next level // TODO: Shows current Exp over the next threshold Exp.
Text::new("120/170")
.mid_top_with_margin_on(state.charwindow_tab1_expbar, 10.0) .mid_top_with_margin_on(state.charwindow_tab1_expbar, 10.0)
.font_id(self.fonts.opensans) .font_id(self.fonts.opensans)
.font_size(15) .font_size(15)
@ -382,6 +386,7 @@ impl<'a> Widget for CharacterWindow<'a> {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(state.charwindow_tab1_statnames, ui); .set(state.charwindow_tab1_statnames, ui);
// TODO: Shows actual stat points.
Text::new( Text::new(
"1234\n\ "1234\n\
\n\ \n\

View File

@ -39,7 +39,8 @@ impl<'a> Chat<'a> {
} }
fn scrolled_to_bottom(state: &State, ui: &UiCell) -> bool { fn scrolled_to_bottom(state: &State, ui: &UiCell) -> bool {
// could be more efficient to cache result and update it when a scroll event has occurred instead of every frame // Might be more efficient to cache result and update it when a scroll event has occurred
// instead of every frame.
if let Some(scroll) = ui if let Some(scroll) = ui
.widget_graph() .widget_graph()
.widget(state.ids.message_box) .widget(state.ids.message_box)
@ -84,7 +85,7 @@ impl<'a> Widget for Chat<'a> {
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event { fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs { id, state, ui, .. } = args; let widget::UpdateArgs { id, state, ui, .. } = args;
// Maintain scrolling // Maintain scrolling.
if !self.new_messages.is_empty() { if !self.new_messages.is_empty() {
state.update(|s| s.messages.extend(self.new_messages.drain(..))); state.update(|s| s.messages.extend(self.new_messages.drain(..)));
ui.scroll_widget(state.ids.message_box, [0.0, std::f64::MAX]); ui.scroll_widget(state.ids.message_box, [0.0, std::f64::MAX]);
@ -93,8 +94,8 @@ impl<'a> Widget for Chat<'a> {
let keyboard_capturer = ui.global_input().current.widget_capturing_keyboard; let keyboard_capturer = ui.global_input().current.widget_capturing_keyboard;
let input_focused = keyboard_capturer == Some(state.ids.input); let input_focused = keyboard_capturer == Some(state.ids.input);
// Only show if it has the keyboard captured // Only show if it has the keyboard captured.
// Chat input with rectangle as background // Chat input uses a rectangle as its background.
if input_focused { if input_focused {
let text_edit = TextEdit::new(&state.input) let text_edit = TextEdit::new(&state.input)
.w(460.0) .w(460.0)
@ -139,7 +140,7 @@ impl<'a> Widget for Chat<'a> {
.scroll_kids_vertically() .scroll_kids_vertically()
.set(state.ids.message_box, ui); .set(state.ids.message_box, ui);
while let Some(item) = items.next(ui) { while let Some(item) = items.next(ui) {
// This would be easier if conrod used the v-metrics from rusttype // This would be easier if conrod used the v-metrics from rusttype.
let widget = if item.i < state.messages.len() { let widget = if item.i < state.messages.len() {
let text = Text::new(&state.messages[item.i]) let text = Text::new(&state.messages[item.i])
.font_size(15) .font_size(15)
@ -147,15 +148,15 @@ impl<'a> Widget for Chat<'a> {
.w(470.0) .w(470.0)
.color(TEXT_COLOR) .color(TEXT_COLOR)
.line_spacing(2.0); .line_spacing(2.0);
// Add space between messages // Add space between messages.
let y = match text.get_y_dimension(ui) { let y = match text.get_y_dimension(ui) {
Dimension::Absolute(y) => y + 2.0, Dimension::Absolute(y) => y + 2.0,
_ => 0.0, _ => 0.0,
}; };
text.h(y) text.h(y)
} else { } else {
// Spacer at bottom of the last message so that it is not cut off // Spacer at bottom of the last message so that it is not cut off.
// Needs to be larger than the space above // Needs to be larger than the space above.
Text::new("") Text::new("")
.font_size(6) .font_size(6)
.font_id(self.fonts.opensans) .font_id(self.fonts.opensans)
@ -165,7 +166,7 @@ impl<'a> Widget for Chat<'a> {
} }
// Chat Arrow // Chat Arrow
// Check if already at bottom // Check if already at bottom.
if !Self::scrolled_to_bottom(state, ui) { if !Self::scrolled_to_bottom(state, ui) {
if Button::image(self.imgs.chat_arrow) if Button::image(self.imgs.chat_arrow)
.w_h(20.0, 20.0) .w_h(20.0, 20.0)
@ -179,11 +180,11 @@ impl<'a> Widget for Chat<'a> {
} }
} }
// If the chat widget is focused return a focus event to pass the focus to the input box // If the chat widget is focused, return a focus event to pass the focus to the input box.
if keyboard_capturer == Some(id) { if keyboard_capturer == Some(id) {
Some(Event::Focus(state.ids.input)) Some(Event::Focus(state.ids.input))
} }
// If enter is pressed and the input box is not empty send the current message // If enter is pressed and the input box is not empty, send the current message.
else if ui else if ui
.widget_input(state.ids.input) .widget_input(state.ids.input)
.presses() .presses()

View File

@ -103,7 +103,7 @@ impl<'a> Widget for EscMenu<'a> {
.set(state.ids.menu_button_2, ui) .set(state.ids.menu_button_2, ui)
.was_clicked() .was_clicked()
{ {
// TODO: Show controls window // TODO: Show controls window.
}; };
// Servers // Servers
if Button::image(self.imgs.button) if Button::image(self.imgs.button)
@ -118,7 +118,7 @@ impl<'a> Widget for EscMenu<'a> {
.set(state.ids.menu_button_3, ui) .set(state.ids.menu_button_3, ui)
.was_clicked() .was_clicked()
{ {
// TODO: Show servers window (is needed in-game?) // TODO: Show servers window (needed in-game?).
}; };
// Logout // Logout
if Button::image(self.imgs.button) if Button::image(self.imgs.button)

View File

@ -103,7 +103,7 @@ impl<'a> Widget for MiniMap<'a> {
} }
// Title // Title
// Make it display the actual location // TODO: Make it display the actual location.
Text::new("Uncanny Valley") Text::new("Uncanny Valley")
.mid_top_with_margin_on(state.ids.mmap_frame, 3.0) .mid_top_with_margin_on(state.ids.mmap_frame, 3.0)
.font_size(14) .font_size(14)

View File

@ -94,13 +94,13 @@ pub enum Event {
Quit, Quit,
} }
// TODO: are these the possible layouts we want? // TODO: Are these the possible layouts we want?
// TODO: maybe replace this with bitflags // TODO: Maybe replace this with bitflags.
// map not here because it currently is displayed over the top of other open windows // `map` is not here because it currently is displayed over the top of other open windows.
#[derive(PartialEq)] #[derive(PartialEq)]
pub enum Windows { pub enum Windows {
Settings, // display settings window Settings, // Display settings window.
CharacterAnd(Option<SmallWindowType>), // show character window + optionally another CharacterAnd(Option<SmallWindowType>), // Show character window + optionally another.
Small(SmallWindowType), Small(SmallWindowType),
None, None,
} }
@ -146,7 +146,7 @@ impl Show {
}; };
} }
fn toggle_charwindow(&mut self) { fn toggle_char_window(&mut self) {
self.open_windows = match self.open_windows { self.open_windows = match self.open_windows {
Windows::CharacterAnd(small) => match small { Windows::CharacterAnd(small) => match small {
Some(small) => Windows::Small(small), Some(small) => Windows::Small(small),
@ -212,14 +212,14 @@ pub struct Hud {
impl Hud { impl Hud {
pub fn new(window: &mut Window, settings: Settings) -> Self { pub fn new(window: &mut Window, settings: Settings) -> Self {
let mut ui = Ui::new(window).unwrap(); let mut ui = Ui::new(window).unwrap();
// TODO: adjust/remove this, right now it is used to demonstrate window scaling functionality // TODO: Adjust/remove this, right now it is used to demonstrate window scaling functionality.
ui.scaling_mode(ScaleMode::RelativeToWindow([1920.0, 1080.0].into())); ui.scaling_mode(ScaleMode::RelativeToWindow([1920.0, 1080.0].into()));
// Generate ids // Generate ids.
let ids = Ids::new(ui.id_generator()); let ids = Ids::new(ui.id_generator());
// Load images // Load images.
let imgs = Imgs::load(&mut ui).expect("Failed to load images"); let imgs = Imgs::load(&mut ui).expect("Failed to load images!");
// Load fonts // Load fonts.
let fonts = Fonts::load(&mut ui).expect("Failed to load fonts"); let fonts = Fonts::load(&mut ui).expect("Failed to load fonts!");
Self { Self {
ui, ui,
@ -251,12 +251,12 @@ impl Hud {
let ref mut ui_widgets = self.ui.set_widgets(); let ref mut ui_widgets = self.ui.set_widgets();
let version = env!("CARGO_PKG_VERSION"); let version = env!("CARGO_PKG_VERSION");
// Don't show anything if the UI is toggled off // Don't show anything if the UI is toggled off.
if !self.show.ui { if !self.show.ui {
return events; return events;
} }
// Display debug window // Display debug window.
if self.show.debug { if self.show.debug {
// Alpha Version // Alpha Version
Text::new(version) Text::new(version)
@ -273,7 +273,7 @@ impl Hud {
.set(self.ids.fps_counter, ui_widgets); .set(self.ids.fps_counter, ui_widgets);
} }
// Add Bag-Space Button // Add Bag-Space Button.
if self.show.inventory_test_button { if self.show.inventory_test_button {
if Button::image(self.imgs.grid_button) if Button::image(self.imgs.grid_button)
.w_h(100.0, 100.0) .w_h(100.0, 100.0)
@ -314,7 +314,7 @@ impl Hud {
}; };
} }
// Bag button and icons near it // Bag button and nearby icons
match Buttons::new( match Buttons::new(
&self.show.open_windows, &self.show.open_windows,
self.show.map, self.show.map,
@ -326,7 +326,7 @@ impl Hud {
{ {
Some(buttons::Event::ToggleBag) => self.show.toggle_bag(), Some(buttons::Event::ToggleBag) => self.show.toggle_bag(),
Some(buttons::Event::ToggleSettings) => self.show.toggle_settings(), Some(buttons::Event::ToggleSettings) => self.show.toggle_settings(),
Some(buttons::Event::ToggleCharacter) => self.show.toggle_charwindow(), Some(buttons::Event::ToggleCharacter) => self.show.toggle_char_window(),
Some(buttons::Event::ToggleSmall(small)) => self.show.toggle_small(small), Some(buttons::Event::ToggleSmall(small)) => self.show.toggle_small(small),
Some(buttons::Event::ToggleMap) => self.show.toggle_map(), Some(buttons::Event::ToggleMap) => self.show.toggle_map(),
None => {} None => {}
@ -365,10 +365,10 @@ impl Hud {
} }
self.new_messages = VecDeque::new(); self.new_messages = VecDeque::new();
//Windows // Windows
//Char Window will always appear at the left side. Other Windows either appear at the left side, // Char Window will always appear at the left side. Other Windows default to the
//or when the Char Window is opened they will appear right from it. // left side, but when the Char Window is opened they will appear to the right of it.
// Settings // Settings
if let Windows::Settings = self.show.open_windows { if let Windows::Settings = self.show.open_windows {
@ -447,7 +447,7 @@ impl Hud {
self.new_messages.push_back(msg); self.new_messages.push_back(msg);
} }
// Checks if a TextEdit widget has the keyboard captured // Checks if a TextEdit widget has the keyboard captured.
fn typing(&self) -> bool { fn typing(&self) -> bool {
if let Some(id) = self.ui.widget_capturing_keyboard() { if let Some(id) = self.ui.widget_capturing_keyboard() {
self.ui self.ui
@ -515,7 +515,7 @@ impl Hud {
true true
} }
Key::CharacterWindow => { Key::CharacterWindow => {
self.show.toggle_charwindow(); self.show.toggle_char_window();
true true
} }
Key::Social => { Key::Social => {
@ -547,7 +547,7 @@ impl Hud {
} }
_ => false, _ => false,
}; };
// Handle cursor grab // Handle cursor grab.
if !self.force_ungrab { if !self.force_ungrab {
if cursor_grabbed != self.show.want_grab { if cursor_grabbed != self.show.want_grab {
global_state.window.grab_cursor(self.show.want_grab); global_state.window.grab_cursor(self.show.want_grab);
@ -571,8 +571,8 @@ impl Hud {
} }
} }
//Get the text to show in the help window, along with the // Get the text to show in the help window and use the
//length of the longest line in order to resize the window // length of the longest line to resize the window.
fn get_help_text(cs: &ControlSettings) -> String { fn get_help_text(cs: &ControlSettings) -> String {
format!( format!(
"{free_cursor:?} = Free cursor\n\ "{free_cursor:?} = Free cursor\n\

View File

@ -237,7 +237,7 @@ impl<'a> Widget for SettingsWindow<'a> {
.set(state.ids.debug_button_label, ui); .set(state.ids.debug_button_label, ui);
} }
// 2 Gameplay//////////////// // 2 Gameplay
if Button::image(if let SettingsTab::Gameplay = state.settings_tab { if Button::image(if let SettingsTab::Gameplay = state.settings_tab {
self.imgs.settings_button_pressed self.imgs.settings_button_pressed
} else { } else {
@ -264,7 +264,7 @@ impl<'a> Widget for SettingsWindow<'a> {
state.update(|s| s.settings_tab = SettingsTab::Gameplay); state.update(|s| s.settings_tab = SettingsTab::Gameplay);
} }
// 3 Controls///////////////////// // 3 Controls
if Button::image(if let SettingsTab::Controls = state.settings_tab { if Button::image(if let SettingsTab::Controls = state.settings_tab {
self.imgs.settings_button_pressed self.imgs.settings_button_pressed
} else { } else {
@ -356,7 +356,7 @@ impl<'a> Widget for SettingsWindow<'a> {
.font_id(self.fonts.opensans) .font_id(self.fonts.opensans)
.font_size(18) .font_size(18)
.set(state.ids.controls_text, ui); .set(state.ids.controls_text, ui);
// TODO: Replace with buttons that show the actual keybind and allow the user to change it. // TODO: Replace with buttons that show actual keybinds and allow the user to change them.
Text::new( Text::new(
"TAB\n\ "TAB\n\
F1\n\ F1\n\
@ -423,7 +423,7 @@ impl<'a> Widget for SettingsWindow<'a> {
.font_size(18) .font_size(18)
.set(state.ids.controls_controls, ui); .set(state.ids.controls_controls, ui);
} }
// 4 Video//////////////////////////////// // 4 Video
if Button::image(if let SettingsTab::Video = state.settings_tab { if Button::image(if let SettingsTab::Video = state.settings_tab {
self.imgs.settings_button_pressed self.imgs.settings_button_pressed
} else { } else {
@ -451,7 +451,7 @@ impl<'a> Widget for SettingsWindow<'a> {
state.update(|s| s.settings_tab = SettingsTab::Video); state.update(|s| s.settings_tab = SettingsTab::Video);
} }
// 5 Sound/////////////////////////////// // 5 Sound
if Button::image(if let SettingsTab::Sound = state.settings_tab { if Button::image(if let SettingsTab::Sound = state.settings_tab {
self.imgs.settings_button_pressed self.imgs.settings_button_pressed
} else { } else {

View File

@ -68,12 +68,13 @@ impl<'a> Widget for Skillbar<'a> {
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event { fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs { state, ui, .. } = args; let widget::UpdateArgs { state, ui, .. } = args;
// TODO: Read from parameter / character struct // TODO: Read from parameter/character struct
let xp_percentage = 0.4; let xp_percentage = 0.4;
let hp_percentage = 1.0; let hp_percentage = 1.0;
let mana_percentage = 1.0; let mana_percentage = 1.0;
// Crosshair TODO: Only show while aiming with a bow or when casting a spell // TODO: Only show while aiming with a bow or when casting a spell.
// Crosshair
// Image::new(self.imgs.crosshair) // Image::new(self.imgs.crosshair)
// .w_h(101.0 * 0.5, 101.0 * 0.5) // .w_h(101.0 * 0.5, 101.0 * 0.5)
// .mid_top_with_margin_on(ui.window, 500.0) // .mid_top_with_margin_on(ui.window, 500.0)
@ -158,14 +159,14 @@ impl<'a> Widget for Skillbar<'a> {
// Level Display // Level Display
// Insert actual Level here // TODO: Insert actual Level here.
Text::new("1") Text::new("1")
.left_from(state.ids.xp_bar, -15.0) .left_from(state.ids.xp_bar, -15.0)
.font_size(10) .font_size(10)
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(state.ids.level_text, ui); .set(state.ids.level_text, ui);
// Insert next Level here // TODO: Insert next Level here.
Text::new("2") Text::new("2")
.right_from(state.ids.xp_bar, -15.0) .right_from(state.ids.xp_bar, -15.0)
.font_size(10) .font_size(10)

View File

@ -24,17 +24,17 @@ use log;
use simplelog::{CombinedLogger, Config, TermLogger, WriteLogger}; use simplelog::{CombinedLogger, Config, TermLogger, WriteLogger};
use std::{fs::File, mem, panic, str::FromStr, thread}; use std::{fs::File, mem, panic, str::FromStr, thread};
/// The URL of the default public server that Voxygen will connect to /// The URL of the default public server that Voxygen will connect to.
const DEFAULT_PUBLIC_SERVER: &'static str = "server.veloren.net"; const DEFAULT_PUBLIC_SERVER: &'static str = "server.veloren.net";
/// A type used to store state that is shared between all play states /// A type used to store state that is shared between all play states.
pub struct GlobalState { pub struct GlobalState {
settings: Settings, settings: Settings,
window: Window, window: Window,
} }
impl GlobalState { impl GlobalState {
/// Called after a change in play state has occured (usually used to reverse any temporary /// Called after a change in play state has occurred (usually used to reverse any temporary
/// effects a state may have made). /// effects a state may have made).
pub fn on_play_state_changed(&mut self) { pub fn on_play_state_changed(&mut self) {
self.window.grab_cursor(false); self.window.grab_cursor(false);
@ -47,16 +47,16 @@ pub enum Direction {
Backwards, Backwards,
} }
// States can either close (and revert to a previous state), push a new state on top of themselves, /// States can either close (and revert to a previous state), push a new state on top of themselves,
// or switch to a totally different state /// or switch to a totally different state.
pub enum PlayStateResult { pub enum PlayStateResult {
/// Pop all play states in reverse order and shut down the program /// Pop all play states in reverse order and shut down the program.
Shutdown, Shutdown,
/// Close the current play state and pop it from the play state stack /// Close the current play state and pop it from the play state stack.
Pop, Pop,
/// Push a new play state onto the play state stack /// Push a new play state onto the play state stack.
Push(Box<dyn PlayState>), Push(Box<dyn PlayState>),
/// Switch the current play state with a new play state /// Switch the current play state with a new play state.
Switch(Box<dyn PlayState>), Switch(Box<dyn PlayState>),
} }
@ -67,16 +67,16 @@ pub trait PlayState {
/// is closed). /// is closed).
fn play(&mut self, direction: Direction, global_state: &mut GlobalState) -> PlayStateResult; fn play(&mut self, direction: Direction, global_state: &mut GlobalState) -> PlayStateResult;
/// Get a descriptive name for this state type /// Get a descriptive name for this state type.
fn name(&self) -> &'static str; fn name(&self) -> &'static str;
} }
fn main() { fn main() {
// Set up the global state // Set up the global state.
let settings = Settings::load(); let settings = Settings::load();
let window = Window::new(&settings).expect("Failed to create window"); let window = Window::new(&settings).expect("Failed to create window!");
// Init logging // Initialize logging.
let term_log_level = std::env::var_os("VOXYGEN_LOG") let term_log_level = std::env::var_os("VOXYGEN_LOG")
.and_then(|env| env.to_str().map(|s| s.to_owned())) .and_then(|env| env.to_str().map(|s| s.to_owned()))
.and_then(|s| log::LevelFilter::from_str(&s).ok()) .and_then(|s| log::LevelFilter::from_str(&s).ok())
@ -91,7 +91,7 @@ fn main() {
]) ])
.unwrap(); .unwrap();
// Set up panic handler to relay swish panic messages to the user // Set up panic handler to relay swish panic messages to the user.
let settings_clone = settings.clone(); let settings_clone = settings.clone();
let default_hook = panic::take_hook(); let default_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| { panic::set_hook(Box::new(move |panic_info| {
@ -155,7 +155,7 @@ fn main() {
let mut global_state = GlobalState { settings, window }; let mut global_state = GlobalState { settings, window };
// Set up the initial play state // Set up the initial play state.
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(&mut global_state))]; let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(&mut global_state))];
states states
.last() .last()
@ -173,14 +173,14 @@ fn main() {
.last_mut() .last_mut()
.map(|last| last.play(direction, &mut global_state)) .map(|last| last.play(direction, &mut global_state))
{ {
// Implement state transfer logic // Implement state transfer logic.
match state_result { match state_result {
PlayStateResult::Shutdown => { PlayStateResult::Shutdown => {
direction = Direction::Backwards; direction = Direction::Backwards;
log::info!("Shutting down all states..."); log::info!("Shutting down all states...");
while states.last().is_some() { while states.last().is_some() {
states.pop().map(|old_state| { states.pop().map(|old_state| {
log::info!("Popped state '{}'", old_state.name()); log::info!("Popped state '{}'.", old_state.name());
global_state.on_play_state_changed(); global_state.on_play_state_changed();
}); });
} }
@ -188,13 +188,13 @@ fn main() {
PlayStateResult::Pop => { PlayStateResult::Pop => {
direction = Direction::Backwards; direction = Direction::Backwards;
states.pop().map(|old_state| { states.pop().map(|old_state| {
log::info!("Popped state '{}'", old_state.name()); log::info!("Popped state '{}'.", old_state.name());
global_state.on_play_state_changed(); global_state.on_play_state_changed();
}); });
} }
PlayStateResult::Push(new_state) => { PlayStateResult::Push(new_state) => {
direction = Direction::Forwards; direction = Direction::Forwards;
log::info!("Pushed state '{}'", new_state.name()); log::info!("Pushed state '{}'.", new_state.name());
states.push(new_state); states.push(new_state);
global_state.on_play_state_changed(); global_state.on_play_state_changed();
} }
@ -202,7 +202,7 @@ fn main() {
direction = Direction::Forwards; direction = Direction::Forwards;
states.last_mut().map(|old_state| { states.last_mut().map(|old_state| {
log::info!( log::info!(
"Switching to state '{}' from state '{}'", "Switching to state '{}' from state '{}'.",
new_state.name(), new_state.name(),
old_state.name() old_state.name()
); );

View File

@ -22,7 +22,7 @@ pub struct CharSelectionState {
} }
impl CharSelectionState { impl CharSelectionState {
/// Create a new `CharSelectionState` /// Create a new `CharSelectionState`.
pub fn new(window: &mut Window, client: Rc<RefCell<Client>>) -> Self { pub fn new(window: &mut Window, client: Rc<RefCell<Client>>) -> Self {
Self { Self {
char_selection_ui: CharSelectionUi::new(window), char_selection_ui: CharSelectionUi::new(window),
@ -32,7 +32,7 @@ impl CharSelectionState {
} }
} }
// The background colour // Background colour
const BG_COLOR: Rgba<f32> = Rgba { const BG_COLOR: Rgba<f32> = Rgba {
r: 0.0, r: 0.0,
g: 0.3, g: 0.3,
@ -42,28 +42,28 @@ const BG_COLOR: Rgba<f32> = Rgba {
impl PlayState for CharSelectionState { impl PlayState for CharSelectionState {
fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult { fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult {
// Set up an fps clock // Set up an fps clock.
let mut clock = Clock::new(); let mut clock = Clock::new();
loop { loop {
// Handle window events // Handle window events.
for event in global_state.window.fetch_events() { for event in global_state.window.fetch_events() {
match event { match event {
Event::Close => { Event::Close => {
return PlayStateResult::Shutdown; return PlayStateResult::Shutdown;
} }
// Pass events to ui // Pass events to ui.
Event::Ui(event) => { Event::Ui(event) => {
self.char_selection_ui.handle_event(event); self.char_selection_ui.handle_event(event);
} }
// Ignore all other events // Ignore all other events.
_ => {} _ => {}
} }
} }
global_state.window.renderer_mut().clear(BG_COLOR); global_state.window.renderer_mut().clear(BG_COLOR);
// Maintain the UI // Maintain the UI.
for event in self for event in self
.char_selection_ui .char_selection_ui
.maintain(global_state.window.renderer_mut()) .maintain(global_state.window.renderer_mut())
@ -89,33 +89,33 @@ impl PlayState for CharSelectionState {
} }
} }
// Maintain the scene // Maintain the scene.
self.scene self.scene
.maintain(global_state.window.renderer_mut(), &self.client.borrow()); .maintain(global_state.window.renderer_mut(), &self.client.borrow());
// Render the scene // Render the scene.
self.scene self.scene
.render(global_state.window.renderer_mut(), &self.client.borrow()); .render(global_state.window.renderer_mut(), &self.client.borrow());
// Draw the UI to the screen // Draw the UI to the screen.
self.char_selection_ui self.char_selection_ui
.render(global_state.window.renderer_mut()); .render(global_state.window.renderer_mut());
// Tick the client (currently only to keep the connection alive) // Tick the client (currently only to keep the connection alive).
self.client self.client
.borrow_mut() .borrow_mut()
.tick(client::Input::default(), clock.get_last_delta()) .tick(client::Input::default(), clock.get_last_delta())
.expect("Failed to tick the client"); .expect("Failed to tick the client");
self.client.borrow_mut().cleanup(); self.client.borrow_mut().cleanup();
// Finish the frame // Finish the frame.
global_state.window.renderer_mut().flush(); global_state.window.renderer_mut().flush();
global_state global_state
.window .window
.swap_buffers() .swap_buffers()
.expect("Failed to swap window buffers"); .expect("Failed to swap window buffers");
// Wait for the next tick // Wait for the next tick.
clock.tick(Duration::from_millis(1000 / FPS)); clock.tick(Duration::from_millis(1000 / FPS));
} }
} }

View File

@ -276,16 +276,16 @@ pub struct CharSelectionUi {
impl CharSelectionUi { impl CharSelectionUi {
pub fn new(window: &mut Window) -> Self { pub fn new(window: &mut Window) -> Self {
let mut ui = Ui::new(window).unwrap(); let mut ui = Ui::new(window).unwrap();
// TODO: adjust/remove this, right now it is used to demonstrate window scaling functionality // TODO: Adjust/remove this, right now it is used to demonstrate window scaling functionality.
ui.scaling_mode(ScaleMode::RelativeToWindow([1920.0, 1080.0].into())); ui.scaling_mode(ScaleMode::RelativeToWindow([1920.0, 1080.0].into()));
// Generate ids // Generate ids
let ids = Ids::new(ui.id_generator()); let ids = Ids::new(ui.id_generator());
// Load images // Load images
let imgs = Imgs::load(&mut ui).expect("Failed to load images"); let imgs = Imgs::load(&mut ui).expect("Failed to load images!");
// Load fonts // Load fonts
let fonts = Fonts::load(&mut ui).expect("Failed to load fonts"); let fonts = Fonts::load(&mut ui).expect("Failed to load fonts!");
// TODO: Randomize initial values // TODO: Randomize initial values.
Self { Self {
ui, ui,
ids, ids,
@ -299,20 +299,20 @@ impl CharSelectionUi {
} }
} }
// TODO: split this up into multiple modules or functions // TODO: Split this into multiple modules or functions.
fn update_layout(&mut self) -> Vec<Event> { fn update_layout(&mut self) -> Vec<Event> {
let mut events = Vec::new(); let mut events = Vec::new();
let ref mut ui_widgets = self.ui.set_widgets(); let ref mut ui_widgets = self.ui.set_widgets();
let version = env!("CARGO_PKG_VERSION"); let version = env!("CARGO_PKG_VERSION");
// Character Selection ///////////////// // Character Selection
// Supposed functionality: // Supposed functionality:
// 3d rendered characters have to be clicked for selection // 3d rendered characters have to be clicked for selection.
// Selected characters will appear in the selection window // Selected characters will appear in the selection window.
// the selection window is only active when there are >0 characters on the server // The selection window is only active when there are >0 characters on the server.
// after logging into the server the character that was played last will be selected automatically // After logging into the server the character that was played last will be selected automatically.
// if >1 characters are on the server but none of them was logged in last the one that was created last will be selected // If >1 characters are on the server but none of them was logged in last the one that was created last will be selected.
// if the no. of characters = character_limit the "Create Character" button won't be clickable anymore // If the no. of characters = character_limit the "Create Character" button won't be clickable anymore.
// Background Image // Background Image
if !self.character_creation { if !self.character_creation {
@ -336,7 +336,7 @@ impl CharSelectionUi {
events.push(Event::Logout); events.push(Event::Logout);
} }
// Create Character Button // Create Character Button.
if Button::image(self.imgs.button) if Button::image(self.imgs.button)
.mid_bottom_with_margin_on(ui_widgets.window, 10.0) .mid_bottom_with_margin_on(ui_widgets.window, 10.0)
.w_h(270.0, 50.0) .w_h(270.0, 50.0)
@ -374,7 +374,7 @@ impl CharSelectionUi {
.font_size(14) .font_size(14)
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(self.ids.version, ui_widgets); .set(self.ids.version, ui_widgets);
// Click Character to Login <-- Temporary! // Click Character to Login TODO: <-- Temporary!
Image::new(self.imgs.window_frame_2) Image::new(self.imgs.window_frame_2)
.mid_top_with_margin_on(ui_widgets.window, 60.0) .mid_top_with_margin_on(ui_widgets.window, 60.0)
.w_h(700.0, 70.0) .w_h(700.0, 70.0)
@ -443,7 +443,7 @@ impl CharSelectionUi {
{} {}
} }
} }
// Character_Creation ////////////// // Character_Creation
else { else {
// Background // Background
//Image::new(self.imgs.bg_creation) //Image::new(self.imgs.bg_creation)
@ -478,7 +478,7 @@ impl CharSelectionUi {
.set(self.ids.create_button, ui_widgets) .set(self.ids.create_button, ui_widgets)
.was_clicked() .was_clicked()
{ {
// TODO: Save character // TODO: Save character.
self.character_creation = false; self.character_creation = false;
} }
// Character Name Input // Character Name Input
@ -519,7 +519,7 @@ impl CharSelectionUi {
.set(self.ids.creation_window, ui_widgets); .set(self.ids.creation_window, ui_widgets);
// Arrows // Arrows
// TODO: lower the resolution of the arrow images & use non decimal sizes below // TODO: Lower the resolution of the arrow images & use non decimal sizes below.
const ARROW_WH: [f64; 2] = [986.0 * 0.03, 1024.0 * 0.03]; const ARROW_WH: [f64; 2] = [986.0 * 0.03, 1024.0 * 0.03];
match self.creation_state { match self.creation_state {
CreationState::Race => { CreationState::Race => {
@ -586,7 +586,7 @@ impl CharSelectionUi {
// Body // Body
//Race Selection // Race Selection
if let CreationState::Race = self.creation_state { if let CreationState::Race = self.creation_state {
Text::new("Choose your Race") Text::new("Choose your Race")
.mid_top_with_margin_on(self.ids.creation_window, 74.0) .mid_top_with_margin_on(self.ids.creation_window, 74.0)
@ -595,7 +595,7 @@ impl CharSelectionUi {
.set(self.ids.select_window_title, ui_widgets); .set(self.ids.select_window_title, ui_widgets);
// Male/Female/Race Icons // Male/Female/Race Icons
// for alignment // Alignment
Rectangle::fill_with([151.0, 68.0], color::TRANSPARENT) Rectangle::fill_with([151.0, 68.0], color::TRANSPARENT)
.mid_top_with_margin_on(self.ids.creation_window, 210.0) .mid_top_with_margin_on(self.ids.creation_window, 210.0)
.set(self.ids.body_type_bg, ui_widgets); .set(self.ids.body_type_bg, ui_widgets);
@ -636,11 +636,11 @@ impl CharSelectionUi {
{ {
self.character_body.body_type = BodyType::Female; self.character_body.body_type = BodyType::Female;
} }
// for alignment // Alignment
Rectangle::fill_with([458.0, 68.0], color::TRANSPARENT) Rectangle::fill_with([458.0, 68.0], color::TRANSPARENT)
.mid_top_with_margin_on(self.ids.creation_window, 120.0) .mid_top_with_margin_on(self.ids.creation_window, 120.0)
.set(self.ids.races_bg, ui_widgets); .set(self.ids.races_bg, ui_widgets);
// TODO: If races where in some sort of array format we could do this in a loop // TODO: If races were in some sort of array format, we could do this in a loop.
// Human // Human
Image::new(if let BodyType::Male = self.character_body.body_type { Image::new(if let BodyType::Male = self.character_body.body_type {
self.imgs.human_m self.imgs.human_m
@ -777,7 +777,7 @@ impl CharSelectionUi {
// Description Headline and Text // Description Headline and Text
// TODO: Load these from files (or from the server???) // TODO: Load these from files (or from the server???).
const HUMAN_DESC: &str = const HUMAN_DESC: &str =
"The former nomads were only recently able to gain a foothold in the world of Veloren. \n\ "The former nomads were only recently able to gain a foothold in the world of Veloren. \n\
\n\ \n\
@ -854,7 +854,6 @@ impl CharSelectionUi {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.wrap_by_word() .wrap_by_word()
.set(self.ids.race_description, ui_widgets); .set(self.ids.race_description, ui_widgets);
// Races Descriptions
} }
if let CreationState::Weapon = self.creation_state { if let CreationState::Weapon = self.creation_state {
@ -863,7 +862,7 @@ impl CharSelectionUi {
.font_size(28) .font_size(28)
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(self.ids.select_window_title, ui_widgets); .set(self.ids.select_window_title, ui_widgets);
// BG for Alignment // Alignment
Rectangle::fill_with([470.0, 60.0], color::TRANSPARENT) Rectangle::fill_with([470.0, 60.0], color::TRANSPARENT)
.mid_top_with_margin_on(self.ids.creation_window, 180.0) .mid_top_with_margin_on(self.ids.creation_window, 180.0)
.set(self.ids.weapon_bg, ui_widgets); .set(self.ids.weapon_bg, ui_widgets);
@ -997,7 +996,7 @@ impl CharSelectionUi {
self.character_body.weapon = Weapon::Staff; self.character_body.weapon = Weapon::Staff;
} }
// TODO: Load these from files (or from the server???) // TODO: Load these from files (or from the server???).
const SWORDSHIELD_DESC: &str = " MISSING "; const SWORDSHIELD_DESC: &str = " MISSING ";
const DAGGERS_DESC: &str = " MISSING "; const DAGGERS_DESC: &str = " MISSING ";
const SWORD_DESC: &str = " MISSING "; const SWORD_DESC: &str = " MISSING ";
@ -1028,12 +1027,11 @@ impl CharSelectionUi {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.wrap_by_word() .wrap_by_word()
.set(self.ids.race_description, ui_widgets); .set(self.ids.race_description, ui_widgets);
// Races Descriptions
} }
// 3 states/windows: 1.Skin & Eyes 2.Hair 3.Accessories // 3 states/windows: 1: Skin & Eyes 2: Hair 3: Accessories
// If one state is activated the other ones collapse // If one state is activated, the other ones collapse.
// The title bar is the button to unfold/collapse the windows // The title bar is the button to unfold/collapse the windows.
// The BG Frame can be stretched to the needed size // The BG Frame can be stretched to the needed size.
// Window BG // Window BG
if let CreationState::Body(state) = self.creation_state { if let CreationState::Body(state) = self.creation_state {
@ -1093,7 +1091,7 @@ impl CharSelectionUi {
{ {
self.creation_state = CreationState::Body(BodyPart::Accessories); self.creation_state = CreationState::Body(BodyPart::Accessories);
} }
} // State 1 fin }
// Hair Open // Hair Open
BodyPart::Hair => { BodyPart::Hair => {
@ -1144,7 +1142,7 @@ impl CharSelectionUi {
{ {
self.creation_state = CreationState::Body(BodyPart::Accessories); self.creation_state = CreationState::Body(BodyPart::Accessories);
} }
} // State 2 fin }
// Open: Accessories // Open: Accessories
BodyPart::Accessories => { BodyPart::Accessories => {
@ -1195,10 +1193,10 @@ impl CharSelectionUi {
{ {
self.creation_state = CreationState::Body(BodyPart::Accessories); self.creation_state = CreationState::Body(BodyPart::Accessories);
} }
} // State 3 fin }
} // match fin }
// Body Customization Window Contents //////////////////////// // Body Customization Window Contents
match state { match state {
BodyPart::SkinEyes => { BodyPart::SkinEyes => {
// Skin Color: Text, Brightness Slider, Picker // Skin Color: Text, Brightness Slider, Picker
@ -1207,18 +1205,18 @@ impl CharSelectionUi {
.font_size(25) .font_size(25)
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(self.ids.skin_color_text, ui_widgets); .set(self.ids.skin_color_text, ui_widgets);
// TODO: Align Buttons here // TODO: Align Buttons here.
// They set an i32 to a value from 0-14 // Users set a variable to a value from 0-14.
// Depending on the race another color will be chosen // Depending on the race another color will be chosen.
// Here only the BG image changes depending on the race. // Only the BG image (190x114 -> 2px border!) changes depending on the race.
Rectangle::fill_with([192.0, 116.0], color::WHITE) Rectangle::fill_with([192.0, 116.0], color::WHITE)
.top_right_with_margins_on(self.ids.skin_eyes_window, 60.0, 30.0) .top_right_with_margins_on(self.ids.skin_eyes_window, 60.0, 30.0)
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(self.ids.skin_rect, ui_widgets); .set(self.ids.skin_rect, ui_widgets);
// TODO:Slider // TODO: Slider
// Sliders actually change the Alpha-Level of the main colour chosen above // Sliders actually change the Alpha-Level of the main colour chosen above.
// -> They will appear "brighter", therefore the sliders are labeled "Brightness" // -> They will appear "brighter", therefore the sliders are labeled "Brightness".
Image::new(self.imgs.slider_range) Image::new(self.imgs.slider_range)
.w_h(208.0, 12.0) .w_h(208.0, 12.0)
.bottom_left_with_margins_on(self.ids.skin_rect, 10.0, -255.0) .bottom_left_with_margins_on(self.ids.skin_rect, 10.0, -255.0)
@ -1241,17 +1239,16 @@ impl CharSelectionUi {
.font_size(25) .font_size(25)
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(self.ids.eye_color_text, ui_widgets); .set(self.ids.eye_color_text, ui_widgets);
// TODO: Align 16 Buttons here // TODO: Align 16 Buttons here.
// // Users set a variable to a value from 0-14.
// They set a variable to a value from 0-14 // Depending on the race another color will be chosen.
// Depending on the race another color will be chosen
// Only the BG image (190x114 -> 2px border!) changes depending on the race. // Only the BG image (190x114 -> 2px border!) changes depending on the race.
Rectangle::fill_with([192.0, 116.0], color::WHITE) Rectangle::fill_with([192.0, 116.0], color::WHITE)
.top_right_with_margins_on(self.ids.skin_eyes_window, 186.0, 30.0) .top_right_with_margins_on(self.ids.skin_eyes_window, 186.0, 30.0)
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(self.ids.eyes_rect, ui_widgets); .set(self.ids.eyes_rect, ui_widgets);
// TODO:Slider // TODO: Slider
Image::new(self.imgs.slider_range) Image::new(self.imgs.slider_range)
.w_h(208.0, 12.0) .w_h(208.0, 12.0)
@ -1270,7 +1267,7 @@ impl CharSelectionUi {
.set(self.ids.eye_color_slider_text, ui_widgets); .set(self.ids.eye_color_slider_text, ui_widgets);
} }
// Hair /////////////////////////////////////////////////////// // Hair
// Hair Styles -> Arrows // Hair Styles -> Arrows
// Hair Color -> Picker // Hair Color -> Picker
@ -1352,7 +1349,7 @@ impl CharSelectionUi {
.set(self.ids.eyebrow_arrow_l, ui_widgets) .set(self.ids.eyebrow_arrow_l, ui_widgets)
.was_clicked() .was_clicked()
{}; {};
// Beard -> Only active when "male" was chosen // Beard -> Only active if "male" was chosen.
if let BodyType::Male = self.character_body.body_type { if let BodyType::Male = self.character_body.body_type {
Text::new("Beard Style") Text::new("Beard Style")
.mid_top_with_margin_on(self.ids.hair_window, 340.0) .mid_top_with_margin_on(self.ids.hair_window, 340.0)
@ -1378,9 +1375,9 @@ impl CharSelectionUi {
} }
} }
// Accessories /////////////////////////////// // Accessories
// Accessory Picker -> Arrows (Name Changes with race!) // Accessory Picker -> Arrows (Name changes with race!)
// Color -> Picker // Color -> Picker
// Brightness -> Slider // Brightness -> Slider
BodyPart::Accessories => { BodyPart::Accessories => {
@ -1450,7 +1447,7 @@ impl CharSelectionUi {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.font_size(14) .font_size(14)
.set(self.ids.warpaint_slider_text, ui_widgets); .set(self.ids.warpaint_slider_text, ui_widgets);
} // Human }
Race::Orc => { Race::Orc => {
Text::new("Head Band") Text::new("Head Band")
.mid_top_with_margin_on(self.ids.accessories_window, 60.0) .mid_top_with_margin_on(self.ids.accessories_window, 60.0)
@ -1516,7 +1513,7 @@ impl CharSelectionUi {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.font_size(14) .font_size(14)
.set(self.ids.warpaint_slider_text, ui_widgets); .set(self.ids.warpaint_slider_text, ui_widgets);
} // Orc }
Race::Elf => { Race::Elf => {
Text::new("Tribe Markings") Text::new("Tribe Markings")
.mid_top_with_margin_on(self.ids.accessories_window, 60.0) .mid_top_with_margin_on(self.ids.accessories_window, 60.0)
@ -1582,7 +1579,7 @@ impl CharSelectionUi {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.font_size(14) .font_size(14)
.set(self.ids.warpaint_slider_text, ui_widgets); .set(self.ids.warpaint_slider_text, ui_widgets);
} // Elf }
Race::Dwarf => { Race::Dwarf => {
Text::new("War Paint") Text::new("War Paint")
.mid_top_with_margin_on(self.ids.accessories_window, 60.0) .mid_top_with_margin_on(self.ids.accessories_window, 60.0)
@ -1648,7 +1645,7 @@ impl CharSelectionUi {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.font_size(14) .font_size(14)
.set(self.ids.warpaint_slider_text, ui_widgets); .set(self.ids.warpaint_slider_text, ui_widgets);
} // Dwarf }
Race::Undead => { Race::Undead => {
Text::new("Teeth") Text::new("Teeth")
.mid_top_with_margin_on(self.ids.accessories_window, 60.0) .mid_top_with_margin_on(self.ids.accessories_window, 60.0)
@ -1714,7 +1711,7 @@ impl CharSelectionUi {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.font_size(14) .font_size(14)
.set(self.ids.warpaint_slider_text, ui_widgets); .set(self.ids.warpaint_slider_text, ui_widgets);
} // Undead }
Race::Danari => { Race::Danari => {
Text::new("Horns") Text::new("Horns")
.mid_top_with_margin_on(self.ids.accessories_window, 60.0) .mid_top_with_margin_on(self.ids.accessories_window, 60.0)
@ -1780,12 +1777,12 @@ impl CharSelectionUi {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.font_size(14) .font_size(14)
.set(self.ids.warpaint_slider_text, ui_widgets); .set(self.ids.warpaint_slider_text, ui_widgets);
} // Danari }
} // match Race fin } // match Race fin
} // Accessories fin }
} // Body Customization Fin }
} // CreationState::Body Fin }
} // Char Creation fin }
events events
} }

View File

@ -9,16 +9,17 @@ use std::{
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
// Error parsing input string or error resolving host name // Error parsing input string or error resolving host name.
BadAddress(std::io::Error), BadAddress(std::io::Error),
// Parsing yielded an empty iterator (specifically to_socket_addrs()) // Parsing yielded an empty iterator (specifically to_socket_addrs()).
NoAddress, NoAddress,
// Parsing/host name resolution successful but could not connect // Parsing/host name resolution successful but could not connect.
ConnectionFailed(ClientError), ConnectionFailed(ClientError),
ClientCrashed, ClientCrashed,
} }
// Used to asynchronusly parse the server address, resolve host names, and create the client (which involves establishing a connection to the server) // Used to asynchronously parse the server address, resolve host names,
// and create the client (which involves establishing a connection to the server).
pub struct ClientInit { pub struct ClientInit {
rx: Receiver<Result<Client, Error>>, rx: Receiver<Result<Client, Error>>,
} }
@ -34,19 +35,20 @@ impl ClientInit {
let (tx, rx) = channel(); let (tx, rx) = channel();
thread::spawn(move || { thread::spawn(move || {
// Sleep the thread to wait for the single-player server to start up // Sleep the thread to wait for the single-player server to start up.
if wait { if wait {
thread::sleep(Duration::from_millis(500)); thread::sleep(Duration::from_millis(500));
} }
// Parses ip address or resolves hostname // Parse ip address or resolves hostname.
// Note: if you use an ipv6 address the number after the last colon will be used as the port unless you use [] around the address // Note: if you use an ipv6 address, the number after the last colon will be used
// as the port unless you use [] around the address.
match server_address match server_address
.to_socket_addrs() .to_socket_addrs()
.or((server_address.as_ref(), default_port).to_socket_addrs()) .or((server_address.as_ref(), default_port).to_socket_addrs())
{ {
Ok(socket_adders) => { Ok(socket_address) => {
let (first_addrs, second_addrs) = let (first_addrs, second_addrs) =
socket_adders.partition::<Vec<_>, _>(|a| a.is_ipv6() == prefer_ipv6); socket_address.partition::<Vec<_>, _>(|a| a.is_ipv6() == prefer_ipv6);
let mut last_err = None; let mut last_err = None;
@ -59,11 +61,11 @@ impl ClientInit {
} }
Err(err) => { Err(err) => {
match err { match err {
// assume connection failed and try next address // Assume the connection failed and try next address.
ClientError::Network(_) => { ClientError::Network(_) => {
last_err = Some(Error::ConnectionFailed(err)) last_err = Some(Error::ConnectionFailed(err))
} }
// TODO: handle error? // TODO: Handle errors?
_ => panic!( _ => panic!(
"Unexpected non-network error when creating client: {:?}", "Unexpected non-network error when creating client: {:?}",
err err
@ -72,11 +74,11 @@ impl ClientInit {
} }
} }
} }
// Parsing/host name resolution successful but no connection succeeded // Parsing/host name resolution successful but no connection succeeded.
let _ = tx.send(Err(last_err.unwrap_or(Error::NoAddress))); let _ = tx.send(Err(last_err.unwrap_or(Error::NoAddress)));
} }
Err(err) => { Err(err) => {
// Error parsing input string or error resolving host name // Error parsing input string or error resolving host name.
let _ = tx.send(Err(Error::BadAddress(err))); let _ = tx.send(Err(Error::BadAddress(err)));
} }
} }
@ -84,8 +86,8 @@ impl ClientInit {
ClientInit { rx } ClientInit { rx }
} }
// Returns None is the thread is still running /// Poll if the thread is complete.
// Otherwise returns the Result of client creation /// Returns None if the thread is still running, otherwise returns the Result of client creation.
pub fn poll(&self) -> Option<Result<Client, Error>> { pub fn poll(&self) -> Option<Result<Client, Error>> {
match self.rx.try_recv() { match self.rx.try_recv() {
Ok(result) => Some(result), Ok(result) => Some(result),

View File

@ -21,7 +21,7 @@ pub struct MainMenuState {
} }
impl MainMenuState { impl MainMenuState {
/// Create a new `MainMenuState` /// Create a new `MainMenuState`.
pub fn new(global_state: &mut GlobalState) -> Self { pub fn new(global_state: &mut GlobalState) -> Self {
Self { Self {
main_menu_ui: MainMenuUi::new(global_state), main_menu_ui: MainMenuUi::new(global_state),
@ -41,29 +41,29 @@ const BG_COLOR: Rgba<f32> = Rgba {
impl PlayState for MainMenuState { impl PlayState for MainMenuState {
fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult { fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult {
// Set up an fps clock // Set up an fps clock.
let mut clock = Clock::new(); let mut clock = Clock::new();
// Used for client creation // Used for client creation.
let mut client_init: Option<ClientInit> = None; let mut client_init: Option<ClientInit> = None;
loop { loop {
// Handle window events // Handle window events.
for event in global_state.window.fetch_events() { for event in global_state.window.fetch_events() {
match event { match event {
Event::Close => return PlayStateResult::Shutdown, Event::Close => return PlayStateResult::Shutdown,
// Pass events to ui // Pass events to ui.
Event::Ui(event) => { Event::Ui(event) => {
self.main_menu_ui.handle_event(event); self.main_menu_ui.handle_event(event);
} }
// Ignore all other events // Ignore all other events.
_ => {} _ => {}
} }
} }
global_state.window.renderer_mut().clear(BG_COLOR); global_state.window.renderer_mut().clear(BG_COLOR);
// Poll client creation // Poll client creation.
match client_init.as_ref().and_then(|init| init.poll()) { match client_init.as_ref().and_then(|init| init.poll()) {
Some(Ok(client)) => { Some(Ok(client)) => {
self.main_menu_ui.connected(); self.main_menu_ui.connected();
@ -86,7 +86,7 @@ impl PlayState for MainMenuState {
None => {} None => {}
} }
// Maintain the UI // 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 { match event {
MainMenuEvent::LoginAttempt { MainMenuEvent::LoginAttempt {
@ -98,9 +98,9 @@ impl PlayState for MainMenuState {
if !net_settings.servers.contains(&server_address) { if !net_settings.servers.contains(&server_address) {
net_settings.servers.push(server_address.clone()); net_settings.servers.push(server_address.clone());
} }
// TODO: Handle this result // TODO: Handle this result.
global_state.settings.save_to_file(); global_state.settings.save_to_file();
// Don't try to connect if there is already a connection in progress // Don't try to connect if there is already a connection in progress.
client_init = client_init.or(Some(ClientInit::new( client_init = client_init.or(Some(ClientInit::new(
(server_address, DEFAULT_PORT, false), (server_address, DEFAULT_PORT, false),
(comp::Player::new(username.clone()), 300), (comp::Player::new(username.clone()), 300),
@ -114,17 +114,17 @@ impl PlayState for MainMenuState {
} }
} }
// Draw the UI to the screen // Draw the UI to the screen.
self.main_menu_ui.render(global_state.window.renderer_mut()); self.main_menu_ui.render(global_state.window.renderer_mut());
// Finish the frame // Finish the frame.
global_state.window.renderer_mut().flush(); global_state.window.renderer_mut().flush();
global_state global_state
.window .window
.swap_buffers() .swap_buffers()
.expect("Failed to swap window buffers"); .expect("Failed to swap window buffers!");
// Wait for the next tick // Wait for the next tick.
clock.tick(Duration::from_millis(1000 / FPS)); clock.tick(Duration::from_millis(1000 / FPS));
} }
} }

View File

@ -13,7 +13,7 @@ pub struct StartSingleplayerState {
} }
impl StartSingleplayerState { impl StartSingleplayerState {
/// Create a new `MainMenuState` /// Create a new `MainMenuState`.
pub fn new() -> Self { pub fn new() -> Self {
let (singleplayer, sock) = Singleplayer::new(); let (singleplayer, sock) = Singleplayer::new();
@ -34,13 +34,12 @@ impl PlayState for StartSingleplayerState {
true, true,
); );
// Client creation // Create the client.
let client = loop { let client = loop {
match client_init.poll() { match client_init.poll() {
Some(Ok(client)) => break client, Some(Ok(client)) => break client,
// An error occured!
Some(Err(err)) => { Some(Err(err)) => {
warn!("Failed to start singleplayer server: {:?}", err); warn!("Failed to start single-player server: {:?}", err);
return PlayStateResult::Pop; return PlayStateResult::Pop;
} }
_ => {} _ => {}
@ -52,7 +51,7 @@ impl PlayState for StartSingleplayerState {
if !net_settings.servers.contains(&server_address) { if !net_settings.servers.contains(&server_address) {
net_settings.servers.push(server_address.clone()); net_settings.servers.push(server_address.clone());
} }
// TODO: Handle this result // TODO: Handle this result.
global_state.settings.save_to_file(); global_state.settings.save_to_file();
PlayStateResult::Push(Box::new(CharSelectionState::new( PlayStateResult::Push(Box::new(CharSelectionState::new(
@ -65,6 +64,6 @@ impl PlayState for StartSingleplayerState {
} }
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
"Starting Singleplayer" "Starting Single-Player"
} }
} }

View File

@ -37,7 +37,7 @@ widget_ids! {
singleplayer_text, singleplayer_text,
usrnm_bg, usrnm_bg,
srvr_bg, srvr_bg,
// Serverlist // Server list
servers_button, servers_button,
servers_frame, servers_frame,
servers_text, servers_text,
@ -237,7 +237,7 @@ impl MainMenuUi {
let netsettings = &global_state.settings.networking; let netsettings = &global_state.settings.networking;
// TODO: draw scroll bar or remove it // TODO: Draw scroll bar or remove it.
let (mut items, scrollbar) = List::flow_down(netsettings.servers.len()) let (mut items, scrollbar) = List::flow_down(netsettings.servers.len())
.top_left_with_margins_on(self.ids.servers_frame, 0.0, 5.0) .top_left_with_margins_on(self.ids.servers_frame, 0.0, 5.0)
.w_h(400.0, 300.0) .w_h(400.0, 300.0)

View File

@ -7,7 +7,7 @@ use crate::render::{
Pipeline, Pipeline,
}; };
/// Given a volume, a position and the cardinal directions, compute each vertex' AO value /// Given volume, position, and cardinal directions, compute each vertex's AO value.
/// `dirs` should be a slice of length 5 so that the sliding window of size 2 over the slice /// `dirs` should be a slice of length 5 so that the sliding window of size 2 over the slice
/// yields each vertex' adjacent positions. /// yields each vertex' adjacent positions.
fn get_ao_quad<V: ReadVol>(vol: &V, pos: Vec3<i32>, dirs: &[Vec3<i32>]) -> Vec4<f32> { fn get_ao_quad<V: ReadVol>(vol: &V, pos: Vec3<i32>, dirs: &[Vec3<i32>]) -> Vec4<f32> {
@ -29,7 +29,7 @@ fn get_ao_quad<V: ReadVol>(vol: &V, pos: Vec3<i32>, dirs: &[Vec3<i32>]) -> Vec4<
.get(pos + offs[0] + offs[1]) .get(pos + offs[0] + offs[1])
.map(|v| !v.is_empty()) .map(|v| !v.is_empty())
.unwrap_or(false); .unwrap_or(false);
// Map both 1 and 2 neighbors to 0.5 occlusion // Map both 1 and 2 neighbors to 0.5 occlusion.
if s1 || s2 || corner { if s1 || s2 || corner {
0.5 0.5
} else { } else {

View File

@ -12,7 +12,7 @@ pub struct Consts<T: Copy + gfx::traits::Pod> {
} }
impl<T: Copy + gfx::traits::Pod> Consts<T> { impl<T: Copy + gfx::traits::Pod> Consts<T> {
/// Create a new `Const<T>` /// Create a new `Const<T>`.
pub fn new(factory: &mut gfx_backend::Factory, len: usize) -> Self { pub fn new(factory: &mut gfx_backend::Factory, len: usize) -> Self {
Self { Self {
buf: factory.create_constant_buffer(len), buf: factory.create_constant_buffer(len),

View File

@ -8,12 +8,12 @@ pub struct Mesh<P: Pipeline> {
} }
impl<P: Pipeline> Mesh<P> { impl<P: Pipeline> Mesh<P> {
/// Create a new `Mesh` /// Create a new `Mesh`.
pub fn new() -> Self { pub fn new() -> Self {
Self { verts: vec![] } Self { verts: vec![] }
} }
/// Clear vertices, allows reusing allocated memory of the underlying Vec /// Clear vertices, allows reusing allocated memory of the underlying Vec.
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.verts.clear(); self.verts.clear();
} }
@ -50,12 +50,12 @@ impl<P: Pipeline> Mesh<P> {
self.verts.push(quad.a); self.verts.push(quad.a);
} }
/// Push the vertices of another mesh onto the end of this mesh /// Push the vertices of another mesh onto the end of this mesh.
pub fn push_mesh(&mut self, other: &Mesh<P>) { pub fn push_mesh(&mut self, other: &Mesh<P>) {
self.verts.extend_from_slice(other.vertices()); self.verts.extend_from_slice(other.vertices());
} }
/// Push the vertices of another mesh onto the end of this mesh /// Map and push the vertices of another mesh onto the end of this mesh.
pub fn push_mesh_map<F: FnMut(P::Vertex) -> P::Vertex>(&mut self, other: &Mesh<P>, mut f: F) { pub fn push_mesh_map<F: FnMut(P::Vertex) -> P::Vertex>(&mut self, other: &Mesh<P>, mut f: F) {
// Reserve enough space in our Vec. This isn't necessary, but it tends to reduce the number // Reserve enough space in our Vec. This isn't necessary, but it tends to reduce the number
// of required (re)allocations. // of required (re)allocations.

View File

@ -33,7 +33,7 @@ use gfx_device_gl as gfx_backend;
// Library // Library
use gfx; use gfx;
/// Used to represent one of many possible errors that may be omitted by the rendering subsystem /// Used to represent one of many possible errors that may be omitted by the rendering subsystem.
#[derive(Debug)] #[derive(Debug)]
pub enum RenderError { pub enum RenderError {
PipelineError(gfx::PipelineStateError<String>), PipelineError(gfx::PipelineStateError<String>),

View File

@ -28,7 +28,7 @@ impl<P: Pipeline> Model<P> {
} }
} }
/// Represents a mesh on the GPU which can be updated dynamically /// Represents a mesh on the GPU which can be updated dynamically.
pub struct DynamicModel<P: Pipeline> { pub struct DynamicModel<P: Pipeline> {
pub vbuf: gfx::handle::Buffer<gfx_backend::Resources, P::Vertex>, pub vbuf: gfx::handle::Buffer<gfx_backend::Resources, P::Vertex>,
} }
@ -42,7 +42,7 @@ impl<P: Pipeline> DynamicModel<P> {
}) })
} }
/// Create a model with a slice of a portion of this model to send to the renderer /// Create a model with a slice of a portion of this model to send to the renderer.
pub fn submodel(&self, range: Range<usize>) -> Model<P> { pub fn submodel(&self, range: Range<usize>) -> Model<P> {
Model { Model {
vbuf: self.vbuf.clone(), vbuf: self.vbuf.clone(),

View File

@ -23,9 +23,9 @@ gfx_defines! {
proj_mat: [[f32; 4]; 4] = "proj_mat", proj_mat: [[f32; 4]; 4] = "proj_mat",
cam_pos: [f32; 4] = "cam_pos", cam_pos: [f32; 4] = "cam_pos",
focus_pos: [f32; 4] = "focus_pos", focus_pos: [f32; 4] = "focus_pos",
// TODO: Fix whatever alignment issue requires these uniforms to be aligned // TODO: Fix whatever alignment issue requires these uniforms to be aligned.
view_distance: [f32; 4] = "view_distance", view_distance: [f32; 4] = "view_distance",
time_of_day: [f32; 4] = "time_of_day", // TODO: Make this f64 time_of_day: [f32; 4] = "time_of_day", // TODO: Make this f64.
tick: [f32; 4] = "tick", tick: [f32; 4] = "tick",
screen_res: [f32; 4] = "screen_res", screen_res: [f32; 4] = "screen_res",
} }

View File

@ -67,8 +67,7 @@ pub struct Renderer {
} }
impl Renderer { impl Renderer {
/// Create a new `Renderer` from a variety of backend-specific components and the window /// Create a new `Renderer` from a variety of backend-specific components and the window targets.
/// targets.
pub fn new( pub fn new(
device: gfx_backend::Device, device: gfx_backend::Device,
mut factory: gfx_backend::Factory, mut factory: gfx_backend::Factory,
@ -186,11 +185,11 @@ impl Renderer {
(&mut self.win_color_view, &mut self.win_depth_view) (&mut self.win_color_view, &mut self.win_depth_view)
} }
/// Resize internal render targets to match window render target dimensions /// Resize internal render targets to match window render target dimensions.
pub fn on_resize(&mut self) -> Result<(), RenderError> { pub fn on_resize(&mut self) -> Result<(), RenderError> {
let dims = self.win_color_view.get_dimensions(); let dims = self.win_color_view.get_dimensions();
// Panics when creating texture with w,h of 0,0 // Avoid panics when creating texture with w,h of 0,0.
if dims.0 != 0 && dims.1 != 0 { if dims.0 != 0 && dims.1 != 0 {
let (tgt_color_view, tgt_depth_view, tgt_color_res) = let (tgt_color_view, tgt_depth_view, tgt_color_res) =
Self::create_rt_views(&mut self.factory, (dims.0, dims.1))?; Self::create_rt_views(&mut self.factory, (dims.0, dims.1))?;
@ -224,7 +223,7 @@ impl Renderer {
} }
/// Queue the clearing of the color and depth targets ready for a new frame to be rendered. /// Queue the clearing of the color and depth targets ready for a new frame to be rendered.
/// TODO: Make a version of this that doesn't clear the colour target for speed /// TODO: Make a version of this that doesn't clear the colour target for speed.
pub fn clear(&mut self, col: Rgba<f32>) { pub fn clear(&mut self, col: Rgba<f32>) {
self.encoder.clear(&self.tgt_color_view, col.into_array()); self.encoder.clear(&self.tgt_color_view, col.into_array());
self.encoder.clear_depth(&self.tgt_depth_view, 1.0); self.encoder.clear_depth(&self.tgt_depth_view, 1.0);
@ -262,7 +261,7 @@ impl Renderer {
Ok(Model::new(&mut self.factory, mesh)) Ok(Model::new(&mut self.factory, mesh))
} }
/// Create a new dynamic model with the specified size /// Create a new dynamic model with the specified size.
pub fn create_dynamic_model<P: Pipeline>( pub fn create_dynamic_model<P: Pipeline>(
&mut self, &mut self,
size: usize, size: usize,
@ -270,7 +269,7 @@ impl Renderer {
DynamicModel::new(&mut self.factory, size) DynamicModel::new(&mut self.factory, size)
} }
/// Update a dynamic model with a mesh and a offset /// Update a dynamic model with a mesh and a offset.
pub fn update_model<P: Pipeline>( pub fn update_model<P: Pipeline>(
&mut self, &mut self,
model: &DynamicModel<P>, model: &DynamicModel<P>,
@ -288,7 +287,7 @@ impl Renderer {
Texture::new(&mut self.factory, image) Texture::new(&mut self.factory, image)
} }
/// Create a new dynamic texture (gfx::memory::Usage::Dynamic) with the specified dimensions /// Create a new dynamic texture (gfx::memory::Usage::Dynamic) with the specified dimensions.
pub fn create_dynamic_texture<P: Pipeline>( pub fn create_dynamic_texture<P: Pipeline>(
&mut self, &mut self,
dims: Vec2<u16>, dims: Vec2<u16>,
@ -296,7 +295,7 @@ impl Renderer {
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 /// Update a texture with the provided offset, size, and data.
pub fn update_texture<P: Pipeline>( pub fn update_texture<P: Pipeline>(
&mut self, &mut self,
texture: &Texture<P>, texture: &Texture<P>,
@ -449,7 +448,7 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>(
}, },
pipe, pipe,
) )
// Do some funky things to work around an oddity in gfx's error ownership rules // Do some funky things to work around an oddity in gfx's error ownership rules.
.map_err(|err| { .map_err(|err| {
RenderError::PipelineError(match err { RenderError::PipelineError(match err {
gfx::PipelineStateError::Program(err) => gfx::PipelineStateError::Program(err), gfx::PipelineStateError::Program(err) => gfx::PipelineStateError::Program(err),

View File

@ -89,7 +89,7 @@ impl<P: Pipeline> Texture<P> {
}) })
} }
// Updates a texture with the given data (used for updating the glyph cache texture) /// Update a texture with the given data (used for updating the glyph cache texture).
pub fn update( pub fn update(
&self, &self,
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>, encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
@ -113,7 +113,7 @@ impl<P: Pipeline> Texture<P> {
) )
.map_err(|err| RenderError::TexUpdateError(err)) .map_err(|err| RenderError::TexUpdateError(err))
} }
/// Get dimensions of the represented image /// Get dimensions of the represented image.
pub fn get_dimensions(&self) -> Vec2<u16> { pub fn get_dimensions(&self) -> Vec2<u16> {
let (w, h, ..) = self.tex.get_info().kind.get_dimensions(); let (w, h, ..) = self.tex.get_info().kind.get_dimensions();
Vec2::new(w, h) Vec2::new(w, h)

View File

@ -1,4 +1,4 @@
// TODO: Get rid of this ugliness // TODO: Get rid of this ugliness.
#[rustfmt::skip] #[rustfmt::skip]
pub fn arr_to_mat(arr: [f32; 16]) -> [[f32; 4]; 4] { pub fn arr_to_mat(arr: [f32; 16]) -> [[f32; 4]; 4] {
[ [

View File

@ -79,7 +79,7 @@ impl Camera {
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 // TODO: Make this more efficient.
let cam_pos = Vec3::from(view_mat.inverted() * Vec4::unit_w()); let cam_pos = Vec3::from(view_mat.inverted() * Vec4::unit_w());
(view_mat, proj_mat, cam_pos) (view_mat, proj_mat, cam_pos)
@ -95,7 +95,7 @@ impl Camera {
self.ori.z = (self.ori.z + delta.z) % (2.0 * PI); self.ori.z = (self.ori.z + delta.z) % (2.0 * PI);
} }
/// Set the orientation of the camera about its focus /// Set the orientation of the camera about its focus.
pub fn set_orientation(&mut self, orientation: Vec3<f32>) { pub fn set_orientation(&mut self, orientation: Vec3<f32>) {
// Wrap camera yaw // Wrap camera yaw
self.ori.x = orientation.x % (2.0 * PI); self.ori.x = orientation.x % (2.0 * PI);
@ -111,7 +111,7 @@ impl Camera {
self.tgt_dist = (self.tgt_dist + delta).max(0.0); self.tgt_dist = (self.tgt_dist + delta).max(0.0);
} }
/// Set the distance of the camera from the target (i.e: zoom) /// Set the distance of the camera from the target (i.e., zoom).
pub fn set_distance(&mut self, dist: f32) { pub fn set_distance(&mut self, dist: f32) {
self.tgt_dist = dist; self.tgt_dist = dist;
} }
@ -146,7 +146,7 @@ impl Camera {
self.aspect = if aspect.is_normal() { aspect } else { 1.0 }; self.aspect = if aspect.is_normal() { aspect } else { 1.0 };
} }
/// Get the orientation of the camera /// Get the orientation of the camera.
pub fn get_orientation(&self) -> Vec3<f32> { pub fn get_orientation(&self) -> Vec3<f32> {
self.ori self.ori
} }

View File

@ -16,7 +16,7 @@ use common::{
comp::{ comp::{
self, self,
actor::{ actor::{
Belt, Chest, Draw, Foot, Hand, Head, Pants, Pigchest, Pighead, Pigleg_l, Pigleg_r, Belt, Chest, Draw, Foot, Hand, Head, Pants, PigChest, PigHead, PigLegL, PigLegR,
Shoulder, Weapon, Shoulder, Weapon,
}, },
Body, HumanoidBody, QuadrupedBody, Body, HumanoidBody, QuadrupedBody,
@ -75,12 +75,12 @@ impl FigureModelCache {
None, None,
], ],
Body::Quadruped(body) => [ Body::Quadruped(body) => [
Some(Self::load_pighead(body.pighead)), Some(Self::load_pig_head(body.pig_head)),
Some(Self::load_pigchest(body.pigchest)), Some(Self::load_pig_chest(body.pig_chest)),
Some(Self::load_piglf_leg(body.pigleg_l)), Some(Self::load_pig_leg_lf(body.pig_leg_l)),
Some(Self::load_pigrf_leg(body.pigleg_r)), Some(Self::load_pig_leg_rf(body.pig_leg_r)),
Some(Self::load_piglb_leg(body.pigleg_l)), Some(Self::load_pig_leg_lb(body.pig_leg_l)),
Some(Self::load_pigrb_leg(body.pigleg_r)), Some(Self::load_pig_leg_rb(body.pig_leg_r)),
None, None,
None, None,
None, None,
@ -117,15 +117,15 @@ impl FigureModelCache {
} }
pub fn clean(&mut self, tick: u64) { pub fn clean(&mut self, tick: u64) {
// TODO: Don't hard-code this // TODO: Don't hard-code this.
self.models self.models
.retain(|_, (_, last_used)| *last_used + 60 > tick); .retain(|_, (_, last_used)| *last_used + 60 > tick);
} }
// TODO: Don't make this public // TODO: Don't make this public.
pub fn load_mesh(filename: &str, position: Vec3<f32>) -> Mesh<FigurePipeline> { pub fn load_mesh(filename: &str, position: Vec3<f32>) -> Mesh<FigurePipeline> {
let fullpath: String = ["/voxygen/voxel/", filename].concat(); let full_path: String = ["/voxygen/voxel/", filename].concat();
Segment::from(assets::load_expect::<DotVoxData>(fullpath.as_str()).as_ref()) Segment::from(assets::load_expect::<DotVoxData>(full_path.as_str()).as_ref())
.generate_mesh(position) .generate_mesh(position)
} }
@ -205,7 +205,7 @@ impl FigureModelCache {
Self::load_mesh( Self::load_mesh(
match weapon { match weapon {
Weapon::Sword => "sword.vox", Weapon::Sword => "sword.vox",
// TODO actually match against other weapons and set the right model // TODO actually match against other weapons and set the right model.
_ => "sword.vox", _ => "sword.vox",
}, },
Vec3::new(0.0, 0.0, -4.0), Vec3::new(0.0, 0.0, -4.0),
@ -238,55 +238,55 @@ impl FigureModelCache {
) )
} }
fn load_pighead(pighead: Pighead) -> Mesh<FigurePipeline> { fn load_pig_head(pig_head: PigHead) -> Mesh<FigurePipeline> {
Self::load_mesh( Self::load_mesh(
match pighead { match pig_head {
Pighead::Default => "pighead.vox", PigHead::Default => "pighead.vox",
}, },
Vec3::new(-6.0, 4.5, 3.0), Vec3::new(-6.0, 4.5, 3.0),
) )
} }
fn load_pigchest(pigchest: Pigchest) -> Mesh<FigurePipeline> { fn load_pig_chest(pig_chest: PigChest) -> Mesh<FigurePipeline> {
Self::load_mesh( Self::load_mesh(
match pigchest { match pig_chest {
Pigchest::Default => "pigchest.vox", PigChest::Default => "pigchest.vox",
}, },
Vec3::new(-5.0, 4.5, 0.0), Vec3::new(-5.0, 4.5, 0.0),
) )
} }
fn load_piglf_leg(pigleg_l: Pigleg_l) -> Mesh<FigurePipeline> { fn load_pig_leg_lf(pig_leg_l: PigLegL) -> Mesh<FigurePipeline> {
Self::load_mesh(
match pig_leg_l {
PigLegL::Default => "pigleg_l.vox",
},
Vec3::new(0.0, -1.0, -1.5),
)
}
fn load_pig_leg_rf(pig_leg_r: PigLegR) -> Mesh<FigurePipeline> {
Self::load_mesh(
match pig_leg_r {
PigLegR::Default => "pigleg_r.vox",
},
Vec3::new(0.0, -1.0, -1.5),
)
}
fn load_pig_leg_lb(pigleg_l: PigLegL) -> Mesh<FigurePipeline> {
Self::load_mesh( Self::load_mesh(
match pigleg_l { match pigleg_l {
Pigleg_l::Default => "pigleg_l.vox", PigLegL::Default => "pigleg_l.vox",
}, },
Vec3::new(0.0, -1.0, -1.5), Vec3::new(0.0, -1.0, -1.5),
) )
} }
fn load_pigrf_leg(pigleg_r: Pigleg_r) -> Mesh<FigurePipeline> { fn load_pig_leg_rb(pig_leg_r: PigLegR) -> Mesh<FigurePipeline> {
Self::load_mesh( Self::load_mesh(
match pigleg_r { match pig_leg_r {
Pigleg_r::Default => "pigleg_r.vox", PigLegR::Default => "pigleg_r.vox",
},
Vec3::new(0.0, -1.0, -1.5),
)
}
fn load_piglb_leg(pigleg_l: Pigleg_l) -> Mesh<FigurePipeline> {
Self::load_mesh(
match pigleg_l {
Pigleg_l::Default => "pigleg_l.vox",
},
Vec3::new(0.0, -1.0, -1.5),
)
}
fn load_pigrb_leg(pigleg_r: Pigleg_r) -> Mesh<FigurePipeline> {
Self::load_mesh(
match pigleg_r {
Pigleg_r::Default => "pigleg_r.vox",
}, },
Vec3::new(0.0, -1.0, -1.5), Vec3::new(0.0, -1.0, -1.5),
) )
@ -411,7 +411,7 @@ impl FigureMgr {
} }
} }
// Clear states that have dead entities // Clear states that have dead entities.
self.character_states self.character_states
.retain(|entity, _| ecs.entities().is_alive(*entity)); .retain(|entity, _| ecs.entities().is_alive(*entity));
self.quadruped_states self.quadruped_states

View File

@ -93,15 +93,15 @@ impl FigureModelCache {
} }
pub fn clean(&mut self, tick: u64) { pub fn clean(&mut self, tick: u64) {
// TODO: Don't hard-code this // TODO: Don't hard-code this.
self.models self.models
.retain(|_, (_, last_used)| *last_used + 60 > tick); .retain(|_, (_, last_used)| *last_used + 60 > tick);
} }
// TODO: Don't make this public // TODO: Don't make this public.
pub fn load_mesh(filename: &str, position: Vec3<f32>) -> Mesh<FigurePipeline> { pub fn load_mesh(filename: &str, position: Vec3<f32>) -> Mesh<FigurePipeline> {
let fullpath: String = ["/voxygen/voxel/", filename].concat(); let full_path: String = ["/voxygen/voxel/", filename].concat();
Segment::from(assets::load_expect::<DotVoxData>(fullpath.as_str()).as_ref()) Segment::from(assets::load_expect::<DotVoxData>(full_path.as_str()).as_ref())
.generate_mesh(position) .generate_mesh(position)
} }
@ -181,7 +181,7 @@ impl FigureModelCache {
Self::load_mesh( Self::load_mesh(
match weapon { match weapon {
Weapon::Sword => "sword.vox", Weapon::Sword => "sword.vox",
// TODO actually match against other weapons and set the right model // TODO actually match against other weapons and set the right model.
_ => "sword.vox", _ => "sword.vox",
}, },
Vec3::new(0.0, 0.0, -4.0), Vec3::new(0.0, 0.0, -4.0),
@ -276,9 +276,9 @@ impl FigureMgr {
state.skeleton.interpolate(&target_skeleton); state.skeleton.interpolate(&target_skeleton);
state.update(renderer, pos.0, dir.0); state.update(renderer, pos.0, dir.0);
} // TODO: Non-humanoid bodies } // TODO: Non-humanoid bodies.
}, },
// TODO: Non-character actors // TODO: Non-character actors.
} }
} }
@ -308,9 +308,9 @@ impl FigureMgr {
state.bone_consts(), state.bone_consts(),
); );
} }
} // TODO: Non-humanoid bodies } // TODO: Non-humanoid bodies.
}, },
// TODO: Non-character actors // TODO: Non-character actors.
} }
} }
} }

View File

@ -93,15 +93,15 @@ impl FigureModelCache {
} }
pub fn clean(&mut self, tick: u64) { pub fn clean(&mut self, tick: u64) {
// TODO: Don't hard-code this // TODO: Don't hard-code this.
self.models self.models
.retain(|_, (_, last_used)| *last_used + 60 > tick); .retain(|_, (_, last_used)| *last_used + 60 > tick);
} }
// TODO: Don't make this public // TODO: Don't make this public.
pub fn load_mesh(filename: &str, position: Vec3<f32>) -> Mesh<FigurePipeline> { pub fn load_mesh(filename: &str, position: Vec3<f32>) -> Mesh<FigurePipeline> {
let fullpath: String = ["/voxygen/voxel/", filename].concat(); let full_path: String = ["/voxygen/voxel/", filename].concat();
Segment::from(assets::load_expect::<DotVoxData>(fullpath.as_str()).as_ref()) Segment::from(assets::load_expect::<DotVoxData>(full_path.as_str()).as_ref())
.generate_mesh(position) .generate_mesh(position)
} }
@ -123,7 +123,7 @@ impl FigureModelCache {
) )
} }
fn load_lf_leg(leg_l: Leg_l) -> Mesh<FigurePipeline> { fn load_leg_lf(leg_l: Leg_l) -> Mesh<FigurePipeline> {
Self::load_mesh( Self::load_mesh(
match belt { match belt {
Belt::Default => "pigleg_l.vox", Belt::Default => "pigleg_l.vox",
@ -132,7 +132,7 @@ impl FigureModelCache {
) )
} }
fn load_rf_leg(leg_R: Leg_r) -> Mesh<FigurePipeline> { fn load_leg_rf(leg_r: Leg_r) -> Mesh<FigurePipeline> {
Self::load_mesh( Self::load_mesh(
match pants { match pants {
Pants::Default => "pigleg_r.vox", Pants::Default => "pigleg_r.vox",
@ -141,7 +141,7 @@ impl FigureModelCache {
) )
} }
fn load_lb_leg(leg_l: Leg_l) -> Mesh<FigurePipeline> { fn load_leg_lb(leg_l: Leg_l) -> Mesh<FigurePipeline> {
Self::load_mesh( Self::load_mesh(
match hand { match hand {
Hand::Default => "pigleg_l.vox", Hand::Default => "pigleg_l.vox",
@ -150,7 +150,7 @@ impl FigureModelCache {
) )
} }
fn load_rb_leg(leg_R: Leg_r) -> Mesh<FigurePipeline> { fn load_leg_rb(leg_r: Leg_r) -> Mesh<FigurePipeline> {
Self::load_mesh( Self::load_mesh(
match hand { match hand {
Hand::Default => "pigleg_r.vox", Hand::Default => "pigleg_r.vox",
@ -214,7 +214,7 @@ impl FigureMgr {
self.states self.states
.retain(|entity, _| ecs.entities().is_alive(*entity)); .retain(|entity, _| ecs.entities().is_alive(*entity));
} } // TODO: Place `render` into above impl and fix `maintain`.
pub fn render( pub fn render(
&mut self, &mut self,

View File

@ -20,7 +20,7 @@ use common::{comp, figure::Segment};
use dot_vox; use dot_vox;
use vek::*; use vek::*;
// TODO: Don't hard-code this // TODO: Don't hard-code this.
const CURSOR_PAN_SCALE: f32 = 0.005; const CURSOR_PAN_SCALE: f32 = 0.005;
struct Skybox { struct Skybox {
@ -78,9 +78,9 @@ impl Scene {
&mut self.camera &mut self.camera
} }
/// Handle an incoming user input event (i.e: cursor moved, key pressed, window closed, etc.). /// Handle an incoming user input event (e.g.: cursor moved, key pressed, window closed).
/// ///
/// If the event is handled, return true /// If the event is handled, return true.
pub fn handle_input_event(&mut self, event: Event) -> bool { pub fn handle_input_event(&mut self, event: Event) -> bool {
match event { match event {
// When the window is resized, change the camera's aspect ratio // When the window is resized, change the camera's aspect ratio
@ -105,7 +105,7 @@ impl Scene {
/// Maintain data such as GPU constant buffers, models, etc. To be called once per tick. /// Maintain data such as GPU constant buffers, models, etc. To be called once per tick.
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) { pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
// Get player position // Get player position.
let player_pos = client let player_pos = client
.state() .state()
.ecs() .ecs()
@ -114,16 +114,16 @@ impl Scene {
.map(|pos| pos.0) .map(|pos| pos.0)
.unwrap_or(Vec3::zero()); .unwrap_or(Vec3::zero());
// Alter camera position to match player // Alter camera position to match player.
self.camera.set_focus_pos(player_pos + Vec3::unit_z() * 2.1); self.camera.set_focus_pos(player_pos + Vec3::unit_z() * 2.1);
// Tick camera for interpolation // Tick camera for interpolation.
self.camera.update(client.state().get_time()); self.camera.update(client.state().get_time());
// Compute camera matrices // Compute camera matrices.
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents(client); let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents(client);
// Update global constants // Update global constants.
renderer renderer
.update_consts( .update_consts(
&mut self.globals, &mut self.globals,
@ -140,22 +140,22 @@ impl Scene {
) )
.expect("Failed to update global constants"); .expect("Failed to update global constants");
// Maintain the terrain // Maintain the terrain.
self.terrain.maintain(renderer, client); self.terrain.maintain(renderer, client);
// Maintain the figures // Maintain the figures.
self.figure_mgr.maintain(renderer, client); self.figure_mgr.maintain(renderer, client);
// Remove unused figures // Remove unused figures.
self.figure_mgr.clean(client.get_tick()); self.figure_mgr.clean(client.get_tick());
} }
/// Render the scene using the provided `Renderer` /// Render the scene using the provided `Renderer`.
pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client) { pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client) {
// Render the skybox first (it appears over everything else so must be rendered first) // Render the skybox first (it appears over everything else so must be rendered first).
renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals); renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
// Render terrain and figures // Render terrain and figures.
self.terrain.render(renderer, &self.globals); self.terrain.render(renderer, &self.globals);
self.figure_mgr.render(renderer, client, &self.globals); self.figure_mgr.render(renderer, client, &self.globals);

View File

@ -19,14 +19,14 @@ struct ChunkMeshState {
active_worker: bool, active_worker: bool,
} }
/// A type produced by mesh worker threads corresponding to the position and mesh of a chunk /// A type produced by mesh worker threads corresponding to the position and mesh of a chunk.
struct MeshWorkerResponse { struct MeshWorkerResponse {
pos: Vec2<i32>, pos: Vec2<i32>,
mesh: Mesh<TerrainPipeline>, mesh: Mesh<TerrainPipeline>,
started_tick: u64, started_tick: u64,
} }
/// Function executed by worker threads dedicated to chunk meshing /// Function executed by worker threads dedicated to chunk meshing.
fn mesh_worker( fn mesh_worker(
pos: Vec2<i32>, pos: Vec2<i32>,
started_tick: u64, started_tick: u64,
@ -44,7 +44,7 @@ pub struct Terrain {
chunks: HashMap<Vec2<i32>, TerrainChunk>, chunks: HashMap<Vec2<i32>, TerrainChunk>,
// The mpsc sender and receiver used for talking to meshing worker threads. // The mpsc sender and receiver used for talking to meshing worker threads.
// We keep the sender component for no reason othe than to clone it and send it to new workers. // We keep the sender component for no reason other than to clone it and send it to new workers.
mesh_send_tmp: mpsc::Sender<MeshWorkerResponse>, mesh_send_tmp: mpsc::Sender<MeshWorkerResponse>,
mesh_recv: mpsc::Receiver<MeshWorkerResponse>, mesh_recv: mpsc::Receiver<MeshWorkerResponse>,
mesh_todo: HashMap<Vec2<i32>, ChunkMeshState>, mesh_todo: HashMap<Vec2<i32>, ChunkMeshState>,
@ -69,7 +69,7 @@ impl Terrain {
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) { pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
let current_tick = client.get_tick(); let current_tick = client.get_tick();
// Add any recently created or changed chunks to the list of chunks to be meshed // Add any recently created or changed chunks to the list of chunks to be meshed.
for pos in client for pos in client
.state() .state()
.changes() .changes()
@ -108,7 +108,7 @@ impl Terrain {
} }
} }
} }
// Remove any models for chunks that have been recently removed // Remove any models for chunks that have been recently removed.
for pos in &client.state().changes().removed_chunks { for pos in &client.state().changes().removed_chunks {
self.chunks.remove(pos); self.chunks.remove(pos);
self.mesh_todo.remove(pos); self.mesh_todo.remove(pos);
@ -117,11 +117,11 @@ impl Terrain {
for todo in self for todo in self
.mesh_todo .mesh_todo
.values_mut() .values_mut()
// Only spawn workers for meshing jobs without an active worker already // Only spawn workers for meshing jobs without an active worker already.
.filter(|todo| !todo.active_worker) .filter(|todo| !todo.active_worker)
{ {
// Find the area of the terrain we want. Because meshing needs to compute things like // Find the area of the terrain we want. Because meshing needs to compute things like
// ambient occlusion and edge elision, we also need to borders of the chunk's // ambient occlusion and edge elision, we also need the borders of the chunk's
// neighbours too (hence the `- 1` and `+ 1`). // neighbours too (hence the `- 1` and `+ 1`).
let aabr = Aabr { let aabr = Aabr {
min: todo min: todo
@ -138,40 +138,40 @@ impl Terrain {
}; };
// Copy out the chunk data we need to perform the meshing. We do this by taking a // Copy out the chunk data we need to perform the meshing. We do this by taking a
// sample of the terrain that includes both the chunk we want and // sample of the terrain that includes both the chunk we want and its neighbours.
let volume = match client.state().terrain().sample(aabr) { let volume = match client.state().terrain().sample(aabr) {
Ok(sample) => sample, Ok(sample) => sample,
// If either this chunk or its neighbours doesn't yet exist, so we keep it in the // Either this chunk or its neighbours doesn't yet exist, so we keep it in the
// todo queue to be processed at a later date when we have its neighbours. // queue to be processed at a later date when we have its neighbours.
Err(VolMap2dErr::NoSuchChunk) => return, Err(VolMap2dErr::NoSuchChunk) => return,
_ => panic!("Unhandled edge case"), _ => panic!("Unhandled edge case"),
}; };
// Clone various things to that they can be moved into the thread // Clone various things so that they can be moved into the thread.
let send = self.mesh_send_tmp.clone(); let send = self.mesh_send_tmp.clone();
let pos = todo.pos; let pos = todo.pos;
// Queue the worker thread // Queue the worker thread.
client.thread_pool().execute(move || { client.thread_pool().execute(move || {
let _ = send.send(mesh_worker(pos, current_tick, volume, aabb)); let _ = send.send(mesh_worker(pos, current_tick, volume, aabb));
}); });
todo.active_worker = true; todo.active_worker = true;
} }
// Receive a chunk mesh from a worker thread, upload it to the GPU and then store it // Receive a chunk mesh from a worker thread and upload it to the GPU, then store it.
// Only pull out one chunk per frame to avoid an unacceptable amount of blocking lag due // Only pull out one chunk per frame to avoid an unacceptable amount of blocking lag due
// to the GPU upload. That still gives us a 60 chunks / second budget to play with. // to the GPU upload. That still gives us a 60 chunks / second budget to play with.
if let Ok(response) = self.mesh_recv.recv_timeout(Duration::new(0, 0)) { if let Ok(response) = self.mesh_recv.recv_timeout(Duration::new(0, 0)) {
match self.mesh_todo.get(&response.pos) { match self.mesh_todo.get(&response.pos) {
// It's the mesh we want, insert the newly finished model into the terrain model // It's the mesh we want, insert the newly finished model into the terrain model
// data structure (convert the mesh to a model first of course) // data structure (convert the mesh to a model first of course).
Some(todo) if response.started_tick == todo.started_tick => { Some(todo) if response.started_tick == todo.started_tick => {
self.chunks.insert( self.chunks.insert(
response.pos, response.pos,
TerrainChunk { TerrainChunk {
model: renderer model: renderer
.create_model(&response.mesh) .create_model(&response.mesh)
.expect("Failed to upload chunk mesh to the GPU"), .expect("Failed to upload chunk mesh to the GPU!"),
locals: renderer locals: renderer
.create_consts(&[TerrainLocals { .create_consts(&[TerrainLocals {
model_offs: Vec3::from( model_offs: Vec3::from(
@ -181,12 +181,12 @@ impl Terrain {
) )
.into_array(), .into_array(),
}]) }])
.expect("Failed to upload chunk locals to the GPU"), .expect("Failed to upload chunk locals to the GPU!"),
}, },
); );
} }
// Chunk must have been removed, or it was spawned on an old tick. Drop the mesh // Chunk must have been removed, or it was spawned on an old tick. Drop the mesh
// since it's either out of date or no longer needed // since it's either out of date or no longer needed.
_ => {} _ => {}
} }
} }

View File

@ -22,11 +22,11 @@ pub struct SessionState {
hud: Hud, hud: Hud,
} }
/// Represents an active game session (i.e: one that is being played) /// Represents an active game session (i.e., the one being played).
impl SessionState { impl SessionState {
/// Create a new `SessionState` /// Create a new `SessionState`.
pub fn new(window: &mut Window, client: Rc<RefCell<Client>>, settings: Settings) -> Self { pub fn new(window: &mut Window, client: Rc<RefCell<Client>>, settings: Settings) -> Self {
// Create a scene for this session. The scene handles visible elements of the game world // Create a scene for this session. The scene handles visible elements of the game world.
let scene = Scene::new(window.renderer_mut(), &client.borrow()); let scene = Scene::new(window.renderer_mut(), &client.borrow());
Self { Self {
scene, scene,
@ -38,7 +38,7 @@ impl SessionState {
} }
} }
// The background colour // Background colour
const BG_COLOR: Rgba<f32> = Rgba { const BG_COLOR: Rgba<f32> = Rgba {
r: 0.0, r: 0.0,
g: 0.3, g: 0.3,
@ -47,9 +47,10 @@ const BG_COLOR: Rgba<f32> = Rgba {
}; };
impl SessionState { impl SessionState {
/// Tick the session (and the client attached to it) /// Tick the session (and the client attached to it).
pub fn tick(&mut self, dt: Duration) -> Result<(), Error> { pub fn tick(&mut self, dt: Duration) -> Result<(), Error> {
// Calculate the movement input vector of the player from the current key presses and the camera direction // Calculate the movement input vector of the player from the current key presses
// and the camera direction.
let ori = self.scene.camera().get_orientation(); let ori = self.scene.camera().get_orientation();
let unit_vecs = ( let unit_vecs = (
Vec2::new(ori[0].cos(), -ori[0].sin()), Vec2::new(ori[0].cos(), -ori[0].sin()),
@ -58,7 +59,7 @@ impl SessionState {
let dir_vec = self.key_state.dir_vec(); let dir_vec = self.key_state.dir_vec();
let move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1]; let move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1];
// Take the input events // Take the input events.
let mut input_events = Vec::new(); let mut input_events = Vec::new();
mem::swap(&mut self.input_events, &mut input_events); mem::swap(&mut self.input_events, &mut input_events);
@ -84,7 +85,7 @@ impl SessionState {
Ok(()) Ok(())
} }
/// Clean up the session (and the client attached to it) after a tick /// Clean up the session (and the client attached to it) after a tick.
pub fn cleanup(&mut self) { pub fn cleanup(&mut self) {
self.client.borrow_mut().cleanup(); self.client.borrow_mut().cleanup();
} }
@ -108,13 +109,13 @@ impl SessionState {
impl PlayState for SessionState { impl PlayState for SessionState {
fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult { fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult {
// Trap the cursor // Trap the cursor.
global_state.window.grab_cursor(true); global_state.window.grab_cursor(true);
// Set up an fps clock // Set up an fps clock.
let mut clock = Clock::new(); let mut clock = Clock::new();
// Load a few chunks TODO: Remove this // Load a few chunks. TODO: Remove this.
/* /*
for x in -6..7 { for x in -6..7 {
for y in -6..7 { for y in -6..7 {
@ -127,9 +128,9 @@ impl PlayState for SessionState {
// Game loop // Game loop
loop { loop {
// Handle window events // Handle window events.
for event in global_state.window.fetch_events() { for event in global_state.window.fetch_events() {
// Pass all events to the ui first // Pass all events to the ui first.
if self.hud.handle_event(event.clone(), global_state) { if self.hud.handle_event(event.clone(), global_state) {
continue; continue;
} }
@ -162,16 +163,16 @@ impl PlayState for SessionState {
// TODO: Do something if the event wasn't handled? // TODO: Do something if the event wasn't handled?
} }
// Perform an in-game tick // Perform an in-game tick.
self.tick(clock.get_last_delta()) self.tick(clock.get_last_delta())
.expect("Failed to tick the scene"); .expect("Failed to tick the scene!");
// Maintain the scene // Maintain the scene.
self.scene.maintain( self.scene.maintain(
global_state.window.renderer_mut(), global_state.window.renderer_mut(),
&mut self.client.borrow_mut(), &mut self.client.borrow_mut(),
); );
// Maintain the UI // Maintain the UI.
for event in self for event in self
.hud .hud
.maintain(global_state.window.renderer_mut(), clock.get_tps()) .maintain(global_state.window.renderer_mut(), clock.get_tps())
@ -188,19 +189,19 @@ impl PlayState for SessionState {
} }
} }
// Render the session // Render the session.
self.render(global_state.window.renderer_mut()); self.render(global_state.window.renderer_mut());
// Display the frame on the window // Display the frame on the window.
global_state global_state
.window .window
.swap_buffers() .swap_buffers()
.expect("Failed to swap window buffers"); .expect("Failed to swap window buffers!");
// Wait for the next tick // Wait for the next tick.
clock.tick(Duration::from_millis(1000 / FPS)); clock.tick(Duration::from_millis(1000 / FPS));
// Clean things up after the tick // Clean things up after the tick.
self.cleanup(); self.cleanup();
} }
} }

View File

@ -5,7 +5,7 @@ use serde_derive::{Deserialize, Serialize};
use std::{fs::File, io::prelude::*, path::PathBuf}; use std::{fs::File, io::prelude::*, path::PathBuf};
use toml; use toml;
/// Settings contains everything that can be configured in the Settings.toml file /// `Settings` contains everything that can be configured in the Settings.toml file.
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)] #[serde(default)]
pub struct Settings { pub struct Settings {
@ -14,7 +14,7 @@ pub struct Settings {
pub log: Log, pub log: Log,
} }
/// ControlSettings contains keybindings /// `ControlSettings` contains keybindings.
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ControlSettings { pub struct ControlSettings {
pub toggle_cursor: VirtualKeyCode, pub toggle_cursor: VirtualKeyCode,
@ -95,20 +95,20 @@ impl Settings {
config config
.merge( .merge(
Config::try_from(&default_settings) Config::try_from(&default_settings)
.expect("Default settings struct could not be converted to Config"), .expect("Default settings struct could not be converted to Config!"),
) )
.unwrap(); .unwrap();
// TODO: log errors here // TODO: Log errors here.
// If merge or try_into fail use the default settings // If merge or try_into fail, use the default settings.
match config.merge::<config::File<_>>(path.into()) { match config.merge::<config::File<_>>(path.into()) {
Ok(_) => match config.try_into() { Ok(_) => match config.try_into() {
Ok(settings) => settings, Ok(settings) => settings,
Err(_) => default_settings, Err(_) => default_settings,
}, },
Err(_) => { Err(_) => {
// Maybe the file didn't exist // Maybe the file didn't exist.
// TODO: Handle this result // TODO: Handle this result.
default_settings.save_to_file(); default_settings.save_to_file();
default_settings default_settings
} }
@ -126,7 +126,7 @@ impl Settings {
fn get_settings_path() -> PathBuf { fn get_settings_path() -> PathBuf {
let proj_dirs = let proj_dirs =
ProjectDirs::from("net", "veloren", "voxygen").expect("No home directory defined."); ProjectDirs::from("net", "veloren", "voxygen").expect("No home directory defined!");
let path = proj_dirs.config_dir(); let path = proj_dirs.config_dir();
path.join("settings"); path.join("settings");
let path = path.with_extension("toml"); let path = path.with_extension("toml");

View File

@ -28,7 +28,7 @@ impl Singleplayer {
let sock = SocketAddr::from(( let sock = SocketAddr::from((
[127, 0, 0, 1], [127, 0, 0, 1],
pick_unused_port().expect("Failed to find unused port"), pick_unused_port().expect("Failed to find unused port!"),
)); ));
let sock2 = sock.clone(); let sock2 = sock.clone();
@ -60,12 +60,12 @@ fn run_server(sock: SocketAddr, rec: Receiver<Msg>) {
let mut clock = Clock::new(); let mut clock = Clock::new();
// Create server // Create server
let mut server = Server::bind(sock).expect("Failed to create server instance"); let mut server = Server::bind(sock).expect("Failed to create server instance!");
loop { loop {
let events = server let events = server
.tick(Input::default(), clock.get_last_delta()) .tick(Input::default(), clock.get_last_delta())
.expect("Failed to tick server"); .expect("Failed to tick server!");
for event in events { for event in events {
match event { match event {
@ -75,7 +75,7 @@ fn run_server(sock: SocketAddr, rec: Receiver<Msg>) {
} }
} }
// Clean up the server after a tick // Clean up the server after a tick.
server.cleanup(); server.cleanup();
match rec.try_recv() { match rec.try_recv() {
@ -86,7 +86,7 @@ fn run_server(sock: SocketAddr, rec: Receiver<Msg>) {
}, },
} }
// Wait for the next tick // Wait for the next tick.
clock.tick(Duration::from_millis(1000 / TPS)); clock.tick(Duration::from_millis(1000 / TPS));
} }
} }

View File

@ -7,12 +7,12 @@ impl Event {
pub fn try_from(event: glutin::Event, window: &glutin::GlWindow) -> Option<Self> { pub fn try_from(event: glutin::Event, window: &glutin::GlWindow) -> Option<Self> {
use conrod_winit::*; use conrod_winit::*;
use winit; use winit;
// A wrapper around the winit window that allows us to implement the trait necessary for enabling // A wrapper around the winit window that allows us to implement the trait necessary for
// the winit <-> conrod conversion functions. // enabling the winit <-> conrod conversion functions.
struct WindowRef<'a>(&'a winit::Window); struct WindowRef<'a>(&'a winit::Window);
// Implement the `WinitWindow` trait for `WindowRef` to allow for generating compatible conversion // Implement the `WinitWindow` trait for `WindowRef` to allow for generating compatible
// functions. // conversion functions.
impl<'a> conrod_winit::WinitWindow for WindowRef<'a> { impl<'a> conrod_winit::WinitWindow for WindowRef<'a> {
fn get_inner_size(&self) -> Option<(u32, u32)> { fn get_inner_size(&self) -> Option<(u32, u32)> {
winit::Window::get_inner_size(&self.0).map(Into::into) winit::Window::get_inner_size(&self.0).map(Into::into)

View File

@ -1,5 +1,5 @@
/// This macro will automatically load all specified assets, get the corresponding FontIds and /// This macro will automatically load all specified assets, get the corresponding FontIds and
/// create a struct with all of them /// create a struct with all of them.
/// ///
/// Example usage: /// Example usage:
/// ``` /// ```

View File

@ -59,12 +59,12 @@ impl GraphicCache {
{ {
match self match self
.rect_map .rect_map
.get(&(graphic_id, dims, source.map(|e| e.to_bits()))) //<-------- TODO: Replace this with rounded representation of source .get(&(graphic_id, dims, source.map(|e| e.to_bits()))) // TODO: Replace this with rounded representation of source
{ {
Some(aabr) => Some(*aabr), Some(aabr) => Some(*aabr),
None => match self.graphic_map.get(&graphic_id) { None => match self.graphic_map.get(&graphic_id) {
Some(graphic) => { Some(graphic) => {
// Allocate rectangle // Allocate rectangle.
let aabr = match self let aabr = match self
.atlas .atlas
.allocate(size2(i32::from(dims.x), i32::from(dims.y))) .allocate(size2(i32::from(dims.x), i32::from(dims.y)))
@ -76,13 +76,16 @@ impl GraphicCache {
max: Vec2::new(max.x as u16, max.y as u16), max: Vec2::new(max.x as u16, max.y as u16),
} }
} }
// Out of room // Out of room.
// TODO: make more room by 1. expanding cache size, 2. removing unused allocations, 3. rearranging rectangles // TODO: Make more room.
// 1) Expand cache size
// 2) Remove unused allocations
// 3) Rearrange rectangles
None => return None, None => return None,
}; };
// Render image // Render image.
// TODO: use source // TODO: Use source.
let data = match graphic { let data = match graphic {
Graphic::Image(ref image) => image Graphic::Image(ref image) => image
.resize_exact( .resize_exact(
@ -99,14 +102,14 @@ impl GraphicCache {
Graphic::Blank => return None, Graphic::Blank => return None,
}; };
// Draw to allocated area // Draw to allocated area.
cacher(aabr, data); cacher(aabr, data);
// Insert area into map for retrieval // Insert area into map for retrieval.
self.rect_map self.rect_map
.insert((graphic_id, dims, source.map(|e| e.to_bits())), aabr); .insert((graphic_id, dims, source.map(|e| e.to_bits())), aabr);
// Return area // Return area.
Some(aabr) Some(aabr)
} }
None => None, None => None,

View File

@ -109,7 +109,7 @@ pub fn draw_vox(
.map(|p| p.data) .map(|p| p.data)
.collect::<Vec<[u8; 4]>>() .collect::<Vec<[u8; 4]>>()
} else { } else {
// TODO: remove clone // TODO: Remove clone.
color.as_ref().to_vec() color.as_ref().to_vec()
} }
} }
@ -121,7 +121,7 @@ fn ao_level(side1: bool, corner: bool, side2: bool) -> u8 {
3 - [side1, corner, side2].iter().filter(|e| **e).count() as u8 3 - [side1, corner, side2].iter().filter(|e| **e).count() as u8
} }
} }
// TODO: generalize meshing code.... // TODO: Generalize meshing code.
fn create_quad( fn create_quad(
origin: Vec3<f32>, origin: Vec3<f32>,
unit_x: Vec3<f32>, unit_x: Vec3<f32>,
@ -140,7 +140,7 @@ fn create_quad(
let c = Vert::new(origin + unit_x + unit_y, col, norm, c_ao); let c = Vert::new(origin + unit_x + unit_y, col, norm, c_ao);
let d = Vert::new(origin + unit_y, col, norm, d_ao); let d = Vert::new(origin + unit_y, col, norm, d_ao);
// Flip to fix anisotropy // Flip to fix anisotropy.
let (a, b, c, d) = if a_ao + c_ao > b_ao + d_ao { let (a, b, c, d) = if a_ao + c_ao > b_ao + d_ao {
(d, a, b, c) (d, a, b, c)
} else { } else {
@ -163,7 +163,7 @@ fn generate_mesh(segment: &Segment, offs: Vec3<f32>) -> Vec<Vert> {
let is_empty = |pos| segment.get(pos).map(|v| v.is_empty()).unwrap_or(true); let is_empty = |pos| segment.get(pos).map(|v| v.is_empty()).unwrap_or(true);
let occluders = |unit_x, unit_y, dir| { let occluders = |unit_x, unit_y, dir| {
// would be nice to generate unit_x and unit_y from a given direction // Would be nice to generate unit_x and unit_y from a given direction.
[ [
!is_empty(pos + dir - unit_x), !is_empty(pos + dir - unit_x),
!is_empty(pos + dir - unit_x - unit_y), !is_empty(pos + dir - unit_x - unit_y),

View File

@ -57,7 +57,7 @@ impl<'a> GraphicCreator<'a> for VoxelMs9Graphic {
} }
/// This macro will automatically load all specified assets, get the corresponding ImgIds and /// This macro will automatically load all specified assets, get the corresponding ImgIds and
/// create a struct with all of them /// create a struct with all of them.
/// ///
/// Example usage: /// Example usage:
/// ``` /// ```

View File

@ -88,7 +88,7 @@ pub struct Ui {
draw_commands: Vec<DrawCommand>, draw_commands: Vec<DrawCommand>,
// Model for drawing the ui // Model for drawing the ui
model: DynamicModel<UiPipeline>, model: DynamicModel<UiPipeline>,
// Stores new window size for updating scaling // Window size for updating scaling
window_resized: Option<Vec2<f64>>, window_resized: Option<Vec2<f64>>,
// Scaling of the ui // Scaling of the ui
scale: Scale, scale: Scale,
@ -110,10 +110,10 @@ impl Ui {
}) })
} }
// Set the scaling mode of the ui // Set the scaling mode of the ui.
pub fn scaling_mode(&mut self, mode: ScaleMode) { pub fn scaling_mode(&mut self, mode: ScaleMode) {
self.scale.scaling_mode(mode); self.scale.scaling_mode(mode);
// Give conrod the new size // Give conrod the new size.
let (w, h) = self.scale.scaled_window_size().into_tuple(); let (w, h) = self.scale.scaled_window_size().into_tuple();
self.ui.handle_event(Input::Resize(w, h)); self.ui.handle_event(Input::Resize(w, h));
} }
@ -134,7 +134,7 @@ impl Ui {
self.ui.set_widgets() self.ui.set_widgets()
} }
// Accepts Option so widget can be unfocused // Accepts Option so widget can be unfocused.
pub fn focus_widget(&mut self, id: Option<WidgId>) { pub fn focus_widget(&mut self, id: Option<WidgId>) {
self.ui.keyboard_capture(match id { self.ui.keyboard_capture(match id {
Some(id) => id, Some(id) => id,
@ -142,12 +142,12 @@ impl Ui {
}); });
} }
// Get id of current widget capturing keyboard // Get id of current widget capturing keyboard.
pub fn widget_capturing_keyboard(&self) -> Option<WidgId> { pub fn widget_capturing_keyboard(&self) -> Option<WidgId> {
self.ui.global_input().current.widget_capturing_keyboard self.ui.global_input().current.widget_capturing_keyboard
} }
// Get whether a widget besides the window is capturing the mouse // Get whether a widget besides the window is capturing the mouse.
pub fn no_widget_capturing_mouse(&self) -> bool { pub fn no_widget_capturing_mouse(&self) -> bool {
self.ui self.ui
.global_input() .global_input()
@ -157,7 +157,7 @@ impl Ui {
.is_none() .is_none()
} }
// Get the widget graph // Get the widget graph.
pub fn widget_graph(&self) -> &Graph { pub fn widget_graph(&self) -> &Graph {
self.ui.widget_graph() self.ui.widget_graph()
} }
@ -203,8 +203,8 @@ impl Ui {
self.draw_commands.clear(); self.draw_commands.clear();
let mut mesh = Mesh::new(); let mut mesh = Mesh::new();
// TODO: this could be removed entirely if the draw call just used both textures // TODO: this could be removed entirely if the draw call just used both textures,
// however this allows for flexibility if we want to interleave other draw calls later // however this allows for flexibility if we want to interweave other draw calls later.
enum State { enum State {
Image, Image,
Plain, Plain,
@ -213,8 +213,8 @@ impl Ui {
let mut current_state = State::Plain; let mut current_state = State::Plain;
let mut start = 0; let mut start = 0;
let window_scizzor = default_scissor(renderer); let window_scissor = default_scissor(renderer);
let mut current_scizzor = window_scizzor; let mut current_scissor = window_scissor;
// Switches to the `Plain` state and completes the previous `Command` if not already in the // Switches to the `Plain` state and completes the previous `Command` if not already in the
// `Plain` state. // `Plain` state.
@ -239,12 +239,12 @@ impl Ui {
.. ..
} = prim; } = prim;
// Check for a change in the scizzor // Check for a change in the scissor.
let new_scizzor = { let new_scissor = {
let (l, b, w, h) = scizzor.l_b_w_h(); let (l, b, w, h) = scizzor.l_b_w_h();
// Calculate minimum x and y coordinates while // Calculate minimum x and y coordinates while
// - flipping y axis (from +up to +down) // flipping y axis (from +up to +down) and
// - moving origin to top-left corner (from middle) // moving origin to top-left corner (from middle).
let min_x = self.ui.win_w / 2.0 + l; let min_x = self.ui.win_w / 2.0 + l;
let min_y = self.ui.win_h / 2.0 - b - h; let min_y = self.ui.win_h / 2.0 - b - h;
Aabr { Aabr {
@ -257,22 +257,22 @@ impl Ui {
y: ((min_y + h) * p_scale_factor) as u16, y: ((min_y + h) * p_scale_factor) as u16,
}, },
} }
.intersection(window_scizzor) .intersection(window_scissor)
}; };
if new_scizzor != current_scizzor { if new_scissor != current_scissor {
// Finish the current command // Finish the current command.
self.draw_commands.push(match current_state { self.draw_commands.push(match current_state {
State::Plain => DrawCommand::plain(start..mesh.vertices().len()), State::Plain => DrawCommand::plain(start..mesh.vertices().len()),
State::Image => DrawCommand::image(start..mesh.vertices().len()), State::Image => DrawCommand::image(start..mesh.vertices().len()),
}); });
start = mesh.vertices().len(); start = mesh.vertices().len();
// Update the scizzor and produce a command. // Update the scissor and produce a command.
current_scizzor = new_scizzor; current_scissor = new_scissor;
self.draw_commands.push(DrawCommand::Scissor(new_scizzor)); self.draw_commands.push(DrawCommand::Scissor(new_scissor));
} }
// Functions for converting for conrod scalar coords to GL vertex coords (-1.0 to 1.0) // Functions for converting for conrod scalar coords to GL vertex coords (-1.0 to 1.0).
let ui_win_w = self.ui.win_w; let ui_win_w = self.ui.win_w;
let ui_win_h = self.ui.win_h; let ui_win_h = self.ui.win_h;
let vx = |x: f64| (x / ui_win_w * 2.0) as f32; let vx = |x: f64| (x / ui_win_w * 2.0) as f32;
@ -303,7 +303,7 @@ impl Ui {
_ => {} _ => {}
} }
// Switch to the image state if we are not in it already // Switch to the image state if we are not in it already.
if let State::Plain = current_state { if let State::Plain = current_state {
self.draw_commands self.draw_commands
.push(DrawCommand::plain(start..mesh.vertices().len())); .push(DrawCommand::plain(start..mesh.vertices().len()));
@ -318,8 +318,8 @@ impl Ui {
(rect.w() * p_scale_factor).round() as u16, (rect.w() * p_scale_factor).round() as u16,
(rect.h() * p_scale_factor).round() as u16, (rect.h() * p_scale_factor).round() as u16,
); );
// Transform the source rectangle into uv coordinate // Transform the source rectangle into uv coordinate.
// TODO: make sure this is right // TODO: Make sure this is right.
let source_aabr = { let source_aabr = {
let (uv_l, uv_r, uv_b, uv_t) = (0.0, 1.0, 0.0, 1.0); /*match source_rect { let (uv_l, uv_r, uv_b, uv_t) = (0.0, 1.0, 0.0, 1.0); /*match source_rect {
Some(src_rect) => { Some(src_rect) => {
@ -339,7 +339,7 @@ impl Ui {
let (cache_w, cache_h) = let (cache_w, cache_h) =
cache_tex.get_dimensions().map(|e| e as f32).into_tuple(); cache_tex.get_dimensions().map(|e| e as f32).into_tuple();
// Cache graphic at particular resolution // Cache graphic at particular resolution.
let uv_aabr = match graphic_cache.cache_res( let uv_aabr = match graphic_cache.cache_res(
*graphic_id, *graphic_id,
resolution, resolution,
@ -371,15 +371,15 @@ impl Ui {
font_id, font_id,
} => { } => {
switch_to_plain_state!(); switch_to_plain_state!();
// Get screen width and height // Get screen width and height.
let (screen_w, screen_h) = let (screen_w, screen_h) =
renderer.get_resolution().map(|e| e as f32).into_tuple(); renderer.get_resolution().map(|e| e as f32).into_tuple();
// Calculate dpi factor // Calculate dpi factor.
let dpi_factor = screen_w / ui_win_w as f32; let dpi_factor = screen_w / ui_win_w as f32;
let positioned_glyphs = text.positioned_glyphs(dpi_factor); let positioned_glyphs = text.positioned_glyphs(dpi_factor);
let (glyph_cache, cache_tex) = self.cache.glyph_cache_mut_and_tex(); let (glyph_cache, cache_tex) = self.cache.glyph_cache_mut_and_tex();
// Queue the glyphs to be cached // Queue the glyphs to be cached.
for glyph in positioned_glyphs { for glyph in positioned_glyphs {
glyph_cache.queue_glyph(font_id.index(), glyph.clone()); glyph_cache.queue_glyph(font_id.index(), glyph.clone());
} }
@ -424,7 +424,7 @@ impl Ui {
} }
PrimitiveKind::Rectangle { color } => { PrimitiveKind::Rectangle { color } => {
let color = srgb_to_linear(color.to_fsa().into()); let color = srgb_to_linear(color.to_fsa().into());
// Don't draw a transparent rectangle // Don't draw a transparent rectangle.
if color[3] == 0.0 { if color[3] == 0.0 {
continue; continue;
} }
@ -442,7 +442,7 @@ impl Ui {
)); ));
} }
PrimitiveKind::TrianglesSingleColor { color, triangles } => { PrimitiveKind::TrianglesSingleColor { color, triangles } => {
// Don't draw transparent triangle or switch state if there are actually no triangles // Don't draw transparent triangle or switch state if there are actually no triangles.
let color = srgb_to_linear(Rgba::from(Into::<[f32; 4]>::into(color))); let color = srgb_to_linear(Rgba::from(Into::<[f32; 4]>::into(color)));
if triangles.is_empty() || color[3] == 0.0 { if triangles.is_empty() || color[3] == 0.0 {
continue; continue;
@ -454,7 +454,7 @@ impl Ui {
let p1 = Vec2::new(vx(tri[0][0]), vy(tri[0][1])); let p1 = Vec2::new(vx(tri[0][0]), vy(tri[0][1]));
let p2 = Vec2::new(vx(tri[1][0]), vy(tri[1][1])); let p2 = Vec2::new(vx(tri[1][0]), vy(tri[1][1]));
let p3 = Vec2::new(vx(tri[2][0]), vy(tri[2][1])); let p3 = Vec2::new(vx(tri[2][0]), vy(tri[2][1]));
// If triangle is clockwise reverse it // If triangle is clockwise, reverse it.
let (v1, v2): (Vec3<f32>, Vec3<f32>) = ((p2 - p1).into(), (p3 - p1).into()); let (v1, v2): (Vec3<f32>, Vec3<f32>) = ((p2 - p1).into(), (p3 - p1).into());
let triangle = if v1.cross(v2).z > 0.0 { let triangle = if v1.cross(v2).z > 0.0 {
[p1.into_array(), p2.into_array(), p3.into_array()] [p1.into_array(), p2.into_array(), p3.into_array()]
@ -469,49 +469,49 @@ impl Ui {
)); ));
} }
} }
_ => {} // TODO: Add this _ => {} // TODO: Add this.
//PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);} //PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);}
// Other uneeded for now // Other unneeded for now.
//PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);} //PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);}
} }
} }
// Enter the final command // Enter the final command.
self.draw_commands.push(match current_state { self.draw_commands.push(match current_state {
State::Plain => DrawCommand::plain(start..mesh.vertices().len()), State::Plain => DrawCommand::plain(start..mesh.vertices().len()),
State::Image => DrawCommand::image(start..mesh.vertices().len()), State::Image => DrawCommand::image(start..mesh.vertices().len()),
}); });
// create a larger dynamic model if the mesh is larger than the current model size // Create a larger dynamic model if the mesh is larger than the current model size.
if self.model.vbuf.len() < mesh.vertices().len() { if self.model.vbuf.len() < mesh.vertices().len() {
self.model = renderer self.model = renderer
.create_dynamic_model(mesh.vertices().len() * 4 / 3) .create_dynamic_model(mesh.vertices().len() * 4 / 3)
.unwrap(); .unwrap();
} }
renderer.update_model(&self.model, &mesh, 0).unwrap(); renderer.update_model(&self.model, &mesh, 0).unwrap();
// Update model with new mesh // Update model with new mesh.
// Handle window resizing // Handle window resizing.
if let Some(new_dims) = self.window_resized.take() { if let Some(new_dims) = self.window_resized.take() {
self.scale.window_resized(new_dims, renderer); self.scale.window_resized(new_dims, renderer);
let (w, h) = self.scale.scaled_window_size().into_tuple(); let (w, h) = self.scale.scaled_window_size().into_tuple();
self.ui.handle_event(Input::Resize(w, h)); self.ui.handle_event(Input::Resize(w, h));
let res = renderer.get_resolution(); let res = renderer.get_resolution();
// Avoid panic in graphic cache when minimizing // Avoid panic in graphic cache when minimizing.
if res.x > 0 && res.y > 0 { if res.x > 0 && res.y > 0 {
self.cache self.cache
.clear_graphic_cache(renderer, renderer.get_resolution().map(|e| e * 4)); .clear_graphic_cache(renderer, renderer.get_resolution().map(|e| e * 4));
} }
// TODO: probably need to resize glyph cache, see conrod's gfx backend for reference // TODO: Probably need to resize glyph cache, see conrod's gfx backend for reference.
} }
} }
pub fn render(&self, renderer: &mut Renderer) { pub fn render(&self, renderer: &mut Renderer) {
let mut scissor = default_scissor(renderer); let mut scissor_to_render = default_scissor(renderer);
for draw_command in self.draw_commands.iter() { for draw_command in self.draw_commands.iter() {
match draw_command { match draw_command {
DrawCommand::Scissor(scizzor) => { DrawCommand::Scissor(scissor) => {
scissor = *scizzor; scissor_to_render = *scissor;
} }
DrawCommand::Draw { kind, verts } => { DrawCommand::Draw { kind, verts } => {
let tex = match kind { let tex = match kind {
@ -519,7 +519,7 @@ impl Ui {
DrawKind::Plain => self.cache.glyph_cache_tex(), DrawKind::Plain => self.cache.glyph_cache_tex(),
}; };
let model = self.model.submodel(verts.clone()); let model = self.model.submodel(verts.clone());
renderer.render_ui_element(&model, &tex, scissor); renderer.render_ui_element(&model, &tex, scissor_to_render);
} }
} }
} }

View File

@ -1,19 +1,18 @@
use crate::{render::Renderer, window::Window}; use crate::{render::Renderer, window::Window};
use vek::*; use vek::*;
// How the ui is scaled /// Type of scaling to use.
pub enum ScaleMode { pub enum ScaleMode {
// Scale against physical size // Scale against physical size.
Absolute(f64), Absolute(f64),
// Use the dpi factor provided by the windowing system (i.e. use logical size) // Use the dpi factor provided by the windowing system (i.e. use logical size).
DpiFactor, DpiFactor,
// Scale based on the window's physical size, but maintain aspect ratio of widgets // Scale based on the window's physical size, but maintain aspect ratio of widgets.
// Contains width and height of the "default" window size (ie where there should be no scaling) // Contains width and height of the "default" window size (ie where there should be no scaling).
RelativeToWindow(Vec2<f64>), RelativeToWindow(Vec2<f64>),
} }
pub struct Scale { pub struct Scale {
// Type of scaling to use
mode: ScaleMode, mode: ScaleMode,
// Current dpi factor // Current dpi factor
dpi_factor: f64, dpi_factor: f64,
@ -31,11 +30,11 @@ impl Scale {
window_dims, window_dims,
} }
} }
// Change the scaling mode // Change the scaling mode.
pub fn scaling_mode(&mut self, mode: ScaleMode) { pub fn scaling_mode(&mut self, mode: ScaleMode) {
self.mode = mode; self.mode = mode;
} }
// Calculate factor to transform between logical coordinates and our scaled coordinates // Calculate factor to transform between logical coordinates and our scaled coordinates.
pub fn scale_factor_logical(&self) -> f64 { pub fn scale_factor_logical(&self) -> f64 {
match self.mode { match self.mode {
ScaleMode::Absolute(scale) => scale / self.dpi_factor, ScaleMode::Absolute(scale) => scale / self.dpi_factor,
@ -45,20 +44,20 @@ impl Scale {
} }
} }
} }
// Calculate factor to transform between physical coordinates and our scaled coordinates // Calculate factor to transform between physical coordinates and our scaled coordinates.
pub fn scale_factor_physical(&self) -> f64 { pub fn scale_factor_physical(&self) -> f64 {
self.scale_factor_logical() * self.dpi_factor self.scale_factor_logical() * self.dpi_factor
} }
// Updates internal window size (and/or dpi_factor) // Updates internal window size (and/or dpi_factor).
pub fn window_resized(&mut self, new_dims: Vec2<f64>, renderer: &Renderer) { pub fn window_resized(&mut self, new_dims: Vec2<f64>, renderer: &Renderer) {
self.dpi_factor = renderer.get_resolution().x as f64 / new_dims.x; self.dpi_factor = renderer.get_resolution().x as f64 / new_dims.x;
self.window_dims = new_dims; self.window_dims = new_dims;
} }
// Get scaled window size // Get scaled window size.
pub fn scaled_window_size(&self) -> Vec2<f64> { pub fn scaled_window_size(&self) -> Vec2<f64> {
self.window_dims / self.scale_factor_logical() self.window_dims / self.scale_factor_logical()
} }
// Transform point from logical to scaled coordinates // Transform point from logical to scaled coordinates.
pub fn scale_point(&self, point: Vec2<f64>) -> Vec2<f64> { pub fn scale_point(&self, point: Vec2<f64>) -> Vec2<f64> {
point / self.scale_factor_logical() point / self.scale_factor_logical()
} }

View File

@ -17,7 +17,7 @@ pub trait ValueFromPercent<T> {
/// Linear value selection. /// Linear value selection.
/// ///
/// If the slider's width is greater than it's height, it will automatically become a horizontal /// If the slider's width is greater than its height, it will automatically become a horizontal
/// slider, otherwise it will be a vertical slider. /// slider, otherwise it will be a vertical slider.
/// ///
/// Its reaction is triggered if the value is updated or if the mouse button is released while /// Its reaction is triggered if the value is updated or if the mouse button is released while
@ -31,9 +31,9 @@ pub struct ImageSlider<T, K> {
max: T, max: T,
/// The amount in which the slider's display should be skewed. /// The amount in which the slider's display should be skewed.
/// ///
/// Higher skew amounts (above 1.0) will weight lower values. /// Higher skew amounts (above 1.0) will weigh lower values.
/// ///
/// Lower skew amounts (below 1.0) will weight heigher values. /// Lower skew amounts (below 1.0) will weigh higher values.
/// ///
/// All skew amounts should be greater than 0.0. /// All skew amounts should be greater than 0.0.
skew: f32, skew: f32,
@ -47,7 +47,7 @@ struct Track {
color: Option<Color>, color: Option<Color>,
src_rect: Option<Rect>, src_rect: Option<Rect>,
breadth: Option<f32>, breadth: Option<f32>,
// Padding on the ends of the track constraining the slider to a smaller area // Padding on the ends of the track constraining the slider to a smaller area.
padding: (f32, f32), padding: (f32, f32),
} }
@ -202,13 +202,13 @@ where
if mouse.buttons.left().is_down() { if mouse.buttons.left().is_down() {
let mouse_abs_xy = mouse.abs_xy(); let mouse_abs_xy = mouse.abs_xy();
let (mouse_offset, track_length) = if is_horizontal { let (mouse_offset, track_length) = if is_horizontal {
// Horizontal. // Horizontal
( (
mouse_abs_xy[0] - rect.x.start - start_pad, mouse_abs_xy[0] - rect.x.start - start_pad,
rect.w() - start_pad - end_pad, rect.w() - start_pad - end_pad,
) )
} else { } else {
// Vertical. // Vertical
( (
mouse_abs_xy[1] - rect.y.start - start_pad, mouse_abs_xy[1] - rect.y.start - start_pad,
rect.h() - start_pad - end_pad, rect.h() - start_pad - end_pad,
@ -264,7 +264,7 @@ where
}) })
.unwrap_or(slider.image_id); .unwrap_or(slider.image_id);
// The rectangle for positioning and sizing the slider. // A rectangle for positioning and sizing the slider.
let value_perc = utils::map_range(new_value, min, max, 0.0, 1.0); let value_perc = utils::map_range(new_value, min, max, 0.0, 1.0);
let unskewed_perc = value_perc.powf(1.0 / skew as f64); let unskewed_perc = value_perc.powf(1.0 / skew as f64);
let slider_rect = if is_horizontal { let slider_rect = if is_horizontal {

View File

@ -105,8 +105,10 @@ impl Widget for ToggleButton {
t_image, t_image,
.. ..
} = self; } = self;
// Check if button was clicked // Check if the button was clicked.
// (can't use .set().was_clicked() because we are changing the image and this is after setting the widget which causes flickering as it takes a frame to change after the mouse button is lifted) // (Can't use `.set().was_clicked()` because we are changing the image after setting the
// widget, which causes flickering since it takes a frame to change after the mouse button
// is lifted).
if ui.widget_input(state.ids.button).clicks().left().count() % 2 == 1 { if ui.widget_input(state.ids.button).clicks().left().count() % 2 == 1 {
value = !value; value = !value;
} }

View File

@ -85,15 +85,15 @@ impl Window {
self.needs_refresh_resize = false; self.needs_refresh_resize = false;
} }
// Copy data that is needed by the events closure to avoid lifetime errors // Copy data that is needed by the events closure to avoid lifetime errors.
// TODO: Remove this if/when the compiler permits it // TODO: Remove this if/when the compiler permits it.
let cursor_grabbed = self.cursor_grabbed; let cursor_grabbed = self.cursor_grabbed;
let renderer = &mut self.renderer; let renderer = &mut self.renderer;
let window = &mut self.window; let window = &mut self.window;
let key_map = &self.key_map; let key_map = &self.key_map;
self.events_loop.poll_events(|event| { self.events_loop.poll_events(|event| {
// Get events for ui // Get events for ui.
if let Some(event) = ui::Event::try_from(event.clone(), &window) { if let Some(event) = ui::Event::try_from(event.clone(), &window) {
events.push(Event::Ui(event)); events.push(Event::Ui(event));
} }
@ -174,7 +174,7 @@ impl Window {
} }
} }
/// Represents a key that the game recognises after keyboard mapping /// Represents a key that the game recognises after keyboard mapping.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum Key { pub enum Key {
ToggleCursor, ToggleCursor,
@ -197,12 +197,12 @@ pub enum Key {
Help, Help,
} }
/// Represents an incoming event from the window /// Represents an incoming event from the window.
#[derive(Clone)] #[derive(Clone)]
pub enum Event { pub enum Event {
/// The window has been requested to close. /// The window has been requested to close.
Close, Close,
/// The window has been resized /// The window has been resized.
Resize(Vec2<u32>), Resize(Vec2<u32>),
/// A key has been typed that corresponds to a specific character. /// A key has been typed that corresponds to a specific character.
Char(char), Char(char),
@ -210,12 +210,12 @@ pub enum Event {
CursorPan(Vec2<f32>), CursorPan(Vec2<f32>),
/// The camera has been requested to zoom. /// The camera has been requested to zoom.
Zoom(f32), Zoom(f32),
/// A key that the game recognises has been pressed down /// A key that the game recognises has been pressed down.
KeyDown(Key), KeyDown(Key),
/// A key that the game recognises has been released down /// A key that the game recognises has been released down.
KeyUp(Key), KeyUp(Key),
/// Event that the ui uses /// Event that the ui uses.
Ui(ui::Event), Ui(ui::Event),
/// Game settings have changed /// Game settings have changed.
SettingsChanged, SettingsChanged,
} }

View File

@ -21,7 +21,7 @@ impl World {
} }
pub fn generate_chunk(chunk_pos: Vec2<i32>) -> TerrainChunk { pub fn generate_chunk(chunk_pos: Vec2<i32>) -> TerrainChunk {
// TODO: This is all test code, remove/improve this later // TODO: This is all test code, remove/improve this later.
let air = Block::empty(); let air = Block::empty();
let stone = Block::new(1, Rgb::new(200, 220, 255)); let stone = Block::new(1, Rgb::new(200, 220, 255));