mirror of
https://github.com/billsonnn/nitro-converter.git
synced 2024-11-26 09:20:51 +01:00
Weird swf reading...
This commit is contained in:
parent
6349a4f0d2
commit
9e983a0e21
@ -1,6 +1,6 @@
|
||||
output.folder.furniture=/home/user/WebstormProjects/sites/assets.nitro.se/game/dcr/furniture/
|
||||
output.folder.figure=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/figure/
|
||||
output.folder.effect=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/effect/
|
||||
output.folder.effect=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/effect-test/
|
||||
output.folder.pet=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/pet/
|
||||
furnidata.url=http://assets.nitro.se/game/gamedata/furnidata-entry.xml
|
||||
figuremap.url=http://assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/figuremap.xml
|
||||
@ -10,9 +10,9 @@ dynamic.download.url.furniture=/home/user/WebstormProjects/sites/assets.nitro.se
|
||||
dynamic.download.url.figure=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf
|
||||
dynamic.download.url.effect=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf
|
||||
dynamic.download.url.pet=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf
|
||||
convert.furniture=0
|
||||
convert.furniture=1
|
||||
convert.figure=0
|
||||
convert.effect=1
|
||||
convert.pet=1
|
||||
convert.effect=0
|
||||
convert.pet=0
|
||||
figure.rotation.enabled=0
|
||||
figure.skip.non-existing.asset.images=0
|
8
package-lock.json
generated
8
package-lock.json
generated
@ -4,6 +4,14 @@
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@gizeta/swf-reader": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@gizeta/swf-reader/-/swf-reader-1.0.0.tgz",
|
||||
"integrity": "sha1-34Huyh7J7miWax2Tbd/iH5Hp3IM=",
|
||||
"requires": {
|
||||
"lzma-purejs": "~0.9.3"
|
||||
}
|
||||
},
|
||||
"@jvitela/mustache-wax": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@jvitela/mustache-wax/-/mustache-wax-1.0.3.tgz",
|
||||
|
@ -9,6 +9,7 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@gizeta/swf-reader": "^1.0.0",
|
||||
"@types/node": "^14.14.22",
|
||||
"bytebuffer": "^5.0.1",
|
||||
"free-tex-packer-core": "^0.3.2",
|
||||
|
@ -108,15 +108,15 @@ import PetConverter from "./converters/pet/PetConverter";
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log("Effect error: " + habboAssetSwf.getDocumentClass());
|
||||
console.log("Pet error: " + habboAssetSwf.getDocumentClass());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log('finished!');
|
||||
|
||||
/*
|
||||
outputFolderFurniture.rmdir({
|
||||
|
||||
/*outputFolderEffect.rmdir({
|
||||
recursive: true,
|
||||
force: true
|
||||
});*/
|
||||
|
@ -10,7 +10,7 @@ export default class Configuration {
|
||||
}
|
||||
|
||||
async init() {
|
||||
const content = await fs.readFile("/home/user/git/nitro-asset-converter-node/config.ini");
|
||||
const content = await fs.readFile("/home/user/git/nitro-asset-converter-node (copy)/config.ini");
|
||||
|
||||
this.parseContent(content.toString("utf-8"));
|
||||
}
|
||||
|
@ -55,7 +55,6 @@ export default class SpriteSheetConverter {
|
||||
contents: imageTag.imgData
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (images.length === 0) {
|
||||
|
@ -44,12 +44,11 @@ export default class EffectDownloader {
|
||||
}
|
||||
|
||||
try {
|
||||
const buffer: Buffer = await readFile(url);
|
||||
const habboAssetSWF = new HabboAssetSWF(buffer);
|
||||
await habboAssetSWF.setupAsync();
|
||||
const newHabboAssetSWF: HabboAssetSWF = new HabboAssetSWF(url);
|
||||
await newHabboAssetSWF.setupAsync();
|
||||
|
||||
EffectDownloader.types.set(className, info.type);
|
||||
await callback(habboAssetSWF);
|
||||
await callback(newHabboAssetSWF);
|
||||
} catch (e) {
|
||||
console.log(className);
|
||||
console.log(e);
|
||||
|
@ -48,12 +48,11 @@ export default class FigureDownloader {
|
||||
return;
|
||||
}
|
||||
|
||||
const buffer: Buffer = await readFile(url);
|
||||
const habboAssetSWF = new HabboAssetSWF(buffer);
|
||||
await habboAssetSWF.setupAsync();
|
||||
const newHabboAssetSWF: HabboAssetSWF = new HabboAssetSWF(url);
|
||||
await newHabboAssetSWF.setupAsync();
|
||||
|
||||
FigureDownloader.types.set(className, lib.part[0]['$'].type);
|
||||
await callback(habboAssetSWF);
|
||||
await callback(newHabboAssetSWF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,11 +73,10 @@ export default class FurnitureDownloader {
|
||||
}
|
||||
|
||||
try {
|
||||
const buffer: Buffer = await readFile(url);
|
||||
const habboAssetSWF = new HabboAssetSWF(buffer);
|
||||
await habboAssetSWF.setupAsync();
|
||||
const newHabboAssetSWF: HabboAssetSWF = new HabboAssetSWF(url);
|
||||
await newHabboAssetSWF.setupAsync();
|
||||
|
||||
await callback(habboAssetSWF, className);
|
||||
await callback(newHabboAssetSWF, className);
|
||||
} catch (e) {
|
||||
console.log("Error with furniture: " + url);
|
||||
console.log(e);
|
||||
|
@ -36,11 +36,10 @@ export default class PetDownloader {
|
||||
continue;
|
||||
}
|
||||
|
||||
const buffer: Buffer = await readFile(url);
|
||||
const habboAssetSWF = new HabboAssetSWF(buffer);
|
||||
await habboAssetSWF.setupAsync();
|
||||
const newHabboAssetSWF: HabboAssetSWF = new HabboAssetSWF(url);
|
||||
await newHabboAssetSWF.setupAsync();
|
||||
|
||||
await callback(habboAssetSWF);
|
||||
await callback(newHabboAssetSWF);
|
||||
}
|
||||
|
||||
itemClassNames.push(pet);
|
||||
|
@ -1,77 +1,74 @@
|
||||
import SymbolClassTag from "./tags/SymbolClassTag";
|
||||
import ImageTag from "./tags/ImageTag";
|
||||
import {readImagesDefineBitsLossless, readImagesJPEG, readSwfAsync} from "../utils/SwfReader";
|
||||
import ITag from "./tags/ITag";
|
||||
import SymbolClassTag from "./tags/SymbolClassTag";
|
||||
import DefineBinaryDataTag from "./tags/DefineBinaryDataTag";
|
||||
import ImageTag from "./tags/ImageTag";
|
||||
import CustomIterator from "../utils/CustomIterator";
|
||||
import CharacterTag from "./tags/CharacterTag";
|
||||
import DefineBinaryDataTag from "./tags/DefineBinaryDataTag";
|
||||
|
||||
const {readFromBufferP, extractImages} = require('swf-extract');
|
||||
|
||||
export interface Tag {
|
||||
code: number,
|
||||
length: number,
|
||||
rawData: Buffer
|
||||
}
|
||||
|
||||
export interface SWFFrameSize {
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number
|
||||
}
|
||||
|
||||
export interface SWFFileLength {
|
||||
compressed: number,
|
||||
uncompressed: number
|
||||
}
|
||||
|
||||
export interface SWF {
|
||||
tags: Array<Tag>,
|
||||
version: number,
|
||||
fileLength: SWFFileLength,
|
||||
frameSize: SWFFrameSize,
|
||||
frameRate: number,
|
||||
frameCount: number
|
||||
}
|
||||
|
||||
export default class HabboAssetSWF {
|
||||
|
||||
private swf: SWF | null;
|
||||
|
||||
private readonly _tags: Array<ITag>;
|
||||
|
||||
private _documentClass: string | null = null;
|
||||
|
||||
constructor(private readonly _buffer: Buffer) {
|
||||
this.swf = null;
|
||||
|
||||
constructor(
|
||||
private readonly _path: string
|
||||
) {
|
||||
this._tags = new Array<ITag>();
|
||||
}
|
||||
|
||||
public async setupAsync() {
|
||||
this.swf = await readFromBufferP(this._buffer);
|
||||
async setupAsync() {
|
||||
const swf = await readSwfAsync(this._path);
|
||||
for (const tag of swf.tags) {
|
||||
|
||||
if (this.swf === null) throw new Error("SWF Can't be null!");
|
||||
switch (tag.header.code) {
|
||||
case 76:
|
||||
this._tags.push(new SymbolClassTag(tag.symbols));
|
||||
break;
|
||||
case 87:
|
||||
this._tags.push(new DefineBinaryDataTag(tag.data))
|
||||
break;
|
||||
|
||||
for (const tag of this.swf.tags) {
|
||||
if (tag.code === 76) {
|
||||
this._tags.push(new SymbolClassTag(tag));
|
||||
case 6:
|
||||
console.log(tag);
|
||||
break;
|
||||
|
||||
case 21:
|
||||
console.log(tag);
|
||||
break;
|
||||
|
||||
case 35:
|
||||
const imageTag = await readImagesJPEG(35, tag);
|
||||
this._tags.push(new ImageTag({
|
||||
code: imageTag.code,
|
||||
characterID: imageTag.characterId,
|
||||
imgType: imageTag.imgType,
|
||||
imgData: imageTag.imgData
|
||||
}));
|
||||
break;
|
||||
|
||||
case 36:
|
||||
const imageTag: any = await readImagesDefineBitsLossless(tag);
|
||||
this._tags.push(new ImageTag({
|
||||
code: imageTag.code,
|
||||
characterID: imageTag.characterId,
|
||||
imgType: imageTag.imgType,
|
||||
imgData: imageTag.imgData
|
||||
}));
|
||||
break;
|
||||
|
||||
case 20:
|
||||
console.log(tag);
|
||||
break;
|
||||
|
||||
case 90:
|
||||
console.log(tag);
|
||||
break;
|
||||
|
||||
default:
|
||||
//console.log(tag.header.code);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tag.code === 87) {
|
||||
this._tags.push(new DefineBinaryDataTag(tag));
|
||||
}
|
||||
}
|
||||
|
||||
const images = await Promise.all(extractImages(this.swf.tags));
|
||||
for (const image of images) {
|
||||
const imgObj: any = image;
|
||||
this._tags.push(new ImageTag({
|
||||
code: imgObj.code,
|
||||
characterID: imgObj.characterId,
|
||||
imgType: imgObj.imgType,
|
||||
imgData: imgObj.imgData
|
||||
}));
|
||||
}
|
||||
|
||||
this.assignClassesToSymbols();
|
||||
@ -89,15 +86,6 @@ export default class HabboAssetSWF {
|
||||
return this._tags.filter((tag: ITag) => tag instanceof DefineBinaryDataTag).map(x => x as DefineBinaryDataTag);
|
||||
}
|
||||
|
||||
public getBinaryTagByName(name: string): DefineBinaryDataTag | null {
|
||||
const streamTag = this.binaryTags()
|
||||
.filter(tag => tag.className === name)[0];
|
||||
|
||||
if (streamTag === undefined) return null;
|
||||
|
||||
return streamTag;
|
||||
}
|
||||
|
||||
private assignClassesToSymbols() {
|
||||
const classes: Map<number, string> = new Map();
|
||||
|
||||
@ -137,13 +125,20 @@ export default class HabboAssetSWF {
|
||||
}
|
||||
}
|
||||
|
||||
public getBinaryTagByName(name: string): DefineBinaryDataTag | null {
|
||||
const streamTag = this.binaryTags()
|
||||
.filter(tag => tag.className === name)[0];
|
||||
|
||||
if (streamTag === undefined) return null;
|
||||
|
||||
return streamTag;
|
||||
}
|
||||
|
||||
public getFullClassName(type: string, documentNameTwice: boolean): string {
|
||||
return this.getFullClassNameSnake(type, documentNameTwice, false);
|
||||
}
|
||||
|
||||
public getFullClassNameSnake(type: string, documentNameTwice: boolean, snakeCase: boolean): string {
|
||||
if (this.swf === null) throw new Error("SWF Can't be null!");
|
||||
|
||||
let result: string = this.getDocumentClass() + "_";
|
||||
if (documentNameTwice) {
|
||||
if (snakeCase) {
|
||||
@ -181,8 +176,4 @@ export default class HabboAssetSWF {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public setDocumentClass(documentClass: string) {
|
||||
this._documentClass = documentClass;
|
||||
}
|
||||
}
|
@ -1,9 +1,6 @@
|
||||
import {Tag} from "../HabboAssetSWF";
|
||||
import ITag from "./ITag";
|
||||
import CharacterTag from "./CharacterTag";
|
||||
|
||||
const {SWFBuffer} = require('swf-extract/swf-buffer');
|
||||
|
||||
export default class DefineBinaryDataTag extends CharacterTag implements ITag {
|
||||
|
||||
private readonly _tag: number;
|
||||
@ -11,15 +8,14 @@ export default class DefineBinaryDataTag extends CharacterTag implements ITag {
|
||||
private readonly _binaryData: string;
|
||||
private readonly _binaryDataBuffer: Buffer;
|
||||
|
||||
constructor(tag: Tag) {
|
||||
constructor(buffer: Buffer) {
|
||||
super();
|
||||
|
||||
const swfBuffer = new SWFBuffer(tag.rawData);
|
||||
this._tag = swfBuffer.readUIntLE(16);
|
||||
this._reserved = swfBuffer.readUIntLE(32);
|
||||
this._tag = buffer.readUInt16LE(0);
|
||||
this._reserved = buffer.readUInt32LE(2);
|
||||
const start = 6; //short 2 + int 4
|
||||
const end = tag.rawData.length;
|
||||
const binary = tag.rawData.slice(start, end);
|
||||
const end = buffer.length;
|
||||
const binary = buffer.slice(start, end);
|
||||
|
||||
this._binaryData = binary.toString("utf-8");
|
||||
this._binaryDataBuffer = binary;
|
||||
|
@ -1,30 +1,22 @@
|
||||
import {Tag} from "../HabboAssetSWF";
|
||||
import ITag from "./ITag";
|
||||
|
||||
const {SWFBuffer} = require('swf-extract/swf-buffer');
|
||||
export interface SymbolClass {
|
||||
id: number,
|
||||
name: string
|
||||
}
|
||||
|
||||
export default class SymbolClassTag implements ITag {
|
||||
|
||||
private readonly _tags: Array<number>;
|
||||
private readonly _names: Array<string>;
|
||||
|
||||
constructor(tag: Tag) {
|
||||
constructor(tags: Array<SymbolClass>) {
|
||||
this._tags = [];
|
||||
this._names = [];
|
||||
|
||||
this.init(tag);
|
||||
}
|
||||
|
||||
init(tag: Tag) {
|
||||
const swfBuffer = new SWFBuffer(tag.rawData);
|
||||
|
||||
const numSymbols = swfBuffer.readUIntLE(16);
|
||||
for (let i = 0; i < numSymbols; i++) {
|
||||
const tagId = swfBuffer.readUIntLE(16);
|
||||
const tagName = swfBuffer.readString("utf-8");
|
||||
|
||||
this._tags.push(tagId);
|
||||
this._names.push(tagName);
|
||||
for (const symbolClass of tags) {
|
||||
this._tags.push(symbolClass.id);
|
||||
this._names.push(symbolClass.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
107
src/utils/SwfReader.ts
Normal file
107
src/utils/SwfReader.ts
Normal file
@ -0,0 +1,107 @@
|
||||
const SWFReader = require('@gizeta/swf-reader');
|
||||
const {extractImage, test} = require("swf-extract");
|
||||
|
||||
var _encoder = require('png-stream/encoder');
|
||||
|
||||
var _encoder2 = _interopRequireDefault(_encoder);
|
||||
|
||||
var _zlib = require('zlib');
|
||||
|
||||
var _zlib2 = _interopRequireDefault(_zlib);
|
||||
|
||||
var _streamToArray = require('stream-to-array');
|
||||
|
||||
var _streamToArray2 = _interopRequireDefault(_streamToArray);
|
||||
|
||||
function _interopRequireDefault(obj: any) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
export function readSwfAsync(path: string): Promise<any> {
|
||||
return new Promise<any>(((resolve, reject) => {
|
||||
SWFReader.read(path, function (err: Error, swf: any) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(swf);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
export async function readImagesJPEG(code: number, tag: any) {
|
||||
return test(code)(tag);
|
||||
}
|
||||
|
||||
export function readImagesDefineBitsLossless(tag: any) {
|
||||
const characterId = tag.characterId,
|
||||
bitmapFormat = tag.bitmapFormat,
|
||||
bitmapWidth = tag.bitmapWidth,
|
||||
bitmapHeight = tag.bitmapHeight,
|
||||
bitmapColorTableSize = tag.bitmapColorTableSize,
|
||||
zlibBitmapData = tag.zlibBitmapData;
|
||||
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
const enc = new _encoder2.default(bitmapWidth, bitmapHeight, {colorSpace: 'rgba'});
|
||||
|
||||
_zlib2.default.unzip(zlibBitmapData, function (err: any, dataBuf: any) {
|
||||
if (err) {
|
||||
return reject(new Error(err));
|
||||
}
|
||||
var output = new Buffer(bitmapWidth * bitmapHeight * 4);
|
||||
var index = 0;
|
||||
var ptr = 0;
|
||||
if (bitmapFormat === 5) {
|
||||
// 32-bit ARGB image
|
||||
for (var y = 0; y < bitmapHeight; ++y) {
|
||||
for (var x = 0; x < bitmapWidth; ++x) {
|
||||
var alpha = dataBuf[ptr];
|
||||
output[index] = dataBuf[ptr + 1];
|
||||
output[index + 1] = dataBuf[ptr + 2];
|
||||
output[index + 2] = dataBuf[ptr + 3];
|
||||
output[index + 3] = alpha;
|
||||
index += 4;
|
||||
ptr += 4;
|
||||
}
|
||||
}
|
||||
} else if (bitmapFormat === 3) {
|
||||
// 8-bit colormapped image
|
||||
var colorMap = [];
|
||||
for (var i = 0; i < bitmapColorTableSize + 1; ++i) {
|
||||
colorMap.push([dataBuf[ptr], dataBuf[ptr + 1], dataBuf[ptr + 2], dataBuf[ptr + 3]]);
|
||||
ptr += 4;
|
||||
}
|
||||
for (var _y2 = 0; _y2 < bitmapHeight; ++_y2) {
|
||||
for (var _x2 = 0; _x2 < bitmapWidth; ++_x2) {
|
||||
var idx = dataBuf[ptr];
|
||||
var color = idx < colorMap.length ? colorMap[idx] : [0, 0, 0, 0];
|
||||
output[index] = color[0];
|
||||
output[index + 1] = color[1];
|
||||
output[index + 2] = color[2];
|
||||
output[index + 3] = color[3];
|
||||
ptr += 1;
|
||||
index += 4;
|
||||
}
|
||||
// skip padding
|
||||
ptr += (4 - bitmapWidth % 4) % 4;
|
||||
}
|
||||
} else {
|
||||
return reject(new Error('unhandled bitmapFormat: ' + bitmapFormat));
|
||||
}
|
||||
enc.end(output);
|
||||
});
|
||||
|
||||
(_streamToArray2.default)(enc).then(function (parts: any) {
|
||||
var buffers = parts.map(function (part: any) {
|
||||
return Buffer.isBuffer(part) ? part : Buffer.from(part);
|
||||
});
|
||||
resolve({
|
||||
code: 36,
|
||||
characterId: characterId,
|
||||
imgType: 'png',
|
||||
imgData: Buffer.concat(buffers)
|
||||
});
|
||||
});
|
||||
}).catch(function (e) {
|
||||
console.error(e);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user