2016-03-16 14:25:35 -04:00
|
|
|
// Copyright 2016 Matthew Collins
|
2015-09-17 11:21:56 -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.
|
|
|
|
|
2016-03-18 07:39:03 -04:00
|
|
|
#![recursion_limit="200"]
|
2016-03-19 12:32:13 -04:00
|
|
|
#![feature(const_fn)]
|
2016-03-18 07:39:03 -04:00
|
|
|
|
2016-03-19 20:29:35 -04:00
|
|
|
extern crate glutin;
|
|
|
|
extern crate image;
|
|
|
|
extern crate time;
|
|
|
|
extern crate byteorder;
|
|
|
|
extern crate serde_json;
|
|
|
|
extern crate steven_openssl as openssl;
|
|
|
|
extern crate hyper;
|
|
|
|
extern crate flate2;
|
|
|
|
extern crate rand;
|
|
|
|
extern crate rustc_serialize;
|
|
|
|
extern crate cgmath;
|
|
|
|
#[macro_use]
|
|
|
|
extern crate log;
|
|
|
|
#[macro_use]
|
|
|
|
extern crate lazy_static;
|
|
|
|
|
2016-03-18 18:24:30 -04:00
|
|
|
#[macro_use]
|
|
|
|
pub mod macros;
|
2016-03-17 18:18:25 -04:00
|
|
|
pub mod ecs;
|
2015-09-17 11:04:25 -04:00
|
|
|
pub mod protocol;
|
|
|
|
pub mod format;
|
|
|
|
pub mod nbt;
|
|
|
|
pub mod item;
|
|
|
|
pub mod gl;
|
|
|
|
pub mod types;
|
|
|
|
pub mod resources;
|
|
|
|
pub mod render;
|
2015-09-18 17:02:08 -04:00
|
|
|
pub mod ui;
|
2015-09-23 15:16:25 -04:00
|
|
|
pub mod screen;
|
2015-09-28 18:37:14 -04:00
|
|
|
#[macro_use]
|
|
|
|
pub mod console;
|
2016-03-18 18:24:30 -04:00
|
|
|
pub mod server;
|
|
|
|
pub mod world;
|
2016-03-19 12:32:13 -04:00
|
|
|
pub mod chunk_builder;
|
2016-03-20 16:17:21 -04:00
|
|
|
pub mod auth;
|
2015-09-17 11:04:25 -04:00
|
|
|
|
2015-09-29 17:33:24 -04:00
|
|
|
use std::sync::{Arc, RwLock, Mutex};
|
2015-09-28 18:37:14 -04:00
|
|
|
use std::marker::PhantomData;
|
2016-03-20 08:04:02 -04:00
|
|
|
use std::thread;
|
|
|
|
use std::sync::mpsc;
|
2015-09-07 16:11:00 -04:00
|
|
|
|
2015-09-28 18:37:14 -04:00
|
|
|
const CL_BRAND: console::CVar<String> = console::CVar {
|
|
|
|
ty: PhantomData,
|
|
|
|
name: "cl_brand",
|
2015-10-07 14:36:59 -04:00
|
|
|
description: "cl_brand has the value of the clients current 'brand'. e.g. \"Steven\" or \
|
|
|
|
\"Vanilla\"",
|
2015-09-28 18:37:14 -04:00
|
|
|
mutable: false,
|
2015-10-01 15:07:27 -04:00
|
|
|
serializable: false,
|
2016-03-16 15:11:50 -04:00
|
|
|
default: &|| "Steven".to_owned(),
|
2015-09-28 18:37:14 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
pub struct Game {
|
|
|
|
renderer: render::Renderer,
|
|
|
|
screen_sys: screen::ScreenSystem,
|
|
|
|
resource_manager: Arc<RwLock<resources::Manager>>,
|
2015-09-29 17:33:24 -04:00
|
|
|
console: Arc<Mutex<console::Console>>,
|
2015-10-01 15:07:27 -04:00
|
|
|
should_close: bool,
|
|
|
|
mouse_pos: (i32, i32),
|
2016-03-18 18:24:30 -04:00
|
|
|
|
|
|
|
server: server::Server,
|
2016-03-21 13:51:25 -04:00
|
|
|
focused: bool,
|
2016-03-19 12:32:13 -04:00
|
|
|
chunk_builder: chunk_builder::ChunkBuilder,
|
2016-03-20 08:04:02 -04:00
|
|
|
|
|
|
|
connect_reply: Option<mpsc::Receiver<Result<server::Server, protocol::Error>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Game {
|
|
|
|
pub fn connect_to(&mut self, address: &str) {
|
|
|
|
let (tx, rx) = mpsc::channel();
|
|
|
|
self.connect_reply = Some(rx);
|
|
|
|
let address = address.to_owned();
|
|
|
|
let resources = self.resource_manager.clone();
|
2016-03-21 06:55:31 -04:00
|
|
|
let console = self.console.clone();
|
2016-03-20 08:04:02 -04:00
|
|
|
thread::spawn(move || {
|
2016-03-21 06:55:31 -04:00
|
|
|
tx.send(server::Server::connect(resources, console, &address)).unwrap();
|
2016-03-20 08:04:02 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-03-21 08:56:38 -04:00
|
|
|
pub fn tick(&mut self, delta: f64) {
|
|
|
|
if !self.server.is_connected() {
|
2016-03-21 13:51:25 -04:00
|
|
|
self.server.yaw += 0.005 * delta;
|
|
|
|
if self.server.yaw > ::std::f64::consts::PI * 2.0 {
|
|
|
|
self.server.yaw = 0.0;
|
2016-03-21 08:56:38 -04:00
|
|
|
}
|
|
|
|
}
|
2016-03-20 08:04:02 -04:00
|
|
|
let mut clear_reply = false;
|
|
|
|
if let Some(ref recv) = self.connect_reply {
|
|
|
|
if let Ok(server) = recv.try_recv() {
|
|
|
|
clear_reply = true;
|
|
|
|
match server {
|
|
|
|
Ok(val) => {
|
|
|
|
self.screen_sys.pop_screen();
|
2016-03-21 06:55:31 -04:00
|
|
|
self.renderer.clear_chunks();
|
2016-03-21 10:05:13 -04:00
|
|
|
self.chunk_builder.wait_for_builders();
|
2016-03-21 13:51:25 -04:00
|
|
|
self.focused = true;
|
2016-03-20 08:04:02 -04:00
|
|
|
self.server = val;
|
|
|
|
},
|
|
|
|
Err(err) => {
|
|
|
|
let msg = match err {
|
|
|
|
protocol::Error::Disconnect(val) => val,
|
|
|
|
err => {
|
|
|
|
let mut msg = format::TextComponent::new(&format!("{}", err));
|
|
|
|
msg.modifier.color = Some(format::Color::Red);
|
|
|
|
format::Component::Text(msg)
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.screen_sys.replace_screen(Box::new(screen::ServerList::new(
|
|
|
|
Some(msg)
|
|
|
|
)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if clear_reply {
|
|
|
|
self.connect_reply = None;
|
|
|
|
}
|
|
|
|
}
|
2015-09-28 18:37:14 -04:00
|
|
|
}
|
|
|
|
|
2015-09-07 16:11:00 -04:00
|
|
|
fn main() {
|
2016-03-19 20:29:35 -04:00
|
|
|
world::block::force_init();
|
2015-09-29 17:33:24 -04:00
|
|
|
let con = Arc::new(Mutex::new(console::Console::new()));
|
2015-09-29 18:24:58 -04:00
|
|
|
{
|
|
|
|
let mut con = con.lock().unwrap();
|
|
|
|
con.register(CL_BRAND);
|
2016-03-20 16:17:21 -04:00
|
|
|
auth::register_vars(&mut con);
|
2015-09-29 18:24:58 -04:00
|
|
|
con.load_config();
|
|
|
|
con.save_config();
|
|
|
|
}
|
2015-10-01 15:07:27 -04:00
|
|
|
|
2015-09-29 17:33:24 -04:00
|
|
|
let proxy = console::ConsoleProxy::new(con.clone());
|
2015-10-01 15:07:27 -04:00
|
|
|
|
2015-09-29 17:33:24 -04:00
|
|
|
log::set_logger(|max_log_level| {
|
|
|
|
max_log_level.set(log::LogLevelFilter::Trace);
|
|
|
|
Box::new(proxy)
|
2016-03-18 18:24:30 -04:00
|
|
|
}).unwrap();
|
2015-09-29 17:33:24 -04:00
|
|
|
|
|
|
|
info!("Starting steven");
|
2015-09-28 18:37:14 -04:00
|
|
|
|
2015-09-17 11:04:25 -04:00
|
|
|
let resource_manager = Arc::new(RwLock::new(resources::Manager::new()));
|
2015-10-07 14:36:59 -04:00
|
|
|
{
|
|
|
|
resource_manager.write().unwrap().tick();
|
|
|
|
}
|
2015-09-17 11:04:25 -04:00
|
|
|
|
2015-10-01 15:07:27 -04:00
|
|
|
let mut window = glutin::WindowBuilder::new()
|
2015-10-07 14:36:59 -04:00
|
|
|
.with_title("Steven".to_string())
|
|
|
|
.with_dimensions(854, 480)
|
|
|
|
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
|
|
|
|
.with_gl_profile(glutin::GlProfile::Core)
|
|
|
|
.with_depth_buffer(24)
|
|
|
|
.with_stencil_buffer(0)
|
|
|
|
.with_vsync()
|
|
|
|
.build()
|
|
|
|
.expect("Could not create Glutin window.");
|
2015-10-01 15:07:27 -04:00
|
|
|
|
|
|
|
unsafe {
|
2016-03-16 14:22:03 -04:00
|
|
|
window.make_current().expect("Could not set current context.");
|
2015-10-01 15:07:27 -04:00
|
|
|
}
|
2015-09-07 16:11:00 -04:00
|
|
|
|
|
|
|
gl::init(&mut window);
|
|
|
|
|
2015-09-28 18:37:14 -04:00
|
|
|
let renderer = render::Renderer::new(resource_manager.clone());
|
2015-09-18 17:02:08 -04:00
|
|
|
let mut ui_container = ui::Container::new();
|
2015-09-17 11:04:25 -04:00
|
|
|
|
|
|
|
let mut last_frame = time::now();
|
|
|
|
let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;
|
|
|
|
|
2015-09-23 15:16:25 -04:00
|
|
|
let mut screen_sys = screen::ScreenSystem::new();
|
2016-03-20 16:17:21 -04:00
|
|
|
screen_sys.add_screen(Box::new(screen::Login::new(con.clone())));
|
2015-09-19 14:08:28 -04:00
|
|
|
|
2016-03-19 12:32:13 -04:00
|
|
|
let textures = renderer.get_textures();
|
2015-09-28 18:37:14 -04:00
|
|
|
let mut game = Game {
|
2016-03-21 06:55:31 -04:00
|
|
|
server: server::Server::dummy_server(resource_manager.clone(), con.clone()),
|
2016-03-21 13:51:25 -04:00
|
|
|
focused: false,
|
2015-09-28 18:37:14 -04:00
|
|
|
renderer: renderer,
|
|
|
|
screen_sys: screen_sys,
|
|
|
|
resource_manager: resource_manager,
|
|
|
|
console: con,
|
2015-10-01 15:07:27 -04:00
|
|
|
should_close: false,
|
|
|
|
mouse_pos: (0, 0),
|
2016-03-19 12:32:13 -04:00
|
|
|
chunk_builder: chunk_builder::ChunkBuilder::new(textures),
|
2016-03-20 08:04:02 -04:00
|
|
|
connect_reply: None,
|
2015-09-28 18:37:14 -04:00
|
|
|
};
|
|
|
|
|
2015-10-01 15:07:27 -04:00
|
|
|
while !game.should_close {
|
2015-10-07 14:36:59 -04:00
|
|
|
{
|
|
|
|
game.resource_manager.write().unwrap().tick();
|
|
|
|
}
|
2015-10-01 15:07:27 -04:00
|
|
|
|
2015-09-17 11:04:25 -04:00
|
|
|
let now = time::now();
|
|
|
|
let diff = now - last_frame;
|
|
|
|
last_frame = now;
|
|
|
|
let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
|
2015-10-01 15:07:27 -04:00
|
|
|
let (width, height) = window.get_inner_size_pixels().unwrap();
|
2015-09-17 11:04:25 -04:00
|
|
|
|
2016-03-21 08:56:38 -04:00
|
|
|
game.tick(delta);
|
2016-03-21 10:05:13 -04:00
|
|
|
game.server.tick(&mut game.renderer, delta);
|
2016-03-19 13:34:12 -04:00
|
|
|
|
2016-03-21 12:51:19 -04:00
|
|
|
game.chunk_builder.tick(&mut game.server.world, &mut game.renderer, delta);
|
2016-03-19 12:32:13 -04:00
|
|
|
|
2015-09-28 18:37:14 -04:00
|
|
|
game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container);
|
2015-10-07 14:36:59 -04:00
|
|
|
game.console
|
|
|
|
.lock()
|
|
|
|
.unwrap()
|
|
|
|
.tick(&mut ui_container, &mut game.renderer, delta, width as f64);
|
2015-09-28 18:37:14 -04:00
|
|
|
ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
|
2015-10-01 15:07:27 -04:00
|
|
|
game.renderer.tick(delta, width, height);
|
|
|
|
|
|
|
|
let _ = window.swap_buffers();
|
2015-09-07 16:11:00 -04:00
|
|
|
|
2015-10-01 15:07:27 -04:00
|
|
|
for event in window.poll_events() {
|
|
|
|
handle_window_event(&window, &mut game, &mut ui_container, event)
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-07 14:36:59 -04:00
|
|
|
fn handle_window_event(window: &glutin::Window,
|
|
|
|
game: &mut Game,
|
|
|
|
ui_container: &mut ui::Container,
|
|
|
|
event: glutin::Event) {
|
2015-10-06 19:10:59 -04:00
|
|
|
use glutin::{Event, VirtualKeyCode};
|
2016-03-21 13:51:25 -04:00
|
|
|
use std::f64::consts::PI;
|
2015-09-07 16:11:00 -04:00
|
|
|
match event {
|
2015-10-06 19:10:59 -04:00
|
|
|
Event::Closed => game.should_close = true,
|
2015-10-01 15:07:27 -04:00
|
|
|
|
2015-10-06 19:10:59 -04:00
|
|
|
Event::MouseMoved((x, y)) => {
|
2015-10-01 15:07:27 -04:00
|
|
|
game.mouse_pos = (x, y);
|
|
|
|
let (width, height) = window.get_inner_size_pixels().unwrap();
|
2016-03-21 13:51:25 -04:00
|
|
|
if game.focused {
|
|
|
|
window.set_cursor_position((width/2) as i32, (height/2) as i32).unwrap();
|
|
|
|
let s = 2000.0 + 0.01;
|
|
|
|
let (rx, ry) = ((x-(width/2) as i32) as f64 / s, (y-(height/2) as i32) as f64 / s);
|
|
|
|
game.server.yaw -= rx;
|
|
|
|
game.server.pitch -= ry;
|
|
|
|
if game.server.pitch < (PI/2.0) + 0.01 {
|
|
|
|
game.server.pitch = (PI/2.0) + 0.01;
|
|
|
|
}
|
|
|
|
if game.server.pitch > (PI/2.0)*3.0 - 0.01 {
|
|
|
|
game.server.pitch = (PI/2.0)*3.0 - 0.01;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64);
|
|
|
|
}
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
2015-10-06 19:10:59 -04:00
|
|
|
Event::MouseInput(glutin::ElementState::Released, glutin::MouseButton::Left) => {
|
2015-10-01 15:07:27 -04:00
|
|
|
let (x, y) = game.mouse_pos;
|
|
|
|
let (width, height) = window.get_inner_size_pixels().unwrap();
|
|
|
|
|
2016-03-21 13:51:25 -04:00
|
|
|
if game.server.is_connected() && !game.focused {
|
|
|
|
game.focused = true;
|
|
|
|
window.set_cursor_position((width/2) as i32, (height/2) as i32).unwrap();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if !game.focused {
|
|
|
|
ui_container.click_at(game, x as f64, y as f64, width as f64, height as f64);
|
|
|
|
}
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
2015-10-06 19:10:59 -04:00
|
|
|
Event::MouseWheel(delta) => {
|
2015-10-01 16:50:37 -04:00
|
|
|
let (x, y) = match delta {
|
|
|
|
glutin::MouseScrollDelta::LineDelta(x, y) => (x, y),
|
2015-10-07 14:36:59 -04:00
|
|
|
glutin::MouseScrollDelta::PixelDelta(x, y) => (x, y),
|
2015-10-01 16:50:37 -04:00
|
|
|
};
|
|
|
|
|
2015-10-01 15:07:27 -04:00
|
|
|
game.screen_sys.on_scroll(x as f64, y as f64);
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
2016-03-21 13:51:25 -04:00
|
|
|
Event::KeyboardInput(glutin::ElementState::Released, _, Some(VirtualKeyCode::Escape)) => {
|
|
|
|
if game.focused {
|
|
|
|
game.focused = false;
|
|
|
|
}
|
|
|
|
}
|
2016-03-20 16:17:21 -04:00
|
|
|
Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(VirtualKeyCode::Grave)) => {
|
2015-10-06 19:10:59 -04:00
|
|
|
game.console.lock().unwrap().toggle();
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
2016-03-20 16:17:21 -04:00
|
|
|
Event::KeyboardInput(state, key, virt) => {
|
|
|
|
ui_container.key_press(game, virt, key, state == glutin::ElementState::Pressed);
|
|
|
|
}
|
|
|
|
Event::ReceivedCharacter(c) => {
|
|
|
|
ui_container.key_type(game, c);
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
|
|
|
_ => (),
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
}
|