buildup times and portal model update

This commit is contained in:
Maxicarlos08 2023-07-18 00:47:19 +02:00
parent 14141ecc80
commit 25fcb04ad3
No known key found for this signature in database
13 changed files with 156 additions and 48 deletions

BIN
assets/voxygen/voxel/object/portal.vox (Stored with Git LFS)

Binary file not shown.

BIN
assets/voxygen/voxel/object/portal_active.vox (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -981,12 +981,22 @@
), ),
Portal: ( Portal: (
bone0: ( bone0: (
offset: (-11.0, -1.5, 0.0), offset: (-33.0, -33.0, 0.0),
central: ("object.portal"), central: ("object.portal"),
), ),
bone1: ( bone1: (
offset: (0.0, 0.0, 0.0), offset: (0.0, 0.0, 0.0),
central: ("armor.empty"), central: ("armor.empty"),
) )
),
PortalActive: (
bone0: (
offset: (-33.0, -33.0, 0.0),
central: ("object.portal_active"),
),
bone1: (
offset: (0.0, 0.0, 0.0),
central: ("armor.empty"),
) )
),
}) })

View File

@ -625,6 +625,7 @@ impl ServerChatCommand {
Float("y", 0., Required), Float("y", 0., Required),
Float("z", 0., Required), Float("z", 0., Required),
Boolean("requires_no_aggro", "true".to_string(), Optional), Boolean("requires_no_aggro", "true".to_string(), Optional),
Float("buildup_time", 5., Optional),
], ],
"Spawns a portal", "Spawns a portal",
Some(Moderator), Some(Moderator),

View File

@ -111,6 +111,7 @@ make_case_elim!(
LightningBolt = 96, LightningBolt = 96,
SpearIcicle = 97, SpearIcicle = 97,
Portal = 98, Portal = 98,
PortalActive = 99,
} }
); );
@ -121,7 +122,7 @@ impl Body {
} }
} }
pub const ALL_OBJECTS: [Body; 99] = [ pub const ALL_OBJECTS: [Body; 100] = [
Body::Arrow, Body::Arrow,
Body::Bomb, Body::Bomb,
Body::Scarecrow, Body::Scarecrow,
@ -221,6 +222,7 @@ pub const ALL_OBJECTS: [Body; 99] = [
Body::LightningBolt, Body::LightningBolt,
Body::SpearIcicle, Body::SpearIcicle,
Body::Portal, Body::Portal,
Body::PortalActive,
]; ];
impl From<Body> for super::Body { impl From<Body> for super::Body {
@ -329,6 +331,7 @@ impl Body {
Body::LightningBolt => "lightning_bolt", Body::LightningBolt => "lightning_bolt",
Body::SpearIcicle => "spear_icicle", Body::SpearIcicle => "spear_icicle",
Body::Portal => "portal", Body::Portal => "portal",
Self::PortalActive => "portal_active",
} }
} }
@ -453,7 +456,7 @@ impl Body {
Body::AdletTrap => 10.0, Body::AdletTrap => 10.0,
Body::Mine => 100.0, Body::Mine => 100.0,
Body::LightningBolt | Body::SpearIcicle => 20000.0, Body::LightningBolt | Body::SpearIcicle => 20000.0,
Body::Portal => 10., // I dont know really Body::Portal | Body::PortalActive => 10., // I dont know really
}; };
Mass(m) Mass(m)

View File

