Reformat using rustfmt
This commit is contained in:
parent
ffc9ac0e47
commit
3704b9eeb8
|
@ -25,191 +25,219 @@ use render;
|
||||||
use format::{Component, TextComponent, Color};
|
use format::{Component, TextComponent, Color};
|
||||||
|
|
||||||
pub struct CVar<T: Sized + Any + 'static> {
|
pub struct CVar<T: Sized + Any + 'static> {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub ty: PhantomData<T>,
|
pub ty: PhantomData<T>,
|
||||||
pub description: &'static str,
|
pub description: &'static str,
|
||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
pub serializable: bool,
|
pub serializable: bool,
|
||||||
pub default: &'static Fn() -> T,
|
pub default: &'static Fn() -> T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Var for CVar<String> {
|
impl Var for CVar<String> {
|
||||||
fn serialize(&self, val: &Box<Any>) -> String {
|
fn serialize(&self, val: &Box<Any>) -> String {
|
||||||
format!("\"{}\"", val.downcast_ref::<String>().unwrap())
|
format!("\"{}\"", val.downcast_ref::<String>().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize(&self, input: &String) -> Box<Any> {
|
fn deserialize(&self, input: &String) -> Box<Any> {
|
||||||
Box::new((&input[1..input.len() - 1]).to_owned())
|
Box::new((&input[1..input.len() - 1]).to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn description(&self) -> &'static str { self.description }
|
fn description(&self) -> &'static str {
|
||||||
fn can_serialize(&self) -> bool { self.serializable }
|
self.description
|
||||||
|
}
|
||||||
|
fn can_serialize(&self) -> bool {
|
||||||
|
self.serializable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Var {
|
pub trait Var {
|
||||||
fn serialize(&self, val: &Box<Any>) -> String;
|
fn serialize(&self, val: &Box<Any>) -> String;
|
||||||
fn deserialize(&self, input: &String) -> Box<Any>;
|
fn deserialize(&self, input: &String) -> Box<Any>;
|
||||||
fn description(&self) -> &'static str;
|
fn description(&self) -> &'static str;
|
||||||
fn can_serialize(&self) -> bool;
|
fn can_serialize(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Console {
|
pub struct Console {
|
||||||
names: HashMap<String, &'static str>,
|
names: HashMap<String, &'static str>,
|
||||||
vars: HashMap<&'static str, Box<Var>>,
|
vars: HashMap<&'static str, Box<Var>>,
|
||||||
var_values: HashMap<&'static str, Box<Any>>,
|
var_values: HashMap<&'static str, Box<Any>>,
|
||||||
|
|
||||||
history: Vec<Component>,
|
history: Vec<Component>,
|
||||||
|
|
||||||
collection: ui::Collection,
|
collection: ui::Collection,
|
||||||
active: bool,
|
active: bool,
|
||||||
position: f64,
|
position: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Console {
|
impl Console {
|
||||||
pub fn new() -> Console {
|
pub fn new() -> Console {
|
||||||
let mut con = Console {
|
Console {
|
||||||
names: HashMap::new(),
|
names: HashMap::new(),
|
||||||
vars: HashMap::new(),
|
vars: HashMap::new(),
|
||||||
var_values: HashMap::new(),
|
var_values: HashMap::new(),
|
||||||
|
|
||||||
history: Vec::with_capacity(200),
|
history: vec![Component::Text(TextComponent::new("")); 200],
|
||||||
|
|
||||||
collection: ui::Collection::new(),
|
collection: ui::Collection::new(),
|
||||||
active: false,
|
active: false,
|
||||||
position: -220.0,
|
position: -220.0,
|
||||||
};
|
}
|
||||||
for _ in 0 .. 200 {
|
}
|
||||||
con.history.push(Component::Text(
|
|
||||||
TextComponent::new("")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
con
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register<T: Sized + Any>(&mut self, var: CVar<T>) where CVar<T> : Var {
|
pub fn register<T: Sized + Any>(&mut self, var: CVar<T>)
|
||||||
if self.vars.contains_key(var.name) {
|
where CVar<T>: Var
|
||||||
panic!("Key registered twice {}", var.name);
|
{
|
||||||
}
|
if self.vars.contains_key(var.name) {
|
||||||
self.names.insert(var.name.to_owned(), var.name);
|
panic!("Key registered twice {}", var.name);
|
||||||
self.var_values.insert(var.name, Box::new((var.default)()));
|
}
|
||||||
self.vars.insert(var.name, Box::new(var));
|
self.names.insert(var.name.to_owned(), var.name);
|
||||||
}
|
self.var_values.insert(var.name, Box::new((var.default)()));
|
||||||
|
self.vars.insert(var.name, Box::new(var));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get<T: Sized + Any>(&self, var: CVar<T>) -> &T where CVar<T> : Var {
|
pub fn get<T: Sized + Any>(&self, var: CVar<T>) -> &T
|
||||||
|
where CVar<T>: Var
|
||||||
|
{
|
||||||
// Should never fail
|
// Should never fail
|
||||||
self.var_values.get(var.name).unwrap().downcast_ref::<T>().unwrap()
|
self.var_values.get(var.name).unwrap().downcast_ref::<T>().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set<T: Sized + Any>(&mut self, var: CVar<T>, val: T) where CVar<T> : Var {
|
pub fn set<T: Sized + Any>(&mut self, var: CVar<T>, val: T)
|
||||||
self.var_values.insert(var.name, Box::new(val));
|
where CVar<T>: Var
|
||||||
self.save_config();
|
{
|
||||||
}
|
self.var_values.insert(var.name, Box::new(val));
|
||||||
|
self.save_config();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_active(&self) -> bool {
|
pub fn is_active(&self) -> bool {
|
||||||
self.active
|
self.active
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle(&mut self) {
|
pub fn toggle(&mut self) {
|
||||||
self.active = !self.active;
|
self.active = !self.active;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self, ui_container: &mut ui::Container, renderer: &mut render::Renderer, delta: f64, width: f64) {
|
pub fn tick(&mut self,
|
||||||
|
ui_container: &mut ui::Container,
|
||||||
|
renderer: &mut render::Renderer,
|
||||||
|
delta: f64,
|
||||||
|
width: f64) {
|
||||||
// To make sure the console is always on top it constant removes and readds itself.
|
// To make sure the console is always on top it constant removes and readds itself.
|
||||||
// Its hacky but the console should never appear for normal users so its not really
|
// Its hacky but the console should never appear for normal users so its not really
|
||||||
// a major issue.
|
// a major issue.
|
||||||
self.collection.remove_all(ui_container);
|
self.collection.remove_all(ui_container);
|
||||||
if !self.active && self.position <= -220.0 {
|
if !self.active && self.position <= -220.0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.active {
|
if self.active {
|
||||||
if self.position < 0.0 {
|
if self.position < 0.0 {
|
||||||
self.position += delta * 4.0;
|
self.position += delta * 4.0;
|
||||||
} else {
|
} else {
|
||||||
self.position = 0.0;
|
self.position = 0.0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if self.position > -220.0 {
|
if self.position > -220.0 {
|
||||||
self.position -= delta * 4.0;
|
self.position -= delta * 4.0;
|
||||||
} else {
|
} else {
|
||||||
self.position = -220.0;
|
self.position = -220.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let w = match ui_container.mode {
|
let w = match ui_container.mode {
|
||||||
ui::Mode::Scaled => width,
|
ui::Mode::Scaled => width,
|
||||||
ui::Mode::Unscaled(scale) => 854.0 / scale,
|
ui::Mode::Unscaled(scale) => 854.0 / scale,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut background = ui::Image::new(
|
let mut background =
|
||||||
render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"),
|
ui::Image::new(render::Renderer::get_texture(renderer.get_textures_ref(),
|
||||||
0.0, self.position, w, 220.0,
|
"steven:solid"),
|
||||||
0.0, 0.0, 1.0, 1.0,
|
0.0,
|
||||||
0, 0, 0
|
self.position,
|
||||||
);
|
w,
|
||||||
background.set_a(180);
|
220.0,
|
||||||
let background = self.collection.add(ui_container.add(background));
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
background.set_a(180);
|
||||||
|
let background = self.collection.add(ui_container.add(background));
|
||||||
|
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
let mut offset = 0.0;
|
let mut offset = 0.0;
|
||||||
for line in self.history.iter().rev() {
|
for line in self.history.iter().rev() {
|
||||||
if offset >= 210.0 {
|
if offset >= 210.0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let mut fmt = ui::Formatted::with_width_limit(renderer, line.clone(), 5.0, 5.0 + offset, w - 1.0);
|
let mut fmt = ui::Formatted::with_width_limit(renderer,
|
||||||
fmt.set_parent(&background);
|
line.clone(),
|
||||||
fmt.set_v_attach(ui::VAttach::Bottom);
|
5.0,
|
||||||
offset += fmt.get_height();
|
5.0 + offset,
|
||||||
lines.push(ui_container.add(fmt));
|
w - 1.0);
|
||||||
}
|
fmt.set_parent(&background);
|
||||||
for fmt in lines {
|
fmt.set_v_attach(ui::VAttach::Bottom);
|
||||||
self.collection.add(fmt);
|
offset += fmt.get_height();
|
||||||
}
|
lines.push(ui_container.add(fmt));
|
||||||
}
|
}
|
||||||
|
for fmt in lines {
|
||||||
|
self.collection.add(fmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_config(&mut self) {
|
pub fn load_config(&mut self) {
|
||||||
if let Ok(file) = fs::File::open("conf.cfg") {
|
if let Ok(file) = fs::File::open("conf.cfg") {
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
for line in reader.lines() {
|
for line in reader.lines() {
|
||||||
let line = line.unwrap();
|
let line = line.unwrap();
|
||||||
if line.starts_with("#") || line.is_empty() {
|
if line.starts_with("#") || line.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let parts = line.splitn(2, ' ').map(|v| v.to_owned()).collect::<Vec<String>>();
|
let parts = line.splitn(2, ' ').map(|v| v.to_owned()).collect::<Vec<String>>();
|
||||||
let (name, arg) = (&parts[0], &parts[1]);
|
let (name, arg) = (&parts[0], &parts[1]);
|
||||||
if let Some(var_name) = self.names.get(name) {
|
if let Some(var_name) = self.names.get(name) {
|
||||||
let var = self.vars.get(var_name).unwrap();
|
let var = self.vars.get(var_name).unwrap();
|
||||||
let val = var.deserialize(&arg);
|
let val = var.deserialize(&arg);
|
||||||
if var.can_serialize() {
|
if var.can_serialize() {
|
||||||
self.var_values.insert(var_name, val);
|
self.var_values.insert(var_name, val);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("Missing prop");
|
println!("Missing prop");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_config(&self) {
|
pub fn save_config(&self) {
|
||||||
let mut file = BufWriter::new(fs::File::create("conf.cfg").unwrap());
|
let mut file = BufWriter::new(fs::File::create("conf.cfg").unwrap());
|
||||||
for (name, var) in &self.vars {
|
for (name, var) in &self.vars {
|
||||||
if !var.can_serialize() {
|
if !var.can_serialize() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for line in var.description().lines() {
|
for line in var.description().lines() {
|
||||||
write!(file, "# {}\n", line).unwrap();
|
write!(file, "# {}\n", line).unwrap();
|
||||||
}
|
}
|
||||||
write!(file, "{} {}\n\n", name, var.serialize(self.var_values.get(name).unwrap())).unwrap();
|
write!(file,
|
||||||
}
|
"{} {}\n\n",
|
||||||
}
|
name,
|
||||||
|
var.serialize(self.var_values.get(name).unwrap()))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn log(&mut self, record: &log::LogRecord) {
|
fn log(&mut self, record: &log::LogRecord) {
|
||||||
let mut file = &record.location().file().replace("\\", "/")[..];
|
let mut file = &record.location().file().replace("\\", "/")[..];
|
||||||
if let Some(pos) = file.rfind("src/") {
|
if let Some(pos) = file.rfind("src/") {
|
||||||
file = &file[pos + 4..];
|
file = &file[pos + 4..];
|
||||||
}
|
}
|
||||||
println!("[{}:{}][{}] {}", file, record.location().line(), record.level(), record.args());
|
println!("[{}:{}][{}] {}",
|
||||||
self.history.remove(0);
|
file,
|
||||||
let mut msg = TextComponent::new("");
|
record.location().line(),
|
||||||
msg.modifier.extra = Some(vec![
|
record.level(),
|
||||||
|
record.args());
|
||||||
|
self.history.remove(0);
|
||||||
|
let mut msg = TextComponent::new("");
|
||||||
|
msg.modifier.extra = Some(vec![
|
||||||
Component::Text(TextComponent::new("[")),
|
Component::Text(TextComponent::new("[")),
|
||||||
{
|
{
|
||||||
let mut msg = TextComponent::new(file);
|
let mut msg = TextComponent::new(file);
|
||||||
|
@ -238,34 +266,30 @@ impl Console {
|
||||||
Component::Text(TextComponent::new("] ")),
|
Component::Text(TextComponent::new("] ")),
|
||||||
Component::Text(TextComponent::new(&format!("{}", record.args())))
|
Component::Text(TextComponent::new(&format!("{}", record.args())))
|
||||||
]);
|
]);
|
||||||
self.history.push(Component::Text(
|
self.history.push(Component::Text(msg));
|
||||||
msg
|
}
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConsoleProxy {
|
pub struct ConsoleProxy {
|
||||||
console: Arc<Mutex<Console>>,
|
console: Arc<Mutex<Console>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConsoleProxy {
|
impl ConsoleProxy {
|
||||||
pub fn new(con: Arc<Mutex<Console>>) -> ConsoleProxy {
|
pub fn new(con: Arc<Mutex<Console>>) -> ConsoleProxy {
|
||||||
ConsoleProxy {
|
ConsoleProxy { console: con }
|
||||||
console: con,
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl log::Log for ConsoleProxy {
|
impl log::Log for ConsoleProxy {
|
||||||
fn enabled(&self, metadata: &log::LogMetadata) -> bool {
|
fn enabled(&self, metadata: &log::LogMetadata) -> bool {
|
||||||
metadata.level() <= log::LogLevel::Trace
|
metadata.level() <= log::LogLevel::Trace
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&self, record: &log::LogRecord) {
|
fn log(&self, record: &log::LogRecord) {
|
||||||
if self.enabled(record.metadata()) {
|
if self.enabled(record.metadata()) {
|
||||||
self.console.lock().unwrap().log(record);
|
self.console.lock().unwrap().log(record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for ConsoleProxy {}
|
unsafe impl Send for ConsoleProxy {}
|
||||||
|
|
|
@ -18,19 +18,25 @@ use std::mem;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Component {
|
pub enum Component {
|
||||||
Text(TextComponent)
|
Text(TextComponent),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component {
|
impl Component {
|
||||||
pub fn from_value(v: &serde_json::Value) -> Self {
|
pub fn from_value(v: &serde_json::Value) -> Self {
|
||||||
let mut modifier = Modifier::from_value(v);
|
let mut modifier = Modifier::from_value(v);
|
||||||
if let Some(val) = v.as_string() {
|
if let Some(val) = v.as_string() {
|
||||||
Component::Text(TextComponent{text: val.to_owned(), modifier: modifier})
|
Component::Text(TextComponent {
|
||||||
} else if v.find("text").is_some(){
|
text: val.to_owned(),
|
||||||
|
modifier: modifier,
|
||||||
|
})
|
||||||
|
} else if v.find("text").is_some() {
|
||||||
Component::Text(TextComponent::from_value(v, modifier))
|
Component::Text(TextComponent::from_value(v, modifier))
|
||||||
} else {
|
} else {
|
||||||
modifier.color = Some(Color::RGB(255, 0, 0));
|
modifier.color = Some(Color::RGB(255, 0, 0));
|
||||||
Component::Text(TextComponent{text: "UNHANDLED".to_owned(), modifier: modifier})
|
Component::Text(TextComponent {
|
||||||
|
text: "UNHANDLED".to_owned(),
|
||||||
|
modifier: modifier,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +55,10 @@ impl fmt::Display for Component {
|
||||||
|
|
||||||
impl Default for Component {
|
impl Default for Component {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Component::Text(TextComponent{text: "".to_owned(), modifier: Default::default()})
|
Component::Text(TextComponent {
|
||||||
|
text: "".to_owned(),
|
||||||
|
modifier: Default::default(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,12 +71,10 @@ pub struct Modifier {
|
||||||
pub strikethrough: Option<bool>,
|
pub strikethrough: Option<bool>,
|
||||||
pub obfuscated: Option<bool>,
|
pub obfuscated: Option<bool>,
|
||||||
pub color: Option<Color>,
|
pub color: Option<Color>,
|
||||||
|
|
||||||
// click_event
|
|
||||||
// hover_event
|
|
||||||
// insertion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Missing events click/hover/insert
|
||||||
|
|
||||||
impl Modifier {
|
impl Modifier {
|
||||||
pub fn from_value(v: &serde_json::Value) -> Self {
|
pub fn from_value(v: &serde_json::Value) -> Self {
|
||||||
let mut m = Modifier {
|
let mut m = Modifier {
|
||||||
|
@ -76,7 +83,9 @@ impl Modifier {
|
||||||
underlined: v.find("underlined").map_or(Option::None, |v| v.as_boolean()),
|
underlined: v.find("underlined").map_or(Option::None, |v| v.as_boolean()),
|
||||||
strikethrough: v.find("strikethrough").map_or(Option::None, |v| v.as_boolean()),
|
strikethrough: v.find("strikethrough").map_or(Option::None, |v| v.as_boolean()),
|
||||||
obfuscated: v.find("obfuscated").map_or(Option::None, |v| v.as_boolean()),
|
obfuscated: v.find("obfuscated").map_or(Option::None, |v| v.as_boolean()),
|
||||||
color: v.find("color").map_or(Option::None, |v| v.as_string()).map(|v| Color::from_string(&v.to_owned())),
|
color: v.find("color")
|
||||||
|
.map_or(Option::None, |v| v.as_string())
|
||||||
|
.map(|v| Color::from_string(&v.to_owned())),
|
||||||
extra: Option::None,
|
extra: Option::None,
|
||||||
};
|
};
|
||||||
if let Some(extra) = v.find("extra") {
|
if let Some(extra) = v.find("extra") {
|
||||||
|
@ -106,9 +115,7 @@ impl TextComponent {
|
||||||
pub fn new(val: &str) -> TextComponent {
|
pub fn new(val: &str) -> TextComponent {
|
||||||
TextComponent {
|
TextComponent {
|
||||||
text: val.to_owned(),
|
text: val.to_owned(),
|
||||||
modifier: Modifier {
|
modifier: Modifier { ..Default::default() },
|
||||||
.. Default::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +161,7 @@ pub enum Color {
|
||||||
LightPurple,
|
LightPurple,
|
||||||
Yellow,
|
Yellow,
|
||||||
White,
|
White,
|
||||||
RGB(u8, u8, u8)
|
RGB(u8, u8, u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Color {
|
impl fmt::Display for Color {
|
||||||
|
@ -195,11 +202,7 @@ impl Color {
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
Err(_) => return Color::White,
|
Err(_) => return Color::White,
|
||||||
};
|
};
|
||||||
Color::RGB(
|
Color::RGB(r, g, b)
|
||||||
r,
|
|
||||||
g,
|
|
||||||
b
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
_ => Color::White,
|
_ => Color::White,
|
||||||
}
|
}
|
||||||
|
@ -229,22 +232,22 @@ impl Color {
|
||||||
|
|
||||||
pub fn to_rgb(&self) -> (u8, u8, u8) {
|
pub fn to_rgb(&self) -> (u8, u8, u8) {
|
||||||
match *self {
|
match *self {
|
||||||
Color::Black =>(0, 0, 0),
|
Color::Black => (0, 0, 0),
|
||||||
Color::DarkBlue =>(0, 0, 170),
|
Color::DarkBlue => (0, 0, 170),
|
||||||
Color::DarkGreen =>(0, 170, 0),
|
Color::DarkGreen => (0, 170, 0),
|
||||||
Color::DarkAqua =>(0, 170, 170),
|
Color::DarkAqua => (0, 170, 170),
|
||||||
Color::DarkRed =>(170, 0, 0),
|
Color::DarkRed => (170, 0, 0),
|
||||||
Color::DarkPurple =>(170, 0, 170),
|
Color::DarkPurple => (170, 0, 170),
|
||||||
Color::Gold =>(255, 170, 0),
|
Color::Gold => (255, 170, 0),
|
||||||
Color::Gray =>(170, 170, 170),
|
Color::Gray => (170, 170, 170),
|
||||||
Color::DarkGray =>(85, 85, 85),
|
Color::DarkGray => (85, 85, 85),
|
||||||
Color::Blue =>(85, 85, 255),
|
Color::Blue => (85, 85, 255),
|
||||||
Color::Green =>(85, 255, 85),
|
Color::Green => (85, 255, 85),
|
||||||
Color::Aqua =>(85, 255, 255),
|
Color::Aqua => (85, 255, 255),
|
||||||
Color::Red =>(255, 85, 85),
|
Color::Red => (255, 85, 85),
|
||||||
Color::LightPurple =>(255, 85, 255),
|
Color::LightPurple => (255, 85, 255),
|
||||||
Color::Yellow =>(255, 255, 85),
|
Color::Yellow => (255, 255, 85),
|
||||||
Color::White =>(255, 255, 255),
|
Color::White => (255, 255, 255),
|
||||||
Color::RGB(r, g, b) => (r, g, b),
|
Color::RGB(r, g, b) => (r, g, b),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,12 +267,12 @@ fn test_color_from() {
|
||||||
}
|
}
|
||||||
let test = Color::from_string(&"red".to_owned());
|
let test = Color::from_string(&"red".to_owned());
|
||||||
match test {
|
match test {
|
||||||
Color::Red => {},
|
Color::Red => {}
|
||||||
_ => panic!("Wrong type"),
|
_ => panic!("Wrong type"),
|
||||||
}
|
}
|
||||||
let test = Color::from_string(&"dark_blue".to_owned());
|
let test = Color::from_string(&"dark_blue".to_owned());
|
||||||
match test {
|
match test {
|
||||||
Color::DarkBlue => {},
|
Color::DarkBlue => {}
|
||||||
_ => panic!("Wrong type"),
|
_ => panic!("Wrong type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,10 +300,11 @@ pub fn convert_legacy(c: &mut Component) {
|
||||||
None => break,
|
None => break,
|
||||||
};
|
};
|
||||||
let color_char = next.1.to_lowercase().next().unwrap();
|
let color_char = next.1.to_lowercase().next().unwrap();
|
||||||
current.text = txt.text[last .. i].to_owned();
|
current.text = txt.text[last..i].to_owned();
|
||||||
last = next.0 + 1;
|
last = next.0 + 1;
|
||||||
|
|
||||||
let mut modifier = if (color_char >= 'a' && color_char <= 'f') || (color_char >= '0' && color_char <= '9') {
|
let mut modifier = if (color_char >= 'a' && color_char <= 'f') ||
|
||||||
|
(color_char >= '0' && color_char <= '9') {
|
||||||
Default::default()
|
Default::default()
|
||||||
} else {
|
} else {
|
||||||
current.modifier.clone()
|
current.modifier.clone()
|
||||||
|
@ -331,7 +335,7 @@ pub fn convert_legacy(c: &mut Component) {
|
||||||
'm' => modifier.strikethrough = Some(true),
|
'm' => modifier.strikethrough = Some(true),
|
||||||
'n' => modifier.underlined = Some(true),
|
'n' => modifier.underlined = Some(true),
|
||||||
'o' => modifier.italic = Some(true),
|
'o' => modifier.italic = Some(true),
|
||||||
'r' => {},
|
'r' => {}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,6 +356,6 @@ pub fn convert_legacy(c: &mut Component) {
|
||||||
}
|
}
|
||||||
txt.text = "".to_owned();
|
txt.text = "".to_owned();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
178
src/gl/mod.rs
178
src/gl/mod.rs
|
@ -48,13 +48,17 @@ pub fn draw_elements(ty: DrawType, count: usize, dty: Type, offset: usize) {
|
||||||
|
|
||||||
/// Sets the size of the viewport of this context.
|
/// Sets the size of the viewport of this context.
|
||||||
pub fn viewport(x: i32, y: i32, w: i32, h: i32) {
|
pub fn viewport(x: i32, y: i32, w: i32, h: i32) {
|
||||||
unsafe { gl::Viewport(x, y, w, h); }
|
unsafe {
|
||||||
|
gl::Viewport(x, y, w, h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the color the color buffer should be cleared to
|
/// Sets the color the color buffer should be cleared to
|
||||||
/// when Clear is called with the color flag.
|
/// when Clear is called with the color flag.
|
||||||
pub fn clear_color(r: f32, g: f32, b: f32, a: f32) {
|
pub fn clear_color(r: f32, g: f32, b: f32, a: f32) {
|
||||||
unsafe { gl::ClearColor(r, g, b, a); }
|
unsafe {
|
||||||
|
gl::ClearColor(r, g, b, a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ClearFlags is a set of flags to mark what should be cleared during
|
/// ClearFlags is a set of flags to mark what should be cleared during
|
||||||
|
@ -64,7 +68,7 @@ pub enum ClearFlags {
|
||||||
Color,
|
Color,
|
||||||
/// Marks the depth buffer to be cleared
|
/// Marks the depth buffer to be cleared
|
||||||
Depth,
|
Depth,
|
||||||
Internal(u32)
|
Internal(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClearFlags {
|
impl ClearFlags {
|
||||||
|
@ -72,7 +76,7 @@ impl ClearFlags {
|
||||||
match self {
|
match self {
|
||||||
ClearFlags::Color => gl::COLOR_BUFFER_BIT,
|
ClearFlags::Color => gl::COLOR_BUFFER_BIT,
|
||||||
ClearFlags::Depth => gl::DEPTH_BUFFER_BIT,
|
ClearFlags::Depth => gl::DEPTH_BUFFER_BIT,
|
||||||
ClearFlags::Internal(val) => val
|
ClearFlags::Internal(val) => val,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,7 +105,9 @@ pub const ALWAYS: Func = gl::ALWAYS;
|
||||||
pub const EQUAL: Func = gl::EQUAL;
|
pub const EQUAL: Func = gl::EQUAL;
|
||||||
|
|
||||||
pub fn depth_func(f: Func) {
|
pub fn depth_func(f: Func) {
|
||||||
unsafe { gl::DepthFunc(f); }
|
unsafe {
|
||||||
|
gl::DepthFunc(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flag is a setting that can be enabled or disabled on the context.
|
/// Flag is a setting that can be enabled or disabled on the context.
|
||||||
|
@ -115,18 +121,24 @@ pub const MULTISAMPLE: Flag = gl::MULTISAMPLE;
|
||||||
|
|
||||||
/// Enables the passed flag.
|
/// Enables the passed flag.
|
||||||
pub fn enable(f: Flag) {
|
pub fn enable(f: Flag) {
|
||||||
unsafe { gl::Enable(f); }
|
unsafe {
|
||||||
|
gl::Enable(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disables the passed flag.
|
/// Disables the passed flag.
|
||||||
pub fn disable(f: Flag) {
|
pub fn disable(f: Flag) {
|
||||||
unsafe { gl::Disable(f); }
|
unsafe {
|
||||||
|
gl::Disable(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the texture slot with the passed id as the
|
/// Sets the texture slot with the passed id as the
|
||||||
/// currently active one.
|
/// currently active one.
|
||||||
pub fn active_texture(id: u32) {
|
pub fn active_texture(id: u32) {
|
||||||
unsafe { gl::ActiveTexture(gl::TEXTURE0 + id); }
|
unsafe {
|
||||||
|
gl::ActiveTexture(gl::TEXTURE0 + id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Factor is used in blending
|
/// Factor is used in blending
|
||||||
|
@ -138,7 +150,9 @@ pub const ZERO_FACTOR: Factor = gl::ZERO;
|
||||||
|
|
||||||
/// Sets the factors to be used when blending.
|
/// Sets the factors to be used when blending.
|
||||||
pub fn blend_func(s_factor: Factor, d_factor: Factor) {
|
pub fn blend_func(s_factor: Factor, d_factor: Factor) {
|
||||||
unsafe { gl::BlendFunc(s_factor, d_factor); }
|
unsafe {
|
||||||
|
gl::BlendFunc(s_factor, d_factor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Face specifies a face to act on.
|
// Face specifies a face to act on.
|
||||||
|
@ -148,7 +162,9 @@ pub const FRONT: Face = gl::FRONT;
|
||||||
|
|
||||||
/// Sets the face to be culled by the gpu.
|
/// Sets the face to be culled by the gpu.
|
||||||
pub fn cull_face(face: Face) {
|
pub fn cull_face(face: Face) {
|
||||||
unsafe { gl::CullFace(face); }
|
unsafe {
|
||||||
|
gl::CullFace(face);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FaceDirection is used to specify an order of vertices, normally
|
// FaceDirection is used to specify an order of vertices, normally
|
||||||
|
@ -219,7 +235,9 @@ impl Texture {
|
||||||
// Allocates a new texture.
|
// Allocates a new texture.
|
||||||
pub fn new() -> Texture {
|
pub fn new() -> Texture {
|
||||||
let mut t = Texture(0);
|
let mut t = Texture(0);
|
||||||
unsafe { gl::GenTextures(1, &mut t.0); }
|
unsafe {
|
||||||
|
gl::GenTextures(1, &mut t.0);
|
||||||
|
}
|
||||||
t
|
t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,25 +248,75 @@ impl Texture {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_pixels(&self, target: TextureTarget, level: i32, format: TextureFormat, ty: Type, pixels: &mut [u8]) {
|
pub fn get_pixels(&self,
|
||||||
|
target: TextureTarget,
|
||||||
|
level: i32,
|
||||||
|
format: TextureFormat,
|
||||||
|
ty: Type,
|
||||||
|
pixels: &mut [u8]) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::GetTexImage(target, level, format, ty, pixels.as_mut_ptr() as *mut gl::types::GLvoid);
|
gl::GetTexImage(target,
|
||||||
|
level,
|
||||||
|
format,
|
||||||
|
ty,
|
||||||
|
pixels.as_mut_ptr() as *mut gl::types::GLvoid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn image_3d(&self, target: TextureTarget, level: i32, width: u32, height: u32, depth: u32, format: TextureFormat, ty: Type, pix: &[u8]) {
|
pub fn image_3d(&self,
|
||||||
|
target: TextureTarget,
|
||||||
|
level: i32,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
depth: u32,
|
||||||
|
format: TextureFormat,
|
||||||
|
ty: Type,
|
||||||
|
pix: &[u8]) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::TexImage3D(target, level, format as i32, width as i32, height as i32, depth as i32, 0, format, ty, pix.as_ptr() as *const gl::types::GLvoid);
|
gl::TexImage3D(target,
|
||||||
|
level,
|
||||||
|
format as i32,
|
||||||
|
width as i32,
|
||||||
|
height as i32,
|
||||||
|
depth as i32,
|
||||||
|
0,
|
||||||
|
format,
|
||||||
|
ty,
|
||||||
|
pix.as_ptr() as *const gl::types::GLvoid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_image_3d(&self, target: TextureTarget, level: i32, x: u32, y: u32, z: u32, width: u32, height: u32, depth: u32, format: TextureFormat, ty: Type, pix: &[u8]) {
|
pub fn sub_image_3d(&self,
|
||||||
|
target: TextureTarget,
|
||||||
|
level: i32,
|
||||||
|
x: u32,
|
||||||
|
y: u32,
|
||||||
|
z: u32,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
depth: u32,
|
||||||
|
format: TextureFormat,
|
||||||
|
ty: Type,
|
||||||
|
pix: &[u8]) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::TexSubImage3D(target, level, x as i32, y as i32, z as i32, width as i32, height as i32, depth as i32, format, ty, pix.as_ptr() as *const gl::types::GLvoid);
|
gl::TexSubImage3D(target,
|
||||||
|
level,
|
||||||
|
x as i32,
|
||||||
|
y as i32,
|
||||||
|
z as i32,
|
||||||
|
width as i32,
|
||||||
|
height as i32,
|
||||||
|
depth as i32,
|
||||||
|
format,
|
||||||
|
ty,
|
||||||
|
pix.as_ptr() as *const gl::types::GLvoid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_parameter(&self, target: TextureTarget, param: TextureParameter, value: TextureValue) {
|
pub fn set_parameter(&self,
|
||||||
|
target: TextureTarget,
|
||||||
|
param: TextureParameter,
|
||||||
|
value: TextureValue) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::TexParameteri(target, param, value);
|
gl::TexParameteri(target, param, value);
|
||||||
}
|
}
|
||||||
|
@ -257,7 +325,9 @@ impl Texture {
|
||||||
|
|
||||||
impl Drop for Texture {
|
impl Drop for Texture {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { gl::DeleteTextures(1, &self.0); }
|
unsafe {
|
||||||
|
gl::DeleteTextures(1, &self.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,17 +368,23 @@ impl Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uniform_location(&self, name: &str) -> Uniform {
|
pub fn uniform_location(&self, name: &str) -> Uniform {
|
||||||
Uniform(unsafe { gl::GetUniformLocation(self.0, ffi::CString::new(name).unwrap().as_ptr()) } )
|
Uniform(unsafe {
|
||||||
|
gl::GetUniformLocation(self.0, ffi::CString::new(name).unwrap().as_ptr())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attribute_location(&self, name: &str) -> Attribute {
|
pub fn attribute_location(&self, name: &str) -> Attribute {
|
||||||
Attribute(unsafe { gl::GetAttribLocation(self.0, ffi::CString::new(name).unwrap().as_ptr()) })
|
Attribute(unsafe {
|
||||||
|
gl::GetAttribLocation(self.0, ffi::CString::new(name).unwrap().as_ptr())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Program {
|
impl Drop for Program {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { gl::DeleteProgram(self.0); }
|
unsafe {
|
||||||
|
gl::DeleteProgram(self.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +397,10 @@ impl Shader {
|
||||||
|
|
||||||
pub fn set_source(&self, src: &str) {
|
pub fn set_source(&self, src: &str) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::ShaderSource(self.0, 1, &ffi::CString::new(src).unwrap().as_ptr(), ptr::null());
|
gl::ShaderSource(self.0,
|
||||||
|
1,
|
||||||
|
&ffi::CString::new(src).unwrap().as_ptr(),
|
||||||
|
ptr::null());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,8 +411,10 @@ impl Shader {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_parameter(&self, param: ShaderParameter) -> i32 {
|
pub fn get_parameter(&self, param: ShaderParameter) -> i32 {
|
||||||
let mut ret : i32 = 0;
|
let mut ret: i32 = 0;
|
||||||
unsafe { gl::GetShaderiv(self.0, param, &mut ret); }
|
unsafe {
|
||||||
|
gl::GetShaderiv(self.0, param, &mut ret);
|
||||||
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,13 +487,22 @@ impl Attribute {
|
||||||
|
|
||||||
pub fn vertex_pointer(&self, size: i32, ty: Type, normalized: bool, stride: i32, offset: i32) {
|
pub fn vertex_pointer(&self, size: i32, ty: Type, normalized: bool, stride: i32, offset: i32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::VertexAttribPointer(self.0 as u32, size, ty, normalized as u8, stride, offset as *const gl::types::GLvoid);
|
gl::VertexAttribPointer(self.0 as u32,
|
||||||
|
size,
|
||||||
|
ty,
|
||||||
|
normalized as u8,
|
||||||
|
stride,
|
||||||
|
offset as *const gl::types::GLvoid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vertex_pointer_int(&self, size: i32, ty: Type, stride: i32, offset: i32) {
|
pub fn vertex_pointer_int(&self, size: i32, ty: Type, stride: i32, offset: i32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::VertexAttribIPointer(self.0 as u32, size, ty, stride, offset as *const gl::types::GLvoid);
|
gl::VertexAttribIPointer(self.0 as u32,
|
||||||
|
size,
|
||||||
|
ty,
|
||||||
|
stride,
|
||||||
|
offset as *const gl::types::GLvoid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -426,7 +516,9 @@ impl VertexArray {
|
||||||
/// Allocates a new VertexArray.
|
/// Allocates a new VertexArray.
|
||||||
pub fn new() -> VertexArray {
|
pub fn new() -> VertexArray {
|
||||||
let mut va = VertexArray(0);
|
let mut va = VertexArray(0);
|
||||||
unsafe { gl::GenVertexArrays(1, &mut va.0); }
|
unsafe {
|
||||||
|
gl::GenVertexArrays(1, &mut va.0);
|
||||||
|
}
|
||||||
va
|
va
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,13 +526,17 @@ impl VertexArray {
|
||||||
/// means buffers/the format of the buffers etc will be bound to
|
/// means buffers/the format of the buffers etc will be bound to
|
||||||
/// this VertexArray.
|
/// this VertexArray.
|
||||||
pub fn bind(&self) {
|
pub fn bind(&self) {
|
||||||
unsafe { gl::BindVertexArray(self.0); }
|
unsafe {
|
||||||
|
gl::BindVertexArray(self.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for VertexArray {
|
impl Drop for VertexArray {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { gl::DeleteVertexArrays(1, &self.0); }
|
unsafe {
|
||||||
|
gl::DeleteVertexArrays(1, &self.0);
|
||||||
|
}
|
||||||
self.0 = 0;
|
self.0 = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -480,7 +576,9 @@ impl Buffer {
|
||||||
/// Allocates a new Buffer.
|
/// Allocates a new Buffer.
|
||||||
pub fn new() -> Buffer {
|
pub fn new() -> Buffer {
|
||||||
let mut b = Buffer(0);
|
let mut b = Buffer(0);
|
||||||
unsafe { gl::GenBuffers(1, &mut b.0); }
|
unsafe {
|
||||||
|
gl::GenBuffers(1, &mut b.0);
|
||||||
|
}
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,12 +586,17 @@ impl Buffer {
|
||||||
/// This will allow it to be the source of operations that act on a buffer
|
/// This will allow it to be the source of operations that act on a buffer
|
||||||
/// (Data, Map etc).
|
/// (Data, Map etc).
|
||||||
pub fn bind(&self, target: BufferTarget) {
|
pub fn bind(&self, target: BufferTarget) {
|
||||||
unsafe { gl::BindBuffer(target, self.0); }
|
unsafe {
|
||||||
|
gl::BindBuffer(target, self.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_data(&self, target: BufferTarget, data: &[u8], usage: BufferUsage) {
|
pub fn set_data(&self, target: BufferTarget, data: &[u8], usage: BufferUsage) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BufferData(target, data.len() as i64, data.as_ptr() as *const gl::types::GLvoid, usage);
|
gl::BufferData(target,
|
||||||
|
data.len() as i64,
|
||||||
|
data.as_ptr() as *const gl::types::GLvoid,
|
||||||
|
usage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,7 +609,10 @@ impl Buffer {
|
||||||
/// length is valid.
|
/// length is valid.
|
||||||
pub fn map(&self, target: BufferTarget, access: Access, length: usize) -> MappedBuffer {
|
pub fn map(&self, target: BufferTarget, access: Access, length: usize) -> MappedBuffer {
|
||||||
unsafe {
|
unsafe {
|
||||||
MappedBuffer{inner: Vec::from_raw_parts(gl::MapBuffer(target, access) as *mut u8, 0, length), target: target}
|
MappedBuffer {
|
||||||
|
inner: Vec::from_raw_parts(gl::MapBuffer(target, access) as *mut u8, 0, length),
|
||||||
|
target: target,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -540,7 +646,9 @@ impl DerefMut for MappedBuffer {
|
||||||
|
|
||||||
impl Drop for MappedBuffer {
|
impl Drop for MappedBuffer {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { gl::UnmapBuffer(self.target); }
|
unsafe {
|
||||||
|
gl::UnmapBuffer(self.target);
|
||||||
|
}
|
||||||
mem::forget(mem::replace(&mut self.inner, Vec::new()));
|
mem::forget(mem::replace(&mut self.inner, Vec::new()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use nbt;
|
use nbt;
|
||||||
use protocol::{Serializable};
|
use protocol::Serializable;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
||||||
|
@ -44,7 +44,7 @@ impl Serializable for Option<Stack> {
|
||||||
if id == -1 {
|
if id == -1 {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
Ok(Some(Stack{
|
Ok(Some(Stack {
|
||||||
id: id as isize,
|
id: id as isize,
|
||||||
count: try!(buf.read_u8()) as isize,
|
count: try!(buf.read_u8()) as isize,
|
||||||
damage: try!(buf.read_i16::<BigEndian>()) as isize,
|
damage: try!(buf.read_i16::<BigEndian>()) as isize,
|
||||||
|
@ -58,7 +58,7 @@ impl Serializable for Option<Stack> {
|
||||||
try!(buf.write_u8(val.count as u8));
|
try!(buf.write_u8(val.count as u8));
|
||||||
try!(buf.write_i16::<BigEndian>(val.damage as i16));
|
try!(buf.write_i16::<BigEndian>(val.damage as i16));
|
||||||
try!(val.tag.write_to(buf));
|
try!(val.tag.write_to(buf));
|
||||||
},
|
}
|
||||||
None => try!(buf.write_i16::<BigEndian>(-1)),
|
None => try!(buf.write_i16::<BigEndian>(-1)),
|
||||||
}
|
}
|
||||||
Result::Ok(())
|
Result::Ok(())
|
||||||
|
|
59
src/main.rs
59
src/main.rs
|
@ -44,8 +44,8 @@ use std::marker::PhantomData;
|
||||||
const CL_BRAND: console::CVar<String> = console::CVar {
|
const CL_BRAND: console::CVar<String> = console::CVar {
|
||||||
ty: PhantomData,
|
ty: PhantomData,
|
||||||
name: "cl_brand",
|
name: "cl_brand",
|
||||||
description: "cl_brand has the value of the clients current 'brand'. \
|
description: "cl_brand has the value of the clients current 'brand'. e.g. \"Steven\" or \
|
||||||
e.g. \"Steven\" or \"Vanilla\"",
|
\"Vanilla\"",
|
||||||
mutable: false,
|
mutable: false,
|
||||||
serializable: false,
|
serializable: false,
|
||||||
default: &|| "steven".to_owned(),
|
default: &|| "steven".to_owned(),
|
||||||
|
@ -74,22 +74,27 @@ fn main() {
|
||||||
log::set_logger(|max_log_level| {
|
log::set_logger(|max_log_level| {
|
||||||
max_log_level.set(log::LogLevelFilter::Trace);
|
max_log_level.set(log::LogLevelFilter::Trace);
|
||||||
Box::new(proxy)
|
Box::new(proxy)
|
||||||
}).unwrap();
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
info!("Starting steven");
|
info!("Starting steven");
|
||||||
|
|
||||||
let resource_manager = Arc::new(RwLock::new(resources::Manager::new()));
|
let resource_manager = Arc::new(RwLock::new(resources::Manager::new()));
|
||||||
{ resource_manager.write().unwrap().tick(); }
|
{
|
||||||
|
resource_manager.write().unwrap().tick();
|
||||||
|
}
|
||||||
|
|
||||||
let mut window = glutin::WindowBuilder::new()
|
let mut window = glutin::WindowBuilder::new()
|
||||||
.with_title("Steven".to_string())
|
.with_title("Steven".to_string())
|
||||||
.with_dimensions(854, 480)
|
.with_dimensions(854, 480)
|
||||||
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
|
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
|
||||||
.with_gl_profile(glutin::GlProfile::Core)
|
.with_gl_profile(glutin::GlProfile::Core)
|
||||||
.with_depth_buffer(24)
|
.with_depth_buffer(24)
|
||||||
.with_stencil_buffer(0)
|
.with_stencil_buffer(0)
|
||||||
.with_vsync()
|
.with_vsync()
|
||||||
.build().ok().expect("Could not create Glutin window.");
|
.build()
|
||||||
|
.ok()
|
||||||
|
.expect("Could not create Glutin window.");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
window.make_current().ok().expect("Could not set current context.");
|
window.make_current().ok().expect("Could not set current context.");
|
||||||
|
@ -116,7 +121,9 @@ fn main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
while !game.should_close {
|
while !game.should_close {
|
||||||
{ game.resource_manager.write().unwrap().tick(); }
|
{
|
||||||
|
game.resource_manager.write().unwrap().tick();
|
||||||
|
}
|
||||||
|
|
||||||
let now = time::now();
|
let now = time::now();
|
||||||
let diff = now - last_frame;
|
let diff = now - last_frame;
|
||||||
|
@ -125,7 +132,10 @@ fn main() {
|
||||||
let (width, height) = window.get_inner_size_pixels().unwrap();
|
let (width, height) = window.get_inner_size_pixels().unwrap();
|
||||||
|
|
||||||
game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container);
|
game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container);
|
||||||
game.console.lock().unwrap().tick(&mut ui_container, &mut game.renderer, delta, width as f64);
|
game.console
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.tick(&mut ui_container, &mut game.renderer, delta, width as f64);
|
||||||
ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
|
ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
|
||||||
game.renderer.tick(delta, width, height);
|
game.renderer.tick(delta, width, height);
|
||||||
|
|
||||||
|
@ -137,7 +147,10 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_window_event(window: &glutin::Window, game: &mut Game, ui_container: &mut ui::Container, event: glutin::Event) {
|
fn handle_window_event(window: &glutin::Window,
|
||||||
|
game: &mut Game,
|
||||||
|
ui_container: &mut ui::Container,
|
||||||
|
event: glutin::Event) {
|
||||||
use glutin::{Event, VirtualKeyCode};
|
use glutin::{Event, VirtualKeyCode};
|
||||||
match event {
|
match event {
|
||||||
Event::Closed => game.should_close = true,
|
Event::Closed => game.should_close = true,
|
||||||
|
@ -147,34 +160,34 @@ fn handle_window_event(window: &glutin::Window, game: &mut Game, ui_container: &
|
||||||
let (width, height) = window.get_inner_size_pixels().unwrap();
|
let (width, height) = window.get_inner_size_pixels().unwrap();
|
||||||
|
|
||||||
ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64);
|
ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64);
|
||||||
},
|
}
|
||||||
|
|
||||||
Event::MouseInput(glutin::ElementState::Released, glutin::MouseButton::Left) => {
|
Event::MouseInput(glutin::ElementState::Released, glutin::MouseButton::Left) => {
|
||||||
let (x, y) = game.mouse_pos;
|
let (x, y) = game.mouse_pos;
|
||||||
let (width, height) = window.get_inner_size_pixels().unwrap();
|
let (width, height) = window.get_inner_size_pixels().unwrap();
|
||||||
|
|
||||||
ui_container.click_at(game, x as f64, y as f64, width as f64, height as f64);
|
ui_container.click_at(game, x as f64, y as f64, width as f64, height as f64);
|
||||||
},
|
}
|
||||||
|
|
||||||
Event::MouseWheel(delta) => {
|
Event::MouseWheel(delta) => {
|
||||||
let (x, y) = match delta {
|
let (x, y) = match delta {
|
||||||
glutin::MouseScrollDelta::LineDelta(x, y) => (x, y),
|
glutin::MouseScrollDelta::LineDelta(x, y) => (x, y),
|
||||||
glutin::MouseScrollDelta::PixelDelta(x, y) => (x, y)
|
glutin::MouseScrollDelta::PixelDelta(x, y) => (x, y),
|
||||||
};
|
};
|
||||||
|
|
||||||
game.screen_sys.on_scroll(x as f64, y as f64);
|
game.screen_sys.on_scroll(x as f64, y as f64);
|
||||||
},
|
}
|
||||||
|
|
||||||
Event::KeyboardInput(glutin::ElementState::Pressed, 41 /* ` GRAVE */, _) => {
|
Event::KeyboardInput(glutin::ElementState::Pressed, 41 /* ` GRAVE */, _) => {
|
||||||
game.console.lock().unwrap().toggle();
|
game.console.lock().unwrap().toggle();
|
||||||
},
|
}
|
||||||
Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(VirtualKeyCode::Grave)) => {
|
Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(VirtualKeyCode::Grave)) => {
|
||||||
game.console.lock().unwrap().toggle();
|
game.console.lock().unwrap().toggle();
|
||||||
},
|
}
|
||||||
Event::KeyboardInput(glutin::ElementState::Pressed, key, virt) => {
|
Event::KeyboardInput(glutin::ElementState::Pressed, key, virt) => {
|
||||||
println!("Key: {:?} {:?}", key, virt);
|
println!("Key: {:?} {:?}", key, virt);
|
||||||
},
|
}
|
||||||
|
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
123
src/nbt/mod.rs
123
src/nbt/mod.rs
|
@ -16,7 +16,7 @@ use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
use super::protocol::{Serializable};
|
use super::protocol::Serializable;
|
||||||
use super::protocol;
|
use super::protocol;
|
||||||
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
||||||
|
|
||||||
|
@ -173,52 +173,53 @@ impl Tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_type(id: u8, buf: &mut io::Read) -> Result<Tag, io::Error> {
|
fn read_type(id: u8, buf: &mut io::Read) -> Result<Tag, io::Error> {
|
||||||
match id {
|
match id {
|
||||||
0 => unreachable!(),
|
0 => unreachable!(),
|
||||||
1 => Ok(Tag::Byte(try!(buf.read_i8()))),
|
1 => Ok(Tag::Byte(try!(buf.read_i8()))),
|
||||||
2 => Ok(Tag::Short(try!(buf.read_i16::<BigEndian>()))),
|
2 => Ok(Tag::Short(try!(buf.read_i16::<BigEndian>()))),
|
||||||
3 => Ok(Tag::Int(try!(buf.read_i32::<BigEndian>()))),
|
3 => Ok(Tag::Int(try!(buf.read_i32::<BigEndian>()))),
|
||||||
4 => Ok(Tag::Long(try!(buf.read_i64::<BigEndian>()))),
|
4 => Ok(Tag::Long(try!(buf.read_i64::<BigEndian>()))),
|
||||||
5 => Ok(Tag::Float(try!(buf.read_f32::<BigEndian>()))),
|
5 => Ok(Tag::Float(try!(buf.read_f32::<BigEndian>()))),
|
||||||
6 => Ok(Tag::Double(try!(buf.read_f64::<BigEndian>()))),
|
6 => Ok(Tag::Double(try!(buf.read_f64::<BigEndian>()))),
|
||||||
7 => Ok(Tag::ByteArray({
|
7 => Ok(Tag::ByteArray({
|
||||||
let len : i32 = try!(Serializable::read_from(buf));
|
let len: i32 = try!(Serializable::read_from(buf));
|
||||||
let mut data = Vec::with_capacity(len as usize);
|
let mut data = Vec::with_capacity(len as usize);
|
||||||
try!(buf.take(len as u64).read_to_end(&mut data));
|
try!(buf.take(len as u64).read_to_end(&mut data));
|
||||||
data
|
data
|
||||||
})),
|
})),
|
||||||
8 => Ok(Tag::String(try!(read_string(buf)))),
|
8 => Ok(Tag::String(try!(read_string(buf)))),
|
||||||
9 => {
|
9 => {
|
||||||
let mut l = Vec::new();
|
let mut l = Vec::new();
|
||||||
let ty = try!(buf.read_u8());
|
let ty = try!(buf.read_u8());
|
||||||
let len : i32 = try!(Serializable::read_from(buf));
|
let len: i32 = try!(Serializable::read_from(buf));
|
||||||
for _ in 0 .. len {
|
for _ in 0..len {
|
||||||
l.push(try!(Tag::read_type(ty, buf)));
|
l.push(try!(Tag::read_type(ty, buf)));
|
||||||
}
|
}
|
||||||
Ok(Tag::List(l))
|
Ok(Tag::List(l))
|
||||||
},
|
|
||||||
10 => {
|
|
||||||
let mut c = Tag::new_compound();
|
|
||||||
loop {
|
|
||||||
let ty = try!(buf.read_u8());
|
|
||||||
if ty == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let name: String = try!(read_string(buf));
|
|
||||||
c.put(&name[..], try!(Tag::read_type(ty, buf)));
|
|
||||||
}
|
|
||||||
Ok(c)
|
|
||||||
},
|
|
||||||
11 => Ok(Tag::IntArray({
|
|
||||||
let len : i32 = try!(Serializable::read_from(buf));
|
|
||||||
let mut data = Vec::with_capacity(len as usize);
|
|
||||||
for _ in 0 .. len {
|
|
||||||
data.push(try!(buf.read_i32::<BigEndian>()));
|
|
||||||
}
|
|
||||||
data
|
|
||||||
})),
|
|
||||||
_ => Err(io::Error::new(io::ErrorKind::InvalidData, protocol::Error::Err("invalid tag".to_owned()))),
|
|
||||||
}
|
}
|
||||||
|
10 => {
|
||||||
|
let mut c = Tag::new_compound();
|
||||||
|
loop {
|
||||||
|
let ty = try!(buf.read_u8());
|
||||||
|
if ty == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let name: String = try!(read_string(buf));
|
||||||
|
c.put(&name[..], try!(Tag::read_type(ty, buf)));
|
||||||
|
}
|
||||||
|
Ok(c)
|
||||||
|
}
|
||||||
|
11 => Ok(Tag::IntArray({
|
||||||
|
let len: i32 = try!(Serializable::read_from(buf));
|
||||||
|
let mut data = Vec::with_capacity(len as usize);
|
||||||
|
for _ in 0..len {
|
||||||
|
data.push(try!(buf.read_i32::<BigEndian>()));
|
||||||
|
}
|
||||||
|
data
|
||||||
|
})),
|
||||||
|
_ => Err(io::Error::new(io::ErrorKind::InvalidData,
|
||||||
|
protocol::Error::Err("invalid tag".to_owned()))),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +230,7 @@ impl Serializable for Tag {
|
||||||
|
|
||||||
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
||||||
match *self {
|
match *self {
|
||||||
Tag::End => {},
|
Tag::End => {}
|
||||||
Tag::Byte(val) => try!(buf.write_i8(val)),
|
Tag::Byte(val) => try!(buf.write_i8(val)),
|
||||||
Tag::Short(val) => try!(buf.write_i16::<BigEndian>(val)),
|
Tag::Short(val) => try!(buf.write_i16::<BigEndian>(val)),
|
||||||
Tag::Int(val) => try!(buf.write_i32::<BigEndian>(val)),
|
Tag::Int(val) => try!(buf.write_i32::<BigEndian>(val)),
|
||||||
|
@ -239,20 +240,20 @@ impl Serializable for Tag {
|
||||||
Tag::ByteArray(ref val) => {
|
Tag::ByteArray(ref val) => {
|
||||||
try!((val.len() as i32).write_to(buf));
|
try!((val.len() as i32).write_to(buf));
|
||||||
try!(buf.write_all(val));
|
try!(buf.write_all(val));
|
||||||
},
|
}
|
||||||
Tag::String(ref val) => try!(write_string(buf, val)),
|
Tag::String(ref val) => try!(write_string(buf, val)),
|
||||||
Tag::List(ref val) => {
|
Tag::List(ref val) => {
|
||||||
if val.is_empty() {
|
if val.is_empty() {
|
||||||
try!(buf.write_u8(0));
|
try!(buf.write_u8(0));
|
||||||
try!(buf.write_i32::<BigEndian>(0));
|
try!(buf.write_i32::<BigEndian>(0));
|
||||||
} else {
|
} else {
|
||||||
try!(buf.write_u8(val[0].internal_id()));
|
try!(buf.write_u8(val[0].internal_id()));
|
||||||
try!(buf.write_i32::<BigEndian>(val.len() as i32));
|
try!(buf.write_i32::<BigEndian>(val.len() as i32));
|
||||||
for e in val {
|
for e in val {
|
||||||
try!(e.write_to(buf));
|
try!(e.write_to(buf));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Tag::Compound(ref val) => {
|
Tag::Compound(ref val) => {
|
||||||
for (k, v) in val {
|
for (k, v) in val {
|
||||||
try!(v.internal_id().write_to(buf));
|
try!(v.internal_id().write_to(buf));
|
||||||
|
@ -260,19 +261,19 @@ impl Serializable for Tag {
|
||||||
try!(v.write_to(buf));
|
try!(v.write_to(buf));
|
||||||
}
|
}
|
||||||
try!(buf.write_u8(0));
|
try!(buf.write_u8(0));
|
||||||
},
|
}
|
||||||
Tag::IntArray(ref val) => {
|
Tag::IntArray(ref val) => {
|
||||||
try!((val.len() as i32).write_to(buf));
|
try!((val.len() as i32).write_to(buf));
|
||||||
for v in val {
|
for v in val {
|
||||||
try!(v.write_to(buf));
|
try!(v.write_to(buf));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
Result::Ok(())
|
Result::Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_string(buf: &mut io::Write, s: &String)-> io::Result<()> {
|
pub fn write_string(buf: &mut io::Write, s: &String) -> io::Result<()> {
|
||||||
let data = s.as_bytes();
|
let data = s.as_bytes();
|
||||||
try!((data.len() as i16).write_to(buf));
|
try!((data.len() as i16).write_to(buf));
|
||||||
buf.write_all(data)
|
buf.write_all(data)
|
||||||
|
|
|
@ -139,7 +139,7 @@ pub trait Serializable: Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serializable for Vec<u8> {
|
impl Serializable for Vec<u8> {
|
||||||
fn read_from(buf: &mut io::Read) -> Result<Vec<u8> , io::Error> {
|
fn read_from(buf: &mut io::Read) -> Result<Vec<u8>, io::Error> {
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
try!(buf.read_to_end(&mut v));
|
try!(buf.read_to_end(&mut v));
|
||||||
Ok(v)
|
Ok(v)
|
||||||
|
@ -206,7 +206,7 @@ impl Serializable for format::Component {
|
||||||
let len = try!(VarInt::read_from(buf)).0;
|
let len = try!(VarInt::read_from(buf)).0;
|
||||||
let mut ret = String::new();
|
let mut ret = String::new();
|
||||||
try!(buf.take(len as u64).read_to_string(&mut ret));
|
try!(buf.take(len as u64).read_to_string(&mut ret));
|
||||||
let val : serde_json::Value = serde_json::from_str(&ret[..]).unwrap();
|
let val: serde_json::Value = serde_json::from_str(&ret[..]).unwrap();
|
||||||
Result::Ok(Self::from_value(&val))
|
Result::Ok(Self::from_value(&val))
|
||||||
}
|
}
|
||||||
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
||||||
|
@ -232,7 +232,11 @@ impl Serializable for bool {
|
||||||
Result::Ok(try!(buf.read_u8()) != 0)
|
Result::Ok(try!(buf.read_u8()) != 0)
|
||||||
}
|
}
|
||||||
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
||||||
try!(buf.write_u8(if *self { 1 } else { 0 }));
|
try!(buf.write_u8(if *self {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}));
|
||||||
Result::Ok(())
|
Result::Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,17 +325,15 @@ impl Serializable for f64 {
|
||||||
pub struct UUID(u64, u64);
|
pub struct UUID(u64, u64);
|
||||||
|
|
||||||
impl Default for UUID {
|
impl Default for UUID {
|
||||||
fn default() -> Self { UUID(0, 0) }
|
fn default() -> Self {
|
||||||
|
UUID(0, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serializable for UUID {
|
impl Serializable for UUID {
|
||||||
fn read_from(buf: &mut io::Read) -> Result<UUID, io::Error> {
|
fn read_from(buf: &mut io::Read) -> Result<UUID, io::Error> {
|
||||||
Result::Ok(
|
Result::Ok(UUID(try!(buf.read_u64::<BigEndian>()),
|
||||||
UUID(
|
try!(buf.read_u64::<BigEndian>())))
|
||||||
try!(buf.read_u64::<BigEndian>()),
|
|
||||||
try!(buf.read_u64::<BigEndian>()),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
||||||
try!(buf.write_u64::<BigEndian>(self.0));
|
try!(buf.write_u64::<BigEndian>(self.0));
|
||||||
|
@ -348,7 +350,7 @@ pub trait Lengthable : Serializable + Copy + Default {
|
||||||
|
|
||||||
pub struct LenPrefixed<L: Lengthable, V> {
|
pub struct LenPrefixed<L: Lengthable, V> {
|
||||||
len: L,
|
len: L,
|
||||||
pub data: Vec<V>
|
pub data: Vec<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <L: Lengthable, V: Default> LenPrefixed<L, V> {
|
impl <L: Lengthable, V: Default> LenPrefixed<L, V> {
|
||||||
|
@ -362,17 +364,20 @@ impl <L: Lengthable, V: Default> LenPrefixed<L, V> {
|
||||||
|
|
||||||
impl <L: Lengthable, V: Serializable> Serializable for LenPrefixed<L, V> {
|
impl <L: Lengthable, V: Serializable> Serializable for LenPrefixed<L, V> {
|
||||||
fn read_from(buf: &mut io::Read) -> Result<LenPrefixed<L, V>, io::Error> {
|
fn read_from(buf: &mut io::Read) -> Result<LenPrefixed<L, V>, io::Error> {
|
||||||
let len_data : L = try!(Serializable::read_from(buf));
|
let len_data: L = try!(Serializable::read_from(buf));
|
||||||
let len : usize = len_data.into();
|
let len: usize = len_data.into();
|
||||||
let mut data : Vec<V> = Vec::with_capacity(len);
|
let mut data: Vec<V> = Vec::with_capacity(len);
|
||||||
for _ in 0 .. len {
|
for _ in 0..len {
|
||||||
data.push(try!(Serializable::read_from(buf)));
|
data.push(try!(Serializable::read_from(buf)));
|
||||||
}
|
}
|
||||||
Result::Ok(LenPrefixed{len: len_data, data: data})
|
Result::Ok(LenPrefixed {
|
||||||
|
len: len_data,
|
||||||
|
data: data,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
||||||
let len_data : L = L::from(self.data.len());
|
let len_data: L = L::from(self.data.len());
|
||||||
try!(len_data.write_to(buf));
|
try!(len_data.write_to(buf));
|
||||||
let data = &self.data;
|
let data = &self.data;
|
||||||
for val in data {
|
for val in data {
|
||||||
|
@ -387,7 +392,7 @@ impl <L: Lengthable, V: Default> Default for LenPrefixed<L, V> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
LenPrefixed {
|
LenPrefixed {
|
||||||
len: default::Default::default(),
|
len: default::Default::default(),
|
||||||
data: default::Default::default()
|
data: default::Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -401,7 +406,7 @@ impl <L: Lengthable, V: fmt::Debug> fmt::Debug for LenPrefixed<L, V> {
|
||||||
// Optimization
|
// Optimization
|
||||||
pub struct LenPrefixedBytes<L: Lengthable> {
|
pub struct LenPrefixedBytes<L: Lengthable> {
|
||||||
len: L,
|
len: L,
|
||||||
pub data: Vec<u8>
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <L: Lengthable> LenPrefixedBytes<L> {
|
impl <L: Lengthable> LenPrefixedBytes<L> {
|
||||||
|
@ -415,15 +420,18 @@ impl <L: Lengthable> LenPrefixedBytes<L> {
|
||||||
|
|
||||||
impl <L: Lengthable> Serializable for LenPrefixedBytes<L> {
|
impl <L: Lengthable> Serializable for LenPrefixedBytes<L> {
|
||||||
fn read_from(buf: &mut io::Read) -> Result<LenPrefixedBytes<L>, io::Error> {
|
fn read_from(buf: &mut io::Read) -> Result<LenPrefixedBytes<L>, io::Error> {
|
||||||
let len_data : L = try!(Serializable::read_from(buf));
|
let len_data: L = try!(Serializable::read_from(buf));
|
||||||
let len : usize = len_data.into();
|
let len: usize = len_data.into();
|
||||||
let mut data : Vec<u8> = Vec::with_capacity(len);
|
let mut data: Vec<u8> = Vec::with_capacity(len);
|
||||||
try!(buf.take(len as u64).read_to_end(&mut data));
|
try!(buf.take(len as u64).read_to_end(&mut data));
|
||||||
Result::Ok(LenPrefixedBytes{len: len_data, data: data})
|
Result::Ok(LenPrefixedBytes {
|
||||||
|
len: len_data,
|
||||||
|
data: data,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
||||||
let len_data : L = L::from(self.data.len());
|
let len_data: L = L::from(self.data.len());
|
||||||
try!(len_data.write_to(buf));
|
try!(len_data.write_to(buf));
|
||||||
try!(buf.write_all(&self.data[..]));
|
try!(buf.write_all(&self.data[..]));
|
||||||
Result::Ok(())
|
Result::Ok(())
|
||||||
|
@ -435,7 +443,7 @@ impl <L: Lengthable> Default for LenPrefixedBytes<L> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
LenPrefixedBytes {
|
LenPrefixedBytes {
|
||||||
len: default::Default::default(),
|
len: default::Default::default(),
|
||||||
data: default::Default::default()
|
data: default::Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -490,9 +498,10 @@ impl Serializable for VarInt {
|
||||||
loop {
|
loop {
|
||||||
let b = try!(buf.read_u8()) as u32;
|
let b = try!(buf.read_u8()) as u32;
|
||||||
val |= (b & PART) << (size * 7);
|
val |= (b & PART) << (size * 7);
|
||||||
size+=1;
|
size += 1;
|
||||||
if size > 5 {
|
if size > 5 {
|
||||||
return Result::Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Err("VarInt too big".to_owned())))
|
return Result::Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||||
|
Error::Err("VarInt too big".to_owned())))
|
||||||
}
|
}
|
||||||
if (b & 0x80) == 0 {
|
if (b & 0x80) == 0 {
|
||||||
break
|
break
|
||||||
|
@ -518,7 +527,9 @@ impl Serializable for VarInt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl default::Default for VarInt {
|
impl default::Default for VarInt {
|
||||||
fn default() -> VarInt { VarInt(0) }
|
fn default() -> VarInt {
|
||||||
|
VarInt(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for VarInt {
|
impl fmt::Debug for VarInt {
|
||||||
|
@ -551,9 +562,10 @@ impl Serializable for VarLong {
|
||||||
loop {
|
loop {
|
||||||
let b = try!(buf.read_u8()) as u64;
|
let b = try!(buf.read_u8()) as u64;
|
||||||
val |= (b & PART) << (size * 7);
|
val |= (b & PART) << (size * 7);
|
||||||
size+=1;
|
size += 1;
|
||||||
if size > 10 {
|
if size > 10 {
|
||||||
return Result::Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Err("VarLong too big".to_owned())))
|
return Result::Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||||
|
Error::Err("VarLong too big".to_owned())))
|
||||||
}
|
}
|
||||||
if (b & 0x80) == 0 {
|
if (b & 0x80) == 0 {
|
||||||
break
|
break
|
||||||
|
@ -579,7 +591,9 @@ impl Serializable for VarLong {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl default::Default for VarLong {
|
impl default::Default for VarLong {
|
||||||
fn default() -> VarLong { VarLong(0) }
|
fn default() -> VarLong {
|
||||||
|
VarLong(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for VarLong {
|
impl fmt::Debug for VarLong {
|
||||||
|
@ -593,7 +607,7 @@ impl fmt::Debug for VarLong {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Serverbound,
|
Serverbound,
|
||||||
Clientbound
|
Clientbound,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The protocol has multiple 'sub-protocols' or states which control which
|
/// The protocol has multiple 'sub-protocols' or states which control which
|
||||||
|
@ -603,7 +617,7 @@ pub enum State {
|
||||||
Handshaking,
|
Handshaking,
|
||||||
Play,
|
Play,
|
||||||
Status,
|
Status,
|
||||||
Login
|
Login,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return for any protocol related error.
|
/// Return for any protocol related error.
|
||||||
|
@ -614,7 +628,7 @@ pub enum Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl convert::From<io::Error> for Error {
|
impl convert::From<io::Error> for Error {
|
||||||
fn from(e : io::Error) -> Error {
|
fn from(e: io::Error) -> Error {
|
||||||
Error::IOError(e)
|
Error::IOError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -629,10 +643,10 @@ impl ::std::error::Error for Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::fmt::Display for Error {
|
impl ::std::fmt::Display for Error {
|
||||||
fn fmt(&self, f : &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Err(ref val) => write!(f, "protocol error: {}", val),
|
Error::Err(ref val) => write!(f, "protocol error: {}", val),
|
||||||
Error::IOError(ref e) => e.fmt(f)
|
Error::IOError(ref e) => e.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -647,12 +661,12 @@ pub struct Conn {
|
||||||
cipher: Option<openssl::EVPCipher>,
|
cipher: Option<openssl::EVPCipher>,
|
||||||
|
|
||||||
compression_threshold: i32,
|
compression_threshold: i32,
|
||||||
compression_read: Option<ZlibDecoder<io::Cursor<Vec<u8>>>>,
|
compression_read: Option<ZlibDecoder<io::Cursor<Vec<u8>>>>,
|
||||||
compression_write: Option<ZlibEncoder<io::Cursor<Vec<u8>>>>,
|
compression_write: Option<ZlibEncoder<io::Cursor<Vec<u8>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Conn {
|
impl Conn {
|
||||||
pub fn new(target: &str) -> Result<Conn, Error>{
|
pub fn new(target: &str) -> Result<Conn, Error> {
|
||||||
// TODO SRV record support
|
// TODO SRV record support
|
||||||
let mut parts = target.split(":").collect::<Vec<&str>>();
|
let mut parts = target.split(":").collect::<Vec<&str>>();
|
||||||
let address = if parts.len() == 1 {
|
let address = if parts.len() == 1 {
|
||||||
|
@ -680,7 +694,11 @@ impl Conn {
|
||||||
try!(VarInt(packet.packet_id()).write_to(&mut buf));
|
try!(VarInt(packet.packet_id()).write_to(&mut buf));
|
||||||
try!(packet.write(&mut buf));
|
try!(packet.write(&mut buf));
|
||||||
|
|
||||||
let mut extra = if self.compression_threshold >= 0 { 1 } else { 0 };
|
let mut extra = if self.compression_threshold >= 0 {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
if self.compression_threshold >= 0 && buf.len() as i32 > self.compression_threshold {
|
if self.compression_threshold >= 0 && buf.len() as i32 > self.compression_threshold {
|
||||||
extra = 0;
|
extra = 0;
|
||||||
let uncompressed_size = buf.len();
|
let uncompressed_size = buf.len();
|
||||||
|
@ -734,11 +752,14 @@ impl Conn {
|
||||||
let pos = buf.position() as usize;
|
let pos = buf.position() as usize;
|
||||||
let ibuf = buf.into_inner();
|
let ibuf = buf.into_inner();
|
||||||
if ibuf.len() != pos {
|
if ibuf.len() != pos {
|
||||||
return Result::Err(Error::Err(format!("Failed to read all of packet 0x{:X}, had {} bytes left", id, ibuf.len() - pos)))
|
return Result::Err(Error::Err(format!("Failed to read all of packet 0x{:X}, \
|
||||||
|
had {} bytes left",
|
||||||
|
id,
|
||||||
|
ibuf.len() - pos)))
|
||||||
}
|
}
|
||||||
Result::Ok(val)
|
Result::Ok(val)
|
||||||
},
|
}
|
||||||
None => Result::Err(Error::Err("missing packet".to_owned()))
|
None => Result::Err(Error::Err("missing packet".to_owned())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -749,28 +770,29 @@ impl Conn {
|
||||||
pub fn set_compresssion(&mut self, threshold: i32, read: bool) {
|
pub fn set_compresssion(&mut self, threshold: i32, read: bool) {
|
||||||
self.compression_threshold = threshold;
|
self.compression_threshold = threshold;
|
||||||
if !read {
|
if !read {
|
||||||
self.compression_write = Some(ZlibEncoder::new(io::Cursor::new(Vec::new()), flate2::Compression::Default));
|
self.compression_write = Some(ZlibEncoder::new(io::Cursor::new(Vec::new()),
|
||||||
|
flate2::Compression::Default));
|
||||||
} else {
|
} else {
|
||||||
self.compression_read = Some(ZlibDecoder::new(io::Cursor::new(Vec::new())));
|
self.compression_read = Some(ZlibDecoder::new(io::Cursor::new(Vec::new())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_status(mut self) -> Result<(Status, time::Duration), Error>{
|
pub fn do_status(mut self) -> Result<(Status, time::Duration), Error> {
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use self::packet::status::serverbound::*;
|
use self::packet::status::serverbound::*;
|
||||||
use self::packet::handshake::serverbound::*;
|
use self::packet::handshake::serverbound::*;
|
||||||
use self::packet::Packet;
|
use self::packet::Packet;
|
||||||
let host = self.host.clone();
|
let host = self.host.clone();
|
||||||
let port = self.port;
|
let port = self.port;
|
||||||
try!(self.write_packet(Handshake{
|
try!(self.write_packet(Handshake {
|
||||||
protocol_version: VarInt(SUPPORTED_PROTOCOL),
|
protocol_version: VarInt(SUPPORTED_PROTOCOL),
|
||||||
host: host,
|
host: host,
|
||||||
port: port,
|
port: port,
|
||||||
next: VarInt(1),
|
next: VarInt(1),
|
||||||
}));
|
}));
|
||||||
self.state = State::Status;
|
self.state = State::Status;
|
||||||
|
|
||||||
try!(self.write_packet(StatusRequest{empty: ()}));
|
try!(self.write_packet(StatusRequest { empty: () }));
|
||||||
|
|
||||||
let status = if let Packet::StatusResponse(res) = try!(self.read_packet()) {
|
let status = if let Packet::StatusResponse(res) = try!(self.read_packet()) {
|
||||||
res.status
|
res.status
|
||||||
|
@ -779,7 +801,7 @@ impl Conn {
|
||||||
};
|
};
|
||||||
|
|
||||||
let start = time::now();
|
let start = time::now();
|
||||||
try!(self.write_packet(StatusPing{ping: 42}));
|
try!(self.write_packet(StatusPing { ping: 42 }));
|
||||||
|
|
||||||
if let Packet::StatusPong(_) = try!(self.read_packet()) {
|
if let Packet::StatusPong(_) = try!(self.read_packet()) {
|
||||||
} else {
|
} else {
|
||||||
|
@ -800,17 +822,26 @@ impl Conn {
|
||||||
|
|
||||||
Ok((Status {
|
Ok((Status {
|
||||||
version: StatusVersion {
|
version: StatusVersion {
|
||||||
name: try!(version.find("name").and_then(Value::as_string).ok_or(invalid_status())).to_owned(),
|
name: try!(version.find("name").and_then(Value::as_string).ok_or(invalid_status()))
|
||||||
protocol: try!(version.find("protocol").and_then(Value::as_i64).ok_or(invalid_status())) as i32,
|
.to_owned(),
|
||||||
|
protocol: try!(version.find("protocol")
|
||||||
|
.and_then(Value::as_i64)
|
||||||
|
.ok_or(invalid_status())) as i32,
|
||||||
},
|
},
|
||||||
players: StatusPlayers {
|
players: StatusPlayers {
|
||||||
max: try!(players.find("max").and_then(Value::as_i64).ok_or(invalid_status())) as i32,
|
max: try!(players.find("max")
|
||||||
online: try!(players.find("online").and_then(Value::as_i64).ok_or(invalid_status())) as i32,
|
.and_then(Value::as_i64)
|
||||||
sample: Vec::new(), // TODO
|
.ok_or(invalid_status())) as i32,
|
||||||
|
online: try!(players.find("online")
|
||||||
|
.and_then(Value::as_i64)
|
||||||
|
.ok_or(invalid_status())) as i32,
|
||||||
|
sample: Vec::new(), /* TODO */
|
||||||
},
|
},
|
||||||
description: format::Component::from_value(try!(val.find("description").ok_or(invalid_status()))),
|
description: format::Component::from_value(try!(val.find("description")
|
||||||
|
.ok_or(invalid_status()))),
|
||||||
favicon: val.find("favicon").and_then(Value::as_string).map(|v| v.to_owned()),
|
favicon: val.find("favicon").and_then(Value::as_string).map(|v| v.to_owned()),
|
||||||
}, ping))
|
},
|
||||||
|
ping))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -848,11 +879,11 @@ impl Read for Conn {
|
||||||
Option::Some(cipher) => {
|
Option::Some(cipher) => {
|
||||||
let ret = try!(self.stream.read(buf));
|
let ret = try!(self.stream.read(buf));
|
||||||
let data = cipher.decrypt(&buf[..ret]);
|
let data = cipher.decrypt(&buf[..ret]);
|
||||||
for i in 0 .. ret {
|
for i in 0..ret {
|
||||||
buf[i] = data[i];
|
buf[i] = data[i];
|
||||||
}
|
}
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -865,7 +896,7 @@ impl Write for Conn {
|
||||||
let data = cipher.encrypt(buf);
|
let data = cipher.encrypt(buf);
|
||||||
try!(self.stream.write_all(&data[..]));
|
try!(self.stream.write_all(&data[..]));
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -901,14 +932,16 @@ pub trait PacketType: Sized {
|
||||||
pub fn test() {
|
pub fn test() {
|
||||||
let mut c = Conn::new("localhost:25565").unwrap();
|
let mut c = Conn::new("localhost:25565").unwrap();
|
||||||
|
|
||||||
c.write_packet(packet::handshake::serverbound::Handshake{
|
c.write_packet(packet::handshake::serverbound::Handshake {
|
||||||
protocol_version: VarInt(71),
|
protocol_version: VarInt(71),
|
||||||
host: "localhost".to_owned(),
|
host: "localhost".to_owned(),
|
||||||
port: 25565,
|
port: 25565,
|
||||||
next: VarInt(2),
|
next: VarInt(2),
|
||||||
}).unwrap();
|
})
|
||||||
|
.unwrap();
|
||||||
c.state = State::Login;
|
c.state = State::Login;
|
||||||
c.write_packet(packet::login::serverbound::LoginStart{username: "Think".to_owned()}).unwrap();
|
c.write_packet(packet::login::serverbound::LoginStart { username: "Think".to_owned() })
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let packet = match c.read_packet().unwrap() {
|
let packet = match c.read_packet().unwrap() {
|
||||||
packet::Packet::EncryptionRequest(val) => val,
|
packet::Packet::EncryptionRequest(val) => val,
|
||||||
|
@ -921,18 +954,19 @@ pub fn test() {
|
||||||
let shared_e = key.encrypt(&shared);
|
let shared_e = key.encrypt(&shared);
|
||||||
let token_e = key.encrypt(&packet.verify_token.data);
|
let token_e = key.encrypt(&packet.verify_token.data);
|
||||||
|
|
||||||
let profile = mojang::Profile{
|
let profile = mojang::Profile {
|
||||||
username: "Think".to_owned(),
|
username: "Think".to_owned(),
|
||||||
id: "b1184d43168441cfa2128b9a3df3b6ab".to_owned(),
|
id: "b1184d43168441cfa2128b9a3df3b6ab".to_owned(),
|
||||||
access_token: "".to_owned()
|
access_token: "".to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
profile.join_server(&packet.server_id, &shared, &packet.public_key.data);
|
profile.join_server(&packet.server_id, &shared, &packet.public_key.data);
|
||||||
|
|
||||||
c.write_packet(packet::login::serverbound::EncryptionResponse{
|
c.write_packet(packet::login::serverbound::EncryptionResponse {
|
||||||
shared_secret: LenPrefixedBytes::new(shared_e),
|
shared_secret: LenPrefixedBytes::new(shared_e),
|
||||||
verify_token: LenPrefixedBytes::new(token_e),
|
verify_token: LenPrefixedBytes::new(token_e),
|
||||||
}).unwrap();
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mut read = c.clone();
|
let mut read = c.clone();
|
||||||
let mut write = c.clone();
|
let mut write = c.clone();
|
||||||
|
@ -940,35 +974,39 @@ pub fn test() {
|
||||||
read.enable_encyption(&shared, true);
|
read.enable_encyption(&shared, true);
|
||||||
write.enable_encyption(&shared, false);
|
write.enable_encyption(&shared, false);
|
||||||
|
|
||||||
loop { match read.read_packet().unwrap() {
|
loop {
|
||||||
packet::Packet::LoginDisconnect(val) => {
|
match read.read_packet().unwrap() {
|
||||||
panic!("Discconect {}", val.reason);
|
packet::Packet::LoginDisconnect(val) => {
|
||||||
},
|
panic!("Discconect {}", val.reason);
|
||||||
packet::Packet::SetInitialCompression(val) => {
|
}
|
||||||
read.set_compresssion(val.threshold.0, true);
|
packet::Packet::SetInitialCompression(val) => {
|
||||||
write.set_compresssion(val.threshold.0, false);
|
read.set_compresssion(val.threshold.0, true);
|
||||||
println!("Compression: {}", val.threshold.0)
|
write.set_compresssion(val.threshold.0, false);
|
||||||
},
|
println!("Compression: {}", val.threshold.0)
|
||||||
packet::Packet::LoginSuccess(val) => {
|
}
|
||||||
println!("Login: {} {}", val.username, val.uuid);
|
packet::Packet::LoginSuccess(val) => {
|
||||||
read.state = State::Play;
|
println!("Login: {} {}", val.username, val.uuid);
|
||||||
write.state = State::Play;
|
read.state = State::Play;
|
||||||
break;
|
write.state = State::Play;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => panic!("Unknown packet"),
|
||||||
}
|
}
|
||||||
_ => panic!("Unknown packet"),
|
}
|
||||||
} }
|
|
||||||
|
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
loop { match read.read_packet().unwrap() {
|
loop {
|
||||||
|
match read.read_packet().unwrap() {
|
||||||
packet::Packet::ServerMessage(val) => println!("MSG: {}", val.message),
|
packet::Packet::ServerMessage(val) => println!("MSG: {}", val.message),
|
||||||
packet::Packet::ChunkData(_) => {},
|
packet::Packet::ChunkData(_) => {}
|
||||||
val => {
|
val => {
|
||||||
println!("{:?}", val);
|
println!("{:?}", val);
|
||||||
if first {
|
if first {
|
||||||
write.write_packet(packet::play::serverbound::ChatMessage{
|
write.write_packet(packet::play::serverbound::ChatMessage {
|
||||||
message: "Hello world".to_owned(),
|
message: "Hello world".to_owned(),
|
||||||
}).unwrap();
|
})
|
||||||
|
.unwrap();
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
count += 1;
|
count += 1;
|
||||||
|
@ -976,7 +1014,8 @@ pub fn test() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ use hyper;
|
||||||
pub struct Profile {
|
pub struct Profile {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub access_token: String
|
pub access_token: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
const JOIN_URL: &'static str = "https://sessionserver.mojang.com/session/minecraft/join";
|
const JOIN_URL: &'static str = "https://sessionserver.mojang.com/session/minecraft/join";
|
||||||
|
@ -34,7 +34,7 @@ impl Profile {
|
||||||
|
|
||||||
// Mojang uses a hex method which allows for
|
// Mojang uses a hex method which allows for
|
||||||
// negatives so we have to account for that.
|
// negatives so we have to account for that.
|
||||||
let negative = hash[0] & 0x80 == 0x80;
|
let negative = hash[0] & 0x80 == 0x80;
|
||||||
if negative {
|
if negative {
|
||||||
twos_compliment(&mut hash);
|
twos_compliment(&mut hash);
|
||||||
}
|
}
|
||||||
|
@ -47,17 +47,18 @@ impl Profile {
|
||||||
};
|
};
|
||||||
|
|
||||||
let join_msg = serde_json::builder::ObjectBuilder::new()
|
let join_msg = serde_json::builder::ObjectBuilder::new()
|
||||||
.insert("accessToken", &self.access_token)
|
.insert("accessToken", &self.access_token)
|
||||||
.insert("selectedProfile", &self.id)
|
.insert("selectedProfile", &self.id)
|
||||||
.insert("serverId", hash_str)
|
.insert("serverId", hash_str)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let join = serde_json::to_string(&join_msg).unwrap();
|
let join = serde_json::to_string(&join_msg).unwrap();
|
||||||
|
|
||||||
let client = hyper::Client::new();
|
let client = hyper::Client::new();
|
||||||
let res = client.post(JOIN_URL)
|
let res = client.post(JOIN_URL)
|
||||||
.body(&join)
|
.body(&join)
|
||||||
.header(hyper::header::ContentType("application/json".parse().unwrap()))
|
.header(hyper::header::ContentType("application/json".parse().unwrap()))
|
||||||
.send().unwrap();
|
.send()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let ret: serde_json::Value = match serde_json::from_reader(res) {
|
let ret: serde_json::Value = match serde_json::from_reader(res) {
|
||||||
Result::Ok(val) => val,
|
Result::Ok(val) => val,
|
||||||
|
@ -69,7 +70,7 @@ impl Profile {
|
||||||
|
|
||||||
fn twos_compliment(data: &mut Vec<u8>) {
|
fn twos_compliment(data: &mut Vec<u8>) {
|
||||||
let mut carry = true;
|
let mut carry = true;
|
||||||
for i in (0 .. data.len()).rev() {
|
for i in (0..data.len()).rev() {
|
||||||
data[i] = !data[i];
|
data[i] = !data[i];
|
||||||
if carry {
|
if carry {
|
||||||
carry = data[i] == 0xFF;
|
carry = data[i] == 0xFF;
|
||||||
|
|
|
@ -91,7 +91,7 @@ state_packets!(
|
||||||
button: u8 =,
|
button: u8 =,
|
||||||
action_number: u16 =,
|
action_number: u16 =,
|
||||||
mode: u8 =,
|
mode: u8 =,
|
||||||
clicked_item: Option<item::Stack> =, // TODO
|
clicked_item: Option<item::Stack> =,
|
||||||
}
|
}
|
||||||
// CloseWindow is sent when the client closes a window.
|
// CloseWindow is sent when the client closes a window.
|
||||||
CloseWindow => 0x07 {
|
CloseWindow => 0x07 {
|
||||||
|
@ -936,7 +936,7 @@ pub struct BlockChangeRecord {
|
||||||
|
|
||||||
impl Serializable for BlockChangeRecord {
|
impl Serializable for BlockChangeRecord {
|
||||||
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
||||||
Ok(BlockChangeRecord{
|
Ok(BlockChangeRecord {
|
||||||
xz: try!(Serializable::read_from(buf)),
|
xz: try!(Serializable::read_from(buf)),
|
||||||
y: try!(Serializable::read_from(buf)),
|
y: try!(Serializable::read_from(buf)),
|
||||||
block_id: try!(Serializable::read_from(buf)),
|
block_id: try!(Serializable::read_from(buf)),
|
||||||
|
@ -959,7 +959,7 @@ pub struct ExplosionRecord {
|
||||||
|
|
||||||
impl Serializable for ExplosionRecord {
|
impl Serializable for ExplosionRecord {
|
||||||
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
||||||
Ok(ExplosionRecord{
|
Ok(ExplosionRecord {
|
||||||
x: try!(Serializable::read_from(buf)),
|
x: try!(Serializable::read_from(buf)),
|
||||||
y: try!(Serializable::read_from(buf)),
|
y: try!(Serializable::read_from(buf)),
|
||||||
z: try!(Serializable::read_from(buf)),
|
z: try!(Serializable::read_from(buf)),
|
||||||
|
@ -982,7 +982,7 @@ pub struct MapIcon {
|
||||||
|
|
||||||
impl Serializable for MapIcon {
|
impl Serializable for MapIcon {
|
||||||
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
||||||
Ok(MapIcon{
|
Ok(MapIcon {
|
||||||
direction_type: try!(Serializable::read_from(buf)),
|
direction_type: try!(Serializable::read_from(buf)),
|
||||||
x: try!(Serializable::read_from(buf)),
|
x: try!(Serializable::read_from(buf)),
|
||||||
z: try!(Serializable::read_from(buf)),
|
z: try!(Serializable::read_from(buf)),
|
||||||
|
@ -998,7 +998,7 @@ impl Serializable for MapIcon {
|
||||||
|
|
||||||
impl Default for MapIcon {
|
impl Default for MapIcon {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
MapIcon {
|
MapIcon {
|
||||||
direction_type: 0,
|
direction_type: 0,
|
||||||
x: 0,
|
x: 0,
|
||||||
z: 0,
|
z: 0,
|
||||||
|
@ -1015,7 +1015,7 @@ pub struct EntityProperty {
|
||||||
|
|
||||||
impl Serializable for EntityProperty {
|
impl Serializable for EntityProperty {
|
||||||
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
||||||
Ok(EntityProperty{
|
Ok(EntityProperty {
|
||||||
key: try!(Serializable::read_from(buf)),
|
key: try!(Serializable::read_from(buf)),
|
||||||
value: try!(Serializable::read_from(buf)),
|
value: try!(Serializable::read_from(buf)),
|
||||||
modifiers: try!(Serializable::read_from(buf)),
|
modifiers: try!(Serializable::read_from(buf)),
|
||||||
|
@ -1038,7 +1038,7 @@ pub struct PropertyModifier {
|
||||||
|
|
||||||
impl Serializable for PropertyModifier {
|
impl Serializable for PropertyModifier {
|
||||||
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
||||||
Ok(PropertyModifier{
|
Ok(PropertyModifier {
|
||||||
uuid: try!(Serializable::read_from(buf)),
|
uuid: try!(Serializable::read_from(buf)),
|
||||||
amount: try!(Serializable::read_from(buf)),
|
amount: try!(Serializable::read_from(buf)),
|
||||||
operation: try!(Serializable::read_from(buf)),
|
operation: try!(Serializable::read_from(buf)),
|
||||||
|
@ -1060,19 +1060,19 @@ pub struct PlayerInfoData {
|
||||||
|
|
||||||
impl Serializable for PlayerInfoData {
|
impl Serializable for PlayerInfoData {
|
||||||
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
||||||
let mut m = PlayerInfoData{
|
let mut m = PlayerInfoData {
|
||||||
action: try!(Serializable::read_from(buf)),
|
action: try!(Serializable::read_from(buf)),
|
||||||
players: Vec::new(),
|
players: Vec::new(),
|
||||||
};
|
};
|
||||||
let len = try!(VarInt::read_from(buf));
|
let len = try!(VarInt::read_from(buf));
|
||||||
for _ in 0 .. len.0 {
|
for _ in 0..len.0 {
|
||||||
let uuid = try!(UUID::read_from(buf));
|
let uuid = try!(UUID::read_from(buf));
|
||||||
match m.action.0 {
|
match m.action.0 {
|
||||||
0 => {
|
0 => {
|
||||||
let name = try!(String::read_from(buf));
|
let name = try!(String::read_from(buf));
|
||||||
let mut props = Vec::new();
|
let mut props = Vec::new();
|
||||||
let plen = try!(VarInt::read_from(buf)).0;
|
let plen = try!(VarInt::read_from(buf)).0;
|
||||||
for _ in 0 .. plen {
|
for _ in 0..plen {
|
||||||
let mut prop = PlayerProperty {
|
let mut prop = PlayerProperty {
|
||||||
name: try!(String::read_from(buf)),
|
name: try!(String::read_from(buf)),
|
||||||
value: try!(String::read_from(buf)),
|
value: try!(String::read_from(buf)),
|
||||||
|
@ -1098,21 +1098,21 @@ impl Serializable for PlayerInfoData {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
m.players.push(p);
|
m.players.push(p);
|
||||||
},
|
}
|
||||||
1 => {
|
1 => {
|
||||||
m.players.push(PlayerDetail::UpdateGamemode{
|
m.players.push(PlayerDetail::UpdateGamemode {
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
gamemode: try!(Serializable::read_from(buf)),
|
gamemode: try!(Serializable::read_from(buf)),
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
2 => {
|
2 => {
|
||||||
m.players.push(PlayerDetail::UpdateLatency{
|
m.players.push(PlayerDetail::UpdateLatency {
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
ping: try!(Serializable::read_from(buf)),
|
ping: try!(Serializable::read_from(buf)),
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
3 => {
|
3 => {
|
||||||
m.players.push(PlayerDetail::UpdateDisplayName{
|
m.players.push(PlayerDetail::UpdateDisplayName {
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
display: {
|
display: {
|
||||||
if try!(bool::read_from(buf)) {
|
if try!(bool::read_from(buf)) {
|
||||||
|
@ -1122,12 +1122,10 @@ impl Serializable for PlayerInfoData {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
4 => {
|
4 => {
|
||||||
m.players.push(PlayerDetail::Remove{
|
m.players.push(PlayerDetail::Remove { uuid: uuid })
|
||||||
uuid: uuid,
|
}
|
||||||
})
|
|
||||||
},
|
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1150,11 +1148,29 @@ impl Default for PlayerInfoData {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum PlayerDetail {
|
pub enum PlayerDetail {
|
||||||
Add{uuid: UUID, name: String, properties: Vec<PlayerProperty>, gamemode: VarInt, ping: VarInt, display: Option<format::Component>},
|
Add {
|
||||||
UpdateGamemode{uuid: UUID, gamemode: VarInt},
|
uuid: UUID,
|
||||||
UpdateLatency{uuid: UUID, ping: VarInt},
|
name: String,
|
||||||
UpdateDisplayName{uuid: UUID, display: Option<format::Component>},
|
properties: Vec<PlayerProperty>,
|
||||||
Remove{uuid: UUID},
|
gamemode: VarInt,
|
||||||
|
ping: VarInt,
|
||||||
|
display: Option<format::Component>,
|
||||||
|
},
|
||||||
|
UpdateGamemode {
|
||||||
|
uuid: UUID,
|
||||||
|
gamemode: VarInt,
|
||||||
|
},
|
||||||
|
UpdateLatency {
|
||||||
|
uuid: UUID,
|
||||||
|
ping: VarInt,
|
||||||
|
},
|
||||||
|
UpdateDisplayName {
|
||||||
|
uuid: UUID,
|
||||||
|
display: Option<format::Component>,
|
||||||
|
},
|
||||||
|
Remove {
|
||||||
|
uuid: UUID,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -13,80 +13,85 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
pub struct Atlas {
|
pub struct Atlas {
|
||||||
free_space: Vec<Rect>,
|
free_space: Vec<Rect>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Rect {
|
pub struct Rect {
|
||||||
pub x: usize,
|
pub x: usize,
|
||||||
pub y: usize,
|
pub y: usize,
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Atlas {
|
impl Atlas {
|
||||||
pub fn new(width: usize, height: usize) -> Atlas {
|
pub fn new(width: usize, height: usize) -> Atlas {
|
||||||
let mut a = Atlas {
|
let mut a = Atlas { free_space: Vec::new() };
|
||||||
free_space: Vec::new(),
|
a.free_space.push(Rect {
|
||||||
};
|
x: 0,
|
||||||
a.free_space.push(Rect{
|
y: 0,
|
||||||
x: 0, y: 0,
|
width: width,
|
||||||
width: width, height: height,
|
height: height,
|
||||||
});
|
});
|
||||||
a
|
a
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, width: usize, height: usize) -> Option<Rect> {
|
pub fn add(&mut self, width: usize, height: usize) -> Option<Rect> {
|
||||||
let mut priority = usize::max_value();
|
let mut priority = usize::max_value();
|
||||||
let mut target: Option<Rect> = None;
|
let mut target: Option<Rect> = None;
|
||||||
let mut target_index = 0;
|
let mut target_index = 0;
|
||||||
// Search through and find the best fit for this texture
|
// Search through and find the best fit for this texture
|
||||||
for (index, free) in self.free_space.iter().enumerate() {
|
for (index, free) in self.free_space.iter().enumerate() {
|
||||||
if free.width >= width && free.height >= height {
|
if free.width >= width && free.height >= height {
|
||||||
let current_priority = (free.width - width) * (free.height - height);
|
let current_priority = (free.width - width) * (free.height - height);
|
||||||
if target.is_none() || current_priority < priority {
|
if target.is_none() || current_priority < priority {
|
||||||
target = Some(*free);
|
target = Some(*free);
|
||||||
priority = current_priority;
|
priority = current_priority;
|
||||||
target_index = index;
|
target_index = index;
|
||||||
}
|
}
|
||||||
// Perfect match, we can break early
|
// Perfect match, we can break early
|
||||||
if priority == 0 {
|
if priority == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if target.is_none() {
|
if target.is_none() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let mut t = target.unwrap();
|
let mut t = target.unwrap();
|
||||||
let ret = Rect{
|
let ret = Rect {
|
||||||
x: t.x, y: t.y,
|
x: t.x,
|
||||||
width: width, height: height,
|
y: t.y,
|
||||||
};
|
width: width,
|
||||||
|
height: height,
|
||||||
|
};
|
||||||
|
|
||||||
if width == t.width {
|
if width == t.width {
|
||||||
t.y += height;
|
t.y += height;
|
||||||
t.height -= height;
|
t.height -= height;
|
||||||
if t.height == 0 {
|
if t.height == 0 {
|
||||||
// Remove empty sections
|
// Remove empty sections
|
||||||
self.free_space.remove(target_index);
|
self.free_space.remove(target_index);
|
||||||
} else {
|
} else {
|
||||||
self.free_space[target_index] = t;
|
self.free_space[target_index] = t;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if t.height > height {
|
if t.height > height {
|
||||||
// Split by height
|
// Split by height
|
||||||
self.free_space.insert(0, Rect{
|
self.free_space.insert(0,
|
||||||
x: t.x, y: t.y + height,
|
Rect {
|
||||||
width: width, height: t.height - height,
|
x: t.x,
|
||||||
});
|
y: t.y + height,
|
||||||
target_index += 1;
|
width: width,
|
||||||
}
|
height: t.height - height,
|
||||||
t.x += width;
|
});
|
||||||
t.width -= width;
|
target_index += 1;
|
||||||
self.free_space[target_index] = t;
|
}
|
||||||
}
|
t.x += width;
|
||||||
|
t.width -= width;
|
||||||
|
self.free_space[target_index] = t;
|
||||||
|
}
|
||||||
|
|
||||||
Some(ret)
|
Some(ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,50 +15,48 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct Registry {
|
pub struct Registry {
|
||||||
shaders: HashMap<String, String>,
|
shaders: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Registry {
|
impl Registry {
|
||||||
pub fn new() -> Registry {
|
pub fn new() -> Registry {
|
||||||
Registry {
|
Registry { shaders: HashMap::new() }
|
||||||
shaders: HashMap::new(),
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register(&mut self, name: &str, source: &str) {
|
pub fn register(&mut self, name: &str, source: &str) {
|
||||||
if self.shaders.contains_key(name) {
|
if self.shaders.contains_key(name) {
|
||||||
panic!("shader {} is already defined", name);
|
panic!("shader {} is already defined", name);
|
||||||
}
|
}
|
||||||
self.shaders.insert(name.to_owned(), source.trim().to_owned());
|
self.shaders.insert(name.to_owned(), source.trim().to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, name: &str) -> String {
|
pub fn get(&self, name: &str) -> String {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
out.push_str("#version 150\n");
|
out.push_str("#version 150\n");
|
||||||
self.get_internal(&mut out, name);
|
self.get_internal(&mut out, name);
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_define(&self, name: &str, define: &str) -> String {
|
pub fn get_define(&self, name: &str, define: &str) -> String {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
out.push_str("#version 150\n");
|
out.push_str("#version 150\n");
|
||||||
out.push_str("#define ");
|
out.push_str("#define ");
|
||||||
out.push_str(define);
|
out.push_str(define);
|
||||||
out.push_str("\n");
|
out.push_str("\n");
|
||||||
self.get_internal(&mut out, name);
|
self.get_internal(&mut out, name);
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_internal(&self, out: &mut String, name: &str) {
|
fn get_internal(&self, out: &mut String, name: &str) {
|
||||||
let src = self.shaders.get(name).unwrap();
|
let src = self.shaders.get(name).unwrap();
|
||||||
for line in src.lines() {
|
for line in src.lines() {
|
||||||
if line.starts_with("#include ") {
|
if line.starts_with("#include ") {
|
||||||
let inc = line["#include ".len()..].trim();
|
let inc = line["#include ".len()..].trim();
|
||||||
self.get_internal(out, &inc);
|
self.get_internal(out, &inc);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out.push_str(&line);
|
out.push_str(&line);
|
||||||
out.push_str("\n");
|
out.push_str("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,11 +16,12 @@ use render::glsl;
|
||||||
use gl;
|
use gl;
|
||||||
|
|
||||||
pub fn add_shaders(reg: &mut glsl::Registry) {
|
pub fn add_shaders(reg: &mut glsl::Registry) {
|
||||||
reg.register("lookup_texture", include_str!("shaders/lookup_texture.glsl"));
|
reg.register("lookup_texture",
|
||||||
reg.register("get_light", include_str!("shaders/get_light.glsl"));
|
include_str!("shaders/lookup_texture.glsl"));
|
||||||
|
reg.register("get_light", include_str!("shaders/get_light.glsl"));
|
||||||
|
|
||||||
reg.register("ui_vertex", include_str!("shaders/ui_vertex.glsl"));
|
reg.register("ui_vertex", include_str!("shaders/ui_vertex.glsl"));
|
||||||
reg.register("ui_frag", include_str!("shaders/ui_frag.glsl"));
|
reg.register("ui_frag", include_str!("shaders/ui_frag.glsl"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -71,39 +72,39 @@ macro_rules! init_shader {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_program(vertex: &str, fragment: &str) -> gl::Program {
|
pub fn create_program(vertex: &str, fragment: &str) -> gl::Program {
|
||||||
let program = gl::Program::new();
|
let program = gl::Program::new();
|
||||||
|
|
||||||
let v = gl::Shader::new(gl::VERTEX_SHADER);
|
let v = gl::Shader::new(gl::VERTEX_SHADER);
|
||||||
v.set_source(vertex);
|
v.set_source(vertex);
|
||||||
v.compile();
|
v.compile();
|
||||||
|
|
||||||
if v.get_parameter(gl::COMPILE_STATUS) == 0 {
|
if v.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||||
println!("Src: {}", vertex);
|
println!("Src: {}", vertex);
|
||||||
panic!("Shader error: {}", v.get_info_log());
|
panic!("Shader error: {}", v.get_info_log());
|
||||||
} else {
|
} else {
|
||||||
let log = v.get_info_log();
|
let log = v.get_info_log();
|
||||||
if !log.is_empty() {
|
if !log.is_empty() {
|
||||||
println!("{}", log);
|
println!("{}", log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let f = gl::Shader::new(gl::FRAGMENT_SHADER);
|
let f = gl::Shader::new(gl::FRAGMENT_SHADER);
|
||||||
f.set_source(fragment);
|
f.set_source(fragment);
|
||||||
f.compile();
|
f.compile();
|
||||||
|
|
||||||
if f.get_parameter(gl::COMPILE_STATUS) == 0 {
|
if f.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||||
println!("Src: {}", fragment);
|
println!("Src: {}", fragment);
|
||||||
panic!("Shader error: {}", f.get_info_log());
|
panic!("Shader error: {}", f.get_info_log());
|
||||||
} else {
|
} else {
|
||||||
let log = f.get_info_log();
|
let log = f.get_info_log();
|
||||||
if !log.is_empty() {
|
if !log.is_empty() {
|
||||||
println!("{}", log);
|
println!("{}", log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
program.attach_shader(v);
|
program.attach_shader(v);
|
||||||
program.attach_shader(f);
|
program.attach_shader(f);
|
||||||
program.link();
|
program.link();
|
||||||
program.use_program();
|
program.use_program();
|
||||||
program
|
program
|
||||||
}
|
}
|
||||||
|
|
810
src/render/ui.rs
810
src/render/ui.rs
|
@ -22,34 +22,34 @@ use render::glsl;
|
||||||
use render::shaders;
|
use render::shaders;
|
||||||
use byteorder::{WriteBytesExt, NativeEndian};
|
use byteorder::{WriteBytesExt, NativeEndian};
|
||||||
use image;
|
use image;
|
||||||
use image::{GenericImage};
|
use image::GenericImage;
|
||||||
|
|
||||||
const UI_WIDTH: f64 = 854.0;
|
const UI_WIDTH: f64 = 854.0;
|
||||||
const UI_HEIGHT: f64 = 480.0;
|
const UI_HEIGHT: f64 = 480.0;
|
||||||
|
|
||||||
pub struct UIState {
|
pub struct UIState {
|
||||||
textures: Arc<RwLock<render::TextureManager>>,
|
textures: Arc<RwLock<render::TextureManager>>,
|
||||||
resources: Arc<RwLock<resources::Manager>>,
|
resources: Arc<RwLock<resources::Manager>>,
|
||||||
pub version: usize,
|
pub version: usize,
|
||||||
|
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
prev_size: usize,
|
prev_size: usize,
|
||||||
count: usize,
|
count: usize,
|
||||||
|
|
||||||
array: gl::VertexArray,
|
array: gl::VertexArray,
|
||||||
buffer: gl::Buffer,
|
buffer: gl::Buffer,
|
||||||
index_buffer: gl::Buffer,
|
index_buffer: gl::Buffer,
|
||||||
index_type: gl::Type,
|
index_type: gl::Type,
|
||||||
max_index: usize,
|
max_index: usize,
|
||||||
|
|
||||||
shader: UIShader,
|
shader: UIShader,
|
||||||
|
|
||||||
// Font
|
// Font
|
||||||
font_pages: Vec<Option<render::Texture>>,
|
font_pages: Vec<Option<render::Texture>>,
|
||||||
font_character_info: Vec<(i32,i32)>,
|
font_character_info: Vec<(i32, i32)>,
|
||||||
char_map: HashMap<char, char>,
|
char_map: HashMap<char, char>,
|
||||||
page_width: f64,
|
page_width: f64,
|
||||||
page_height: f64,
|
page_height: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
init_shader! {
|
init_shader! {
|
||||||
|
@ -70,390 +70,478 @@ init_shader! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIState {
|
impl UIState {
|
||||||
pub fn new(glsl: &glsl::Registry, textures: Arc<RwLock<render::TextureManager>>, res: Arc<RwLock<resources::Manager>>) -> UIState {
|
pub fn new(glsl: &glsl::Registry,
|
||||||
let shader = UIShader::new(glsl);
|
textures: Arc<RwLock<render::TextureManager>>,
|
||||||
|
res: Arc<RwLock<resources::Manager>>)
|
||||||
|
-> UIState {
|
||||||
|
let shader = UIShader::new(glsl);
|
||||||
|
|
||||||
let array = gl::VertexArray::new();
|
let array = gl::VertexArray::new();
|
||||||
array.bind();
|
array.bind();
|
||||||
let buffer = gl::Buffer::new();
|
let buffer = gl::Buffer::new();
|
||||||
buffer.bind(gl::ARRAY_BUFFER);
|
buffer.bind(gl::ARRAY_BUFFER);
|
||||||
shader.position.enable();
|
shader.position.enable();
|
||||||
shader.texture_info.enable();
|
shader.texture_info.enable();
|
||||||
shader.texture_offset.enable();
|
shader.texture_offset.enable();
|
||||||
shader.color.enable();
|
shader.color.enable();
|
||||||
shader.position.vertex_pointer_int(3, gl::SHORT, 28, 0);
|
shader.position.vertex_pointer_int(3, gl::SHORT, 28, 0);
|
||||||
shader.texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 28, 8);
|
shader.texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 28, 8);
|
||||||
shader.texture_offset.vertex_pointer_int(3, gl::SHORT, 28, 16);
|
shader.texture_offset.vertex_pointer_int(3, gl::SHORT, 28, 16);
|
||||||
shader.color.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 28, 24);
|
shader.color.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 28, 24);
|
||||||
|
|
||||||
let index_buffer = gl::Buffer::new();
|
let index_buffer = gl::Buffer::new();
|
||||||
index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
||||||
|
|
||||||
let mut pages = Vec::with_capacity(0x100);
|
let mut pages = Vec::with_capacity(0x100);
|
||||||
for _ in 0 .. 0x100 {
|
for _ in 0..0x100 {
|
||||||
pages.push(Option::None);
|
pages.push(Option::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut char_map = HashMap::new();
|
let mut char_map = HashMap::new();
|
||||||
let ascii_chars = "ÀÁÂÈÊËÍÓÔÕÚßãõğİıŒœŞşŴŵžȇ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø׃áíóúñѪº¿®¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αβΓπΣσμτΦΘΩδ∞∅∈∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■";
|
let ascii_chars = "ÀÁÂÈÊËÍÓÔÕÚßãõğİıŒœŞşŴŵžȇ \
|
||||||
for (pos, c) in ascii_chars.chars().enumerate() {
|
!\"#$%&'()*+,-./0123456789:;\
|
||||||
char_map.insert(c, ::std::char::from_u32(pos as u32).unwrap());
|
<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ \
|
||||||
}
|
ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø׃áíóúñѪº¿®¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞\
|
||||||
|
╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αβΓπΣσμτΦΘΩδ∞∅∈∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■";
|
||||||
|
for (pos, c) in ascii_chars.chars().enumerate() {
|
||||||
|
char_map.insert(c, ::std::char::from_u32(pos as u32).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
let mut state = UIState {
|
let mut state = UIState {
|
||||||
textures: textures,
|
textures: textures,
|
||||||
resources: res,
|
resources: res,
|
||||||
version: 0xFFFF,
|
version: 0xFFFF,
|
||||||
|
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
count: 0,
|
count: 0,
|
||||||
prev_size: 0,
|
prev_size: 0,
|
||||||
|
|
||||||
index_type: gl::UNSIGNED_BYTE,
|
index_type: gl::UNSIGNED_BYTE,
|
||||||
array: array,
|
array: array,
|
||||||
buffer: buffer,
|
buffer: buffer,
|
||||||
index_buffer: index_buffer,
|
index_buffer: index_buffer,
|
||||||
max_index: 0,
|
max_index: 0,
|
||||||
|
|
||||||
shader: shader,
|
shader: shader,
|
||||||
|
|
||||||
// Font
|
// Font
|
||||||
font_pages: pages,
|
font_pages: pages,
|
||||||
font_character_info: vec![(0, 0); 0x10000],
|
font_character_info: vec![(0, 0); 0x10000],
|
||||||
char_map: char_map,
|
char_map: char_map,
|
||||||
page_width: 0.0,
|
page_width: 0.0,
|
||||||
page_height: 0.0,
|
page_height: 0.0,
|
||||||
};
|
};
|
||||||
state.load_font();
|
state.load_font();
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self, width: u32, height: u32) {
|
pub fn tick(&mut self, width: u32, height: u32) {
|
||||||
{
|
{
|
||||||
let version = self.resources.read().unwrap().version();
|
let version = self.resources.read().unwrap().version();
|
||||||
if self.version != version {
|
if self.version != version {
|
||||||
self.version = version;
|
self.version = version;
|
||||||
self.load_font();
|
self.load_font();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Prevent clipping with the world
|
// Prevent clipping with the world
|
||||||
gl::clear(gl::ClearFlags::Depth);
|
gl::clear(gl::ClearFlags::Depth);
|
||||||
gl::depth_func(gl::LESS_OR_EQUAL);
|
gl::depth_func(gl::LESS_OR_EQUAL);
|
||||||
gl::enable(gl::BLEND);
|
gl::enable(gl::BLEND);
|
||||||
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
|
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
self.shader.program.use_program();
|
self.shader.program.use_program();
|
||||||
self.shader.texture.set_int(0);
|
self.shader.texture.set_int(0);
|
||||||
if self.count > 0 {
|
if self.count > 0 {
|
||||||
self.array.bind();
|
self.array.bind();
|
||||||
if self.max_index < self.count {
|
if self.max_index < self.count {
|
||||||
let (data, ty) = render::generate_element_buffer(self.count);
|
let (data, ty) = render::generate_element_buffer(self.count);
|
||||||
self.index_type = ty;
|
self.index_type = ty;
|
||||||
self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
||||||
self.index_buffer.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW);
|
self.index_buffer.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW);
|
||||||
self.max_index = self.count;
|
self.max_index = self.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.shader.screensize.set_float2(width as f32, height as f32);
|
self.shader.screensize.set_float2(width as f32, height as f32);
|
||||||
|
|
||||||
self.buffer.bind(gl::ARRAY_BUFFER);
|
self.buffer.bind(gl::ARRAY_BUFFER);
|
||||||
if self.data.len() > self.prev_size {
|
if self.data.len() > self.prev_size {
|
||||||
self.prev_size = self.data.len();
|
self.prev_size = self.data.len();
|
||||||
self.buffer.set_data(gl::ARRAY_BUFFER, &self.data, gl::STREAM_DRAW);
|
self.buffer.set_data(gl::ARRAY_BUFFER, &self.data, gl::STREAM_DRAW);
|
||||||
} else {
|
} else {
|
||||||
let mut target = self.buffer.map(gl::ARRAY_BUFFER, gl::WRITE_ONLY, self.data.len());
|
let mut target = self.buffer.map(gl::ARRAY_BUFFER, gl::WRITE_ONLY, self.data.len());
|
||||||
target.write_all(&self.data[..]).unwrap();
|
target.write_all(&self.data[..]).unwrap();
|
||||||
}
|
}
|
||||||
gl::draw_elements(gl::TRIANGLES, self.count, self.index_type, 0);
|
gl::draw_elements(gl::TRIANGLES, self.count, self.index_type, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
gl::disable(gl::BLEND);
|
gl::disable(gl::BLEND);
|
||||||
self.data.clear();
|
self.data.clear();
|
||||||
self.count = 0;
|
self.count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_bytes(&mut self, data: &Vec<u8>) {
|
pub fn add_bytes(&mut self, data: &Vec<u8>) {
|
||||||
self.data.extend(data);
|
self.data.extend(data);
|
||||||
self.count += (data.len() / (28 * 4)) * 6;
|
self.count += (data.len() / (28 * 4)) * 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn character_texture(&mut self, c: char) -> render::Texture {
|
pub fn character_texture(&mut self, c: char) -> render::Texture {
|
||||||
let raw = c as u32;
|
let raw = c as u32;
|
||||||
let page = raw >> 8;
|
let page = raw >> 8;
|
||||||
// Lazy load fonts to size memory
|
// Lazy load fonts to size memory
|
||||||
if self.font_pages[page as usize].is_none() {
|
if self.font_pages[page as usize].is_none() {
|
||||||
let name = if page == 0 {
|
let name = if page == 0 {
|
||||||
"font/ascii".to_owned()
|
"font/ascii".to_owned()
|
||||||
} else {
|
} else {
|
||||||
format!("font/unicode_page_{:02X}", page)
|
format!("font/unicode_page_{:02X}", page)
|
||||||
};
|
};
|
||||||
let textures = self.textures.clone();
|
let textures = self.textures.clone();
|
||||||
self.font_pages[page as usize] = Some(render::Renderer::get_texture(&textures, &name));
|
self.font_pages[page as usize] = Some(render::Renderer::get_texture(&textures, &name));
|
||||||
}
|
}
|
||||||
let p = self.font_pages[page as usize].clone().unwrap();
|
let p = self.font_pages[page as usize].clone().unwrap();
|
||||||
|
|
||||||
let raw = if page == 0 {
|
let raw = if page == 0 {
|
||||||
(*self.char_map.get(&c).unwrap_or(&c)) as u32
|
(*self.char_map.get(&c).unwrap_or(&c)) as u32
|
||||||
} else {
|
} else {
|
||||||
raw
|
raw
|
||||||
};
|
};
|
||||||
let ch = raw & 0xFF;
|
let ch = raw & 0xFF;
|
||||||
let cx = ch & 0xF;
|
let cx = ch & 0xF;
|
||||||
let cy = ch >> 4;
|
let cy = ch >> 4;
|
||||||
let info = self.font_character_info[raw as usize];
|
let info = self.font_character_info[raw as usize];
|
||||||
if page == 0 {
|
if page == 0 {
|
||||||
let sw = (self.page_width / 16.0) as u32;
|
let sw = (self.page_width / 16.0) as u32;
|
||||||
let sh = (self.page_height / 16.0) as u32;
|
let sh = (self.page_height / 16.0) as u32;
|
||||||
return p.relative(
|
return p.relative((cx * sw + info.0 as u32) as f32 / (self.page_width as f32),
|
||||||
(cx * sw + info.0 as u32) as f32 / (self.page_width as f32),
|
(cy * sh) as f32 / (self.page_height as f32),
|
||||||
(cy * sh) as f32 / (self.page_height as f32),
|
(info.1 - info.0) as f32 / (self.page_width as f32),
|
||||||
(info.1 - info.0) as f32 / (self.page_width as f32),
|
(sh as f32) / (self.page_height as f32))
|
||||||
(sh as f32) / (self.page_height as f32)
|
}
|
||||||
)
|
p.relative((cx * 16 + info.0 as u32) as f32 / 256.0,
|
||||||
}
|
(cy * 16) as f32 / 256.0,
|
||||||
p.relative(
|
(info.1 - info.0) as f32 / 256.0,
|
||||||
(cx * 16 + info.0 as u32) as f32 / 256.0,
|
16.0 / 256.0)
|
||||||
(cy * 16) as f32 / 256.0,
|
}
|
||||||
(info.1 - info.0) as f32 / 256.0,
|
|
||||||
16.0 / 256.0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn size_of_string(&self, val: &str) -> f64 {
|
pub fn size_of_string(&self, val: &str) -> f64 {
|
||||||
let mut size = 0.0;
|
let mut size = 0.0;
|
||||||
for c in val.chars() {
|
for c in val.chars() {
|
||||||
size += self.size_of_char(c) + 2.0;
|
size += self.size_of_char(c) + 2.0;
|
||||||
}
|
}
|
||||||
size - 2.0
|
size - 2.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size_of_char(&self, c: char) -> f64 {
|
pub fn size_of_char(&self, c: char) -> f64 {
|
||||||
if c == ' ' {
|
if c == ' ' {
|
||||||
return 4.0;
|
return 4.0;
|
||||||
}
|
}
|
||||||
let r = c as u32;
|
let r = c as u32;
|
||||||
if r >> 8 == 0 {
|
if r >> 8 == 0 {
|
||||||
let r = (*self.char_map.get(&c).unwrap_or(&c)) as u32;
|
let r = (*self.char_map.get(&c).unwrap_or(&c)) as u32;
|
||||||
let info = self.font_character_info[r as usize];
|
let info = self.font_character_info[r as usize];
|
||||||
let sw = self.page_width / 16.0;
|
let sw = self.page_width / 16.0;
|
||||||
return (((info.1 - info.0) as f64) / sw) * 16.0;
|
return (((info.1 - info.0) as f64) / sw) * 16.0;
|
||||||
}
|
}
|
||||||
let info = self.font_character_info[c as usize];
|
let info = self.font_character_info[c as usize];
|
||||||
(info.1 - info.0) as f64
|
(info.1 - info.0) as f64
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_font(&mut self) {
|
fn load_font(&mut self) {
|
||||||
for page in &mut self.font_pages {
|
for page in &mut self.font_pages {
|
||||||
*page = None;
|
*page = None;
|
||||||
}
|
}
|
||||||
let res = self.resources.read().unwrap();
|
let res = self.resources.read().unwrap();
|
||||||
if let Some(mut info) = res.open("minecraft", "font/glyph_sizes.bin") {
|
if let Some(mut info) = res.open("minecraft", "font/glyph_sizes.bin") {
|
||||||
let mut data = Vec::with_capacity(0x10000);
|
let mut data = Vec::with_capacity(0x10000);
|
||||||
info.read_to_end(&mut data).unwrap();
|
info.read_to_end(&mut data).unwrap();
|
||||||
for (i, info) in self.font_character_info.iter_mut().enumerate() {
|
for (i, info) in self.font_character_info.iter_mut().enumerate() {
|
||||||
// Top nibble - start position
|
// Top nibble - start position
|
||||||
// Bottom nibble - end position
|
// Bottom nibble - end position
|
||||||
info.0 = (data[i] >> 4) as i32;
|
info.0 = (data[i] >> 4) as i32;
|
||||||
info.1 = (data[i] & 0xF) as i32 + 1;
|
info.1 = (data[i] & 0xF) as i32 + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(mut val) = res.open("minecraft", "textures/font/ascii.png") {
|
if let Some(mut val) = res.open("minecraft", "textures/font/ascii.png") {
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
val.read_to_end(&mut data).unwrap();
|
val.read_to_end(&mut data).unwrap();
|
||||||
if let Ok(img) = image::load_from_memory(&data) {
|
if let Ok(img) = image::load_from_memory(&data) {
|
||||||
let (width, height) = img.dimensions();
|
let (width, height) = img.dimensions();
|
||||||
self.page_width = width as f64;
|
self.page_width = width as f64;
|
||||||
self.page_height = height as f64;
|
self.page_height = height as f64;
|
||||||
let sw = width / 16;
|
let sw = width / 16;
|
||||||
let sh = height / 16;
|
let sh = height / 16;
|
||||||
for i in 0 .. 256 {
|
for i in 0..256 {
|
||||||
let cx = (i & 0xF) * sw;
|
let cx = (i & 0xF) * sw;
|
||||||
let cy = (i >> 4) * sh;
|
let cy = (i >> 4) * sh;
|
||||||
let mut start = true;
|
let mut start = true;
|
||||||
'x_loop: for x in 0 .. sw {
|
'x_loop: for x in 0..sw {
|
||||||
for y in 0 .. sh {
|
for y in 0..sh {
|
||||||
let a = img.get_pixel(cx+x, cy+y).data[3];
|
let a = img.get_pixel(cx + x, cy + y).data[3];
|
||||||
if start && a != 0 {
|
if start && a != 0 {
|
||||||
self.font_character_info[i as usize].0 = x as i32;
|
self.font_character_info[i as usize].0 = x as i32;
|
||||||
start = false;
|
start = false;
|
||||||
continue 'x_loop;
|
continue 'x_loop;
|
||||||
} else if !start && a != 0 {
|
} else if !start && a != 0 {
|
||||||
continue 'x_loop;
|
continue 'x_loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !start {
|
if !start {
|
||||||
self.font_character_info[i as usize].1 = x as i32;
|
self.font_character_info[i as usize].1 = x as i32;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_text(&mut self, val: &str, x: f64, y: f64, r: u8, g: u8, b: u8) -> UIText {
|
pub fn new_text(&mut self, val: &str, x: f64, y: f64, r: u8, g: u8, b: u8) -> UIText {
|
||||||
self.new_text_scaled(val, x, y, 1.0, 1.0, r, g, b)
|
self.new_text_scaled(val, x, y, 1.0, 1.0, r, g, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_text_scaled(&mut self, val: &str, x: f64, y: f64, sx: f64, sy: f64, r: u8, g: u8, b: u8) -> UIText {
|
pub fn new_text_scaled(&mut self,
|
||||||
self.create_text(val, x, y, sx, sy, 0.0, r, g, b)
|
val: &str,
|
||||||
}
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
sx: f64,
|
||||||
|
sy: f64,
|
||||||
|
r: u8,
|
||||||
|
g: u8,
|
||||||
|
b: u8)
|
||||||
|
-> UIText {
|
||||||
|
self.create_text(val, x, y, sx, sy, 0.0, r, g, b)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_text_rotated(&mut self, val: &str, x: f64, y: f64, sx: f64, sy: f64, rotation: f64, r: u8, g: u8, b: u8) -> UIText {
|
pub fn new_text_rotated(&mut self,
|
||||||
self.create_text(val, x, y, sx, sy, rotation, r, g, b)
|
val: &str,
|
||||||
}
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
sx: f64,
|
||||||
|
sy: f64,
|
||||||
|
rotation: f64,
|
||||||
|
r: u8,
|
||||||
|
g: u8,
|
||||||
|
b: u8)
|
||||||
|
-> UIText {
|
||||||
|
self.create_text(val, x, y, sx, sy, rotation, r, g, b)
|
||||||
|
}
|
||||||
|
|
||||||
fn create_text(&mut self, val: &str, x: f64, y: f64, sx: f64, sy: f64, rotation: f64, r: u8, g: u8, b: u8) -> UIText {
|
fn create_text(&mut self,
|
||||||
let mut elements = Vec::new();
|
val: &str,
|
||||||
let mut offset = 0.0;
|
x: f64,
|
||||||
for ch in val.chars() {
|
y: f64,
|
||||||
if ch == ' ' {
|
sx: f64,
|
||||||
offset += 6.0;
|
sy: f64,
|
||||||
continue;
|
rotation: f64,
|
||||||
}
|
r: u8,
|
||||||
let texture = self.character_texture(ch);
|
g: u8,
|
||||||
let w = self.size_of_char(ch);
|
b: u8)
|
||||||
|
-> UIText {
|
||||||
|
let mut elements = Vec::new();
|
||||||
|
let mut offset = 0.0;
|
||||||
|
for ch in val.chars() {
|
||||||
|
if ch == ' ' {
|
||||||
|
offset += 6.0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let texture = self.character_texture(ch);
|
||||||
|
let w = self.size_of_char(ch);
|
||||||
|
|
||||||
let mut dsx = offset + 2.0;
|
let mut dsx = offset + 2.0;
|
||||||
let mut dsy = 2.0;
|
let mut dsy = 2.0;
|
||||||
let mut dx = offset;
|
let mut dx = offset;
|
||||||
let mut dy = 0.0;
|
let mut dy = 0.0;
|
||||||
if rotation != 0.0 {
|
if rotation != 0.0 {
|
||||||
let c = rotation.cos();
|
let c = rotation.cos();
|
||||||
let s = rotation.sin();
|
let s = rotation.sin();
|
||||||
let tmpx = dsx - (w * 0.5);
|
let tmpx = dsx - (w * 0.5);
|
||||||
let tmpy = dsy - (16.0 * 0.5);
|
let tmpy = dsy - (16.0 * 0.5);
|
||||||
dsx = (w * 0.5) + (tmpx*c - tmpy*s);
|
dsx = (w * 0.5) + (tmpx * c - tmpy * s);
|
||||||
dsy = (16.0 * 0.5) + (tmpy*c + tmpx*s);
|
dsy = (16.0 * 0.5) + (tmpy * c + tmpx * s);
|
||||||
let tmpx = dx - (w * 0.5);
|
let tmpx = dx - (w * 0.5);
|
||||||
let tmpy = dy - (16.0 * 0.5);
|
let tmpy = dy - (16.0 * 0.5);
|
||||||
dx = (w * 0.5) + (tmpx*c - tmpy*s);
|
dx = (w * 0.5) + (tmpx * c - tmpy * s);
|
||||||
dy = (16.0 * 0.5) + (tmpy*c + tmpx*s);
|
dy = (16.0 * 0.5) + (tmpy * c + tmpx * s);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut shadow = UIElement::new(&texture, x+dsx*sx, y+dsy*sy, w*sx, 16.0*sy, 0.0, 0.0, 1.0, 1.0);
|
let mut shadow = UIElement::new(&texture,
|
||||||
shadow.r = ((r as f64) * 0.25) as u8;
|
x + dsx * sx,
|
||||||
shadow.g = ((g as f64) * 0.25) as u8;
|
y + dsy * sy,
|
||||||
shadow.b = ((b as f64) * 0.25) as u8;
|
w * sx,
|
||||||
shadow.rotation = rotation;
|
16.0 * sy,
|
||||||
elements.push(shadow);
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0);
|
||||||
|
shadow.r = ((r as f64) * 0.25) as u8;
|
||||||
|
shadow.g = ((g as f64) * 0.25) as u8;
|
||||||
|
shadow.b = ((b as f64) * 0.25) as u8;
|
||||||
|
shadow.rotation = rotation;
|
||||||
|
elements.push(shadow);
|
||||||
|
|
||||||
let mut text = UIElement::new(&texture, x+dx*sx, y+dy*sy, w*sx, 16.0*sy, 0.0, 0.0, 1.0, 1.0);
|
let mut text = UIElement::new(&texture,
|
||||||
text.r = r;
|
x + dx * sx,
|
||||||
text.g = g;
|
y + dy * sy,
|
||||||
text.b = b;
|
w * sx,
|
||||||
text.rotation = rotation;
|
16.0 * sy,
|
||||||
elements.push(text);
|
0.0,
|
||||||
offset += w + 2.0;
|
0.0,
|
||||||
}
|
1.0,
|
||||||
UIText {
|
1.0);
|
||||||
elements: elements,
|
text.r = r;
|
||||||
width: (offset - 2.0) * sx,
|
text.g = g;
|
||||||
}
|
text.b = b;
|
||||||
}
|
text.rotation = rotation;
|
||||||
|
elements.push(text);
|
||||||
|
offset += w + 2.0;
|
||||||
|
}
|
||||||
|
UIText {
|
||||||
|
elements: elements,
|
||||||
|
width: (offset - 2.0) * sx,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UIText {
|
pub struct UIText {
|
||||||
pub elements: Vec<UIElement>,
|
pub elements: Vec<UIElement>,
|
||||||
pub width: f64,
|
pub width: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIText {
|
impl UIText {
|
||||||
pub fn bytes(&self, width: f64, height: f64) -> Vec<u8> {
|
pub fn bytes(&self, width: f64, height: f64) -> Vec<u8> {
|
||||||
let mut buf = Vec::with_capacity(28*4*self.elements.len());
|
let mut buf = Vec::with_capacity(28 * 4 * self.elements.len());
|
||||||
for e in &self.elements {
|
for e in &self.elements {
|
||||||
buf.extend(e.bytes(width, height));
|
buf.extend(e.bytes(width, height));
|
||||||
}
|
}
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UIElement {
|
pub struct UIElement {
|
||||||
pub x: f64,
|
pub x: f64,
|
||||||
pub y: f64,
|
pub y: f64,
|
||||||
pub w: f64,
|
pub w: f64,
|
||||||
pub h: f64,
|
pub h: f64,
|
||||||
pub layer: isize,
|
pub layer: isize,
|
||||||
pub t_x: u16,
|
pub t_x: u16,
|
||||||
pub t_y: u16,
|
pub t_y: u16,
|
||||||
pub t_w: u16,
|
pub t_w: u16,
|
||||||
pub t_h: u16,
|
pub t_h: u16,
|
||||||
pub t_offsetx: i16,
|
pub t_offsetx: i16,
|
||||||
pub t_offsety: i16,
|
pub t_offsety: i16,
|
||||||
pub t_atlas: i16,
|
pub t_atlas: i16,
|
||||||
pub t_sizew: i16,
|
pub t_sizew: i16,
|
||||||
pub t_sizeh: i16,
|
pub t_sizeh: i16,
|
||||||
pub r: u8,
|
pub r: u8,
|
||||||
pub g: u8,
|
pub g: u8,
|
||||||
pub b: u8,
|
pub b: u8,
|
||||||
pub a: u8,
|
pub a: u8,
|
||||||
pub rotation: f64,
|
pub rotation: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIElement {
|
impl UIElement {
|
||||||
pub fn new(tex: &render::Texture, x: f64, y: f64, width: f64, height: f64, tx: f64, ty: f64, tw: f64, th: f64) -> UIElement {
|
pub fn new(tex: &render::Texture,
|
||||||
let twidth = tex.get_width();
|
x: f64,
|
||||||
let theight = tex.get_height();
|
y: f64,
|
||||||
UIElement {
|
width: f64,
|
||||||
x: x / UI_WIDTH,
|
height: f64,
|
||||||
y: y / UI_HEIGHT,
|
tx: f64,
|
||||||
w: width / UI_WIDTH,
|
ty: f64,
|
||||||
h: height / UI_HEIGHT,
|
tw: f64,
|
||||||
layer: 0,
|
th: f64)
|
||||||
t_x: tex.get_x() as u16,
|
-> UIElement {
|
||||||
t_y: tex.get_y() as u16,
|
let twidth = tex.get_width();
|
||||||
t_w: twidth as u16,
|
let theight = tex.get_height();
|
||||||
t_h: theight as u16,
|
UIElement {
|
||||||
t_atlas: tex.atlas as i16,
|
x: x / UI_WIDTH,
|
||||||
t_offsetx: (tx * (twidth as f64) * 16.0) as i16,
|
y: y / UI_HEIGHT,
|
||||||
t_offsety: (ty * (theight as f64) * 16.0) as i16,
|
w: width / UI_WIDTH,
|
||||||
t_sizew: (tw * (twidth as f64) * 16.0) as i16,
|
h: height / UI_HEIGHT,
|
||||||
t_sizeh: (th * (theight as f64) * 16.0) as i16,
|
layer: 0,
|
||||||
r: 255,
|
t_x: tex.get_x() as u16,
|
||||||
g: 255,
|
t_y: tex.get_y() as u16,
|
||||||
b: 255,
|
t_w: twidth as u16,
|
||||||
a: 255,
|
t_h: theight as u16,
|
||||||
rotation: 0.0,
|
t_atlas: tex.atlas as i16,
|
||||||
}
|
t_offsetx: (tx * (twidth as f64) * 16.0) as i16,
|
||||||
}
|
t_offsety: (ty * (theight as f64) * 16.0) as i16,
|
||||||
|
t_sizew: (tw * (twidth as f64) * 16.0) as i16,
|
||||||
|
t_sizeh: (th * (theight as f64) * 16.0) as i16,
|
||||||
|
r: 255,
|
||||||
|
g: 255,
|
||||||
|
b: 255,
|
||||||
|
a: 255,
|
||||||
|
rotation: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn bytes(&self, width: f64, height: f64) -> Vec<u8> {
|
pub fn bytes(&self, width: f64, height: f64) -> Vec<u8> {
|
||||||
let mut buf = Vec::with_capacity(28*4);
|
let mut buf = Vec::with_capacity(28 * 4);
|
||||||
self.append_vertex(&mut buf, self.x, self.y, self.t_offsetx, self.t_offsety, width, height);
|
self.append_vertex(&mut buf,
|
||||||
self.append_vertex(&mut buf, self.x + self.w, self.y, self.t_offsetx + self.t_sizew, self.t_offsety, width, height);
|
self.x,
|
||||||
self.append_vertex(&mut buf, self.x, self.y + self.h, self.t_offsetx, self.t_offsety + self.t_sizeh, width, height);
|
self.y,
|
||||||
self.append_vertex(&mut buf, self.x + self.w, self.y + self.h, self.t_offsetx + self.t_sizew, self.t_offsety + self.t_sizeh, width, height);
|
self.t_offsetx,
|
||||||
buf
|
self.t_offsety,
|
||||||
}
|
width,
|
||||||
|
height);
|
||||||
|
self.append_vertex(&mut buf,
|
||||||
|
self.x + self.w,
|
||||||
|
self.y,
|
||||||
|
self.t_offsetx + self.t_sizew,
|
||||||
|
self.t_offsety,
|
||||||
|
width,
|
||||||
|
height);
|
||||||
|
self.append_vertex(&mut buf,
|
||||||
|
self.x,
|
||||||
|
self.y + self.h,
|
||||||
|
self.t_offsetx,
|
||||||
|
self.t_offsety + self.t_sizeh,
|
||||||
|
width,
|
||||||
|
height);
|
||||||
|
self.append_vertex(&mut buf,
|
||||||
|
self.x + self.w,
|
||||||
|
self.y + self.h,
|
||||||
|
self.t_offsetx + self.t_sizew,
|
||||||
|
self.t_offsety + self.t_sizeh,
|
||||||
|
width,
|
||||||
|
height);
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused_must_use)]
|
#[allow(unused_must_use)]
|
||||||
pub fn append_vertex(&self, buf: &mut Vec<u8>, x: f64, y: f64, tx: i16, ty: i16, width: f64, height: f64) {
|
pub fn append_vertex(&self,
|
||||||
let mut dx = x as f64;
|
buf: &mut Vec<u8>,
|
||||||
let mut dy = y as f64;
|
x: f64,
|
||||||
if self.rotation != 0.0 {
|
y: f64,
|
||||||
let c = self.rotation.cos();
|
tx: i16,
|
||||||
let s = self.rotation.sin();
|
ty: i16,
|
||||||
let tmpx = dx - self.x - (self.w / 2.0);
|
width: f64,
|
||||||
let tmpy = dy - self.y - (self.h / 2.0);
|
height: f64) {
|
||||||
dx = (self.w / 2.0) + (tmpx * c - tmpy * s) + self.x;
|
let mut dx = x as f64;
|
||||||
dy = (self.h / 2.0) + (tmpy * c + tmpx * s) + self.y;
|
let mut dy = y as f64;
|
||||||
}
|
if self.rotation != 0.0 {
|
||||||
|
let c = self.rotation.cos();
|
||||||
|
let s = self.rotation.sin();
|
||||||
|
let tmpx = dx - self.x - (self.w / 2.0);
|
||||||
|
let tmpy = dy - self.y - (self.h / 2.0);
|
||||||
|
dx = (self.w / 2.0) + (tmpx * c - tmpy * s) + self.x;
|
||||||
|
dy = (self.h / 2.0) + (tmpy * c + tmpx * s) + self.y;
|
||||||
|
}
|
||||||
|
|
||||||
buf.write_i16::<NativeEndian>((dx*width+0.5).floor() as i16);
|
buf.write_i16::<NativeEndian>((dx * width + 0.5).floor() as i16);
|
||||||
buf.write_i16::<NativeEndian>((dy*height+0.5).floor() as i16);
|
buf.write_i16::<NativeEndian>((dy * height + 0.5).floor() as i16);
|
||||||
buf.write_i16::<NativeEndian>((self.layer * 256) as i16);
|
buf.write_i16::<NativeEndian>((self.layer * 256) as i16);
|
||||||
buf.write_i16::<NativeEndian>(0);
|
buf.write_i16::<NativeEndian>(0);
|
||||||
buf.write_u16::<NativeEndian>(self.t_x);
|
buf.write_u16::<NativeEndian>(self.t_x);
|
||||||
buf.write_u16::<NativeEndian>(self.t_y);
|
buf.write_u16::<NativeEndian>(self.t_y);
|
||||||
buf.write_u16::<NativeEndian>(self.t_w);
|
buf.write_u16::<NativeEndian>(self.t_w);
|
||||||
buf.write_u16::<NativeEndian>(self.t_h);
|
buf.write_u16::<NativeEndian>(self.t_h);
|
||||||
buf.write_i16::<NativeEndian>(tx);
|
buf.write_i16::<NativeEndian>(tx);
|
||||||
buf.write_i16::<NativeEndian>(ty);
|
buf.write_i16::<NativeEndian>(ty);
|
||||||
buf.write_i16::<NativeEndian>(self.t_atlas);
|
buf.write_i16::<NativeEndian>(self.t_atlas);
|
||||||
buf.write_i16::<NativeEndian>(0);
|
buf.write_i16::<NativeEndian>(0);
|
||||||
buf.write_u8(self.r);
|
buf.write_u8(self.r);
|
||||||
buf.write_u8(self.g);
|
buf.write_u8(self.g);
|
||||||
buf.write_u8(self.b);
|
buf.write_u8(self.b);
|
||||||
buf.write_u8(self.a);
|
buf.write_u8(self.a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub trait Pack {
|
||||||
|
|
||||||
pub struct Manager {
|
pub struct Manager {
|
||||||
packs: Vec<Box<Pack>>,
|
packs: Vec<Box<Pack>>,
|
||||||
version: usize,
|
version: usize,
|
||||||
|
|
||||||
vanilla_chan: Option<mpsc::Receiver<bool>>,
|
vanilla_chan: Option<mpsc::Receiver<bool>>,
|
||||||
}
|
}
|
||||||
|
@ -41,16 +41,16 @@ pub struct Manager {
|
||||||
impl Manager {
|
impl Manager {
|
||||||
pub fn new() -> Manager {
|
pub fn new() -> Manager {
|
||||||
let mut m = Manager {
|
let mut m = Manager {
|
||||||
packs: Vec::new(),
|
packs: Vec::new(),
|
||||||
version: 0,
|
version: 0,
|
||||||
vanilla_chan: None,
|
vanilla_chan: None,
|
||||||
};
|
};
|
||||||
m.add_pack(Box::new(InternalPack));
|
m.add_pack(Box::new(InternalPack));
|
||||||
m.download_vanilla();
|
m.download_vanilla();
|
||||||
m
|
m
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the 'version' of the manager. The version is
|
/// Returns the 'version' of the manager. The version is
|
||||||
/// increase everytime a pack is added or removed.
|
/// increase everytime a pack is added or removed.
|
||||||
pub fn version(&self) -> usize {
|
pub fn version(&self) -> usize {
|
||||||
self.version
|
self.version
|
||||||
|
@ -61,7 +61,7 @@ impl Manager {
|
||||||
let path = format!("assets/{}/{}", plugin, name);
|
let path = format!("assets/{}/{}", plugin, name);
|
||||||
match pack.open(&path) {
|
match pack.open(&path) {
|
||||||
Some(val) => return Some(val),
|
Some(val) => return Some(val),
|
||||||
None => {},
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
@ -73,14 +73,14 @@ impl Manager {
|
||||||
let path = format!("assets/{}/{}", plugin, name);
|
let path = format!("assets/{}/{}", plugin, name);
|
||||||
match pack.open(&path) {
|
match pack.open(&path) {
|
||||||
Some(val) => ret.push(val),
|
Some(val) => ret.push(val),
|
||||||
None => {},
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
// Check to see if the download of vanilla has completed
|
// Check to see if the download of vanilla has completed
|
||||||
// (if it was started)
|
// (if it was started)
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
if let Some(ref recv) = self.vanilla_chan {
|
if let Some(ref recv) = self.vanilla_chan {
|
||||||
|
@ -102,9 +102,7 @@ impl Manager {
|
||||||
fn load_vanilla(&mut self) {
|
fn load_vanilla(&mut self) {
|
||||||
let loc = format!("./resources-{}", RESOURCES_VERSION);
|
let loc = format!("./resources-{}", RESOURCES_VERSION);
|
||||||
let location = path::Path::new(&loc);
|
let location = path::Path::new(&loc);
|
||||||
self.add_pack(Box::new(DirPack{
|
self.add_pack(Box::new(DirPack { root: location.to_path_buf() }))
|
||||||
root: location.to_path_buf(),
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn download_vanilla(&mut self) {
|
fn download_vanilla(&mut self) {
|
||||||
|
@ -120,9 +118,11 @@ impl Manager {
|
||||||
println!("Vanilla assets missing, obtaining");
|
println!("Vanilla assets missing, obtaining");
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let client = hyper::Client::new();
|
let client = hyper::Client::new();
|
||||||
let url = format!("https://s3.amazonaws.com/Minecraft.Download/versions/{0}/{0}.jar", RESOURCES_VERSION);
|
let url = format!("https://s3.amazonaws.com/Minecraft.Download/versions/{0}/{0}.jar",
|
||||||
|
RESOURCES_VERSION);
|
||||||
let res = client.get(&url)
|
let res = client.get(&url)
|
||||||
.send().unwrap();
|
.send()
|
||||||
|
.unwrap();
|
||||||
let mut file = fs::File::create(format!("{}.tmp", RESOURCES_VERSION)).unwrap();
|
let mut file = fs::File::create(format!("{}.tmp", RESOURCES_VERSION)).unwrap();
|
||||||
|
|
||||||
let length = *res.headers.get::<hyper::header::ContentLength>().unwrap();
|
let length = *res.headers.get::<hyper::header::ContentLength>().unwrap();
|
||||||
|
@ -140,7 +140,7 @@ impl Manager {
|
||||||
let loc = format!("./resources-{}", RESOURCES_VERSION);
|
let loc = format!("./resources-{}", RESOURCES_VERSION);
|
||||||
let location = path::Path::new(&loc);
|
let location = path::Path::new(&loc);
|
||||||
let count = zip.len();
|
let count = zip.len();
|
||||||
for i in 0 .. count {
|
for i in 0..count {
|
||||||
let mut file = zip.by_index(i).unwrap();
|
let mut file = zip.by_index(i).unwrap();
|
||||||
if !file.name().starts_with("assets/") {
|
if !file.name().starts_with("assets/") {
|
||||||
continue;
|
continue;
|
||||||
|
@ -194,7 +194,8 @@ impl <T: io::Read> io::Read for ProgressRead<T> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
let size = try!(self.read.read(buf));
|
let size = try!(self.read.read(buf));
|
||||||
self.progress += size as u64;
|
self.progress += size as u64;
|
||||||
println!("Progress: {:.2}", (self.progress as f64) / (self.total as f64));
|
println!("Progress: {:.2}",
|
||||||
|
(self.progress as f64) / (self.total as f64));
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,65 +18,81 @@ use ui;
|
||||||
use render;
|
use render;
|
||||||
|
|
||||||
pub struct Login {
|
pub struct Login {
|
||||||
elements: Option<UIElements>,
|
elements: Option<UIElements>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UIElements {
|
struct UIElements {
|
||||||
logo: ui::logo::Logo,
|
logo: ui::logo::Logo,
|
||||||
elements: ui::Collection,
|
elements: ui::Collection,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Login {
|
impl Login {
|
||||||
pub fn new() -> Login {
|
pub fn new() -> Login {
|
||||||
Login {
|
Login { elements: None }
|
||||||
elements: None,
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Screen for Login {
|
impl super::Screen for Login {
|
||||||
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||||
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container);
|
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container);
|
||||||
let mut elements = ui::Collection::new();
|
let mut elements = ui::Collection::new();
|
||||||
|
|
||||||
// Login
|
// Login
|
||||||
let (mut login, mut txt) = super::new_button_text(renderer, "Login", 0.0, 100.0, 400.0, 40.0);
|
let (mut login, mut txt) = super::new_button_text(renderer,
|
||||||
login.set_v_attach(ui::VAttach::Middle);
|
"Login",
|
||||||
login.set_h_attach(ui::HAttach::Center);
|
0.0,
|
||||||
let re = ui_container.add(login);
|
100.0,
|
||||||
txt.set_parent(&re);
|
400.0,
|
||||||
let tre = ui_container.add(txt);
|
40.0);
|
||||||
super::button_action(ui_container, re.clone(), Some(tre.clone()), Some(Rc::new(|game, _| {
|
login.set_v_attach(ui::VAttach::Middle);
|
||||||
game.screen_sys.replace_screen(Box::new(super::ServerList::new(None)));
|
login.set_h_attach(ui::HAttach::Center);
|
||||||
})));
|
let re = ui_container.add(login);
|
||||||
elements.add(re);
|
txt.set_parent(&re);
|
||||||
elements.add(tre);
|
let tre = ui_container.add(txt);
|
||||||
|
super::button_action(ui_container,
|
||||||
|
re.clone(),
|
||||||
|
Some(tre.clone()),
|
||||||
|
Some(Rc::new(|game, _| {
|
||||||
|
game.screen_sys
|
||||||
|
.replace_screen(Box::new(super::ServerList::new(None)));
|
||||||
|
})));
|
||||||
|
elements.add(re);
|
||||||
|
elements.add(tre);
|
||||||
|
|
||||||
// Disclaimer
|
// Disclaimer
|
||||||
let mut warn = ui::Text::new(renderer, "Not affiliated with Mojang/Minecraft", 5.0, 5.0, 255, 200, 200);
|
let mut warn = ui::Text::new(renderer,
|
||||||
warn.set_v_attach(ui::VAttach::Bottom);
|
"Not affiliated with Mojang/Minecraft",
|
||||||
warn.set_h_attach(ui::HAttach::Right);
|
5.0,
|
||||||
elements.add(ui_container.add(warn));
|
5.0,
|
||||||
|
255,
|
||||||
|
200,
|
||||||
|
200);
|
||||||
|
warn.set_v_attach(ui::VAttach::Bottom);
|
||||||
|
warn.set_h_attach(ui::HAttach::Right);
|
||||||
|
elements.add(ui_container.add(warn));
|
||||||
|
|
||||||
self.elements = Some(UIElements {
|
self.elements = Some(UIElements {
|
||||||
logo: logo,
|
logo: logo,
|
||||||
elements: elements,
|
elements: elements,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||||
// Clean up
|
// Clean up
|
||||||
{
|
{
|
||||||
let elements = self.elements.as_mut().unwrap();
|
let elements = self.elements.as_mut().unwrap();
|
||||||
elements.logo.remove(ui_container);
|
elements.logo.remove(ui_container);
|
||||||
elements.elements.remove_all(ui_container);
|
elements.elements.remove_all(ui_container);
|
||||||
}
|
}
|
||||||
self.elements = None
|
self.elements = None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
fn tick(&mut self,
|
||||||
let elements = self.elements.as_mut().unwrap();
|
delta: f64,
|
||||||
|
renderer: &mut render::Renderer,
|
||||||
|
ui_container: &mut ui::Container) {
|
||||||
|
let elements = self.elements.as_mut().unwrap();
|
||||||
|
|
||||||
elements.logo.tick(renderer, ui_container);
|
elements.logo.tick(renderer, ui_container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,189 +25,318 @@ use ui;
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub trait Screen {
|
pub trait Screen {
|
||||||
// Called once
|
// Called once
|
||||||
fn init(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {}
|
fn init(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||||
fn deinit(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {}
|
}
|
||||||
|
fn deinit(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||||
|
}
|
||||||
|
|
||||||
// May be called multiple times
|
// May be called multiple times
|
||||||
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container);
|
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container);
|
||||||
fn on_deactive(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container);
|
fn on_deactive(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container);
|
||||||
|
|
||||||
// Called every frame the screen is active
|
// Called every frame the screen is active
|
||||||
fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container);
|
fn tick(&mut self,
|
||||||
|
delta: f64,
|
||||||
|
renderer: &mut render::Renderer,
|
||||||
|
ui_container: &mut ui::Container);
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
fn on_scroll(&mut self, x: f64, y: f64) {}
|
fn on_scroll(&mut self, x: f64, y: f64) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ScreenInfo {
|
struct ScreenInfo {
|
||||||
screen: Box<Screen>,
|
screen: Box<Screen>,
|
||||||
init: bool,
|
init: bool,
|
||||||
active: bool,
|
active: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ScreenSystem {
|
pub struct ScreenSystem {
|
||||||
screens: Vec<ScreenInfo>,
|
screens: Vec<ScreenInfo>,
|
||||||
remove_queue: Vec<ScreenInfo>,
|
remove_queue: Vec<ScreenInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScreenSystem {
|
impl ScreenSystem {
|
||||||
pub fn new() -> ScreenSystem {
|
pub fn new() -> ScreenSystem {
|
||||||
ScreenSystem {
|
ScreenSystem {
|
||||||
screens: Vec::new(),
|
screens: Vec::new(),
|
||||||
remove_queue: Vec::new(),
|
remove_queue: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_screen(&mut self, screen: Box<Screen>) {
|
pub fn add_screen(&mut self, screen: Box<Screen>) {
|
||||||
self.screens.push(ScreenInfo {
|
self.screens.push(ScreenInfo {
|
||||||
screen: screen,
|
screen: screen,
|
||||||
init: false,
|
init: false,
|
||||||
active: false,
|
active: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_screen(&mut self) {
|
pub fn pop_screen(&mut self) {
|
||||||
if let Some(screen) = self.screens.pop() {
|
if let Some(screen) = self.screens.pop() {
|
||||||
self.remove_queue.push(screen);
|
self.remove_queue.push(screen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_screen(&mut self, screen: Box<Screen>) {
|
pub fn replace_screen(&mut self, screen: Box<Screen>) {
|
||||||
self.pop_screen();
|
self.pop_screen();
|
||||||
self.add_screen(screen);
|
self.add_screen(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
pub fn tick(&mut self,
|
||||||
for screen in &mut self.remove_queue {
|
delta: f64,
|
||||||
if screen.active {
|
renderer: &mut render::Renderer,
|
||||||
screen.screen.on_deactive(renderer, ui_container);
|
ui_container: &mut ui::Container) {
|
||||||
}
|
for screen in &mut self.remove_queue {
|
||||||
if screen.init {
|
if screen.active {
|
||||||
screen.screen.deinit(renderer, ui_container);
|
screen.screen.on_deactive(renderer, ui_container);
|
||||||
}
|
}
|
||||||
}
|
if screen.init {
|
||||||
self.remove_queue.clear();
|
screen.screen.deinit(renderer, ui_container);
|
||||||
if self.screens.is_empty() {
|
}
|
||||||
return;
|
}
|
||||||
}
|
self.remove_queue.clear();
|
||||||
|
if self.screens.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Update state for screens
|
// Update state for screens
|
||||||
let len = self.screens.len();
|
let len = self.screens.len();
|
||||||
for screen in &mut self.screens[..len - 1] {
|
for screen in &mut self.screens[..len - 1] {
|
||||||
if screen.active {
|
if screen.active {
|
||||||
screen.active = false;
|
screen.active = false;
|
||||||
screen.screen.on_deactive(renderer, ui_container);
|
screen.screen.on_deactive(renderer, ui_container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let current = self.screens.last_mut().unwrap();
|
let current = self.screens.last_mut().unwrap();
|
||||||
if !current.init {
|
if !current.init {
|
||||||
current.init = true;
|
current.init = true;
|
||||||
current.screen.init(renderer, ui_container);
|
current.screen.init(renderer, ui_container);
|
||||||
}
|
}
|
||||||
if !current.active {
|
if !current.active {
|
||||||
current.active = true;
|
current.active = true;
|
||||||
current.screen.on_active(renderer, ui_container);
|
current.screen.on_active(renderer, ui_container);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle current
|
// Handle current
|
||||||
current.screen.tick(delta, renderer, ui_container);
|
current.screen.tick(delta, renderer, ui_container);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_scroll(&mut self, x: f64, y: f64) {
|
pub fn on_scroll(&mut self, x: f64, y: f64) {
|
||||||
if self.screens.is_empty() {
|
if self.screens.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let current = self.screens.last_mut().unwrap();
|
let current = self.screens.last_mut().unwrap();
|
||||||
current.screen.on_scroll(x, y);
|
current.screen.on_scroll(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_button(renderer: &mut render::Renderer, x: f64, y: f64, w: f64, h: f64) -> ui::Batch {
|
pub fn new_button(renderer: &mut render::Renderer, x: f64, y: f64, w: f64, h: f64) -> ui::Batch {
|
||||||
let mut batch = ui::Batch::new(x, y, w, h);
|
let mut batch = ui::Batch::new(x, y, w, h);
|
||||||
|
|
||||||
let texture = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/widgets").relative(
|
let texture = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/widgets")
|
||||||
0.0, 66.0 / 256.0, 200.0 / 256.0, 20.0 / 256.0
|
.relative(0.0, 66.0 / 256.0, 200.0 / 256.0, 20.0 / 256.0);
|
||||||
);
|
|
||||||
|
|
||||||
// Corners
|
// Corners
|
||||||
batch.add(ui::Image::new(texture.clone(), 0.0, 0.0, 4.0, 4.0, 0.0, 0.0, 2.0 / 200.0, 2.0 / 20.0, 255, 255, 255));
|
batch.add(ui::Image::new(texture.clone(),
|
||||||
batch.add(ui::Image::new(texture.clone(), w - 4.0, 0.0, 4.0, 4.0, 198.0 / 200.0, 0.0, 2.0 / 200.0, 2.0 / 20.0, 255, 255, 255));
|
0.0,
|
||||||
batch.add(ui::Image::new(texture.clone(), 0.0, h - 6.0, 4.0, 6.0, 0.0, 17.0 / 20.0, 2.0 / 200.0, 3.0 / 20.0, 255, 255, 255));
|
0.0,
|
||||||
batch.add(ui::Image::new(texture.clone(), w - 4.0, h - 6.0, 4.0, 6.0, 198.0 / 200.0, 17.0 / 20.0, 2.0 / 200.0, 3.0 / 20.0, 255, 255, 255));
|
4.0,
|
||||||
|
4.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
2.0 / 200.0,
|
||||||
|
2.0 / 20.0,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255));
|
||||||
|
batch.add(ui::Image::new(texture.clone(),
|
||||||
|
w - 4.0,
|
||||||
|
0.0,
|
||||||
|
4.0,
|
||||||
|
4.0,
|
||||||
|
198.0 / 200.0,
|
||||||
|
0.0,
|
||||||
|
2.0 / 200.0,
|
||||||
|
2.0 / 20.0,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255));
|
||||||
|
batch.add(ui::Image::new(texture.clone(),
|
||||||
|
0.0,
|
||||||
|
h - 6.0,
|
||||||
|
4.0,
|
||||||
|
6.0,
|
||||||
|
0.0,
|
||||||
|
17.0 / 20.0,
|
||||||
|
2.0 / 200.0,
|
||||||
|
3.0 / 20.0,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255));
|
||||||
|
batch.add(ui::Image::new(texture.clone(),
|
||||||
|
w - 4.0,
|
||||||
|
h - 6.0,
|
||||||
|
4.0,
|
||||||
|
6.0,
|
||||||
|
198.0 / 200.0,
|
||||||
|
17.0 / 20.0,
|
||||||
|
2.0 / 200.0,
|
||||||
|
3.0 / 20.0,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255));
|
||||||
|
|
||||||
// Widths
|
// Widths
|
||||||
batch.add(ui::Image::new(texture.clone().relative(
|
batch.add(ui::Image::new(texture.clone()
|
||||||
2.0 / 200.0, 0.0, 196.0 / 200.0, 2.0 / 20.0
|
.relative(2.0 / 200.0, 0.0, 196.0 / 200.0, 2.0 / 20.0),
|
||||||
), 4.0, 0.0, w - 8.0, 4.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255));
|
4.0,
|
||||||
batch.add(ui::Image::new(texture.clone().relative(
|
0.0,
|
||||||
2.0 / 200.0, 17.0 / 20.0, 196.0 / 200.0, 3.0 / 20.0
|
w - 8.0,
|
||||||
), 4.0, h - 6.0, w - 8.0, 6.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255));
|
4.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255));
|
||||||
|
batch.add(ui::Image::new(texture.clone().relative(2.0 / 200.0,
|
||||||
|
17.0 / 20.0,
|
||||||
|
196.0 / 200.0,
|
||||||
|
3.0 / 20.0),
|
||||||
|
4.0,
|
||||||
|
h - 6.0,
|
||||||
|
w - 8.0,
|
||||||
|
6.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255));
|
||||||
|
|
||||||
// Heights
|
// Heights
|
||||||
batch.add(ui::Image::new(texture.clone().relative(
|
batch.add(ui::Image::new(texture.clone().relative(0.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0),
|
||||||
0.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0
|
0.0,
|
||||||
), 0.0, 4.0, 4.0, h - 10.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255));
|
4.0,
|
||||||
batch.add(ui::Image::new(texture.clone().relative(
|
4.0,
|
||||||
198.0 / 200.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0
|
h - 10.0,
|
||||||
), w - 4.0, 4.0, 4.0, h - 10.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255));
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255));
|
||||||
|
batch.add(ui::Image::new(texture.clone().relative(198.0 / 200.0,
|
||||||
|
2.0 / 20.0,
|
||||||
|
2.0 / 200.0,
|
||||||
|
15.0 / 20.0),
|
||||||
|
w - 4.0,
|
||||||
|
4.0,
|
||||||
|
4.0,
|
||||||
|
h - 10.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255));
|
||||||
|
|
||||||
// Center
|
// Center
|
||||||
batch.add(ui::Image::new(texture.clone().relative(
|
batch.add(ui::Image::new(texture.clone().relative(2.0 / 200.0,
|
||||||
2.0 / 200.0, 2.0 / 20.0, 196.0 / 200.0, 15.0 / 20.0
|
2.0 / 20.0,
|
||||||
), 4.0, 4.0, w - 8.0, h - 10.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255));
|
196.0 / 200.0,
|
||||||
|
15.0 / 20.0),
|
||||||
|
4.0,
|
||||||
|
4.0,
|
||||||
|
w - 8.0,
|
||||||
|
h - 10.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255));
|
||||||
|
|
||||||
batch
|
batch
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_button_text(renderer: &mut render::Renderer, val: &str, x: f64, y: f64, w: f64, h: f64) -> (ui::Batch, ui::Text) {
|
pub fn new_button_text(renderer: &mut render::Renderer,
|
||||||
let batch = new_button(renderer, x, y, w, h);
|
val: &str,
|
||||||
let mut text = ui::Text::new(renderer, val, 0.0, 0.0, 255, 255, 255);
|
x: f64,
|
||||||
text.set_v_attach(ui::VAttach::Middle);
|
y: f64,
|
||||||
text.set_h_attach(ui::HAttach::Center);
|
w: f64,
|
||||||
(batch, text)
|
h: f64)
|
||||||
|
-> (ui::Batch, ui::Text) {
|
||||||
|
let batch = new_button(renderer, x, y, w, h);
|
||||||
|
let mut text = ui::Text::new(renderer, val, 0.0, 0.0, 255, 255, 255);
|
||||||
|
text.set_v_attach(ui::VAttach::Middle);
|
||||||
|
text.set_h_attach(ui::HAttach::Center);
|
||||||
|
(batch, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn button_action(ui_container: &mut ui::Container,
|
pub fn button_action(ui_container: &mut ui::Container,
|
||||||
btn: ui::ElementRef<ui::Batch>, txt: Option<ui::ElementRef<ui::Text>>,
|
btn: ui::ElementRef<ui::Batch>,
|
||||||
click: Option<ui::ClickFunc>
|
txt: Option<ui::ElementRef<ui::Text>>,
|
||||||
) {
|
click: Option<ui::ClickFunc>) {
|
||||||
let batch = ui_container.get_mut(&btn);
|
let batch = ui_container.get_mut(&btn);
|
||||||
batch.add_hover_func(Rc::new(move |over, game, ui_container| {
|
batch.add_hover_func(Rc::new(move |over, game, ui_container| {
|
||||||
let texture = render::Renderer::get_texture(game.renderer.get_textures_ref(), "gui/widgets").relative(
|
let texture = render::Renderer::get_texture(game.renderer.get_textures_ref(),
|
||||||
0.0, (if over { 86.0 } else { 66.0 }) / 256.0, 200.0 / 256.0, 20.0 / 256.0
|
"gui/widgets")
|
||||||
);
|
.relative(0.0,
|
||||||
|
(if over {
|
||||||
|
86.0
|
||||||
|
} else {
|
||||||
|
66.0
|
||||||
|
}) / 256.0,
|
||||||
|
200.0 / 256.0,
|
||||||
|
20.0 / 256.0);
|
||||||
|
|
||||||
{
|
{
|
||||||
let batch = ui_container.get_mut(&btn);
|
let batch = ui_container.get_mut(&btn);
|
||||||
for i in 0 .. batch.len() {
|
for i in 0..batch.len() {
|
||||||
let img = batch.get_mut_at::<ui::Image>(i);
|
let img = batch.get_mut_at::<ui::Image>(i);
|
||||||
match i {
|
match i {
|
||||||
_i @ 0 ...3 => img.set_texture(texture.clone()),
|
_i @ 0 ...3 => img.set_texture(texture.clone()),
|
||||||
4 => img.set_texture(texture.clone().relative(
|
4 => img.set_texture(texture.clone().relative(2.0 / 200.0,
|
||||||
2.0 / 200.0, 0.0, 196.0 / 200.0, 2.0 / 20.0
|
0.0,
|
||||||
)),
|
196.0 / 200.0,
|
||||||
5 => img.set_texture(texture.clone().relative(
|
2.0 / 20.0)),
|
||||||
2.0 / 200.0, 17.0 / 20.0, 196.0 / 200.0, 3.0 / 20.0
|
5 => img.set_texture(texture.clone().relative(2.0 / 200.0,
|
||||||
)),
|
17.0 / 20.0,
|
||||||
6 => img.set_texture(texture.clone().relative(
|
196.0 / 200.0,
|
||||||
0.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0
|
3.0 / 20.0)),
|
||||||
)),
|
6 => img.set_texture(texture.clone().relative(0.0,
|
||||||
7 => img.set_texture(texture.clone().relative(
|
2.0 / 20.0,
|
||||||
198.0 / 200.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0
|
2.0 / 200.0,
|
||||||
)),
|
15.0 / 20.0)),
|
||||||
8 => img.set_texture(texture.clone().relative(
|
7 => img.set_texture(texture.clone().relative(198.0 / 200.0,
|
||||||
2.0 / 200.0, 2.0 / 20.0, 196.0 / 200.0, 15.0 / 20.0
|
2.0 / 20.0,
|
||||||
)),
|
2.0 / 200.0,
|
||||||
_ => unreachable!(),
|
15.0 / 20.0)),
|
||||||
}
|
8 => img.set_texture(texture.clone().relative(2.0 / 200.0,
|
||||||
}
|
2.0 / 20.0,
|
||||||
}
|
196.0 / 200.0,
|
||||||
let txt = txt.clone();
|
15.0 / 20.0)),
|
||||||
if let Some(txt) = txt {
|
_ => unreachable!(),
|
||||||
let text = ui_container.get_mut(&txt);
|
}
|
||||||
text.set_b(if over { 160 } else { 255 });
|
}
|
||||||
}
|
}
|
||||||
}));
|
let txt = txt.clone();
|
||||||
if let Some(click) = click {
|
if let Some(txt) = txt {
|
||||||
batch.add_click_func(click);
|
let text = ui_container.get_mut(&txt);
|
||||||
}
|
text.set_b(if over {
|
||||||
}
|
160
|
||||||
|
} else {
|
||||||
|
255
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
if let Some(click) = click {
|
||||||
|
batch.add_click_func(click);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,448 +29,549 @@ use time;
|
||||||
use image;
|
use image;
|
||||||
use rustc_serialize::base64::FromBase64;
|
use rustc_serialize::base64::FromBase64;
|
||||||
use rand;
|
use rand;
|
||||||
use rand::{Rng};
|
use rand::Rng;
|
||||||
|
|
||||||
pub struct ServerList {
|
pub struct ServerList {
|
||||||
elements: Option<UIElements>,
|
elements: Option<UIElements>,
|
||||||
disconnect_reason: Option<Component>,
|
disconnect_reason: Option<Component>,
|
||||||
|
|
||||||
needs_reload: Rc<RefCell<bool>>,
|
needs_reload: Rc<RefCell<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UIElements {
|
struct UIElements {
|
||||||
logo: ui::logo::Logo,
|
logo: ui::logo::Logo,
|
||||||
elements: ui::Collection,
|
elements: ui::Collection,
|
||||||
servers: Vec<Server>,
|
servers: Vec<Server>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Server {
|
struct Server {
|
||||||
collection: ui::Collection,
|
collection: ui::Collection,
|
||||||
back: ui::ElementRef<ui::Image>,
|
back: ui::ElementRef<ui::Image>,
|
||||||
offset: f64,
|
offset: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
|
|
||||||
motd: ui::ElementRef<ui::Formatted>,
|
motd: ui::ElementRef<ui::Formatted>,
|
||||||
ping: ui::ElementRef<ui::Image>,
|
ping: ui::ElementRef<ui::Image>,
|
||||||
players: ui::ElementRef<ui::Text>,
|
players: ui::ElementRef<ui::Text>,
|
||||||
version: ui::ElementRef<ui::Formatted>,
|
version: ui::ElementRef<ui::Formatted>,
|
||||||
|
|
||||||
icon: ui::ElementRef<ui::Image>,
|
icon: ui::ElementRef<ui::Image>,
|
||||||
icon_texture: Option<String>,
|
icon_texture: Option<String>,
|
||||||
|
|
||||||
done_ping: bool,
|
done_ping: bool,
|
||||||
recv: mpsc::Receiver<PingInfo>,
|
recv: mpsc::Receiver<PingInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PingInfo {
|
struct PingInfo {
|
||||||
motd: format::Component,
|
motd: format::Component,
|
||||||
ping: time::Duration,
|
ping: time::Duration,
|
||||||
exists: bool,
|
exists: bool,
|
||||||
online: i32,
|
online: i32,
|
||||||
max: i32,
|
max: i32,
|
||||||
protocol_version: i32,
|
protocol_version: i32,
|
||||||
protocol_name: String,
|
protocol_name: String,
|
||||||
favicon: Option<image::DynamicImage>,
|
favicon: Option<image::DynamicImage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
fn update_position(&mut self) {
|
fn update_position(&mut self) {
|
||||||
if self.offset < 0.0 {
|
if self.offset < 0.0 {
|
||||||
self.y = self.offset * 200.0;
|
self.y = self.offset * 200.0;
|
||||||
} else {
|
} else {
|
||||||
self.y = self.offset * 100.0;
|
self.y = self.offset * 100.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerList {
|
impl ServerList {
|
||||||
pub fn new(disconnect_reason: Option<Component>) -> ServerList {
|
pub fn new(disconnect_reason: Option<Component>) -> ServerList {
|
||||||
ServerList {
|
ServerList {
|
||||||
elements: None,
|
elements: None,
|
||||||
disconnect_reason: disconnect_reason,
|
disconnect_reason: disconnect_reason,
|
||||||
needs_reload: Rc::new(RefCell::new(false)),
|
needs_reload: Rc::new(RefCell::new(false)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reload_server_list(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
fn reload_server_list(&mut self,
|
||||||
let elements = self.elements.as_mut().unwrap();
|
renderer: &mut render::Renderer,
|
||||||
*self.needs_reload.borrow_mut() = false;
|
ui_container: &mut ui::Container) {
|
||||||
{
|
let elements = self.elements.as_mut().unwrap();
|
||||||
|
*self.needs_reload.borrow_mut() = false;
|
||||||
|
{
|
||||||
// Clean up previous list entries and icons.
|
// Clean up previous list entries and icons.
|
||||||
let mut tex = renderer.get_textures_ref().write().unwrap();
|
let mut tex = renderer.get_textures_ref().write().unwrap();
|
||||||
for server in &mut elements.servers {
|
for server in &mut elements.servers {
|
||||||
server.collection.remove_all(ui_container);
|
server.collection.remove_all(ui_container);
|
||||||
if let Some(ref icon) = server.icon_texture {
|
if let Some(ref icon) = server.icon_texture {
|
||||||
tex.remove_dynamic("steven_icon", &icon);
|
tex.remove_dynamic("steven_icon", &icon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elements.servers.clear();
|
elements.servers.clear();
|
||||||
|
|
||||||
let file = match fs::File::open("servers.json") {
|
let file = match fs::File::open("servers.json") {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
let servers_info: serde_json::Value = serde_json::from_reader(file).unwrap();
|
let servers_info: serde_json::Value = serde_json::from_reader(file).unwrap();
|
||||||
let servers = servers_info.find("servers").unwrap().as_array().unwrap();
|
let servers = servers_info.find("servers").unwrap().as_array().unwrap();
|
||||||
let mut offset = 0.0;
|
let mut offset = 0.0;
|
||||||
|
|
||||||
// Default icon whilst we ping the servers or if the server doesn't provide one
|
// Default icon whilst we ping the servers or if the server doesn't provide one
|
||||||
let default_icon = render::Renderer::get_texture(renderer.get_textures_ref(), "misc/unknown_server");
|
let default_icon = render::Renderer::get_texture(renderer.get_textures_ref(),
|
||||||
|
"misc/unknown_server");
|
||||||
// General gui icons
|
// General gui icons
|
||||||
let icons = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/icons");
|
let icons = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/icons");
|
||||||
|
|
||||||
for svr in servers {
|
for svr in servers {
|
||||||
let name = svr.find("name").unwrap().as_string().unwrap();
|
let name = svr.find("name").unwrap().as_string().unwrap();
|
||||||
let address = svr.find("address").unwrap().as_string().unwrap().to_owned();
|
let address = svr.find("address").unwrap().as_string().unwrap().to_owned();
|
||||||
|
|
||||||
let solid = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid");
|
let solid = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid");
|
||||||
|
|
||||||
// Everything is attached to this
|
// Everything is attached to this
|
||||||
let mut back = ui::Image::new(solid, 0.0, offset * 100.0, 700.0, 100.0, 0.0, 0.0, 1.0, 1.0, 0, 0, 0);
|
let mut back = ui::Image::new(solid,
|
||||||
back.set_a(100);
|
0.0,
|
||||||
back.set_v_attach(ui::VAttach::Middle);
|
offset * 100.0,
|
||||||
back.set_h_attach(ui::HAttach::Center);
|
700.0,
|
||||||
|
100.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
back.set_a(100);
|
||||||
|
back.set_v_attach(ui::VAttach::Middle);
|
||||||
|
back.set_h_attach(ui::HAttach::Center);
|
||||||
|
|
||||||
let (send, recv) = mpsc::channel::<PingInfo>();
|
let (send, recv) = mpsc::channel::<PingInfo>();
|
||||||
let mut server = Server {
|
let mut server = Server {
|
||||||
collection: ui::Collection::new(),
|
collection: ui::Collection::new(),
|
||||||
back: ui_container.add(back),
|
back: ui_container.add(back),
|
||||||
offset: offset,
|
offset: offset,
|
||||||
y: 0.0,
|
y: 0.0,
|
||||||
done_ping: false,
|
done_ping: false,
|
||||||
recv: recv,
|
recv: recv,
|
||||||
|
|
||||||
motd: Default::default(),
|
motd: Default::default(),
|
||||||
ping: Default::default(),
|
ping: Default::default(),
|
||||||
players: Default::default(),
|
players: Default::default(),
|
||||||
version: Default::default(),
|
version: Default::default(),
|
||||||
|
|
||||||
icon: Default::default(),
|
icon: Default::default(),
|
||||||
icon_texture: None,
|
icon_texture: None,
|
||||||
};
|
};
|
||||||
server.collection.add(server.back.clone());
|
server.collection.add(server.back.clone());
|
||||||
server.update_position();
|
server.update_position();
|
||||||
// Make whole entry interactable
|
// Make whole entry interactable
|
||||||
{
|
{
|
||||||
let back = ui_container.get_mut(&server.back);
|
let back = ui_container.get_mut(&server.back);
|
||||||
let back_ref = server.back.clone();
|
let back_ref = server.back.clone();
|
||||||
let address = address.clone();
|
let address = address.clone();
|
||||||
back.add_hover_func(Rc::new(move |over, _, ui_container| {
|
back.add_hover_func(Rc::new(move |over, _, ui_container| {
|
||||||
let back = ui_container.get_mut(&back_ref);
|
let back = ui_container.get_mut(&back_ref);
|
||||||
back.set_a(if over { 200 } else { 100 });
|
back.set_a(if over {
|
||||||
}));
|
200
|
||||||
|
} else {
|
||||||
|
100
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
back.add_click_func(Rc::new(move |_, _| {
|
back.add_click_func(Rc::new(move |_, _| {
|
||||||
println!("Connecting to {}", address);
|
println!("Connecting to {}", address);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server name
|
// Server name
|
||||||
let mut text = ui::Text::new(renderer, &name, 100.0, 5.0, 255, 255, 255);
|
let mut text = ui::Text::new(renderer, &name, 100.0, 5.0, 255, 255, 255);
|
||||||
text.set_parent(&server.back);
|
text.set_parent(&server.back);
|
||||||
server.collection.add(ui_container.add(text));
|
server.collection.add(ui_container.add(text));
|
||||||
|
|
||||||
// Server icon
|
// Server icon
|
||||||
let mut icon = ui::Image::new(default_icon.clone(), 5.0, 5.0, 90.0, 90.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255);
|
let mut icon = ui::Image::new(default_icon.clone(),
|
||||||
icon.set_parent(&server.back);
|
5.0,
|
||||||
server.icon = server.collection.add(ui_container.add(icon));
|
5.0,
|
||||||
|
90.0,
|
||||||
|
90.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255);
|
||||||
|
icon.set_parent(&server.back);
|
||||||
|
server.icon = server.collection.add(ui_container.add(icon));
|
||||||
|
|
||||||
// Ping indicator
|
// Ping indicator
|
||||||
let mut ping = ui::Image::new(icons.clone(), 5.0, 5.0, 20.0, 16.0, 0.0, 56.0/256.0, 10.0/256.0, 8.0/256.0, 255, 255, 255);
|
let mut ping = ui::Image::new(icons.clone(),
|
||||||
ping.set_h_attach(ui::HAttach::Right);
|
5.0,
|
||||||
ping.set_parent(&server.back);
|
5.0,
|
||||||
server.ping = server.collection.add(ui_container.add(ping));
|
20.0,
|
||||||
|
16.0,
|
||||||
|
0.0,
|
||||||
|
56.0 / 256.0,
|
||||||
|
10.0 / 256.0,
|
||||||
|
8.0 / 256.0,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255);
|
||||||
|
ping.set_h_attach(ui::HAttach::Right);
|
||||||
|
ping.set_parent(&server.back);
|
||||||
|
server.ping = server.collection.add(ui_container.add(ping));
|
||||||
|
|
||||||
// Player count
|
// Player count
|
||||||
let mut players = ui::Text::new(renderer, "???", 30.0, 5.0, 255, 255, 255);
|
let mut players = ui::Text::new(renderer, "???", 30.0, 5.0, 255, 255, 255);
|
||||||
players.set_h_attach(ui::HAttach::Right);
|
players.set_h_attach(ui::HAttach::Right);
|
||||||
players.set_parent(&server.back);
|
players.set_parent(&server.back);
|
||||||
server.players = server.collection.add(ui_container.add(players));
|
server.players = server.collection.add(ui_container.add(players));
|
||||||
|
|
||||||
// Server's message of the day
|
// Server's message of the day
|
||||||
let mut motd = ui::Formatted::with_width_limit(renderer, Component::Text(TextComponent::new("Connecting...")), 100.0, 23.0, 700.0 - (90.0 + 10.0 + 5.0));
|
let mut motd =
|
||||||
motd.set_parent(&server.back);
|
ui::Formatted::with_width_limit(renderer,
|
||||||
server.motd = server.collection.add(ui_container.add(motd));
|
Component::Text(TextComponent::new("Connecting.\
|
||||||
|
..")),
|
||||||
|
100.0,
|
||||||
|
23.0,
|
||||||
|
700.0 - (90.0 + 10.0 + 5.0));
|
||||||
|
motd.set_parent(&server.back);
|
||||||
|
server.motd = server.collection.add(ui_container.add(motd));
|
||||||
|
|
||||||
// Version information
|
// Version information
|
||||||
let mut version = ui::Formatted::with_width_limit(renderer, Component::Text(TextComponent::new("")), 100.0, 5.0, 700.0 - (90.0 + 10.0 + 5.0));
|
let mut version =
|
||||||
version.set_v_attach(ui::VAttach::Bottom);
|
ui::Formatted::with_width_limit(renderer,
|
||||||
version.set_parent(&server.back);
|
Component::Text(TextComponent::new("")),
|
||||||
server.version = server.collection.add(ui_container.add(version));
|
100.0,
|
||||||
|
5.0,
|
||||||
|
700.0 - (90.0 + 10.0 + 5.0));
|
||||||
|
version.set_v_attach(ui::VAttach::Bottom);
|
||||||
|
version.set_parent(&server.back);
|
||||||
|
server.version = server.collection.add(ui_container.add(version));
|
||||||
|
|
||||||
// Delete entry button
|
// Delete entry button
|
||||||
let (mut del, mut txt) = super::new_button_text(renderer, "X", 0.0, 0.0, 25.0, 25.0);
|
let (mut del, mut txt) = super::new_button_text(renderer, "X", 0.0, 0.0, 25.0, 25.0);
|
||||||
del.set_v_attach(ui::VAttach::Bottom);
|
del.set_v_attach(ui::VAttach::Bottom);
|
||||||
del.set_h_attach(ui::HAttach::Right);
|
del.set_h_attach(ui::HAttach::Right);
|
||||||
del.set_parent(&server.back);
|
del.set_parent(&server.back);
|
||||||
let re = ui_container.add(del);
|
let re = ui_container.add(del);
|
||||||
txt.set_parent(&re);
|
txt.set_parent(&re);
|
||||||
let tre = ui_container.add(txt);
|
let tre = ui_container.add(txt);
|
||||||
super::button_action(ui_container, re.clone(), Some(tre.clone()), None);
|
super::button_action(ui_container, re.clone(), Some(tre.clone()), None);
|
||||||
server.collection.add(re);
|
server.collection.add(re);
|
||||||
server.collection.add(tre);
|
server.collection.add(tre);
|
||||||
|
|
||||||
// Edit entry button
|
// Edit entry button
|
||||||
let (mut edit, mut txt) = super::new_button_text(renderer, "E", 25.0, 0.0, 25.0, 25.0);
|
let (mut edit, mut txt) = super::new_button_text(renderer, "E", 25.0, 0.0, 25.0, 25.0);
|
||||||
edit.set_v_attach(ui::VAttach::Bottom);
|
edit.set_v_attach(ui::VAttach::Bottom);
|
||||||
edit.set_h_attach(ui::HAttach::Right);
|
edit.set_h_attach(ui::HAttach::Right);
|
||||||
edit.set_parent(&server.back);
|
edit.set_parent(&server.back);
|
||||||
let re = ui_container.add(edit);
|
let re = ui_container.add(edit);
|
||||||
txt.set_parent(&re);
|
txt.set_parent(&re);
|
||||||
let tre = ui_container.add(txt);
|
let tre = ui_container.add(txt);
|
||||||
super::button_action(ui_container, re.clone(), Some(tre.clone()), None);
|
super::button_action(ui_container, re.clone(), Some(tre.clone()), None);
|
||||||
server.collection.add(re);
|
server.collection.add(re);
|
||||||
server.collection.add(tre);
|
server.collection.add(tre);
|
||||||
|
|
||||||
elements.servers.push(server);
|
elements.servers.push(server);
|
||||||
offset += 1.0;
|
offset += 1.0;
|
||||||
|
|
||||||
// Don't block the main thread whilst pinging the server
|
// Don't block the main thread whilst pinging the server
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
match protocol::Conn::new(&address).and_then(|conn| conn.do_status()) {
|
match protocol::Conn::new(&address).and_then(|conn| conn.do_status()) {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
let mut desc = res.0.description;
|
let mut desc = res.0.description;
|
||||||
format::convert_legacy(&mut desc);
|
format::convert_legacy(&mut desc);
|
||||||
let favicon = if let Some(icon) = res.0.favicon {
|
let favicon = if let Some(icon) = res.0.favicon {
|
||||||
let data = icon["data:image/png;base64,".len()..].from_base64().unwrap();
|
let data = icon["data:image/png;base64,".len()..]
|
||||||
Some(image::load_from_memory(
|
.from_base64()
|
||||||
&data
|
.unwrap();
|
||||||
).unwrap())
|
Some(image::load_from_memory(&data).unwrap())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
drop(send.send(PingInfo {
|
drop(send.send(PingInfo {
|
||||||
motd: desc,
|
motd: desc,
|
||||||
ping: res.1,
|
ping: res.1,
|
||||||
exists: true,
|
exists: true,
|
||||||
online: res.0.players.online,
|
online: res.0.players.online,
|
||||||
max: res.0.players.max,
|
max: res.0.players.max,
|
||||||
protocol_version: res.0.version.protocol,
|
protocol_version: res.0.version.protocol,
|
||||||
protocol_name: res.0.version.name,
|
protocol_name: res.0.version.name,
|
||||||
favicon: favicon,
|
favicon: favicon,
|
||||||
}));
|
}));
|
||||||
},
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let e = format!("{}", err);
|
let e = format!("{}", err);
|
||||||
let mut msg = TextComponent::new(&e);
|
let mut msg = TextComponent::new(&e);
|
||||||
msg.modifier.color = Some(format::Color::Red);
|
msg.modifier.color = Some(format::Color::Red);
|
||||||
drop(send.send(PingInfo {
|
drop(send.send(PingInfo {
|
||||||
motd: Component::Text(msg),
|
motd: Component::Text(msg),
|
||||||
ping: time::Duration::seconds(99999),
|
ping: time::Duration::seconds(99999),
|
||||||
exists: false,
|
exists: false,
|
||||||
online: 0,
|
online: 0,
|
||||||
max: 0,
|
max: 0,
|
||||||
protocol_version: 0,
|
protocol_version: 0,
|
||||||
protocol_name: "".to_owned(),
|
protocol_name: "".to_owned(),
|
||||||
favicon: None,
|
favicon: None,
|
||||||
}));
|
}));
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Screen for ServerList {
|
impl super::Screen for ServerList {
|
||||||
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||||
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container);
|
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container);
|
||||||
let mut elements = ui::Collection::new();
|
let mut elements = ui::Collection::new();
|
||||||
|
|
||||||
// Refresh the server list
|
// Refresh the server list
|
||||||
let (mut refresh, mut txt) = super::new_button_text(renderer, "Refresh", 300.0, -50.0-15.0, 100.0, 30.0);
|
let (mut refresh, mut txt) = super::new_button_text(renderer,
|
||||||
refresh.set_v_attach(ui::VAttach::Middle);
|
"Refresh",
|
||||||
refresh.set_h_attach(ui::HAttach::Center);
|
300.0,
|
||||||
let re = ui_container.add(refresh);
|
-50.0 - 15.0,
|
||||||
txt.set_parent(&re);
|
100.0,
|
||||||
let tre = ui_container.add(txt);
|
30.0);
|
||||||
let nr = self.needs_reload.clone();
|
refresh.set_v_attach(ui::VAttach::Middle);
|
||||||
super::button_action(ui_container, re.clone(), Some(tre.clone()), Some(Rc::new(move |_, _| {
|
refresh.set_h_attach(ui::HAttach::Center);
|
||||||
*nr.borrow_mut() = true;
|
let re = ui_container.add(refresh);
|
||||||
})));
|
txt.set_parent(&re);
|
||||||
elements.add(re);
|
let tre = ui_container.add(txt);
|
||||||
elements.add(tre);
|
let nr = self.needs_reload.clone();
|
||||||
|
super::button_action(ui_container,
|
||||||
|
re.clone(),
|
||||||
|
Some(tre.clone()),
|
||||||
|
Some(Rc::new(move |_, _| {
|
||||||
|
*nr.borrow_mut() = true;
|
||||||
|
})));
|
||||||
|
elements.add(re);
|
||||||
|
elements.add(tre);
|
||||||
|
|
||||||
// Add a new server to the list
|
// Add a new server to the list
|
||||||
let (mut add, mut txt) = super::new_button_text(renderer, "Add", 200.0, -50.0-15.0, 100.0, 30.0);
|
let (mut add, mut txt) = super::new_button_text(renderer,
|
||||||
add.set_v_attach(ui::VAttach::Middle);
|
"Add",
|
||||||
add.set_h_attach(ui::HAttach::Center);
|
200.0,
|
||||||
let re = ui_container.add(add);
|
-50.0 - 15.0,
|
||||||
txt.set_parent(&re);
|
100.0,
|
||||||
let tre = ui_container.add(txt);
|
30.0);
|
||||||
super::button_action(ui_container, re.clone(), Some(tre.clone()), None);
|
add.set_v_attach(ui::VAttach::Middle);
|
||||||
elements.add(re);
|
add.set_h_attach(ui::HAttach::Center);
|
||||||
elements.add(tre);
|
let re = ui_container.add(add);
|
||||||
|
txt.set_parent(&re);
|
||||||
|
let tre = ui_container.add(txt);
|
||||||
|
super::button_action(ui_container, re.clone(), Some(tre.clone()), None);
|
||||||
|
elements.add(re);
|
||||||
|
elements.add(tre);
|
||||||
|
|
||||||
// Options menu
|
// Options menu
|
||||||
let mut options = super::new_button(renderer, 5.0, 25.0, 40.0, 40.0);
|
let mut options = super::new_button(renderer, 5.0, 25.0, 40.0, 40.0);
|
||||||
options.set_v_attach(ui::VAttach::Bottom);
|
options.set_v_attach(ui::VAttach::Bottom);
|
||||||
options.set_h_attach(ui::HAttach::Right);
|
options.set_h_attach(ui::HAttach::Right);
|
||||||
let re = ui_container.add(options);
|
let re = ui_container.add(options);
|
||||||
let mut cog = ui::Image::new(render::Renderer::get_texture(renderer.get_textures_ref(), "steven:gui/cog"), 0.0, 0.0, 40.0, 40.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255);
|
let mut cog = ui::Image::new(render::Renderer::get_texture(renderer.get_textures_ref(),
|
||||||
cog.set_parent(&re);
|
"steven:gui/cog"),
|
||||||
cog.set_v_attach(ui::VAttach::Middle);
|
0.0,
|
||||||
cog.set_h_attach(ui::HAttach::Center);
|
0.0,
|
||||||
super::button_action(ui_container, re.clone(), None, None);
|
40.0,
|
||||||
elements.add(re);
|
40.0,
|
||||||
elements.add(ui_container.add(cog));
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255);
|
||||||
|
cog.set_parent(&re);
|
||||||
|
cog.set_v_attach(ui::VAttach::Middle);
|
||||||
|
cog.set_h_attach(ui::HAttach::Center);
|
||||||
|
super::button_action(ui_container, re.clone(), None, None);
|
||||||
|
elements.add(re);
|
||||||
|
elements.add(ui_container.add(cog));
|
||||||
|
|
||||||
// Disclaimer
|
// Disclaimer
|
||||||
let mut warn = ui::Text::new(renderer, "Not affiliated with Mojang/Minecraft", 5.0, 5.0, 255, 200, 200);
|
let mut warn = ui::Text::new(renderer,
|
||||||
warn.set_v_attach(ui::VAttach::Bottom);
|
"Not affiliated with Mojang/Minecraft",
|
||||||
warn.set_h_attach(ui::HAttach::Right);
|
5.0,
|
||||||
elements.add(ui_container.add(warn));
|
5.0,
|
||||||
|
255,
|
||||||
|
200,
|
||||||
|
200);
|
||||||
|
warn.set_v_attach(ui::VAttach::Bottom);
|
||||||
|
warn.set_h_attach(ui::HAttach::Right);
|
||||||
|
elements.add(ui_container.add(warn));
|
||||||
|
|
||||||
// If we are kicked from a server display the reason
|
// If we are kicked from a server display the reason
|
||||||
if let Some(ref disconnect_reason) = self.disconnect_reason {
|
if let Some(ref disconnect_reason) = self.disconnect_reason {
|
||||||
let mut dis_msg = ui::Text::new(renderer, "Disconnected", 0.0, 32.0, 255, 0, 0);
|
let mut dis_msg = ui::Text::new(renderer, "Disconnected", 0.0, 32.0, 255, 0, 0);
|
||||||
dis_msg.set_h_attach(ui::HAttach::Center);
|
dis_msg.set_h_attach(ui::HAttach::Center);
|
||||||
let mut dis = ui::Formatted::with_width_limit(renderer, disconnect_reason.clone(), 0.0, 48.0, 600.0);
|
let mut dis = ui::Formatted::with_width_limit(renderer,
|
||||||
dis.set_h_attach(ui::HAttach::Center);
|
disconnect_reason.clone(),
|
||||||
let mut back = ui::Image::new(
|
0.0,
|
||||||
render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"),
|
48.0,
|
||||||
0.0, 30.0,
|
600.0);
|
||||||
dis.get_width().max(dis_msg.get_width()) + 4.0, dis.get_height() + 4.0 + 16.0,
|
dis.set_h_attach(ui::HAttach::Center);
|
||||||
0.0, 0.0, 1.0, 1.0,
|
let mut back =
|
||||||
0, 0, 0
|
ui::Image::new(render::Renderer::get_texture(renderer.get_textures_ref(),
|
||||||
);
|
"steven:solid"),
|
||||||
back.set_a(100);
|
0.0,
|
||||||
back.set_h_attach(ui::HAttach::Center);
|
30.0,
|
||||||
elements.add(ui_container.add(back));
|
dis.get_width().max(dis_msg.get_width()) + 4.0,
|
||||||
elements.add(ui_container.add(dis));
|
dis.get_height() + 4.0 + 16.0,
|
||||||
elements.add(ui_container.add(dis_msg));
|
0.0,
|
||||||
}
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
back.set_a(100);
|
||||||
|
back.set_h_attach(ui::HAttach::Center);
|
||||||
|
elements.add(ui_container.add(back));
|
||||||
|
elements.add(ui_container.add(dis));
|
||||||
|
elements.add(ui_container.add(dis_msg));
|
||||||
|
}
|
||||||
|
|
||||||
self.elements = Some(UIElements {
|
self.elements = Some(UIElements {
|
||||||
logo: logo,
|
logo: logo,
|
||||||
elements: elements,
|
elements: elements,
|
||||||
servers: Vec::new(),
|
servers: Vec::new(),
|
||||||
});
|
});
|
||||||
self.reload_server_list(renderer, ui_container);
|
self.reload_server_list(renderer, ui_container);
|
||||||
}
|
}
|
||||||
fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||||
// Clean up
|
// Clean up
|
||||||
{
|
{
|
||||||
let elements = self.elements.as_mut().unwrap();
|
let elements = self.elements.as_mut().unwrap();
|
||||||
elements.logo.remove(ui_container);
|
elements.logo.remove(ui_container);
|
||||||
elements.elements.remove_all(ui_container);
|
elements.elements.remove_all(ui_container);
|
||||||
for server in &mut elements.servers {
|
for server in &mut elements.servers {
|
||||||
server.collection.remove_all(ui_container);
|
server.collection.remove_all(ui_container);
|
||||||
}
|
}
|
||||||
elements.servers.clear();
|
elements.servers.clear();
|
||||||
}
|
}
|
||||||
self.elements = None
|
self.elements = None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
fn tick(&mut self,
|
||||||
if *self.needs_reload.borrow() {
|
delta: f64,
|
||||||
self.reload_server_list(renderer, ui_container);
|
renderer: &mut render::Renderer,
|
||||||
}
|
ui_container: &mut ui::Container) {
|
||||||
let elements = self.elements.as_mut().unwrap();
|
if *self.needs_reload.borrow() {
|
||||||
|
self.reload_server_list(renderer, ui_container);
|
||||||
|
}
|
||||||
|
let elements = self.elements.as_mut().unwrap();
|
||||||
|
|
||||||
elements.logo.tick(renderer, ui_container);
|
elements.logo.tick(renderer, ui_container);
|
||||||
|
|
||||||
for s in &mut elements.servers {
|
for s in &mut elements.servers {
|
||||||
// Animate the entries
|
// Animate the entries
|
||||||
{
|
{
|
||||||
let back = ui_container.get_mut(&s.back);
|
let back = ui_container.get_mut(&s.back);
|
||||||
let dy = s.y - back.get_y();
|
let dy = s.y - back.get_y();
|
||||||
if dy*dy > 1.0 {
|
if dy * dy > 1.0 {
|
||||||
let y = back.get_y();
|
let y = back.get_y();
|
||||||
back.set_y(y + delta * dy * 0.1);
|
back.set_y(y + delta * dy * 0.1);
|
||||||
} else {
|
} else {
|
||||||
back.set_y(s.y);
|
back.set_y(s.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep checking to see if the server has finished being
|
// Keep checking to see if the server has finished being
|
||||||
// pinged
|
// pinged
|
||||||
if !s.done_ping {
|
if !s.done_ping {
|
||||||
match s.recv.try_recv() {
|
match s.recv.try_recv() {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
s.done_ping = true;
|
s.done_ping = true;
|
||||||
{
|
{
|
||||||
let motd = ui_container.get_mut(&s.motd);
|
let motd = ui_container.get_mut(&s.motd);
|
||||||
motd.set_component(renderer, res.motd);
|
motd.set_component(renderer, res.motd);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let ping = ui_container.get_mut(&s.ping);
|
let ping = ui_container.get_mut(&s.ping);
|
||||||
// Selects the icon for the given ping range
|
// Selects the icon for the given ping range
|
||||||
let y = match res.ping.num_milliseconds() {
|
let y = match res.ping.num_milliseconds() {
|
||||||
_x @ 0 ... 75 => 16.0 / 256.0,
|
_x @ 0 ... 75 => 16.0 / 256.0,
|
||||||
_x @ 76 ... 150 => 24.0 / 256.0,
|
_x @ 76 ... 150 => 24.0 / 256.0,
|
||||||
_x @ 151 ... 225 => 32.0 / 256.0,
|
_x @ 151 ... 225 => 32.0 / 256.0,
|
||||||
_x @ 226 ... 350 => 40.0 / 256.0,
|
_x @ 226 ... 350 => 40.0 / 256.0,
|
||||||
_x @ 351 ... 999 => 48.0 / 256.0,
|
_x @ 351 ... 999 => 48.0 / 256.0,
|
||||||
_ => 56.0 / 256.0,
|
_ => 56.0 / 256.0,
|
||||||
};
|
};
|
||||||
ping.set_t_y(y);
|
ping.set_t_y(y);
|
||||||
}
|
}
|
||||||
if res.exists {
|
if res.exists {
|
||||||
{
|
{
|
||||||
let players = ui_container.get_mut(&s.players);
|
let players = ui_container.get_mut(&s.players);
|
||||||
let txt = if res.protocol_version == protocol::SUPPORTED_PROTOCOL {
|
let txt = if res.protocol_version == protocol::SUPPORTED_PROTOCOL {
|
||||||
players.set_g(255);
|
players.set_g(255);
|
||||||
players.set_b(255);
|
players.set_b(255);
|
||||||
format!("{}/{}", res.online, res.max)
|
format!("{}/{}", res.online, res.max)
|
||||||
} else {
|
} else {
|
||||||
players.set_g(85);
|
players.set_g(85);
|
||||||
players.set_b(85);
|
players.set_b(85);
|
||||||
format!("Out of date {}/{}", res.online, res.max)
|
format!("Out of date {}/{}", res.online, res.max)
|
||||||
};
|
};
|
||||||
players.set_text(renderer, &txt);
|
players.set_text(renderer, &txt);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let version = ui_container.get_mut(&s.version);
|
let version = ui_container.get_mut(&s.version);
|
||||||
let mut txt = TextComponent::new(&res.protocol_name);
|
let mut txt = TextComponent::new(&res.protocol_name);
|
||||||
txt.modifier.color = Some(format::Color::Yellow);
|
txt.modifier.color = Some(format::Color::Yellow);
|
||||||
let mut msg = Component::Text(txt);
|
let mut msg = Component::Text(txt);
|
||||||
format::convert_legacy(&mut msg);
|
format::convert_legacy(&mut msg);
|
||||||
version.set_component(renderer, msg);
|
version.set_component(renderer, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(favicon) = res.favicon {
|
if let Some(favicon) = res.favicon {
|
||||||
let name: String = rand::thread_rng().gen_ascii_chars().take(30).collect();
|
let name: String = rand::thread_rng()
|
||||||
let tex = renderer.get_textures_ref();
|
.gen_ascii_chars()
|
||||||
s.icon_texture = Some(name.clone());
|
.take(30)
|
||||||
let icon_tex = tex.write().unwrap().put_dynamic("steven_icon", &name, favicon);
|
.collect();
|
||||||
let icon = ui_container.get_mut(&s.icon);
|
let tex = renderer.get_textures_ref();
|
||||||
icon.set_texture(icon_tex);
|
s.icon_texture = Some(name.clone());
|
||||||
}
|
let icon_tex = tex.write()
|
||||||
},
|
.unwrap()
|
||||||
Err(mpsc::TryRecvError::Disconnected) => {
|
.put_dynamic("steven_icon", &name, favicon);
|
||||||
s.done_ping = true;
|
let icon = ui_container.get_mut(&s.icon);
|
||||||
let motd = ui_container.get_mut(&s.motd);
|
icon.set_texture(icon_tex);
|
||||||
let mut txt = TextComponent::new("Channel dropped");
|
}
|
||||||
txt.modifier.color = Some(format::Color::Red);
|
}
|
||||||
motd.set_component(renderer, Component::Text(txt));
|
Err(mpsc::TryRecvError::Disconnected) => {
|
||||||
},
|
s.done_ping = true;
|
||||||
_ => {}
|
let motd = ui_container.get_mut(&s.motd);
|
||||||
}
|
let mut txt = TextComponent::new("Channel dropped");
|
||||||
}
|
txt.modifier.color = Some(format::Color::Red);
|
||||||
}
|
motd.set_component(renderer, Component::Text(txt));
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn on_scroll(&mut self, _: f64, y: f64) {
|
fn on_scroll(&mut self, _: f64, y: f64) {
|
||||||
let elements = self.elements.as_mut().unwrap();
|
let elements = self.elements.as_mut().unwrap();
|
||||||
if elements.servers.is_empty() {
|
if elements.servers.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut diff = y / 1.0;
|
let mut diff = y / 1.0;
|
||||||
{
|
{
|
||||||
let last = elements.servers.last().unwrap();
|
let last = elements.servers.last().unwrap();
|
||||||
if last.offset+diff <= 2.0 {
|
if last.offset + diff <= 2.0 {
|
||||||
diff = 2.0 - last.offset;
|
diff = 2.0 - last.offset;
|
||||||
}
|
}
|
||||||
let first = elements.servers.first().unwrap();
|
let first = elements.servers.first().unwrap();
|
||||||
if first.offset + diff >= 0.0 {
|
if first.offset + diff >= 0.0 {
|
||||||
diff = -first.offset;
|
diff = -first.offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for s in &mut elements.servers {
|
for s in &mut elements.servers {
|
||||||
s.offset += diff;
|
s.offset += diff;
|
||||||
s.update_position();
|
s.update_position();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,14 @@
|
||||||
pub struct Map {
|
pub struct Map {
|
||||||
bits: Vec<u64>,
|
bits: Vec<u64>,
|
||||||
bit_size: usize,
|
bit_size: usize,
|
||||||
length: usize
|
length: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_map() {
|
fn test_map() {
|
||||||
let mut map = Map::new(4096, 4);
|
let mut map = Map::new(4096, 4);
|
||||||
for i in 0 .. 4096 {
|
for i in 0..4096 {
|
||||||
for j in 0 .. 16 {
|
for j in 0..16 {
|
||||||
map.set(i, j);
|
map.set(i, j);
|
||||||
if map.get(i) != j {
|
if map.get(i) != j {
|
||||||
panic!("Fail");
|
panic!("Fail");
|
||||||
|
@ -33,11 +33,11 @@ fn test_map() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_map_odd() {
|
fn test_map_odd() {
|
||||||
for size in 1 .. 16 {
|
for size in 1..16 {
|
||||||
let mut map = Map::new(64*3, size);
|
let mut map = Map::new(64 * 3, size);
|
||||||
let max = (1 << size) - 1;
|
let max = (1 << size) - 1;
|
||||||
for i in 0 .. 64*3 {
|
for i in 0..64 * 3 {
|
||||||
for j in 0 .. max {
|
for j in 0..max {
|
||||||
map.set(i, j);
|
map.set(i, j);
|
||||||
if map.get(i) != j {
|
if map.get(i) != j {
|
||||||
panic!("Index: {} wanted {} and got {}", i, j, map.get(i));
|
panic!("Index: {} wanted {} and got {}", i, j, map.get(i));
|
||||||
|
@ -52,9 +52,9 @@ impl Map {
|
||||||
let mut map = Map {
|
let mut map = Map {
|
||||||
bit_size: size,
|
bit_size: size,
|
||||||
length: len,
|
length: len,
|
||||||
bits: Vec::with_capacity((len*size)/64)
|
bits: Vec::with_capacity((len * size) / 64),
|
||||||
};
|
};
|
||||||
for _ in 0 .. len {
|
for _ in 0..len {
|
||||||
map.bits.push(0)
|
map.bits.push(0)
|
||||||
}
|
}
|
||||||
map
|
map
|
||||||
|
@ -62,7 +62,7 @@ impl Map {
|
||||||
|
|
||||||
pub fn resize(self, size: usize) -> Map {
|
pub fn resize(self, size: usize) -> Map {
|
||||||
let mut n = Map::new(self.length, size);
|
let mut n = Map::new(self.length, size);
|
||||||
for i in 0 .. self.length {
|
for i in 0..self.length {
|
||||||
n.set(i, self.get(i));
|
n.set(i, self.get(i));
|
||||||
}
|
}
|
||||||
n
|
n
|
||||||
|
@ -73,7 +73,7 @@ impl Map {
|
||||||
let pos = i / 64;
|
let pos = i / 64;
|
||||||
let mask = (1 << self.bit_size) - 1;
|
let mask = (1 << self.bit_size) - 1;
|
||||||
let ii = i % 64;
|
let ii = i % 64;
|
||||||
self.bits[pos] = (self.bits[pos] & !(mask << ii )) | ((val << ii) as u64);
|
self.bits[pos] = (self.bits[pos] & !(mask << ii)) | ((val << ii) as u64);
|
||||||
let pos2 = (i + self.bit_size - 1) / 64;
|
let pos2 = (i + self.bit_size - 1) / 64;
|
||||||
if pos2 != pos {
|
if pos2 != pos {
|
||||||
let used = 64 - ii;
|
let used = 64 - ii;
|
||||||
|
|
|
@ -13,19 +13,19 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
pub struct Set {
|
pub struct Set {
|
||||||
data : Vec<u64>
|
data: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_set() {
|
fn test_set() {
|
||||||
let mut set = Set::new(200);
|
let mut set = Set::new(200);
|
||||||
for i in 0 .. 200 {
|
for i in 0..200 {
|
||||||
if i % 3 == 0 {
|
if i % 3 == 0 {
|
||||||
set.set(i, true)
|
set.set(i, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i in 0 .. 200 {
|
for i in 0..200 {
|
||||||
if set.get(i) != (i%3 == 0) {
|
if set.get(i) != (i % 3 == 0) {
|
||||||
panic!("Fail")
|
panic!("Fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,10 +33,8 @@ fn test_set() {
|
||||||
|
|
||||||
impl Set {
|
impl Set {
|
||||||
pub fn new(size: usize) -> Set {
|
pub fn new(size: usize) -> Set {
|
||||||
let mut set = Set {
|
let mut set = Set { data: Vec::with_capacity(size) };
|
||||||
data: Vec::with_capacity(size)
|
for _ in 0..size {
|
||||||
};
|
|
||||||
for _ in 0 .. size {
|
|
||||||
set.data.push(0)
|
set.data.push(0)
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
|
@ -44,13 +42,13 @@ impl Set {
|
||||||
|
|
||||||
pub fn set(&mut self, i: usize, v: bool) {
|
pub fn set(&mut self, i: usize, v: bool) {
|
||||||
if v {
|
if v {
|
||||||
self.data[i>>6] |= 1 << (i & 0x3F)
|
self.data[i >> 6] |= 1 << (i & 0x3F)
|
||||||
} else {
|
} else {
|
||||||
self.data[i>>6] &= !(1 << (i & 0x3F))
|
self.data[i >> 6] &= !(1 << (i & 0x3F))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&mut self, i: usize) -> bool {
|
pub fn get(&mut self, i: usize) -> bool {
|
||||||
(self.data[i>>6] & (1 << (i & 0x3F))) != 0
|
(self.data[i >> 6] & (1 << (i & 0x3F))) != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use protocol::{Serializable};
|
use protocol::Serializable;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
||||||
|
@ -26,11 +26,8 @@ pub struct Position(u64);
|
||||||
impl Position {
|
impl Position {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn new(x: i32, y: i32, z: i32) -> Position {
|
fn new(x: i32, y: i32, z: i32) -> Position {
|
||||||
Position(
|
Position((((x as u64) & 0x3FFFFFF) << 38) | (((y as u64) & 0xFFF) << 26) |
|
||||||
(((x as u64) & 0x3FFFFFF) << 38) |
|
((z as u64) & 0x3FFFFFF))
|
||||||
(((y as u64) & 0xFFF) << 26) |
|
|
||||||
((z as u64) & 0x3FFFFFF)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_x(&self) -> i32 {
|
fn get_x(&self) -> i32 {
|
||||||
|
|
|
@ -18,7 +18,7 @@ use std::io;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use protocol;
|
use protocol;
|
||||||
use protocol::{Serializable};
|
use protocol::Serializable;
|
||||||
use format;
|
use format;
|
||||||
use item;
|
use item;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ pub struct MetadataKey<T: MetaValue> {
|
||||||
impl <T: MetaValue> MetadataKey<T> {
|
impl <T: MetaValue> MetadataKey<T> {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
// TODO: Make const later when possible
|
// TODO: Make const later when possible
|
||||||
/*const*/ fn new(index: i32) -> MetadataKey<T> {
|
/*const*/ fn new(index: i32) -> MetadataKey<T> {
|
||||||
MetadataKey {
|
MetadataKey {
|
||||||
index: index,
|
index: index,
|
||||||
ty: PhantomData,
|
ty: PhantomData,
|
||||||
|
@ -78,11 +78,10 @@ impl Serializable for Metadata {
|
||||||
4 => m.put_raw(index, try!(format::Component::read_from(buf))),
|
4 => m.put_raw(index, try!(format::Component::read_from(buf))),
|
||||||
5 => m.put_raw(index, try!(Option::<item::Stack>::read_from(buf))),
|
5 => m.put_raw(index, try!(Option::<item::Stack>::read_from(buf))),
|
||||||
6 => m.put_raw(index, try!(bool::read_from(buf))),
|
6 => m.put_raw(index, try!(bool::read_from(buf))),
|
||||||
7 => m.put_raw(index, [
|
7 => m.put_raw(index,
|
||||||
try!(f32::read_from(buf)),
|
[try!(f32::read_from(buf)),
|
||||||
try!(f32::read_from(buf)),
|
try!(f32::read_from(buf)),
|
||||||
try!(f32::read_from(buf))
|
try!(f32::read_from(buf))]),
|
||||||
]),
|
|
||||||
8 => m.put_raw(index, try!(super::Position::read_from(buf))),
|
8 => m.put_raw(index, try!(super::Position::read_from(buf))),
|
||||||
9 => {
|
9 => {
|
||||||
if try!(bool::read_from(buf)) {
|
if try!(bool::read_from(buf)) {
|
||||||
|
@ -90,7 +89,7 @@ impl Serializable for Metadata {
|
||||||
} else {
|
} else {
|
||||||
m.put_raw::<Option<super::Position>>(index, None);
|
m.put_raw::<Option<super::Position>>(index, None);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
10 => m.put_raw(index, try!(protocol::VarInt::read_from(buf))),
|
10 => m.put_raw(index, try!(protocol::VarInt::read_from(buf))),
|
||||||
11 => {
|
11 => {
|
||||||
if try!(bool::read_from(buf)) {
|
if try!(bool::read_from(buf)) {
|
||||||
|
@ -98,9 +97,11 @@ impl Serializable for Metadata {
|
||||||
} else {
|
} else {
|
||||||
m.put_raw::<Option<protocol::UUID>>(index, None);
|
m.put_raw::<Option<protocol::UUID>>(index, None);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
12 => m.put_raw(index, try!(protocol::VarInt::read_from(buf)).0 as u16),
|
12 => m.put_raw(index, try!(protocol::VarInt::read_from(buf)).0 as u16),
|
||||||
_ => return Err(io::Error::new(io::ErrorKind::InvalidInput, protocol::Error::Err("unknown metadata type".to_owned()))),
|
_ => return Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||||
|
protocol::Error::Err("unknown metadata type"
|
||||||
|
.to_owned()))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(m)
|
Ok(m)
|
||||||
|
@ -113,46 +114,46 @@ impl Serializable for Metadata {
|
||||||
Value::Byte(ref val) => {
|
Value::Byte(ref val) => {
|
||||||
try!(u8::write_to(&0, buf));
|
try!(u8::write_to(&0, buf));
|
||||||
try!(val.write_to(buf));
|
try!(val.write_to(buf));
|
||||||
},
|
}
|
||||||
Value::Int(ref val) => {
|
Value::Int(ref val) => {
|
||||||
try!(u8::write_to(&1, buf));
|
try!(u8::write_to(&1, buf));
|
||||||
try!(protocol::VarInt(*val).write_to(buf));
|
try!(protocol::VarInt(*val).write_to(buf));
|
||||||
},
|
}
|
||||||
Value::Float(ref val) => {
|
Value::Float(ref val) => {
|
||||||
try!(u8::write_to(&2, buf));
|
try!(u8::write_to(&2, buf));
|
||||||
try!(val.write_to(buf));
|
try!(val.write_to(buf));
|
||||||
},
|
}
|
||||||
Value::String(ref val) => {
|
Value::String(ref val) => {
|
||||||
try!(u8::write_to(&3, buf));
|
try!(u8::write_to(&3, buf));
|
||||||
try!(val.write_to(buf));
|
try!(val.write_to(buf));
|
||||||
},
|
}
|
||||||
Value::FormatComponent(ref val) => {
|
Value::FormatComponent(ref val) => {
|
||||||
try!(u8::write_to(&4, buf));
|
try!(u8::write_to(&4, buf));
|
||||||
try!(val.write_to(buf));
|
try!(val.write_to(buf));
|
||||||
},
|
}
|
||||||
Value::OptionalItemStack(ref val) => {
|
Value::OptionalItemStack(ref val) => {
|
||||||
try!(u8::write_to(&5, buf));
|
try!(u8::write_to(&5, buf));
|
||||||
try!(val.write_to(buf));
|
try!(val.write_to(buf));
|
||||||
},
|
}
|
||||||
Value::Bool(ref val) => {
|
Value::Bool(ref val) => {
|
||||||
try!(u8::write_to(&6, buf));
|
try!(u8::write_to(&6, buf));
|
||||||
try!(val.write_to(buf));
|
try!(val.write_to(buf));
|
||||||
},
|
}
|
||||||
Value::Vector(ref val) => {
|
Value::Vector(ref val) => {
|
||||||
try!(u8::write_to(&7, buf));
|
try!(u8::write_to(&7, buf));
|
||||||
try!(val[0].write_to(buf));
|
try!(val[0].write_to(buf));
|
||||||
try!(val[1].write_to(buf));
|
try!(val[1].write_to(buf));
|
||||||
try!(val[2].write_to(buf));
|
try!(val[2].write_to(buf));
|
||||||
},
|
}
|
||||||
Value::Position(ref val) => {
|
Value::Position(ref val) => {
|
||||||
try!(u8::write_to(&8, buf));
|
try!(u8::write_to(&8, buf));
|
||||||
try!(val.write_to(buf));
|
try!(val.write_to(buf));
|
||||||
},
|
}
|
||||||
Value::OptionalPosition(ref val) => {
|
Value::OptionalPosition(ref val) => {
|
||||||
try!(u8::write_to(&9, buf));
|
try!(u8::write_to(&9, buf));
|
||||||
try!(val.is_some().write_to(buf));
|
try!(val.is_some().write_to(buf));
|
||||||
try!(val.write_to(buf));
|
try!(val.write_to(buf));
|
||||||
},
|
}
|
||||||
Value::Direction(ref val) => {
|
Value::Direction(ref val) => {
|
||||||
try!(u8::write_to(&10, buf));
|
try!(u8::write_to(&10, buf));
|
||||||
try!(val.write_to(buf));
|
try!(val.write_to(buf));
|
||||||
|
@ -161,7 +162,7 @@ impl Serializable for Metadata {
|
||||||
try!(u8::write_to(&11, buf));
|
try!(u8::write_to(&11, buf));
|
||||||
try!(val.is_some().write_to(buf));
|
try!(val.is_some().write_to(buf));
|
||||||
try!(val.write_to(buf));
|
try!(val.write_to(buf));
|
||||||
},
|
}
|
||||||
Value::Block(ref val) => {
|
Value::Block(ref val) => {
|
||||||
try!(u8::write_to(&11, buf));
|
try!(u8::write_to(&11, buf));
|
||||||
try!(protocol::VarInt(*val as i32).write_to(buf));
|
try!(protocol::VarInt(*val as i32).write_to(buf));
|
||||||
|
@ -374,9 +375,9 @@ mod test {
|
||||||
|
|
||||||
const TEST: MetadataKey<String> =
|
const TEST: MetadataKey<String> =
|
||||||
MetadataKey {
|
MetadataKey {
|
||||||
index: 0,
|
index: 0,
|
||||||
ty: PhantomData,
|
ty: PhantomData,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic() {
|
fn basic() {
|
||||||
|
|
|
@ -18,4 +18,4 @@ pub use self::blockpos::*;
|
||||||
mod metadata;
|
mod metadata;
|
||||||
pub use self::metadata::*;
|
pub use self::metadata::*;
|
||||||
|
|
||||||
pub mod bit;
|
pub mod bit;
|
||||||
|
|
136
src/ui/batch.rs
136
src/ui/batch.rs
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct BatchRef<T: UIElement> {
|
pub struct BatchRef<T: UIElement> {
|
||||||
index: usize,
|
index: usize,
|
||||||
ty: PhantomData<T>,
|
ty: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_element!(Batch {
|
ui_element!(Batch {
|
||||||
|
@ -28,83 +28,93 @@ ui_element!(Batch {
|
||||||
impl Batch {
|
impl Batch {
|
||||||
base_impl!();
|
base_impl!();
|
||||||
|
|
||||||
pub fn new(x: f64, y: f64, w: f64, h: f64) -> Batch {
|
pub fn new(x: f64, y: f64, w: f64, h: f64) -> Batch {
|
||||||
ui_create!(Batch {
|
ui_create!(Batch {
|
||||||
x: x,
|
x: x,
|
||||||
y: y,
|
y: y,
|
||||||
width: w,
|
width: w,
|
||||||
height: h,
|
height: h,
|
||||||
|
|
||||||
elements: Vec::new()
|
elements: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _: &mut render::Renderer) {}
|
fn update(&mut self, _: &mut render::Renderer) {
|
||||||
|
}
|
||||||
|
|
||||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8> {
|
fn draw(&mut self,
|
||||||
if self.dirty {
|
renderer: &mut render::Renderer,
|
||||||
self.dirty = false;
|
r: &Region,
|
||||||
self.data.clear();
|
width: f64,
|
||||||
|
height: f64,
|
||||||
|
delta: f64)
|
||||||
|
-> &Vec<u8> {
|
||||||
|
if self.dirty {
|
||||||
|
self.dirty = false;
|
||||||
|
self.data.clear();
|
||||||
|
|
||||||
let sx = r.w / self.width;
|
let sx = r.w / self.width;
|
||||||
let sy = r.h / self.height;
|
let sy = r.h / self.height;
|
||||||
|
|
||||||
for e in &mut self.elements {
|
for e in &mut self.elements {
|
||||||
let reg = Container::get_draw_region_raw(e, sx, sy, r);
|
let reg = Container::get_draw_region_raw(e, sx, sy, r);
|
||||||
e.set_dirty(true);
|
e.set_dirty(true);
|
||||||
self.data.extend(e.draw(renderer, ®, width, height, delta));
|
self.data.extend(e.draw(renderer, ®, width, height, delta));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_size(&self) -> (f64, f64) {
|
pub fn get_size(&self) -> (f64, f64) {
|
||||||
(self.width, self.height)
|
(self.width, self.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add<T: UIElement>(&mut self, e: T) -> BatchRef<T> {
|
pub fn add<T: UIElement>(&mut self, e: T) -> BatchRef<T> {
|
||||||
self.elements.push(e.wrap());
|
self.elements.push(e.wrap());
|
||||||
BatchRef { index: self.elements.len() - 1, ty: PhantomData }
|
BatchRef {
|
||||||
}
|
index: self.elements.len() - 1,
|
||||||
|
ty: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get<T: UIElement>(&self, r: BatchRef<T>) -> &T {
|
pub fn get<T: UIElement>(&self, r: BatchRef<T>) -> &T {
|
||||||
T::unwrap_ref(&self.elements[r.index])
|
T::unwrap_ref(&self.elements[r.index])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut<T: UIElement>(&mut self, r: BatchRef<T>) -> &mut T {
|
pub fn get_mut<T: UIElement>(&mut self, r: BatchRef<T>) -> &mut T {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
T::unwrap_ref_mut(&mut self.elements[r.index])
|
T::unwrap_ref_mut(&mut self.elements[r.index])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut_at<T: UIElement>(&mut self, index: usize) -> &mut T {
|
pub fn get_mut_at<T: UIElement>(&mut self, index: usize) -> &mut T {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
T::unwrap_ref_mut(&mut self.elements[index])
|
T::unwrap_ref_mut(&mut self.elements[index])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.elements.len()
|
self.elements.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_field!(width, f64, get_width, set_width);
|
lazy_field!(width, f64, get_width, set_width);
|
||||||
lazy_field!(height, f64, get_height, set_height);
|
lazy_field!(height, f64, get_height, set_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIElement for Batch {
|
impl UIElement for Batch {
|
||||||
fn wrap(self) -> Element {
|
fn wrap(self) -> Element {
|
||||||
Element::Batch(self)
|
Element::Batch(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwrap_ref<'a>(e: &'a Element) -> &'a Batch {
|
fn unwrap_ref<'a>(e: &'a Element) -> &'a Batch {
|
||||||
match e {
|
match e {
|
||||||
&Element::Batch(ref val) => val,
|
&Element::Batch(ref val) => val,
|
||||||
_ => panic!("Incorrect type"),
|
_ => panic!("Incorrect type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Batch {
|
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Batch {
|
||||||
match e {
|
match e {
|
||||||
&mut Element::Batch(ref mut val) => val,
|
&mut Element::Batch(ref mut val) => val,
|
||||||
_ => panic!("Incorrect type"),
|
_ => panic!("Incorrect type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,88 +27,104 @@ ui_element!(Formatted {
|
||||||
impl Formatted {
|
impl Formatted {
|
||||||
base_impl!();
|
base_impl!();
|
||||||
|
|
||||||
pub fn new(renderer: &mut render::Renderer, val: format::Component, x: f64, y: f64) -> Formatted {
|
pub fn new(renderer: &mut render::Renderer,
|
||||||
let mut f = ui_create!(Formatted {
|
val: format::Component,
|
||||||
val: val,
|
x: f64,
|
||||||
x: x,
|
y: f64)
|
||||||
y: y,
|
-> Formatted {
|
||||||
width: 0.0,
|
let mut f = ui_create!(Formatted {
|
||||||
height: 18.0,
|
val: val,
|
||||||
scale_x: 1.0,
|
x: x,
|
||||||
scale_y: 1.0,
|
y: y,
|
||||||
|
width: 0.0,
|
||||||
|
height: 18.0,
|
||||||
|
scale_x: 1.0,
|
||||||
|
scale_y: 1.0,
|
||||||
|
|
||||||
text: Vec::new(),
|
text: Vec::new(),
|
||||||
max_width: -1.0,
|
max_width: -1.0,
|
||||||
lines: 0
|
lines: 0,
|
||||||
});
|
});
|
||||||
f.init_component(renderer);
|
f.init_component(renderer);
|
||||||
f
|
f
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_width_limit(renderer: &mut render::Renderer, val: format::Component, x: f64, y: f64, max_width: f64) -> Formatted {
|
pub fn with_width_limit(renderer: &mut render::Renderer,
|
||||||
let mut f = ui_create!(Formatted {
|
val: format::Component,
|
||||||
val: val,
|
x: f64,
|
||||||
x: x,
|
y: f64,
|
||||||
y: y,
|
max_width: f64)
|
||||||
width: 0.0,
|
-> Formatted {
|
||||||
height: 18.0,
|
let mut f = ui_create!(Formatted {
|
||||||
scale_x: 1.0,
|
val: val,
|
||||||
scale_y: 1.0,
|
x: x,
|
||||||
|
y: y,
|
||||||
|
width: 0.0,
|
||||||
|
height: 18.0,
|
||||||
|
scale_x: 1.0,
|
||||||
|
scale_y: 1.0,
|
||||||
|
|
||||||
text: Vec::new(),
|
text: Vec::new(),
|
||||||
max_width: max_width,
|
max_width: max_width,
|
||||||
lines: 0
|
lines: 0,
|
||||||
});
|
});
|
||||||
f.init_component(renderer);
|
f.init_component(renderer);
|
||||||
f
|
f
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_component(&mut self, renderer: &mut render::Renderer, val: format::Component) {
|
|
||||||
self.val = val;
|
|
||||||
self.init_component(renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_component(&mut self, renderer: &mut render::Renderer) {
|
pub fn set_component(&mut self, renderer: &mut render::Renderer, val: format::Component) {
|
||||||
self.text.clear();
|
self.val = val;
|
||||||
let mut state = FormatState {
|
self.init_component(renderer);
|
||||||
lines: 0,
|
}
|
||||||
width: 0.0,
|
|
||||||
offset: 0.0,
|
|
||||||
text: Vec::new(),
|
|
||||||
max_width: self.max_width,
|
|
||||||
renderer: &renderer,
|
|
||||||
};
|
|
||||||
state.build(&self.val, format::Color::White);
|
|
||||||
self.height = (state.lines + 1) as f64 * 18.0;
|
|
||||||
self.width = state.width;
|
|
||||||
self.lines = state.lines;
|
|
||||||
self.text = state.text;
|
|
||||||
self.dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, renderer: &mut render::Renderer) {
|
fn init_component(&mut self, renderer: &mut render::Renderer) {
|
||||||
self.init_component(renderer);
|
self.text.clear();
|
||||||
}
|
let mut state = FormatState {
|
||||||
|
lines: 0,
|
||||||
|
width: 0.0,
|
||||||
|
offset: 0.0,
|
||||||
|
text: Vec::new(),
|
||||||
|
max_width: self.max_width,
|
||||||
|
renderer: &renderer,
|
||||||
|
};
|
||||||
|
state.build(&self.val, format::Color::White);
|
||||||
|
self.height = (state.lines + 1) as f64 * 18.0;
|
||||||
|
self.width = state.width;
|
||||||
|
self.lines = state.lines;
|
||||||
|
self.text = state.text;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8> {
|
fn update(&mut self, renderer: &mut render::Renderer) {
|
||||||
if self.dirty {
|
self.init_component(renderer);
|
||||||
self.dirty = false;
|
}
|
||||||
self.data.clear();
|
|
||||||
let sx = r.w / self.width;
|
|
||||||
let sy = r.h / self.height;
|
|
||||||
|
|
||||||
for e in &mut self.text {
|
fn draw(&mut self,
|
||||||
let reg = Container::get_draw_region_raw(e, sx, sy, r);
|
renderer: &mut render::Renderer,
|
||||||
e.set_dirty(true);
|
r: &Region,
|
||||||
self.data.extend(e.draw(renderer, ®, width, height, delta));
|
width: f64,
|
||||||
}
|
height: f64,
|
||||||
}
|
delta: f64)
|
||||||
&self.data
|
-> &Vec<u8> {
|
||||||
}
|
if self.dirty {
|
||||||
|
self.dirty = false;
|
||||||
|
self.data.clear();
|
||||||
|
let sx = r.w / self.width;
|
||||||
|
let sy = r.h / self.height;
|
||||||
|
|
||||||
pub fn get_size(&self) -> (f64, f64) {
|
for e in &mut self.text {
|
||||||
((self.width + 2.0) * self.scale_x, self.height * self.scale_y)
|
let reg = Container::get_draw_region_raw(e, sx, sy, r);
|
||||||
}
|
e.set_dirty(true);
|
||||||
|
self.data.extend(e.draw(renderer, ®, width, height, delta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_size(&self) -> (f64, f64) {
|
||||||
|
((self.width + 2.0) * self.scale_x,
|
||||||
|
self.height * self.scale_y)
|
||||||
|
}
|
||||||
|
|
||||||
lazy_field!(width, f64, get_width, set_width);
|
lazy_field!(width, f64, get_width, set_width);
|
||||||
lazy_field!(height, f64, get_height, set_height);
|
lazy_field!(height, f64, get_height, set_height);
|
||||||
|
@ -118,87 +134,97 @@ impl Formatted {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIElement for Formatted {
|
impl UIElement for Formatted {
|
||||||
fn wrap(self) -> Element {
|
fn wrap(self) -> Element {
|
||||||
Element::Formatted(self)
|
Element::Formatted(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwrap_ref<'a>(e: &'a Element) -> &'a Formatted {
|
fn unwrap_ref<'a>(e: &'a Element) -> &'a Formatted {
|
||||||
match e {
|
match e {
|
||||||
&Element::Formatted(ref val) => val,
|
&Element::Formatted(ref val) => val,
|
||||||
_ => panic!("Incorrect type"),
|
_ => panic!("Incorrect type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Formatted {
|
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Formatted {
|
||||||
match e {
|
match e {
|
||||||
&mut Element::Formatted(ref mut val) => val,
|
&mut Element::Formatted(ref mut val) => val,
|
||||||
_ => panic!("Incorrect type"),
|
_ => panic!("Incorrect type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FormatState<'a> {
|
struct FormatState<'a> {
|
||||||
max_width: f64,
|
max_width: f64,
|
||||||
lines: usize,
|
lines: usize,
|
||||||
offset: f64,
|
offset: f64,
|
||||||
width: f64,
|
width: f64,
|
||||||
text: Vec<Element>,
|
text: Vec<Element>,
|
||||||
renderer: &'a render::Renderer,
|
renderer: &'a render::Renderer,
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetColorFn = Fn() -> format::Color;
|
|
||||||
|
|
||||||
impl <'a> FormatState<'a> {
|
impl <'a> FormatState<'a> {
|
||||||
fn build(&mut self, c: &format::Component, color: format::Color) {
|
fn build(&mut self, c: &format::Component, color: format::Color) {
|
||||||
match c {
|
match c {
|
||||||
&format::Component::Text(ref txt) => {
|
&format::Component::Text(ref txt) => {
|
||||||
let col = FormatState::get_color(&txt.modifier, color);
|
let col = FormatState::get_color(&txt.modifier, color);
|
||||||
self.append_text(&txt.text, col);
|
self.append_text(&txt.text, col);
|
||||||
let modi = &txt.modifier;
|
let modi = &txt.modifier;
|
||||||
if let Some(ref extra) = modi.extra {
|
if let Some(ref extra) = modi.extra {
|
||||||
for e in extra {
|
for e in extra {
|
||||||
self.build(e, col);
|
self.build(e, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_text(&mut self, txt: &str, color: format::Color) {
|
fn append_text(&mut self, txt: &str, color: format::Color) {
|
||||||
let mut width = 0.0;
|
let mut width = 0.0;
|
||||||
let mut last = 0;
|
let mut last = 0;
|
||||||
for (i, c) in txt.char_indices() {
|
for (i, c) in txt.char_indices() {
|
||||||
let size = self.renderer.ui.size_of_char(c) + 2.0;
|
let size = self.renderer.ui.size_of_char(c) + 2.0;
|
||||||
if (self.max_width > 0.0 && self.offset + width + size > self.max_width) || c == '\n' {
|
if (self.max_width > 0.0 && self.offset + width + size > self.max_width) || c == '\n' {
|
||||||
let (rr, gg, bb) = color.to_rgb();
|
let (rr, gg, bb) = color.to_rgb();
|
||||||
let text = Text::new(self.renderer, &txt[last .. i], self.offset, (self.lines*18 + 1) as f64, rr, gg, bb);
|
let text = Text::new(self.renderer,
|
||||||
self.text.push(text.wrap());
|
&txt[last..i],
|
||||||
last = i;
|
self.offset,
|
||||||
if c == '\n' {
|
(self.lines * 18 + 1) as f64,
|
||||||
last += 1;
|
rr,
|
||||||
}
|
gg,
|
||||||
self.offset = 0.0;
|
bb);
|
||||||
self.lines += 1;
|
self.text.push(text.wrap());
|
||||||
width = 0.0;
|
last = i;
|
||||||
}
|
if c == '\n' {
|
||||||
width += size;
|
last += 1;
|
||||||
if self.offset + width > self.width {
|
}
|
||||||
self.width = self.offset + width;
|
self.offset = 0.0;
|
||||||
}
|
self.lines += 1;
|
||||||
}
|
width = 0.0;
|
||||||
|
}
|
||||||
|
width += size;
|
||||||
|
if self.offset + width > self.width {
|
||||||
|
self.width = self.offset + width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if last != txt.len() {
|
if last != txt.len() {
|
||||||
let (rr, gg, bb) = color.to_rgb();
|
let (rr, gg, bb) = color.to_rgb();
|
||||||
let text = Text::new(self.renderer, &txt[last..], self.offset, (self.lines*18 + 1) as f64, rr, gg, bb);
|
let text = Text::new(self.renderer,
|
||||||
self.offset += text.width + 4.0; // TODO Why is this 4 not 2?
|
&txt[last..],
|
||||||
self.text.push(text.wrap());
|
self.offset,
|
||||||
if self.offset > self.width {
|
(self.lines * 18 + 1) as f64,
|
||||||
self.width = self.offset;
|
rr,
|
||||||
}
|
gg,
|
||||||
}
|
bb);
|
||||||
}
|
self.offset += text.width + 4.0; // TODO Why is this 4 not 2?
|
||||||
|
self.text.push(text.wrap());
|
||||||
|
if self.offset > self.width {
|
||||||
|
self.width = self.offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_color(modi: &format::Modifier, color: format::Color) -> format::Color {
|
fn get_color(modi: &format::Modifier, color: format::Color) -> format::Color {
|
||||||
modi.color.unwrap_or(color)
|
modi.color.unwrap_or(color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
143
src/ui/image.rs
143
src/ui/image.rs
|
@ -31,55 +31,82 @@ ui_element!(Image {
|
||||||
impl Image {
|
impl Image {
|
||||||
base_impl!();
|
base_impl!();
|
||||||
|
|
||||||
pub fn new(texture: render::Texture, x: f64, y: f64, w: f64, h: f64, t_x: f64, t_y: f64, t_width: f64, t_height: f64, r: u8, g: u8, b: u8) -> Image {
|
pub fn new(texture: render::Texture,
|
||||||
ui_create!(Image {
|
x: f64,
|
||||||
texture: texture,
|
y: f64,
|
||||||
x: x,
|
w: f64,
|
||||||
y: y,
|
h: f64,
|
||||||
width: w,
|
t_x: f64,
|
||||||
height: h,
|
t_y: f64,
|
||||||
|
t_width: f64,
|
||||||
|
t_height: f64,
|
||||||
|
r: u8,
|
||||||
|
g: u8,
|
||||||
|
b: u8)
|
||||||
|
-> Image {
|
||||||
|
ui_create!(Image {
|
||||||
|
texture: texture,
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
width: w,
|
||||||
|
height: h,
|
||||||
|
|
||||||
t_x: t_x,
|
t_x: t_x,
|
||||||
t_y: t_y,
|
t_y: t_y,
|
||||||
t_width: t_width,
|
t_width: t_width,
|
||||||
t_height: t_height,
|
t_height: t_height,
|
||||||
|
|
||||||
r: r,
|
r: r,
|
||||||
g: g,
|
g: g,
|
||||||
b: b,
|
b: b,
|
||||||
a: 255
|
a: 255,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _: &mut render::Renderer) {}
|
fn update(&mut self, _: &mut render::Renderer) {
|
||||||
|
}
|
||||||
|
|
||||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, _: f64) -> &Vec<u8> {
|
fn draw(&mut self,
|
||||||
if self.dirty {
|
renderer: &mut render::Renderer,
|
||||||
self.dirty = false;
|
r: &Region,
|
||||||
self.texture = renderer.check_texture(self.texture.clone());
|
width: f64,
|
||||||
let mut e = render::ui::UIElement::new(&self.texture, r.x, r.y, r.w, r.h, self.t_x, self.t_y, self.t_width, self.t_height);
|
height: f64,
|
||||||
e.r = self.r;
|
_: f64)
|
||||||
e.g = self.g;
|
-> &Vec<u8> {
|
||||||
e.b = self.b;
|
if self.dirty {
|
||||||
e.a = self.a;
|
self.dirty = false;
|
||||||
e.layer = self.layer;
|
self.texture = renderer.check_texture(self.texture.clone());
|
||||||
self.data = e.bytes(width, height);
|
let mut e = render::ui::UIElement::new(&self.texture,
|
||||||
}
|
r.x,
|
||||||
&self.data
|
r.y,
|
||||||
}
|
r.w,
|
||||||
|
r.h,
|
||||||
|
self.t_x,
|
||||||
|
self.t_y,
|
||||||
|
self.t_width,
|
||||||
|
self.t_height);
|
||||||
|
e.r = self.r;
|
||||||
|
e.g = self.g;
|
||||||
|
e.b = self.b;
|
||||||
|
e.a = self.a;
|
||||||
|
e.layer = self.layer;
|
||||||
|
self.data = e.bytes(width, height);
|
||||||
|
}
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_size(&self) -> (f64, f64) {
|
pub fn get_size(&self) -> (f64, f64) {
|
||||||
(self.width, self.height)
|
(self.width, self.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_texture(&self) -> render::Texture {
|
pub fn get_texture(&self) -> render::Texture {
|
||||||
self.texture.clone()
|
self.texture.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_texture(&mut self, val: render::Texture) {
|
pub fn set_texture(&mut self, val: render::Texture) {
|
||||||
self.texture = val;
|
self.texture = val;
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_field!(width, f64, get_width, set_width);
|
lazy_field!(width, f64, get_width, set_width);
|
||||||
lazy_field!(height, f64, get_height, set_height);
|
lazy_field!(height, f64, get_height, set_height);
|
||||||
|
@ -96,21 +123,21 @@ impl Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIElement for Image {
|
impl UIElement for Image {
|
||||||
fn wrap(self) -> Element {
|
fn wrap(self) -> Element {
|
||||||
Element::Image(self)
|
Element::Image(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwrap_ref<'a>(e: &'a Element) -> &'a Image {
|
fn unwrap_ref<'a>(e: &'a Element) -> &'a Image {
|
||||||
match e {
|
match e {
|
||||||
&Element::Image(ref val) => val,
|
&Element::Image(ref val) => val,
|
||||||
_ => panic!("Incorrect type"),
|
_ => panic!("Incorrect type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Image {
|
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Image {
|
||||||
match e {
|
match e {
|
||||||
&mut Element::Image(ref mut val) => val,
|
&mut Element::Image(ref mut val) => val,
|
||||||
_ => panic!("Incorrect type"),
|
_ => panic!("Incorrect type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
285
src/ui/logo.rs
285
src/ui/logo.rs
|
@ -9,160 +9,175 @@ use rand;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
pub struct Logo {
|
pub struct Logo {
|
||||||
resources: Arc<RwLock<resources::Manager>>,
|
resources: Arc<RwLock<resources::Manager>>,
|
||||||
|
|
||||||
shadow: ui::ElementRef<ui::Batch>,
|
shadow: ui::ElementRef<ui::Batch>,
|
||||||
layer0: ui::ElementRef<ui::Batch>,
|
layer0: ui::ElementRef<ui::Batch>,
|
||||||
|
|
||||||
text: ui::ElementRef<ui::Text>,
|
text: ui::ElementRef<ui::Text>,
|
||||||
text_base_scale: f64,
|
text_base_scale: f64,
|
||||||
text_orig_x: f64,
|
text_orig_x: f64,
|
||||||
text_index: isize,
|
text_index: isize,
|
||||||
text_strings: Vec<String>,
|
text_strings: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Logo {
|
impl Logo {
|
||||||
pub fn new(resources: Arc<RwLock<resources::Manager>>, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Logo {
|
pub fn new(resources: Arc<RwLock<resources::Manager>>,
|
||||||
let mut l = Logo {
|
renderer: &mut render::Renderer,
|
||||||
resources: resources,
|
ui_container: &mut ui::Container)
|
||||||
shadow: Default::default(),
|
-> Logo {
|
||||||
layer0: Default::default(),
|
let mut l = Logo {
|
||||||
text: Default::default(),
|
resources: resources,
|
||||||
text_base_scale: 0.0,
|
shadow: Default::default(),
|
||||||
text_orig_x: 0.0,
|
layer0: Default::default(),
|
||||||
text_index: -1,
|
text: Default::default(),
|
||||||
text_strings: Vec::new(),
|
text_base_scale: 0.0,
|
||||||
};
|
text_orig_x: 0.0,
|
||||||
l.init(renderer, ui_container);
|
text_index: -1,
|
||||||
l
|
text_strings: Vec::new(),
|
||||||
}
|
};
|
||||||
|
l.init(renderer, ui_container);
|
||||||
|
l
|
||||||
|
}
|
||||||
|
|
||||||
fn init(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
fn init(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||||
let res = self.resources.read().unwrap();
|
let res = self.resources.read().unwrap();
|
||||||
|
|
||||||
let mut logo = res.open("steven", "logo/logo.txt").unwrap();
|
let mut logo = res.open("steven", "logo/logo.txt").unwrap();
|
||||||
let mut logo_str = String::new();
|
let mut logo_str = String::new();
|
||||||
logo.read_to_string(&mut logo_str).unwrap();
|
logo.read_to_string(&mut logo_str).unwrap();
|
||||||
|
|
||||||
let solid = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid");
|
let solid = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid");
|
||||||
let stone = render::Renderer::get_texture(renderer.get_textures_ref(), "blocks/planks_oak");
|
let stone = render::Renderer::get_texture(renderer.get_textures_ref(), "blocks/planks_oak");
|
||||||
|
|
||||||
let mut shadow_batch = ui::Batch::new(0.0, 8.0, 100.0, 100.0);
|
let mut shadow_batch = ui::Batch::new(0.0, 8.0, 100.0, 100.0);
|
||||||
let mut layer0 = ui::Batch::new(0.0, 8.0, 100.0, 100.0);
|
let mut layer0 = ui::Batch::new(0.0, 8.0, 100.0, 100.0);
|
||||||
|
|
||||||
shadow_batch.set_h_attach(ui::HAttach::Center);
|
shadow_batch.set_h_attach(ui::HAttach::Center);
|
||||||
layer0.set_h_attach(ui::HAttach::Center);
|
layer0.set_h_attach(ui::HAttach::Center);
|
||||||
|
|
||||||
let mut row = 0;
|
let mut row = 0;
|
||||||
for line in logo_str.lines() {
|
for line in logo_str.lines() {
|
||||||
if line.is_empty() {
|
if line.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (i, c) in line.chars().enumerate() {
|
for (i, c) in line.chars().enumerate() {
|
||||||
if c == ' ' {
|
if c == ' ' {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let x = i * 4;
|
let x = i * 4;
|
||||||
let y = row * 8;
|
let y = row * 8;
|
||||||
let (r, g, b) = if c == ':' {
|
let (r, g, b) = if c == ':' {
|
||||||
(255, 255, 255)
|
(255, 255, 255)
|
||||||
} else {
|
} else {
|
||||||
(170, 170, 170)
|
(170, 170, 170)
|
||||||
};
|
};
|
||||||
let mut shadow = ui::Image::new(
|
let mut shadow = ui::Image::new(solid.clone(),
|
||||||
solid.clone(),
|
(x + 2) as f64,
|
||||||
(x+2) as f64, (y+4) as f64, 4.0, 8.0,
|
(y + 4) as f64,
|
||||||
0.0, 0.0, 1.0, 1.0,
|
4.0,
|
||||||
0, 0, 0
|
8.0,
|
||||||
);
|
0.0,
|
||||||
shadow.set_a(100);
|
0.0,
|
||||||
shadow_batch.add(shadow);
|
1.0,
|
||||||
|
1.0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
shadow.set_a(100);
|
||||||
|
shadow_batch.add(shadow);
|
||||||
|
|
||||||
|
|
||||||
let img = ui::Image::new(
|
let img = ui::Image::new(stone.clone(),
|
||||||
stone.clone(),
|
x as f64,
|
||||||
x as f64, y as f64, 4.0, 8.0,
|
y as f64,
|
||||||
(x%16) as f64 / 16.0, (y%16) as f64 / 16.0, 4.0/16.0, 8.0/16.0,
|
4.0,
|
||||||
r, g, b
|
8.0,
|
||||||
);
|
(x % 16) as f64 / 16.0,
|
||||||
layer0.add(img);
|
(y % 16) as f64 / 16.0,
|
||||||
|
4.0 / 16.0,
|
||||||
|
8.0 / 16.0,
|
||||||
|
r,
|
||||||
|
g,
|
||||||
|
b);
|
||||||
|
layer0.add(img);
|
||||||
|
|
||||||
let width = (x + 4) as f64;
|
let width = (x + 4) as f64;
|
||||||
if shadow_batch.get_width() < width {
|
if shadow_batch.get_width() < width {
|
||||||
shadow_batch.set_width(width);
|
shadow_batch.set_width(width);
|
||||||
layer0.set_width(width);
|
layer0.set_width(width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
row += 1;
|
row += 1;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut splashes = res.open_all("minecraft", "texts/splashes.txt");
|
let mut splashes = res.open_all("minecraft", "texts/splashes.txt");
|
||||||
for file in &mut splashes {
|
for file in &mut splashes {
|
||||||
let mut texts = String::new();
|
let mut texts = String::new();
|
||||||
file.read_to_string(&mut texts).unwrap();
|
file.read_to_string(&mut texts).unwrap();
|
||||||
for line in texts.lines() {
|
for line in texts.lines() {
|
||||||
self.text_strings.push(line.to_owned().replace("\r", ""));
|
self.text_strings.push(line.to_owned().replace("\r", ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut r: rand::XorShiftRng = rand::SeedableRng::from_seed([45, 64, 32, 12]);
|
let mut r: rand::XorShiftRng = rand::SeedableRng::from_seed([45, 64, 32, 12]);
|
||||||
r.shuffle(&mut self.text_strings[..]);
|
r.shuffle(&mut self.text_strings[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
shadow_batch.set_height(row as f64 * 8.0);
|
shadow_batch.set_height(row as f64 * 8.0);
|
||||||
layer0.set_height(row as f64 * 8.0);
|
layer0.set_height(row as f64 * 8.0);
|
||||||
|
|
||||||
self.shadow = ui_container.add(shadow_batch);
|
self.shadow = ui_container.add(shadow_batch);
|
||||||
self.layer0 = ui_container.add(layer0);
|
self.layer0 = ui_container.add(layer0);
|
||||||
|
|
||||||
let mut txt = ui::Text::new(renderer, "", 0.0, -8.0, 255, 255, 0);
|
let mut txt = ui::Text::new(renderer, "", 0.0, -8.0, 255, 255, 0);
|
||||||
txt.set_h_attach(ui::HAttach::Right);
|
txt.set_h_attach(ui::HAttach::Right);
|
||||||
txt.set_v_attach(ui::VAttach::Bottom);
|
txt.set_v_attach(ui::VAttach::Bottom);
|
||||||
txt.set_parent(&self.shadow);
|
txt.set_parent(&self.shadow);
|
||||||
txt.set_rotation(-consts::PI / 8.0);
|
txt.set_rotation(-consts::PI / 8.0);
|
||||||
|
|
||||||
let width = txt.get_width();
|
|
||||||
self.text_base_scale = 300.0 / width;
|
|
||||||
if self.text_base_scale > 1.0 {
|
|
||||||
self.text_base_scale = 1.0;
|
|
||||||
}
|
|
||||||
txt.set_x((-width / 2.0) * self.text_base_scale);
|
|
||||||
self.text_orig_x = txt.get_x();
|
|
||||||
self.text = ui_container.add(txt);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tick(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
let width = txt.get_width();
|
||||||
let now = time::now().to_timespec();
|
self.text_base_scale = 300.0 / width;
|
||||||
|
if self.text_base_scale > 1.0 {
|
||||||
|
self.text_base_scale = 1.0;
|
||||||
|
}
|
||||||
|
txt.set_x((-width / 2.0) * self.text_base_scale);
|
||||||
|
self.text_orig_x = txt.get_x();
|
||||||
|
self.text = ui_container.add(txt);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||||
|
let now = time::now().to_timespec();
|
||||||
|
|
||||||
// Splash text
|
// Splash text
|
||||||
let text = ui_container.get_mut(&self.text);
|
let text = ui_container.get_mut(&self.text);
|
||||||
let text_index = (now.sec / 15) as isize % self.text_strings.len() as isize;
|
let text_index = (now.sec / 15) as isize % self.text_strings.len() as isize;
|
||||||
if self.text_index != text_index {
|
if self.text_index != text_index {
|
||||||
self.text_index = text_index;
|
self.text_index = text_index;
|
||||||
text.set_text(renderer, &self.text_strings[text_index as usize]);
|
text.set_text(renderer, &self.text_strings[text_index as usize]);
|
||||||
let width = text.get_width();
|
let width = text.get_width();
|
||||||
self.text_base_scale = 300.0 / width;
|
self.text_base_scale = 300.0 / width;
|
||||||
if self.text_base_scale > 1.0 {
|
if self.text_base_scale > 1.0 {
|
||||||
self.text_base_scale = 1.0;
|
self.text_base_scale = 1.0;
|
||||||
}
|
}
|
||||||
text.set_x((-width / 2.0) * self.text_base_scale);
|
text.set_x((-width / 2.0) * self.text_base_scale);
|
||||||
self.text_orig_x = text.get_x();
|
self.text_orig_x = text.get_x();
|
||||||
}
|
}
|
||||||
|
|
||||||
let timer = now.nsec as f64 / 1000000000.0;
|
let timer = now.nsec as f64 / 1000000000.0;
|
||||||
let mut offset = timer / 0.5;
|
let mut offset = timer / 0.5;
|
||||||
if offset > 1.0 {
|
if offset > 1.0 {
|
||||||
offset = 2.0 - offset;
|
offset = 2.0 - offset;
|
||||||
}
|
}
|
||||||
offset = ((offset * consts::PI).cos() + 1.0) / 2.0;
|
offset = ((offset * consts::PI).cos() + 1.0) / 2.0;
|
||||||
text.set_scale_x((0.7 + (offset / 3.0)) * self.text_base_scale);
|
text.set_scale_x((0.7 + (offset / 3.0)) * self.text_base_scale);
|
||||||
text.set_scale_y((0.7 + (offset / 3.0)) * self.text_base_scale);
|
text.set_scale_y((0.7 + (offset / 3.0)) * self.text_base_scale);
|
||||||
let scale = text.get_scale_x();
|
let scale = text.get_scale_x();
|
||||||
text.set_x(self.text_orig_x * scale * self.text_base_scale);
|
text.set_x(self.text_orig_x * scale * self.text_base_scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(&self, ui_container: &mut ui::Container) {
|
pub fn remove(&self, ui_container: &mut ui::Container) {
|
||||||
ui_container.remove(&self.shadow);
|
ui_container.remove(&self.shadow);
|
||||||
ui_container.remove(&self.layer0);
|
ui_container.remove(&self.layer0);
|
||||||
ui_container.remove(&self.text);
|
ui_container.remove(&self.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
527
src/ui/mod.rs
527
src/ui/mod.rs
|
@ -25,11 +25,11 @@ const SCALED_WIDTH: f64 = 854.0;
|
||||||
const SCALED_HEIGHT: f64 = 480.0;
|
const SCALED_HEIGHT: f64 = 480.0;
|
||||||
|
|
||||||
pub enum Element {
|
pub enum Element {
|
||||||
Image(Image),
|
Image(Image),
|
||||||
Batch(Batch),
|
Batch(Batch),
|
||||||
Text(Text),
|
Text(Text),
|
||||||
Formatted(Formatted),
|
Formatted(Formatted),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ClickFunc = Rc<Fn(&mut ::Game, &mut Container)>;
|
pub type ClickFunc = Rc<Fn(&mut ::Game, &mut Container)>;
|
||||||
|
@ -44,7 +44,7 @@ impl Element {
|
||||||
Element::$name(ref val) => val.click_funcs.clone(),
|
Element::$name(ref val) => val.click_funcs.clone(),
|
||||||
)+
|
)+
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_hover_funcs(&self) -> Vec<HoverFunc> {
|
fn get_hover_funcs(&self) -> Vec<HoverFunc> {
|
||||||
|
@ -53,7 +53,7 @@ impl Element {
|
||||||
Element::$name(ref val) => val.hover_funcs.clone(),
|
Element::$name(ref val) => val.hover_funcs.clone(),
|
||||||
)+
|
)+
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_call_hover(&mut self, new: bool) -> bool{
|
fn should_call_hover(&mut self, new: bool) -> bool{
|
||||||
|
@ -93,7 +93,7 @@ impl Element {
|
||||||
Element::$name(ref val) => (val.v_attach, val.h_attach),
|
Element::$name(ref val) => (val.v_attach, val.h_attach),
|
||||||
)+
|
)+
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_offset(&self) -> (f64, f64) {
|
fn get_offset(&self) -> (f64, f64) {
|
||||||
|
@ -102,7 +102,7 @@ impl Element {
|
||||||
Element::$name(ref val) => (val.x, val.y),
|
Element::$name(ref val) => (val.x, val.y),
|
||||||
)+
|
)+
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_size(&self) -> (f64, f64) {
|
fn get_size(&self) -> (f64, f64) {
|
||||||
|
@ -111,7 +111,7 @@ impl Element {
|
||||||
Element::$name(ref val) => val.get_size(),
|
Element::$name(ref val) => val.get_size(),
|
||||||
)+
|
)+
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_dirty(&self) -> bool {
|
fn is_dirty(&self) -> bool {
|
||||||
|
@ -120,7 +120,7 @@ impl Element {
|
||||||
Element::$name(ref val) => val.dirty,
|
Element::$name(ref val) => val.dirty,
|
||||||
)+
|
)+
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_dirty(&mut self, dirty: bool) {
|
fn set_dirty(&mut self, dirty: bool) {
|
||||||
|
@ -129,7 +129,7 @@ impl Element {
|
||||||
Element::$name(ref mut val) => val.dirty = dirty,
|
Element::$name(ref mut val) => val.dirty = dirty,
|
||||||
)+
|
)+
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, renderer: &mut render::Renderer) {
|
fn update(&mut self, renderer: &mut render::Renderer) {
|
||||||
|
@ -138,16 +138,16 @@ impl Element {
|
||||||
Element::$name(ref mut val) => val.update(renderer),
|
Element::$name(ref mut val) => val.update(renderer),
|
||||||
)+
|
)+
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8>{
|
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8> {
|
||||||
match *self {
|
match *self {
|
||||||
$(
|
$(
|
||||||
Element::$name(ref mut val) => val.draw(renderer, r, width, height, delta),
|
Element::$name(ref mut val) => val.draw(renderer, r, width, height, delta),
|
||||||
)+
|
)+
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -161,319 +161,330 @@ element_impl!(
|
||||||
);
|
);
|
||||||
|
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
Scaled,
|
Scaled,
|
||||||
Unscaled(f64)
|
Unscaled(f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum VAttach {
|
pub enum VAttach {
|
||||||
Top,
|
Top,
|
||||||
Middle,
|
Middle,
|
||||||
Bottom,
|
Bottom,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum HAttach {
|
pub enum HAttach {
|
||||||
Left,
|
Left,
|
||||||
Center,
|
Center,
|
||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Region {
|
struct Region {
|
||||||
x: f64,
|
x: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
w: f64,
|
w: f64,
|
||||||
h: f64,
|
h: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Region {
|
impl Region {
|
||||||
fn intersects(&self, o: &Region) -> bool {
|
fn intersects(&self, o: &Region) -> bool {
|
||||||
!(self.x+self.w < o.x ||
|
!(self.x + self.w < o.x || self.x > o.x + o.w || self.y + self.h < o.y ||
|
||||||
self.x > o.x+o.w ||
|
self.y > o.y + o.h)
|
||||||
self.y+self.h < o.y ||
|
}
|
||||||
self.y > o.y+o.h)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reference to an element currently attached to a
|
/// Reference to an element currently attached to a
|
||||||
/// container.
|
/// container.
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
pub struct ElementRef<T> {
|
pub struct ElementRef<T> {
|
||||||
inner: ElementRefInner,
|
inner: ElementRefInner,
|
||||||
ty: PhantomData<T>,
|
ty: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T> Clone for ElementRef<T> {
|
impl <T> Clone for ElementRef<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
ElementRef {
|
ElementRef {
|
||||||
inner: self.inner,
|
inner: self.inner,
|
||||||
ty: PhantomData,
|
ty: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Hash, PartialEq, Eq, Clone, Copy)]
|
#[derive(Hash, PartialEq, Eq, Clone, Copy)]
|
||||||
struct ElementRefInner {
|
struct ElementRefInner {
|
||||||
index: usize,
|
index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T> Default for ElementRef<T> {
|
impl <T> Default for ElementRef<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
ElementRef {
|
ElementRef {
|
||||||
inner: ElementRefInner{ index: 0 },
|
inner: ElementRefInner { index: 0 },
|
||||||
ty: PhantomData,
|
ty: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows for easy cleanup
|
/// Allows for easy cleanup
|
||||||
pub struct Collection {
|
pub struct Collection {
|
||||||
elements: Vec<ElementRefInner>,
|
elements: Vec<ElementRefInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Collection {
|
impl Collection {
|
||||||
pub fn new() -> Collection {
|
pub fn new() -> Collection {
|
||||||
Collection {
|
Collection { elements: Vec::new() }
|
||||||
elements: Vec::new(),
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add<T: UIElement>(&mut self, element: ElementRef<T>) -> ElementRef<T> {
|
pub fn add<T: UIElement>(&mut self, element: ElementRef<T>) -> ElementRef<T> {
|
||||||
self.elements.push(element.inner);
|
self.elements.push(element.inner);
|
||||||
element
|
element
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_all(&mut self, container: &mut Container) {
|
pub fn remove_all(&mut self, container: &mut Container) {
|
||||||
for e in &self.elements {
|
for e in &self.elements {
|
||||||
container.remove_raw(e);
|
container.remove_raw(e);
|
||||||
}
|
}
|
||||||
self.elements.clear();
|
self.elements.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SCREEN: Region = Region{x: 0.0, y: 0.0, w: SCALED_WIDTH, h: SCALED_HEIGHT};
|
const SCREEN: Region = Region {
|
||||||
|
x: 0.0,
|
||||||
|
y: 0.0,
|
||||||
|
w: SCALED_WIDTH,
|
||||||
|
h: SCALED_HEIGHT,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Container {
|
pub struct Container {
|
||||||
pub mode: Mode,
|
pub mode: Mode,
|
||||||
elements: HashMap<ElementRefInner, Element>,
|
elements: HashMap<ElementRefInner, Element>,
|
||||||
// We need the order
|
// We need the order
|
||||||
elements_list: Vec<ElementRefInner>,
|
elements_list: Vec<ElementRefInner>,
|
||||||
version: usize,
|
version: usize,
|
||||||
|
|
||||||
last_sw: f64,
|
last_sw: f64,
|
||||||
last_sh: f64,
|
last_sh: f64,
|
||||||
last_width: f64,
|
last_width: f64,
|
||||||
last_height: f64,
|
last_height: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Container {
|
impl Container {
|
||||||
pub fn new() -> Container {
|
pub fn new() -> Container {
|
||||||
Container {
|
Container {
|
||||||
mode: Mode::Scaled,
|
mode: Mode::Scaled,
|
||||||
elements: HashMap::new(),
|
elements: HashMap::new(),
|
||||||
elements_list: Vec::new(),
|
elements_list: Vec::new(),
|
||||||
version: 0xFFFF,
|
version: 0xFFFF,
|
||||||
last_sw: 0.0,
|
last_sw: 0.0,
|
||||||
last_sh: 0.0,
|
last_sh: 0.0,
|
||||||
last_width: 0.0,
|
last_width: 0.0,
|
||||||
last_height: 0.0,
|
last_height: 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add<T: UIElement>(&mut self, e: T) -> ElementRef<T> {
|
pub fn add<T: UIElement>(&mut self, e: T) -> ElementRef<T> {
|
||||||
let mut r = ElementRefInner{index: rand::random()};
|
let mut r = ElementRefInner { index: rand::random() };
|
||||||
while self.elements.contains_key(&r) {
|
while self.elements.contains_key(&r) {
|
||||||
r = ElementRefInner{index: rand::random()};
|
r = ElementRefInner { index: rand::random() };
|
||||||
}
|
}
|
||||||
self.elements.insert(r, e.wrap());
|
self.elements.insert(r, e.wrap());
|
||||||
self.elements_list.push(r);
|
self.elements_list.push(r);
|
||||||
ElementRef{inner: r, ty: PhantomData}
|
ElementRef {
|
||||||
}
|
inner: r,
|
||||||
|
ty: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get<T: UIElement>(&self, r: &ElementRef<T>) -> &T {
|
pub fn get<T: UIElement>(&self, r: &ElementRef<T>) -> &T {
|
||||||
T::unwrap_ref(self.elements.get(&r.inner).unwrap())
|
T::unwrap_ref(self.elements.get(&r.inner).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut<T: UIElement>(&mut self, r: &ElementRef<T>) -> &mut T {
|
pub fn get_mut<T: UIElement>(&mut self, r: &ElementRef<T>) -> &mut T {
|
||||||
T::unwrap_ref_mut(self.elements.get_mut(&r.inner).unwrap())
|
T::unwrap_ref_mut(self.elements.get_mut(&r.inner).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove<T: UIElement>(&mut self, r: &ElementRef<T>) {
|
pub fn remove<T: UIElement>(&mut self, r: &ElementRef<T>) {
|
||||||
self.remove_raw(&r.inner);
|
self.remove_raw(&r.inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_raw(&mut self, r: &ElementRefInner) {
|
|
||||||
self.elements.remove(&r);
|
|
||||||
self.elements_list.iter()
|
|
||||||
.position(|&e| e.index == r.index)
|
|
||||||
.map(|e| self.elements_list.remove(e))
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tick(&mut self, renderer: &mut render::Renderer, delta: f64, width: f64, height: f64) {
|
fn remove_raw(&mut self, r: &ElementRefInner) {
|
||||||
let (sw, sh) = match self.mode {
|
self.elements.remove(&r);
|
||||||
Mode::Scaled => (SCALED_WIDTH / width, SCALED_HEIGHT / height),
|
self.elements_list
|
||||||
Mode::Unscaled(scale) => (scale, scale),
|
.iter()
|
||||||
};
|
.position(|&e| e.index == r.index)
|
||||||
|
.map(|e| self.elements_list.remove(e))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
if self.last_sw != sw || self.last_sh != sh
|
pub fn tick(&mut self, renderer: &mut render::Renderer, delta: f64, width: f64, height: f64) {
|
||||||
|| self.last_width != width || self.last_height != height
|
let (sw, sh) = match self.mode {
|
||||||
|| self.version != renderer.ui.version {
|
Mode::Scaled => (SCALED_WIDTH / width, SCALED_HEIGHT / height),
|
||||||
self.last_sw = sw;
|
Mode::Unscaled(scale) => (scale, scale),
|
||||||
self.last_sh = sh;
|
};
|
||||||
self.last_width = width;
|
|
||||||
self.last_height = height;
|
if self.last_sw != sw || self.last_sh != sh || self.last_width != width ||
|
||||||
for (_, e) in &mut self.elements {
|
self.last_height != height || self.version != renderer.ui.version {
|
||||||
e.set_dirty(true);
|
self.last_sw = sw;
|
||||||
if self.version != renderer.ui.version {
|
self.last_sh = sh;
|
||||||
e.update(renderer);
|
self.last_width = width;
|
||||||
}
|
self.last_height = height;
|
||||||
}
|
for (_, e) in &mut self.elements {
|
||||||
self.version = renderer.ui.version;
|
e.set_dirty(true);
|
||||||
}
|
if self.version != renderer.ui.version {
|
||||||
|
e.update(renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.version = renderer.ui.version;
|
||||||
|
}
|
||||||
|
|
||||||
// Borrow rules seem to prevent us from doing this in the first pass
|
// Borrow rules seem to prevent us from doing this in the first pass
|
||||||
// so we split it.
|
// so we split it.
|
||||||
let regions = self.collect_elements(sw, sh);
|
let regions = self.collect_elements(sw, sh);
|
||||||
for re in &self.elements_list {
|
for re in &self.elements_list {
|
||||||
let mut e = self.elements.get_mut(re).unwrap();
|
let mut e = self.elements.get_mut(re).unwrap();
|
||||||
if !e.should_draw() {
|
if !e.should_draw() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(&(ref r, ref dirty)) = regions.get(re) {
|
if let Some(&(ref r, ref dirty)) = regions.get(re) {
|
||||||
e.set_dirty(*dirty);
|
e.set_dirty(*dirty);
|
||||||
let data = e.draw(renderer, r, width, height, delta);
|
let data = e.draw(renderer, r, width, height, delta);
|
||||||
renderer.ui.add_bytes(data);
|
renderer.ui.add_bytes(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_elements(&self, sw: f64, sh: f64) -> HashMap<ElementRefInner, (Region, bool)> {
|
fn collect_elements(&self, sw: f64, sh: f64) -> HashMap<ElementRefInner, (Region, bool)> {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
for (re, e) in &self.elements {
|
for (re, e) in &self.elements {
|
||||||
if !e.should_draw() {
|
if !e.should_draw() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let r = self.get_draw_region(e, sw, sh);
|
let r = self.get_draw_region(e, sw, sh);
|
||||||
if r.intersects(&SCREEN) {
|
if r.intersects(&SCREEN) {
|
||||||
// Mark this as dirty if any of its
|
// Mark this as dirty if any of its
|
||||||
// parents are dirty too.
|
// parents are dirty too.
|
||||||
let mut dirty = e.is_dirty();
|
let mut dirty = e.is_dirty();
|
||||||
let mut parent = e.get_parent();
|
let mut parent = e.get_parent();
|
||||||
while !dirty && parent.is_some() {
|
while !dirty && parent.is_some() {
|
||||||
let p = self.elements.get(&parent.unwrap()).unwrap();
|
let p = self.elements.get(&parent.unwrap()).unwrap();
|
||||||
dirty = p.is_dirty();
|
dirty = p.is_dirty();
|
||||||
parent = p.get_parent();
|
parent = p.get_parent();
|
||||||
}
|
}
|
||||||
map.insert(*re, (r, dirty));
|
map.insert(*re, (r, dirty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn click_at(&mut self, game: &mut ::Game, x: f64, y: f64, width: f64, height: f64) {
|
pub fn click_at(&mut self, game: &mut ::Game, x: f64, y: f64, width: f64, height: f64) {
|
||||||
let (sw, sh) = match self.mode {
|
let (sw, sh) = match self.mode {
|
||||||
Mode::Scaled => (SCALED_WIDTH / width, SCALED_HEIGHT / height),
|
Mode::Scaled => (SCALED_WIDTH / width, SCALED_HEIGHT / height),
|
||||||
Mode::Unscaled(scale) => (scale, scale),
|
Mode::Unscaled(scale) => (scale, scale),
|
||||||
};
|
};
|
||||||
let mx = (x / width) * SCALED_WIDTH;
|
let mx = (x / width) * SCALED_WIDTH;
|
||||||
let my = (y / height) * SCALED_HEIGHT;
|
let my = (y / height) * SCALED_HEIGHT;
|
||||||
let mut click = None;
|
let mut click = None;
|
||||||
for re in self.elements_list.iter().rev() {
|
for re in self.elements_list.iter().rev() {
|
||||||
let e = self.elements.get(re).unwrap();
|
let e = self.elements.get(re).unwrap();
|
||||||
let funcs = e.get_click_funcs();
|
let funcs = e.get_click_funcs();
|
||||||
if !funcs.is_empty() {
|
if !funcs.is_empty() {
|
||||||
let r = self.get_draw_region(e, sw, sh);
|
let r = self.get_draw_region(e, sw, sh);
|
||||||
if mx >= r.x && mx <= r.x + r.w && my >= r.y && my <= r.y + r.h {
|
if mx >= r.x && mx <= r.x + r.w && my >= r.y && my <= r.y + r.h {
|
||||||
click = Some(funcs);
|
click = Some(funcs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(click) = click {
|
if let Some(click) = click {
|
||||||
for c in &click {
|
for c in &click {
|
||||||
c(game, self);
|
c(game, self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hover_at(&mut self, game: &mut ::Game, x: f64, y: f64, width: f64, height: f64) {
|
pub fn hover_at(&mut self, game: &mut ::Game, x: f64, y: f64, width: f64, height: f64) {
|
||||||
let (sw, sh) = match self.mode {
|
let (sw, sh) = match self.mode {
|
||||||
Mode::Scaled => (SCALED_WIDTH / width, SCALED_HEIGHT / height),
|
Mode::Scaled => (SCALED_WIDTH / width, SCALED_HEIGHT / height),
|
||||||
Mode::Unscaled(scale) => (scale, scale),
|
Mode::Unscaled(scale) => (scale, scale),
|
||||||
};
|
};
|
||||||
let mx = (x / width) * SCALED_WIDTH;
|
let mx = (x / width) * SCALED_WIDTH;
|
||||||
let my = (y / height) * SCALED_HEIGHT;
|
let my = (y / height) * SCALED_HEIGHT;
|
||||||
let mut hovers = Vec::new();
|
let mut hovers = Vec::new();
|
||||||
for re in self.elements_list.iter().rev() {
|
for re in self.elements_list.iter().rev() {
|
||||||
let e = self.elements.get(re).unwrap();
|
let e = self.elements.get(re).unwrap();
|
||||||
let funcs = e.get_hover_funcs();
|
let funcs = e.get_hover_funcs();
|
||||||
if !funcs.is_empty() {
|
if !funcs.is_empty() {
|
||||||
let r = self.get_draw_region(e, sw, sh);
|
let r = self.get_draw_region(e, sw, sh);
|
||||||
hovers.push((*re, funcs, mx >= r.x && mx <= r.x + r.w && my >= r.y && my <= r.y + r.h));
|
hovers.push((*re,
|
||||||
}
|
funcs,
|
||||||
}
|
mx >= r.x && mx <= r.x + r.w && my >= r.y && my <= r.y + r.h));
|
||||||
for hover in &hovers {
|
}
|
||||||
let call = {
|
}
|
||||||
let e = self.elements.get_mut(&hover.0).unwrap();
|
for hover in &hovers {
|
||||||
e.should_call_hover(hover.2)
|
let call = {
|
||||||
};
|
let e = self.elements.get_mut(&hover.0).unwrap();
|
||||||
if call {
|
e.should_call_hover(hover.2)
|
||||||
for f in &hover.1 {
|
};
|
||||||
f(hover.2, game, self);
|
if call {
|
||||||
}
|
for f in &hover.1 {
|
||||||
}
|
f(hover.2, game, self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_draw_region(&self, e: &Element, sw: f64, sh: f64) -> Region {
|
fn get_draw_region(&self, e: &Element, sw: f64, sh: f64) -> Region {
|
||||||
let super_region = match e.get_parent() {
|
let super_region = match e.get_parent() {
|
||||||
Some(ref p) => self.get_draw_region(self.elements.get(p).unwrap(), sw, sh),
|
Some(ref p) => self.get_draw_region(self.elements.get(p).unwrap(), sw, sh),
|
||||||
None => SCREEN,
|
None => SCREEN,
|
||||||
};
|
};
|
||||||
Container::get_draw_region_raw(e, sw, sh, &super_region)
|
Container::get_draw_region_raw(e, sw, sh, &super_region)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_draw_region_raw(e: &Element, sw: f64, sh: f64, super_region: &Region) -> Region {
|
fn get_draw_region_raw(e: &Element, sw: f64, sh: f64, super_region: &Region) -> Region {
|
||||||
let mut r = Region{x:0.0,y:0.0,w:0.0,h:0.0};
|
let mut r = Region {
|
||||||
let (w, h) = e.get_size();
|
x: 0.0,
|
||||||
let (ox, oy) = e.get_offset();
|
y: 0.0,
|
||||||
r.w = w * sw;
|
w: 0.0,
|
||||||
r.h = h * sh;
|
h: 0.0,
|
||||||
let (v_attach, h_attach) = e.get_attachment();
|
};
|
||||||
match h_attach {
|
let (w, h) = e.get_size();
|
||||||
HAttach::Left => r.x = ox * sw,
|
let (ox, oy) = e.get_offset();
|
||||||
HAttach::Center => r.x = (super_region.w / 2.0) - (r.w / 2.0) + ox * sw,
|
r.w = w * sw;
|
||||||
HAttach::Right => r.x = super_region.w - ox * sw - r.w,
|
r.h = h * sh;
|
||||||
}
|
let (v_attach, h_attach) = e.get_attachment();
|
||||||
match v_attach {
|
match h_attach {
|
||||||
VAttach::Top => r.y = oy * sh,
|
HAttach::Left => r.x = ox * sw,
|
||||||
VAttach::Middle => r.y = (super_region.h / 2.0) - (r.h / 2.0) + oy * sh,
|
HAttach::Center => r.x = (super_region.w / 2.0) - (r.w / 2.0) + ox * sw,
|
||||||
VAttach::Bottom => r.y = super_region.h - oy * sh - r.h,
|
HAttach::Right => r.x = super_region.w - ox * sw - r.w,
|
||||||
}
|
}
|
||||||
r.x += super_region.x;
|
match v_attach {
|
||||||
r.y += super_region.y;
|
VAttach::Top => r.y = oy * sh,
|
||||||
r
|
VAttach::Middle => r.y = (super_region.h / 2.0) - (r.h / 2.0) + oy * sh,
|
||||||
}
|
VAttach::Bottom => r.y = super_region.h - oy * sh - r.h,
|
||||||
|
}
|
||||||
|
r.x += super_region.x;
|
||||||
|
r.y += super_region.y;
|
||||||
|
r
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UIElement {
|
pub trait UIElement {
|
||||||
fn wrap(self) -> Element;
|
fn wrap(self) -> Element;
|
||||||
fn unwrap_ref(&Element) -> &Self;
|
fn unwrap_ref(&Element) -> &Self;
|
||||||
fn unwrap_ref_mut(&mut Element) -> &mut Self;
|
fn unwrap_ref_mut(&mut Element) -> &mut Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! lazy_field {
|
macro_rules! lazy_field {
|
||||||
($name:ident, $t:ty, $get:ident, $set:ident) => (
|
($name:ident, $t:ty, $get:ident, $set:ident) => (
|
||||||
pub fn $get(&self) -> $t {
|
pub fn $get(&self) -> $t {
|
||||||
self.$name
|
self.$name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn $set(&mut self, val: $t) {
|
pub fn $set(&mut self, val: $t) {
|
||||||
if self.$name != val {
|
if self.$name != val {
|
||||||
self.$name = val;
|
self.$name = val;
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -487,16 +498,16 @@ macro_rules! ui_element {
|
||||||
),+
|
),+
|
||||||
}
|
}
|
||||||
) => (
|
) => (
|
||||||
pub struct $name {
|
pub struct $name {
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
parent: Option<ElementRefInner>,
|
parent: Option<ElementRefInner>,
|
||||||
should_draw: bool,
|
should_draw: bool,
|
||||||
layer: isize,
|
layer: isize,
|
||||||
x: f64,
|
x: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
v_attach: VAttach,
|
v_attach: VAttach,
|
||||||
h_attach: HAttach,
|
h_attach: HAttach,
|
||||||
click_funcs: Vec<ClickFunc>,
|
click_funcs: Vec<ClickFunc>,
|
||||||
hover_funcs: Vec<HoverFunc>,
|
hover_funcs: Vec<HoverFunc>,
|
||||||
hovered: bool,
|
hovered: bool,
|
||||||
|
@ -532,7 +543,7 @@ macro_rules! base_impl {
|
||||||
|
|
||||||
macro_rules! ui_create {
|
macro_rules! ui_create {
|
||||||
($name:ident {
|
($name:ident {
|
||||||
$($field:ident: $e:expr),+
|
$($field:ident: $e:expr,)+
|
||||||
}) => (
|
}) => (
|
||||||
$name {
|
$name {
|
||||||
dirty: true,
|
dirty: true,
|
||||||
|
@ -553,9 +564,9 @@ macro_rules! ui_create {
|
||||||
|
|
||||||
// Include instead of mod so we can access private parts.
|
// Include instead of mod so we can access private parts.
|
||||||
// Its a bit ew doing it this way but it saves us making
|
// Its a bit ew doing it this way but it saves us making
|
||||||
// fields public that should be private or having a huge
|
// fields public that should be private or having a huge
|
||||||
// file.
|
// file.
|
||||||
include!("image.rs");
|
include!("image.rs");
|
||||||
include!("batch.rs");
|
include!("batch.rs");
|
||||||
include!("text.rs");
|
include!("text.rs");
|
||||||
include!("formatted.rs");
|
include!("formatted.rs");
|
||||||
|
|
169
src/ui/text.rs
169
src/ui/text.rs
|
@ -28,65 +28,94 @@ ui_element!(Text {
|
||||||
impl Text {
|
impl Text {
|
||||||
base_impl!();
|
base_impl!();
|
||||||
|
|
||||||
pub fn new(renderer: &render::Renderer, val: &str, x: f64, y: f64, r: u8, g: u8, b: u8) -> Text {
|
pub fn new(renderer: &render::Renderer,
|
||||||
ui_create!(Text {
|
val: &str,
|
||||||
val: val.to_owned(),
|
x: f64,
|
||||||
x: x,
|
y: f64,
|
||||||
y: y,
|
r: u8,
|
||||||
width: renderer.ui.size_of_string(val),
|
g: u8,
|
||||||
height: 18.0,
|
b: u8)
|
||||||
scale_x: 1.0,
|
-> Text {
|
||||||
scale_y: 1.0,
|
ui_create!(Text {
|
||||||
rotation: 0.0,
|
val: val.to_owned(),
|
||||||
r: r,
|
x: x,
|
||||||
g: g,
|
y: y,
|
||||||
b: b,
|
width: renderer.ui.size_of_string(val),
|
||||||
a: 255
|
height: 18.0,
|
||||||
})
|
scale_x: 1.0,
|
||||||
}
|
scale_y: 1.0,
|
||||||
|
rotation: 0.0,
|
||||||
|
r: r,
|
||||||
|
g: g,
|
||||||
|
b: b,
|
||||||
|
a: 255,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn update(&mut self, renderer: &mut render::Renderer) {
|
fn update(&mut self, renderer: &mut render::Renderer) {
|
||||||
self.width = renderer.ui.size_of_string(&self.val);
|
self.width = renderer.ui.size_of_string(&self.val);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, _: f64) -> &Vec<u8> {
|
fn draw(&mut self,
|
||||||
if self.dirty {
|
renderer: &mut render::Renderer,
|
||||||
self.dirty = false;
|
r: &Region,
|
||||||
let sx = r.w / self.width;
|
width: f64,
|
||||||
let sy = r.h / self.height;
|
height: f64,
|
||||||
let mut text = if self.rotation == 0.0 {
|
_: f64)
|
||||||
renderer.ui.new_text_scaled(&self.val, r.x, r.y, sx*self.scale_x, sy*self.scale_y, self.r, self.g, self.b)
|
-> &Vec<u8> {
|
||||||
} else {
|
if self.dirty {
|
||||||
let c = self.rotation.cos();
|
self.dirty = false;
|
||||||
let s = self.rotation.sin();
|
let sx = r.w / self.width;
|
||||||
let tmpx = r.w / 2.0;
|
let sy = r.h / self.height;
|
||||||
let tmpy = r.h / 2.0;
|
let mut text = if self.rotation == 0.0 {
|
||||||
let w = (tmpx*c - tmpy*s).abs();
|
renderer.ui.new_text_scaled(&self.val,
|
||||||
let h = (tmpy*c + tmpx*s).abs();
|
r.x,
|
||||||
renderer.ui.new_text_rotated(&self.val, r.x+w-(r.w / 2.0), r.y+h-(r.h / 2.0), sx*self.scale_x, sy*self.scale_y, self.rotation, self.r, self.g, self.b)
|
r.y,
|
||||||
};
|
sx * self.scale_x,
|
||||||
for e in &mut text.elements {
|
sy * self.scale_y,
|
||||||
e.a = self.a;
|
self.r,
|
||||||
e.layer = self.layer;
|
self.g,
|
||||||
}
|
self.b)
|
||||||
self.data = text.bytes(width, height);
|
} else {
|
||||||
}
|
let c = self.rotation.cos();
|
||||||
&self.data
|
let s = self.rotation.sin();
|
||||||
}
|
let tmpx = r.w / 2.0;
|
||||||
|
let tmpy = r.h / 2.0;
|
||||||
|
let w = (tmpx * c - tmpy * s).abs();
|
||||||
|
let h = (tmpy * c + tmpx * s).abs();
|
||||||
|
renderer.ui.new_text_rotated(&self.val,
|
||||||
|
r.x + w - (r.w / 2.0),
|
||||||
|
r.y + h - (r.h / 2.0),
|
||||||
|
sx * self.scale_x,
|
||||||
|
sy * self.scale_y,
|
||||||
|
self.rotation,
|
||||||
|
self.r,
|
||||||
|
self.g,
|
||||||
|
self.b)
|
||||||
|
};
|
||||||
|
for e in &mut text.elements {
|
||||||
|
e.a = self.a;
|
||||||
|
e.layer = self.layer;
|
||||||
|
}
|
||||||
|
self.data = text.bytes(width, height);
|
||||||
|
}
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_size(&self) -> (f64, f64) {
|
pub fn get_size(&self) -> (f64, f64) {
|
||||||
((self.width + 2.0) * self.scale_x, self.height * self.scale_y)
|
((self.width + 2.0) * self.scale_x,
|
||||||
}
|
self.height * self.scale_y)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_text(&self) -> &str {
|
pub fn get_text(&self) -> &str {
|
||||||
&self.val
|
&self.val
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_text(&mut self, renderer: &render::Renderer, val: &str) {
|
pub fn set_text(&mut self, renderer: &render::Renderer, val: &str) {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
self.val = val.to_owned();
|
self.val = val.to_owned();
|
||||||
self.width = renderer.ui.size_of_string(val);
|
self.width = renderer.ui.size_of_string(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_field!(width, f64, get_width, set_width);
|
lazy_field!(width, f64, get_width, set_width);
|
||||||
lazy_field!(height, f64, get_height, set_height);
|
lazy_field!(height, f64, get_height, set_height);
|
||||||
|
@ -100,21 +129,21 @@ impl Text {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIElement for Text {
|
impl UIElement for Text {
|
||||||
fn wrap(self) -> Element {
|
fn wrap(self) -> Element {
|
||||||
Element::Text(self)
|
Element::Text(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwrap_ref<'a>(e: &'a Element) -> &'a Text {
|
fn unwrap_ref<'a>(e: &'a Element) -> &'a Text {
|
||||||
match e {
|
match e {
|
||||||
&Element::Text(ref val) => val,
|
&Element::Text(ref val) => val,
|
||||||
_ => panic!("Incorrect type"),
|
_ => panic!("Incorrect type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Text {
|
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Text {
|
||||||
match e {
|
match e {
|
||||||
&mut Element::Text(ref mut val) => val,
|
&mut Element::Text(ref mut val) => val,
|
||||||
_ => panic!("Incorrect type"),
|
_ => panic!("Incorrect type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue