diff --git a/lib/bsp_loader/src/lib.rs b/lib/bsp_loader/src/lib.rs
index 21d16f3d8..c4e9f19e3 100644
--- a/lib/bsp_loader/src/lib.rs
+++ b/lib/bsp_loader/src/lib.rs
@@ -1,19 +1,9 @@
+use strafesnet_deferred_loader::deferred_loader::{LoadFailureMode,MeshDeferredLoader,RenderConfigDeferredLoader};
+
 mod bsp;
 mod mesh;
 pub mod loader;
 
-pub struct Bsp(vbsp::Bsp);
-impl Bsp{
-	pub const fn new(value:vbsp::Bsp)->Self{
-		Self(value)
-	}
-}
-impl AsRef<vbsp::Bsp> for Bsp{
-	fn as_ref(&self)->&vbsp::Bsp{
-		&self.0
-	}
-}
-
 const VALVE_SCALE:f32=1.0/16.0;
 pub(crate) fn valve_transform([x,y,z]:[f32;3])->strafesnet_common::integer::Planar64Vec3{
 	strafesnet_common::integer::vec3::try_from_f32_array([x*VALVE_SCALE,z*VALVE_SCALE,-y*VALVE_SCALE]).unwrap()
@@ -31,6 +21,35 @@ impl std::fmt::Display for ReadError{
 }
 impl std::error::Error for ReadError{}
 
+
+#[derive(Debug)]
+pub enum LoadError{
+	Texture(loader::TextureError),
+	Mesh(loader::MeshError),
+}
+impl std::fmt::Display for LoadError{
+	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
+		write!(f,"{self:?}")
+	}
+}
+impl std::error::Error for LoadError{}
+impl From<loader::TextureError> for LoadError{
+	fn from(value:loader::TextureError)->Self{
+		Self::Texture(value)
+	}
+}
+impl From<loader::MeshError> for LoadError{
+	fn from(value:loader::MeshError)->Self{
+		Self::Mesh(value)
+	}
+}
+pub struct Bsp(vbsp::Bsp);
+impl AsRef<vbsp::Bsp> for Bsp{
+	fn as_ref(&self)->&vbsp::Bsp{
+		&self.0
+	}
+}
+
 pub fn read<R:std::io::Read>(mut input:R)->Result<Bsp,ReadError>{
 	let mut s=Vec::new();
 
@@ -39,5 +58,30 @@ pub fn read<R:std::io::Read>(mut input:R)->Result<Bsp,ReadError>{
 
 	vbsp::Bsp::read(s.as_slice()).map(Bsp::new).map_err(ReadError::Bsp)
 }
+impl Bsp{
+	pub const fn new(value:vbsp::Bsp)->Self{
+		Self(value)
+	}
+	pub fn to_snf(&self,failure_mode:LoadFailureMode)->Result<strafesnet_common::map::CompleteMap,LoadError>{
+		let mut texture_deferred_loader=RenderConfigDeferredLoader::new();
+		let mut mesh_deferred_loader=MeshDeferredLoader::new();
 
-pub use bsp::convert;
+		let map_step1=bsp::convert(
+			self,
+			&mut texture_deferred_loader,
+			&mut mesh_deferred_loader,
+		);
+
+		let mut mesh_loader=loader::MeshLoader::new(self,&mut texture_deferred_loader);
+		let prop_meshes=mesh_deferred_loader.into_meshes(&mut mesh_loader,failure_mode).map_err(LoadError::Mesh)?;
+
+		let map_step2=map_step1.add_prop_meshes(prop_meshes);
+
+		let mut texture_loader=loader::TextureLoader::new();
+		let render_configs=texture_deferred_loader.into_render_configs(&mut texture_loader,failure_mode).map_err(LoadError::Texture)?;
+
+		let map=map_step2.add_render_configs_and_textures(render_configs);
+
+		Ok(map)
+	}
+}
diff --git a/lib/deferred_loader/src/deferred_loader.rs b/lib/deferred_loader/src/deferred_loader.rs
index 345e4aac1..dfdc907a1 100644
--- a/lib/deferred_loader/src/deferred_loader.rs
+++ b/lib/deferred_loader/src/deferred_loader.rs
@@ -4,6 +4,7 @@ use crate::mesh::Meshes;
 use crate::texture::{RenderConfigs,Texture};
 use strafesnet_common::model::{Mesh,MeshId,RenderConfig,RenderConfigId,TextureId};
 
+#[derive(Clone,Copy,Debug)]
 pub enum LoadFailureMode{
 	DefaultToNone,
 	Fatal,
diff --git a/lib/rbx_loader/src/lib.rs b/lib/rbx_loader/src/lib.rs
index 98a22c678..7a9de02ca 100644
--- a/lib/rbx_loader/src/lib.rs
+++ b/lib/rbx_loader/src/lib.rs
@@ -1,5 +1,6 @@
 use std::io::Read;
 use rbx_dom_weak::WeakDom;
+use strafesnet_deferred_loader::deferred_loader::{LoadFailureMode,MeshDeferredLoader,RenderConfigDeferredLoader};
 
 mod rbx;
 mod mesh;
@@ -31,6 +32,9 @@ impl Model{
 		let services=context.convert_into_place();
 		Place{dom,services}
 	}
+	pub fn to_snf(&self,failure_mode:LoadFailureMode)->Result<strafesnet_common::map::CompleteMap,LoadError>{
+		to_snf(self,failure_mode)
+	}
 }
 impl AsRef<WeakDom> for Model{
 	fn as_ref(&self)->&WeakDom{
@@ -62,6 +66,9 @@ impl Place{
 			}
 		}
 	}
+	pub fn to_snf(&self,failure_mode:LoadFailureMode)->Result<strafesnet_common::map::CompleteMap,LoadError>{
+		to_snf(self,failure_mode)
+	}
 }
 impl AsRef<WeakDom> for Place{
 	fn as_ref(&self)->&WeakDom{
@@ -93,6 +100,49 @@ pub fn read<R:Read>(input:R)->Result<Model,ReadError>{
 	}
 }
 
-//ConvertError
+#[derive(Debug)]
+pub enum LoadError{
+	Texture(loader::TextureError),
+	Mesh(loader::MeshError),
+}
+impl std::fmt::Display for LoadError{
+	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
+		write!(f,"{self:?}")
+	}
+}
+impl std::error::Error for LoadError{}
+impl From<loader::TextureError> for LoadError{
+	fn from(value:loader::TextureError)->Self{
+		Self::Texture(value)
+	}
+}
+impl From<loader::MeshError> for LoadError{
+	fn from(value:loader::MeshError)->Self{
+		Self::Mesh(value)
+	}
+}
 
