-
-
Notifications
You must be signed in to change notification settings - Fork 218
/
Copy pathengine.rs
190 lines (172 loc) · 5.99 KB
/
engine.rs
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
//! Godot engine classes and methods.
// Re-exports of generated symbols
use crate::builtin::{GodotString, NodePath};
use crate::engine::resource_loader::CacheMode;
use crate::obj::dom::EngineDomain;
use crate::obj::{Gd, GodotClass, Inherits};
pub use gen::central_core::global;
pub use gen::classes::*;
pub use gen::utilities;
/// Output of generated code.
pub(super) mod gen {
#[allow(unused_imports, dead_code, non_upper_case_globals, non_snake_case)]
pub(crate) mod classes {
// Path to core/classes/obj
// Do not write macro for this, as it confuses IDEs -- just search&replace
include!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../target/godot-gen/core/classes/mod.rs"
));
}
pub mod utilities {
// Path to core/utilities.rs
// Do not write macro for this, as it confuses IDEs -- just search&replace
include!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../target/godot-gen/core/utilities.rs"
));
}
#[allow(non_upper_case_globals, non_snake_case)]
pub mod central_core {
// Path to core/utilities.rs
// Do not write macro for this, as it confuses IDEs -- just search&replace
include!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../target/godot-gen/core/central.rs"
));
}
}
/// Extension trait with convenience functions for the node tree.
pub trait NodeExt {
/// Retrieves the node at path `path`, panicking if not found or bad type.
///
/// # Panics
/// If the node is not found, or if it does not have type `T` or inherited.
fn get_node_as<T>(&self, path: impl Into<NodePath>) -> Gd<T>
where
T: GodotClass + Inherits<Node>,
{
let path = path.into();
let copy = path.clone(); // TODO avoid copy
self.try_get_node_as(path).unwrap_or_else(|| {
panic!(
"There is no node of type {ty} path `{copy}`",
ty = T::CLASS_NAME
)
})
}
/// Retrieves the node at path `path` (fallible).
///
/// If the node is not found, or if it does not have type `T` or inherited,
/// `None` will be returned.
fn try_get_node_as<T>(&self, path: impl Into<NodePath>) -> Option<Gd<T>>
where
T: GodotClass + Inherits<Node>;
}
impl NodeExt for Node {
fn try_get_node_as<T>(&self, path: impl Into<NodePath>) -> Option<Gd<T>>
where
T: GodotClass + Inherits<Node>,
{
let path = path.into();
// TODO differentiate errors (not found, bad type) with Result
self.get_node_or_null(path)
.and_then(|node| node.try_cast::<T>())
}
}
impl<U> NodeExt for Gd<U>
where
U: GodotClass<Declarer = EngineDomain> + Inherits<Node>,
{
fn try_get_node_as<T>(&self, path: impl Into<NodePath>) -> Option<Gd<T>>
where
T: GodotClass + Inherits<Node>,
{
// TODO this could be implemented without share(), but currently lacks the proper bounds
// This would need more sophisticated upcast design, e.g. T::upcast_{ref|mut}::<U>() for indirect relations
// to make the indirect Deref more explicit
use crate::obj::Share;
let path = path.into();
let node = self.share().upcast::<Node>();
<Node as NodeExt>::try_get_node_as(&*node, path)
}
}
/// Loads a resource from the filesystem located at `path`, panicking on error.
///
/// See [`try_load`] for more information.
///
/// # Example
///
/// ```no_run
/// use godot::prelude::*;
///
/// let scene = load::<PackedScene>("res://path/to/Main.tscn");
/// ```
///
/// # Panics
/// If the resource cannot be loaded, or is not of type `T` or inherited.
#[inline]
pub fn load<T>(path: impl Into<GodotString>) -> Gd<T>
where
T: GodotClass + Inherits<Resource>,
{
let path = path.into();
load_impl(&path).unwrap_or_else(|| panic!("failed to load node at path `{path}`"))
}
/// Loads a resource from the filesystem located at `path`.
///
/// The resource is loaded on the method call (unless it's referenced already elsewhere, e.g. in another script or in the scene),
/// which might cause slight delay, especially when loading scenes.
///
/// If the resource cannot be loaded, or is not of type `T` or inherited, this method returns `None`.
///
/// This method is a simplified version of [`ResourceLoader::load()`][crate::api::ResourceLoader::load],
/// which can be used for more advanced scenarios.
///
/// # Note:
/// Resource paths can be obtained by right-clicking on a resource in the Godot editor (_FileSystem_ dock) and choosing "Copy Path",
/// or by dragging the file from the _FileSystem_ dock into the script.
///
/// The path must be absolute (typically starting with `res://`), a local path will fail.
///
/// # Example:
/// Loads a scene called `Main` located in the `path/to` subdirectory of the Godot project and caches it in a variable.
/// The resource is directly stored with type `PackedScene`.
///
/// ```no_run
/// use godot::prelude::*;
///
/// if let Some(scene) = try_load::<PackedScene>("res://path/to/Main.tscn") {
/// // all good
/// } else {
/// // handle error
/// }
/// ```
// TODO Result to differentiate 2 errors
#[inline]
pub fn try_load<T>(path: impl Into<GodotString>) -> Option<Gd<T>>
where
T: GodotClass + Inherits<Resource>,
{
load_impl(&path.into())
}
// Separate function, to avoid constructing string twice
// Note that more optimizations than that likely make no sense, as loading is quite expensive
fn load_impl<T>(path: &GodotString) -> Option<Gd<T>>
where
T: GodotClass + Inherits<Resource>,
{
let type_hint = T::CLASS_NAME;
ResourceLoader::singleton()
.load(
path.clone(), /* TODO unclone */
type_hint.into(),
CacheMode::CACHE_MODE_REUSE,
)
.and_then(|res| res.try_cast::<T>())
}