Skip to content

Instantly share code, notes, and snippets.

@Hipnosis183
Created August 26, 2023 09:23
Show Gist options
  • Save Hipnosis183/6816bdc781ea4a4d2118ac3afeb3bc3c to your computer and use it in GitHub Desktop.
Save Hipnosis183/6816bdc781ea4a4d2118ac3afeb3bc3c to your computer and use it in GitHub Desktop.
Million Versus Online - Asset Downloader
// Requires NPM package 'node-fetch'.
// npm install node-fetch@2
const fetch = require('node-fetch');
const fs = require('fs');
const http = require('http');
const util = require('util');
const pipeline = util.promisify(require('stream').pipeline);
// Import file list.
let filesGot = 0;
let filesTotal = 0;
const filesList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 51, 52, 53, 54, 60, 61, 62, 63, 64, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 152, 153, 157, 159, 162, 163, 175, 176, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199];
// Game server information.
const serverHost = 'http://m-versus.com/';
const serverUrl = `${serverHost}version/android/`;
http.createServer().listen(3000, '127.0.0.1', async () => {
console.log(`[Million Versus Online - Assets Downloader]\n`);
await getResources();
//await getWebsite();
console.log(`[DONE] ${filesGot}/${filesTotal} files.`);
process.exit(0); // Terminate server process.
});
const getResources = async () => {
console.log(`[RESOURCES]`);
filesTotal += filesList.length;
const pathResources = createPath('jp.co.ateam.mva/files');
for (let [i, z] of filesList.entries()) {
const zoneVersion = await fetch(`${serverUrl}get_zone_version.php?z=${z}`, { method: 'GET' });
const $zoneVersion = hexNum(strHex((await zoneVersion.buffer()).toString('latin1')).slice(0, 8));
if ($zoneVersion) {
const fileName = `zone${z}`;
const fileUrl = `${serverUrl}get_data.php?mode=zone&version=${$zoneVersion}&z=${z}`;
console.log(`[${i + 1}/${filesList.length}] ${fileName}`);
if (await fileDownload(fileName, fileUrl, pathResources)) { filesGot++; }; }
} console.log();
}
const getWebsite = async () => {
console.log(`[WEBSITE]`);
filesTotal += 980;
const pathWebsite = createPath('m-versus.com/bull/character_make/image_gif');
const charSex = ['01', '02'];
const charColor = ['00', '01', '02', '03', '04', '05', '06'];
const charHair = ['00', '01', '02', '03', '04', '05', '06'];
const charHColor = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09'];
for (let s of charSex) {
for (let c of charColor) {
for (let h of charHair) {
for (let hc of charHColor) {
const fileName = `${c}_${s}_${h}_${hc}.gif`;
const fileUrl = `${serverHost}bull/character_make/image_gif/${fileName}`;
if (await fileDownload(fileName, fileUrl, pathWebsite)) { filesGot++; };
}}}} console.log();
}
const createPath = (output) => {
// Create output path if it doesn't exist.
const outputPath = `./${output}/`;
if (!fs.existsSync(outputPath)) { fs.mkdirSync(outputPath, { recursive: true }); }
return outputPath;
}
const fileDownload = async (name, url, output) => {
try { // Download data from url.
const fileData = await fetch(url, { method: 'GET' });
// Write downloaded data into a new file stream.
await pipeline(fileData.body, fs.createWriteStream(output + name));
console.log(`[OK] >>${output.slice(1)}${name}`); return 1;
} catch { // Failed to download file.
console.log(`[ERROR] ${output.slice(1)}${name} (${url})`); return 0;
}
}
// Return number representation of the given byte string.
const hexNum = (s) => {
const n = s.match(/../g).reverse().join('');
return parseInt(`0x${n}`, 16);
}
// Return byte representation of the given string.
const strHex = (s) => {
return Array.from(s, b => b.charCodeAt(0).toString(16).padStart(2, '0')).join('').toUpperCase();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment