diff --git a/src/main/entity/game-achievements.entity.ts b/src/main/entity/game-achievements.entity.ts index 48ca958b..29cca558 100644 --- a/src/main/entity/game-achievements.entity.ts +++ b/src/main/entity/game-achievements.entity.ts @@ -1,20 +1,15 @@ -import { - Column, - Entity, - JoinColumn, - OneToOne, - PrimaryGeneratedColumn, -} from "typeorm"; -import type { Game } from "./game.entity"; +import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; @Entity("game_achievement") export class GameAchievement { @PrimaryGeneratedColumn() id: number; - @OneToOne("Game", "achievements") - @JoinColumn() - game: Game; + @Column("text") + objectId: string; + + @Column("text") + shop: string; @Column("text", { nullable: true }) unlockedAchievements: string; diff --git a/src/main/entity/game.entity.ts b/src/main/entity/game.entity.ts index 98606167..190e7470 100644 --- a/src/main/entity/game.entity.ts +++ b/src/main/entity/game.entity.ts @@ -12,7 +12,6 @@ import { Repack } from "./repack.entity"; import type { GameShop, GameStatus } from "@types"; import { Downloader } from "@shared"; import type { DownloadQueue } from "./download-queue.entity"; -import { GameAchievement } from "./game-achievements.entity"; @Entity("game") export class Game { @@ -77,9 +76,6 @@ export class Game { @JoinColumn() repack: Repack; - @OneToOne("GameAchievement", "game") - achievements: GameAchievement; - @OneToOne("DownloadQueue", "game") downloadQueue: DownloadQueue; diff --git a/src/main/events/catalogue/get-game-achievements.ts b/src/main/events/catalogue/get-game-achievements.ts index acd7a4a6..fff05248 100644 --- a/src/main/events/catalogue/get-game-achievements.ts +++ b/src/main/events/catalogue/get-game-achievements.ts @@ -1,23 +1,19 @@ -import type { GameShop } from "@types"; - +import type { GameAchievement, GameShop } from "@types"; import { registerEvent } from "../register-event"; import { HydraApi } from "@main/services"; import { gameAchievementRepository, gameRepository } from "@main/repository"; -import { GameAchievement } from "@main/entity"; const getGameAchievements = async ( _event: Electron.IpcMainInvokeEvent, objectId: string, shop: GameShop ): Promise => { - const game = await gameRepository.findOne({ - where: { objectID: objectId, shop }, - relations: { - achievements: true, - }, - }); - - const cachedAchievements = game?.achievements?.achievements; + const [game, cachedAchievements] = await Promise.all([ + gameRepository.findOne({ + where: { objectID: objectId, shop }, + }), + gameAchievementRepository.findOne({ where: { objectId, shop } }), + ]); const apiAchievement = HydraApi.get( "/games/achievements", @@ -28,10 +24,11 @@ const getGameAchievements = async ( if (game) { gameAchievementRepository.upsert( { - game: { id: game.id }, + objectId, + shop, achievements: JSON.stringify(achievements), }, - ["game"] + ["objectId", "shop"] ); } @@ -39,12 +36,12 @@ const getGameAchievements = async ( }) .catch(() => []); - const gameAchievements = cachedAchievements - ? JSON.parse(cachedAchievements) + const gameAchievements = cachedAchievements?.achievements + ? JSON.parse(cachedAchievements.achievements) : await apiAchievement; const unlockedAchievements = JSON.parse( - game?.achievements?.unlockedAchievements || "[]" + cachedAchievements?.unlockedAchievements || "[]" ) as { name: string; unlockTime: number }[]; return gameAchievements diff --git a/src/main/migrations/20240919030940_create_game_achievement.ts b/src/main/migrations/20240919030940_create_game_achievement.ts index a03ea2fc..791eeb29 100644 --- a/src/main/migrations/20240919030940_create_game_achievement.ts +++ b/src/main/migrations/20240919030940_create_game_achievement.ts @@ -6,10 +6,11 @@ export const CreateGameAchievement: HydraMigration = { up: (knex: Knex) => { return knex.schema.createTable("game_achievement", (table) => { table.increments("id").primary(); - table.integer("gameId").notNullable().unique(); + table.text("objectId").notNullable(); + table.text("shop").notNullable(); table.text("achievements"); table.text("unlockedAchievements"); - table.foreign("gameId").references("game.id").onDelete("CASCADE"); + table.unique(["objectId", "shop"]); }); }, diff --git a/src/main/services/achievements/services/save-all-local-steam-achivements.ts b/src/main/services/achievements/services/save-all-local-steam-achivements.ts index 6db5f96a..fde1ba19 100644 --- a/src/main/services/achievements/services/save-all-local-steam-achivements.ts +++ b/src/main/services/achievements/services/save-all-local-steam-achivements.ts @@ -9,17 +9,18 @@ export const saveAllLocalSteamAchivements = async () => { for (const key of Object.keys(gameAchievementFiles)) { const objectId = key; - const game = await gameRepository.findOne({ - where: { objectID: objectId }, - }); + const [game, localAchievements] = await Promise.all([ + gameRepository.findOne({ + where: { objectID: objectId, shop: "steam", isDeleted: false }, + }), + gameAchievementRepository.findOne({ + where: { objectId, shop: "steam" }, + }), + ]); if (!game) continue; - const savedGameAchievements = await gameAchievementRepository.findOneBy({ - game: game, - }); - - if (!savedGameAchievements || !savedGameAchievements.achievements) { + if (!localAchievements || !localAchievements.achievements) { HydraApi.get( "/games/achievements", { @@ -31,10 +32,11 @@ export const saveAllLocalSteamAchivements = async () => { .then((achievements) => { return gameAchievementRepository.upsert( { - game: { id: game.id }, + objectId, + shop: "steam", achievements: JSON.stringify(achievements), }, - ["game"] + ["objectId", "shop"] ); }) .catch(console.log); @@ -58,12 +60,13 @@ export const saveAllLocalSteamAchivements = async () => { } } - await gameAchievementRepository.upsert( + gameAchievementRepository.upsert( { - game: { id: game.id }, + objectId, + shop: "steam", unlockedAchievements: JSON.stringify(unlockedAchievements), }, - ["game"] + ["objectId", "shop"] ); } }; diff --git a/src/renderer/src/context/game-details/game-details.context.tsx b/src/renderer/src/context/game-details/game-details.context.tsx index cd02f7a2..c8ac4814 100644 --- a/src/renderer/src/context/game-details/game-details.context.tsx +++ b/src/renderer/src/context/game-details/game-details.context.tsx @@ -31,6 +31,7 @@ export const gameDetailsContext = createContext({ showRepacksModal: false, showGameOptionsModal: false, stats: null, + achievements: [], hasNSFWContentBlocked: false, setGameColor: () => {}, selectGameExecutable: async () => null, diff --git a/src/renderer/src/hooks/use-date.ts b/src/renderer/src/hooks/use-date.ts index 3657a76e..a0cfdb9f 100644 --- a/src/renderer/src/hooks/use-date.ts +++ b/src/renderer/src/hooks/use-date.ts @@ -70,7 +70,10 @@ export function useDate() { format: (timestamp: number): string => { const locale = getDateLocale(); - return format(timestamp, locale == enUS ? "MM/dd/yyyy - HH:mm" : "dd/MM/yyyy - HH:mm"); + return format( + timestamp, + locale == enUS ? "MM/dd/yyyy - HH:mm" : "dd/MM/yyyy - HH:mm" + ); }, }; } diff --git a/src/renderer/src/pages/game-details/sidebar/sidebar.tsx b/src/renderer/src/pages/game-details/sidebar/sidebar.tsx index dee44b1f..0ef16194 100644 --- a/src/renderer/src/pages/game-details/sidebar/sidebar.tsx +++ b/src/renderer/src/pages/game-details/sidebar/sidebar.tsx @@ -7,7 +7,7 @@ import * as styles from "./sidebar.css"; import { gameDetailsContext } from "@renderer/context"; import { useDate, useFormat } from "@renderer/hooks"; import { DownloadIcon, PeopleIcon } from "@primer/octicons-react"; -import { SPACING_UNIT, vars } from "@renderer/theme.css"; +import { SPACING_UNIT } from "@renderer/theme.css"; export function Sidebar() { const [_howLongToBeat, _setHowLongToBeat] = useState<{