2021-03-11 22:27:03 +00:00
|
|
|
use crate::make_case_elim;
|
2021-03-11 16:48:59 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
|
|
make_case_elim!(
|
|
|
|
body,
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
|
|
#[repr(u32)]
|
|
|
|
pub enum Body {
|
|
|
|
DefaultAirship = 0,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
impl From<Body> for super::Body {
|
|
|
|
fn from(body: Body) -> Self { super::Body::Ship(body) }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Body {
|
2021-03-11 22:27:03 +00:00
|
|
|
pub fn manifest_entry(&self) -> &'static str {
|
2021-03-11 16:48:59 +00:00
|
|
|
match self {
|
2021-03-12 04:42:53 +00:00
|
|
|
Body::DefaultAirship => "Human_Airship",
|
2021-03-11 16:48:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-12 23:19:10 +00:00
|
|
|
/// Terrain is 11.0 scale relative to small-scale voxels, and all figures get
|
|
|
|
/// multiplied by 0.8 in rendering. For now, have a constant in `comp::Scale`
|
|
|
|
/// that compensates for both of these, but there might be a more elegant way
|
|
|
|
/// (e.g. using `Scale(0.8)` for everything else and not having a magic number
|
|
|
|
/// in figure rendering, and multiplying terrain models by 11.0 in animation).
|
|
|
|
pub const AIRSHIP_SCALE: f32 = 11.0 / 0.8;
|
|
|
|
|
2021-03-11 22:27:03 +00:00
|
|
|
/// Duplicate of some of the things defined in `voxygen::scene::figure::load` to
|
|
|
|
/// avoid having to refactor all of that to `common` for using voxels as
|
|
|
|
/// collider geometry
|
2021-03-11 16:48:59 +00:00
|
|
|
pub mod figuredata {
|
|
|
|
use crate::{
|
|
|
|
assets::{self, AssetExt, AssetHandle, DotVoxAsset, Ron},
|
2021-03-11 22:27:03 +00:00
|
|
|
figure::cell::Cell,
|
|
|
|
terrain::{
|
|
|
|
block::{Block, BlockKind},
|
|
|
|
sprite::SpriteKind,
|
|
|
|
},
|
|
|
|
volumes::dyna::{ColumnAccess, Dyna},
|
2021-03-11 16:48:59 +00:00
|
|
|
};
|
|
|
|
use hashbrown::HashMap;
|
2021-03-11 22:27:03 +00:00
|
|
|
use lazy_static::lazy_static;
|
|
|
|
use serde::Deserialize;
|
2021-03-12 04:42:53 +00:00
|
|
|
use vek::Vec3;
|
2021-03-11 16:48:59 +00:00
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
pub struct VoxSimple(pub String);
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
pub struct ShipCentralSpec(pub HashMap<super::Body, SidedShipCentralVoxSpec>);
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
pub struct SidedShipCentralVoxSpec {
|
|
|
|
pub bone0: ShipCentralSubSpec,
|
|
|
|
pub bone1: ShipCentralSubSpec,
|
|
|
|
pub bone2: ShipCentralSubSpec,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
pub struct ShipCentralSubSpec {
|
|
|
|
pub offset: [f32; 3],
|
2021-03-12 04:42:53 +00:00
|
|
|
pub phys_offset: [f32; 3],
|
2021-03-11 16:48:59 +00:00
|
|
|
pub central: VoxSimple,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// manual instead of through `make_vox_spec!` so that it can be in `common`
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct ShipSpec {
|
|
|
|
pub central: AssetHandle<Ron<ShipCentralSpec>>,
|
2021-03-12 04:42:53 +00:00
|
|
|
pub colliders: HashMap<String, VoxelCollider>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct VoxelCollider {
|
|
|
|
pub dyna: Dyna<Block, (), ColumnAccess>,
|
|
|
|
pub translation: Vec3<f32>,
|
2021-03-11 16:48:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl assets::Compound for ShipSpec {
|
2021-03-11 22:27:03 +00:00
|
|
|
fn load<S: assets::source::Source>(
|
|
|
|
cache: &assets::AssetCache<S>,
|
|
|
|
_: &str,
|
|
|
|
) -> Result<Self, assets::Error> {
|
2021-03-12 22:14:08 +00:00
|
|
|
let manifest: AssetHandle<Ron<ShipCentralSpec>> =
|
|
|
|
AssetExt::load("server.manifests.ship_manifest")?;
|
2021-03-12 04:42:53 +00:00
|
|
|
let mut colliders = HashMap::new();
|
2021-03-11 22:27:03 +00:00
|
|
|
for (_, spec) in (manifest.read().0).0.iter() {
|
|
|
|
for bone in [&spec.bone0, &spec.bone1, &spec.bone2].iter() {
|
|
|
|
// TODO: avoid the requirement for symlinks in "voxygen.voxel.object.", and load
|
|
|
|
// the models from "server.voxel." instead
|
|
|
|
let vox =
|
2021-03-12 04:42:53 +00:00
|
|
|
cache.load::<DotVoxAsset>(&["server.voxel.", &bone.central.0].concat())?;
|
2021-03-11 22:27:03 +00:00
|
|
|
let dyna = Dyna::<Cell, (), ColumnAccess>::from_vox(&vox.read().0, false);
|
2021-03-12 04:42:53 +00:00
|
|
|
let dyna = dyna.map_into(|cell| {
|
2021-03-11 22:27:03 +00:00
|
|
|
if let Some(rgb) = cell.get_color() {
|
|
|
|
Block::new(BlockKind::Misc, rgb)
|
|
|
|
} else {
|
|
|
|
Block::air(SpriteKind::Empty)
|
|
|
|
}
|
2021-03-12 04:42:53 +00:00
|
|
|
});
|
|
|
|
let collider = VoxelCollider {
|
|
|
|
dyna,
|
|
|
|
translation: Vec3::from(bone.offset) + Vec3::from(bone.phys_offset),
|
|
|
|
};
|
|
|
|
colliders.insert(bone.central.0.clone(), collider);
|
2021-03-11 22:27:03 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-11 16:48:59 +00:00
|
|
|
Ok(ShipSpec {
|
2021-03-11 22:27:03 +00:00
|
|
|
central: manifest,
|
2021-03-12 04:42:53 +00:00
|
|
|
colliders,
|
2021-03-11 16:48:59 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-03-11 22:27:03 +00:00
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
// TODO: load this from the ECS as a resource, and maybe make it more general than ships
|
|
|
|
// (although figuring out how to keep the figure bones in sync with the terrain offsets seems
|
|
|
|
// like a hard problem if they're not the same manifest)
|
2021-03-12 04:42:53 +00:00
|
|
|
pub static ref VOXEL_COLLIDER_MANIFEST: AssetHandle<ShipSpec> = AssetExt::load_expect("server.manifests.ship_manifest");
|
2021-03-11 22:27:03 +00:00
|
|
|
}
|
2021-03-11 16:48:59 +00:00
|
|
|
}
|