mirror of
https://github.com/redstrate/Kawari.git
synced 2025-07-12 08:47:45 +00:00
Begin adding zone collision visualization
If you run kawari-navimesh and give it a zone ID, it can now show you the loaded collision meshes. I only tested it in inn rooms so far, but already works super well.
This commit is contained in:
parent
f5f166c78f
commit
85cec9f092
3 changed files with 3453 additions and 22 deletions
3339
Cargo.lock
generated
3339
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
23
Cargo.toml
23
Cargo.toml
|
@ -34,6 +34,10 @@ required-features = ["oodle"]
|
|||
[[bin]]
|
||||
name = "kawari-launcher"
|
||||
|
||||
[[bin]]
|
||||
name = "kawari-navimesh"
|
||||
required-features = ["visualizer"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
strip = true
|
||||
|
@ -42,9 +46,15 @@ codegen-units = 1
|
|||
panic = "abort"
|
||||
|
||||
[features]
|
||||
# Default featureset
|
||||
default = []
|
||||
|
||||
# Oodle compression
|
||||
oodle = []
|
||||
|
||||
# Navmesh visualizer
|
||||
visualizer = ["dep:bevy"]
|
||||
|
||||
[build-dependencies]
|
||||
# Serialization of IPC opcodes
|
||||
serde = { version = "1.0", features = ["derive"], default-features = false }
|
||||
|
@ -74,6 +84,19 @@ bitflags = { version = "2.9", default-features = false }
|
|||
# excel sheet data
|
||||
icarus = { git = "https://github.com/redstrate/Icarus", branch = "ver/2025.06.28.0000.0000", features = ["Warp", "Tribe", "ClassJob", "World", "TerritoryType", "Race", "Aetheryte", "EquipSlotCategory", "Action", "WeatherRate", "PlaceName", "GilShopItem"], default-features = false }
|
||||
|
||||
# navimesh visualization
|
||||
bevy = { version = "0.16", features = ["std",
|
||||
"bevy_asset",
|
||||
"bevy_color",
|
||||
"bevy_pbr",
|
||||
"bevy_render",
|
||||
"bevy_scene",
|
||||
"bevy_state",
|
||||
"bevy_window",
|
||||
"bevy_winit",
|
||||
"tonemapping_luts",
|
||||
"x11"], default-features = false, optional = true }
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||
# Used for the web servers
|
||||
axum = { version = "0.8", features = ["json", "tokio", "http1", "form", "query", "multipart"], default-features = false }
|
||||
|
|
|
@ -1,20 +1,102 @@
|
|||
use bevy::{
|
||||
asset::RenderAssetUsages,
|
||||
prelude::*,
|
||||
render::mesh::{Indices, PrimitiveTopology},
|
||||
};
|
||||
use icarus::TerritoryType::TerritoryTypeSheet;
|
||||
use kawari::config::get_config;
|
||||
use physis::{
|
||||
common::{Language, Platform},
|
||||
layer::{LayerEntryData, LayerGroup},
|
||||
layer::{LayerEntryData, LayerGroup, ModelCollisionType, Transformation},
|
||||
lvb::Lvb,
|
||||
pcb::{Pcb, ResourceNode},
|
||||
resource::{Resource, SqPackResource},
|
||||
};
|
||||
|
||||
#[derive(Resource)]
|
||||
struct ZoneToLoad(u16);
|
||||
|
||||
fn main() {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let config = get_config();
|
||||
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let zone_id: u16 = args[1].parse().unwrap();
|
||||
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_systems(Startup, setup)
|
||||
.insert_resource(ZoneToLoad(zone_id))
|
||||
.run();
|
||||
}
|
||||
|
||||
/// Walk each node, add it's collision model to the scene.
|
||||
fn walk_node(
|
||||
node: &ResourceNode,
|
||||
commands: &mut Commands,
|
||||
meshes: &mut ResMut<Assets<Mesh>>,
|
||||
materials: &mut ResMut<Assets<StandardMaterial>>,
|
||||
transform: &Transformation,
|
||||
) {
|
||||
if !node.vertices.is_empty() {
|
||||
let mut mesh = Mesh::new(
|
||||
PrimitiveTopology::TriangleList,
|
||||
RenderAssetUsages::RENDER_WORLD,
|
||||
);
|
||||
|
||||
let mut positions = Vec::new();
|
||||
for vec in &node.vertices {
|
||||
positions.push(vec.clone());
|
||||
}
|
||||
|
||||
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions);
|
||||
|
||||
let mut indices = Vec::new();
|
||||
for polygon in &node.polygons {
|
||||
let mut vec: Vec<u32> = Vec::from(&polygon.vertex_indices)
|
||||
.iter()
|
||||
.map(|x| *x as u32)
|
||||
.collect();
|
||||
assert!(vec.len() == 3);
|
||||
indices.append(&mut vec);
|
||||
}
|
||||
|
||||
mesh.insert_indices(Indices::U32(indices));
|
||||
|
||||
commands.spawn((
|
||||
Mesh3d(meshes.add(mesh)),
|
||||
MeshMaterial3d(materials.add(Color::srgb(
|
||||
fastrand::f32(),
|
||||
fastrand::f32(),
|
||||
fastrand::f32(),
|
||||
))),
|
||||
Transform {
|
||||
translation: Vec3::from_array(transform.translation),
|
||||
rotation: Quat::from_euler(
|
||||
EulerRot::XYZ,
|
||||
transform.rotation[0],
|
||||
transform.rotation[1],
|
||||
transform.rotation[2],
|
||||
),
|
||||
scale: Vec3::from_array(transform.scale),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
for child in &node.children {
|
||||
walk_node(&child, commands, meshes, materials, transform);
|
||||
}
|
||||
}
|
||||
|
||||
/// Setup 3D scene.
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
zone_id: Res<ZoneToLoad>,
|
||||
) {
|
||||
let zone_id = zone_id.0;
|
||||
let config = get_config();
|
||||
|
||||
tracing::info!("Generating navmesh for zone {zone_id}!");
|
||||
|
||||
let mut sqpack_resource =
|
||||
|
@ -34,7 +116,7 @@ fn main() {
|
|||
|
||||
for path in &lvb.scns[0].header.path_layer_group_resources {
|
||||
if path.contains("bg.lgb") {
|
||||
tracing::info!("Processing {path}");
|
||||
tracing::info!("Processing {path}...");
|
||||
|
||||
let lgb_file = sqpack_resource.read(path).unwrap();
|
||||
let lgb = LayerGroup::from_existing(&lgb_file);
|
||||
|
@ -52,8 +134,23 @@ fn main() {
|
|||
if let LayerEntryData::BG(bg) = &object.data {
|
||||
if !bg.collision_asset_path.value.is_empty() {
|
||||
tracing::info!("Considering {} for navimesh", object.instance_id);
|
||||
|
||||
tracing::info!("- Loading {}", bg.collision_asset_path.value);
|
||||
|
||||
// NOTE: assert is here to find out the unknown
|
||||
assert!(bg.collision_type == ModelCollisionType::Replace);
|
||||
|
||||
let pcb_file = sqpack_resource
|
||||
.read(&bg.collision_asset_path.value)
|
||||
.unwrap();
|
||||
let pcb = Pcb::from_existing(&pcb_file).unwrap();
|
||||
|
||||
walk_node(
|
||||
&pcb.root_node,
|
||||
&mut commands,
|
||||
&mut meshes,
|
||||
&mut materials,
|
||||
&object.transform,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,4 +158,10 @@ fn main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// camera
|
||||
commands.spawn((
|
||||
Camera3d::default(),
|
||||
Transform::from_xyz(15.0, 15.0, 15.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||
));
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue