2016-03-16 14:25:35 -04:00
|
|
|
// Copyright 2016 Matthew Collins
|
2015-09-28 18:37:14 -04:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2015-09-23 15:16:25 -04:00
|
|
|
|
2015-09-25 09:48:35 -04:00
|
|
|
use std::cell::RefCell;
|
2020-06-21 15:17:24 -04:00
|
|
|
use std::rc::Rc;
|
|
|
|
use std::sync::mpsc;
|
|
|
|
use std::thread;
|
|
|
|
use std_or_web::fs;
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2018-11-04 14:48:03 -05:00
|
|
|
use crate::format;
|
|
|
|
use crate::format::{Component, TextComponent};
|
|
|
|
use crate::protocol;
|
2020-06-21 15:17:24 -04:00
|
|
|
use crate::render;
|
|
|
|
use crate::ui;
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2020-12-27 18:06:03 -05:00
|
|
|
use instant::Duration;
|
2015-10-07 14:36:59 -04:00
|
|
|
use rand::Rng;
|
2015-09-23 15:16:25 -04:00
|
|
|
|
|
|
|
pub struct ServerList {
|
2015-10-07 14:36:59 -04:00
|
|
|
elements: Option<UIElements>,
|
|
|
|
disconnect_reason: Option<Component>,
|
2015-09-25 09:48:35 -04:00
|
|
|
|
2015-10-07 14:36:59 -04:00
|
|
|
needs_reload: Rc<RefCell<bool>>,
|
2015-09-23 15:16:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
struct UIElements {
|
2015-10-07 14:36:59 -04:00
|
|
|
logo: ui::logo::Logo,
|
|
|
|
servers: Vec<Server>,
|
2016-04-24 07:22:04 -04:00
|
|
|
|
|
|
|
_add_btn: ui::ButtonRef,
|
|
|
|
_refresh_btn: ui::ButtonRef,
|
|
|
|
_options_btn: ui::ButtonRef,
|
|
|
|
_disclaimer: ui::TextRef,
|
|
|
|
|
|
|
|
_disconnected: Option<ui::ImageRef>,
|
2015-09-23 15:16:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
struct Server {
|
2016-04-24 07:22:04 -04:00
|
|
|
back: ui::ImageRef,
|
2015-10-07 14:36:59 -04:00
|
|
|
offset: f64,
|
|
|
|
y: f64,
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2016-04-24 07:22:04 -04:00
|
|
|
motd: ui::FormattedRef,
|
|
|
|
ping: ui::ImageRef,
|
|
|
|
players: ui::TextRef,
|
|
|
|
version: ui::FormattedRef,
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2016-04-24 07:22:04 -04:00
|
|
|
icon: ui::ImageRef,
|
2015-10-07 14:36:59 -04:00
|
|
|
icon_texture: Option<String>,
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2015-10-07 14:36:59 -04:00
|
|
|
done_ping: bool,
|
|
|
|
recv: mpsc::Receiver<PingInfo>,
|
2015-09-25 09:00:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
struct PingInfo {
|
2015-10-07 14:36:59 -04:00
|
|
|
motd: format::Component,
|
2018-09-30 01:57:55 -04:00
|
|
|
ping: Duration,
|
2015-10-07 14:36:59 -04:00
|
|
|
exists: bool,
|
|
|
|
online: i32,
|
|
|
|
max: i32,
|
|
|
|
protocol_version: i32,
|
|
|
|
protocol_name: String,
|
2019-05-05 21:37:37 -04:00
|
|
|
forge_mods: Vec<crate::protocol::forge::ForgeMod>,
|
2015-10-07 14:36:59 -04:00
|
|
|
favicon: Option<image::DynamicImage>,
|
2015-09-23 15:16:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Server {
|
2015-10-07 14:36:59 -04:00
|
|
|
fn update_position(&mut self) {
|
|
|
|
if self.offset < 0.0 {
|
|
|
|
self.y = self.offset * 200.0;
|
|
|
|
} else {
|
|
|
|
self.y = self.offset * 100.0;
|
|
|
|
}
|
|
|
|
}
|
2015-09-23 15:16:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ServerList {
|
2015-10-07 14:36:59 -04:00
|
|
|
pub fn new(disconnect_reason: Option<Component>) -> ServerList {
|
|
|
|
ServerList {
|
|
|
|
elements: None,
|
2018-11-04 16:43:30 -05:00
|
|
|
disconnect_reason,
|
2015-10-07 14:36:59 -04:00
|
|
|
needs_reload: Rc::new(RefCell::new(false)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
fn reload_server_list(
|
|
|
|
&mut self,
|
|
|
|
renderer: &mut render::Renderer,
|
|
|
|
ui_container: &mut ui::Container,
|
|
|
|
) {
|
2015-10-07 14:36:59 -04:00
|
|
|
let elements = self.elements.as_mut().unwrap();
|
|
|
|
*self.needs_reload.borrow_mut() = false;
|
|
|
|
{
|
2016-04-24 07:22:04 -04:00
|
|
|
// Clean up previous list icons.
|
2015-10-07 14:36:59 -04:00
|
|
|
let mut tex = renderer.get_textures_ref().write().unwrap();
|
|
|
|
for server in &mut elements.servers {
|
|
|
|
if let Some(ref icon) = server.icon_texture {
|
2016-09-15 10:15:52 -04:00
|
|
|
tex.remove_dynamic(icon);
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elements.servers.clear();
|
|
|
|
|
|
|
|
let file = match fs::File::open("servers.json") {
|
|
|
|
Ok(val) => val,
|
|
|
|
Err(_) => return,
|
|
|
|
};
|
|
|
|
let servers_info: serde_json::Value = serde_json::from_reader(file).unwrap();
|
2018-10-23 21:47:21 -04:00
|
|
|
let servers = servers_info.get("servers").unwrap().as_array().unwrap();
|
2015-10-07 14:36:59 -04:00
|
|
|
let mut offset = 0.0;
|
2015-09-23 15:16:25 -04:00
|
|
|
|
2016-04-01 19:46:39 -04:00
|
|
|
for (index, svr) in servers.iter().enumerate() {
|
2018-10-23 21:47:21 -04:00
|
|
|
let name = svr.get("name").unwrap().as_str().unwrap().to_owned();
|
|
|
|
let address = svr.get("address").unwrap().as_str().unwrap().to_owned();
|
2015-09-23 15:16:25 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Everything is attached to this
|
2016-04-24 07:22:04 -04:00
|
|
|
let back = ui::ImageBuilder::new()
|
|
|
|
.texture("steven:solid")
|
|
|
|
.position(0.0, offset * 100.0)
|
|
|
|
.size(700.0, 100.0)
|
|
|
|
.colour((0, 0, 0, 100))
|
|
|
|
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
|
|
|
|
.create(ui_container);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
|
|
|
let (send, recv) = mpsc::channel::<PingInfo>();
|
2016-03-20 16:17:21 -04:00
|
|
|
// Make whole entry interactable
|
2015-10-07 14:36:59 -04:00
|
|
|
{
|
2016-04-24 07:22:04 -04:00
|
|
|
let mut backr = back.borrow_mut();
|
2015-10-07 14:36:59 -04:00
|
|
|
let address = address.clone();
|
2016-04-24 07:22:04 -04:00
|
|
|
backr.add_hover_func(move |this, over, _| {
|
2020-06-21 15:17:24 -04:00
|
|
|
this.colour.3 = if over { 200 } else { 100 };
|
2016-04-24 07:22:04 -04:00
|
|
|
false
|
2016-03-20 16:17:21 -04:00
|
|
|
});
|
2016-04-24 07:22:04 -04:00
|
|
|
backr.add_click_func(move |_, game| {
|
2020-06-21 15:17:24 -04:00
|
|
|
game.screen_sys
|
|
|
|
.replace_screen(Box::new(super::connecting::Connecting::new(&address)));
|
2016-03-20 08:04:02 -04:00
|
|
|
game.connect_to(&address);
|
2016-04-24 07:22:04 -04:00
|
|
|
true
|
2016-03-20 16:17:21 -04:00
|
|
|
});
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
2015-09-23 15:16:25 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Server name
|
2016-04-24 07:22:04 -04:00
|
|
|
ui::TextBuilder::new()
|
|
|
|
.text(name.clone())
|
|
|
|
.position(100.0, 5.0)
|
|
|
|
.attach(&mut *back.borrow_mut());
|
2015-09-23 15:16:25 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Server icon
|
2016-04-24 07:22:04 -04:00
|
|
|
let icon = ui::ImageBuilder::new()
|
|
|
|
.texture("misc/unknown_server")
|
|
|
|
.position(5.0, 5.0)
|
|
|
|
.size(90.0, 90.0)
|
|
|
|
.attach(&mut *back.borrow_mut());
|
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Ping indicator
|
2016-04-24 07:22:04 -04:00
|
|
|
let ping = ui::ImageBuilder::new()
|
|
|
|
.texture("gui/icons")
|
|
|
|
.position(5.0, 5.0)
|
|
|
|
.size(20.0, 16.0)
|
|
|
|
.texture_coords((0.0, 56.0 / 256.0, 10.0 / 256.0, 8.0 / 256.0))
|
|
|
|
.alignment(ui::VAttach::Top, ui::HAttach::Right)
|
|
|
|
.attach(&mut *back.borrow_mut());
|
2015-09-23 15:16:25 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Player count
|
2016-04-24 07:22:04 -04:00
|
|
|
let players = ui::TextBuilder::new()
|
|
|
|
.text("???")
|
|
|
|
.position(30.0, 5.0)
|
|
|
|
.alignment(ui::VAttach::Top, ui::HAttach::Right)
|
|
|
|
.attach(&mut *back.borrow_mut());
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Server's message of the day
|
2016-04-24 07:22:04 -04:00
|
|
|
let motd = ui::FormattedBuilder::new()
|
|
|
|
.text(Component::Text(TextComponent::new("Connecting...")))
|
|
|
|
.position(100.0, 23.0)
|
|
|
|
.max_width(700.0 - (90.0 + 10.0 + 5.0))
|
|
|
|
.attach(&mut *back.borrow_mut());
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Version information
|
2016-04-24 07:22:04 -04:00
|
|
|
let version = ui::FormattedBuilder::new()
|
|
|
|
.text(Component::Text(TextComponent::new("")))
|
|
|
|
.position(100.0, 5.0)
|
|
|
|
.max_width(700.0 - (90.0 + 10.0 + 5.0))
|
|
|
|
.alignment(ui::VAttach::Bottom, ui::HAttach::Left)
|
|
|
|
.attach(&mut *back.borrow_mut());
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Delete entry button
|
2016-04-24 07:22:04 -04:00
|
|
|
let delete_entry = ui::ButtonBuilder::new()
|
|
|
|
.position(0.0, 0.0)
|
|
|
|
.size(25.0, 25.0)
|
|
|
|
.alignment(ui::VAttach::Bottom, ui::HAttach::Right)
|
|
|
|
.attach(&mut *back.borrow_mut());
|
|
|
|
{
|
|
|
|
let mut btn = delete_entry.borrow_mut();
|
|
|
|
let txt = ui::TextBuilder::new()
|
|
|
|
.text("X")
|
|
|
|
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
|
|
|
|
.attach(&mut *btn);
|
|
|
|
btn.add_text(txt);
|
2020-07-04 20:42:17 -04:00
|
|
|
let index = index;
|
|
|
|
let sname = name.clone();
|
|
|
|
let saddr = address.clone();
|
|
|
|
btn.add_click_func(move |_, game| {
|
|
|
|
game.screen_sys.replace_screen(Box::new(
|
|
|
|
super::delete_server::DeleteServerEntry::new(index, &sname, &saddr),
|
|
|
|
));
|
|
|
|
true
|
|
|
|
})
|
2016-04-24 07:22:04 -04:00
|
|
|
}
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Edit entry button
|
2016-04-24 07:22:04 -04:00
|
|
|
let edit_entry = ui::ButtonBuilder::new()
|
|
|
|
.position(25.0, 0.0)
|
|
|
|
.size(25.0, 25.0)
|
|
|
|
.alignment(ui::VAttach::Bottom, ui::HAttach::Right)
|
|
|
|
.attach(&mut *back.borrow_mut());
|
|
|
|
{
|
|
|
|
let mut btn = edit_entry.borrow_mut();
|
|
|
|
let txt = ui::TextBuilder::new()
|
|
|
|
.text("E")
|
|
|
|
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
|
|
|
|
.attach(&mut *btn);
|
|
|
|
btn.add_text(txt);
|
|
|
|
let index = index;
|
|
|
|
let sname = name.clone();
|
|
|
|
let saddr = address.clone();
|
|
|
|
btn.add_click_func(move |_, game| {
|
2020-06-21 15:17:24 -04:00
|
|
|
game.screen_sys.replace_screen(Box::new(
|
|
|
|
super::edit_server::EditServerEntry::new(Some((
|
|
|
|
index,
|
|
|
|
sname.clone(),
|
|
|
|
saddr.clone(),
|
|
|
|
))),
|
|
|
|
));
|
2016-04-24 07:22:04 -04:00
|
|
|
true
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut server = Server {
|
2018-11-04 16:43:30 -05:00
|
|
|
back,
|
|
|
|
offset,
|
2016-04-24 07:22:04 -04:00
|
|
|
y: 0.0,
|
|
|
|
done_ping: false,
|
2018-11-04 16:43:30 -05:00
|
|
|
recv,
|
2016-04-24 07:22:04 -04:00
|
|
|
|
2018-11-04 16:43:30 -05:00
|
|
|
motd,
|
|
|
|
ping,
|
|
|
|
players,
|
|
|
|
version,
|
2015-10-07 14:36:59 -04:00
|
|
|
|
2018-11-04 16:43:30 -05:00
|
|
|
icon,
|
2016-04-24 07:22:04 -04:00
|
|
|
icon_texture: None,
|
|
|
|
};
|
|
|
|
server.update_position();
|
2015-10-07 14:36:59 -04:00
|
|
|
elements.servers.push(server);
|
|
|
|
offset += 1.0;
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Don't block the main thread whilst pinging the server
|
2015-10-07 14:36:59 -04:00
|
|
|
thread::spawn(move || {
|
2020-06-21 15:17:24 -04:00
|
|
|
match protocol::Conn::new(&address, protocol::SUPPORTED_PROTOCOLS[0])
|
|
|
|
.and_then(|conn| conn.do_status())
|
|
|
|
{
|
2015-10-07 14:36:59 -04:00
|
|
|
Ok(res) => {
|
|
|
|
let mut desc = res.0.description;
|
|
|
|
format::convert_legacy(&mut desc);
|
|
|
|
let favicon = if let Some(icon) = res.0.favicon {
|
2018-09-30 20:58:40 -04:00
|
|
|
let data_base64 = &icon["data:image/png;base64,".len()..];
|
2020-07-03 14:20:08 -04:00
|
|
|
let data_base64: String =
|
|
|
|
data_base64.chars().filter(|c| !c.is_whitespace()).collect();
|
2019-01-05 22:55:27 -05:00
|
|
|
let data = base64::decode(data_base64).unwrap();
|
2015-10-07 14:36:59 -04:00
|
|
|
Some(image::load_from_memory(&data).unwrap())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
drop(send.send(PingInfo {
|
|
|
|
motd: desc,
|
|
|
|
ping: res.1,
|
|
|
|
exists: true,
|
|
|
|
online: res.0.players.online,
|
|
|
|
max: res.0.players.max,
|
|
|
|
protocol_version: res.0.version.protocol,
|
|
|
|
protocol_name: res.0.version.name,
|
2019-05-05 21:37:37 -04:00
|
|
|
forge_mods: res.0.forge_mods,
|
2018-11-04 16:43:30 -05:00
|
|
|
favicon,
|
2015-10-07 14:36:59 -04:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
let e = format!("{}", err);
|
|
|
|
let mut msg = TextComponent::new(&e);
|
|
|
|
msg.modifier.color = Some(format::Color::Red);
|
2016-04-24 07:22:04 -04:00
|
|
|
let _ = send.send(PingInfo {
|
2015-10-07 14:36:59 -04:00
|
|
|
motd: Component::Text(msg),
|
2018-09-30 01:57:55 -04:00
|
|
|
ping: Duration::new(99999, 0),
|
2015-10-07 14:36:59 -04:00
|
|
|
exists: false,
|
|
|
|
online: 0,
|
|
|
|
max: 0,
|
|
|
|
protocol_version: 0,
|
|
|
|
protocol_name: "".to_owned(),
|
2019-05-05 21:37:37 -04:00
|
|
|
forge_mods: vec![],
|
2015-10-07 14:36:59 -04:00
|
|
|
favicon: None,
|
2016-04-24 07:22:04 -04:00
|
|
|
});
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2015-09-23 15:16:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl super::Screen for ServerList {
|
2015-10-07 14:36:59 -04:00
|
|
|
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
2016-04-24 07:22:04 -04:00
|
|
|
let logo = ui::logo::Logo::new(renderer.resources.clone(), ui_container);
|
2015-09-23 15:16:25 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Refresh the server list
|
2016-04-24 07:22:04 -04:00
|
|
|
let refresh = ui::ButtonBuilder::new()
|
|
|
|
.position(300.0, -50.0 - 15.0)
|
|
|
|
.size(100.0, 30.0)
|
|
|
|
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
|
|
|
|
.draw_index(2)
|
|
|
|
.create(ui_container);
|
|
|
|
{
|
|
|
|
let mut refresh = refresh.borrow_mut();
|
|
|
|
let txt = ui::TextBuilder::new()
|
|
|
|
.text("Refresh")
|
|
|
|
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
|
|
|
|
.attach(&mut *refresh);
|
|
|
|
refresh.add_text(txt);
|
|
|
|
let nr = self.needs_reload.clone();
|
|
|
|
refresh.add_click_func(move |_, _| {
|
|
|
|
*nr.borrow_mut() = true;
|
|
|
|
true
|
|
|
|
})
|
|
|
|
}
|
2015-09-23 15:16:25 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Add a new server to the list
|
2016-04-24 07:22:04 -04:00
|
|
|
let add = ui::ButtonBuilder::new()
|
|
|
|
.position(200.0, -50.0 - 15.0)
|
|
|
|
.size(100.0, 30.0)
|
|
|
|
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
|
|
|
|
.draw_index(2)
|
|
|
|
.create(ui_container);
|
|
|
|
{
|
|
|
|
let mut add = add.borrow_mut();
|
|
|
|
let txt = ui::TextBuilder::new()
|
|
|
|
.text("Add")
|
|
|
|
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
|
|
|
|
.attach(&mut *add);
|
|
|
|
add.add_text(txt);
|
|
|
|
add.add_click_func(move |_, game| {
|
2020-06-21 15:17:24 -04:00
|
|
|
game.screen_sys
|
|
|
|
.replace_screen(Box::new(super::edit_server::EditServerEntry::new(None)));
|
2016-04-24 07:22:04 -04:00
|
|
|
true
|
|
|
|
})
|
|
|
|
}
|
2015-09-23 15:16:25 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Options menu
|
2016-04-24 07:22:04 -04:00
|
|
|
let options = ui::ButtonBuilder::new()
|
|
|
|
.position(5.0, 25.0)
|
|
|
|
.size(40.0, 40.0)
|
|
|
|
.alignment(ui::VAttach::Bottom, ui::HAttach::Right)
|
|
|
|
.create(ui_container);
|
|
|
|
{
|
|
|
|
let mut options = options.borrow_mut();
|
|
|
|
ui::ImageBuilder::new()
|
|
|
|
.texture("steven:gui/cog")
|
|
|
|
.position(0.0, 0.0)
|
|
|
|
.size(40.0, 40.0)
|
|
|
|
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
|
|
|
|
.attach(&mut *options);
|
|
|
|
options.add_click_func(|_, game| {
|
2020-06-21 15:17:24 -04:00
|
|
|
game.screen_sys
|
|
|
|
.add_screen(Box::new(super::SettingsMenu::new(game.vars.clone(), false)));
|
2016-04-24 07:22:04 -04:00
|
|
|
true
|
|
|
|
});
|
|
|
|
}
|
2015-10-07 14:36:59 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Disclaimer
|
2016-04-24 07:22:04 -04:00
|
|
|
let disclaimer = ui::TextBuilder::new()
|
|
|
|
.text("Not affiliated with Mojang/Minecraft")
|
|
|
|
.position(5.0, 5.0)
|
|
|
|
.colour((255, 200, 200, 255))
|
|
|
|
.alignment(ui::VAttach::Bottom, ui::HAttach::Right)
|
|
|
|
.create(ui_container);
|
2015-09-23 15:16:25 -04:00
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// If we are kicked from a server display the reason
|
2016-04-24 07:22:04 -04:00
|
|
|
let disconnected = if let Some(ref disconnect_reason) = self.disconnect_reason {
|
|
|
|
let (width, height) = ui::Formatted::compute_size(renderer, disconnect_reason, 600.0);
|
|
|
|
let background = ui::ImageBuilder::new()
|
|
|
|
.texture("steven:solid")
|
|
|
|
.position(0.0, 3.0)
|
2020-06-21 15:17:24 -04:00
|
|
|
.size(
|
|
|
|
width.max(renderer.ui.size_of_string("Disconnected")) + 4.0,
|
|
|
|
height + 4.0 + 16.0,
|
|
|
|
)
|
2016-04-24 07:22:04 -04:00
|
|
|
.colour((0, 0, 0, 100))
|
|
|
|
.alignment(ui::VAttach::Top, ui::HAttach::Center)
|
2016-04-24 09:05:21 -04:00
|
|
|
.draw_index(10)
|
2016-04-24 07:22:04 -04:00
|
|
|
.create(ui_container);
|
|
|
|
ui::TextBuilder::new()
|
|
|
|
.text("Disconnected")
|
|
|
|
.position(0.0, 2.0)
|
|
|
|
.colour((255, 0, 0, 255))
|
|
|
|
.alignment(ui::VAttach::Top, ui::HAttach::Center)
|
|
|
|
.attach(&mut *background.borrow_mut());
|
|
|
|
ui::FormattedBuilder::new()
|
|
|
|
.text(disconnect_reason.clone())
|
|
|
|
.position(0.0, 18.0)
|
|
|
|
.max_width(600.0)
|
|
|
|
.alignment(ui::VAttach::Top, ui::HAttach::Center)
|
|
|
|
.attach(&mut *background.borrow_mut());
|
|
|
|
Some(background)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2015-10-07 14:36:59 -04:00
|
|
|
|
|
|
|
self.elements = Some(UIElements {
|
2018-11-04 16:43:30 -05:00
|
|
|
logo,
|
2015-10-07 14:36:59 -04:00
|
|
|
servers: Vec::new(),
|
2016-04-24 07:22:04 -04:00
|
|
|
|
|
|
|
_add_btn: add,
|
|
|
|
_refresh_btn: refresh,
|
|
|
|
_options_btn: options,
|
|
|
|
_disclaimer: disclaimer,
|
|
|
|
|
|
|
|
_disconnected: disconnected,
|
2015-10-07 14:36:59 -04:00
|
|
|
});
|
|
|
|
self.reload_server_list(renderer, ui_container);
|
|
|
|
}
|
2016-04-24 07:22:04 -04:00
|
|
|
fn on_deactive(&mut self, renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
|
2016-03-20 16:17:21 -04:00
|
|
|
// Clean up
|
2015-10-07 14:36:59 -04:00
|
|
|
{
|
|
|
|
let elements = self.elements.as_mut().unwrap();
|
2016-03-28 14:06:10 -04:00
|
|
|
let mut tex = renderer.get_textures_ref().write().unwrap();
|
2015-10-07 14:36:59 -04:00
|
|
|
for server in &mut elements.servers {
|
2016-03-28 14:06:10 -04:00
|
|
|
if let Some(ref icon) = server.icon_texture {
|
2016-09-15 10:15:52 -04:00
|
|
|
tex.remove_dynamic(icon);
|
2016-03-28 14:06:10 -04:00
|
|
|
}
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
self.elements = None
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
fn tick(
|
|
|
|
&mut self,
|
|
|
|
delta: f64,
|
|
|
|
renderer: &mut render::Renderer,
|
|
|
|
ui_container: &mut ui::Container,
|
|
|
|
) -> Option<Box<dyn super::Screen>> {
|
2015-10-07 14:36:59 -04:00
|
|
|
if *self.needs_reload.borrow() {
|
|
|
|
self.reload_server_list(renderer, ui_container);
|
|
|
|
}
|
|
|
|
let elements = self.elements.as_mut().unwrap();
|
|
|
|
|
2016-04-24 07:22:04 -04:00
|
|
|
elements.logo.tick(renderer);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
|
|
|
for s in &mut elements.servers {
|
2016-03-20 16:17:21 -04:00
|
|
|
// Animate the entries
|
2015-10-07 14:36:59 -04:00
|
|
|
{
|
2016-04-24 07:22:04 -04:00
|
|
|
let mut back = s.back.borrow_mut();
|
|
|
|
let dy = s.y - back.y;
|
2015-10-07 14:36:59 -04:00
|
|
|
if dy * dy > 1.0 {
|
2016-04-24 07:22:04 -04:00
|
|
|
let y = back.y;
|
|
|
|
back.y = y + delta * dy * 0.1;
|
2015-10-07 14:36:59 -04:00
|
|
|
} else {
|
2016-04-24 07:22:04 -04:00
|
|
|
back.y = s.y;
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-20 16:17:21 -04:00
|
|
|
// Keep checking to see if the server has finished being
|
|
|
|
// pinged
|
2015-10-07 14:36:59 -04:00
|
|
|
if !s.done_ping {
|
|
|
|
match s.recv.try_recv() {
|
|
|
|
Ok(res) => {
|
|
|
|
s.done_ping = true;
|
2016-04-24 07:22:04 -04:00
|
|
|
s.motd.borrow_mut().set_text(res.motd);
|
|
|
|
// Selects the icon for the given ping range
|
2018-09-30 01:57:55 -04:00
|
|
|
// TODO: switch to as_millis() experimental duration_as_u128 #50202 once available?
|
2020-06-21 15:17:24 -04:00
|
|
|
let ping_ms = (res.ping.subsec_nanos() as f64) / 1000000.0
|
|
|
|
+ (res.ping.as_secs() as f64) * 1000.0;
|
2018-09-30 01:57:55 -04:00
|
|
|
let y = match ping_ms.round() as u64 {
|
2020-06-21 15:17:24 -04:00
|
|
|
_x @ 0..=75 => 16.0 / 256.0,
|
|
|
|
_x @ 76..=150 => 24.0 / 256.0,
|
|
|
|
_x @ 151..=225 => 32.0 / 256.0,
|
|
|
|
_x @ 226..=350 => 40.0 / 256.0,
|
|
|
|
_x @ 351..=999 => 48.0 / 256.0,
|
2016-04-24 07:22:04 -04:00
|
|
|
_ => 56.0 / 256.0,
|
|
|
|
};
|
|
|
|
s.ping.borrow_mut().texture_coords.1 = y;
|
2015-10-07 14:36:59 -04:00
|
|
|
if res.exists {
|
|
|
|
{
|
2016-04-24 07:22:04 -04:00
|
|
|
let mut players = s.players.borrow_mut();
|
2020-06-21 15:17:24 -04:00
|
|
|
let txt = if protocol::SUPPORTED_PROTOCOLS
|
|
|
|
.contains(&res.protocol_version)
|
|
|
|
{
|
2016-04-24 07:22:04 -04:00
|
|
|
players.colour.1 = 255;
|
|
|
|
players.colour.2 = 255;
|
2015-10-07 14:36:59 -04:00
|
|
|
format!("{}/{}", res.online, res.max)
|
|
|
|
} else {
|
2016-04-24 07:22:04 -04:00
|
|
|
players.colour.1 = 85;
|
|
|
|
players.colour.2 = 85;
|
2015-10-07 14:36:59 -04:00
|
|
|
format!("Out of date {}/{}", res.online, res.max)
|
|
|
|
};
|
2016-04-24 07:22:04 -04:00
|
|
|
players.text = txt;
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
2020-06-21 15:17:24 -04:00
|
|
|
let sm =
|
|
|
|
format!("{} mods + {}", res.forge_mods.len(), res.protocol_name);
|
2020-07-02 20:25:55 -04:00
|
|
|
let st = if !res.forge_mods.is_empty() {
|
2020-06-21 15:17:24 -04:00
|
|
|
&sm
|
|
|
|
} else {
|
|
|
|
&res.protocol_name
|
|
|
|
};
|
2019-05-05 21:37:37 -04:00
|
|
|
let mut txt = TextComponent::new(&st);
|
2016-04-24 07:22:04 -04:00
|
|
|
txt.modifier.color = Some(format::Color::Yellow);
|
|
|
|
let mut msg = Component::Text(txt);
|
|
|
|
format::convert_legacy(&mut msg);
|
|
|
|
s.version.borrow_mut().set_text(msg);
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
|
|
|
if let Some(favicon) = res.favicon {
|
2020-06-21 15:17:24 -04:00
|
|
|
let name: String = std::iter::repeat(())
|
|
|
|
.map(|()| {
|
|
|
|
rand::thread_rng().sample(&rand::distributions::Alphanumeric)
|
2020-12-27 19:14:11 -05:00
|
|
|
as char
|
2020-06-21 15:17:24 -04:00
|
|
|
})
|
|
|
|
.take(30)
|
|
|
|
.collect();
|
2015-10-07 14:36:59 -04:00
|
|
|
let tex = renderer.get_textures_ref();
|
|
|
|
s.icon_texture = Some(name.clone());
|
2020-06-21 15:17:24 -04:00
|
|
|
let icon_tex = tex.write().unwrap().put_dynamic(&name, favicon);
|
2016-04-24 07:22:04 -04:00
|
|
|
s.icon.borrow_mut().texture = icon_tex.name;
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(mpsc::TryRecvError::Disconnected) => {
|
|
|
|
s.done_ping = true;
|
|
|
|
let mut txt = TextComponent::new("Channel dropped");
|
|
|
|
txt.modifier.color = Some(format::Color::Red);
|
2016-04-24 07:22:04 -04:00
|
|
|
s.motd.borrow_mut().set_text(Component::Text(txt));
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-20 19:43:31 -04:00
|
|
|
None
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn on_scroll(&mut self, _: f64, y: f64) {
|
|
|
|
let elements = self.elements.as_mut().unwrap();
|
|
|
|
if elements.servers.is_empty() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let mut diff = y / 1.0;
|
|
|
|
{
|
|
|
|
let last = elements.servers.last().unwrap();
|
|
|
|
if last.offset + diff <= 2.0 {
|
|
|
|
diff = 2.0 - last.offset;
|
|
|
|
}
|
|
|
|
let first = elements.servers.first().unwrap();
|
|
|
|
if first.offset + diff >= 0.0 {
|
|
|
|
diff = -first.offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for s in &mut elements.servers {
|
|
|
|
s.offset += diff;
|
|
|
|
s.update_position();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|