Merge branch 'feature/game-achievements' into chore/test-preview

# Conflicts:
#	yarn.lock
This commit is contained in:
Zamitto 2024-10-02 22:59:32 -03:00
commit 8b5ed96e9b
11 changed files with 82 additions and 51 deletions

View file

@ -6,7 +6,7 @@ export const checkUnlockedAchievements = (
unlockedAchievements: any
): UnlockedAchievement[] => {
if (type === Cracker.onlineFix) return onlineFixMerge(unlockedAchievements);
if (type === Cracker.goldberg)
if (type === Cracker.goldberg || type === Cracker.goldberg2)
return goldbergUnlockedAchievements(unlockedAchievements);
if (type == Cracker.generic) return genericMerge(unlockedAchievements);
return defaultMerge(unlockedAchievements);

View file

@ -9,6 +9,15 @@ import { Game } from "@main/entity";
const publicDir = path.join("C:", "Users", "Public", "Documents");
const appData = app.getPath("appData");
const crackers = [
Cracker.codex,
Cracker.goldberg,
Cracker.goldberg2,
Cracker.rune,
Cracker.onlineFix,
Cracker.generic,
];
const addGame = (
achievementFiles: Map<string, AchievementFile[]>,
achievementPath: string,
@ -39,14 +48,6 @@ const getObjectIdsInFolder = (path: string) => {
};
export const findSteamGameAchievementFiles = (game: Game) => {
const crackers = [
Cracker.codex,
Cracker.goldberg,
Cracker.rune,
Cracker.onlineFix,
Cracker.generic,
];
const achievementFiles: AchievementFile[] = [];
for (const cracker of crackers) {
let achievementPath: string;
@ -58,9 +59,9 @@ export const findSteamGameAchievementFiles = (game: Game) => {
} else if (cracker === Cracker.goldberg) {
achievementPath = path.join(appData, "Goldberg SteamEmu Saves");
fileLocation = ["achievements.json"];
} else if (cracker === Cracker.generic) {
achievementPath = path.join(publicDir, Cracker.generic);
fileLocation = ["user_stats.ini"];
} else if (cracker === Cracker.goldberg2) {
achievementPath = path.join(appData, "GSE Saves");
fileLocation = ["achievements.json"];
} else {
achievementPath = path.join(publicDir, "Steam", cracker);
fileLocation = ["achievements.ini"];
@ -102,13 +103,6 @@ export const findAchievementFileInExecutableDirectory = (
export const findAllSteamGameAchievementFiles = () => {
const gameAchievementFiles = new Map<string, AchievementFile[]>();
const crackers = [
Cracker.codex,
Cracker.goldberg,
Cracker.rune,
Cracker.onlineFix,
];
for (const cracker of crackers) {
let achievementPath: string;
let fileLocation: string[];
@ -116,6 +110,9 @@ export const findAllSteamGameAchievementFiles = () => {
if (cracker === Cracker.onlineFix) {
achievementPath = path.join(publicDir, Cracker.onlineFix);
fileLocation = ["Stats", "Achievements.ini"];
} else if (cracker === Cracker.goldberg2) {
achievementPath = path.join(appData, "GSE Saves");
fileLocation = ["achievements.json"];
} else if (cracker === Cracker.goldberg) {
achievementPath = path.join(appData, "Goldberg SteamEmu Saves");
fileLocation = ["achievements.json"];

View file

@ -52,7 +52,9 @@ export const mergeAchievements = async (
const newAchievements = achievements
.filter((achievement) => {
return !unlockedAchievements.some((localAchievement) => {
return localAchievement.name === achievement.name.toUpperCase();
return (
localAchievement.name.toUpperCase() === achievement.name.toUpperCase()
);
});
})
.map((achievement) => {
@ -64,10 +66,16 @@ export const mergeAchievements = async (
if (newAchievements.length && publishNotification) {
const achievementsInfo = newAchievements
.sort((a, b) => {
return a.unlockTime - b.unlockTime;
})
.map((achievement) => {
return JSON.parse(localGameAchievement?.achievements || "[]").find(
(steamAchievement) => {
return achievement.name === steamAchievement.name;
return (
achievement.name.toUpperCase() ===
steamAchievement.name.toUpperCase()
);
}
);
})
@ -85,12 +93,6 @@ export const mergeAchievements = async (
shop,
achievementsInfo
);
WindowManager.notificationWindow?.setBounds({ y: 50 });
setTimeout(() => {
WindowManager.notificationWindow?.setBounds({ y: -9999 });
}, 4000);
}
const mergedLocalAchievements = unlockedAchievements.concat(newAchievements);

View file

@ -151,19 +151,21 @@ export class WindowManager {
maximizable: false,
autoHideMenuBar: true,
minimizable: false,
focusable: true,
focusable: false,
skipTaskbar: true,
frame: false,
width: 240,
height: 60,
x: 25,
y: -9999,
y: 25,
webPreferences: {
preload: path.join(__dirname, "../preload/index.mjs"),
sandbox: false,
},
});
this.notificationWindow.setIgnoreMouseEvents(true);
this.notificationWindow.webContents.openDevTools();
this.notificationWindow.setVisibleOnAllWorkspaces(true, {
visibleOnFullScreen: true,
});

View file

@ -9,7 +9,7 @@
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: local: *; media-src 'self' local: data: *;"
/>
</head>
<body style="background-color: #1c1c1c">
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>

View file

@ -35,7 +35,6 @@ globalStyle("body", {
userSelect: "none",
fontFamily: "Noto Sans, sans-serif",
fontSize: vars.size.body,
background: vars.color.background,
color: vars.color.body,
margin: "0",
});

View file

@ -28,7 +28,7 @@ import {
import { store } from "./store";
import resources from "@locales";
import { Achievemnt } from "./pages/achievement/achievement";
import { Achievement } from "./pages/achievement/achievement";
import "./workers";
import { RepacksContextProvider } from "./context";
@ -70,7 +70,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
<Route path="/settings" Component={Settings} />
<Route path="/profile/:userId" Component={Profile} />
</Route>
<Route path="/achievement-notification" Component={Achievemnt} />
<Route path="/achievement-notification" Component={Achievement} />
</Routes>
</HashRouter>
</RepacksContextProvider>

View file

@ -1,14 +1,18 @@
import { useEffect, useMemo, useState } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import achievementSound from "@renderer/assets/audio/achievement.wav";
import { useTranslation } from "react-i18next";
import { vars } from "@renderer/theme.css";
export function Achievemnt() {
interface AchievementInfo {
displayName: string;
iconUrl: string;
}
export function Achievement() {
const { t } = useTranslation("achievement");
const [achievementInfo, setAchievementInfo] = useState<{
displayName: string;
icon: string;
} | null>(null);
const [achievements, setAchievements] = useState<AchievementInfo[]>([]);
const achievementAnimation = useRef(-1);
const audio = useMemo(() => {
const audio = new Audio(achievementSound);
@ -23,11 +27,7 @@ export function Achievemnt() {
if (!achievements) return;
if (achievements.length) {
const achievement = achievements[0];
setAchievementInfo({
displayName: achievement.displayName,
icon: achievement.iconUrl,
});
setAchievements((ach) => ach.concat(achievements));
}
audio.play();
@ -39,7 +39,26 @@ export function Achievemnt() {
};
}, [audio]);
if (!achievementInfo) return <p>Nada</p>;
const hasAchievementsPending = achievements.length > 0;
useEffect(() => {
if (hasAchievementsPending) {
let zero = performance.now();
achievementAnimation.current = requestAnimationFrame(
function animateLock(time) {
if (time - zero > 3000) {
zero = performance.now();
setAchievements((ach) => ach.slice(1));
}
achievementAnimation.current = requestAnimationFrame(animateLock);
}
);
} else {
cancelAnimationFrame(achievementAnimation.current);
}
}, [hasAchievementsPending]);
if (!hasAchievementsPending) return null;
return (
<div
@ -48,16 +67,17 @@ export function Achievemnt() {
flexDirection: "row",
gap: "8px",
alignItems: "center",
background: vars.color.background,
}}
>
<img
src={achievementInfo.icon}
alt={achievementInfo.displayName}
src={achievements[0].iconUrl}
alt={achievements[0].displayName}
style={{ width: 60, height: 60 }}
/>
<div>
<p>{t("achievement_unlocked")}</p>
<p>{achievementInfo.displayName}</p>
<p>{achievements[0].displayName}</p>
</div>
</div>
);

View file

@ -29,5 +29,6 @@ export enum Cracker {
rune = "RUNE",
onlineFix = "OnlineFix",
goldberg = "Goldberg",
goldberg2 = "Goldberg2",
generic = "Generic",
}