diff --git a/src/Components/Modules/ArenaLength.cpp b/src/Components/Modules/ArenaLength.cpp
index d7a94f09..e94ea544 100644
--- a/src/Components/Modules/ArenaLength.cpp
+++ b/src/Components/Modules/ArenaLength.cpp
@@ -2,7 +2,10 @@
 
 namespace Components
 {
-	Game::newMapArena_t ArenaLength::NewArenas[128];
+	constexpr auto NEW_ARENA_COUNT = 128;
+
+	Game::newMapArena_t ArenaLength::NewArenas[NEW_ARENA_COUNT];
+	char* ArenaLength::NewArenaInfos[NEW_ARENA_COUNT];
 
 	__declspec(naked) void ArenaLength::ArenaMapOffsetHook1()
 	{
@@ -57,16 +60,28 @@ namespace Components
 
 	ArenaLength::ArenaLength()
 	{
-		// Reallocate array
-		Utils::Hook::Set<Game::newMapArena_t*>(0x417807, &ArenaLength::NewArenas[0]);
-		Utils::Hook::Set<Game::newMapArena_t*>(0x420717, &ArenaLength::NewArenas[0]);
-		Utils::Hook::Set<Game::newMapArena_t*>(0x49BD22, &ArenaLength::NewArenas[0]);
-		Utils::Hook::Set<Game::newMapArena_t*>(0x4A9649, &ArenaLength::NewArenas[0]);
-		Utils::Hook::Set<Game::newMapArena_t*>(0x4A97C2, &ArenaLength::NewArenas[0]);
-		Utils::Hook::Set<Game::newMapArena_t*>(0x4D077E, &ArenaLength::NewArenas[0]);
-		Utils::Hook::Set<Game::newMapArena_t*>(0x630B00, &ArenaLength::NewArenas[0]);
-		Utils::Hook::Set<Game::newMapArena_t*>(0x630B2E, &ArenaLength::NewArenas[0]);
-		Utils::Hook::Set<Game::newMapArena_t*>(0x632782, &ArenaLength::NewArenas[0]);
+		// Reallocate  ui_arenaInfos
+		Utils::Hook::Set<char**>(0x4A95F0 + 3, ArenaLength::NewArenaInfos);
+		Utils::Hook::Set<char**>(0x4A9620 + 3, ArenaLength::NewArenaInfos);
+		Utils::Hook::Set<char**>(0x4A9653 + 3, ArenaLength::NewArenaInfos);
+		Utils::Hook::Set<char**>(0x4A9684 + 3, ArenaLength::NewArenaInfos);
+		Utils::Hook::Set<char**>(0x4A96B7 + 3, ArenaLength::NewArenaInfos);
+		Utils::Hook::Set<char**>(0x4A97B3 + 3, ArenaLength::NewArenaInfos);
+		Utils::Hook::Set<char**>(0x630A9A + 3, ArenaLength::NewArenaInfos);
+
+		// Increase size - patch max arena count
+		Utils::Hook::Set<unsigned int>(0x630AA2 + 1, NEW_ARENA_COUNT);
+
+		// Reallocate sharedUiInfo.mapList
+		Utils::Hook::Set<Game::newMapArena_t*>(0x417807, ArenaLength::NewArenas);
+		Utils::Hook::Set<Game::newMapArena_t*>(0x420717, ArenaLength::NewArenas);
+		Utils::Hook::Set<Game::newMapArena_t*>(0x49BD22, ArenaLength::NewArenas);
+		Utils::Hook::Set<Game::newMapArena_t*>(0x4A9649, ArenaLength::NewArenas);
+		Utils::Hook::Set<Game::newMapArena_t*>(0x4A97C2, ArenaLength::NewArenas);
+		Utils::Hook::Set<Game::newMapArena_t*>(0x4D077E, ArenaLength::NewArenas);
+		Utils::Hook::Set<Game::newMapArena_t*>(0x630B00, ArenaLength::NewArenas);
+		Utils::Hook::Set<Game::newMapArena_t*>(0x630B2E, ArenaLength::NewArenas);
+		Utils::Hook::Set<Game::newMapArena_t*>(0x632782, ArenaLength::NewArenas);
 
 		Utils::Hook::Set<char*>(0x4A967A, ArenaLength::NewArenas[0].description);
 		Utils::Hook::Set<char*>(0x4A96AD, ArenaLength::NewArenas[0].mapimage);
@@ -109,12 +124,7 @@ namespace Components
 		Utils::Hook(0x632799, ArenaLength::ArenaMapOffsetHook3, HOOK_JUMP).install()->quick();
 		Utils::Hook(0x4064B2, ArenaLength::ArenaMapOffsetHook4, HOOK_JUMP).install()->quick();
 
-		Utils::Hook::Set<BYTE>(0x4A95F8, 32);
-
+		Utils::Hook::Set<BYTE>(0x4A95F8, sizeof(Game::newMapArena_t::mapName));
 		Utils::Hook::Set<int>(0x42F22B, offsetof(Game::newMapArena_t, mapName) - offsetof(Game::newMapArena_t, other));
-
-		// patch max arena count
-		constexpr auto arenaCount = sizeof(ArenaLength::NewArenas) / sizeof(Game::newMapArena_t);
-		Utils::Hook::Set<std::uint32_t>(0x630AA3, arenaCount);
 	}
 }
diff --git a/src/Components/Modules/ArenaLength.hpp b/src/Components/Modules/ArenaLength.hpp
index f495b5c7..7b1c7eee 100644
--- a/src/Components/Modules/ArenaLength.hpp
+++ b/src/Components/Modules/ArenaLength.hpp
@@ -7,7 +7,8 @@ namespace Components
 	public:
 		ArenaLength();
 
-		static Game::newMapArena_t NewArenas[128];
+		static Game::newMapArena_t NewArenas[];
+		static char* NewArenaInfos[];
 
 	private:
 		static void ArenaMapOffsetHook1();
diff --git a/src/Components/Modules/AssetHandler.cpp b/src/Components/Modules/AssetHandler.cpp
index d7606ee5..825fb0f0 100644
--- a/src/Components/Modules/AssetHandler.cpp
+++ b/src/Components/Modules/AssetHandler.cpp
@@ -571,210 +571,6 @@ namespace Components
 
 		AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool*)
 		{
-#ifdef DEBUG
-// #define DUMP_TECHSETS
-#ifdef DUMP_TECHSETS
-			if (type == Game::XAssetType::ASSET_TYPE_VERTEXDECL && !name.empty() && name[0] != ',')
-			{
-				std::filesystem::create_directories("techsets/vertexdecl");
-
-				auto vertexdecl = asset.vertexDecl;
-
-				std::vector<json11::Json> routingData;
-				for (int i = 0; i < vertexdecl->streamCount; i++)
-				{
-					routingData.push_back(json11::Json::object
-					{
-						{ "source", (int)vertexdecl->routing.data[i].source },
-						{ "dest", (int)vertexdecl->routing.data[i].dest },
-					});
-				}
-
-				std::vector<json11::Json> declData;
-				for (int i = 0; i < 16; i++)
-				{
-					if (vertexdecl->routing.decl[i])
-					{
-						routingData.push_back(int(vertexdecl->routing.decl[i]));
-					}
-					else
-					{
-						routingData.push_back(nullptr);
-					}
-				}
-
-				nlohmann::json vertexData = json11::Json::object
-				{
-					{ "name", vertexdecl->name },
-					{ "streamCount", vertexdecl->streamCount },
-					{ "hasOptionalSource", vertexdecl->hasOptionalSource },
-					{ "routing", routingData },
-					{ "decl", declData },
-				};
-
-				auto stringData = vertexData.dump();
-
-				auto fp = fopen(Utils::String::VA("techsets/vertexdecl/%s.%s.json", vertexdecl->name, Zones::Version() > 276 ? "codo" : "iw4"), "wb");
-				fwrite(&stringData[0], stringData.size(), 1, fp);
-				fclose(fp);
-			}
-
-			if (type == Game::ASSET_TYPE_TECHNIQUE_SET && !name.empty() && name[0] != ',')
-			{
-				std::filesystem::create_directory("techsets");
-				std::filesystem::create_directories("techsets/techniques");
-				
-				auto techset = asset.techniqueSet;
-
-				std::vector<json11::Json> techniques;
-				for (int technique = 0; technique < 48; technique++)
-				{
-					auto curTech = techset->techniques[technique];
-					if (curTech)
-					{
-						std::vector<json11::Json> passDataArray;
-						for (int pass = 0; pass < curTech->passCount; pass++)
-						{
-							auto curPass = &curTech->passArray[pass];
-
-							std::vector<json11::Json> argDataArray;
-							for (int arg = 0; arg < curPass->perObjArgCount + curPass->perPrimArgCount + curPass->stableArgCount; arg++)
-							{
-								auto curArg = &curPass->args[arg];
-
-								if (curArg->type == 1 || curArg->type == 7)
-								{
-									std::vector<float> literalConsts;
-									if (curArg->u.literalConst != 0)
-									{
-										literalConsts.push_back(curArg->u.literalConst[0]);
-										literalConsts.push_back(curArg->u.literalConst[1]);
-										literalConsts.push_back(curArg->u.literalConst[2]);
-										literalConsts.push_back(curArg->u.literalConst[3]);
-									}
-
-									nlohmann::json argData = json11::Json::object
-									{
-										{ "type", curArg->type },
-										{ "value", literalConsts },
-									};
-									argDataArray.push_back(argData);
-								}
-								else if (curArg->type == 3 || curArg->type == 5)
-								{
-									nlohmann::json argData = json11::Json::object
-									{
-										{ "type", curArg->type },
-										{ "firstRow", curArg->u.codeConst.firstRow },
-										{ "rowCount", curArg->u.codeConst.rowCount },
-										{ "index", curArg->u.codeConst.index },
-									};
-									argDataArray.push_back(argData);
-								}
-								else
-								{
-									nlohmann::json argData = json11::Json::object
-									{
-										{ "type", curArg->type },
-										{ "value", static_cast<int>(curArg->u.codeSampler) },
-									};
-									argDataArray.push_back(argData);
-								}
-							}
-
-							nlohmann::json passData = json11::Json::object
-							{
-								{ "perObjArgCount", curPass->perObjArgCount },
-								{ "perPrimArgCount", curPass->perPrimArgCount },
-								{ "stableArgCount", curPass->stableArgCount },
-								{ "args", argDataArray },
-								{ "pixelShader", curPass->pixelShader ? curPass->pixelShader->name : "" },
-								{ "vertexShader", curPass->vertexShader ? curPass->vertexShader->name : "" },
-								{ "vertexDecl", curPass->vertexDecl ? curPass->vertexDecl->name : "" },
-							};
-							passDataArray.push_back(passData);
-						}
-
-						nlohmann::json techData = json11::Json::object
-						{
-							{ "name", curTech->name },
-							{ "index", technique },
-							{ "flags", curTech->flags },
-							{ "numPasses", curTech->passCount },
-							{ "pass", passDataArray },
-						};
-
-						auto stringData = techData.dump();
-						
-						auto fp = fopen(Utils::String::VA("techsets/techniques/%s.%s.json", curTech->name, Zones::Version() > 276 ? "codo" : "iw4"), "wb");
-						fwrite(&stringData[0], stringData.size(), 1, fp);
-						fclose(fp);
-						
-						nlohmann::json techsetTechnique = json11::Json::object
-						{
-							{ "name", curTech->name },
-							{ "index", technique },
-						};
-						techniques.push_back(techsetTechnique);
-					}
-					else
-					{
-						techniques.push_back(nullptr);
-					}
-				}
-
-				nlohmann::json techsetData = json11::Json::object
-				{
-					{ "name", techset->name },
-					{ "techniques", techniques },
-				};
-
-				auto stringData = techsetData.dump();
-
-				auto fp = fopen(Utils::String::VA("techsets/%s.%s.json", techset->name, Zones::Version() > 276 ? "codo" : "iw4"), "wb");
-				fwrite(&stringData[0], stringData.size(), 1, fp);
-				fclose(fp);
-			}
-#endif
-
-			if (type == Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET && Zones::Version() >= 460)
-			{
-				auto techset = asset.techniqueSet;
-				if (techset)
-				{
-					for (int t = 0; t < 48; t++)
-					{
-						if (techset->techniques[t])
-						{
-							for (int p = 0; p < techset->techniques[t]->passCount; p++)
-							{
-								for (int a = 0; a < techset->techniques[t]->passArray[p].perObjArgCount +
-									techset->techniques[t]->passArray[p].perPrimArgCount +
-									techset->techniques[t]->passArray[p].stableArgCount; a++)
-								{
-									auto arg = &techset->techniques[t]->passArray[p].args[a];
-									if (arg->type == 3 || arg->type == 5)
-									{
-										if (arg->u.codeConst.index > 140)
-										{
-											OutputDebugStringA(Utils::String::VA("codeConst %i is out of range for %s::%s[%i]\n", arg->u.codeConst.index,
-												techset->name, techset->techniques[t]->name, p));
-
-											if (!ZoneBuilder::IsEnabled())
-											{
-												__debugbreak();
-											}
-										}
-									}
-								}
-							}
-						}
-					}
-				}
-			}
-			
-#endif
-			
 			if (Dvar::Var("r_noVoid").get<bool>() && type == Game::XAssetType::ASSET_TYPE_XMODEL && name == "void")
 			{
 				asset.model->numLods = 0;
diff --git a/src/Components/Modules/FastFiles.cpp b/src/Components/Modules/FastFiles.cpp
index b27ab321..e56732f1 100644
--- a/src/Components/Modules/FastFiles.cpp
+++ b/src/Components/Modules/FastFiles.cpp
@@ -10,6 +10,8 @@ namespace Components
 	symmetric_CTR FastFiles::CurrentCTR;
 	std::vector<std::string> FastFiles::ZonePaths;
 
+	Dvar::Var FastFiles::g_loadingInitialZones;
+
 	bool FastFiles::IsIW4xZone = false;
 	bool FastFiles::StreamRead = false;
 
@@ -133,8 +135,10 @@ namespace Components
 
 
 	// This has to be called only once, when the game starts
-	void FastFiles::LoadInitialZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
+	void FastFiles::LoadInitialZones(Game::XZoneInfo* zoneInfo, unsigned int zoneCount, int sync)
 	{
+		g_loadingInitialZones.set(true);
+
 		std::vector<Game::XZoneInfo> data;
 		Utils::Merge(&data, zoneInfo, zoneCount);
 
@@ -152,7 +156,7 @@ namespace Components
 	}
 
 	// This has to be called every time the cgame is reinitialized
-	void FastFiles::LoadDLCUIZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
+	void FastFiles::LoadDLCUIZones(Game::XZoneInfo* zoneInfo, unsigned int zoneCount, int sync)
 	{
 		std::vector<Game::XZoneInfo> data;
 		Utils::Merge(&data, zoneInfo, zoneCount);
@@ -177,7 +181,7 @@ namespace Components
 		return FastFiles::LoadLocalizeZones(data.data(), data.size(), sync);
 	}
 
-	void FastFiles::LoadGfxZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
+	void FastFiles::LoadGfxZones(Game::XZoneInfo* zoneInfo, unsigned int zoneCount, int sync)
 	{
 		std::vector<Game::XZoneInfo> data;
 		Utils::Merge(&data, zoneInfo, zoneCount);
@@ -191,7 +195,7 @@ namespace Components
 	}
 
 	// This has to be called every time fastfiles are loaded :D
-	void FastFiles::LoadLocalizeZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
+	void FastFiles::LoadLocalizeZones(Game::XZoneInfo* zoneInfo, unsigned int zoneCount, int sync)
 	{
 		std::vector<Game::XZoneInfo> data;
 		Utils::Merge(&data, zoneInfo, zoneCount);
@@ -213,6 +217,11 @@ namespace Components
 		data.push_back(info);
 
 		Game::DB_LoadXAssets(data.data(), data.size(), sync);
+
+		Scheduler::OnGameInitialized([]
+		{
+			g_loadingInitialZones.set(false);
+		}, Scheduler::Pipeline::MAIN);
 	}
 
 	// Name is a bit weird, due to FasFileS and ExistS :P
@@ -394,7 +403,7 @@ namespace Components
 		return Utils::Hook::Call<int(unsigned char*, int, unsigned char*)>(0x5BA240)(buffer, length, ivValue);
 	}
 
-	static int InflateInitDecrypt(z_streamp strm, const char *version, int stream_size)
+	static int InflateInitDecrypt(z_streamp strm, const char* version, int stream_size)
 	{
 		if (Zones::Version() >= 319)
 		{
@@ -436,7 +445,7 @@ namespace Components
 		return std::min(partialProgress + (currentProgress * singleProgress), 1.0f);
 	}
 
-	void FastFiles::LoadZonesStub(Game::XZoneInfo *zoneInfo, unsigned int zoneCount)
+	void FastFiles::LoadZonesStub(Game::XZoneInfo* zoneInfo, unsigned int zoneCount)
 	{
 		FastFiles::CurrentZone = 0;
 		FastFiles::MaxZones = zoneCount;
@@ -500,6 +509,7 @@ namespace Components
 	FastFiles::FastFiles()
 	{
 		Dvar::Register<bool>("ui_zoneDebug", false, Game::DVAR_ARCHIVE, "Display current loaded zone.");
+		g_loadingInitialZones = Dvar::Register<bool>("g_loadingInitialZones", true, Game::DVAR_NONE, "Is loading initial zones");
 
 		// Fix XSurface assets
 		Utils::Hook(0x0048E8A5, FastFiles::Load_XSurfaceArray, HOOK_CALL).install()->quick();
@@ -580,7 +590,7 @@ namespace Components
 				if (FastFiles::Current().empty() || !Dvar::Var("ui_zoneDebug").get<bool>()) return;
 
 				auto* const font = Game::R_RegisterFont("fonts/consoleFont", 0);
-				float color[4] = {1.0f, 1.0f, 1.0f, (Game::CL_IsCgameInitialized() ? 0.3f : 1.0f)};
+				float color[4] = { 1.0f, 1.0f, 1.0f, (Game::CL_IsCgameInitialized() ? 0.3f : 1.0f) };
 
 				auto FFTotalSize = *reinterpret_cast<std::uint32_t*>(0x10AA5D8);
 				auto FFCurrentOffset = *reinterpret_cast<std::uint32_t*>(0x10AA608);
@@ -617,11 +627,11 @@ namespace Components
 			while (!Game::Sys_IsDatabaseReady()) std::this_thread::sleep_for(100ms);
 		});
 
-#ifdef DEBUG
+#ifdef _DEBUG
 		// ZoneBuilder debugging
 		Utils::IO::WriteFile("userraw/logs/iw4_reads.log", "", false);
 		Utils::Hook(0x4A8FA0, FastFiles::LogStreamRead, HOOK_JUMP).install()->quick();
-		Utils::Hook(0x4BCB62, []()
+		Utils::Hook(0x4BCB62, []
 		{
 			FastFiles::StreamRead = true;
 			Utils::Hook::Call<void(bool)>(0x4B8DB0)(true); // currently set to Load_GfxWorld
diff --git a/src/Components/Modules/FastFiles.hpp b/src/Components/Modules/FastFiles.hpp
index 1e8d3bd2..24f0a03a 100644
--- a/src/Components/Modules/FastFiles.hpp
+++ b/src/Components/Modules/FastFiles.hpp
@@ -40,6 +40,8 @@ namespace Components
 
 		static char LastByteRead;
 
+		static Dvar::Var g_loadingInitialZones;
+
 		static Key CurrentKey;
 		static std::vector<std::string> ZonePaths;
 		static const char* GetZoneLocation(const char* file);
diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp
index 00cf934a..27cd6e9c 100644
--- a/src/Components/Modules/Maps.cpp
+++ b/src/Components/Modules/Maps.cpp
@@ -11,6 +11,7 @@ namespace Components
 	std::string Maps::CurrentMainZone;
 	std::vector<std::pair<std::string, std::string>> Maps::DependencyList;
 	std::vector<std::string> Maps::CurrentDependencies;
+	std::vector<std::string> Maps::FoundCustomMaps;
 
 	Dvar::Var Maps::RListSModels;
 
@@ -105,8 +106,8 @@ namespace Components
 
 		if (Maps::UserMap.isValid())
 		{
-			const std::string mapname = Maps::UserMap.getName();
-			const auto* arena = Utils::String::VA("usermaps/%s/%s.arena", mapname.data(), mapname.data());
+			const auto mapname = Maps::UserMap.getName();
+			const auto arena = GetArenaPath(mapname);
 
 			if (Utils::IO::FileExists(arena))
 			{
@@ -183,17 +184,17 @@ namespace Components
 	void Maps::OverrideMapEnts(Game::MapEnts* ents)
 	{
 		auto callback = [] (Game::XAssetHeader header, void* ents)
-			{
-				Game::MapEnts* mapEnts = reinterpret_cast<Game::MapEnts*>(ents);
-				Game::clipMap_t* clipMap = header.clipMap;
+		{
+			Game::MapEnts* mapEnts = reinterpret_cast<Game::MapEnts*>(ents);
+			Game::clipMap_t* clipMap = header.clipMap;
 
-				if (clipMap && mapEnts && !_stricmp(mapEnts->name, clipMap->name))
-				{
-					clipMap->mapEnts = mapEnts;
-					//*Game::marMapEntsPtr = mapEnts;
-					//Game::G_SpawnEntitiesFromString();
-				}
-			};
+			if (clipMap && mapEnts && !_stricmp(mapEnts->name, clipMap->name))
+			{
+				clipMap->mapEnts = mapEnts;
+				//*Game::marMapEntsPtr = mapEnts;
+				//Game::G_SpawnEntitiesFromString();
+			}
+		};
 
 		// Internal doesn't lock the thread, as locking is impossible, due to executing this in the thread that holds the current lock
 		Game::DB_EnumXAssets_Internal(Game::XAssetType::ASSET_TYPE_CLIPMAP_MP, callback, ents, true);
@@ -338,12 +339,33 @@ namespace Components
 		return (Utils::String::StartsWith(entity, "dyn_") || Utils::String::StartsWith(entity, "node_") || Utils::String::StartsWith(entity, "actor_"));
 	}
 
+	std::unordered_map<std::string, std::string> Maps::ParseCustomMapArena(const std::string& singleMapArena)
+	{
+		static const std::regex regex("  (\\w*) *\"?((?:\\w| )*)\"?");
+		std::unordered_map<std::string, std::string> arena;
+
+		std::smatch m;
+
+		std::string::const_iterator search_start(singleMapArena.cbegin());
+
+		while (std::regex_search(search_start, singleMapArena.cend(), m, regex))
+		{
+			if (m.size() > 2)
+			{
+				arena.emplace(m[1].str(), m[2].str());
+				search_start = m.suffix().first;
+			}
+		}
+
+		return arena;
+	}
+
 	Maps::MapDependencies Maps::GetDependenciesForMap(const std::string& map)
 	{
 		std::string teamAxis = "opforce_composite";
 		std::string teamAllies = "us_army";
 
-		Maps::MapDependencies dependencies{};
+		Maps::MapDependencies dependencies;
 
 		// True by default - cause some maps won't have an arenafile entry
 		dependencies.requiresTeamZones = true;
@@ -578,6 +600,40 @@ namespace Components
 		return Utils::IO::DirectoryExists(std::format("usermaps/{}", mapname)) && Utils::IO::FileExists(std::format("usermaps/{}/{}.ff", mapname, mapname));
 	}
 
+	void Maps::ScanCustomMaps()
+	{
+		FoundCustomMaps.clear();
+		Logger::Print("Scanning custom maps...\n");
+
+		auto basePath = std::format("{}\\usermaps", (*Game::fs_basepath)->current.string);
+
+		auto entries = Utils::IO::ListFiles(basePath);
+
+		for (const auto& entry : entries)
+		{
+			if (entry.is_directory())
+			{
+				auto zoneName = entry.path().filename().string();
+				auto mapPath = std::format("{}\\{}.ff", entry.path().string(), zoneName);
+				if (Utils::IO::FileExists(mapPath))
+				{
+					FoundCustomMaps.push_back(zoneName);
+					Logger::Print("Discovered custom map {}\n", zoneName);
+				}
+			}
+		}
+	}
+
+	std::string Maps::GetArenaPath(const std::string& mapName)
+	{
+		return std::format("usermaps/{}/{}.arena", mapName, mapName);
+	}
+
+	const std::vector<std::string>& Maps::GetCustomMaps()
+	{
+		return FoundCustomMaps;
+	}
+
 	Game::XAssetEntry* Maps::GetAssetEntryPool()
 	{
 		return *reinterpret_cast<Game::XAssetEntry**>(0x48E6F4);
@@ -696,13 +752,9 @@ namespace Components
 
 			Maps::AddDlc({ 1, "Stimulus Pack", {"mp_complex", "mp_compact", "mp_storm", "mp_overgrown", "mp_crash"} });
 			Maps::AddDlc({ 2, "Resurgence Pack", {"mp_abandon", "mp_vacant", "mp_trailerpark", "mp_strike", "mp_fuel2"} });
-			Maps::AddDlc({ 3, "Nuketown", {"mp_nuked"} });
-			Maps::AddDlc({ 4, "Classics Pack #1", {"mp_cross_fire", "mp_cargoship", "mp_bloc"} });
-			Maps::AddDlc({ 5, "Classics Pack #2", {"mp_killhouse", "mp_bog_sh"} });
-			Maps::AddDlc({ 6, "Freighter", {"mp_cargoship_sh"} });
-			Maps::AddDlc({ 7, "Resurrection Pack", {"mp_shipment_long", "mp_rust_long", "mp_firingrange"} });
-			Maps::AddDlc({ 8, "Recycled Pack", {"mp_bloc_sh", "mp_crash_tropical", "mp_estate_tropical", "mp_fav_tropical", "mp_storm_spring"} });
-			Maps::AddDlc({ 9, "Classics Pack #3", {"mp_farm", "mp_backlot", "mp_pipeline", "mp_countdown", "mp_crash_snow", "mp_carentan", "mp_broadcast", "mp_showdown", "mp_convoy"} });
+			Maps::AddDlc({ 3, "IW4x Classics", {"mp_nuked", "mp_cross_fire", "mp_cargoship", "mp_bloc", "mp_killhouse", "mp_bog_sh", "mp_cargoship_sh", "mp_shipment_long", "mp_rust_long", "mp_firingrange", "mp_bloc_sh", "mp_crash_tropical", "mp_estate_tropical", "mp_fav_tropical", "mp_storm_spring"} });
+			Maps::AddDlc({ 4, "Call Of Duty 4 Pack", {"mp_farm", "mp_backlot", "mp_pipeline", "mp_countdown", "mp_crash_snow", "mp_carentan", "mp_broadcast", "mp_showdown", "mp_convoy"} });
+			Maps::AddDlc({ 5, "Modern Warfare 3 Pack", {"mp_dome", "mp_hardhat", "mp_paris", "mp_seatown", "mp_bravo", "mp_underground", "mp_plaza2", "mp_village", "mp_alpha"}});
 
 			Maps::UpdateDlcStatus();
 
diff --git a/src/Components/Modules/Maps.hpp b/src/Components/Modules/Maps.hpp
index 28e1d89f..356cf6fe 100644
--- a/src/Components/Modules/Maps.hpp
+++ b/src/Components/Modules/Maps.hpp
@@ -63,6 +63,12 @@ namespace Components
 		static bool IsCustomMap();
 		static bool IsUserMap(const std::string& mapname);
 
+		static void ScanCustomMaps();
+		static std::string GetArenaPath(const std::string& mapName);
+		static const std::vector<std::string>& GetCustomMaps();
+
+		static std::unordered_map<std::string, std::string> ParseCustomMapArena(const std::string& singleMapArena);
+
 	private:
 		class DLC
 		{
@@ -85,6 +91,7 @@ namespace Components
 
 		static std::vector<std::pair<std::string, std::string>> DependencyList;
 		static std::vector<std::string> CurrentDependencies;
+		static std::vector<std::string> FoundCustomMaps;
 
 		static Dvar::Var RListSModels;
 
diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp
index cfd8024b..41fc91b9 100644
--- a/src/Components/Modules/QuickPatch.cpp
+++ b/src/Components/Modules/QuickPatch.cpp
@@ -527,18 +527,21 @@ namespace Components
 			std::vector<std::string> fastFiles;
 			if (std::strcmp(param->get(1), "all") == 0)
 			{
-				for (const auto& f : Utils::IO::ListFiles("zone/english", false))
+				for (const auto& entry : Utils::IO::ListFiles("zone/english", false))
 				{
+					const auto& f = entry.path().string();
 					fastFiles.emplace_back(f.substr(7, f.length() - 10));
 				}
 
-				for (const auto& f : Utils::IO::ListFiles("zone/dlc", false))
+				for (const auto& entry : Utils::IO::ListFiles("zone/dlc", false))
 				{
+					const auto& f = entry.path().string();
 					fastFiles.emplace_back(f.substr(3, f.length() - 6));
 				}
 
-				for (const auto& f : Utils::IO::ListFiles("zone/patch", false))
+				for (const auto& entry : Utils::IO::ListFiles("zone/patch", false))
 				{
+					const auto& f = entry.path().string();
 					fastFiles.emplace_back(f.substr(5, f.length() - 8));
 				}
 			}
diff --git a/src/Components/Modules/Renderer.cpp b/src/Components/Modules/Renderer.cpp
index fd4619b2..4eed9557 100644
--- a/src/Components/Modules/Renderer.cpp
+++ b/src/Components/Modules/Renderer.cpp
@@ -17,6 +17,7 @@ namespace Components
 	Dvar::Var Renderer::r_playerDrawDebugDistance;
 	Dvar::Var Renderer::r_forceTechnique;
 	Dvar::Var Renderer::r_listSamplers;
+	Dvar::Var Renderer::r_drawLights;
 
 	float cyan[4] = { 0.0f, 0.5f, 0.5f, 1.0f };
 	float red[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
@@ -183,11 +184,9 @@ namespace Components
 	{
 		if (!r_drawTriggers.get<bool>()) return;
 
-		auto entities = Game::g_entities;
-
 		for (std::size_t i = 0; i < Game::MAX_GENTITIES; ++i)
 		{
-			auto* ent = &entities[i];
+			auto* ent = &Game::g_entities[i];
 
 			if (ent->r.isInUse)
 			{
@@ -264,7 +263,7 @@ namespace Components
 		if (!val) return;
 
 		auto clientNum = Game::CG_GetClientNum();
-		Game::gentity_t* clientEntity = &Game::g_entities[clientNum];
+		auto* clientEntity = &Game::g_entities[clientNum];
 
 		// Ingame only & player only
 		if (!Game::CL_IsCgameInitialized() || clientEntity->client == nullptr)
@@ -358,7 +357,7 @@ namespace Components
 		if (!val) return;
 
 		auto clientNum = Game::CG_GetClientNum();
-		Game::gentity_t* clientEntity = &Game::g_entities[clientNum];
+		auto* clientEntity = &Game::g_entities[clientNum];
 
 		// Ingame only & player only
 		if (!Game::CL_IsCgameInitialized() || clientEntity->client == nullptr)
@@ -538,6 +537,82 @@ namespace Components
 		}
 	}
 
+	void Renderer::DrawPrimaryLights()
+	{
+		if (!r_drawLights.get<bool>())
+		{
+			return;
+		}
+
+		auto clientNum = Game::CG_GetClientNum();
+		auto* clientEntity = &Game::g_entities[clientNum];
+
+		// Ingame only & player only
+		if (!Game::CL_IsCgameInitialized() || clientEntity->client == nullptr)
+		{
+			return;
+		}
+
+		auto scene = Game::scene;
+		auto asset = Game::DB_FindXAssetEntry(Game::XAssetType::ASSET_TYPE_COMWORLD, Utils::String::VA("maps/mp/%s.d3dbsp", (*Game::sv_mapname)->current.string));
+
+		if (asset == nullptr)
+		{
+			return;
+		}
+
+		auto world = asset->asset.header.comWorld;
+
+		for (size_t i = 0; i < world->primaryLightCount; i++)
+		{
+			auto light = &world->primaryLights[i];
+
+			float to[3];
+			to[0] = light->origin[0] + light->dir[0] * 10;
+			to[1] = light->origin[1] + light->dir[1] * 10;
+			to[2] = light->origin[2] + light->dir[2] * 10;
+
+			auto n = light->defName == nullptr ? "NONE" : light->defName;
+
+			auto str = std::format("LIGHT #{} ({})", i, n);
+
+			float color[4]{};
+			color[3] = 1.0f;
+			color[0] = light->color[0];
+			color[1] = light->color[1];
+			color[2] = light->color[2];
+
+
+			Game::R_AddDebugLine(color, light->origin, to);
+			Game::R_AddDebugString(color, light->origin, 1.0f, str.data());
+		}
+
+		if (scene)
+		{
+			for (size_t i = 0; i < scene->addedLightCount; i++)
+			{
+				auto light = &scene->addedLight[i];
+
+				float color[4]{};
+				color[3] = 1.0f;
+				color[0] = light->color[0];
+				color[1] = light->color[1];
+				color[2] = light->color[2];
+
+				float to[3];
+				to[0] = light->origin[0] + light->dir[0] * 10;
+				to[1] = light->origin[1] + light->dir[1] * 10;
+				to[2] = light->origin[2] + light->dir[2] * 10;
+
+				auto str = std::format("ADDED LIGHT #{}", i);
+
+				Game::R_AddDebugLine(color, light->origin, to);
+				Game::R_AddDebugString(color, light->origin, 1.0f, str.data());
+				
+			}
+		}
+	}
+
 	int Renderer::FixSunShadowPartitionSize(Game::GfxCamera* camera, Game::GfxSunShadowMapMetrics* mapMetrics, Game::GfxSunShadow* sunShadow, Game::GfxSunShadowClip* clip, float* partitionFraction)
 	{
 		auto result = Utils::Hook::Call<int(Game::GfxCamera*, Game::GfxSunShadowMapMetrics*, Game::GfxSunShadow*, Game::GfxSunShadowClip*, float*)>(0x5463B0)(camera, mapMetrics, sunShadow, clip, partitionFraction);
@@ -567,6 +642,7 @@ namespace Components
 				DebugDrawTriggers();
 				ForceTechnique();
 				ListSamplers();
+				DrawPrimaryLights();
 			}
 		}, Scheduler::Pipeline::RENDERER);
 
@@ -629,6 +705,7 @@ namespace Components
 			Renderer::r_playerDrawDebugDistance = Game::Dvar_RegisterInt("r_drawDebugDistance", 1000, 0, 50000, Game::DVAR_ARCHIVE, "r_draw debug functions draw distance relative to the player");
 			Renderer::r_forceTechnique = Game::Dvar_RegisterInt("r_forceTechnique", 0, 0, 14, Game::DVAR_NONE, "Force a base technique on the renderer");
 			Renderer::r_listSamplers = Game::Dvar_RegisterBool("r_listSamplers", false, Game::DVAR_NONE, "List samplers & sampler states");
+			Renderer::r_drawLights = Game::Dvar_RegisterBool("r_drawLights", false, Game::DVAR_NONE, "Draw every comworld light in the level");
 		});
 	}
 
diff --git a/src/Components/Modules/Renderer.hpp b/src/Components/Modules/Renderer.hpp
index f1e00a96..327f11f6 100644
--- a/src/Components/Modules/Renderer.hpp
+++ b/src/Components/Modules/Renderer.hpp
@@ -42,6 +42,7 @@ namespace Components
 		static void DebugDrawAABBTrees();
 		static void ForceTechnique();
 		static void ListSamplers();
+		static void DrawPrimaryLights();
 
 		static int FixSunShadowPartitionSize(Game::GfxCamera* camera, Game::GfxSunShadowMapMetrics* mapMetrics, Game::GfxSunShadow* sunShadow, Game::GfxSunShadowClip* clip, float* partitionFraction);
 
@@ -60,5 +61,6 @@ namespace Components
 		static Dvar::Var r_playerDrawDebugDistance;
 		static Dvar::Var r_forceTechnique;
 		static Dvar::Var r_listSamplers;
+		static Dvar::Var r_drawLights;
 	};
 }
diff --git a/src/Components/Modules/UIFeeder.cpp b/src/Components/Modules/UIFeeder.cpp
index 5ed500c8..526f745a 100644
--- a/src/Components/Modules/UIFeeder.cpp
+++ b/src/Components/Modules/UIFeeder.cpp
@@ -129,7 +129,7 @@ namespace Components
 			fld ds:739FD0h
 
 			mov eax, 41A0D7h
-			jmp eax;
+			jmp eax
 		}
 	}
 
@@ -279,74 +279,81 @@ namespace Components
 
 	unsigned int UIFeeder::GetMapCount()
 	{
-		Game::UI_UpdateArenas();
-		Game::UI_SortArenas();
-		return *Game::arenaCount;
+		return Maps::GetCustomMaps().size();
 	}
 
 	const char* UIFeeder::GetMapText(unsigned int index, int /*column*/)
 	{
-		Game::UI_UpdateArenas();
-		Game::UI_SortArenas();
-
-		if (index < static_cast<unsigned int>(*Game::arenaCount))
+		const auto& maps = Maps::GetCustomMaps();
+		if (index < maps.size())
 		{
-			return Game::SEH_StringEd_GetString(ArenaLength::NewArenas[reinterpret_cast<int*>(0x633E934)[index]].uiName);
+			return maps.at(index).data();
 		}
 
+#ifdef DEBUG
+		if (IsDebuggerPresent())
+		{
+			__debugbreak();
+		}
+#endif
+
 		return "";
 	}
 
 	void UIFeeder::SelectMap(unsigned int index)
 	{
-		Game::UI_UpdateArenas();
-		Game::UI_SortArenas();
+		const auto& maps = Maps::GetCustomMaps();
 
-		if (index < static_cast<unsigned int>(*Game::arenaCount))
+		if (index < maps.size())
 		{
-			index = reinterpret_cast<int*>(0x633E934)[index];
-			const char* map_name = ArenaLength::NewArenas[index].mapName;
-			const char* long_name = ArenaLength::NewArenas[index].uiName;
-			const char* description = ArenaLength::NewArenas[index].description;
+			std::string mapName = maps[index];
 
-			UIMapName.set(map_name);
-			UIMapLong.set(Game::SEH_StringEd_GetString(long_name));
-			UIMapDesc.set(Game::SEH_StringEd_GetString(description));
+			std::string longName = mapName;
+			std::string description = "(Missing arena file!)";
+
+			const auto& arenaPath = Maps::GetArenaPath(mapName);
+
+			if (Utils::IO::FileExists(arenaPath))
+			{
+				const auto& arena = Maps::ParseCustomMapArena(Utils::IO::ReadFile(arenaPath));
+
+				if (arena.contains("longname"))
+				{
+					longName = arena.at("longname");
+				}
+
+				if (arena.contains("map"))
+				{
+					mapName = arena.at("map");
+				}
+
+				if (arena.contains("description"))
+				{
+					description = arena.at("description");
+				}
+			}
+
+			UIMapName.set(Localization::Get(mapName.data()));
+			UIMapLong.set(Localization::Get(longName.data()));
+			UIMapDesc.set(Localization::Get(description.data()));
 		}
 	}
 
 	void UIFeeder::ApplyMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
 	{
-		const auto mapname = Dvar::Var("ui_map_name").get<std::string>();
+		const auto* mapname = Dvar::Var("ui_map_name").get<const char*>();
 
-		Dvar::Var("ui_mapname").set(mapname);
-		Utils::Hook::Call<void(const char*)>(0x503B50)(mapname.data()); // Party_SetDisplayMapName
+		if (*mapname)
+		{
+			Game::Dvar_SetString(*Game::ui_mapname, mapname);
+			Utils::Hook::Call<void(const char*)>(0x503B50)(mapname); // Party_SetDisplayMapName
+		}
 	}
 
 	void UIFeeder::ApplyInitialMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
 	{
-		const auto* mapname = (*Game::ui_mapname)->current.string;
-
-		Game::UI_UpdateArenas();
-		Game::UI_SortArenas();
-
-		for (unsigned int i = 0; i < static_cast<unsigned int>(*Game::arenaCount); ++i)
-		{
-			if (!std::strcmp(ArenaLength::NewArenas[i].mapName, mapname))
-			{
-				for (unsigned int j = 0; j < static_cast<unsigned int>(*Game::arenaCount); ++j)
-				{
-					if (reinterpret_cast<unsigned int*>(0x633E934)[j] == i)
-					{
-						SelectMap(j);
-						Select(60.0f, j);
-						break;
-					}
-				}
-
-				break;
-			}
-		}
+		Maps::ScanCustomMaps();
+		Select(60.0f, 0); // Will select nothing if there's no map
 	}
 
 	int UIFeeder::CheckSelection(int feeder)
@@ -387,8 +394,8 @@ namespace Components
 
 		Events::OnDvarInit([]
 		{
-			UIMapLong = Dvar::Register<const char*>("ui_map_long", "Afghan", Game::DVAR_NONE, "");
-			UIMapName = Dvar::Register<const char*>("ui_map_name", "mp_afghan", Game::DVAR_NONE, "");
+			UIMapLong = Dvar::Register<const char*>("ui_map_long", "", Game::DVAR_NONE, "");
+			UIMapName = Dvar::Register<const char*>("ui_map_name", "", Game::DVAR_NONE, "");
 			UIMapDesc = Dvar::Register<const char*>("ui_map_desc", "", Game::DVAR_NONE, "");
 		});
 
diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp
index 452622cf..c1b7a133 100644
--- a/src/Components/Modules/ZoneBuilder.cpp
+++ b/src/Components/Modules/ZoneBuilder.cpp
@@ -1336,8 +1336,9 @@ namespace Components
 
 				const auto dir = std::format("zone/{}", Game::Win_GetLanguage());
 				auto fileList = Utils::IO::ListFiles(dir, false);
-				for (auto zone : fileList)
+				for (const auto& entry : fileList)
 				{
+					auto zone = entry.path().string();
 					Utils::String::Replace(zone, Utils::String::VA("zone/%s/", Game::Win_GetLanguage()), "");
 					Utils::String::Replace(zone, ".ff", "");
 
@@ -1431,8 +1432,10 @@ namespace Components
 				auto list = Utils::IO::ListFiles("zone/techsets", false);
 				int i = 0;
 				int subCount = 0;
-				for (auto it : list)
+				for (const auto& entry : list)
 				{
+					auto it = entry.path().string();
+
 					Utils::String::Replace(it, "zone/techsets/", "");
 					Utils::String::Replace(it, ".ff", "");
 
@@ -1555,7 +1558,7 @@ namespace Components
 
 				// create csv with the techsets in it
 				csvStr.clear();
-				for (auto tech : curTechsets_list)
+				for (const auto& tech : curTechsets_list)
 				{
 					auto mat = ZoneBuilder::FindMaterialByTechnique(tech);
 					if (mat.length() == 0)
diff --git a/src/Components/Modules/Zones.cpp b/src/Components/Modules/Zones.cpp
index 947fbdfb..2206df39 100644
--- a/src/Components/Modules/Zones.cpp
+++ b/src/Components/Modules/Zones.cpp
@@ -47,7 +47,7 @@ namespace Components
 
 	Game::XAssetType currentAssetType = Game::XAssetType::ASSET_TYPE_INVALID;
 	Game::XAssetType previousAssetType = Game::XAssetType::ASSET_TYPE_INVALID;
-	
+
 	bool Zones::LoadFxEffectDef(bool atStreamStart, char* buffer, int size)
 	{
 		int count = 0;
@@ -124,7 +124,7 @@ namespace Components
 		}
 
 		bool result = Game::Load_Stream(atStreamStart, xmodel, size);
-		
+
 		if (Zones::Version() >= VERSION_ALPHA2)
 		{
 			Game::XModel model[2]; // Allocate 2 models, as we exceed the buffer
@@ -325,7 +325,7 @@ namespace Components
 		{
 			auto stringCount = (Zones::Version() >= 460) ? 62 : 52;
 			auto arraySize = stringCount * 4;
-			
+
 			// 236
 			*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 124);
 			Game::Load_XStringArray(false, stringCount);
@@ -360,31 +360,31 @@ namespace Components
 		{
 			for (int i = 0; i < 16; i++)
 			{
-				*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 1028 + (i * 4));
+				*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 1028 + (i * 4));
 				Game::Load_FxEffectDefHandle(false);
 			}
 
 			for (int i = 0; i < 16; i++)
 			{
-				*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 1124 + (i * 4));
+				*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 1124 + (i * 4));
 				Game::Load_FxEffectDefHandle(false);
 			}
 
 			for (int i = 0; i < 16; i++)
 			{
-				*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 1188 + (i * 4));
+				*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 1188 + (i * 4));
 				Game::Load_FxEffectDefHandle(false);
 			}
 
 			for (int i = 0; i < 16; i++)
 			{
-				*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 1316 + (i * 4));
+				*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 1316 + (i * 4));
 				Game::Load_FxEffectDefHandle(false);
 			}
 
 			for (int i = 0; i < 5; i++)
 			{
-				*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 1444 + (i * 4));
+				*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 1444 + (i * 4));
 				Game::Load_FxEffectDefHandle(false);
 			}
 		}
