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",
|
||||
"network",
|
||||
"network/protocol",
|
||||
"worldsim"
|
||||
]
|
||||
|
||||
# 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-net = { package = "veloren-common-net", path = "../common/net" }
|
||||
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"] }
|
||||
num_cpus = "1.0"
|
||||
|
@ -27,9 +27,17 @@ use std::{
|
||||
use structopt::StructOpt;
|
||||
use tracing::{info, trace};
|
||||
|
||||
use worldsim::{
|
||||
regionmanager::{RegionManager, meta::RegionManagerMsg},
|
||||
server::meta::{ServerMsg},
|
||||
job::JobManager,
|
||||
region::Region,
|
||||
};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref LOG: TuiLog<'static> = TuiLog::default();
|
||||
}
|
||||
|
||||
const TPS: u64 = 30;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
@ -155,6 +163,18 @@ fn main() -> io::Result<()> {
|
||||
|
||||
let server_port = &server_settings.gameserver_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
|
||||
let mut server = Server::new(
|
||||
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…
Reference in New Issue
Block a user