mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-03 08:43:48 +03:00
feat: update achievement audio and refactors
This commit is contained in:
parent
084b7f5b9c
commit
c18c41ac95
@ -315,5 +315,8 @@
|
|||||||
"report_reason_other": "Other",
|
"report_reason_other": "Other",
|
||||||
"profile_reported": "Profile reported",
|
"profile_reported": "Profile reported",
|
||||||
"your_friend_code": "Your friend code:"
|
"your_friend_code": "Your friend code:"
|
||||||
|
},
|
||||||
|
"achievement": {
|
||||||
|
"achievement_unlocked": "Achievement unlocked"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,5 +317,8 @@
|
|||||||
"report_reason_other": "Outro",
|
"report_reason_other": "Outro",
|
||||||
"profile_reported": "Perfil reportado",
|
"profile_reported": "Perfil reportado",
|
||||||
"your_friend_code": "Seu código de amigo:"
|
"your_friend_code": "Seu código de amigo:"
|
||||||
|
},
|
||||||
|
"achievement": {
|
||||||
|
"achievement_unlocked": "Conquista desbloqueada"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,5 +277,8 @@
|
|||||||
"friend_code_copied": "Código de amigo copiado",
|
"friend_code_copied": "Código de amigo copiado",
|
||||||
"image_process_failure": "Falha ao processar a imagem",
|
"image_process_failure": "Falha ao processar a imagem",
|
||||||
"your_friend_code": "Seu código de amigo:"
|
"your_friend_code": "Seu código de amigo:"
|
||||||
|
},
|
||||||
|
"achievement": {
|
||||||
|
"achievement_unlocked": "Conquista desbloqueada"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,23 +7,18 @@ import {
|
|||||||
userPreferencesRepository,
|
userPreferencesRepository,
|
||||||
} from "@main/repository";
|
} from "@main/repository";
|
||||||
import { UserNotLoggedInError } from "@shared";
|
import { UserNotLoggedInError } from "@shared";
|
||||||
|
import { Game } from "@main/entity";
|
||||||
|
|
||||||
const getGameAchievements = async (
|
const getAchievementsDataFromApi = async (
|
||||||
_event: Electron.IpcMainInvokeEvent,
|
|
||||||
objectId: string,
|
objectId: string,
|
||||||
shop: GameShop
|
shop: string,
|
||||||
): Promise<GameAchievement[]> => {
|
game: Game | null
|
||||||
const [game, cachedAchievements, userPreferences] = await Promise.all([
|
) => {
|
||||||
gameRepository.findOne({
|
const userPreferences = await userPreferencesRepository.findOne({
|
||||||
where: { objectID: objectId, shop },
|
|
||||||
}),
|
|
||||||
gameAchievementRepository.findOne({ where: { objectId, shop } }),
|
|
||||||
userPreferencesRepository.findOne({
|
|
||||||
where: { id: 1 },
|
where: { id: 1 },
|
||||||
}),
|
});
|
||||||
]);
|
|
||||||
|
|
||||||
const apiAchievement = HydraApi.get("/games/achievements", {
|
return HydraApi.get("/games/achievements", {
|
||||||
objectId,
|
objectId,
|
||||||
shop,
|
shop,
|
||||||
language: userPreferences?.language || "en",
|
language: userPreferences?.language || "en",
|
||||||
@ -46,10 +41,23 @@ const getGameAchievements = async (
|
|||||||
if (err instanceof UserNotLoggedInError) throw err;
|
if (err instanceof UserNotLoggedInError) throw err;
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getGameAchievements = async (
|
||||||
|
_event: Electron.IpcMainInvokeEvent,
|
||||||
|
objectId: string,
|
||||||
|
shop: GameShop
|
||||||
|
): Promise<GameAchievement[]> => {
|
||||||
|
const [game, cachedAchievements] = await Promise.all([
|
||||||
|
gameRepository.findOne({
|
||||||
|
where: { objectID: objectId, shop },
|
||||||
|
}),
|
||||||
|
gameAchievementRepository.findOne({ where: { objectId, shop } }),
|
||||||
|
]);
|
||||||
|
|
||||||
const gameAchievements = cachedAchievements?.achievements
|
const gameAchievements = cachedAchievements?.achievements
|
||||||
? JSON.parse(cachedAchievements.achievements)
|
? JSON.parse(cachedAchievements.achievements)
|
||||||
: await apiAchievement;
|
: await getAchievementsDataFromApi(objectId, shop, game);
|
||||||
|
|
||||||
const unlockedAchievements = JSON.parse(
|
const unlockedAchievements = JSON.parse(
|
||||||
cachedAchievements?.unlockedAchievements || "[]"
|
cachedAchievements?.unlockedAchievements || "[]"
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
import { registerEvent } from "../register-event";
|
||||||
|
import { updateLocalUnlockedAchivements } from "@main/services/achievements/update-local-unlocked-achivements";
|
||||||
|
|
||||||
|
const updateGameUnlockedAchievements = async (
|
||||||
|
_event: Electron.IpcMainInvokeEvent,
|
||||||
|
objectId: string
|
||||||
|
) => {
|
||||||
|
return updateLocalUnlockedAchivements(false, objectId);
|
||||||
|
};
|
||||||
|
|
||||||
|
registerEvent("updateGameUnlockedAchievements", updateGameUnlockedAchievements);
|
@ -10,6 +10,7 @@ import "./catalogue/search-games";
|
|||||||
import "./catalogue/get-game-stats";
|
import "./catalogue/get-game-stats";
|
||||||
import "./catalogue/get-trending-games";
|
import "./catalogue/get-trending-games";
|
||||||
import "./catalogue/get-game-achievements";
|
import "./catalogue/get-game-achievements";
|
||||||
|
import "./catalogue/update-game-unlocked-achievements";
|
||||||
import "./hardware/get-disk-free-space";
|
import "./hardware/get-disk-free-space";
|
||||||
import "./library/add-game-to-library";
|
import "./library/add-game-to-library";
|
||||||
import "./library/create-game-shortcut";
|
import "./library/create-game-shortcut";
|
||||||
|
@ -62,21 +62,28 @@ export const mergeAchievements = async (
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
if (newAchievements.length) {
|
if (newAchievements.length && publishNotification) {
|
||||||
const achievement = newAchievements.at(-1)!;
|
const achievementsInfo = newAchievements
|
||||||
const achievementInfo = JSON.parse(
|
.map((achievement) => {
|
||||||
localGameAchievement?.achievements || "[]"
|
return JSON.parse(localGameAchievement?.achievements || "[]").find(
|
||||||
).find((steamAchievement) => {
|
(steamAchievement) => {
|
||||||
return achievement.name === steamAchievement.name;
|
return achievement.name === steamAchievement.name;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter((achievement) => achievement)
|
||||||
|
.map((achievement) => {
|
||||||
|
return {
|
||||||
|
displayName: achievement.displayName,
|
||||||
|
iconUrl: achievement.icon,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
if (publishNotification) {
|
|
||||||
WindowManager.notificationWindow?.webContents.send(
|
WindowManager.notificationWindow?.webContents.send(
|
||||||
"on-achievement-unlocked",
|
"on-achievement-unlocked",
|
||||||
objectId,
|
objectId,
|
||||||
shop,
|
shop,
|
||||||
achievementInfo.displayName,
|
achievementsInfo
|
||||||
achievementInfo.icon
|
|
||||||
);
|
);
|
||||||
|
|
||||||
WindowManager.notificationWindow?.setBounds({ y: 50 });
|
WindowManager.notificationWindow?.setBounds({ y: 50 });
|
||||||
@ -85,7 +92,6 @@ export const mergeAchievements = async (
|
|||||||
WindowManager.notificationWindow?.setBounds({ y: -9999 });
|
WindowManager.notificationWindow?.setBounds({ y: -9999 });
|
||||||
}, 4000);
|
}, 4000);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const mergedLocalAchievements = unlockedAchievements.concat(newAchievements);
|
const mergedLocalAchievements = unlockedAchievements.concat(newAchievements);
|
||||||
|
|
||||||
|
@ -29,12 +29,12 @@ export const watchProcesses = async () => {
|
|||||||
if (games.length === 0) return;
|
if (games.length === 0) return;
|
||||||
const processes = await PythonInstance.getProcessList();
|
const processes = await PythonInstance.getProcessList();
|
||||||
|
|
||||||
|
const processSet = new Set(processes.map((process) => process.exe));
|
||||||
|
|
||||||
for (const game of games) {
|
for (const game of games) {
|
||||||
const executablePath = game.executablePath!;
|
const executablePath = game.executablePath!;
|
||||||
|
|
||||||
const gameProcess = processes.find((runningProcess) => {
|
const gameProcess = processSet.has(executablePath);
|
||||||
return executablePath == runningProcess.exe;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (gameProcess) {
|
if (gameProcess) {
|
||||||
if (gamesPlaytime.has(game.id)) {
|
if (gamesPlaytime.has(game.id)) {
|
||||||
|
@ -51,21 +51,21 @@ contextBridge.exposeInMainWorld("electron", {
|
|||||||
getTrendingGames: () => ipcRenderer.invoke("getTrendingGames"),
|
getTrendingGames: () => ipcRenderer.invoke("getTrendingGames"),
|
||||||
getGameAchievements: (objectId: string, shop: GameShop) =>
|
getGameAchievements: (objectId: string, shop: GameShop) =>
|
||||||
ipcRenderer.invoke("getGameAchievements", objectId, shop),
|
ipcRenderer.invoke("getGameAchievements", objectId, shop),
|
||||||
|
updateGameUnlockedAchievements: (objectId: string) =>
|
||||||
|
ipcRenderer.invoke("updateGameUnlockedAchievements", objectId),
|
||||||
onAchievementUnlocked: (
|
onAchievementUnlocked: (
|
||||||
cb: (
|
cb: (
|
||||||
objectId: string,
|
objectId: string,
|
||||||
shop: GameShop,
|
shop: GameShop,
|
||||||
displayName: string,
|
achievements?: { displayName: string; iconUrl: string }[]
|
||||||
iconUrl: string
|
|
||||||
) => void
|
) => void
|
||||||
) => {
|
) => {
|
||||||
const listener = (
|
const listener = (
|
||||||
_event: Electron.IpcRendererEvent,
|
_event: Electron.IpcRendererEvent,
|
||||||
objectId: string,
|
objectId: string,
|
||||||
shop: GameShop,
|
shop: GameShop,
|
||||||
displayName: string,
|
achievements?: { displayName: string; iconUrl: string }[]
|
||||||
iconUrl: string
|
) => cb(objectId, shop, achievements);
|
||||||
) => cb(objectId, shop, displayName, iconUrl);
|
|
||||||
ipcRenderer.on("on-achievement-unlocked", listener);
|
ipcRenderer.on("on-achievement-unlocked", listener);
|
||||||
return () =>
|
return () =>
|
||||||
ipcRenderer.removeListener("on-achievement-unlocked", listener);
|
ipcRenderer.removeListener("on-achievement-unlocked", listener);
|
||||||
|
BIN
src/renderer/src/assets/audio/achievement.wav
Normal file
BIN
src/renderer/src/assets/audio/achievement.wav
Normal file
Binary file not shown.
@ -179,6 +179,8 @@ export function GameDetailsContextProvider({
|
|||||||
}, [game?.id, isGameRunning, updateGame]);
|
}, [game?.id, isGameRunning, updateGame]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
window.electron.updateGameUnlockedAchievements(objectID!).catch(() => {});
|
||||||
|
|
||||||
const unsubscribe = window.electron.onAchievementUnlocked(
|
const unsubscribe = window.electron.onAchievementUnlocked(
|
||||||
(objectId, shop) => {
|
(objectId, shop) => {
|
||||||
if (objectID !== objectId || shop !== shop) return;
|
if (objectID !== objectId || shop !== shop) return;
|
||||||
|
4
src/renderer/src/declaration.d.ts
vendored
4
src/renderer/src/declaration.d.ts
vendored
@ -70,12 +70,12 @@ declare global {
|
|||||||
objectId: string,
|
objectId: string,
|
||||||
shop: GameShop
|
shop: GameShop
|
||||||
) => Promise<GameAchievement[]>;
|
) => Promise<GameAchievement[]>;
|
||||||
|
updateGameUnlockedAchievements: (objectId: string) => Promise<void>;
|
||||||
onAchievementUnlocked: (
|
onAchievementUnlocked: (
|
||||||
cb: (
|
cb: (
|
||||||
objectId: string,
|
objectId: string,
|
||||||
shop: GameShop,
|
shop: GameShop,
|
||||||
displayName: string,
|
achievements?: { displayName: string; iconUrl: string }[]
|
||||||
iconUrl: string
|
|
||||||
) => void
|
) => void
|
||||||
) => () => Electron.IpcRenderer;
|
) => () => Electron.IpcRenderer;
|
||||||
|
|
||||||
|
@ -1,27 +1,34 @@
|
|||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
|
import achievementSound from "@renderer/assets/audio/achievement.wav";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export function Achievemnt() {
|
export function Achievemnt() {
|
||||||
|
const { t } = useTranslation("achievement");
|
||||||
|
|
||||||
const [achievementInfo, setAchievementInfo] = useState<{
|
const [achievementInfo, setAchievementInfo] = useState<{
|
||||||
displayName: string;
|
displayName: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
const audio = useMemo(() => {
|
const audio = useMemo(() => {
|
||||||
const audio = new Audio(
|
const audio = new Audio(achievementSound);
|
||||||
"https://cms-public-artifacts.artlist.io/content/sfx/aac/94201_690187_Classics_-_Achievement_Unlocked_-_MASTERED_-_2496.aac"
|
audio.volume = 0.2;
|
||||||
);
|
|
||||||
|
|
||||||
audio.preload = "auto";
|
audio.preload = "auto";
|
||||||
return audio;
|
return audio;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribe = window.electron.onAchievementUnlocked(
|
const unsubscribe = window.electron.onAchievementUnlocked(
|
||||||
(_object, _shop, displayName, icon) => {
|
(_object, _shop, achievements) => {
|
||||||
|
if (!achievements) return;
|
||||||
|
|
||||||
|
if (achievements.length) {
|
||||||
|
const achievement = achievements[0];
|
||||||
setAchievementInfo({
|
setAchievementInfo({
|
||||||
displayName,
|
displayName: achievement.displayName,
|
||||||
icon,
|
icon: achievement.iconUrl,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
audio.play();
|
audio.play();
|
||||||
}
|
}
|
||||||
@ -49,7 +56,7 @@ export function Achievemnt() {
|
|||||||
style={{ width: 60, height: 60 }}
|
style={{ width: 60, height: 60 }}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<p>Achievement unlocked</p>
|
<p>{t("achievement_unlocked")}</p>
|
||||||
<p>{achievementInfo.displayName}</p>
|
<p>{achievementInfo.displayName}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user