@@ -421,7 +421,7 @@ namespace Components
 		{
 			auto offset = (Zones::Version() >= 460) ? 1476 : 916;
 			auto count = (Zones::Version() >= 461) ? 58 : (Zones::Version() >= 460) ? 57 : 52;
-			
+
 			// 53 soundalias name references; up to and including 1124
 			for (int i = 0; i < count; ++i, offset += 4)
 			{
@@ -457,7 +457,7 @@ namespace Components
 				if (*reinterpret_cast<DWORD*>(varWeaponCompleteDef + 1708) == -1)
 				{
 					*reinterpret_cast<void**>(varWeaponCompleteDef + 1708) = Game::DB_AllocStreamPos(3);
-					*Game::varsnd_alias_list_name = *reinterpret_cast<Game::snd_alias_list_t * **>(varWeaponCompleteDef + 1708);
+					*Game::varsnd_alias_list_name = *reinterpret_cast<Game::snd_alias_list_t***>(varWeaponCompleteDef + 1708);
 
 					Game::Load_snd_alias_list_nameArray(true, 31);
 				}
@@ -472,7 +472,7 @@ namespace Components
 				if (*reinterpret_cast<DWORD*>(varWeaponCompleteDef + 1712) == -1)
 				{
 					*reinterpret_cast<void**>(varWeaponCompleteDef + 1712) = Game::DB_AllocStreamPos(3);
-					*Game::varsnd_alias_list_name = *reinterpret_cast<Game::snd_alias_list_t * **>(varWeaponCompleteDef + 1712);
+					*Game::varsnd_alias_list_name = *reinterpret_cast<Game::snd_alias_list_t***>(varWeaponCompleteDef + 1712);
 
 					Game::Load_snd_alias_list_nameArray(true, 31);
 				}
@@ -552,7 +552,7 @@ namespace Components
 			// 1192
 			for (int offset = 1716; offset <= 1728; offset += 4)
 			{
-				*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + offset);
+				*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + offset);
 				Game::Load_FxEffectDefHandle(false);
 			}
 		}
