gctGenerator/site/.vuepress/components/DownloadButton.vue

217 lines
6.3 KiB
Vue
Raw Normal View History

2020-06-28 06:33:20 +09:00
<template>
2021-06-11 07:48:15 +09:00
<div>
<ButtonComponent
label="Download"
:onClick="onClick"
:disabled="(!codes || codes.length === 0) && !stageLoaderCode"
2022-01-17 03:17:07 +09:00
/>
2021-06-11 07:48:15 +09:00
</div>
2020-06-28 06:33:20 +09:00
</template>
<script>
2020-06-30 05:30:29 +09:00
// Data
import gameVersions from '../data/gameVersions.json';
2020-07-10 12:21:13 +09:00
// Util
import { translate, translateCode } from '../i18n/localeHelper';
2020-07-10 12:21:13 +09:00
// customizable code
import codegens from './codes/codegen.js';
2020-06-28 06:33:20 +09:00
export default {
props: {
codes: { type: Array },
2020-06-28 10:45:44 +09:00
stageLoaderCode: { type: String },
2020-06-28 06:33:20 +09:00
format: { type: String },
2020-06-28 10:45:44 +09:00
versionIdentifier: { type: String },
2020-06-28 06:33:20 +09:00
},
2021-06-11 07:48:15 +09:00
data() {
2022-01-17 03:17:07 +09:00
return {};
2021-06-11 07:48:15 +09:00
},
2020-06-28 06:33:20 +09:00
methods: {
onClick() {
2020-06-28 10:45:44 +09:00
if (!(this.codes || this.codes.length === 0) && !this.stageLoaderCode) {
2020-06-28 06:33:20 +09:00
return;
}
2020-06-28 10:45:44 +09:00
const c = [...(this.codes ?? [])];
if (this.stageLoaderCode)
c.push({
2020-06-29 00:35:18 +09:00
title: 'Stage List Loader',
author: 'Noki Doki',
date: '-',
version: '',
2020-06-28 10:45:44 +09:00
source: this.stageLoaderCode,
});
2020-06-28 06:33:20 +09:00
try {
2020-07-01 13:19:15 +09:00
window._paq.push([
'trackEvent',
'GCT Generator',
'Code Download',
JSON.stringify({
gameVersion: this.versionIdentifier,
format: this.format,
2020-07-01 14:26:48 +09:00
codes: c.map((code) => ({
title: code.title,
version: code.version,
})),
}),
]);
} catch {}
2020-07-01 14:26:48 +09:00
const fileName = gameVersions.find((v) => v.identifier === this.versionIdentifier).version;
2020-06-30 05:30:29 +09:00
// apply customizable codes
for (const code of c) {
const codegen = codegens[code.id];
if (codegen) {
code.source = codegen(this.versionIdentifier);
}
}
// generate file
const codeSize = c.reduce((a, e) => a+e.source.length, 0)/2 + 16; // 8(00D0)+8(F000)
// console.log(codeSize, c);
2020-06-28 06:33:20 +09:00
switch (this.format) {
2020-06-29 00:35:18 +09:00
case 'gct':
this.alertGCTCodeSize(codeSize);
2020-07-03 10:53:48 +09:00
this.generateGCT(c, fileName);
2020-06-28 06:33:20 +09:00
break;
2020-06-29 00:35:18 +09:00
case 'dolphin':
this.alertDolphinCodeSize(codeSize);
2020-07-03 10:53:48 +09:00
this.generateDolphinINI(c, fileName);
2020-06-28 06:33:20 +09:00
break;
2020-06-29 00:35:18 +09:00
case 'gcm':
this.alertDolphinCodeSize(codeSize);
2020-07-03 10:53:48 +09:00
this.generateCheatManagerTXT(c, fileName);
2020-06-28 06:33:20 +09:00
break;
case 'gci+gct':
this.generateGCI(c, fileName) &&
this.generateGCT(this.getGCILoader(), fileName);
break;
case 'gci+dolphin':
this.generateGCI(c, fileName) &&
this.generateDolphinINI(this.getGCILoader(), fileName);
break;
case 'gci+gcm':
this.generateGCI(c, fileName) &&
this.generateCheatManagerTXT(this.getGCILoader(), fileName);
break;
case 'gci':
this.generateGCI(c, fileName);
break;
2020-06-28 06:33:20 +09:00
}
2020-06-28 10:45:44 +09:00
},
alertGCTCodeSize(size) {
if (size > 5000) {
alert(translate('generatorconfig.alert.gct', this.$lang).replaceAll('{size}', size));
}
},
alertDolphinCodeSize(size) {
if (size > 3272) { // 0x3000-0x2338
// excluding header+footer
alert(translate('generatorconfig.alert.dolphin', this.$lang).replaceAll('{size}', size-16));
}
},
getGCILoader() {
const {codes} = gameVersions.find((v) => v.identifier === this.versionIdentifier);
const code = codes.find(code => code.id === 'GCILoader');
return [code];
},
2020-07-03 10:53:48 +09:00
generateGCT(codes, version) {
let code = '00D0C0DE00D0C0DE';
codes.forEach((c) => (code += c.source));
2021-01-15 08:39:49 +09:00
code += 'F000000000000000';
2020-07-03 10:53:48 +09:00
let rawData = new Uint8Array(code.length / 2);
for (let x = 0; x < rawData.length; x++) {
rawData[x] = parseInt(code.substr(x * 2, 2), 16);
}
this.downloadFile(rawData, `${version}.gct`);
},
generateDolphinINI(codes, version) {
let data = 'Paste the following on top of your games .ini file:\r\n[Gecko]';
codes.forEach((code) => {
2020-07-10 12:21:13 +09:00
const codeTitle =
typeof code.title === 'string' ? code.title : translateCode(code, this.$lang).title;
data += `\r\n$${codeTitle} (${code.date}) [${code.author}]\r\n`;
2020-07-03 10:53:48 +09:00
data += code.source
.match(/.{8}/g)
.join(' ')
.replace(/(.{17})./g, '$1\r\n');
});
this.downloadFile(data, `${version}.txt`);
},
generateCheatManagerTXT(codes, version) {
let data = `${version}\r\nSuper Mario Sunshine`;
codes.forEach((code) => {
2020-07-10 12:21:13 +09:00
const codeTitle =
typeof code.title === 'string' ? code.title : translateCode(code, this.$lang).title;
data += `\r\n\r\n${codeTitle} (${code.date}) [${code.author}]\r\n`;
2020-07-03 10:53:48 +09:00
data += code.source
.match(/.{8}/g)
.join(' ')
.replace(/(.{17})./g, '$1\r\n');
});
this.downloadFile(data, `${version}.txt`);
},
generateGCI(codes, version) {
if (!['GMSJ01'].includes(version)) {
alert('GCI format is not yet supported for versions other than GMSJ01');
return false; // error
}
let code = '00D0C0DE00D0C0DE';
codes.forEach((c) => (code += c.source));
code += 'C0000000000000023C60818081E3A7FC7DE478504E800020'; // return
const blockCount = 2; // TODO
const gciSize = 0x40+0x2000*blockCount;
const padSize = 0x40; // TODO
let rawData = new Uint8Array(gciSize);
for (let iD=padSize, iC=0; iD<rawData.length; iD++, iC+=2) {
rawData[iD] = parseInt(code.slice(iC, iC+2), 16);
}
// game id
[...new TextEncoder().encode(version), 0xff, 0x00].forEach((e, i) => rawData[i] = e);
// file name
[...new TextEncoder().encode('gct')].forEach((e, i) => rawData[0x8+i] = e);
// block count
rawData[0x39] = blockCount;
// ff*6
for (let i=0x3A; i<0x40; i++) rawData[i] = 0xff;
this.downloadFile(rawData, `01-${version.slice(0, 4)}-gct.gci`);
return true; // good
},
2020-07-03 10:53:48 +09:00
downloadFile(data, filename) {
var file = new Blob([data], {
type: 'application/octet-stream',
});
if (window.navigator.msSaveOrOpenBlob) window.navigator.msSaveOrOpenBlob(file, filename);
else {
var a = document.createElement('a'),
url = window.URL.createObjectURL(file);
a.href = url;
a.download = filename;
a.click();
setTimeout(function () {
window.URL.revokeObjectURL(url);
}, 500);
}
},
2020-06-28 10:45:44 +09:00
},
2020-06-28 06:33:20 +09:00
};
</script>