mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add a toggle to negotiate the use of server-authoritative physics.
This commit is contained in:
parent
d6f4537d39
commit
50d0314a75
@ -48,6 +48,7 @@
|
||||
"hud.settings.free_look_behavior": "Free look behavior",
|
||||
"hud.settings.auto_walk_behavior": "Auto walk behavior",
|
||||
"hud.settings.camera_clamp_behavior": "Camera clamp behavior",
|
||||
"hud.settings.player_physics_behavior": "Player physics behavior",
|
||||
"hud.settings.stop_auto_walk_on_input": "Stop auto walk on movement",
|
||||
"hud.settings.auto_camera": "Auto camera",
|
||||
"hud.settings.reset_gameplay": "Reset to Defaults",
|
||||
|
@ -786,7 +786,8 @@ impl Client {
|
||||
| ClientGeneral::UnlockSkill(_)
|
||||
| ClientGeneral::RefundSkill(_)
|
||||
| ClientGeneral::RequestSiteInfo(_)
|
||||
| ClientGeneral::UnlockSkillGroup(_) => &mut self.in_game_stream,
|
||||
| ClientGeneral::UnlockSkillGroup(_)
|
||||
| ClientGeneral::RequestPlayerPhysics { .. } => &mut self.in_game_stream,
|
||||
//Only in game, terrain
|
||||
ClientGeneral::TerrainChunkRequest { .. } => &mut self.terrain_stream,
|
||||
//Always possible
|
||||
@ -800,6 +801,12 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_player_physics(&mut self, server_authoritative: bool) {
|
||||
self.send_msg(ClientGeneral::RequestPlayerPhysics {
|
||||
server_authoritative,
|
||||
})
|
||||
}
|
||||
|
||||
fn send_msg<S>(&mut self, msg: S)
|
||||
where
|
||||
S: Into<ClientMsg>,
|
||||
|
@ -81,6 +81,9 @@ pub enum ClientGeneral {
|
||||
//Always possible
|
||||
ChatMsg(String),
|
||||
Terminate,
|
||||
RequestPlayerPhysics {
|
||||
server_authoritative: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl ClientMsg {
|
||||
@ -117,7 +120,8 @@ impl ClientMsg {
|
||||
| ClientGeneral::UnlockSkill(_)
|
||||
| ClientGeneral::RefundSkill(_)
|
||||
| ClientGeneral::RequestSiteInfo(_)
|
||||
| ClientGeneral::UnlockSkillGroup(_) => {
|
||||
| ClientGeneral::UnlockSkillGroup(_)
|
||||
| ClientGeneral::RequestPlayerPhysics { .. } => {
|
||||
c_type == ClientType::Game && presence.is_some()
|
||||
},
|
||||
//Always possible
|
||||
|
@ -32,3 +32,36 @@ pub enum GameMode {
|
||||
/// server
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub struct PlayerEntity(pub Option<Entity>);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PlayerPhysicsSetting {
|
||||
/// true if the client wants server-authoratative physics (e.g. to use
|
||||
/// airships properly)
|
||||
pub client_optin: bool,
|
||||
/// true if the server is forcing server-authoratative physics (e.g. as
|
||||
/// punishment for wallhacking)
|
||||
pub server_optout: bool,
|
||||
}
|
||||
|
||||
impl Default for PlayerPhysicsSetting {
|
||||
fn default() -> PlayerPhysicsSetting {
|
||||
PlayerPhysicsSetting {
|
||||
client_optin: false,
|
||||
server_optout: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlayerPhysicsSetting {
|
||||
pub fn server_authoritative(&self) -> bool { self.client_optin || self.server_optout }
|
||||
|
||||
pub fn client_authoritative(&self) -> bool { !self.server_authoritative() }
|
||||
}
|
||||
|
||||
/// List of which players are using client-authoratative vs server-authoratative
|
||||
/// physics, as a stop-gap until we can use server-authoratative physics for
|
||||
/// everyone
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct PlayerPhysicsSettings {
|
||||
pub settings: hashbrown::HashMap<uuid::Uuid, PlayerPhysicsSetting>,
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use common::{
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
outcome::Outcome,
|
||||
region::RegionMap,
|
||||
resources::{DeltaTime, GameMode, PlayerEntity, Time, TimeOfDay},
|
||||
resources::{DeltaTime, GameMode, PlayerEntity, PlayerPhysicsSettings, Time, TimeOfDay},
|
||||
slowjob::SlowJobPool,
|
||||
terrain::{Block, TerrainChunk, TerrainGrid},
|
||||
time::DayPeriod,
|
||||
@ -278,6 +278,7 @@ impl State {
|
||||
ecs.insert(SysMetrics::default());
|
||||
ecs.insert(PhysicsMetrics::default());
|
||||
ecs.insert(Trades::default());
|
||||
ecs.insert(PlayerPhysicsSettings::default());
|
||||
|
||||
// Load plugins from asset directory
|
||||
#[cfg(feature = "plugins")]
|
||||
|
@ -5,10 +5,10 @@ use crate::{
|
||||
Tick,
|
||||
};
|
||||
use common::{
|
||||
comp::{Collider, ForceUpdate, Inventory, InventoryUpdate, Last, Ori, Pos, Vel},
|
||||
comp::{Collider, ForceUpdate, Inventory, InventoryUpdate, Last, Ori, Player, Pos, Vel},
|
||||
outcome::Outcome,
|
||||
region::{Event as RegionEvent, RegionMap},
|
||||
resources::TimeOfDay,
|
||||
resources::{PlayerPhysicsSettings, TimeOfDay},
|
||||
terrain::TerrainChunkSize,
|
||||
uid::Uid,
|
||||
vol::RectVolSize,
|
||||
@ -45,6 +45,8 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, InventoryUpdate>,
|
||||
Write<'a, DeletedEntities>,
|
||||
Write<'a, Vec<Outcome>>,
|
||||
Read<'a, PlayerPhysicsSettings>,
|
||||
ReadStorage<'a, Player>,
|
||||
TrackedComps<'a>,
|
||||
ReadTrackers<'a>,
|
||||
);
|
||||
@ -76,6 +78,8 @@ impl<'a> System<'a> for Sys {
|
||||
mut inventory_updates,
|
||||
mut deleted_entities,
|
||||
mut outcomes,
|
||||
player_physics_settings,
|
||||
players,
|
||||
tracked_comps,
|
||||
trackers,
|
||||
): Self::SystemData,
|
||||
@ -201,7 +205,8 @@ impl<'a> System<'a> for Sys {
|
||||
for (client, _, client_entity, client_pos) in &mut subscribers {
|
||||
let mut comp_sync_package = CompSyncPackage::new();
|
||||
|
||||
for (_, entity, &uid, (&pos, last_pos), vel, ori, force_update, collider) in (
|
||||
for (_, entity, &uid, (&pos, last_pos), vel, ori, force_update, collider, player) in
|
||||
(
|
||||
region.entities(),
|
||||
&entities,
|
||||
&uids,
|
||||
@ -210,13 +215,18 @@ impl<'a> System<'a> for Sys {
|
||||
(&orientations, last_vel.mask().maybe()).maybe(),
|
||||
force_updates.mask().maybe(),
|
||||
colliders.maybe(),
|
||||
players.maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let player_physics_setting = player
|
||||
.and_then(|p| player_physics_settings.settings.get(&p.uuid()).cloned())
|
||||
.unwrap_or_default();
|
||||
// Decide how regularly to send physics updates.
|
||||
let send_now = if client_entity == &entity {
|
||||
// Don't send client physics updates about itself unless force update is set
|
||||
force_update.is_some() || true
|
||||
// or the client is subject to server-authoritative physics
|
||||
force_update.is_some() || player_physics_setting.server_authoritative()
|
||||
} else if matches!(collider, Some(Collider::Voxel { .. })) {
|
||||
// Things with a voxel collider (airships, etc.) need to have very stable
|
||||
// physics so we always send updated for these where
|
||||
|
@ -1,7 +1,10 @@
|
||||
use crate::{client::Client, presence::Presence, Settings};
|
||||
use common::{
|
||||
comp::{CanBuild, ControlEvent, Controller, ForceUpdate, Health, Ori, Pos, SkillSet, Vel},
|
||||
comp::{
|
||||
CanBuild, ControlEvent, Controller, ForceUpdate, Health, Ori, Player, Pos, SkillSet, Vel,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::PlayerPhysicsSettings,
|
||||
terrain::TerrainGrid,
|
||||
vol::ReadVol,
|
||||
};
|
||||
@ -30,6 +33,8 @@ impl Sys {
|
||||
controllers: &mut WriteStorage<'_, Controller>,
|
||||
settings: &Read<'_, Settings>,
|
||||
build_areas: &Read<'_, BuildAreas>,
|
||||
player_physics_settings: &mut Write<'_, PlayerPhysicsSettings>,
|
||||
maybe_player: &Option<&Player>,
|
||||
msg: ClientGeneral,
|
||||
) -> Result<(), crate::error::Error> {
|
||||
let presence = match maybe_presence {
|
||||
@ -40,6 +45,12 @@ impl Sys {
|
||||
return Ok(());
|
||||
},
|
||||
};
|
||||
let player_physics_setting = maybe_player.map(|p| {
|
||||
player_physics_settings
|
||||
.settings
|
||||
.entry(p.uuid())
|
||||
.or_default()
|
||||
});
|
||||
match msg {
|
||||
// Go back to registered state (char selection screen)
|
||||
ClientGeneral::ExitInGame => {
|
||||
@ -93,14 +104,15 @@ impl Sys {
|
||||
}
|
||||
},
|
||||
ClientGeneral::PlayerPhysics { pos, vel, ori } => {
|
||||
/*if matches!(presence.kind, PresenceKind::Character(_))
|
||||
if matches!(presence.kind, PresenceKind::Character(_))
|
||||
&& force_updates.get(entity).is_none()
|
||||
&& healths.get(entity).map_or(true, |h| !h.is_dead)
|
||||
&& player_physics_setting.map_or(true, |s| s.client_authoritative())
|
||||
{
|
||||
let _ = positions.insert(entity, pos);
|
||||
let _ = velocities.insert(entity, vel);
|
||||
let _ = orientations.insert(entity, ori);
|
||||
}*/
|
||||
}
|
||||
},
|
||||
ClientGeneral::BreakBlock(pos) => {
|
||||
if let Some(comp_can_build) = can_build.get(entity) {
|
||||
@ -156,6 +168,13 @@ impl Sys {
|
||||
ClientGeneral::RequestSiteInfo(id) => {
|
||||
server_emitter.emit(ServerEvent::RequestSiteInfo { entity, id });
|
||||
},
|
||||
ClientGeneral::RequestPlayerPhysics {
|
||||
server_authoritative,
|
||||
} => {
|
||||
if let Some(setting) = player_physics_setting {
|
||||
setting.client_optin = server_authoritative;
|
||||
}
|
||||
},
|
||||
_ => tracing::error!("not a client_in_game msg"),
|
||||
}
|
||||
Ok(())
|
||||
@ -184,6 +203,8 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Controller>,
|
||||
Read<'a, Settings>,
|
||||
Read<'a, BuildAreas>,
|
||||
Write<'a, PlayerPhysicsSettings>,
|
||||
ReadStorage<'a, Player>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "msg::in_game";
|
||||
@ -209,12 +230,19 @@ impl<'a> System<'a> for Sys {
|
||||
mut controllers,
|
||||
settings,
|
||||
build_areas,
|
||||
mut player_physics_settings,
|
||||
players,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let mut server_emitter = server_event_bus.emitter();
|
||||
|
||||
for (entity, client, mut maybe_presence) in
|
||||
(&entities, &mut clients, (&mut presences).maybe()).join()
|
||||
for (entity, client, mut maybe_presence, player) in (
|
||||
&entities,
|
||||
&mut clients,
|
||||
(&mut presences).maybe(),
|
||||
players.maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let _ = super::try_recv_all(client, 2, |client, msg| {
|
||||
Self::handle_client_in_game_msg(
|
||||
@ -234,6 +262,8 @@ impl<'a> System<'a> for Sys {
|
||||
&mut controllers,
|
||||
&settings,
|
||||
&build_areas,
|
||||
&mut player_physics_settings,
|
||||
&player,
|
||||
msg,
|
||||
)
|
||||
});
|
||||
|
@ -44,6 +44,8 @@ widget_ids! {
|
||||
auto_walk_behavior_list,
|
||||
camera_clamp_behavior_text,
|
||||
camera_clamp_behavior_list,
|
||||
player_physics_behavior_text,
|
||||
player_physics_behavior_list,
|
||||
stop_auto_walk_on_input_button,
|
||||
stop_auto_walk_on_input_label,
|
||||
auto_camera_button,
|
||||
@ -438,6 +440,43 @@ impl<'a> Widget for Gameplay<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Player physics behavior
|
||||
Text::new(
|
||||
&self
|
||||
.localized_strings
|
||||
.get("hud.settings.player_physics_behavior"),
|
||||
)
|
||||
.down_from(state.ids.auto_walk_behavior_list, 10.0)
|
||||
.right_from(state.ids.camera_clamp_behavior_text, 118.0)
|
||||
.font_size(self.fonts.cyri.scale(14))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.set(state.ids.player_physics_behavior_text, ui);
|
||||
|
||||
let player_physics_selected =
|
||||
self.global_state.settings.gameplay.player_physics_behavior as usize;
|
||||
|
||||
if let Some(clicked) = DropDownList::new(
|
||||
&["Client-authoritative", "Server-authoritative"],
|
||||
Some(player_physics_selected),
|
||||
)
|
||||
.w_h(200.0, 30.0)
|
||||
.color(MENU_BG)
|
||||
.label_color(TEXT_COLOR)
|
||||
.label_font_id(self.fonts.cyri.conrod_id)
|
||||
.down_from(state.ids.player_physics_behavior_text, 8.0)
|
||||
.set(state.ids.player_physics_behavior_list, ui)
|
||||
{
|
||||
match clicked {
|
||||
0 => events.push(ChangePlayerPhysicsBehavior {
|
||||
server_authoritative: false,
|
||||
}),
|
||||
_ => events.push(ChangePlayerPhysicsBehavior {
|
||||
server_authoritative: true,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// Stop autowalk on input toggle
|
||||
let stop_auto_walk_on_input_toggle = ToggleButton::new(
|
||||
self.global_state.settings.gameplay.stop_auto_walk_on_input,
|
||||
|
@ -88,6 +88,9 @@ impl SessionState {
|
||||
scene
|
||||
.camera_mut()
|
||||
.set_fov_deg(global_state.settings.graphics.fov);
|
||||
client
|
||||
.borrow_mut()
|
||||
.request_player_physics(global_state.settings.gameplay.player_physics_behavior);
|
||||
let hud = Hud::new(global_state, &client.borrow());
|
||||
let walk_forward_dir = scene.camera().forward_xy();
|
||||
let walk_right_dir = scene.camera().right_xy();
|
||||
|
@ -46,6 +46,7 @@ pub enum Gameplay {
|
||||
ChangeFreeLookBehavior(PressBehavior),
|
||||
ChangeAutoWalkBehavior(PressBehavior),
|
||||
ChangeCameraClampBehavior(PressBehavior),
|
||||
ChangePlayerPhysicsBehavior { server_authoritative: bool },
|
||||
ChangeStopAutoWalkOnInput(bool),
|
||||
ChangeAutoCamera(bool),
|
||||
|
||||
@ -224,6 +225,15 @@ impl SettingsChange {
|
||||
Gameplay::ChangeCameraClampBehavior(behavior) => {
|
||||
settings.gameplay.camera_clamp_behavior = behavior;
|
||||
},
|
||||
Gameplay::ChangePlayerPhysicsBehavior {
|
||||
server_authoritative,
|
||||
} => {
|
||||
settings.gameplay.player_physics_behavior = server_authoritative;
|
||||
session_state
|
||||
.client
|
||||
.borrow_mut()
|
||||
.request_player_physics(server_authoritative);
|
||||
},
|
||||
Gameplay::ChangeStopAutoWalkOnInput(state) => {
|
||||
settings.gameplay.stop_auto_walk_on_input = state;
|
||||
},
|
||||
|
@ -14,6 +14,7 @@ pub struct GameplaySettings {
|
||||
pub free_look_behavior: PressBehavior,
|
||||
pub auto_walk_behavior: PressBehavior,
|
||||
pub camera_clamp_behavior: PressBehavior,
|
||||
pub player_physics_behavior: bool,
|
||||
pub stop_auto_walk_on_input: bool,
|
||||
pub auto_camera: bool,
|
||||
}
|
||||
@ -30,6 +31,7 @@ impl Default for GameplaySettings {
|
||||
free_look_behavior: PressBehavior::Toggle,
|
||||
auto_walk_behavior: PressBehavior::Toggle,
|
||||
camera_clamp_behavior: PressBehavior::Toggle,
|
||||
player_physics_behavior: false,
|
||||
stop_auto_walk_on_input: true,
|
||||
auto_camera: false,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user