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"
|
name = "veloren-rtsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ron 0.7.0",
|
"hashbrown 0.12.3",
|
||||||
|
"ron 0.8.0",
|
||||||
"serde",
|
"serde",
|
||||||
"veloren-common",
|
"veloren-common",
|
||||||
|
"veloren-world",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -6942,6 +6944,7 @@ dependencies = [
|
|||||||
"veloren-common-systems",
|
"veloren-common-systems",
|
||||||
"veloren-network",
|
"veloren-network",
|
||||||
"veloren-plugin-api",
|
"veloren-plugin-api",
|
||||||
|
"veloren-rtsim",
|
||||||
"veloren-server-agent",
|
"veloren-server-agent",
|
||||||
"veloren-world",
|
"veloren-world",
|
||||||
]
|
]
|
||||||
|
@ -5,5 +5,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
common = { package = "veloren-common", path = "../common" }
|
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"] }
|
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,
|
Deserialize, Deserializer, Serialize, Serializer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default, PartialEq, Eq, Hash)]
|
||||||
pub struct V<T>(pub T);
|
pub struct V<T>(pub T);
|
||||||
|
|
||||||
impl<T: Serialize> Serialize for V<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> {
|
impl<U, T: Latest<U>> Latest<U> for V<T> {
|
||||||
fn to_unversioned(self) -> U { self.0.to_unversioned() }
|
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> {
|
pub trait Latest<T> {
|
||||||
fn to_unversioned(self) -> T;
|
fn to_unversioned(self) -> T;
|
||||||
fn from_unversioned(x: T) -> Self;
|
fn from_unversioned(x: &T) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Version: Sized + DeserializeOwned {
|
pub trait Version: Sized + DeserializeOwned {
|
||||||
|
@ -1,10 +1,30 @@
|
|||||||
pub mod helper;
|
pub mod helper;
|
||||||
pub mod version;
|
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 {
|
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,11 +15,17 @@
|
|||||||
// conclusion that there's just no way to add the feature you want to add
|
// 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.
|
// 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
|
// Please note that in *very specific* cases, it is possible to make a change to
|
||||||
// module, or submodules.
|
// 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
|
// 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).
|
// for it (later versions should be kept at the top of each file).
|
||||||
//
|
//
|
||||||
// 2) Rename the duplicated version, incrementing the version number (i.e: V0
|
// 2) Rename the duplicated version, incrementing the version number (i.e: V0
|
||||||
// becomes V1).
|
// becomes V1).
|
||||||
@ -38,7 +44,8 @@
|
|||||||
// The *golden rule* is that, once merged to master, an old version's type must
|
// The *golden rule* is that, once merged to master, an old version's type must
|
||||||
// not be changed!
|
// not be changed!
|
||||||
|
|
||||||
pub mod world;
|
pub mod actor;
|
||||||
|
pub mod nature;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
helper::{Bottom, Latest, Version, V},
|
helper::{Bottom, Latest, Version, V},
|
||||||
@ -46,23 +53,28 @@ use super::{
|
|||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
impl Latest<Data> for DataV0 {
|
pub type LatestData = DataV0;
|
||||||
|
|
||||||
|
impl Latest<Data> for LatestData {
|
||||||
fn to_unversioned(self) -> Data {
|
fn to_unversioned(self) -> Data {
|
||||||
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 {
|
Self {
|
||||||
world: Latest::from_unversioned(data.world),
|
nature: Latest::from_unversioned(&data.nature),
|
||||||
|
actors: Latest::from_unversioned(&data.actors),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct DataV0 {
|
pub struct DataV0 {
|
||||||
world: V<world::WorldV0>,
|
nature: V<nature::NatureV0>,
|
||||||
|
actors: V<actor::ActorsV0>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Version for DataV0 {
|
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 data;
|
||||||
|
pub mod gen;
|
||||||
|
|
||||||
/*
|
use self::data::Data;
|
||||||
pub struct RtState<'a> {
|
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-systems = { package = "veloren-common-systems", path = "../common/systems" }
|
||||||
common-net = { package = "veloren-common-net", path = "../common/net" }
|
common-net = { package = "veloren-common-net", path = "../common/net" }
|
||||||
world = { package = "veloren-world", path = "../world" }
|
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 }
|
network = { package = "veloren-network", path = "../network", features = ["metrics", "compression", "quic"], default-features = false }
|
||||||
|
|
||||||
server-agent = {package = "veloren-server-agent", path = "agent"}
|
server-agent = {package = "veloren-server-agent", path = "agent"}
|
||||||
|
@ -236,7 +236,7 @@ pub struct ReadData<'a> {
|
|||||||
pub light_emitter: ReadStorage<'a, LightEmitter>,
|
pub light_emitter: ReadStorage<'a, LightEmitter>,
|
||||||
#[cfg(feature = "worldgen")]
|
#[cfg(feature = "worldgen")]
|
||||||
pub world: ReadExpect<'a, Arc<world::World>>,
|
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 buffs: ReadStorage<'a, Buffs>,
|
||||||
pub combos: ReadStorage<'a, Combo>,
|
pub combos: ReadStorage<'a, Combo>,
|
||||||
pub active_abilities: ReadStorage<'a, ActiveAbilities>,
|
pub active_abilities: ReadStorage<'a, ActiveAbilities>,
|
||||||
|
@ -9,6 +9,7 @@ pub enum Error {
|
|||||||
StreamErr(StreamError),
|
StreamErr(StreamError),
|
||||||
DatabaseErr(rusqlite::Error),
|
DatabaseErr(rusqlite::Error),
|
||||||
PersistenceErr(PersistenceError),
|
PersistenceErr(PersistenceError),
|
||||||
|
RtsimError(ron::Error),
|
||||||
Other(String),
|
Other(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ impl Display for Error {
|
|||||||
Self::StreamErr(err) => write!(f, "Stream Error: {}", err),
|
Self::StreamErr(err) => write!(f, "Stream Error: {}", err),
|
||||||
Self::DatabaseErr(err) => write!(f, "Database Error: {}", err),
|
Self::DatabaseErr(err) => write!(f, "Database Error: {}", err),
|
||||||
Self::PersistenceErr(err) => write!(f, "Persistence 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),
|
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 should_delete {
|
||||||
|
/*
|
||||||
if let Some(rtsim_entity) = state
|
if let Some(rtsim_entity) = state
|
||||||
.ecs()
|
.ecs()
|
||||||
.read_storage::<RtSimEntity>()
|
.read_storage::<RtSimEntity>()
|
||||||
@ -530,6 +531,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt
|
|||||||
.write_resource::<RtSim>()
|
.write_resource::<RtSim>()
|
||||||
.destroy_entity(rtsim_entity.0);
|
.destroy_entity(rtsim_entity.0);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
if let Err(e) = state.delete_entity_recorded(entity) {
|
if let Err(e) = state.delete_entity_recorded(entity) {
|
||||||
error!(?e, ?entity, "Failed to delete destroyed entity");
|
error!(?e, ?entity, "Failed to delete destroyed entity");
|
||||||
|
@ -30,6 +30,7 @@ pub mod persistence;
|
|||||||
mod pet;
|
mod pet;
|
||||||
pub mod presence;
|
pub mod presence;
|
||||||
pub mod rtsim;
|
pub mod rtsim;
|
||||||
|
pub mod rtsim2;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod state_ext;
|
pub mod state_ext;
|
||||||
pub mod sys;
|
pub mod sys;
|
||||||
@ -548,6 +549,7 @@ impl Server {
|
|||||||
let connection_handler = ConnectionHandler::new(network, &runtime);
|
let connection_handler = ConnectionHandler::new(network, &runtime);
|
||||||
|
|
||||||
// Initiate real-time world simulation
|
// Initiate real-time world simulation
|
||||||
|
/*
|
||||||
#[cfg(feature = "worldgen")]
|
#[cfg(feature = "worldgen")]
|
||||||
{
|
{
|
||||||
rtsim::init(&mut state, &world, index.as_index_ref());
|
rtsim::init(&mut state, &world, index.as_index_ref());
|
||||||
@ -555,6 +557,20 @@ impl Server {
|
|||||||
}
|
}
|
||||||
#[cfg(not(feature = "worldgen"))]
|
#[cfg(not(feature = "worldgen"))]
|
||||||
rtsim::init(&mut state);
|
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 {
|
let server_constants = ServerConstants {
|
||||||
day_cycle_coefficient: 1440.0 / settings.day_length,
|
day_cycle_coefficient: 1440.0 / settings.day_length,
|
||||||
@ -694,11 +710,18 @@ impl Server {
|
|||||||
add_local_systems(dispatcher_builder);
|
add_local_systems(dispatcher_builder);
|
||||||
sys::msg::add_server_systems(dispatcher_builder);
|
sys::msg::add_server_systems(dispatcher_builder);
|
||||||
sys::add_server_systems(dispatcher_builder);
|
sys::add_server_systems(dispatcher_builder);
|
||||||
|
/*
|
||||||
#[cfg(feature = "worldgen")]
|
#[cfg(feature = "worldgen")]
|
||||||
{
|
{
|
||||||
rtsim::add_server_systems(dispatcher_builder);
|
rtsim::add_server_systems(dispatcher_builder);
|
||||||
weather::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,
|
false,
|
||||||
Some(&mut state_tick_metrics),
|
Some(&mut state_tick_metrics),
|
||||||
@ -805,6 +828,7 @@ impl Server {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for entity in to_delete {
|
for entity in to_delete {
|
||||||
|
/*
|
||||||
// Assimilate entities that are part of the real-time world simulation
|
// Assimilate entities that are part of the real-time world simulation
|
||||||
if let Some(rtsim_entity) = self
|
if let Some(rtsim_entity) = self
|
||||||
.state
|
.state
|
||||||
@ -818,6 +842,7 @@ impl Server {
|
|||||||
.write_resource::<RtSim>()
|
.write_resource::<RtSim>()
|
||||||
.assimilate_entity(rtsim_entity.0);
|
.assimilate_entity(rtsim_entity.0);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
if let Err(e) = self.state.delete_entity_recorded(entity) {
|
if let Err(e) = self.state.delete_entity_recorded(entity) {
|
||||||
error!(?e, "Failed to delete agent outside the terrain");
|
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>>,
|
Read<'a, EventBus<ServerEvent>>,
|
||||||
WriteStorage<'a, Agent>,
|
WriteStorage<'a, Agent>,
|
||||||
WriteStorage<'a, Controller>,
|
WriteStorage<'a, Controller>,
|
||||||
WriteExpect<'a, RtSim>,
|
//WriteExpect<'a, RtSim>,
|
||||||
);
|
);
|
||||||
|
|
||||||
const NAME: &'static str = "agent";
|
const NAME: &'static str = "agent";
|
||||||
@ -41,9 +41,9 @@ impl<'a> System<'a> for Sys {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
job: &mut Job<Self>,
|
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);
|
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()),
|
can_fly: body.map_or(false, |b| b.fly_thrust().is_some()),
|
||||||
};
|
};
|
||||||
let health_fraction = health.map_or(1.0, Health::fraction);
|
let health_fraction = health.map_or(1.0, Health::fraction);
|
||||||
|
/*
|
||||||
let rtsim_entity = read_data
|
let rtsim_entity = read_data
|
||||||
.rtsim_entities
|
.rtsim_entities
|
||||||
.get(entity)
|
.get(entity)
|
||||||
.and_then(|rtsim_ent| rtsim.get_entity(rtsim_ent.0));
|
.and_then(|rtsim_ent| rtsim.get_entity(rtsim_ent.0));
|
||||||
|
*/
|
||||||
|
|
||||||
if traversal_config.can_fly && matches!(body, Some(Body::Ship(_))) {
|
if traversal_config.can_fly && matches!(body, Some(Body::Ship(_))) {
|
||||||
// hack (kinda): Never turn off flight airships
|
// hack (kinda): Never turn off flight airships
|
||||||
@ -226,7 +228,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
// inputs.
|
// inputs.
|
||||||
let mut behavior_data = BehaviorData {
|
let mut behavior_data = BehaviorData {
|
||||||
agent,
|
agent,
|
||||||
rtsim_entity,
|
// rtsim_entity,
|
||||||
agent_data: data,
|
agent_data: data,
|
||||||
read_data: &read_data,
|
read_data: &read_data,
|
||||||
event_emitter: &mut event_emitter,
|
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());
|
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() {
|
for (agent, rtsim_entity) in (&mut agents, &read_data.rtsim_entities).join() {
|
||||||
// Entity must be loaded in as it has an agent component :)
|
// Entity must be loaded in as it has an agent component :)
|
||||||
// React to all events in the controller
|
// 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: &'a mut Agent,
|
||||||
pub agent_data: AgentData<'a>,
|
pub agent_data: AgentData<'a>,
|
||||||
// TODO: Move rtsim back into AgentData after rtsim2 when it has a separate crate
|
// 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 read_data: &'a ReadData<'a>,
|
||||||
pub event_emitter: &'a mut Emitter<'c, ServerEvent>,
|
pub event_emitter: &'a mut Emitter<'c, ServerEvent>,
|
||||||
pub controller: &'a mut Controller,
|
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
|
// Remember this attack if we're an RtSim entity
|
||||||
|
/*
|
||||||
if let Some(attacker_stats) =
|
if let Some(attacker_stats) =
|
||||||
bdata.rtsim_entity.and(bdata.read_data.stats.get(attacker))
|
bdata.rtsim_entity.and(bdata.read_data.stats.get(attacker))
|
||||||
{
|
{
|
||||||
@ -284,6 +285,7 @@ fn target_if_attacked(bdata: &mut BehaviorData) -> bool {
|
|||||||
.agent
|
.agent
|
||||||
.add_fight_to_memory(&attacker_stats.name, bdata.read_data.time.0);
|
.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 let Some(tgt_health) = bdata.read_data.healths.get(target) {
|
||||||
// If target is dead, forget them
|
// If target is dead, forget them
|
||||||
if tgt_health.is_dead {
|
if tgt_health.is_dead {
|
||||||
|
/*
|
||||||
if let Some(tgt_stats) = bdata.rtsim_entity.and(bdata.read_data.stats.get(target)) {
|
if let Some(tgt_stats) = bdata.rtsim_entity.and(bdata.read_data.stats.get(target)) {
|
||||||
bdata.agent.forget_enemy(&tgt_stats.name);
|
bdata.agent.forget_enemy(&tgt_stats.name);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
bdata.agent.target = None;
|
bdata.agent.target = None;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -496,7 +500,7 @@ fn handle_timed_events(bdata: &mut BehaviorData) -> bool {
|
|||||||
bdata.controller,
|
bdata.controller,
|
||||||
bdata.read_data,
|
bdata.read_data,
|
||||||
bdata.event_emitter,
|
bdata.event_emitter,
|
||||||
will_ambush(bdata.rtsim_entity, &bdata.agent_data),
|
will_ambush(/* bdata.rtsim_entity */ None, &bdata.agent_data),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
bdata.agent_data.handle_sounds_heard(
|
bdata.agent_data.handle_sounds_heard(
|
||||||
@ -639,7 +643,7 @@ fn do_combat(bdata: &mut BehaviorData) -> bool {
|
|||||||
let BehaviorData {
|
let BehaviorData {
|
||||||
agent,
|
agent,
|
||||||
agent_data,
|
agent_data,
|
||||||
rtsim_entity,
|
// rtsim_entity,
|
||||||
read_data,
|
read_data,
|
||||||
event_emitter,
|
event_emitter,
|
||||||
controller,
|
controller,
|
||||||
@ -746,7 +750,7 @@ fn do_combat(bdata: &mut BehaviorData) -> bool {
|
|||||||
controller,
|
controller,
|
||||||
read_data,
|
read_data,
|
||||||
event_emitter,
|
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,
|
read_data,
|
||||||
event_emitter,
|
event_emitter,
|
||||||
rng,
|
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 {
|
fn will_ambush(rtsim_entity: Option<&RtSimEntity>, agent_data: &AgentData) -> bool {
|
||||||
|
// TODO: implement for rtsim2
|
||||||
agent_data
|
agent_data
|
||||||
.health
|
.health
|
||||||
.map_or(false, |h| h.current() / h.maximum() > 0.7)
|
.map_or(false, |h| h.current() / h.maximum() > 0.7)
|
||||||
@ -786,6 +791,7 @@ fn remembers_fight_with(
|
|||||||
read_data: &ReadData,
|
read_data: &ReadData,
|
||||||
other: EcsEntity,
|
other: EcsEntity,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
// TODO: implement for rtsim2
|
||||||
let name = || read_data.stats.get(other).map(|stats| stats.name.clone());
|
let name = || read_data.stats.get(other).map(|stats| stats.name.clone());
|
||||||
|
|
||||||
rtsim_entity.map_or(false, |rtsim_entity| {
|
rtsim_entity.map_or(false, |rtsim_entity| {
|
||||||
|
@ -108,21 +108,17 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
|||||||
|
|
||||||
match subject {
|
match subject {
|
||||||
Subject::Regular => {
|
Subject::Regular => {
|
||||||
|
/*
|
||||||
if let Some(rtsim_entity) = &bdata.rtsim_entity {
|
if let Some(rtsim_entity) = &bdata.rtsim_entity {
|
||||||
if matches!(rtsim_entity.kind, RtSimEntityKind::Prisoner) {
|
if matches!(rtsim_entity.kind, RtSimEntityKind::Prisoner) {
|
||||||
agent_data.chat_npc("npc-speech-prisoner", event_emitter);
|
agent_data.chat_npc("npc-speech-prisoner", event_emitter);
|
||||||
} else if let (
|
} else if let Some((_travel_to, destination_name) = &agent.rtsim_controller.travel_to {
|
||||||
Some((_travel_to, destination_name)),
|
|
||||||
Some(rtsim_entity),
|
|
||||||
) =
|
|
||||||
(&agent.rtsim_controller.travel_to, &&bdata.rtsim_entity)
|
|
||||||
{
|
|
||||||
let personality = &rtsim_entity.brain.personality;
|
let personality = &rtsim_entity.brain.personality;
|
||||||
let standard_response_msg = || -> String {
|
let standard_response_msg = || -> String {
|
||||||
if personality.will_ambush {
|
if personality.will_ambush {
|
||||||
format!(
|
format!(
|
||||||
"I'm heading to {}! Want to come along? We'll \
|
"I'm heading to {}! Want to come along? We'll make \
|
||||||
make great travel buddies, hehe.",
|
great travel buddies, hehe.",
|
||||||
destination_name
|
destination_name
|
||||||
)
|
)
|
||||||
} else if personality
|
} else if personality
|
||||||
@ -153,118 +149,129 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
|||||||
));
|
));
|
||||||
if rtsim_entity.brain.remembers_character(&tgt_stats.name) {
|
if rtsim_entity.brain.remembers_character(&tgt_stats.name) {
|
||||||
if personality.will_ambush {
|
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
|
} else if personality
|
||||||
.personality_traits
|
.personality_traits
|
||||||
.contains(PersonalityTrait::Extroverted)
|
.contains(PersonalityTrait::Extroverted)
|
||||||
{
|
{
|
||||||
format!(
|
if personality
|
||||||
"Greetings fair {}! It has been far too long \
|
.personality_traits
|
||||||
since last I saw you. I'm going to {} right \
|
.contains(PersonalityTrait::Extroverted)
|
||||||
now.",
|
{
|
||||||
&tgt_stats.name, destination_name
|
format!(
|
||||||
)
|
"Greetings fair {}! It has been far \
|
||||||
} else if personality
|
too long since last I saw you. I'm \
|
||||||
.personality_traits
|
going to {} right now.",
|
||||||
.contains(PersonalityTrait::Disagreeable)
|
&tgt_stats.name, destination_name
|
||||||
{
|
)
|
||||||
"Oh. It's you again.".to_string()
|
} else if personality
|
||||||
|
.personality_traits
|
||||||
|
.contains(PersonalityTrait::Disagreeable)
|
||||||
|
{
|
||||||
|
"Oh. It's you again.".to_string()
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"Hi again {}! Unfortunately I'm in a \
|
||||||
|
hurry right now. See you!",
|
||||||
|
&tgt_stats.name
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
format!(
|
standard_response_msg()
|
||||||
"Hi again {}! Unfortunately I'm in a hurry \
|
|
||||||
right now. See you!",
|
|
||||||
&tgt_stats.name
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
standard_response_msg()
|
standard_response_msg()
|
||||||
|
};
|
||||||
|
agent_data.chat_npc(msg, event_emitter);
|
||||||
|
}
|
||||||
|
} 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(
|
||||||
|
"npc-speech-merchant_advertisement",
|
||||||
|
event_emitter,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let default_msg = "npc-speech-merchant_busy";
|
||||||
|
let msg = default_msg/*agent_data.rtsim_entity.map_or(default_msg, |e| {
|
||||||
|
if e.brain
|
||||||
|
.personality
|
||||||
|
.personality_traits
|
||||||
|
.contains(PersonalityTrait::Disagreeable)
|
||||||
|
{
|
||||||
|
"npc-speech-merchant_busy_rude"
|
||||||
|
} else {
|
||||||
|
default_msg
|
||||||
}
|
}
|
||||||
} else {
|
})*/;
|
||||||
standard_response_msg()
|
agent_data.chat_npc(msg, event_emitter);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
/*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::Adventurous => {
|
||||||
|
"npc-speech-villager_adventurous"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Closed => {
|
||||||
|
"npc-speech-villager_closed"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Conscientious => {
|
||||||
|
"npc-speech-villager_conscientious"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Busybody => {
|
||||||
|
"npc-speech-villager_busybody"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Unconscientious => {
|
||||||
|
"npc-speech-villager_unconscientious"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Extroverted => {
|
||||||
|
"npc-speech-villager_extroverted"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Introverted => {
|
||||||
|
"npc-speech-villager_introverted"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Agreeable => {
|
||||||
|
"npc-speech-villager_agreeable"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Sociable => {
|
||||||
|
"npc-speech-villager_sociable"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Disagreeable => {
|
||||||
|
"npc-speech-villager_disagreeable"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Neurotic => {
|
||||||
|
"npc-speech-villager_neurotic"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Seeker => {
|
||||||
|
"npc-speech-villager_seeker"
|
||||||
|
},
|
||||||
|
PersonalityTrait::SadLoner => {
|
||||||
|
"npc-speech-villager_sad_loner"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Worried => {
|
||||||
|
"npc-speech-villager_worried"
|
||||||
|
},
|
||||||
|
PersonalityTrait::Stable => {
|
||||||
|
"npc-speech-villager_stable"
|
||||||
|
},
|
||||||
};
|
};
|
||||||
agent_data.chat_npc(msg, event_emitter);
|
agent_data.chat_npc(msg, event_emitter);
|
||||||
} else if agent
|
} else*/
|
||||||
.behavior
|
|
||||||
.can_trade(agent_data.alignment.copied(), by)
|
|
||||||
{
|
{
|
||||||
if !agent.behavior.is(BehaviorState::TRADING) {
|
agent_data.chat_npc("npc-speech-villager", event_emitter);
|
||||||
controller.push_initiate_invite(by, InviteKind::Trade);
|
|
||||||
agent_data.chat_npc(
|
|
||||||
"npc-speech-merchant_advertisement",
|
|
||||||
event_emitter,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let default_msg = "npc-speech-merchant_busy";
|
|
||||||
let msg = &bdata.rtsim_entity.map_or(default_msg, |e| {
|
|
||||||
if e.brain
|
|
||||||
.personality
|
|
||||||
.personality_traits
|
|
||||||
.contains(PersonalityTrait::Disagreeable)
|
|
||||||
{
|
|
||||||
"npc-speech-merchant_busy_rude"
|
|
||||||
} 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| {
|
|
||||||
e.brain.personality.random_chat_trait(&mut rng)
|
|
||||||
}) {
|
|
||||||
let msg = match extreme_trait {
|
|
||||||
PersonalityTrait::Open => "npc-speech-villager_open",
|
|
||||||
PersonalityTrait::Adventurous => {
|
|
||||||
"npc-speech-villager_adventurous"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Closed => {
|
|
||||||
"npc-speech-villager_closed"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Conscientious => {
|
|
||||||
"npc-speech-villager_conscientious"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Busybody => {
|
|
||||||
"npc-speech-villager_busybody"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Unconscientious => {
|
|
||||||
"npc-speech-villager_unconscientious"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Extroverted => {
|
|
||||||
"npc-speech-villager_extroverted"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Introverted => {
|
|
||||||
"npc-speech-villager_introverted"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Agreeable => {
|
|
||||||
"npc-speech-villager_agreeable"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Sociable => {
|
|
||||||
"npc-speech-villager_sociable"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Disagreeable => {
|
|
||||||
"npc-speech-villager_disagreeable"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Neurotic => {
|
|
||||||
"npc-speech-villager_neurotic"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Seeker => {
|
|
||||||
"npc-speech-villager_seeker"
|
|
||||||
},
|
|
||||||
PersonalityTrait::SadLoner => {
|
|
||||||
"npc-speech-villager_sad_loner"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Worried => {
|
|
||||||
"npc-speech-villager_worried"
|
|
||||||
},
|
|
||||||
PersonalityTrait::Stable => {
|
|
||||||
"npc-speech-villager_stable"
|
|
||||||
},
|
|
||||||
};
|
|
||||||
agent_data.chat_npc(msg, event_emitter);
|
|
||||||
} else {
|
|
||||||
agent_data.chat_npc("npc-speech-villager", event_emitter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -295,6 +302,7 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Subject::Mood => {
|
Subject::Mood => {
|
||||||
|
/*
|
||||||
if let Some(rtsim_entity) = &bdata.rtsim_entity {
|
if let Some(rtsim_entity) = &bdata.rtsim_entity {
|
||||||
if !rtsim_entity.brain.remembers_mood() {
|
if !rtsim_entity.brain.remembers_mood() {
|
||||||
// TODO: the following code will need a rework to
|
// 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(
|
2 => agent.rtsim_controller.events.push(
|
||||||
RtSimEvent::SetMood(Memory {
|
RtSimEvent::SetMood(Memory {
|
||||||
item: MemoryItem::Mood {
|
item: MemoryItem::Mood {
|
||||||
state: MoodState::Bad(MoodContext::GoodWeather),
|
state: MoodState::Bad(
|
||||||
|
MoodContext::GoodWeather,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
time_to_forget: read_data.time.0 + 86400.0,
|
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);
|
agent_data.chat_npc(msg, event_emitter);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
},
|
},
|
||||||
Subject::Location(location) => {
|
Subject::Location(location) => {
|
||||||
if let Some(tgt_pos) = read_data.positions.get(target) {
|
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 {
|
if used {
|
||||||
agent.inbox.pop_front();
|
agent.inbox.pop_front();
|
||||||
}
|
}
|
||||||
|
return used;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ use crate::{
|
|||||||
chunk_serialize::ChunkSendEntry,
|
chunk_serialize::ChunkSendEntry,
|
||||||
client::Client,
|
client::Client,
|
||||||
presence::{Presence, RepositionOnChunkLoad},
|
presence::{Presence, RepositionOnChunkLoad},
|
||||||
rtsim::RtSim,
|
rtsim2,
|
||||||
settings::Settings,
|
settings::Settings,
|
||||||
ChunkRequest, Tick,
|
ChunkRequest, Tick,
|
||||||
};
|
};
|
||||||
@ -49,6 +49,11 @@ pub type TerrainPersistenceData<'a> = ();
|
|||||||
|
|
||||||
pub const SAFE_ZONE_RADIUS: f32 = 200.0;
|
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
|
/// This system will handle loading generated chunks and unloading
|
||||||
/// unneeded chunks.
|
/// unneeded chunks.
|
||||||
/// 1. Inserts newly generated chunks into the TerrainGrid
|
/// 1. Inserts newly generated chunks into the TerrainGrid
|
||||||
@ -73,7 +78,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
WriteExpect<'a, TerrainGrid>,
|
WriteExpect<'a, TerrainGrid>,
|
||||||
Write<'a, TerrainChanges>,
|
Write<'a, TerrainChanges>,
|
||||||
Write<'a, Vec<ChunkRequest>>,
|
Write<'a, Vec<ChunkRequest>>,
|
||||||
WriteExpect<'a, RtSim>,
|
//WriteExpect<'a, RtSim>,
|
||||||
|
RtSimData<'a>,
|
||||||
TerrainPersistenceData<'a>,
|
TerrainPersistenceData<'a>,
|
||||||
WriteStorage<'a, Pos>,
|
WriteStorage<'a, Pos>,
|
||||||
ReadStorage<'a, Presence>,
|
ReadStorage<'a, Presence>,
|
||||||
@ -105,7 +111,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
mut terrain,
|
mut terrain,
|
||||||
mut terrain_changes,
|
mut terrain_changes,
|
||||||
mut chunk_requests,
|
mut chunk_requests,
|
||||||
mut rtsim,
|
//mut rtsim,
|
||||||
|
mut rtsim2,
|
||||||
mut _terrain_persistence,
|
mut _terrain_persistence,
|
||||||
mut positions,
|
mut positions,
|
||||||
presences,
|
presences,
|
||||||
@ -174,7 +181,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
terrain_changes.modified_chunks.insert(key);
|
terrain_changes.modified_chunks.insert(key);
|
||||||
} else {
|
} else {
|
||||||
terrain_changes.new_chunks.insert(key);
|
terrain_changes.new_chunks.insert(key);
|
||||||
rtsim.hook_load_chunk(key);
|
#[cfg(feature = "worldgen")]
|
||||||
|
rtsim2.hook_load_chunk(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle chunk supplement
|
// Handle chunk supplement
|
||||||
@ -378,7 +386,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
// TODO: code duplication for chunk insertion between here and state.rs
|
// TODO: code duplication for chunk insertion between here and state.rs
|
||||||
terrain.remove(key).map(|chunk| {
|
terrain.remove(key).map(|chunk| {
|
||||||
terrain_changes.removed_chunks.insert(key);
|
terrain_changes.removed_chunks.insert(key);
|
||||||
rtsim.hook_unload_chunk(key);
|
#[cfg(feature = "worldgen")]
|
||||||
|
rtsim2.hook_unload_chunk(key);
|
||||||
chunk
|
chunk
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user