First upload

This commit is contained in:
XargonWan 2022-03-14 12:01:23 +01:00
commit 67f387b5a4
15 changed files with 8216 additions and 0 deletions

30
es_input.cfg Normal file
View file

@ -0,0 +1,30 @@
<?xml version="1.0"?>
<inputList>
<inputConfig type="keyboard" deviceName="Keyboard" deviceGUID="-1">
<input name="a" type="key" id="122" value="1" />
<input name="b" type="key" id="120" value="1" />
<input name="down" type="key" id="1073741905" value="1" />
<input name="hotkeyenable" type="key" id="32" value="1" />
<input name="left" type="key" id="1073741904" value="1" />
<input name="leftanalogdown" type="key" id="107" value="1" />
<input name="leftanalogleft" type="key" id="106" value="1" />
<input name="leftanalogright" type="key" id="108" value="1" />
<input name="leftanalogup" type="key" id="105" value="1" />
<input name="leftshoulder" type="key" id="119" value="1" />
<input name="leftthumb" type="key" id="99" value="1" />
<input name="lefttrigger" type="key" id="113" value="1" />
<input name="right" type="key" id="1073741903" value="1" />
<input name="rightanalogdown" type="key" id="1073741914" value="1" />
<input name="rightanalogleft" type="key" id="1073741916" value="1" />
<input name="rightanalogright" type="key" id="1073741918" value="1" />
<input name="rightanalogup" type="key" id="1073741920" value="1" />
<input name="rightshoulder" type="key" id="101" value="1" />
<input name="rightthumb" type="key" id="118" value="1" />
<input name="righttrigger" type="key" id="114" value="1" />
<input name="select" type="key" id="8" value="1" />
<input name="start" type="key" id="13" value="1" />
<input name="up" type="key" id="1073741906" value="1" />
<input name="x" type="key" id="97" value="1" />
<input name="y" type="key" id="115" value="1" />
</inputConfig>
</inputList>

78
es_settings.cfg Normal file
View file

@ -0,0 +1,78 @@
<?xml version="1.0"?>
<config>
<bool name="EnableSounds" value="false" />
<bool name="ScrapeFanart" value="false" />
<bool name="ScrapeManual" value="false" />
<bool name="ScrapeMap" value="false" />
<int name="ScreenSaverTime" value="180000" />
<int name="recent.sort" value="7" />
<string name="3do.HiddenExt" value="iso;bin" />
<string name="AudioCard" value="default" />
<string name="AudioDevice" value="Playback" />
<string name="CollectionSystemsAuto" value="favorites, recent" />
<string name="CollectionSystemsCustom" value="" />
<string name="DefaultGridSize" value="" />
<string name="FolderViewMode" value="always" />
<string name="GameTransitionStyle" value="auto" />
<string name="GamelistViewStyle" value="automatic" />
<string name="HiddenSystems" value="" />
<string name="INPUT P1" value="DEFAULT" />
<string name="INPUT P1NAME" value="DEFAULT" />
<string name="INPUT P2" value="DEFAULT" />
<string name="INPUT P2NAME" value="DEFAULT" />
<string name="INPUT P3" value="DEFAULT" />
<string name="INPUT P3NAME" value="DEFAULT" />
<string name="INPUT P4" value="DEFAULT" />
<string name="INPUT P4NAME" value="DEFAULT" />
<string name="INPUT P5" value="DEFAULT" />
<string name="INPUT P5NAME" value="DEFAULT" />
<string name="INPUT P6NAME" value="DEFAULT" />
<string name="INPUT P7NAME" value="DEFAULT" />
<string name="INPUT P8NAME" value="DEFAULT" />
<string name="Language" value="en_US" />
<string name="LastSystem" value="megadrive" />
<string name="OMXAudioDev" value="both" />
<string name="Overclock" value="none" />
<string name="PowerSaverMode" value="default" />
<string name="Scraper" value="ArcadeDB" />
<string name="ScrapperImageSrc" value="ss" />
<string name="ScrapperLogoSrc" value="" />
<string name="ScrapperThumbSrc" value="" />
<string name="ScreenSaverBehavior" value="black" />
<string name="ScreenSaverDecorations" value="none" />
<string name="ScreenSaverGameInfo" value="never" />
<string name="ShowBattery" value="text" />
<string name="SlideshowScreenSaverImageDir" value="/storage/screenshots" />
<string name="SlideshowScreenSaverImageFilter" value=".png,.jpg" />
<string name="SlideshowScreenSaverVideoDir" value="/storage/roms/mplayer" />
<string name="SlideshowScreenSaverVideoFilter" value=".mp4,.avi,.mkv,.flv,.mpg,.mov" />
<string name="SortSystems" value="alpha" />
<string name="StartupSystem" value="lastsystem" />
<string name="ThemeColorSet" value="red" />
<string name="ThemeGamelistView" value="" />
<string name="ThemeIconSet" value="" />
<string name="ThemeMenu" value="" />
<string name="ThemeRegionName" value="" />
<string name="ThemeSet" value="es-theme-art-book-next" />
<string name="ThemeSystemView" value="" />
<string name="TransitionStyle" value="auto" />
<string name="UIMode" value="Full" />
<string name="UIMode_passkey" value="aaaba" />
<string name="amigacd32.HiddenExt" value="iso" />
<string name="megacd.HiddenExt" value="iso" />
<string name="neogeocd.HiddenExt" value="iso" />
<string name="pcenginecd.HiddenExt" value="iso;img;bin" />
<string name="pcfx.HiddenExt" value="toc" />
<string name="psx.HiddenExt" value="bin;img;iso" />
<string name="saturn.HiddenExt" value="iso" />
<string name="segacd.HiddenExt" value="iso" />
<string name="subset.88-mph" value="on" />
<string name="subset.airen-thumbs" value="thumb-image" />
<string name="subset.background-art" value="on" />
<string name="subset.blindornot" value="blind-on" />
<string name="subset.clickset" value="click1" />
<string name="subset.colorset" value="red" />
<string name="subset.metadata" value="custommeta" />
<string name="subset.themestyle" value="light" />
<string name="tg16cd.HiddenExt" value="iso;img;bin" />
</config>

2168
es_systems.cfg Normal file

File diff suppressed because it is too large Load diff

195
export_func.sh Executable file
View file

