From b42b29b99488f5c90cecf3f1184b72e1384bc1ff Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 30 Jan 2025 10:55:01 -0800
Subject: [PATCH] hooray

---
 lib/rbx_loader/src/union.rs | 123 ++++++++++++++++++------------------
 1 file changed, 61 insertions(+), 62 deletions(-)

diff --git a/lib/rbx_loader/src/union.rs b/lib/rbx_loader/src/union.rs
index 30afbbf..644372e 100644
--- a/lib/rbx_loader/src/union.rs
+++ b/lib/rbx_loader/src/union.rs
@@ -6,7 +6,6 @@ use strafesnet_common::integer::vec3;
 #[derive(Debug)]
 pub enum Error{
 	Block,
-	NotSupposedToHappen,
 	MissingVertexId(u32),
 	Planar64Vec3(strafesnet_common::integer::Planar64TryFromFloatError),
 	RobloxPhysicsData(rbx_mesh::physics_data::Error),
@@ -54,78 +53,78 @@ impl MeshDataNormalChecker{
 
 impl std::error::Error for Error{}
 pub fn convert(roblox_physics_data:&[u8],roblox_mesh_data:&[u8])->Result<model::Mesh,Error>{
-	match (roblox_physics_data,roblox_mesh_data){
-		(b"",b"")=>return Err(Error::Block),
-		(b"",_)
-		|(_,b"")=>return Err(Error::NotSupposedToHappen),
-		_=>(),
-	}
-
-	// graphical
-	let mesh_data=rbx_mesh::read_mesh_data_versioned(
-		std::io::Cursor::new(roblox_mesh_data)
-	).map_err(Error::RobloxMeshData)?;
-	let graphics_mesh=match mesh_data{
-		rbx_mesh::mesh_data::CSGPHS::CSGK(_)=>return Err(Error::NotSupposedToHappen),
-		rbx_mesh::mesh_data::CSGPHS::CSGPHS2(mesh_data2)=>mesh_data2.mesh,
-		rbx_mesh::mesh_data::CSGPHS::CSGPHS4(mesh_data4)=>mesh_data4.mesh,
-	};
-
-	// physical
-	let physics_data=rbx_mesh::read_physics_data(
-		std::io::Cursor::new(roblox_physics_data)
-	).map_err(Error::RobloxPhysicsData)?;
-	let physics_convex_meshes=match physics_data{
-		rbx_mesh::physics_data::PhysicsData::CSGK(_)
-		// have not seen this format in practice
-		|rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::Block)
-		=>return Err(Error::NotSupposedToHappen),
-		rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::Meshes(meshes))
-		=>meshes.meshes,
-		rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::PhysicsInfoMesh(pim))
-		=>vec![pim.mesh],
-	};
+	const NORMAL_FACES:usize=6;
+	let mut polygon_groups_normal_id=vec![Vec::new();NORMAL_FACES];
 
 	// build graphics and physics meshes
 	let mut mb=strafesnet_common::model::MeshBuilder::new();
 	// graphics