-pub use rbx::convert;
+fn to_snf(dom:impl AsRef<WeakDom>,failure_mode:LoadFailureMode)->Result<strafesnet_common::map::CompleteMap,LoadError>{
+	let dom=dom.as_ref();
+
+	let mut texture_deferred_loader=RenderConfigDeferredLoader::new();
+	let mut mesh_deferred_loader=MeshDeferredLoader::new();
+
+	let map_step1=rbx::convert(
+		dom,
+		&mut texture_deferred_loader,
+		&mut mesh_deferred_loader,
+	);
+
+	let mut mesh_loader=loader::MeshLoader::new();
+	let meshpart_meshes=mesh_deferred_loader.into_meshes(&mut mesh_loader,failure_mode).map_err(LoadError::Mesh)?;
+
+	let map_step2=map_step1.add_meshpart_meshes_and_calculate_attributes(meshpart_meshes);
+
+	let mut texture_loader=loader::TextureLoader::new();
+	let render_configs=texture_deferred_loader.into_render_configs(&mut texture_loader,failure_mode).map_err(LoadError::Texture)?;
+
+	let map=map_step2.add_render_configs_and_textures(render_configs);
+
+	Ok(map)
+}
diff --git a/strafe-client/src/file.rs b/strafe-client/src/file.rs
index 40eaa4a3a..6bec7460f 100644
--- a/strafe-client/src/file.rs
+++ b/strafe-client/src/file.rs
@@ -1,8 +1,5 @@
 use std::io::Read;
 
-#[cfg(any(feature="roblox",feature="source"))]
-use strafesnet_deferred_loader::deferred_loader::{LoadFailureMode,MeshDeferredLoader,RenderConfigDeferredLoader};
-
 #[allow(dead_code)]
 #[derive(Debug)]
 pub enum ReadError{
@@ -69,13 +66,9 @@ pub enum LoadError{
 	ReadError(ReadError),
 	File(std::io::Error),
 	#[cfg(feature="roblox")]
-	LoadRobloxMesh(strafesnet_rbx_loader::loader::MeshError),
-	#[cfg(feature="roblox")]
-	LoadRobloxTexture(strafesnet_rbx_loader::loader::TextureError),
+	LoadRoblox(strafesnet_rbx_loader::LoadError),
 	#[cfg(feature="source")]
-	LoadSourceMesh(strafesnet_bsp_loader::loader::MeshError),
-	#[cfg(feature="source")]
-	LoadSourceTexture(strafesnet_bsp_loader::loader::TextureError),
+	LoadSource(strafesnet_bsp_loader::LoadError),
 }
 impl std::fmt::Display for LoadError{
 	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -85,7 +78,7 @@ impl std::fmt::Display for LoadError{
 impl std::error::Error for LoadError{}
 
 pub enum LoadFormat{
-	#[cfg(feature="snf")]
+	#[cfg(any(feature="snf",feature="roblox",feature="source"))]
 	Map(strafesnet_common::map::CompleteMap),
 	#[cfg(feature="snf")]
 	Bot(strafesnet_snf::bot::Segment),
@@ -103,50 +96,13 @@ pub fn load<P:AsRef<std::path::Path>>(path:P)->Result<LoadFormat,LoadError>{
 		ReadFormat::Roblox(model)=>{
 			let mut place=model.into_place();
 			place.run_scripts();
-
-			let mut texture_deferred_loader=RenderConfigDeferredLoader::new();
-			let mut mesh_deferred_loader=MeshDeferredLoader::new();
-
-			let map_step1=strafesnet_rbx_loader::convert(
-				place.as_ref(),
-				&mut texture_deferred_loader,
-				&mut mesh_deferred_loader,
-			);
-
-			let mut mesh_loader=strafesnet_rbx_loader::loader::MeshLoader::new();
-			let meshpart_meshes=mesh_deferred_loader.into_meshes(&mut mesh_loader,LoadFailureMode::DefaultToNone).map_err(LoadError::LoadRobloxMesh)?;
-
-			let map_step2=map_step1.add_meshpart_meshes_and_calculate_attributes(meshpart_meshes);
-
-			let mut texture_loader=strafesnet_rbx_loader::loader::TextureLoader::new();
-			let render_configs=texture_deferred_loader.into_render_configs(&mut texture_loader,LoadFailureMode::DefaultToNone).map_err(LoadError::LoadRobloxTexture)?;
-
-			let map=map_step2.add_render_configs_and_textures(render_configs);
-
-			Ok(LoadFormat::Map(map))
+			Ok(LoadFormat::Map(
+				place.to_snf(LoadFailureMode::DefaultToNone).map_err(LoadError::LoadRoblox)?
+			))
 		},
 		#[cfg(feature="source")]
-		ReadFormat::Source(bsp)=>{
-			let mut texture_deferred_loader=RenderConfigDeferredLoader::new();
-			let mut mesh_deferred_loader=MeshDeferredLoader::new();
-
-			let map_step1=strafesnet_bsp_loader::convert(
-				&bsp,
-				&mut texture_deferred_loader,
-				&mut mesh_deferred_loader,
-			);
-
-			let mut mesh_loader=strafesnet_bsp_loader::loader::MeshLoader::new(&bsp,&mut texture_deferred_loader);
-			let prop_meshes=mesh_deferred_loader.into_meshes(&mut mesh_loader,LoadFailureMode::DefaultToNone).map_err(LoadError::LoadSourceMesh)?;
-
-			let map_step2=map_step1.add_prop_meshes(prop_meshes);
-
-			let mut texture_loader=strafesnet_bsp_loader::loader::TextureLoader::new();
-			let render_configs=texture_deferred_loader.into_render_configs(&mut texture_loader,LoadFailureMode::DefaultToNone).map_err(LoadError::LoadSourceTexture)?;
-
-			let map=map_step2.add_render_configs_and_textures(render_configs);
-
-			Ok(LoadFormat::Map(map))
-		},
+		ReadFormat::Source(bsp)=>Ok(LoadFormat::Map(
+			bsp.to_snf(LoadFailureMode::DefaultToNone).map_err(LoadError::LoadSource)?
+		)),
 	}
 }