summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock187
-rw-r--r--Cargo.toml2
-rw-r--r--a.md4
-rw-r--r--network/src/lib.rs2
-rw-r--r--server/Cargo.toml5
-rw-r--r--server/src/main.rs129
-rw-r--r--shared/Cargo.lock (renamed from network/Cargo.lock)0
-rw-r--r--shared/Cargo.toml (renamed from network/Cargo.toml)3
-rw-r--r--shared/src/lib.rs4
-rw-r--r--shared/src/packets.rs (renamed from network/src/packets.rs)17
-rw-r--r--shared/src/store.rs33
-rw-r--r--shared/src/tree.rs70
12 files changed, 434 insertions, 22 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 58e5aff..4f78eb0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -34,6 +34,55 @@ dependencies = [
]
[[package]]
+name = "anstream"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
name = "anyhow"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -159,6 +208,52 @@ dependencies = [
]
[[package]]
+name = "clap"
+version = "4.5.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+
+[[package]]
name = "combine"
version = "4.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -230,6 +325,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
+name = "env_filter"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
+dependencies = [
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "env_filter",
+ "humantime",
+ "log",
+]
+
+[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -257,6 +375,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
name = "indexmap"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -267,6 +397,12 @@ dependencies = [
]
[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -502,6 +638,15 @@ dependencies = [
]
[[package]]
+name = "redb"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea0a72cd7140de9fc3e318823b883abf819c20d478ec89ce880466dc2ef263c6"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -570,6 +715,11 @@ name = "server"
version = "0.1.0"
dependencies = [
"anyhow",
+ "clap",
+ "env_logger",
+ "log",
+ "weareshared",
+ "xdg",
]
[[package]]
@@ -579,6 +729,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
name = "syn"
version = "2.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -633,15 +789,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
-name = "vrding"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "audiopus",
- "bincode",
- "cpal",
- "glam",
-]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "walkdir"
@@ -721,6 +872,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
[[package]]
+name = "weareshared"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "audiopus",
+ "bincode",
+ "cpal",
+ "glam",
+ "redb",
+]
+
+[[package]]
name = "web-sys"
version = "0.3.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -915,3 +1078,9 @@ checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980"
dependencies = [
"memchr",
]
+
+[[package]]
+name = "xdg"
+version = "2.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546"
diff --git a/Cargo.toml b/Cargo.toml
index af54789..8635706 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,3 +1,3 @@
[workspace]
-members = ["network", "server"]
+members = ["shared", "server"]
resolver = "3"
diff --git a/a.md b/a.md
index eeb13a9..ddc3601 100644
--- a/a.md
+++ b/a.md
@@ -7,7 +7,7 @@ type Res = u128
02 respond_resource(name: Res, data: Vec<u8>)
03 add(id: Obj, prefab: Res)
04 remove(id: Obj)
-05 position(id: Obj, pos: Vec3)
+05 position(id: Obj, pos: Vec3, rot: Vec3)
06 pose(id: Obj, params: Vec<f32>)
07 parent(parent: Obj, child: Obj)
08 sound(id: Obj, data: Vec<u8>)
@@ -38,7 +38,7 @@ type Part = {
### Mesh
```
-[vertex count:u32] [index count:u32] ([x:f32] [y:f32] [z:f32] [u:f32] [v:f32])* ([n:u32])*
+[vertex count:u16] [index count:u16] ([x:f32] [y:f32] [z:f32] [u:f32] [v:f32])* ([n:u16])*
```
### Texture
diff --git a/network/src/lib.rs b/network/src/lib.rs
deleted file mode 100644
index d13c81d..0000000
--- a/network/src/lib.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-
-pub mod packets;
diff --git a/server/Cargo.toml b/server/Cargo.toml
index a504e65..3a091bd 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -5,3 +5,8 @@ edition = "2024"
[dependencies]
anyhow = "1.0.95"
+clap = { version = "4.5.23", features = ["derive"] }
+env_logger = "0.11.6"
+log = "0.4.22"
+weareshared = { path = "../shared" }
+xdg = "2.5.2"
diff --git a/server/src/main.rs b/server/src/main.rs
index e7a11a9..02ea03f 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -1,3 +1,128 @@
-fn main() {
- println!("Hello, world!");
+use anyhow::Result;
+use clap::Parser;
+use log::{debug, info};
+use std::{
+ collections::HashMap,
+ io::{BufReader, BufWriter},
+ net::{IpAddr, TcpListener, TcpStream},
+ sync::{
+ Arc, Mutex,
+ mpsc::{Receiver, Sender, channel},
+ },
+ thread::spawn,
+};
+use weareshared::{packets::Packet, store::ResourceStore, tree::SceneTree};
+
+#[derive(Parser, Debug)]
+struct Args {
+ #[arg(short, long, default_value = "::0")]
+ bind_addr: IpAddr,
+ #[arg(short, long, default_value = "28555")]
+ port: u16,
+}
+
+struct State {
+ tx: HashMap<usize, Sender<Packet>>,
+ store: ResourceStore,
+ tree: SceneTree,
+}
+
+fn main() -> Result<()> {
+ env_logger::init_from_env("LOG");
+ let args = Args::parse();
+
+ let listener = TcpListener::bind((args.bind_addr, args.port))?;
+ info!("bound to {}", listener.local_addr()?);
+ let state = Arc::new(Mutex::new(State::new()?));
+ for conn in 0.. {
+ let (sock, addr) = listener.accept()?;
+ info!("{addr} connected");
+ let (tx, rx) = channel();
+ state.lock().unwrap().tx.insert(conn, tx);
+ let state2 = state.clone();
+ let sock2 = sock.try_clone().unwrap();
+ spawn(move || {
+ let _ = handle_conn_read(conn, sock, state2.clone());
+ info!("{addr} disconnected");
+ state2.lock().unwrap().tx.remove(&conn);
+ });
+ spawn(move || {
+ let _ = handle_conn_write(conn, sock2, rx);
+ });
+ }
+ Ok(())
+}
+
+fn handle_conn_read(conn: usize, sock: TcpStream, state: Arc<Mutex<State>>) -> Result<()> {
+ let mut sock = BufReader::new(sock);
+ loop {
+ let packet = Packet::deserialize(&mut sock)?;
+ debug!("{conn} <- {packet:?}");
+ state.lock().unwrap().handle_packet(conn, packet)?;
+ }
+}
+fn handle_conn_write(conn: usize, sock: TcpStream, rx: Receiver<Packet>) -> Result<()> {
+ let mut sock = BufWriter::new(sock);
+ for packet in rx {
+ debug!("{conn} -> {packet:?}");
+ packet.serialize(&mut sock)?;
+ }
+ Ok(())
+}
+impl State {
+ pub fn new() -> Result<Self> {
+ Ok(Self {
+ tx: HashMap::new(),
+ store: ResourceStore::new(
+ &xdg::BaseDirectories::with_prefix("weareserver")?.place_cache_file("resources")?,
+ )?,
+ tree: SceneTree::default(),
+ })
+ }
+ pub fn broadcast(&self, packet: Packet) -> Result<()> {
+ for tx in self.tx.values() {
+ tx.send(packet.clone())?;
+ }
+ Ok(())
+ }
+ pub fn send(&self, conn: usize, packet: Packet) -> Result<()> {
+ if let Some(tx) = self.tx.get(&conn) {
+ tx.send(packet)?;
+ }
+ Ok(())
+ }
+ pub fn handle_packet(&mut self, conn: usize, packet: Packet) -> Result<()> {
+ self.tree.update(&packet);
+ match packet {
+ Packet::RequestResource(resource) => {
+ if let Some(r) = self.store.get(resource)? {
+ self.send(conn, Packet::RespondResource(resource, r))?;
+ } else {
+ self.broadcast(Packet::RequestResource(resource))?;
+ }
+ }
+ Packet::RespondResource(resource, vec) => {
+ self.broadcast(Packet::RespondResource(resource, vec))?;
+ }
+ Packet::Add(object, resource) => {
+ self.broadcast(Packet::Add(object, resource))?;
+ }
+ Packet::Remove(object) => {
+ self.broadcast(Packet::Remove(object))?;
+ }
+ Packet::Position(object, pos, rot) => {
+ self.broadcast(Packet::Position(object, pos, rot))?;
+ }
+ Packet::Pose(object, vec) => {
+ self.broadcast(Packet::Pose(object, vec))?;
+ }
+ Packet::Parent(parent, child) => {
+ self.broadcast(Packet::Parent(parent, child))?;
+ }
+ Packet::Sound(object, vec) => {
+ self.broadcast(Packet::Sound(object, vec))?;
+ }
+ }
+ Ok(())
+ }
}
diff --git a/network/Cargo.lock b/shared/Cargo.lock
index 8e3c9b7..8e3c9b7 100644
--- a/network/Cargo.lock
+++ b/shared/Cargo.lock
diff --git a/network/Cargo.toml b/shared/Cargo.toml
index 2f6c8fa..9236576 100644
--- a/network/Cargo.toml
+++ b/shared/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "vrding"
+name = "weareshared"
version = "0.1.0"
edition = "2024"
@@ -9,3 +9,4 @@ audiopus = "0.2.0"
bincode = "1.3.3"
cpal = "0.15.3"
glam = { version = "0.29.2", features = ["serde"] }
+redb = "2.4.0"
diff --git a/shared/src/lib.rs b/shared/src/lib.rs
new file mode 100644
index 0000000..a692a82
--- /dev/null
+++ b/shared/src/lib.rs
@@ -0,0 +1,4 @@
+
+pub mod packets;
+pub mod store;
+pub mod tree;
diff --git a/network/src/packets.rs b/shared/src/packets.rs
index 03c7270..79dd1ea 100644
--- a/network/src/packets.rs
+++ b/shared/src/packets.rs
@@ -2,15 +2,18 @@ use anyhow::{Result, bail};
use glam::Vec3;
use std::io::{Read, Write};
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Resource(pub u128);
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Object(pub u128);
+#[derive(Debug, Clone)]
pub enum Packet {
RequestResource(Resource),
RespondResource(Resource, Vec<u8>),
Add(Object, Resource),
Remove(Object),
- Position(Object, Vec3),
+ Position(Object, Vec3, Vec3),
Pose(Object, Vec<f32>),
Parent(Object, Object),
Sound(Object, Vec<u8>),
@@ -38,12 +41,15 @@ impl Packet {
w.write_all(&[0x04])?;
w.write_all(&object.0.to_be_bytes())?;
}
- Packet::Position(object, vec3) => {
+ Packet::Position(object, pos, rot) => {
w.write_all(&[0x05])?;
w.write_all(&object.0.to_be_bytes())?;
- w.write_all(&vec3.x.to_be_bytes())?;
- w.write_all(&vec3.y.to_be_bytes())?;
- w.write_all(&vec3.z.to_be_bytes())?;
+ w.write_all(&pos.x.to_be_bytes())?;
+ w.write_all(&pos.y.to_be_bytes())?;
+ w.write_all(&pos.z.to_be_bytes())?;
+ w.write_all(&rot.x.to_be_bytes())?;
+ w.write_all(&rot.y.to_be_bytes())?;
+ w.write_all(&rot.z.to_be_bytes())?;
}
Packet::Pose(object, vec) => {
w.write_all(&[0x06])?;
@@ -74,6 +80,7 @@ impl Packet {
0x05 => Packet::Position(
Object(read_u128(r)?),
Vec3::new(read_float(r)?, read_float(r)?, read_float(r)?),
+ Vec3::new(read_float(r)?, read_float(r)?, read_float(r)?),
),
0x06 => Packet::Pose(Object(read_u128(r)?), read_params(r)?),
0x07 => Packet::Parent(Object(read_u128(r)?), Object(read_u128(r)?)),
diff --git a/shared/src/store.rs b/shared/src/store.rs
new file mode 100644
index 0000000..83f1a25
--- /dev/null
+++ b/shared/src/store.rs
@@ -0,0 +1,33 @@
+use crate::packets::Resource;
+use anyhow::Result;
+use redb::{Database, TableDefinition};
+use std::path::Path;
+
+const T_ENTRIES: TableDefinition<u128, &[u8]> = TableDefinition::new("e");
+
+pub struct ResourceStore {
+ db: Database,
+}
+impl ResourceStore {
+ pub fn new(path: &Path) -> Result<Self> {
+ Ok(Self {
+ db: Database::create(path)?,
+ })
+ }
+ pub fn get(&self, key: Resource) -> Result<Option<Vec<u8>>> {
+ let txn = self.db.begin_read()?;
+ let ent = txn.open_table(T_ENTRIES)?;
+ match ent.get(key.0)? {
+ Some(x) => Ok(Some(x.value().to_vec())),
+ None => Ok(None),
+ }
+ }
+ pub fn set(&self, key: Resource, value: &[u8]) -> Result<()> {
+ let txn = self.db.begin_write()?;
+ let mut ent = txn.open_table(T_ENTRIES)?;
+ ent.insert(key.0, value)?;
+ drop(ent);
+ txn.commit()?;
+ Ok(())
+ }
+}
diff --git a/shared/src/tree.rs b/shared/src/tree.rs
new file mode 100644
index 0000000..fce6f8a
--- /dev/null
+++ b/shared/src/tree.rs
@@ -0,0 +1,70 @@
+use crate::packets::{Object, Packet, Resource};
+use glam::Vec3;
+use std::collections::HashMap;
+
+pub struct SceneTree {
+ objects: HashMap<Object, ObjectData>,
+}
+struct ObjectData {
+ pos: Vec3,
+ rot: Vec3,
+ parent: Object,
+ pose: Vec<f32>,
+ res: Resource,
+}
+impl Default for SceneTree {
+ fn default() -> Self {
+ Self {
+ objects: Default::default(),
+ }
+ }
+}
+impl SceneTree {
+ pub fn update(&mut self, p: &Packet) {
+ match p {
+ Packet::Add(object, res) => {
+ self.objects.insert(*object, ObjectData {
+ parent: Object(0),
+ pos: Vec3::ZERO,
+ rot: Vec3::ZERO,
+ pose: Vec::new(),
+ res: *res,
+ });
+ }
+ Packet::Remove(object) => {
+ self.objects.remove(&object);
+ }
+ Packet::Position(object, pos, rot) => {
+ if let Some(o) = self.objects.get_mut(&object) {
+ o.pos = *pos;
+ o.rot = *rot;
+ }
+ }
+ Packet::Pose(object, pose) => {
+ if let Some(o) = self.objects.get_mut(&object) {
+ o.pose = pose.to_vec();
+ }
+ }
+ Packet::Parent(parent, child) => {
+ if let Some(o) = self.objects.get_mut(&parent) {
+ o.parent = *child
+ }
+ }
+ _ => (),
+ }
+ }
+
+ pub fn prime_client(&self) -> impl Iterator<Item = Packet> {
+ self.objects
+ .iter()
+ .map(|(object, data)| {
+ [
+ Packet::Add(*object, data.res),
+ Packet::Parent(*object, data.parent),
+ Packet::Position(*object, data.pos, data.rot),
+ Packet::Pose(*object, data.pose.clone()),
+ ]
+ })
+ .flatten()
+ }
+}