mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-14 20:22:10 +00:00
feat: real time achievement track
This commit is contained in:
parent
24d21b9839
commit
5c790edb2c
14 changed files with 181 additions and 407 deletions
|
@ -2,80 +2,77 @@ import { watch } from "node:fs/promises";
|
|||
import { getGameAchievementsToWatch } from "./get-game-achievements-to-watch";
|
||||
import { checkUnlockedAchievements } from "./util/check-unlocked-achievements";
|
||||
import { parseAchievementFile } from "./util/parseAchievementFile";
|
||||
import { gameAchievementRepository } from "@main/repository";
|
||||
import { Game } from "@main/entity";
|
||||
import { mergeAchievements } from "./merge-achievements";
|
||||
import fs from "node:fs";
|
||||
import { AchievementFile } from "./types";
|
||||
|
||||
type GameAchievementObserver = {
|
||||
[id: number]: AbortController | null;
|
||||
[id: number]: AbortController;
|
||||
};
|
||||
|
||||
const gameAchievementObserver: GameAchievementObserver = {};
|
||||
|
||||
export const startGameAchievementObserver = async (gameId: number) => {
|
||||
if (
|
||||
gameAchievementObserver[gameId] === null ||
|
||||
gameAchievementObserver[gameId]
|
||||
) {
|
||||
return;
|
||||
const processAchievementFile = async (game: Game, file: AchievementFile) => {
|
||||
const localAchievementFile = await parseAchievementFile(file.filePath);
|
||||
console.log(localAchievementFile);
|
||||
|
||||
if (localAchievementFile) {
|
||||
const unlockedAchievements = checkUnlockedAchievements(
|
||||
file.type,
|
||||
localAchievementFile
|
||||
);
|
||||
console.log(unlockedAchievements);
|
||||
|
||||
if (unlockedAchievements.length) {
|
||||
mergeAchievements(game.objectID, game.shop, unlockedAchievements);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
console.log(`Starting: ${gameId}`);
|
||||
export const startGameAchievementObserver = async (game: Game) => {
|
||||
if (gameAchievementObserver[game.id]) return;
|
||||
|
||||
const achievementsToWatch = await getGameAchievementsToWatch(gameId);
|
||||
console.log(`Starting: ${game.title}`);
|
||||
|
||||
if (!achievementsToWatch) {
|
||||
console.log("No achievements to observe");
|
||||
gameAchievementObserver[gameId] = null;
|
||||
return;
|
||||
}
|
||||
const achievementFiles = await getGameAchievementsToWatch(game.id);
|
||||
|
||||
const { steamId, checkedAchievements, achievementFiles } =
|
||||
achievementsToWatch;
|
||||
|
||||
gameAchievementObserver[gameId] = new AbortController();
|
||||
|
||||
const achievements = checkedAchievements.all;
|
||||
console.log(
|
||||
"Achievements files to observe for:",
|
||||
game.title,
|
||||
achievementFiles
|
||||
);
|
||||
|
||||
for (const file of achievementFiles) {
|
||||
const signal = gameAchievementObserver[gameId]?.signal;
|
||||
if (!signal) return;
|
||||
console.log(`cracker: ${file.type}, steamId: ${steamId}`);
|
||||
if (!fs.existsSync(file.filePath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(`cracker: ${file.type}, objectId: ${game.objectID}`);
|
||||
|
||||
if (!gameAchievementObserver[game.id]) {
|
||||
const abortController = new AbortController();
|
||||
gameAchievementObserver[game.id] = abortController;
|
||||
}
|
||||
|
||||
const signal = gameAchievementObserver[game.id]?.signal;
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
processAchievementFile(game, file);
|
||||
|
||||
const watcher = watch(file.filePath, {
|
||||
signal,
|
||||
});
|
||||
|
||||
for await (const event of watcher) {
|
||||
if (event.eventType === "change") {
|
||||
console.log("file modified");
|
||||
const localAchievementFile = await parseAchievementFile(
|
||||
file.filePath
|
||||
);
|
||||
|
||||
if (!localAchievementFile) continue;
|
||||
|
||||
const checked = checkUnlockedAchievements(
|
||||
file.type,
|
||||
localAchievementFile,
|
||||
achievements
|
||||
);
|
||||
|
||||
if (checked.new) {
|
||||
console.log(checked.new);
|
||||
|
||||
gameAchievementRepository.update(
|
||||
{
|
||||
game: { id: steamId },
|
||||
},
|
||||
{
|
||||
achievements: JSON.stringify(checked.all),
|
||||
}
|
||||
);
|
||||
}
|
||||
processAchievementFile(game, file);
|
||||
}
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.log(`cracker: ${file.type}, steamId ${steamId}`);
|
||||
if (err?.name === "AbortError") return;
|
||||
console.log(`cracker: ${file.type}, steamId ${game.objectID}`);
|
||||
throw err;
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -1,61 +1,25 @@
|
|||
import { gameRepository, gameAchievementRepository } from "@main/repository";
|
||||
import { steamGetAchivement } from "./steam/steam-get-achivement";
|
||||
import { gameRepository } from "@main/repository";
|
||||
import { steamFindGameAchievementFiles } from "./steam/steam-find-game-achivement-files";
|
||||
import { AchievementFile, CheckedAchievements } from "./types";
|
||||
import { parseAchievementFile } from "./util/parseAchievementFile";
|
||||
import { checkUnlockedAchievements } from "./util/check-unlocked-achievements";
|
||||
import { AchievementFile } from "./types";
|
||||
|
||||
export const getGameAchievementsToWatch = async (
|
||||
gameId: number
|
||||
): Promise<
|
||||
| {
|
||||
steamId: number;
|
||||
checkedAchievements: CheckedAchievements;
|
||||
achievementFiles: AchievementFile[];
|
||||
}
|
||||
| undefined
|
||||
> => {
|
||||
): Promise<AchievementFile[]> => {
|
||||
const game = await gameRepository.findOne({ where: { id: gameId } });
|
||||
|
||||
if (!game || game.shop !== "steam") return;
|
||||
if (!game || game.shop !== "steam") return [];
|
||||
|
||||
const steamId = Number(game.objectID);
|
||||
|
||||
const achievements = await steamGetAchivement(game);
|
||||
|
||||
console.log(achievements);
|
||||
|
||||
if (!achievements || !achievements.length) return;
|
||||
|
||||
const achievementFiles = steamFindGameAchievementFiles(game.objectID)[
|
||||
steamId
|
||||
];
|
||||
console.log(achievementFiles);
|
||||
if (!achievementFiles || !achievementFiles.length) return;
|
||||
console.log(
|
||||
"achivements files:",
|
||||
achievementFiles,
|
||||
game.title,
|
||||
game.objectID
|
||||
);
|
||||
|
||||
const checkedAchievements: CheckedAchievements = {
|
||||
all: achievements,
|
||||
new: [],
|
||||
};
|
||||
|
||||
for (const achievementFile of achievementFiles) {
|
||||
const file = await parseAchievementFile(achievementFile.filePath);
|
||||
|
||||
checkedAchievements.new.push(
|
||||
...checkUnlockedAchievements(achievementFile.type, file, achievements).new
|
||||
);
|
||||
}
|
||||
|
||||
if (checkedAchievements.new.length) {
|
||||
await gameAchievementRepository.update(
|
||||
{
|
||||
game: { id: gameId },
|
||||
},
|
||||
{
|
||||
unlockedAchievements: JSON.stringify(checkedAchievements.all),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return { steamId, checkedAchievements, achievementFiles };
|
||||
return achievementFiles || [];
|
||||
};
|
||||
|
|
51
src/main/services/achievements/merge-achievements.ts
Normal file
51
src/main/services/achievements/merge-achievements.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { gameAchievementRepository } from "@main/repository";
|
||||
import { UnlockedAchievement } from "./types";
|
||||
|
||||
export const mergeAchievements = async (
|
||||
objectId: string,
|
||||
shop: string,
|
||||
achievements: UnlockedAchievement[]
|
||||
) => {
|
||||
const localGameAchievement = await gameAchievementRepository.findOne({
|
||||
where: {
|
||||
objectId,
|
||||
shop,
|
||||
},
|
||||
});
|
||||
|
||||
const unlockedAchievements = JSON.parse(
|
||||
localGameAchievement?.unlockedAchievements || "[]"
|
||||
);
|
||||
|
||||
console.log("file achievemets:", achievements);
|
||||
const newAchievements = achievements.filter((achievement) => {
|
||||
return !unlockedAchievements.some((localAchievement) => {
|
||||
return localAchievement.name === achievement.name;
|
||||
});
|
||||
});
|
||||
|
||||
const mergedAchievements = unlockedAchievements.concat(newAchievements);
|
||||
|
||||
console.log("merged achievemetns", mergedAchievements);
|
||||
gameAchievementRepository.upsert(
|
||||
{
|
||||
objectId,
|
||||
shop,
|
||||
unlockedAchievements: JSON.stringify(mergedAchievements),
|
||||
},
|
||||
["objectId", "shop"]
|
||||
);
|
||||
|
||||
// return HydraApi.get("/profile/games/achievements").then(async (response) => {
|
||||
// console.log(response);
|
||||
// });
|
||||
|
||||
// if (game.remoteId) {
|
||||
// HydraApi.put("/profile/games/achievements", {
|
||||
// id: game.remoteId,
|
||||
// achievements: unlockedAchievements,
|
||||
// }).catch(() => {
|
||||
// console.log("erro");
|
||||
// });
|
||||
// }
|
||||
};
|
|
@ -1,7 +0,0 @@
|
|||
import { HydraApi } from "../hydra-api";
|
||||
|
||||
export const mergeWithRemoteAchievements = async () => {
|
||||
return HydraApi.get("/profile/games/achievements").then(async (response) => {
|
||||
console.log(response);
|
||||
});
|
||||
};
|
|
@ -2,13 +2,14 @@ import { gameAchievementRepository, gameRepository } from "@main/repository";
|
|||
import { steamFindGameAchievementFiles } from "./steam/steam-find-game-achivement-files";
|
||||
import { parseAchievementFile } from "./util/parseAchievementFile";
|
||||
import { HydraApi } from "@main/services";
|
||||
import { checkUnlockedAchievements } from "./util/check-unlocked-achievements";
|
||||
import { mergeAchievements } from "./merge-achievements";
|
||||
import { UnlockedAchievement } from "./types";
|
||||
|
||||
export const saveAllLocalSteamAchivements = async () => {
|
||||
const gameAchievementFiles = steamFindGameAchievementFiles();
|
||||
|
||||
for (const key of Object.keys(gameAchievementFiles)) {
|
||||
const objectId = key;
|
||||
|
||||
for (const objectId of Object.keys(gameAchievementFiles)) {
|
||||
const [game, localAchievements] = await Promise.all([
|
||||
gameRepository.findOne({
|
||||
where: { objectID: objectId, shop: "steam", isDeleted: false },
|
||||
|
@ -42,40 +43,20 @@ export const saveAllLocalSteamAchivements = async () => {
|
|||
.catch(console.log);
|
||||
}
|
||||
|
||||
const unlockedAchievements: { name: string; unlockTime: number }[] = [];
|
||||
const unlockedAchievements: UnlockedAchievement[] = [];
|
||||
|
||||
for (const achievementFile of gameAchievementFiles[key]) {
|
||||
for (const achievementFile of gameAchievementFiles[objectId]) {
|
||||
const localAchievementFile = await parseAchievementFile(
|
||||
achievementFile.filePath
|
||||
);
|
||||
|
||||
console.log(achievementFile.filePath);
|
||||
|
||||
for (const a of Object.keys(localAchievementFile)) {
|
||||
// TODO: use checkUnlockedAchievements after refactoring it to be generic
|
||||
unlockedAchievements.push({
|
||||
name: a,
|
||||
unlockTime: localAchievementFile[a].UnlockTime,
|
||||
});
|
||||
}
|
||||
unlockedAchievements.push(
|
||||
...checkUnlockedAchievements(achievementFile.type, localAchievementFile)
|
||||
);
|
||||
}
|
||||
|
||||
gameAchievementRepository.upsert(
|
||||
{
|
||||
objectId,
|
||||
shop: "steam",
|
||||
unlockedAchievements: JSON.stringify(unlockedAchievements),
|
||||
},
|
||||
["objectId", "shop"]
|
||||
);
|
||||
|
||||
if (game.remoteId) {
|
||||
HydraApi.put("/profile/games/achievements", {
|
||||
id: game.remoteId,
|
||||
achievements: unlockedAchievements,
|
||||
}).catch(() => {
|
||||
console.log("erro");
|
||||
});
|
||||
}
|
||||
mergeAchievements(objectId, "steam", unlockedAchievements);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
import { logger } from "@main/services";
|
||||
import { AchievementInfo } from "../types";
|
||||
import { JSDOM } from "jsdom";
|
||||
|
||||
export const steamAchievementInfo = async (
|
||||
objectId: string
|
||||
): Promise<AchievementInfo[] | undefined> => {
|
||||
const fetchUrl = `https://steamcommunity.com/stats/${objectId}/achievements`;
|
||||
|
||||
const achievementInfosHtmlText = await fetch(fetchUrl, {
|
||||
method: "GET",
|
||||
//headers: { "Accept-Language": "" },
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.status === 200) return res.text();
|
||||
throw new Error();
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(err, { method: "getSteamGameAchievements" });
|
||||
return;
|
||||
});
|
||||
|
||||
if (!achievementInfosHtmlText) return;
|
||||
|
||||
const achievementInfos: AchievementInfo[] = [];
|
||||
|
||||
const window = new JSDOM(achievementInfosHtmlText).window;
|
||||
|
||||
const itens = Array.from(
|
||||
window.document.getElementsByClassName("achieveRow")
|
||||
);
|
||||
|
||||
for (const item of itens) {
|
||||
const imageUrl = item
|
||||
.getElementsByClassName("achieveImgHolder")?.[0]
|
||||
.getElementsByTagName("img")?.[0]?.src;
|
||||
|
||||
const achievementName = item
|
||||
.getElementsByClassName("achieveTxt")?.[0]
|
||||
.getElementsByTagName("h3")?.[0].innerHTML;
|
||||
|
||||
const achievementDescription = item
|
||||
.getElementsByClassName("achieveTxt")?.[0]
|
||||
.getElementsByTagName("h5")?.[0].innerHTML;
|
||||
|
||||
achievementInfos.push({
|
||||
imageUrl: imageUrl ?? "",
|
||||
title: achievementName ?? "",
|
||||
description: achievementDescription ?? "",
|
||||
});
|
||||
}
|
||||
|
||||
return achievementInfos;
|
||||
};
|
|
@ -1,28 +0,0 @@
|
|||
import { Achievement, AchievementInfo, AchievementPercentage } from "../types";
|
||||
|
||||
export const steamAchievementMerge = (
|
||||
achievementPercentage: AchievementPercentage[],
|
||||
achievementInfo: AchievementInfo[]
|
||||
): Achievement[] | undefined => {
|
||||
if (achievementPercentage.length > achievementInfo.length) return;
|
||||
|
||||
const size = achievementPercentage.length;
|
||||
|
||||
const achievements: Achievement[] = new Array(size);
|
||||
|
||||
for (let i = 0; i < size; i++) {
|
||||
achievements[i] = {
|
||||
id: achievementPercentage[i].name,
|
||||
percent: achievementPercentage[i].percent,
|
||||
imageUrl: achievementInfo[i].imageUrl,
|
||||
title: achievementInfo[i].title,
|
||||
description: achievementInfo[i].description,
|
||||
achieved: false,
|
||||
curProgress: 0,
|
||||
maxProgress: 0,
|
||||
unlockTime: 0,
|
||||
};
|
||||
}
|
||||
|
||||
return achievements;
|
||||
};
|
|
@ -12,16 +12,14 @@ const addGame = (
|
|||
) => {
|
||||
const filePath = path.join(achievementPath, objectId, ...fileLocation);
|
||||
|
||||
if (fs.existsSync(filePath)) {
|
||||
const achivementFile = {
|
||||
type,
|
||||
filePath,
|
||||
};
|
||||
const achivementFile = {
|
||||
type,
|
||||
filePath,
|
||||
};
|
||||
|
||||
achievementFiles[objectId]
|
||||
? achievementFiles[objectId].push(achivementFile)
|
||||
: (achievementFiles[objectId] = [achivementFile]);
|
||||
}
|
||||
achievementFiles[objectId]
|
||||
? achievementFiles[objectId].push(achivementFile)
|
||||
: (achievementFiles[objectId] = [achivementFile]);
|
||||
};
|
||||
|
||||
export const steamFindGameAchievementFiles = (
|
||||
|
@ -55,30 +53,16 @@ export const steamFindGameAchievementFiles = (
|
|||
fileLocation = ["achievements.ini"];
|
||||
}
|
||||
|
||||
if (!fs.existsSync(achievementPath)) continue;
|
||||
const objectIds = objectId ? [objectId] : fs.readdirSync(achievementPath);
|
||||
|
||||
const objectIds = fs.readdirSync(achievementPath);
|
||||
|
||||
if (objectId) {
|
||||
if (objectIds.includes(objectId)) {
|
||||
addGame(
|
||||
gameAchievementFiles,
|
||||
achievementPath,
|
||||
objectId,
|
||||
fileLocation,
|
||||
cracker
|
||||
);
|
||||
}
|
||||
} else {
|
||||
for (const objectId of objectIds) {
|
||||
addGame(
|
||||
gameAchievementFiles,
|
||||
achievementPath,
|
||||
objectId,
|
||||
fileLocation,
|
||||
cracker
|
||||
);
|
||||
}
|
||||
for (const objectId of objectIds) {
|
||||
addGame(
|
||||
gameAchievementFiles,
|
||||
achievementPath,
|
||||
objectId,
|
||||
fileLocation,
|
||||
cracker
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
import { gameAchievementRepository } from "@main/repository";
|
||||
import { steamGlobalAchievementPercentages } from "./steam-global-achievement-percentages";
|
||||
import { steamAchievementInfo } from "./steam-achievement-info";
|
||||
import { steamAchievementMerge } from "./steam-achievement-merge";
|
||||
import { Achievement } from "../types";
|
||||
import { Game } from "@main/entity";
|
||||
|
||||
export const steamGetAchivement = async (
|
||||
game: Game
|
||||
): Promise<Achievement[] | undefined> => {
|
||||
const gameAchivement = await gameAchievementRepository.findOne({
|
||||
where: { game: game },
|
||||
});
|
||||
|
||||
if (!gameAchivement) {
|
||||
const achievementPercentage = await steamGlobalAchievementPercentages(
|
||||
game.objectID
|
||||
);
|
||||
console.log(achievementPercentage);
|
||||
if (!achievementPercentage) {
|
||||
await gameAchievementRepository.save({
|
||||
game,
|
||||
achievements: "[]",
|
||||
});
|
||||
return [];
|
||||
}
|
||||
|
||||
const achievementInfo = await steamAchievementInfo(game.objectID);
|
||||
console.log(achievementInfo);
|
||||
if (!achievementInfo) return;
|
||||
|
||||
const achievements = steamAchievementMerge(
|
||||
achievementPercentage,
|
||||
achievementInfo
|
||||
);
|
||||
|
||||
if (!achievements) return;
|
||||
|
||||
await gameAchievementRepository.save({
|
||||
game,
|
||||
achievements: JSON.stringify(achievements),
|
||||
});
|
||||
|
||||
return achievements;
|
||||
} else {
|
||||
return JSON.parse(gameAchivement.achievements);
|
||||
}
|
||||
};
|
|
@ -1,33 +0,0 @@
|
|||
import { logger } from "@main/services";
|
||||
import { AchievementPercentage } from "../types";
|
||||
|
||||
interface GlobalAchievementPercentages {
|
||||
achievementpercentages: {
|
||||
achievements: Array<AchievementPercentage>;
|
||||
};
|
||||
}
|
||||
|
||||
export const steamGlobalAchievementPercentages = async (
|
||||
objectId: string
|
||||
): Promise<AchievementPercentage[] | undefined> => {
|
||||
const fetchUrl = `https://api.steampowered.com/ISteamUserStats/GetGlobalAchievementPercentagesForApp/v0002/?gameid=${objectId}`;
|
||||
|
||||
const achievementPercentages: Array<AchievementPercentage> | undefined = (
|
||||
await fetch(fetchUrl, {
|
||||
method: "GET",
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.status === 200) return res.json();
|
||||
return;
|
||||
})
|
||||
.then((data: GlobalAchievementPercentages) => data)
|
||||
.catch((err) => {
|
||||
logger.error(err, { method: "getSteamGameAchievements" });
|
||||
return;
|
||||
})
|
||||
)?.achievementpercentages.achievements;
|
||||
|
||||
if (!achievementPercentages) return;
|
||||
|
||||
return achievementPercentages;
|
||||
};
|
|
@ -10,6 +10,11 @@ export interface CheckedAchievements {
|
|||
new: Achievement[];
|
||||
}
|
||||
|
||||
export interface UnlockedAchievement {
|
||||
name: string;
|
||||
unlockTime: number;
|
||||
}
|
||||
|
||||
export interface Achievement {
|
||||
id: string;
|
||||
percent: number;
|
||||
|
|
|
@ -1,102 +1,63 @@
|
|||
import { Achievement, CheckedAchievements, Cracker } from "../types";
|
||||
import { Cracker, UnlockedAchievement } from "../types";
|
||||
|
||||
export const checkUnlockedAchievements = (
|
||||
type: Cracker,
|
||||
unlockedAchievements: any,
|
||||
achievements: Achievement[]
|
||||
): CheckedAchievements => {
|
||||
if (type === Cracker.onlineFix)
|
||||
return onlineFixMerge(unlockedAchievements, achievements);
|
||||
unlockedAchievements: any
|
||||
): UnlockedAchievement[] => {
|
||||
if (type === Cracker.onlineFix) return onlineFixMerge(unlockedAchievements);
|
||||
if (type === Cracker.goldberg)
|
||||
return goldbergUnlockedAchievements(unlockedAchievements, achievements);
|
||||
return defaultMerge(unlockedAchievements, achievements);
|
||||
return goldbergUnlockedAchievements(unlockedAchievements);
|
||||
return defaultMerge(unlockedAchievements);
|
||||
};
|
||||
|
||||
const onlineFixMerge = (
|
||||
unlockedAchievements: any,
|
||||
achievements: Achievement[]
|
||||
): CheckedAchievements => {
|
||||
const newUnlockedAchievements: Achievement[] = [];
|
||||
const onlineFixMerge = (unlockedAchievements: any): UnlockedAchievement[] => {
|
||||
const parsedUnlockedAchievements: UnlockedAchievement[] = [];
|
||||
|
||||
for (const achievement of achievements) {
|
||||
if (achievement.achieved) continue;
|
||||
for (const achievement of Object.keys(unlockedAchievements)) {
|
||||
const unlockedAchievement = unlockedAchievements[achievement];
|
||||
|
||||
const unlockedAchievement = unlockedAchievements[achievement.id];
|
||||
|
||||
if (!unlockedAchievement) continue;
|
||||
|
||||
achievement.achieved = Boolean(
|
||||
unlockedAchievement?.achieved ?? achievement.achieved
|
||||
);
|
||||
|
||||
achievement.unlockTime =
|
||||
unlockedAchievement?.timestamp ?? achievement.unlockTime;
|
||||
|
||||
if (achievement.achieved) {
|
||||
newUnlockedAchievements.push(achievement);
|
||||
if (unlockedAchievement?.achieved) {
|
||||
parsedUnlockedAchievements.push({
|
||||
name: achievement,
|
||||
unlockTime: unlockedAchievement.timestamp,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { all: achievements, new: newUnlockedAchievements };
|
||||
return parsedUnlockedAchievements;
|
||||
};
|
||||
|
||||
const goldbergUnlockedAchievements = (
|
||||
unlockedAchievements: any,
|
||||
achievements: Achievement[]
|
||||
): CheckedAchievements => {
|
||||
const newUnlockedAchievements: Achievement[] = [];
|
||||
unlockedAchievements: any
|
||||
): UnlockedAchievement[] => {
|
||||
const newUnlockedAchievements: UnlockedAchievement[] = [];
|
||||
|
||||
for (const achievement of achievements) {
|
||||
if (achievement.achieved) continue;
|
||||
for (const achievement of Object.keys(unlockedAchievements)) {
|
||||
const unlockedAchievement = unlockedAchievements[achievement];
|
||||
|
||||
const unlockedAchievement = unlockedAchievements[achievement.id];
|
||||
|
||||
if (!unlockedAchievement) continue;
|
||||
|
||||
achievement.achieved = Boolean(
|
||||
unlockedAchievement?.earned ?? achievement.achieved
|
||||
);
|
||||
|
||||
achievement.unlockTime =
|
||||
unlockedAchievement?.earned_time ?? achievement.unlockTime;
|
||||
|
||||
if (achievement.achieved) {
|
||||
newUnlockedAchievements.push(achievement);
|
||||
if (unlockedAchievement?.earned) {
|
||||
newUnlockedAchievements.push({
|
||||
name: achievement,
|
||||
unlockTime: unlockedAchievement.earned_time,
|
||||
});
|
||||
}
|
||||
}
|
||||
return { all: achievements, new: newUnlockedAchievements };
|
||||
return newUnlockedAchievements;
|
||||
};
|
||||
|
||||
const defaultMerge = (
|
||||
unlockedAchievements: any,
|
||||
achievements: Achievement[]
|
||||
): CheckedAchievements => {
|
||||
const newUnlockedAchievements: Achievement[] = [];
|
||||
console.log("checkUnlockedAchievements");
|
||||
for (const achievement of achievements) {
|
||||
if (achievement.achieved) continue;
|
||||
const defaultMerge = (unlockedAchievements: any): UnlockedAchievement[] => {
|
||||
const newUnlockedAchievements: UnlockedAchievement[] = [];
|
||||
|
||||
const unlockedAchievement = unlockedAchievements[achievement.id];
|
||||
for (const achievement of Object.keys(unlockedAchievements)) {
|
||||
const unlockedAchievement = unlockedAchievements[achievement];
|
||||
|
||||
if (!unlockedAchievement) continue;
|
||||
|
||||
achievement.achieved = Boolean(
|
||||
unlockedAchievement?.Achieved ?? achievement.achieved
|
||||
);
|
||||
|
||||
achievement.curProgress =
|
||||
unlockedAchievement?.CurProgress ?? achievement.curProgress;
|
||||
|
||||
achievement.maxProgress =
|
||||
unlockedAchievement?.MaxProgress ?? achievement.maxProgress;
|
||||
|
||||
achievement.unlockTime =
|
||||
unlockedAchievement?.UnlockTime ?? achievement.unlockTime;
|
||||
|
||||
if (achievement.achieved) {
|
||||
newUnlockedAchievements.push(achievement);
|
||||
if (unlockedAchievement?.Achieved) {
|
||||
newUnlockedAchievements.push({
|
||||
name: achievement,
|
||||
unlockTime: unlockedAchievement.UnlockTime,
|
||||
});
|
||||
}
|
||||
}
|
||||
console.log("newUnlocked: ", newUnlockedAchievements);
|
||||
return { all: achievements, new: newUnlockedAchievements };
|
||||
|
||||
return newUnlockedAchievements;
|
||||
};
|
||||
|
|
|
@ -79,7 +79,7 @@ function onOpenGame(game: Game) {
|
|||
createGame({ ...game, lastTimePlayed: new Date() }).catch(() => {});
|
||||
}
|
||||
|
||||
startGameAchievementObserver(game.id);
|
||||
startGameAchievementObserver(game);
|
||||
}
|
||||
|
||||
function onTickGame(game: Game) {
|
||||
|
@ -116,6 +116,8 @@ function onTickGame(game: Game) {
|
|||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
startGameAchievementObserver(game);
|
||||
}
|
||||
|
||||
const onCloseGame = (game: Game) => {
|
||||
|
|
|
@ -123,7 +123,6 @@ export function GameDetailsContextProvider({
|
|||
if (statsResult.status === "fulfilled") setStats(statsResult.value);
|
||||
|
||||
if (achievements.status === "fulfilled") {
|
||||
console.log(achievements.value);
|
||||
setAchievements(achievements.value);
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue