-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathgo_to.rs
More file actions
118 lines (98 loc) 路 3.04 KB
/
Copy pathgo_to.rs
File metadata and controls
118 lines (98 loc) 路 3.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use crate::activity::context::ActivityContext;
use crate::activity::status::{NopStatus, Status};
use crate::ecs::ComponentGetError;
use crate::event::prelude::*;
use crate::{ComponentWorld, FollowPathComponent};
use common::*;
use unit::world::WorldPoint;
use world::{NavigationError, SearchGoal};
#[derive(Debug, Error)]
pub enum GotoError {
#[error("Can't get FollowPathComponent: {0}")]
MissingComponent(#[from] ComponentGetError),
#[error("Failed to navigate: {0}")]
Navigation(#[from] NavigationError),
#[error("Goto was cancelled")]
Cancelled,
}
pub struct GoToSubactivity<'a> {
context: &'a ActivityContext,
complete: bool,
}
pub enum GoingToStatus<T: Status + 'static = NopStatus> {
Default,
Target(&'static str),
Custom(T),
}
impl GoingToStatus {
pub fn default() -> Self {
GoingToStatus::Default
}
pub fn target(target: &'static str) -> Self {
GoingToStatus::Target(target)
}
}
impl<'a> GoToSubactivity<'a> {
pub fn new(context: &'a ActivityContext) -> Self {
Self {
context,
complete: false,
}
}
pub async fn go_to<T: Status + 'static>(
&mut self,
dest: WorldPoint,
speed: NormalizedFloat,
goal: SearchGoal,
status: GoingToStatus<T>,
) -> Result<(), GotoError> {
let ctx = self.context;
ctx.update_status(status);
let path_token;
{
let mut follow_path = ctx
.world()
.component_mut::<FollowPathComponent>(ctx.entity())
.map_err(GotoError::MissingComponent)?;
// assign path
path_token = follow_path.new_path_with_goal(dest, goal, speed);
}
// await arrival
let goto_result = ctx
.subscribe_to_specific_until(ctx.entity(), EntityEventType::Arrived, |evt| match evt {
EntityEventPayload::Arrived(token, result) if token == path_token => Ok(result),
_ => Err(evt),
})
.await;
let result = match goto_result {
None => return Err(GotoError::Cancelled),
Some(Ok(_)) => Ok(()),
Some(Err(err)) => Err(err.into()),
};
self.complete = true;
result
}
}
impl Drop for GoToSubactivity<'_> {
fn drop(&mut self) {
if !self.complete {
debug!("aborting incomplete goto"; self.context.entity());
self.context.clear_path();
}
}
}
impl<T: Status> Display for GoingToStatus<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
GoingToStatus::Default => f.write_str("Going to target"),
GoingToStatus::Target(target) => write!(f, "Going to {}", target),
GoingToStatus::Custom(custom) => Display::fmt(custom, f),
}
}
}
impl<T: Status> Status for GoingToStatus<T> {
fn exertion(&self) -> f32 {
// TODO use target moving speed or get the actual speed when applying exertion in other system?
1.0
}
}