Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/toyobayashi/wz
MapleStory wz reader for Node.js and browser.
https://github.com/toyobayashi/wz
maplestory wz
Last synced: 11 days ago
JSON representation
MapleStory wz reader for Node.js and browser.
- Host: GitHub
- URL: https://github.com/toyobayashi/wz
- Owner: toyobayashi
- Created: 2020-10-09T15:53:53.000Z (about 4 years ago)
- Default Branch: main
- Last Pushed: 2024-01-03T14:39:55.000Z (10 months ago)
- Last Synced: 2024-05-02T02:06:50.948Z (6 months ago)
- Topics: maplestory, wz
- Language: TypeScript
- Homepage: wz-mu.vercel.app
- Size: 2.9 MB
- Stars: 31
- Watchers: 2
- Forks: 8
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# node-wz
MapleStory wz reader for Node.js and browser.
Incompletely port from [lastbattle/Harepacker-resurrected/MapleLib/WzLib](https://github.com/lastbattle/Harepacker-resurrected/tree/master/MapleLib/WzLib).
[API Documentation](https://github.com/toyobayashi/wz/blob/main/docs/api/index.md)
## Build
Environment:
* Node.js v12+
* CMake v3.6+
* Emscripten toolchain latest
* Set environment variable `$EMSDK` to emsdk path
* Add `$EMSDK` and `$EMSDK/upstream/emscripten` to `$PATH`
* Make for Windows (Windows only)
``` bash
git clone https://github.com/toyobayashi/wz.git
cd wz
`````` bash
npm install
npm run build
```Windows
``` bat
npm install
npm run build
```## Example
``` bash
npm install @tybys/wz
```### Node.js (v10.20+)
``` js
const path = require('path')
const {
walkWzFileAsync,
WzMapleVersion,
WzObjectType,
WzBinaryProperty,
ErrorLogger
} = require('@tybys/wz')/**
* @param {string} wzFilePath - WZ file path
* @param {WzMapleVersion} mapleVersion - MapleStory version
* @param {string} dir - Output directory path
*/
async function saveSounds (wzFilePath, mapleVersion, dir) {
let n = 0// let _doNotUseMe
/**
* @template {import('@tybys/wz').WzObject} T
* @param {T} obj - wz object
* @returns {Promise}
*/
async function callback (obj) {
// obj is available only in this scope
// _doNotUseMe = obj // ! do not do this
if (obj.objectType === WzObjectType.Property && obj instanceof WzBinaryProperty) {
const relativePath = path.win32.relative(wzFilePath, obj.fullPath).replace(/\\/g, '/')
const file = path.join(dir, path.extname(relativePath) === '' ? `${relativePath}.mp3` : relativePath)
console.log(`Saving ${path.resolve(file)}`)
await obj.saveToFile(file)
n++
}
return false // continue walking
}await walkWzFileAsync(wzFilePath, mapleVersion, callback)
console.log(`Total files: ${n}`)
if (ErrorLogger.errorsPresent()) {
ErrorLogger.saveToFile('WzError.log')
}
}saveSounds('C:\\Nexon\\MapleStory\\Sound.wz', WzMapleVersion.BMS, 'Sound')
```### Modern browser
Browser environment should be with ES2018+ and WebAssembly support.
``` html
```
``` js
///(function () {
const input = document.getElementById('file')input.addEventListener('change', async (e) => {
const f = e.target.files[0] // Select the Sound.wz fileawait wz.walkWzFileAsync(f, wz.WzMapleVersion.BMS, async (obj) => {
if (obj.objectType === wz.WzObjectType.Property && obj instanceof wz.WzBinaryProperty) {
console.log(obj.fullPath)const buf = (await obj.getBytes(false)) // MP3 Uint8Array
const blob = new Blob([buf.buffer], { type: 'audio/mp3' })
const src = URL.createObjectURL(blob)
const audio = new Audio()
audio.src = src
audio.play()await obj.saveToFile('1.mp3') // trigger download
return true
}
})
})
})()
```#### Webpack
Add `CopyWebpackPlugin` to copy `wz.wasm` file
``` js
const CopyWebpackPlugin = require('copy-webpack-plugin')module.exports = {
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: 'node_modules/@tybys/wz/dist/wz.wasm', to: '${the same place with output bundle}/wz.wasm' }
]
})
],
/* resolve: {
alias: {
'@tybys/binreader': '@tybys/binreader/lib/esm-modern/index.js'
}
} */
}
`````` js
import { walkWzFileAsync, /* ... */ } from '@tybys/wz'
```### Old browser
For example IE11:
``` html
if (typeof BigInt === 'undefined') {
window.BigInt = function BigInt (n) {
return n;
};
}// https://github.com/amiller-gh/currentScript-polyfill/blob/master/currentScript.js
```
#### Webpack
``` js
const CopyWebpackPlugin = require('copy-webpack-plugin')module.exports = {
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: 'node_modules/@tybys/wz/dist/wz.js.mem', to: '${the same place with output bundle}/wz.js.mem' }
]
})
],
resolve: {
alias: {
'@tybys/wz': '@tybys/wz/lib/esm/index.js' // es5 output
}
}
}
```### Advanced
Though `walkWzFileAsync()` is easy to use, it is much more slower in browser than in Node.js. It is recommanded to use class API to do specific directory or image operation.
``` js
const { init, WzFile, WzMapleVersion, WzBinaryProperty, WzImage, WzDirectory, WzFileParseStatus, getErrorDescription } = require('@tybys/wz')async function main () {
// Must call init() first to initialize Webassembly
// before calling other API in browser.
// In nodejs it is just return Promise.resolve()
await init()// Construct a WzFile object
const wz = new WzFile('C:\\Nexon\\MapleStory\\Sound.wz', WzMapleVersion.BMS)const r = await wz.parseWzFile()
if (r !== WzFileParseStatus.SUCCESS) {
throw new Error(getErrorDescription(r))
}// Access main directory
/** @type {WzDirectory} */
const mainDirectory = wz.wzDirectory // ! not null/** @type {WzImage | null} */
const img = mainDirectory.at('Bgm50.img')
if (img === null) throw new Error('404')// Parse the image before use it
await img.parseImage()// Access image properties
const props = img.wzProperties // getter returns Setfor (const prop of props) {
if (prop instanceof WzBinaryProperty) {
console.log(prop.fullPath)
// do something
// prop.saveToFile()
}
}
wz.dispose()
}main()
```