mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
start working on RFC#11,
implement a regionmanager and basic region component as well as tests for those this is a fist implementation and likly to change Former-commit-id: fdb7097dc30ab1642d25a02532458bcc2811ab61
This commit is contained in:
parent
add74cd0ea
commit
1456497bd0
558
Cargo.lock
generated
558
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,7 @@ members = [
|
|||||||
"world",
|
"world",
|
||||||
"network",
|
"network",
|
||||||
"network/protocol",
|
"network/protocol",
|
||||||
|
"worldsim"
|
||||||
]
|
]
|
||||||
|
|
||||||
# default profile for devs, fast to compile, okay enough to run, no debug information
|
# default profile for devs, fast to compile, okay enough to run, no debug information
|
||||||
|
1
assets/voxygen/.gitignore
vendored
Normal file
1
assets/voxygen/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
tmp/
|
@ -28,6 +28,7 @@ common = { package = "veloren-common", path = "../common" }
|
|||||||
common-base = { package = "veloren-common-base", path = "../common/base" }
|
common-base = { package = "veloren-common-base", path = "../common/base" }
|
||||||
common-net = { package = "veloren-common-net", path = "../common/net" }
|
common-net = { package = "veloren-common-net", path = "../common/net" }
|
||||||
common-frontend = { package = "veloren-common-frontend", path = "../common/frontend" }
|
common-frontend = { package = "veloren-common-frontend", path = "../common/frontend" }
|
||||||
|
worldsim = { package = "veloren-worldsim", path = "../worldsim" }
|
||||||
|
|
||||||
tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] }
|
tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] }
|
||||||
num_cpus = "1.0"
|
num_cpus = "1.0"
|
||||||
|
@ -27,9 +27,17 @@ use std::{
|
|||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use tracing::{info, trace};
|
use tracing::{info, trace};
|
||||||
|
|
||||||
|
use worldsim::{
|
||||||
|
regionmanager::{RegionManager, meta::RegionManagerMsg},
|
||||||
|
server::meta::{ServerMsg},
|
||||||
|
job::JobManager,
|
||||||
|
region::Region,
|
||||||
|
};
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
pub static ref LOG: TuiLog<'static> = TuiLog::default();
|
pub static ref LOG: TuiLog<'static> = TuiLog::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
const TPS: u64 = 30;
|
const TPS: u64 = 30;
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
fn main() -> io::Result<()> {
|
||||||
@ -155,6 +163,18 @@ fn main() -> io::Result<()> {
|
|||||||
|
|
||||||
let server_port = &server_settings.gameserver_address.port();
|
let server_port = &server_settings.gameserver_address.port();
|
||||||
let metrics_port = &server_settings.metrics_address.port();
|
let metrics_port = &server_settings.metrics_address.port();
|
||||||
|
|
||||||
|
let (region_manager_tx, region_manager_rx) = mpsc::channel::<RegionManagerMsg>();
|
||||||
|
let (server_tx, server_rx) = mpsc::channel::<ServerMsg>();
|
||||||
|
|
||||||
|
let mut region_manager = RegionManager::new(region_manager_tx, server_rx);
|
||||||
|
let mut job_manager: Arc<JobManager> = Arc::new(JobManager::new());
|
||||||
|
let mut server = worldsim::server::Server::new(server_tx,region_manager_rx,job_manager.clone());
|
||||||
|
let mut region = Region::new((0,0),job_manager.clone());
|
||||||
|
|
||||||
|
job_manager.repeat(move || region_manager.work() );
|
||||||
|
job_manager.repeat(move || server.work() );
|
||||||
|
|
||||||
// Create server
|
// Create server
|
||||||
let mut server = Server::new(
|
let mut server = Server::new(
|
||||||
server_settings,
|
server_settings,
|
||||||
|
21
worldsim/Cargo.toml
Normal file
21
worldsim/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "veloren-worldsim"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Marcel Märtens <marcel.cochem@googlemail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sphynx = { git = "https://gitlab.com/veloren/sphynx.git", features = ["serde1"] }
|
||||||
|
|
||||||
|
specs = { version = "0.14", features = ["serde"] }
|
||||||
|
shred = { version = "0.7", features = ["nightly"] }
|
||||||
|
vek = { version = "0.9", features = ["serde"] }
|
||||||
|
dot_vox = "4.0"
|
||||||
|
threadpool = "1.7"
|
||||||
|
mio = "0.6"
|
||||||
|
mio-extras = "2.0"
|
||||||
|
serde = "1.0"
|
||||||
|
serde_derive = "1.0"
|
||||||
|
bincode = "1.0"
|
||||||
|
log = "0.4"
|
||||||
|
rand = "0.5"
|
22
worldsim/src/job/mod.rs
Normal file
22
worldsim/src/job/mod.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use std::thread;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
/*only have one JobManager per System because it bounds to all threads*/
|
||||||
|
pub struct JobManager {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JobManager{
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repeat<F>(&self, mut f: F) where F: FnMut() -> bool, F: Send + 'static {
|
||||||
|
let worker = thread::spawn(move || {
|
||||||
|
while f() {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
19
worldsim/src/lib.rs
Normal file
19
worldsim/src/lib.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#![feature(euclidean_division, duration_float, trait_alias, bind_by_move_pattern_guards)]
|
||||||
|
|
||||||
|
extern crate serde_derive;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
pub mod job;
|
||||||
|
pub mod regionmanager;
|
||||||
|
pub mod region;
|
||||||
|
pub mod server;
|
||||||
|
pub mod lodstore;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
assert_eq!(2 + 2, 4);
|
||||||
|
}
|
||||||
|
}
|
47
worldsim/src/lodstore/index.rs
Normal file
47
worldsim/src/lodstore/index.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
use vek::*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
For our LodStructures we need a type that covers the values from 0 - 2047 in steps of 1/32.
|
||||||
|
which is 11 bits for the digits before the decimal point and 5 bits for the digits after the decimal point.
|
||||||
|
Because for accessing the decimal point makes no difference we use a u16 to represent this value.
|
||||||
|
The value needs to be shiftet to get it's "real inworld size",
|
||||||
|
e.g. 1 represents 1/32
|
||||||
|
32 represents 1
|
||||||
|
65535 represents 2047 + 31/32
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub type LodIndex = Vec3<u16>;
|
||||||
|
|
||||||
|
pub fn to_lod_i(pos: Vec3<u16>) -> LodIndex {
|
||||||
|
pos.map(|x| x * 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*will round*/
|
||||||
|
pub fn to_lod_f(pos: Vec3<f32>) -> LodIndex {
|
||||||
|
pos.map(|x| (x * 32.0).round() as u16)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_pos_i(index: LodIndex) -> Vec3<u16> {
|
||||||
|
index.map(|x| x / 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_pos_f(index: LodIndex) -> Vec3<f32> {
|
||||||
|
index.map(|x| x as f32 / 32.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub const LEVEL_LENGTH_POW_MAX: i8 = 11;
|
||||||
|
pub const LEVEL_LENGTH_POW_MIN: i8 = -4;
|
||||||
|
|
||||||
|
pub const LEVEL_INDEX_POW_MAX: u8 = 15;
|
||||||
|
pub const LEVEL_INDEX_POW_MIN: u8 = 0;
|
||||||
|
|
||||||
|
pub const fn length_to_index(n: i8) -> u8 { (n+4) as u8 }
|
||||||
|
|
||||||
|
pub const fn two_pow_u(n: u8) -> u16 {
|
||||||
|
1 << n
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn two_pow_i(n: i8) -> f32 {
|
||||||
|
2.0_f32.powi(n as i32)
|
||||||
|
}
|
135
worldsim/src/lodstore/mod.rs
Normal file
135
worldsim/src/lodstore/mod.rs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
pub mod index;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use vek::*;
|
||||||
|
use index::{
|
||||||
|
LodIndex,
|
||||||
|
length_to_index,
|
||||||
|
two_pow_u,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Alternative impl idea:
|
||||||
|
1) Put LodLayer to a trait to give everyone the power to store it themself.
|
||||||
|
2) Put childs in up to 8 different VECs, and have a index in LogLayer, pointing to the fist childred in this supervector, and ge the length from E.
|
||||||
|
all access is only possible if the Owner sturcture is given
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct LodLayer<E> {
|
||||||
|
pub data: E,
|
||||||
|
pub childs: Vec<LodLayer<E>>, //Optimization potential: size_of<Vec> == 24 and last layer doesnt need Vec at all.
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Layer: Sized {
|
||||||
|
fn new() -> LodLayer<Self>;
|
||||||
|
|
||||||
|
fn get_level(layer: &LodLayer<Self>) -> i8;
|
||||||
|
fn get_lower_level(layer: &LodLayer<Self>) -> Option<i8>;
|
||||||
|
|
||||||
|
/*Drills down the layer and creates childs*/
|
||||||
|
fn drill_down(layer: &mut LodLayer<Self>);
|
||||||
|
|
||||||
|
/*needs to recalc parent values and remove childs*/
|
||||||
|
fn drill_up(parent: &mut LodLayer<Self>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> LodLayer<E> {
|
||||||
|
pub fn new_data(data: E) -> Self {
|
||||||
|
Self {
|
||||||
|
data,
|
||||||
|
childs: vec!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Layer> LodLayer<E> {
|
||||||
|
// gets the internal index on this layer from relative position
|
||||||
|
|
||||||
|
fn get_internal_index(&self, relative: LodIndex) -> Vec3<u16> {
|
||||||
|
let ll = length_to_index(E::get_lower_level(self).expect("your type is wrong configured!, configure Layer trait correctly"));
|
||||||
|
let length_per_children: u16 = two_pow_u(ll);
|
||||||
|
let child_index = relative.map(|i| (i / length_per_children));
|
||||||
|
return child_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_internal_index_and_remainder(&self, relative: LodIndex) -> (Vec3<u16>, LodIndex) {
|
||||||
|
let ll = length_to_index(E::get_lower_level(self).expect("your type is wrong configured!, configure Layer trait correctly"));
|
||||||
|
let length_per_children: u16 = two_pow_u(ll);
|
||||||
|
let child_index = relative.map(|i| (i / length_per_children));
|
||||||
|
let remainder_index = relative.map2(child_index, |i,c| (i - c * length_per_children));
|
||||||
|
return (child_index, remainder_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*flatten the (1,2,3) child to 1*4+2*4+3*3*4 = 48*/
|
||||||
|
fn get_flat_index(&self, internal_index: Vec3<u16>) -> usize {
|
||||||
|
let ll = E::get_lower_level(self).expect("your type is wrong configured!, configure Layer trait correctly");
|
||||||
|
let cl = E::get_level(self);
|
||||||
|
let childs_per_dimentsion = (cl - ll) as usize;
|
||||||
|
let index = internal_index.x as usize + internal_index.y as usize * childs_per_dimentsion + internal_index.z as usize * childs_per_dimentsion * childs_per_dimentsion;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
//index must be local to self
|
||||||
|
fn get(&self, relative: LodIndex) -> &LodLayer<E> {
|
||||||
|
// index is local for now
|
||||||
|
if self.childs.is_empty() {
|
||||||
|
return &self
|
||||||
|
} else {
|
||||||
|
let (int, rem) = self.get_internal_index_and_remainder(relative);
|
||||||
|
let index = self.get_flat_index(int);
|
||||||
|
&self.childs.get(index).unwrap().get(rem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
These functions allow you to make the LodLayer provide a certain LOD for the specified area
|
||||||
|
*/
|
||||||
|
/*is at least minimum or maximum*/
|
||||||
|
pub fn make_at_least(&mut self, lower: LodIndex, upper: LodIndex, level: i8) {
|
||||||
|
if E::get_level(self) <= level {
|
||||||
|
//println!("done");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let (li, lr) = self.get_internal_index_and_remainder(lower);
|
||||||
|
let (ui, ur) = self.get_internal_index_and_remainder(upper);
|
||||||
|
|
||||||
|
if self.childs.is_empty() {
|
||||||
|
E::drill_down(self);
|
||||||
|
//println!("dd");
|
||||||
|
}
|
||||||
|
let ll = length_to_index(E::get_lower_level(self).expect("your type is wrong configured!, configure Layer trait correctly"));
|
||||||
|
let length_per_children: u16 = two_pow_u(ll);
|
||||||
|
//println!("li {} lr {} ui {} ur {} length {}", li, lr, ui, ur, length_per_children);
|
||||||
|
if E::get_lower_level(self).unwrap() <= level {
|
||||||
|
//println!("done");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for z in li.z..ui.z+1 {
|
||||||
|
for y in li.y..ui.y+1 {
|
||||||
|
for x in li.x..ui.x+1 {
|
||||||
|
//recursive call make_at_least
|
||||||
|
let mut new_lower = LodIndex::new(0,0,0);
|
||||||
|
let mut new_upper = LodIndex::new(length_per_children-1,length_per_children-1,length_per_children-1);
|
||||||
|
if x == li.x { new_lower.x = lr.x; }
|
||||||
|
if y == li.y { new_lower.y = lr.y; }
|
||||||
|
if z == li.z { new_lower.z = lr.z; }
|
||||||
|
if x == ui.x { new_upper.x = ur.x; }
|
||||||
|
if y == ui.y { new_upper.y = ur.y; }
|
||||||
|
if z == ui.z { new_upper.z = ur.z; }
|
||||||
|
let index = self.get_flat_index(LodIndex::new(x,y,z));
|
||||||
|
//println!("lo {} up {} layer {} inr {} in {}, vec {}", new_lower, new_upper, E::get_level(self), LodIndex::new(x,y,z), index, self.childs.len());
|
||||||
|
self.childs[index].make_at_least( new_lower, new_upper, level );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn make_at_most(&mut self, lower: LodIndex, upper: LodIndex, level: i8) {
|
||||||
|
|
||||||
|
}
|
||||||
|
fn make_exactly(&mut self, lower: LodIndex, upper: LodIndex, level: i8) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1
worldsim/src/region/lod/mod.rs
Normal file
1
worldsim/src/region/lod/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod terrain;
|
144
worldsim/src/region/lod/terrain.rs
Normal file
144
worldsim/src/region/lod/terrain.rs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
use crate::lodstore::Layer;
|
||||||
|
use crate::lodstore::LodLayer;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Terrain {
|
||||||
|
// 11 is max
|
||||||
|
Unused11,
|
||||||
|
Region9 { //512m this is for normal simulation if no player nearby
|
||||||
|
precent_air: f32,
|
||||||
|
percent_forrest: f32,
|
||||||
|
percent_lava: f32,
|
||||||
|
percent_water: f32,
|
||||||
|
},
|
||||||
|
Chunk5 {//32m, same detail as region, but to not force block1 everywhere in 512 area
|
||||||
|
precent_air: f32,
|
||||||
|
percent_forrest: f32,
|
||||||
|
percent_lava: f32,
|
||||||
|
percent_water: f32,
|
||||||
|
},
|
||||||
|
Block1 {
|
||||||
|
material: u32,
|
||||||
|
},
|
||||||
|
SubBlock_4 {
|
||||||
|
material: u32,
|
||||||
|
},
|
||||||
|
// -4 is min
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Terrain {
|
||||||
|
fn new() -> Self {
|
||||||
|
Terrain::Unused11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const LAYER5: i8 = 11;
|
||||||
|
const LAYER4: i8 = 9;
|
||||||
|
const LAYER3: i8 = 5;
|
||||||
|
const LAYER2: i8 = 0;
|
||||||
|
const LAYER1: i8 = -4;
|
||||||
|
|
||||||
|
|
||||||
|
impl Layer for Terrain {
|
||||||
|
fn new() -> LodLayer<Terrain> {
|
||||||
|
let mut n = LodLayer::<Terrain>::new_data(Terrain::Unused11);
|
||||||
|
Self::drill_down(&mut n);
|
||||||
|
n
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_level(layer: &LodLayer<Self>) -> i8 {
|
||||||
|
match &layer.data {
|
||||||
|
Terrain::Unused11 => LAYER5,
|
||||||
|
Terrain::Region9{..} => LAYER4,
|
||||||
|
Terrain::Chunk5{..} => LAYER3,
|
||||||
|
Terrain::Block1{..} => LAYER2,
|
||||||
|
Terrain::SubBlock_4{..} => -LAYER1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_lower_level(layer: &LodLayer<Self>) -> Option<i8> {
|
||||||
|
match &layer.data {
|
||||||
|
Terrain::Unused11 => Some(LAYER4),
|
||||||
|
Terrain::Region9{..} => Some(LAYER3),
|
||||||
|
Terrain::Chunk5{..} => Some(LAYER2),
|
||||||
|
Terrain::Block1{..} => Some(LAYER1),
|
||||||
|
Terrain::SubBlock_4{..} => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drill_down(layer: &mut LodLayer<Terrain>) {
|
||||||
|
match &layer.data {
|
||||||
|
Terrain::Unused11 => {
|
||||||
|
let n = LodLayer::new_data(Terrain::Region9{
|
||||||
|
precent_air: 1.0,
|
||||||
|
percent_forrest: 0.0,
|
||||||
|
percent_lava: 0.0,
|
||||||
|
percent_water: 0.0,
|
||||||
|
});
|
||||||
|
layer.childs = vec![n; 2_usize.pow((LAYER5-LAYER4) as u32 *3)];
|
||||||
|
},
|
||||||
|
Terrain::Region9{..} => {
|
||||||
|
let n = LodLayer::new_data(Terrain::Chunk5{
|
||||||
|
precent_air: 1.0,
|
||||||
|
percent_forrest: 0.0,
|
||||||
|
percent_lava: 0.0,
|
||||||
|
percent_water: 0.0,
|
||||||
|
});
|
||||||
|
layer.childs = vec![n; 2_usize.pow((LAYER4-LAYER3) as u32 *3)];
|
||||||
|
},
|
||||||
|
Terrain::Chunk5{..} => {
|
||||||
|
let n = LodLayer::new_data( Terrain::Block1{
|
||||||
|
material: 10,
|
||||||
|
});
|
||||||
|
layer.childs = vec![n; 2_usize.pow((LAYER3-LAYER2) as u32 *3)];
|
||||||
|
},
|
||||||
|
Terrain::Block1{..} => {
|
||||||
|
let n = LodLayer::new_data( Terrain::SubBlock_4{
|
||||||
|
material: 10,
|
||||||
|
});
|
||||||
|
layer.childs = vec![n; 2_usize.pow((LAYER2-LAYER1) as u32 *3)];
|
||||||
|
},
|
||||||
|
Terrain::SubBlock_4{..} => {
|
||||||
|
panic!("cannot drillDown further")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn drill_up(parent: &mut LodLayer<Terrain>) {
|
||||||
|
match &parent.data {
|
||||||
|
Terrain::Unused11 => {
|
||||||
|
panic!("cannot drillUp further")
|
||||||
|
},
|
||||||
|
Terrain::Region9{..} => {
|
||||||
|
//recalculate values here
|
||||||
|
parent.data = Terrain::Region9{
|
||||||
|
precent_air: 1.0,
|
||||||
|
percent_forrest: 0.0,
|
||||||
|
percent_lava: 0.0,
|
||||||
|
percent_water: 0.0,
|
||||||
|
};
|
||||||
|
parent.childs = vec![];
|
||||||
|
},
|
||||||
|
Terrain::Chunk5{..} => {
|
||||||
|
parent.data = Terrain::Chunk5{
|
||||||
|
precent_air: 1.0,
|
||||||
|
percent_forrest: 0.0,
|
||||||
|
percent_lava: 0.0,
|
||||||
|
percent_water: 0.0,
|
||||||
|
};
|
||||||
|
parent.childs = vec![];
|
||||||
|
},
|
||||||
|
Terrain::Block1{..} => {
|
||||||
|
parent.data = Terrain::Block1{
|
||||||
|
material: 10,
|
||||||
|
};
|
||||||
|
parent.childs = vec![];
|
||||||
|
},
|
||||||
|
Terrain::SubBlock_4{..} => {
|
||||||
|
parent.data = Terrain::SubBlock_4{
|
||||||
|
material: 10,
|
||||||
|
};
|
||||||
|
parent.childs = vec![];
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
worldsim/src/region/meta.rs
Normal file
14
worldsim/src/region/meta.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use crate::regionmanager::meta::RegionId;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct RegionMeta {
|
||||||
|
id: RegionId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegionMeta {
|
||||||
|
pub fn new(id: RegionId) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
worldsim/src/region/mod.rs
Normal file
87
worldsim/src/region/mod.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
pub mod meta;
|
||||||
|
mod lod;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
regionmanager::meta::RegionId,
|
||||||
|
job::JobManager,
|
||||||
|
lodstore::LodLayer,
|
||||||
|
lodstore::Layer,
|
||||||
|
};
|
||||||
|
use lod::terrain::Terrain;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Region {
|
||||||
|
id: RegionId,
|
||||||
|
jobmanager: Arc<JobManager>,
|
||||||
|
|
||||||
|
pub block: LodLayer<Terrain>,
|
||||||
|
temp: LodLayer<Terrain>,
|
||||||
|
light: LodLayer<Terrain>,
|
||||||
|
evil: LodLayer<Terrain>,
|
||||||
|
civ: LodLayer<Terrain>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Region {
|
||||||
|
pub fn new(id: RegionId, jobmanager: Arc<JobManager>) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
jobmanager,
|
||||||
|
block: Terrain::new(),
|
||||||
|
temp: Terrain::new(),
|
||||||
|
light: Terrain::new(),
|
||||||
|
evil: Terrain::new(),
|
||||||
|
civ: Terrain::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
pub type aaa = LodLayer<e::Terain>;
|
||||||
|
|
||||||
|
fn example() {
|
||||||
|
let own = e::Terain::new();
|
||||||
|
let t8 = own.get(Vec3::new(1,1,1));
|
||||||
|
//let tn = own.get2((1,2,3))
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{
|
||||||
|
regionmanager::meta::RegionId,
|
||||||
|
job::JobManager,
|
||||||
|
lodstore::LodLayer,
|
||||||
|
lodstore::Layer,
|
||||||
|
region::lod::terrain::Terrain,
|
||||||
|
region::Region,
|
||||||
|
};
|
||||||
|
use vek::*;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::{thread, time};
|
||||||
|
/*
|
||||||
|
#[test]
|
||||||
|
fn createRegion() {
|
||||||
|
let mut r = Region::new((0,0), Arc::new(JobManager::new()));
|
||||||
|
r.block.make_at_least(Vec3::new(0,0,0), Vec3::new(65535,65535,65535), 9);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn createRegionToBlock() {
|
||||||
|
// one region fully blown needs around 80 GB, 1/8 of a region needs 10GB for full block level
|
||||||
|
let mut r = Region::new((0,0), Arc::new(JobManager::new()));
|
||||||
|
r.block.make_at_least(Vec3::new(0,0,0), Vec3::new(65535/2,65535/2,65535/2), 0);
|
||||||
|
r.block.make_at_least(Vec3::new(0,0,0), Vec3::new(65535/2,65535/2,65535/2), 0);
|
||||||
|
|
||||||
|
thread::sleep(time::Duration::from_secs(100));
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
#[test]
|
||||||
|
fn createRegionToSubBlock() {
|
||||||
|
let mut r = Region::new((0,0), Arc::new(JobManager::new()));
|
||||||
|
r.block.make_at_least(Vec3::new(0,0,0), Vec3::new(65535,65535,65535), -4);
|
||||||
|
}*/
|
||||||
|
}
|
43
worldsim/src/regionmanager/meta.rs
Normal file
43
worldsim/src/regionmanager/meta.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Server {
|
||||||
|
connection_details: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Server {
|
||||||
|
pub fn new(connection_details: String) -> Self {
|
||||||
|
Self {
|
||||||
|
connection_details,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum RegionManagerMsg {
|
||||||
|
Attached{server_id: u64, seed: u64},
|
||||||
|
NewServerInMesh{server_id: u64, server_connection_details: ()},
|
||||||
|
CreateRegion{region_id: RegionId},
|
||||||
|
TakeOverRegionFrom{region_id: RegionId, server_id: u64},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type RegionIdSize = i8;
|
||||||
|
pub type RegionId = (/*x*/RegionIdSize, /*y*/RegionIdSize /*z = 0*/);
|
||||||
|
|
||||||
|
pub const RegionMIN:i8 = -64;
|
||||||
|
pub const RegionMAX:i8 = 63;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Region {
|
||||||
|
pub tick_time: Duration,
|
||||||
|
pub server_id: Option<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Region {
|
||||||
|
pub fn new(server_id: Option<u8>) -> Self {
|
||||||
|
Self {
|
||||||
|
tick_time: Duration::from_millis(0),
|
||||||
|
server_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
worldsim/src/regionmanager/mod.rs
Normal file
100
worldsim/src/regionmanager/mod.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
pub mod meta;
|
||||||
|
use std::sync::{
|
||||||
|
Arc,
|
||||||
|
mpsc,
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
};
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::time::Duration;
|
||||||
|
use crate::{
|
||||||
|
regionmanager::meta::{
|
||||||
|
Server, Region, RegionId, RegionManagerMsg, RegionMIN, RegionMAX,
|
||||||
|
},
|
||||||
|
server::meta::{
|
||||||
|
ServerMsg,
|
||||||
|
},
|
||||||
|
job::JobManager,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RegionManager {
|
||||||
|
tx: mpsc::Sender<RegionManagerMsg>,
|
||||||
|
rx: mpsc::Receiver<ServerMsg>,
|
||||||
|
running: Arc<AtomicBool>,
|
||||||
|
servers: Vec<Server>,
|
||||||
|
regions: HashMap<RegionId, Region>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegionManager{
|
||||||
|
pub fn new(tx: mpsc::Sender<RegionManagerMsg>, rx: mpsc::Receiver<ServerMsg>) -> Self {
|
||||||
|
|
||||||
|
let running = Arc::new(AtomicBool::new(true));
|
||||||
|
|
||||||
|
let mut servers = vec!();
|
||||||
|
let mut regions = HashMap::new();
|
||||||
|
|
||||||
|
for x in RegionMIN..RegionMAX {
|
||||||
|
for y in RegionMIN..RegionMAX {
|
||||||
|
regions.insert((x,y), Region::new(None));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
tx,
|
||||||
|
rx,
|
||||||
|
running,
|
||||||
|
servers,
|
||||||
|
regions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rearange(&mut self) {
|
||||||
|
//This is a super intelligent algorithm which says which chunks should be handled by which server
|
||||||
|
//It is widely important, that it causes as minimal shifting as necessary
|
||||||
|
|
||||||
|
//.... fell f*** it for now
|
||||||
|
for x in RegionMIN..RegionMAX {
|
||||||
|
for y in RegionMIN..RegionMAX {
|
||||||
|
if !self.servers.is_empty() {
|
||||||
|
let old = self.regions.get(&(x,y)).unwrap().server_id;
|
||||||
|
|
||||||
|
self.regions.get_mut(&(x,y)).unwrap().server_id = Some(((x as usize) % self.servers.len()) as u8);
|
||||||
|
if let Some(id) = old {
|
||||||
|
self.tx.send(RegionManagerMsg::TakeOverRegionFrom{region_id: (x,y), server_id: id as u64});
|
||||||
|
} else {
|
||||||
|
self.tx.send(RegionManagerMsg::CreateRegion{region_id: (x,y)});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.regions.get_mut(&(x,y)).unwrap().server_id = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn work(
|
||||||
|
&mut self,
|
||||||
|
//jm: &JobManager,
|
||||||
|
) -> bool {
|
||||||
|
match self.rx.try_recv() {
|
||||||
|
Ok(msg) => {
|
||||||
|
match msg {
|
||||||
|
ServerMsg::Attach() => {
|
||||||
|
//ERROR i cannot acceess self here ...
|
||||||
|
self.servers.push(Server::new("Hello".to_string()) );
|
||||||
|
self.tx.send(RegionManagerMsg::Attached{server_id: self.servers.len() as u64 , seed: 1337});
|
||||||
|
error!("yay");
|
||||||
|
println!("attached");
|
||||||
|
self.rearange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
//panic!("Work error {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(Duration::from_millis(10));
|
||||||
|
self.running.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
10
worldsim/src/server/meta.rs
Normal file
10
worldsim/src/server/meta.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum ServerMsg {
|
||||||
|
Attach(),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type RegionIdSize = i8;
|
||||||
|
pub type RegionId = (/*x*/RegionIdSize, /*y*/RegionIdSize /*z = 0*/);
|
||||||
|
|
||||||
|
pub const RegionMIN:i8 = -64;
|
||||||
|
pub const RegionMAX:i8 = 63;
|
94
worldsim/src/server/mod.rs
Normal file
94
worldsim/src/server/mod.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
pub mod meta;
|
||||||
|
use std::sync::{
|
||||||
|
mpsc,
|
||||||
|
Arc,
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
};
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
job::JobManager,
|
||||||
|
regionmanager::meta::RegionManagerMsg,
|
||||||
|
region::Region,
|
||||||
|
server::meta::RegionId,
|
||||||
|
server::meta::ServerMsg,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
one server per physical host
|
||||||
|
*/
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Server {
|
||||||
|
tx: mpsc::Sender<ServerMsg>,
|
||||||
|
rx: mpsc::Receiver<RegionManagerMsg>,
|
||||||
|
running: Arc<AtomicBool>,
|
||||||
|
id: Option<u64>,
|
||||||
|
seed: Option<u64>,
|
||||||
|
state: u64,
|
||||||
|
jobmanager: Arc<JobManager>,
|
||||||
|
region: HashMap<RegionId,Region>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Server {
|
||||||
|
pub fn new(tx: mpsc::Sender<ServerMsg>, rx: mpsc::Receiver<RegionManagerMsg>, jobmanager: Arc<JobManager>) -> Self {
|
||||||
|
let running = Arc::new(AtomicBool::new(true));
|
||||||
|
|
||||||
|
Self {
|
||||||
|
tx,
|
||||||
|
rx,
|
||||||
|
running,
|
||||||
|
id: None,
|
||||||
|
seed: None,
|
||||||
|
state: 0,
|
||||||
|
jobmanager: jobmanager.clone(),
|
||||||
|
region: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn work(
|
||||||
|
&mut self,
|
||||||
|
//jm: &JobManager,
|
||||||
|
) -> bool {
|
||||||
|
match self.state {
|
||||||
|
0 => {
|
||||||
|
self.tx.send(ServerMsg::Attach());
|
||||||
|
self.state += 1;
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.rx.try_recv() {
|
||||||
|
Ok(msg) => {
|
||||||
|
match msg {
|
||||||
|
RegionManagerMsg::Attached{server_id, seed} => {
|
||||||
|
self.id = Some(server_id);
|
||||||
|
self.seed = Some(seed);
|
||||||
|
},
|
||||||
|
RegionManagerMsg::NewServerInMesh{server_id, server_connection_details} => {
|
||||||
|
println!("new server found");
|
||||||
|
},
|
||||||
|
RegionManagerMsg::CreateRegion{region_id} => {
|
||||||
|
let mut r = Region::new(region_id, self.jobmanager.clone());
|
||||||
|
r.block.make_at_least(Vec3::new(0,0,0), Vec3::new(65535,65535,65535), 9);
|
||||||
|
self.region.insert(region_id, r);
|
||||||
|
println!("create region");
|
||||||
|
},
|
||||||
|
RegionManagerMsg::TakeOverRegionFrom{region_id, server_id} => {
|
||||||
|
println!("new server in mesh");
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
//panic!("Work error {:?}", e);
|
||||||
|
sleep(Duration::from_millis(10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
self.running.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user