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",
|
||||
"specs",
|
||||
"specs-idvs",
|
||||
"strum",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"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(Legs): Item("common.items.npc_armor.pants.leather_blue"),
|
||||
|
@ -110,8 +110,8 @@ pub struct EntityConfig {
|
||||
/// Hands:
|
||||
/// - TwoHanded(ItemSpec) for one 2h or 1h weapon,
|
||||
/// - Paired(ItemSpec) for two 1h weapons aka berserker mode,
|
||||
/// - Mix { mainhand: ItemSpec, offhand: ItemSpec,
|
||||
/// } for two different 1h weapons,
|
||||
/// - Mix { mainhand: ItemSpec, offhand: ItemSpec, }
|
||||
/// for two different 1h weapons,
|
||||
/// - Uninit which means that tool should be specified somewhere in code,
|
||||
/// Where ItemSpec is taken from loadout_builder module
|
||||
// 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-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", rev = "8be2abcddf8f524cb5876e8dd20a7e47cfaf7573" }
|
||||
|
||||
strum = { version = "0.21", features = ["derive"] }
|
||||
bincode = "1.3.2"
|
||||
num_cpus = "1.0"
|
||||
tracing = "0.1"
|
||||
|
@ -1,9 +1,11 @@
|
||||
use super::*;
|
||||
use common::{
|
||||
comp::inventory::{loadout_builder::make_potion_bag, slot::ArmorSlot},
|
||||
resources::Time,
|
||||
rtsim::{Memory, MemoryItem},
|
||||
store::Id,
|
||||
terrain::TerrainGrid,
|
||||
trade, LoadoutBuilder,
|
||||
};
|
||||
use rand_distr::{Distribution, Normal};
|
||||
use std::f32::consts::PI;
|
||||
@ -24,11 +26,19 @@ pub struct Entity {
|
||||
pub brain: Brain,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, strum::EnumIter)]
|
||||
pub enum RtSimEntityKind {
|
||||
Random,
|
||||
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_BODY: u32 = 1;
|
||||
const PERM_LOADOUT: u32 = 2;
|
||||
@ -54,12 +64,7 @@ impl Entity {
|
||||
.into()
|
||||
},
|
||||
x if x < 0.50 => {
|
||||
let species = *(&[
|
||||
// Flame Wyvern not incuded until proper introduction
|
||||
comp::bird_large::Species::Phoenix,
|
||||
comp::bird_large::Species::Cockatrice,
|
||||
comp::bird_large::Species::Roc,
|
||||
])
|
||||
let species = *BIRD_LARGE_ROSTER
|
||||
.choose(&mut self.rng(PERM_SPECIES))
|
||||
.unwrap();
|
||||
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 {
|
||||
match self.get_body() {
|
||||
comp::Body::Humanoid(_) => match self.kind {
|
||||
RtSimEntityKind::Cultist => "",
|
||||
RtSimEntityKind::Random => "",
|
||||
},
|
||||
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!(),
|
||||
},
|
||||
comp::Body::Humanoid(_) => humanoid_config(self.kind),
|
||||
comp::Body::BirdMedium(b) => bird_medium_config(b),
|
||||
comp::Body::BirdLarge(b) => bird_large_config(b),
|
||||
_ => 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) {
|
||||
self.brain.route = match self.brain.route.clone() {
|
||||
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()
|
||||
.filter(|&(site_id, site)| {
|
||||
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)
|
||||
})
|
||||
.min_by_key(|(_, site)| {
|
||||
|
@ -108,44 +108,49 @@ impl<'a> System<'a> for Sys {
|
||||
for id in to_reify {
|
||||
rtsim.reify_entity(id);
|
||||
let entity = &rtsim.entities[id];
|
||||
let entity_config = entity.get_entity_config();
|
||||
let rtsim_entity = Some(RtSimEntity(id));
|
||||
|
||||
let body = entity.get_body();
|
||||
let spawn_pos = terrain
|
||||
.find_space(entity.pos.map(|e| e.floor() as i32))
|
||||
.map(|e| e as f32)
|
||||
+ Vec3::new(0.5, 0.5, body.flying_height());
|
||||
|
||||
let pos = comp::Pos(spawn_pos);
|
||||
let mut loadout_rng = entity.loadout_rng();
|
||||
let entity_info = NpcData::from_entity_info(
|
||||
EntityInfo::at(pos.0).with_asset_expect(entity_config),
|
||||
&mut loadout_rng,
|
||||
);
|
||||
if let NpcData::Data {
|
||||
pos,
|
||||
stats,
|
||||
skill_set,
|
||||
health,
|
||||
poise,
|
||||
loadout,
|
||||
agent,
|
||||
// Body discarded here so that species and body type are consistent between
|
||||
// reifications
|
||||
body: _,
|
||||
alignment,
|
||||
scale,
|
||||
drop_item,
|
||||
} = entity_info
|
||||
{
|
||||
let event = match body {
|
||||
comp::Body::Ship(ship) => ServerEvent::CreateShip {
|
||||
|
||||
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 ad_hoc_loadout = entity.get_adhoc_loadout();
|
||||
// Body is rewritten so that body parameters
|
||||
// are consistent between reifications
|
||||
let entity_info = EntityInfo::at(pos.0)
|
||||
.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,
|
||||
ship,
|
||||
mountable: false,
|
||||
stats,
|
||||
skill_set,
|
||||
health,
|
||||
poise,
|
||||
loadout,
|
||||
agent,
|
||||
rtsim_entity,
|
||||
},
|
||||
_ => ServerEvent::CreateNpc {
|
||||
body,
|
||||
alignment,
|
||||
scale,
|
||||
drop_item,
|
||||
} => ServerEvent::CreateNpc {
|
||||
pos,
|
||||
stats,
|
||||
skill_set,
|
||||
@ -161,9 +166,10 @@ impl<'a> System<'a> for Sys {
|
||||
rtsim_entity,
|
||||
projectile: None,
|
||||
},
|
||||
};
|
||||
server_emitter.emit(event);
|
||||
}
|
||||
NpcData::Waypoint(_) => unimplemented!(),
|
||||
}
|
||||
};
|
||||
server_emitter.emit(event);
|
||||
}
|
||||
|
||||
// Update rtsim with real entity data
|
||||
|
Loading…
Reference in New Issue
Block a user