はじめに
LZ4に正式対応し, Pak File Compression Format(s)
で指定できるように思えますが, そんなことはないです.
原因
FCompression::IsFormatValid
が原因と思われます. コメントからすると, 不具合のように見えます.
bool FCompression::IsFormatValid(FName FormatName)
{
// build in formats are always valid
if (FormatName == NAME_Zlib || FormatName == NAME_Gzip)
{
return true;
}
// otherwise, if we can get the format class, we are good!
return GetCompressionFormat(FormatName, false) != nullptr;
}
圧縮形式
zlibのチェックサム計算も軽くはないことに注意です.
- zlib
- 圧縮率と速度のバランスが良いが, 今では旧い, zstandardを代わりに使うべき
- checksumは必ず計算する
- ZStandard
- 圧縮率と速度のバランスが良い
- checksumはオプション
- LZ4
- 圧縮・伸張速度に重点を置いたもの
- LZSSだけなので上記2つより圧縮率は低い
- 圧縮に時間をかけても, 伸張速度はほとんど変わらない
- checksumはオプション
- 圧縮・伸張速度に重点を置いたもの
- Lizard
- LZ5を名乗る, LZ4を改良したと主張している
PakのLZ4圧縮
FCompression
を書き換えることは影響範囲を考えてやりたくないです. エンジンのプラグインを書きます.
UnrealPak
は独立したプログラムのため, 単純なエディタ拡張ではUnrealPak
から見えません.
LZ4CompressionFormat.cpp
#include "LZ4Compression.h"
#include "CoreMinimal.h"
#include "Misc/Compression.h"
#include "Misc/ICompressionFormat.h"
#define LOCTEXT_NAMESPACE "FLZ4CompressionModule"
namespace
{
DEFINE_LOG_CATEGORY_STATIC(LogLZ4CompressionFormat, Log, All);
struct LZ4CompressionFormat : public ICompressionFormat
{
FName GetCompressionFormatName() override;
bool Compress(void* CompressedBuffer, int32& CompressedSize, const void* UncompressedBuffer, int32 UncompressedSize, int32 CompressionData) override;
bool Uncompress(void* UncompressedBuffer, int32& UncompressedSize, const void* CompressedBuffer, int32 CompressedSize, int32 CompressionData) override;
int32 GetCompressedBufferSize(int32 UncompressedSize, int32 CompressionData) override;
uint32 GetVersion() override;
FString GetDDCKeySuffix() override;
};
FName LZ4CompressionFormat::GetCompressionFormatName()
{
return "lz4";
}
bool LZ4CompressionFormat::Compress(void* CompressedBuffer, int32& CompressedSize, const void* UncompressedBuffer, int32 UncompressedSize, int32 CompressionData)
{
UE_LOG(LogLZ4CompressionFormat, Warning, TEXT("Compress"));
if(!FCompression::CompressMemory(NAME_LZ4, CompressedBuffer, CompressedSize, UncompressedBuffer, UncompressedSize, COMPRESS_NoFlags, CompressionData)) {
UE_LOG(LogLZ4CompressionFormat, Warning, TEXT("Faile to compress"));
return false;
}
return true;
}
bool LZ4CompressionFormat::Uncompress(void* UncompressedBuffer, int32& UncompressedSize, const void* CompressedBuffer, int32 CompressedSize, int32 CompressionData)
{
UE_LOG(LogLZ4CompressionFormat, Warning, TEXT("Uncompress"));
if(!FCompression::UncompressMemory(NAME_LZ4, UncompressedBuffer, UncompressedSize, CompressedBuffer, CompressedSize, COMPRESS_NoFlags, CompressionData)) {
UE_LOG(LogLZ4CompressionFormat, Warning, TEXT("Faile to uncompress"));
return false;
}
return true;
}
int32 LZ4CompressionFormat::GetCompressedBufferSize(int32 UncompressedSize, int32 CompressionData)
{
return FCompression::CompressMemoryBound(NAME_LZ4, UncompressedSize, COMPRESS_NoFlags, CompressionData);
}
uint32 LZ4CompressionFormat::GetVersion()
{
return FCompression::GetCompressorVersion(NAME_LZ4);
}
FString LZ4CompressionFormat::GetDDCKeySuffix()
{
static const FString suffix = "2AEE7CBB0BD24E71B0D516ECE2AB68C1";
return suffix;
}
} // namespace
FLZ4CompressionModule::FLZ4CompressionModule()
: compressionFormat_(nullptr)
{
}
FLZ4CompressionModule::~FLZ4CompressionModule()
{
delete compressionFormat_;
}
void FLZ4CompressionModule::StartupModule()
{
compressionFormat_ = new LZ4CompressionFormat();
IModularFeatures::Get().RegisterModularFeature(COMPRESSION_FORMAT_FEATURE_NAME, compressionFormat_);
}
void FLZ4CompressionModule::ShutdownModule()
{
IModularFeatures::Get().UnregisterModularFeature(COMPRESSION_FORMAT_FEATURE_NAME, compressionFormat_);
delete compressionFormat_;
compressionFormat_ = nullptr;
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FLZ4CompressionModule, LZ4Compression)
まとめ
今回は, Pak File Compression Format(s)
にlz4
を書けばLZ4圧縮になるはずです. これを応用すれば好きなフォーマットにできるはずです.