@@ -581,7 +581,7 @@ namespace Components
 			static int matOffsets1[] = { 1732, 1736, 1952, 1956, 1960, 1964, 1968, 1972, 1980, 1988, 2000, 2004, 2008, 2012 };
 			for (int i = 0; i < ARRAYSIZE(matOffsets1); ++i)
 			{
-				*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + matOffsets1[i]);
+				*Game::varMaterialHandle = reinterpret_cast<Game::Material**>(varWeaponCompleteDef + matOffsets1[i]);
 				Game::Load_MaterialHandle(false);
 			}
 		}
@@ -643,7 +643,7 @@ namespace Components
 		{
 			for (int offset = 2332; offset <= 2344; offset += 4)
 			{
-				*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + offset);
+				*Game::varMaterialHandle = reinterpret_cast<Game::Material**>(varWeaponCompleteDef + offset);
 				Game::Load_MaterialHandle(false);
 			}
 		}
@@ -666,10 +666,10 @@ namespace Components
 
 		if (Zones::Version() >= 460)
 		{
-			*Game::varPhysCollmapPtr = reinterpret_cast<Game::PhysCollmap * *>(varWeaponCompleteDef + 2544);
+			*Game::varPhysCollmapPtr = reinterpret_cast<Game::PhysCollmap**>(varWeaponCompleteDef + 2544);
 			Game::Load_PhysCollmapPtr(false);
 
-			*Game::varPhysPresetPtr = reinterpret_cast<Game::PhysPreset * *>(varWeaponCompleteDef + 2548);
+			*Game::varPhysPresetPtr = reinterpret_cast<Game::PhysPreset**>(varWeaponCompleteDef + 2548);
 			Game::Load_PhysPresetPtr(false);
 		}
 		else if (Zones::ZoneVersion >= 359)
