mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Make Rtsim entity config work
This commit is contained in:
parent
27823ce8fa
commit
8af4cf1a37
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -6195,6 +6195,7 @@ dependencies = [
|
|||||||
"slab",
|
"slab",
|
||||||
"specs",
|
"specs",
|
||||||
"specs-idvs",
|
"specs-idvs",
|
||||||
|
"strum",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"vek",
|
"vek",
|
||||||
|
11
assets/common/entity/wild/aggressive/roc.ron
Normal file
11
assets/common/entity/wild/aggressive/roc.ron
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
EntityConfig (
|
||||||
|
name: Automatic,
|
||||||
|
body: RandomWith("roc"),
|
||||||
|
alignment: Alignment(Enemy),
|
||||||
|
|
||||||
|
loot: LootTable("common.loot_tables.creature.bird_large.roc"),
|
||||||
|
|
||||||
|
hands: Uninit,
|
||||||
|
|
||||||
|
meta: [],
|
||||||
|
)
|
11
assets/common/entity/wild/peaceful/phoenix.ron
Normal file
11
assets/common/entity/wild/peaceful/phoenix.ron
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
EntityConfig (
|
||||||
|
name: Automatic,
|
||||||
|
body: RandomWith("phoenix"),
|
||||||
|
alignment: Alignment(Wild),
|
||||||
|
|
||||||
|
loot: LootTable("common.loot_tables.creature.bird_large.phoenix"),
|
||||||
|
|
||||||
|
hands: Uninit,
|
||||||
|
|
||||||
|
meta: [],
|
||||||
|
)
|
18
assets/common/entity/world/traveler.ron
Normal file
18
assets/common/entity/world/traveler.ron
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
EntityConfig (
|
||||||
|
name: Automatic,
|
||||||
|
body: RandomWith("humanoid"),
|
||||||
|
alignment: Alignment(Npc),
|
||||||
|
|
||||||
|
loot: LootTable("common.loot_tables.creature.humanoid"),
|
||||||
|
|
||||||
|
hands: TwoHanded(Choice([
|
||||||
|
(1.0, Some(Item("common.items.weapons.sword.iron-0"))),
|
||||||
|
(1.0, Some(Item("common.items.weapons.bow.hardwood-2"))),
|
||||||
|
(1.0, Some(Item("common.items.weapons.axe.steel_axe-0"))),
|
||||||
|
(1.0, Some(Item("common.items.weapons.staff.frostwood_torch"))),
|
||||||
|
])),
|
||||||
|
|
||||||
|
meta: [
|
||||||
|
LoadoutAsset("common.loadout.world.traveler"),
|
||||||
|
],
|
||||||
|
)
|
@ -1,10 +1,4 @@
|
|||||||
({
|
({
|
||||||
ActiveMainhand: Choice([
|
|
||||||
(1.0, Some(Item("common.items.weapons.sword.iron-0"))),
|
|
||||||
(1.0, Some(Item("common.items.weapons.bow.hardwood-2"))),
|
|
||||||
(1.0, Some(Item("common.items.weapons.axe.steel_axe-0"))),
|
|
||||||
(1.0, Some(Item("common.items.weapons.staff.frostwood_torch"))),
|
|
||||||
]),
|
|
||||||
|
|
||||||
Armor(Chest): Item("common.items.npc_armor.chest.leather_blue"),
|
Armor(Chest): Item("common.items.npc_armor.chest.leather_blue"),
|
||||||
Armor(Legs): Item("common.items.npc_armor.pants.leather_blue"),
|
Armor(Legs): Item("common.items.npc_armor.pants.leather_blue"),
|
||||||
|
@ -110,8 +110,8 @@ pub struct EntityConfig {
|
|||||||
/// Hands:
|
/// Hands:
|
||||||
/// - TwoHanded(ItemSpec) for one 2h or 1h weapon,
|
/// - TwoHanded(ItemSpec) for one 2h or 1h weapon,
|
||||||
/// - Paired(ItemSpec) for two 1h weapons aka berserker mode,
|
/// - Paired(ItemSpec) for two 1h weapons aka berserker mode,
|
||||||
/// - Mix { mainhand: ItemSpec, offhand: ItemSpec,
|
/// - Mix { mainhand: ItemSpec, offhand: ItemSpec, }
|
||||||
/// } for two different 1h weapons,
|
/// for two different 1h weapons,
|
||||||
/// - Uninit which means that tool should be specified somewhere in code,
|
/// - Uninit which means that tool should be specified somewhere in code,
|
||||||
/// Where ItemSpec is taken from loadout_builder module
|
/// Where ItemSpec is taken from loadout_builder module
|
||||||
// TODO: better name for this?
|
// TODO: better name for this?
|
||||||
|
@ -28,6 +28,7 @@ network = { package = "veloren-network", path = "../network", features = ["metri
|
|||||||
specs = { git = "https://github.com/amethyst/specs.git", features = ["shred-derive"], rev = "f985bec5d456f7b0dd8aae99848f9473c2cd9d46" }
|
specs = { git = "https://github.com/amethyst/specs.git", features = ["shred-derive"], rev = "f985bec5d456f7b0dd8aae99848f9473c2cd9d46" }
|
||||||
specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", rev = "8be2abcddf8f524cb5876e8dd20a7e47cfaf7573" }
|
specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", rev = "8be2abcddf8f524cb5876e8dd20a7e47cfaf7573" }
|
||||||
|
|
||||||
|
strum = { version = "0.21", features = ["derive"] }
|
||||||
bincode = "1.3.2"
|
bincode = "1.3.2"
|
||||||
num_cpus = "1.0"
|
num_cpus = "1.0"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use common::{
|
use common::{
|
||||||
|
comp::inventory::{loadout_builder::make_potion_bag, slot::ArmorSlot},
|
||||||
resources::Time,
|
resources::Time,
|
||||||
rtsim::{Memory, MemoryItem},
|
rtsim::{Memory, MemoryItem},
|
||||||
store::Id,
|
store::Id,
|
||||||
terrain::TerrainGrid,
|
terrain::TerrainGrid,
|
||||||
|
trade, LoadoutBuilder,
|
||||||
};
|
};
|
||||||
use rand_distr::{Distribution, Normal};
|
use rand_distr::{Distribution, Normal};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
@ -24,11 +26,19 @@ pub struct Entity {
|
|||||||
pub brain: Brain,
|
pub brain: Brain,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, strum::EnumIter)]
|
||||||
pub enum RtSimEntityKind {
|
pub enum RtSimEntityKind {
|
||||||
Random,
|
Random,
|
||||||
Cultist,
|
Cultist,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BIRD_LARGE_ROSTER: &[comp::bird_large::Species] = &[
|
||||||
|
// Flame Wyvern not incuded until proper introduction
|
||||||
|
comp::bird_large::Species::Phoenix,
|
||||||
|
comp::bird_large::Species::Cockatrice,
|
||||||
|
comp::bird_large::Species::Roc,
|
||||||
|
];
|
||||||
|
|
||||||
const PERM_SPECIES: u32 = 0;
|
const PERM_SPECIES: u32 = 0;
|
||||||
const PERM_BODY: u32 = 1;
|
const PERM_BODY: u32 = 1;
|
||||||
const PERM_LOADOUT: u32 = 2;
|
const PERM_LOADOUT: u32 = 2;
|
||||||
@ -54,12 +64,7 @@ impl Entity {
|
|||||||
.into()
|
.into()
|
||||||
},
|
},
|
||||||
x if x < 0.50 => {
|
x if x < 0.50 => {
|
||||||
let species = *(&[
|
let species = *BIRD_LARGE_ROSTER
|
||||||
// Flame Wyvern not incuded until proper introduction
|
|
||||||
comp::bird_large::Species::Phoenix,
|
|
||||||
comp::bird_large::Species::Cockatrice,
|
|
||||||
comp::bird_large::Species::Roc,
|
|
||||||
])
|
|
||||||
.choose(&mut self.rng(PERM_SPECIES))
|
.choose(&mut self.rng(PERM_SPECIES))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
comp::bird_large::Body::random_with(&mut self.rng(PERM_BODY), &species)
|
comp::bird_large::Body::random_with(&mut self.rng(PERM_BODY), &species)
|
||||||
@ -84,31 +89,26 @@ impl Entity {
|
|||||||
|
|
||||||
pub fn get_entity_config(&self) -> &str {
|
pub fn get_entity_config(&self) -> &str {
|
||||||
match self.get_body() {
|
match self.get_body() {
|
||||||
comp::Body::Humanoid(_) => match self.kind {
|
comp::Body::Humanoid(_) => humanoid_config(self.kind),
|
||||||
RtSimEntityKind::Cultist => "",
|
comp::Body::BirdMedium(b) => bird_medium_config(b),
|
||||||
RtSimEntityKind::Random => "",
|
comp::Body::BirdLarge(b) => bird_large_config(b),
|
||||||
},
|
|
||||||
comp::Body::BirdMedium(b) => match b.species {
|
|
||||||
comp::bird_medium::Species::Duck => "",
|
|
||||||
comp::bird_medium::Species::Chicken => "",
|
|
||||||
comp::bird_medium::Species::Goose => "",
|
|
||||||
comp::bird_medium::Species::Peacock => "",
|
|
||||||
comp::bird_medium::Species::Eagle => "",
|
|
||||||
comp::bird_medium::Species::Owl => "",
|
|
||||||
comp::bird_medium::Species::Parrot => "",
|
|
||||||
},
|
|
||||||
comp::Body::BirdLarge(b) => match b.species {
|
|
||||||
comp::bird_large::Species::Phoenix => "",
|
|
||||||
comp::bird_large::Species::Cockatrice => "",
|
|
||||||
comp::bird_large::Species::Roc => "",
|
|
||||||
// Wildcard match used here as there is an array above which limits what species are
|
|
||||||
// used
|
|
||||||
_ => unimplemented!(),
|
|
||||||
},
|
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_adhoc_loadout(
|
||||||
|
&self,
|
||||||
|
) -> fn(LoadoutBuilder, Option<&trade::SiteInformation>) -> LoadoutBuilder {
|
||||||
|
let body = self.get_body();
|
||||||
|
let kind = &self.kind;
|
||||||
|
// give potions to traveler humanoids or return loadout as is otherwise
|
||||||
|
if let (comp::Body::Humanoid(_), RtSimEntityKind::Random) = (body, kind) {
|
||||||
|
|l, _| l.bag(ArmorSlot::Bag1, Some(make_potion_bag(100)))
|
||||||
|
} else {
|
||||||
|
|l, _| l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self, time: &Time, terrain: &TerrainGrid, world: &World, index: &IndexRef) {
|
pub fn tick(&mut self, time: &Time, terrain: &TerrainGrid, world: &World, index: &IndexRef) {
|
||||||
self.brain.route = match self.brain.route.clone() {
|
self.brain.route = match self.brain.route.clone() {
|
||||||
Travel::Lost => {
|
Travel::Lost => {
|
||||||
@ -706,3 +706,86 @@ impl Brain {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn humanoid_config(kind: RtSimEntityKind) -> &'static str {
|
||||||
|
match kind {
|
||||||
|
RtSimEntityKind::Cultist => "common.entity.dungeon.tier-5.cultist",
|
||||||
|
RtSimEntityKind::Random => "common.entity.world.traveler",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bird_medium_config(body: comp::bird_medium::Body) -> &'static str {
|
||||||
|
match body.species {
|
||||||
|
comp::bird_medium::Species::Duck => "common.entity.wild.peaceful.duck",
|
||||||
|
comp::bird_medium::Species::Chicken => "common.entity.wild.peaceful.chicken",
|
||||||
|
comp::bird_medium::Species::Goose => "common.entity.wild.peaceful.goose",
|
||||||
|
comp::bird_medium::Species::Peacock => "common.entity.wild.peaceful.peacock",
|
||||||
|
comp::bird_medium::Species::Eagle => "common.entity.wild.peaceful.eagle",
|
||||||
|
comp::bird_medium::Species::Owl => "common.entity.wild.peaceful.owl",
|
||||||
|
comp::bird_medium::Species::Parrot => "common.entity.wild.peaceful.parrot",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bird_large_config(body: comp::bird_large::Body) -> &'static str {
|
||||||
|
match body.species {
|
||||||
|
comp::bird_large::Species::Phoenix => "common.entity.wild.peaceful.phoenix",
|
||||||
|
comp::bird_large::Species::Cockatrice => "common.entity.wild.aggressive.cockatrice",
|
||||||
|
comp::bird_large::Species::Roc => "common.entity.wild.aggressive.roc",
|
||||||
|
// Wildcard match used here as there is an array above
|
||||||
|
// which limits what species are used
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use common::generation::EntityInfo;
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
// Brief, Incomplete and Mostly Wrong Test that all entity configs do exist.
|
||||||
|
//
|
||||||
|
// NOTE: Doesn't checks for ships, because we don't produce entity configs
|
||||||
|
// for them yet.
|
||||||
|
#[test]
|
||||||
|
fn test_entity_configs() {
|
||||||
|
let dummy_pos = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
// Bird Large test
|
||||||
|
for bird_large_species in BIRD_LARGE_ROSTER {
|
||||||
|
let female_body = comp::bird_large::Body {
|
||||||
|
species: *bird_large_species,
|
||||||
|
body_type: comp::bird_large::BodyType::Female,
|
||||||
|
};
|
||||||
|
let male_body = comp::bird_large::Body {
|
||||||
|
species: *bird_large_species,
|
||||||
|
body_type: comp::bird_large::BodyType::Male,
|
||||||
|
};
|
||||||
|
|
||||||
|
let female_config = bird_large_config(female_body);
|
||||||
|
std::mem::drop(EntityInfo::at(dummy_pos).with_asset_expect(female_config));
|
||||||
|
let male_config = bird_large_config(male_body);
|
||||||
|
std::mem::drop(EntityInfo::at(dummy_pos).with_asset_expect(male_config));
|
||||||
|
}
|
||||||
|
// Bird Medium test
|
||||||
|
for bird_med_species in comp::bird_medium::ALL_SPECIES {
|
||||||
|
let female_body = comp::bird_medium::Body {
|
||||||
|
species: bird_med_species,
|
||||||
|
body_type: comp::bird_medium::BodyType::Female,
|
||||||
|
};
|
||||||
|
let male_body = comp::bird_medium::Body {
|
||||||
|
species: bird_med_species,
|
||||||
|
body_type: comp::bird_medium::BodyType::Male,
|
||||||
|
};
|
||||||
|
|
||||||
|
let female_config = bird_medium_config(female_body);
|
||||||
|
std::mem::drop(EntityInfo::at(dummy_pos).with_asset_expect(female_config));
|
||||||
|
let male_config = bird_medium_config(male_body);
|
||||||
|
std::mem::drop(EntityInfo::at(dummy_pos).with_asset_expect(male_config));
|
||||||
|
}
|
||||||
|
// Humanoid test
|
||||||
|
for kind in RtSimEntityKind::iter() {
|
||||||
|
let config = humanoid_config(kind);
|
||||||
|
std::mem::drop(EntityInfo::at(dummy_pos).with_asset_expect(config));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -166,7 +166,8 @@ pub fn init(
|
|||||||
.iter()
|
.iter()
|
||||||
.filter(|&(site_id, site)| {
|
.filter(|&(site_id, site)| {
|
||||||
site.is_settlement()
|
site.is_settlement()
|
||||||
// TODO: Remove this later, starting town should not be special-cased
|
// TODO: Remove this later, starting town should not be
|
||||||
|
// special-cased
|
||||||
&& spawn_town_id.map_or(false, |spawn_id| spawn_id != site_id)
|
&& spawn_town_id.map_or(false, |spawn_id| spawn_id != site_id)
|
||||||
})
|
})
|
||||||
.min_by_key(|(_, site)| {
|
.min_by_key(|(_, site)| {
|
||||||
|
@ -108,20 +108,37 @@ impl<'a> System<'a> for Sys {
|
|||||||
for id in to_reify {
|
for id in to_reify {
|
||||||
rtsim.reify_entity(id);
|
rtsim.reify_entity(id);
|
||||||
let entity = &rtsim.entities[id];
|
let entity = &rtsim.entities[id];
|
||||||
let entity_config = entity.get_entity_config();
|
|
||||||
let rtsim_entity = Some(RtSimEntity(id));
|
let rtsim_entity = Some(RtSimEntity(id));
|
||||||
|
|
||||||
let body = entity.get_body();
|
let body = entity.get_body();
|
||||||
let spawn_pos = terrain
|
let spawn_pos = terrain
|
||||||
.find_space(entity.pos.map(|e| e.floor() as i32))
|
.find_space(entity.pos.map(|e| e.floor() as i32))
|
||||||
.map(|e| e as f32)
|
.map(|e| e as f32)
|
||||||
+ Vec3::new(0.5, 0.5, body.flying_height());
|
+ Vec3::new(0.5, 0.5, body.flying_height());
|
||||||
|
|
||||||
let pos = comp::Pos(spawn_pos);
|
let pos = comp::Pos(spawn_pos);
|
||||||
|
|
||||||
|
let event = if let comp::Body::Ship(ship) = body {
|
||||||
|
ServerEvent::CreateShip {
|
||||||
|
pos,
|
||||||
|
ship,
|
||||||
|
mountable: false,
|
||||||
|
agent: Some(comp::Agent::from_body(&body)),
|
||||||
|
rtsim_entity,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let entity_config = entity.get_entity_config();
|
||||||
let mut loadout_rng = entity.loadout_rng();
|
let mut loadout_rng = entity.loadout_rng();
|
||||||
let entity_info = NpcData::from_entity_info(
|
let ad_hoc_loadout = entity.get_adhoc_loadout();
|
||||||
EntityInfo::at(pos.0).with_asset_expect(entity_config),
|
// Body is rewritten so that body parameters
|
||||||
&mut loadout_rng,
|
// are consistent between reifications
|
||||||
);
|
let entity_info = EntityInfo::at(pos.0)
|
||||||
if let NpcData::Data {
|
.with_asset_expect(entity_config)
|
||||||
|
.with_lazy_loadout(ad_hoc_loadout)
|
||||||
|
.with_body(body)
|
||||||
|
.with_health_scaling(10);
|
||||||
|
match NpcData::from_entity_info(entity_info, &mut loadout_rng) {
|
||||||
|
NpcData::Data {
|
||||||
pos,
|
pos,
|
||||||
stats,
|
stats,
|
||||||
skill_set,
|
skill_set,
|
||||||
@ -129,23 +146,11 @@ impl<'a> System<'a> for Sys {
|
|||||||
poise,
|
poise,
|
||||||
loadout,
|
loadout,
|
||||||
agent,
|
agent,
|
||||||
// Body discarded here so that species and body type are consistent between
|
body,
|
||||||
// reifications
|
|
||||||
body: _,
|
|
||||||
alignment,
|
alignment,
|
||||||
scale,
|
scale,
|
||||||
drop_item,
|
drop_item,
|
||||||
} = entity_info
|
} => ServerEvent::CreateNpc {
|
||||||
{
|
|
||||||
let event = match body {
|
|
||||||
comp::Body::Ship(ship) => ServerEvent::CreateShip {
|
|
||||||
pos,
|
|
||||||
ship,
|
|
||||||
mountable: false,
|
|
||||||
agent,
|
|
||||||
rtsim_entity,
|
|
||||||
},
|
|
||||||
_ => ServerEvent::CreateNpc {
|
|
||||||
pos,
|
pos,
|
||||||
stats,
|
stats,
|
||||||
skill_set,
|
skill_set,
|
||||||
@ -161,10 +166,11 @@ impl<'a> System<'a> for Sys {
|
|||||||
rtsim_entity,
|
rtsim_entity,
|
||||||
projectile: None,
|
projectile: None,
|
||||||
},
|
},
|
||||||
|
NpcData::Waypoint(_) => unimplemented!(),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
server_emitter.emit(event);
|
server_emitter.emit(event);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Update rtsim with real entity data
|
// Update rtsim with real entity data
|
||||||
for (pos, rtsim_entity, agent) in (&positions, &rtsim_entities, &mut agents).join() {
|
for (pos, rtsim_entity, agent) in (&positions, &rtsim_entities, &mut agents).join() {
|
||||||
|
Loading…
Reference in New Issue
Block a user