all ra2 stock files with corresponding _txt are parsed

main
q3k 2022-04-14 22:51:49 +00:00
parent 13c9fe6678
commit e4c810ab06
5 changed files with 199 additions and 20 deletions

View File

@ -36,9 +36,10 @@ impl Atom for f32 {
}
}
impl Serializable for [f32; 3] {
impl<const N: usize> Serializable for [f32; N] {
fn write<W: std::io::Write, S: std::string::ToString>(&self, name: S, w: &mut WriteStream<W>) -> WriteResult<()> {
w.emit(&format!("{} {:.6}\t{:.6}\t{:.6}", name.to_string(), self[0], self[1], self[2]))
let fields = self.iter().map(|v| format!("{:.6}", v)).collect::<Vec<String>>().join("\t");
w.emit(&format!("{} {}", name.to_string(), fields))
}
}

View File

@ -186,13 +186,6 @@ pub struct TLV {
}
impl TLV {
pub fn error<S: std::string::ToString>(&self, msg: S) -> ReadError {
ReadError {
msg: msg.to_string(),
stack: vec![],
}
}
pub fn check<R: std::io::Read>(&self, r: &mut ReadStream<R>) -> ReadResult<()> {
let expected = self.start_pos + self.length as usize + 12usize;
if expected != r.pos {

View File

@ -96,6 +96,7 @@ pub enum MapKind {
Diffuse = 1,
SelfIllum = 5,
Opacity = 6,
Reflect = 9,
}
impl gma::Serializable for MapKind {
@ -104,12 +105,15 @@ impl gma::Serializable for MapKind {
MapKind::Diffuse => w.emit("*MAP_DIFFUSE"),
MapKind::SelfIllum => w.emit("*MAP_SELFILLUM"),
MapKind::Opacity => w.emit("*MAP_OPACITY"),
MapKind::Reflect => w.emit("*MAP_REFLECT"),
}
}
}
#[derive(Debug,GMISerializable,GMASerializable)]
pub enum MapType {
Explicit = 0,
Spherical = 1,
Screen = 4,
}
@ -181,12 +185,14 @@ pub enum Shading {
#[derive(Debug, GMISerializable,GMASerializable)]
pub enum Falloff {
In = 0,
InTwoSided = 1,
}
#[derive(Debug,GMISerializable,GMASerializable)]
pub enum XPType {
Other = 0,
Filter = 1,
Additive = 3,
}
#[derive(Debug,GMISerializable,GMASerializable)]
@ -274,11 +280,13 @@ pub struct ObjectList {
#[derive(Debug)]
pub enum Object {
Geometry(GeometryObject),
Camera(CameraObject),
Light(LightObject),
AttachmentPoint(AttachmentPointObject),
ConstraintSolver(ConstraintSolverObject),
Simulation(SimulationObject),
RBCollection(RBCollectionObject),
ConstraintSolver(ConstraintSolverObject),
AngularDashpot(AngularDashpotObject),
}
impl gmi::Serializable for Object {
@ -286,11 +294,13 @@ impl gmi::Serializable for Object {
let tlv = r.tlv()?;
let (res, check) = match (tlv.tag, tlv.flags) {
(2, 4) => (Object::Geometry(r.read("geometry")?), false),
(4, 2) => (Object::Camera(r.read("camera")?), false),
(5, 3) => (Object::Light(r.read("light")?), false),
(21, 2) => (Object::AttachmentPoint(r.read("attachmentpoint")?), true),
(42, 3) => (Object::ConstraintSolver(r.read("constraintsolver")?), false),
(30, 2) => (Object::Simulation(r.read("simulation")?), false),
(31, 4) => (Object::RBCollection(r.read("rigidbodycollection")?), false),
(42, 3) => (Object::ConstraintSolver(r.read("constraintsolver")?), false),
(49, 2) => (Object::AngularDashpot(r.read("angulardashpot")?), false),
_ => return Err(r.error(format!("unknown object type ({}, {})", tlv.tag, tlv.flags))),
};
if check {
@ -304,11 +314,13 @@ impl gma::Serializable for Object {
fn write<W: io::Write, S: string::ToString>(&self, _name: S, w: &mut gma::WriteStream<W>) -> gma::WriteResult<()> {
match self {
Object::Geometry(o) => o.write("", w),
Object::Camera(o) => o.write("", w),
Object::Light(o) => o.write("", w),
Object::AttachmentPoint(o) => o.write("", w),
Object::ConstraintSolver(o) => o.write("", w),
Object::Simulation(o) => o.write("", w),
Object::RBCollection(o) => o.write("", w),
Object::ConstraintSolver(o) => o.write("", w),
Object::AngularDashpot(o) => o.write("", w),
}
}
}
@ -327,6 +339,29 @@ pub struct GeometryObject {
pub mesh: Mesh,
}
#[derive(Debug,GMISerializable,GMASerializable)]
#[gma_name("CAMERA")]
pub struct CameraObject {
#[gma_name("NODE_NAME")]
pub name: String,
#[gma_name("NODE_TM")]
pub tm1: TransformMatrix,
#[gma_name("NODE_TM")]
pub tm2: Option<TransformMatrix>,
pub type_: CameraType,
pub hither: f32,
pub yon: f32,
pub near: f32,
pub far: f32,
pub fov: f32,
pub tdist: f32,
}
#[derive(Debug,GMISerializable,GMASerializable)]
pub enum CameraType {
Target = 0,
}
#[derive(Debug,GMISerializable,GMASerializable)]
#[gmi_tagged(17, 2)]
#[gma_name("NODE_TM")]
@ -612,6 +647,8 @@ pub enum LightType {
#[derive(Debug,GMISerializable,GMASerializable)]
pub enum LightShadows {
Off = 0,
Mapped = 1,
Raytraced = 2,
}
#[derive(Debug,GMASerializable)]
@ -648,14 +685,87 @@ pub struct ConstraintSolverObject {
}
#[derive(Debug,GMISerializable,GMASerializable)]
#[gmi_tagged(44, 2)]
#[gmi_tagged_nolen(44, 2)]
pub struct ConstraintList {
pub constraints: Vec<Constraint>,
}
#[derive(Debug,GMISerializable,GMASerializable)]
#[derive(Debug)]
pub enum Constraint {
Foo = 1,
Hinge(HingeConstraint),
PointToPoint(PointToPointConstraint),
}
impl gmi::Serializable for Constraint {
fn read<R: io::Read>(r: &mut gmi::ReadStream<R>) -> gmi::ReadResult<Self> {
let tlv = r.tlv()?;
let (res, check) = match (tlv.tag, tlv.flags) {
(47, 2) => (Constraint::Hinge(r.read("hinge")?), false),
(53, 2) => (Constraint::PointToPoint(r.read("pointtopoint")?), false),
_ => return Err(r.error(format!("unknown constraint type ({}, {})", tlv.tag, tlv.flags))),
};
if check {
tlv.check(r)?;
}
Ok(res)
}
}
impl gma::Serializable for Constraint {
fn write<W: io::Write, S: string::ToString>(&self, _name: S, w: &mut gma::WriteStream<W>) -> gma::WriteResult<()> {
match self {
Constraint::Hinge(o) => o.write("", w),
Constraint::PointToPoint(o) => o.write("", w),
}
}
}
#[derive(Debug,GMISerializable,GMASerializable)]
pub struct HingeConstraint {
#[gma_name("NODE_NAME")]
pub name: String,
pub tm: TransformMatrix,
#[gma_name("BODY1")]
pub body1: String,
#[gma_name("BODY2")]
pub body2: String,
#[gma_name("POINT")]
pub point: [f32; 3],
#[gma_name("SPIN_AXIS")]
pub spin_axis: [f32; 3],
#[gma_name("IS_LIMITED")]
pub is_limited: u8,
#[gma_name("FRICTION")]
pub friction: f32,
#[gma_name("ANGLE_LIMITS")]
pub angle_limits: [f32; 2],
}
#[derive(Debug,GMISerializable,GMASerializable)]
pub struct PointToPointConstraint {
#[gma_name("NODE_NAME")]
pub name: String,
pub tm: TransformMatrix,
#[gma_name("BODY1")]
pub body1: String,
#[gma_name("BODY2")]
pub body2: String,
pub points: PTPPoints,
}
#[derive(Debug,GMISerializable)]
pub struct PTPPoints {
a: Point,
b: Point,
}
impl gma::Serializable for PTPPoints {
fn write<W: io::Write, S: string::ToString>(&self, _name: S, w: &mut gma::WriteStream<W>) -> gma::WriteResult<()> {
w.emit("*POINT 1")?;
w.emit(&format!("(\t{:.6}\t{:.6}\t{:.6}\t)", self.a.x, self.a.y, self.a.z))?;
w.emit(&format!("(\t{:.6}\t{:.6}\t{:.6}\t)", self.b.x, self.b.y, self.b.z))?;
Ok(())
}
}
#[derive(Debug,GMISerializable,GMASerializable)]
@ -796,6 +906,7 @@ impl gma::Serializable for NestedRigidBodyList {
#[derive(Debug,GMISerializable,GMASerializable)]
pub enum GeoType {
Standard = 0,
Plane = 1,
}
#[derive(Debug,GMISerializable,GMASerializable)]
@ -818,3 +929,42 @@ impl gma::Serializable for DisabledCollisionPair {
self.a, self.b))
}
}
#[derive(Debug,GMISerializable,GMASerializable)]
#[gma_name("GMID_HAVOK_ANGULAR_DASHPOT")]
pub struct AngularDashpotObject {
#[gma_name("NODE_NAME")]
pub name: String,
pub tm: TransformMatrix,
#[gma_name("BODY1")]
pub body1: String,
#[gma_name("BODY2")]
pub body2: String,
#[gma_name("STRENGTH")]
pub strength: f32,
#[gma_name("DAMPING")]
pub damping: f32,
#[gma_name("ALLOW_INTERPENETRATIONS")]
pub allow_interpenetrations: u8,
#[gma_name("QUATERNION")]
pub quaternion: Quaternion,
}
#[derive(Debug)]
pub struct Quaternion([f32; 4]);
impl gmi::Serializable for Quaternion {
fn read<R: io::Read>(r: &mut gmi::ReadStream<R>) -> gmi::ReadResult<Self> {
<[f32; 4]>::read(r).map(|el| Quaternion(el))
}
}
impl gma::Serializable for Quaternion {
fn write<W: io::Write, S: string::ToString>(&self, name: S, w: &mut gma::WriteStream<W>) -> gma::WriteResult<()> {
w.emit(&name.to_string())?;
let values = self.0.iter().map(|v| format!("{:.6}", v)).collect::<Vec<_>>().join("\t");
w.emit(&format!("(\t{}\t)", values))?;
Ok(())
}
}

View File

@ -82,7 +82,7 @@ pub fn gmi_serializable_macro(input: TokenStream) -> TokenStream {
tlv_header = quote! {
let tlv = _r.tlv()?;
if tlv.tag != #ty || tlv.flags != #flags {
return Err(tlv.error(format!("unsupported tag/flags (wanted {}/{}, got {}/{})", #ty, #flags, tlv.tag, tlv.flags)));
return Err(_r.error(format!("unsupported tag/flags (wanted {}/{}, got {}/{})", #ty, #flags, tlv.tag, tlv.flags)));
}
};
if !tagged.nolen {
@ -109,7 +109,7 @@ pub fn gmi_serializable_macro(input: TokenStream) -> TokenStream {
let v: u32 = _r.read("value")?;
let res = match v {
#(#branches)*
_ => return Err(_r.error("unknown ")),
_ => return Err(_r.error(format!("unknown enum value {}", v))),
};
#tlv_footer
Ok(res)

View File

@ -1,8 +1,43 @@
fn main() -> std::io::Result<()> {
let f = std::fs::File::open("/home/q3k/Games/RA2/Robot Arena 2 v1.4/Arenas/box/boxarena.gmf")?;
let gmf = gmflib::GMF::read_gmi(f).unwrap();
let txt_gmfs = vec![
"Arenas/practice arena/practice_arena_txt.gmf",
"Arenas/octagon/octagon_txt.gmf",
"Arenas/parkinglot/parkinglot_txt.gmf",
"Arenas/flextop/flextop_txt.gmf",
"Arenas/barrels/barrels_txt.gmf",
"Arenas/cones/cones_txt.gmf",
"Arenas/skull/skull_txt.gmf",
"Arenas/crates/crates_txt.gmf",
"Arenas/bridge/bridge_txt.gmf",
"Arenas/cinderblocks/blocks_txt.gmf",
"Arenas/event_results/event_results_txt.gmf",
"Arenas/compressor/compressor_txt.gmf",
"Arenas/hilltop/hilltop_txt.gmf",
"Arenas/kingofhill/king_txt.gmf",
"Arenas/electric/electric_txt.gmf",
"Arenas/half/half_txt.gmf",
"Arenas/box/boxarena_txt.gmf",
"Arenas/tabletop/clawtop_txt.gmf",
"Arenas/ramps/ramps_txt.gmf",
"UI/botlab/AP_box_selected_txt.gmf",
"UI/botlab/heading_arrow_txt.gmf",
"UI/botlab/AP_box_unselected_txt.gmf",
"Components/cannon/cannon_txt.gmf",
];
gmf.write_gma(std::io::stdout()).unwrap();
for txt_gmf_path in txt_gmfs.iter() {
let txt_gmf_path = "/home/q3k/Games/RA2/Robot Arena 2 v1.4/".to_string() + txt_gmf_path;
let gmf_path = txt_gmf_path.replace("_txt.gmf", ".gmf");
println!("Testing {} vs {}...", txt_gmf_path, gmf_path);
let f = std::fs::File::open(gmf_path).unwrap();
let gmf = gmflib::GMF::read_gmi(f).unwrap();
}
//let f = std::fs::File::open("/home/q3k/Games/RA2/Robot Arena 2 v1.4/Arenas/barrels/barrels.gmf")?;
//let gmf = gmflib::GMF::read_gmi(f).unwrap();
//gmf.write_gma(std::io::stdout()).unwrap();
Ok(())
}