lamb-mp-decoder
v1.0.0
Published
A TypeScript library for decoding Lamb MP format
Downloads
11
Maintainers
Readme
Lamb MP Decoder
A TypeScript library for decoding Lamb MP format (and older formats).
🚀 Demo
Check out the live demo: https://matthewmmorrow.github.io/lamb-mp-decoder/
📦 Installation
npm install lamb-mp-decoder📖 Usage
The decoder must be able to decrypt using AES-CBC and decompress using LZ4 blocks (not frames). Since these might vary depending on the deployment environment the LambMPDecoder constructor requires functions for these operations to be provided. Works with both slot_#.mp and meta_#.mp files.
Example browser-based usage
import { LambMPDecoder } from 'lamb-mp-decoder';
import * as lz4 from '@addmaple/lz4/inline';
// Decrypt using built-in Crypto utilities
async function decrypt(key: ArrayBuffer, iv: ArrayBuffer, input: ArrayBuffer): Promise {
const algorithm = { name: "AES-CBC", iv: iv };
const cryptoKey = await window.crypto.subtle.importKey(
"raw",
key,
{ name: "AES-CBC" },
false,
["decrypt"]
);
const decrypted = await window.crypto.subtle.decrypt(algorithm, cryptoKey, input);
return decrypted;
}
// Decompress using @addmaple/lz4 library
async function decompress(input: Uint8Array, originalSize: number): Promise {
return (lz4 as any).decompressBlock(input, originalSize);
}
// Create decoder instance
const decoder = new LambMPDecoder({
decrypt,
decompress
});
// Read the save file from an ArrayBuffer (loaded elsewhere)
const result = await decoder.readSave(fileContent);🔧 API
LambMPDecoder
Class-based decoder.
Constructor
Requires a Utilties object with the necessary operations.
interface Utilities {
decompress: (input: Uint8Array, originalSize: number) => Promise<Uint8Array>; // LZ4 block decompression
decrypt: (key: ArrayBuffer, iv: ArrayBuffer, data: ArrayBuffer) => Promise<ArrayBuffer>; // AES-CBC decryption
}Methods
readSave(encryptedData: ArrayBuffer): Promise<SaveData>- Read the data from the raw input
interface SaveData {
type: SaveType; // How the original data was formatted. Might determine which fields are available in the output.
data: any; // The decoded data as an object
}Technical details
Reading
The original Cult of the Lamb save file was a normal JSON file.
In the second version, the .JSON file was encrypted using AES-CBC. The first byte of the file was marked as E for encrypted. The next 16 bytes represent the key and the next 16 bytes after that are the IV. This can be used to decrypt the remain bytes into a standard JSON string.
With the release of Woolhaven, the file format has been changed to a .MP file. This contains encrypted MessagePack data. MessagePack is a binary format consisting of just a series of data type codes and the data bytes. Since Cult of the Lamb is built in Unity, the C# version of MessagePack is used to encode the data. This brings a further complication since it can also LZ4 compress the data, which is not a standard feature, adding manual work in non-C# environments like the browser. The MessagePack object produced by the library consists of an extension type 98 representing the uncompressed lengths of the following byte arrays. These arrays can be manually decompressed using LZ4 block decompressiong. This provides another encoded MessagePack object which can then be decoded. Finally, any keys and data structure must be recontituted on the raw resulting data types.
Writing
In theory, the same steps for reading the file should be reversable to writing the file. This poses risks as any error could cause subtle issues in the game. There are no plans to support this and is outside the scope of this package.
🛠️ Development
# Install dependencies
npm install
# Build the library
npm run build
# Build and serve demo
npm run demo:dev
# Watch mode for development
npm run watch📄 License
MIT
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
