futarina-x-explorer/extract_all_data.js
2025-07-23 07:19:01 -05:00

301 lines
13 KiB
JavaScript

// Simple script to extract all game data using global variables
// Paste this into the developer console (F12) while the game is running
(function() {
console.log('Starting data extraction...');
// Create extraction folder
const fs = require('fs');
const path = require('path');
const extractPath = path.join(process.cwd(), 'package.nw', 'extracted_data');
if (!fs.existsSync(extractPath)) {
fs.mkdirSync(extractPath, { recursive: true });
console.log('Created extraction folder:', extractPath);
}
// Map of global variables to filenames
const dataMap = {
// Standard RPG Maker data
'$dataActors': 'Actors.json',
'$dataAnimations': 'Animations.json',
'$dataArmors': 'Armors.json',
'$dataClasses': 'Classes.json',
'$dataCommonEvents': 'CommonEvents.json',
'$dataEnemies': 'Enemies.json',
'$dataItems': 'Items.json',
'$dataMapInfos': 'MapInfos.json',
'$dataSkills': 'Skills.json',
'$dataStates': 'States.json',
'$dataTilesets': 'Tilesets.json',
'$dataTroops': 'Troops.json',
'$dataWeapons': 'Weapons.json'
};
// Custom game data mappings from plugins.js
const customDataMap = {
// Based on CustomData plugin configuration
'gallery': 'Gallery.json',
'db_1': 'DB_enmt.json',
'msg_1': 'MSG_enmt.json',
'testScenario': 'testScenario.json',
'areaName': 'Area.json',
'scnText': 'StartAndEnd.json',
'credits': 'CreditList.json',
'frames': 'Frames.json',
'destinations': 'Destinations.json'
};
// Try additional possible variable names
const additionalVars = [
'TrpParticleGroups', 'TrpParticles'
];
let extractedCount = 0;
let failedCount = 0;
const results = [];
console.log('\nExtracting data from global variables...');
console.log('='.repeat(50));
// Extract standard RPG Maker data
Object.entries(dataMap).forEach(([varName, filename]) => {
try {
const data = window[varName];
if (data !== undefined && data !== null) {
console.log(`Extracting: ${filename} from ${varName}`);
const outputPath = path.join(extractPath, filename);
const jsonContent = JSON.stringify(data, null, 2);
fs.writeFileSync(outputPath, jsonContent, 'utf8');
extractedCount++;
const size = Array.isArray(data) ? data.length : Object.keys(data).length;
results.push(`${filename} - Success (${size} entries)`);
console.log(`✓ Extracted: ${filename}`);
} else {
results.push(`${filename} - Skipped (variable not loaded)`);
console.log(`⚠ Skipped: ${filename} (${varName} not available)`);
}
} catch (error) {
failedCount++;
results.push(`${filename} - Failed: ${error.message}`);
console.error(`✗ Failed to extract ${filename}:`, error);
}
});
// Extract custom game data (these might be in $gameSystem or other locations)
Object.entries(customDataMap).forEach(([propName, filename]) => {
try {
// Try multiple possible locations for custom data
let data = null;
const possibleLocations = [
() => window[propName],
() => window['$data' + propName],
() => window['$gameSystem'] && window['$gameSystem'][propName],
() => window['$gameTemp'] && window['$gameTemp'][propName],
() => window['$gameVariables'] && window['$gameVariables'][propName]
];
for (const getLocation of possibleLocations) {
try {
const locationData = getLocation();
if (locationData !== undefined && locationData !== null) {
data = locationData;
break;
}
} catch (e) {
// Continue to next location
}
}
if (data !== null) {
console.log(`Extracting: ${filename} from custom data (${propName})`);
const outputPath = path.join(extractPath, filename);
const jsonContent = JSON.stringify(data, null, 2);
fs.writeFileSync(outputPath, jsonContent, 'utf8');
extractedCount++;
const size = Array.isArray(data) ? data.length : Object.keys(data).length;
results.push(`${filename} - Success (${size} entries)`);
console.log(`✓ Extracted: ${filename}`);
} else {
results.push(`${filename} - Skipped (custom data not found)`);
console.log(`⚠ Skipped: ${filename} (${propName} not available)`);
}
} catch (error) {
failedCount++;
results.push(`${filename} - Failed: ${error.message}`);
console.error(`✗ Failed to extract ${filename}:`, error);
}
});
// Try additional variables that might exist
additionalVars.forEach(varName => {
try {
const filename = varName + '.json';
const possibleVars = [`$data${varName}`, varName, `$gameSystem.${varName}`];
for (const testVar of possibleVars) {
try {
let data;
if (testVar.includes('.')) {
const parts = testVar.split('.');
data = window[parts[0]] && window[parts[0]][parts[1]];
} else {
data = window[testVar];
}
if (data !== undefined && data !== null) {
console.log(`Extracting: ${filename} from ${testVar}`);
const outputPath = path.join(extractPath, filename);
const jsonContent = JSON.stringify(data, null, 2);
fs.writeFileSync(outputPath, jsonContent, 'utf8');
extractedCount++;
const size = Array.isArray(data) ? data.length : Object.keys(data).length;
results.push(`${filename} - Success (${size} entries)`);
console.log(`✓ Extracted: ${filename}`);
break;
}
} catch (e) {
// Continue to next variable
}
}
} catch (error) {
console.log(`Note: ${varName} not available or failed to extract`);
}
});
console.log('\nSearching for external message data...');
// First, let's explore what global variables are available
console.log('Scanning all global variables for potential message data...');
const allGlobalVars = Object.getOwnPropertyNames(window);
// Filter for variables that might contain message/dialogue data
const potentialMessageVars = allGlobalVars.filter(name => {
const lowerName = name.toLowerCase();
return lowerName.includes('extern') ||
lowerName.includes('message') ||
lowerName.includes('csv') ||
lowerName.includes('dialogue') ||
lowerName.includes('dialog') ||
lowerName.includes('text') ||
lowerName.includes('msg') ||
(name.startsWith('$data') && (lowerName.includes('message') || lowerName.includes('csv') || lowerName.includes('extern')));
});
console.log('Found potential message variables:', potentialMessageVars);
// Also log all $data variables for reference
const dataVars = allGlobalVars.filter(name => name.startsWith('$data'));
console.log('All $data variables available:', dataVars);
// Common external message variable patterns to try
const csvVars = [
'$dataExternMessage_ab003',
'$dataExternMessage',
'$dataExtMessage',
'$dataExternalMessage',
'$dataCSV_ab003',
'$dataMessages',
'$dataDialogue',
'$dataExternMessage_ab003_csv',
'$dataCSV',
'externMessage',
'externalMessage',
'$externMessageCSV'
];
// Combine known CSV vars with discovered ones
const allCsvVars = [...new Set([...csvVars, ...potentialMessageVars])];
console.log(`\nTrying to extract from ${allCsvVars.length} potential variables...`);
allCsvVars.forEach(varName => {
try {
const data = window[varName];
if (data !== undefined && data !== null) {
const filename = varName.replace('$data', '').replace('$', '') + '.json';
console.log(`\n🎯 Found data in: ${varName}`);
console.log(`Data type: ${typeof data}`);
console.log(`Data structure: ${Array.isArray(data) ? 'Array' : 'Object'}`);
console.log(`Size: ${Array.isArray(data) ? data.length : Object.keys(data).length} entries`);
// Log a sample of the data to help identify what we found
if (Array.isArray(data) && data.length > 0) {
console.log(`Sample data (first item): ${JSON.stringify(data[0]).substring(0, 100)}...`);
} else if (typeof data === 'object') {
const keys = Object.keys(data).slice(0, 5);
console.log(`Sample keys: ${keys.join(', ')}`);
}
const outputPath = path.join(extractPath, filename);
let content;
// Handle different data formats
if (Array.isArray(data)) {
// If it's an array of strings (CSV-like), also save as .csv
if (data.length > 0 && data.every(item => typeof item === 'string')) {
const csvPath = path.join(extractPath, varName.replace('$data', '').replace('$', '') + '.csv');
fs.writeFileSync(csvPath, data.join('\n'), 'utf8');
console.log(`✓ Also saved as CSV: ${varName.replace('$data', '').replace('$', '') + '.csv'}`);
}
content = JSON.stringify(data, null, 2);
} else if (typeof data === 'string') {
// If it's a string, save both as .txt and JSON
const txtPath = path.join(extractPath, varName.replace('$data', '').replace('$', '') + '.txt');
fs.writeFileSync(txtPath, data, 'utf8');
console.log(`✓ Also saved as TXT: ${varName.replace('$data', '').replace('$', '') + '.txt'}`);
content = JSON.stringify(data, null, 2);
} else {
content = JSON.stringify(data, null, 2);
}
fs.writeFileSync(outputPath, content, 'utf8');
extractedCount++;
results.push(`${filename} - Success (${varName})`);
console.log(`✓ Extracted: ${filename}`);
}
} catch (error) {
// Only log actual errors, not missing variables
if (window[varName] !== undefined) {
console.log(`⚠ Error extracting ${varName}:`, error.message);
}
}
});
// Summary
console.log('\n' + '='.repeat(50));
console.log('EXTRACTION SUMMARY:');
console.log('='.repeat(50));
const totalAttempted = Object.keys(dataMap).length + Object.keys(customDataMap).length + additionalVars.length;
console.log(`Total attempted: ${totalAttempted}`);
console.log(`Successfully extracted: ${extractedCount}`);
console.log(`Failed: ${failedCount}`);
console.log(`Output folder: ${extractPath}`);
console.log('\nDetailed results:');
results.forEach(result => console.log(result));
if (extractedCount > 0) {
console.log(`\n🎉 Extraction complete! Check the 'extracted_data' folder for your files.`);
console.log(`📁 Path: ${extractPath}`);
} else {
console.log('\n❌ No files were successfully extracted. Make sure you are in the game and data is loaded.');
}
return {
success: extractedCount,
failed: failedCount,
total: totalAttempted,
outputPath: extractPath,
results: results
};
})();