mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
changes per MR feedback. simplier Option handling with zip, filter, and fewr unwraps. use kind keyword (not typed). if lets when possible. additional syntax cleanup
This commit is contained in:
parent
8b83b48b9b
commit
f60bd80cc2
@ -3,7 +3,7 @@ use specs::{Join, WorldExt};
|
||||
use vek::*;
|
||||
|
||||
use super::target::{self, Target};
|
||||
use client::{self, Client};
|
||||
use client::Client;
|
||||
use common::{
|
||||
comp,
|
||||
consts::MAX_PICKUP_RANGE,
|
||||
@ -61,42 +61,39 @@ pub(super) fn select_interactable(
|
||||
if let Some(interactable) = entity_target
|
||||
.and_then(|t| {
|
||||
if t.distance < MAX_PICKUP_RANGE {
|
||||
let entity = t.typed.0;
|
||||
let entity = t.kind.0;
|
||||
Some(Interactable::Entity(entity))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.or_else(|| {
|
||||
collect_target
|
||||
.map(|t| {
|
||||
get_block(client, t).map(|b| {
|
||||
Interactable::Block(b, t.position_int(), Some(Interaction::Collect))
|
||||
})
|
||||
})
|
||||
.unwrap_or(None)
|
||||
collect_target.and_then(|t| {
|
||||
get_block(client, t)
|
||||
.map(|b| Interactable::Block(b, t.position_int(), Some(Interaction::Collect)))
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
mine_target
|
||||
.map(|t| {
|
||||
get_block(client, t).and_then(|b| {
|
||||
// Handling edge detection. sometimes the casting (in Target mod) returns a
|
||||
// position which is actually empty, which we do not want labeled as an
|
||||
// interactable. We are only returning the mineable air
|
||||
// elements (e.g. minerals). The mineable weakrock are used
|
||||
// in the terrain selected_pos, but is not an interactable.
|
||||
if b.mine_tool().is_some() && b.is_air() {
|
||||
Some(Interactable::Block(b, t.position_int(), None))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
mine_target.and_then(|t| {
|
||||
get_block(client, t).and_then(|b| {
|
||||
// Handling edge detection. sometimes the casting (in Target mod) returns a
|
||||
// position which is actually empty, which we do not want labeled as an
|
||||
// interactable. We are only returning the mineable air
|
||||
// elements (e.g. minerals). The mineable weakrock are used
|
||||
// in the terrain selected_pos, but is not an interactable.
|
||||
if b.mine_tool().is_some() && b.is_air() {
|
||||
Some(Interactable::Block(b, t.position_int(), None))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or(None)
|
||||
})
|
||||
})
|
||||
{
|
||||
Some(interactable)
|
||||
} else {
|
||||
// If there are no directly targeted interactables select the closest one if any
|
||||
// are in range
|
||||
let ecs = client.state().ecs();
|
||||
let player_entity = client.entity();
|
||||
let positions = ecs.read_storage::<comp::Pos>();
|
||||
|
@ -425,28 +425,26 @@ impl PlayState for SessionState {
|
||||
|
||||
drop(client);
|
||||
|
||||
fn is_nearest_target<T>(shortest_dist: f32, target: Option<Target<T>>) -> bool {
|
||||
target
|
||||
.map(|t| (t.distance <= shortest_dist))
|
||||
.unwrap_or(false)
|
||||
fn is_nearest_target<T>(shortest_dist: f32, target: Target<T>) -> bool {
|
||||
target.distance <= shortest_dist
|
||||
}
|
||||
|
||||
// Only highlight terrain blocks which can be interacted with
|
||||
if is_mining && is_nearest_target(shortest_dist, mine_target) {
|
||||
mine_target.map(|mt| self.scene.set_select_pos(Some(mt.position_int())));
|
||||
} else if can_build && is_nearest_target(shortest_dist, build_target) {
|
||||
build_target.map(|bt| self.scene.set_select_pos(Some(bt.position_int())));
|
||||
if let Some(mt) =
|
||||
mine_target.filter(|mt| is_mining && is_nearest_target(shortest_dist, *mt))
|
||||
{
|
||||
self.scene.set_select_pos(Some(mt.position_int()));
|
||||
} else if let Some(bt) =
|
||||
build_target.filter(|bt| can_build && is_nearest_target(shortest_dist, *bt))
|
||||
{
|
||||
self.scene.set_select_pos(Some(bt.position_int()));
|
||||
} else {
|
||||
self.scene.set_select_pos(None);
|
||||
self.inputs.select_pos = entity_target.map(|et| et.position);
|
||||
}
|
||||
|
||||
// Throw out distance info, it will be useful in the future
|
||||
self.target_entity = if let Some(target::Entity(e)) = entity_target.map(|t| t.typed) {
|
||||
Some(e)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.target_entity = entity_target.map(|t| t.kind.0);
|
||||
|
||||
// Handle window events.
|
||||
for event in events {
|
||||
@ -471,15 +469,17 @@ impl PlayState for SessionState {
|
||||
let mut client = self.client.borrow_mut();
|
||||
// Mine and build targets can be the same block. make building take
|
||||
// precedence.
|
||||
if state
|
||||
&& can_build
|
||||
&& is_nearest_target(shortest_dist, build_target)
|
||||
{
|
||||
self.inputs.select_pos = build_target.map(|t| t.position);
|
||||
client.remove_block(build_target.unwrap().position_int());
|
||||
// Order of precedence: build, then mining, then attack.
|
||||
if let Some(build_target) = build_target.filter(|bt| {
|
||||
state && can_build && is_nearest_target(shortest_dist, *bt)
|
||||
}) {
|
||||
self.inputs.select_pos = Some(build_target.position);
|
||||
client.remove_block(build_target.position_int());
|
||||
} else {
|
||||
if is_mining && is_nearest_target(shortest_dist, mine_target) {
|
||||
self.inputs.select_pos = mine_target.map(|t| t.position);
|
||||
if let Some(mine_target) = mine_target.filter(|mt| {
|
||||
is_mining && is_nearest_target(shortest_dist, *mt)
|
||||
}) {
|
||||
self.inputs.select_pos = Some(mine_target.position);
|
||||
}
|
||||
client.handle_input(
|
||||
InputKind::Primary,
|
||||
@ -491,17 +491,14 @@ impl PlayState for SessionState {
|
||||
},
|
||||
GameInput::Secondary => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if state
|
||||
&& can_build
|
||||
&& is_nearest_target(shortest_dist, build_target)
|
||||
{
|
||||
if let Some(build_target) = build_target {
|
||||
self.inputs.select_pos = Some(build_target.position);
|
||||
client.place_block(
|
||||
build_target.position_int(),
|
||||
self.selected_block,
|
||||
);
|
||||
}
|
||||
if let Some(build_target) = build_target.filter(|bt| {
|
||||
state && can_build && is_nearest_target(shortest_dist, *bt)
|
||||
}) {
|
||||
self.inputs.select_pos = Some(build_target.position);
|
||||
client.place_block(
|
||||
build_target.position_int(),
|
||||
self.selected_block,
|
||||
);
|
||||
} else {
|
||||
client.handle_input(
|
||||
InputKind::Secondary,
|
||||
|
@ -1,3 +1,4 @@
|
||||
use ordered_float::OrderedFloat;
|
||||
use specs::{Join, WorldExt};
|
||||
use vek::*;
|
||||
|
||||
@ -13,7 +14,7 @@ use common_base::span;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Target<T> {
|
||||
pub typed: T,
|
||||
pub kind: T,
|
||||
pub distance: f32,
|
||||
pub position: Vec3<f32>,
|
||||
}
|
||||
@ -98,9 +99,7 @@ pub(super) fn targets_under_cursor(
|
||||
let (mine_pos, _, mine_cam_ray) = is_mining
|
||||
.then(|| find_pos(|b: Block| b.mine_tool().is_some()))
|
||||
.unwrap_or((None, None, None));
|
||||
let (_, solid_pos, solid_cam_ray) = can_build
|
||||
.then(|| find_pos(|b: Block| b.is_solid()))
|
||||
.unwrap_or((None, None, None));
|
||||
let (_, solid_pos, solid_cam_ray) = find_pos(|b: Block| b.is_solid());
|
||||
|
||||
// Find shortest cam_dist of non-entity targets.
|
||||
// Note that some of these targets can technically be in Air, such as the
|
||||
@ -117,7 +116,7 @@ pub(super) fn targets_under_cursor(
|
||||
Some((d, Ok(Some(_)))) => Some(d),
|
||||
_ => None,
|
||||
})
|
||||
.min_by(|d1, d2| d1.partial_cmp(d2).unwrap())
|
||||
.min_by(|d1, d2| OrderedFloat(*d1).cmp(&OrderedFloat(*d2)))
|
||||
.unwrap_or(MAX_PICKUP_RANGE);
|
||||
|
||||
// See if ray hits entities
|
||||
@ -189,16 +188,16 @@ pub(super) fn targets_under_cursor(
|
||||
let dist_to_player = player_cylinder.min_distance(target_cylinder);
|
||||
if dist_to_player < MAX_TARGET_RANGE {
|
||||
Some(Target {
|
||||
typed: Entity(*e),
|
||||
kind: Entity(*e),
|
||||
position: p,
|
||||
distance: dist_to_player,
|
||||
})
|
||||
} else { None }
|
||||
});
|
||||
|
||||
let build_target = if let (Some(position), Some(ray)) = (solid_pos, solid_cam_ray) {
|
||||
Some(Target {
|
||||
typed: Build,
|
||||
let build_target = if can_build {
|
||||
solid_pos.zip(solid_cam_ray).map(|(position, ray)| Target {
|
||||
kind: Build,
|
||||
distance: ray.0,
|
||||
position,
|
||||
})
|
||||
@ -206,25 +205,19 @@ pub(super) fn targets_under_cursor(
|
||||
None
|
||||
};
|
||||
|
||||
let collect_target = if let (Some(position), Some(ray)) = (collect_pos, collect_cam_ray) {
|
||||
Some(Target {
|
||||
typed: Collectable,
|
||||
let collect_target = collect_pos
|
||||
.zip(collect_cam_ray)
|
||||
.map(|(position, ray)| Target {
|
||||
kind: Collectable,
|
||||
distance: ray.0,
|
||||
position,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
});
|
||||
|
||||
let mine_target = if let (Some(position), Some(ray)) = (mine_pos, mine_cam_ray) {
|
||||
Some(Target {
|
||||
typed: Mine,
|
||||
distance: ray.0,
|
||||
position,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mine_target = mine_pos.zip(mine_cam_ray).map(|(position, ray)| Target {
|
||||
kind: Mine,
|
||||
distance: ray.0,
|
||||
position,
|
||||
});
|
||||
|
||||
// Return multiple possible targets
|
||||
// GameInput events determine which target to use.
|
||||
|
Loading…
Reference in New Issue
Block a user