Skip to content

Commit 943167a

Browse files
authored
feat: Set d3d and win exec version (#10)
1 parent 1a8d412 commit 943167a

File tree

5 files changed

+230
-10
lines changed

5 files changed

+230
-10
lines changed

games-metadata.js

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,9 @@ function createDefaultMetadata(gameInstallDir = null) {
274274
executable32bit: 'Unknown',
275275
executable64bit: 'Unknown',
276276
vulkanVersions: null,
277-
installDir: gameInstallDir || null
277+
installDir: gameInstallDir || null,
278+
custom_d3d: false,
279+
custom_exec: false
278280
};
279281
}
280282

@@ -404,6 +406,45 @@ function cleanupUninstalledGamesMetadata(installedGames) {
404406
}
405407
}
406408

409+
/**
410+
* Save custom metadata for a game
411+
* @param {string} appId The Steam app ID
412+
* @param {Object} customMetadata The custom metadata to save
413+
* @returns {Object} Result indicating success or failure
414+
*/
415+
async function saveCustomGameMetadata(appId, customMetadata) {
416+
try {
417+
console.log(`Saving custom metadata for game ${appId}:`, customMetadata);
418+
419+
// Load existing metadata
420+
let metadata = loadMetadataFromCache(appId);
421+
422+
if (!metadata) {
423+
console.log(`No existing metadata found for game ${appId}, creating default`);
424+
metadata = createDefaultMetadata();
425+
}
426+
427+
// Merge custom metadata with existing metadata
428+
Object.assign(metadata, customMetadata);
429+
430+
// Save the updated metadata
431+
saveMetadataToCache(appId, metadata);
432+
433+
console.log(`Successfully saved custom metadata for game ${appId}`);
434+
435+
return {
436+
success: true,
437+
message: 'Metadata saved successfully'
438+
};
439+
} catch (error) {
440+
console.error(`Error saving custom metadata for game ${appId}:`, error);
441+
return {
442+
success: false,
443+
message: `Error saving metadata: ${error.message}`
444+
};
445+
}
446+
}
447+
407448
// Export functions
408449
module.exports = {
409450
initCacheDirs,
@@ -413,5 +454,6 @@ module.exports = {
413454
getDxvkInfoForGame,
414455
saveMetadataToCache,
415456
loadMetadataFromCache,
416-
cleanupUninstalledGamesMetadata
457+
cleanupUninstalledGamesMetadata,
458+
saveCustomGameMetadata
417459
};

main.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,3 +579,35 @@ ipcMain.handle('get-game-dxvk-status', async (event, gameId) => {
579579
};
580580
}
581581
});
582+
583+
// IPC handler for saving custom game metadata
584+
ipcMain.handle('save-custom-game-metadata', async (event, gameId, metadataUpdates) => {
585+
try {
586+
console.log(`save-custom-game-metadata IPC handler called for game ${gameId}`);
587+
console.log('Metadata updates:', metadataUpdates);
588+
589+
if (!gameId) {
590+
return { success: false, message: 'Game ID is required' };
591+
}
592+
593+
// Save the custom metadata
594+
const result = await gameMetadata.saveCustomGameMetadata(gameId, metadataUpdates);
595+
596+
// Find the game to get its name for display purpose
597+
const game = steamGames.find(g => g.appid === gameId);
598+
const gameName = game ? game.name : `Game ${gameId}`;
599+
600+
console.log(`Custom metadata saved for ${gameName}:`, result);
601+
602+
return {
603+
success: result.success,
604+
message: result.success ? `Successfully updated metadata for ${gameName}` : result.message
605+
};
606+
} catch (error) {
607+
console.error(`Error saving custom metadata for game ${gameId}:`, error);
608+
return {
609+
success: false,
610+
message: `Error saving custom metadata: ${error.message}`
611+
};
612+
}
613+
});

preload.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ contextBridge.exposeInMainWorld(
3131

3232
// New functions for enhanced DLL management
3333
checkBackupExists: (gameDir) => ipcRenderer.invoke('check-backup-exists', gameDir),
34-
removeDxvkFromGame: (game) => ipcRenderer.invoke('remove-dxvk-from-game', game.appid)
34+
removeDxvkFromGame: (game) => ipcRenderer.invoke('remove-dxvk-from-game', game.appid),
35+
36+
// Game metadata customization
37+
saveCustomGameMetadata: (gameId, metadataUpdates) =>
38+
ipcRenderer.invoke('save-custom-game-metadata', gameId, metadataUpdates)
3539
}
3640
);
3741

