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

This commit is contained in:
Zamitto 2024-10-05 20:33:06 -03:00
commit 8fdc6c4ab2
6 changed files with 96 additions and 34 deletions

View file

@ -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;

View file

@ -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 () => {

View file

@ -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,
}); });
} }

View file

@ -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) {

View file

@ -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");
} }

View file

@ -35,4 +35,5 @@ export enum Cracker {
skidrow = "SKIDROW", skidrow = "SKIDROW",
creamAPI = "CreamAPI", creamAPI = "CreamAPI",
smartSteamEmu = "SmartSteamEmu", smartSteamEmu = "SmartSteamEmu",
_3dm = "3dm",
} }