mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
Merge branch 'feature/game-achievements' into chore/test-preview
This commit is contained in:
commit
8fdc6c4ab2
6 changed files with 96 additions and 34 deletions
|
@ -62,9 +62,7 @@ export const checkAchievementFileChange = async (games: Game[]) => {
|
||||||
const achievementFileInsideDirectory =
|
const achievementFileInsideDirectory =
|
||||||
findAchievementFileInExecutableDirectory(game);
|
findAchievementFileInExecutableDirectory(game);
|
||||||
|
|
||||||
if (achievementFileInsideDirectory) {
|
gameAchievementFiles.push(...achievementFileInsideDirectory);
|
||||||
gameAchievementFiles.push(achievementFileInsideDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gameAchievementFiles.length) continue;
|
if (!gameAchievementFiles.length) continue;
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,10 @@ const getPathFromCracker = async (cracker: Cracker) => {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cracker === Cracker._3dm) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
achievementsLogger.error(`Cracker ${cracker} not implemented`);
|
achievementsLogger.error(`Cracker ${cracker} not implemented`);
|
||||||
throw new Error(`Cracker ${cracker} not implemented`);
|
throw new Error(`Cracker ${cracker} not implemented`);
|
||||||
};
|
};
|
||||||
|
@ -163,22 +167,33 @@ export const findAchievementFiles = async (game: Game) => {
|
||||||
|
|
||||||
export const findAchievementFileInExecutableDirectory = (
|
export const findAchievementFileInExecutableDirectory = (
|
||||||
game: Game
|
game: Game
|
||||||
): AchievementFile | null => {
|
): AchievementFile[] => {
|
||||||
if (!game.executablePath) {
|
if (!game.executablePath) {
|
||||||
return null;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const steamDataPath = path.join(
|
return [
|
||||||
game.executablePath,
|
{
|
||||||
"..",
|
type: Cracker.userstats,
|
||||||
"SteamData",
|
filePath: path.join(
|
||||||
"user_stats.ini"
|
game.executablePath,
|
||||||
);
|
"..",
|
||||||
|
"SteamData",
|
||||||
return {
|
"user_stats.ini"
|
||||||
type: Cracker.userstats,
|
),
|
||||||
filePath: steamDataPath,
|
},
|
||||||
};
|
{
|
||||||
|
type: Cracker._3dm,
|
||||||
|
filePath: path.join(
|
||||||
|
game.executablePath,
|
||||||
|
"..",
|
||||||
|
"3DMGAME",
|
||||||
|
"Player",
|
||||||
|
"stats",
|
||||||
|
"achievements.ini"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const findAllAchievementFiles = async () => {
|
export const findAllAchievementFiles = async () => {
|
||||||
|
|
|
@ -45,6 +45,11 @@ export const parseAchievementFile = async (
|
||||||
return processSkidrow(parsed);
|
return processSkidrow(parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === Cracker._3dm) {
|
||||||
|
const parsed = await iniParse(filePath);
|
||||||
|
return process3DM(parsed);
|
||||||
|
}
|
||||||
|
|
||||||
achievementsLogger.log(`${type} achievements found on ${filePath}`);
|
achievementsLogger.log(`${type} achievements found on ${filePath}`);
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
@ -69,11 +74,10 @@ const iniParse = async (filePath: string) => {
|
||||||
object[objectName] = {};
|
object[objectName] = {};
|
||||||
} else {
|
} else {
|
||||||
const [name, ...value] = line.split("=");
|
const [name, ...value] = line.split("=");
|
||||||
object[objectName][name.trim()] = value.join("").trim();
|
object[objectName][name.trim()] = value.join("=").trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Parsed ini", object);
|
|
||||||
return object;
|
return object;
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
|
@ -139,6 +143,28 @@ const processGoldberg = (unlockedAchievements: any): UnlockedAchievement[] => {
|
||||||
return newUnlockedAchievements;
|
return newUnlockedAchievements;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const process3DM = (unlockedAchievements: any): UnlockedAchievement[] => {
|
||||||
|
const newUnlockedAchievements: UnlockedAchievement[] = [];
|
||||||
|
|
||||||
|
const achievements = unlockedAchievements["State"];
|
||||||
|
const times = unlockedAchievements["Time"];
|
||||||
|
|
||||||
|
for (const achievement of Object.keys(achievements)) {
|
||||||
|
if (achievements[achievement] == "0101") {
|
||||||
|
const time = times[achievement];
|
||||||
|
|
||||||
|
newUnlockedAchievements.push({
|
||||||
|
name: achievement,
|
||||||
|
unlockTime: new DataView(
|
||||||
|
new Uint8Array(Buffer.from(time.toString(), "hex")).buffer
|
||||||
|
).getUint32(0, true),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newUnlockedAchievements;
|
||||||
|
};
|
||||||
|
|
||||||
const processDefault = (unlockedAchievements: any): UnlockedAchievement[] => {
|
const processDefault = (unlockedAchievements: any): UnlockedAchievement[] => {
|
||||||
const newUnlockedAchievements: UnlockedAchievement[] = [];
|
const newUnlockedAchievements: UnlockedAchievement[] = [];
|
||||||
|
|
||||||
|
@ -195,7 +221,7 @@ const processUserStats = (unlockedAchievements: any): UnlockedAchievement[] => {
|
||||||
|
|
||||||
if (!isNaN(unlockTime)) {
|
if (!isNaN(unlockTime)) {
|
||||||
newUnlockedAchievements.push({
|
newUnlockedAchievements.push({
|
||||||
name: achievement,
|
name: achievement.replace(/"/g, ``),
|
||||||
unlockTime: unlockTime,
|
unlockTime: unlockTime,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,35 +2,41 @@ import { gameAchievementRepository, gameRepository } from "@main/repository";
|
||||||
import {
|
import {
|
||||||
findAllAchievementFiles,
|
findAllAchievementFiles,
|
||||||
findAchievementFiles,
|
findAchievementFiles,
|
||||||
|
findAchievementFileInExecutableDirectory,
|
||||||
} from "./find-achivement-files";
|
} from "./find-achivement-files";
|
||||||
import { parseAchievementFile } from "./parse-achievement-file";
|
import { parseAchievementFile } from "./parse-achievement-file";
|
||||||
import { mergeAchievements } from "./merge-achievements";
|
import { mergeAchievements } from "./merge-achievements";
|
||||||
import type { UnlockedAchievement } from "@types";
|
import type { UnlockedAchievement } from "@types";
|
||||||
import { getGameAchievementData } from "./get-game-achievement-data";
|
import { getGameAchievementData } from "./get-game-achievement-data";
|
||||||
|
import { achievementsLogger } from "../logger";
|
||||||
|
|
||||||
export const updateAllLocalUnlockedAchievements = async () => {
|
export const updateAllLocalUnlockedAchievements = async () => {
|
||||||
const gameAchievementFilesMap = await findAllAchievementFiles();
|
const gameAchievementFilesMap = await findAllAchievementFiles();
|
||||||
|
|
||||||
for (const objectId of gameAchievementFilesMap.keys()) {
|
const games = await gameRepository.find({
|
||||||
const gameAchievementFiles = gameAchievementFilesMap.get(objectId)!;
|
where: {
|
||||||
|
isDeleted: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const [game, localAchievements] = await Promise.all([
|
for (const game of games) {
|
||||||
gameRepository.findOne({
|
const gameAchievementFiles =
|
||||||
where: { objectID: objectId, shop: "steam", isDeleted: false },
|
gameAchievementFilesMap.get(game.objectID) || [];
|
||||||
}),
|
const achievementFileInsideDirectory =
|
||||||
gameAchievementRepository.findOne({
|
findAchievementFileInExecutableDirectory(game);
|
||||||
where: { objectId, shop: "steam" },
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!game) continue;
|
gameAchievementFiles.push(...achievementFileInsideDirectory);
|
||||||
|
|
||||||
|
const localAchievements = await gameAchievementRepository.findOne({
|
||||||
|
where: { objectId: game.objectID, shop: "steam" },
|
||||||
|
});
|
||||||
|
|
||||||
if (!localAchievements || !localAchievements.achievements) {
|
if (!localAchievements || !localAchievements.achievements) {
|
||||||
await getGameAchievementData(objectId, "steam")
|
await getGameAchievementData(game.objectID, "steam")
|
||||||
.then((achievements) => {
|
.then((achievements) => {
|
||||||
return gameAchievementRepository.upsert(
|
return gameAchievementRepository.upsert(
|
||||||
{
|
{
|
||||||
objectId,
|
objectId: game.objectID,
|
||||||
shop: "steam",
|
shop: "steam",
|
||||||
achievements: JSON.stringify(achievements),
|
achievements: JSON.stringify(achievements),
|
||||||
},
|
},
|
||||||
|
@ -47,13 +53,20 @@ export const updateAllLocalUnlockedAchievements = async () => {
|
||||||
achievementFile.filePath,
|
achievementFile.filePath,
|
||||||
achievementFile.type
|
achievementFile.type
|
||||||
);
|
);
|
||||||
console.log("Parsed for", game.title, parsedAchievements);
|
|
||||||
if (parsedAchievements.length) {
|
if (parsedAchievements.length) {
|
||||||
unlockedAchievements.push(...parsedAchievements);
|
unlockedAchievements.push(...parsedAchievements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
achievementsLogger.log(
|
||||||
|
"Achievement file for",
|
||||||
|
game.title,
|
||||||
|
achievementFile.filePath,
|
||||||
|
parsedAchievements
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
mergeAchievements(objectId, "steam", unlockedAchievements, false);
|
mergeAchievements(game.objectID, "steam", unlockedAchievements, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,6 +84,11 @@ export const updateLocalUnlockedAchivements = async (objectId: string) => {
|
||||||
|
|
||||||
const gameAchievementFiles = await findAchievementFiles(game);
|
const gameAchievementFiles = await findAchievementFiles(game);
|
||||||
|
|
||||||
|
const achievementFileInsideDirectory =
|
||||||
|
findAchievementFileInExecutableDirectory(game);
|
||||||
|
|
||||||
|
gameAchievementFiles.push(...achievementFileInsideDirectory);
|
||||||
|
|
||||||
console.log("Achievements files for", game.title, gameAchievementFiles);
|
console.log("Achievements files for", game.title, gameAchievementFiles);
|
||||||
|
|
||||||
if (!localAchievements || !localAchievements.achievements) {
|
if (!localAchievements || !localAchievements.achievements) {
|
||||||
|
|
|
@ -10,6 +10,10 @@ log.transports.file.resolvePathFn = (
|
||||||
return path.join(logsPath, "pythoninstance.txt");
|
return path.join(logsPath, "pythoninstance.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (message?.scope == "achievements") {
|
||||||
|
return path.join(logsPath, "achievements.txt");
|
||||||
|
}
|
||||||
|
|
||||||
if (message?.level === "error") {
|
if (message?.level === "error") {
|
||||||
return path.join(logsPath, "error.txt");
|
return path.join(logsPath, "error.txt");
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,4 +35,5 @@ export enum Cracker {
|
||||||
skidrow = "SKIDROW",
|
skidrow = "SKIDROW",
|
||||||
creamAPI = "CreamAPI",
|
creamAPI = "CreamAPI",
|
||||||
smartSteamEmu = "SmartSteamEmu",
|
smartSteamEmu = "SmartSteamEmu",
|
||||||
|
_3dm = "3dm",
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue