aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--games/rstnode/Cargo.lock215
-rw-r--r--games/rstnode/Cargo.toml3
-rw-r--r--games/rstnode/log.rs61
-rw-r--r--games/rstnode/rst-client/Cargo.toml10
-rw-r--r--games/rstnode/rst-client/src/graphics/entities/mod.rs35
-rw-r--r--games/rstnode/rst-client/src/graphics/mod.rs2
-rw-r--r--games/rstnode/rst-client/src/input.rs2
-rw-r--r--games/rstnode/rst-client/src/main.rs6
-rw-r--r--games/rstnode/rst-client/src/net.rs1
-rw-r--r--games/rstnode/rst-client/src/settings.rs1
-rw-r--r--games/rstnode/rst-client/src/state/_match.rs0
-rw-r--r--games/rstnode/rst-client/src/state/if_impl.rs70
-rw-r--r--games/rstnode/rst-client/src/state/map.rs10
-rw-r--r--games/rstnode/rst-client/src/state/mod.rs (renamed from games/rstnode/rst-client/src/state.rs)51
-rw-r--r--games/rstnode/rst-core/Cargo.toml1
-rw-r--r--games/rstnode/rst-core/src/_if.rs4
-rw-r--r--games/rstnode/rst-core/src/_match.rs12
-rw-r--r--games/rstnode/rst-core/src/data.rs49
-rw-r--r--games/rstnode/rst-core/src/error.rs51
-rw-r--r--games/rstnode/rst-core/src/lib.rs9
-rw-r--r--games/rstnode/rst-core/src/lobby.rs3
-rw-r--r--games/rstnode/rst-core/src/mailbox.rs78
-rw-r--r--games/rstnode/rst-core/src/map.rs20
-rw-r--r--games/rstnode/rst-core/src/net/endpoint.rs49
-rw-r--r--games/rstnode/rst-core/src/net/gen.rs52
-rw-r--r--games/rstnode/rst-core/src/net/handler.rs17
-rw-r--r--games/rstnode/rst-core/src/net/mod.rs20
-rw-r--r--games/rstnode/rst-core/src/net/parser.rs17
-rw-r--r--games/rstnode/rst-core/src/server.rs62
-rw-r--r--games/rstnode/rst-core/src/wire/game/action.rs (renamed from games/rstnode/rst-core/src/wire/action.rs)0
-rw-r--r--games/rstnode/rst-core/src/wire/game/mod.rs5
-rw-r--r--games/rstnode/rst-core/src/wire/game/update.rs (renamed from games/rstnode/rst-core/src/wire/update.rs)19
-rw-r--r--games/rstnode/rst-core/src/wire/mod.rs11
-rw-r--r--games/rstnode/rst-core/src/wire/proto/mod.rs25
-rw-r--r--games/rstnode/rst-core/src/wire/proto/request.rs41
-rw-r--r--games/rstnode/rst-core/src/wire/proto/response.rs0
-rw-r--r--games/rstnode/rst-core/src/wire/req.rs2
-rw-r--r--games/rstnode/rst-core/src/wire/resp.rs10
-rw-r--r--games/rstnode/rst-server/Cargo.toml12
-rw-r--r--games/rstnode/rst-server/src/constants.rs5
-rw-r--r--games/rstnode/rst-server/src/log.rs24
-rw-r--r--games/rstnode/rst-server/src/main.rs19
-rw-r--r--games/rstnode/rst-server/src/net/mod.rs43
-rw-r--r--games/rstnode/rst-server/src/net/parser.rs9
-rw-r--r--games/rstnode/rst-server/src/server.rs153
45 files changed, 1102 insertions, 187 deletions
diff --git a/games/rstnode/Cargo.lock b/games/rstnode/Cargo.lock
index a7f7a83b6123..0247eaf0006f 100644
--- a/games/rstnode/Cargo.lock
+++ b/games/rstnode/Cargo.lock
@@ -164,6 +164,14 @@ dependencies = [
]
[[package]]
+name = "async-quic"
+version = "0.1.0"
+dependencies = [
+ "async-std",
+ "quinn-proto",
+]
+
+[[package]]
name = "async-std"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -250,6 +258,12 @@ checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
[[package]]
name = "base64"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
+
+[[package]]
+name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
@@ -290,6 +304,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
+name = "bitvec"
+version = "0.19.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7ba35e9565969edb811639dbebfe34edc0368e472c5018474c8eb2543397f81"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
+[[package]]
name = "blake2"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -364,11 +390,23 @@ checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
[[package]]
name = "bytes"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
+
+[[package]]
+name = "bytes"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
[[package]]
+name = "bytesize"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da"
+
+[[package]]
name = "bzip2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -509,9 +547,9 @@ checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
[[package]]
name = "clang-sys"
-version = "1.0.3"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0659001ab56b791be01d4b729c44376edc6718cf389a502e579b77b758f3296c"
+checksum = "5cb92721cb37482245ed88428f72253ce422b3b4ee169c70a0642521bb5db4cc"
dependencies = [
"glob",
"libc",
@@ -629,7 +667,7 @@ version = "4.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc4369b5e4c0cddf64ad8981c0111e7df4f7078f4d6ba98fb31f2e17c4c57b7e"
dependencies = [
- "bytes",
+ "bytes 1.0.1",
"memchr",
]
@@ -1280,6 +1318,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
[[package]]
+name = "err-derive"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22deed3a8124cff5fa835713fa105621e43bbdc46690c3a6b68328a012d350d4"
+dependencies = [
+ "proc-macro-error",
+ "proc-macro2 1.0.24",
+ "quote 1.0.8",
+ "rustversion",
+ "syn 1.0.60",
+ "synstructure",
+]
+
+[[package]]
name = "error-chain"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1378,6 +1430,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
+name = "funty"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
+
+[[package]]
name = "futf"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1619,9 +1677,9 @@ dependencies = [
[[package]]
name = "ggez"
-version = "0.6.0-rc0"
+version = "0.6.0-rc1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abbd382ca53791d06ccdf41aa339716e7617862b354e64f9033b47d65b964908"
+checksum = "74b418a47a9e1ee8dbd8f7a9378851e7af13dbc1b88132c3eaec39bd73e614b3"
dependencies = [
"approx 0.4.0",
"bitflags",
@@ -2129,10 +2187,23 @@ dependencies = [
]
[[package]]
+name = "lexical-core"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616"
+dependencies = [
+ "arrayvec",
+ "bitflags",
+ "cfg-if 0.1.10",
+ "ryu",
+ "static_assertions",
+]
+
+[[package]]
name = "libc"
-version = "0.2.85"
+version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3"
+checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
[[package]]
name = "libflate"
@@ -2673,6 +2744,8 @@ version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab6f70b46d6325aa300f1c7bb3d470127dfc27806d8ea6bf294ee0ce643ce2b1"
dependencies = [
+ "bitvec",
+ "lexical-core",
"memchr",
"version_check",
]
@@ -3223,6 +3296,30 @@ dependencies = [
]
[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2 1.0.24",
+ "quote 1.0.8",
+ "syn 1.0.60",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2 1.0.24",
+ "quote 1.0.8",
+ "version_check",
+]
+
+[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3294,6 +3391,22 @@ dependencies = [
]
[[package]]
+name = "quinn-proto"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0ea0a358c179c6b7af34805c675d1664a9c6a234a7acd7efdbb32d2f39d3d2a"
+dependencies = [
+ "bytes 0.5.6",
+ "err-derive",
+ "rand 0.7.3",
+ "ring",
+ "rustls 0.17.0",
+ "slab",
+ "tracing",
+ "webpki",
+]
+
+[[package]]
name = "quote"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3312,6 +3425,12 @@ dependencies = [
]
[[package]]
+name = "radium"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
+
+[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3650,6 +3769,7 @@ dependencies = [
"ratman-identity 0.4.0",
"serde",
"serde_yaml",
+ "tracing",
]
[[package]]
@@ -3660,7 +3780,10 @@ version = "0.1.0"
name = "rst-node-client"
version = "0.0.0"
dependencies = [
+ "async-std",
+ "async-trait",
"cairo-rs",
+ "chrono",
"clap",
"ggez",
"librsvg",
@@ -3677,7 +3800,11 @@ name = "rst-node-server"
version = "0.0.0"
dependencies = [
"async-std",
+ "async-trait",
+ "chrono",
+ "num_cpus",
"rst-core",
+ "systemstat",
"tracing",
"tracing-subscriber",
]
@@ -3688,7 +3815,7 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
dependencies = [
- "base64",
+ "base64 0.13.0",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils 0.8.1",
@@ -3717,11 +3844,24 @@ dependencies = [
[[package]]
name = "rustls"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0d4a31f5d68413404705d6982529b0e11a9aacd4839d1d6222ee3b8cb4015e1"
+dependencies = [
+ "base64 0.11.0",
+ "log",
+ "ring",
+ "sct",
+ "webpki",
+]
+
+[[package]]
+name = "rustls"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "064fd21ff87c6e87ed4506e68beb42459caa4a0e2eb144932e6776768556980b"
dependencies = [
- "base64",
+ "base64 0.13.0",
"log",
"ring",
"sct",
@@ -3739,6 +3879,12 @@ dependencies = [
]
[[package]]
+name = "rustversion"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd"
+
+[[package]]
name = "rusty-xinput"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3855,9 +4001,9 @@ dependencies = [
[[package]]
name = "serde_yaml"
-version = "0.8.16"
+version = "0.8.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdd2af560da3c1fdc02cb80965289254fc35dff869810061e2d8290ee48848ae"
+checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
dependencies = [
"dtoa",
"linked-hash-map",
@@ -4163,6 +4309,39 @@ dependencies = [
]
[[package]]
+name = "synstructure"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
+dependencies = [
+ "proc-macro2 1.0.24",
+ "quote 1.0.8",
+ "syn 1.0.60",
+ "unicode-xid 0.2.1",
+]
+
+[[package]]
+name = "systemstat"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31c241679f72241744c20d064a4db7feeb2caa214a8d6e2d4243b8c674a29a5"
+dependencies = [
+ "bytesize",
+ "chrono",
+ "lazy_static",
+ "libc",
+ "nom 6.1.0",
+ "time 0.1.43",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "tap"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36474e732d1affd3a6ed582781b3683df3d0563714c59c39591e8ff707cf078e"
+
+[[package]]
name = "tar"
version = "0.4.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4462,9 +4641,9 @@ dependencies = [
[[package]]
name = "unicode-normalization"
-version = "0.1.16"
+version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606"
+checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef"
dependencies = [
"tinyvec 1.1.1",
]
@@ -4508,14 +4687,14 @@ version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "294b85ef5dbc3670a72e82a89971608a1fcc4ed5c7c5a2895230d31a95f0569b"
dependencies = [
- "base64",
+ "base64 0.13.0",
"chunked_transfer",
"cookie",
"cookie_store",
"log",
"once_cell",
"qstring",
- "rustls",
+ "rustls 0.19.0",
"url",
"webpki",
"webpki-roots",
@@ -4852,6 +5031,12 @@ dependencies = [
]
[[package]]
+name = "wyz"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
+
+[[package]]
name = "x11-dl"
version = "2.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/games/rstnode/Cargo.toml b/games/rstnode/Cargo.toml
index 4aa2532acf2d..5dc3bd29c5f5 100644
--- a/games/rstnode/Cargo.toml
+++ b/games/rstnode/Cargo.toml
@@ -5,6 +5,9 @@ members = [
"rst-launcher",
"rst-client",
"rst-server",
+
+ # Utility libraries
+ "async-quic"
]
# [profile.release.overrides."*"]
diff --git a/games/rstnode/log.rs b/games/rstnode/log.rs
new file mode 100644
index 000000000000..6462413952e1
--- /dev/null
+++ b/games/rstnode/log.rs
@@ -0,0 +1,61 @@
+//! Logging specifics
+
+const BANNER: &'static str = "
+██████╗ ███████╗████████╗ ███╗ ██╗ ██████╗ ██████╗ ███████╗
+██╔══██╗██╔════╝╚══██╔══╝ ████╗ ██║██╔═══██╗██╔══██╗██╔════╝
+██████╔╝███████╗ ██║ ██╔██╗ ██║██║ ██║██║ ██║█████╗
+██╔══██╗╚════██║ ██║ ██║╚██╗██║██║ ██║██║ ██║██╔══╝
+██║ ██║███████║ ██║ ██║ ╚████║╚██████╔╝██████╔╝███████╗
+╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚══════╝";
+
+use systemstat::{Platform, System};
+use tracing_subscriber::{filter::LevelFilter, fmt, EnvFilter};
+
+#[cfg(not(target_os = "windows"))]
+const PLATFORM_DISCLAIMER: &'static str = "Platform: Unspecified *nix-like";
+#[cfg(target_os = "windows")]
+static PLATFORM_DISCLAIMER: &'static str =
+ "WARNING: Windows server hosts are not officially supported!";
+
+pub(crate) fn initialise() {
+ let filter = EnvFilter::try_from_env("RST_LOG")
+ .unwrap_or_default()
+ .add_directive(LevelFilter::DEBUG.into())
+ .add_directive("async_std=error".parse().unwrap())
+ .add_directive("gfx_device_gl=error".parse().unwrap())
+ .add_directive("ggez=error".parse().unwrap())
+ .add_directive("selectors=error".parse().unwrap())
+ .add_directive("gilrs=error".parse().unwrap())
+ .add_directive("mio=error".parse().unwrap());
+
+ // Initialise the logger
+ fmt().with_env_filter(filter).init();
+ info!("Initialising...");
+ info!("{}", BANNER);
+ info!("{}", PLATFORM_DISCLAIMER);
+ info!("Available cores: {}", num_cpus::get());
+ info!("Available RAM: {}", mem());
+ info!("Version: {}", crate::constants::VERSION);
+}
+
+fn mem() -> String {
+ let sys = System::new();
+ let mem = sys.memory().unwrap();
+ format!(
+ "{} / {}",
+ mem.free.to_string_as(true),
+ mem.total.to_string_as(true)
+ )
+}
+
+#[macro_export]
+macro_rules! fatal {
+ () => {
+ error!("Unknown failure!");
+ std::process::exit(2)
+ };
+ ($($arg:tt)*) => ({
+ error!($($arg)*);
+ std::process::exit(2)
+ })
+}
diff --git a/games/rstnode/rst-client/Cargo.toml b/games/rstnode/rst-client/Cargo.toml
index 7b5155f8108c..281b44376902 100644
--- a/games/rstnode/rst-client/Cargo.toml
+++ b/games/rstnode/rst-client/Cargo.toml
@@ -8,14 +8,18 @@ authors = ["Bread Machine", "Katharina Fey <kookie@spacekookie.de>"]
[dependencies]
rst-core = { path = "../rst-core" }
+# async-quic = { path = "../async-quic" }
cairo-rs = { version="0.8.0", features=["v1_16", "png", "svg"] }
librsvg = { git = "https://gitlab.gnome.org/GNOME/librsvg.git", rev = "d34f570f" }
-ggez = "0.6.0-rc0"
+ggez = "0.6.0-rc1"
mint = "0.5" # Required because ggez is trash
svg = "0.9"
+async-trait = "0.1"
+async-std = { version = "1.0", features = ["unstable", "attributes"] }
+chrono = { version = "0.4", features = ["serde"] }
clap = "2.0"
+tempfile = "*"
tracing = "0.1"
-tracing-subscriber = "0.2"
-tempfile = "*" \ No newline at end of file
+tracing-subscriber = "0.2" \ No newline at end of file
diff --git a/games/rstnode/rst-client/src/graphics/entities/mod.rs b/games/rstnode/rst-client/src/graphics/entities/mod.rs
index a3289f6f412d..db675f816fbf 100644
--- a/games/rstnode/rst-client/src/graphics/entities/mod.rs
+++ b/games/rstnode/rst-client/src/graphics/entities/mod.rs
@@ -3,10 +3,10 @@
//! Generally the naming convention should be: `{type}Rndr`
//! (`Renderer`, but shorter).
-use crate::color;
use super::prelude::*;
+use crate::color;
-use rst_core::data::{Owner, Node, Color};
+use rst_core::data::{Color, Link, Node, Owner};
use std::sync::Arc;
/// A set of universal X/Y coordinates
@@ -24,10 +24,6 @@ pub struct NodeRndr {
}
impl Renderer for NodeRndr {
- fn update(&mut self, _: &mut ClientState, _: &mut Context) -> GameResult<()> {
- Ok(())
- }
-
fn draw(&self, s: &ClientState, ctx: &mut Context) -> GameResult<()> {
let frame = s.assets().find("frame/frame_s").unwrap();
let icon = s.assets().find("relay/relay1").unwrap();
@@ -39,10 +35,35 @@ impl Renderer for NodeRndr {
Owner::Player(ref p) => color::to(p.color),
Owner::Neutral => color::to(Color::white()),
};
-
+
frame.draw(ctx, DrawParam::new().dest([x, y]).color(color))?;
icon.draw(ctx, DrawParam::new().dest([x, y]).color(color))?;
Ok(())
}
}
+
+pub struct LinkRndr {
+ pub loc: Coordinates,
+ pub inner: Arc<Link>,
+}
+
+impl Renderer for LinkRndr {
+ fn draw(&self, s: &ClientState, ctx: &mut Context) -> GameResult<()> {
+ // let frame = s.assets().find("frame/frame_s").unwrap();
+ // let icon = s.assets().find("relay/relay1").unwrap();
+
+ // let x = self.loc.0 - frame.width() as f32;
+ // let y = self.loc.1 - frame.height() as f32;
+
+ // let color = match self.inner.owner {
+ // Owner::Player(ref p) => color::to(p.color),
+ // Owner::Neutral => color::to(Color::white()),
+ // };
+
+ // frame.draw(ctx, DrawParam::new().dest([x, y]).color(color))?;
+ // icon.draw(ctx, DrawParam::new().dest([x, y]).color(color))?;
+
+ Ok(())
+ }
+}
diff --git a/games/rstnode/rst-client/src/graphics/mod.rs b/games/rstnode/rst-client/src/graphics/mod.rs
index a7ba676ecc6b..757d44d312d4 100644
--- a/games/rstnode/rst-client/src/graphics/mod.rs
+++ b/games/rstnode/rst-client/src/graphics/mod.rs
@@ -31,6 +31,6 @@ pub(self) mod prelude {
/// A rendering trait which is given graphics context, and game state
pub trait Renderer {
- fn update(&mut self, _state: &mut ClientState, _ctx: &mut Context) -> GameResult<()>;
+ // fn update(&mut self, _state: &mut ClientState, _ctx: &mut Context) -> GameResult<()>:
fn draw(&self, _state: &ClientState, _ctx: &mut Context) -> GameResult<()>;
}
diff --git a/games/rstnode/rst-client/src/input.rs b/games/rstnode/rst-client/src/input.rs
index e9d2516a94c3..83ae17286d61 100644
--- a/games/rstnode/rst-client/src/input.rs
+++ b/games/rstnode/rst-client/src/input.rs
@@ -60,7 +60,7 @@ impl EventHandler for InputHandle {
}
fn mouse_wheel_event(&mut self, _ctx: &mut Context, _: f32, y: f32) {
- self.scroll_offset += y * 0.1;
+ self.scroll_offset -= y * 0.25;
}
fn draw(&mut self, _: &mut Context) -> GameResult<()> {
diff --git a/games/rstnode/rst-client/src/main.rs b/games/rstnode/rst-client/src/main.rs
index a6ba4a59cdc1..4159a37d1d4a 100644
--- a/games/rstnode/rst-client/src/main.rs
+++ b/games/rstnode/rst-client/src/main.rs
@@ -1,5 +1,8 @@
//! RST Node game client
+// Remove the warning spam
+#![allow(warnings)]
+
#[macro_use]
extern crate tracing;
@@ -21,7 +24,8 @@ mod window;
pub(crate) use settings::{GameSettings, GraphicsSettings, WindowSettings};
pub(crate) use state::*;
-fn main() {
+#[async_std::main]
+async fn main() {
// Initialise logging mechanism
log::initialise();
diff --git a/games/rstnode/rst-client/src/net.rs b/games/rstnode/rst-client/src/net.rs
new file mode 100644
index 000000000000..ff3c47774ac6
--- /dev/null
+++ b/games/rstnode/rst-client/src/net.rs
@@ -0,0 +1 @@
+//! Client networking endpoint logic
diff --git a/games/rstnode/rst-client/src/settings.rs b/games/rstnode/rst-client/src/settings.rs
index cb44eacca3a3..7fd0ba6881c1 100644
--- a/games/rstnode/rst-client/src/settings.rs
+++ b/games/rstnode/rst-client/src/settings.rs
@@ -43,7 +43,6 @@ pub struct Samples(pub u8);
impl<'s> From<&'s Samples> for NumSamples {
fn from(s: &'s Samples) -> Self {
match s.0 {
- 0 => Self::Zero,
1 => Self::One,
2 => Self::Two,
4 => Self::Four,
diff --git a/games/rstnode/rst-client/src/state/_match.rs b/games/rstnode/rst-client/src/state/_match.rs
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/games/rstnode/rst-client/src/state/_match.rs
diff --git a/games/rstnode/rst-client/src/state/if_impl.rs b/games/rstnode/rst-client/src/state/if_impl.rs
new file mode 100644
index 000000000000..38bac369d3cc
--- /dev/null
+++ b/games/rstnode/rst-client/src/state/if_impl.rs
@@ -0,0 +1,70 @@
+#![allow(unused)]
+
+use super::ClientState;
+use async_trait::async_trait;
+use chrono::{DateTime, Utc};
+use rst_core::{
+ wire::{
+ game::Action, AuthErr, Lobby, LobbyErr, LobbyId, LobbyUpdate, MatchErr, MatchId, RegErr,
+ UpdateState, User, UserId,
+ },
+ GameIf, Match,
+};
+use std::sync::Arc;
+
+#[async_trait]
+impl GameIf for ClientState {
+ async fn register(self: Arc<Self>, name: String, pw: String) -> Result<UserId, RegErr> {
+ todo!()
+ }
+
+ async fn login(self: Arc<Self>, name: String, pw: String) -> Result<User, AuthErr> {
+ todo!()
+ }
+
+ async fn logout(self: Arc<Self>, user: User) -> Result<(), AuthErr> {
+ todo!()
+ }
+
+ async fn anonymous(self: Arc<Self>, name: String) -> Result<User, AuthErr> {
+ todo!()
+ }
+
+ async fn join(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<Lobby, LobbyErr> {
+ todo!()
+ }
+
+ async fn leave(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<(), LobbyErr> {
+ todo!()
+ }
+
+ async fn ready(
+ self: Arc<Self>,
+ user: User,
+ lobby: LobbyId,
+ ready: bool,
+ ) -> Result<LobbyUpdate, LobbyErr> {
+ todo!()
+ }
+
+ async fn start_req(
+ self: Arc<Self>,
+ user: UserId,
+ lobby: LobbyId,
+ ) -> Result<DateTime<Utc>, LobbyErr> {
+ todo!()
+ }
+
+ async fn perform_action(
+ self: Arc<Self>,
+ user: User,
+ mtch: MatchId,
+ act: Action,
+ ) -> UpdateState {
+ todo!()
+ }
+
+ async fn leave_match(self: Arc<Self>, user: User, mtch: MatchId) -> Result<(), MatchErr> {
+ todo!()
+ }
+}
diff --git a/games/rstnode/rst-client/src/state/map.rs b/games/rstnode/rst-client/src/state/map.rs
new file mode 100644
index 000000000000..1c4666da6b4f
--- /dev/null
+++ b/games/rstnode/rst-client/src/state/map.rs
@@ -0,0 +1,10 @@
+use rst_core::map::{Map, MapNode};
+
+/// Client map state wrapper
+///
+/// The map state is calculated by the server and updates are streamed
+/// to all clients in a [Match](rst_core::Match).
+pub struct MapState {
+ inner: Map,
+}
+
diff --git a/games/rstnode/rst-client/src/state.rs b/games/rstnode/rst-client/src/state/mod.rs
index 8099cf9add96..45e69eee10bb 100644
--- a/games/rstnode/rst-client/src/state.rs
+++ b/games/rstnode/rst-client/src/state/mod.rs
@@ -1,5 +1,10 @@
//! Game client state handling
+mod map;
+pub use map::*;
+
+mod if_impl;
+
use crate::{
assets::Assets,
graphics::{
@@ -11,7 +16,10 @@ use crate::{
GameSettings,
};
use ggez::{event::EventHandler, graphics, Context, GameResult};
-use rst_core::data::{Color, Level, Node, Owner, Player, Upgrade};
+use rst_core::{
+ data::{Color, Level, Link, Node, Owner, Player, Upgrade},
+ io::Io,
+};
use std::sync::Arc;
pub struct ClientState {
@@ -21,17 +29,28 @@ pub struct ClientState {
vp: Viewport,
// Game state
- node: NodeRndr,
+ node1: NodeRndr,
+ node2: NodeRndr,
+ link: Arc<Link>,
}
impl ClientState {
pub fn new(settings: GameSettings, assets: Assets) -> Self {
+ let link = Arc::new(Link {
+ id: 0,
+ a: 0,
+ b: 1,
+ length: 12,
+ pp: vec![],
+ io: Io::default(),
+ });
+
Self {
assets,
settings,
vp: Viewport::new(),
input: InputHandle::new(),
- node: NodeRndr {
+ node1: NodeRndr {
loc: Coordinates(512.0, 512.0),
inner: Arc::new(Node {
id: 0,
@@ -44,11 +63,27 @@ impl ClientState {
money: 1000.into(),
}),
type_: Upgrade::Relay(Level::One),
- links: 0,
- link_states: vec![],
- buffer: vec![],
+ links: 1,
+ router: None,
+ link_states: vec![Arc::clone(&link)],
+ buffer: vec![].into(),
+ }),
+ },
+ node2: NodeRndr {
+ loc: Coordinates(128.0, 128.0),
+ inner: Arc::new(Node {
+ id: 0,
+ health: 100.into(),
+ max_health: 100.into(),
+ owner: Owner::Neutral,
+ type_: Upgrade::Relay(Level::One),
+ links: 1,
+ router: None,
+ link_states: vec![Arc::clone(&link)],
+ buffer: vec![].into(),
}),
},
+ link,
}
}
@@ -80,14 +115,14 @@ impl EventHandler for ClientState {
self.input.mouse_wheel_event(ctx, x, y);
let zoom = self.input.scroll_offset;
self.viewport().zoom(zoom);
-
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
graphics::clear(ctx, graphics::Color::from_rgb(15, 15, 15));
// Render the node
- self.node.draw(&self, ctx).unwrap();
+ self.node1.draw(&self, ctx).unwrap();
+ self.node2.draw(&self, ctx).unwrap();
graphics::present(ctx)
}
diff --git a/games/rstnode/rst-core/Cargo.toml b/games/rstnode/rst-core/Cargo.toml
index da0d3fa0ad55..08294475112e 100644
--- a/games/rstnode/rst-core/Cargo.toml
+++ b/games/rstnode/rst-core/Cargo.toml
@@ -27,3 +27,4 @@ chrono = { version = "0.4", features = ["serde"] }
const_env = "0.1"
quadtree_rs = "0.1"
rand = "0.7"
+tracing = "0.1" \ No newline at end of file
diff --git a/games/rstnode/rst-core/src/_if.rs b/games/rstnode/rst-core/src/_if.rs
index 1a842840708c..f3ed8ee5ffde 100644
--- a/games/rstnode/rst-core/src/_if.rs
+++ b/games/rstnode/rst-core/src/_if.rs
@@ -1,8 +1,8 @@
//! A common trait interface between the server and the client
use crate::wire::{
- Action, AuthErr, Lobby, LobbyErr, LobbyId, LobbyUpdate, MatchErr, MatchId, RegErr, UpdateState,
- User, UserId,
+ game::Action, AuthErr, Lobby, LobbyErr, LobbyId, LobbyUpdate, MatchErr, MatchId, RegErr,
+ UpdateState, User, UserId,
};
use async_std::sync::Arc;
use async_trait::async_trait;
diff --git a/games/rstnode/rst-core/src/_match.rs b/games/rstnode/rst-core/src/_match.rs
index ce75af5af393..e1cc45374ebc 100644
--- a/games/rstnode/rst-core/src/_match.rs
+++ b/games/rstnode/rst-core/src/_match.rs
@@ -1,8 +1,9 @@
use crate::{
data::Player,
lobby::MetaLobby,
+ mailbox::{Inbox, Outbox},
map::Map,
- wire::{Action, LobbyUser, MatchId, UserId},
+ wire::{game::Action, LobbyUser, MatchId, UserId},
};
use async_std::sync::{Arc, RwLock};
use chrono::{DateTime, Utc};
@@ -23,7 +24,9 @@ pub struct Match {
/// The active game map
pub map: Map,
/// Input inbox (handled in-order each game tick)
- inbox: RwLock<VecDeque<Action>>,
+ inbox: Inbox,
+ /// Update outbox
+ outbox: Outbox,
/// The time the match was initialised
init_t: DateTime<Utc>,
/// The synced time the match was started
@@ -46,7 +49,8 @@ impl From<MetaLobby> for Match {
})
.collect(),
map: Map::new(),
- inbox: Default::default(),
+ inbox: Inbox::new(),
+ outbox: Outbox::new(),
init_t: Utc::now(),
start_t: None,
}
@@ -61,7 +65,7 @@ impl Match {
/// Queue a new game action
pub async fn queue(&self, cmd: Action) {
- self.inbox.write().await.push_back(cmd);
+ self.inbox.queue(cmd).await;
}
pub async fn handle_inbox(&mut self) {
diff --git a/games/rstnode/rst-core/src/data.rs b/games/rstnode/rst-core/src/data.rs
index d0494fdef3e2..44d4e2a1a456 100644
--- a/games/rstnode/rst-core/src/data.rs
+++ b/games/rstnode/rst-core/src/data.rs
@@ -4,10 +4,13 @@
use crate::io::Io;
use async_std::sync::Arc;
-use rand::seq::SliceRandom;
-use rand::thread_rng;
+use rand::{seq::SliceRandom, thread_rng};
+use ratman::Router;
use serde::{Deserialize, Serialize};
-use std::sync::atomic::{AtomicBool, AtomicU16, AtomicU32};
+use std::{
+ collections::VecDeque,
+ sync::atomic::{AtomicBool, AtomicU16, AtomicU32, Ordering},
+};
pub type NodeId = usize;
@@ -31,9 +34,12 @@ pub struct Node {
pub links: u8,
/// Active link states
pub link_states: Vec<Arc<Link>>,
+ /// Router state
+ #[serde(skip)]
+ pub router: Option<Router>,
/// Input buffer
#[serde(skip)]
- pub buffer: Vec<Packet>,
+ pub buffer: VecDeque<Packet>,
}
pub type LinkId = usize;
@@ -42,19 +48,19 @@ pub type LinkId = usize;
#[derive(Serialize, Deserialize)]
pub struct Link {
/// This link ID
- id: LinkId,
+ pub id: LinkId,
/// Node 1
- a: NodeId,
+ pub a: NodeId,
/// Node 2
- b: NodeId,
+ pub b: NodeId,
/// The step length
- length: usize,
+ pub length: usize,
/// Packets present on this link
#[serde(skip)]
- pp: Vec<(Packet, AtomicU32)>,
+ pub pp: Vec<(Packet, AtomicU32)>,
/// Actual Rx, Tx pair
#[serde(skip)]
- io: Io,
+ pub io: Io,
}
pub type PacketId = usize;
@@ -86,8 +92,27 @@ pub struct Player {
pub money: AtomicU16,
}
+// This is required because atomics can't safely be cloned
+impl Clone for Player {
+ fn clone(&self) -> Self {
+ let Self {
+ ref id,
+ ref name,
+ ref color,
+ ref money,
+ } = self;
+
+ Self {
+ id: id.clone(),
+ name: name.clone(),
+ color: color.clone(),
+ money: money.load(Ordering::Relaxed).into(),
+ }
+ }
+}
+
/// Optionally, players can create teams
-#[derive(Serialize, Deserialize)]
+#[derive(Clone, Serialize, Deserialize)]
pub struct Team {
/// Name of the team
name: String,
@@ -189,8 +214,6 @@ pub enum Owner {
Player(Player),
}
-
-
/// Encodes upgrade level without numbers
#[derive(Copy, Clone, Serialize, Deserialize)]
pub enum Level {
diff --git a/games/rstnode/rst-core/src/error.rs b/games/rstnode/rst-core/src/error.rs
new file mode 100644
index 000000000000..38c93bbe823f
--- /dev/null
+++ b/games/rstnode/rst-core/src/error.rs
@@ -0,0 +1,51 @@
+pub use crate::wire::{AuthErr, LobbyErr, MatchErr, RegErr};
+use serde::{Deserialize, Serialize};
+use std::fmt::{self, Display, Formatter};
+
+/// A wrapper around the different RST node errors that can occur
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum Error {
+ /// Failure in the registration process
+ Register(RegErr),
+ /// Failure in the authentication process
+ Auth(AuthErr),
+ /// Failure handling a lobby
+ Lobby(LobbyErr),
+ /// Failure in a match setting
+ Match(MatchErr),
+}
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ write!(f, "An RST error")
+ }
+}
+
+/// A RST Node specific error
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl From<RegErr> for Error {
+ fn from(e: RegErr) -> Self {
+ Error::Register(e)
+ }
+}
+
+impl From<AuthErr> for Error {
+ fn from(e: AuthErr) -> Self {
+ Error::Auth(e)
+ }
+}
+
+impl From<LobbyErr> for Error {
+ fn from(e: LobbyErr) -> Self {
+ Error::Lobby(e)
+ }
+}
+
+impl From<MatchErr> for Error {
+ fn from(e: MatchErr) -> Self {
+ Error::Match(e)
+ }
+}
diff --git a/games/rstnode/rst-core/src/lib.rs b/games/rstnode/rst-core/src/lib.rs
index 5ee4e49750c9..dc1a84f63b58 100644
--- a/games/rstnode/rst-core/src/lib.rs
+++ b/games/rstnode/rst-core/src/lib.rs
@@ -13,9 +13,15 @@
//! which is them implemented by [Server](crate::server::Server), and
//! [MatchClient](crate::client::MatchClient).
+// Remove the warning spam
+#![allow(warnings)]
+
#[macro_use]
extern crate const_env;
+#[macro_use]
+extern crate tracing;
+
pub(crate) mod _loop;
mod _if;
@@ -26,11 +32,14 @@ pub use _match::Match;
pub mod config;
pub mod data;
+pub mod error;
pub mod gens;
pub mod io;
pub mod lobby;
+pub mod mailbox;
pub mod map;
pub mod mapstore;
+pub mod net;
pub mod server;
pub mod stats;
pub mod users;
diff --git a/games/rstnode/rst-core/src/lobby.rs b/games/rstnode/rst-core/src/lobby.rs
index 496f98bd7b6f..d58ba7ceb8ee 100644
--- a/games/rstnode/rst-core/src/lobby.rs
+++ b/games/rstnode/rst-core/src/lobby.rs
@@ -2,6 +2,7 @@
use crate::{
data::{Color, ColorPalette},
+ mailbox::Outbox,
users::MetaUser,
wire::{Lobby, LobbyErr, LobbyId, LobbyUpdate, LobbyUser, User, UserId},
};
@@ -68,6 +69,7 @@ impl LobbyList {
pub struct MetaLobby {
pub palette: Vec<Color>,
pub inner: Lobby,
+ pub outbox: Outbox,
}
impl MetaLobby {
@@ -80,6 +82,7 @@ impl MetaLobby {
players: vec![],
settings: vec![],
},
+ outbox: Outbox::new(),
}
}
diff --git a/games/rstnode/rst-core/src/mailbox.rs b/games/rstnode/rst-core/src/mailbox.rs
new file mode 100644
index 000000000000..c7e4512dbeae
--- /dev/null
+++ b/games/rstnode/rst-core/src/mailbox.rs
@@ -0,0 +1,78 @@
+use crate::wire::{
+ game::{Action, Update},
+ Lobby,
+};
+
+use async_std::sync::RwLock;
+use std::collections::VecDeque;
+
+pub enum ClientUpdate {
+ /// Change to the lobby state
+ Lobby(Lobby),
+ /// A game simulation update
+ GameUpdate(Update),
+}
+
+impl<'l> From<&'l Lobby> for ClientUpdate {
+ fn from(l: &'l Lobby) -> Self {
+ ClientUpdate::Lobby(l.clone())
+ }
+}
+
+impl<'l> From<&'l Update> for ClientUpdate {
+ fn from(u: &'l Update) -> Self {
+ ClientUpdate::GameUpdate(u.clone())
+ }
+}
+
+/// A message out buffer that can be attached to any server entity
+pub struct Outbox {
+ queue: RwLock<VecDeque<ClientUpdate>>,
+}
+
+impl Outbox {
+ pub fn new() -> Self {
+ Self {
+ queue: Default::default(),
+ }
+ }
+
+ /// Queue a new item to send out
+ pub async fn queue(&self, update: impl Into<ClientUpdate>) {
+ let mut q = self.queue.write().await;
+ q.push_back(update.into());
+ }
+
+ /// Run a closure for all queued items
+ pub async fn run_for<F: Fn(&ClientUpdate)>(&self, handle: F) {
+ let q = self.queue.read().await;
+ q.iter().for_each(|item| handle(item));
+ }
+
+ /// Clear the outbox for the next update interval
+ pub async fn clear(&self) {
+ self.queue.write().await.clear();
+ }
+}
+
+pub struct Inbox {
+ queue: RwLock<VecDeque<Action>>,
+}
+
+impl Inbox {
+ pub fn new() -> Self {
+ Self {
+ queue: Default::default(),
+ }
+ }
+
+ /// Queue a new item to send out
+ pub async fn queue(&self, update: impl Into<Action>) {
+ let mut q = self.queue.write().await;
+ q.push_back(update.into());
+ }
+
+ pub async fn pop(&self) -> Option<Action> {
+ self.queue.write().await.pop_front()
+ }
+}
diff --git a/games/rstnode/rst-core/src/map.rs b/games/rstnode/rst-core/src/map.rs
index 37f758b4a433..8c6578177e6c 100644
--- a/games/rstnode/rst-core/src/map.rs
+++ b/games/rstnode/rst-core/src/map.rs
@@ -1,17 +1,11 @@
//! Implements a map graph and world logic
use crate::{
- config::{LinkCfg, MapCfg, NodeCfg},
data::{Link, Node, NodeId},
- server::{ServerErr, ServerResult},
wire::Response,
};
use async_std::sync::Arc;
-use quadtree_rs::{
- area::{Area, AreaBuilder},
- point::Point,
- Quadtree,
-};
+use quadtree_rs::{area::AreaBuilder, point::Point, Quadtree};
use std::collections::BTreeMap;
pub struct MapNode {
@@ -29,7 +23,7 @@ pub struct Map {
/// Node IDs mapped to coordinates
nodes: BTreeMap<NodeId, (i64, i64)>,
/// Link IDs mapped to link objects
- links: BTreeMap<u16, Arc<Link>>,
+ _links: BTreeMap<u16, Arc<Link>>,
/// A coordinate map for the network
coord: Quadtree<i64, Arc<MapNode>>,
}
@@ -38,16 +32,14 @@ impl Map {
pub fn new() -> Self {
Self {
nodes: BTreeMap::new(),
- links: BTreeMap::new(),
+ _links: BTreeMap::new(),
coord: Quadtree::new(2),
}
}
- pub fn update<F>(&mut self, cb: F) -> ServerResult<Response>
- where
- F: Fn(&mut Map) -> ServerResult<Response>,
- {
- unimplemented!()
+ /// Get the position of a node by its ID
+ pub fn node_position(&self, id: NodeId) -> Option<(i64, i64)> {
+ self.nodes.get(&id).cloned()
}
/// Get all objects that can be selected by a single point
diff --git a/games/rstnode/rst-core/src/net/endpoint.rs b/games/rstnode/rst-core/src/net/endpoint.rs
new file mode 100644
index 000000000000..0c8e2f912421
--- /dev/null
+++ b/games/rstnode/rst-core/src/net/endpoint.rs
@@ -0,0 +1,49 @@
+use crate::{server::Server, Id};
+use async_std::{
+ net::UdpSocket,
+ sync::{Arc, RwLock},
+ task,
+};
+use std::{
+ collections::BTreeMap,
+ net::SocketAddr,
+ sync::atomic::{AtomicBool, Ordering},
+};
+
+pub struct Endpoint {
+ running: AtomicBool,
+ socket: UdpSocket,
+ bind: String,
+ clients: RwLock<BTreeMap<Id, Client>>,
+}
+
+pub struct Client {}
+
+impl Endpoint {
+ pub async fn new(bind: &str) -> Arc<Self> {
+ let socket = UdpSocket::bind(bind).await.unwrap();
+ Arc::new(Self {
+ running: true.into(),
+ socket,
+ bind: bind.into(),
+ clients: Default::default(),
+ })
+ }
+
+ /// Stop the endpoint
+ pub fn stop(self: &Arc<Self>) {
+ self.running.store(false, Ordering::Relaxed);
+ }
+
+ pub async fn listen(self: &Arc<Self>, serv: Arc<Server>) {
+ let mut buf = vec![0; 1024];
+
+ info!("Listening for connections on {}", self.bind);
+ while self.running.load(Ordering::Relaxed) {
+ let (int, peer) = self.socket.recv_from(&mut buf).await.unwrap();
+ if int > 1024 {
+ warn!("Read a larger chunk than buffer?");
+ }
+ }
+ }
+}
diff --git a/games/rstnode/rst-core/src/net/gen.rs b/games/rstnode/rst-core/src/net/gen.rs
new file mode 100644
index 000000000000..f0a1f58f1905
--- /dev/null
+++ b/games/rstnode/rst-core/src/net/gen.rs
@@ -0,0 +1,52 @@
+use crate::{
+ error::Error,
+ wire::{
+ AuthErr, Lobby, LobbyErr, LobbyId, LobbyUpdate, MatchErr, RegErr, Response, UpdateState,
+ User, UserId,
+ },
+};
+use chrono::{DateTime, Utc};
+
+pub fn register(r: Result<UserId, RegErr>) -> Response {
+ Response::Register(r)
+}
+
+pub fn login(r: Result<User, AuthErr>) -> Response {
+ Response::Login(r)
+}
+
+pub fn logout(r: Result<(), AuthErr>) -> Response {
+ Response::Logout(r)
+}
+
+pub fn rooms(r: Vec<(String, LobbyId)>) -> Response {
+ Response::Rooms(r)
+}
+
+pub fn join(r: Result<Lobby, LobbyErr>) -> Response {
+ Response::Join(r)
+}
+
+pub fn leave(r: Result<(), LobbyErr>) -> Response {
+ Response::Leave(r)
+}
+
+pub fn ready(r: LobbyUpdate) -> Response {
+ Response::Ready(r)
+}
+
+pub fn start_req(r: DateTime<Utc>) -> Response {
+ Response::StartReq(r)
+}
+
+pub fn game_update(r: UpdateState) -> Response {
+ Response::GameUpdate(r)
+}
+
+pub fn leave_game(r: Result<(), MatchErr>) -> Response {
+ Response::LeaveGame(r)
+}
+
+pub fn invalid() -> Response {
+ Response::Invalid
+}
diff --git a/games/rstnode/rst-core/src/net/handler.rs b/games/rstnode/rst-core/src/net/handler.rs
new file mode 100644
index 000000000000..aa0ab6a281c5
--- /dev/null
+++ b/games/rstnode/rst-core/src/net/handler.rs
@@ -0,0 +1,17 @@
+use crate::{
+ net::Client,
+ server::Server,
+ wire::{Request, Response},
+};
+use async_std::sync::{Receiver, Sender};
+
+pub struct Handler {
+ tx: Sender<Response>,
+}
+
+impl Handler {
+ /// Start a message handler with a handle to send a reply back to the clients
+ pub fn start(req: Request) {
+
+ }
+}
diff --git a/games/rstnode/rst-core/src/net/mod.rs b/games/rstnode/rst-core/src/net/mod.rs
new file mode 100644
index 000000000000..f60cb3b97668
--- /dev/null
+++ b/games/rstnode/rst-core/src/net/mod.rs
@@ -0,0 +1,20 @@
+mod endpoint;
+pub use endpoint::*;
+
+mod gen;
+pub use gen::*;
+
+mod handler;
+pub use handler::*;
+
+mod parser;
+pub use parser::*;
+
+// #[async_std::test]
+// async fn user_connection() {
+// let serv = Server::new();
+// let ep = Endpoint::new("localhost:9999").await;
+// task::spawn(async move { ep.listen(serv).await });
+
+// // Create a fake client here
+// }
diff --git a/games/rstnode/rst-core/src/net/parser.rs b/games/rstnode/rst-core/src/net/parser.rs
new file mode 100644
index 000000000000..d7fdf3de964a
--- /dev/null
+++ b/games/rstnode/rst-core/src/net/parser.rs
@@ -0,0 +1,17 @@
+use crate::{
+ error::Error,
+ wire::{Request, Response},
+ GameIf,
+};
+use std::sync::Arc;
+
+/// Parse a request and call a game interface function for it
+pub async fn request(req: Request, game: Arc<impl GameIf>) -> Response {
+ use Request::*;
+ match req {
+ Register(name, pw) => super::register(game.register(name, pw).await),
+ Login(name, pw_hash) => super::login(game.login(name, pw_hash).await),
+ Logout(user) => super::logout(game.logout(user).await),
+ _ => super::invalid(),
+ }
+}
diff --git a/games/rstnode/rst-core/src/server.rs b/games/rstnode/rst-core/src/server.rs
index 3d95c3638c98..68fa2a074e34 100644
--- a/games/rstnode/rst-core/src/server.rs
+++ b/games/rstnode/rst-core/src/server.rs
@@ -4,18 +4,17 @@
//! connections according to a address given to the initialiser.
use crate::{
- _if::GameIf,
- _match::Match,
data::Player,
lobby::LobbyList,
map::Map,
users::UserStore,
wire::{
- Action, AuthErr, Lobby, LobbyErr, LobbyId, LobbyUpdate, MatchErr, MatchId, RegErr,
+ game::Action, AuthErr, Lobby, LobbyErr, LobbyId, LobbyUpdate, MatchErr, MatchId, RegErr,
Response, UpdateState, User, UserId,
},
+ GameIf, Match,
};
-use async_std::sync::{Arc, Mutex, RwLock};
+use async_std::sync::{Arc, Mutex};
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use std::{collections::BTreeMap, path::Path};
@@ -40,12 +39,12 @@ pub struct Server {
impl Server {
/// Create a new game server
- fn new() -> Self {
- Self {
+ pub(crate) fn new() -> Arc<Self> {
+ Arc::new(Self {
matches: Default::default(),
users: UserStore::new(),
lobbies: LobbyList::new(),
- }
+ })
}
/// Open the state dir of a game server
@@ -68,15 +67,15 @@ impl Server {
Ok(0)
}
- pub async fn update_map<F>(self: Arc<Self>, id: MatchId, cb: F) -> ServerResult<Response>
- where
- F: Fn(&mut Map) -> ServerResult<Response>,
- {
- match self.matches.get(&id) {
- Some(ref m) => m.lock().await.map.update(cb),
- None => Err(ServerErr::NoSuchMatch),
- }
- }
+ // pub async fn update_map<F>(self: Arc<Self>, id: MatchId, cb: F) -> ServerResult<Response>
+ // where
+ // F: Fn(&mut Map) -> ServerResult<Response>,
+ // {
+ // match self.matches.get(&id) {
+ // Some(ref m) => m.lock().await.map.update(cb),
+ // None => Err(ServerErr::NoSuchMatch),
+ // }
+ // }
pub async fn update_players<F>(self: Arc<Self>, id: MatchId, cb: F) -> ServerResult<Response>
where
@@ -91,31 +90,32 @@ impl Server {
#[async_trait]
impl GameIf for Server {
- async fn register(self: Arc<Self>, name: String, pw: String) -> Result<UserId, RegErr> {
- unimplemented!()
+ async fn register(self: Arc<Self>, _name: String, _pw: String) -> Result<UserId, RegErr> {
+ todo!()
}
- async fn login(self: Arc<Self>, name: String, pw: String) -> Result<User, AuthErr> {
- unimplemented!()
+ async fn login(self: Arc<Self>, _name: String, _pw: String) -> Result<User, AuthErr> {
+ todo!()
}
- async fn logout(self: Arc<Self>, user: User) -> Result<(), AuthErr> {
- unimplemented!()
+ async fn logout(self: Arc<Self>, _user: User) -> Result<(), AuthErr> {
+ todo!()
}
async fn anonymous(self: Arc<Self>, name: String) -> Result<User, AuthErr> {
- let (_, auth) = self.users.add(name, None, true).await;
- Ok(auth)
+ // let (_, auth) = self.users.add(name, None, true).await;
+ // Ok(auth)
+ todo!()
}
async fn join(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<Lobby, LobbyErr> {
let mu = self.users.get(&user).await?;
- self.lobbies.get_mut(lobby, |mut l| l.join(&mu)).await
+ self.lobbies.get_mut(lobby, |l| l.join(&mu)).await
}
async fn leave(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<(), LobbyErr> {
let mu = self.users.get(&user).await?;
- self.lobbies.get_mut(lobby, |mut l| l.leave(&mu)).await
+ self.lobbies.get_mut(lobby, |l| l.leave(&mu)).await
}
async fn ready(
@@ -124,9 +124,7 @@ impl GameIf for Server {
lobby: LobbyId,
ready: bool,
) -> Result<LobbyUpdate, LobbyErr> {
- self.lobbies
- .get_mut(lobby, |mut l| l.ready(user, ready))
- .await
+ self.lobbies.get_mut(lobby, |l| l.ready(user, ready)).await
}
/// A start request was received
@@ -135,8 +133,8 @@ impl GameIf for Server {
user: UserId,
lobby: LobbyId,
) -> Result<DateTime<Utc>, LobbyErr> {
- self.lobbies.get_mut(lobby, |mut l| l.start(user)).await?;
- let lob = self.lobbies.consume(lobby).await?;
+ self.lobbies.get_mut(lobby, |l| l.start(user)).await??;
+ let _lob = self.lobbies.consume(lobby).await?;
Ok(Utc::now())
}
@@ -149,7 +147,7 @@ impl GameIf for Server {
unimplemented!()
}
- async fn leave_match(self: Arc<Self>, user: User, mtch: MatchId) -> Result<(), MatchErr> {
+ async fn leave_match(self: Arc<Self>, _user: User, _mtch: MatchId) -> Result<(), MatchErr> {
unimplemented!()
}
}
diff --git a/games/rstnode/rst-core/src/wire/action.rs b/games/rstnode/rst-core/src/wire/game/action.rs
index 22ab7ce6868e..22ab7ce6868e 100644
--- a/games/rstnode/rst-core/src/wire/action.rs
+++ b/games/rstnode/rst-core/src/wire/game/action.rs
diff --git a/games/rstnode/rst-core/src/wire/game/mod.rs b/games/rstnode/rst-core/src/wire/game/mod.rs
new file mode 100644
index 000000000000..2cb32cbaa79c
--- /dev/null
+++ b/games/rstnode/rst-core/src/wire/game/mod.rs
@@ -0,0 +1,5 @@
+mod action;
+pub use action::*;
+
+mod update;
+pub use update::*;
diff --git a/games/rstnode/rst-core/src/wire/update.rs b/games/rstnode/rst-core/src/wire/game/update.rs
index a1b47ff07e50..44a2e646bd34 100644
--- a/games/rstnode/rst-core/src/wire/update.rs
+++ b/games/rstnode/rst-core/src/wire/game/update.rs
@@ -1,11 +1,13 @@
//! Update to the game state
-use super::UserId;
-use crate::data::{NodeId, PacketId, Player, Upgrade};
+use crate::{
+ data::{NodeId, PacketId, Player, Upgrade},
+ wire::UserId,
+};
use serde::{Deserialize, Serialize};
/// An update provided by the game server
-#[derive(Serialize, Deserialize)]
+#[derive(Clone, Serialize, Deserialize)]
pub enum Update {
/// Update made to a node
Node(NodeUpdate),
@@ -20,7 +22,7 @@ pub enum Update {
}
/// Update made to a node
-#[derive(Serialize, Deserialize)]
+#[derive(Clone, Serialize, Deserialize)]
pub enum NodeUpdate {
/// The node owner changed
Owner(Player),
@@ -35,7 +37,7 @@ pub enum NodeUpdate {
}
/// Update made to a link
-#[derive(Serialize, Deserialize)]
+#[derive(Clone, Serialize, Deserialize)]
pub enum LinkUpdate {
/// Take a packet from a node's buffer
TakePacket(PacketId),
@@ -44,20 +46,21 @@ pub enum LinkUpdate {
}
/// Update made to a packet
-#[derive(Serialize, Deserialize)]
+#[derive(Clone, Serialize, Deserialize)]
pub enum PacketUpdate {
/// Advance a packet along one step along the link
Increment(PacketId),
}
/// Update made to the user set
-#[derive(Serialize, Deserialize)]
+#[derive(Clone, Serialize, Deserialize)]
pub enum UserUpdate {
UserLeft(UserId),
+ UserPaused(UserId),
}
/// An error occured, can be non-fatal
-#[derive(Serialize, Deserialize)]
+#[derive(Clone, Serialize, Deserialize)]
pub enum UpdateError {
/// You are the last user in the match
LastUser,
diff --git a/games/rstnode/rst-core/src/wire/mod.rs b/games/rstnode/rst-core/src/wire/mod.rs
index 493f0bcb6885..1f15bca79028 100644
--- a/games/rstnode/rst-core/src/wire/mod.rs
+++ b/games/rstnode/rst-core/src/wire/mod.rs
@@ -1,20 +1,19 @@
//! Network formats and container messages
-mod action;
-pub use action::*;
-
mod env;
pub use env::*;
+pub mod game;
+
+mod proto;
+pub use proto::*;
+
mod resp;
pub use resp::*;
mod req;
pub use req::*;
-mod update;
-pub use update::*;
-
use crate::{data::Color, Id};
use serde::{Deserialize, Serialize};
diff --git a/games/rstnode/rst-core/src/wire/proto/mod.rs b/games/rstnode/rst-core/src/wire/proto/mod.rs
new file mode 100644
index 000000000000..07598bc85540
--- /dev/null
+++ b/games/rstnode/rst-core/src/wire/proto/mod.rs
@@ -0,0 +1,25 @@
+//! This module implements the client-server game protocol
+
+use super::{Request, Response};
+
+pub enum NetErr {
+ Refused,
+ Dropped,
+ Timeout,
+ BadData,
+}
+
+/// Use this function to send a request to a partical remote
+///
+/// The function makes sure that you get a valid response back, but
+/// does not yet ensure that this response is correct for the request
+/// in question.
+pub fn request_to(r: Request, remote: String) -> Result<Response, NetErr> {
+ todo!()
+}
+
+/// Use this function to send a response to a client
+pub fn response_to(r: Response, client: String) -> Result<(), NetErr> {
+ todo!()
+}
+
diff --git a/games/rstnode/rst-core/src/wire/proto/request.rs b/games/rstnode/rst-core/src/wire/proto/request.rs
new file mode 100644
index 000000000000..a95c240c4a14
--- /dev/null
+++ b/games/rstnode/rst-core/src/wire/proto/request.rs
@@ -0,0 +1,41 @@
+use crate::wire::{Action, LobbyId, MatchId, Request, User};
+
+pub fn register(name: String, pw: String) -> Request {
+ Request::Register(name, pw)
+}
+c
+pub fn login(name: String, pw: String) -> Request {
+ Request::Login(name, pw)
+}
+
+pub fn logout(user: User) -> Request {
+ Request::Logout(user)
+}
+
+pub fn anonymous(name: String) -> Request {
+ Request::Anonymous(name)
+}
+
+pub fn join(user: User, lid: LobbyId) -> Request {
+ Request::Join(user, lid)
+}
+
+pub fn leave(user: User, lid: LobbyId) -> Request {
+ Request::Leave(user, lid)
+}
+
+pub fn ready(user: User, lid: LobbyId, ready: bool) -> Request {
+ Request::Ready(user, lid, ready)
+}
+
+pub fn start_req(user: User, lid: LobbyId) -> Request {
+ Request::StartReq(user, lid)
+}
+
+pub fn game_action(user: User, mid: MatchId, act: Action) -> Request {
+ Request::GameAction(user, mid, act)
+}
+
+pub fn leave_game(user: User, mid: MatchId) -> Request {
+ Request::LeaveGame(user, mid)
+}
diff --git a/games/rstnode/rst-core/src/wire/proto/response.rs b/games/rstnode/rst-core/src/wire/proto/response.rs
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/games/rstnode/rst-core/src/wire/proto/response.rs
diff --git a/games/rstnode/rst-core/src/wire/req.rs b/games/rstnode/rst-core/src/wire/req.rs
index ffefcbdb6ac7..be5c905795a9 100644
--- a/games/rstnode/rst-core/src/wire/req.rs
+++ b/games/rstnode/rst-core/src/wire/req.rs
@@ -1,4 +1,4 @@
-use super::{action::Action, LobbyId, MatchId, User};
+use super::{game::Action, LobbyId, MatchId, User};
use serde::{Deserialize, Serialize};
/// A message sent from the game client to the server
diff --git a/games/rstnode/rst-core/src/wire/resp.rs b/games/rstnode/rst-core/src/wire/resp.rs
index ef2e192a6044..99598cceb9e6 100644
--- a/games/rstnode/rst-core/src/wire/resp.rs
+++ b/games/rstnode/rst-core/src/wire/resp.rs
@@ -27,9 +27,11 @@ pub enum Response {
GameUpdate(UpdateState),
/// Leave the match (forfeit)
LeaveGame(Result<(), MatchErr>),
+ /// The given request was entirely invalid
+ Invalid,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RegErr {
/// The password is way too bad
BadPassword,
@@ -39,7 +41,7 @@ pub enum RegErr {
OtherError,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AuthErr {
/// Wrong password for the user
WrongPassword,
@@ -51,7 +53,7 @@ pub enum AuthErr {
OtherError,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum LobbyErr {
/// The requested room is already full
RoomFull,
@@ -85,7 +87,7 @@ pub enum UpdateState {
}
/// An error that can occur in a match
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MatchErr {
/// The provided player wasn't in the match (anymore?)
NotInMatch,
diff --git a/games/rstnode/rst-server/Cargo.toml b/games/rstnode/rst-server/Cargo.toml
index bf175b81325d..8903e637fc3f 100644
--- a/games/rstnode/rst-server/Cargo.toml
+++ b/games/rstnode/rst-server/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "rst-node-server"
-description = "Backend game server"
+description = "RST Node game server"
version = "0.0.0"
edition = "2018"
license = "AGPL-3.0-or-later"
@@ -8,6 +8,12 @@ authors = ["Bread Machine", "Katharina Fey <kookie@spacekookie.de>"]
[dependencies]
rst-core = { path = "../rst-core" }
-async-std = { version = "1.0", features = ["attributes"] }
+async-std = { version = "1.0", features = ["unstable", "attributes"] }
+async-trait = "0.1"
+
+chrono = { version = "0.4", features = ["serde"] }
tracing = "0.1"
-tracing-subscriber = "0.2" \ No newline at end of file
+tracing-subscriber = "0.2"
+num_cpus = "1.0"
+systemstat = "0.1"
+
diff --git a/games/rstnode/rst-server/src/constants.rs b/games/rstnode/rst-server/src/constants.rs
index e40a5c35c5db..8dc23f7c68d8 100644
--- a/games/rstnode/rst-server/src/constants.rs
+++ b/games/rstnode/rst-server/src/constants.rs
@@ -1,5 +1,6 @@
-
-
pub const NAME: &'static str = "RST Node";
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub const AUTHORS: &'static str = env!("CARGO_PKG_AUTHORS");
+
+pub const DEFAULT_BIND: &'static str = "0.0.0.0";
+pub const DEFAULT_PORT: u16 = 10022;
diff --git a/games/rstnode/rst-server/src/log.rs b/games/rstnode/rst-server/src/log.rs
index 62d03167bb7a..676395134a59 100644
--- a/games/rstnode/rst-server/src/log.rs
+++ b/games/rstnode/rst-server/src/log.rs
@@ -8,8 +8,15 @@ const BANNER: &'static str = "
██║ ██║███████║ ██║ ██║ ╚████║╚██████╔╝██████╔╝███████╗
╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚══════╝";
+use systemstat::{Platform, System};
use tracing_subscriber::{filter::LevelFilter, fmt, EnvFilter};
+#[cfg(not(target_os = "windows"))]
+const PLATFORM_DISCLAIMER: &'static str = "Platform: Unspecified *nix-like";
+#[cfg(target_os = "windows")]
+static PLATFORM_DISCLAIMER: &'static str =
+ "WARNING: Windows server hosts are not officially supported!";
+
pub(crate) fn initialise() {
let filter = EnvFilter::try_from_env("RST_LOG")
.unwrap_or_default()
@@ -19,13 +26,24 @@ pub(crate) fn initialise() {
// Initialise the logger
fmt().with_env_filter(filter).init();
- info!("Initialising server...");
+ info!("Initialising...");
info!("{}", BANNER);
- info!("Available cores: unknown");
- info!("Available RAM: unknown");
+ info!("{}", PLATFORM_DISCLAIMER);
+ info!("Available cores: {}", num_cpus::get());
+ info!("Available RAM: {}", mem());
info!("Version: {}", crate::constants::VERSION);
}
+fn mem() -> String {
+ let sys = System::new();
+ let mem = sys.memory().unwrap();
+ format!(
+ "{} / {}",
+ mem.free.to_string_as(true),
+ mem.total.to_string_as(true)
+ )
+}
+
#[macro_export]
macro_rules! fatal {
() => {
diff --git a/games/rstnode/rst-server/src/main.rs b/games/rstnode/rst-server/src/main.rs
index d3335e941ca8..fbdd33bb864d 100644
--- a/games/rstnode/rst-server/src/main.rs
+++ b/games/rstnode/rst-server/src/main.rs
@@ -1,15 +1,22 @@
+//! RST Node game server
+
+// Remove the warning spam
+#![allow(warnings)]
+
#[macro_use]
extern crate tracing;
-mod constants;
-mod log;
-mod net;
-use net::ServerEndpoint;
+pub(crate) mod constants;
+pub(crate) mod log;
+
+use rst_core::net::Endpoint;
#[async_std::main]
async fn main() {
log::initialise();
- let serv = ServerEndpoint::new("0.0.0.0:10022").await;
- serv.listen().await;
+ let addr = format!("{}:{}", constants::DEFAULT_BIND, constants::DEFAULT_PORT);
+ let serv = Endpoint::new(addr.as_str()).await;
+ // serv.listen().await;
+ // net::run().await;
}
diff --git a/games/rstnode/rst-server/src/net/mod.rs b/games/rstnode/rst-server/src/net/mod.rs
deleted file mode 100644
index deb35f7f89b9..000000000000
--- a/games/rstnode/rst-server/src/net/mod.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-#![allow(unused)]
-
-mod parser;
-
-use async_std::{
- net::UdpSocket,
- sync::{Arc, RwLock},
- task,
-};
-use rst_core::Id;
-use std::{collections::BTreeMap, net::SocketAddr};
-
-pub struct ServerEndpoint {
- socket: UdpSocket,
- bind: String,
- clients: RwLock<BTreeMap<Id, Client>>,
-}
-
-impl ServerEndpoint {
- pub async fn new(bind: &str) -> Arc<Self> {
- let socket = UdpSocket::bind(bind).await.unwrap();
- Arc::new(Self {
- socket,
- bind: bind.into(),
- clients: Default::default(),
- })
- }
-
- pub async fn listen(self: &Arc<Self>) {
- let mut buf = vec![0; 1024];
-
- info!("Listening for connections on {}", self.bind);
-
- loop {
- let (_, peer) = self.socket.recv_from(&mut buf).await.unwrap();
- }
- }
-}
-
-pub struct Client {
- addr: SocketAddr,
-}
-
diff --git a/games/rstnode/rst-server/src/net/parser.rs b/games/rstnode/rst-server/src/net/parser.rs
deleted file mode 100644
index d320e13095bb..000000000000
--- a/games/rstnode/rst-server/src/net/parser.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use rst_core::wire::Request;
-
-pub async fn request(req: Request) {
- use Request::*;
- match req {
- Register(name, pw) => {},
- _ => todo!(),
- }
-}
diff --git a/games/rstnode/rst-server/src/server.rs b/games/rstnode/rst-server/src/server.rs
new file mode 100644
index 000000000000..9badba85d1a6
--- /dev/null
+++ b/games/rstnode/rst-server/src/server.rs
@@ -0,0 +1,153 @@
+//! Game server state handler
+//!
+//! A server can host many lobbies at the same time. It listens for
+//! connections according to a address given to the initialiser.
+
+use async_std::sync::{Arc, Mutex};
+use async_trait::async_trait;
+use chrono::{DateTime, Utc};
+use rst_core::{
+ data::Player,
+ lobby::LobbyList,
+ map::Map,
+ users::UserStore,
+ wire::{
+ Action, AuthErr, Lobby, LobbyErr, LobbyId, LobbyUpdate, MatchErr, MatchId, RegErr,
+ Response, UpdateState, User, UserId,
+ },
+ GameIf, Match,
+};
+use std::{collections::BTreeMap, path::Path};
+
+/// A convenience result wrapper for server actions
+pub type ServerResult<T> = Result<T, ServerErr>;
+pub enum ServerErr {
+ /// The requested directory is corrupted
+ NoSuchDir,
+ /// Corrupted game state
+ Corrupted,
+ /// No such match found
+ NoSuchMatch,
+}
+
+/// The game's server backend
+pub struct Server {
+ matches: BTreeMap<MatchId, Mutex<Match>>,
+ users: UserStore,
+ lobbies: LobbyList,
+}
+
+impl Server {
+ /// Create a new game server
+ pub(crate) fn new() -> Arc<Self> {
+ Arc::new(Self {
+ matches: Default::default(),
+ users: UserStore::new(),
+ lobbies: LobbyList::new(),
+ })
+ }
+
+ /// Open the state dir of a game server
+ pub async fn open(self: Arc<Self>, path: &Path) -> ServerResult<()> {
+ Ok(())
+ }
+
+ /// Stop accepting new game connections and shutdown gracefully
+ ///
+ /// Returns the number of matches still going on.
+ pub async fn shutdown(self: Arc<Self>) -> ServerResult<u64> {
+ Ok(0)
+ }
+
+ /// Save and close the statedir and kicking all players
+ ///
+ /// Returns the number of players that were kicked off the server
+ /// prematurely.
+ pub async fn kill(self: Arc<Self>) -> ServerResult<u64> {
+ Ok(0)
+ }
+
+ // pub async fn update_map<F>(self: Arc<Self>, id: MatchId, cb: F) -> ServerResult<Response>
+ // where
+ // F: Fn(&mut Map) -> ServerResult<Response>,
+ // {
+ // match self.matches.get(&id) {
+ // Some(ref m) => m.lock().await.map.update(cb),
+ // None => Err(ServerErr::NoSuchMatch),
+ // }
+ // }
+
+ pub async fn update_players<F>(self: Arc<Self>, id: MatchId, cb: F) -> ServerResult<Response>
+ where
+ F: Fn(&mut Vec<Player>) -> ServerResult<Response>,
+ {
+ match self.matches.get(&id) {
+ Some(ref mut m) => cb(&mut m.lock().await.players),
+ None => Err(ServerErr::NoSuchMatch),
+ }
+ }
+}
+
+#[async_trait]
+impl GameIf for Server {
+ async fn register(self: Arc<Self>, _name: String, _pw: String) -> Result<UserId, RegErr> {
+ todo!()
+ }
+
+ async fn login(self: Arc<Self>, _name: String, _pw: String) -> Result<User, AuthErr> {
+ todo!()
+ }
+
+ async fn logout(self: Arc<Self>, _user: User) -> Result<(), AuthErr> {
+ todo!()
+ }
+
+ async fn anonymous(self: Arc<Self>, name: String) -> Result<User, AuthErr> {
+ // let (_, auth) = self.users.add(name, None, true).await;
+ // Ok(auth)
+ todo!()
+ }
+
+ async fn join(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<Lobby, LobbyErr> {
+ let mu = self.users.get(&user).await?;
+ self.lobbies.get_mut(lobby, |l| l.join(&mu)).await
+ }
+
+ async fn leave(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<(), LobbyErr> {
+ let mu = self.users.get(&user).await?;
+ self.lobbies.get_mut(lobby, |l| l.leave(&mu)).await
+ }
+
+ async fn ready(
+ self: Arc<Self>,
+ user: User,
+ lobby: LobbyId,
+ ready: bool,
+ ) -> Result<LobbyUpdate, LobbyErr> {
+ self.lobbies.get_mut(lobby, |l| l.ready(user, ready)).await
+ }
+
+ /// A start request was received
+ async fn start_req(
+ self: Arc<Self>,
+ user: UserId,
+ lobby: LobbyId,
+ ) -> Result<DateTime<Utc>, LobbyErr> {
+ self.lobbies.get_mut(lobby, |l| l.start(user)).await??;
+ let _lob = self.lobbies.consume(lobby).await?;
+ Ok(Utc::now())
+ }
+
+ async fn perform_action(
+ self: Arc<Self>,
+ user: User,
+ mtch: MatchId,
+ act: Action,
+ ) -> UpdateState {
+ unimplemented!()
+ }
+
+ async fn leave_match(self: Arc<Self>, _user: User, _mtch: MatchId) -> Result<(), MatchErr> {
+ unimplemented!()
+ }
+}