Example #1
0
void CmdUnloadPlugin(const CCommandContext &context, const CCommand &command){
	if(command.ArgC() != 2){
		META_CONPRINT("Usage: js_unload [plugin_dir]\n");
		return;
	}

	auto pl = SMJS_Plugin::GetPluginByDir(command.Arg(1));
	if(pl == NULL){
		META_CONPRINTF("Plugin \"%s\" is not loaded!\n", command.Arg(1));
		return;
	}

	delete pl;
	META_CONPRINTF("Plugin \"%s\" unloaded successfully!\n", command.Arg(1));
}
Example #2
0
void CmdLoadPlugin(const CCommandContext &context, const CCommand &command){
	if(command.ArgC() != 2){
		META_CONPRINT("Usage: js_load [plugin_dir]\n");
		return;
	}

	auto pl = SMJS_Plugin::GetPluginByDir(command.Arg(1));
	if(pl != NULL){
		META_CONPRINTF("Plugin \"%s\" is already loaded!\n", command.Arg(1));
		return;
	}

	pl = LoadPlugin(command.Arg(1));
	if(pl == NULL){
		META_CONPRINTF("Plugin \"%s\" failed to load!\n", command.Arg(1));
	}else{
		META_CONPRINTF("Plugin \"%s\" loaded successfully!\n", command.Arg(1));
	}
}
	void ConnectOperation::RunThinkPart() {
		if(NULL == this->database) {
			this->callback->OnError(this->dbDriver, this->dbInfo, this->connectionError);
			return;
		}

		META_CONPRINTF("Got db...\n");

		this->callback->OnSuccess(this->dbDriver, this->dbInfo, this->database);
	}
