mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
160 lines
5.1 KiB
Rust
160 lines
5.1 KiB
Rust
use common::{
|
|
comp::{
|
|
inventory::item::MaterialStatManifest, tool::AbilityMap, Auras, Buffs, CharacterActivity,
|
|
CharacterState, Collider, Combo, Controller, Energy, EnteredAuras, Health, Ori, Pos, Stats,
|
|
Vel,
|
|
},
|
|
resources::{DeltaTime, GameMode, Time},
|
|
shared_server_config::ServerConstants,
|
|
skillset_builder::SkillSetBuilder,
|
|
terrain::{
|
|
Block, BlockKind, MapSizeLg, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainGrid,
|
|
},
|
|
};
|
|
use common_ecs::{dispatch, System};
|
|
use common_net::sync::WorldSyncExt;
|
|
use common_state::State;
|
|
use rand::{prelude::*, rngs::SmallRng};
|
|
use specs::{Builder, Entity, WorldExt};
|
|
use std::{error::Error, sync::Arc, time::Duration};
|
|
use vek::{Rgb, Vec2, Vec3};
|
|
use veloren_common_systems::{character_behavior, phys};
|
|
|
|
pub const EPSILON: f32 = 0.00002;
|
|
const DT_MILLIS: u64 = 10;
|
|
const MILLIS_PER_SEC: f64 = 1_000.0;
|
|
pub const DT: Duration = Duration::from_millis(DT_MILLIS);
|
|
pub const DT_F64: f64 = DT_MILLIS as f64 / MILLIS_PER_SEC;
|
|
|
|
const DEFAULT_WORLD_CHUNKS_LG: MapSizeLg =
|
|
if let Ok(map_size_lg) = MapSizeLg::new(Vec2 { x: 10, y: 10 }) {
|
|
map_size_lg
|
|
} else {
|
|
panic!("Default world chunk size does not satisfy required invariants.");
|
|
};
|
|
|
|
pub fn setup(add_systems: impl Fn(&mut specs::DispatcherBuilder)) -> State {
|
|
let pools = State::pools(GameMode::Server);
|
|
let mut state = State::new(
|
|
GameMode::Server,
|
|
pools,
|
|
DEFAULT_WORLD_CHUNKS_LG,
|
|
Arc::new(TerrainChunk::water(0)),
|
|
add_systems,
|
|
common_state::plugin::PluginMgr::default(),
|
|
);
|
|
state.ecs_mut().insert(MaterialStatManifest::with_empty());
|
|
state.ecs_mut().insert(AbilityMap::load().cloned());
|
|
state.ecs_mut().read_resource::<Time>();
|
|
state.ecs_mut().read_resource::<DeltaTime>();
|
|
for x in 0..2 {
|
|
for y in 0..2 {
|
|
generate_chunk(&mut state, Vec2::new(x, y));
|
|
}
|
|
}
|
|
|
|
state
|
|
}
|
|
pub fn add_char_and_phys_systems(dispatch_builder: &mut specs::DispatcherBuilder) {
|
|
dispatch::<character_behavior::Sys>(dispatch_builder, &[]);
|
|
dispatch::<phys::Sys>(dispatch_builder, &[&character_behavior::Sys::sys_name()]);
|
|
}
|
|
|
|
pub fn tick(state: &mut State, dt: Duration) {
|
|
state.tick(
|
|
dt,
|
|
false,
|
|
None,
|
|
&ServerConstants {
|
|
day_cycle_coefficient: 24.0,
|
|
},
|
|
|_, _| {},
|
|
);
|
|
}
|
|
|
|
pub fn set_control(
|
|
state: &mut State,
|
|
entity: Entity,
|
|
control: Controller,
|
|
) -> Result<(), specs::error::Error> {
|
|
let mut storage = state.ecs_mut().write_storage::<Controller>();
|
|
storage.insert(entity, control).map(|_| ())
|
|
}
|
|
|
|
pub fn get_transform(state: &State, entity: Entity) -> Result<(Pos, Vel, Ori), Box<dyn Error>> {
|
|
let storage = state.ecs().read_storage::<Pos>();
|
|
let pos = *storage
|
|
.get(entity)
|
|
.ok_or("Storage does not contain Entity Pos")?;
|
|
let storage = state.ecs().read_storage::<Vel>();
|
|
let vel = *storage
|
|
.get(entity)
|
|
.ok_or("Storage does not contain Entity Vel")?;
|
|
let storage = state.ecs().read_storage::<Ori>();
|
|
let ori = *storage
|
|
.get(entity)
|
|
.ok_or("Storage does not contain Entity Ori")?;
|
|
|
|
Ok((pos, vel, ori))
|
|
}
|
|
|
|
pub fn create_player(state: &mut State) -> Entity {
|
|
let body = common::comp::Body::Humanoid(common::comp::humanoid::Body::random_with(
|
|
&mut thread_rng(),
|
|
&common::comp::humanoid::Species::Human,
|
|
));
|
|
let (p0, p1, radius) = body.sausage();
|
|
let collider = Collider::CapsulePrism {
|
|
p0,
|
|
p1,
|
|
radius,
|
|
z_min: 0.0,
|
|
z_max: body.height(),
|
|
};
|
|
let skill_set = SkillSetBuilder::default().build();
|
|
|
|
state
|
|
.ecs_mut()
|
|
.create_entity_synced()
|
|
.with(Pos(Vec3::new(16.0, 16.0, 265.0)))
|
|
.with(Vel::default())
|
|
.with(Ori::default())
|
|
.with(body.mass())
|
|
.with(body.density())
|
|
.with(collider)
|
|
.with(body)
|
|
.with(Controller::default())
|
|
.with(CharacterState::default())
|
|
.with(CharacterActivity::default())
|
|
.with(Buffs::default())
|
|
.with(Combo::default())
|
|
.with(Auras::default())
|
|
.with(EnteredAuras::default())
|
|
.with(Energy::new(body))
|
|
.with(Health::new(body))
|
|
.with(skill_set)
|
|
.with(Stats::empty(body))
|
|
.build()
|
|
}
|
|
|
|
#[allow(clippy::needless_pass_by_ref_mut)]
|
|
pub fn generate_chunk(state: &mut State, chunk_pos: Vec2<i32>) {
|
|
let (x, y) = chunk_pos.map(|e| e.to_le_bytes()).into_tuple();
|
|
let mut rng = SmallRng::from_seed([
|
|
x[0], x[1], x[2], x[3], y[0], y[1], y[2], y[3], x[0], x[1], x[2], x[3], y[0], y[1], y[2],
|
|
y[3], x[0], x[1], x[2], x[3], y[0], y[1], y[2], y[3], x[0], x[1], x[2], x[3], y[0], y[1],
|
|
y[2], y[3],
|
|
]);
|
|
let height = rng.gen::<i32>() % 8;
|
|
|
|
state.ecs().write_resource::<TerrainGrid>().insert(
|
|
chunk_pos,
|
|
Arc::new(TerrainChunk::new(
|
|
256 + if rng.gen::<u8>() < 64 { height } else { 0 },
|
|
Block::new(BlockKind::Grass, Rgb::new(11, 102, 35)),
|
|
Block::air(SpriteKind::Empty),
|
|
TerrainChunkMeta::void(),
|
|
)),
|
|
);
|
|
}
|