Merge branch 'feature/game-achievements' of github.com:hydralauncher/hydra into feature/cloud-sync

This commit is contained in:
Chubby Granny Chaser
2024-10-16 10:46:35 +01:00
48 changed files with 1597 additions and 376 deletions

View File

@@ -1,57 +1,32 @@
import type { GameAchievement, GameShop, UnlockedAchievement } from "@types";
import type {
AchievementData,
GameShop,
RemoteUnlockedAchievement,
UnlockedAchievement,
UserAchievement,
} from "@types";
import { registerEvent } from "../register-event";
import {
gameAchievementRepository,
userAuthRepository,
userPreferencesRepository,
} from "@main/repository";
import { getGameAchievementData } from "@main/services/achievements/get-game-achievement-data";
import { HydraApi } from "@main/services";
const getAchievements = async (
shop: string,
objectId: string,
userId?: string
) => {
const userAuth = await userAuthRepository.findOne({ where: { userId } });
const getAchievementLocalUser = async (shop: string, objectId: string) => {
const cachedAchievements = await gameAchievementRepository.findOne({
where: { objectId, shop },
});
const achievementsData = cachedAchievements?.achievements
? JSON.parse(cachedAchievements.achievements)
: await getGameAchievementData(objectId, shop);
const achievementsData = await getGameAchievementData(objectId, shop);
if (!userId || userAuth) {
const unlockedAchievements = JSON.parse(
cachedAchievements?.unlockedAchievements || "[]"
) as UnlockedAchievement[];
return { achievementsData, unlockedAchievements };
}
const unlockedAchievements = await HydraApi.get<UnlockedAchievement[]>(
`/users/${userId}/games/achievements`,
{ shop, objectId, language: "en" }
);
return { achievementsData, unlockedAchievements };
};
export const getGameAchievements = async (
objectId: string,
shop: GameShop,
userId?: string
): Promise<GameAchievement[]> => {
const { achievementsData, unlockedAchievements } = await getAchievements(
shop,
objectId,
userId
);
const unlockedAchievements = JSON.parse(
cachedAchievements?.unlockedAchievements || "[]"
) as UnlockedAchievement[];
return achievementsData
.map((achievementData) => {
const unlockedAchiement = unlockedAchievements.find(
const unlockedAchiementData = unlockedAchievements.find(
(localAchievement) => {
return (
localAchievement.name.toUpperCase() ==
@@ -60,29 +35,112 @@ export const getGameAchievements = async (
}
);
if (unlockedAchiement) {
const icongray = achievementData.icongray.endsWith("/")
? achievementData.icon
: achievementData.icongray;
if (unlockedAchiementData) {
return {
...achievementData,
unlocked: true,
unlockTime: unlockedAchiement.unlockTime,
unlockTime: unlockedAchiementData.unlockTime,
};
}
return { ...achievementData, unlocked: false, unlockTime: null };
return {
...achievementData,
unlocked: false,
unlockTime: null,
icon: icongray,
} as UserAchievement;
})
.sort((a, b) => {
if (a.unlocked && !b.unlocked) return -1;
if (!a.unlocked && b.unlocked) return 1;
return b.unlockTime - a.unlockTime;
if (a.unlocked && b.unlocked) {
return b.unlockTime! - a.unlockTime!;
}
return Number(a.hidden) - Number(b.hidden);
});
};
const getAchievementsRemoteUser = async (
shop: string,
objectId: string,
userId: string
) => {
const userPreferences = await userPreferencesRepository.findOne({
where: { id: 1 },
});
const achievementsData: AchievementData[] = await getGameAchievementData(
objectId,
shop
);
const unlockedAchievements = await HydraApi.get<RemoteUnlockedAchievement[]>(
`/users/${userId}/games/achievements`,
{ shop, objectId, language: userPreferences?.language || "en" }
);
return achievementsData
.map((achievementData) => {
const unlockedAchiementData = unlockedAchievements.find(
(localAchievement) => {
return (
localAchievement.name.toUpperCase() ==
achievementData.name.toUpperCase()
);
}
);
const icongray = achievementData.icongray.endsWith("/")
? achievementData.icon
: achievementData.icongray;
if (unlockedAchiementData) {
return {
...achievementData,
unlocked: true,
unlockTime: unlockedAchiementData.unlockTime,
};
}
return {
...achievementData,
unlocked: false,
unlockTime: null,
icon: icongray,
} as UserAchievement;
})
.sort((a, b) => {
if (a.unlocked && !b.unlocked) return -1;
if (!a.unlocked && b.unlocked) return 1;
if (a.unlocked && b.unlocked) {
return b.unlockTime! - a.unlockTime!;
}
return Number(a.hidden) - Number(b.hidden);
});
};
export const getGameAchievements = async (
objectId: string,
shop: GameShop,
userId?: string
): Promise<UserAchievement[]> => {
if (!userId) {
return getAchievementLocalUser(shop, objectId);
}
return getAchievementsRemoteUser(shop, objectId, userId);
};
const getGameAchievementsEvent = async (
_event: Electron.IpcMainInvokeEvent,
objectId: string,
shop: GameShop,
userId?: string
): Promise<GameAchievement[]> => {
): Promise<UserAchievement[]> => {
return getGameAchievements(objectId, shop, userId);
};

View File

@@ -50,7 +50,8 @@ const openGameInstaller = async (
}
if (fs.lstatSync(gamePath).isFile()) {
return executeGameInstaller(gamePath);
shell.showItemInFolder(gamePath);
return true;
}
const setupPath = path.join(gamePath, "setup.exe");

View File

@@ -1,15 +1,18 @@
import { registerEvent } from "../register-event";
import * as Sentry from "@sentry/electron/main";
import { HydraApi } from "@main/services";
import { HydraApi, logger } from "@main/services";
import { ProfileVisibility, UserDetails } from "@types";
import { userAuthRepository } from "@main/repository";
import {
userAuthRepository,
userSubscriptionRepository,
} from "@main/repository";
import { UserNotLoggedInError } from "@shared";
const getMe = async (
_event: Electron.IpcMainInvokeEvent
): Promise<UserDetails | null> => {
return HydraApi.get<UserDetails>(`/profile/me`)
.then(async (me) => {
.then((me) => {
userAuthRepository.upsert(
{
id: 1,
@@ -20,6 +23,23 @@ const getMe = async (
["id"]
);
if (me.subscription) {
userSubscriptionRepository.upsert(
{
id: 1,
subscriptionId: me.subscription?.id || "",
status: me.subscription?.status || "",
planId: me.subscription?.plan.id || "",
planName: me.subscription?.plan.name || "",
expiresAt: me.subscription?.expiresAt || null,
user: { id: 1 },
},
["id"]
);
} else {
userSubscriptionRepository.delete({ id: 1 });
}
Sentry.setUser({ id: me.id, username: me.username });
return me;
@@ -28,7 +48,7 @@ const getMe = async (
if (err instanceof UserNotLoggedInError) {
return null;
}
logger.error("Failed to get logged user", err);
const loggedUser = await userAuthRepository.findOne({ where: { id: 1 } });
if (loggedUser) {
@@ -38,6 +58,17 @@ const getMe = async (
username: "",
bio: "",
profileVisibility: "PUBLIC" as ProfileVisibility,
subscription: loggedUser.subscription
? {
id: loggedUser.subscription.subscriptionId,
status: loggedUser.subscription.status,
plan: {
id: loggedUser.subscription.planId,
name: loggedUser.subscription.planName,
},
expiresAt: loggedUser.subscription.expiresAt,
}
: null,
};
}