patchwork-mapconverter
Version:
Executable wrapper for https://github.com/ChiefOfGxBxL/WC3MapTranslator
128 lines (107 loc) • 4.34 kB
text/typescript
import { HexBuffer } from '../HexBuffer'
import { W3Buffer } from '../W3Buffer'
import { type WarResult, type JsonResult } from '../CommonInterfaces'
import { type Translator } from './Translator'
import { type Region } from '../data/Region'
export class RegionsTranslator implements Translator<Region[]> {
private static instance: RegionsTranslator
private constructor () {}
public static getInstance (): RegionsTranslator {
if (this.instance == null) {
this.instance = new this()
}
return this.instance
}
public static jsonToWar (regions: Region[]): WarResult {
return this.getInstance().jsonToWar(regions)
}
public static warToJson (buffer: Buffer): JsonResult<Region[]> {
return this.getInstance().warToJson(buffer)
}
public jsonToWar (regionsJson: Region[]): WarResult {
const outBufferToWar = new HexBuffer()
/*
* Header
*/
outBufferToWar.addInt(5) // file version
outBufferToWar.addInt(regionsJson?.length || 0) // number of regions
/*
* Body
*/
regionsJson?.forEach(region => {
// Position
// Note that the .w3x guide has these coords wrong - the guide swaps bottom and right, but this is incorrect; bottom should be written before right
outBufferToWar.addFloat(region.position.left)
outBufferToWar.addFloat(region.position.bottom)
outBufferToWar.addFloat(region.position.right)
outBufferToWar.addFloat(region.position.top)
outBufferToWar.addString(region.name)
outBufferToWar.addInt(region.id)
// Weather effect name - lookup necessary: char[4]
if (region.weatherEffect != null) {
outBufferToWar.addChars(region.weatherEffect) // Weather effect is optional - defaults to 0000 for "none"
} else {
// We can't put a string "0000", because ASCII 0's differ from 0x0 bytes
outBufferToWar.addByte(0)
outBufferToWar.addByte(0)
outBufferToWar.addByte(0)
outBufferToWar.addByte(0)
}
// Ambient sound - refer to names defined in .w3s file
outBufferToWar.addString(region.ambientSound != null ? region.ambientSound : '') // May be empty string
// Color of region used by editor
// Careful! The order in .w3r is BB GG RR, whereas the JSON spec order is [RR, GG, BB]
outBufferToWar.addByte(region.color[2]) // blue
outBufferToWar.addByte(region.color[1]) // green
outBufferToWar.addByte(region.color[0]) // red
// End of structure - for some reason the .w3r needs this here;
// Value is set to 0xff based on observing the .w3r file, but not sure if it could be something else
outBufferToWar.addByte(0xff)
})
return {
errors: [],
buffer: outBufferToWar.getBuffer()
}
}
public warToJson (buffer: Buffer): JsonResult<Region[]> {
const result: Region[] = []
const outBufferToJSON = new W3Buffer(buffer)
const fileVersion = outBufferToJSON.readInt() // File version
const numRegions = outBufferToJSON.readInt() // # of regions
for (let i = 0; i < numRegions; i++) {
const region: Region = {
name: '',
id: 0,
weatherEffect: '',
ambientSound: '',
color: [0, 0, 0],
position: {
left: 0,
bottom: 0,
right: 0,
top: 0
}
}
region.position.left = outBufferToJSON.readFloat()
region.position.bottom = outBufferToJSON.readFloat()
region.position.right = outBufferToJSON.readFloat()
region.position.top = outBufferToJSON.readFloat()
region.name = outBufferToJSON.readString()
region.id = outBufferToJSON.readInt()
region.weatherEffect = outBufferToJSON.readChars(4)
region.ambientSound = outBufferToJSON.readString()
region.color = [
outBufferToJSON.readByte(), // red
outBufferToJSON.readByte(), // green
outBufferToJSON.readByte() // blue
]
region.color.reverse() // json wants it in RGB, but .w3r file stores it as BB GG RR
outBufferToJSON.readByte() // end of region structure
result.push(region)
}
return {
errors: [],
json: result
}
}
}