@ -3,7 +3,6 @@ use crate::{resources::Time, uid::Uid};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use specs::{Component, DerefFlaggedStorage}; use specs::{Component, DerefFlaggedStorage};
use std::time::Duration; use std::time::Duration;
use vek::Vec3;
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Object { pub enum Object {
@ -23,13 +22,3 @@ pub enum Object {
impl Component for Object { impl Component for Object {
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>; type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
} }
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Teleporter {
pub target: Vec3<f32>,
pub requires_no_aggro: bool,
}
impl Component for Teleporter {
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
}

View File

@ -34,6 +34,7 @@ pub mod projectile;
pub mod shockwave; pub mod shockwave;
pub mod skillset; pub mod skillset;
mod stats; mod stats;
mod teleport;
pub mod visual; pub mod visual;
// Reexports // Reexports
@ -86,7 +87,7 @@ pub use self::{
location::{MapMarker, MapMarkerChange, MapMarkerUpdate, Waypoint, WaypointArea}, location::{MapMarker, MapMarkerChange, MapMarkerUpdate, Waypoint, WaypointArea},
loot_owner::LootOwner, loot_owner::LootOwner,
melee::{Melee, MeleeConstructor, MeleeConstructorKind}, melee::{Melee, MeleeConstructor, MeleeConstructorKind},
misc::{Object, Teleporter}, misc::Object,
ori::Ori, ori::Ori,
pet::Pet, pet::Pet,
phys::{ phys::{
@ -103,6 +104,7 @@ pub use self::{
SkillGroup, SkillGroupKind, SkillSet, SkillGroup, SkillGroupKind, SkillSet,
}, },
stats::{Stats, StatsModifier}, stats::{Stats, StatsModifier},
teleport::{Teleporter, Teleporting},
visual::{LightAnimation, LightEmitter}, visual::{LightAnimation, LightEmitter},
}; };

View File

@ -0,0 +1,27 @@
use serde::{Deserialize, Serialize};
use specs::{Component, DerefFlaggedStorage, Entity};
use vek::Vec3;
use crate::resources::{Secs, Time};
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Teleporter {
pub target: Vec3<f32>,
pub requires_no_aggro: bool,
pub buildup_time: Secs,
}
impl Component for Teleporter {
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Teleporting {
pub teleport_start: Time,
pub portal: Entity,
pub end_time: Time,
}
impl Component for Teleporting {
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
}

View File

@ -220,6 +220,7 @@ impl State {
ecs.register::<comp::Admin>(); ecs.register::<comp::Admin>();
ecs.register::<comp::Stance>(); ecs.register::<comp::Stance>();
ecs.register::<comp::Teleporter>(); ecs.register::<comp::Teleporter>();
ecs.register::<comp::Teleporting>();
// Register components send from clients -> server // Register components send from clients -> server
ecs.register::<comp::Controller>(); ecs.register::<comp::Controller>();

View File

@ -2051,15 +2051,17 @@ fn handle_spawn_portal(
) -> CmdResult<()> { ) -> CmdResult<()> {
let pos = position(server, target, "target")?; let pos = position(server, target, "target")?;
if let (Some(x), Some(y), Some(z), requires_no_aggro) = if let (Some(x), Some(y), Some(z), requires_no_aggro, buildup_time) =
parse_cmd_args!(args, f32, f32, f32, bool) parse_cmd_args!(args, f32, f32, f32, bool, f64)
{ {
let requires_no_aggro = requires_no_aggro.unwrap_or(false); let requires_no_aggro = requires_no_aggro.unwrap_or(false);
let buildup_time = Secs(buildup_time.unwrap_or(0.));
server server
.state .state
.create_teleporter(pos, comp::Teleporter { .create_teleporter(pos, comp::Teleporter {
target: Vec3::new(x, y, z), target: Vec3::new(x, y, z),
requires_no_aggro, requires_no_aggro,
buildup_time,
}) })
.build(); .build();

View File

@ -1,16 +1,22 @@
use common::{ use common::{
comp::{Agent, ForceUpdate, Player, Pos, Teleporter}, comp::{object, Agent, Body, ForceUpdate, Player, Pos, Teleporter, Teleporting},
resources::Time,
CachedSpatialGrid, CachedSpatialGrid,
}; };
use common_ecs::{Origin, Phase, System}; use common_ecs::{Origin, Phase, System};
use specs::{Entities, Join, Read, ReadStorage, WriteStorage}; use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
use vek::Vec3;
const TELEPORT_RADIUS: f32 = 1.; const TELEPORT_RADIUS: f32 = 3.;
const MAX_AGGRO_DIST: f32 = 200.; // If an entity further than this is aggroed at a player, the portal will still work const MAX_AGGRO_DIST: f32 = 200.; // If an entity further than this is aggroed at a player, the portal will still work
#[derive(Default)] #[derive(Default)]
pub struct Sys; pub struct Sys;
fn in_portal_range(player_pos: Vec3<f32>, portal_pos: Vec3<f32>) -> bool {
player_pos.distance_squared(portal_pos) <= (TELEPORT_RADIUS).powi(2)
}
impl<'a> System<'a> for Sys { impl<'a> System<'a> for Sys {
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -19,7 +25,10 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, Teleporter>, ReadStorage<'a, Teleporter>,
ReadStorage<'a, Agent>, ReadStorage<'a, Agent>,
WriteStorage<'a, ForceUpdate>, WriteStorage<'a, ForceUpdate>,
WriteStorage<'a, Teleporting>,
WriteStorage<'a, Body>,
Read<'a, CachedSpatialGrid>, Read<'a, CachedSpatialGrid>,
Read<'a, Time>,
); );
const NAME: &'static str = "teleporter"; const NAME: &'static str = "teleporter";
@ -35,47 +44,101 @@ impl<'a> System<'a> for Sys {
teleporters, teleporters,
agent, agent,
mut forced_update, mut forced_update,
mut teleporting,
mut bodies,
spatial_grid, spatial_grid,
time,
): Self::SystemData, ): Self::SystemData,
) { ) {
let mut attempt_teleport = vec![]; let mut attempt_teleport = vec![];
let mut player_data = (&entities, &positions, &players).join(); let mut cancel_teleport = vec![];
let mut start_teleporting = vec![];
for (_entity, teleporter_pos, teleporter) in (&entities, &positions, &teleporters).join() { let mut player_data = (&entities, &positions, &players, teleporting.maybe()).join();
let nearby_entities = spatial_grid
let check_aggro = |entity, pos: Vec3<f32>| {
spatial_grid
.0 .0
.in_circle_aabr(teleporter_pos.0.xy(), TELEPORT_RADIUS); .in_circle_aabr(pos.xy(), MAX_AGGRO_DIST)
for (entity, position, _) in nearby_entities.filter_map(|entity| {
player_data
.get(entity, &entities)
.filter(|(_, player_pos, _)| {
player_pos.0.distance_squared(teleporter_pos.0) <= (TELEPORT_RADIUS).powi(2)
})
}) {
// TODO: Check for aggro
attempt_teleport.push((entity, position.0, teleporter))
}
}
for (entity, origin_pos, teleporter) in attempt_teleport {
if teleporter.requires_no_aggro {
// FIXME: How does this go with performance?
let is_aggroed = spatial_grid
.0
.in_circle_aabr(origin_pos.xy(), MAX_AGGRO_DIST)
.any(|agent_entity| { .any(|agent_entity| {
agent.get(agent_entity).map_or(false, |agent| { agent.get(agent_entity).map_or(false, |agent| {
agent.target.map_or(false, |agent_target| { agent.target.map_or(false, |agent_target| {
agent_target.target == entity && agent_target.aggro_on agent_target.target == entity && agent_target.aggro_on
}) })
}) })
}); })
};
for (portal_entity, teleporter_pos, mut body, teleporter) in
(&entities, &positions, &mut bodies, &teleporters).join()
{
let nearby_entities = spatial_grid
.0
.in_circle_aabr(teleporter_pos.0.xy(), TELEPORT_RADIUS);
let mut is_active = false;
for (entity, pos, _, teleporting) in nearby_entities.filter_map(|entity| {
player_data
.get(entity, &entities)
.filter(|(_, player_pos, _, _)| in_portal_range(player_pos.0, teleporter_pos.0))
}) {
if teleporter.requires_no_aggro && check_aggro(entity, pos.0) {
if teleporting.is_some() {
cancel_teleport.push(entity)
};
if is_aggroed {
continue; continue;
} }
if teleporting.is_none() {
start_teleporting.push((entity, Teleporting {
teleport_start: *time,
portal: portal_entity,
end_time: Time(time.0 + teleporter.buildup_time.0),
}));
} }
is_active = true;
}
if (*body == Body::Object(object::Body::PortalActive)) != is_active {
*body = Body::Object(if is_active {
object::Body::PortalActive
} else {
object::Body::Portal
});
}
}
for (entity, teleporting_data) in start_teleporting {
let _ = teleporting.insert(entity, teleporting_data);
}
for (entity, position, _, teleporting) in
(&entities, &positions, &players, &teleporting).join()
{
let portal_pos = positions.get(teleporting.portal);
let Some(teleporter) = teleporters.get(teleporting.portal) else {
cancel_teleport.push(entity);
continue
};
if portal_pos.map_or(true, |portal_pos| {
!in_portal_range(position.0, portal_pos.0)
}) {
cancel_teleport.push(entity);
} else if teleporting.end_time.0 <= time.0 {
attempt_teleport.push((entity, *teleporter));
cancel_teleport.push(entity);
}
}
for entity in cancel_teleport {
teleporting.remove(entity);
}
for (entity, teleporter) in attempt_teleport {
positions positions
.get_mut(entity) .get_mut(entity)
.map(|position| position.0 = teleporter.target); .map(|position| position.0 = teleporter.target);

View File

@ -3,7 +3,10 @@ use crate::{
util::{RandomField, Sampler, CARDINALS}, util::{RandomField, Sampler, CARDINALS},
Land, Land,
}; };
use common::{terrain::{BlockKind, SpriteKind}, generation::SpecialEntity}; use common::{
generation::SpecialEntity,
terrain::{BlockKind, SpriteKind},
};
use rand::prelude::*; use rand::prelude::*;
use std::sync::Arc; use std::sync::Arc;
use vek::*; use vek::*;
@ -326,7 +329,8 @@ impl Structure for CoastalWorkshop {
} }
painter.spawn( painter.spawn(
EntityInfo::at((center - 2).with_z(base - 2).map(|e| e as f32 + 0.5)).into_special(SpecialEntity::Waypoint), EntityInfo::at((center - 2).with_z(base - 2).map(|e| e as f32 + 0.5))
.into_special(SpecialEntity::Waypoint),
); );
} }
} }

View File

@ -11,6 +11,7 @@ use common::{
astar::Astar, astar::Astar,
comp::Teleporter, comp::Teleporter,
generation::{ChunkSupplement, EntityInfo, SpecialEntity}, generation::{ChunkSupplement, EntityInfo, SpecialEntity},
resources::Secs,
store::{Id, Store}, store::{Id, Store},
terrain::{ terrain::{
BiomeKind, Block, BlockKind, SpriteKind, Structure, StructuresGroup, TerrainChunkSize, BiomeKind, Block, BlockKind, SpriteKind, Structure, StructuresGroup, TerrainChunkSize,
@ -668,12 +669,14 @@ impl Floor {
SpecialEntity::Teleporter(Teleporter { SpecialEntity::Teleporter(Teleporter {
target: bottom_pos+ Vec3::unit_x() * 5., target: bottom_pos+ Vec3::unit_x() * 5.,
requires_no_aggro: false, requires_no_aggro: false,
buildup_time: Secs(1.),
}), }),
)); ));
supplement.add_entity(EntityInfo::at(bottom_pos).into_special( supplement.add_entity(EntityInfo::at(bottom_pos).into_special(
SpecialEntity::Teleporter(Teleporter { SpecialEntity::Teleporter(Teleporter {
target: top_pos+ Vec3::unit_x() * 5., target: top_pos+ Vec3::unit_x() * 5.,
requires_no_aggro: true, requires_no_aggro: true,
buildup_time: Secs(3.),
}), }),
)); ));
} }