2022-06-04 21:59:19 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use common::{
|
|
|
|
comp::{
|
2023-04-06 20:27:34 +00:00
|
|
|
item::MaterialStatManifest, skills::GeneralSkill, tool::AbilityMap, CharacterActivity,
|
|
|
|
CharacterState, Controller, Energy, Ori, PhysicsState, Poise, Pos, Skill, Stats, Vel,
|
2022-06-04 21:59:19 +00:00
|
|
|
},
|
|
|
|
resources::{DeltaTime, GameMode, Time},
|
2023-03-22 12:49:54 +00:00
|
|
|
shared_server_config::ServerConstants,
|
2022-09-09 15:29:43 +00:00
|
|
|
terrain::{MapSizeLg, TerrainChunk},
|
2022-06-04 21:59:19 +00:00
|
|
|
uid::Uid,
|
|
|
|
util::Dir,
|
2023-03-22 12:49:54 +00:00
|
|
|
SkillSetBuilder,
|
2022-06-04 21:59:19 +00:00
|
|
|
};
|
|
|
|
use common_ecs::dispatch;
|
|
|
|
use common_state::State;
|
|
|
|
use rand::thread_rng;
|
|
|
|
use specs::{Builder, Entity, WorldExt};
|
2022-09-09 15:29:43 +00:00
|
|
|
use std::{sync::Arc, time::Duration};
|
|
|
|
use vek::{approx::AbsDiffEq, Vec2, Vec3};
|
2022-06-04 21:59:19 +00:00
|
|
|
use veloren_common_systems::character_behavior;
|
|
|
|
|
2022-09-09 15:29:43 +00:00
|
|
|
const DEFAULT_WORLD_CHUNKS_LG: MapSizeLg =
|
|
|
|
if let Ok(map_size_lg) = MapSizeLg::new(Vec2 { x: 1, y: 1 }) {
|
|
|
|
map_size_lg
|
|
|
|
} else {
|
|
|
|
panic!("Default world chunk size does not satisfy required invariants.");
|
|
|
|
};
|
|
|
|
|
2022-06-04 21:59:19 +00:00
|
|
|
fn setup() -> State {
|
2022-09-09 15:29:43 +00:00
|
|
|
let pools = State::pools(GameMode::Server);
|
|
|
|
let mut state = State::new(
|
|
|
|
GameMode::Server,
|
|
|
|
pools,
|
|
|
|
DEFAULT_WORLD_CHUNKS_LG,
|
|
|
|
Arc::new(TerrainChunk::water(0)),
|
2024-01-03 04:38:31 +00:00
|
|
|
|dispatch_builder| {
|
|
|
|
dispatch::<character_behavior::Sys>(dispatch_builder, &[]);
|
|
|
|
},
|
2022-09-09 15:29:43 +00:00
|
|
|
);
|
2022-06-04 21:59:19 +00:00
|
|
|
let msm = MaterialStatManifest::load().cloned();
|
|
|
|
state.ecs_mut().insert(msm);
|
2023-03-03 23:21:37 +00:00
|
|
|
state.ecs_mut().insert(AbilityMap::load().cloned());
|
2022-06-04 21:59:19 +00:00
|
|
|
state.ecs_mut().read_resource::<Time>();
|
|
|
|
state.ecs_mut().read_resource::<DeltaTime>();
|
|
|
|
state
|
|
|
|
}
|
|
|
|
|
2022-07-15 12:08:04 +00:00
|
|
|
fn create_entity(state: &mut State, ori: Ori) -> Entity {
|
2022-06-04 21:59:19 +00:00
|
|
|
let body = common::comp::Body::Humanoid(common::comp::humanoid::Body::random_with(
|
|
|
|
&mut thread_rng(),
|
|
|
|
&common::comp::humanoid::Species::Human,
|
|
|
|
));
|
|
|
|
let skill_set = SkillSetBuilder::default().build();
|
|
|
|
state
|
|
|
|
.ecs_mut()
|
|
|
|
.create_entity()
|
|
|
|
.with(CharacterState::Idle(common::states::idle::Data::default()))
|
2023-04-06 20:27:34 +00:00
|
|
|
.with(CharacterActivity::default())
|
2022-06-04 21:59:19 +00:00
|
|
|
.with(Pos(Vec3::zero()))
|
|
|
|
.with(Vel::default())
|
|
|
|
.with(ori)
|
|
|
|
.with(body.mass())
|
|
|
|
.with(body.density())
|
|
|
|
.with(body)
|
|
|
|
.with(Energy::new(
|
|
|
|
body,
|
|
|
|
skill_set
|
|
|
|
.skill_level(Skill::General(GeneralSkill::EnergyIncrease))
|
|
|
|
.unwrap_or(0),
|
|
|
|
))
|
|
|
|
.with(Controller::default())
|
|
|
|
.with(Poise::new(body))
|
|
|
|
.with(skill_set)
|
|
|
|
.with(PhysicsState::default())
|
2023-03-29 23:11:59 +00:00
|
|
|
.with(Stats::empty(body))
|
2022-06-04 21:59:19 +00:00
|
|
|
.with(Uid(1))
|
|
|
|
.build()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn tick(state: &mut State, dt: Duration) {
|
|
|
|
state.tick(
|
|
|
|
dt,
|
|
|
|
false,
|
2023-03-12 21:02:47 +00:00
|
|
|
None,
|
2023-05-14 21:27:47 +00:00
|
|
|
&ServerConstants {
|
|
|
|
day_cycle_coefficient: 24.0,
|
|
|
|
},
|
2023-04-10 17:40:31 +00:00
|
|
|
|_, _| {},
|
2022-06-04 21:59:19 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn orientation_shortcut() {
|
|
|
|
let mut state = setup();
|
|
|
|
const TESTCASES: usize = 5;
|
|
|
|
let testcases: [(Vec3<f32>, Vec3<f32>); TESTCASES] = [
|
|
|
|
// horizontal is unchanged
|
|
|
|
(Vec3::unit_x(), Vec3::unit_x()),
|
|
|
|
// nearly vertical takes time to adjust
|
|
|
|
(Vec3::new(0.1, 0.1, 1.0), Vec3::new(0.149, 0.149, 0.978)),
|
|
|
|
// intermediate case
|
|
|
|
(Vec3::new(0.6, 0.6, 0.1), Vec3::new(0.706, 0.706, 0.052)),
|
|
|
|
// edge case: nearly horizontal after system
|
|
|
|
(Vec3::new(0.6, 0.6, 0.0556), Vec3::new(0.707, 0.707, 0.000)),
|
|
|
|
// small enough to be horizontal in one step
|
|
|
|
(Vec3::new(0.6, 0.6, 0.04), Vec3::new(0.707, 0.707, 0.000)),
|
|
|
|
];
|
|
|
|
let mut entities: [Option<Entity>; TESTCASES] = [None; TESTCASES];
|
|
|
|
for i in 0..TESTCASES {
|
|
|
|
entities[i] = Some(create_entity(
|
|
|
|
&mut state,
|
|
|
|
Ori::from_unnormalized_vec(testcases[i].0).unwrap_or_default(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
tick(&mut state, Duration::from_secs_f32(0.033));
|
|
|
|
let results = state.ecs().read_storage::<Ori>();
|
|
|
|
for i in 0..TESTCASES {
|
|
|
|
if let Some(e) = entities[i] {
|
|
|
|
let result = Dir::from(*results.get(e).expect("Ori missing"));
|
2023-04-06 20:27:34 +00:00
|
|
|
assert!(
|
|
|
|
result.abs_diff_eq(&testcases[i].1, 0.0005),
|
|
|
|
"{:?} != {:?}",
|
|
|
|
result,
|
|
|
|
testcases[i].1
|
|
|
|
);
|
2022-06-04 21:59:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|