Upload via GUI (43 Dateien)
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* discordpresence.js – Discord Rich Presence ("Spielt Minecraft über AeroMC")
|
||||
* -----------------------------------------------------------------------------
|
||||
* Verbindet sich rein lokal über die IPC-Pipe des laufenden Discord-Clients.
|
||||
* SET_ACTIVITY braucht dafür bewusst KEINE Authentifizierung/OAuth (anders als
|
||||
* der Rest der RPC-API) – daher hier absichtlich client.request(...) direkt
|
||||
* statt client.user.setActivity(...), das erst nach einem Login funktioniert.
|
||||
*
|
||||
* Immer aktiv, ohne eigene Einstellung – braucht also keine Zustimmung/kein
|
||||
* Häkchen. Läuft trotzdem komplett unauffällig: ist Discord nicht installiert
|
||||
* oder nicht gestartet, bleibt es einfach inaktiv, ohne den Launcher oder den
|
||||
* Spielstart zu stören – jeder Fehler hier wird bewusst verschluckt.
|
||||
*/
|
||||
|
||||
const { Client } = require('@xhayper/discord-rpc');
|
||||
|
||||
// Von M_Viper unter discord.com/developers/applications angelegte AeroMC-App.
|
||||
// Öffentliche Anwendungs-ID, kein Geheimnis (genau wie DEFAULT_CLIENT_ID bei
|
||||
// der Microsoft-Anmeldung in auth.js) – gilt für alle AeroMC-Nutzer gleich.
|
||||
const DEFAULT_CLIENT_ID = '1538173087730630686';
|
||||
|
||||
const LAUNCHER_WEBSITE = 'https://aeromc.viper.ipv64.net/';
|
||||
|
||||
let clientId = DEFAULT_CLIENT_ID;
|
||||
let client = null;
|
||||
let connecting = null;
|
||||
|
||||
function resolveClientId() {
|
||||
return (clientId && String(clientId).trim()) || DEFAULT_CLIENT_ID;
|
||||
}
|
||||
|
||||
async function connect() {
|
||||
if (client && client.isConnected) return client;
|
||||
if (connecting) return connecting;
|
||||
|
||||
const id = resolveClientId();
|
||||
const c = new Client({ clientId: id });
|
||||
c.on('disconnected', () => { if (client === c) client = null; });
|
||||
connecting = c.connect()
|
||||
.then(() => { client = c; connecting = null; return c; })
|
||||
.catch((err) => { connecting = null; throw err; });
|
||||
return connecting;
|
||||
}
|
||||
|
||||
/*
|
||||
* activity: { details, state, startTimestamp }
|
||||
* details/state -> die beiden Zeilen unter dem Profilbild in Discord
|
||||
* startTimestamp -> Discord zeigt die Spielzeit dann selbst laufend an
|
||||
*/
|
||||
async function setActivity(activity) {
|
||||
try {
|
||||
const c = await connect();
|
||||
await c.request('SET_ACTIVITY', {
|
||||
pid: process.pid,
|
||||
activity: {
|
||||
details: activity.details,
|
||||
state: activity.state,
|
||||
timestamps: activity.startTimestamp ? { start: activity.startTimestamp } : undefined,
|
||||
assets: { large_image: 'aeromc_logo', large_text: 'AeroMC Launcher' },
|
||||
// Discord zeigt Buttons Betrachtern des Profils an (nicht sich selbst) -
|
||||
// maximal 2 sind erlaubt, hier reicht einer.
|
||||
buttons: [{ label: 'AeroMC herunterladen', url: LAUNCHER_WEBSITE }],
|
||||
instance: false,
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
// Discord nicht installiert/nicht gestartet o. Ä. - bewusst lautlos
|
||||
}
|
||||
}
|
||||
|
||||
async function clearActivity() {
|
||||
try {
|
||||
if (!client || !client.isConnected) return;
|
||||
await client.request('SET_ACTIVITY', { pid: process.pid });
|
||||
} catch { /* egal */ }
|
||||
}
|
||||
|
||||
async function shutdown() {
|
||||
const c = client;
|
||||
client = null;
|
||||
connecting = null;
|
||||
if (!c) return;
|
||||
try { await c.destroy(); } catch { /* egal */ }
|
||||
}
|
||||
|
||||
/*
|
||||
* Verbindet direkt beim Start. settings.discordClientId erlaubt weiterhin
|
||||
* (rein optional, per Hand in settings.json) eine eigene App-ID zu setzen -
|
||||
* ohne eigenes Einstellungsfeld, ohne dass es dafür einen Schalter braucht.
|
||||
*/
|
||||
function configure(settings) {
|
||||
const nextId = (settings && settings.discordClientId) || DEFAULT_CLIENT_ID;
|
||||
const idChanged = nextId !== clientId;
|
||||
clientId = nextId;
|
||||
|
||||
if (idChanged) { shutdown().then(() => connect().catch(() => {})); }
|
||||
else if (!client) { connect().catch(() => {}); }
|
||||
}
|
||||
|
||||
module.exports = { configure, setActivity, clearActivity, shutdown, DEFAULT_CLIENT_ID };
|
||||
+12
-3
@@ -32,6 +32,7 @@ const crashreports = require('./crashreports');
|
||||
const skins = require('./skins');
|
||||
const servers = require('./servers');
|
||||
const mcping = require('./mcping');
|
||||
const discordpresence = require('./discordpresence');
|
||||
|
||||
// undici als globales fetch verwenden -> ermöglicht Proxy via setGlobalDispatcher
|
||||
const undici = require('undici');
|
||||
@@ -297,6 +298,7 @@ app.whenReady().then(() => {
|
||||
decrypt: (b) => safeStorage.decryptString(Buffer.from(b, 'base64')),
|
||||
});
|
||||
applyProxy(store.getSettings());
|
||||
discordpresence.configure(store.getSettings());
|
||||
const autostartAn = !!store.getSettings().autostart;
|
||||
// Autostart-Eintrag/Tray mit der Einstellung synchron halten (falls z. B.
|
||||
// von Hand an der Registry gedreht wurde oder nach einem Update)
|
||||
@@ -362,7 +364,7 @@ app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit();
|
||||
});
|
||||
|
||||
app.on('before-quit', () => { appIsQuitting = true; });
|
||||
app.on('before-quit', () => { appIsQuitting = true; discordpresence.shutdown(); });
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Java-Erkennung (für Anzeige in den Einstellungen)
|
||||
@@ -390,6 +392,7 @@ ipcMain.handle('settings:save', (_e, patch) => {
|
||||
const s = store.saveSettings(patch);
|
||||
applyProxy(s);
|
||||
if (patch && Object.prototype.hasOwnProperty.call(patch, 'autostart')) applyAutostart(s.autostart);
|
||||
if (patch && Object.prototype.hasOwnProperty.call(patch, 'discordClientId')) discordpresence.configure(s);
|
||||
return s;
|
||||
});
|
||||
|
||||
@@ -1935,9 +1938,15 @@ ipcMain.handle('instances:launch', async (_e, id, accountId, launchOpts) => {
|
||||
if (evt.phase === 'launch') {
|
||||
launchStart = Date.now();
|
||||
if (!gezaehlt) { gezaehlt = true; kontoSpieltJetzt(kontoId); }
|
||||
discordpresence.setActivity({
|
||||
details: 'Spielt Minecraft',
|
||||
state: `${inst.name} · ${inst.minecraft.version}`,
|
||||
startTimestamp: launchStart,
|
||||
});
|
||||
}
|
||||
if (evt.phase === 'exit') {
|
||||
if (gezaehlt) { gezaehlt = false; kontoSpieltNichtMehr(kontoId); }
|
||||
discordpresence.clearActivity();
|
||||
if (launchStart) {
|
||||
const secs = Math.max(0, Math.round((Date.now() - launchStart) / 1000));
|
||||
launchStart = 0; // Spielzeit nur einmal gutschreiben
|
||||
@@ -1951,11 +1960,11 @@ ipcMain.handle('instances:launch', async (_e, id, accountId, launchOpts) => {
|
||||
});
|
||||
// Start fehlgeschlagen, obwohl schon gezählt -> Zählung zurücknehmen,
|
||||
// sonst bliebe das Konto für immer als "spielt" stehen
|
||||
if (!res.ok && gezaehlt) { gezaehlt = false; kontoSpieltNichtMehr(kontoId); }
|
||||
if (!res.ok && gezaehlt) { gezaehlt = false; kontoSpieltNichtMehr(kontoId); discordpresence.clearActivity(); }
|
||||
if (res.ok) store.updateInstance(id, { lastPlayed: new Date().toISOString() });
|
||||
return res;
|
||||
} catch (err) {
|
||||
if (gezaehlt) { gezaehlt = false; kontoSpieltNichtMehr(kontoId); }
|
||||
if (gezaehlt) { gezaehlt = false; kontoSpieltNichtMehr(kontoId); discordpresence.clearActivity(); }
|
||||
return { ok: false, message: 'Start fehlgeschlagen: ' + err.message };
|
||||
}
|
||||
});
|
||||
|
||||
@@ -77,6 +77,7 @@ const DEFAULT_SETTINGS = {
|
||||
bedrockEnabled: true, // Bedrock-Bereich anzeigen (nur wenn auch installiert)
|
||||
desktopNotifications: true, // Windows-Meldung bei fertigem Hintergrund-Download/-Backup
|
||||
autostart: false, // mit Windows starten, im Infobereich statt als Fenster
|
||||
discordClientId: '', // optional, nur per Hand in settings.json; leer => eingebaute AeroMC-App-ID
|
||||
bgSkin: '', // '' = aus, 'active' = aktives Konto, sonst Konto-UUID
|
||||
bgSkinOpacity: 55, // Deckkraft des Hintergrund-Skins in %
|
||||
bgSkinPose: 'walking', // Pose des 3D-Renders (falls der Pose-Dienst erreichbar ist)
|
||||
|
||||
Reference in New Issue
Block a user