-	const NORMAL_FACES:usize=6;
-	let mut polygon_groups_normal_id=vec![Vec::new();NORMAL_FACES];
-	for [vertex_id0,vertex_id1,vertex_id2] in graphics_mesh.faces{
-		let face=[
-			graphics_mesh.vertices.get(vertex_id0.0 as usize).ok_or(Error::MissingVertexId(vertex_id0.0))?,
-			graphics_mesh.vertices.get(vertex_id1.0 as usize).ok_or(Error::MissingVertexId(vertex_id1.0))?,
-			graphics_mesh.vertices.get(vertex_id2.0 as usize).ok_or(Error::MissingVertexId(vertex_id2.0))?,
-		];
-		let mut normal_agreement_checker=MeshDataNormalChecker::new();
-		let face=face.into_iter().map(|vertex|{
-			normal_agreement_checker.check(vertex.normal_id);
-			let pos=mb.acquire_pos_id(vec3::try_from_f32_array(vertex.pos)?);
-			let normal=mb.acquire_normal_id(vec3::try_from_f32_array(vertex.norm)?);
-			let tex=mb.acquire_tex_id(glam::Vec2::from_array(vertex.tex));
-			let color=mb.acquire_color_id(glam::Vec4::from_array(vertex.color.map(|f|f as f32/255.0f32)));
-			Ok(mb.acquire_vertex_id(IndexedVertex{pos,tex,normal,color}))
-		}).collect::<Result<Vec<_>,_>>().map_err(Error::Planar64Vec3)?;
-		if let Some(normal_id)=normal_agreement_checker.into_agreed_normal(){
-			polygon_groups_normal_id[normal_id as usize-1].push(face);
-		}else{
-			panic!("Empty face!");
+	let graphics_groups=if !roblox_mesh_data.is_empty(){
+		let mesh_data=rbx_mesh::read_mesh_data_versioned(
+			std::io::Cursor::new(roblox_mesh_data)
+		).map_err(Error::RobloxMeshData)?;
+		let graphics_mesh=match mesh_data{
+			rbx_mesh::mesh_data::CSGPHS::CSGK(_)=>return Err(Error::Block),
+			rbx_mesh::mesh_data::CSGPHS::CSGPHS2(mesh_data2)=>mesh_data2.mesh,
+			rbx_mesh::mesh_data::CSGPHS::CSGPHS4(mesh_data4)=>mesh_data4.mesh,
+		};
+		for [vertex_id0,vertex_id1,vertex_id2] in graphics_mesh.faces{
+			let face=[
+				graphics_mesh.vertices.get(vertex_id0.0 as usize).ok_or(Error::MissingVertexId(vertex_id0.0))?,
+				graphics_mesh.vertices.get(vertex_id1.0 as usize).ok_or(Error::MissingVertexId(vertex_id1.0))?,
+				graphics_mesh.vertices.get(vertex_id2.0 as usize).ok_or(Error::MissingVertexId(vertex_id2.0))?,
+			];
+			let mut normal_agreement_checker=MeshDataNormalChecker::new();
+			let face=face.into_iter().map(|vertex|{
+				normal_agreement_checker.check(vertex.normal_id);
+				let pos=mb.acquire_pos_id(vec3::try_from_f32_array(vertex.pos)?);
+				let normal=mb.acquire_normal_id(vec3::try_from_f32_array(vertex.norm)?);
+				let tex=mb.acquire_tex_id(glam::Vec2::from_array(vertex.tex));
+				let color=mb.acquire_color_id(glam::Vec4::from_array(vertex.color.map(|f|f as f32/255.0f32)));
+				Ok(mb.acquire_vertex_id(IndexedVertex{pos,tex,normal,color}))
+			}).collect::<Result<Vec<_>,_>>().map_err(Error::Planar64Vec3)?;
+			if let Some(normal_id)=normal_agreement_checker.into_agreed_normal(){
+				polygon_groups_normal_id[normal_id as usize-1].push(face);
+			}else{
+				panic!("Empty face!");
+			}
 		}
-	}
-	let graphics_groups=(0..polygon_groups_normal_id.len()).map(|polygon_group_id|{
-		model::IndexedGraphicsGroup{
-			render:RenderConfigId::new(0),
-			groups:vec![PolygonGroupId::new(polygon_group_id as u32)]
-		}
-	}).collect();
+		(0..polygon_groups_normal_id.len()).map(|polygon_group_id|{
+			model::IndexedGraphicsGroup{
+				render:RenderConfigId::new(0),
+				groups:vec![PolygonGroupId::new(polygon_group_id as u32)]
+			}
+		}).collect()
+	}else{
+		Vec::new()
+	};
 
 	//physics
-	let color=mb.acquire_color_id(glam::Vec4::ONE);
-	let tex=mb.acquire_tex_id(glam::Vec2::ZERO);
+	let physics_convex_meshes=if !roblox_physics_data.is_empty(){
+		let physics_data=rbx_mesh::read_physics_data(
+			std::io::Cursor::new(roblox_physics_data)
+		).map_err(Error::RobloxPhysicsData)?;
+		let physics_convex_meshes=match physics_data{
+			rbx_mesh::physics_data::PhysicsData::CSGK(_)
+			// have not seen this format in practice
+			|rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::Block)
+			=>return Err(Error::Block),
+			rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::Meshes(meshes))
+			=>meshes.meshes,
+			rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::PhysicsInfoMesh(pim))
+			=>vec![pim.mesh],
+		};
+		physics_convex_meshes
+	}else{
+		Vec::new()
+	};
 	let polygon_groups:Vec<PolygonGroup>=polygon_groups_normal_id.into_iter().map(|faces|
 		// graphics polygon groups (to be rendered)
 		Ok(PolygonGroup::PolygonList(PolygonList::new(faces)))
 	).chain(physics_convex_meshes.into_iter().map(|mesh|{
+		// this can be factored out of the loop but I am lazy
+		let color=mb.acquire_color_id(glam::Vec4::ONE);
+		let tex=mb.acquire_tex_id(glam::Vec2::ZERO);
 		// physics polygon groups (to do physics)
 		Ok(PolygonGroup::PolygonList(PolygonList::new(mesh.faces.into_iter().map(|[vertex_id0,vertex_id1,vertex_id2]|{
 			let face=[