1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
//! # 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};
use std::sync::atomic::Ordering;
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::<u16>()
{
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, server_running, port) =
server::start_any_port(use_ipv4).expect("Unable to start local server");
server_port = port;
(server_handle, server_running)
})
} 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, running)) = server_handle {
running.store(false, Ordering::Relaxed);
handle.join().expect("Server thread closed unexpectedly.");
}
}
|