Skip to content

Commit

Permalink
feat: namigator nif improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
pikdum committed Sep 12, 2024
1 parent ba0bbd6 commit 503ba5f
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 67 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ vanilla private server
## running

```bash
# need elixir
# need elixir + cargo
git clone https://github.com/pikdum/thistle_tea.git
cd thistle_tea
mix deps.get
mix deps.compile

# need docker + expect + no running mysql/mariadb
./scripts/generate-mangos0-db.sh
Expand Down
15 changes: 11 additions & 4 deletions lib/namigator.ex
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
defmodule ThistleTea.Namigator do
use Rustler, otp_app: :thistle_tea, crate: "thistletea_namigator"

def build(_wow_dir, _map_dir), do: :erlang.nif_error(:nif_not_loaded)
def load(_map_dir), do: :erlang.nif_error(:nif_not_loaded)
def get_zone_and_area(_map, _x, _y, _z), do: :erlang.nif_error(:nif_not_loaded)
def build(_wow_dir, _out_dir), do: :erlang.nif_error(:nif_not_loaded)
def load(_out_dir), do: :erlang.nif_error(:nif_not_loaded)
def get_zone_and_area(_map_id, _x, _y, _z), do: :erlang.nif_error(:nif_not_loaded)

def find_random_point_around_circle(_map, _x, _y, _z, _radius),
def find_random_point_around_circle(_map_id, _x, _y, _z, _radius),
do: :erlang.nif_error(:nif_not_loaded)

def load_all_adts(_map_id), do: :erlang.nif_error(:nif_not_loaded)
def load_adt_at(_map_id, _x, _y), do: :erlang.nif_error(:nif_not_loaded)
def unload_adt(_map_id, _x, _y), do: :erlang.nif_error(:nif_not_loaded)

def find_path(_map_id, _start_x, _start_y, _start_z, _stop_x, _stop_y, _stop_z),
do: :erlang.nif_error(:nif_not_loaded)
end
180 changes: 118 additions & 62 deletions native/thistletea_namigator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,27 @@ use std::sync::Mutex;

static PATHFINDING_MAPS: Lazy<Mutex<Option<PathfindingMaps>>> = Lazy::new(|| Mutex::new(None));

#[derive(Debug)]
pub struct PathfindingMaps {
static MAPS_TO_PROCESS: &[Map] = &[
Map::EasternKingdoms,
Map::Kalimdor,
Map::DevelopmentLand,
// TODO: add all other maps here
];

struct PathfindingMaps {
maps: HashMap<u32, PathfindMap>,
}

impl PathfindingMaps {
pub fn new() -> Self {
fn new() -> Self {
Self {
maps: HashMap::new(),
}
}

pub fn load(&mut self, out_dir: &str) -> Result<(), String> {
fn load(&mut self, out_dir: &str) -> Result<(), String> {
let output = PathBuf::from(out_dir);

const MAPS_TO_PROCESS: &[Map] = &[
Map::EasternKingdoms,
Map::Kalimdor,
Map::DevelopmentLand,
// TODO: add all
];

for &map in MAPS_TO_PROCESS {
let map_file_name = map.directory_name();
let map_id = map.as_int();
Expand All @@ -44,36 +43,24 @@ impl PathfindingMaps {
Ok(())
}

pub fn get_zone_and_area(
&mut self,
map_id: u32,
x: f32,
y: f32,
z: f32,
) -> Result<(u32, u32), String> {
if let Some(map) = self.maps.get_mut(&map_id) {
let _adt = map.load_adt_at(x, y);
// TODO: maybe keep tack of loaded adts, so i can unload them later?
map.get_zone_and_area(x, y, z).map_err(|e| e.to_string())
} else {
Err(format!("Map with ID '{}' not found", map_id))
}
fn with_map<F, R>(&self, map_id: u32, f: F) -> Result<R, String>
where
F: FnOnce(&PathfindMap) -> Result<R, String>,
{
self.maps
.get(&map_id)
.ok_or_else(|| format!("Map with ID '{}' not found", map_id))
.and_then(f)
}

pub fn find_random_point_around_circle(
&mut self,
map_id: u32,
start: Vector3d,
radius: f32,
) -> Result<Vector3d, String> {
if let Some(map) = self.maps.get_mut(&map_id) {
let _adt = map.load_adt_at(start.x, start.y);
// TODO: maybe keep tack of loaded adts, so i can unload them later?
map.find_random_point_around_circle(start, radius)
.map_err(|e| e.to_string())
} else {
Err(format!("Map with ID '{}' not found", map_id))
}
fn with_map_mut<F, R>(&mut self, map_id: u32, f: F) -> Result<R, String>
where
F: FnOnce(&mut PathfindMap) -> Result<R, String>,
{
self.maps
.get_mut(&map_id)
.ok_or_else(|| format!("Map with ID '{}' not found", map_id))
.and_then(f)
}
}

Expand All @@ -98,13 +85,6 @@ fn build(wow_dir: String, out_dir: String) -> NifResult<bool> {
println!("BVH already built, skipping...");
}

const MAPS_TO_PROCESS: &[Map] = &[
Map::EasternKingdoms,
Map::Kalimdor,
Map::DevelopmentLand,
// TODO: add all
];

for &map in MAPS_TO_PROCESS {
let map_file_name = map.directory_name();

Expand Down Expand Up @@ -137,33 +117,109 @@ fn load(out_dir: String) -> NifResult<bool> {

#[rustler::nif]
fn get_zone_and_area(map_id: u32, x: f32, y: f32, z: f32) -> NifResult<Option<(u32, u32)>> {
let mut global_maps = PATHFINDING_MAPS.lock().unwrap();
match &mut *global_maps {
Some(maps) => match maps.get_zone_and_area(map_id, x, y, z) {
Ok((zone, area)) => Ok(Some((zone, area))),
Err(_) => Ok(None),
},
None => Ok(None),
}
with_global_maps(|maps| {
maps.with_map(map_id, |map| {
map.get_zone_and_area(x, y, z).map_err(|e| e.to_string())
})
})
}

#[rustler::nif(schedule = "DirtyCpu")]
#[rustler::nif]
fn find_random_point_around_circle(
map_id: u32,
x: f32,
y: f32,
z: f32,
radius: f32,
) -> NifResult<Option<(f32, f32, f32)>> {
with_global_maps(|maps| {
maps.with_map(map_id, |map| {
let start = Vector3d { x, y, z };
map.find_random_point_around_circle(start, radius)
.map(|point| (point.x, point.y, point.z))
.map_err(|e| e.to_string())
})
})
}

#[rustler::nif(schedule = "DirtyCpu")]
fn load_all_adts(map_id: u32) -> NifResult<Option<u32>> {
with_global_maps_mut(|maps| {
maps.with_map_mut(map_id, |map| map.load_all_adts().map_err(|e| e.to_string()))
})
}

#[rustler::nif]
fn load_adt_at(map_id: u32, x: f32, y: f32) -> NifResult<Option<(f32, f32)>> {
with_global_maps_mut(|maps| {
maps.with_map_mut(map_id, |map| {
map.load_adt_at(x, y).map_err(|e| e.to_string())
})
})
}

#[rustler::nif]
fn unload_adt(map_id: u32, x: i32, y: i32) -> NifResult<Option<()>> {
with_global_maps(|maps| {
maps.with_map(map_id, |map| {
map.unload_adt(x, y).map_err(|e| e.to_string())
})
})
}

#[rustler::nif]
fn find_path(
map_id: u32,
start_x: f32,
start_y: f32,
start_z: f32,
stop_x: f32,
stop_y: f32,
stop_z: f32,
) -> NifResult<Option<Vec<(f32, f32, f32)>>> {
with_global_maps_mut(|maps| {
maps.with_map_mut(map_id, |map| {
let start = Vector3d {
x: start_x,
y: start_y,
z: start_z,
};
let stop = Vector3d {
x: stop_x,
y: stop_y,
z: stop_z,
};
map.find_path(start, stop)
.map(|path| path.iter().map(|&v| (v.x, v.y, v.z)).collect())
.map_err(|e| e.to_string())
})
})
}

fn with_global_maps<F, R>(f: F) -> NifResult<Option<R>>
where
F: FnOnce(&PathfindingMaps) -> Result<R, String>,
{
let global_maps = PATHFINDING_MAPS.lock().unwrap();
match &*global_maps {
Some(maps) => match f(maps) {
Ok(result) => Ok(Some(result)),
Err(_) => Ok(None),
},
None => Ok(None),
}
}

fn with_global_maps_mut<F, R>(f: F) -> NifResult<Option<R>>
where
F: FnOnce(&mut PathfindingMaps) -> Result<R, String>,
{
let mut global_maps = PATHFINDING_MAPS.lock().unwrap();
match &mut *global_maps {
Some(maps) => {
let start = Vector3d { x, y, z };
match maps.find_random_point_around_circle(map_id, start, radius) {
Ok(point) => Ok(Some((point.x, point.y, point.z))),
Err(_) => Ok(None),
}
}
Some(maps) => match f(maps) {
Ok(result) => Ok(Some(result)),
Err(_) => Ok(None),
},
None => Ok(None),
}
}
Expand Down

0 comments on commit 503ba5f

Please sign in to comment.