mirror of
https://github.com/RetroDECK/RetroDECK.git
synced 2024-11-27 08:05:42 +00:00
701 lines
30 KiB
Python
Executable file
701 lines
30 KiB
Python
Executable file
#!/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)
|