@@ -688,7 +688,7 @@ namespace Components
 
 		if (Zones::Version() >= 460)
 		{
-			*Game::varXModelPtr = reinterpret_cast<Game::XModel * *>(varWeaponCompleteDef + 2656);
+			*Game::varXModelPtr = reinterpret_cast<Game::XModel**>(varWeaponCompleteDef + 2656);
 			Game::Load_XModelPtr(false);
 		}
 		else if (Zones::ZoneVersion >= 359)
@@ -704,10 +704,10 @@ namespace Components
 
 		if (Zones::Version() >= 460)
 		{
-			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2664);
+			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2664);
 			Game::Load_FxEffectDefHandle(false);
 
-			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2668);
+			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2668);
 			Game::Load_FxEffectDefHandle(false);
 		}
 		else if (Zones::ZoneVersion >= 359)
@@ -729,10 +729,10 @@ namespace Components
 
 		if (Zones::Version() >= 460)
 		{
-			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 2672);
+			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 2672);
 			Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
 
-			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 2676);
+			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 2676);
 			Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
 		}
 		else if (Zones::ZoneVersion >= 359)
@@ -754,13 +754,13 @@ namespace Components
 
 		if (Zones::Version() >= 460)
 		{
-			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2952);
+			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2952);
 			Game::Load_FxEffectDefHandle(false);
 