void CEntityManager::PrintDump()
{
	META_CONPRINTF("=====================================\n");
	
	SourceHook::List<CEntity *> cent_list;

	CEntity *cent;
	int networked_count = 0;
	int non_networked_count = 0;
	for(int i=0;i<NUM_ENT_ENTRIES;i++)
	{
		cent = pEntityData[i];
		if(cent != NULL)
		{
			cent_list.push_back(cent);
			if(i < MAX_EDICTS)
				networked_count++;
			else
				non_networked_count++;
		}
	}

#ifdef _DEBUG
	META_CONPRINTF("CEntity Instance:\t\t%lld\n",CEntityManager::count);
#endif
	META_CONPRINTF("CEntity Factory:\t\t%d\n",pFactoryTrie.size());
	META_CONPRINTF("CEntity Swap:\t\t\t%d\n",pSwapTrie.size());
	META_CONPRINTF("CEntity Cache:\t\t\t%d\n",pCacheTrie.size());
	META_CONPRINTF("CEntity Hook:\t\t\t%d\n",pHookedTrie.size());
	META_CONPRINTF("CEntity Networked:\t\t%d\n",networked_count);
	META_CONPRINTF("CEntity Non Networked:\t\t%d\n",non_networked_count);
	META_CONPRINTF("CEntity Total:\t\t\t%d\n",networked_count+non_networked_count);

	char buffer[128];
	pFactoryTrie.bad_iterator(buffer,128, &cent_list,our_trie_iterator);

	cent_list.clear();
	META_CONPRINTF("=====================================\n");
}
void our_trie_iterator(KTrie<IEntityFactory_CE *> *pTrie, const char *name, IEntityFactory_CE *& obj, void *data)
{
	SourceHook::List<CEntity *> *cent_list = (SourceHook::List<CEntity *> *)data;
	int count = 0;
	SourceHook::List<CEntity *>::iterator _iter;
	CEntity *pInfo;
	for(_iter=cent_list->begin(); _iter!=cent_list->end(); _iter++)
	{
		pInfo = (*_iter);

		if(strcmp(name, pInfo->GetClassname()) == 0)
		{
			count++;
			continue;
		}
		IType *pType = GetType(pInfo->BaseEntity());
		IBaseType *pBase = pType->GetBaseType();

		do 
		{
			const char *classname = GetTypeName(pBase->GetTypeInfo());
			if(strcmp(classname, name) == 0)
			{
				count++;
			}
		} while (pBase->GetNumBaseClasses() && (pBase = pBase->GetBaseClass(0)));
		pType->Destroy();
	}

	if(strlen(name) < 7)
		META_CONPRINTF("%s:\t\t\t\t%d\n",name,count);
	else if(strlen(name) < 15)
		META_CONPRINTF("%s:\t\t\t%d\n",name,count);
	else if(strlen(name) < 23)
		META_CONPRINTF("%s:\t\t%d\n",name,count);
	else
		META_CONPRINTF("%s:\t%d\n",name,count);
}
Example #6
0
cell_t GetSendTableByNetclass(IPluginContext *pContext, const cell_t *params) {
	char *title;
	pContext->LocalToString(params[1], &title);

	ServerClass *sc = UTIL_FindServerClass(title);
	if (sc == NULL)
	{
		META_CONPRINTF("Could not open find netclass \"%s\"\n", title);
		return BAD_HANDLE;
	}

	return g_pHandleSys->CreateHandle(g_SendTableHandle,
		sc->m_pTable,
		pContext->GetIdentity(),
		myself->GetIdentity(),
		NULL);
}
void GlobalApprehensivePlugin::FireGameEvent(IGameEvent * event)
{
	if (event == NULL)
		return;
	std::string name(event->GetName());
	if (name == playerDeathEvent)
	{
		int attackerId = event->GetInt("attacker");
		std::string attackerName = GetPlayerName(attackerId);
		uint32 attackerAccountId = GetAccountID(attackerId);
		int assisterId = event->GetInt("assister");
		int victimId = event->GetInt("userid");
		std::string victimName = GetPlayerName(victimId);
		uint32 victimAccountId = GetAccountID(victimId);
		std::string attackerWeapon(event->GetString("weapon"));
		bool headshot = event->GetBool("headshot");
		META_CONPRINTF("%s (%d) killed %s (%d) with weapon %s\n", attackerName.c_str(), attackerAccountId, victimName.c_str(), victimAccountId, attackerWeapon.c_str());
	}
}
Example #8
0
void *ResolveDemangledSymbol(void* handle, const char* symbol, int& type, char* argsBuffer, unsigned int len) {
#ifdef PLATFORM_WINDOWS

	return GetProcAddress((HMODULE)handle, symbol);
	
#elif defined PLATFORM_LINUX

	struct link_map* dlmap;
	struct stat dlstat;
	int dlfile;
	uintptr_t map_base;
	Elf32_Ehdr* file_hdr;
	Elf32_Shdr* sections, * shstrtab_hdr, * symtab_hdr, * strtab_hdr;
	Elf32_Sym* symtab;
	const char* shstrtab, * strtab;
	uint16_t section_count;
	uint32_t symbol_count;
	LibSymbolTable* libtable;
	SymbolTable* table;
	Symbol* symbol_entry = NULL;

	dlmap = (struct link_map*)handle;
	symtab_hdr = NULL;
	strtab_hdr = NULL;
	table = NULL;
	
	/* See if we already have a symbol table for this library */
	/*for (size_t i = 0; i < m_SymTables.size(); i++)
	{
		libtable = m_SymTables[i];
		if (libtable->lib_base == dlmap->l_addr)
		{
			table = &libtable->table;
			break;
		}
	}*/

	/* If we don't have a symbol table for this library, then create one */
	if (table == NULL)
	{
		libtable = new LibSymbolTable();
		libtable->table.Initialize();
		libtable->lib_base = dlmap->l_addr;
		libtable->last_pos = 0;
		table = &libtable->table;
		m_SymTables.push_back(libtable);
	}

	// TODO Make this work with demangled symbols ?
	/* See if the symbol is already cached in our table */
	/*symbol_entry = table->FindSymbol(symbol, strlen(symbol));
	if (symbol_entry != NULL)
	{
		return symbol_entry->address;
	}*/

	/* If symbol isn't in our table, then we have open the actual library */
	dlfile = open(dlmap->l_name, O_RDONLY);
	if (dlfile == -1 || fstat(dlfile, &dlstat) == -1)
	{
		close(dlfile);
		return NULL;
	}

	/* Map library file into memory */
	file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
	map_base = (uintptr_t)file_hdr;
	if (file_hdr == MAP_FAILED)
	{
		close(dlfile);
		return NULL;
	}
	close(dlfile);

	if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF)
	{
		munmap(file_hdr, dlstat.st_size);
		return NULL;
	}

	sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff);
	section_count = file_hdr->e_shnum;
	/* Get ELF section header string table */
	shstrtab_hdr = &sections[file_hdr->e_shstrndx];
	shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset);

	/* Iterate sections while looking for ELF symbol table and string table */
	for (uint16_t i = 0; i < section_count; i++)
	{
		Elf32_Shdr &hdr = sections[i];
		const char *section_name = shstrtab + hdr.sh_name;

		if (strcmp(section_name, ".symtab") == 0)
		{
			symtab_hdr = &hdr;
		}
		else if (strcmp(section_name, ".strtab") == 0)
		{
			strtab_hdr = &hdr;
		}
	}

	/* Uh oh, we don't have a symbol table or a string table */
	if (symtab_hdr == NULL || strtab_hdr == NULL)
	{
		munmap(file_hdr, dlstat.st_size);
		return NULL;
	}

	symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset);
	strtab = (const char *)(map_base + strtab_hdr->sh_offset);
	symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;

	/* Iterate symbol table starting from the position we were at last time */
	for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
	{
		Elf32_Sym& sym = symtab[i];
		unsigned char sym_type = ELF32_ST_TYPE(sym.st_info);
		const char* sym_name = strtab + sym.st_name;
		Symbol* cur_sym;

		/* Skip symbols that are undefined or do not refer to functions or objects */
		if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT))
		{
			continue;
		}

		char *name_demangled = NULL;
		int status;
		size_t length = 0;
		name_demangled = abi::__cxa_demangle(sym_name, NULL, &length, &status);

		if (status != 0) {
			continue;
		}

		//META_CONPRINTF("[MASTERHOOK] Checkpoint: 1\n");
		//META_CONPRINTF("[MASTERHOOK] Checkpoint: 1.1 \"%s\"\n", name_demangled);
		//META_CONPRINTF("[MASTERHOOK] Checkpoint: 1.2\n");

		char* brace_open = NULL;
		if (sym_type == STT_FUNC && strrchr(symbol, '(')  == NULL) { // Is Function and passed symbol doesn't have an arglist

			// Let's strip off the arglist as we don't want to compare with that
			brace_open = strrchr(name_demangled, '(');

			if (brace_open != NULL) {
				brace_open[0] = '\0';
			}
		}

		/* Caching symbols as we go along */
		cur_sym = table->InternSymbol(name_demangled, strlen(name_demangled), (void *)(dlmap->l_addr + sym.st_value));
		if (strcmp(name_demangled, symbol) == 0) {

			if (brace_open != NULL) {
				char* brace_close = strrchr(brace_open+1, ')');

				if (brace_close != NULL) {
					brace_close[0] = '\0';
				}

				if (length > strlen(brace_open+1)) {
					brace_close[len] = '\0';
				}
				//META_CONPRINTF("[MASTERHOOK] Checkpoint: 2 \"%s\" d:%d\n", brace_open+1, len);
				memmove(argsBuffer, brace_open+1, len);
				argsBuffer[len] = '\0';
			}

			symbol_entry = cur_sym;
			libtable->last_pos = ++i;
			type = STT_FUNC;
			free(name_demangled);
			break;
		}

		//META_CONPRINTF("[MASTERHOOK] Checkpoint: 3 \"%s\"\n", name_demangled);
		free(name_demangled);
		//META_CONPRINTF("[MASTERHOOK] Checkpoint: 4\n");
	}
#ifdef DEBUG
	//META_CONPRINTF("[MASTERHOOK] Checkpoint: 5 - End of Symbol Table\n");
#endif

	munmap(file_hdr, dlstat.st_size);
#ifdef DEBUG
	META_CONPRINTF("[MASTERHOOK] type: %d\n", type);
#endif
	return symbol_entry ? symbol_entry->address : NULL;

#elif defined PLATFORM_APPLE
	
	uintptr_t dlbase, linkedit_addr;
	uint32_t image_count;
	struct mach_header *file_hdr;
	struct load_command *loadcmds;
	struct segment_command *linkedit_hdr;
	struct symtab_command *symtab_hdr;
	struct nlist *symtab;
	const char *strtab;
	uint32_t loadcmd_count;
	uint32_t symbol_count;
	LibSymbolTable *libtable;
	SymbolTable *table;
	Symbol *symbol_entry;
	
	dlbase = 0;
	image_count = m_ImageList->infoArrayCount;
	linkedit_hdr = NULL;
	symtab_hdr = NULL;
	table = NULL;
	
	/* Loop through mach-o images in process.
	 * We can skip index 0 since that is just the executable.
	 */
	for (uint32_t i = 1; i < image_count; i++)
	{
		const struct dyld_image_info &info = m_ImageList->infoArray[i];
		
		/* "Load" each one until we get a matching handle */
		void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
		if (h == handle)
		{
			dlbase = (uintptr_t)info.imageLoadAddress;
			dlclose(h);
			break;
		}
		
		dlclose(h);
	}
	
	if (!dlbase)
	{
		/* Uh oh, we couldn't find a matching handle */
		return NULL;
	}
	
	/* See if we already have a symbol table for this library */
	for (size_t i = 0; i < m_SymTables.size(); i++)
	{
		libtable = m_SymTables[i];
		if (libtable->lib_base == dlbase)
		{
			table = &libtable->table;
			break;
		}
	}
	
	/* If we don't have a symbol table for this library, then create one */
	if (table == NULL)
	{
		libtable = new LibSymbolTable();
		libtable->table.Initialize();
		libtable->lib_base = dlbase;
		libtable->last_pos = 0;
		table = &libtable->table;
		m_SymTables.push_back(libtable);
	}
	
	/* See if the symbol is already cached in our table */
	symbol_entry = table->FindSymbol(symbol, strlen(symbol));
	if (symbol_entry != NULL)
	{
		return symbol_entry->address;
	}
	
	/* If symbol isn't in our table, then we have to locate it in memory */
	
	file_hdr = (struct mach_header *)dlbase;
	loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
	loadcmd_count = file_hdr->ncmds;
	
	/* Loop through load commands until we find the ones for the symbol table */
	for (uint32_t i = 0; i < loadcmd_count; i++)
	{
		if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
		{
			struct segment_command *seg = (struct segment_command *)loadcmds;
			if (strcmp(seg->segname, "__LINKEDIT") == 0)
			{
				linkedit_hdr = seg;
				if (symtab_hdr)
				{
					break;
				}
			}
		}
		else if (loadcmds->cmd == LC_SYMTAB)
		{
			symtab_hdr = (struct symtab_command *)loadcmds;
			if (linkedit_hdr)
			{
				break;
			}
		}

		/* Load commands are not of a fixed size which is why we add the size */
		loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
	}
	
	if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
	{
		/* Uh oh, no symbol table */
		return NULL;
	}

	linkedit_addr = dlbase + linkedit_hdr->vmaddr;
	symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
	strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
	symbol_count = symtab_hdr->nsyms;
	
	/* Iterate symbol table starting from the position we were at last time */
	for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
	{
		struct nlist &sym = symtab[i];
		/* Ignore the prepended underscore on all symbols, so +1 here */
		const char *sym_name = strtab + sym.n_un.n_strx + 1;
		Symbol *cur_sym;
		
		/* Skip symbols that are undefined */
		if (sym.n_sect == NO_SECT)
		{
			continue;
		}
		
		/* Caching symbols as we go along */
		cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
		if (strcmp(symbol, sym_name) == 0)
		{
			symbol_entry = cur_sym;
			libtable->last_pos = ++i;
			break;
		}
	}
	
	return symbol_entry ? symbol_entry->address : NULL;

#endif
}
Example #9
0
/* Given Elf header, Elf_Scn, and Elf32_Shdr 
 * print out the symbol table 
 */
void *GetSymbolAdress(const char *filename, const char *symbol) {

#ifdef PLATFORM_POSIX

	int fd;
	Elf *elf;
	GElf_Ehdr elfhdr;

	if (elf_version(EV_CURRENT) == EV_NONE) {
		META_CONPRINTF("ELF library is out of date, Quitting\n");
	}

	fd = open(filename, O_RDONLY);
	if (fd < 0) {
		META_CONPRINTF("[Masterhook] Unable to open \"%s\"\n", filename);
	}

	elf = elf_begin(fd, ELF_C_READ, NULL);
	if (gelf_getehdr(elf, &elfhdr) == 0)	{
		META_CONPRINTF("Cannot read elf header. This usually means that %s is not a valid elf file\n", filename);
	}

	Elf_Scn* section = 0;
	Elf32_Shdr *shdr = NULL;
	bool symtabFound = false;
	while ((section = elf_nextscn(elf, section)) != 0) {
		if ((shdr = elf32_getshdr (section)) != 0) {
			if (shdr->sh_type == SHT_SYMTAB) {
				symtabFound = true;
				break;
			}
		}
	}

	if (shdr == NULL || !symtabFound) {
		return NULL;
	}

	Elf_Scn *scn = section;

	Elf_Data *data;
	char *name;
	data = 0;
	int number = 0;
	if ((data = elf_getdata(scn, data)) == 0 || data->d_size == 0){
		META_CONPRINTF("Section had no data!\n");
		return NULL;
	}

	Elf32_Sym *esym = (Elf32_Sym*) data->d_buf;
	Elf32_Sym *lastsym = (Elf32_Sym*) ((char*) data->d_buf + data->d_size);
	for (; esym < lastsym; esym++) {
		if ((esym->st_value == 0) || (ELF32_ST_BIND(esym->st_info) == STB_WEAK) || (ELF32_ST_BIND(esym->st_info) == STB_NUM) || (ELF32_ST_TYPE(esym->st_info) != STT_FUNC)) {
			continue;
		}

		name = elf_strptr(elf, shdr->sh_link , (size_t)esym->st_name);
		if(!name){
			META_CONPRINTF("%s\n", elf_errmsg(elf_errno()));
			return NULL;
		}

		char *name_demangled = 0;
		int* status;
		name_demangled = abi::__cxa_demangle(name, 0, 0, status);

		#ifdef DEBUG
		META_CONPRINTF("%d: Name: %s == %s Address: 0x%x\n", number++, name_demangled, symbol, esym->st_value);
#endif

		if (name_demangled != NULL) {
			if (strstr(name_demangled, symbol)) {
				return (void*)esym->st_value;
			}
		}

		//free(name_demangled);
	}
#endif

	return NULL;
}
	INavMesh *NavMeshLoader::Load(char *error, int errorMaxlen) {
		strcpy_s(error, errorMaxlen, "");

		char navPath[1024];
		g_pSM->BuildPath(Path_Game, navPath, sizeof(navPath), "maps\\%s.nav", this->mapName);

		FILE *fileHandle = fopen(navPath, "rb");

		if(!fileHandle) {
			sprintf_s(error, errorMaxlen, "Unable to find navigation mesh: %s", navPath);
			return NULL;
		}

		unsigned int magicNumber;
		int elementsRead = this->ReadData(&magicNumber, sizeof(unsigned int), 1, fileHandle);

		if(elementsRead != 1) {
			fclose(fileHandle);
			sprintf_s(error, errorMaxlen, "Error reading magic number value from navigation mesh: %s", navPath);
			return NULL;
		}

		if(magicNumber != 0xFEEDFACE) {
			fclose(fileHandle);
			sprintf_s(error, errorMaxlen, "Invalid magic number value from navigation mesh: %s [%p]", navPath, magicNumber);
			return NULL;
		}

		unsigned int version;
		elementsRead = this->ReadData(&version, sizeof(unsigned int), 1, fileHandle);

		if(elementsRead != 1) {
			fclose(fileHandle);
			sprintf_s(error, errorMaxlen, "Error reading version number from navigation mesh: %s", navPath);
			return NULL;
		}

		if (version < 6 || version > 16) {
			fclose(fileHandle);
			sprintf_s(error, errorMaxlen, "Invalid version number value from navigation mesh: %s [%d]", navPath, version);
			return NULL;
		}

		unsigned int navMeshSubVersion = 0;

		if(version >= 10) {
			this->ReadData(&navMeshSubVersion, sizeof(unsigned int), 1, fileHandle);
		}

		unsigned int saveBspSize;
		this->ReadData(&saveBspSize, sizeof(unsigned int), 1, fileHandle);

		char bspPath[1024];
		g_pSM->BuildPath(Path_Game, bspPath, sizeof(bspPath), "maps\\%s.bsp", this->mapName);

		unsigned int actualBspSize = 0;

#ifdef PLATFORM_WINDOWS
		struct _stat s;
		_stat(bspPath, &s);
		actualBspSize = s.st_size;
#elif defined PLATFORM_POSIX
		struct stat s;
		stat(bspPath, &s);
		actualBspSize = s.st_size;
#endif

		if(actualBspSize != saveBspSize) {
			META_CONPRINTF("WARNING: Navigation mesh was not built with the same version of the map [%d vs %d].\n", actualBspSize, saveBspSize);
		}

		unsigned char meshAnalyzed = 0;

		if(version >= 14) {
			this->ReadData(&meshAnalyzed, sizeof(unsigned char), 1, fileHandle);
		}

		bool isMeshAnalyzed = meshAnalyzed != 0;

		//META_CONPRINTF("Is mesh analyzed: %s\n", isMeshAnalyzed ? "yes" : "no");

		unsigned short placeCount;
		this->ReadData(&placeCount, sizeof(unsigned short), 1, fileHandle);

		//META_CONPRINTF("Nav version: %d; BSPSize: %d; MagicNumber: %p; SubVersion: %d [v10+only]; Place Count: %d\n", version, saveBspSize, magicNumber, navMeshSubVersion, placeCount);
		
		List<INavMeshPlace*> *places = new List<INavMeshPlace*>();

		for(unsigned int placeIndex = 0; placeIndex < placeCount; placeIndex++) {
			unsigned short placeSize;

			this->ReadData(&placeSize, sizeof(unsigned short), 1, fileHandle);

			char placeName[256];
			this->ReadData(placeName, sizeof(unsigned char), placeSize, fileHandle);

			places->Append(new NavMeshPlace(placeIndex, placeName));
			//META_CONPRINTF("Parsed place: %s [%d]\n", placeName, placeIndex);
		}

		unsigned char unnamedAreas = 0;
		if(version > 11) {
			this->ReadData(&unnamedAreas, sizeof(unsigned char), 1, fileHandle);
		}

		bool hasUnnamedAreas = unnamedAreas != 0;

		//META_CONPRINTF("Has unnamed areas: %s\n", hasUnnamedAreas ? "yes" : "no");

		IList<INavMeshArea*> *areas = new List<INavMeshArea*>();

		unsigned int areaCount;
		this->ReadData(&areaCount, sizeof(unsigned int), 1, fileHandle);

		//META_CONPRINTF("Area count: %d\n", areaCount);

		for(unsigned int areaIndex = 0; areaIndex < areaCount; areaIndex++) {
			unsigned int areaID;
			float x1, y1, z1, x2, y2, z2;
			unsigned int areaFlags = 0;
			IList<INavMeshConnection*> *connections = new List<INavMeshConnection*>();
			IList<INavMeshHidingSpot*> *hidingSpots = new List<INavMeshHidingSpot*>();
			IList<INavMeshEncounterPath*> *encounterPaths = new List<INavMeshEncounterPath*>();
			IList<INavMeshLadderConnection*> *ladderConnections = new List<INavMeshLadderConnection*>();
			IList<INavMeshCornerLightIntensity*> *cornerLightIntensities = new List<INavMeshCornerLightIntensity*>();
			IList<INavMeshVisibleArea*> *visibleAreas = new List<INavMeshVisibleArea*>();
			unsigned int inheritVisibilityFrom = 0;
			unsigned char hidingSpotCount = 0;
			unsigned int visibleAreaCount = 0;
			float earliestOccupyTimeFirstTeam = 0.0f;
			float earliestOccupyTimeSecondTeam = 0.0f;
			float northEastCornerZ;
			float southWestCornerZ;
			unsigned short placeID = 0;
			unsigned char unk01 = 0;

			this->ReadData(&areaID, sizeof(unsigned int), 1, fileHandle);

			//META_CONPRINTF("Area ID: %d\n", areaID);

			if(version <= 8) {
				this->ReadData(&areaFlags, sizeof(unsigned char), 1, fileHandle);
			}
			else if(version < 13) {
				this->ReadData(&areaFlags, sizeof(unsigned short), 1, fileHandle);
			}
			else {
				this->ReadData(&areaFlags, sizeof(unsigned int), 1, fileHandle);
			}

			//META_CONPRINTF("Area Flags: %d\n", areaFlags);
			this->ReadData(&x1, sizeof(float), 1, fileHandle);
			this->ReadData(&y1, sizeof(float), 1, fileHandle);
			this->ReadData(&z1, sizeof(float), 1, fileHandle);
			this->ReadData(&x2, sizeof(float), 1, fileHandle);
			this->ReadData(&y2, sizeof(float), 1, fileHandle);
			this->ReadData(&z2, sizeof(float), 1, fileHandle);

			//META_CONPRINTF("Area extent: (%f, %f, %f), (%f, %f, %f)\n", x1, y1, z1, x2, y2, z2);

			this->ReadData(&northEastCornerZ, sizeof(float), 1, fileHandle);
			this->ReadData(&southWestCornerZ, sizeof(float), 1, fileHandle);

			//META_CONPRINTF("Corners: NW(%f), SW(%f)\n", northEastCornerZ, southWestCornerZ);

			// CheckWaterLevel() are we underwater in this area?

			for(unsigned int direction = 0; direction < NAV_DIR_COUNT; direction++) {
				unsigned int connectionCount;
				this->ReadData(&connectionCount, sizeof(unsigned int), 1, fileHandle);

				//META_CONPRINTF("Connection count: %d (%p)\n", connectionCount, connectionCount);

				for(int connectionIndex = 0; connectionIndex < connectionCount; connectionIndex++) {
					unsigned int connectingAreaID;
					this->ReadData(&connectingAreaID, sizeof(unsigned int), 1, fileHandle);

					INavMeshConnection *connection = new NavMeshConnection(connectingAreaID, (NavDirType)direction);
					connections->Append(connection);
				}
			}

			this->ReadData(&hidingSpotCount, sizeof(unsigned char), 1, fileHandle);
			//META_CONPRINTF("Hiding Spot Count: %d\n", hidingSpotCount);

			for(unsigned int hidingSpotIndex = 0; hidingSpotIndex < hidingSpotCount; hidingSpotIndex++) {
				unsigned int hidingSpotID;
				this->ReadData(&hidingSpotID, sizeof(unsigned int), 1, fileHandle);

				float hidingSpotX, hidingSpotY, hidingSpotZ;
				this->ReadData(&hidingSpotX, sizeof(float), 1, fileHandle);
				this->ReadData(&hidingSpotY, sizeof(float), 1, fileHandle);
				this->ReadData(&hidingSpotZ, sizeof(float), 1, fileHandle);

				unsigned char hidingSpotFlags;
				this->ReadData(&hidingSpotFlags, sizeof(unsigned char), 1, fileHandle);

				INavMeshHidingSpot *hidingSpot = new NavMeshHidingSpot(hidingSpotID, hidingSpotX, hidingSpotY, hidingSpotZ, hidingSpotFlags);
				hidingSpots->Append(hidingSpot);
				//META_CONPRINTF("Parsed hiding spot (%f, %f, %f) with ID [%p] and flags [%p]\n", hidingSpotX, hidingSpotY, hidingSpotZ, hidingSpotID, hidingSpotFlags);
			}

			// These are old but we just need to read the data.
			if(version < 15) {
				unsigned char approachAreaCount;
				this->ReadData(&approachAreaCount, sizeof(unsigned char), 1, fileHandle);

				for(unsigned int approachAreaIndex = 0; approachAreaIndex < approachAreaCount; approachAreaIndex++) {
					unsigned int approachHereID;
					this->ReadData(&approachHereID, sizeof(unsigned int), 1, fileHandle);
					
					unsigned int approachPrevID;
					this->ReadData(&approachPrevID, sizeof(unsigned int), 1, fileHandle);

					unsigned char approachType;
					this->ReadData(&approachType, sizeof(unsigned char), 1, fileHandle);

					unsigned int approachNextID;
					this->ReadData(&approachNextID, sizeof(unsigned int), 1, fileHandle);

					unsigned char approachHow;
					this->ReadData(&approachHow, sizeof(unsigned char), 1, fileHandle);
				}
			}

			unsigned int encounterPathCount;
			this->ReadData(&encounterPathCount, sizeof(unsigned int), 1, fileHandle);
			//META_CONPRINTF("Encounter Path Count: %d\n", encounterPathCount);

			for(unsigned int encounterPathIndex = 0; encounterPathIndex < encounterPathCount; encounterPathIndex++) {
				unsigned int encounterFromID;
				this->ReadData(&encounterFromID, sizeof(unsigned int), 1, fileHandle);

				unsigned char encounterFromDirection;
				this->ReadData(&encounterFromDirection, sizeof(unsigned char), 1, fileHandle);

				unsigned int encounterToID;
				this->ReadData(&encounterToID, sizeof(unsigned int), 1, fileHandle);

				unsigned char encounterToDirection;
				this->ReadData(&encounterToDirection, sizeof(unsigned char), 1, fileHandle);

				unsigned char encounterSpotCount;
				this->ReadData(&encounterSpotCount, sizeof(unsigned char), 1, fileHandle);
	
				//META_CONPRINTF("Encounter [from ID %d] [from dir %p] [to ID %d] [to dir %p] [spot count %d]\n", encounterFromID, encounterFromDirection, encounterToID, encounterToDirection, encounterSpotCount);
				IList<INavMeshEncounterSpot*> *encounterSpots = new List<INavMeshEncounterSpot*>();

				for(int encounterSpotIndex = 0; encounterSpotIndex < encounterSpotCount; encounterSpotIndex++) {
					unsigned int encounterSpotOrderId;
					this->ReadData(&encounterSpotOrderId, sizeof(unsigned int), 1, fileHandle);

					unsigned char encounterSpotT;
					this->ReadData(&encounterSpotT, sizeof(unsigned char), 1, fileHandle);

					float encounterSpotParametricDistance = (float)encounterSpotT / 255.0f;

					INavMeshEncounterSpot *encounterSpot = new NavMeshEncounterSpot(encounterSpotOrderId, encounterSpotParametricDistance);
					encounterSpots->Append(encounterSpot);
					//META_CONPRINTF("Encounter spot [order id %d] and [T %p]\n", encounterSpotOrderId, encounterSpotT);
				}

				INavMeshEncounterPath *encounterPath = new NavMeshEncounterPath(encounterFromID, (NavDirType)encounterFromDirection, encounterToID, (NavDirType)encounterToDirection, encounterSpots);
				encounterPaths->Append(encounterPath);
			}

			this->ReadData(&placeID, sizeof(unsigned short), 1, fileHandle);

			//META_CONPRINTF("Place ID: %d\n", placeID);

			for(unsigned int ladderDirection = 0; ladderDirection < NAV_LADDER_DIR_COUNT; ladderDirection++) {
				unsigned int ladderConnectionCount;
				this->ReadData(&ladderConnectionCount, sizeof(unsigned int), 1, fileHandle);

				//META_CONPRINTF("Ladder Connection Count: %d\n", ladderConnectionCount);

				for(unsigned int ladderConnectionIndex = 0; ladderConnectionIndex < ladderConnectionCount; ladderConnectionIndex++) {
					unsigned int ladderConnectID;
					this->ReadData(&ladderConnectID, sizeof(unsigned int), 1, fileHandle);
					
					INavMeshLadderConnection *ladderConnection = new NavMeshLadderConnection(ladderConnectID, (NavLadderDirType)ladderDirection);
					ladderConnections->Append(ladderConnection);
					//META_CONPRINTF("Parsed ladder connect [ID %d]\n", ladderConnectID);
				}
			}

			this->ReadData(&earliestOccupyTimeFirstTeam, sizeof(float), 1, fileHandle);
			this->ReadData(&earliestOccupyTimeSecondTeam, sizeof(float), 1, fileHandle);

			if(version >= 11) {
				for (int navCornerIndex = 0; navCornerIndex < NAV_CORNER_COUNT; navCornerIndex++) {
    				float navCornerLightIntensity;
					this->ReadData(&navCornerLightIntensity, sizeof(float), 1, fileHandle);

					INavMeshCornerLightIntensity *cornerLightIntensity = new NavMeshCornerLightIntensity((NavCornerType)navCornerIndex, navCornerLightIntensity);
					cornerLightIntensities->Append(cornerLightIntensity);
					//META_CONPRINTF("Light intensity: [%f] [idx %d]\n", navCornerLightIntensity, navCornerIndex);
		 		}

				if(version >= 16) {
					this->ReadData(&visibleAreaCount, sizeof(unsigned int), 1, fileHandle);

					//META_CONPRINTF("Visible area count: %d\n", visibleAreaCount);

					for(unsigned int visibleAreaIndex = 0; visibleAreaIndex < visibleAreaCount; visibleAreaIndex++) {
						unsigned int visibleAreaID;
						this->ReadData(&visibleAreaID, sizeof(unsigned int), 1, fileHandle);

						unsigned char visibleAreaAttributes;
						this->ReadData(&visibleAreaAttributes, sizeof(unsigned char), 1, fileHandle);

						INavMeshVisibleArea *visibleArea = new NavMeshVisibleArea(visibleAreaID, visibleAreaAttributes);
						visibleAreas->Append(visibleArea);
						//META_CONPRINTF("Parsed visible area [%d] with attr [%p]\n", visibleAreaID, visibleAreaAttributes);
					}

					this->ReadData(&inheritVisibilityFrom, sizeof(unsigned int), 1, fileHandle);

					//META_CONPRINTF("Inherit visibilty from: %d\n", inheritVisibilityFrom);

					this->ReadData(&unk01, sizeof(unsigned char), 1, fileHandle);
				}
			}

			INavMeshArea *area = new NavMeshArea(areaID, areaFlags, placeID, x1, y1, z1, x2, y2, z2,
				northEastCornerZ, southWestCornerZ, connections, hidingSpots, encounterPaths, ladderConnections,
				cornerLightIntensities, visibleAreas, inheritVisibilityFrom, earliestOccupyTimeFirstTeam, earliestOccupyTimeSecondTeam, unk01);

			areas->Append(area);
		}

		unsigned int ladderCount;
		this->ReadData(&ladderCount, sizeof(unsigned int), 1, fileHandle);
		
		//META_CONPRINTF("Ladder count: %d\n", ladderCount);
		IList<INavMeshLadder*> *ladders = new List<INavMeshLadder*>();

		for(unsigned int ladderIndex = 0; ladderIndex < ladderCount; ladderIndex++) {
			unsigned int ladderID;
			this->ReadData(&ladderID, sizeof(unsigned int), 1, fileHandle);

			float ladderWidth;
			this->ReadData(&ladderWidth, sizeof(float), 1, fileHandle);
			
			float ladderTopX, ladderTopY, ladderTopZ, ladderBottomX, ladderBottomY, ladderBottomZ;

			this->ReadData(&ladderTopX, sizeof(float), 1, fileHandle);
			this->ReadData(&ladderTopY, sizeof(float), 1, fileHandle);
			this->ReadData(&ladderTopZ, sizeof(float), 1, fileHandle);
			this->ReadData(&ladderBottomX, sizeof(float), 1, fileHandle);
			this->ReadData(&ladderBottomY, sizeof(float), 1, fileHandle);
			this->ReadData(&ladderBottomZ, sizeof(float), 1, fileHandle);

			float ladderLength;
			this->ReadData(&ladderLength, sizeof(float), 1, fileHandle);
			
			unsigned int ladderDirection;
			this->ReadData(&ladderDirection, sizeof(unsigned int), 1, fileHandle);

			unsigned int ladderTopForwardAreaID;
			this->ReadData(&ladderTopForwardAreaID, sizeof(unsigned int), 1, fileHandle);

			unsigned int ladderTopLeftAreaID;
			this->ReadData(&ladderTopLeftAreaID, sizeof(unsigned int), 1, fileHandle);

			unsigned int ladderTopRightAreaID;
			this->ReadData(&ladderTopRightAreaID, sizeof(unsigned int), 1, fileHandle);
			
			unsigned int ladderTopBehindAreaID;
			this->ReadData(&ladderTopBehindAreaID, sizeof(unsigned int), 1, fileHandle);

			unsigned int ladderBottomAreaID;
			this->ReadData(&ladderBottomAreaID, sizeof(unsigned int), 1, fileHandle);
			
			INavMeshLadder *ladder = new NavMeshLadder(ladderID, ladderWidth, ladderLength, ladderTopX, ladderTopY, ladderTopZ,
				ladderBottomX, ladderBottomY, ladderBottomZ, (NavDirType)ladderDirection,
				ladderTopForwardAreaID, ladderTopLeftAreaID, ladderTopRightAreaID, ladderTopBehindAreaID, ladderBottomAreaID);

			ladders->Append(ladder);
		}

		fclose(fileHandle);
		INavMesh *mesh = new NavMesh(magicNumber, version, navMeshSubVersion, saveBspSize, isMeshAnalyzed, places, areas, ladders);

		return mesh;
	}