@ -0,0 +1,195 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2019-present Shanti Gilbert (https://github.com/shantigilbert)
# Copyright (C) 2020-present Fewtarius
# This content was taken from 99-distribution.conf and made as a shell script for steam deck
# TODO: remove absolute paths and put the variables INSTALL_DIR
export PATH="$PATH:/usr/local/bin:/usr/bin:/storage/bin"
export SDL_GAMECONTROLLERCONFIG_FILE="~/retrodeck/storage/.config/SDL-GameControllerDB/gamecontrollerdb.txt"
EE_DIR="~/retrodeck/storage/.config/distribution"
EE_CONF="${EE_DIR}/configs/distribution.conf"
ES_CONF="~/retrodeck/storage/.emulationstation/es_settings.cfg"
EE_DEVICE=$(cat ~/retrodeck/storage/.config/.OS_ARCH)
JSLISTENCONF="~/retrodeck/storage/.config/distribution/configs/jslisten.cfg"
get_ee_setting() {
# Argument $1 is the setting name, EmuELEC settings alway start with ee_ e.g. ee_novideo
# Usage: get_ee_setting setting [platform] [rom]
# Only the setting argument is required
# Priority is: GAME, PLATFORM, GLOBAL, EE_SETTING if at any point one returns 0 it means its dissabled, if it returns empty it will continue onto the next one.
SETTING="${1}"
PLATFORM="${2}"
ROM="${3}"
#ROM
ROM=$(echo [\"${ROM}\"] | sed -e 's|\[|\\\[|g' | sed -e 's|\]|\\\]|g' | sed -e 's|(|\\\(|g' | sed -e 's|)|\\\)|g')
PAT="^${PLATFORM}${ROM}[.-]${SETTING}=(.*)"
EES=$(cat "${EE_CONF}" | grep -oE "${PAT}")
EES="${EES##*=}"
if [ -z "${EES}" ]; then
#PLATFORM
PAT="^${PLATFORM}[.-]${SETTING}=(.*)"
EES=$(cat "${EE_CONF}" | grep -oE "${PAT}")
EES="${EES##*=}"
fi
if [ -z "${EES}" ]; then
#GLOBAL
PAT="^global[.-]${SETTING}=(.*)"
EES=$(cat "${EE_CONF}" | grep -oE "${PAT}")
EES="${EES##*=}"
fi
if [ -z "${EES}" ]; then
#EE_SETTINGS
PAT="^${SETTING}=(.*)"
EES=$(cat "${EE_CONF}" | grep -oE "${PAT}")
EES="${EES##*=}"
fi
echo "${EES}"
}
set_ee_setting() {
# argument $1 is the setting name e.g. nes.integerscale. $2 is the value, e.g "1"
sed -i "/$1=/d" "${EE_CONF}"
[ $2 == "disable" ] && echo "#${1}=" >> "${EE_CONF}" || echo "${1}=${2}" >> "${EE_CONF}"
}
get_es_setting() {
echo $(sed -n "s|\s*<${1} name=\"${2}\" value=\"\(.*\)\" />|\1|p" ${ES_CONF})
}
normperf() {
# A foo function as in steam deck is not needed, however sometime it's called and I am lazy to edit everything, sorry -Xargon
return
}
maxperf() {
# A foo function as in steam deck is not needed, however sometime it's called and I am lazy to edit everything, sorry -Xargon
return
}
ee_check_bios() {
PLATFORM="${1}"
CORE="${2}"
EMULATOR="${3}"
ROMNAME="${4}"
LOG="${5}"
if [[ -z "$LOG" ]]; then
LOG="/tmp/logs/exec.log"
cat /etc/motd > "$LOG"
fi
MISSINGBIOS="$(batocera-systems --strictfilter ${PLATFORM})"
if [ "$?" == "2" ]; then
# formating so it looks nice :)
PLATFORMNAME="${MISSINGBIOS##*>}" # read from -P onwards
PLATFORMNAME="${PLATFORMNAME%%MISSING*}" # until a space is found
PLATFORMNAME=$(echo $PLATFORMNAME | sed -e 's/\\n//g')
if [[ -f "${LOG}" ]]; then
echo "${CORE} ${EMULATOR} ${ROMNAME}" >> $LOG
echo "${PLATFORMNAME} missing BIOS - Could not find all BIOS: " >> $LOG
echo "please make sure you copied the files into the corresponding folder " >> $LOG
echo "${MISSINGBIOS}" >> $LOG
fi
MISSINGBIOS=$(echo "$MISSINGBIOS" | sed -e 's/$/\\n/g')
/usr/bin/error.sh "${PLATFORMNAME} missing BIOS" "Could not find all BIOS/files in /storage/roms, the game may not work:\n\n ${MISSINGBIOS}\n\nPlease make sure you copied the files into the corresponding folder."
error_process="$!"
pkill -P $error_process
fi
}
message_stream () {
local MESSAGE=$1
local DELAY=$2
local LOADBUFFER=0
local ANSI=0
for (( i=0; i<${#MESSAGE}; i++ ))
do
CHAR="${MESSAGE:$i:1}"
# Is this an escape character?
if [ "${CHAR}" == "\\" ]
then
LOADBUFFER=1
BUFFER="$BUFFER${CHAR}"
continue
fi
# Is this ANSI? (\e[*[a-Z])
if [ "${BUFFER}" == "\e[" ] && [ "${LOADBUFFER}" -eq 1 ]
then
ANSI=1
BUFFER="$BUFFER${CHAR}"
continue
fi
if [ "${LOADBUFFER}" -eq 1 ] && [ "${ANSI}" -eq 1 ]
then
# If it isn't ANSI it's a control char like \n
if [[ "${CHAR}" =~ [a-Z] ]]
then
echo -ne "${BUFFER}${CHAR}" >/dev/console
unset BUFFER
LOADBUFFER=0
ANSI=0
fi
else
# otherwise it's text
echo -ne "${BUFFER}${CHAR}" >/dev/console
unset BUFFER
LOADBUFFER=0
ANSI=0
fi
sleep ${DELAY}
done
}
spinny_cursor() {
message_stream "$1" 0
for (( c=0; c<=$2; c++ ))
do
echo -ne '\e[2D' '-' > /dev/console
sleep .01
echo -ne '\e[2D' '\\' > /dev/console
sleep .01
echo -ne '\e[2D' '|' > /dev/console
sleep .01
echo -ne '\e[2D' '/' > /dev/console
sleep .01
done
echo -ne '\e[80D\e[K' > /dev/console
}
jslisten() {
# A foo function as in steam deck is not needed, however sometime it's called and I am lazy to edit everything, sorry -Xargon
return
}
# 351EDECK specific code
export -f get_ee_setting
export -f set_ee_setting
export -f get_es_setting
export -f maxperf
export -f normperf
export -f ee_check_bios
export -f message_stream
export -f spinny_cursor
#export -f jslisten
#export -f init_port

248
install-retrodeck.sh Executable file
View file

@ -0,0 +1,248 @@
#!/bin/bash
INSTALL_DIR=~/retrodeck
CORES_LINK=https://buildbot.libretro.com/stable/1.10.1/linux/x86_64/RetroArch_cores.7z
PREVIOUS_DIR=$PWD
echo "Welcome to the RetroDECK installer."
echo "RetroDECK will be installed in $INSTALL_DIR."
# TODO-MAYBE: give the option to change the installation directory?
echo "WARNING: RetroDECK will replace your retroarch.cfg, the former one will be renamed moved in ~/.config/retroarch/retroarch.cfg.bak."
echo "Whenever a choice is prompted just accept it to continue (yes/enter), root password will be asked."
# but maybe it will not affect the original retroarch, let's see
# maybe --root option of pacman may be useful to install my own copy of retroarch without messing the one already installed
read -n 1 -r -s -p $'Press enter to continue...\n'
echo "Installing RetroDECK in $INSTALL_DIR, please stand by."
cd $INSTALL_DIR
# TODO: download everything from retrodeck github
# git clone --recursive https://github.com/XargonWan/RetroDECK retrodeck
# Initalizing rom folders
if [ test ! -d "$INSTALL_DIR/storage/roms/" ]; then
mkdir -p $INSTALL_DIR/storage/roms/
fi
if [ test ! -d "$INSTALL_DIR/roms" ]; then
ln -s $INSTALL_DIR/storage/roms $INSTALL_DIR/roms
fi
mkdir -p $INSTALL_DIR/roms/3do
mkdir -p $INSTALL_DIR/roms/amiga
mkdir -p $INSTALL_DIR/roms/amigacd32
mkdir -p $INSTALL_DIR/roms/amstradcpc
mkdir -p $INSTALL_DIR/roms/arcade
mkdir -p $INSTALL_DIR/roms/atari2600
mkdir -p $INSTALL_DIR/roms/atari5200
mkdir -p $INSTALL_DIR/roms/atari7800
mkdir -p $INSTALL_DIR/roms/atarist
mkdir -p $INSTALL_DIR/roms/atari800
mkdir -p $INSTALL_DIR/roms/atomiswave
mkdir -p $INSTALL_DIR/roms/channelf
mkdir -p $INSTALL_DIR/roms/colecovision
mkdir -p $INSTALL_DIR/roms/c64
mkdir -p $INSTALL_DIR/roms/c128
mkdir -p $INSTALL_DIR/roms/vic20
mkdir -p $INSTALL_DIR/roms/laserdisc
mkdir -p $INSTALL_DIR/roms/dreamcast
mkdir -p $INSTALL_DIR/roms/easyrpg
mkdir -p $INSTALL_DIR/roms/famicom
mkdir -p $INSTALL_DIR/roms/fbn
mkdir -p $INSTALL_DIR/roms/gb
mkdir -p $INSTALL_DIR/roms/gbh
mkdir -p $INSTALL_DIR/roms/gameandwatch
mkdir -p $INSTALL_DIR/roms/gba
mkdir -p $INSTALL_DIR/roms/fds
mkdir -p $INSTALL_DIR/roms/c16
mkdir -p $INSTALL_DIR/roms/ggh
mkdir -p $INSTALL_DIR/roms/gbah
mkdir -p $INSTALL_DIR/roms/intellivision
mkdir -p $INSTALL_DIR/roms/gbch
mkdir -p $INSTALL_DIR/roms/atarilynx
mkdir -p $INSTALL_DIR/roms/mame
mkdir -p $INSTALL_DIR/roms/dos
mkdir -p $INSTALL_DIR/roms/snesmsu1
mkdir -p $INSTALL_DIR/roms/msx
mkdir -p $INSTALL_DIR/roms/msx2
mkdir -p $INSTALL_DIR/roms/naomi
mkdir -p $INSTALL_DIR/roms/neogeo
mkdir -p $INSTALL_DIR/roms/ngp
mkdir -p $INSTALL_DIR/roms/nds
mkdir -p $INSTALL_DIR/roms/n64
mkdir -p $INSTALL_DIR/roms/nes
mkdir -p $INSTALL_DIR/roms/nesh
mkdir -p $INSTALL_DIR/roms/ngpc
mkdir -p $INSTALL_DIR/roms/neocd
mkdir -p $INSTALL_DIR/roms/pc-9800
mkdir -p $INSTALL_DIR/roms/pcengine
mkdir -p $INSTALL_DIR/roms/pcenginecd
mkdir -p $INSTALL_DIR/roms/pcfx
mkdir -p $INSTALL_DIR/roms/openbor
mkdir -p $INSTALL_DIR/roms/piece
mkdir -p $INSTALL_DIR/roms/odyssey2
mkdir -p $INSTALL_DIR/roms/psp
mkdir -p $INSTALL_DIR/roms/pspminis
mkdir -p $INSTALL_DIR/roms/pokemini
mkdir -p $INSTALL_DIR/roms/homebrew
mkdir -p $INSTALL_DIR/roms/ports
mkdir -p $INSTALL_DIR/roms/sc-3000
mkdir -p $INSTALL_DIR/roms/scummvm
mkdir -p $INSTALL_DIR/roms/psx
mkdir -p $INSTALL_DIR/roms/segacd
mkdir -p $INSTALL_DIR/roms/sega32x
mkdir -p $INSTALL_DIR/roms/genesis
mkdir -p $INSTALL_DIR/roms/genh
mkdir -p $INSTALL_DIR/roms/mastersystem
mkdir -p $INSTALL_DIR/roms/megadrive
mkdir -p $INSTALL_DIR/roms/megaduck
mkdir -p $INSTALL_DIR/roms/saturn
mkdir -p $INSTALL_DIR/roms/sg-1000
mkdir -p $INSTALL_DIR/roms/x1
mkdir -p $INSTALL_DIR/roms/zxspectrum
mkdir -p $INSTALL_DIR/roms/zx81
mkdir -p $INSTALL_DIR/roms/pc-8800
mkdir -p $INSTALL_DIR/roms/snes
mkdir -p $INSTALL_DIR/roms/supergrafx
mkdir -p $INSTALL_DIR/roms/pico-8
mkdir -p $INSTALL_DIR/roms/megacd
mkdir -p $INSTALL_DIR/roms/snesh
mkdir -p $INSTALL_DIR/roms/satellaview
mkdir -p $INSTALL_DIR/roms/sfc
mkdir -p $INSTALL_DIR/roms/sufami
mkdir -p $INSTALL_DIR/roms/tic-80
mkdir -p $INSTALL_DIR/roms/tg16
mkdir -p $INSTALL_DIR/roms/solarus
mkdir -p $INSTALL_DIR/roms/vectrex
mkdir -p $INSTALL_DIR/roms/gbc
mkdir -p $INSTALL_DIR/roms/videopac
mkdir -p $INSTALL_DIR/roms/virtualboy
mkdir -p $INSTALL_DIR/roms/wonderswan
mkdir -p $INSTALL_DIR/roms/wonderswancolor
mkdir -p $INSTALL_DIR/roms/ecwolf
mkdir -p $INSTALL_DIR/roms/x68000
mkdir -p $INSTALL_DIR/roms/build
mkdir -p $INSTALL_DIR/roms/tools
mkdir -p $INSTALL_DIR/roms/imageviewer
mkdir -p $INSTALL_DIR/roms/gamegear
mkdir -p $INSTALL_DIR/roms/tg16cd
mkdir -p $INSTALL_DIR/roms/j2me
mkdir -p $INSTALL_DIR/roms/uzebox
mkdir -p $INSTALL_DIR/roms/supervision
mkdir -p $INSTALL_DIR/roms/doom
# Initializing directories
mkdir -p $INSTALL_DIR/storage/.config/
mkdir -p $INSTALL_DIR/usr/
mkdir -p $INSTALL_DIR/emulators
ln -s $INSTALL_DIR/emulationstation ~/.emulationstation
# Defining architecture
rm -f $INSTALL_DIR/storage/.config/.OS_ARCH
touch $INSTALL_DIR/storage/.config/.OS_ARCH
echo "DECK" >> $INSTALL_DIR/storage/.config/.OS_ARCH
# Installing RetroArch
sudo pacman -S retroarch
# Setting up RetroArch
mkdir -p ~/.config/retroarch/
mv ~/.config/retroarch/retroarch.cfg ~/.config/retroarch/retroarch.cfg.bak
mv $INSTALL_DIR/retroarch.cfg ~/.config/retroarch/
# TODO: download controller config
# Installing libretro cores
cd $INSTALL_DIR/emulators
if test -f "$INSTALL_DIR/emulators/RetroArch_cores.7z"; then
read -p "The RetroArch cores seems to be already downloaded, do you want to re-download them? [Y/n]: " -n 1 -r
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
break
else
rm -rf RetroArch*
wget $CORES_LINK
fi
else
wget $CORES_LINK
fi
7z x RetroArch_cores.7z
mv $INSTALL_DIR/emulators/RetroArch-Linux-x86_64/RetroArch-Linux-x86_64.AppImage.home/.config/retroarch/cores $INSTALL_DIR/emulators/
# TODO: Installing standalone emulators
# Installing 351elec-emulationstation
cd $INSTALL_DIR
git clone --recursive https://github.com/351ELEC/351elec-emulationstation emulationstation
cd emulationstation
sudo pacman -S base-devel cmake freeimage sdl2_mixer sdl2 rapidjson boost
cmake -DENABLE_EMUELEC=1 -DGLES2=0 -DDISABLE_KODI=1 -DENABLE_FILEMANAGER=0 -DCEC=0 -DRG552=1
make -j$(nproc)
cp $INSTALL_DIR/es_systems.cfg $INSTALL_DIR/emulationstation/
cp $INSTALL_DIR/es_settings.cfg $INSTALL_DIR/emulationstation/
cp $INSTALL_DIR/es_input.cfg $INSTALL_DIR/emulationstation/
# Installing default theme
mkdir -p $INSTALL_DIR/emulationstation/themes
cd $INSTALL_DIR/emulationstation/themes
git clone --recursive https://github.com/anthonycaccese/es-theme-art-book-next
# Downloading needed files
# TODO 351elec-es-packages batocera-config batocera-scraper batocera-settings runemu.py setsettings.py
# Creating desktop element
rm -f ~/Desktop/RetroDECK.desktop
touch ~/Desktop/RetroDECK.desktop
cat << EOF >> ~/Desktop/RetroDECK.desktop
[Desktop Entry]
Comment=An enbedded emulation system.
Exec=$INSTALL_DIR/retrodeck.sh
GenericName=RetroDECK
Icon=$INSTALL_DIR/res/icon128.png
MimeType=
Name=RetroDECK
Path=$INSTALL_DIR/
StartupNotify=true
Terminal=false
TerminalOptions=
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=
X-KDE-SubstituteUID=false
X-KDE-Username=
EOF
# Creating start script
rm -rf $INSTALL_DIR/retrodeck.sh
touch $INSTALL_DIR/retrodeck.sh
cat << EOF >> $INSTALL_DIR/retrodeck.sh
#!/bin/bash
$INSTALL_DIR/export_func.sh
mkdir -p /tmp/logs
if [ test -d "/tmp/cores" ]; then break
else
ln -s $INSTALL_DIR/emulators/cores /tmp/cores
fi
$INSTALL_DIR/emulationstation/emulationstation
EOF
chmod 777 $INSTALL_DIR/retrodeck.sh
chmod 777 $INSTALL_DIR/export_func.sh
# Cleaning up
# TODO: these removal must be made when I am sure tghis file is safe on github
#rm -rf $INSTALL_DIR/emulators/RetroArch-Linux-x86_64
#rm -rf $INSTALL_DIR/emulators/RetroArch_cores.7z
#rm $INSTALL_DIR/es_systems.cfg $INSTALL_DIR/emulationstation/
#rm $INSTALL_DIR/es_settings.cfg $INSTALL_DIR/emulationstation/
#rm $INSTALL_DIR/es_input.cfg $INSTALL_DIR/emulationstation/
echo "Installation terminated, you can run RetroDECK from the desktop link or add it on your Steam Library."
# TODO: maybe I can add it to the steam library directly, I think I have to close steam and design a banner
cd $PREVIOUS_DIR

BIN
res/icon128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

BIN
res/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

View file

@ -0,0 +1,232 @@
## ------------ A - 351ELEC configuration ------------ #
## Enable D-Pad to analogue at boot until we create a proper toggle
global.analogue=1
## Enable SSH at boot
ee_ssh.enabled=1
## Enable SAMBA at boot
ee_samba.enabled=1
## Enable Bluetooth at boot
ee_bluetooth.enabled=0
## Use maxperf, enable max settings for GPU and performance governer, this setting can be set globally, per platform or per game on the ES menu
global.maxperf=0
## Always show boot video
#ee_bootvideo.enabled=0
## Set video mode
ee_videomode=720p60hz
## What to start at boot Emulationstation or Retroarch
ee_boot=Emulationstation
## Enable splash screens
ee_splash.enabled=0
## set to 1 if you have long loading times after quitting a game, you will lose sound mixing in ES, this only affects S905/S912 devices as all others use alsa.
#ee_alsa.always=0
## Force splash screens to display for X seconds
#ee_splash.delay=0
## Some external HDDs take longer to mount than ES to load, if your external ROMS do not mount in time, increase this timer
#ee_load.delay=0
# Enable Advance mame auto gamepad configuration 1,0 (default 1)
advmame_auto_gamepad=0
## EmulationStation menu style
## default -> default all options menu
## none -> no menu except the game search menu
## bartop -> less menu, only needed for bartops
#system.es.menu=default
# ------------ B - Network ------------ #
## Set system hostname
system.hostname=351ELEC
## Activate wifi (0,1)
wifi.enabled=1
## Wifi SSID (string)
#wifi.ssid=
## Wifi KEY (string)
## after rebooting the "new key" is replace by a hidden value "enc:xxxxx"
## you can edit the "enc:xxxxx" value to replace by a clear value, it will be updated again at the following reboot
## Escape your special chars (# ; $) with a backslash : $ => \$
#wifi.key=
# secondary wifi (not configurable via the user interface)
#wifi2.ssid=new ssid
#wifi2.key=new key
# third wifi (not configurable via the user interface)
#wifi3.ssid=new ssid
#wifi3.key=new key
# ------------ C - Audio ------------ #
## Set the audio device (auto, hdmi, jack, speakers, headphones) mostly for OdroidGoAdvance
## Set system volume (0..100)
## Enable or disable system sounds in ES (0,1)
audio.bgmusic=1
# -------------- D - Controllers ----------------- #
# Enable support for standard bluetooth controllers
controllers.bluetooth.enabled=1
# ------------ F - Language and keyboard ------------ #
## Set the language of the system (fr_FR,en_US,en_GB,de_DE,pt_BR,es_ES,it_IT,eu_ES,tr_TR,zh_CN)
system.language=en_US
## Set you local time
## Select your timezone from : ls /usr/share/zoneinfo/ (string)
system.timezone=Europe/London
# ------------ G - UPDATES ------------ #
## Automatically check for updates at start (0,1)
updates.enabled=1
updates.type=release
# fan profile - controls fan speed (values: default/performance/quiet)
# Not used for DECK
# fan.profile=default
# ------------ H - HERE IT IS - GLOBAL EMULATOR CONFIGURATION ------------ #
## The global value will be used for all emulators, except if the value
## is redefined in the emulator
## Bezel on by default
global.bezel=default
## Retroarch menu driver, ozone (default), rgui or xmb
global.retroarch.menu_driver=ozone
## Shader set
## Automatically select shaders for all systems
## (none, retro, scanlines)
## Once enabled, your screen will be cropped, and you will have a pixel perfect image (0,1)
global.integerscale=1
## Set gpslp shader for all emulators (prefer shadersets above). Absolute path (string)
#global.shaders=
## Set ratio for all emulators (auto,4/3,16/9,16/10,custom)
global.ratio=4/3
## Set autosave/load savestate for all emulators (0,1,2,3)
global.autosave=2
## Set incremental savestates for all emulators (0,1)
global.incrementalsavestates=0
## Set runahead frames for all emulators (0,1,2,3,4,5,6)
global.runahead=0
## Set secondinstance for runahead for all emulators (0,1)
global.secondinstance=0
## Enable retroarchievements (0,1)
## Set your www.retroachievements.org username/password
## Escape your special chars (# ; $) with a backslash : $ => \$
global.retroachievements=1
global.retroachievements.hardcore=0
global.retroachievements.leaderboards=disabled
global.retroachievements.challengeindicators=0
global.retroachievements.richpresence=0
global.retroachievements.testunofficial=0
global.retroachievements.soundenable=0
global.retroachievements.verbose=0
global.retroachievements.screenshot=1
global.retroachievements.username=
global.retroachievements.password=
## Enable RetroArch AI game translation service
#global.ai_service_enabled=0
#global.ai_service_url=
#global.ai_target_lang=
## Configurations generated by Emulationstation
audio.display_titles=1
audio.persystem=0
global.netplay=0
global.netplay.port=55435
global.netplay.relay=none
audio.device=headphone
audio.volume=75
brightness.level=50
system.brightness=50
## Device Overclock
overclock=0
# ------------ I - EMULATORS CHOICES ----------- #
## You can override the global configuration here
## Here is the snes example
#snes.shaders=mysnesshader.gplsp
3do.maxperf=1
3do.rewind=0
arcade.maxperf=1
arcade.autosave=0
atari2600.ratio=squarepixel
atarilynx.ratio=squarepixel
atarilynx.shaderset=handheld/lcd3x.glslp
atomiswave.maxperf=1
dreamcast.maxperf=1
fbn.ratio=squarepixel
gamegear.bezel.overlay.grid=1
gamegear.bezel.overlay.shadow=1
gamegear.ratio=squarepixel
gb.bezel.overlay.grid=1
gb.bezel.overlay.shadow=1
gb.ratio=squarepixel
gba.ratio=squarepixel
gba.shaderset=handheld/lcd3x.glslp
gbah.ratio=squarepixel
gbah.shaderset=handheld/lcd3x.glslp
gbc.bezel.overlay.grid=1
gbc.bezel.overlay.shadow=1
gbc.ratio=squarepixel
gbch.bezel.overlay.grid=1
gbch.bezel.overlay.shadow=1
gbch.ratio=squarepixel
gbh.bezel.overlay.grid=1
gbh.bezel.overlay.shadow=1
gbh.ratio=squarepixel
ggh.bezel.overlay.grid=1
ggh.bezel.overlay.shadow=1
ggh.ratio=squarepixel
j2me.maxperf=1
megadrive.ratio=squarepixel
mame.autosave=0
mame.maxperf=1
n64.maxperf=1
nds.maxperf=1
naomi.maxperf=1
ngp.ratio=squarepixel
ngp.shaderset=handheld/lcd3x.glslp
ngpc.ratio=squarepixel
ngpc.shaderset=handheld/lcd3x.glslp
pc.maxperf=1
pcfx.maxperf=1
pokemini.ratio=3/2
psp.maxperf=1
psp.ratio=squarepixel
pspminis.maxperf=1
pspminis.ratio=squarepixel
psx.integerscaleoverscale=1
saturn.ratio=squarepixel
segacd.ratio=squarepixel
supervision.bezel.overlay.grid=1
supervision.bezel.overlay.shadow=1
supervision.ratio=squarepixel
uzebox.integerscale=1
vectrex.ratio=3/4
virtualboy.maxperf=1
virtualboy.ratio=squarepixel
wonderswan.ratio=squarepixel
wonderswan.shaderset=handheld/lcd3x.glslp
wonderswancolor.ratio=squarepixel
wonderswancolor.shaderset=handheld/lcd3x.glslp

File diff suppressed because it is too large Load diff

236
usr/bin/351elec-es-packages Executable file
View file

@ -0,0 +1,236 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2020-present Batocera
# Copyright (C) 2020-present Fewtarius
#
# Download and install packages supported binary packages
#
# Usage:
# 351elec-es-package 'list' or 'install <package>'
#
# If you don't provide a <package>, the list of packages will be downloaded and sent back to you.
#
ARCH="$(cat /storage/.config/.OS_ARCH)"
if [ "${ARCH}" == "RG351P" ]; then
DEVICE="RG351P"
elif [ "${ARCH}" == "RG351V" ]; then
DEVICE="RG351V"
elif [ "${ARCH}" == "RG351MP" ]; then
DEVICE="RG351MP"
elif [ "${ARCH}" == "RG552" ]; then
DEVICE="RG552"
fi
DISTRO="351ELEC"
CONFIGDIR="/storage/.config/packages"
PACKAGELIST="https://raw.githubusercontent.com/351ELEC/351ELEC-metadata/main/${ARCH}/packages.cfg"
LOCALPACKAGELIST="/storage/.config/packages.cfg"
# Community Package List Schema
#
# {PACKAGE NAME}|{PACKAGE URL}|{SHA256SUM}
#
# Half_Life|https://github.com/blah/half-life-1231.zip|d06489dcf04c602ddacc6f80b2809e6d25fd6298c461966e666e19d3188e04be
#
# packages.cfg must be a plain text pipe delimited file.
# Community Package Schema
#
# URL: https://github.com/blah/half-life-1231.zip
# Content:
# half-life/ <- must match "package" name ^
# install.sh <- must be named install.sh/uninstall.sh and be in the package root.
# uninstall.sh
# Relevant files/directories included in install.sh/uninstall.sh
# Minimum:
# system-half-life.png
# system-half-life-thumb.png
#
# The package blob may be hosted elsewhere, as long as install.sh is able to download it.
###############################
#
# Prepare the system for installation
if [ ! -d "${CONFIGDIR}" ]
then
mkdir -p "${CONFIGDIR}"
fi
###############################
#
function usage() {
echo "$0 - downloads and installs packages supported packages in ${DISTRO}"
echo " "
echo "It accepts two modes: 'list' and 'install <package>'"
echo "- 'list' for the list of packages available online, and if they are"
echo " [A]vailable to install, [I]nstalled or [?]unknown."
echo "- 'install <package>' to install the package, from its package name."
echo "- 'remove <package>' to delete an installed package."
echo " "
exit 1
}
###############################
#
function check_url() {
[[ "$1" =~ ^(https?|ftp)://.*$ ]] && echo "[A]" || echo "[?]"
}
###############################
#
function git_name() {
echo "$1" | sed "s,.*/\(.*\),\1,"
}
###############################
#
function repo_name() {
echo "$1" | sed "s,.*github.com/\([A-Za-z0-9_-]*\)/.*,\1,"
}
###############################
#
function list_packages() {
fn=$(date +"%s")
tmp="/tmp/packages_${fn}"
echo "* ${DISTRO} packages *"
if [ -f ${LOCALPACKAGELIST} ]; then
cp -f "${LOCALPACKAGELIST}" "${tmp}"
else
curl -H 'Cache-Control: no-cache' -sfL "${PACKAGELIST}" -o "${tmp}" || exit 1
sed -i 's/\r$//' "${tmp}"
fi
while IFS=$'|' read name url shasum; do
[ x"${name}" == "x" ] && continue
ia=$(check_url "${url}")
[ -d "${CONFIGDIR}"/"${name}" ] && ia="[I]"
echo "${ia} ${name} - ${url}"
done < "${tmp}"
[[ -e "${tmp}" ]] && rm "${tmp}"
}
###############################
#
function getPer() {
TARFILE="$1"
TARVAL="$2"
while true; do
CURVAL=$(stat "$TARFILE" | grep -E '^[ ]*Size:' | sed -e s+'^[ ]*Size: \([0-9][0-9]*\) .*$'+'\1'+)
CURVAL=$((CURVAL / 1024 / 1024))
PER=$((${CURVAL} * 100 / ${TARVAL}))
echo "${PER}% - ${package} - [${TARVAL}MB]"
sleep 2
done
}
###############################
#
function install_package() {
package="$1"
success_installed=0
fn=$(date +"%s")
tmp="/tmp/packages_${fn}"
if [ -f ${LOCALPACKAGELIST} ]; then
cp -f "${LOCALPACKAGELIST}" "${tmp}"
else
curl -H 'Cache-Control: no-cache' -sfL "${PACKAGELIST}" -o "${tmp}" || exit 1
sed -i 's/\r$//' "${tmp}"
fi
while IFS=$'|' read name url shasum; do
[ x"${name}" != x"${package}" ] && continue
ia=$(check_url "${url}")
if [ x"${ia}" != x"[A]" ]; then
echo "Error - invalid package URL ${url}"
exit 1
else
cd ${CONFIGDIR}
filename=$(echo ${url} | sed "s#^.*/##")
curl -H 'Cache-Control: no-cache' -sfL "${url}" -o "${filename}" || exit 1
if [ -f "${filename}" ]; then
echo "Verifying package checksum"
dldsum=$(sha256sum ${filename} | awk '{print $1}')
if [ ! "${shasum}" == "${dldsum}" ]
then
echo "Error - Checksum does not match."
success_installed=0
else
echo "Unzipping ${filename} package files >>> 99%"
if [ -d "${CONFIGDIR}/${filename}" ]
then
rm -rf "${CONFIGDIR}/${filename}"
fi
unzip "${filename}" >/dev/null 2>&1
rm "${filename}"
echo "Installing ${filename} package"
sh ./${package}/install.sh
if [ $? == 0 ]
then
success_installed=1
else
echo "Error - Installation failed."
success_installed=0
fi
fi
else
echo "Error - ${package} zip file could not be downloaded from ${url}"
exit 1
fi
fi
done < "${tmp}"
[[ -e "${tmp}" ]] && rm "${tmp}"
if [ "${success_installed}" == 1 ]; then
echo "${package} is now installed >>> 100%"
exit 0
else
echo "Error - ${package} could not be installed"
exit 1
fi
}
###############################
#
function remove_package() {
package="$1"
success_removed=0
filename=${package}
if [ -d "${CONFIGDIR}/${package}" ]; then
sh ${CONFIGDIR}/${package}/uninstall.sh
if [ $? == 0 ]
then
rm -rf "${CONFIGDIR}"/"${filename}" && success_removed=1
else
echo "Unable to uninstall ${package}"
success_removed=0
fi
else
echo "${package} doesn't appear to be in ${CONFIGDIR}/${filename}"
fi
if [ "${success_removed}" == 1 ]; then
TERMINAL=0 && echo "${package} uninstalled >>>100"
exit 0
else
echo "Error - ${package} could not be removed"
exit 1
fi
}
#### Main loop
#
command="$1"
package="$2"
if ! [ -d "${CONFIGDIR}" ]; then
echo "Error - package directory ${CONFIGDIR} is not valid."
exit 1
fi
if [ x"${command}" == "xlist" ]; then
list_packages
elif [ x"${command}" == "xinstall" ]; then
[ x"${package}" != "x" ] && install_package ${package} || usage
elif [ x"${command}" == "xremove" ]; then
[ x"${package}" != "x" ] && remove_package ${package} || usage
else
usage
fi

373
usr/bin/batocera-config Executable file
View file

@ -0,0 +1,373 @@
#!/bin/bash
if [ ! "$1" ];then
echo -e "usage : batocera-config [command] [args]\nWith command in\n\toverscan [enable|disable]\n\tlsaudio\n\tgetaudio\n\taudio [hdmi|jack|auto|custom|x,y]\n\tcanupdate\n\tupdate\n\twifi [enable|disable] ssid key\n\tstorage [current|list|INTERNAL|ANYEXTERNAL|RAM|DEV UUID]\n\tsetRootPassword [password]\n\tgetRootPassword\n\ttz [|tz]"
exit 1
fi
configFile="/storage/.config/distribution/configs/config.txt"
storageFile="/storage/.config/distribution/configs/batocera-boot.conf"
command="$1"
mode="$2"
extra1="$3"
extra2="$4"
extra3="$5"
extra4="$6"
arch=$(cat /storage/.config/.OS_ARCH)
updateurl="https://127.0.0.1"
preBootConfig() {
mount -o remount,rw /boot
}
postBootConfig() {
mount -o remount,ro /boot
}
bato_config_set_value () {
key=$1
value=$2
[ -z "$value" ] && value=0
cat "$configFile" | grep "$key"
valPresent=$?
if [ "$valPresent" != "0" ];then
echo "$key=$value" >> "$configFile"
else
sed -i "s/#\?$key=.*/$key=$value/g" "$configFile"
fi
}
#log=/userdata/system/logs/batocera.log
#systemsetting="python /usr/lib/python2.7/site-packages/configgen/settings/batoceraSettings.py"
log=/tmp/logs/systemsettings.log
systemsetting="/usr/bin/batocera-settings"
echo "----config ----" >> $log
if [ "$command" == "getRootPassword" ]; then
# security disabled, force the default one without changing boot configuration
securityenabled="`$systemsetting -command load -key system.security.enabled`"
if [ "$securityenabled" != "1" ];then
echo "linux"
exit 0
fi
ENCPASSWD=$(grep -E '^[ \t]*rootshadowpassword[ \t]*=' "${storageFile}" | sed -e s+'^[ \t]*rootshadowpassword[ \t]*='++)
if test -z "${ENCPASSWD}"
then
exit 1
fi
if ! batocera-encode decode "${ENCPASSWD}"
then
exit 1
fi
exit 0
fi
if [ "$command" == "setRootPassword" ]; then
PASSWD=${2}
# security disabled, don't change
securityenabled="`$systemsetting -command load -key system.security.enabled`"
if [ "$securityenabled" != "1" ];then
exit 0
fi
# if no password if provided, generate one
if test -z "${PASSWD}"
then
PASSWD=$(tr -cd _A-Z-a-z-0-9 < /dev/urandom | fold -w8 | head -n1)
fi
PASSWDENC=$(batocera-encode encode "${PASSWD}")
preBootConfig
if grep -qE '^[ \t]*rootshadowpassword[ \t]*=' "${storageFile}"
then
# update it
if ! sed -i -e s@'^[ \t]*rootshadowpassword[ \t]*=.*$'@"rootshadowpassword=${PASSWDENC}"@ "${storageFile}"
then
postBootConfig
exit 1
fi
postBootConfig
exit 0
else
# create it
if ! echo "rootshadowpassword=${PASSWDENC}" >> "${storageFile}"
then
postBootConfig
exit 1
fi
postBootConfig
exit 0
fi
fi
if [ "$command" == "overscan" ]; then
if [ "$mode" == "set" ];then
# set will set overscan values abd also enable this mode
if [ -z "$extra1" ] || [ -z "$extra2" ] || [ -z "$extra3" ] || [ -z "$extra4" ]; then
echo "$0 $command $mode needs 4 arguments:"
echo "$0 $command $mode overscan_left overscan_right overscan_top overscan_bottom"
exit 2
fi
preBootConfig
[ -f "$configFile" ] || touch "$configFile"
echo "setting overscan values $extra1 $extra2 $extra3 $extra4 " >> $log
bato_config_set_value disable_overscan 0
bato_config_set_value overscan_scale 1
bato_config_set_value overscan_left "$extra1"
bato_config_set_value overscan_right "$extra2"
bato_config_set_value overscan_top "$extra3"
bato_config_set_value overscan_bottom "$extra4"
postBootConfig
exit 0
fi
if [ -f "$configFile" ];then
preBootConfig
if [ "$mode" == "enable" ];then
echo "enabling overscan" >> $log
bato_config_set_value disable_overscan 0
bato_config_set_value overscan_scale 1
elif [ "$mode" == "disable" ];then
echo "disabling overscan" >> $log
bato_config_set_value disable_overscan 1
bato_config_set_value overscan_scale 0
else
postBootConfig
exit 1
fi
postBootConfig
exit 0
else
exit 2
fi
fi
if [ "$command" == "lsoutputs" ]
then
echo "auto"
batocera-resolution listOutputs
fi
if [ "$command" == "lsaudio" ];then
if [[ "${arch}" =~ "rpi" ]]
then
echo "hdmi"
echo "jack"
echo "auto"
elif [[ "${arch}" =~ "x86" ]];then
echo "auto"
echo "custom"
LANG=C aplay -l | grep -E '^card [0-9]*:' | sed -e s+'^card \([0-9]*\): \([^,]*\), device \([0-9]*\): [^\[]* \[\([^]]*\)].*$'+'\1,\3 \4 \2'+
else
echo "auto"
fi
fi
if [ "$command" == "getaudio" ];then
$systemsetting -command load -key audio.device
exit 0
fi
if [ "$command" == "audio" ];then
# this code is specific to the rpi
# don't set it on other boards
# find a more generic way would be nice
if [[ "${arch}" =~ "rpi" ]]
then
# this is specific to the rpi
cmdVal="0"
if [ "$mode" == "hdmi" ];then
cmdVal="2"
elif [ "$mode" == "jack" ];then
cmdVal="1"
fi
echo "setting audio output mode : $mode" >> $log
amixer cset numid=3 $cmdVal || exit 1
elif [[ "${arch}" =~ "x86" ]]
then
# auto: no .asoundrc file
# custom: don't touch the .asoundrc file
# any other, create the .asoundrd file
if [ "$mode" == "auto" ];then
rm -rf /userdata/system/.asoundrc || exit 1
elif [ "$mode" != "custom" ];then
if echo "${mode}" | grep -qE '^[0-9]*,[0-9]* '
then
cardnb=$(echo "${mode}" | sed -e s+'^\([0-9]*\),.*$'+'\1'+)
devicenb=$(echo "${mode}" | sed -e s+'^[0-9]*,\([0-9]*\) .*$'+'\1'+)
cat > /userdata/system/.asoundrc <<EOF
pcm.!default { type plug slave { pcm "hw:${cardnb},${devicenb}" } }
ctl.!default { type hw card ${cardnb} }
EOF
aplay "/usr/share/sounds/Mallet.wav"
fi
fi
elif [[ "${arch}" =~ RG351 ]]
then
case "${mode}" in
"auto"|"speakers")
amixer cset name='Playback Path' SPK
;;
"headphone")
amixer cset name='Playback Path' HP
;;
esac
fi
exit 0
fi
if [ "$command" == "volume" ];then
if [ "$mode" != "" ];then
echo "setting audio volume : $mode" >> $log
# on my pc, the master is turned off at boot
# i don't know what are the rules to set here.
amixer set Master unmute || exit 1
amixer set Master -- ${mode}% || exit 1
# maximize the sound to be sure it's not 0, allow errors
amixer set PCM -- 100% #|| exit 1
amixer set Headphone -- 100% #|| exit 1
exit 0
fi
exit 12
fi
if [ "$command" == "gpiocontrollers" ];then
command="module"
mode="load"
extra1="mk_arcade_joystick_rpi"
extra2="map=1,2"
fi
if [ "$command" == "module" ];then
modulename="$extra1"
map="$extra2"
# remove in all cases
rmmod /lib/modules/`uname -r`/extra/${modulename}.ko >> $log
if [ "$mode" == "load" ];then
echo "loading module $modulename args = $map" >> $log
insmod /lib/modules/`uname -r`/extra/${modulename}.ko $map >> $log
[ "$?" ] || exit 1
fi
exit 0
fi
if [ "$command" == "canupdate" ];then
available=$(updatecheck canupdate)
echo "$available"
if [[ "$available" != "no" ]]; then
exit 0
fi
exit 12
fi
if [ "$command" == "update" ];then
351elec-upgrade
exit $?
fi
if [[ "$command" == "wifi" ]]; then
ssid="$3"
psk="$4"
if [[ "$mode" == "enable" ]]; then
echo "configure wifi" >> $log
mkdir -p "/storage/.cache/connman" || exit 1
cat > "/storage/.cache/connman/wifi.config" <<EOF
[global]
Name=351elec
[service_351elec_default]
Type=wifi
Name=${ssid}
EOF
if test "${psk}" != ""
then
echo "Passphrase=${psk}" >> "/storage/.cache/connman/wifi.config"
fi
# Power up the WIFI device
if [ "$(cat /sys/firmware/devicetree/base/model)" == "Anbernic RG552" ]; then
echo 1 > /sys/class/gpio/gpio113/value
else
echo 1 > /sys/class/gpio/gpio5/value
fi
sleep 3
connmanctl enable wifi || exit 1
connmanctl scan wifi || exit 1
exit 0
fi
if [[ "$mode" =~ "start" ]]; then
if [[ "$mode" != "forcestart" ]]; then
settingsWlan="`$systemsetting -command load -key wifi.enabled`"
if [ "$settingsWlan" != "1" ];then
exit 1
fi
fi
# Power up the WIFI device
if [ "$(cat /sys/firmware/devicetree/base/model)" == "Anbernic RG552" ]; then
echo 1 > /sys/class/gpio/gpio113/value
else
echo 1 > /sys/class/gpio/gpio5/value
fi
sleep 3
connmanctl enable wifi || exit 1
connmanctl scan wifi || exit 1
exit 0
fi
if [[ "$mode" == "disable" ]]; then
connmanctl disable wifi
# Power down the WIFI device
if [ "$(cat /sys/firmware/devicetree/base/model)" == "Anbernic RG552" ]; then
echo 0 > /sys/class/gpio/gpio113/value
else
echo 0 > /sys/class/gpio/gpio5/value
fi
exit $?
fi
if [[ "$mode" == "list" ]]; then
WAVAILABLE=$(connmanctl services | cut -b 5- | sed -e s+'^\([^ ]*\).*$'+'\1'+ | grep -vE '^Wired$|^<hidden>$')
if test -n "${ssid}"
then
echo "${WAVAILABLE}" | grep -qE '^'"${ssid}"'$' || echo "${ssid}"
fi
echo "${WAVAILABLE}"
exit 0
fi
fi
if [[ "$command" == "storage" ]]; then
exit 0;
fi
if [[ "$command" == "forgetBT" ]]; then
killall -9 hcitool
systemctl stop bluetooth
rm -rf /storage/.cache/bluetooth/*
systemctl start bluetooth
exit 0
fi
if [ "$command" == "tz" ];then
if test "$mode" == ""
then
cat /storage/.config/distribution/configs/tz
else
if test -f "/usr/share/zoneinfo/${mode}"
then
echo "TIMEZONE=${mode}" > /storage/.cache/timezone
systemctl restart tz-data.service
fi
fi
exit $?
fi
exit 10

84
usr/bin/batocera-scraper Executable file
View file

@ -0,0 +1,84 @@
#!/bin/bash
# If we are on Steam Deck
arch=$(cat /storage/.config/.OS_ARCH)
if [ $arch == "DECK" ];then
INSTALL_DIR="~/retrodeck"
systemsetting=$INSTALL_DIR+"/usr/bin/batocera-settings"
syslang=$($systemsetting -command load -key system.language)
IMGSTYLE=$($systemsetting -command load -key scrapper.style)
if test $# = 1
then
DOSYS=$1
fi
# supported languages : en, fr, es, de, pt
case "${syslang}" in
fr_FR)
sslang=fr,en
;;
es_ES)
sslang=es,en
;;
de_DE)
sslang=de,en
;;
pt_PT)
sslang=pt,en
;;
pt_BR)
sslang=pt,en
;;
*)
sslang=en
esac
if test -z "${IMGSTYLE}"
then
IMGSTYLE="b,f,a,l,3b,s"
fi
do_scrap() {
LRDIR=$1
NF=$(ls "${LRDIR}" | grep -vE '\.txt$|\.xml$' | wc -l)
if test "${NF}" -gt 0
then
BASEDIR=$(basename "${LRDIR}")
echo "GAME: system ${BASEDIR}"
EXTRAOPT=
for x in "mame" "fba" "fba_libretro" "neogeo"
do
test "${LRDIR}" = $INSTALL_DIR+"/storage/roms/${x}" && EXTRAOPT="-mame"
done
(cd "${LRDIR}" && sselph-scraper -console_src ss,gdb,ovgdb -lang "${sslang}" -console_img "${IMGSTYLE}" -download_videos -workers 5 ${EXTRAOPT}) 2>&1
fi
}
# find system to scrape
(if test -n "${DOSYS}"
then
test -d $INSTALL_DIR+"/storage/roms/${DOSYS}" && echo $INSTALL_DIR+"/storage/roms/${DOSYS}"
else
find /storage/roms -maxdepth 1 -mindepth 1 -type d
fi) |
while read RDIR1
do
# read the 2 next dir
read RDIR2
read RDIR3
read RDIR4
do_scrap "${RDIR1}" &
test -n "${RDIR2}" && do_scrap "${RDIR2}" &
test -n "${RDIR3}" && do_scrap "${RDIR3}" &
test -n "${RDIR4}" && do_scrap "${RDIR4}" &
wait
done
# synchronize to not make the usb/sdcard slowing down once finnished
sync

272
usr/bin/batocera-settings Executable file
View file

@ -0,0 +1,272 @@
#!/bin/bash
# batocera-settings can mimic batoceraSettings.py
# goal: abolish this python script, it's useless for the sake of the load feature only
# get a more user friendly environment for setting, getting and saving keys
#
# Usage of BASE COMMAND:
# longform: <filename> --command <cmd> --key <key> --value <value>
#
# shortform: <file> <cmd> <key> <value>
#
# --command load write enable disable status
# --key any key in emuelec.conf (kodi.enabled...)
# --value any alphanumerical string
# use quotation marks to avoid globbing use slashes escape special characters
# This script reads only 1st occurrence if string and writes only to this first hit
#
# This script uses #-Character to comment values
#
# If there is a boolean value (0,1) then then enable and disable command will set the corresponding
# boolean value.
# Examples:
# 'batocera-settings --command load --key wifi.enabled' will print out 0 or 1
# 'batocera-settings --command write --key wifi.ssid -value "This is my NET"' will set 'wlan.ssid=This is my NET'
# 'batocera-settings enable wifi.ssid' will remove # from configfile (activate)
# 'batocera-settings disable wifi.enabled' will set key wifi.enabled=0
# 'botocera-settings /myown/config.file --command status --key my.key' will output status of own config.file and my.key
# by cyperghost - 2019/12/30
##### INITS #####
# If we are on Steam Deck
arch=$(cat /storage/.config/.OS_ARCH)
if [ $arch == "DECK" ];then
INSTALL_DIR="~/retrodeck"
BATOCERA_CONFIGFILE=$INSTALL_DIR+"/storage/.config/distribution/configs/distribution.conf"
COMMENT_CHAR_SEARCH="[#|;]"
COMMENT_CHAR="#"
##### INITS #####
##### Function Calls #####
function get_config() {
#Will search for key.value and #key.value for only one occurrence
#If the character is the COMMENT CHAR then set value to it
#Otherwise strip till the equal-char to obtain value
local val
local ret
val="$(grep -E -m1 "^\s*$1\s*=" $BATOCERA_CONFIGFILE)"
ret=$?
if [[ $ret -eq 1 ]]; then
val="$(grep -E -m1 "^$COMMENT_CHAR_SEARCH\s*$1\s*=" $BATOCERA_CONFIGFILE)"
ret=$?
[[ $ret -eq 0 ]] && val=$COMMENT_CHAR
else
#Maybe here some finetuning to catch key.value = ENTRY without blanks
val="${val#*=}"
fi
echo "$val"
return $ret
}
function set_config() {
#Will search for first key.name at beginning of line and write value to it
sed -i "1,/^\(\s*$1\s*=\).*/s//\1$2/" "$BATOCERA_CONFIGFILE"
}
function uncomment_config() {
#Will search for first Comment Char at beginning of line and remove it
sed -i "1,/^$COMMENT_CHAR_SEARCH\(\s*$1\)/s//\1/" "$BATOCERA_CONFIGFILE"
}
function comment_config() {
#Will search for first key.name at beginning of line and add a comment char to it
sed -i "1,/^\(\s*$1\)/s//$COMMENT_CHAR\1/" "$BATOCERA_CONFIGFILE"
}
function check_argument() {
# This method does not accept arguments starting with '-'.
if [[ -z "$2" || "$2" =~ ^- ]]; then
echo >&2
echo "ERROR: '$1' is missing an argument." >&2
echo >&2
echo "Just type '$0' to see usage page." >&2
echo >&2
return 1
fi
}
function dash_style() {
#This function is needed to "simulate" the python script with single dash
#commands. It will also accept the more common posix double dashes
#Accept dashes and double dashes and build new array ii with parameter set
#The else-branch can be used for the shortform
for i in --command --key --value; do
if [[ -z "$1" ]]; then
continue
elif [[ "$i" =~ ^-{0,1}"${1,,}" ]]; then
check_argument $1 $2
[[ $? -eq 0 ]] || exit 1
ii+=("$2")
shift 2
else
ii+=("$1")
shift 1
fi
done
}
function usage() {
val=" Usage of BASE COMMAND:
<file> --command <cmd> --key <key> --value <value>
shortform: <file> <cmd> <key> <value>
--command load write enable disable status
--key any key in emuelec.conf (kodi.enabled...)
--value any alphanumerical string
use quotation marks to avoid globbing
For write command --value <value> must be provided
exit codes: exit 0 = value is available, proper exit
exit 1 = general error
exit 2 = file error
exit 10 = value found, but empty
exit 11 = value found, but not activated
exit 12 = value not found
If you don't set a filename then default is '~/storage/.config/distribution.conf'"
echo "$val"
}
##### Function Calls #####
##### MAIN FUNCTION #####
function main() {
#Filename parsed?
if [[ -f "$1" ]]; then
BATOCERA_CONFIGFILE="$1"
shift
else
[[ -f "$BATOCERA_CONFIGFILE" ]] || { echo "not found: $BATOCERA_CONFIGFILE" >&2; exit 2; }
fi
#How much arguments are parsed, up to 6 then it is the long format
#up to 3 then it is the short format
if [[ ${#@} -eq 0 || ${#@} -gt 6 ]]; then
usage
exit 1
else
dash_style "$@"
command="${ii[0]}"
keyvalue="${ii[1]}"
newvalue="${ii[2]}"
unset ii
fi
[[ -z $keyvalue ]] && { echo "error: Please provide a proper keyvalue" >&2; exit 1; }
# value processing, switch case
case "${command,,}" in
"read"|"get"|"load")
val="$(get_config $keyvalue)"
ret=$?
[[ "$val" == "$COMMENT_CHAR" ]] && exit 11
[[ -z "$val" && $ret -eq 0 ]] && exit 10
[[ -z "$val" && $ret -eq 1 ]] && exit 12
[[ -n "$val" ]] && echo "$val" && exit 0
;;
"stat"|"status")
val="$(get_config $keyvalue)"
ret=$?
[[ -f "$BATOCERA_CONFIGFILE" ]] && echo "ok: found '$BATOCERA_CONFIGFILE'" >&2 || echo "error: not found '$BATOCERA_CONFIGFILE'" >&2
[[ -w "$BATOCERA_CONFIGFILE" ]] && echo "ok: r/w file '$BATOCERA_CONFIGFILE'" >&2 || echo "error: r/o file '$BATOCERA_CONFIGFILE'" >&2
[[ -z "$val" && $ret -eq 1 ]] && echo "error: '$keyvalue' not found!" >&2
[[ -z "$val" && $ret -eq 0 ]] && echo "error: '$keyvalue' is empty - use 'comment' command to retrieve" >&2
[[ "$val" == "$COMMENT_CHAR" ]] && echo "error: '$keyvalue' is commented $COMMENT_CHAR!" >&2 && val=
[[ -n "$val" ]] && echo "ok: '$keyvalue' $val"
exit 0
;;
"set"|"write"|"save")
#Is file write protected?
[[ -w "$BATOCERA_CONFIGFILE" ]] || { echo "r/o file: $BATOCERA_CONFIGFILE" >&2; exit 2; }
#We can comment line above to erase keys, it's much saver to check if a value is setted
[[ -z "$newvalue" ]] && echo "error: '$keyvalue' needs value to be setted" >&2 && exit 1
val="$(get_config $keyvalue)"
ret=$?
if [[ "$val" == "$COMMENT_CHAR" ]]; then
echo "$keyvalue: hashed out!" >&2
uncomment_config "$keyvalue"
set_config "$keyvalue" "$newvalue"
echo "$keyvalue: set from '$val' to '$newvalue'" >&2
exit 0
elif [[ -z "$val" && $ret -eq 1 ]]; then
echo "$keyvalue: not found!" >&2
exit 12
elif [[ "$val" != "$newvalue" ]]; then
set_config "$keyvalue" "$newvalue"
exit 0
fi
;;
"uncomment"|"enable"|"activate")
val="$(get_config $keyvalue)"
ret=$?
# Boolean
if [[ "$val" == "$COMMENT_CHAR" ]]; then
uncomment_config "$keyvalue"
echo "$keyvalue: removed '$COMMENT_CHAR', key is active" >&2
elif [[ "$val" == "0" ]]; then
set_config "$keyvalue" "1"
echo "$keyvalue: boolean set '1'" >&2
elif [[ -z "$val" && $ret -eq 1 ]]; then
echo "$keyvalue: not found!" && exit 2
fi
;;
"comment"|"disable"|"remark")
val="$(get_config $keyvalue)"
ret=$?
# Boolean
[[ "$val" == "$COMMENT_CHAR" || "$val" == "0" ]] && exit 0
if [[ -z "$val" && $ret -eq 1 ]]; then
echo "$keyvalue: not found!" >&2 && exit 12
elif [[ "$val" == "1" ]]; then
set_config "$keyvalue" "0"
echo "$keyvalue: boolean set to '0'" >&2
else
comment_config "$keyvalue"
echo "$keyvalue: added '$COMMENT_CHAR', key is not active" >&2
fi
;;
*)
echo "ERROR: invalid command '$command'" >&2
exit 1
;;
esac
}
##### MAIN FUNCTION #####
##### MAIN CALL #####
# Prepare arrays from fob python script
# Keyword for python call is mimic_python
# Attention the unset is needed to eliminate first argument (python basefile)
if [[ "${#@}" -eq 1 && "$1" =~ "mimic_python" ]]; then
#batoceraSettings.py fob
readarray -t arr <<< "$1"
unset arr[0]
else
#regular call by shell
arr=("$@")
fi
main "${arr[@]}"
##### MAIN CALL #####

405
usr/bin/runemu.py Executable file
View file

@ -0,0 +1,405 @@
#!/usr/bin/env python3
import datetime
import os
import shlex
import subprocess
import sys
from dataclasses import dataclass
from pathlib import Path
from time import perf_counter
from typing import TYPE_CHECKING, Optional
from setsettings import set_settings
# If we are on Steam Deck we want a prefix
# TODO: INSTALL_DIR + '/storage/.config/.OS_ARCH' was not working, dunno why, I'll check later
# DEVICE = "DECK" #for the moment this will do
INSTALL_DIR = os.path.expanduser('~/retrodeck')
with open(INSTALL_DIR + r'/storage/.config/.OS_ARCH', 'r') as file:
DEVICE = file.read().rstrip()
#if DEVICE == "DECK" :
#
#else:
# INSTALL_DIR = ""
if TYPE_CHECKING:
#These except Union are deprecated in 3.9 and should be replaced with collections.abc / builtin list type, but we have 3.8 for now
from typing import List, Mapping, MutableMapping, Sequence, Union
LOGS_DIR = Path('/tmp/logs')
RA_TEMP_CONF = INSTALL_DIR + '/storage/.config/retroarch/retroarch.cfg'
RA_APPEND_CONF = '/tmp/raappend.cfg'
log_path = LOGS_DIR / 'exec.log'
def call_profile_func(function_name: str, *args: str) -> str:
# if we are on Steam Deck
if DEVICE == "DECK" :
proc = subprocess.run(f'. {INSTALL_DIR}/export_func.sh', shell=True, stdout=subprocess.PIPE, check=True, text=True)
else:
#We are going to want to call some stuff from /etc/profile, they are defined in ../profile.d/99-distribution.conf
#But on Steam Deck this is not needed as these stuff is called by another script as profile.d is just for embedded distros
proc = subprocess.run(f'. /etc/profile && {shlex.quote(function_name)} {shlex.join(args)}', shell=True, stdout=subprocess.PIPE, check=True, text=True)
return proc.stdout.strip('\n')
def get_es_setting(setting_type: str, setting_name: str) -> str:
#from es_settings.cfg (XML)
return call_profile_func('get_es_setting', setting_type, setting_name)
log_level = get_es_setting('string', 'LogLevel') #If set to default, would equal empty string
def jslisten_set(*exe_names: str):
#exe_names are passed as one argument, intended for killall to use them later
if DEVICE != "DECK" :
call_profile_func('jslisten', 'set', shlex.join(exe_names))
def jslisten_stop():
#call_profile_func('jslisten', 'stop')
if DEVICE != "DECK" :
subprocess.check_call(['systemctl', 'stop', 'jslisten'])
def get_elec_setting(setting_name, platform=None, rom=None):
#From distribution.conf
#Potentially this can be reimplemented in Python if that turns out to be a good idea
return call_profile_func('get_ee_setting', setting_name, platform, rom)
def set_elec_setting(setting_name, value):
call_profile_func('set_ee_setting', setting_name, value)
def check_bios(platform, core, emulator, game, log_path_):
call_profile_func('ee_check_bios', platform, core, emulator, game, log_path_)
def log(text):
with log_path.open('at', encoding='utf-8') as log_file:
print(text, file=log_file)
def cleanup_and_quit(return_code):
if log_level == 'debug':
log(f'Cleaning up and exiting with return code {return_code}')
if DEVICE != "DECK" :
jslisten_stop()
clear_screen()
call_profile_func('normperf')
call_profile_func('set_audio', 'default')
sys.exit(return_code)
def clear_screen():
if DEVICE != "DECK" :
if log_level == 'debug':
log('Clearing screen')
with open('/dev/console', 'wb') as console:
subprocess.run('clear', stdout=console, check=True)
def list_archive(path: Path) -> 'List[str]':
#7z path needs to be given explicitly, otherwise it won't find 7z.so
sevenzip_proc = subprocess.run(['/usr/bin/7z', 'l', '-slt', path], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False)
if sevenzip_proc.returncode != 0:
raise OSError(sevenzip_proc.stderr.strip())
#Ignore the first Path = line which is the archive itself
return [line[len('Path = '):] for line in sevenzip_proc.stdout.splitlines() if line.startswith('Path = ')][1:]
def extract_archive(path: Path) -> Path:
#Assume there is only one file, otherwise things get weird
inner_filename = list_archive(path)[0]
#Since save files etc may be placed in the ROM folder, we should extract there so everything still works transparently, which also helps with overrides and such
subprocess.check_call(['/usr/bin/7z', 'e', f'-o{str(path.parent)}', path, inner_filename], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return path.parent.joinpath(inner_filename)
@dataclass(frozen=True)
class StandaloneEmulator():
jskill_name: str
args: 'Sequence[str]'
should_extract: bool = False
standalone_emulators: 'MutableMapping[str, StandaloneEmulator]' = {
'AMIBERRY': StandaloneEmulator('amiberry', ['/usr/bin/amiberry.start', '<path>']),
'AdvanceMame': StandaloneEmulator('advmame', ['/usr/bin/advmame.sh', '<path>']),
'HATARISA': StandaloneEmulator('hatari', ['/usr/bin/hatari.start', '<path>']),
'hypseus_singe': StandaloneEmulator('hypseus', ['/usr/bin/hypseus.sh', '<path>']),
'OPENBOR': StandaloneEmulator('openbor', ['/usr/bin/openbor.sh', '<path>']),
'PPSSPPSDL': StandaloneEmulator('PPSSPPSDL', ['/usr/bin/ppsspp.sh', '<path>']),
'SCUMMVMSA': StandaloneEmulator('scummvm', ['/usr/bin/scummvm.start', 'sa', '<path>']),
'drastic': StandaloneEmulator('drastic', ['/usr/bin/drastic.sh', '<path>']),
'ecwolf': StandaloneEmulator('ecwolf', ['/usr/bin/ecwolf.sh', '<path>']),
'gzdoom': StandaloneEmulator('gzdoom', ['/usr/bin/gzdoom.sh', '<path>']),
'lzdoom': StandaloneEmulator('lzdoom', ['/usr/bin/lzdoom.sh', '<path>']),
'mpv': StandaloneEmulator('mpv', ['/usr/bin/mpv_video.sh', '<path>']),
'pico8': StandaloneEmulator('pico8_dyn', ['/usr/bin/pico-8.sh', '<path>']),
'piemu': StandaloneEmulator('piemu', ['/usr/bin/bash', '-l', '/usr/bin/piemu.sh', '<path>']),
'raze': StandaloneEmulator('raze', ['/usr/bin/raze.sh', '<path>']),
'solarus': StandaloneEmulator('solarus-run', ['/usr/bin/solarus.sh', '<path>']),
}
def _load_customized_standalone_emulators():
try:
with open(INSTALL_DIR + '/storage/.config/standalone_emulators', 'rt', encoding='utf-8') as f:
for line in f:
if ': ' not in line or line.startswith('#'):
continue
name, rest = line.rstrip().split(': ', 1)
args = rest.split(' ')
kill_name = name
should_extract = False
#If name of exe to kill was not listed, assume it is the same as the emulator name
if not args[0].startswith('/'):
kill_name = args[0]
args = args[1:]
if args[-1] == 'should_extract':
args = args[:-1]
should_extract = True
standalone_emulators[name] = StandaloneEmulator(kill_name, args, should_extract)
except (FileNotFoundError, ValueError):
pass
_load_customized_standalone_emulators()
class EmuRunner():
def __init__(self, rom: Optional[Path], platform: Optional[str], emulator: Optional[str], core: Optional[str], args: 'Mapping[str, str]') -> None:
self.rom = rom
self.platform = platform
self.emulator = emulator
self.core = core
self.args = args
self.temp_files: 'List[Path]' = [] #Files that we extracted from archives, etc. to clean up later
self.environment = os.environ.copy()
def download_things_if_needed(self) -> None:
if self.core == 'freej2me':
#freej2me needs the JDK to be downloaded on the first run
subprocess.run(INSTALL_DIR + '/usr/bin/freej2me.sh', check=True)
self.environment['JAVA_HOME']=INSTALL_DIR + '/storage/jdk'
self.environment['PATH'] = INSTALL_DIR + '/storage/jdk/bin:' + os.environ['PATH']
elif self.core == 'easyrpg':
# easyrpg needs runtime files to be downloaded on the first run
subprocess.run(INSTALL_DIR + '/usr/bin/easyrpg.sh', check=True)
def toggle_max_performance(self) -> None:
if get_elec_setting('maxperf', self.platform, self.rom.name if self.rom else None) == '1':
if log_level == 'debug':
log('Enabling max performance as requested')
call_profile_func('maxperf')
else:
call_profile_func('normperf')
def set_settings(self) -> str:
rom_name = str(self.rom) if self.rom else ''
core = self.core if self.core else ''
platform = self.platform if self.platform else ''
return set_settings(rom_name, core, platform, controllers=self.args.get('controllers', ''), autosave=self.args.get('autosave', ''), snapshot=self.args.get('state_slot', ''))
def get_standalone_emulator_command(self) -> 'Sequence[Union[str, Path]]':
if not self.emulator:
raise ValueError('runemu.py was called improperly, tried to launch a standard emulator with no emulator')
if log_level != 'minimal':
log('Running a standalone emulator:')
log(f'platform: {self.platform}')
log(f'emulator: {self.emulator}')
#Core is not actually relevant (other than Mupen64Plus which is in another function)
emu = standalone_emulators[self.emulator]
path = self.rom
if self.rom and emu.should_extract and self.rom.suffix in {'.zip', '.7z', '.gz', '.bz2'}:
path = extract_archive(self.rom)
self.temp_files.append(path)
command = [arg for arg in (path if arg == '<path>' else arg for arg in emu.args) if arg]
jslisten_set(emu.jskill_name)
return command
def get_retroarch_command(self, shader_arg: str) -> 'Sequence[Union[str, Path]]':
if log_level != 'minimal':
log('Running a libretro core via RetroArch')
log(f'platform: {self.platform}')
log(f'core: {self.core}')
retroarch_binary = 'retroarch'
if self.core in {'pcsx_rearmed', 'parallel_n64'}:
retroarch_binary = 'retroarch32'
self.environment['LD_LIBRARY_PATH'] = '/usr/lib32'
rom_path: 'Optional[Union[str, Path]]' = self.rom
if self.rom:
if self.platform == 'doom' and self.rom.suffix == '.doom':
subprocess.run(['dos2unix', self.rom], check=True) #Hmmmmm but do we need that
with self.rom.open('rt', encoding='utf-8') as doomfile:
for line in doomfile:
key, _, value = line.partition('=')
if key == 'IWAD':
rom_path = value
break
if self.core == 'scummvm' and self.rom.suffix == '.scummvm':
#ScummVM libretro core actually only works with .scummvm files that just have the game ID with no path specified, which isn't how they are generated by the scummvm scanner script
#But if you give it any other path to a file, it will autodetect a game inside that file's parent directory, even if the file doesn't actually exist
#This would otherwise be what /usr/bin/scummvm.start tries to do when its first arg is "libretro", by cd'ing into that game directory
path = Path(self.rom.read_text(encoding='utf-8').split('"')[1])
rom_path = path / 'game'
jslisten_set(retroarch_binary)
command: 'List[Union[str, Path]]' = [os.path.join('/usr/bin/', retroarch_binary), '-L', Path('/tmp/cores/', f'{self.core}_libretro.so')]
if log_level != 'minimal':
command.append('--verbose')
if 'host' in self.args or 'connect' in self.args:
netplay_nick = get_elec_setting('netplay.nickname')
if not netplay_nick:
netplay_nick = '351ELEC'
if 'connect' in self.args:
set_elec_setting('netplay.client.port', self.args['port'])
set_elec_setting('netplay.client.ip', self.args['connect']) #We should now have parsed that properly so it's just a hostname/IP address, no --port argument
command += ['--connect', self.args['connect'] + '|' + self.args['port']]
if 'host' in self.args:
command += ['--host', self.args['host']]
command += ['--nick', netplay_nick]
if self.core == 'fbneo' and self.platform == 'neocd':
command += ['--subsystem', self.platform]
if shader_arg:
#Returned from setsettings, this is of the form "--shader-set /tmp/shaders/blahblahblah", apparently actually needed even if video_shader is set in RA_APPEND_CONF
command += shlex.split(shader_arg)
command += ['--config', RA_TEMP_CONF, '--appendconfig', RA_APPEND_CONF]
if rom_path:
command.append(rom_path)
return command
def get_retrorun_command(self) -> 'Sequence[Union[str, Path]]':
if not self.rom:
raise ValueError('runemu.py was called improperly, tried to launch retrorun with no game')
if not self.platform:
raise ValueError('runemu.py was called improperly, tried to launch retrorun with no platform')
if not self.core:
raise ValueError('runemu.py was called improperly, tried to launch retrorun with no platform')
core_path = Path('/tmp/cores/', f'{self.core}_libretro.so')
if log_level != 'minimal':
log('Running a libretro core via retrorun')
log(f'platform: {self.platform}')
log(f'core: {self.core}')
jslisten_set('retrorun', 'retrorun32')
path = self.rom
if self.rom.suffix in {'.zip', '.7z', '.gz', '.bz2'} and self.platform not in {'arcade', 'naomi', 'atomiswave', 'fbneo', 'mame'}:
path = extract_archive(self.rom)
self.temp_files.append(path)
return [INSTALL_DIR + '/usr/bin/retrorun.sh', core_path, path, self.platform]
def get_mupen64plus_standalone_command(self) -> 'Sequence[Union[str, Path]]':
if not self.rom:
raise ValueError('runemu.py was called improperly, tried to launch Mupen64Plus standalone with no video plugin')
if not self.core:
raise ValueError('runemu.py was called improperly, tried to launch Mupen64Plus standalone with no video plugin')
if log_level != 'minimal':
log(f'Running Mupen64Plus standalone with {self.core} video plugin')
jslisten_set('mupen64plus')
path = self.rom
if self.rom.suffix in {'.zip', '.7z', '.gz', '.bz2'}:
path = extract_archive(self.rom)
self.temp_files.append(path)
return [INSTALL_DIR + '/usr/bin/m64p.sh', self.core, path]
def get_command(self, shader_arg: str='') -> 'Sequence[Union[str, Path]]':
is_libretro_port = self.core and not self.emulator
#If true this was called from the inside of a port .sh that runs a libretro port (e.g. 2048, tyrQuake, etc), it makes no sense otherwise
if self.rom and (self.rom.suffix == '.sh' or self.platform == 'tools'):
#If the ROM is a shell script then just execute it (tools, ports, Pico-8 splore, ScummVM scanner, etc)
return ['/usr/bin/bash', '-l', self.rom]
elif self.emulator == 'retroarch' or is_libretro_port:
return self.get_retroarch_command(shader_arg)
elif self.emulator == 'retrorun':
return self.get_retrorun_command()
elif self.emulator == 'mupen64plussa':
return self.get_mupen64plus_standalone_command()
else:
return self.get_standalone_emulator_command()
def run(self, command: 'Sequence[Union[str, Path]]') -> None:
clear_screen()
if log_level != 'minimal':
log(f'Executing game: {self.rom}')
log(f'Executing {command}')
with log_path.open('at', encoding='utf-8') as log_file:
subprocess.run(command, stdout=log_file, stderr=subprocess.STDOUT, check=True, text=True, env=self.environment)
def cleanup_temp_files(self) -> None:
for temp_file in self.temp_files:
temp_file.unlink(missing_ok=True)
def main():
time_started = perf_counter()
i = 0
args: dict[str, str] = {}
while i < len(sys.argv)-1:
if sys.argv[i].startswith('--'):
args[sys.argv[i][2:]] = sys.argv[i + 1]
i += 1
continue
if sys.argv[i].startswith('-'):
args[sys.argv[i][1:]] = sys.argv[i + 1]
i += 1
continue
i += 1
rom = Path(args['rom']) if 'rom' in args else None
platform = args.get('platform')
core = args.get('core')
emulator = args.get('emulator')
log_path.unlink(missing_ok=True)
LOGS_DIR.mkdir(parents=True, exist_ok=True)
log_path.touch()
log(f'Emulation run log: Started at {datetime.datetime.now()}')
log(f'Args: {args}')
runner = EmuRunner(rom, platform, emulator, core, args)
runner.download_things_if_needed()
runner.toggle_max_performance()
#Disable netplay by default
set_elec_setting('netplay.client.ip', 'disable')
set_elec_setting('netplay.client.port', 'disable')
jslisten_stop()
shader_arg = runner.set_settings()
command = runner.get_command(shader_arg)
if log_level != 'minimal':
log(f'Took {perf_counter() - time_started} seconds to start up')
clear_screen()
try:
runner.run(command)
exit_code = 0
except subprocess.CalledProcessError as cpe:
log(f'Process exited improperly with return code {cpe.returncode}')
exit_code = 1
requires_bios = {'atari5200', 'atari800', 'atari7800', 'atarilynx', 'colecovision', 'amiga', 'amigacd32', 'o2em', 'intellivision', 'pcengine', 'pcenginecd', 'pcfx', 'fds', 'segacd', 'saturn', 'dreamcast', 'naomi', 'atomiswave', 'x68000', 'neogeo', 'neogeocd', 'msx', 'msx2', 'sc-3000'}
if platform in requires_bios:
if platform == 'msx2':
platform_to_check = 'msx2'
elif platform == 'pcenginecd':
platform_to_check = 'pcengine'
elif platform == 'amigacd32':
platform_to_check = 'amiga'
else:
platform_to_check = platform
check_bios(platform_to_check, core, emulator, rom, log_path)
finally:
runner.cleanup_temp_files()
cleanup_and_quit(exit_code)
if __name__ == '__main__':
main()

700
usr/bin/setsettings.py Executable file
View file

@ -0,0 +1,700 @@
#!/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)