-			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2956);
+			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2956);
 			Game::Load_FxEffectDefHandle(false);
 
-			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2984);
+			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2984);
 			Game::Load_FxEffectDefHandle(false);
 		}
 		else if (Zones::ZoneVersion >= 359)
@@ -788,24 +788,24 @@ namespace Components
 
 		if (Zones::Version() >= 460)
 		{
-			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 2988);
+			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 2988);
 			Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
 
-			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2992);
+			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2992);
 			Game::Load_FxEffectDefHandle(false);
 
-			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2996);
+			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2996);
 			Game::Load_FxEffectDefHandle(false);
 
-			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 3000);
+			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 3000);
 			Game::Load_FxEffectDefHandle(false);
 
-			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 3004);
+			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 3004);
 			Game::Load_FxEffectDefHandle(false);
 
-			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 3008);
+			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 3008);
 			Game::Load_FxEffectDefHandle(false);
-			
+
 			*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3196);
 			Game::Load_XString(false);
 		}
@@ -953,37 +953,37 @@ namespace Components
 
 		if (Zones::Version() >= 460)
 		{
-			*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef * *>(varWeaponCompleteDef + 3492 + offsetShift);
+			*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef**>(varWeaponCompleteDef + 3492 + offsetShift);
 			Game::Load_TracerDefPtr(false);
 
-			*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef * *>(varWeaponCompleteDef + 3496 + offsetShift);
+			*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef**>(varWeaponCompleteDef + 3496 + offsetShift);
 			Game::Load_TracerDefPtr(false);
 
-			*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef * *>(varWeaponCompleteDef + 3500 + offsetShift);
+			*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef**>(varWeaponCompleteDef + 3500 + offsetShift);
 			Game::Load_TracerDefPtr(false);
-			
-			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3528 + offsetShift);
+
+			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 3528 + offsetShift);
 			Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); // 2848
 
-			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 3532 + offsetShift);
+			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 3532 + offsetShift);
 			Game::Load_FxEffectDefHandle(false);
 
 			*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3536 + offsetShift);
 			Game::Load_XString(false);
 
-			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3552 + offsetShift);
+			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 3552 + offsetShift);
 			Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
 
-			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3556 + offsetShift);
+			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 3556 + offsetShift);
 			Game::Load_snd_alias_list_nameArray(false, 4);
 
-			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3572 + offsetShift);
+			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 3572 + offsetShift);
 			Game::Load_snd_alias_list_nameArray(false, 4);
 
-			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3588 + offsetShift);
+			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 3588 + offsetShift);
 			Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
 
-			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3592 + offsetShift);
+			*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 3592 + offsetShift);
 			Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
 		}
 		else if (Zones::ZoneVersion >= 359)
@@ -1049,7 +1049,7 @@ namespace Components
 		{
 			for (int i = 0, offset = 3660 + offsetShift; i < 6; ++i, offset += 4)
 			{
-				*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + offset);
+				*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + offset);
 				Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
 			}
 		}
@@ -1091,16 +1091,16 @@ namespace Components
 			*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3732 + offsetShift);
 			Game::Load_XString(false);
 
-			*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3740 + offsetShift);
+			*Game::varMaterialHandle = reinterpret_cast<Game::Material**>(varWeaponCompleteDef + 3740 + offsetShift);
 			Game::Load_MaterialHandle(false);
 
-			*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3744 + offsetShift);
+			*Game::varMaterialHandle = reinterpret_cast<Game::Material**>(varWeaponCompleteDef + 3744 + offsetShift);
 			Game::Load_MaterialHandle(false);
 
-			*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3748 + offsetShift);
+			*Game::varMaterialHandle = reinterpret_cast<Game::Material**>(varWeaponCompleteDef + 3748 + offsetShift);
 			Game::Load_MaterialHandle(false);
 
-			*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3752 + offsetShift);
+			*Game::varMaterialHandle = reinterpret_cast<Game::Material**>(varWeaponCompleteDef + 3752 + offsetShift);
 			Game::Load_MaterialHandle(false);
 		}
 		else if (Zones::ZoneVersion >= 359)
@@ -1441,11 +1441,11 @@ namespace Components
 			Game::Load_XString(false);
 
 			*reinterpret_cast<void**>(varWeaponAttach + 8) = Game::DB_AllocStreamPos(3);
-			Zones::LoadWeaponAttachStuff(*reinterpret_cast<DWORD * *>(varWeaponAttach + 8), *reinterpret_cast<int*>(varWeaponAttach + 4));
+			Zones::LoadWeaponAttachStuff(*reinterpret_cast<DWORD**>(varWeaponAttach + 8), *reinterpret_cast<int*>(varWeaponAttach + 4));
 
 			Game::DB_PopStreamPos();
 		}
