Skip to content

Commit

Permalink
Port Road Navigation to Rust
Browse files Browse the repository at this point in the history
  • Loading branch information
TitanNano committed Jun 24, 2024
1 parent f6529c0 commit e21f72b
Show file tree
Hide file tree
Showing 18 changed files with 764 additions and 327 deletions.
44 changes: 18 additions & 26 deletions native/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions native/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = "2021"
crate-type = ["cdylib"]

[dependencies]
godot = { git = "https://github.com/godot-rust/gdext", rev = "22fd33d4d5213a3fe5db9a58547888cebe35c647", features = ["experimental-threads"]}
godot = { git = "https://github.com/godot-rust/gdext", rev = "4c8ea83fc3452485f7b33f2411c136a248457334", features = ["experimental-threads"] }
lerp = "0.4.0"
backtrace = "0.3.64"
num = "0.4.0"
Expand All @@ -17,5 +17,6 @@ num_enum = "0.7.1"
derive-debug = "0.1.2"
thiserror = "1.0.56"
anyhow = { version = "1.0.79" }
rand = "0.8.5"

godot-rust-script = { git = "https://github.com/titannano/godot-rust-script", rev = "821b21a3a330d2b4de20069a1013e4903f95a601" }
godot-rust-script = { git = "https://github.com/titannano/godot-rust-script", rev = "da275fb0cb61e24571295c8d5a3cce4123fdce24" }
2 changes: 2 additions & 0 deletions native/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
mod objects;
mod resources;
mod road_navigation;
mod scripts;
mod terrain_builder;
mod util;
Expand Down
4 changes: 4 additions & 0 deletions native/src/resources.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod road_navigation;
mod world_constants;

pub use world_constants::*;
199 changes: 199 additions & 0 deletions native/src/resources/road_navigation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
use godot::{
builtin::{Dictionary, Transform3D, Vector3},
engine::{IResource, Node3D, Resource},
obj::{Base, Gd},
register::{godot_api, GodotClass},
};

use crate::{
road_navigation::RoadNavigation,
util::logger,
world::city_data::{Building, ToDictionary, TryFromDictionary},
};

use super::WorldConstants;

#[derive(GodotClass)]
#[class(base = Resource)]
pub(crate) struct RoadNavigationRes {
inner: Option<RoadNavigation>,

#[var(get = world_constants, set = set_world_constants)]
#[export]
world_constants: Option<Gd<WorldConstants>>,
}

#[godot_api]
impl RoadNavigationRes {
#[func]
fn world_constants(&self) -> Option<Gd<WorldConstants>> {
self.world_constants.clone()
}

#[func]
fn set_world_constants(&mut self, value: Gd<WorldConstants>) {
self.inner = Some(RoadNavigation::new(value.clone()));
self.world_constants = Some(value);
}

#[func]
fn insert_node(&mut self, building: Dictionary, object: Gd<Node3D>) {
let Some(inner) = self.inner.as_mut() else {
logger::error!("Road Navigation resource is not ready!");
return;
};

let building = match Building::try_from_dict(&building) {
Ok(building) => building,
Err(err) => {
logger::error!("Failed to read building dict: {}", err);
return;
}
};

inner.insert_node(building, object);
}

#[func]
fn get_nearest_node(&self, global_translation: Vector3) -> Dictionary {
let Some(inner) = self.inner.as_ref() else {
logger::error!("Road Navigation resource is not ready!");
return Dictionary::new();
};

let node = inner.get_nearest_node(global_translation);

let Some(building) = node.as_ref().map(|node| node.building()) else {
logger::error!("Failed to get nearest navigation node!");
return Dictionary::new();
};

building.to_dict()
}

#[func]
fn get_next_node(
&self,
current: Dictionary,
target: Dictionary,
actor_orientation: Vector3,
) -> Dictionary {
let current = match Building::try_from_dict(&current) {
Ok(current) => current,
Err(err) => {
logger::error!("Invalid current building dictionary: {}", err);
return Dictionary::new();
}
};

let target = match Building::try_from_dict(&target) {
Ok(target) => target,
Err(err) => {
logger::error!("Invalid target building dictionary: {}", err);
return Dictionary::new();
}
};

let Some(inner) = self.inner.as_ref() else {
logger::error!("Road Navigation resource is not ready!");
return Dictionary::new();
};

let Some(current_node) = inner.get_node(current.tile_coords) else {
logger::error!("Current node does not exist: {:?}", current);
return Dictionary::new();
};

let Some(target_node) = inner.get_node(target.tile_coords) else {
logger::error!("Target node does not exist: {:?}", target);
return Dictionary::new();
};

let dict = inner
.get_next_node(&current_node, &target_node, actor_orientation)
.building()
.to_dict();

dict
}

#[func]
fn has_arrived(&self, location: Vector3, direction: Vector3, building: Dictionary) -> bool {
let building = match Building::try_from_dict(&building) {
Ok(building) => building,
Err(err) => {
logger::error!(
"Node is not a valid building dictionary: {}\n{:?}",
err,
building
);
return false;
}
};

let Some(inner) = self.inner.as_ref() else {
logger::error!("Road Navigation resource is not ready!");
return false;
};

let Some(node) = inner.get_node(building.tile_coords) else {
logger::error!("Navigation node does not exist!");
return false;
};

match node.has_arrived(location, direction) {
Ok(result) => result,
Err(err) => {
logger::error!("Failed perform arrival check: {:?}", err);
false
}
}
}

#[func]
fn get_random_node(&self) -> Dictionary {
let Some(inner) = self.inner.as_ref() else {
logger::error!("Road Navigation resource is not ready!");
return Dictionary::new();
};

inner.get_random_node().building().to_dict()
}

#[func]
fn get_global_transform(&self, node: Dictionary, direction: Vector3) -> Transform3D {
let node = match Building::try_from_dict(&node) {
Ok(node) => node,
Err(err) => {
logger::error!(
"Node is not a valid building dictionary: {}\n{:?}",
err,
node
);
return Transform3D::default();
}
};

let Some(inner) = self.inner.as_ref() else {
logger::error!("Road Navigation resource is not ready!");
return Transform3D::default();
};

let Some(nav_node) = inner.get_node(node.tile_coords) else {
logger::error!("Nav node does not exist: {:?}", node.tile_coords);
return Transform3D::default();
};

nav_node.get_global_transform(direction)
}
}

#[godot_api]
impl IResource for RoadNavigationRes {
fn init(_base: Base<Resource>) -> Self {
Self {
inner: None,
world_constants: None,
}
}
}
Loading

0 comments on commit e21f72b

Please sign in to comment.