Reformat using rustfmt

This commit is contained in:
Thinkofdeath 2015-10-07 19:36:59 +01:00
parent ffc9ac0e47
commit 3704b9eeb8
29 changed files with 3503 additions and 2785 deletions

View File

@ -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 {}

View File

@ -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();
} }
}, }
} }
} }

View File

@ -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()));
} }
} }

View File

@ -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(())

View File

@ -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);
}, }
_ => () _ => (),
} }
} }

View File

@ -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)

View File

@ -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!();
} }

View File

@ -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;

View File

@ -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)]

View File

@ -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)
} }
} }

View File

@ -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

View File

@ -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
} }

View File

@ -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);
} }
} }

View File

@ -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)
} }
} }

View File

@ -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);
} }
} }

View File

@ -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);
}
}

View File

@ -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();
} }
} }
} }

View File

@ -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;

View File

@ -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
} }
} }

View File

@ -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 {

View File

@ -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() {

View File

@ -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;

View File

@ -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, &reg, width, height, delta)); self.data.extend(e.draw(renderer, &reg, 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"),
} }
} }
} }

View File

@ -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, &reg, 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, &reg, 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)
} }
} }

View File

@ -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"),
} }
} }
} }

View File

@ -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);
} }
} }

View File

@ -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");

View File

@ -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"),
} }
} }
} }