mdx-m3-viewer
Version:
A browser WebGL model viewer. Mainly focused on models of the games Warcraft 3 and Starcraft 2.
232 lines (166 loc) • 6.04 kB
JavaScript
class WeuConverter extends Component {
constructor(parentElement) {
super({ className: 'client' });
this.triggerData = new ModelViewer.default.parsers.w3x.wtg.TriggerData();
this.weTriggerData = new ModelViewer.default.parsers.w3x.wtg.TriggerData();
this.ready = false;
this.metaElement = createElement({ className: 'meta', container: this.container });
this.metaStack = [this.metaElement];
this.visibleMeta = null;
this.changesElement = createElement({ className: 'changes', container: this.container });
this.visibleChanges = null;
this.load();
parentElement.appendChild(this.container);
}
async load() {
this.text('Fetching files: "UI\\TriggerData.txt", "TriggerDataWEU.txt", "TriggerDataYDWE.txt", "TriggerDataCustom.txt"');
this.text('Please wait...');
let [blzResponse, weuResponse, ydweResponse, customResponse] = await Promise.all([
fetch(localOrHive('UI\\TriggerData.txt')),
fetch('TriggerDataWEU.txt'),
fetch('TriggerDataYDWE.txt'),
fetch('TriggerDataCustom.txt'),
]);
let [blzText, weuText, ydweText, customText] = await Promise.all([
blzResponse.text(),
weuResponse.text(),
ydweResponse.text(),
customResponse.text(),
]);
this.triggerData.addTriggerData(blzText); // WE trigger data
this.triggerData.addTriggerData(weuText, true); // WEU trigger data
this.triggerData.addTriggerData(ydweText, true); // YDWE trigger data
this.triggerData.addTriggerData(customText, true);
this.weTriggerData.addTriggerData(blzText); // WE trigger data
this.ready = true;
this.text('Ready, drag and drop a TFT map (*.w3x) or campaign (*.w3n) anywhere on the page');
}
clear() {
this.metaElement.innerHTML = '';
this.changesElement.innerHTML = '';
}
indent() {
this.metaStack.unshift(createElement({ className: 'indent', container: this.metaStack[0] }));
}
deindent() {
this.metaStack.shift();
}
text(text) {
createElement({ textContent: text, container: this.metaStack[0] });
this.metaElement.scrollTo(0, 10000000);
}
error(text) {
createElement({ className: 'error', textContent: text, container: this.metaStack[0] });
this.metaElement.scrollTo(0, 10000000);
}
results(results) {
this.metaStack[0].appendChild((new WeuMeta(this, results)).container);
this.metaElement.scrollTo(0, 10000000);
}
showChanges(meta) {
if (this.visibleMeta) {
this.visibleMeta.changesToggle.toggle();
}
this.visibleMeta = meta;
meta.changes.show();
}
hideChanges() {
if (this.visibleMeta) {
this.visibleMeta.changes.hide();
this.visibleMeta = null;
}
}
convertMap(name, buffer) {
this.text(`Parsing ${name}`);
let map = new ModelViewer.default.parsers.w3x.Map();
try {
map.load(buffer);
} catch (e) {
this.error(`Failed to parse: ${e}`);
this.error('This map is most likely protected/optimized');
return;
}
let changesCount = 0;
let results = ModelViewer.default.utils.convertWeu(map, this.triggerData, this.weTriggerData);
this.indent();
if (results.ok) {
let changes = results.changes;
if (changes.length) {
changesCount = changes.length;
this.results(results);
} else {
this.text('Found nothing to convert');
}
} else {
this.error(results.error);
}
this.deindent();
return { parser: map, changes: changesCount };
}
async convertCampaign(name, buffer) {
this.text(`Parsing ${name}`);
let campaign = new ModelViewer.default.parsers.mpq.Archive();
try {
campaign.load(buffer);
} catch (e) {
this.error(`Failed to parse: ${e}`);
this.error('This campaign is most likely protected/optimized');
return;
}
this.text('Looking for maps');
let totalChanges = 0;
let changedMaps = 0;
for (let fileName of campaign.getFileNames()) {
if (fileName.substr(fileName.lastIndexOf('.')).toLowerCase() === '.w3x') {
this.indent();
let results = this.convertMap(fileName, campaign.get(fileName).arrayBuffer());
this.deindent();
if (results) {
totalChanges += results.changes;
changedMaps += 1;
campaign.set(fileName, results.parser.save());
}
await aFrame();
}
}
if (totalChanges) {
this.text(`Converted with ${totalChanges} changes in ${changedMaps} maps`);
} else {
this.text('Found nothing to convert');
}
return { parser: campaign, changes: totalChanges };
}
convertFile(file) {
if (this.ready && file) {
let name = file.name;
let ext = name.substr(name.lastIndexOf('.')).toLowerCase();
let isMap = ext === '.w3x';
let isCampaign = ext === '.w3n';
this.clear();
if (isMap || isCampaign) {
this.text(`Reading ${name}`);
let reader = new FileReader();
reader.addEventListener('loadend', async (e) => {
let buffer = e.target.result;
let results;
this.indent();
if (isMap) {
results = this.convertMap(name, buffer);
} else {
results = await this.convertCampaign(name, buffer);
}
this.deindent();
if (results && results.changes) {
name = `${name.slice(0, -4)}_no_weu${ext}`;
this.text(`Saving as ${name}`);
this.metaElement.scrollTo(0, 10000000);
saveAs(new Blob([results.parser.save()], { type: 'application/octet-stream' }), name);
}
});
reader.readAsArrayBuffer(file);
} else {
this.error(`${name} is not a TFT map/campaign`);
}
}
}
}