generate empire starting systems

This commit is contained in:
Michael Zhang 2023-12-30 20:40:47 -05:00
parent cd8793e55c
commit e0fa661845
15 changed files with 632 additions and 81 deletions

371
Cargo.lock generated
View file

@ -2,6 +2,12 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "Inflector"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
[[package]]
name = "addr2line"
version = "0.21.0"
@ -163,6 +169,20 @@ dependencies = [
"syn 2.0.43",
]
[[package]]
name = "async-tungstenite"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e6acf7e4a267eecbb127ed696bb2d50572c22ba7f586a646321e1798d8336a1"
dependencies = [
"futures-io",
"futures-util",
"log",
"pin-project-lite",
"tokio",
"tungstenite",
]
[[package]]
name = "asynchronous-codec"
version = "0.6.2"
@ -196,12 +216,53 @@ dependencies = [
"winapi",
]
[[package]]
name = "autocfg"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78"
dependencies = [
"autocfg 1.1.0",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "axum"
version = "0.6.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
dependencies = [
"async-trait",
"axum-core 0.3.4",
"bitflags 1.3.2",
"bytes",
"futures-util",
"http 0.2.11",
"http-body 0.4.6",
"hyper 0.14.28",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"rustversion",
"serde",
"serde_json",
"serde_path_to_error",
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tower",
"tower-layer",
"tower-service",
]
[[package]]
name = "axum"
version = "0.7.2"
@ -209,7 +270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d"
dependencies = [
"async-trait",
"axum-core",
"axum-core 0.4.1",
"bytes",
"futures-util",
"http 1.0.0",
@ -235,6 +296,23 @@ dependencies = [
"tower-service",
]
[[package]]
name = "axum-core"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c"
dependencies = [
"async-trait",
"bytes",
"futures-util",
"http 0.2.11",
"http-body 0.4.6",
"mime",
"rustversion",
"tower-layer",
"tower-service",
]
[[package]]
name = "axum-core"
version = "0.4.1"
@ -260,13 +338,16 @@ name = "backend"
version = "0.1.0"
dependencies = [
"anyhow",
"axum",
"axum 0.7.2",
"chrono",
"clap 4.4.11",
"colourado",
"names",
"petgraph 0.6.4",
"prisma-client-rust",
"rand 0.8.5",
"rand_chacha 0.3.1",
"rspc",
"serde",
"serde_json",
"tokio",
@ -316,6 +397,12 @@ version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5"
[[package]]
name = "base64"
version = "0.21.5"
@ -661,6 +748,15 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "cmake"
version = "0.1.50"
@ -686,6 +782,15 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "colourado"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d51b47ec6e60f823a917da8b2e0b2261e3ca1976de32f94f7338687363b727e"
dependencies = [
"rand 0.6.5",
]
[[package]]
name = "combine"
version = "3.8.1"
@ -736,6 +841,17 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "cookie"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
dependencies = [
"percent-encoding",
"time",
"version_check",
]
[[package]]
name = "core-foundation"
version = "0.9.4"
@ -811,7 +927,7 @@ version = "0.9.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d"
dependencies = [
"autocfg",
"autocfg 1.1.0",
"cfg-if",
"crossbeam-utils",
]
@ -1112,6 +1228,15 @@ dependencies = [
"serde_json",
]
[[package]]
name = "document-features"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95"
dependencies = [
"litrs",
]
[[package]]
name = "dotenv"
version = "0.15.0"
@ -1402,6 +1527,12 @@ dependencies = [
"syn 2.0.43",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "funty"
version = "2.0.0"
@ -1761,6 +1892,25 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "httpz"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6769d2cb10425c442c41a787d1a3719744770a188cfa7885cd4d8126fa13f37a"
dependencies = [
"async-tungstenite",
"axum 0.6.20",
"base64 0.20.0",
"cookie",
"form_urlencoded",
"futures",
"http 0.2.11",
"hyper 0.14.28",
"sha1",
"thiserror",
"tokio",
]
[[package]]
name = "hyper"
version = "0.14.28"
@ -1891,7 +2041,7 @@ version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"autocfg 1.1.0",
"hashbrown 0.12.3",
"serde",
]
@ -2177,13 +2327,19 @@ version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
[[package]]
name = "litrs"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
[[package]]
name = "lock_api"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
dependencies = [
"autocfg",
"autocfg 1.1.0",
"scopeguard",
]
@ -2737,7 +2893,7 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [
"autocfg",
"autocfg 1.1.0",
"num-integer",
"num-traits",
]
@ -2757,7 +2913,7 @@ version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"autocfg 1.1.0",
"num-traits",
]
@ -2767,7 +2923,7 @@ version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"autocfg 1.1.0",
"num-integer",
"num-traits",
]
@ -2778,7 +2934,7 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"autocfg 1.1.0",
"num-bigint",
"num-integer",
"num-traits",
@ -2790,7 +2946,7 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
"autocfg 1.1.0",
]
[[package]]
@ -3256,10 +3412,12 @@ dependencies = [
"psl",
"query-connector",
"query-core",
"rspc",
"schema",
"serde",
"serde-value",
"serde_json",
"specta",
"thiserror",
"user-facing-errors",
"uuid",
@ -3293,6 +3451,7 @@ dependencies = [
"convert_case 0.6.0",
"proc-macro2",
"quote",
"specta",
"syn 1.0.109",
]
@ -3613,6 +3772,25 @@ dependencies = [
"nibble_vec",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
dependencies = [
"autocfg 0.1.8",
"libc",
"rand_chacha 0.1.1",
"rand_core 0.4.2",
"rand_hc 0.1.0",
"rand_isaac",
"rand_jitter",
"rand_os",
"rand_pcg",
"rand_xorshift",
"winapi",
]
[[package]]
name = "rand"
version = "0.7.3"
@ -3623,7 +3801,7 @@ dependencies = [
"libc",
"rand_chacha 0.2.2",
"rand_core 0.5.1",
"rand_hc",
"rand_hc 0.2.0",
]
[[package]]
@ -3637,6 +3815,16 @@ dependencies = [
"rand_core 0.6.4",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
dependencies = [
"autocfg 0.1.8",
"rand_core 0.3.1",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
@ -3657,6 +3845,21 @@ dependencies = [
"rand_core 0.6.4",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
version = "0.5.1"
@ -3675,6 +3878,15 @@ dependencies = [
"getrandom 0.2.11",
]
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
@ -3684,6 +3896,59 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
dependencies = [
"libc",
"rand_core 0.4.2",
"winapi",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
dependencies = [
"cloudabi",
"fuchsia-cprng",
"libc",
"rand_core 0.4.2",
"rdrand",
"winapi",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
dependencies = [
"autocfg 0.1.8",
"rand_core 0.4.2",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "raw-cpuid"
version = "10.7.0"
@ -3693,6 +3958,15 @@ dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
@ -3873,6 +4147,21 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "rspc"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c68477fb8c11280503aeab140c41b7a0eed57156a73185062ffb4782c18a918f"
dependencies = [
"futures",
"httpz",
"serde",
"serde_json",
"specta",
"thiserror",
"tokio",
]
[[package]]
name = "rusqlite"
version = "0.25.4"
@ -4325,7 +4614,7 @@ version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
"autocfg 1.1.0",
]
[[package]]
@ -4354,6 +4643,39 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "specta"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2240c3aa020aa61d2c569087d213baafbb212f4ceb9de9dd162376ea6aa0fe3"
dependencies = [
"chrono",
"document-features",
"indexmap 1.9.3",
"indoc",
"once_cell",
"paste",
"serde",
"serde_json",
"specta-macros",
"thiserror",
"uuid",
]
[[package]]
name = "specta-macros"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4605306321c356e03873b8ee71d7592a5e7c508add325c3ed0677c16fdf1bcfb"
dependencies = [
"Inflector",
"itertools 0.10.5",
"proc-macro2",
"quote",
"syn 1.0.109",
"termcolor",
]
[[package]]
name = "spin"
version = "0.9.8"
@ -5076,6 +5398,25 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "tungstenite"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788"
dependencies = [
"base64 0.13.1",
"byteorder",
"bytes",
"http 0.2.11",
"httparse",
"log",
"rand 0.8.5",
"sha1",
"thiserror",
"url",
"utf-8",
]
[[package]]
name = "twox-hash"
version = "1.6.3"
@ -5200,6 +5541,12 @@ dependencies = [
"user-facing-error-macros",
]
[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utf8parse"
version = "0.2.1"

View file

@ -10,10 +10,17 @@ anyhow = "1.0.76"
axum = { version = "0.7.2", features = ["http2"] }
chrono = "0.4.31"
clap = { version = "4.4.11", features = ["derive"] }
prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust", tag = "0.6.10" }
serde = { version = "1.0.193", features = ["derive"] }
tokio = { version = "1.35.1", features = ["full"] }
serde_json = "1.0.108"
petgraph = "0.6.4"
names = "0.14.0"
rand = "0.8.5"
rspc = { version = "0.1.3", features = ["axum"] }
rand_chacha = "0.3.1"
colourado = "0.2.0"
[dependencies.prisma-client-rust]
git = "https://github.com/Brendonovich/prisma-client-rust"
tag = "0.6.10"
features = ["rspc"]

View file

@ -4,13 +4,14 @@ use anyhow::Result;
use petgraph::{
algo::min_spanning_tree, data::FromElements, graphmap::UnGraphMap,
};
use rand::SeedableRng;
use triangle::{triangulate, Point, TrianglulateOpts};
use crate::state::{StarSystemCoreState, StarSystemId};
pub struct Map {
pub star_systems: HashMap<StarSystemId, StarSystemCoreState>,
pub hyperlanes: UnGraphMap<usize, ()>,
pub hyperlanes: UnGraphMap<StarSystemId, ()>,
}
pub fn generate_map() -> Result<Map> {
@ -42,6 +43,7 @@ pub fn generate_map() -> Result<Map> {
let star_system = StarSystemCoreState {
id,
position: (point.x, point.y),
owned_by_empire_id: None,
};
star_systems.insert(id, star_system);
}
@ -49,9 +51,21 @@ pub fn generate_map() -> Result<Map> {
// Format the hyperlanes into petgraph
let mut hyperlanes = UnGraphMap::default();
for indexes in result.triangle_list.into_iter() {
hyperlanes.add_edge(indexes[0], indexes[1], ());
hyperlanes.add_edge(indexes[0], indexes[2], ());
hyperlanes.add_edge(indexes[1], indexes[2], ());
hyperlanes.add_edge(
StarSystemId(indexes[0] as i32),
StarSystemId(indexes[1] as i32),
(),
);
hyperlanes.add_edge(
StarSystemId(indexes[0] as i32),
StarSystemId(indexes[2] as i32),
(),
);
hyperlanes.add_edge(
StarSystemId(indexes[1] as i32),
StarSystemId(indexes[2] as i32),
(),
);
}
// Let's just drop some random % of hyperlanes

View file

@ -4,11 +4,17 @@ use std::collections::HashMap;
use anyhow::Result;
use chrono::Utc;
use colourado::{ColorPalette, PaletteType};
use names::Generator as NameGenerator;
use petgraph::algo::k_shortest_path;
use rand::{
rngs::ThreadRng, seq::SliceRandom, thread_rng, RngCore, SeedableRng,
};
use rand_chacha::ChaCha12Rng;
use crate::{
prisma::PrismaClient,
state::{EmpireCoreState, EmpireId, GameCoreState, UniverseId},
state::{EmpireCoreState, EmpireId, GameCoreState, StarSystemId, UniverseId},
};
use self::map::generate_map;
@ -16,20 +22,74 @@ use self::map::generate_map;
pub async fn generate_initial_game_state(
client: &PrismaClient,
) -> Result<GameCoreState> {
// Generate a seed
let mut seed = [0; 32];
{
let mut rng = thread_rng();
rng.fill_bytes(&mut seed);
}
let mut seeded_rng = ChaCha12Rng::from_seed(seed);
// Generate a new universe ID
let universe = client.universe().create(json!({}), vec![]).exec().await?;
let mut map = generate_map()?;
// TODO: take this in via some kind of world-gen options
let num_empires = 10;
// Pick `num_empires` amount of starting systems.
let starting_points = {
let mut starting_points = Vec::<StarSystemId>::new();
let mut star_system_ids = map.star_systems.keys().collect::<Vec<_>>();
star_system_ids.shuffle(&mut seeded_rng);
let mut iter = star_system_ids.iter();
// TODO: Is this slow? make this process faster than O(n^2 * whatever)
while starting_points.len() < num_empires {
let next_starting_point = **iter.next().unwrap();
let distances =
k_shortest_path(&map.hyperlanes, next_starting_point, None, 1, |_| 1);
if starting_points
.iter()
.all(|starting_point| *distances.get(starting_point).unwrap() > 5)
{
starting_points.push(next_starting_point);
}
}
starting_points
};
// Generate color palettes for empires
let palette =
ColorPalette::new(num_empires as u32, PaletteType::Pastel, false);
// Generate some empires
let mut empires = HashMap::new();
let name_generator = NameGenerator::default();
for (idx, name) in name_generator.take(10).enumerate() {
for (idx, ((name, capital_system_id), color)) in name_generator
.take(num_empires)
.zip(starting_points)
.zip(palette.colors.into_iter())
.enumerate()
{
let id = EmpireId(idx as i32);
let empire = EmpireCoreState { id, name };
// Set the star system's owner
map
.star_systems
.get_mut(&capital_system_id)
.unwrap()
.owned_by_empire_id = Some(id);
let empire = EmpireCoreState {
id,
name,
color,
capital_system_id,
};
empires.insert(id, empire);
}
let map = generate_map()?;
Ok(GameCoreState {
universe_id: UniverseId(universe.id),
current_instant: Utc::now(),

View file

@ -6,6 +6,7 @@ mod generate;
pub mod prisma;
mod routes;
pub mod state;
mod utils;
use std::sync::Arc;
@ -14,7 +15,7 @@ use axum::{routing::get, Router};
use clap::{Parser, Subcommand};
use prisma::PrismaClient;
use routes::{universe_list, universe_map};
use routes::{empire_list, universe_list, universe_map};
use crate::generate::generate_initial_game_state;
@ -50,8 +51,10 @@ async fn main() -> Result<()> {
let app = Router::new()
.route("/", get(|| async { "Hello, World!" }))
.route("/universe", get(universe_list))
.route("/universe/:universe_id/empires", get(empire_list))
.route("/universe/:universe_id/map", get(universe_map))
.with_state(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:1440").await?;
axum::serve(listener, app).await?;
}
@ -59,7 +62,6 @@ async fn main() -> Result<()> {
Command::Seed => {
let game_state = generate_initial_game_state(&client).await?;
game_state.save_to_database(&client).await?;
println!("Done.");
}
}

View file

@ -6,7 +6,7 @@ use prisma_client_rust::Direction;
use serde_json::Value;
use crate::{
prisma::{star_system, star_system_edges},
prisma::{empire, star_system, star_system_edges},
state::UniverseId,
AppState,
};
@ -25,18 +25,33 @@ pub async fn universe_list(state: State<AppState>) -> Json<Value> {
}))
}
pub async fn empire_list(
Path((universe_id,)): Path<(i32,)>,
state: State<AppState>,
) -> Json<Value> {
let empires = state
.prisma
.empire()
.find_many(vec![empire::universe_id::equals(universe_id)])
.exec()
.await
.unwrap();
Json(json!({
"empires": empires,
}))
}
pub async fn universe_map(
Path((universe_id,)): Path<(i32,)>,
state: State<AppState>,
) -> Json<Value> {
let universe_id = UniverseId(universe_id);
let points = state
.prisma
.star_system()
.find_many(vec![star_system::universe_id::equals(universe_id.0)])
.find_many(vec![star_system::universe_id::equals(universe_id)])
.order_by(star_system::index::order(Direction::Asc))
.select(star_system::select!({ index coord_x coord_y }))
.select(star_system::select!({ index coord_x coord_y owned_by_empire_id }))
.exec()
.await
.unwrap();
@ -44,7 +59,7 @@ pub async fn universe_map(
let edges = state
.prisma
.star_system_edges()
.find_many(vec![star_system_edges::universe_id::equals(universe_id.0)])
.find_many(vec![star_system_edges::universe_id::equals(universe_id)])
.select(star_system_edges::select!({ from_system_id to_system_id }))
.exec()
.await

View file

@ -1,9 +1,15 @@
use colourado::Color;
use super::StarSystemId;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct EmpireId(pub i32);
pub struct EmpireCoreState {
pub id: EmpireId,
pub name: String,
pub color: Color,
pub capital_system_id: StarSystemId,
}
pub struct EmpireDerivedState {}

View file

@ -1,10 +1,13 @@
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use anyhow::Result;
use chrono::{DateTime, Utc};
use petgraph::graphmap::UnGraphMap;
use crate::prisma::{empire, star_system, star_system_edges, PrismaClient};
use crate::{
prisma::{empire, star_system, star_system_edges, PrismaClient},
utils::format_color,
};
use super::{EmpireCoreState, EmpireId, StarSystemCoreState, StarSystemId};
@ -13,10 +16,12 @@ pub struct UniverseId(pub i32);
pub struct GameCoreState {
pub universe_id: UniverseId,
/// The instant of time that this game state was captured at
pub current_instant: DateTime<Utc>,
pub empires: HashMap<EmpireId, EmpireCoreState>,
pub star_systems: HashMap<StarSystemId, StarSystemCoreState>,
pub hyperlanes: UnGraphMap<usize, ()>,
pub hyperlanes: UnGraphMap<StarSystemId, ()>,
}
pub struct GameDerivedState<'a> {
@ -26,6 +31,7 @@ pub struct GameDerivedState<'a> {
impl GameCoreState {
pub async fn save_to_database(&self, client: &PrismaClient) -> Result<()> {
// Save star systems to database
let mut owned_systems = HashMap::new();
client
.star_system()
.create_many(
@ -33,6 +39,9 @@ impl GameCoreState {
.star_systems
.values()
.map(|star_system| {
if let Some(empire_id) = star_system.owned_by_empire_id {
owned_systems.insert(star_system.id, empire_id);
}
star_system::create_unchecked(
star_system.id.0,
self.universe_id.0,
@ -57,8 +66,8 @@ impl GameCoreState {
.map(|edge| {
star_system_edges::create_unchecked(
self.universe_id.0,
edge.0 as i32,
edge.1 as i32,
edge.0 .0 as i32,
edge.1 .0 as i32,
vec![],
)
})
@ -79,6 +88,7 @@ impl GameCoreState {
empire::create_unchecked(
self.universe_id.0,
empire.name.clone(),
format_color(empire.color),
vec![empire::id::set(empire.id.0)],
)
})
@ -88,6 +98,21 @@ impl GameCoreState {
.exec()
.await?;
// Update the ownership
for (star_system_id, empire_id) in owned_systems.into_iter() {
client
.star_system()
.update(
star_system::UniqueWhereParam::UniverseIdIndexEquals(
self.universe_id.0,
star_system_id.0,
),
vec![star_system::owned_by_empire_id::set(Some(empire_id.0))],
)
.exec()
.await?;
}
Ok(())
}
}

View file

@ -1,11 +1,14 @@
use super::EmpireId;
/// This is only guaranteed to be unique for a specific UniverseId
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StarSystemId(pub i32);
#[derive(Debug)]
pub struct StarSystemCoreState {
pub id: StarSystemId,
pub position: (f64, f64),
pub owned_by_empire_id: Option<EmpireId>,
}
pub struct StarSystemDerivedState {}

9
backend/src/utils.rs Normal file
View file

@ -0,0 +1,9 @@
use colourado::Color;
pub fn format_color(color: Color) -> String {
let red = (color.red * 255.0) as usize;
let green = (color.green * 255.0) as usize;
let blue = (color.blue * 255.0) as usize;
format!("{:02x}{:02x}{:02x}", red, green, blue)
}

View file

@ -1,6 +1,24 @@
import { Button, InputGroup, Menu, Popover } from "@blueprintjs/core";
import { Button, InputGroup, Menu, MenuItem, Popover } from "@blueprintjs/core";
import { useQuery } from "react-query";
import { useParams } from "react-router-dom";
import { useAppDispatch, useAppSelector } from "../store";
import { changeActiveEmpire } from "../store/someShit";
export default function EmpireSelector() {
const dispatch = useAppDispatch();
const { universeId } = useParams();
const { isLoading, data } = useQuery(
`universe ${universeId} empire list`,
() =>
fetch(`/api/universe/${universeId}/empires`).then((res) => res.json()),
);
const activeEmpireId = useAppSelector(
(state) => state.someShit.activeEmpireId,
);
if (isLoading) return <>...</>;
const empireMap = new Map(data.empires.map((empire) => [empire.id, empire]));
return (
<Popover
content={
@ -11,7 +29,14 @@ export default function EmpireSelector() {
placeholder="Search for empire..."
autoFocus
/>
...
{data.empires.map((empire) => (
<MenuItem
key={empire.id}
text={empire.name}
active={empire.id === activeEmpireId}
onClick={() => dispatch(changeActiveEmpire(empire.id))}
/>
))}
</Menu>
}
placement="bottom-end"
@ -20,7 +45,11 @@ export default function EmpireSelector() {
alignText="left"
icon="user"
rightIcon="caret-down"
text="(select empire)"
text={
activeEmpireId
? empireMap.get(activeEmpireId).name
: "(select empire)"
}
/>
</Popover>
);

View file

@ -4,20 +4,30 @@ import { Canvas, type MeshProps, useLoader } from "@react-three/fiber";
import styles from "./MapView.module.scss";
import { useParams } from "react-router-dom";
import { MapControls, Text } from "@react-three/drei";
import { DoubleSide, TextureLoader } from "three";
import { ColorRepresentation, DoubleSide, TextureLoader } from "three";
export default function MapView({}) {
const { universeId } = useParams();
const { isLoading, data } = useQuery(`universe ${universeId} points`, () =>
fetch(`/api/universe/${universeId}/map`).then((res) => res.json()),
const { isLoading, data: mapData } = useQuery(
`universe ${universeId} points`,
() => fetch(`/api/universe/${universeId}/map`).then((res) => res.json()),
);
const { isLoading: isEmpireLoading, data: empireData } = useQuery(
`universe ${universeId} empire list`,
() =>
fetch(`/api/universe/${universeId}/empires`).then((res) => res.json()),
);
const outerSpace = useLoader(
TextureLoader,
"https://s3-us-west-2.amazonaws.com/s.cdpn.io/96252/space.jpg",
);
if (isLoading) return <>...</>;
console.log("data", data);
if (isLoading || isEmpireLoading) return <>...</>;
console.log("data", empireData);
const empireMap = new Map(
empireData.empires.map((empire) => [empire.id, empire]),
);
return (
<main className={styles.main}>
@ -30,33 +40,49 @@ export default function MapView({}) {
<meshStandardMaterial map={outerSpace} side={DoubleSide} />
</mesh>
{data.points.map((point) => {
{mapData.points.map((point) => {
const x = point.coordX / 80;
const y = point.coordY / 80;
return (
<StarSystem key={point.index} system={point} position={[x, 0, y]} />
<StarSystem
key={point.index}
system={point}
empires={empireMap}
position={[x, 0, y]}
/>
);
})}
{data.edges.map((edge) => {
{mapData.edges.map((edge) => {
return (
<Hyperlane
key={`${edge.fromSystemId}:${edge.toSystemId}`}
edge={edge}
points={data.points}
points={mapData.points}
/>
);
})}
{/* {empireData.empires.map((empire) => {
return <EmpireMarker empire={empire} points={mapData.points} />;
})} */}
</Canvas>
</main>
);
}
function StarSystem({ system, position, ...props }: MeshProps) {
function StarSystem({ system, position, empires, ...props }: MeshProps) {
const meshRef = useRef();
const [hovered, setHover] = useState(false);
const [active, setActive] = useState(false);
let color: ColorRepresentation = "skyblue";
let owner;
if (system.ownedByEmpireId !== null) {
owner = empires.get(system.ownedByEmpireId);
color = parseInt(owner.color, 16);
}
return (
<mesh
{...props}
@ -69,17 +95,20 @@ function StarSystem({ system, position, ...props }: MeshProps) {
>
<sphereGeometry args={[0.05]} />
{owner && (
<Text
color="white"
fontSize={0.18}
// fontSize={0.18}
fontSize={0.48}
anchorX="center"
anchorY="middle"
position={[0, 0.1, 0]}
position={[0, 0.2, 0]}
>
{system.index}
{owner.name}
</Text>
)}
<meshStandardMaterial color={hovered ? "white" : "skyblue"} />
<meshStandardMaterial color={hovered ? "white" : color} />
</mesh>
);
}

View file

@ -1,10 +1,9 @@
import { createSlice } from "@reduxjs/toolkit";
import type { PayloadAction } from "@reduxjs/toolkit";
import type { RootState } from "../../app/store";
// Define a type for the slice state
interface SomeShitState {
activeEmpireId: string | null;
activeEmpireId: number | null;
}
// Define the initial state using that type
@ -13,27 +12,15 @@ const initialState: SomeShitState = {
};
export const someShitSlice = createSlice({
name: "counter",
// `createSlice` will infer the state type from the `initialState` argument
name: "someShit",
initialState,
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
// Use the PayloadAction type to declare the contents of `action.payload`
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload;
changeActiveEmpire: (state, action: PayloadAction<number>) => {
state.activeEmpireId = action.payload;
},
},
});
export const { increment, decrement, incrementByAmount } =
someShitSlice.actions;
// Other code such as selectors can use the imported `RootState` type
export const selectCount = (state: RootState) => state.counter.value;
export const { changeActiveEmpire } = someShitSlice.actions;
export default someShitSlice.reducer;

View file

@ -4,5 +4,13 @@ version = "0.1.0"
edition = "2021"
[dependencies]
prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust", tag = "0.6.10" }
prisma-client-rust-cli = { git = "https://github.com/Brendonovich/prisma-client-rust", tag = "0.6.10" }
[dependencies.prisma-client-rust]
git = "https://github.com/Brendonovich/prisma-client-rust"
tag = "0.6.10"
features = ["rspc"]
[dependencies.prisma-client-rust-cli]
git = "https://github.com/Brendonovich/prisma-client-rust"
tag = "0.6.10"
features = ["rspc"]

View file

@ -42,16 +42,23 @@ model Player {
}
model Empire {
id Int @id @default(autoincrement())
id Int @default(autoincrement())
universeId Int
universe Universe @relation(fields: [universeId], references: [id])
name String
color String?
color String
// capitalSystemId Int
// capitalSystem StarSystem @relation("capital", fields: [universeId, capitalSystemId], references: [universeId, index])
playerId String? @unique
player Player? @relation(fields: [playerId], references: [id])
starSystems StarSystem[] @relation("owner")
@@id([universeId, id])
}
model StarSystem {
@ -65,6 +72,9 @@ model StarSystem {
inbound StarSystemEdges[] @relation("inbound")
outbound StarSystemEdges[] @relation("outbound")
ownedByEmpireId Int?
ownedByEmpire Empire? @relation("owner", fields: [universeId, ownedByEmpireId], references: [universeId, id])
@@id([universeId, index])
}