mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Began integrating rtsim2 into server
This commit is contained in:
parent
ca80d831ce
commit
0cafafdaa7
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -6888,9 +6888,11 @@ dependencies = [
|
||||
name = "veloren-rtsim"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"ron 0.7.0",
|
||||
"hashbrown 0.12.3",
|
||||
"ron 0.8.0",
|
||||
"serde",
|
||||
"veloren-common",
|
||||
"veloren-world",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6942,6 +6944,7 @@ dependencies = [
|
||||
"veloren-common-systems",
|
||||
"veloren-network",
|
||||
"veloren-plugin-api",
|
||||
"veloren-rtsim",
|
||||
"veloren-server-agent",
|
||||
"veloren-world",
|
||||
]
|
||||
|
@ -5,5 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
common = { package = "veloren-common", path = "../common" }
|
||||
ron = "0.7"
|
||||
world = { package = "veloren-world", path = "../world" }
|
||||
ron = "0.8"
|
||||
serde = { version = "1.0.110", features = ["derive"] }
|
||||
hashbrown = { version = "0.12", features = ["rayon", "serde", "nightly"] }
|
||||
|
13
rtsim/src/data/actor.rs
Normal file
13
rtsim/src/data/actor.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use hashbrown::HashMap;
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct ActorId {
|
||||
pub idx: u32,
|
||||
pub gen: u32,
|
||||
}
|
||||
|
||||
pub struct Actor {}
|
||||
|
||||
pub struct Actors {
|
||||
pub actors: HashMap<ActorId, Actor>,
|
||||
}
|
@ -3,6 +3,7 @@ use serde::{
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Default, PartialEq, Eq, Hash)]
|
||||
pub struct V<T>(pub T);
|
||||
|
||||
impl<T: Serialize> Serialize for V<T> {
|
||||
@ -22,12 +23,12 @@ impl<'de, T: Version> Deserialize<'de> for V<T> {
|
||||
impl<U, T: Latest<U>> Latest<U> for V<T> {
|
||||
fn to_unversioned(self) -> U { self.0.to_unversioned() }
|
||||
|
||||
fn from_unversioned(x: U) -> Self { Self(T::from_unversioned(x)) }
|
||||
fn from_unversioned(x: &U) -> Self { Self(T::from_unversioned(x)) }
|
||||
}
|
||||
|
||||
pub trait Latest<T> {
|
||||
fn to_unversioned(self) -> T;
|
||||
fn from_unversioned(x: T) -> Self;
|
||||
fn from_unversioned(x: &T) -> Self;
|
||||
}
|
||||
|
||||
pub trait Version: Sized + DeserializeOwned {
|
||||
|
@ -1,10 +1,30 @@
|
||||
pub mod helper;
|
||||
pub mod version;
|
||||
|
||||
pub mod world;
|
||||
pub mod actor;
|
||||
pub mod nature;
|
||||
|
||||
pub use self::world::World;
|
||||
pub use self::{
|
||||
actor::{Actor, ActorId, Actors},
|
||||
nature::Nature,
|
||||
};
|
||||
|
||||
use self::helper::Latest;
|
||||
use ron::error::SpannedResult;
|
||||
use serde::Deserialize;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
pub struct Data {
|
||||
world: World,
|
||||
pub nature: Nature,
|
||||
pub actors: Actors,
|
||||
}
|
||||
|
||||
impl Data {
|
||||
pub fn from_reader<R: Read>(reader: R) -> SpannedResult<Self> {
|
||||
ron::de::from_reader(reader).map(version::LatestData::to_unversioned)
|
||||
}
|
||||
|
||||
pub fn write_to<W: Write>(&self, writer: W) -> Result<(), ron::Error> {
|
||||
ron::ser::to_writer(writer, &version::LatestData::from_unversioned(self))
|
||||
}
|
||||
}
|
||||
|
1
rtsim/src/data/nature.rs
Normal file
1
rtsim/src/data/nature.rs
Normal file
@ -0,0 +1 @@
|
||||
pub struct Nature {}
|
85
rtsim/src/data/version/actor.rs
Normal file
85
rtsim/src/data/version/actor.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use super::*;
|
||||
use crate::data::{Actor, ActorId, Actors};
|
||||
use hashbrown::HashMap;
|
||||
|
||||
// ActorId
|
||||
|
||||
impl Latest<ActorId> for ActorIdV0 {
|
||||
fn to_unversioned(self) -> ActorId {
|
||||
ActorId {
|
||||
idx: self.idx,
|
||||
gen: self.gen,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_unversioned(id: &ActorId) -> Self {
|
||||
Self {
|
||||
idx: id.idx,
|
||||
gen: id.gen,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct ActorIdV0 {
|
||||
pub idx: u32,
|
||||
pub gen: u32,
|
||||
}
|
||||
|
||||
impl Version for ActorIdV0 {
|
||||
type Prev = Bottom;
|
||||
|
||||
fn migrate(x: Self::Prev) -> Self { match x {} }
|
||||
}
|
||||
|
||||
// Actor
|
||||
|
||||
impl Latest<Actor> for ActorV0 {
|
||||
fn to_unversioned(self) -> Actor { Actor {} }
|
||||
|
||||
fn from_unversioned(actor: &Actor) -> Self { Self {} }
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct ActorV0 {}
|
||||
|
||||
impl Version for ActorV0 {
|
||||
type Prev = Bottom;
|
||||
|
||||
fn migrate(x: Self::Prev) -> Self { match x {} }
|
||||
}
|
||||
|
||||
// Actors
|
||||
|
||||
impl Latest<Actors> for ActorsV0 {
|
||||
fn to_unversioned(self) -> Actors {
|
||||
Actors {
|
||||
actors: self
|
||||
.actors
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.to_unversioned(), v.to_unversioned()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_unversioned(actors: &Actors) -> Self {
|
||||
Self {
|
||||
actors: actors
|
||||
.actors
|
||||
.iter()
|
||||
.map(|(k, v)| (Latest::from_unversioned(k), Latest::from_unversioned(v)))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ActorsV0 {
|
||||
actors: HashMap<V<ActorIdV0>, V<ActorV0>>,
|
||||
}
|
||||
|
||||
impl Version for ActorsV0 {
|
||||
type Prev = Bottom;
|
||||
|
||||
fn migrate(x: Self::Prev) -> Self { match x {} }
|
||||
}
|
@ -15,8 +15,14 @@
|
||||
// conclusion that there's just no way to add the feature you want to add
|
||||
// without creating a new version of the data structure in question.
|
||||
//
|
||||
// That said, here's how to make a change to one of the structures in this
|
||||
// module, or submodules.
|
||||
// Please note that in *very specific* cases, it is possible to make a change to
|
||||
// an existing data structure that is backward-compatible. For example, adding a
|
||||
// new variant to an enum or a new field to a struct (where said field is
|
||||
// annotated with `#[serde(default)]`) is generally considered to be a
|
||||
// backward-compatible change.
|
||||
//
|
||||
// That said, here's how to make a breaking change to one of the structures in
|
||||
// this module, or submodules.
|
||||
//
|
||||
// 1) Duplicate the latest version of the data structure and the `Version` impl
|
||||
// for it (later versions should be kept at the top of each file).
|
||||
@ -38,7 +44,8 @@
|
||||
// The *golden rule* is that, once merged to master, an old version's type must
|
||||
// not be changed!
|
||||
|
||||
pub mod world;
|
||||
pub mod actor;
|
||||
pub mod nature;
|
||||
|
||||
use super::{
|
||||
helper::{Bottom, Latest, Version, V},
|
||||
@ -46,23 +53,28 @@ use super::{
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
impl Latest<Data> for DataV0 {
|
||||
pub type LatestData = DataV0;
|
||||
|
||||
impl Latest<Data> for LatestData {
|
||||
fn to_unversioned(self) -> Data {
|
||||
Data {
|
||||
world: self.world.to_unversioned(),
|
||||
nature: self.nature.to_unversioned(),
|
||||
actors: self.actors.to_unversioned(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_unversioned(data: Data) -> Self {
|
||||
fn from_unversioned(data: &Data) -> Self {
|
||||
Self {
|
||||
world: Latest::from_unversioned(data.world),
|
||||
nature: Latest::from_unversioned(&data.nature),
|
||||
actors: Latest::from_unversioned(&data.actors),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct DataV0 {
|
||||
world: V<world::WorldV0>,
|
||||
nature: V<nature::NatureV0>,
|
||||
actors: V<actor::ActorsV0>,
|
||||
}
|
||||
|
||||
impl Version for DataV0 {
|
||||
|
17
rtsim/src/data/version/nature.rs
Normal file
17
rtsim/src/data/version/nature.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use super::*;
|
||||
use crate::data::Nature;
|
||||
|
||||
impl Latest<crate::data::Nature> for NatureV0 {
|
||||
fn to_unversioned(self) -> Nature { Nature {} }
|
||||
|
||||
fn from_unversioned(nature: &Nature) -> Self { Self {} }
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct NatureV0 {}
|
||||
|
||||
impl Version for NatureV0 {
|
||||
type Prev = Bottom;
|
||||
|
||||
fn migrate(x: Self::Prev) -> Self { match x {} }
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
use super::*;
|
||||
use crate::data::World;
|
||||
|
||||
impl Latest<crate::data::World> for WorldV0 {
|
||||
fn to_unversioned(self) -> World { World {} }
|
||||
|
||||
fn from_unversioned(world: World) -> Self { Self {} }
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct WorldV0 {}
|
||||
|
||||
impl Version for WorldV0 {
|
||||
type Prev = Bottom;
|
||||
|
||||
fn migrate(x: Self::Prev) -> Self { match x {} }
|
||||
}
|
@ -1 +0,0 @@
|
||||
pub struct World {}
|
14
rtsim/src/gen/mod.rs
Normal file
14
rtsim/src/gen/mod.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use crate::data::{Actors, Data, Nature};
|
||||
use hashbrown::HashMap;
|
||||
use world::World;
|
||||
|
||||
impl Data {
|
||||
pub fn generate(world: &World) -> Self {
|
||||
Self {
|
||||
nature: Nature {},
|
||||
actors: Actors {
|
||||
actors: HashMap::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
pub mod data;
|
||||
pub mod gen;
|
||||
|
||||
/*
|
||||
pub struct RtState<'a> {
|
||||
use self::data::Data;
|
||||
use std::sync::Arc;
|
||||
use world::World;
|
||||
|
||||
pub struct RtState {
|
||||
pub data: Data,
|
||||
}
|
||||
*/
|
||||
|
@ -23,6 +23,7 @@ common-state = { package = "veloren-common-state", path = "../common/state" }
|
||||
common-systems = { package = "veloren-common-systems", path = "../common/systems" }
|
||||
common-net = { package = "veloren-common-net", path = "../common/net" }
|
||||
world = { package = "veloren-world", path = "../world" }
|
||||
rtsim2 = { package = "veloren-rtsim", path = "../rtsim" }
|
||||
network = { package = "veloren-network", path = "../network", features = ["metrics", "compression", "quic"], default-features = false }
|
||||
|
||||
server-agent = {package = "veloren-server-agent", path = "agent"}
|
||||
|
@ -236,7 +236,7 @@ pub struct ReadData<'a> {
|
||||
pub light_emitter: ReadStorage<'a, LightEmitter>,
|
||||
#[cfg(feature = "worldgen")]
|
||||
pub world: ReadExpect<'a, Arc<world::World>>,
|
||||
pub rtsim_entities: ReadStorage<'a, RtSimEntity>,
|
||||
// pub rtsim_entities: ReadStorage<'a, RtSimEntity>,
|
||||
pub buffs: ReadStorage<'a, Buffs>,
|
||||
pub combos: ReadStorage<'a, Combo>,
|
||||
pub active_abilities: ReadStorage<'a, ActiveAbilities>,
|
||||
|
@ -9,6 +9,7 @@ pub enum Error {
|
||||
StreamErr(StreamError),
|
||||
DatabaseErr(rusqlite::Error),
|
||||
PersistenceErr(PersistenceError),
|
||||
RtsimError(ron::Error),
|
||||
Other(String),
|
||||
}
|
||||
|
||||
@ -41,6 +42,7 @@ impl Display for Error {
|
||||
Self::StreamErr(err) => write!(f, "Stream Error: {}", err),
|
||||
Self::DatabaseErr(err) => write!(f, "Database Error: {}", err),
|
||||
Self::PersistenceErr(err) => write!(f, "Persistence Error: {}", err),
|
||||
Self::RtsimError(err) => write!(f, "Rtsim Error: {}", err),
|
||||
Self::Other(err) => write!(f, "Error: {}", err),
|
||||
}
|
||||
}
|
||||
|
@ -519,6 +519,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt
|
||||
}
|
||||
|
||||
if should_delete {
|
||||
/*
|
||||
if let Some(rtsim_entity) = state
|
||||
.ecs()
|
||||
.read_storage::<RtSimEntity>()
|
||||
@ -530,6 +531,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt
|
||||
.write_resource::<RtSim>()
|
||||
.destroy_entity(rtsim_entity.0);
|
||||
}
|
||||
*/
|
||||
|
||||
if let Err(e) = state.delete_entity_recorded(entity) {
|
||||
error!(?e, ?entity, "Failed to delete destroyed entity");
|
||||
|
@ -30,6 +30,7 @@ pub mod persistence;
|
||||
mod pet;
|
||||
pub mod presence;
|
||||
pub mod rtsim;
|
||||
pub mod rtsim2;
|
||||
pub mod settings;
|
||||
pub mod state_ext;
|
||||
pub mod sys;
|
||||
@ -548,6 +549,7 @@ impl Server {
|
||||
let connection_handler = ConnectionHandler::new(network, &runtime);
|
||||
|
||||
// Initiate real-time world simulation
|
||||
/*
|
||||
#[cfg(feature = "worldgen")]
|
||||
{
|
||||
rtsim::init(&mut state, &world, index.as_index_ref());
|
||||
@ -555,6 +557,20 @@ impl Server {
|
||||
}
|
||||
#[cfg(not(feature = "worldgen"))]
|
||||
rtsim::init(&mut state);
|
||||
*/
|
||||
|
||||
// Init rtsim, loading it from disk if possible
|
||||
#[cfg(feature = "worldgen")]
|
||||
{
|
||||
match rtsim2::RtSim::new(&world, data_dir.to_owned()) {
|
||||
Ok(rtsim) => state.ecs_mut().insert(rtsim),
|
||||
Err(err) => {
|
||||
error!("Failed to load rtsim: {}", err);
|
||||
return Err(Error::RtsimError(err));
|
||||
},
|
||||
}
|
||||
weather::init(&mut state, &world);
|
||||
}
|
||||
|
||||
let server_constants = ServerConstants {
|
||||
day_cycle_coefficient: 1440.0 / settings.day_length,
|
||||
@ -694,11 +710,18 @@ impl Server {
|
||||
add_local_systems(dispatcher_builder);
|
||||
sys::msg::add_server_systems(dispatcher_builder);
|
||||
sys::add_server_systems(dispatcher_builder);
|
||||
/*
|
||||
#[cfg(feature = "worldgen")]
|
||||
{
|
||||
rtsim::add_server_systems(dispatcher_builder);
|
||||
weather::add_server_systems(dispatcher_builder);
|
||||
}
|
||||
*/
|
||||
#[cfg(feature = "worldgen")]
|
||||
{
|
||||
rtsim2::add_server_systems(dispatcher_builder);
|
||||
weather::add_server_systems(dispatcher_builder);
|
||||
}
|
||||
},
|
||||
false,
|
||||
Some(&mut state_tick_metrics),
|
||||
@ -805,6 +828,7 @@ impl Server {
|
||||
};
|
||||
|
||||
for entity in to_delete {
|
||||
/*
|
||||
// Assimilate entities that are part of the real-time world simulation
|
||||
if let Some(rtsim_entity) = self
|
||||
.state
|
||||
@ -818,6 +842,7 @@ impl Server {
|
||||
.write_resource::<RtSim>()
|
||||
.assimilate_entity(rtsim_entity.0);
|
||||
}
|
||||
*/
|
||||
|
||||
if let Err(e) = self.state.delete_entity_recorded(entity) {
|
||||
error!(?e, "Failed to delete agent outside the terrain");
|
||||
|
70
server/src/rtsim2/mod.rs
Normal file
70
server/src/rtsim2/mod.rs
Normal file
@ -0,0 +1,70 @@
|
||||
pub mod tick;
|
||||
|
||||
use common::grid::Grid;
|
||||
use common_ecs::{dispatch, System};
|
||||
use rtsim2::{data::Data, RtState};
|
||||
use specs::{DispatcherBuilder, WorldExt};
|
||||
use std::{fs::File, io, path::PathBuf, sync::Arc};
|
||||
use tracing::info;
|
||||
use vek::*;
|
||||
use world::World;
|
||||
|
||||
pub struct RtSim {
|
||||
file_path: PathBuf,
|
||||
chunk_states: Grid<bool>, // true = loaded
|
||||
state: RtState,
|
||||
}
|
||||
|
||||
impl RtSim {
|
||||
pub fn new(world: &World, data_dir: PathBuf) -> Result<Self, ron::Error> {
|
||||
let file_path = Self::get_file_path(data_dir);
|
||||
|
||||
Ok(Self {
|
||||
chunk_states: Grid::populate_from(world.sim().get_size().as_(), |_| false),
|
||||
state: RtState {
|
||||
data: {
|
||||
info!("Looking for rtsim state in {}...", file_path.display());
|
||||
match File::open(&file_path) {
|
||||
Ok(file) => {
|
||||
info!("Rtsim state found. Attending to load...");
|
||||
Data::from_reader(file)?
|
||||
},
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => {
|
||||
info!("No rtsim state found. Generating from initial world state...");
|
||||
Data::generate(&world)
|
||||
},
|
||||
Err(e) => return Err(e.into()),
|
||||
}
|
||||
},
|
||||
},
|
||||
file_path,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_file_path(mut data_dir: PathBuf) -> PathBuf {
|
||||
let mut path = std::env::var("VELOREN_RTSIM")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| {
|
||||
data_dir.push("rtsim");
|
||||
data_dir
|
||||
});
|
||||
path.push("state.ron");
|
||||
path
|
||||
}
|
||||
|
||||
pub fn hook_load_chunk(&mut self, key: Vec2<i32>) {
|
||||
if let Some(is_loaded) = self.chunk_states.get_mut(key) {
|
||||
*is_loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hook_unload_chunk(&mut self, key: Vec2<i32>) {
|
||||
if let Some(is_loaded) = self.chunk_states.get_mut(key) {
|
||||
*is_loaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
dispatch::<tick::Sys>(dispatch_builder, &[]);
|
||||
}
|
179
server/src/rtsim2/tick.rs
Normal file
179
server/src/rtsim2/tick.rs
Normal file
@ -0,0 +1,179 @@
|
||||
#![allow(dead_code)] // TODO: Remove this when rtsim is fleshed out
|
||||
|
||||
use super::*;
|
||||
use crate::sys::terrain::NpcData;
|
||||
use common::{
|
||||
comp,
|
||||
event::{EventBus, ServerEvent},
|
||||
generation::{BodyBuilder, EntityConfig, EntityInfo},
|
||||
resources::{DeltaTime, Time},
|
||||
};
|
||||
use common_ecs::{Job, Origin, Phase, System};
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Read<'a, DeltaTime>,
|
||||
Read<'a, Time>,
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
WriteExpect<'a, RtSim>,
|
||||
ReadExpect<'a, Arc<world::World>>,
|
||||
ReadExpect<'a, world::IndexOwned>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "rtsim::tick";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
_job: &mut Job<Self>,
|
||||
(dt, time, server_event_bus, mut rtsim, world, index): Self::SystemData,
|
||||
) {
|
||||
let rtsim = &mut *rtsim;
|
||||
// rtsim.tick += 1;
|
||||
|
||||
// Update unloaded rtsim entities, in groups at a time
|
||||
/*
|
||||
const TICK_STAGGER: usize = 30;
|
||||
let entities_per_iteration = rtsim.entities.len() / TICK_STAGGER;
|
||||
let mut to_reify = Vec::new();
|
||||
for (id, entity) in rtsim
|
||||
.entities
|
||||
.iter_mut()
|
||||
.skip((rtsim.tick as usize % TICK_STAGGER) * entities_per_iteration)
|
||||
.take(entities_per_iteration)
|
||||
.filter(|(_, e)| !e.is_loaded)
|
||||
{
|
||||
if rtsim
|
||||
.chunk_states
|
||||
.get(entity.pos.xy())
|
||||
.copied()
|
||||
.unwrap_or(false)
|
||||
{
|
||||
to_reify.push(id);
|
||||
} else {
|
||||
// Simulate behaviour
|
||||
if let Some(travel_to) = &entity.controller.travel_to {
|
||||
// Move towards target at approximate character speed
|
||||
entity.pos += Vec3::from(
|
||||
(travel_to.0.xy() - entity.pos.xy())
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::zero)
|
||||
* entity.get_body().max_speed_approx()
|
||||
* entity.controller.speed_factor,
|
||||
) * dt;
|
||||
}
|
||||
|
||||
if let Some(alt) = world
|
||||
.sim()
|
||||
.get_alt_approx(entity.pos.xy().map(|e| e.floor() as i32))
|
||||
{
|
||||
entity.pos.z = alt;
|
||||
}
|
||||
}
|
||||
// entity.tick(&time, &terrain, &world, &index.as_index_ref());
|
||||
}
|
||||
*/
|
||||
|
||||
// Tick entity AI each time if it's loaded
|
||||
// for (_, entity) in rtsim.entities.iter_mut().filter(|(_, e)|
|
||||
// e.is_loaded) { entity.last_time_ticked = time.0;
|
||||
// entity.tick(&time, &terrain, &world, &index.as_index_ref());
|
||||
// }
|
||||
|
||||
/*
|
||||
let mut server_emitter = server_event_bus.emitter();
|
||||
for id in to_reify {
|
||||
rtsim.reify_entity(id);
|
||||
let entity = &rtsim.entities[id];
|
||||
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 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_path = 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_config = EntityConfig::from_asset_expect_owned(entity_config_path)
|
||||
.with_body(BodyBuilder::Exact(body));
|
||||
|
||||
let mut entity_info = EntityInfo::at(pos.0)
|
||||
.with_entity_config(entity_config, Some(entity_config_path), &mut loadout_rng)
|
||||
.with_lazy_loadout(ad_hoc_loadout);
|
||||
// Merchants can be traded with
|
||||
if let Some(economy) = entity.get_trade_info(&world, &index) {
|
||||
entity_info = entity_info
|
||||
.with_agent_mark(comp::agent::Mark::Merchant)
|
||||
.with_economy(&economy);
|
||||
}
|
||||
match NpcData::from_entity_info(entity_info) {
|
||||
NpcData::Data {
|
||||
pos,
|
||||
stats,
|
||||
skill_set,
|
||||
health,
|
||||
poise,
|
||||
inventory,
|
||||
agent,
|
||||
body,
|
||||
alignment,
|
||||
scale,
|
||||
loot,
|
||||
} => ServerEvent::CreateNpc {
|
||||
pos,
|
||||
stats,
|
||||
skill_set,
|
||||
health,
|
||||
poise,
|
||||
inventory,
|
||||
agent,
|
||||
body,
|
||||
alignment,
|
||||
scale,
|
||||
anchor: None,
|
||||
loot,
|
||||
rtsim_entity,
|
||||
projectile: None,
|
||||
},
|
||||
// EntityConfig can't represent Waypoints at all
|
||||
// as of now, and if someone will try to spawn
|
||||
// rtsim waypoint it is definitely error.
|
||||
NpcData::Waypoint(_) => unimplemented!(),
|
||||
}
|
||||
};
|
||||
server_emitter.emit(event);
|
||||
}
|
||||
|
||||
// Update rtsim with real entity data
|
||||
for (pos, rtsim_entity, agent) in (&positions, &rtsim_entities, &mut agents).join() {
|
||||
rtsim
|
||||
.entities
|
||||
.get_mut(rtsim_entity.0)
|
||||
.filter(|e| e.is_loaded)
|
||||
.map(|entity| {
|
||||
entity.pos = pos.0;
|
||||
agent.rtsim_controller = entity.controller.clone();
|
||||
});
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
@ -32,7 +32,7 @@ impl<'a> System<'a> for Sys {
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
WriteStorage<'a, Agent>,
|
||||
WriteStorage<'a, Controller>,
|
||||
WriteExpect<'a, RtSim>,
|
||||
//WriteExpect<'a, RtSim>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "agent";
|
||||
@ -41,9 +41,9 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
fn run(
|
||||
job: &mut Job<Self>,
|
||||
(read_data, event_bus, mut agents, mut controllers, mut rtsim): Self::SystemData,
|
||||
(read_data, event_bus, mut agents, mut controllers /* mut rtsim */): Self::SystemData,
|
||||
) {
|
||||
let rtsim = &mut *rtsim;
|
||||
//let rtsim = &mut *rtsim;
|
||||
job.cpu_stats.measure(ParMode::Rayon);
|
||||
|
||||
(
|
||||
@ -161,10 +161,12 @@ impl<'a> System<'a> for Sys {
|
||||
can_fly: body.map_or(false, |b| b.fly_thrust().is_some()),
|
||||
};
|
||||
let health_fraction = health.map_or(1.0, Health::fraction);
|
||||
/*
|
||||
let rtsim_entity = read_data
|
||||
.rtsim_entities
|
||||
.get(entity)
|
||||
.and_then(|rtsim_ent| rtsim.get_entity(rtsim_ent.0));
|
||||
*/
|
||||
|
||||
if traversal_config.can_fly && matches!(body, Some(Body::Ship(_))) {
|
||||
// hack (kinda): Never turn off flight airships
|
||||
@ -226,7 +228,7 @@ impl<'a> System<'a> for Sys {
|
||||
// inputs.
|
||||
let mut behavior_data = BehaviorData {
|
||||
agent,
|
||||
rtsim_entity,
|
||||
// rtsim_entity,
|
||||
agent_data: data,
|
||||
read_data: &read_data,
|
||||
event_emitter: &mut event_emitter,
|
||||
@ -240,6 +242,7 @@ impl<'a> System<'a> for Sys {
|
||||
debug_assert!(controller.inputs.look_dir.map(|e| !e.is_nan()).reduce_and());
|
||||
},
|
||||
);
|
||||
/*
|
||||
for (agent, rtsim_entity) in (&mut agents, &read_data.rtsim_entities).join() {
|
||||
// Entity must be loaded in as it has an agent component :)
|
||||
// React to all events in the controller
|
||||
@ -258,5 +261,6 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ pub struct BehaviorData<'a, 'b, 'c> {
|
||||
pub agent: &'a mut Agent,
|
||||
pub agent_data: AgentData<'a>,
|
||||
// TODO: Move rtsim back into AgentData after rtsim2 when it has a separate crate
|
||||
pub rtsim_entity: Option<&'a RtSimEntity>,
|
||||
// pub rtsim_entity: Option<&'a RtSimEntity>,
|
||||
pub read_data: &'a ReadData<'a>,
|
||||
pub event_emitter: &'a mut Emitter<'c, ServerEvent>,
|
||||
pub controller: &'a mut Controller,
|
||||
@ -277,6 +277,7 @@ fn target_if_attacked(bdata: &mut BehaviorData) -> bool {
|
||||
}
|
||||
|
||||
// Remember this attack if we're an RtSim entity
|
||||
/*
|
||||
if let Some(attacker_stats) =
|
||||
bdata.rtsim_entity.and(bdata.read_data.stats.get(attacker))
|
||||
{
|
||||
@ -284,6 +285,7 @@ fn target_if_attacked(bdata: &mut BehaviorData) -> bool {
|
||||
.agent
|
||||
.add_fight_to_memory(&attacker_stats.name, bdata.read_data.time.0);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -316,9 +318,11 @@ fn untarget_if_dead(bdata: &mut BehaviorData) -> bool {
|
||||
if let Some(tgt_health) = bdata.read_data.healths.get(target) {
|
||||
// If target is dead, forget them
|
||||
if tgt_health.is_dead {
|
||||
/*
|
||||
if let Some(tgt_stats) = bdata.rtsim_entity.and(bdata.read_data.stats.get(target)) {
|
||||
bdata.agent.forget_enemy(&tgt_stats.name);
|
||||
}
|
||||
*/
|
||||
bdata.agent.target = None;
|
||||
return true;
|
||||
}
|
||||
@ -496,7 +500,7 @@ fn handle_timed_events(bdata: &mut BehaviorData) -> bool {
|
||||
bdata.controller,
|
||||
bdata.read_data,
|
||||
bdata.event_emitter,
|
||||
will_ambush(bdata.rtsim_entity, &bdata.agent_data),
|
||||
will_ambush(/* bdata.rtsim_entity */ None, &bdata.agent_data),
|
||||
);
|
||||
} else {
|
||||
bdata.agent_data.handle_sounds_heard(
|
||||
@ -639,7 +643,7 @@ fn do_combat(bdata: &mut BehaviorData) -> bool {
|
||||
let BehaviorData {
|
||||
agent,
|
||||
agent_data,
|
||||
rtsim_entity,
|
||||
// rtsim_entity,
|
||||
read_data,
|
||||
event_emitter,
|
||||
controller,
|
||||
@ -746,7 +750,7 @@ fn do_combat(bdata: &mut BehaviorData) -> bool {
|
||||
controller,
|
||||
read_data,
|
||||
event_emitter,
|
||||
will_ambush(*rtsim_entity, agent_data),
|
||||
will_ambush(/* *rtsim_entity */None, agent_data),
|
||||
);
|
||||
}
|
||||
|
||||
@ -764,9 +768,9 @@ fn do_combat(bdata: &mut BehaviorData) -> bool {
|
||||
read_data,
|
||||
event_emitter,
|
||||
rng,
|
||||
remembers_fight_with(*rtsim_entity, read_data, target),
|
||||
remembers_fight_with(/* *rtsim_entity */None, read_data, target),
|
||||
);
|
||||
remember_fight(*rtsim_entity, read_data, agent, target);
|
||||
remember_fight(/* *rtsim_entity */ None, read_data, agent, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -775,6 +779,7 @@ fn do_combat(bdata: &mut BehaviorData) -> bool {
|
||||
}
|
||||
|
||||
fn will_ambush(rtsim_entity: Option<&RtSimEntity>, agent_data: &AgentData) -> bool {
|
||||
// TODO: implement for rtsim2
|
||||
agent_data
|
||||
.health
|
||||
.map_or(false, |h| h.current() / h.maximum() > 0.7)
|
||||
@ -786,6 +791,7 @@ fn remembers_fight_with(
|
||||
read_data: &ReadData,
|
||||
other: EcsEntity,
|
||||
) -> bool {
|
||||
// TODO: implement for rtsim2
|
||||
let name = || read_data.stats.get(other).map(|stats| stats.name.clone());
|
||||
|
||||
rtsim_entity.map_or(false, |rtsim_entity| {
|
||||
|
@ -108,21 +108,17 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
||||
|
||||
match subject {
|
||||
Subject::Regular => {
|
||||
/*
|
||||
if let Some(rtsim_entity) = &bdata.rtsim_entity {
|
||||
if matches!(rtsim_entity.kind, RtSimEntityKind::Prisoner) {
|
||||
agent_data.chat_npc("npc-speech-prisoner", event_emitter);
|
||||
} else if let (
|
||||
Some((_travel_to, destination_name)),
|
||||
Some(rtsim_entity),
|
||||
) =
|
||||
(&agent.rtsim_controller.travel_to, &&bdata.rtsim_entity)
|
||||
{
|
||||
} else if let Some((_travel_to, destination_name) = &agent.rtsim_controller.travel_to {
|
||||
let personality = &rtsim_entity.brain.personality;
|
||||
let standard_response_msg = || -> String {
|
||||
if personality.will_ambush {
|
||||
format!(
|
||||
"I'm heading to {}! Want to come along? We'll \
|
||||
make great travel buddies, hehe.",
|
||||
"I'm heading to {}! Want to come along? We'll make \
|
||||
great travel buddies, hehe.",
|
||||
destination_name
|
||||
)
|
||||
} else if personality
|
||||
@ -153,15 +149,23 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
||||
));
|
||||
if rtsim_entity.brain.remembers_character(&tgt_stats.name) {
|
||||
if personality.will_ambush {
|
||||
"Just follow me a bit more, hehe.".to_string()
|
||||
format!(
|
||||
"I'm heading to {}! Want to come along? We'll \
|
||||
make great travel buddies, hehe.",
|
||||
destination_name
|
||||
)
|
||||
} else if personality
|
||||
.personality_traits
|
||||
.contains(PersonalityTrait::Extroverted)
|
||||
{
|
||||
if personality
|
||||
.personality_traits
|
||||
.contains(PersonalityTrait::Extroverted)
|
||||
{
|
||||
format!(
|
||||
"Greetings fair {}! It has been far too long \
|
||||
since last I saw you. I'm going to {} right \
|
||||
now.",
|
||||
"Greetings fair {}! It has been far \
|
||||
too long since last I saw you. I'm \
|
||||
going to {} right now.",
|
||||
&tgt_stats.name, destination_name
|
||||
)
|
||||
} else if personality
|
||||
@ -171,8 +175,8 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
||||
"Oh. It's you again.".to_string()
|
||||
} else {
|
||||
format!(
|
||||
"Hi again {}! Unfortunately I'm in a hurry \
|
||||
right now. See you!",
|
||||
"Hi again {}! Unfortunately I'm in a \
|
||||
hurry right now. See you!",
|
||||
&tgt_stats.name
|
||||
)
|
||||
}
|
||||
@ -183,10 +187,9 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
||||
standard_response_msg()
|
||||
};
|
||||
agent_data.chat_npc(msg, event_emitter);
|
||||
} else if agent
|
||||
.behavior
|
||||
.can_trade(agent_data.alignment.copied(), by)
|
||||
{
|
||||
}
|
||||
} else*/
|
||||
if agent.behavior.can_trade(agent_data.alignment.copied(), by) {
|
||||
if !agent.behavior.is(BehaviorState::TRADING) {
|
||||
controller.push_initiate_invite(by, InviteKind::Trade);
|
||||
agent_data.chat_npc(
|
||||
@ -195,7 +198,7 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
||||
);
|
||||
} else {
|
||||
let default_msg = "npc-speech-merchant_busy";
|
||||
let msg = &bdata.rtsim_entity.map_or(default_msg, |e| {
|
||||
let msg = default_msg/*agent_data.rtsim_entity.map_or(default_msg, |e| {
|
||||
if e.brain
|
||||
.personality
|
||||
.personality_traits
|
||||
@ -205,16 +208,20 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
||||
} else {
|
||||
default_msg
|
||||
}
|
||||
});
|
||||
})*/;
|
||||
agent_data.chat_npc(msg, event_emitter);
|
||||
}
|
||||
} else {
|
||||
let mut rng = thread_rng();
|
||||
if let Some(extreme_trait) = &bdata.rtsim_entity.and_then(|e| {
|
||||
/*if let Some(extreme_trait) =
|
||||
agent_data.rtsim_entity.and_then(|e| {
|
||||
e.brain.personality.random_chat_trait(&mut rng)
|
||||
}) {
|
||||
})
|
||||
{
|
||||
let msg = match extreme_trait {
|
||||
PersonalityTrait::Open => "npc-speech-villager_open",
|
||||
PersonalityTrait::Open => {
|
||||
"npc-speech-villager_open"
|
||||
},
|
||||
PersonalityTrait::Adventurous => {
|
||||
"npc-speech-villager_adventurous"
|
||||
},
|
||||
@ -262,11 +269,11 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
||||
},
|
||||
};
|
||||
agent_data.chat_npc(msg, event_emitter);
|
||||
} else {
|
||||
} else*/
|
||||
{
|
||||
agent_data.chat_npc("npc-speech-villager", event_emitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Subject::Trade => {
|
||||
if agent.behavior.can_trade(agent_data.alignment.copied(), by) {
|
||||
@ -295,6 +302,7 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
||||
}
|
||||
},
|
||||
Subject::Mood => {
|
||||
/*
|
||||
if let Some(rtsim_entity) = &bdata.rtsim_entity {
|
||||
if !rtsim_entity.brain.remembers_mood() {
|
||||
// TODO: the following code will need a rework to
|
||||
@ -325,7 +333,9 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
||||
2 => agent.rtsim_controller.events.push(
|
||||
RtSimEvent::SetMood(Memory {
|
||||
item: MemoryItem::Mood {
|
||||
state: MoodState::Bad(MoodContext::GoodWeather),
|
||||
state: MoodState::Bad(
|
||||
MoodContext::GoodWeather,
|
||||
),
|
||||
},
|
||||
time_to_forget: read_data.time.0 + 86400.0,
|
||||
}),
|
||||
@ -340,7 +350,7 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
||||
};
|
||||
agent_data.chat_npc(msg, event_emitter);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
},
|
||||
Subject::Location(location) => {
|
||||
if let Some(tgt_pos) = read_data.positions.get(target) {
|
||||
@ -750,6 +760,7 @@ pub fn handle_inbox_cancel_interactions(bdata: &mut BehaviorData) -> bool {
|
||||
if used {
|
||||
agent.inbox.pop_front();
|
||||
}
|
||||
return used;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
chunk_serialize::ChunkSendEntry,
|
||||
client::Client,
|
||||
presence::{Presence, RepositionOnChunkLoad},
|
||||
rtsim::RtSim,
|
||||
rtsim2,
|
||||
settings::Settings,
|
||||
ChunkRequest, Tick,
|
||||
};
|
||||
@ -49,6 +49,11 @@ pub type TerrainPersistenceData<'a> = ();
|
||||
|
||||
pub const SAFE_ZONE_RADIUS: f32 = 200.0;
|
||||
|
||||
#[cfg(feature = "worldgen")]
|
||||
type RtSimData<'a> = WriteExpect<'a, rtsim2::RtSim>;
|
||||
#[cfg(not(feature = "worldgen"))]
|
||||
type RtSimData<'a> = ();
|
||||
|
||||
/// This system will handle loading generated chunks and unloading
|
||||
/// unneeded chunks.
|
||||
/// 1. Inserts newly generated chunks into the TerrainGrid
|
||||
@ -73,7 +78,8 @@ impl<'a> System<'a> for Sys {
|
||||
WriteExpect<'a, TerrainGrid>,
|
||||
Write<'a, TerrainChanges>,
|
||||
Write<'a, Vec<ChunkRequest>>,
|
||||
WriteExpect<'a, RtSim>,
|
||||
//WriteExpect<'a, RtSim>,
|
||||
RtSimData<'a>,
|
||||
TerrainPersistenceData<'a>,
|
||||
WriteStorage<'a, Pos>,
|
||||
ReadStorage<'a, Presence>,
|
||||
@ -105,7 +111,8 @@ impl<'a> System<'a> for Sys {
|
||||
mut terrain,
|
||||
mut terrain_changes,
|
||||
mut chunk_requests,
|
||||
mut rtsim,
|
||||
//mut rtsim,
|
||||
mut rtsim2,
|
||||
mut _terrain_persistence,
|
||||
mut positions,
|
||||
presences,
|
||||
@ -174,7 +181,8 @@ impl<'a> System<'a> for Sys {
|
||||
terrain_changes.modified_chunks.insert(key);
|
||||
} else {
|
||||
terrain_changes.new_chunks.insert(key);
|
||||
rtsim.hook_load_chunk(key);
|
||||
#[cfg(feature = "worldgen")]
|
||||
rtsim2.hook_load_chunk(key);
|
||||
}
|
||||
|
||||
// Handle chunk supplement
|
||||
@ -378,7 +386,8 @@ impl<'a> System<'a> for Sys {
|
||||
// TODO: code duplication for chunk insertion between here and state.rs
|
||||
terrain.remove(key).map(|chunk| {
|
||||
terrain_changes.removed_chunks.insert(key);
|
||||
rtsim.hook_unload_chunk(key);
|
||||
#[cfg(feature = "worldgen")]
|
||||
rtsim2.hook_unload_chunk(key);
|
||||
chunk
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user