jshackles / RetroGOG

RetroArch integrations for GOG Galaxy 2.0
92 stars 11 forks source link

Game Boy, Game Boy Color, and Game Boy Advance all showing as "Game Boy" #13

Open XyberDAWG opened 3 years ago

XyberDAWG commented 3 years ago

Shouldnt these three all show up as Integrations with different names, and different Lists in GOG?

jshackles commented 3 years ago

This is (currently) by design. Unfortunately, GOG Galaxy does not have platform integration IDs for either Game Boy Color, or Game Boy Advance. Just "Nintendo Game Boy".

https://galaxy-integrations-python-api.readthedocs.io/en/latest/platforms.html

There are currently efforts underway to include these platforms in the GOG Galaxy API

https://github.com/gogcom/galaxy-integrations-python-api/issues/160

manuth commented 3 years ago

@XyberDAWG I tinkered with the original RetroGOG plugin.py-file to include GB, GBC and GBA games all at once. Sadly games which can't be found on GOGs gamesdb act quite weird (they show up as "Unknown Game") but apart from that, this workaround should work for you.

Just replace the content your RetroGOG "Nintendo Game Boy"'s plugin.py with following:

plugin.py ```py import asyncio import subprocess import sys import json, urllib.request, os, os.path import user_config import datetime import logging import time from collections import namedtuple from typing import Any, Callable, Dict, List, NewType, Optional from galaxy.api.consts import LicenseType, LocalGameState, Platform from galaxy.api.plugin import Plugin, create_and_run_plugin from galaxy.api.types import Achievement, Authentication, Game, LicenseInfo, LocalGame, GameTime from version import __version__ as version class Retroarch(Plugin): def __init__(self, reader, writer, token): super().__init__(Platform.NintendoGameBoy, version, reader, writer, token) self.internal_game_list: dict[str, tuple[str, Game]] = {} self.internal_game_list = None self.playlist_paths = { "gb": user_config.emu_path + "playlists/Nintendo - Game Boy.lpl", "gbc": user_config.emu_path + "playlists/Nintendo - Game Boy Color.lpl", "gba": user_config.emu_path + "playlists/Nintendo - Game Boy Advance.lpl" } self.proc = None self.game_run = "" @property def game_list(self): if self.internal_game_list is None: self.internal_game_list = {} self.update_game_list() return self.internal_game_list async def authenticate(self, stored_credentials = None): creds = {} creds["user"] = "RAUser" self.store_credentials(creds) return Authentication("RAUser", "Retroarch") async def pass_login_credentials(self, step, credentials, cookies): creds = {} creds["user"] = "RAUser" self.store_credentials(creds) return Authentication("RAUser", "Retroarch") async def get_owned_games(self): game_list = [] if self.game_list is not None: self.update_game_list() for game_id in self.game_list: game_list.append(self.game_list[game_id][1]) return game_list # Format helper for game names def format_game(self, game): game_return = game.rsplit(" (")[0] game_return = game_return.replace("'","") return game_return #Scans retroarch playlist for roms in rom_path and adds them to self.game_cache #as roms don't need to be installed, owned games and local games are the same and both run update_game_cache def update_game_list(self): game_list: dict[str, tuple[str, Game]] = {} for console_id in self.playlist_paths: playlist_path = self.playlist_paths[console_id] if os.path.isfile(playlist_path): with open(playlist_path) as playlist_data: playlist = json.load(playlist_data) for game in playlist["items"]: game_path = game["path"].split("#")[0] if os.path.isfile(game_path): game_title = self.format_game(game["label"]) game_id = game_title + " " + console_id.upper() game_list[game_id] = ( game_path, Game( game_id, game_title, None, LicenseInfo(LicenseType.SinglePurchase, None))) #adds games when added while running for game_id in game_list: if game_id not in self.game_list: self.game_list[game_id] = game_list[game_id] self.add_game(game_list[game_id][1]) #removes games when removed while running for game_id in self.game_list: if game_id not in game_list: self.game_list.pop(game_id) self.remove_game(game_id) async def get_local_games(self): local_game_list = [] for game_id in self.game_list: local_game_list.append(LocalGame(self.game_list[game_id][1].game_id, 1)) return local_game_list # Only as placeholders so the launch game feature is recognized async def install_game(self, game_id): pass async def uninstall_game(self, game_id): pass def shutdown(self): pass #potentially give user more customization possibilities like starting in fullscreen etc async def launch_game(self, game_id: str): if game_id in self.game_list: game_entry = self.game_list[game_id] self.update_local_game_status(LocalGame(game_id, 2)) self.game_run = game_id self.proc = subprocess.Popen( os.path.abspath(os.path.join(user_config.emu_path, "retroarch.exe")) + " -L \"" + os.path.abspath(os.path.join(user_config.emu_path, "cores", user_config.core) + "\" " + "\"" + os.path.abspath(game_entry[0]) + "\"")) #imports retroarch playtime if existent. For this to work, activate "Save runtime log (aggregate)" in RetroArch settings -> Savings async def get_game_time(self, game_id: str, context: any): file_path = "" time = 0 last_played = None game_entry = self.game_list[game_id] log_path = os.path.join(user_config.emu_path, "playlists", "logs", os.path.basename(game_entry[0]).rsplit("#")[0].rsplit(".", 1)[0] + ".lrtl") if os.path.isfile(log_path): with open(log_path) as log_data: log = json.load(log_data) last_played = datetime.datetime.timestamp(datetime.datetime.strptime(log["last_played"], '%Y-%m-%d %H:%M:%S')) runtime_span = datetime.datetime.strptime(log["runtime"], '%H:%M:%S') runtime = runtime_span.hour * 60 + runtime_span.minute return GameTime(game_id, time, last_played) #checks if game is (still) running, adjusts game_cache and game_time def tick(self): try: if self.proc.poll() is not None: self.update_local_game_status(LocalGame(self.game_run, 1)) self.update_game_time(self.get_game_time(self.game_run, None)) self.proc = None except AttributeError: pass self.update_game_list() self.get_local_games() def main(): create_and_run_plugin(Retroarch, sys.argv) if __name__ == "__main__": main() ```