RetroDECK/usr/bin/setsettings.py
2022-03-14 12:01:23 +01:00

701 lines
30 KiB
Python
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
#
# setsettings.py:
# Copyright (C) 2021-present konsumschaf
# Copyright (C) 2021-present konsumlamm
#
# based on setsettings.sh:
# Copyright (C) 2019-present Shanti Gilbert (https://github.com/shantigilbert)
# Copyright (C) 2020-present Fewtarius
# Convert ES settings from distribution.conf to RetroArch configuration in raappend.conf.
from argparse import ArgumentParser
from configparser import ConfigParser
from dataclasses import dataclass
from glob import iglob
import os
import random
import re
import shutil
# If we are on Steam Deck we want a prefix
DEVICE = "DECK"
# TODO: put a real check on the .OS_ARCH file, or maybe not as we are obviously running on Deck
INSTALL_DIR = os.path.expanduser("~/retrodeck")
# if DEVICE == "DECK" :
#
#else:
# INSTALL_DIR = ""
# Files and Folder
ra_conf = INSTALL_DIR + "/storage/.config/retroarch/retroarch.cfg"
ra_source_conf = INSTALL_DIR + "/usr/config/retroarch/retroarch.cfg"
ra_core_conf = INSTALL_DIR + "/storage/.config/retroarch/retroarch-core-options.cfg"
ra_append_conf = "/tmp/raappend.cfg"
os_arch_conf = INSTALL_DIR + "/storage/.config/.OS_ARCH"
snapshots = INSTALL_DIR + "/storage/roms/savestates"
# Logging
class Logger:
dir = "/tmp/logs"
file = "exec.log"
script_basename = os.path.basename(__file__)
def __init__(self):
if not os.path.isdir(self.dir):
os.makedirs(self.dir)
self.file_handle = open(f'{self.dir}/{self.file}',"a+")
def log(self, text: str) -> None:
self.file_handle.write(f'{self.script_basename}: {text}\n')
def __del__(self):
self.file_handle.close()
# No Sections in distribution.conf, we have to fake our own
class MyConfigParser(ConfigParser):
def read(self, filename: str) -> None:
text = open(filename, encoding="utf_8").read()
self.read_string("[351elec]\n" + text, filename)
@dataclass
class Config:
rom_name: str
platform: str
distribution_conf = INSTALL_DIR + "/storage/.config/distribution/configs/distribution.conf"
def __post_init__(self):
# Read the distribution.conf to a dictionary
config_parser = MyConfigParser(strict=False)
config_parser.read(self.distribution_conf)
self.config = config_parser['351elec']
def get_setting(self, setting: str) -> str:
"""Get the settings from distribution.conf"""
pat_rom = f'{self.platform}["{self.rom_name}"].{setting}'
pat_platform = f'{self.platform}.{setting}'
pat_global = f'global.{setting}'
if pat_rom in self.config:
value = self.config[pat_rom]
elif pat_platform in self.config:
value = self.config[pat_platform]
elif pat_global in self.config:
value = self.config[pat_global]
else:
value = ""
if value == "0":
value = ""
return value
def get_bool_string(self, setting: str) -> str:
"""For readability a function that returns "true" and "false" directly."""
if self.get_setting(setting):
return "true"
else:
return "false"
# Delete lines from a config file
def delete_lines(file_path: str, lines: tuple) -> None:
with open(file_path, "r") as input:
tmp_file = f'/tmp/{os.path.basename(file_path)}.tmp'
with open(tmp_file, "w") as output:
for line in input:
write_this_line = True
for item in lines:
if line.strip().startswith(item):
write_this_line = False
break
if write_this_line:
output.write(line)
# replace file with original name
shutil.move(tmp_file, file_path)
# Append dictionary to the end of a file
def write_file(file_path: str, dictionary: dict, separator: str = ' = ', quote_sign: str = '"') -> None:
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, "a") as file:
for (key, value) in dictionary.items():
file.write(f'{key}{separator}{quote_sign}{value}{quote_sign}\n')
# Generate the config out of the distribution.conf
def set_settings(rom_name: str, core: str, platform: str, controllers: str, autosave: str, snapshot: str) -> str:
logger = Logger()
shader_path = ''
#
# Do some checks and clean up first
#
# Log current call:
logger.log(f'ROM: {rom_name}')
logger.log(f'Platform: {platform}')
logger.log(f'Core: {core}')
logger.log(f'Controllers: {controllers}')
logger.log(f'Autosave: {autosave}')
logger.log(f'Snapshot: {snapshot}')
# We only need the ROM, but we get the fullpath
rom_name = os.path.basename(rom_name)
# Delete any existing raappend.cfg first
if os.path.isfile(ra_append_conf):
os.remove(ra_append_conf)
# Restore retroarch.cfg if it is missing or empty
if not os.path.isfile(ra_conf) or os.stat(ra_conf).st_size == 0:
shutil.copy(ra_source_conf,ra_conf)
# Get the Device Name
with open(os_arch_conf, encoding="utf-8") as f:
device_name = f.readline().strip()
logger.log(f'Device: {device_name}')
# Is the CORE 32 or 64bit?
if core in {'pcsx_rearmed', 'parallel_n64'}:
bits='32bit'
else:
bits='64bit'
logger.log(f'core is {bits}')
# Dictionary for the raappend.cfg
ra_append_dict = {}
# Create config from distribution.conf
config = Config(rom_name, platform)
#
# Global configuration directly in retroarch.cfg
#
# RA menu rgui, ozone, glui or xmb (fallback if everthing else fails)
# if empty (auto in ES) do nothing to enable configuration in RA
if menu_driver := config.get_setting('retroarch.menu_driver'):
ra_dict = {}
# delete setting only if we set new ones
# therefore configuring in RA is still possible
delete_lines(ra_conf, ('menu_driver', 'menu_linear_filter'))
if menu_driver == 'rgui':
ra_dict['menu_driver'] = 'rgui'
ra_dict['menu_linear_filter'] = 'true'
elif menu_driver == 'ozone':
ra_dict['menu_driver'] = 'ozone'
elif menu_driver == 'glui':
ra_dict['menu_driver'] = 'glui'
else:
# play it save and set xmb if nothing else matches
ra_dict['menu_driver'] = 'xmb'
write_file(ra_conf, ra_dict)
#
# Convert the settings from distribution.conf to raappend.cfg
#
# FPS
ra_append_dict['fps_show'] = config.get_bool_string("showFPS")
# Retroachievements / Cheevos
retro_achievements = {
'arcade', 'atari2600', 'atari7800', 'atarilynx', 'colecovision',
'famicom', 'fbn', 'fds', 'gamegear', 'gb', 'gba', 'gbah', 'gbc', 'gbch',
'gbh', 'genesis', 'genh', 'ggh', 'intellivision', 'mastersystem',
'megacd', 'megadrive', 'megadrive-japan', 'msx', 'msx2', 'n64',
'neogeo', 'neogeocd', 'nes', 'nesh', 'ngp', 'ngpc', 'odyssey2',
'pcengine', 'pcenginecd', 'pcfx', 'pokemini', 'psp', 'psx', 'sega32x',
'segacd', 'sfc', 'sg-1000', 'snes', 'snesh', 'snesmsu1', 'supergrafx',
'supervision', 'tg16', 'tg16cd', 'vectrex', 'virtualboy', 'wonderswan',
'wonderswancolor',
}
if platform in retro_achievements:
if config.get_setting("retroachievements"):
ra_append_dict['cheevos_enable'] = "true"
ra_append_dict['cheevos_username'] = config.get_setting("retroachievements.username")
ra_append_dict['cheevos_password'] = config.get_setting("retroachievements.password")
ra_append_dict['cheevos_hardcore_mode_enable'] = config.get_bool_string("retroachievements.hardcore")
value = config.get_setting("retroachievements.leaderboards")
if value == "enabled":
ra_append_dict['cheevos_leaderboards_enable'] = "true"
elif value == "trackers only":
ra_append_dict['cheevos_leaderboards_enable'] = "trackers"
elif value == "notifications only":
ra_append_dict['cheevos_leaderboards_enable'] = "notifications"
else:
ra_append_dict['cheevos_leaderboards_enable'] = "false"
ra_append_dict['cheevos_verbose_enable'] = config.get_bool_string("retroachievements.verbose")
ra_append_dict['cheevos_auto_screenshot'] = config.get_bool_string("retroachievements.screenshot")
ra_append_dict['cheevos_richpresence_enable'] = config.get_bool_string("retroachievements.richpresence")
ra_append_dict['cheevos_challenge_indicators'] = config.get_bool_string("retroachievements.challengeindicators")
ra_append_dict['cheevos_test_unofficial'] = config.get_bool_string("retroachievements.testunofficial")
ra_append_dict['cheevos_badges_enable'] = config.get_bool_string("retroachievements.badges")
ra_append_dict['cheevos_start_active'] = config.get_bool_string("retroachievements.active")
ra_append_dict['cheevos_unlock_sound_enable'] = config.get_bool_string("retroachievements.soundenable")
else:
ra_append_dict['cheevos_enable'] = "false"
ra_append_dict['cheevos_username'] = ""
ra_append_dict['cheevos_password'] = ""
ra_append_dict['cheevos_hardcore_mode_enable'] = "false"
ra_append_dict['cheevos_leaderboards_enable'] = "false"
ra_append_dict['cheevos_verbose_enable'] = "false"
ra_append_dict['cheevos_test_unofficial'] = "false"
ra_append_dict['cheevos_unlock_sound_enable'] = "false"
ra_append_dict['cheevos_auto_screenshot'] = "false"
ra_append_dict['cheevos_badges_enable'] = "false"
ra_append_dict['cheevos_start_active'] = "false"
ra_append_dict['cheevos_richpresence_enable'] = "false"
ra_append_dict['cheevos_challenge_indicators'] = "false"
# Netplay
if config.get_setting("netplay"):
ra_append_dict['netplay'] = "true"
# Not needed any more?
## Disable Cheevos Hardcore Mode to allow savestates
#if 'cheevos_hardcore_mode_enable' in ra_append_dict:
# ra_append_dict['cheevos_hardcore_mode_enable'] = "false"
# Host or Client
value = config.get_setting('netplay.mode')
if value == 'host':
ra_append_dict['netplay_mode'] = "false"
ra_append_dict['netplay_client_swap_input'] = "false"
ra_append_dict['netplay_ip_port'] = config.get_setting('netplay.port')
elif value == 'client':
ra_append_dict['netplay_mode'] = "true"
ra_append_dict['netplay_ip_address'] = config.get_setting('netplay.client.ip')
ra_append_dict['netplay_ip_port'] = config.get_setting('netplay.client.port')
ra_append_dict['netplay_client_swap_input'] = "true"
# Relay
if value := config.get_setting('netplay.relay'):
ra_append_dict['netplay_use_mitm_server'] = "true"
ra_append_dict['netplay_mitm_server'] = value
else:
ra_append_dict['netplay_use_mitm_server'] = "false"
ra_append_dict['netplay_delay_frames'] = config.get_setting('netplay.frames')
ra_append_dict['netplay_nickname'] = config.get_setting('netplay.nickname')
# spectator mode
ra_append_dict['netplay_spectator_mode_enable'] = config.get_bool_string("netplay.spectator")
ra_append_dict['netplay_public_announce'] = config.get_bool_string("netplay_public_announce")
else:
ra_append_dict['netplay'] = "false"
# AI Translation Service
if config.get_setting('ai_service_enabled'):
ra_append_dict['ai_service_enable'] = "true"
LangCodes = {
"false": "0", "En": "1", "Fr": "3", "Pt": "49", "De": "5",
"El": "30", "Es": "2", "Cs": "8", "Da": "9", "Hr": "11", "Hu": "35",
"It": "4", "Ja": "6", "Ko": "12", "Nl": "7", "Nn": "46", "Po": "48",
"Ro": "50", "Ru": "51", "Sv": "10", "Tr": "59", "Zh": "13",
}
ai_lang = config.get_setting('ai_target_lang')
if ai_lang in LangCodes:
ra_append_dict['ai_service_target_lang'] = f'{LangCodes[ai_lang]}'
else:
# use English as default
ra_append_dict['ai_service_target_lang'] = "1"
if ai_url := config.get_setting('ai_service_url'):
ra_append_dict['ai_service_url'] = f'{ai_url}&mode=Fast&output=png&target_lang={ai_lang}'
else:
ra_append_dict['ai_service_url'] = f'http://ztranslate.net/service?api_key=BATOCERA&mode=Fast&output=png&target_lang={ai_lang}'
else:
ra_append_dict['ai_service_enable'] = "false"
#
# Global/System/Game specific settings
#
# Ratio
# default to 22 (core provided) if case anything goes wrong
ra_append_dict['aspect_ratio_index'] = "22"
if ratio := config.get_setting('ratio'):
index_rations = {
'4/3': '0', '16/9': '1', '16/10': '2', '16/15': '3', '21/9': '4',
'1/1': '5', '2/1': '6', '3/2': '7', '3/4': '8', '4/1': '9',
'9/16': '10', '5/4': '11', '6/5': '12', '7/9': '13', '8/3': '14',
'8/7': '15', '19/12': '16', '19/14': '17', '30/17': '18',
'32/9': '19', 'config': '20', 'squarepixel': '21', 'core': '22',
'custom': '23', 'full' : '24',
}
if ratio in index_rations:
ra_append_dict['aspect_ratio_index'] = index_rations[ratio]
# Bilinear filtering
ra_append_dict['video_smooth'] = config.get_bool_string("smooth")
# Video Integer Scale
ra_append_dict['video_scale_integer'] = config.get_bool_string("integerscale")
# Video Integer Scale Overscale
ra_append_dict['video_scale_integer_overscale'] = config.get_bool_string("integerscaleoverscale")
# RGA Scaling / CTX Scaling
ra_append_dict['video_ctx_scaling'] = config.get_bool_string("rgascale")
# Shaderset
if shaderset := config.get_setting('shaderset'):
ra_append_dict['video_shader_enable'] = "true"
ra_append_dict['video_shader'] = shaderset
# We need to print the shader folder for runemu.sh to use it
shader_path = f'--set-shader /tmp/shaders/{shaderset}'
else:
ra_append_dict['video_shader_enable'] = "false"
ra_append_dict['video_shader'] = ""
# Filters
# Set correct path for video- and audio-filters depending on 32/64bit
ra_append_dict['audio_filter_dir'] = f'/usr/share/retroarch/filters/{bits}/audio'
ra_append_dict['video_filter_dir'] = f'/usr/share/retroarch/filters/{bits}/video'
# Filterset
if filterset := config.get_setting('filterset'):
# Filter do not work with RGA/CTX enabled
ra_append_dict['video_ctx_scaling'] = "false"
ra_append_dict['video_filter'] = f'/usr/share/retroarch/filters/{bits}/video/{filterset}'
else:
ra_append_dict['video_filter'] = ""
# Rewind
no_rewind = {'sega32x', 'psx', 'zxspectrum', 'odyssey2', 'mame', 'n64', 'dreamcast', 'atomiswave', 'naomi', 'neogeocd', 'saturn', 'psp', 'pspminis'}
if config.get_setting('rewind') and platform not in no_rewind:
ra_append_dict['rewind_enable'] = "true"
else:
ra_append_dict['rewind_enable'] = "false"
# Saves
# Incrementalsavestates
if config.get_setting('incrementalsavestates'):
ra_append_dict['savestate_auto_index'] = "true"
ra_append_dict['savestate_max_keep'] = "0"
else:
ra_append_dict['savestate_auto_index'] = "false"
ra_append_dict['savestate_max_keep'] = "50"
# Autosave
if config.get_setting('autosave'):
ra_append_dict['savestate_auto_save'] = "true"
ra_append_dict['savestate_auto_load'] = "true"
else:
ra_append_dict['savestate_auto_save'] = "false"
ra_append_dict['savestate_auto_load'] = "false"
# Snapshots
ra_append_dict['savestate_directory'] = f'{snapshots}/{platform}'
if snapshot:
if autosave == "1":
ra_append_dict['savestate_auto_load'] = "true"
ra_append_dict['savestate_auto_save'] = "true"
else:
ra_append_dict['savestate_auto_load'] = "false"
ra_append_dict['savestate_auto_save'] = "false"
ra_append_dict['state_slot'] = f'{snapshot}'
# Runahead
# Runahead 1st Instance
no_run_ahead = {'psp', 'sega32x', 'n64', 'dreamcast', 'atomiswave', 'naomi', 'neogeocd', 'saturn'}
if (runahead := config.get_setting('runahead')) and platform not in no_run_ahead:
ra_append_dict['run_ahead_enabled'] = "true"
ra_append_dict['run_ahead_frames'] = runahead
else:
ra_append_dict['run_ahead_enabled'] = "false"
ra_append_dict['run_ahead_frames'] = "1"
# Runahead 2nd Instance
if config.get_setting('secondinstance') and platform not in no_run_ahead:
ra_append_dict['run_ahead_secondary_instance'] = "true"
else:
ra_append_dict['run_ahead_secondary_instance'] = "false"
# Auto Frame Relay
ra_append_dict['video_frame_delay_auto'] = config.get_bool_string("video_frame_delay_auto")
# maxperf / CPU Governor
if config.get_setting('maxperf'):
ra_append_dict['cpu_scaling_mode'] = '2'
else:
ra_append_dict['cpu_scaling_mode'] = '4'
#
# Settings for special cores
#
## atari800 core needs other settings when emulation atari5200
if core == 'atari800':
logger.log('Atari 800 section')
retrocore_dict = {}
atari800_dict = {}
atari_dict = {}
atari_conf = INSTALL_DIR + '/storage/.config/distribution/configs/atari800.cfg'
atari800_conf = INSTALL_DIR + '/storage/.config/retroarch/config/Atari800/Atari800.opt'
delete_lines(ra_core_conf, ('atari800_system =',))
delete_lines(atari_conf, ('RAM_SIZE', 'STEREO_POKEY', 'BUILTIN_BASIC'))
if os.path.isfile(atari800_conf):
delete_lines(atari800_conf, ('atari800_system',))
if platform == 'atari5200':
retrocore_dict['atari800_system'] = '5200'
atari800_dict['atari800_system'] = '5200'
atari_dict['RAM_SIZE'] = '16'
atari_dict['STEREO_POKEY'] = '0'
atari_dict['BUILTIN_BASIC'] = '0'
else:
retrocore_dict['atari800_system'] = '800XL (64K)'
atari800_dict['atari800_system'] = '800XL (64K)'
atari_dict['RAM_SIZE'] = '64'
atari_dict['STEREO_POKEY'] = '1'
atari_dict['BUILTIN_BASIC'] = '1'
write_file(ra_core_conf, retrocore_dict)
# The format of the atari800.cfg is different
# ('key=value' instead of 'key = "value"')
write_file(atari_conf, atari_dict, separator='=', quote_sign='')
write_file(atari800_conf, atari800_dict)
# Gambatte
if core == 'gambatte':
logger.log('Gambatte section')
gambatte_dict = {}
gambatte_conf = INSTALL_DIR + "/storage/.config/retroarch/config/Gambatte/Gambatte.opt"
if os.path.isfile(gambatte_conf):
delete_lines(gambatte_conf, ('gambatte_gb_colorization', 'gambatte_gb_internal_palette'))
else:
gambatte_dict['gambatte_gbc_color_correction'] = 'disabled'
colorization = config.get_setting('renderer.colorization')
logger.log(f'gambatte colorization: {colorization}')
if not colorization or colorization == 'auto':
gambatte_dict['gambatte_gb_colorization'] = 'disabled'
elif colorization == 'Best Guess':
gambatte_dict['gambatte_gb_colorization'] = 'auto'
elif colorization == 'GBC' or colorization == 'SGB':
gambatte_dict['gambatte_gb_colorization'] = colorization
else:
gambatte_dict['gambatte_gb_colorization'] = 'internal'
gambatte_dict['gambatte_gb_internal_palette'] = colorization
write_file(gambatte_conf, gambatte_dict)
#
# Controllers
#
# We set up the controller index
if controllers:
for player in range(1,6):
logger.log(f'Controller section {player}')
if pindex := re.search(fr'p{player}index\s+([0-9]+)', controllers):
ra_append_dict['input_player{player}_joypad_index'] = pindex.group(1)
# Setting controller type for different cores
if platform == "atari5200":
ra_append_dict['input_libretro_device_p{player}'] = '513'
#
# Bezels / Decorations
#
# List of possible Bezel Folders
bezel_dir = ('/tmp/overlays/bezels', INSTALL_DIR + '/storage/roms/bezels')
# Define the resolutions of the different systems (0:x 1:y 2:width 3:height) as seen in Scaling -> Aspect Ration -> Custom
# Devices (width x hight)
# RG351P/M = 480x320
# RG351V/MP = 640x480
# RG552 = 1920x1152
# DECK = 1280x800
# Consoles (width x hight)
# GB/GBC/GG = 160x144
# supervision = 160x160
# Pokemini = 96x64
# ngp/ngpc = 160x152
# wonderswan/wonderswancolor = 224×144
if device_name == "RG351P":
system_viewport = {
'standard': (1, 1, 479, 319), # max-1
'gb': (80, 16, 320, 288), # x2
'gbh': (80, 16, 320, 288), # x2
'gbc': (80, 16, 320, 288), # x2
'gbch': (80, 16, 320, 288), # x2
'supervision': (80, 0, 320, 320), # x2
'gamegear': (80, 16, 320, 288), # x2
'ggh': (80, 16, 320, 288), # x2
'pokemini': (96, 64, 288, 192), # x3
'ngp': (80, 8, 320, 304), # x2
'ngpc': (80, 8, 320, 304), # x2
'wonderswan': (16, 16, 448, 288), # x2
'wonderswancolor': (16, 16, 448, 288), # x2
}
elif device_name == "RG351V" or device_name == "RG351MP":
system_viewport = {
'standard': (1, 1, 639, 479), # max-1
'gb': (80, 24, 480, 432), # x3
'gbh': (80, 24, 480, 432), # x3
'gbc': (80, 24, 480, 432), # x3
'gbch': (80, 24, 480, 432), # x3
'supervision': (80, 0, 480, 480), # x3
'gamegear': (80, 24, 480, 432), # x3
'ggh': (80, 24, 480, 432), # x3
'pokemini': (128, 112, 384, 256), # x4
'ngp': (80, 12, 480, 456), # x3
'ngpc': (80, 12, 480, 456), # x3
'wonderswan': (96, 96, 448, 288), # x2
'wonderswancolor': (96, 96, 448, 288), # x2
}
elif device_name == "RG552":
system_viewport = {
'standard': (1, 1, 1919, 1151), # max-1
'gb': (320, 0, 1280, 1152), # x8
'gbh': (320, 0, 1280, 1152), # x8
'gbc': (320, 0, 1280, 1152), # x8
'gbch': (320, 0, 1280, 1152), # x8
'supervision': (400, 16, 1120, 1120), # x7
'gamegear': (320, 0, 1280, 1152), # x8
'ggh': (320, 0, 1280, 1152), # x8
'pokemini': (384, 192, 1152, 768), # x12
'ngp': (400, 44, 1120, 1064), # x7
'ngpc': (400, 44, 1120, 1064), # x7
'wonderswan': (64, 0, 1792, 1152), # x8
'wonderswancolor': (64, 0, 1792, 1152), # x8
}
elif device_name == "DECK":
#just copied from 552, I have to edit this
system_viewport = {
'standard': (1, 1, 1279, 799), # max-1
'gb': (320, 0, 1280, 1152), # x8
'gbh': (320, 0, 1280, 1152), # x8
'gbc': (320, 0, 1280, 1152), # x8
'gbch': (320, 0, 1280, 1152), # x8
'supervision': (400, 16, 1120, 1120), # x7
'gamegear': (320, 0, 1280, 1152), # x8
'ggh': (320, 0, 1280, 1152), # x8
'pokemini': (384, 192, 1152, 768), # x12
'ngp': (400, 44, 1120, 1064), # x7
'ngpc': (400, 44, 1120, 1064), # x7
'wonderswan': (64, 0, 1792, 1152), # x8
'wonderswancolor': (64, 0, 1792, 1152), # x8
}
bezel_cfg = None
if (bezel := config.get_setting('bezel')) and platform in system_viewport:
logger.log(f'bezel: {bezel} platform: {platform} rom: {rom_name}')
tmp_bezel = "/tmp/351elec-bezel.cfg"
game_cfg = ''
# set path
path = ''
for searchpath in bezel_dir:
if os.path.isdir(f'{searchpath}/{bezel}'):
path = f'{searchpath}/{bezel}'
bezel_system = config.get_setting('bezel.system.override')
if not bezel_system or bezel_system == "AUTO":
bezel_system = platform
bezel_system_png = f'{path}/systems/{bezel_system}.png'
logger.log(f'Bezel system png: {bezel_system_png}')
game_bezel_override = config.get_setting('bezel.game.override')
logger.log(f'Game bezel override: {game_bezel_override}')
if not game_bezel_override or game_bezel_override == "AUTO":
logger.log('No game specific override found. Looking for games')
# is there a $ROMNAME.cfg?
# exactly the same / just the name / default
# Random bezels have to match $ROMNAME./d+.cfg
romdir = f'{path}/systems/{bezel_system}/games'
full_name = os.path.splitext(rom_name)[0]
short_name = full_name.split(' (')[0]
if os.path.isdir(romdir):
with os.scandir(romdir) as it:
full_list = [entry.name for entry in it if entry.is_file() and entry.name.endswith('.cfg')]
for romname in (full_name, short_name , 'default'):
logger.log(f'Looking at: {romdir}/{romname}')
file_list = [file for file in full_list if re.fullmatch(fr'{re.escape(romname)}\.[0-9]+\.cfg', file)]
if len(file_list) > 0:
game_cfg = f'{romdir}/{random.choice(file_list)}'
logger.log(f'Using random config: {game_cfg}')
break
elif os.path.isfile(f'{romdir}/{romname}.cfg'):
game_cfg = f'{romdir}/{romname}.cfg'
logger.log(f'Using ROM config: {game_cfg}')
break
else:
game_cfg = f'{path}/systems/{bezel_system}/games/{game_bezel_override}.cfg'
if os.path.isfile(game_cfg):
logger.log(f'game config file exists: {game_cfg}')
with open(game_cfg) as f:
contents = f.read().strip()
bezel_system_png = f'{path}/systems/{bezel_system}/games/{contents}'
logger.log(f'bezel png: {bezel_system_png}')
if os.path.isfile(bezel_system_png):
tmp_bezel_dict = {}
tmp_bezel_dict['overlays'] = '1'
tmp_bezel_dict['overlay0_full_screen'] = 'true'
tmp_bezel_dict['overlay0_normalized'] = 'true'
tmp_bezel_dict['overlay0_overlay'] = bezel_system_png
overlays_dir = f'{path}/systems/{bezel_system}/overlays/'
count = 0
if os.path.isdir(overlays_dir):
for overlay_png in iglob(f'{overlays_dir}/*.png'):
overlay_name = os.path.splitext(os.path.basename(overlay_png))[0]
overlay_setting = config.get_setting(f'bezel.overlay.{overlay_name}')
if not overlay_setting:
continue
logger.log(f'Adding overlay. name: {overlay_name} overlay setting: {overlay_setting}')
tmp_bezel_dict[f'overlay0_desc{count}_overlay'] = overlay_png
tmp_bezel_dict[f'overlay0_desc{count}'] = 'nul,0.5,0.5,rect,0.5,0.5'
count += 1
tmp_bezel_dict['overlay0_descs'] = count
if os.path.isfile(tmp_bezel):
os.remove(tmp_bezel)
write_file(tmp_bezel, tmp_bezel_dict)
bezel_cfg = tmp_bezel
if bezel_cfg is not None:
logger.log('using bezel')
# configure bezel
ra_append_dict['input_overlay_enable'] = 'true'
ra_append_dict['input_overlay'] = bezel_cfg
ra_append_dict['input_overlay_hide_in_menu'] = 'true'
ra_append_dict['input_overlay_opacity'] = '1.000000'
ra_append_dict['input_overlay_show_inputs'] = '2'
ra_append_dict['video_scale_integer'] = 'false'
ra_append_dict['aspect_ratio_index'] = '23'
# configure custom scaling
# needs some grouping to reflect the hack systems as well (i. e. gb=gb, gbh, gbc and gbch)
ra_append_dict['custom_viewport_x'] = system_viewport[platform][0]
ra_append_dict['custom_viewport_y'] = system_viewport[platform][1]
ra_append_dict['custom_viewport_width'] = system_viewport[platform][2]
ra_append_dict['custom_viewport_height'] = system_viewport[platform][3]
else:
logger.log('not using bezel')
# disable decorations
ra_append_dict['input_overlay_enable'] = 'false'
# set standard resolution for custom scaling
ra_append_dict['custom_viewport_x'] = system_viewport['standard'][0]
ra_append_dict['custom_viewport_y'] = system_viewport['standard'][1]
ra_append_dict['custom_viewport_width'] = system_viewport['standard'][2]
ra_append_dict['custom_viewport_height'] = system_viewport['standard'][3]
# DECK specific options TODO: integrate better in the code
# TODO: not working
#ra_append_dict['video_windowed_fullscreen'] = "true"
# Write the raappend.cfg
logger.log('Write raappend.cfg')
write_file(ra_append_conf, ra_append_dict)
logger.log('done ...')
return shader_path
# Main (if we are run as a script and not as a module)
if __name__ == '__main__':
# Arguments
parser = ArgumentParser(description="Convert ES settings from distribution.conf to RetroArch configuration in raappend.conf.")
parser.add_argument("--core", help="core", required=True)
parser.add_argument("--platform", help="platform", required=True)
parser.add_argument("--rom", help="ROM file name", required=True)
parser.add_argument("--controllers", help="controller config", default="-p1index 0")
parser.add_argument("--autosave", help="autosave", default="0")
parser.add_argument("--snapshot", help="snapshot", default="")
args = parser.parse_args()
shader_path = set_settings(rom_name=args.rom, core=args.core, platform=args.platform, controllers=args.controllers, autosave=args.autosave, snapshot=args.snapshot)
if shader_path:
print(shader_path)