mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Char Window, Mana, Health, Exp-Bar
Former-commit-id: 546d29aae7441232892c7b7438708e93fb440128
This commit is contained in:
parent
c1af42522d
commit
8ecb849970
2
.gitignore
vendored
2
.gitignore
vendored
@ -22,3 +22,5 @@
|
|||||||
assets/voxygen
|
assets/voxygen
|
||||||
UI3.rar
|
UI3.rar
|
||||||
assets.rar
|
assets.rar
|
||||||
|
*.rar
|
||||||
|
assets/voxygen
|
||||||
|
74
common/src/net/error.rs
Normal file
74
common/src/net/error.rs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PostError {
|
||||||
|
InvalidMessage,
|
||||||
|
InternalError,
|
||||||
|
Disconnected,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PostErrorInternal {
|
||||||
|
Io(std::io::Error),
|
||||||
|
Serde(bincode::Error),
|
||||||
|
ChannelRecv(std::sync::mpsc::TryRecvError),
|
||||||
|
ChannelSend, // Empty because I couldn't figure out how to handle generic type in mpsc::TrySendError properly
|
||||||
|
MsgSizeLimitExceeded,
|
||||||
|
MioError,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Into<&'a PostErrorInternal>> From<T> for PostError {
|
||||||
|
fn from(err: T) -> Self {
|
||||||
|
match err.into() {
|
||||||
|
// TODO: Are I/O errors always disconnect errors?
|
||||||
|
PostErrorInternal::Io(_) => PostError::Disconnected,
|
||||||
|
PostErrorInternal::Serde(_) => PostError::InvalidMessage,
|
||||||
|
PostErrorInternal::MsgSizeLimitExceeded => PostError::InvalidMessage,
|
||||||
|
PostErrorInternal::MioError => PostError::InternalError,
|
||||||
|
PostErrorInternal::ChannelRecv(_) => PostError::InternalError,
|
||||||
|
PostErrorInternal::ChannelSend => PostError::InternalError,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PostErrorInternal> for PostError {
|
||||||
|
fn from(err: PostErrorInternal) -> Self {
|
||||||
|
(&err).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for PostErrorInternal {
|
||||||
|
fn from(err: std::io::Error) -> Self {
|
||||||
|
PostErrorInternal::Io(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bincode::Error> for PostErrorInternal {
|
||||||
|
fn from(err: bincode::Error) -> Self {
|
||||||
|
PostErrorInternal::Serde(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::sync::mpsc::TryRecvError> for PostErrorInternal {
|
||||||
|
fn from(err: std::sync::mpsc::TryRecvError) -> Self {
|
||||||
|
PostErrorInternal::ChannelRecv(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
impl From<std::io::Error> for PostError {
|
||||||
|
fn from(err: std::io::Error) -> Self {
|
||||||
|
(&PostErrorInternal::from(err)).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bincode::Error> for PostError {
|
||||||
|
fn from(err: bincode::Error) -> Self {
|
||||||
|
(&PostErrorInternal::from(err)).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::sync::mpsc::TryRecvError> for PostError {
|
||||||
|
fn from(err: std::sync::mpsc::TryRecvError) -> Self {
|
||||||
|
(&PostErrorInternal::from(err)).into()
|
||||||
|
}
|
||||||
|
}
|
270
common/src/net/postbox.rs
Normal file
270
common/src/net/postbox.rs
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
// Standard
|
||||||
|
use std::{
|
||||||
|
collections::VecDeque,
|
||||||
|
convert::TryFrom,
|
||||||
|
io::{
|
||||||
|
ErrorKind,
|
||||||
|
Read,
|
||||||
|
},
|
||||||
|
net::SocketAddr,
|
||||||
|
thread,
|
||||||
|
time::Duration,
|
||||||
|
sync::mpsc::TryRecvError,
|
||||||
|
};
|
||||||
|
|
||||||
|
// External
|
||||||
|
use bincode;
|
||||||
|
use mio::{net::TcpStream, Events, Poll, PollOpt, Ready, Token};
|
||||||
|
use mio_extras::channel::{channel, Receiver, Sender};
|
||||||
|
|
||||||
|
// Crate
|
||||||
|
use super::{
|
||||||
|
data::ControlMsg,
|
||||||
|
error::{
|
||||||
|
PostError,
|
||||||
|
PostErrorInternal,
|
||||||
|
},
|
||||||
|
PostRecv,
|
||||||
|
PostSend,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const CTRL_TOKEN: Token = Token(0); // Token for thread control messages
|
||||||
|
const DATA_TOKEN: Token = Token(1); // Token for thread data exchange
|
||||||
|
const CONN_TOKEN: Token = Token(2); // Token for TcpStream for the PostBox child thread
|
||||||
|
const MESSAGE_SIZE_CAP: u64 = 1 << 20; // Maximum accepted length of a packet
|
||||||
|
|
||||||
|
/// A high-level wrapper of [`TcpStream`](mio::net::TcpStream).
|
||||||
|
/// [`PostBox`] takes care of serializing sent packets and deserializing received packets in the background, providing a simple API for sending and receiving objects over network.
|
||||||
|
pub struct PostBox<S, R>
|
||||||
|
where
|
||||||
|
S: PostSend,
|
||||||
|
R: PostRecv,
|
||||||
|
{
|
||||||
|
handle: Option<thread::JoinHandle<()>>,
|
||||||
|
ctrl: Sender<ControlMsg>,
|
||||||
|
recv: Receiver<Result<R, PostErrorInternal>>,
|
||||||
|
send: Sender<S>,
|
||||||
|
poll: Poll,
|
||||||
|
err: Option<PostErrorInternal>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, R> PostBox<S, R>
|
||||||
|
where
|
||||||
|
S: PostSend,
|
||||||
|
R: PostRecv,
|
||||||
|
{
|
||||||
|
/// Creates a new [`PostBox`] connected to specified address, meant to be used by the client
|
||||||
|
pub fn to_server<A: Into<SocketAddr>>(addr: A) -> Result<PostBox<S, R>, PostError> {
|
||||||
|
let connection = TcpStream::connect(&addr.into())?;
|
||||||
|
Self::from_tcpstream(connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`PostBox`] from an existing connection, meant to be used by [`PostOffice`](super::PostOffice) on the server
|
||||||
|
pub fn from_tcpstream(connection: TcpStream) -> Result<PostBox<S, R>, PostError> {
|
||||||
|
let (ctrl_tx, ctrl_rx) = channel(); // Control messages
|
||||||
|
let (send_tx, send_rx) = channel(); // main thread -[data to be serialized and sent]> worker thread
|
||||||
|
let (recv_tx, recv_rx) = channel(); // main thread <[received and deserialized data]- worker thread
|
||||||
|
let thread_poll = Poll::new().unwrap();
|
||||||
|
let postbox_poll = Poll::new().unwrap();
|
||||||
|
thread_poll
|
||||||
|
.register(&connection, CONN_TOKEN, Ready::readable(), PollOpt::edge())
|
||||||
|
.unwrap();
|
||||||
|
thread_poll
|
||||||
|
.register(&ctrl_rx, CTRL_TOKEN, Ready::readable(), PollOpt::edge())
|
||||||
|
.unwrap();
|
||||||
|
thread_poll
|
||||||
|
.register(&send_rx, DATA_TOKEN, Ready::readable(), PollOpt::edge())
|
||||||
|
.unwrap();
|
||||||
|
postbox_poll
|
||||||
|
.register(&recv_rx, DATA_TOKEN, Ready::readable(), PollOpt::edge())
|
||||||
|
.unwrap();
|
||||||
|
let handle = thread::Builder::new()
|
||||||
|
.name("postbox_worker".into())
|
||||||
|
.spawn(move || postbox_thread(connection, ctrl_rx, send_rx, recv_tx, thread_poll))?;
|
||||||
|
Ok(PostBox {
|
||||||
|
handle: Some(handle),
|
||||||
|
ctrl: ctrl_tx,
|
||||||
|
recv: recv_rx,
|
||||||
|
send: send_tx,
|
||||||
|
poll: postbox_poll,
|
||||||
|
err: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return an `Option<PostError>` indicating the current status of the `PostBox`.
|
||||||
|
pub fn status(&self) -> Option<PostError> {
|
||||||
|
self.err.as_ref().map(|err| err.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Non-blocking sender method
|
||||||
|
pub fn send(&mut self, data: S) -> Result<(), PostError> {
|
||||||
|
match &mut self.err {
|
||||||
|
err @ None => if let Err(_) = self.send.send(data) {
|
||||||
|
*err = Some(PostErrorInternal::MioError);
|
||||||
|
Err(err.as_ref().unwrap().into())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
err => Err(err.as_ref().unwrap().into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Non-blocking receiver method returning an iterator over already received and deserialized objects
|
||||||
|
/// # Errors
|
||||||
|
/// If the other side disconnects PostBox won't realize that until you try to send something
|
||||||
|
pub fn new_messages(&mut self) -> impl ExactSizeIterator<Item = R> {
|
||||||
|
let mut events = Events::with_capacity(4096);
|
||||||
|
let mut items = VecDeque::new();
|
||||||
|
|
||||||
|
// If an error occured, or previously occured, just give up
|
||||||
|
if let Some(_) = self.err {
|
||||||
|
return items.into_iter();
|
||||||
|
} else if let Err(err) = self.poll.poll(&mut events, Some(Duration::new(0, 0))) {
|
||||||
|
self.err = Some(err.into());
|
||||||
|
return items.into_iter();
|
||||||
|
}
|
||||||
|
|
||||||
|
for event in events {
|
||||||
|
match event.token() {
|
||||||
|
DATA_TOKEN => loop {
|
||||||
|
match self.recv.try_recv() {
|
||||||
|
Ok(Ok(item)) => items.push_back(item),
|
||||||
|
Err(TryRecvError::Empty) => break,
|
||||||
|
Err(err) => self.err = Some(err.into()),
|
||||||
|
Ok(Err(err)) => self.err = Some(err.into()),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn postbox_thread<S, R>(
|
||||||
|
mut connection: TcpStream,
|
||||||
|
ctrl_rx: Receiver<ControlMsg>,
|
||||||
|
send_rx: Receiver<S>,
|
||||||
|
recv_tx: Sender<Result<R, PostErrorInternal>>,
|
||||||
|
poll: Poll,
|
||||||
|
) where
|
||||||
|
S: PostSend,
|
||||||
|
R: PostRecv,
|
||||||
|
{
|
||||||
|
// Receiving related variables
|
||||||
|
let mut events = Events::with_capacity(64);
|
||||||
|
let mut recv_buff = Vec::new();
|
||||||
|
let mut recv_nextlen: u64 = 0;
|
||||||
|
loop {
|
||||||
|
let mut disconnected = false;
|
||||||
|
poll.poll(&mut events, Some(Duration::from_millis(20)))
|
||||||
|
.expect("Failed to execute poll(), most likely fault of the OS");
|
||||||
|
println!("FINISHED POLL!");
|
||||||
|
for event in events.iter() {
|
||||||
|
println!("EVENT!");
|
||||||
|
match event.token() {
|
||||||
|
CTRL_TOKEN => match ctrl_rx.try_recv().unwrap() {
|
||||||
|
ControlMsg::Shutdown => return,
|
||||||
|
},
|
||||||
|
CONN_TOKEN => match connection.read_to_end(&mut recv_buff) {
|
||||||
|
Ok(_) => {}
|
||||||
|
// Returned when all the data has been read
|
||||||
|
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
|
||||||
|
Err(e) => recv_tx.send(Err(e.into())).unwrap(),
|
||||||
|
},
|
||||||
|
DATA_TOKEN => {
|
||||||
|
let msg = send_rx.try_recv().unwrap();
|
||||||
|
println!("Send: {:?}", msg);
|
||||||
|
let mut packet = bincode::serialize(&msg).unwrap();
|
||||||
|
packet.splice(0..0, (packet.len() as u64).to_be_bytes().iter().cloned());
|
||||||
|
match connection.write_bufs(&[packet.as_slice().into()]) {
|
||||||
|
Ok(_) => { println!("Sent!"); }
|
||||||
|
Err(e) => {
|
||||||
|
println!("Send error!");
|
||||||
|
recv_tx.send(Err(e.into())).unwrap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loop {
|
||||||
|
if recv_nextlen == 0 && recv_buff.len() >= 8 {
|
||||||
|
println!("Read nextlen");
|
||||||
|
recv_nextlen = u64::from_be_bytes(
|
||||||
|
<[u8; 8]>::try_from(recv_buff.drain(0..8).collect::<Vec<u8>>().as_slice()).unwrap(),
|
||||||
|
);
|
||||||
|
if recv_nextlen > MESSAGE_SIZE_CAP {
|
||||||
|
recv_tx.send(Err(PostErrorInternal::MsgSizeLimitExceeded)).unwrap();
|
||||||
|
connection.shutdown(std::net::Shutdown::Both).unwrap();
|
||||||
|
recv_buff.drain(..);
|
||||||
|
recv_nextlen = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if recv_buff.len() as u64 >= recv_nextlen && recv_nextlen != 0 {
|
||||||
|
match bincode::deserialize(recv_buff
|
||||||
|
.drain(
|
||||||
|
0..usize::try_from(recv_nextlen)
|
||||||
|
.expect("Message size was larger than usize (insane message size and 32 bit OS)"),
|
||||||
|
)
|
||||||
|
.collect::<Vec<u8>>()
|
||||||
|
.as_slice()) {
|
||||||
|
Ok(msg) => {
|
||||||
|
println!("Recv: {:?}", msg);
|
||||||
|
recv_tx
|
||||||
|
.send(Ok(msg))
|
||||||
|
.unwrap();
|
||||||
|
recv_nextlen = 0;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Recv error: {:?}", e);
|
||||||
|
recv_tx.send(Err(e.into())).unwrap();
|
||||||
|
recv_nextlen = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match connection.take_error().unwrap() {
|
||||||
|
Some(e) => {
|
||||||
|
if e.kind() == ErrorKind::BrokenPipe {
|
||||||
|
disconnected = true;
|
||||||
|
}
|
||||||
|
recv_tx.send(Err(e.into())).unwrap();
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
if disconnected == true {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop after disconnected
|
||||||
|
loop {
|
||||||
|
poll.poll(&mut events, None)
|
||||||
|
.expect("Failed to execute poll(), most likely fault of the OS");
|
||||||
|
for event in events.iter() {
|
||||||
|
match event.token() {
|
||||||
|
CTRL_TOKEN => match ctrl_rx.try_recv().unwrap() {
|
||||||
|
ControlMsg::Shutdown => return,
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, R> Drop for PostBox<S, R>
|
||||||
|
where
|
||||||
|
S: PostSend,
|
||||||
|
R: PostRecv,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.ctrl.send(ControlMsg::Shutdown).unwrap_or(());
|
||||||
|
self.handle.take().map(|handle| handle.join());
|
||||||
|
}
|
||||||
|
}
|
150
common/src/net/postoffice.rs
Normal file
150
common/src/net/postoffice.rs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// Standard
|
||||||
|
use core::time::Duration;
|
||||||
|
use std::{
|
||||||
|
collections::VecDeque,
|
||||||
|
net::SocketAddr,
|
||||||
|
thread,
|
||||||
|
sync::mpsc::TryRecvError,
|
||||||
|
};
|
||||||
|
|
||||||
|
// External
|
||||||
|
use mio::{net::TcpListener, Events, Poll, PollOpt, Ready, Token};
|
||||||
|
use mio_extras::channel::{channel, Receiver, Sender};
|
||||||
|
|
||||||
|
// Crate
|
||||||
|
use super::{
|
||||||
|
data::ControlMsg,
|
||||||
|
error::{
|
||||||
|
PostError,
|
||||||
|
PostErrorInternal,
|
||||||
|
},
|
||||||
|
postbox::PostBox,
|
||||||
|
PostRecv,
|
||||||
|
PostSend,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const CTRL_TOKEN: Token = Token(0); // Token for thread control messages
|
||||||
|
const DATA_TOKEN: Token = Token(1); // Token for thread data exchange
|
||||||
|
const CONN_TOKEN: Token = Token(2); // Token for TcpStream for the PostBox child thread
|
||||||
|
|
||||||
|
/// A high-level wrapper of [`TcpListener`](mio::net::TcpListener).
|
||||||
|
/// [`PostOffice`] listens for incoming connections in the background and wraps them into [`PostBox`]es, providing a simple non-blocking API for receiving them.
|
||||||
|
pub struct PostOffice<S, R>
|
||||||
|
where
|
||||||
|
S: PostSend,
|
||||||
|
R: PostRecv,
|
||||||
|
{
|
||||||
|
handle: Option<thread::JoinHandle<()>>,
|
||||||
|
ctrl: Sender<ControlMsg>,
|
||||||
|
recv: Receiver<Result<PostBox<S, R>, PostErrorInternal>>,
|
||||||
|
poll: Poll,
|
||||||
|
err: Option<PostErrorInternal>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, R> PostOffice<S, R>
|
||||||
|
where
|
||||||
|
S: PostSend,
|
||||||
|
R: PostRecv,
|
||||||
|
{
|
||||||
|
/// Creates a new [`PostOffice`] listening on specified address
|
||||||
|
pub fn new<A: Into<SocketAddr>>(addr: A) -> Result<Self, PostError> {
|
||||||
|
let listener = TcpListener::bind(&addr.into())?;
|
||||||
|
let (ctrl_tx, ctrl_rx) = channel();
|
||||||
|
let (recv_tx, recv_rx) = channel();
|
||||||
|
|
||||||
|
let thread_poll = Poll::new()?;
|
||||||
|
let postbox_poll = Poll::new()?;
|
||||||
|
thread_poll.register(&listener, CONN_TOKEN, Ready::readable(), PollOpt::edge())?;
|
||||||
|
thread_poll.register(&ctrl_rx, CTRL_TOKEN, Ready::readable(), PollOpt::edge())?;
|
||||||
|
postbox_poll.register(&recv_rx, DATA_TOKEN, Ready::readable(), PollOpt::edge())?;
|
||||||
|
|
||||||
|
let handle = thread::Builder::new()
|
||||||
|
.name("postoffice_worker".into())
|
||||||
|
.spawn(move || postoffice_thread(listener, ctrl_rx, recv_tx, thread_poll))?;
|
||||||
|
|
||||||
|
Ok(PostOffice {
|
||||||
|
handle: Some(handle),
|
||||||
|
ctrl: ctrl_tx,
|
||||||
|
recv: recv_rx,
|
||||||
|
poll: postbox_poll,
|
||||||
|
err: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return an `Option<PostError>` indicating the current status of the `PostOffice`.
|
||||||
|
pub fn status(&self) -> Option<PostError> {
|
||||||
|
self.err.as_ref().map(|err| err.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Non-blocking method returning an iterator over new connections wrapped in [`PostBox`]es
|
||||||
|
pub fn new_connections(
|
||||||
|
&mut self,
|
||||||
|
) -> impl ExactSizeIterator<Item = PostBox<S, R>> {
|
||||||
|
let mut events = Events::with_capacity(256);
|
||||||
|
let mut conns = VecDeque::new();
|
||||||
|
|
||||||
|
// If an error occured, or previously occured, just give up
|
||||||
|
if let Some(_) = self.err {
|
||||||
|
return conns.into_iter();
|
||||||
|
} else if let Err(err) = self.poll.poll(&mut events, Some(Duration::new(0, 0))) {
|
||||||
|
self.err = Some(err.into());
|
||||||
|
return conns.into_iter();
|
||||||
|
}
|
||||||
|
|
||||||
|
for event in events {
|
||||||
|
match event.token() {
|
||||||
|
DATA_TOKEN => loop {
|
||||||
|
match self.recv.try_recv() {
|
||||||
|
Ok(Ok(conn)) => conns.push_back(conn),
|
||||||
|
Err(TryRecvError::Empty) => break,
|
||||||
|
Err(err) => self.err = Some(err.into()),
|
||||||
|
Ok(Err(err)) => self.err = Some(err.into()),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conns.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn postoffice_thread<S, R>(
|
||||||
|
listener: TcpListener,
|
||||||
|
ctrl_rx: Receiver<ControlMsg>,
|
||||||
|
recv_tx: Sender<Result<PostBox<S, R>, PostErrorInternal>>,
|
||||||
|
poll: Poll,
|
||||||
|
) where
|
||||||
|
S: PostSend,
|
||||||
|
R: PostRecv,
|
||||||
|
{
|
||||||
|
let mut events = Events::with_capacity(256);
|
||||||
|
loop {
|
||||||
|
poll.poll(&mut events, None).expect("Failed to execute recv_poll.poll() in PostOffce receiver thread, most likely fault of the OS.");
|
||||||
|
for event in events.iter() {
|
||||||
|
match event.token() {
|
||||||
|
CTRL_TOKEN => match ctrl_rx.try_recv().unwrap() {
|
||||||
|
ControlMsg::Shutdown => return,
|
||||||
|
},
|
||||||
|
CONN_TOKEN => {
|
||||||
|
let (conn, _addr) = listener.accept().unwrap();
|
||||||
|
recv_tx.send(PostBox::from_tcpstream(conn)
|
||||||
|
// TODO: Is it okay to count a failure to create a postbox here as an 'internal error'?
|
||||||
|
.map_err(|_| PostErrorInternal::MioError)).unwrap();
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, R> Drop for PostOffice<S, R>
|
||||||
|
where
|
||||||
|
S: PostSend,
|
||||||
|
R: PostRecv,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.ctrl.send(ControlMsg::Shutdown).unwrap_or(()); // If this fails the thread is dead already
|
||||||
|
self.handle.take().map(|handle| handle.join());
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@ use conrod_core::{
|
|||||||
image::Id as ImgId,
|
image::Id as ImgId,
|
||||||
text::font::Id as FontId,
|
text::font::Id as FontId,
|
||||||
widget::{Button, Image, Rectangle, Scrollbar, Text},
|
widget::{Button, Image, Rectangle, Scrollbar, Text},
|
||||||
widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
widget_ids, Colorable, Labelable, Positionable, Sizeable, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
widget_ids! {
|
widget_ids! {
|
||||||
@ -62,6 +62,9 @@ widget_ids! {
|
|||||||
sb_grid_r,
|
sb_grid_r,
|
||||||
sb_grid_bg_l,
|
sb_grid_bg_l,
|
||||||
sb_grid_bg_r,
|
sb_grid_bg_r,
|
||||||
|
xp_bar_progress,
|
||||||
|
health_bar_color,
|
||||||
|
mana_bar_color,
|
||||||
// Level Display
|
// Level Display
|
||||||
level_text,
|
level_text,
|
||||||
next_level_text,
|
next_level_text,
|
||||||
@ -108,6 +111,7 @@ widget_ids! {
|
|||||||
spellbook_title,
|
spellbook_title,
|
||||||
//4 Charwindow
|
//4 Charwindow
|
||||||
charwindow_frame,
|
charwindow_frame,
|
||||||
|
charwindow,
|
||||||
charwindow_bg,
|
charwindow_bg,
|
||||||
charwindow_icon,
|
charwindow_icon,
|
||||||
charwindow_close,
|
charwindow_close,
|
||||||
@ -118,9 +122,12 @@ widget_ids! {
|
|||||||
charwindow_tab1_level,
|
charwindow_tab1_level,
|
||||||
charwindow_tab1_exp,
|
charwindow_tab1_exp,
|
||||||
charwindow_tab1_stats,
|
charwindow_tab1_stats,
|
||||||
|
charwindow_tab1_statnames,
|
||||||
charwindow_tab1_stats_numbers,
|
charwindow_tab1_stats_numbers,
|
||||||
charwindow_tab1_expbar,
|
charwindow_tab1_expbar,
|
||||||
charwindow_tab1_expbar_progress,
|
charwindow_rectangle,
|
||||||
|
charwindow_exp_rectangle,
|
||||||
|
charwindow_exp_progress_rectangle,
|
||||||
//5 Quest-Log
|
//5 Quest-Log
|
||||||
questlog_frame,
|
questlog_frame,
|
||||||
questlog_bg,
|
questlog_bg,
|
||||||
@ -199,6 +206,7 @@ pub(self) struct Imgs {
|
|||||||
button_blank: ImgId,
|
button_blank: ImgId,
|
||||||
button_blue_mo: ImgId,
|
button_blue_mo: ImgId,
|
||||||
button_blue_press: ImgId,
|
button_blue_press: ImgId,
|
||||||
|
window_bg: ImgId,
|
||||||
// Social-Window
|
// Social-Window
|
||||||
social_bg: ImgId,
|
social_bg: ImgId,
|
||||||
social_icon: ImgId,
|
social_icon: ImgId,
|
||||||
@ -210,12 +218,12 @@ pub(self) struct Imgs {
|
|||||||
spellbook_bg: ImgId,
|
spellbook_bg: ImgId,
|
||||||
spellbook_icon: ImgId,
|
spellbook_icon: ImgId,
|
||||||
// Char Window
|
// Char Window
|
||||||
charwindow_bg: ImgId,
|
charwindow: ImgId,
|
||||||
charwindow_icon: ImgId,
|
charwindow_icon: ImgId,
|
||||||
charwindow_tab_bg: ImgId,
|
charwindow_tab_bg: ImgId,
|
||||||
charwindow_tab: ImgId,
|
charwindow_tab: ImgId,
|
||||||
charwindow_expbar: ImgId,
|
charwindow_expbar: ImgId,
|
||||||
progress_bar: ImgId,
|
progress_frame: ImgId,
|
||||||
progress: ImgId,
|
progress: ImgId,
|
||||||
|
|
||||||
// Quest-Log Window
|
// Quest-Log Window
|
||||||
@ -312,6 +320,9 @@ impl Imgs {
|
|||||||
button_blue_mo: load("element/buttons/blue_mo.png"),
|
button_blue_mo: load("element/buttons/blue_mo.png"),
|
||||||
button_blue_press: load("element/buttons/blue_press.png"),
|
button_blue_press: load("element/buttons/blue_press.png"),
|
||||||
|
|
||||||
|
// Window BG
|
||||||
|
window_bg: load("element/misc_backgrounds/window_bg.png"),
|
||||||
|
|
||||||
//Social Window
|
//Social Window
|
||||||
social_bg: load("element/misc_backgrounds/small_bg.png"),
|
social_bg: load("element/misc_backgrounds/small_bg.png"),
|
||||||
social_icon: load("element/icons/social.png"),
|
social_icon: load("element/icons/social.png"),
|
||||||
@ -325,17 +336,15 @@ impl Imgs {
|
|||||||
spellbook_bg: load("element/misc_backgrounds/small_bg.png"),
|
spellbook_bg: load("element/misc_backgrounds/small_bg.png"),
|
||||||
spellbook_icon: load("element/icons/spellbook.png"),
|
spellbook_icon: load("element/icons/spellbook.png"),
|
||||||
|
|
||||||
|
|
||||||
//Char Window
|
//Char Window
|
||||||
charwindow_bg: load("element/misc_backgrounds/char_bg.png"),
|
charwindow: load("element/misc_backgrounds/charwindow.png"),
|
||||||
charwindow_icon: load("element/icons/charwindow.png"),
|
charwindow_icon: load("element/icons/charwindow.png"),
|
||||||
charwindow_tab_bg: load("element/frames/tab.png"),
|
charwindow_tab_bg: load("element/frames/tab.png"),
|
||||||
charwindow_tab: load("element/buttons/tab.png"),
|
charwindow_tab: load("element/buttons/tab.png"),
|
||||||
charwindow_expbar: load("element/misc_backgrounds/small_bg.png"),
|
charwindow_expbar: load("element/misc_backgrounds/small_bg.png"),
|
||||||
progress_bar: load("element/frames/progress_bar.png"),
|
progress_frame: load("element/frames/progress_bar.png"),
|
||||||
progress: load("element/misc_backgrounds/progress.png"),
|
progress: load("element/misc_backgrounds/progress.png"),
|
||||||
|
|
||||||
|
|
||||||
//Quest-Log Window
|
//Quest-Log Window
|
||||||
questlog_bg: load("element/misc_backgrounds/small_bg.png"),
|
questlog_bg: load("element/misc_backgrounds/small_bg.png"),
|
||||||
questlog_icon: load("element/icons/questlog.png"),
|
questlog_icon: load("element/icons/questlog.png"),
|
||||||
@ -400,6 +409,9 @@ pub struct Hud {
|
|||||||
map_open: bool,
|
map_open: bool,
|
||||||
show_ui: bool,
|
show_ui: bool,
|
||||||
inventory_space: u32,
|
inventory_space: u32,
|
||||||
|
xp_percentage: f64,
|
||||||
|
hp_percentage: f64,
|
||||||
|
mana_percentage: f64,
|
||||||
inventorytest_button: bool,
|
inventorytest_button: bool,
|
||||||
settings_tab: SettingsTab,
|
settings_tab: SettingsTab,
|
||||||
}
|
}
|
||||||
@ -448,6 +460,9 @@ impl Hud {
|
|||||||
open_windows: Windows::None,
|
open_windows: Windows::None,
|
||||||
font_metamorph,
|
font_metamorph,
|
||||||
font_opensans,
|
font_opensans,
|
||||||
|
xp_percentage: 0.8,
|
||||||
|
hp_percentage: 0.8,
|
||||||
|
mana_percentage: 0.8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,7 +553,7 @@ impl Hud {
|
|||||||
.align_bottom_of(self.ids.mmap_frame)
|
.align_bottom_of(self.ids.mmap_frame)
|
||||||
.set(self.ids.mmap_icons, ui_widgets);
|
.set(self.ids.mmap_icons, ui_widgets);
|
||||||
// Title
|
// Title
|
||||||
// TODO Make it display the actual Location
|
// Make it display the actual location
|
||||||
Text::new("Uncanny Valley")
|
Text::new("Uncanny Valley")
|
||||||
.mid_top_with_margin_on(self.ids.mmap_frame, 5.0)
|
.mid_top_with_margin_on(self.ids.mmap_frame, 5.0)
|
||||||
.font_size(14)
|
.font_size(14)
|
||||||
@ -599,7 +614,7 @@ impl Hud {
|
|||||||
Some(Small::Social) => Windows::CharacterAnd(None),
|
Some(Small::Social) => Windows::CharacterAnd(None),
|
||||||
_ => Windows::CharacterAnd(Some(Small::Social)),
|
_ => Windows::CharacterAnd(Some(Small::Social)),
|
||||||
},
|
},
|
||||||
Windows::Settings => unreachable!(),
|
Windows::Settings => Windows::Settings,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,7 +634,7 @@ impl Hud {
|
|||||||
Some(Small::Spellbook) => Windows::CharacterAnd(None),
|
Some(Small::Spellbook) => Windows::CharacterAnd(None),
|
||||||
_ => Windows::CharacterAnd(Some(Small::Spellbook)),
|
_ => Windows::CharacterAnd(Some(Small::Spellbook)),
|
||||||
},
|
},
|
||||||
Windows::Settings => unreachable!(),
|
Windows::Settings => Windows::Settings,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
//4 Char-Window
|
//4 Char-Window
|
||||||
@ -638,7 +653,7 @@ impl Hud {
|
|||||||
},
|
},
|
||||||
Windows::Small(small) => Windows::CharacterAnd(Some(small)),
|
Windows::Small(small) => Windows::CharacterAnd(Some(small)),
|
||||||
Windows::None => Windows::CharacterAnd(None),
|
Windows::None => Windows::CharacterAnd(None),
|
||||||
Windows::Settings => unreachable!(),
|
Windows::Settings => Windows::Settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//5 Quest-Log
|
//5 Quest-Log
|
||||||
@ -657,7 +672,7 @@ impl Hud {
|
|||||||
Some(Small::Questlog) => Windows::CharacterAnd(None),
|
Some(Small::Questlog) => Windows::CharacterAnd(None),
|
||||||
_ => Windows::CharacterAnd(Some(Small::Questlog)),
|
_ => Windows::CharacterAnd(Some(Small::Questlog)),
|
||||||
},
|
},
|
||||||
Windows::Settings => unreachable!(),
|
Windows::Settings => Windows::Settings,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -670,6 +685,10 @@ impl Hud {
|
|||||||
.mid_bottom_of(ui_widgets.window)
|
.mid_bottom_of(ui_widgets.window)
|
||||||
.set(self.ids.xp_bar, ui_widgets);
|
.set(self.ids.xp_bar, ui_widgets);
|
||||||
|
|
||||||
|
Rectangle::fill_with([406.0 * (self.xp_percentage), 5.0], color::rgb(0.31, 0.14, 0.4)) // "W=406*[Exp. %]"
|
||||||
|
.top_left_with_margins_on(self.ids.xp_bar, 5.0, 21.0)
|
||||||
|
.set(self.ids.xp_bar_progress, ui_widgets);
|
||||||
|
|
||||||
// Left Grid
|
// Left Grid
|
||||||
Image::new(self.imgs.sb_grid)
|
Image::new(self.imgs.sb_grid)
|
||||||
.w_h(2240.0 / 12.0, 448.0 / 12.0)
|
.w_h(2240.0 / 12.0, 448.0 / 12.0)
|
||||||
@ -707,19 +726,32 @@ impl Hud {
|
|||||||
.align_bottom_of(self.ids.sb_grid_bg_r)
|
.align_bottom_of(self.ids.sb_grid_bg_r)
|
||||||
.set(self.ids.r_click, ui_widgets);
|
.set(self.ids.r_click, ui_widgets);
|
||||||
|
|
||||||
// Health and mana bars
|
// Health Bar
|
||||||
Image::new(self.imgs.health_bar)
|
Image::new(self.imgs.health_bar)
|
||||||
.w_h(1120.0 / 6.0, 96.0 / 6.0)
|
.w_h(1120.0 / 6.0, 96.0 / 6.0)
|
||||||
.left_from(self.ids.l_click, 0.0)
|
.left_from(self.ids.l_click, 0.0)
|
||||||
.align_top_of(self.ids.l_click)
|
.align_top_of(self.ids.l_click)
|
||||||
.set(self.ids.health_bar, ui_widgets);
|
.set(self.ids.health_bar, ui_widgets);
|
||||||
|
|
||||||
|
// Filling
|
||||||
|
Rectangle::fill_with([182.0 * (self.hp_percentage), 6.0], color::rgb(0.09, 0.36, 0.0)) // "W=182.0 * [Health. %]"
|
||||||
|
.top_right_with_margins_on(self.ids.health_bar, 5.0, 0.0)
|
||||||
|
.set(self.ids.health_bar_color, ui_widgets);
|
||||||
|
|
||||||
|
|
||||||
|
// Mana Bar
|
||||||
Image::new(self.imgs.mana_bar)
|
Image::new(self.imgs.mana_bar)
|
||||||
.w_h(1120.0 / 6.0, 96.0 / 6.0)
|
.w_h(1120.0 / 6.0, 96.0 / 6.0)
|
||||||
.right_from(self.ids.r_click, 0.0)
|
.right_from(self.ids.r_click, 0.0)
|
||||||
.align_top_of(self.ids.r_click)
|
.align_top_of(self.ids.r_click)
|
||||||
.set(self.ids.mana_bar, ui_widgets);
|
.set(self.ids.mana_bar, ui_widgets);
|
||||||
|
|
||||||
|
// Filling
|
||||||
|
Rectangle::fill_with([182.0 * (self.hp_percentage), 6.0], color::rgb(0.15, 0.14, 0.39)) // "W=182.0 * [Mana. %]"
|
||||||
|
.top_left_with_margins_on(self.ids.mana_bar, 5.0, 0.0)
|
||||||
|
.set(self.ids.mana_bar_color, ui_widgets);
|
||||||
|
|
||||||
|
|
||||||
// Buffs/Debuffs
|
// Buffs/Debuffs
|
||||||
|
|
||||||
// Buffs
|
// Buffs
|
||||||
@ -730,14 +762,14 @@ impl Hud {
|
|||||||
|
|
||||||
// Insert actual Level here
|
// Insert actual Level here
|
||||||
Text::new("1")
|
Text::new("1")
|
||||||
.left_from(self.ids.xp_bar, -20.0)
|
.left_from(self.ids.xp_bar, -15.0)
|
||||||
.font_size(14)
|
.font_size(14)
|
||||||
.rgba(220.0, 220.0, 220.0, 0.8)
|
.rgba(220.0, 220.0, 220.0, 0.8)
|
||||||
.set(self.ids.level_text, ui_widgets);
|
.set(self.ids.level_text, ui_widgets);
|
||||||
|
|
||||||
// Insert next Level here
|
// Insert next Level here
|
||||||
Text::new("2")
|
Text::new("2")
|
||||||
.right_from(self.ids.xp_bar, -20.0)
|
.right_from(self.ids.xp_bar, -15.0)
|
||||||
.font_size(14)
|
.font_size(14)
|
||||||
.rgba(220.0, 220.0, 220.0, 0.8)
|
.rgba(220.0, 220.0, 220.0, 0.8)
|
||||||
.set(self.ids.next_level_text, ui_widgets);
|
.set(self.ids.next_level_text, ui_widgets);
|
||||||
@ -1038,7 +1070,7 @@ impl Hud {
|
|||||||
self.open_windows = match self.open_windows {
|
self.open_windows = match self.open_windows {
|
||||||
Windows::Small(_) => Windows::None,
|
Windows::Small(_) => Windows::None,
|
||||||
Windows::CharacterAnd(_) => Windows::CharacterAnd(None),
|
Windows::CharacterAnd(_) => Windows::CharacterAnd(None),
|
||||||
_ => unreachable!(),
|
_ => Windows::Settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Title
|
// Title
|
||||||
@ -1085,7 +1117,7 @@ impl Hud {
|
|||||||
self.open_windows = match self.open_windows {
|
self.open_windows = match self.open_windows {
|
||||||
Windows::Small(_) => Windows::None,
|
Windows::Small(_) => Windows::None,
|
||||||
Windows::CharacterAnd(_) => Windows::CharacterAnd(None),
|
Windows::CharacterAnd(_) => Windows::CharacterAnd(None),
|
||||||
_ => unreachable!(),
|
_ => Windows::Settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Title
|
// Title
|
||||||
@ -1132,7 +1164,7 @@ impl Hud {
|
|||||||
self.open_windows = match self.open_windows {
|
self.open_windows = match self.open_windows {
|
||||||
Windows::Small(_) => Windows::None,
|
Windows::Small(_) => Windows::None,
|
||||||
Windows::CharacterAnd(_) => Windows::CharacterAnd(None),
|
Windows::CharacterAnd(_) => Windows::CharacterAnd(None),
|
||||||
_ => unreachable!(),
|
_ => Windows::Settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Title
|
// Title
|
||||||
@ -1153,11 +1185,16 @@ impl Hud {
|
|||||||
.set(self.ids.charwindow_frame, ui_widgets);
|
.set(self.ids.charwindow_frame, ui_widgets);
|
||||||
|
|
||||||
// BG
|
// BG
|
||||||
Image::new(self.imgs.charwindow_bg)
|
Image::new(self.imgs.window_bg)
|
||||||
.w_h(348.0, 404.0)
|
.w_h(348.0, 404.0)
|
||||||
.mid_top_with_margin_on(self.ids.charwindow_frame, 48.0)
|
.mid_top_with_margin_on(self.ids.charwindow_frame, 48.0)
|
||||||
.set(self.ids.charwindow_bg, ui_widgets);
|
.set(self.ids.charwindow_bg, ui_widgets);
|
||||||
|
|
||||||
|
// Overlay
|
||||||
|
Image::new(self.imgs.charwindow)
|
||||||
|
.middle_of(self.ids.charwindow_bg)
|
||||||
|
.set(self.ids.charwindow, ui_widgets);
|
||||||
|
|
||||||
//Icon
|
//Icon
|
||||||
//Image::new(self.imgs.charwindow_icon)
|
//Image::new(self.imgs.charwindow_icon)
|
||||||
//.w_h(224.0 / 3.0, 224.0 / 3.0)
|
//.w_h(224.0 / 3.0, 224.0 / 3.0)
|
||||||
@ -1178,6 +1215,7 @@ impl Hud {
|
|||||||
None => Windows::None,
|
None => Windows::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
Text::new("Character Name") //Add in actual Character Name
|
Text::new("Character Name") //Add in actual Character Name
|
||||||
.mid_top_with_margin_on(self.ids.charwindow_frame, 7.0)
|
.mid_top_with_margin_on(self.ids.charwindow_frame, 7.0)
|
||||||
@ -1188,6 +1226,10 @@ impl Hud {
|
|||||||
.w_h(205.0, 412.0)
|
.w_h(205.0, 412.0)
|
||||||
.mid_left_with_margin_on(self.ids.charwindow_frame, -205.0)
|
.mid_left_with_margin_on(self.ids.charwindow_frame, -205.0)
|
||||||
.set(self.ids.charwindow_tab_bg, ui_widgets);
|
.set(self.ids.charwindow_tab_bg, ui_widgets);
|
||||||
|
// Tab Rectangle
|
||||||
|
Rectangle::fill_with([192.0, 371.0], color::rgba(0.0, 0.0, 0.0, 0.8))
|
||||||
|
.top_right_with_margins_on(self.ids.charwindow_tab_bg, 20.0, 0.0)
|
||||||
|
.set(self.ids.charwindow_rectangle, ui_widgets);
|
||||||
// Tab Button
|
// 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)
|
||||||
@ -1197,25 +1239,63 @@ impl Hud {
|
|||||||
.label_font_id(self.font_opensans)
|
.label_font_id(self.font_opensans)
|
||||||
.label_font_size(14)
|
.label_font_size(14)
|
||||||
.set(self.ids.charwindow_tab1, ui_widgets);
|
.set(self.ids.charwindow_tab1, ui_widgets);
|
||||||
Text::new("1") //Add in actual Character Level later
|
Text::new("1") //Add in actual Character Level
|
||||||
.mid_top_with_margin_on(self.ids.charwindow_tab_bg, 14.0)
|
.mid_top_with_margin_on(self.ids.charwindow_rectangle, 10.0)
|
||||||
.font_id(self.font_opensans)
|
.font_id(self.font_opensans)
|
||||||
.font_size(30)
|
.font_size(30)
|
||||||
.rgba(220.0, 220.0, 220.0, 0.8)
|
.rgba(220.0, 220.0, 220.0, 0.8)
|
||||||
.set(self.ids.charwindow_tab1_level, ui_widgets);
|
.set(self.ids.charwindow_tab1_level, ui_widgets);
|
||||||
// Stats
|
// Exp-Bar Background
|
||||||
Text::new("Stat 1")
|
Rectangle::fill_with([170.0, 10.0], color::BLACK)
|
||||||
.top_left_with_margins_on(self.ids.charwindow_tab_bg, 40.0, 20.0)
|
.mid_top_with_margin_on(self.ids.charwindow_rectangle, 50.0)
|
||||||
|
.set(self.ids.charwindow_exp_rectangle, ui_widgets);
|
||||||
|
// Exp-Bar Progress
|
||||||
|
Rectangle::fill_with([170.0 * (self.xp_percentage), 6.0], color::rgb(0.31, 0.14, 0.40)) // 0.8 = Experience percantage
|
||||||
|
.mid_left_with_margin_on(self.ids.charwindow_tab1_expbar, 1.0)
|
||||||
|
.set(self.ids.charwindow_exp_progress_rectangle, ui_widgets);
|
||||||
|
// Exp-Bar Foreground Frame
|
||||||
|
Image::new(self.imgs.progress_frame)
|
||||||
|
.w_h(170.0, 10.0)
|
||||||
|
.middle_of(self.ids.charwindow_exp_rectangle)
|
||||||
|
.set(self.ids.charwindow_tab1_expbar, ui_widgets);
|
||||||
|
// Exp-Text
|
||||||
|
Text::new("120/170") // Shows the Exp / Exp to reach the next level
|
||||||
|
.mid_top_with_margin_on(self.ids.charwindow_tab1_expbar, 10.0)
|
||||||
.font_id(self.font_opensans)
|
.font_id(self.font_opensans)
|
||||||
.font_size(20)
|
.font_size(15)
|
||||||
|
.rgba(220.0, 220.0, 220.0, 0.8)
|
||||||
|
.set(self.ids.charwindow_tab1_exp, ui_widgets);
|
||||||
|
|
||||||
|
// Stats
|
||||||
|
Text::new(
|
||||||
|
"Stamina\n\
|
||||||
|
\n\
|
||||||
|
Strength\n\
|
||||||
|
\n\
|
||||||
|
Dexterity\n\
|
||||||
|
\n\
|
||||||
|
Intelligence",
|
||||||
|
)
|
||||||
|
.top_left_with_margins_on(self.ids.charwindow_rectangle, 100.0, 20.0)
|
||||||
|
.font_id(self.font_opensans)
|
||||||
|
.font_size(16)
|
||||||
|
.rgba(220.0, 220.0, 220.0, 0.8)
|
||||||
|
.set(self.ids.charwindow_tab1_statnames, ui_widgets);
|
||||||
|
|
||||||
|
Text::new(
|
||||||
|
"1234\n\
|
||||||
|
\n\
|
||||||
|
12312\n\
|
||||||
|
\n\
|
||||||
|
12414\n\
|
||||||
|
\n\
|
||||||
|
124124",
|
||||||
|
)
|
||||||
|
.right_from(self.ids.charwindow_tab1_statnames, 10.0)
|
||||||
|
.font_id(self.font_opensans)
|
||||||
|
.font_size(16)
|
||||||
.rgba(220.0, 220.0, 220.0, 0.8)
|
.rgba(220.0, 220.0, 220.0, 0.8)
|
||||||
.set(self.ids.charwindow_tab1_stats, ui_widgets);
|
.set(self.ids.charwindow_tab1_stats, ui_widgets);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//2 Map
|
//2 Map
|
||||||
@ -1372,7 +1452,7 @@ impl Hud {
|
|||||||
Some(Small::Questlog) => Windows::CharacterAnd(None),
|
Some(Small::Questlog) => Windows::CharacterAnd(None),
|
||||||
_ => Windows::CharacterAnd(Some(Small::Questlog)),
|
_ => Windows::CharacterAnd(Some(Small::Questlog)),
|
||||||
},
|
},
|
||||||
Windows::Settings => unreachable!(),
|
Windows::Settings => Windows::Settings,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn toggle_map(&mut self) {
|
pub fn toggle_map(&mut self) {
|
||||||
@ -1387,7 +1467,7 @@ impl Hud {
|
|||||||
},
|
},
|
||||||
Windows::Small(small) => Windows::CharacterAnd(Some(small)),
|
Windows::Small(small) => Windows::CharacterAnd(Some(small)),
|
||||||
Windows::None => Windows::CharacterAnd(None),
|
Windows::None => Windows::CharacterAnd(None),
|
||||||
Windows::Settings => unreachable!(),
|
Windows::Settings => Windows::Settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn toggle_social(&mut self) {
|
pub fn toggle_social(&mut self) {
|
||||||
@ -1398,7 +1478,7 @@ impl Hud {
|
|||||||
Some(Small::Social) => Windows::CharacterAnd(None),
|
Some(Small::Social) => Windows::CharacterAnd(None),
|
||||||
_ => Windows::CharacterAnd(Some(Small::Social)),
|
_ => Windows::CharacterAnd(Some(Small::Social)),
|
||||||
},
|
},
|
||||||
Windows::Settings => unreachable!(),
|
Windows::Settings => Windows::Settings,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn toggle_spellbook(&mut self) {
|
pub fn toggle_spellbook(&mut self) {
|
||||||
@ -1409,7 +1489,7 @@ impl Hud {
|
|||||||
Some(Small::Spellbook) => Windows::CharacterAnd(None),
|
Some(Small::Spellbook) => Windows::CharacterAnd(None),
|
||||||
_ => Windows::CharacterAnd(Some(Small::Spellbook)),
|
_ => Windows::CharacterAnd(Some(Small::Spellbook)),
|
||||||
},
|
},
|
||||||
Windows::Settings => unreachable!(),
|
Windows::Settings => Windows::Settings,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn toggle_settings(&mut self) {
|
pub fn toggle_settings(&mut self) {
|
||||||
|
@ -461,7 +461,6 @@ impl CharSelectionUi {
|
|||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
self.selected_char_no = Some(1);
|
self.selected_char_no = Some(1);
|
||||||
self.creation_state = CreationState::Race;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Veloren Logo and Alpha Version
|
// Veloren Logo and Alpha Version
|
||||||
|
Loading…
Reference in New Issue
Block a user