Skip to content

Converted LeonBlade's xnbcil to a library for browsers for ES6 modules.

License

Notifications You must be signed in to change notification settings

lybell-art/xnb-js

Repository files navigation

xnb.js

xnb.js is the javascript library that allows you to handle xnb files on the web or in a node.js environment.

Description

The xnb format is a compressed data format used by Microsoft XNA Game Studio and is known for its use in games such as the Stardew Valley. xnb.js allows xnb files to be handled on the web without installing any other programs, making it easy to create utility web app or programs, for games using xnb files. Currently, xnb decompression has been fully implemented, and due to the absence of an open-source JavaScript library that implements the LZX compression algorithm, packing returns uncompressed or compressed xnb files with the lz4 compression algorithm.

Based on LeonBlade's XnbCli, xnb.js is rewritten some code dedicated to node.js into universal code regardless of environment. All credits to LeonBlade.

Try this!

Web XNB Previewer : https://lybell-art.github.io/xnb-js

Install

You can install xnb.js with npm, or download the library directly and upload it to your own web server or use the existing CDN without a build system. I recommend that you load xnb.js using the es6 module.

cdn

You can load and use a library hosted online. Here's how to use it:

Load as ES6 Module(Recommended)

import * as XNB from "https://cdn.jsdelivr.net/npm/xnb@1.3.0/dist/xnb.module.js";

Load as UMD

<script src="https://cdn.jsdelivr.net/npm/xnb@1.3.0/dist/xnb.min.js"></script>

If you need to support ES5, such as IE11, I recommend using xnb.es5.min.js.

npm

npm install xnb

There's no default export. You can use it like this:

import * as XNB from 'xnb';

Examples

Browsers example

Load and unpack the xnb file, and show the result as image.

import { unpackToContent } from "xnb";
let previewUrl="";
const outputImageCanvas = document.getElementById("output");

document.getElementById("input").addEventListener("change", 
function handleFiles()
{
	if(!this.files || this.files.length === 0) return;
	// read file
	const file=this.files[0];

	// unpack xnb file as contents
	unpackToContent(file).then(function(content){
		// check content's type, and make blob url
		if(content.type === "png")
		{
			window.URL.revokeObjectURL(previewUrl);
			previewUrl = window.URL.createObjectURL(content.content);
			outputImageCanvas.src = previewUrl;
		}
	});
});

Node.js example

Load and unpack the xnb file, and save the results as files.

import { unpackToFiles } from "xnb";
import { readFile } from 'node:fs/promises';

readFile("./Abigail.xnb") // read xnb file as Buffer
.then(xnb=>unpackToFiles(xnb, {fileName:"Abigail.xnb"})) // unpack xnb file
.then(outputs=>{
	// save data to outputs folder
	const writers = [];
	for(let {data, extension} of outputs)
	{
		const writePath = path.resolve("./outputs", `Abigail.${extension}`);
		writers.push(writeFile(writePath, data));
	}
	return Promise.all(writers);
});

API

See this link.

Customs

After 1.1 update, you can load and use only a portion of the existing readers, or you can add a custom reader to use it. After 1.3 update, we bring up a file that specifies the type structure of data to be imported into the custom scheme and suggest how to unpack the easier custom data structure.

Load only part of existing readers

import * as XNB from "@xnb-js/core";
import { LightweightTexture2DReader as Texture2DReader } from "@xnb-js/readers";

XNB.setReaders({Texture2DReader});

xnb.unpackToXnbData(file);

Add custom plugins

import * as XNB from "xnb";

// Your class must inherit the basereader, and the class name must end with "Reader".
class CustomReader extends XNB.readers.BaseReader{
	static isTypeOf(type) {
		// The name of the reader or data type used in the XNA game studio. 
		// Returns true or false if you want the name to be read from this reader.
	}
	static hasSubType() {
		// Returns if the data type this reader will read has sub-types. 
		// For example, array, list, and dictionary have sub-types.
	}
	static parseTypeList() {
		// Used to insert type data in the process of converting a json file to a yaml file.
		// Return the array in the order in which the sub-readers are actually used.
	}
	static type()
	{
		// Simplified data type. In default, returns the first part except Reader.
		// If the class name differs from the actual simplified data type name, it should returns that of actual.
	}
	isValueType() {
		// Returns true if the data type is primitive data type.
	}
	get type() {
		// Returns string type of reader.
	}
	read(buffer, resolver) {
		// Reads the buffer by the specification of the type reader.
	}
	write(buffer, content, resolver) {
		// Writes into the buffer.
	}
	parseTypeList() {
		// for have sub-types readers
		// Used to insert type data in the process of converting a json file to a yaml file.
		// Return the array in the order in which the sub-readers are actually used.
	}
}

XNB.addReaders({CustomReader});

...

Add custom scheme

Custom scheme is a data structure which defines the c# class that the reflective reader reads, and has the following grammar;

const myScheme =  {
	DisplayName: "String", // Specify the field name of the custom class with key, and data type with value.
	$Description: "String", // You can add $ prefix to express nullable field.
	IsDebuff: "Boolean",
	IconSpriteIndex: "Int32",
	$Effects: "StardewValley.GameData.Buffs.BuffAttributesData", //  If you are fetching another custom class, please write the full name of the C# class.
	$ActionsOnApply: ["String"], // [] means a List type.
	$CustomFields: {"String": "String"} // {} means a Dictionary type.
}
XNB.addSchemes({"StardewValley.GameData.Buffs.BuffData": myScheme}); // The key value contains the full name of reflected c# class.

External resource

xnb.js contains dxt.js, lz4.js, and png.js as bundle. libsquish(=dxt.js) and lz4.js were rewritten for es6 module system. The licenses for the original libraries are as follows.

Library Source Code License
dxt.js(Libsquish) https://sourceforge.net/projects/libsquish/ MIT License
LZ4-js https://github.com/pierrec/node-lz4 MIT License
png.js https://github.com/lukeapage/pngjs MIT License

License

GNU LGPL 3.0

Other language

About

Converted LeonBlade's xnbcil to a library for browsers for ES6 modules.

Resources

License

Stars

Watchers

Forks

Packages

No packages published