Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

UnrealStormLib

Unreal Engine plugin wrapping StormLib for reading Blizzard MPQ archives.

StormLib itself is not modified beyond what's needed to compile as a UE module (source reorganized into Public/Private, two files renamed to dodge symbol collisions between its own bundled zlib/bzip2/pklib copies, one build-only warning suppressed). All credit for the actual MPQ implementation goes to Ladislav Zezula and StormLib's contributors.

Installation

Clone or download this repo into your project's Plugins/ folder, or grab a prebuilt version from releases.

Adding the dependency

In your module's .Build.cs:

PrivateDependencyModuleNames.Add("UnrealStormLib");

Then #include "StormLib.h" - that's the real upstream API header, unrenamed, so StormLib's own docs and examples apply directly.

Usage example

Opening an MPQ and reading a file by its internal path:

#include "StormLib.h"

bool ReadFileFromMpq(const FString& MpqPath, const FString& InternalFilePath, TArray<uint8>& OutData)
{
	HANDLE MpqHandle = nullptr;
	if (!SFileOpenArchive(*MpqPath, 0, MPQ_OPEN_READ_ONLY, &MpqHandle))
	{
		return false;
	}

	bool bOk = false;
	HANDLE FileHandle = nullptr;
	if (SFileOpenFileEx(MpqHandle, TCHAR_TO_ANSI(*InternalFilePath), 0, &FileHandle))
	{
		const DWORD Size = SFileGetFileSize(FileHandle, nullptr);
		if (Size != SFILE_INVALID_SIZE && Size > 0)
		{
			OutData.SetNumUninitialized(static_cast<int32>(Size));
			DWORD BytesRead = 0;
			SFileReadFile(FileHandle, OutData.GetData(), Size, &BytesRead, nullptr);
			bOk = OutData.Num() > 0;
		}
		SFileCloseFile(FileHandle);
	}

	SFileCloseArchive(MpqHandle);
	return bOk;
}

Opening a whole Data/ folder's worth of patch MPQs stacked in priority order (patches first, so later opens override earlier ones on file lookup):

TArray<FString> MpqPaths;
IFileManager::Get().FindFilesRecursive(MpqPaths, *DataDir, TEXT("*.mpq"), true, false, false);
// sort MpqPaths so patches / patch-2 / locale come before base archives, per your game's patch chain

TArray<HANDLE> MpqHandles;
for (const FString& Path : MpqPaths)
{
	HANDLE ArchHandle = nullptr;
	if (SFileOpenArchive(*Path, 0, MPQ_OPEN_READ_ONLY, &ArchHandle))
	{
		MpqHandles.Add(ArchHandle);
	}
}

// Try each open handle in order; first hit wins (patches shadow base files).
TArray<uint8> FileData;
for (HANDLE Handle : MpqHandles)
{
	HANDLE FileHandle = nullptr;
	if (!SFileOpenFileEx(Handle, "World\\Maps\\Azeroth\\Azeroth_32_48.adt", 0, &FileHandle))
	{
		continue;
	}

	const DWORD Size = SFileGetFileSize(FileHandle, nullptr);
	if (Size != SFILE_INVALID_SIZE && Size > 0)
	{
		FileData.SetNumUninitialized(static_cast<int32>(Size));
		DWORD BytesRead = 0;
		SFileReadFile(FileHandle, FileData.GetData(), Size, &BytesRead, nullptr);
	}

	SFileCloseFile(FileHandle);
	break;
}

About

Unreal Engine plugin wrapping StormLib for reading Blizzard MPQ archives.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages