Skip to content

Commit 0086bef

Browse files
committed
wip
1 parent 1d494be commit 0086bef

File tree

8 files changed

+269
-0
lines changed

8 files changed

+269
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ p2arch0_eng
88
generated.*.toml
99
/deploy*.bat
1010
/deploy*.ps1
11+
*.log
12+
*.dat

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ members = [
1919
"mod-tavern-show-all-sailors",
2020
"mod-town-hall-details",
2121
"mod-trading-office-prices-synchronization",
22+
"navpointmatrixcli",
2223
#"p3-agent",
2324
"p3-agent-loader",
2425
"p3-aim",
@@ -42,3 +43,5 @@ sysinfo = "0.29"
4243
win_dbg_logger = "0.1"
4344
num-traits = "0.2"
4445
num-derive = "0.4"
46+
byteorder = "1.5.0"
47+
pathfinding = "4.11.0"

navpointmatrixcli/Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "navpointmatrixcli"
3+
edition = "2021"
4+
version.workspace = true
5+
6+
[dependencies]
7+
p3-api = { path = "../p3-api" }
8+
clap = { workspace = true }
9+
log = { workspace = true }
10+
pathfinding = { workspace = true }
11+
geo = "0.29.3"

navpointmatrixcli/src/main.rs

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
use std::fs::{self};
2+
3+
use p3_api::data::{navigation_matrix::NavigationMatrix, navigation_vector::NavigationVector, navpoint_matrix::NavpointMatrix};
4+
use pathfinding::prelude::{build_path, dijkstra_all};
5+
6+
pub struct DirectlyConnectedNodes {
7+
pub connected_nodes: Vec<(u16, u16)>,
8+
}
9+
10+
fn main() {
11+
let _navigation_matrix = NavigationMatrix::deserialize(&fs::read(r"C:\Users\Benni\Patrician 3_workbench\navdata\nav_matrix.dat").unwrap());
12+
let navigation_vector = NavigationVector::deserialize(&fs::read(r"C:\Users\Benni\Patrician 3_workbench\navdata\nav_vec.dat").unwrap());
13+
let original_navpoint_matrix = NavpointMatrix::deserialize(&fs::read(r"C:\Users\Benni\Patrician 3_workbench\navdata\matrix_int.dat").unwrap());
14+
15+
/*
16+
let original_connected_nodes = DirectlyConnectedNodes::from_navpoint_matrix(&original_navpoint_matrix);
17+
fs::write("./connections.orig.dat", original_connected_nodes.serialize()).unwrap();
18+
for (source, destination) in &original_connected_nodes.connected_nodes {
19+
println!("{source} {destination}")
20+
}
21+
*/
22+
23+
/*
24+
let calculated_connected_nodes = DirectlyConnectedNodes::from_navigation_vector(&navigation_vector, &navigation_matrix);
25+
fs::write("./connections.calculated.dat", calculated_connected_nodes.serialize()).unwrap();
26+
for (source, destination) in &calculated_connected_nodes.connected_nodes {
27+
println!("{source} {destination}")
28+
}
29+
*/
30+
31+
//let connected_nodes = DirectlyConnectedNodes::from_file(&fs::read("./connections.orig.dat").unwrap());
32+
33+
let mut new_navpoint_matrix = NavpointMatrix::new(navigation_vector.length);
34+
let connected_nodes = DirectlyConnectedNodes::from_navpoint_matrix(&original_navpoint_matrix);
35+
for (source_index, _node) in navigation_vector.points.iter().enumerate() {
36+
let source_index = source_index as u16;
37+
let parents = dijkstra_all(&source_index, |n| connected_nodes.get_neighbours(*n, &navigation_vector));
38+
for target_index in 0..navigation_vector.points.len() as u16 {
39+
if source_index != target_index {
40+
let path = build_path(&(target_index), &parents);
41+
let distance = 0;
42+
//println!("{source_index} -> {target_index} {path:?}");
43+
new_navpoint_matrix.set_next(source_index, target_index, path[1], distance, navigation_vector.length)
44+
} else {
45+
new_navpoint_matrix.set_next(source_index, source_index, source_index, 0, navigation_vector.length)
46+
}
47+
}
48+
}
49+
50+
{
51+
println!(
52+
"{} {} {}",
53+
navigation_vector.get_distance(0, 14),
54+
navigation_vector.get_distance(0, 9),
55+
navigation_vector.get_distance(9, 14)
56+
);
57+
}
58+
59+
//assert_eq!(original_navpoint_matrix, new_navpoint_matrix)
60+
assert_eq!(original_navpoint_matrix.matrix.len(), new_navpoint_matrix.matrix.len());
61+
println!("Asserting {} cells", original_navpoint_matrix.matrix.len());
62+
//println!("{:?}", &original_navpoint_matrix.matrix[0..10]);
63+
//println!("{:?}", &new_navpoint_matrix.matrix[0..10]);
64+
for i in 0..original_navpoint_matrix.matrix.len() {
65+
let orig_next = original_navpoint_matrix.matrix[i].next;
66+
let calculated_next = new_navpoint_matrix.matrix[i].next;
67+
println!("cell {i}: {orig_next} == {calculated_next}");
68+
assert_eq!(orig_next, calculated_next);
69+
}
70+
}
71+
72+
fn is_connected(p0: (i16, i16), p1: (i16, i16), navigation_matrix: &NavigationMatrix) -> bool {
73+
if p0 == p1 {
74+
return true;
75+
}
76+
77+
// Bresenham's Line Algorithm
78+
let (mut x0, mut y0) = p0;
79+
let (x1, y1) = p1;
80+
let dx = (x1 - x0).abs();
81+
let sx = if x0 < x1 { 1 } else { -1 };
82+
let dy = -(y1 - y0).abs();
83+
let sy = if y0 < y1 { 1 } else { -1 };
84+
let mut error = dx + dy;
85+
loop {
86+
if navigation_matrix.data[x0 as usize + navigation_matrix.width as usize * y0 as usize] == 1 {
87+
return false;
88+
}
89+
let e2 = 2 * error;
90+
if e2 >= dy {
91+
if x0 == x1 {
92+
break;
93+
}
94+
error += dy;
95+
x0 += sx;
96+
}
97+
if e2 <= dx {
98+
if y0 == y1 {
99+
break;
100+
}
101+
error += dx;
102+
y0 += sy;
103+
}
104+
}
105+
106+
navigation_matrix.data[x0 as usize + navigation_matrix.width as usize * y0 as usize] == 0
107+
}
108+
109+
impl DirectlyConnectedNodes {
110+
pub fn serialize(&self) -> Vec<u8> {
111+
let mut buf = vec![];
112+
for pair in &self.connected_nodes {
113+
buf.extend_from_slice(&pair.0.to_le_bytes());
114+
buf.extend_from_slice(&pair.1.to_le_bytes());
115+
}
116+
buf
117+
}
118+
119+
pub fn get_neighbours(&self, node_index: u16, nav_vec: &NavigationVector) -> Vec<(u16, i128)> {
120+
let mut neighbours = vec![];
121+
for n in &self.connected_nodes {
122+
if n.0 == node_index {
123+
neighbours.push((n.1, nav_vec.get_distance(n.0 as _, n.1 as _)));
124+
}
125+
}
126+
127+
neighbours
128+
}
129+
130+
pub fn from_file(data: &[u8]) -> Self {
131+
let len = data.len() / 4;
132+
let mut connected_nodes = Vec::with_capacity(len);
133+
for i in 0..len {
134+
let source = u16::from_le_bytes(data[i..i + 2].try_into().unwrap());
135+
let destination = u16::from_le_bytes(data[i + 2..i + 4].try_into().unwrap());
136+
connected_nodes.push((source, destination));
137+
}
138+
139+
Self { connected_nodes }
140+
}
141+
142+
pub fn from_navigation_vector(navigation_vector: &NavigationVector, navigation_matrix: &NavigationMatrix) -> Self {
143+
let mut nodes = vec![];
144+
for (source_index, source) in navigation_vector.points.iter().enumerate() {
145+
println!("Calculating neighbours for node {source_index}");
146+
for (destination_index, destination) in navigation_vector.points.iter().enumerate() {
147+
if is_connected(*source, *destination, navigation_matrix) {
148+
nodes.push((source_index as _, destination_index as _))
149+
}
150+
}
151+
}
152+
153+
DirectlyConnectedNodes { connected_nodes: nodes }
154+
}
155+
156+
pub fn from_navpoint_matrix(navpoint_matrix: &NavpointMatrix) -> Self {
157+
let mut nodes = vec![];
158+
let nodes_count = navpoint_matrix.matrix.len().isqrt();
159+
for source_index in 0..nodes_count {
160+
for destination_index in 0..nodes_count {
161+
let cell = &navpoint_matrix.matrix[source_index * nodes_count + destination_index];
162+
if cell.next == destination_index as u16 {
163+
nodes.push((source_index as _, destination_index as _));
164+
}
165+
}
166+
}
167+
DirectlyConnectedNodes { connected_nodes: nodes }
168+
}
169+
}

p3-api/src/data/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ pub mod convoy;
88
pub mod enums;
99
pub mod mission;
1010
pub mod missions;
11+
pub mod navigation_matrix;
12+
pub mod navigation_vector;
13+
pub mod navpoint_matrix;
1114
pub mod office;
1215
pub mod p3_ptr;
1316
pub mod screen_game_ini_anim;

p3-api/src/data/navigation_matrix.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#[derive(Debug)]
2+
pub struct NavigationMatrix {
3+
pub width: u16,
4+
pub height: u16,
5+
pub data: Vec<u8>,
6+
}
7+
8+
impl NavigationMatrix {
9+
pub fn deserialize(data: &[u8]) -> Self {
10+
let width: u16 = u16::from_le_bytes(data[0..2].try_into().unwrap());
11+
let height: u16 = u16::from_le_bytes(data[2..4].try_into().unwrap());
12+
let data = data[4..].to_vec();
13+
NavigationMatrix { width, height, data }
14+
}
15+
}

p3-api/src/data/navigation_vector.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#[derive(Debug)]
2+
pub struct NavigationVector {
3+
pub length: u16,
4+
pub points: Vec<(i16, i16)>,
5+
}
6+
7+
impl NavigationVector {
8+
pub fn deserialize(data: &[u8]) -> Self {
9+
let length: u16 = u16::from_le_bytes(data[0..2].try_into().unwrap());
10+
let mut points = vec![];
11+
for i in 0..length as usize {
12+
let x = i16::from_le_bytes(data[4 + 4 * i..4 + 4 * i + 2].try_into().unwrap());
13+
let y = i16::from_le_bytes(data[4 + 4 * i + 2..4 + 4 * i + 4].try_into().unwrap());
14+
points.push((x, y));
15+
}
16+
17+
NavigationVector { length, points }
18+
}
19+
20+
pub fn get_distance(&self, source_index: usize, destination_index: usize) -> i128 {
21+
let s = self.points[source_index];
22+
let d = self.points[destination_index];
23+
let i_square = (s.0 as i64 - d.0 as i64).pow(2) + (s.1 as i64 - d.1 as i64).pow(2);
24+
((i_square as f64).sqrt()) as i128
25+
}
26+
}

p3-api/src/data/navpoint_matrix.rs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#[derive(Debug, Eq, PartialEq)]
2+
pub struct NavpointMatrix {
3+
pub matrix: Vec<NavpointMatrixCell>,
4+
}
5+
6+
#[derive(Debug, Eq, PartialEq, Clone)]
7+
pub struct NavpointMatrixCell {
8+
pub distance: i32,
9+
pub next: u16,
10+
}
11+
12+
impl Default for NavpointMatrixCell {
13+
fn default() -> Self {
14+
Self { distance: -1, next: u16::MAX }
15+
}
16+
}
17+
18+
impl NavpointMatrix {
19+
pub fn new(width: u16) -> Self {
20+
Self {
21+
matrix: vec![Default::default(); (width as usize).pow(2)],
22+
}
23+
}
24+
25+
pub fn deserialize(data: &[u8]) -> Self {
26+
let elements = data.len() / 6;
27+
let mut matrix = Vec::with_capacity(elements);
28+
for i in 0..elements {
29+
let distance = i32::from_le_bytes(data[i * 6..i * 6 + 4].try_into().unwrap());
30+
let next = u16::from_le_bytes(data[i * 6 + 4..i * 6 + 4 + 2].try_into().unwrap());
31+
matrix.push(NavpointMatrixCell { distance, next })
32+
}
33+
34+
NavpointMatrix { matrix }
35+
}
36+
37+
pub fn set_next(&mut self, source: u16, destination: u16, next: u16, distance: i32, width: u16) {
38+
self.matrix[source as usize * width as usize + destination as usize] = NavpointMatrixCell { distance, next }
39+
}
40+
}

0 commit comments

Comments
 (0)