renderer.js

Lines changed: 122 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,24 @@ function formatMetadataValue(value) {
3434
return value;
3535
}
3636

37+
// Save custom game metadata
38+
async function saveCustomGameMetadata(gameId, metadataUpdates) {
39+
try {
40+
// Call the main process to save the custom metadata
41+
const result = await window.electronAPI.saveCustomGameMetadata(gameId, metadataUpdates);
42+
if (result.success) {
43+
console.log(`Successfully saved custom metadata for game ${gameId}`);
44+
return true;
45+
} else {
46+
console.error(`Failed to save custom metadata: ${result.message}`);
47+
return false;
48+
}
49+
} catch (error) {
50+
console.error('Error saving custom metadata:', error);
51+
return false;
52+
}
53+
}
54+
3755
// Format date to a readable string
3856
function formatDate(dateString) {
3957
const date = new Date(dateString);
@@ -135,12 +153,53 @@ async function initInstalledGamesTab() {
135153

136154
additionalDetails = `
137155
<div class="detail-row">
138-
<span class="detail-label">Direct3D:</span>
139-
<span class="detail-value">${direct3dInfo}</span>
156+
<span class="detail-label">Direct3D:</span>`;
157+
158+
// If Direct3D info is unknown or custom_d3d is true, show a dropdown selector
159+
if (direct3dInfo === 'No info about Direct3D versions' || metadata.custom_d3d === true) {
160+
additionalDetails += `
161+
<span class="detail-value custom-selector">
162+
<select class="direct3d-selector" data-game-id="${game.appid}">
163+
<option value="">Choose Direct3D version</option>
164+
<option value="Direct3D 8" ${metadata.direct3dVersions === 'Direct3D 8' ? 'selected' : ''}>Direct3D 8</option>
165+
<option value="Direct3D 9" ${metadata.direct3dVersions === 'Direct3D 9' ? 'selected' : ''}>Direct3D 9</option>
166+
<option value="Direct3D 10" ${metadata.direct3dVersions === 'Direct3D 10' ? 'selected' : ''}>Direct3D 10</option>
167+
<option value="Direct3D 11" ${metadata.direct3dVersions === 'Direct3D 11' ? 'selected' : ''}>Direct3D 11</option>
168+
</select>
169+
</span>`;
170+
} else {
171+
additionalDetails += `
172+
<span class="detail-value">${direct3dInfo}</span>`;
173+
}
174+
175+
additionalDetails += `
140176
</div>
141177
<div class="detail-row">
142-
<span class="detail-label">Windows exec:</span>
143-
<span class="detail-value">${executableInfo}</span>
178+
<span class="detail-label">Windows exec:</span>`;
179+
180+
// If executable info is unknown or custom_exec is true, show a dropdown selector
181+
if (executableInfo === 'No info about Windows executable' || metadata.custom_exec === true) {
182+
const is32bit = metadata.executable32bit === 'true';
183+
const is64bit = metadata.executable64bit === 'true';
184+
let selectedValue = '';
185+
186+
if (is32bit) selectedValue = 'x32';
187+
else if (is64bit) selectedValue = 'x64';
188+
189+
additionalDetails += `
190+
<span class="detail-value custom-selector">
191+
<select class="executable-selector" data-game-id="${game.appid}">
192+
<option value="">Choose architecture</option>
193+
<option value="x32" ${selectedValue === 'x32' ? 'selected' : ''}>32-bit</option>
194+
<option value="x64" ${selectedValue === 'x64' ? 'selected' : ''}>64-bit</option>
195+
</select>
196+
</span>`;
197+
} else {
198+
additionalDetails += `
199+
<span class="detail-value">${executableInfo}</span>`;
200+
}
201+
202+
additionalDetails += `
144203
</div>`;
145204
}
146205

@@ -166,11 +225,15 @@ async function initInstalledGamesTab() {
166225
// Only show the button for non-Vulkan games
167226
let buttonHtml = '';
168227
if (!hasVulkan) {
169-
const buttonClass = hasCompleteInfo ? 'action-btn' : 'action-btn disabled';
228+
// Set the button as enabled if:
229+
// 1. We have complete info from PCGamingWiki OR
230+
// 2. We have both custom_d3d and custom_exec (user has selected both values)
231+
const hasCompletedCustomInfo = metadata.custom_d3d === true && metadata.custom_exec === true;
232+
const buttonClass = hasCompleteInfo || hasCompletedCustomInfo ? 'action-btn' : 'action-btn disabled';
170233
const buttonText = dxvkStatus && dxvkStatus.patched ? 'Update DXVK' : 'Manage DXVK';
171234

172235
buttonHtml = '<div class="buttons-container">';
173-
buttonHtml += `<button class="${buttonClass}" data-game-id="${game.appid}" ${!hasCompleteInfo ? 'disabled' : ''}>${buttonText}</button>`;
236+
buttonHtml += `<button class="${buttonClass}" data-game-id="${game.appid}" ${!hasCompleteInfo && !hasCompletedCustomInfo ? 'disabled' : ''}>${buttonText}</button>`;
174237

175238
// Add restore button if game has DXVK installed (patched), regardless of backup status
176239
if (dxvkStatus && dxvkStatus.patched) {
@@ -198,6 +261,58 @@ async function initInstalledGamesTab() {
198261
});
199262
}
200263

264+
// Add event listeners to the dropdowns if they exist
265+
const direct3dSelector = gameCard.querySelector('.direct3d-selector');
266+
if (direct3dSelector) {
267+
direct3dSelector.addEventListener('change', async (e) => {
268+
const gameId = e.target.getAttribute('data-game-id');
269+
const selectedDirect3D = e.target.value;
270+
271+
if (selectedDirect3D) {
272+
console.log(`Selected Direct3D version ${selectedDirect3D} for game ${gameId}`);
273+
274+
// Update the game metadata
275+
const metadataUpdates = {
276+
direct3dVersions: selectedDirect3D,
277+
custom_d3d: true
278+
};
279+
280+
if (await saveCustomGameMetadata(gameId, metadataUpdates)) {
281+
// Reload the installed games tab to reflect changes
282+
await initInstalledGamesTab();
283+
} else {
284+
alert('Failed to save Direct3D information. Please try again.');
285+
}
286+
}
287+
});
288+
}
289+
290+
const executableSelector = gameCard.querySelector('.executable-selector');
291+
if (executableSelector) {
292+
executableSelector.addEventListener('change', async (e) => {
293+
const gameId = e.target.getAttribute('data-game-id');
294+
const selectedExec = e.target.value;
295+
296+
if (selectedExec) {
297+
console.log(`Selected Windows executable architecture ${selectedExec} for game ${gameId}`);
298+
299+
// Update the game metadata
300+
const metadataUpdates = {
301+
executable32bit: selectedExec === 'x32' ? 'true' : 'false',
302+
executable64bit: selectedExec === 'x64' ? 'true' : 'false',
303+
custom_exec: true
304+
};
305+
306+
if (await saveCustomGameMetadata(gameId, metadataUpdates)) {
307+
// Reload the installed games tab to reflect changes
308+
await initInstalledGamesTab();
309+
} else {
310+
alert('Failed to save executable architecture information. Please try again.');
311+
}
312+
}
313+
});
314+
}
315+
201316
// Add event listener to restore button if it exists
202317
const restoreBtn = gameCard.querySelector('.restore-btn');
203318
if (restoreBtn) {
@@ -803,4 +918,4 @@ async function initDxvkGplasyncTab() {
803918
console.error('Error getting DXVK-gplasync releases:', error);
804919
gplasyncContainer.innerHTML = `<p>Error loading DXVK-gplasync releases: ${error.message}</p>`;
805920
}
806-
}
921+
}

styles.css

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,33 @@ h2 {
195195
border: 1px solid #e0e0e0;
196196
}
197197

198+
/* Custom selector styles */
199+
.custom-selector select {
200+
padding: 4px 8px;
201+
border-radius: 4px;
202+
border: 1px solid #ccc;
203+
background-color: #fff;
204+
font-size: 14px;
205+
color: #333;
206+
width: 100%;
207+
max-width: 200px;
208+
transition: border-color 0.3s;
209+
}
210+
211+
.custom-selector select:hover {
212+
border-color: #3498db;
213+
}
214+
215+
.custom-selector select:focus {
216+
outline: none;
217+
border-color: #3498db;
218+
box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
219+
}
220+
221+
.custom-selector select option {
222+
padding: 4px;
223+
}
224+
198225
/* DXVK Status Styles */
199226
.dxvk-status {
200227
margin-top: 5px;

0 commit comments

Comments
 (0)