You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
6.6 KiB
232 lines
6.6 KiB
// File Manager functionality |
|
(function() { |
|
const modal = document.getElementById('fileManagerModal'); |
|
const fileManagerBtn = document.getElementById('fileManagerBtn'); |
|
const closeModalBtn = document.getElementById('closeModal'); |
|
const dropZone = document.getElementById('dropZone'); |
|
const fileInput = document.getElementById('fileInput'); |
|
const browseBtn = document.getElementById('browseBtn'); |
|
const resetSettingsBtn = document.getElementById('resetSettingsBtn'); |
|
const mpqFilesList = document.getElementById('mpqFilesList'); |
|
|
|
// Open/close modal |
|
fileManagerBtn.addEventListener('click', () => { |
|
modal.classList.add('show'); |
|
refreshFileList(); |
|
}); |
|
|
|
closeModalBtn.addEventListener('click', () => { |
|
modal.classList.remove('show'); |
|
}); |
|
|
|
modal.addEventListener('click', (e) => { |
|
if (e.target === modal) { |
|
modal.classList.remove('show'); |
|
} |
|
}); |
|
|
|
// Browse button |
|
browseBtn.addEventListener('click', () => { |
|
fileInput.click(); |
|
}); |
|
|
|
// Drag and drop |
|
dropZone.addEventListener('click', () => { |
|
fileInput.click(); |
|
}); |
|
|
|
dropZone.addEventListener('dragover', (e) => { |
|
e.preventDefault(); |
|
dropZone.classList.add('dragover'); |
|
}); |
|
|
|
dropZone.addEventListener('dragleave', () => { |
|
dropZone.classList.remove('dragover'); |
|
}); |
|
|
|
dropZone.addEventListener('drop', (e) => { |
|
e.preventDefault(); |
|
dropZone.classList.remove('dragover'); |
|
handleFiles(e.dataTransfer.files); |
|
}); |
|
|
|
fileInput.addEventListener('change', (e) => { |
|
handleFiles(e.target.files); |
|
}); |
|
|
|
// Handle file upload |
|
function handleFiles(files) { |
|
if (!files || files.length === 0) return; |
|
|
|
// Wait for Module and FS to be ready |
|
if (typeof Module === 'undefined' || typeof FS === 'undefined') { |
|
alert('Game is still loading. Please wait and try again.'); |
|
return; |
|
} |
|
|
|
const mpqFiles = Array.from(files).filter(f => |
|
f.name.toLowerCase().endsWith('.mpq') |
|
); |
|
|
|
if (mpqFiles.length === 0) { |
|
alert('Please select MPQ files only.'); |
|
return; |
|
} |
|
|
|
let processed = 0; |
|
mpqFiles.forEach(file => { |
|
const reader = new FileReader(); |
|
reader.onload = function(e) { |
|
try { |
|
const data = new Uint8Array(e.target.result); |
|
// Upload to the devilution subdirectory where the game searches |
|
const path = '/libsdl/diasurgical/devilution/' + file.name; // Might want to make this dynamic later, since source mods might rename the paths |
|
|
|
// Create directory if it doesn't exist |
|
try { |
|
FS.mkdir('/libsdl/diasurgical/devilution'); |
|
} catch (e) { |
|
// Directory might already exist, ignore |
|
} |
|
|
|
// Write file to IDBFS-backed directory |
|
FS.writeFile(path, data); |
|
console.log('Uploaded:', file.name, '(' + formatBytes(file.size) + ')'); |
|
|
|
processed++; |
|
if (processed === mpqFiles.length) { |
|
// Sync to IndexedDB |
|
FS.syncfs(false, function(err) { |
|
if (err) { |
|
console.error('Error syncing files:', err); |
|
alert('Error saving files. Check console.'); |
|
} else { |
|
alert('Files uploaded successfully! Reloading game...'); |
|
setTimeout(() => location.reload(), 500); |
|
} |
|
}); |
|
} |
|
} catch (err) { |
|
console.error('Error writing file:', err); |
|
alert('Error uploading file: ' + file.name); |
|
} |
|
}; |
|
reader.readAsArrayBuffer(file); |
|
}); |
|
} |
|
|
|
// Refresh file list |
|
function refreshFileList() { |
|
if (typeof Module === 'undefined' || typeof FS === 'undefined') { |
|
mpqFilesList.innerHTML = '<p class="info-text">Game is loading...</p>'; |
|
return; |
|
} |
|
|
|
try { |
|
// Check if devilution directory exists |
|
try { |
|
FS.stat('/libsdl/diasurgical/devilution'); |
|
} catch (e) { |
|
// Directory doesn't exist yet |
|
mpqFilesList.innerHTML = '<p class="info-text">No MPQ files found.</p>'; |
|
return; |
|
} |
|
|
|
const files = FS.readdir('/libsdl/diasurgical/devilution'); |
|
const mpqFiles = files.filter(f => |
|
f.toLowerCase().endsWith('.mpq') && f !== '.' && f !== '..' |
|
); |
|
|
|
if (mpqFiles.length === 0) { |
|
mpqFilesList.innerHTML = '<p class="info-text">No MPQ files found.</p>'; |
|
return; |
|
} |
|
|
|
mpqFilesList.innerHTML = mpqFiles.map(filename => { |
|
const path = '/libsdl/diasurgical/devilution/' + filename; |
|
const stat = FS.stat(path); |
|
return ` |
|
<div class="file-item"> |
|
<span class="file-item-name">${filename}</span> |
|
<span class="file-item-size">${formatBytes(stat.size)}</span> |
|
<button class="btn btn-delete" onclick="deleteFile('${filename}')">Delete</button> |
|
</div> |
|
`; |
|
}).join(''); |
|
} catch (err) { |
|
console.error('Error reading files:', err); |
|
mpqFilesList.innerHTML = '<p class="info-text">Error reading files.</p>'; |
|
} |
|
} |
|
|
|
// Delete file |
|
window.deleteFile = function(filename) { |
|
if (!confirm('Delete ' + filename + '? This will reload the game.')) { |
|
return; |
|
} |
|
|
|
try { |
|
const path = '/libsdl/diasurgical/devilution/' + filename; |
|
FS.unlink(path); |
|
|
|
// Sync deletion to IndexedDB |
|
FS.syncfs(false, function(err) { |
|
if (err) { |
|
console.error('Error syncing deletion:', err); |
|
alert('Error deleting file. Check console.'); |
|
} else { |
|
alert('File deleted! Reloading game...'); |
|
setTimeout(() => location.reload(), 500); |
|
} |
|
}); |
|
} catch (err) { |
|
console.error('Error deleting file:', err); |
|
alert('Error deleting file: ' + filename); |
|
} |
|
}; |
|
|
|
// Reset settings |
|
resetSettingsBtn.addEventListener('click', () => { |
|
if (!confirm('Reset game settings? This will delete diablo.ini but keep your saves. The game will reload.')) { |
|
return; |
|
} |
|
|
|
try { |
|
const iniPath = '/libsdl/diasurgical/devilution/diablo.ini'; |
|
|
|
// Check if file exists |
|
try { |
|
FS.stat(iniPath); |
|
// File exists, delete it |
|
FS.unlink(iniPath); |
|
console.log('Deleted diablo.ini'); |
|
} catch (e) { |
|
// File doesn't exist, that's fine |
|
console.log('diablo.ini not found (already reset)'); |
|
} |
|
|
|
// Sync to IndexedDB |
|
FS.syncfs(false, function(err) { |
|
if (err) { |
|
console.error('Error syncing settings reset:', err); |
|
alert('Error resetting settings. Check console.'); |
|
} else { |
|
alert('Settings reset! Reloading game...'); |
|
setTimeout(() => location.reload(), 500); |
|
} |
|
}); |
|
} catch (err) { |
|
console.error('Error resetting settings:', err); |
|
alert('Error resetting settings.'); |
|
} |
|
}); |
|
|
|
// Helper function |
|
function formatBytes(bytes) { |
|
if (bytes === 0) return '0 Bytes'; |
|
const k = 1024; |
|
const sizes = ['Bytes', 'KB', 'MB', 'GB']; |
|
const i = Math.floor(Math.log(bytes) / Math.log(k)); |
|
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]; |
|
} |
|
})();
|
|
|