mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
review
This commit is contained in:
parent
0c9a942027
commit
e5e26149ed
@ -46,7 +46,6 @@ macro_rules! synced_components {
|
||||
beam_segment: BeamSegment,
|
||||
alignment: Alignment,
|
||||
stance: Stance,
|
||||
teleporter: Teleporter,
|
||||
// TODO: change this to `SyncFrom::ClientEntity` and sync the bare minimum
|
||||
// from other entities (e.g. just keys needed to show appearance
|
||||
// based on their loadout). Also, it looks like this actually has
|
||||
@ -235,10 +234,6 @@ impl NetSync for Stance {
|
||||
const SYNC_FROM: SyncFrom = SyncFrom::AnyEntity;
|
||||
}
|
||||
|
||||
impl NetSync for Teleporter {
|
||||
const SYNC_FROM: SyncFrom = SyncFrom::AnyEntity;
|
||||
}
|
||||
|
||||
// These are synced only from the client's own entity.
|
||||
|
||||
impl NetSync for Admin {
|
||||
|
@ -1,8 +1,12 @@
|
||||
use super::item::Reagent;
|
||||
use crate::{resources::Time, uid::Uid};
|
||||
use crate::{
|
||||
resources::{Secs, 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 {
|
||||
@ -17,8 +21,36 @@ pub enum Object {
|
||||
spawned_at: Time,
|
||||
timeout: Duration,
|
||||
},
|
||||
Portal {
|
||||
target: Vec3<f32>,
|
||||
requires_no_aggro: bool,
|
||||
buildup_time: Secs,
|
||||
},
|
||||
}
|
||||
|
||||
impl Component for Object {
|
||||
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PortalData {
|
||||
pub target: Vec3<f32>,
|
||||
pub requires_no_aggro: bool,
|
||||
pub buildup_time: Secs,
|
||||
}
|
||||
|
||||
impl From<PortalData> for Object {
|
||||
fn from(
|
||||
PortalData {
|
||||
target,
|
||||
requires_no_aggro,
|
||||
buildup_time,
|
||||
}: PortalData,
|
||||
) -> Self {
|
||||
Self::Portal {
|
||||
target,
|
||||
requires_no_aggro,
|
||||
buildup_time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ mod last;
|
||||
mod location;
|
||||
pub mod loot_owner;
|
||||
pub mod melee;
|
||||
mod misc;
|
||||
pub mod misc;
|
||||
pub mod ori;
|
||||
pub mod pet;
|
||||
mod phys;
|
||||
@ -104,7 +104,7 @@ pub use self::{
|
||||
SkillGroup, SkillGroupKind, SkillSet,
|
||||
},
|
||||
stats::{Stats, StatsModifier},
|
||||
teleport::{Teleporter, Teleporting},
|
||||
teleport::Teleporting,
|
||||
visual::{LightAnimation, LightEmitter},
|
||||
};
|
||||
|
||||
|
@ -1,19 +1,6 @@
|
||||
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>>;
|
||||
}
|
||||
use crate::resources::Time;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct Teleporting {
|
||||
|
@ -32,3 +32,5 @@ pub const SOUND_TRAVEL_DIST_PER_VOLUME: f32 = 3.0;
|
||||
// Stat increase per level (multiplied by 10 compared to what you'll see in UI)
|
||||
pub const ENERGY_PER_LEVEL: u16 = 5;
|
||||
pub const HP_PER_LEVEL: u16 = 5;
|
||||
|
||||
pub const TELEPORTER_RADIUS: f32 = 3.;
|
||||
|
@ -6,7 +6,8 @@ use crate::{
|
||||
agent::Sound,
|
||||
dialogue::Subject,
|
||||
invite::{InviteKind, InviteResponse},
|
||||
DisconnectReason, Ori, Pos, Teleporter,
|
||||
misc::PortalData,
|
||||
DisconnectReason, Ori, Pos,
|
||||
},
|
||||
lottery::LootSpec,
|
||||
mounting::VolumePos,
|
||||
@ -239,7 +240,7 @@ pub enum ServerEvent {
|
||||
driver: Option<NpcBuilder>,
|
||||
},
|
||||
CreateWaypoint(Vec3<f32>),
|
||||
CreateTeleporter(Vec3<f32>, Teleporter),
|
||||
CreateTeleporter(Vec3<f32>, PortalData),
|
||||
ClientDisconnect(EcsEntity, DisconnectReason),
|
||||
ClientDisconnectWithoutPersistence(EcsEntity),
|
||||
Command(EcsEntity, String, Vec<String>),
|
||||
|
@ -3,7 +3,8 @@ use crate::{
|
||||
comp::{
|
||||
self, agent, humanoid,
|
||||
inventory::loadout_builder::{LoadoutBuilder, LoadoutSpec},
|
||||
Alignment, Body, Item, Teleporter,
|
||||
misc::PortalData,
|
||||
Alignment, Body, Item,
|
||||
},
|
||||
lottery::LootSpec,
|
||||
npc::{self, NPC_NAMES},
|
||||
@ -166,7 +167,7 @@ pub fn try_all_entity_configs() -> Result<Vec<String>, Error> {
|
||||
#[derive(Clone)]
|
||||
pub enum SpecialEntity {
|
||||
Waypoint,
|
||||
Teleporter(Teleporter),
|
||||
Teleporter(PortalData),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -219,7 +219,6 @@ impl State {
|
||||
ecs.register::<comp::LootOwner>();
|
||||
ecs.register::<comp::Admin>();
|
||||
ecs.register::<comp::Stance>();
|
||||
ecs.register::<comp::Teleporter>();
|
||||
ecs.register::<comp::Teleporting>();
|
||||
|
||||
// Register components send from clients -> server
|
||||
|
@ -33,21 +33,20 @@ use common::{
|
||||
slot::Slot,
|
||||
},
|
||||
invite::InviteKind,
|
||||
AdminRole, ChatType, Inventory, Item, LightEmitter, Presence, PresenceKind, WaypointArea,
|
||||
misc::PortalData,
|
||||
AdminRole, ChatType, Inventory, Item, LightEmitter, WaypointArea,
|
||||
},
|
||||
depot,
|
||||
effect::Effect,
|
||||
event::{EventBus, ServerEvent},
|
||||
generation::{EntityConfig, EntityInfo},
|
||||
link::Is,
|
||||
mounting::{Rider, VolumeRider},
|
||||
npc::{self, get_npc_name},
|
||||
outcome::Outcome,
|
||||
parse_cmd_args,
|
||||
resources::{BattleMode, PlayerPhysicsSettings, Secs, Time, TimeOfDay, TimeScale},
|
||||
rtsim::{Actor, Role},
|
||||
terrain::{Block, BlockKind, CoordinateConversions, SpriteKind, TerrainChunkSize},
|
||||
uid::{IdMaps, Uid},
|
||||
uid::Uid,
|
||||
vol::ReadVol,
|
||||
weather, Damage, DamageKind, DamageSource, Explosion, LoadoutBuilder, RadiusEffect,
|
||||
};
|
||||
@ -223,89 +222,6 @@ fn position(server: &Server, entity: EcsEntity, descriptor: &str) -> CmdResult<c
|
||||
.ok_or_else(|| format!("Cannot get position for {:?}!", descriptor))
|
||||
}
|
||||
|
||||
fn position_mut<T>(
|
||||
server: &mut Server,
|
||||
entity: EcsEntity,
|
||||
descriptor: &str,
|
||||
dismount_volume: Option<bool>,
|
||||
f: impl for<'a> FnOnce(&'a mut comp::Pos) -> T,
|
||||
) -> CmdResult<T> {
|
||||
if dismount_volume.unwrap_or(true) {
|
||||
server
|
||||
.state
|
||||
.ecs()
|
||||
.write_storage::<Is<VolumeRider>>()
|
||||
.remove(entity);
|
||||
}
|
||||
|
||||
let entity = server
|
||||
.state
|
||||
.read_storage::<Is<Rider>>()
|
||||
.get(entity)
|
||||
.and_then(|is_rider| {
|
||||
server
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<IdMaps>()
|
||||
.uid_entity(is_rider.mount)
|
||||
})
|
||||
.map(Ok)
|
||||
.or_else(|| {
|
||||
server
|
||||
.state
|
||||
.read_storage::<Is<VolumeRider>>()
|
||||
.get(entity)
|
||||
.and_then(|volume_rider| {
|
||||
Some(match volume_rider.pos.kind {
|
||||
common::mounting::Volume::Terrain => {
|
||||
Err("Tried to move the world.".to_string())
|
||||
},
|
||||
common::mounting::Volume::Entity(uid) => Ok(server
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<IdMaps>()
|
||||
.uid_entity(uid)?),
|
||||
})
|
||||
})
|
||||
})
|
||||
.unwrap_or(Ok(entity))?;
|
||||
|
||||
let mut maybe_pos = None;
|
||||
|
||||
let res = server
|
||||
.state
|
||||
.ecs()
|
||||
.write_storage::<comp::Pos>()
|
||||
.get_mut(entity)
|
||||
.map(|pos| {
|
||||
let res = f(pos);
|
||||
maybe_pos = Some(pos.0);
|
||||
res
|
||||
})
|
||||
.ok_or_else(|| format!("Cannot get position for {:?}!", descriptor));
|
||||
|
||||
if let Some(pos) = maybe_pos {
|
||||
if server
|
||||
.state
|
||||
.ecs()
|
||||
.read_storage::<Presence>()
|
||||
.get(entity)
|
||||
.map(|presence| presence.kind == PresenceKind::Spectator)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
server.notify_client(entity, ServerGeneral::SpectatePosition(pos));
|
||||
} else {
|
||||
server
|
||||
.state
|
||||
.ecs()
|
||||
.write_storage::<comp::ForceUpdate>()
|
||||
.get_mut(entity)
|
||||
.map(|force_update| force_update.update());
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn insert_or_replace_component<C: specs::Component>(
|
||||
server: &mut Server,
|
||||
entity: EcsEntity,
|
||||
@ -859,9 +775,11 @@ fn handle_jump(
|
||||
) -> CmdResult<()> {
|
||||
if let (Some(x), Some(y), Some(z), dismount_volume) = parse_cmd_args!(args, f32, f32, f32, bool)
|
||||
{
|
||||
position_mut(server, target, "target", dismount_volume, |current_pos| {
|
||||
current_pos.0 += Vec3::new(x, y, z)
|
||||
})
|
||||
server
|
||||
.state
|
||||
.position_mut(target, dismount_volume, |current_pos| {
|
||||
current_pos.0 += Vec3::new(x, y, z)
|
||||
})
|
||||
} else {
|
||||
Err(action.help_string())
|
||||
}
|
||||
@ -876,9 +794,11 @@ fn handle_goto(
|
||||
) -> CmdResult<()> {
|
||||
if let (Some(x), Some(y), Some(z), dismount_volume) = parse_cmd_args!(args, f32, f32, f32, bool)
|
||||
{
|
||||
position_mut(server, target, "target", dismount_volume, |current_pos| {
|
||||
current_pos.0 = Vec3::new(x, y, z)
|
||||
})
|
||||
server
|
||||
.state
|
||||
.position_mut(target, dismount_volume, |current_pos| {
|
||||
current_pos.0 = Vec3::new(x, y, z)
|
||||
})
|
||||
} else {
|
||||
Err(action.help_string())
|
||||
}
|
||||
@ -911,9 +831,11 @@ fn handle_site(
|
||||
false,
|
||||
);
|
||||
|
||||
position_mut(server, target, "target", dismount_volume, |current_pos| {
|
||||
current_pos.0 = site_pos
|
||||
})
|
||||
server
|
||||
.state
|
||||
.position_mut(target, dismount_volume, |current_pos| {
|
||||
current_pos.0 = site_pos
|
||||
})
|
||||
} else {
|
||||
Err(action.help_string())
|
||||
}
|
||||
@ -936,9 +858,11 @@ fn handle_respawn(
|
||||
.ok_or("No waypoint set")?
|
||||
.get_pos();
|
||||
|
||||
position_mut(server, target, "target", Some(true), |current_pos| {
|
||||
current_pos.0 = waypoint;
|
||||
})
|
||||
server
|
||||
.state
|
||||
.position_mut(target, Some(true), |current_pos| {
|
||||
current_pos.0 = waypoint;
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_kill(
|
||||
@ -1308,9 +1232,11 @@ fn handle_tp(
|
||||
return Err(action.help_string());
|
||||
};
|
||||
let player_pos = position(server, player, "player")?;
|
||||
position_mut(server, target, "target", dismount_volume, |target_pos| {
|
||||
*target_pos = player_pos
|
||||
})
|
||||
server
|
||||
.state
|
||||
.position_mut(target, dismount_volume, |target_pos| {
|
||||
*target_pos = player_pos
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_rtsim_tp(
|
||||
@ -1338,9 +1264,11 @@ fn handle_rtsim_tp(
|
||||
} else {
|
||||
return Err(action.help_string());
|
||||
};
|
||||
position_mut(server, target, "target", dismount_volume, |target_pos| {
|
||||
target_pos.0 = pos;
|
||||
})
|
||||
server
|
||||
.state
|
||||
.position_mut(target, dismount_volume, |target_pos| {
|
||||
target_pos.0 = pos;
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_rtsim_info(
|
||||
@ -2058,10 +1986,10 @@ fn handle_spawn_portal(
|
||||
let buildup_time = Secs(buildup_time.unwrap_or(7.));
|
||||
server
|
||||
.state
|
||||
.create_teleporter(pos, comp::Teleporter {
|
||||
.create_teleporter(pos, PortalData {
|
||||
target: Vec3::new(x, y, z),
|
||||
requires_no_aggro,
|
||||
buildup_time,
|
||||
requires_no_aggro,
|
||||
})
|
||||
.build();
|
||||
|
||||
@ -4112,7 +4040,7 @@ fn handle_location(
|
||||
if let Some(name) = parse_cmd_args!(args, String) {
|
||||
let loc = server.state.ecs().read_resource::<Locations>().get(&name);
|
||||
match loc {
|
||||
Ok(loc) => position_mut(server, target, "target", Some(true), |target_pos| {
|
||||
Ok(loc) => server.state.position_mut(target, Some(true), |target_pos| {
|
||||
target_pos.0 = loc;
|
||||
}),
|
||||
Err(e) => Err(e.to_string()),
|
||||
|
@ -9,9 +9,10 @@ use common::{
|
||||
aura::{Aura, AuraKind, AuraTarget},
|
||||
beam,
|
||||
buff::{BuffCategory, BuffData, BuffKind, BuffSource},
|
||||
misc::PortalData,
|
||||
ship::figuredata::VOXEL_COLLIDER_MANIFEST,
|
||||
shockwave, Alignment, BehaviorCapability, Body, ItemDrops, LightEmitter, Object, Ori, Pos,
|
||||
Projectile, Teleporter, TradingBehavior, Vel, WaypointArea,
|
||||
Projectile, TradingBehavior, Vel, WaypointArea,
|
||||
},
|
||||
event::{EventBus, NpcBuilder, UpdateCharacterMetadata},
|
||||
mounting::{Mounting, Volume, VolumeMounting, VolumePos},
|
||||
@ -419,9 +420,9 @@ pub fn handle_create_waypoint(server: &mut Server, pos: Vec3<f32>) {
|
||||
.build();
|
||||
}
|
||||
|
||||
pub fn handle_create_teleporter(server: &mut Server, pos: Vec3<f32>, teleporter: Teleporter) {
|
||||
pub fn handle_create_teleporter(server: &mut Server, pos: Vec3<f32>, portal: PortalData) {
|
||||
server
|
||||
.state
|
||||
.create_teleporter(comp::Pos(pos), teleporter)
|
||||
.create_teleporter(comp::Pos(pos), portal)
|
||||
.build();
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
BuffKind, BuffSource, PhysicsState,
|
||||
},
|
||||
rtsim,
|
||||
sys::{teleporter::TELEPORT_RADIUS, terrain::SAFE_ZONE_RADIUS},
|
||||
sys::terrain::SAFE_ZONE_RADIUS,
|
||||
Server, SpawnPoint, StateExt,
|
||||
};
|
||||
use authc::Uuid;
|
||||
@ -22,8 +22,9 @@ use common::{
|
||||
item::flatten_counted_items,
|
||||
loot_owner::LootOwnerKind,
|
||||
Alignment, Auras, Body, CharacterState, Energy, Group, Health, HealthChange, Inventory,
|
||||
Player, Poise, Pos, SkillSet, Stats,
|
||||
Object, Player, Poise, Pos, SkillSet, Stats,
|
||||
},
|
||||
consts::TELEPORTER_RADIUS,
|
||||
event::{EventBus, ServerEvent},
|
||||
lottery::distribute_many,
|
||||
outcome::{HealthChangeInfo, Outcome},
|
||||
@ -43,7 +44,7 @@ use hashbrown::HashSet;
|
||||
use rand::Rng;
|
||||
use specs::{join::Join, Builder, Entity as EcsEntity, Entity, WorldExt};
|
||||
use std::{collections::HashMap, iter, sync::Arc, time::Duration};
|
||||
use tracing::{debug, error};
|
||||
use tracing::{debug, error, warn};
|
||||
use vek::{Vec2, Vec3};
|
||||
|
||||
#[derive(Hash, Eq, PartialEq)]
|
||||
@ -1658,16 +1659,12 @@ pub fn handle_remove_light_emitter(server: &mut Server, entity: EcsEntity) {
|
||||
}
|
||||
|
||||
pub fn handle_teleport_to_position(server: &mut Server, entity: EcsEntity, position: Vec3<f32>) {
|
||||
let ecs = server.state.ecs();
|
||||
|
||||
ecs.write_storage::<comp::Pos>()
|
||||
.get_mut(entity)
|
||||
.map(|old_position| {
|
||||
old_position.0 = position;
|
||||
});
|
||||
ecs.write_storage::<comp::ForceUpdate>()
|
||||
.get_mut(entity)
|
||||
.map(|forced_update| forced_update.update());
|
||||
if let Err(error) = server
|
||||
.state
|
||||
.position_mut(entity, Some(true), |pos| pos.0 = position)
|
||||
{
|
||||
warn!("Failed to teleport entity: {error}");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_start_teleporting(server: &mut Server, entity: EcsEntity, portal: EcsEntity) {
|
||||
@ -1681,15 +1678,20 @@ pub fn handle_start_teleporting(server: &mut Server, entity: EcsEntity, portal:
|
||||
.flatten()
|
||||
.zip(positions.get(portal))
|
||||
.filter(|(entity_pos, portal_pos)| {
|
||||
entity_pos.0.distance_squared(portal_pos.0) <= TELEPORT_RADIUS.powi(2)
|
||||
entity_pos.0.distance_squared(portal_pos.0) <= TELEPORTER_RADIUS.powi(2)
|
||||
})
|
||||
.and_then(|(_, _)| {
|
||||
Some(
|
||||
now + ecs
|
||||
.read_storage::<comp::Teleporter>()
|
||||
.get(portal)?
|
||||
.buildup_time
|
||||
.0,
|
||||
.read_storage::<comp::Object>()
|
||||
.get(portal)
|
||||
.and_then(|object| {
|
||||
if let Object::Portal { buildup_time, .. } = object {
|
||||
Some(buildup_time.0)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})?,
|
||||
)
|
||||
})
|
||||
{
|
||||
|
@ -213,8 +213,8 @@ impl Server {
|
||||
driver,
|
||||
} => handle_create_ship(self, pos, ori, ship, rtsim_entity, driver, Vec::new()),
|
||||
ServerEvent::CreateWaypoint(pos) => handle_create_waypoint(self, pos),
|
||||
ServerEvent::CreateTeleporter(pos, teleporter) => {
|
||||
handle_create_teleporter(self, pos, teleporter)
|
||||
ServerEvent::CreateTeleporter(pos, portal) => {
|
||||
handle_create_teleporter(self, pos, portal)
|
||||
},
|
||||
ServerEvent::ClientDisconnect(entity, reason) => {
|
||||
frontend_events.push(handle_client_disconnect(self, entity, reason, false))
|
||||
|
@ -18,13 +18,14 @@ use common::{
|
||||
comp::{
|
||||
self,
|
||||
item::{ItemKind, MaterialStatManifest},
|
||||
misc::PortalData,
|
||||
object,
|
||||
skills::{GeneralSkill, Skill},
|
||||
ChatType, Group, Inventory, Item, LootOwner, Object, Player, Poise, Presence, PresenceKind,
|
||||
},
|
||||
effect::Effect,
|
||||
link::{Link, LinkHandle},
|
||||
mounting::{Mounting, VolumeMounting},
|
||||
link::{Is, Link, LinkHandle},
|
||||
mounting::{Mounting, Rider, VolumeMounting, VolumeRider},
|
||||
resources::{Secs, Time, TimeOfDay},
|
||||
rtsim::{Actor, RtSimEntity},
|
||||
slowjob::SlowJobPool,
|
||||
@ -118,11 +119,7 @@ pub trait StateExt {
|
||||
/// Creates a teleporter entity, which allows players to teleport to the
|
||||
/// `target` position. You might want to require the teleporting entity
|
||||
/// to not have agro for teleporting.
|
||||
fn create_teleporter(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
teleporter: comp::Teleporter,
|
||||
) -> EcsEntityBuilder;
|
||||
fn create_teleporter(&mut self, pos: comp::Pos, portal: PortalData) -> EcsEntityBuilder;
|
||||
/// Insert common/default components for a new character joining the server
|
||||
fn initialize_character_data(
|
||||
&mut self,
|
||||
@ -161,6 +158,12 @@ pub trait StateExt {
|
||||
) -> Result<(), specs::error::WrongGeneration>;
|
||||
/// Get the given entity as an [`Actor`], if it is one.
|
||||
fn entity_as_actor(&self, entity: EcsEntity) -> Option<Actor>;
|
||||
fn position_mut<T>(
|
||||
&mut self,
|
||||
entity: EcsEntity,
|
||||
dismount_volume: Option<bool>,
|
||||
f: impl for<'a> FnOnce(&'a mut comp::Pos) -> T,
|
||||
) -> Result<T, String>;
|
||||
}
|
||||
|
||||
impl StateExt for State {
|
||||
@ -616,14 +619,10 @@ impl StateExt for State {
|
||||
))
|
||||
}
|
||||
|
||||
fn create_teleporter(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
teleporter: comp::Teleporter,
|
||||
) -> EcsEntityBuilder {
|
||||
fn create_teleporter(&mut self, pos: comp::Pos, portal: PortalData) -> EcsEntityBuilder {
|
||||
self.create_object(pos, object::Body::Portal)
|
||||
.with(comp::Immovable)
|
||||
.with(teleporter)
|
||||
.with(comp::Object::from(portal))
|
||||
}
|
||||
|
||||
fn initialize_character_data(
|
||||
@ -1244,6 +1243,76 @@ impl StateExt for State {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn position_mut<T>(
|
||||
&mut self,
|
||||
entity: EcsEntity,
|
||||
dismount_volume: Option<bool>,
|
||||
f: impl for<'a> FnOnce(&'a mut comp::Pos) -> T,
|
||||
) -> Result<T, String> {
|
||||
if dismount_volume.unwrap_or(true) {
|
||||
self.ecs().write_storage::<Is<VolumeRider>>().remove(entity);
|
||||
}
|
||||
|
||||
let entity = self
|
||||
.read_storage::<Is<Rider>>()
|
||||
.get(entity)
|
||||
.and_then(|is_rider| {
|
||||
self.ecs()
|
||||
.read_resource::<IdMaps>()
|
||||
.uid_entity(is_rider.mount)
|
||||
})
|
||||
.map(Ok)
|
||||
.or_else(|| {
|
||||
self.read_storage::<Is<VolumeRider>>()
|
||||
.get(entity)
|
||||
.and_then(|volume_rider| {
|
||||
Some(match volume_rider.pos.kind {
|
||||
common::mounting::Volume::Terrain => {
|
||||
Err("Tried to move the world.".to_string())
|
||||
},
|
||||
common::mounting::Volume::Entity(uid) => {
|
||||
Ok(self.ecs().read_resource::<IdMaps>().uid_entity(uid)?)
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
.unwrap_or(Ok(entity))?;
|
||||
|
||||
let mut maybe_pos = None;
|
||||
|
||||
let res = self
|
||||
.ecs()
|
||||
.write_storage::<comp::Pos>()
|
||||
.get_mut(entity)
|
||||
.map(|pos| {
|
||||
let res = f(pos);
|
||||
maybe_pos = Some(pos.0);
|
||||
res
|
||||
})
|
||||
.ok_or_else(|| "Cannot get position for entity!".to_string());
|
||||
|
||||
if let Some(pos) = maybe_pos {
|
||||
if self
|
||||
.ecs()
|
||||
.read_storage::<Presence>()
|
||||
.get(entity)
|
||||
.map(|presence| presence.kind == PresenceKind::Spectator)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
self.read_storage::<Client>().get(entity).map(|client| {
|
||||
client.send_fallible(ServerGeneral::SpectatePosition(pos));
|
||||
});
|
||||
} else {
|
||||
self.ecs()
|
||||
.write_storage::<comp::ForceUpdate>()
|
||||
.get_mut(entity)
|
||||
.map(|force_update| force_update.update());
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
fn send_to_group(g: &Group, ecs: &specs::World, msg: &comp::ChatMsg) {
|
||||
|
@ -1,9 +1,10 @@
|
||||
use common::{
|
||||
comp::{Object, PhysicsState, Pos, Vel},
|
||||
comp::{object, Body, Object, PhysicsState, Pos, Teleporting, Vel},
|
||||
consts::TELEPORTER_RADIUS,
|
||||
effect::Effect,
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::{DeltaTime, Time},
|
||||
Damage, DamageKind, DamageSource, Explosion, RadiusEffect,
|
||||
CachedSpatialGrid, Damage, DamageKind, DamageSource, Explosion, RadiusEffect,
|
||||
};
|
||||
use common_ecs::{Job, Origin, Phase, System};
|
||||
use specs::{Entities, Join, Read, ReadStorage};
|
||||
@ -18,10 +19,13 @@ impl<'a> System<'a> for Sys {
|
||||
Read<'a, DeltaTime>,
|
||||
Read<'a, Time>,
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
Read<'a, CachedSpatialGrid>,
|
||||
ReadStorage<'a, Pos>,
|
||||
ReadStorage<'a, Vel>,
|
||||
ReadStorage<'a, PhysicsState>,
|
||||
ReadStorage<'a, Object>,
|
||||
ReadStorage<'a, Body>,
|
||||
ReadStorage<'a, Teleporting>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "object";
|
||||
@ -30,17 +34,30 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
fn run(
|
||||
_job: &mut Job<Self>,
|
||||
(entities, _dt, time, server_bus, positions, velocities, physics_states, objects): Self::SystemData,
|
||||
(
|
||||
entities,
|
||||
_dt,
|
||||
time,
|
||||
server_bus,
|
||||
spatial_grid,
|
||||
positions,
|
||||
velocities,
|
||||
physics_states,
|
||||
objects,
|
||||
bodies,
|
||||
teleporting,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let mut server_emitter = server_bus.emitter();
|
||||
|
||||
// Objects
|
||||
for (entity, pos, vel, physics, object) in (
|
||||
for (entity, pos, vel, physics, object, body) in (
|
||||
&entities,
|
||||
&positions,
|
||||
&velocities,
|
||||
&physics_states,
|
||||
&objects,
|
||||
&bodies,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -73,7 +90,7 @@ impl<'a> System<'a> for Sys {
|
||||
const ENABLE_RECURSIVE_FIREWORKS: bool = true;
|
||||
if ENABLE_RECURSIVE_FIREWORKS {
|
||||
use common::{
|
||||
comp::{object, Body, LightEmitter, Projectile},
|
||||
comp::{LightEmitter, Projectile},
|
||||
util::Dir,
|
||||
};
|
||||
use rand::Rng;
|
||||
@ -169,6 +186,31 @@ impl<'a> System<'a> for Sys {
|
||||
server_emitter.emit(ServerEvent::Delete(entity));
|
||||
}
|
||||
},
|
||||
Object::Portal { .. } => {
|
||||
let is_active = spatial_grid
|
||||
.0
|
||||
.in_circle_aabr(pos.0.xy(), TELEPORTER_RADIUS)
|
||||
.any(|entity| {
|
||||
(&positions, &teleporting)
|
||||
.join()
|
||||
.get(entity, &entities)
|
||||
.map_or(false, |(teleporter_pos, _)| {
|
||||
pos.0.distance_squared(teleporter_pos.0)
|
||||
<= TELEPORTER_RADIUS.powi(2)
|
||||
})
|
||||
});
|
||||
|
||||
if (*body == Body::Object(object::Body::PortalActive)) != is_active {
|
||||
server_bus.emit_now(ServerEvent::ChangeBody {
|
||||
entity,
|
||||
new_body: Body::Object(if is_active {
|
||||
object::Body::PortalActive
|
||||
} else {
|
||||
object::Body::Portal
|
||||
}),
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use common::{
|
||||
comp::{object, Agent, Alignment, Body, CharacterState, Pos, Teleporter, Teleporting},
|
||||
comp::{Agent, Alignment, CharacterState, Object, Pos, Teleporting},
|
||||
consts::TELEPORTER_RADIUS,
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::Time,
|
||||
uid::Uid,
|
||||
@ -9,7 +10,6 @@ use common_ecs::{Origin, Phase, System};
|
||||
use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
|
||||
use vek::Vec3;
|
||||
|
||||
pub 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 PET_TELEPORT_RADIUS: f32 = 20.;
|
||||
|
||||
@ -17,7 +17,7 @@ const PET_TELEPORT_RADIUS: f32 = 20.;
|
||||
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)
|
||||
player_pos.distance_squared(portal_pos) <= TELEPORTER_RADIUS.powi(2)
|
||||
}
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
@ -25,11 +25,10 @@ impl<'a> System<'a> for Sys {
|
||||
Entities<'a>,
|
||||
ReadStorage<'a, Pos>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadStorage<'a, Teleporter>,
|
||||
ReadStorage<'a, Alignment>,
|
||||
ReadStorage<'a, Agent>,
|
||||
ReadStorage<'a, Object>,
|
||||
WriteStorage<'a, Teleporting>,
|
||||
ReadStorage<'a, Body>,
|
||||
ReadStorage<'a, CharacterState>,
|
||||
Read<'a, CachedSpatialGrid>,
|
||||
Read<'a, Time>,
|
||||
@ -46,11 +45,10 @@ impl<'a> System<'a> for Sys {
|
||||
entities,
|
||||
positions,
|
||||
uids,
|
||||
teleporters,
|
||||
alignments,
|
||||
agent,
|
||||
objects,
|
||||
mut teleporting,
|
||||
bodies,
|
||||
character_states,
|
||||
spatial_grid,
|
||||
time,
|
||||
@ -72,31 +70,6 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
let mut cancel_teleporting = Vec::new();
|
||||
|
||||
for (portal_entity, teleporter_pos, body, _) in
|
||||
(&entities, &positions, &bodies, &teleporters).join()
|
||||
{
|
||||
let is_active = spatial_grid
|
||||
.0
|
||||
.in_circle_aabr(teleporter_pos.0.xy(), TELEPORT_RADIUS)
|
||||
.any(|entity| {
|
||||
(&positions, &teleporting)
|
||||
.join()
|
||||
.get(entity, &entities)
|
||||
.map_or(false, |(pos, _)| in_portal_range(pos.0, teleporter_pos.0))
|
||||
});
|
||||
|
||||
if (*body == Body::Object(object::Body::PortalActive)) != is_active {
|
||||
event_bus.emit_now(ServerEvent::ChangeBody {
|
||||
entity: portal_entity,
|
||||
new_body: Body::Object(if is_active {
|
||||
object::Body::PortalActive
|
||||
} else {
|
||||
object::Body::Portal
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (entity, uid, position, teleporting, character_state) in (
|
||||
&entities,
|
||||
&uids,
|
||||
@ -107,14 +80,16 @@ impl<'a> System<'a> for Sys {
|
||||
.join()
|
||||
{
|
||||
let portal_pos = positions.get(teleporting.portal);
|
||||
let Some(teleporter) = teleporters.get(teleporting.portal) else {
|
||||
let Some(Object::Portal { target, requires_no_aggro, .. }) = objects
|
||||
.get(teleporting.portal)
|
||||
else {
|
||||
cancel_teleporting.push(entity);
|
||||
continue
|
||||
};
|
||||
|
||||
if portal_pos.map_or(true, |portal_pos| {
|
||||
!in_portal_range(position.0, portal_pos.0)
|
||||
}) || (teleporter.requires_no_aggro && check_aggro(entity, position.0))
|
||||
}) || (*requires_no_aggro && check_aggro(entity, position.0))
|
||||
|| !matches!(
|
||||
character_state,
|
||||
CharacterState::Idle(_) | CharacterState::Wielding(_)
|
||||
@ -142,7 +117,7 @@ impl<'a> System<'a> for Sys {
|
||||
cancel_teleporting.push(entity);
|
||||
event_bus.emit_now(ServerEvent::TeleportToPosition {
|
||||
entity,
|
||||
position: teleporter.target,
|
||||
position: *target,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ use crate::{
|
||||
use common::{
|
||||
calendar::Calendar,
|
||||
comp::{
|
||||
self, agent, biped_small, bird_medium, skillset::skills, BehaviorCapability, ForceUpdate,
|
||||
Pos, Presence, Teleporter, Waypoint,
|
||||
self, agent, biped_small, bird_medium, misc::PortalData, skillset::skills,
|
||||
BehaviorCapability, ForceUpdate, Pos, Presence, Waypoint,
|
||||
},
|
||||
event::{EventBus, NpcBuilder, ServerEvent},
|
||||
generation::{EntityInfo, SpecialEntity},
|
||||
@ -418,7 +418,7 @@ pub enum NpcData {
|
||||
loot: LootSpec<String>,
|
||||
},
|
||||
Waypoint(Vec3<f32>),
|
||||
Teleporter(Vec3<f32>, Teleporter),
|
||||
Teleporter(Vec3<f32>, PortalData),
|
||||
}
|
||||
|
||||
impl NpcData {
|
||||
|
@ -2233,12 +2233,13 @@ impl Hud {
|
||||
.map_or(Vec3::zero(), |e| e.0);
|
||||
let over_pos = pos + Vec3::unit_z() * 1.5;
|
||||
|
||||
let is_campfire = body.is_campfire();
|
||||
overitem::Overitem::new(
|
||||
i18n.get_msg(if is_campfire {
|
||||
i18n.get_msg(if body.is_campfire() {
|
||||
"hud-crafting-campfire"
|
||||
} else {
|
||||
} else if body.is_portal() {
|
||||
"hud-portal"
|
||||
} else {
|
||||
"hud-use"
|
||||
}),
|
||||
overitem::TEXT_COLOR,
|
||||
pos.distance_squared(player_pos),
|
||||
@ -2250,7 +2251,13 @@ impl Hud {
|
||||
&global_state.window.key_layout,
|
||||
vec![(
|
||||
Some(GameInput::Interact),
|
||||
i18n.get_msg(if is_campfire { "hud-sit" } else { "hud-activate" }).to_string(),
|
||||
i18n.get_msg(if body.is_campfire() {
|
||||
"hud-sit"
|
||||
} else if body.is_portal() {
|
||||
"hud-activate"
|
||||
} else {
|
||||
"hud-use"
|
||||
}).to_string(),
|
||||
)],
|
||||
)
|
||||
.x_y(0.0, 100.0)
|
||||
|
@ -10,7 +10,7 @@ use client::Client;
|
||||
use common::{
|
||||
comp,
|
||||
comp::{ship::figuredata::VOXEL_COLLIDER_MANIFEST, tool::ToolKind, Collider, Content},
|
||||
consts::{MAX_PICKUP_RANGE, MAX_SPRITE_MOUNT_RANGE},
|
||||
consts::{MAX_PICKUP_RANGE, MAX_SPRITE_MOUNT_RANGE, TELEPORTER_RADIUS},
|
||||
link::Is,
|
||||
mounting::{Mount, Rider, VolumePos, VolumeRider},
|
||||
terrain::{Block, TerrainGrid, UnlockKind},
|
||||
@ -247,7 +247,7 @@ pub(super) fn select_interactable(
|
||||
// * Are not riding the player
|
||||
let not_riding_player = is_rider
|
||||
.map_or(true, |is_rider| Some(&is_rider.mount) != uids.get(viewpoint_entity));
|
||||
let is_interactable = (b.is_campfire() || (b.is_portal() && (p.0.distance_squared(player_pos) <= 3f32.powi(2))) || has_stats_or_item.is_some()) && not_riding_player;
|
||||
let is_interactable = (b.is_campfire() || (b.is_portal() && (p.0.distance_squared(player_pos) <= TELEPORTER_RADIUS.powi(2))) || has_stats_or_item.is_some()) && not_riding_player;
|
||||
if !is_interactable {
|
||||
return None;
|
||||
};
|
||||
|
@ -1883,24 +1883,23 @@ impl SiteKind {
|
||||
SiteKind::Dungeon => {
|
||||
on_land() && {
|
||||
let land = Land::from_sim(sim);
|
||||
let loc = loc.map(|v| TerrainChunkSize::RECT_SIZE.y as i32 * v);
|
||||
let loc = loc.cpos_to_wpos();
|
||||
let dungeon_aabr = Aabr {
|
||||
min: loc - Vec2::broadcast(200),
|
||||
max: loc + Vec2::broadcast(200),
|
||||
};
|
||||
|
||||
// Get shallow caves under the dungeon
|
||||
let mut tunnels = cave::tunnels_at(loc, 1, &land)
|
||||
// Make sure there are no shallow caves near the dungeon
|
||||
let collides_with_cave = cave::tunnels_at(loc, 1, &land)
|
||||
.chain(cave::tunnels_at(loc, 2, &land))
|
||||
.filter(|tunnel| {
|
||||
dungeon_aabr.collides_with_aabr(Aabr {
|
||||
.all(|tunnel| {
|
||||
!dungeon_aabr.collides_with_aabr(Aabr {
|
||||
min: tunnel.nodes().0.wpos,
|
||||
max: tunnel.nodes().1.wpos,
|
||||
})
|
||||
});
|
||||
|
||||
// Make sure there are no shallow caves near the dungeon
|
||||
tunnels.next().is_none()
|
||||
collides_with_cave
|
||||
}
|
||||
},
|
||||
SiteKind::Refactor | SiteKind::Settlement => suitable_for_town(),
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
use common::{
|
||||
assets::{self, AssetExt, AssetHandle},
|
||||
astar::Astar,
|
||||
comp::Teleporter,
|
||||
comp::misc::PortalData,
|
||||
generation::{ChunkSupplement, EntityInfo, SpecialEntity},
|
||||
resources::Secs,
|
||||
store::{Id, Store},
|
||||
@ -666,14 +666,14 @@ impl Floor {
|
||||
|
||||
// Move both a bit to the side to prevent teleportation loop, ideally we'd have the portals at another location
|
||||
supplement.add_entity(EntityInfo::at(top_pos).into_special(
|
||||
SpecialEntity::Teleporter(Teleporter {
|
||||
SpecialEntity::Teleporter(PortalData {
|
||||
target: bottom_pos + Vec3::unit_x() * 5.,
|
||||
requires_no_aggro: true,
|
||||
buildup_time: Secs(5.),
|
||||
}),
|
||||
));
|
||||
supplement.add_entity(EntityInfo::at(bottom_pos).into_special(
|
||||
SpecialEntity::Teleporter(Teleporter {
|
||||
SpecialEntity::Teleporter(PortalData {
|
||||
target: top_pos + Vec3::unit_x() * 5.,
|
||||
requires_no_aggro: true,
|
||||
buildup_time: Secs(5.),
|
||||
|
Loading…
Reference in New Issue
Block a user