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: (
bone0: (
offset: (-11.0, -1.5, 0.0),
offset: (-33.0, -33.0, 0.0),
central: ("object.portal"),
),
bone1: (
offset: (0.0, 0.0, 0.0),
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("z", 0., Required),
Boolean("requires_no_aggro", "true".to_string(), Optional),
Float("buildup_time", 5., Optional),
],
"Spawns a portal",
Some(Moderator),

View File

@ -111,6 +111,7 @@ make_case_elim!(
LightningBolt = 96,
SpearIcicle = 97,
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::Bomb,
Body::Scarecrow,
@ -221,6 +222,7 @@ pub const ALL_OBJECTS: [Body; 99] = [
Body::LightningBolt,
Body::SpearIcicle,
Body::Portal,
Body::PortalActive,
];
impl From<Body> for super::Body {
@ -329,6 +331,7 @@ impl Body {
Body::LightningBolt => "lightning_bolt",
Body::SpearIcicle => "spear_icicle",
Body::Portal => "portal",
Self::PortalActive => "portal_active",
}
}
@ -453,7 +456,7 @@ impl Body {
Body::AdletTrap => 10.0,
Body::Mine => 100.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)

View File

@ -3,7 +3,6 @@ use crate::{resources::Time, uid::Uid};
use serde::{Deserialize, Serialize};
use specs::{Component, DerefFlaggedStorage};
use std::time::Duration;
use vek::Vec3;
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Object {
@ -23,13 +22,3 @@ pub enum Object {
impl Component for Object {
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 skillset;
mod stats;
mod teleport;
pub mod visual;
// Reexports
@ -86,7 +87,7 @@ pub use self::{
location::{MapMarker, MapMarkerChange, MapMarkerUpdate, Waypoint, WaypointArea},
loot_owner::LootOwner,
melee::{Melee, MeleeConstructor, MeleeConstructorKind},
misc::{Object, Teleporter},
misc::Object,
ori::Ori,
pet::Pet,
phys::{
@ -103,6 +104,7 @@ pub use self::{
SkillGroup, SkillGroupKind, SkillSet,
},
stats::{Stats, StatsModifier},
teleport::{Teleporter, Teleporting},
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::Stance>();
ecs.register::<comp::Teleporter>();
ecs.register::<comp::Teleporting>();
// Register components send from clients -> server
ecs.register::<comp::Controller>();

View File

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

View File

@ -1,16 +1,22 @@
use common::{
comp::{Agent, ForceUpdate, Player, Pos, Teleporter},
comp::{object, Agent, Body, ForceUpdate, Player, Pos, Teleporter, Teleporting},
resources::Time,
CachedSpatialGrid,
};
use common_ecs::{Origin, Phase, System};
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
#[derive(Default)]
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 {
type SystemData = (
Entities<'a>,
@ -19,7 +25,10 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, Teleporter>,
ReadStorage<'a, Agent>,
WriteStorage<'a, ForceUpdate>,
WriteStorage<'a, Teleporting>,
WriteStorage<'a, Body>,
Read<'a, CachedSpatialGrid>,
Read<'a, Time>,
);
const NAME: &'static str = "teleporter";
@ -35,47 +44,101 @@ impl<'a> System<'a> for Sys {
teleporters,
agent,
mut forced_update,
mut teleporting,
mut bodies,
spatial_grid,
time,
): Self::SystemData,
) {
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 check_aggro = |entity, pos: Vec3<f32>| {
spatial_grid
.0
.in_circle_aabr(pos.xy(), MAX_AGGRO_DIST)
.any(|agent_entity| {
agent.get(agent_entity).map_or(false, |agent| {
agent.target.map_or(false, |agent_target| {
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);
for (entity, position, _) in nearby_entities.filter_map(|entity| {
let mut is_active = false;
for (entity, pos, _, teleporting) 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)
})
.filter(|(_, player_pos, _, _)| in_portal_range(player_pos.0, teleporter_pos.0))
}) {
// TODO: Check for aggro
attempt_teleport.push((entity, position.0, teleporter))
if teleporter.requires_no_aggro && check_aggro(entity, pos.0) {
if teleporting.is_some() {
cancel_teleport.push(entity)
};
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, 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| {
agent.get(agent_entity).map_or(false, |agent| {
agent.target.map_or(false, |agent_target| {
agent_target.target == entity && agent_target.aggro_on
})
})
});
for (entity, teleporting_data) in start_teleporting {
let _ = teleporting.insert(entity, teleporting_data);
}
if is_aggroed {
continue;
}
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
.get_mut(entity)
.map(|position| position.0 = teleporter.target);

View File

@ -3,7 +3,10 @@ use crate::{
util::{RandomField, Sampler, CARDINALS},
Land,
};
use common::{terrain::{BlockKind, SpriteKind}, generation::SpecialEntity};
use common::{
generation::SpecialEntity,
terrain::{BlockKind, SpriteKind},
};
use rand::prelude::*;
use std::sync::Arc;
use vek::*;
@ -326,7 +329,8 @@ impl Structure for CoastalWorkshop {
}
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,
comp::Teleporter,
generation::{ChunkSupplement, EntityInfo, SpecialEntity},
resources::Secs,
store::{Id, Store},
terrain::{
BiomeKind, Block, BlockKind, SpriteKind, Structure, StructuresGroup, TerrainChunkSize,
@ -668,12 +669,14 @@ impl Floor {
SpecialEntity::Teleporter(Teleporter {
target: bottom_pos+ Vec3::unit_x() * 5.,
requires_no_aggro: false,
buildup_time: Secs(1.),
}),
));
supplement.add_entity(EntityInfo::at(bottom_pos).into_special(
SpecialEntity::Teleporter(Teleporter {
target: top_pos+ Vec3::unit_x() * 5.,
requires_no_aggro: true,
buildup_time: Secs(3.),
}),
));
}