Merge branch 'isse/spectator-fixes' into 'master'

Various spectator fixes.

See merge request veloren/veloren!3534
This commit is contained in:
Marcel 2022-08-15 09:33:03 +00:00
commit 6c17f7b95b
5 changed files with 122 additions and 76 deletions

View File

@ -30,7 +30,7 @@ use common::{
slot::{EquipSlot, InvSlotId, Slot},
CharacterState, ChatMode, ControlAction, ControlEvent, Controller, ControllerInputs,
GroupManip, InputKind, InventoryAction, InventoryEvent, InventoryUpdateEvent,
MapMarkerChange, Pos, UtteranceKind,
MapMarkerChange, UtteranceKind,
},
event::{EventBus, LocalEvent},
grid::Grid,
@ -106,6 +106,7 @@ pub enum Event {
CharacterEdited(CharacterId),
CharacterError(String),
MapMarker(comp::MapMarkerUpdate),
StartSpectate(Vec3<f32>),
SpectatePosition(Vec3<f32>),
}
@ -881,7 +882,7 @@ impl Client {
pub fn request_character(&mut self, character_id: CharacterId) {
self.send_msg(ClientGeneral::Character(character_id));
//Assume we are in_game unless server tells us otherwise
// Assume we are in_game unless server tells us otherwise
self.presence = Some(PresenceKind::Character(character_id));
}
@ -889,7 +890,6 @@ impl Client {
pub fn request_spectate(&mut self) {
self.send_msg(ClientGeneral::Spectate);
//Assume we are in_game unless server tells us otherwise
self.presence = Some(PresenceKind::Spectator);
}
@ -1348,17 +1348,25 @@ impl Client {
self.send_msg(ClientGeneral::UpdateMapMarker(event));
}
pub fn spectate_position(&mut self, pos: Vec3<f32>) {
if let Some(position) = self
/// Set the current position to spectate, returns true if the client's
/// player has a Pos component to write to.
pub fn spectate_position(&mut self, pos: Vec3<f32>) -> bool {
let write = if let Some(position) = self
.state
.ecs()
.write_storage::<comp::Pos>()
.get_mut(self.entity())
{
position.0 = pos;
}
true
} else {
false
};
if write {
self.send_msg(ClientGeneral::SpectatePosition(pos));
}
write
}
/// Checks whether a player can swap their weapon+ability `Loadout` settings
/// and sends the `ControlAction` event that signals to do the swap.
@ -2346,12 +2354,7 @@ impl Client {
},
ServerGeneral::SpectatorSuccess(spawn_point) => {
if let Some(vd) = self.view_distance {
self.state
.ecs()
.write_storage()
.insert(self.entity(), Pos(spawn_point))
.expect("This shouldn't exist");
events.push(Event::SpectatePosition(spawn_point));
events.push(Event::StartSpectate(spawn_point));
debug!("client is now in ingame state on server");
self.set_view_distance(vd);
}

View File

@ -37,6 +37,8 @@ pub struct ServerProfile {
pub characters: HashMap<CharacterId, CharacterProfile>,
/// Selected character in the chararacter selection screen
pub selected_character: Option<CharacterId>,
/// Last spectate position
pub spectate_position: Option<vek::Vec3<f32>>,
}
impl Default for ServerProfile {
@ -44,6 +46,7 @@ impl Default for ServerProfile {
ServerProfile {
characters: HashMap::new(),
selected_character: None,
spectate_position: None,
}
}
}
@ -192,6 +195,41 @@ impl Profile {
.selected_character = selected_character;
}
/// Get the selected_character for the provided server.
///
/// if the server does not exist then the default spectate_position (None)
/// is returned.
///
/// # Arguments
///
/// * server - current server the player is on.
pub fn get_spectate_position(&self, server: &str) -> Option<vek::Vec3<f32>> {
self.servers
.get(server)
.map(|s| s.spectate_position)
.unwrap_or_default()
}
/// Set the spectate_position for the provided server.
///
/// If the server does not exist then the appropriate fields
/// will be initialised and the selected_character added.
///
/// # Arguments
///
/// * server - current server the player is on.
/// * spectate_position - option containing the position we're spectating
pub fn set_spectate_position(
&mut self,
server: &str,
spectate_position: Option<vek::Vec3<f32>>,
) {
self.servers
.entry(server.to_string())
.or_insert(ServerProfile::default())
.spectate_position = spectate_position;
}
/// Save the current profile to disk.
fn save_to_file(&self, config_dir: &Path) -> std::io::Result<()> {
let path = Profile::get_path(config_dir);

View File

@ -5706,7 +5706,7 @@ impl FigureMgr {
}
}
pub fn render_player<'a>(
pub fn render_viewpoint<'a>(
&'a self,
drawer: &mut FigureDrawer<'_, 'a>,
state: &State,
@ -5774,7 +5774,7 @@ impl FigureMgr {
entity: EcsEntity,
body: &Body,
inventory: Option<&Inventory>,
is_player: bool,
is_viewpoint: bool,
pos: Vec3<f32>,
figure_lod_render_distance: f32,
mut_count: usize,
@ -5783,14 +5783,14 @@ impl FigureMgr {
) -> Option<FigureModelRef> {
let body = *body;
let player_camera_mode = if is_player {
let viewpoint_camera_mode = if is_viewpoint {
camera.get_mode()
} else {
CameraMode::default()
};
let focus_pos = camera.get_focus_pos();
let cam_pos = camera.dependents().cam_pos + focus_pos.map(|e| e.trunc());
let character_state = if is_player { character_state } else { None };
let character_state = if is_viewpoint { character_state } else { None };
let FigureMgr {
col_lights: ref col_lights_,
@ -5847,7 +5847,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -5864,7 +5864,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -5881,7 +5881,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -5898,7 +5898,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -5915,7 +5915,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -5932,7 +5932,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -5949,7 +5949,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -5966,7 +5966,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -5983,7 +5983,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -6000,7 +6000,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -6017,7 +6017,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -6034,7 +6034,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -6051,7 +6051,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -6068,7 +6068,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -6085,7 +6085,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -6102,7 +6102,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
item_key,
),
@ -6121,7 +6121,7 @@ impl FigureMgr {
body,
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),
@ -6139,7 +6139,7 @@ impl FigureMgr {
VolumeKey { entity, mut_count },
inventory,
tick,
player_camera_mode,
viewpoint_camera_mode,
character_state,
None,
),

View File

@ -562,7 +562,7 @@ impl Scene {
let yaw = siny_cosp.atan2(cosy_cosp);
self.camera
.set_orientation_instant(Vec3::new(yaw, pitch, -roll));
.set_orientation_instant(Vec3::new(-yaw, pitch, roll));
}
// Alter camera position to match player.
@ -1192,7 +1192,7 @@ impl Scene {
&'a self,
drawer: &mut Drawer<'a>,
state: &State,
player_entity: EcsEntity,
viewpoint_entity: EcsEntity,
tick: u64,
scene_data: &SceneData,
) {
@ -1251,10 +1251,10 @@ impl Scene {
prof_span!(guard, "main pass");
if let Some(mut first_pass) = drawer.first_pass() {
self.figure_mgr.render_player(
self.figure_mgr.render_viewpoint(
&mut first_pass.draw_figures(),
state,
player_entity,
viewpoint_entity,
tick,
camera_data,
);
@ -1264,7 +1264,7 @@ impl Scene {
self.figure_mgr.render(
&mut first_pass.draw_figures(),
state,
player_entity,
viewpoint_entity,
tick,
camera_data,
);

View File

@ -81,7 +81,6 @@ pub struct SessionState {
selected_block: Block,
walk_forward_dir: Vec2<f32>,
walk_right_dir: Vec2<f32>,
freefly_vel: Vec3<f32>,
free_look: bool,
auto_walk: bool,
camera_clamp: bool,
@ -143,7 +142,6 @@ impl SessionState {
selected_block: Block::new(BlockKind::Misc, Rgb::broadcast(255)),
walk_forward_dir,
walk_right_dir,
freefly_vel: Vec3::zero(),
free_look: false,
auto_walk: false,
camera_clamp: false,
@ -368,6 +366,22 @@ impl SessionState {
client::Event::MapMarker(event) => {
self.hud.show.update_map_markers(event);
},
client::Event::StartSpectate(spawn_point) => {
let server_name = &client.server_info().name;
let spawn_point = global_state
.profile
.get_spectate_position(server_name)
.unwrap_or(spawn_point);
client
.state()
.ecs()
.write_storage()
.insert(client.entity(), Pos(spawn_point))
.expect("This shouldn't exist");
self.scene.camera_mut().force_focus_pos(spawn_point);
},
client::Event::SpectatePosition(pos) => {
self.scene.camera_mut().force_focus_pos(pos);
},
@ -493,7 +507,14 @@ impl PlayState for SessionState {
drop(client);
if presence == PresenceKind::Spectator {
self.client.borrow_mut().spectate_position(cam_pos);
let mut client = self.client.borrow_mut();
if client.spectate_position(cam_pos) {
let server_name = &client.server_info().name;
global_state.profile.set_spectate_position(
server_name,
Some(self.scene.camera().get_focus_pos()),
);
}
}
// Nearest block to consider with GameInput primary or secondary key.
@ -906,11 +927,9 @@ impl PlayState for SessionState {
let client = self.client.borrow();
camera.next_mode(
client.is_moderator(),
client
.presence()
.map(|presence| presence != PresenceKind::Spectator)
.unwrap_or(true)
|| self.viewpoint_entity.is_some(),
client.presence().map_or(true, |presence| {
presence != PresenceKind::Spectator
}) || self.viewpoint_entity.is_some(),
);
},
GameInput::Select => {
@ -1091,37 +1110,23 @@ impl PlayState for SessionState {
self.inputs.move_dir =
self.walk_right_dir * axis_right + self.walk_forward_dir * axis_up;
}
self.freefly_vel = Vec3::zero();
},
CameraMode::Freefly => {
// Move the camera freely in 3d space. Apply acceleration so that
// the movement feels more natural and controlled.
const FREEFLY_ACCEL: f32 = 120.0;
const FREEFLY_DAMPING: f32 = 80.0;
const FREEFLY_MAX_SPEED: f32 = 50.0;
const FREEFLY_SPEED: f32 = 50.0;
const FREEFLY_SPEED_BOOST: f32 = 5.0;
let forward = self.scene.camera().forward();
let right = self.scene.camera().right();
let dir = right * axis_right + forward * axis_up;
let forward = self.scene.camera().forward().with_z(0.0).normalized();
let right = self.scene.camera().right().with_z(0.0).normalized();
let up = Vec3::unit_z();
let up_axis = self.key_state.swim_up as i32 as f32
- self.key_state.swim_down as i32 as f32;
if self.freefly_vel.magnitude_squared() > 0.01 {
let new_vel = self.freefly_vel
- self.freefly_vel.normalized() * (FREEFLY_DAMPING * dt);
if self.freefly_vel.dot(new_vel) > 0.0 {
self.freefly_vel = new_vel;
} else {
self.freefly_vel = Vec3::zero();
}
}
if dir.magnitude_squared() > 0.01 {
self.freefly_vel += dir * (FREEFLY_ACCEL * dt);
if self.freefly_vel.magnitude() > FREEFLY_MAX_SPEED {
self.freefly_vel = self.freefly_vel.normalized() * FREEFLY_MAX_SPEED;
}
}
let dir = (right * axis_right + forward * axis_up + up * up_axis).normalized();
let boost = if self.inputs_state.contains(&GameInput::SpectateSpeedBoost) {
let speed = FREEFLY_SPEED
* if self.inputs_state.contains(&GameInput::SpectateSpeedBoost) {
FREEFLY_SPEED_BOOST
} else {
1.0
@ -1130,7 +1135,7 @@ impl PlayState for SessionState {
let pos = self.scene.camera().get_focus_pos();
self.scene
.camera_mut()
.set_focus_pos(pos + self.freefly_vel * dt * boost);
.set_focus_pos(pos + dir * dt * speed);
// Do not apply any movement to the player character
self.inputs.move_dir = Vec2::zero();
@ -1773,7 +1778,7 @@ impl PlayState for SessionState {
self.scene.render(
drawer,
client.state(),
client.entity(),
viewpoint_entity,
client.get_tick(),
&scene_data,
);