Skip to content

Instantly share code, notes, and snippets.

@barncastle
Created August 10, 2022 16:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save barncastle/addb4287d9e8a6b50e5ba48c0ab931dc to your computer and use it in GitHub Desktop.
Save barncastle/addb4287d9e8a6b50e5ba48c0ab931dc to your computer and use it in GitHub Desktop.
Core functions for reading War For Kingship's BIN files
var PackageItemType;
(function (PackageItemType) {
PackageItemType[PackageItemType["Image"] = 0] = "Image";
PackageItemType[PackageItemType["MovieClip"] = 1] = "MovieClip";
PackageItemType[PackageItemType["Sound"] = 2] = "Sound";
PackageItemType[PackageItemType["Component"] = 3] = "Component";
PackageItemType[PackageItemType["Atlas"] = 4] = "Atlas";
PackageItemType[PackageItemType["Font"] = 5] = "Font";
PackageItemType[PackageItemType["Swf"] = 6] = "Swf";
PackageItemType[PackageItemType["Misc"] = 7] = "Misc";
PackageItemType[PackageItemType["Unknown"] = 8] = "Unknown";
})(PackageItemType = {});
var ObjectType;
(function (ObjectType) {
ObjectType[ObjectType["Image"] = 0] = "Image";
ObjectType[ObjectType["MovieClip"] = 1] = "MovieClip";
ObjectType[ObjectType["Swf"] = 2] = "Swf";
ObjectType[ObjectType["Graph"] = 3] = "Graph";
ObjectType[ObjectType["Loader"] = 4] = "Loader";
ObjectType[ObjectType["Group"] = 5] = "Group";
ObjectType[ObjectType["Text"] = 6] = "Text";
ObjectType[ObjectType["RichText"] = 7] = "RichText";
ObjectType[ObjectType["InputText"] = 8] = "InputText";
ObjectType[ObjectType["Component"] = 9] = "Component";
ObjectType[ObjectType["List"] = 10] = "List";
ObjectType[ObjectType["Label"] = 11] = "Label";
ObjectType[ObjectType["Button"] = 12] = "Button";
ObjectType[ObjectType["ComboBox"] = 13] = "ComboBox";
ObjectType[ObjectType["ProgressBar"] = 14] = "ProgressBar";
ObjectType[ObjectType["Slider"] = 15] = "Slider";
ObjectType[ObjectType["ScrollBar"] = 16] = "ScrollBar";
ObjectType[ObjectType["Tree"] = 17] = "Tree";
})(ObjectType = {});
class UIPackage {
constructor() {
this.id = null;
this.name = null;
this._resKey = null; // internal name e.g. FightView
this._items = new Array();
this._itemsById = {};
this._itemsByName = {};
this._sprites = {};
this._dependencies = new Array();
this._branches = new Array();
this._branchIndex = -1;
}
}
class PackageItem {
constructor(_owner) {
this.owner = _owner;
this.type = null;
this.id = null;
this.name = null;
this.file = null;
this.objectType = -1;
this.width = 0;
this.height = 0;
this.tileGridIndice = 0;
this.interval = 0;
this.repeatDelay = 0;
this.scaleByTile = false;
this.smoothing = false;
this.rawData = null;
this.pixelHitTestData = null; // PixelHitTestData
this.scale9Grid = null; // Rectangle
}
}
class PixelHitTestData {
constructor() {
this.pixelWidth = 0;
this.scale = 1;
this.pixels = [];
}
}
class AtlasSprite() {
constructor() {
this.rect = new Rectangle();
this.offset = new Point();
this.originalSize = new Point();
this.atlas = null; // PackageItem
this.rotated = false;
}
}
class Rectangle {
constructor() {
this.x = 0;
this.y = 0;
this.width = 0;
this.height = 0;
}
}
class Point {
constructor() {
this.x = 0;
this.y = 0;
}
}
UIPackage.prototype.loadPackage = function (buffer) {
if (buffer.readUnsignedInt() != 0x46475549)
throw "FairyGUI: old package format found";
// read header
buffer.version = buffer.readInt();
var compressed = buffer.readBool();
this._id = buffer.readUTF();
this._name = buffer.readUTF();
buffer.position += 20; // skip
// zlib decompress if required
if (compressed) {
var buf = new Uint8Array(buffer.buffer, buffer.position, buffer.length - buffer.position);
var inflater = new Zlib.RawInflate(buf);
var buffer2 = new ByteBuffer(inflater.decompress());
buffer2.version = buffer.version;
buffer = buffer2;
}
var cnt, i;
var fileNamePrefix = this._resKey + "_";
// the index table is a byte count, bool useShort and ushort/uint array struct
// each value is an offset to a specific block of data or 0 if unused
// -- see ByteBuffer.seek --
var indexTablePos = buffer.position;
// block 4 - string table
buffer.seek(indexTablePos, 4);
cnt = buffer.readInt();
buffer.stringTable = new Array(cnt);
for (i = 0; i < cnt; i++)
buffer.stringTable[i] = buffer.readUTF();
// block 0 - dependancies and branches
buffer.seek(indexTablePos, 0);
cnt = buffer.readShort();
for (i = 0; i < cnt; i++)
this._dependencies.push({ id: buffer.readS(), name: buffer.readS() });
if (buffer.version >= 2) {
cnt = buffer.readShort();
this._branches = buffer.readSArray(cnt);
}
// block 1 - PackageItems
buffer.seek(indexTablePos, 1);
cnt = buffer.readShort();
for (i = 0; i < cnt; i++) {
var nextPos = buffer.readInt() + buffer.position;
var pi = new PackageItem(this);
pi.type = buffer.readByte();
pi.id = buffer.readS();
pi.name = buffer.readS();
buffer.readS(); // deprecated
pi.file = buffer.readS();
buffer.readBool(); // deprecated
pi.width = buffer.readInt();
pi.height = buffer.readInt();
switch (pi.type) {
case PackageItemType.Image:
{
pi.objectType = ObjectType.Image;
var scaleOption = buffer.readByte();
if (scaleOption == 1) {
pi.scale9Grid = new Rectangle();
pi.scale9Grid.x = buffer.readInt();
pi.scale9Grid.y = buffer.readInt();
pi.scale9Grid.width = buffer.readInt();
pi.scale9Grid.height = buffer.readInt();
pi.tileGridIndice = buffer.readInt();
}
else if (scaleOption == 2) {
pi.scaleByTile = true;
}
pi.smoothing = buffer.readBool();
break;
}
case PackageItemType.MovieClip:
{
pi.objectType = ObjectType.MovieClip;
pi.smoothing = buffer.readBool();
pi.rawData = buffer.readBuffer();
break;
}
case PackageItemType.Font:
{
pi.rawData = buffer.readBuffer();
break;
}
case PackageItemType.Component:
{
var extension = buffer.readByte();
pi.objectType = extension || ObjectType.Component;
pi.rawData = buffer.readBuffer();
break;
}
case PackageItemType.Atlas:
case PackageItemType.Sound:
case PackageItemType.Misc:
{
pi.file = fileNamePrefix + getFileName(pi.file);
break;
}
}
if (buffer.version >= 2) {
var str = buffer.readS();
if (str)
pi.name = str + "/" + pi.name;
var branchCnt = buffer.readUnsignedByte();
if (branchCnt > 0) {
if (this._branches.Length > 0)
pi.branches = buffer.readSArray(branchCnt);
else
this._itemsById[buffer.readS()] = pi;
}
var highResCnt = buffer.readUnsignedByte();
pi.highResolution = buffer.readSArray(highResCnt);
}
this._items.push(pi);
this._itemsById[pi.id] = pi;
if (pi.name != null)
this._itemsByName[pi.name] = pi;
buffer.position = nextPos;
}
// block 2 - sprites
buffer.seek(indexTablePos, 2);
cnt = buffer.readShort();
for (i = 0; i < cnt; i++) {
var nextPos = buffer.readShort() + buffer.position;
var itemId = buffer.readS();
var sprite = new AtlasSprite();
sprite.atlas = this._itemsById[buffer.readS()];
sprite.rect.x = buffer.readInt();
sprite.rect.y = buffer.readInt();
sprite.rect.width = buffer.readInt();
sprite.rect.height = buffer.readInt();
sprite.rotated = buffer.readBool();
if (buffer.version >= 2 && buffer.readBool()) {
sprite.offset.x = buffer.readInt();
sprite.offset.y = buffer.readInt();
sprite.originalSize.x = buffer.readInt();
sprite.originalSize.y = buffer.readInt();
}
else {
sprite.originalSize.x = sprite.rect.width;
sprite.originalSize.y = sprite.rect.height;
}
this._sprites[itemId] = sprite;
buffer.position = nextPos;
}
// block 3 (optional) - HitTestData for Image items
if (buffer.seek(indexTablePos, 3)) {
cnt = buffer.readShort();
for (i = 0; i < cnt; i++) {
var nextPos = buffer.readInt() + buffer.position;
var pi = this._itemsById[buffer.readS()];
if (pi && pi.type == PackageItemType.Image) {
pi.pixelHitTestData = new PixelHitTestData();
pi.pixelHitTestData.load(buffer);
}
buffer.position = nextPos;
}
}
};
PixelHitTestData.prototype.load = function (buffer) {
buffer.readInt(); // deprecated
this.pixelWidth = buffer.readInt();
this.scale = 1 / buffer.readByte();
this.pixels = [];
var len = buffer.readInt();
for (var i = 0; i < len; i++) {
this.pixels[i] = buffer.readByte() & 0xFF; // unsigned cast
}
};
function getFileName(source) {
var i = source.lastIndexOf("/");
if (i != -1)
source = source.substr(i + 1);
i = source.lastIndexOf("\\");
if (i != -1)
source = source.substr(i + 1);
i = source.lastIndexOf(".");
if (i != -1)
return source.substring(0, i);
return source;
};
class ByteBuffer extends egret.ByteArray {
constructor(buffer, bufferExtSize) {
super(this, buffer, bufferExtSize);
this.stringTable = null;
this.version = 0;
}
readBool() {
return this.readByte() == 1;
}
readS() {
var index = this.readUnsignedShort();
if (index == 0xFFFE)
return null;
if (index == 0xFFFD)
return "";
return this.stringTable[index];
}
readSArray(cnt) {
var ret = new Array(cnt);
for (var i = 0; i < cnt; i++)
ret[i] = this.readS();
return ret;
}
readBuffer() {
var count = this.readUnsignedInt(); // new buffer byte size
var ba = new ByteBuffer(new Uint8Array(this.buffer, this.position, count));
ba.stringTable = this.stringTable;
ba.version = this.version;
this.position += count;
return ba;
}
seek(indexTablePos, blockIndex) {
var tmp = this.position;
this.position = indexTablePos;
var segCount = this.readByte();
var useShort = this.readBool();
var newPos = 0;
if (blockIndex < segCount) {
if (useShort) {
this.position += 2 * blockIndex;
newPos = this.readUnsignedShort();
}
else {
this.position += 4 * blockIndex;
newPos = this.readUnsignedInt();
}
}
if (newPos > 0) {
this.position = indexTablePos + newPos;
return true;
} else {
this.position = tmp;
return false;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment