mirror of
https://git.sanhost.net/sanasol/hytale-f2p
synced 2026-02-26 16:21:49 -03:00
Merge branch 'main' of https://github.com/fazrigading/Hytale-F2P
This commit is contained in:
@@ -365,6 +365,41 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-input-group">
|
||||||
|
<label class="settings-input-label">GPU Preference</label>
|
||||||
|
<div class="segmented-control">
|
||||||
|
<input type="radio" id="gpu-auto" name="gpuPreference" value="auto" checked>
|
||||||
|
<label for="gpu-auto">Auto</label>
|
||||||
|
<input type="radio" id="gpu-integrated" name="gpuPreference" value="integrated">
|
||||||
|
<label for="gpu-integrated">Integrated</label>
|
||||||
|
<input type="radio" id="gpu-dedicated" name="gpuPreference" value="dedicated">
|
||||||
|
<label for="gpu-dedicated">Dedicated</label>
|
||||||
|
</div>
|
||||||
|
<p class="settings-hint">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
Select your preferred GPU (Linux: affects DRI_PRIME)
|
||||||
|
</p>
|
||||||
|
<div id="gpu-detection-info" class="gpu-detection-info"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-section">
|
||||||
|
<h3 class="settings-section-title">
|
||||||
|
<i class="fab fa-discord"></i>
|
||||||
|
Discord Integration
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="settings-option">
|
||||||
|
<label class="settings-checkbox">
|
||||||
|
<input type="checkbox" id="discordRPCCheck" checked />
|
||||||
|
<span class="checkmark"></span>
|
||||||
|
<div class="checkbox-content">
|
||||||
|
<div class="checkbox-title">Enable Discord Rich Presence</div>
|
||||||
|
<div class="checkbox-description">Show your launcher activity on Discord</div>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
@@ -406,6 +441,48 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-section">
|
||||||
|
<h3 class="settings-section-title">
|
||||||
|
<i class="fas fa-coffee"></i>
|
||||||
|
Java Runtime
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="settings-option">
|
||||||
|
<label class="settings-checkbox">
|
||||||
|
<input type="checkbox" id="customJavaCheck" />
|
||||||
|
<span class="checkmark"></span>
|
||||||
|
<div class="checkbox-content">
|
||||||
|
<div class="checkbox-title">Use Custom Java Path</div>
|
||||||
|
<div class="checkbox-description">Override the bundled Java runtime with your own installation</div>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="customJavaOptions" class="custom-java-options" style="display: none;">
|
||||||
|
<div class="settings-input-group">
|
||||||
|
<label class="settings-input-label">Java Executable Path</label>
|
||||||
|
<div class="settings-input-with-button">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="customJavaPath"
|
||||||
|
class="settings-input"
|
||||||
|
placeholder="Select Java path..."
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
|
<button id="browseJavaBtn" class="settings-browse-btn">
|
||||||
|
<i class="fas fa-folder-open"></i>
|
||||||
|
Browse
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p class="settings-hint">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
Select the Java installation folder (supports Windows, Mac, Linux)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -212,6 +212,15 @@ export async function launch() {
|
|||||||
javaPath = window.SettingsAPI.getCurrentJavaPath();
|
javaPath = window.SettingsAPI.getCurrentJavaPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let gpuPreference = 'auto';
|
||||||
|
try {
|
||||||
|
if (window.electronAPI && window.electronAPI.loadGpuPreference) {
|
||||||
|
gpuPreference = await window.electronAPI.loadGpuPreference();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading GPU preference:', error);
|
||||||
|
}
|
||||||
|
|
||||||
if (window.LauncherUI) window.LauncherUI.showProgress();
|
if (window.LauncherUI) window.LauncherUI.showProgress();
|
||||||
isDownloading = true;
|
isDownloading = true;
|
||||||
if (playBtn) {
|
if (playBtn) {
|
||||||
@@ -223,7 +232,7 @@ export async function launch() {
|
|||||||
if (window.LauncherUI) window.LauncherUI.updateProgress({ message: 'Starting game...' });
|
if (window.LauncherUI) window.LauncherUI.updateProgress({ message: 'Starting game...' });
|
||||||
|
|
||||||
if (window.electronAPI && window.electronAPI.launchGame) {
|
if (window.electronAPI && window.electronAPI.launchGame) {
|
||||||
const result = await window.electronAPI.launchGame(playerName, javaPath, '');
|
const result = await window.electronAPI.launchGame(playerName, javaPath, '', gpuPreference);
|
||||||
|
|
||||||
isDownloading = false;
|
isDownloading = false;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ let customJavaPath;
|
|||||||
let browseJavaBtn;
|
let browseJavaBtn;
|
||||||
let settingsPlayerName;
|
let settingsPlayerName;
|
||||||
let discordRPCCheck;
|
let discordRPCCheck;
|
||||||
|
let gpuPreferenceRadios;
|
||||||
|
|
||||||
// UUID Management elements
|
// UUID Management elements
|
||||||
let currentUuidDisplay;
|
let currentUuidDisplay;
|
||||||
@@ -142,6 +143,7 @@ function showCustomConfirm(message, title = 'Confirm Action', onConfirm, onCance
|
|||||||
document.addEventListener('keydown', handleEscape);
|
document.addEventListener('keydown', handleEscape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function initSettings() {
|
export function initSettings() {
|
||||||
setupSettingsElements();
|
setupSettingsElements();
|
||||||
loadAllSettings();
|
loadAllSettings();
|
||||||
@@ -154,6 +156,7 @@ function setupSettingsElements() {
|
|||||||
browseJavaBtn = document.getElementById('browseJavaBtn');
|
browseJavaBtn = document.getElementById('browseJavaBtn');
|
||||||
settingsPlayerName = document.getElementById('settingsPlayerName');
|
settingsPlayerName = document.getElementById('settingsPlayerName');
|
||||||
discordRPCCheck = document.getElementById('discordRPCCheck');
|
discordRPCCheck = document.getElementById('discordRPCCheck');
|
||||||
|
gpuPreferenceRadios = document.querySelectorAll('input[name="gpuPreference"]');
|
||||||
|
|
||||||
// UUID Management elements
|
// UUID Management elements
|
||||||
currentUuidDisplay = document.getElementById('currentUuid');
|
currentUuidDisplay = document.getElementById('currentUuid');
|
||||||
@@ -226,6 +229,15 @@ function setupSettingsElements() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gpuPreferenceRadios) {
|
||||||
|
gpuPreferenceRadios.forEach(radio => {
|
||||||
|
radio.addEventListener('change', async () => {
|
||||||
|
await saveGpuPreference();
|
||||||
|
await updateGpuLabel();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleCustomJava() {
|
function toggleCustomJava() {
|
||||||
@@ -361,11 +373,85 @@ async function loadPlayerName() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function saveGpuPreference() {
|
||||||
|
try {
|
||||||
|
if (window.electronAPI && window.electronAPI.saveGpuPreference && gpuPreferenceRadios) {
|
||||||
|
const gpuPreference = Array.from(gpuPreferenceRadios).find(radio => radio.checked)?.value || 'auto';
|
||||||
|
await window.electronAPI.saveGpuPreference(gpuPreference);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error saving GPU preference:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateGpuLabel() {
|
||||||
|
const detectionInfo = document.getElementById('gpu-detection-info');
|
||||||
|
if (!detectionInfo) return;
|
||||||
|
|
||||||
|
if (gpuPreferenceRadios) {
|
||||||
|
const checked = Array.from(gpuPreferenceRadios).find(radio => radio.checked);
|
||||||
|
if (checked) {
|
||||||
|
try {
|
||||||
|
if (window.electronAPI && window.electronAPI.getDetectedGpu) {
|
||||||
|
const detected = await window.electronAPI.getDetectedGpu();
|
||||||
|
if (checked.value === 'auto') {
|
||||||
|
if (detected.dedicatedName) {
|
||||||
|
detectionInfo.textContent = `dGPU detected, using ${detected.dedicatedName}`;
|
||||||
|
} else {
|
||||||
|
detectionInfo.textContent = `dGPU not detected, using iGPU (${detected.integratedName}) instead`;
|
||||||
|
}
|
||||||
|
detectionInfo.style.display = 'block';
|
||||||
|
} else if (checked.value === 'integrated') {
|
||||||
|
detectionInfo.textContent = `Detected: ${detected.integratedName}`;
|
||||||
|
detectionInfo.style.display = 'block';
|
||||||
|
} else if (checked.value === 'dedicated') {
|
||||||
|
if (detected.dedicatedName) {
|
||||||
|
detectionInfo.textContent = `Detected: ${detected.dedicatedName}`;
|
||||||
|
} else {
|
||||||
|
detectionInfo.textContent = `No dedicated GPU detected`;
|
||||||
|
}
|
||||||
|
detectionInfo.style.display = 'block';
|
||||||
|
} else {
|
||||||
|
detectionInfo.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting detected GPU:', error);
|
||||||
|
detectionInfo.style.display = 'none';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
detectionInfo.style.display = 'none';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
detectionInfo.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadGpuPreference() {
|
||||||
|
try {
|
||||||
|
if (window.electronAPI && window.electronAPI.loadGpuPreference && gpuPreferenceRadios) {
|
||||||
|
const savedPreference = await window.electronAPI.loadGpuPreference();
|
||||||
|
if (savedPreference) {
|
||||||
|
for (const radio of gpuPreferenceRadios) {
|
||||||
|
if (radio.value === savedPreference) {
|
||||||
|
radio.checked = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await updateGpuLabel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading GPU preference:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function loadAllSettings() {
|
async function loadAllSettings() {
|
||||||
await loadCustomJavaPath();
|
await loadCustomJavaPath();
|
||||||
await loadPlayerName();
|
await loadPlayerName();
|
||||||
await loadCurrentUuid();
|
await loadCurrentUuid();
|
||||||
await loadDiscordRPC();
|
await loadDiscordRPC();
|
||||||
|
await loadGpuPreference();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openGameLocation() {
|
async function openGameLocation() {
|
||||||
|
|||||||
@@ -1005,6 +1005,7 @@ body {
|
|||||||
transform: translateY(0.5rem);
|
transform: translateY(0.5rem);
|
||||||
transition: all 0.3s ease 0.1s;
|
transition: all 0.3s ease 0.1s;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
|
line-clamp: 2;
|
||||||
-webkit-line-clamp: 2;
|
-webkit-line-clamp: 2;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -1888,6 +1889,7 @@ body {
|
|||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
margin: 0.75rem 0;
|
margin: 0.75rem 0;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
|
line-clamp: 3;
|
||||||
-webkit-line-clamp: 3;
|
-webkit-line-clamp: 3;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -2675,6 +2677,7 @@ body {
|
|||||||
color: rgba(255, 255, 255, 0.5);
|
color: rgba(255, 255, 255, 0.5);
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
|
line-clamp: 2;
|
||||||
-webkit-line-clamp: 2;
|
-webkit-line-clamp: 2;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -3095,6 +3098,7 @@ body {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
|
line-clamp: 2;
|
||||||
-webkit-line-clamp: 2;
|
-webkit-line-clamp: 2;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
@@ -3758,7 +3762,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.settings-header {
|
.settings-header {
|
||||||
margin-bottom: 3rem;
|
margin-bottom: 1rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4047,6 +4051,14 @@ body {
|
|||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gpu-detection-info {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
font-weight: 500;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#settings-page {
|
#settings-page {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -4078,7 +4090,53 @@ body {
|
|||||||
background: linear-gradient(135deg, #a855f7, #60a5fa);
|
background: linear-gradient(135deg, #a855f7, #60a5fa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.segmented-control {
|
||||||
|
display: flex;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 8px;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
.segmented-control input[type="radio"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.segmented-control label {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
color: #d1d5db;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
background: transparent;
|
||||||
|
border-right: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
font-family: 'JetBrains Mono', monospace;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.segmented-control label:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
.segmented-control input[type="radio"]:checked + label {
|
||||||
|
background: linear-gradient(135deg, #9333ea, #3b82f6);
|
||||||
|
color: white;
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
.segmented-control label:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.segmented-control input[type="radio"]:checked + label:hover {
|
||||||
|
background: linear-gradient(135deg, #7c3aed, #2563eb);
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
.segmented-control:focus-within {
|
||||||
|
border-color: rgba(147, 51, 234, 0.3);
|
||||||
|
box-shadow: 0 0 20px rgba(147, 51, 234, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#update-popup-overlay {
|
#update-popup-overlay {
|
||||||
|
|||||||
@@ -277,6 +277,15 @@ function loadChatColor() {
|
|||||||
return config.chatColor || '#3498db';
|
return config.chatColor || '#3498db';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saveGpuPreference(gpuPreference) {
|
||||||
|
saveConfig({ gpuPreference: gpuPreference || 'auto' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadGpuPreference() {
|
||||||
|
const config = loadConfig();
|
||||||
|
return config.gpuPreference || 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
loadConfig,
|
loadConfig,
|
||||||
saveConfig,
|
saveConfig,
|
||||||
@@ -308,5 +317,8 @@ module.exports = {
|
|||||||
setUuidForUser,
|
setUuidForUser,
|
||||||
generateNewUuid,
|
generateNewUuid,
|
||||||
deleteUuidForUser,
|
deleteUuidForUser,
|
||||||
resetCurrentUserUuid
|
resetCurrentUserUuid,
|
||||||
|
// GPU Preference exports
|
||||||
|
saveGpuPreference,
|
||||||
|
loadGpuPreference
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,14 +20,16 @@ const {
|
|||||||
getUuidForUser,
|
getUuidForUser,
|
||||||
isFirstLaunch,
|
isFirstLaunch,
|
||||||
markAsLaunched,
|
markAsLaunched,
|
||||||
CONFIG_FILE,
|
|
||||||
// UUID Management
|
// UUID Management
|
||||||
getCurrentUuid,
|
getCurrentUuid,
|
||||||
getAllUuidMappings,
|
getAllUuidMappings,
|
||||||
setUuidForUser,
|
setUuidForUser,
|
||||||
generateNewUuid,
|
generateNewUuid,
|
||||||
deleteUuidForUser,
|
deleteUuidForUser,
|
||||||
resetCurrentUserUuid
|
resetCurrentUserUuid,
|
||||||
|
// GPU Preference
|
||||||
|
saveGpuPreference,
|
||||||
|
loadGpuPreference
|
||||||
} = require('./core/config');
|
} = require('./core/config');
|
||||||
|
|
||||||
const { getResolvedAppDir, getModsPath } = require('./core/paths');
|
const { getResolvedAppDir, getModsPath } = require('./core/paths');
|
||||||
@@ -77,6 +79,9 @@ const {
|
|||||||
handleFirstLaunchCheck
|
handleFirstLaunchCheck
|
||||||
} = require('./services/firstLaunch');
|
} = require('./services/firstLaunch');
|
||||||
|
|
||||||
|
// Utils
|
||||||
|
const { detectGpu } = require('./utils/platformUtils');
|
||||||
|
|
||||||
// Re-export all functions to maintain backward compatibility
|
// Re-export all functions to maintain backward compatibility
|
||||||
module.exports = {
|
module.exports = {
|
||||||
// Game launch functions
|
// Game launch functions
|
||||||
@@ -111,6 +116,11 @@ module.exports = {
|
|||||||
saveDiscordRPC,
|
saveDiscordRPC,
|
||||||
loadDiscordRPC,
|
loadDiscordRPC,
|
||||||
|
|
||||||
|
// GPU Preference functions
|
||||||
|
saveGpuPreference,
|
||||||
|
loadGpuPreference,
|
||||||
|
detectGpu,
|
||||||
|
|
||||||
// Version functions
|
// Version functions
|
||||||
getInstalledClientVersion,
|
getInstalledClientVersion,
|
||||||
getLatestClientVersion,
|
getLatestClientVersion,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const { promisify } = require('util');
|
|||||||
const { spawn } = require('child_process');
|
const { spawn } = require('child_process');
|
||||||
const { v4: uuidv4 } = require('uuid');
|
const { v4: uuidv4 } = require('uuid');
|
||||||
const { getResolvedAppDir, findClientPath } = require('../core/paths');
|
const { getResolvedAppDir, findClientPath } = require('../core/paths');
|
||||||
const { setupWaylandEnvironment } = require('../utils/platformUtils');
|
const { setupWaylandEnvironment, setupGpuEnvironment } = require('../utils/platformUtils');
|
||||||
const { saveUsername, saveInstallPath, loadJavaPath, getUuidForUser, getAuthServerUrl, getAuthDomain } = require('../core/config');
|
const { saveUsername, saveInstallPath, loadJavaPath, getUuidForUser, getAuthServerUrl, getAuthDomain } = require('../core/config');
|
||||||
const { resolveJavaPath, getJavaExec, getBundledJavaPath, detectSystemJava, JAVA_EXECUTABLE } = require('./javaManager');
|
const { resolveJavaPath, getJavaExec, getBundledJavaPath, detectSystemJava, JAVA_EXECUTABLE } = require('./javaManager');
|
||||||
const { getInstalledClientVersion, getLatestClientVersion } = require('../services/versionManager');
|
const { getInstalledClientVersion, getLatestClientVersion } = require('../services/versionManager');
|
||||||
@@ -101,7 +101,7 @@ function generateLocalTokens(uuid, name) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function launchGame(playerName = 'Player', progressCallback, javaPathOverride, installPathOverride) {
|
async function launchGame(playerName = 'Player', progressCallback, javaPathOverride, installPathOverride, gpuPreference = 'auto') {
|
||||||
const customAppDir = getResolvedAppDir(installPathOverride);
|
const customAppDir = getResolvedAppDir(installPathOverride);
|
||||||
const customGameDir = path.join(customAppDir, 'release', 'package', 'game', 'latest');
|
const customGameDir = path.join(customAppDir, 'release', 'package', 'game', 'latest');
|
||||||
const customJreDir = path.join(customAppDir, 'release', 'package', 'jre', 'latest');
|
const customJreDir = path.join(customAppDir, 'release', 'package', 'jre', 'latest');
|
||||||
@@ -281,6 +281,9 @@ exec "$REAL_JAVA" "\${ARGS[@]}"
|
|||||||
const waylandEnv = setupWaylandEnvironment();
|
const waylandEnv = setupWaylandEnvironment();
|
||||||
Object.assign(env, waylandEnv);
|
Object.assign(env, waylandEnv);
|
||||||
|
|
||||||
|
const gpuEnv = setupGpuEnvironment(gpuPreference);
|
||||||
|
Object.assign(env, gpuEnv);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let spawnOptions = {
|
let spawnOptions = {
|
||||||
stdio: ['ignore', 'pipe', 'pipe'],
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
@@ -352,7 +355,7 @@ exec "$REAL_JAVA" "\${ARGS[@]}"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function launchGameWithVersionCheck(playerName = 'Player', progressCallback, javaPathOverride, installPathOverride) {
|
async function launchGameWithVersionCheck(playerName = 'Player', progressCallback, javaPathOverride, installPathOverride, gpuPreference = 'auto') {
|
||||||
try {
|
try {
|
||||||
if (progressCallback) {
|
if (progressCallback) {
|
||||||
progressCallback('Checking for updates...', 0, null, null, null);
|
progressCallback('Checking for updates...', 0, null, null, null);
|
||||||
@@ -403,7 +406,7 @@ async function launchGameWithVersionCheck(playerName = 'Player', progressCallbac
|
|||||||
progressCallback('Launching game...', 80, null, null, null);
|
progressCallback('Launching game...', 80, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await launchGame(playerName, progressCallback, javaPathOverride, installPathOverride);
|
return await launchGame(playerName, progressCallback, javaPathOverride, installPathOverride, gpuPreference);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in version check and launch:', error);
|
console.error('Error in version check and launch:', error);
|
||||||
if (progressCallback) {
|
if (progressCallback) {
|
||||||
|
|||||||
@@ -65,9 +65,100 @@ function setupWaylandEnvironment() {
|
|||||||
return envVars;
|
return envVars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function detectGpu() {
|
||||||
|
if (process.platform !== 'linux') {
|
||||||
|
return { mode: 'integrated', vendor: 'intel', integratedName: 'Unknown', dedicatedName: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const output = execSync('lspci -nn | grep \'VGA\\|3D\'', { encoding: 'utf8' });
|
||||||
|
// console.log('GPU detection raw output:', output);
|
||||||
|
const lines = output.split('\n').filter(line => line.trim());
|
||||||
|
// console.log('GPU detection parsed lines:', lines);
|
||||||
|
|
||||||
|
let integratedName = null;
|
||||||
|
let dedicatedName = null;
|
||||||
|
let hasNvidia = false;
|
||||||
|
let hasAmd = false;
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
// console.log('Checking line:', line);
|
||||||
|
if (line.includes('VGA') || line.includes('3D')) {
|
||||||
|
// console.log('Line contains VGA or 3D');
|
||||||
|
|
||||||
|
const match = line.match(/\[([^\]]+)\]/g);
|
||||||
|
let modelName = null;
|
||||||
|
if (match && match.length >= 2) {
|
||||||
|
modelName = match[1].slice(1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.includes('10de:') || line.toLowerCase().includes('nvidia')) {
|
||||||
|
hasNvidia = true;
|
||||||
|
dedicatedName = "NVIDIA " + modelName || 'NVIDIA GPU';
|
||||||
|
console.log('Detected NVIDIA GPU:', dedicatedName);
|
||||||
|
} else if (line.includes('1002:') || line.toLowerCase().includes('amd') || line.toLowerCase().includes('radeon')) {
|
||||||
|
hasAmd = true;
|
||||||
|
dedicatedName = "AMD " + modelName || 'AMD GPU';
|
||||||
|
console.log('Detected AMD GPU:', dedicatedName);
|
||||||
|
} else if (line.includes('8086:') || line.toLowerCase().includes('intel')) {
|
||||||
|
integratedName = "Intel " + modelName || 'Intel GPU';
|
||||||
|
console.log('Detected Intel GPU:', integratedName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log('hasNvidia:', hasNvidia, 'hasAmd:', hasAmd, 'integratedName:', integratedName, 'dedicatedName:', dedicatedName);
|
||||||
|
|
||||||
|
if (hasNvidia) {
|
||||||
|
return { mode: 'dedicated', vendor: 'nvidia', integratedName: integratedName || 'Intel GPU', dedicatedName };
|
||||||
|
} else if (hasAmd) {
|
||||||
|
return { mode: 'dedicated', vendor: 'amd', integratedName: integratedName || 'Intel GPU', dedicatedName };
|
||||||
|
} else {
|
||||||
|
return { mode: 'integrated', vendor: 'intel', integratedName: integratedName || 'Intel GPU', dedicatedName: null };
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('GPU detection failed, falling back to integrated:', error.message);
|
||||||
|
return { mode: 'integrated', vendor: 'intel', integratedName: 'Unknown', dedicatedName: null };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupGpuEnvironment(gpuPreference) {
|
||||||
|
if (process.platform !== 'linux') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
let finalPreference = gpuPreference;
|
||||||
|
let detected = detectGpu();
|
||||||
|
|
||||||
|
if (gpuPreference === 'auto') {
|
||||||
|
finalPreference = detected.mode;
|
||||||
|
console.log(`Auto-detected GPU: ${detected.vendor} (${detected.mode})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Preferred GPU set to:', finalPreference);
|
||||||
|
|
||||||
|
const envVars = {};
|
||||||
|
|
||||||
|
if (finalPreference === 'dedicated') {
|
||||||
|
envVars.DRI_PRIME = '1';
|
||||||
|
if (detected.vendor === 'nvidia') {
|
||||||
|
envVars.__NV_PRIME_RENDER_OFFLOAD = '1';
|
||||||
|
envVars.__GLX_VENDOR_LIBRARY_NAME = 'nvidia';
|
||||||
|
envVars.__GL_SHADER_DISK_CACHE = '1';
|
||||||
|
envVars.__GL_SHADER_DISK_CACHE_PATH = '/tmp';
|
||||||
|
}
|
||||||
|
console.log('GPU environment variables:', envVars);
|
||||||
|
} else {
|
||||||
|
console.log('Using integrated GPU, no environment variables set');
|
||||||
|
}
|
||||||
|
return envVars;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getOS,
|
getOS,
|
||||||
getArch,
|
getArch,
|
||||||
isWaylandSession,
|
isWaylandSession,
|
||||||
setupWaylandEnvironment
|
setupWaylandEnvironment,
|
||||||
|
detectGpu,
|
||||||
|
setupGpuEnvironment
|
||||||
};
|
};
|
||||||
|
|||||||
46
main.js
46
main.js
@@ -161,6 +161,19 @@ app.whenReady().then(async () => {
|
|||||||
console.log('Node.js version:', process.versions.node);
|
console.log('Node.js version:', process.versions.node);
|
||||||
console.log('Log directory:', logger.getLogDirectory());
|
console.log('Log directory:', logger.getLogDirectory());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { loadGpuPreference, detectGpu } = require('./backend/launcher');
|
||||||
|
const savedPreference = loadGpuPreference();
|
||||||
|
if (savedPreference === 'auto') {
|
||||||
|
global.detectedGpu = detectGpu(); // if 'auto' selected = preload GPU detection
|
||||||
|
console.log('GPU auto-detection completed on startup:', global.detectedGpu);
|
||||||
|
} else {
|
||||||
|
console.log('GPU preference is manual, skipping auto-detection');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Failed to preload GPU detection:', error.message);
|
||||||
|
global.detectedGpu = { mode: 'integrated', vendor: 'intel' };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Initialize Profile Manager (runs migration if needed)
|
// Initialize Profile Manager (runs migration if needed)
|
||||||
@@ -282,7 +295,7 @@ app.on('window-all-closed', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('launch-game', async (event, playerName, javaPath, installPath) => {
|
ipcMain.handle('launch-game', async (event, playerName, javaPath, installPath, gpuPreference) => {
|
||||||
try {
|
try {
|
||||||
const progressCallback = (message, percent, speed, downloaded, total) => {
|
const progressCallback = (message, percent, speed, downloaded, total) => {
|
||||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||||
@@ -297,7 +310,7 @@ ipcMain.handle('launch-game', async (event, playerName, javaPath, installPath) =
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await launchGameWithVersionCheck(playerName, progressCallback, javaPath, installPath);
|
const result = await launchGameWithVersionCheck(playerName, progressCallback, javaPath, installPath, gpuPreference);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -710,6 +723,35 @@ ipcMain.handle('get-update-info', async () => {
|
|||||||
return updateManager.getUpdateInfo();
|
return updateManager.getUpdateInfo();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('get-gpu-info', () => {
|
||||||
|
try {
|
||||||
|
return app.getGPUInfo('complete');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting GPU info:', error);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('save-gpu-preference', (event, gpuPreference) => {
|
||||||
|
const { saveGpuPreference } = require('./backend/launcher');
|
||||||
|
saveGpuPreference(gpuPreference);
|
||||||
|
return { success: true };
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('load-gpu-preference', () => {
|
||||||
|
const { loadGpuPreference } = require('./backend/launcher');
|
||||||
|
return loadGpuPreference();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('get-detected-gpu', () => {
|
||||||
|
if (global.detectedGpu) {
|
||||||
|
return global.detectedGpu;
|
||||||
|
}
|
||||||
|
const { detectGpu } = require('./backend/launcher');
|
||||||
|
global.detectedGpu = detectGpu();
|
||||||
|
return global.detectedGpu;
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.handle('window-close', () => {
|
ipcMain.handle('window-close', () => {
|
||||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||||
mainWindow.close();
|
mainWindow.close();
|
||||||
|
|||||||
@@ -93,6 +93,3 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const { contextBridge, ipcRenderer } = require('electron');
|
const { contextBridge, ipcRenderer } = require('electron');
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('electronAPI', {
|
contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
launchGame: (playerName, javaPath, installPath) => ipcRenderer.invoke('launch-game', playerName, javaPath, installPath),
|
launchGame: (playerName, javaPath, installPath, gpuPreference) => ipcRenderer.invoke('launch-game', playerName, javaPath, installPath, gpuPreference),
|
||||||
installGame: (playerName, javaPath, installPath) => ipcRenderer.invoke('install-game', playerName, javaPath, installPath),
|
installGame: (playerName, javaPath, installPath) => ipcRenderer.invoke('install-game', playerName, javaPath, installPath),
|
||||||
closeWindow: () => ipcRenderer.invoke('window-close'),
|
closeWindow: () => ipcRenderer.invoke('window-close'),
|
||||||
minimizeWindow: () => ipcRenderer.invoke('window-minimize'),
|
minimizeWindow: () => ipcRenderer.invoke('window-minimize'),
|
||||||
@@ -49,6 +49,11 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|||||||
ipcRenderer.on('show-update-popup', (event, data) => callback(data));
|
ipcRenderer.on('show-update-popup', (event, data) => callback(data));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getGpuInfo: () => ipcRenderer.invoke('get-gpu-info'),
|
||||||
|
saveGpuPreference: (gpuPreference) => ipcRenderer.invoke('save-gpu-preference', gpuPreference),
|
||||||
|
loadGpuPreference: () => ipcRenderer.invoke('load-gpu-preference'),
|
||||||
|
getDetectedGpu: () => ipcRenderer.invoke('get-detected-gpu'),
|
||||||
|
|
||||||
acceptFirstLaunchUpdate: (existingGame) => ipcRenderer.invoke('accept-first-launch-update', existingGame),
|
acceptFirstLaunchUpdate: (existingGame) => ipcRenderer.invoke('accept-first-launch-update', existingGame),
|
||||||
markAsLaunched: () => ipcRenderer.invoke('mark-as-launched'),
|
markAsLaunched: () => ipcRenderer.invoke('mark-as-launched'),
|
||||||
onFirstLaunchUpdate: (callback) => {
|
onFirstLaunchUpdate: (callback) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user