//! # Graf Karto cartographer //! //! ### What is it exactly //! Graf Karto is a table top role playing game (TTRPG) map creation tool that is optimised for real //! time map interaction. //! //! ### Motivation //! While there are certainly many TTRPG map creation tools for single user and multi user available //! online and on the market, we felt that most of them lack features or are to unwieldy to seriously //! consider for real time dungeon drawing, say for instance when drawing a map for an old school //! revival style game. This is why Graf Karto is optimised for speed above pretty graphical features. //! The aim is for the user not to have to think much about how they are going to achieve what they are //! doing and how they are going to make it pretty, but should just be able to *do* it, to have time to //! worry about other things. This does not mean that all maps created should visually be equivalent to //! a steaming pile of hot garbage, but if the visuals should try to get in the way, usability and speed //! takes precedence. #![allow(dead_code)] #![warn(missing_docs)] #[macro_use] extern crate log; pub mod client; pub mod math; pub mod net; pub mod server; pub mod stable_vec; pub mod transformable; pub mod world; use clap::{App, Arg}; use server::DEFAULT_PORT; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}; fn main() { pretty_env_logger::init(); println!("Graf Karto version: {}", clap::crate_version!()); let default_port = DEFAULT_PORT.to_string(); let matches = App::new("Graf Karto") .version(clap::crate_version!()) .author(clap::crate_authors!()) .about(clap::crate_description!()) .arg(Arg::with_name("connect") .short("c") .value_name("SERVER_ADDRESS") .help("Specify an IP in case an external server should be used (starts a local server if not set).")) .arg(Arg::with_name("port") .short("p") .value_name("SERVER_PORT") .help("Set the port the server listens on or should listen on. When starting a local server, others may be tried if it cannot be bound.") .default_value(&default_port)) .arg(Arg::with_name("ipv4") .short("v4") .help("Use virgin IPv4 instead of chad IPv6.. you monster")) .get_matches(); let use_ipv4 = matches.is_present("ipv4"); let mut server_port = match matches .value_of("port") .expect("No port found, eventhough it should have a default value") .parse::() { Ok(port) => port, Err(e) => { error!("Not a valid server port: {:?}", e); warn!("Using default port {}", DEFAULT_PORT); DEFAULT_PORT } }; let server_handle = if !matches.is_present("connect") { Some({ let (server_handle, port) = server::start_any_port(use_ipv4).expect("Unable to start local server"); server_port = port; server_handle }) } else { None }; let server_address = match matches.value_of("connect") { None => { // Local server will be started. if use_ipv4 { SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), server_port) } else { SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), server_port) } } Some(addr) => { let addrs = (addr, server_port) .to_socket_addrs() .expect("Not a valid address"); let mut addr = None; for a in addrs { if use_ipv4 && a.is_ipv4() { addr = Some(a); break; } else if !use_ipv4 && a.is_ipv6() { addr = Some(a); break; } } addr.expect("Could not find a valid ip address on that hostname") } }; client::run(dbg!(server_address)); if let Some(handle) = server_handle { handle.join().expect("Server thread closed unexpectedly."); } }