-		
+
 	}
 
 	bool Zones::LoadMaterialShaderArgumentArray(bool atStreamStart, Game::MaterialShaderArgument* argument, int size)
@@ -1455,7 +1455,7 @@ namespace Components
 
 		Game::MaterialPass* curPass = *Game::varMaterialPass;
 		int count = curPass->perPrimArgCount + curPass->perObjArgCount + curPass->stableArgCount;
-		
+
 		for (int i = 0; i < count && (Zones::ZoneVersion >= VERSION_ALPHA2); ++i)
 		{
 			Game::MaterialShaderArgument* arg = &argument[i];
@@ -1544,13 +1544,13 @@ namespace Components
 					}
 					else if (Zones::Version() == 461)
 					{
-						static std::unordered_map<std::uint16_t, std::uint16_t> mapped_constants = 
+						static std::unordered_map<std::uint16_t, std::uint16_t> mapped_constants =
 						{
 							// mp_raid
 							{ 33, 31 },
 							{ 34, 32 },
 							{ 36, 34 },
-							{ 39, 37 },	
+							{ 39, 37 },
 							{ 40, 38 },
 							{ 42, 40 },
 							{ 43, 41 },
@@ -1582,7 +1582,7 @@ namespace Components
 
 							// dont know if this applies to 460 too, but I dont have 460 files to test
 							if (!strncmp(techsetName, "wc_unlit_add", 12) ||
-								!strncmp(techsetName, "wc_unlit_multiply", 17) )
+								!strncmp(techsetName, "wc_unlit_multiply", 17))
 							{
 								// fixes glass and water
 								arg->u.codeConst.index = 116;
@@ -1653,10 +1653,10 @@ namespace Components
 						{
 							if (arg->u.codeConst.index == 257)
 							{
-								if (FastFiles::Current() != "mp_conflict" && FastFiles::Current() != "mp_derail_sh" && FastFiles::Current() != "mp_overwatch_sh" && 
+								if (FastFiles::Current() != "mp_conflict" && FastFiles::Current() != "mp_derail_sh" && FastFiles::Current() != "mp_overwatch_sh" &&
 									FastFiles::Current() != "mp_con_spring" && FastFiles::Current() != "mp_resistance_sh" && FastFiles::Current() != "mp_lookout_sh")
 								{
-									const auto varMaterialTechniqueSet = *reinterpret_cast<Game::MaterialTechniqueSet * *>(0x112AE8C);
+									const auto varMaterialTechniqueSet = *reinterpret_cast<Game::MaterialTechniqueSet**>(0x112AE8C);
 									if (varMaterialTechniqueSet->name && !strncmp(varMaterialTechniqueSet->name, "mc_", 3))
 									{
 										// fixes trees
@@ -1789,25 +1789,26 @@ namespace Components
 		return result;
 	}
 
-	void Zones::FixImageCategory(Game::GfxImage* image) {
+	void Zones::FixImageCategory(Game::GfxImage* image)
+	{
 		// CODO makes use of additional enumerator values (9, 10, 11) that don't exist in IW4
 		// We have to translate them. 9 is for Reflection probes,  11 is for Compass,  10 is for Lightmap
 		switch (image->category)
 		{
-			case 9:
-				image->category = Game::ImageCategory::IMG_CATEGORY_AUTO_GENERATED;
-				break;
-			case 10:
-				image->category = Game::ImageCategory::IMG_CATEGORY_LIGHTMAP;
-				break;
-			case 11:
-				image->category = Game::ImageCategory::IMG_CATEGORY_LOAD_FROM_FILE;
-				break;
+		case 9:
+			image->category = Game::ImageCategory::IMG_CATEGORY_AUTO_GENERATED;
+			break;
+		case 10:
+			image->category = Game::ImageCategory::IMG_CATEGORY_LIGHTMAP;
+			break;
+		case 11:
+			image->category = Game::ImageCategory::IMG_CATEGORY_LOAD_FROM_FILE;
+			break;
 		}
 
 
-		if (image->category > 7 || image->category < 0) {
-
+		if (image->category > 7 || image->category < 0)
+		{
 #ifdef DEBUG
 			if (IsDebuggerPresent()) __debugbreak();
 #endif
@@ -1837,15 +1838,15 @@ namespace Components
 				if (Zones::Version() >= 423)
 				{
 					// don't read assets that are unused by codol, for some retarded reason their header is written in the FF anyway
-					if (*reinterpret_cast<int*>(buffer + (i * 8)) == Game::XAssetType::ASSET_TYPE_CLIPMAP_SP || 
-						*reinterpret_cast<int*>(buffer + (i * 8)) == Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP || 
+					if (*reinterpret_cast<int*>(buffer + (i * 8)) == Game::XAssetType::ASSET_TYPE_CLIPMAP_SP ||
+						*reinterpret_cast<int*>(buffer + (i * 8)) == Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP ||
 						*reinterpret_cast<int*>(buffer + (i * 8)) == Game::XAssetType::ASSET_TYPE_GAMEWORLD_MP)
 					{
 						*reinterpret_cast<int*>(buffer + (i * 8)) = Game::XAssetType::ASSET_TYPE_UI_MAP;
 						*reinterpret_cast<int**>(buffer + (i * 8) + 4) = nullptr;
 					}
 				}
-				
+
 				AssetHandler::Relocate(buffer + (i * 16), buffer + (i * 8) + 0, 4);
 				AssetHandler::Relocate(buffer + (i * 16) + 8, buffer + (i * 8) + 4, 4);
 			}
@@ -1860,7 +1861,7 @@ namespace Components
 		if (Zones::ZoneVersion >= 359) size += 4;
 		// 446 amd above adds an additional technique
 		if (Zones::ZoneVersion >= 446) size += 4;
-		
+
 		bool result = Game::Load_Stream(atStreamStart, buffer, size);
 
 		if (Zones::ZoneVersion >= 359)
@@ -1888,8 +1889,8 @@ namespace Components
 
 		if (Zones::Version() >= 446)
 		{
-			auto lastTechnique = **reinterpret_cast<Game::MaterialTechnique * **>(0x112AEDC);
-			auto varMaterialTechniqueSet = **reinterpret_cast<Game::MaterialTechniqueSet * **>(0x112B070);
+			auto lastTechnique = **reinterpret_cast<Game::MaterialTechnique***>(0x112AEDC);
+			auto varMaterialTechniqueSet = **reinterpret_cast<Game::MaterialTechniqueSet***>(0x112B070);
 
 			// patch last technique to match iw4
 			varMaterialTechniqueSet->techniques[47] = lastTechnique;
@@ -1920,7 +1921,7 @@ namespace Components
 			std::memmove(buffer + 0x50, codol_material + 0x58, 0x10);
 
 			std::memset(buffer + 0x48 + 5, 0, 3);
-			
+
 			// relocate pointers
 			AssetHandler::Relocate(buffer + 10, buffer, 4);
 			AssetHandler::Relocate(buffer + 0x1B, buffer + 4, 4);
@@ -1933,12 +1934,12 @@ namespace Components
 			reinterpret_cast<Game::Material*>(buffer)->stateBitsEntry[47] = codol_material[0x50];
 		}
 		else if (Zones::ZoneVersion >= 359)
-		{			
+		{
 			struct material339_s
 			{
 				char drawSurfBegin[8]; // 4
 				//int surfaceTypeBits;
-				const char *name;
+				const char* name;
 				char drawSurf[6];
 
 				union
@@ -1987,7 +1988,7 @@ namespace Components
 	int gfxLightMapExtraCount = 0;
 	int* gfxLightMapExtraPtr1 = nullptr;
 	int* gfxLightMapExtraPtr2 = nullptr;
-	
+
 	bool Zones::LoadGfxWorld(bool atStreamStart, char* buffer, int size)
 	{
 		gfxLightMapExtraPtr1 = nullptr;
@@ -1996,7 +1997,7 @@ namespace Components
 		if (Zones::Version() >= 460) size += 984;
 		else if (Zones::Version() >= 423) size += 980;
 		else if (Zones::Version() >= 359) size += 968;
-		
+
 		bool result = Game::Load_Stream(atStreamStart, buffer, size);
 
 		// fix 4 byte difference in FF ver 460+ this turns 460+ into 423
@@ -2005,7 +2006,7 @@ namespace Components
 			std::memmove(buffer + 0x34, buffer + 0x38, size - 0x38);
 			AssetHandler::Relocate(buffer + 0x38, buffer + 0x34, size - 0x38);
 		}
-		
+
 		// fix 12 byte difference in FF ver 423+, this turns 423+ into 359
 		if (Zones::Version() >= 423)
 		{
@@ -2018,7 +2019,7 @@ namespace Components
 			std::memmove(buffer + 0x50 + 0x10, buffer + 0x50 + 0x1C, size - 0x6C);
 			AssetHandler::Relocate(buffer + 0x50 + 0x1C, buffer + 0x50 + 0x10, size - 0x6C);
 		}
-				
+
 		if (Zones::Version() >= 359)
 		{
 			int sunDiff = 8;	// Stuff that is part of the sunflare we would overwrite
@@ -2123,7 +2124,7 @@ namespace Components
 		{
 			return 19;
 		}
-		
+
 		if (Zones::Version() >= VERSION_ALPHA2)
 		{
 			return 16;
@@ -2257,7 +2258,7 @@ namespace Components
 			retn
 		}
 	}
-	
+
 	__declspec(naked) void Zones::GetCurrentAssetTypeStub()
 	{
 		__asm pushad;
@@ -2269,7 +2270,7 @@ namespace Components
 			// get asset type
 			mov eax, ds:0x112aa54
 			mov eax, [eax];
-			
+
 			// log asset type
 			// mov previousAssetType, currentAssetType;
 			mov currentAssetType, eax;
@@ -2294,10 +2295,10 @@ namespace Components
 		if (Zones::Version() >= 446)
 		{
 			for (auto i = 0; i < count; i++)
-			{	
+			{
 				std::memcpy(buffer + (48 * i) + 0, buffer + (64 * i) + 0, 24);
 				std::memcpy(buffer + (48 * i) + 24, buffer + (64 * i) + 32, 24);
-				
+
 				AssetHandler::Relocate(buffer + (64 * i) + 0, buffer + (48 * i) + 0, 24);
 				AssetHandler::Relocate(buffer + (64 * i) + 32, buffer + (48 * i) + 24, 24);
 			}
@@ -2308,14 +2309,14 @@ namespace Components
 
 	int currentGfxSurfaceIndex = 0;
 	std::vector<std::pair<int, int*>> gfxSurfaceExtraData;
-	
+
 	int Zones::LoadGfxXSurfaceArray(bool atStreamStart, char* buffer, int size)
 	{
 		currentGfxSurfaceIndex = 0;
 		gfxSurfaceExtraData.clear();
 
 		int count = 0;
-		
+
 		if (Zones::Version() >= 423)
 		{
 			size /= 40;
@@ -2369,7 +2370,7 @@ namespace Components
 	int Zones::LoadGfxReflectionProbes(bool atStreamStart, char* buffer, int size)
 	{
 		int count = 0;
-		
+
 		if (Zones::Version() >= 446)
 		{
 			size /= 12;
@@ -2385,7 +2386,7 @@ namespace Components
 			{
 				auto garbage = *reinterpret_cast<char**>(buffer + (20 * i) + 12);
 				auto garbage_count = *reinterpret_cast<int*>(buffer + (20 * i) + 16);
-				
+
 				if (garbage != nullptr)
 				{
 					garbage = Game::DB_AllocStreamPos(3);
@@ -2435,7 +2436,7 @@ namespace Components
 	__declspec(naked) void Zones::LoadXModelColSurfPtr()
 	{
 		static auto DB_ConvertOffsetToPointer_Address = 0x4A82B0;
-		
+
 		__asm
 		{
 			cmp dword ptr[eax], 0;
@@ -2535,7 +2536,7 @@ namespace Components
 
 	static Game::MapEnts codolMapEnts;
 	static Game::MapEnts* codolMapEntsPtr;
-	
+
 	int Zones::LoadMapEnts(bool atStreamStart, Game::MapEnts* buffer, int size)
 	{
 		if (Zones::Version() >= 446)
@@ -2556,16 +2557,16 @@ namespace Components
 
 		return Game::Load_Stream(atStreamStart, buffer, size);
 	}
-	
+
 	ClipInfo* varClipInfoPtr;
 	void Zones::Load_ClipInfo(bool atStreamStart)
 	{
 		AssertSize(ClipInfo, 64);
 		AssertSize(Game::cplane_s, 20);
 		AssertSize(Game::Bounds, 24);
-		
+
 		Game::Load_Stream(atStreamStart, varClipInfoPtr, sizeof ClipInfo);
-		
+
 		if (varClipInfoPtr->cPlanes)
 		{
 			if (varClipInfoPtr->cPlanes == reinterpret_cast<Game::cplane_s*>(0xFFFFFFFF))
@@ -2623,7 +2624,7 @@ namespace Components
 		if (varClipInfoPtr->cLeafBrushNodes)
 		{
 			if (varClipInfoPtr->cLeafBrushNodes == reinterpret_cast<Game::cLeafBrushNode_s*>(0xFFFFFFFF))
-			{			
+			{
 				varClipInfoPtr->cLeafBrushNodes = reinterpret_cast<Game::cLeafBrushNode_s*>(Game::DB_AllocStreamPos(3));
 				*reinterpret_cast<Game::cLeafBrushNode_s**>(0x112B130) = varClipInfoPtr->cLeafBrushNodes;
 				Utils::Hook::Call<void(bool, int)>(0x4C29D0)(true, varClipInfoPtr->numCLeafBrushNodes);
@@ -2692,13 +2693,13 @@ namespace Components
 			}
 		}
 	}
-	
+
 	int Zones::LoadClipMap(bool atStreamStart)
 	{
 		if (Zones::Version() >= 446)
-		{			
+		{
 			AssertOffset(codolClipMap_t, pInfo, 72);
-			
+
 			AssertSize(Game::cStaticModel_s, 76);
 			AssertOffset(codolClipMap_t, numStaticModels, 76);
 			AssertOffset(codolClipMap_t, staticModelList, 80);
@@ -2707,7 +2708,7 @@ namespace Components
 			Game::Load_Stream(atStreamStart, varClipMap, 256);
 
 			Game::DB_PushStreamPos(3);
-			
+
 			*Game::varXString = &varClipMap->name;
 			Game::Load_XString(false);
 
@@ -2715,12 +2716,12 @@ namespace Components
 			Load_ClipInfo(false);
 
 			Game::DB_PushStreamPos(0);
-			
+
 			varClipInfoPtr = varClipMap->pInfo;
 			ClipInfo** assetPointer = nullptr;
 			if (varClipMap->pInfo)
 			{
-				if (varClipMap->pInfo == reinterpret_cast<ClipInfo*>(0xFFFFFFFF) || 
+				if (varClipMap->pInfo == reinterpret_cast<ClipInfo*>(0xFFFFFFFF) ||
 					varClipMap->pInfo == reinterpret_cast<ClipInfo*>(0xFFFFFFFE))
 				{
 					const auto needsToAllocPointer = varClipMap->pInfo == reinterpret_cast<ClipInfo*>(0xFFFFFFFE);
@@ -2842,7 +2843,7 @@ namespace Components
 							}
 						}
 					}
-					
+
 					Game::DB_PopStreamPos();
 				}
 
@@ -2887,7 +2888,7 @@ namespace Components
 
 			AssertOffset(codolClipMap_t, dynEntCount[0], 196);
 			AssertOffset(codolClipMap_t, dynEntCount[1], 198);
-			
+
 			// dynamic entity shit
 			for (int i = 0; i < 2; i++)
 			{
@@ -2900,7 +2901,7 @@ namespace Components
 			}
 
 			Game::DB_PushStreamPos(2);
-			
+
 			for (int i = 0; i < 2; i++)
 			{
 				if (varClipMap->dynEntPoseList[i])
@@ -2927,7 +2928,7 @@ namespace Components
 			}
 
 			Game::DB_PopStreamPos();
-			
+
 			Game::DB_PopStreamPos();
 
 			auto codolMap = new codolClipMap_t;
@@ -2935,7 +2936,7 @@ namespace Components
 
 			auto cancerMap = reinterpret_cast<codolClipMap_t*>(varClipMap);
 			auto iw4Map = reinterpret_cast<Game::clipMap_t*>(varClipMap);
-			
+
 			memcpy(&iw4Map->planeCount, &codolMap->info.numCPlanes, 8);
 			memcpy(&iw4Map->numStaticModels, &codolMap->numStaticModels, 8);
 			memcpy(&iw4Map->numMaterials, &codolMap->info.numMaterials, 24);
@@ -2954,9 +2955,9 @@ namespace Components
 			AssetHandler::Relocate(&cancerMap->numVerts, &iw4Map->vertCount, 52);
 			AssetHandler::Relocate(&cancerMap->info.numBrushes, &iw4Map->numBrushes, 16);
 			AssetHandler::Relocate(&cancerMap->smodelNodeCount, &iw4Map->smodelNodeCount, 48);
-			
+
 			delete codolMap;
-			
+
 			return 1;
 		}
 		else
@@ -3027,13 +3028,13 @@ namespace Components
 
 	std::unordered_map<int, Zones::FileData> Zones::fileDataMap;
 	std::mutex Zones::fileDataMutex;
-	
+
 	__declspec(naked) int Zones::FS_FOpenFileReadForThreadOriginal(const char*, int*, int)
 	{
 		__asm
 		{
 			sub esp, 0x33C
-			
+
 			push 0x643276
 			ret
 		}
@@ -3060,7 +3061,7 @@ namespace Components
 			{
 				skipFile = true;
 			}
-			
+
 			// if the header seems encrypted...
 			if (fileBuffer.size() > 4 && readSize == retval && !skipFile)
 			{
@@ -3084,7 +3085,7 @@ namespace Components
 				register_cipher(&aes_desc);
 
 				auto aes = find_cipher("aes");
-		
+
 				// attempt to decrypt the IWI
 				symmetric_CTR ctr_state;
 				ZeroMemory(&ctr_state, sizeof(symmetric_CTR));
@@ -3095,12 +3096,12 @@ namespace Components
 
 				auto strippedFileName = std::filesystem::path(file).filename().string();
 				auto nonce = HashCRC32StringInt(strippedFileName, strippedFileName.size());
-				
+
 				std::uint8_t iv[16];
 				std::memset(iv, 0, sizeof iv);
 				std::memcpy(iv, &nonce, 4);
 				std::memcpy(iv + 4, &unpackedSize, 4);
-				
+
 				ctr_start(aes, reinterpret_cast<unsigned char*>(&aesIV[0]), &aesKey[0], sizeof aesKey, 0, CTR_COUNTER_BIG_ENDIAN, &ctr_state);
 
 				// decrypt image
@@ -3118,7 +3119,7 @@ namespace Components
 
 					readDataSize += blockSize;
 				}
-				
+
 				ctr_done(&ctr_state);
 
 				if (static_cast<std::uint8_t>(decryptedData[0]) == 0x78)
@@ -3145,7 +3146,7 @@ namespace Components
 			// un-read data, file is apparently not encrypted
 			Game::FS_Seek(*filePointer, 0, Game::FS_SEEK_SET);
 		}
-		
+
 		return retval;
 	}
 
@@ -3194,7 +3195,7 @@ namespace Components
 	void Zones::FS_FCloseFileHook(int filePointer)
 	{
 		std::lock_guard _(fileDataMutex);
-		
+
 		FS_FCloseFileOriginal(filePointer);
 
 		if (const auto itr = fileDataMap.find(filePointer); itr != fileDataMap.end())
@@ -3337,7 +3338,7 @@ namespace Components
 
 	void Zones::LoadFxWorldAsset(Game::FxWorld** asset)
 	{
-		Utils::Hook::Call<void(Game::FxWorld * *)>(0x4857F0)(asset);
+		Utils::Hook::Call<void(Game::FxWorld**)>(0x4857F0)(asset);
 
 		if (Zones::Version() >= 423 && asset && *asset)
 		{
@@ -3351,7 +3352,7 @@ namespace Components
 			memset(&glassMap, 0, sizeof Game::GameWorldMp);
 			memset(&glassData, 0, sizeof Game::G_GlassData);
 			glassPieces.clear();
-			
+
 			// generate glassPieces array
 			const auto pieceCount = (*asset)->glassSys.initPieceCount;
 			if (pieceCount > 0)
@@ -3399,7 +3400,7 @@ namespace Components
 			}
 		}
 
-		return Utils::Hook::Call<void(Game::XModel * *)>(0x47A690)(asset);
+		return Utils::Hook::Call<void(Game::XModel**)>(0x47A690)(asset);
 	}
 
 	// patch max file amount returned by Sys_ListFiles
@@ -3436,7 +3437,7 @@ namespace Components
 	}
 
 	void Zones::LoadTracerDef(bool atStreamStart, Game::TracerDef* tracer, int size)
-	{		
+	{
 		if (Zones::Version() >= 460)
 		{
 			size = 116;
@@ -3444,7 +3445,7 @@ namespace Components
 
 		Game::Load_Stream(atStreamStart, tracer, size);
 		*Game::varFxEffectDefHandle = nullptr;
-		
+
 		if (Zones::Version() >= 460)
 		{
 			*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(tracer + 8);
@@ -3460,10 +3461,10 @@ namespace Components
 		{
 			Game::Load_FxEffectDefHandle(false);
 		}
-		
+
 		Game::DB_PopStreamPos();
 	}
-	
+
 	char* Zones::ParseShellShock_Stub(const char** data_p)
 	{
 		auto token = Game::Com_Parse(data_p);
@@ -3479,71 +3480,74 @@ namespace Components
 	{
 		Zones::ZoneVersion = 0;
 
-		Command::Add("decryptImages", [](Command::Params*)
+		if (ZoneBuilder::IsEnabled())
 		{
-			auto images = FileSystem::GetSysFileList("iw4x/images", "iwi");
-			Logger::Print("decrypting {} images...\n", images.size());
-			
-			for (auto& image : images)
+			Command::Add("decryptImages", [](Command::Params*)
 			{
-				char* buffer = nullptr;
-				auto fileLength = Game::FS_ReadFile(Utils::String::VA("images/%s", image.data()), &buffer);
+				auto images = FileSystem::GetSysFileList("iw4x/images", "iwi");
+				Logger::Print("decrypting {} images...\n", images.size());
 
-				if (fileLength && buffer)
+				for (auto& image : images)
 				{
-					if (!std::filesystem::exists("raw/images"))
-					{
-						std::filesystem::create_directories("raw/images");
-					}
+					char* buffer = nullptr;
+					auto fileLength = Game::FS_ReadFile(Utils::String::Format("images/{}", image), &buffer);
 
-					if (!std::filesystem::exists(Utils::String::VA("raw/images/%s", image.data())))
+					if (fileLength && buffer)
 					{
-						const auto fp = fopen(Utils::String::VA("raw/images/%s", image.data()), "wb");
-						if (fp)
+						if (!std::filesystem::exists("raw/images"))
 						{
-							fwrite(buffer, fileLength, 1, fp);
-							fclose(fp);
+							std::filesystem::create_directories("raw/images");
 						}
+
+						if (!std::filesystem::exists(Utils::String::Format("raw/images/{}", image)))
+						{
+							const auto fp = fopen(Utils::String::Format("raw/images/{}", image), "wb");
+							if (fp)
+							{
+								fwrite(buffer, fileLength, 1, fp);
+								fclose(fp);
+							}
+						}
+
+						Game::FS_FreeFile(buffer);
 					}
-
-					Game::FS_FreeFile(buffer);
 				}
-			}
 
-			Logger::Print("decrypted {} images!\n", images.size());
-		});
+				Logger::Print("decrypted {} images!\n", images.size());
+			});
 
-		Command::Add("decryptSounds", []([[maybe_unused]] Command::Params* params)
-		{
-			auto sounds = FileSystem::GetSysFileList("iw4x/sound", "iwi");
-			Logger::Print("decrypting {} sounds...\n", sounds.size());
-
-			for (auto& sound : sounds)
+			Command::Add("decryptSounds", []([[maybe_unused]] Command::Params* params)
 			{
-				char* buffer = nullptr;
-				auto len = Game::FS_ReadFile(Utils::String::Format("sound/{}", sound), &buffer);
+				auto sounds = FileSystem::GetSysFileList("iw4x/sound", "iwi");
+				Logger::Print("decrypting {} sounds...\n", sounds.size());
 
-				if (len && buffer)
+				for (auto& sound : sounds)
 				{
-					auto path = std::filesystem::path(sound.data());
-					std::filesystem::create_directories("raw/sound" / path.parent_path());
+					char* buffer = nullptr;
+					auto len = Game::FS_ReadFile(Utils::String::Format("sound/{}", sound), &buffer);
 
-					if (!std::filesystem::exists(std::format("raw/sound/{}", sound)))
+					if (len && buffer)
 					{
-						FILE* fp;
-						if (!fopen_s(&fp, Utils::String::Format("raw/sound/{}", sound), "wb") && fp)
+						auto path = std::filesystem::path(sound.data());
+						std::filesystem::create_directories("raw/sound" / path.parent_path());
+
+						if (!std::filesystem::exists(std::format("raw/sound/{}", sound)))
 						{
-							fwrite(buffer, len, 1, fp);
-							fclose(fp);
+							FILE* fp;
+							if (!fopen_s(&fp, Utils::String::Format("raw/sound/{}", sound), "wb") && fp)
+							{
+								fwrite(buffer, len, 1, fp);
+								fclose(fp);
+							}
 						}
+
+						Game::FS_FreeFile(buffer);
 					}
-
-					Game::FS_FreeFile(buffer);
 				}
-			}
 
-			Logger::Print("decrypted {} sounds!\n", sounds.size());
-		});
+				Logger::Print("decrypted {} sounds!\n", sounds.size());
+			});
+		}
 
 		// patch max filecount Sys_ListFiles can return
 		Utils::Hook::Set<std::uint32_t>(0x45A66B, (maxFileCount + fileCountMultiplier) * 4);
@@ -3552,7 +3556,7 @@ namespace Components
 		Utils::Hook::Set<std::uint32_t>(0x45A8CE, maxFileCount);
 		Utils::Hook(0x45A806, RelocateFileCount, HOOK_CALL).install()->quick();
 		Utils::Hook(0x45A6A0, RelocateFileCount, HOOK_CALL).install()->quick();
-		
+
 #ifndef DEBUG
 		// Ignore missing soundaliases for now
 		// TODO: Include them in the dependency zone!
@@ -3566,11 +3570,14 @@ namespace Components
 		Utils::Hook::Set<BYTE>(0x418B31, 0x72);
 
 		// encrypted images hooks
-		Utils::Hook(0x462000, Zones::FS_FCloseFileHook, HOOK_JUMP).install()->quick();
-		Utils::Hook(0x4A04C0, Zones::FS_ReadHook, HOOK_JUMP).install()->quick();
-		Utils::Hook(0x643270, Zones::FS_FOpenFileReadForThreadHook, HOOK_JUMP).install()->quick();
-		Utils::Hook(0x4A63D0, Zones::FS_SeekHook, HOOK_JUMP).install()->quick();
-		
+		if (ZoneBuilder::IsEnabled())
+		{
+			Utils::Hook(0x462000, Zones::FS_FCloseFileHook, HOOK_JUMP).install()->quick();
+			Utils::Hook(0x4A04C0, Zones::FS_ReadHook, HOOK_JUMP).install()->quick();
+			Utils::Hook(0x643270, Zones::FS_FOpenFileReadForThreadHook, HOOK_JUMP).install()->quick();
+			Utils::Hook(0x4A63D0, Zones::FS_SeekHook, HOOK_JUMP).install()->quick();
+		}
+
 		// asset hooks
 		Utils::Hook(0x47146D, Zones::LoadTracerDef, HOOK_CALL).install()->quick();
 		Utils::Hook(0x4714A3, Zones::LoadTracerDefFxEffect, HOOK_JUMP).install()->quick();
@@ -3624,7 +3631,7 @@ namespace Components
 
 		Utils::Hook(0x4B4EA1, Zones::ParseShellShock_Stub, HOOK_CALL).install()->quick();
 		Utils::Hook(0x4B4F0C, Zones::ParseShellShock_Stub, HOOK_CALL).install()->quick();
-		
+
 		Utils::Hook(0x4F4D3B, []
 		{
 			if (Zones::ZoneVersion >= VERSION_ALPHA3)
@@ -3639,7 +3646,7 @@ namespace Components
 		}, HOOK_CALL).install()->quick();
 
 		// Change stream for images
-		Utils::Hook(0x4D3225, [] ()
+		Utils::Hook(0x4D3225, []()
 		{
 			Game::DB_PushStreamPos((Zones::ZoneVersion >= 332) ? 3 : 0);
 		}, HOOK_CALL).install()->quick();
@@ -3651,7 +3658,7 @@ namespace Components
 		// Easy dirty disk debugging
 		Utils::Hook::Set<WORD>(0x4CF7F0, 0xC3CC);
 		// disable _invoke_watson to allow debugging
-		Utils::Hook::Set<WORD>(0x6B9602,0xCCCC);
+		Utils::Hook::Set<WORD>(0x6B9602, 0xCCCC);
 #endif
 	}
 }
diff --git a/src/Utils/IO.cpp b/src/Utils/IO.cpp
index c8687e8b..e3606955 100644
--- a/src/Utils/IO.cpp
+++ b/src/Utils/IO.cpp
@@ -97,22 +97,22 @@ namespace Utils::IO
 		return std::filesystem::is_empty(directory);
 	}
 
-	std::vector<std::string> ListFiles(const std::filesystem::path& directory, const bool recursive)
+	std::vector<std::filesystem::directory_entry> ListFiles(const std::filesystem::path& directory, const bool recursive)
 	{
-		std::vector<std::string> files;
+		std::vector<std::filesystem::directory_entry> files;
 
 		if (recursive)
 		{
 			for (auto& file : std::filesystem::recursive_directory_iterator(directory))
 			{
-				files.push_back(file.path().generic_string());
+				files.push_back(file);
 			}
 		}
 		else
 		{
 			for (auto& file : std::filesystem::directory_iterator(directory))
 			{
-				files.push_back(file.path().generic_string());
+				files.push_back(file);
 			}
 		}
 
diff --git a/src/Utils/IO.hpp b/src/Utils/IO.hpp
index a0d4e39c..4d31ec31 100644
--- a/src/Utils/IO.hpp
+++ b/src/Utils/IO.hpp
@@ -11,5 +11,5 @@ namespace Utils::IO
 	bool CreateDir(const std::string& dir);
 	[[nodiscard]] bool DirectoryExists(const std::filesystem::path& directory);
 	[[nodiscard]] bool DirectoryIsEmpty(const std::filesystem::path& directory);
-	[[nodiscard]] std::vector<std::string> ListFiles(const std::filesystem::path& directory, bool recursive = false);
+	[[nodiscard]] std::vector<std::filesystem::directory_entry> ListFiles(const std::filesystem::path& directory, bool recursive = false);
 }
diff --git a/src/Utils/Thread.cpp b/src/Utils/Thread.cpp
index c6e5423c..70f81997 100644
--- a/src/Utils/Thread.cpp
+++ b/src/Utils/Thread.cpp
@@ -78,45 +78,4 @@ namespace Utils::Thread
 
 		return ids;
 	}
-
-	void ForEachThread(const std::function<void(HANDLE)>& callback)
-	{
-		const auto ids = GetThreadIds();
-
-		for (const auto& id : ids)
-		{
-			auto* const thread = OpenThread(THREAD_ALL_ACCESS, FALSE, id);
-			if (thread != nullptr)
-			{
-				const auto _ = gsl::finally([thread]()
-				{
-					CloseHandle(thread);
-				});
-
-				callback(thread);
-			}
-		}
-	}
-
-	void SuspendOtherThreads()
-	{
-		ForEachThread([](const HANDLE thread)
-		{
-			if (GetThreadId(thread) != GetCurrentThreadId())
-			{
-				SuspendThread(thread);
-			}
-		});
-	}
-
-	void ResumeOtherThreads()
-	{
-		ForEachThread([](const HANDLE thread)
-		{
-			if (GetThreadId(thread) != GetCurrentThreadId())
-			{
-				ResumeThread(thread);
-			}
-		});
-	}
 }
diff --git a/src/Utils/Thread.hpp b/src/Utils/Thread.hpp
index 084eb2ce..02e76277 100644
--- a/src/Utils/Thread.hpp
+++ b/src/Utils/Thread.hpp
@@ -16,8 +16,4 @@ namespace Utils::Thread
 	}
 
 	std::vector<DWORD> GetThreadIds();
-	void ForEachThread(const std::function<void(HANDLE)>& callback);
-
-	void SuspendOtherThreads();
-	void ResumeOtherThreads();
 }