Compare commits
377 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bfbbbdda7b | |||
| 67a885b43b | |||
| a49fe03fc2 | |||
| a7b07dc0f9 | |||
| f9a767f8ae | |||
| 42a4786a25 | |||
| b166eac200 | |||
| c06316f4aa | |||
| 09d96d9e4d | |||
| 66703970b6 | |||
| 0d3314a39b | |||
| 748492cc68 | |||
| e18ad31c53 | |||
| 0dd297f0f8 | |||
| 0da4becd46 | |||
| d284911d4a | |||
| e772eb3906 | |||
| 577ee4c3e0 | |||
| c534df8303 | |||
| a36c8f7de8 | |||
| dfb5f1b687 | |||
| d8eea015fd | |||
| f17b7eb2c9 | |||
| 33146626a9 | |||
| 78e12f774d | |||
| 689d8debb1 | |||
| 8be1ed8af5 | |||
| 0fabdb3f3a | |||
| 7a64e7e479 | |||
| 8c1589d7cd | |||
| 5a74b137f2 | |||
| 52ba182610 | |||
| b07eb79609 | |||
| 4e3915f527 | |||
| 9f620f276d | |||
| e3787b5ccf | |||
| 3d81a052c6 | |||
| 6353be1599 | |||
| bc6ee4877b | |||
| 6b38cc3740 | |||
| 9285fb9fdf | |||
| f5c609413a | |||
| a304f11b1d | |||
| e10ac1086f | |||
| 4533ed61ac | |||
| 235e41653d | |||
| 433479b1c3 | |||
| 2b4736f224 | |||
| 41f1dcf9d2 | |||
| 45b97cf39b | |||
| 95b1225219 | |||
| 70f6c40b26 | |||
| 43bc54fca9 | |||
| a5ec31ffef | |||
| 81cbf82ddc | |||
| 6cea506c6f | |||
| d7d49f261d | |||
| 4692a5c0b7 | |||
| d32ea32f1e | |||
| f5f053cc4e | |||
| bb3c6dc9fc | |||
| 496d4de1de | |||
| 71f8437ecb | |||
| e7767105d6 | |||
| 9cfda8514e | |||
| e0c6700a4d | |||
| 12bf158398 | |||
| ea01c86821 | |||
| 96459432a6 | |||
| 089194c663 | |||
| 7a70227535 | |||
| 7adfb3123b | |||
| 1d28075601 | |||
| af7aa688bb | |||
| beb524f523 | |||
| 18c9c151a8 | |||
| 83820baf79 | |||
| abf50350e7 | |||
| 6588d0d17a | |||
| 648736df48 | |||
| 6278a443df | |||
| 615295f1f9 | |||
| 593135d02b | |||
| 78ea41a2ca | |||
| 105600878e | |||
| 415202e15f | |||
| 618a6f6c9f | |||
| af70f35bf2 | |||
| 43bb0a3a1c | |||
| 8d9f83b1cc | |||
| 7d713afbdd | |||
| 5044ef8ab1 | |||
| 5b4fe5667a | |||
| a4d3efa087 | |||
| 9cb8adce55 | |||
| c061981de0 | |||
| b2f76fc436 | |||
| dc58fbe900 | |||
| 0e80142da1 | |||
| ee77bc7c9b | |||
| b978248c03 | |||
| 85d2b5be5a | |||
| cee35297d6 | |||
| edde08849f | |||
| f649053e00 | |||
| 6c6b4bcd3a | |||
| 1fef816572 | |||
| a6203cf6e9 | |||
| 200bb0f6e3 | |||
| 1dd2fca3db | |||
| 5444f3b807 | |||
| 897d81a188 | |||
| eae18c446a | |||
| fb7402e394 | |||
| 63dc9cbe7c | |||
| ac63f4809f | |||
| 0bdf3ada25 | |||
| aa684b903b | |||
| db0ae36702 | |||
| 3d5e812c6f | |||
| 07f6810835 | |||
| b3e2a43cf8 | |||
| 96f4abbc07 | |||
| d96746c933 | |||
| 4391ebd94a | |||
| 081029e3d1 | |||
| 541724b63c | |||
| 304afbb50d | |||
| 1ba88f48bb | |||
| 8f8c9c35f1 | |||
| 1c07d032ef | |||
| c500a17b1a | |||
| 6d0347b48a | |||
| 83af0ff4af | |||
| 32c13eee1d | |||
| 42597a76f0 | |||
| 7c59a520aa | |||
| 3c124d8519 | |||
| 76282a11da | |||
| 5249bf6a56 | |||
| 12e0dac777 | |||
| b4e3bede3b | |||
| 679731f004 | |||
| 3bbd29916b | |||
| 6516330289 | |||
| 0628ea920b | |||
| 40a4133565 | |||
| b4425fe1be | |||
| 809cbcbc21 | |||
| 2ae2b994a8 | |||
| 8ce36cdc03 | |||
| 3707a86c79 | |||
| eea3ec7f95 | |||
| 4a2c6761fc | |||
| 7a4e179f4c | |||
| 11eaadb739 | |||
| 41b77b54ea | |||
| 22689bd9ee | |||
| 831535c86f | |||
| ce43955784 | |||
| e85f4f4309 | |||
| 00b3f33530 | |||
| 1b0116a0cb | |||
| 486281427c | |||
| 8ccdc415bc | |||
| 008049265d | |||
| fef407b839 | |||
| 084570bc4b | |||
| 3d91e0c3e3 | |||
| b5a942b4fe | |||
| 5c5cc8453d | |||
| 30495795cd | |||
| 073cdd2815 | |||
| fe21c73f75 | |||
| a6cba2ce2a | |||
| 9afd971b43 | |||
| b0f9136fe8 | |||
| b513439565 | |||
| 42494e5019 | |||
| 8653234cb3 | |||
| 6a14761770 | |||
| 399a5c93b2 | |||
| be2db3c95a | |||
| 7f7ac4c5fb | |||
| 7ca98bb496 | |||
| e9cf27411b | |||
| d8f1a5a118 | |||
| 07ea2d8ec4 | |||
| 2c63963134 | |||
| c9d9e71631 | |||
| 69726baa48 | |||
| c02a44d020 | |||
| 1c0c3eb6aa | |||
| 7f9f30181e | |||
| 2bc788beea | |||
| 4a0d20c1a1 | |||
| 2ea9efd622 | |||
| 723f4ab16b | |||
| a242ae78eb | |||
| c037e1465f | |||
| 3e8578f2fd | |||
| 0050646ad7 | |||
| f2ef7e345f | |||
| 3c0698d14b | |||
| ec677c8d26 | |||
| f115c82512 | |||
| 9f4f8ab15b | |||
| 532d8bcaee | |||
| 2978b8443c | |||
| 3b1fbcd9d3 | |||
| de4d4c27c7 | |||
| 91bf6ad996 | |||
| 312885bec1 | |||
| 8641e1b3ba | |||
| ca203d96b0 | |||
| 6774c8731a | |||
| b603f3b75c | |||
| b546826b67 | |||
| a39263aeb5 | |||
| ecaa5b9dee | |||
| 7fcc468353 | |||
| 52952942e9 | |||
| 81dc449637 | |||
| ce25524ed9 | |||
| 30a3522def | |||
| f62de70aa5 | |||
| ec190adc51 | |||
| 7095824874 | |||
| b243f48fff | |||
| 3bc052e948 | |||
| 482e237d08 | |||
| 86f38ab024 | |||
| c837d736bb | |||
| ab94fd484f | |||
| 1508b11044 | |||
| b4e18d1b63 | |||
| f49272288d | |||
| f1dd82c65e | |||
| 7aa7eaffb9 | |||
| 6577fa9810 | |||
| 6aabc4eca8 | |||
| bf5b3d3c99 | |||
| 420eb39c16 | |||
| 6dd764c04c | |||
| 95d5141a2b | |||
| 51c6c3904d | |||
| 32a39afc75 | |||
| fd967cc2a3 | |||
| 8c0bb09667 | |||
| 8c753d6cfe | |||
| 276e681f29 | |||
| f23b17e1b8 | |||
| f1e10fa4b1 | |||
| be67cd03cb | |||
| d7dfe12fb4 | |||
| be437afd2f | |||
| f72688773a | |||
| fb328d8d92 | |||
| 36e6d2fcc7 | |||
| 7b3293341b | |||
| 0a7b72a51b | |||
| 6265973cc6 | |||
| f1edc47a80 | |||
| 8f60d5c80f | |||
| c42489fa81 | |||
| 66b60c988a | |||
| 5d20e98aba | |||
| 617ee3f96c | |||
| 083f7c2e4f | |||
| a8ea1795bf | |||
| 8a6cb4b5a8 | |||
| 53edf065a5 | |||
| bf65be483d | |||
| 1e90047368 | |||
| abd1160f87 | |||
| 55d7dd9d89 | |||
| b7eb1afb86 | |||
| 25ddb4a531 | |||
| 79f7c2224b | |||
| 8adda4fc7d | |||
| 5d23743133 | |||
| 2558e5d6a6 | |||
| 859b81b7e0 | |||
| 30369f58a9 | |||
| 30afc80a64 | |||
| 949eee8d08 | |||
| 1fae30bd33 | |||
| d8817bf0f3 | |||
| 5279b10b67 | |||
| 391f46be22 | |||
| 44809bf28f | |||
| 3cd113c46f | |||
| 3d195c6a4d | |||
| 423d30ac29 | |||
| b07b73e005 | |||
| 418d9c4684 | |||
| 1801a48eaa | |||
| 8e8fbcdd2e | |||
| d5834de5e7 | |||
| a52e3fe1e5 | |||
| eb261bc2bf | |||
| 7b5f735714 | |||
| 404c2c4f43 | |||
| 57f1a33e51 | |||
| fa277352b0 | |||
| f502984e05 | |||
| c205b5bfd3 | |||
| c6625e137d | |||
| 0ad7e1d715 | |||
| 1f8d5be9a7 | |||
| 21673affbb | |||
| a0a1255ef3 | |||
| 206a5ec7f6 | |||
| 8661273568 | |||
| 6aed340831 | |||
| f7bfb6aea1 | |||
| c5ae117cf8 | |||
| a1c9dc3f12 | |||
| 0f3e70706d | |||
| 722ca67b87 | |||
| 981897df8c | |||
| 3a066dfc03 | |||
| 870481e34e | |||
| 9f5f2334d7 | |||
| 330a66c81c | |||
| 92b4d4dc32 | |||
| 531fab51be | |||
| 3f027fad63 | |||
| 6eb46dd63c | |||
| 70830ae016 | |||
| 8a88a736ad | |||
| d580d2be9a | |||
| 0e3fc0e981 | |||
| 4907b2dd32 | |||
| 3ad2a5760e | |||
| e474a09642 | |||
| f5296c9f79 | |||
| f8e1ed3920 | |||
| 9aeca88946 | |||
| 3961c066be | |||
| 4aeb3da6eb | |||
| bf9e370ddd | |||
| 7c72fa98fd | |||
| 0824586db9 | |||
| 8a22c6d929 | |||
| 8f76619d7d | |||
| d94d9fc5d7 | |||
| 38312f8add | |||
| d52b1e1b5a | |||
| 06c9d9b826 | |||
| 20a669dbbb | |||
| 68c8c431a2 | |||
| d6b1fdfa7b | |||
| 6ac9208c7f | |||
| fdcfaf3fad | |||
| dd08dfafc8 | |||
| 22a019abb1 | |||
| e112ae75eb | |||
| 0de1073094 | |||
| 18a1a6afe6 | |||
| 149bd86a89 | |||
| dbe67853dc | |||
| 4f30be19b1 | |||
| 0347033d89 | |||
| 5fc36d5743 | |||
| c745ec18bb | |||
| 0e84317fbc | |||
| b7df075dec | |||
| da3e30f735 | |||
| 9bd0ea0ba6 | |||
| 91df63c660 | |||
| bea8abd60d | |||
| 86bb226db4 | |||
| 5bbdc7f821 | |||
| f23b0ca493 | |||
| 538b503bcb | |||
| cabc56550b |
@@ -4,27 +4,43 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
Linux:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: hendrikmuhs/ccache-action@v1.2.5
|
||||
with:
|
||||
key: Linux
|
||||
- name: Install Packages
|
||||
run: |
|
||||
sudo apt-get purge grub\* --yes --allow-remove-essential
|
||||
sudo add-apt-repository ppa:okirby/qt6-backports --yes
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get upgrade
|
||||
sudo apt-get -y install cmake libhidapi-dev libsamplerate0-dev libspeex-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qtbase5-dev libqt5svg5-dev build-essential nasm git zip
|
||||
sudo apt-get -y install cmake ninja-build libusb-1.0-0-dev libhidapi-dev libsamplerate0-dev libspeex-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qt6-base-dev libqt6svg6-dev build-essential nasm git zip appstream
|
||||
- name: Prepare Environment
|
||||
run: |
|
||||
echo "GIT_REVISION=$(git describe --tags --always)" >> $GITHUB_ENV
|
||||
- name: Build RMG (Portable)
|
||||
run: ./Source/Script/Build.sh Release
|
||||
- name: Build RMG (AppImage)
|
||||
run: |
|
||||
mkdir Build Build/AppImage Bin/ -p
|
||||
export src_dir="$(pwd)"
|
||||
export build_dir="$(pwd)/build"
|
||||
export bin_dir="$(pwd)/Bin/AppImage"
|
||||
cmake -S "$src_dir" -B "$build_dir" -DCMAKE_BUILD_TYPE="Release" -DPORTABLE_INSTALL="OFF" -DUPDATER=ON -DAPPIMAGE_UPDATER=ON -DCMAKE_INSTALL_PREFIX="/usr" -G "Ninja"
|
||||
cmake --build "$build_dir"
|
||||
cmake --install "$build_dir" --prefix="$bin_dir/usr"
|
||||
shell: bash
|
||||
- name: Upload RMG (Portable)
|
||||
- name: Create AppImage
|
||||
run: |
|
||||
./Package/AppImage/Create.sh
|
||||
shell: bash
|
||||
- name: Upload RMG (AppImage)
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: RMG-Portable-Linux64-${{ env.GIT_REVISION }}
|
||||
path: Bin/Release/*
|
||||
path: Bin/*.AppImage
|
||||
|
||||
Windows:
|
||||
runs-on: windows-2019
|
||||
@@ -32,6 +48,9 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: hendrikmuhs/ccache-action@v1.2.5
|
||||
with:
|
||||
key: Windows
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
path-type: inherit
|
||||
@@ -39,20 +58,20 @@ jobs:
|
||||
install: >-
|
||||
make
|
||||
mingw-w64-x86_64-cmake
|
||||
mingw-w64-x86_64-ninja
|
||||
mingw-w64-x86_64-gcc
|
||||
mingw-w64-x86_64-hidapi
|
||||
mingw-w64-x86_64-freetype
|
||||
mingw-w64-x86_64-libpng
|
||||
mingw-w64-x86_64-SDL2
|
||||
mingw-w64-x86_64-jasper
|
||||
mingw-w64-x86_64-qt5
|
||||
mingw-w64-x86_64-qt6
|
||||
mingw-w64-x86_64-SDL2
|
||||
mingw-w64-x86_64-libusb
|
||||
mingw-w64-x86_64-hidapi
|
||||
mingw-w64-x86_64-speexdsp
|
||||
mingw-w64-x86_64-libsamplerate
|
||||
mingw-w64-x86_64-python3-pip
|
||||
mingw-w64-x86_64-python3-pyopenssl
|
||||
mingw-w64-x86_64-nasm
|
||||
mingw-w64-x86_64-minizip
|
||||
git
|
||||
- name: Prepare Environment
|
||||
run: |
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
# CMake build directory
|
||||
Build/
|
||||
Bin/
|
||||
# VSCode Configuration
|
||||
.vscode/
|
||||
# Clangd cache
|
||||
.cache/
|
||||
.cache/
|
||||
# Archlinux Package
|
||||
Package/ArchLinux/pkg/
|
||||
Package/ArchLinux/rmg/
|
||||
Package/ArchLinux/src/
|
||||
Package/ArchLinux/*.pkg.*
|
||||
# Clangd compile_commands.json
|
||||
compile_commands.json
|
||||
# AppImage
|
||||
squashfs-root
|
||||
*.AppImage
|
||||
@@ -5,6 +5,11 @@ cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
option(PORTABLE_INSTALL "Portable Installation" ON)
|
||||
option(NO_GIT_CLONE "Disables git clone usage for 3rdParty dependencies" OFF)
|
||||
option(UPDATER "Enables updater" ${PORTABLE_INSTALL})
|
||||
option(APPIMAGE_UPDATER "Enables AppImage updater" OFF)
|
||||
option(DISCORD_RPC "Enables Discord Rich Presence" ON)
|
||||
option(USE_CCACHE "Enables usage of ccache when ccache has been found" ON)
|
||||
option(FORCE_XCB "Forces Qt to use the xcb platform on linux" ${LINUX})
|
||||
|
||||
project(RMG)
|
||||
|
||||
@@ -17,11 +22,40 @@ execute_process(
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
if (USE_CCACHE)
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if (CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
else(CCACHE_FOUND)
|
||||
set(USE_CCACHE OFF)
|
||||
endif(CCACHE_FOUND)
|
||||
endif(USE_CCACHE)
|
||||
|
||||
if (NOT PORTABLE_INSTALL AND (WIN32 OR MSYS))
|
||||
message(WARNING "Not-Portable build not supported on windows, re-enabling PORTABLE_INSTALL!")
|
||||
set(PORTABLE_INSTALL ON)
|
||||
endif()
|
||||
|
||||
if (NOT PORTABLE_INSTALL AND UPDATER AND NOT APPIMAGE_UPDATER)
|
||||
message(WARNING "Not-Portable builds don't support the updater, disabling UPDATER")
|
||||
set(UPDATER OFF)
|
||||
endif()
|
||||
|
||||
if (APPIMAGE_UPDATER AND (WIN32 OR MSYS))
|
||||
message(WARNING "AppImage updater not supported on windows, disabling APPIMAGE_UPDATER!")
|
||||
set(APPIMAGE_UPDATER OFF)
|
||||
endif()
|
||||
|
||||
if (UPDATER AND NOT (WIN32 OR MSYS) AND NOT APPIMAGE_UPDATER)
|
||||
message(WARNING "Only AppImage updater is supported on linux, disabling UPDATER!")
|
||||
set(UPDATER OFF)
|
||||
endif()
|
||||
|
||||
if (FORCE_XCB AND (WIN32 OR MSYS))
|
||||
message(WARNING "XCB Qt platform not supported on windows, disabling FORCE_XCB!")
|
||||
set(FORCE_XCB OFF)
|
||||
endif()
|
||||
|
||||
if (PORTABLE_INSTALL)
|
||||
set(CMAKE_INSTALL_PREFIX "")
|
||||
set(INSTALL_PATH "Bin/${CMAKE_BUILD_TYPE}")
|
||||
@@ -41,6 +75,9 @@ else()
|
||||
set(ICON_INSTALL_PATH "share/icons/hicolor/scalable/apps/")
|
||||
endif()
|
||||
|
||||
add_subdirectory(Source/3rdParty)
|
||||
add_subdirectory(Source/3rdParty/7-Zip)
|
||||
|
||||
add_subdirectory(Source/RMG-Core)
|
||||
add_subdirectory(Source/RMG)
|
||||
add_subdirectory(Source/RMG-Audio)
|
||||
@@ -59,15 +96,17 @@ if (WIN32)
|
||||
add_subdirectory(Source/Installer)
|
||||
|
||||
add_custom_target(bundle_dependencies
|
||||
COMMAND "${CMAKE_SOURCE_DIR}/Source/Script/BundleDependencies.sh" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}/RMG.exe" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}/" "/mingw64/bin"
|
||||
COMMAND bash "${CMAKE_SOURCE_DIR}/Source/Script/BundleDependencies.sh" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}/RMG.exe" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}" "/mingw64/bin"
|
||||
)
|
||||
endif()
|
||||
endif(WIN32)
|
||||
|
||||
add_subdirectory(Source/3rdParty)
|
||||
install(FILES ${MUPEN64PLUSCORE_LIB}
|
||||
DESTINATION ${CORE_INSTALL_PATH}
|
||||
)
|
||||
install(FILES ${MUPEN64PLUSCORE_INI} Data/font.ttf Data/stylesheet.qss
|
||||
install(FILES ${MUPEN64PLUSCORE_INI} Data/font.ttf
|
||||
DESTINATION ${DATA_INSTALL_PATH}
|
||||
)
|
||||
install(FILES ${SDL_GAMECONTROLLERDB}
|
||||
DESTINATION ${DATA_INSTALL_PATH}
|
||||
)
|
||||
file(GLOB GENERATED_CHEAT_FILES ${CMAKE_SOURCE_DIR}/Data/Cheats/Generated/*.cht)
|
||||
@@ -87,7 +126,7 @@ install(FILES ${MUPEN64PLUS_PLUGIN_RSP_PARALLEL}
|
||||
install(FILES ${MUPEN64PLUS_PLUGIN_INPUT_RAPHNET}
|
||||
DESTINATION ${PLUGIN_INSTALL_PATH}/Input
|
||||
)
|
||||
install(FILES ${MUPEN64PLUS_PLUGIN_INPUT_GCA}
|
||||
install(FILES ${MUPEN64PLUS_PLUGIN_INPUT_GCN}
|
||||
DESTINATION ${PLUGIN_INSTALL_PATH}/Input
|
||||
)
|
||||
install(FILES ${MUPEN64PLUS_PLUGIN_GFX_ANGRYLION}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
[0CA6AEDA-BB9CFDD9-C:45]
|
||||
Name=Carnivale - Cenzo's Adventure (USA) (Prototype)
|
||||
|
||||
$Infinite Max Silver & Gold Coins
|
||||
Note=This seems to act as Health?
|
||||
810A2E7E 001E
|
||||
810A2E80 001E
|
||||
810A2E82 001E
|
||||
|
||||
$Infinite Max Peas
|
||||
Note=Max Pea Shooter Ammo
|
||||
810A2E7A 001E
|
||||
|
||||
$Unlock Everything
|
||||
Note=This Unlocks All Items in Single & All Multi Player Characters and Tracks.(Thanks Retroben!)
|
||||
810A2E90 0003
|
||||
810A2E92 87F9
|
||||
810A2E94 87F9
|
||||
|
||||
$Press L for Warp Select (Single Mode)
|
||||
Note=Press the L-Button as you go through a door (Thanks SubDrag!)
|
||||
D00A3359 0020
|
||||
800CA85B 00??
|
||||
01 Blue Background Race
|
||||
02 Dark Mountains Race
|
||||
03 Purple/Yellow Mountains Race
|
||||
04 Cloud Floor Race (from the locked main area)
|
||||
05 Main Area
|
||||
06 Maze
|
||||
07 King Race Super Rat Ride
|
||||
08 Mallet Game
|
||||
09 Duck Game
|
||||
0A Puppet Show (Come back later)
|
||||
0B Rock Paper Scissors Game
|
||||
0C Create Password
|
||||
0D Main Menu
|
||||
0E Select New Game
|
||||
0F Boss Intro Guy with hammer
|
||||
10 Options Menu
|
||||
11 Boss Intro Meet Strongman
|
||||
12 Main Menu
|
||||
|
||||
$Max Strength in Mallet Game
|
||||
811B08A6 0162
|
||||
|
||||
$Perfect Aim In Mallet Game (Line up and Shoot)
|
||||
Note=Use with Max Strength in Mallet Game. Wait until the Eyeball is past the 2 Red Lines (centre) and then press A
|
||||
811B0BD4 FFF2
|
||||
811B0B28 FDD2
|
||||
811605C8 FDD2
|
||||
81153148 FDD2
|
||||
|
||||
$1 Lap to Race (All Characters & Races)
|
||||
Note=For Single and Multi Player Modes. This will display 1 of 3, but on the first checkpoint you will get the message "You win" 1 Lap to race will also make you come in 1st and win. a big thanks to Parasyte for working with me on this! You are "Magic" lol
|
||||
81060020 2400
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
[1FBAF161-2C1C54F1-C:41]
|
||||
Name=1080 Snowboarding (JU) (M2)
|
||||
|
||||
$Enable All Levels & Boarders
|
||||
80255089 00FF
|
||||
8025508B 0005
|
||||
81255096 FCFF
|
||||
80255098 0007
|
||||
|
||||
$Have All\Contest First Place Done
|
||||
80244098 0007
|
||||
|
||||
$Have All\Match Levels Completed
|
||||
8025508A 0005
|
||||
|
||||
$Have All\Trick Attacks Done
|
||||
81255096 FCFF
|
||||
|
||||
$Infinite Damage All Players & Levels
|
||||
803F4C3C 0024
|
||||
807F4C3C 0024
|
||||
|
||||
$Infinite Lives & Continues
|
||||
8026B1CB 0003
|
||||
|
||||
$Always First Place (Player 1)
|
||||
81267B88 2400
|
||||
Note=The game will still show you in 2nd when you are behind. But when you cross the finish line, you will win!
|
||||
|
||||
$Open Level Character Select
|
||||
Note=With these codes, you have to press the buttons listed below when you are viewing a certain boarders stats. Highlight Akari Hayami's stats, and then hold down the C-Left button and then press the A button to be the Crystal Boarder. Highlight Kensuke Kimachi's stats, and then hold down the C-Up button and then press the A button to be the Metal Boarder. Hightlight Rob Haywood's stats, and then hold down the C-Right button and then press the A button to be the Panda Boarder
|
||||
8125508A 00??
|
||||
01 Easy Level
|
||||
02 Easy & Normal Level
|
||||
03 Easy Normal & Hard Levels
|
||||
04 Easy Normal Hard Levels & Crystal Boarder
|
||||
05 Easy Normal Hard Levels & Crystal & Metal Boarders
|
||||
|
||||
$Play As
|
||||
800200E7 00??
|
||||
00 Dion Blaster
|
||||
01 Kensuke Kimachi
|
||||
02 Akari Hayami
|
||||
03 Ricky Winterborn
|
||||
04 Rob Haywood
|
||||
05 Silver Boarder
|
||||
06 Gold Boarder
|
||||
07 Panda Boarder
|
||||
|
||||
$Freeze Timer In\Match Race
|
||||
D1267B20 05E1
|
||||
81267B20 1000
|
||||
|
||||
$Freeze Timer In\Time Attack
|
||||
D12660CC 05E1
|
||||
812660CC 1000
|
||||
|
||||
$Freeze Timer In\Trick Attack
|
||||
D1266138 05E1
|
||||
81266138 1000
|
||||
|
||||
$Freeze Timer In\Contest
|
||||
D126628C 05E1
|
||||
8126628C 1000
|
||||
@@ -0,0 +1,55 @@
|
||||
[58FD3F25-D92EAA8D-C:50]
|
||||
Name=1080 Snowboarding (E) (M4)
|
||||
|
||||
$Enable All Levels & Boarders
|
||||
80250AB9 00FF
|
||||
80250ABB 0005
|
||||
81250AC6 FCFF
|
||||
80250AC8 0007
|
||||
|
||||
$Infinite Damage All Players and Levels
|
||||
803F4C00 0024
|
||||
807F4C00 0024
|
||||
|
||||
$Infinite Lives & Continues
|
||||
802648A4 0003
|
||||
|
||||
$Open Level Character Select
|
||||
Note=With these codes, you have to press the buttons listed below when you are viewing a certain boarders stats. Highlight Akari Hayami's stats, and then hold down the C-Left button and then press the A button to be the Crystal Boarder. Highlight Kensuke Kimachi's stats, and then hold down the C-Up button and then press the A button to be the Metal Boarder. Hightlight Rob Haywood's stats, and then hold down the C-Right button and then press the A button to be the Panda Boarder
|
||||
8125508A 00??
|
||||
01 Easy Level
|
||||
02 Easy & Normal Level
|
||||
03 Easy Normal & Hard Levels
|
||||
04 Easy Normal Hard Levels & Crystal Boarder
|
||||
05 Easy Normal Hard Levels & Crystal & Metal Boarders
|
||||
|
||||
$Play As
|
||||
8001A0E7 00??
|
||||
00 Dion Blaster
|
||||
01 Kensuke Kimachi
|
||||
02 Akari Hayami
|
||||
03 Ricky Winterborn
|
||||
04 Rob Haywood
|
||||
05 Silver Boarder
|
||||
06 Gold Boarder
|
||||
07 Panda Boarder
|
||||
|
||||
$Always First Place (Player 1)
|
||||
812679BC 2400
|
||||
Note=The game will still show you in 2nd when you are behind. But when you cross the finish line, you will win!
|
||||
|
||||
$Freeze Timer In\Match Race
|
||||
D1267954 05E1
|
||||
81267954 1000
|
||||
|
||||
$Freeze Timer In\Time Attack
|
||||
D1265D4C 05E1
|
||||
81265D4C 1000
|
||||
|
||||
$Freeze Timer In\Trick Attack
|
||||
D1265DB8 05E1
|
||||
81265DB8 1000
|
||||
|
||||
$Freeze Timer In\Contest
|
||||
D1265F48 05E1
|
||||
81265F48 1000
|
||||
@@ -0,0 +1,33 @@
|
||||
[7BD65F9E-76B6A083-C:45]
|
||||
Name=007 - The World is Not Enough (U) (Prototype - 2020 release)
|
||||
|
||||
$Enable Cheats Menu
|
||||
800811F0 0005
|
||||
|
||||
$Invincible
|
||||
80130ACD 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$All Weapons
|
||||
80130AE0 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$All Gadgets
|
||||
80130AE1 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$All Missions
|
||||
80130AE2 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$Infinite Health (All Levels)
|
||||
81045D68 2400
|
||||
|
||||
$Infinite Ammo (All Guns for all Levels)
|
||||
Note=The Clip will count down but you will never run out of Ammo.
|
||||
81040730 2400
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
[8825E18B-3297746B-C:50]
|
||||
Name=Aidyn Chronicles - The First Mage (Europe) (Prototype) (2)
|
||||
|
||||
$Infinite\Max Health
|
||||
80279308 001E
|
||||
|
||||
$Infinite\99 Health Potions
|
||||
Note=Do Not put this cheat on until you have collected your 1st Health Potion from the 1st Cheat or you will not be able to get into the Sub menu and Continue the game.
|
||||
80278D3B 0063
|
||||
|
||||
$Have\Max Gold
|
||||
50000401 0000
|
||||
80277AA5 00FF
|
||||
|
||||
$Have\Max Total XP
|
||||
50000401 0000
|
||||
8027931D 00FF
|
||||
|
||||
$Have\Max Total XP Remaning to Start
|
||||
Note=This will give you 16777215 Total XP Remaning to start with and after your 1st batle will allow you to buy your Max Stats
|
||||
50000401 0000
|
||||
80279321 00FF
|
||||
|
||||
$Play As Character
|
||||
Note=Enable this at the start of a Game, before a next Level, or before a Cutscene to become your chosen option.
|
||||
810E108E ????
|
||||
25F9 Alaron
|
||||
2A43 Marari Female
|
||||
2C17 Spirit
|
||||
2CC0 Marari Male
|
||||
2D4A GiantBat
|
||||
2E82 Chaos Trooper
|
||||
3094 Gryphon
|
||||
324D Ogre
|
||||
32CC GiantRat
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
[8EAA1A2C-61C09930-C:00]
|
||||
Name=Aidyn Chronicles - The First Mage (USA) (Prototype)
|
||||
|
||||
$Infinite\Max Health
|
||||
80275AA1 001E
|
||||
|
||||
$Infinite\99 Health Potions
|
||||
Note=Do Not put this cheat on until you have collected your 1st Health Potion from the 1st Cheat or you will not be able to get into the Sub menu and Continue the game.
|
||||
8027540F 0063
|
||||
|
||||
$Have\Max Gold
|
||||
50000401 0000
|
||||
8027423E 00FF
|
||||
|
||||
$Have\Max Total XP
|
||||
50000401 0000
|
||||
80275AB6 00FF
|
||||
|
||||
$Have\Max Total XP Remaning to Start
|
||||
Note=This will give you 16777215 Total XP Remaning to start with and after your 1st batle will allow you to buy your Max Stats
|
||||
50000401 0000
|
||||
80275ABA 00FF
|
||||
|
||||
$Play As Character
|
||||
Note=Enable this at the start of a Game, before a next Level, or before a Cutscene to become your chosen option.
|
||||
810E0D6E ????
|
||||
25F9 Alaron
|
||||
2A43 Marari Female
|
||||
2C17 Spirit
|
||||
2CC0 Marari Male
|
||||
2D4A GiantBat
|
||||
2E82 Chaos Trooper
|
||||
3094 Gryphon
|
||||
324D Ogre
|
||||
32CC GiantRat
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
[A92E0966-341C3912-C:45]
|
||||
Name=007 - The World is Not Enough (U) (Beta) [!]
|
||||
|
||||
$Invincible
|
||||
8011E157 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$Have All Gadgets
|
||||
8011E159 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$Enable All Missions
|
||||
8011E15A 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$Have All Weapons
|
||||
8011E158 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$Infinite Health (All Levels)
|
||||
8106AC88 2400
|
||||
|
||||
$Infinite Ammo (All Guns for all Levels)
|
||||
8106246C 2400
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
[D0E29F11-E029063F-C:50]
|
||||
Name=Aidyn Chronicles - The First Mage (Europe) (Prototype) (1)
|
||||
|
||||
$Infinite\Max Health
|
||||
80279208 001E
|
||||
|
||||
$Infinite\99 Health Potions
|
||||
Note=Do Not put this cheat on until you have collected your 1st Health Potion from the 1st Cheat or you will not be able to get into the Sub menu and Continue the game.
|
||||
80278C3B 0063
|
||||
|
||||
$Have\Max Gold
|
||||
50000401 0000
|
||||
802779A5 00FF
|
||||
|
||||
$Have\Max Total XP
|
||||
50000401 0000
|
||||
8027921D 00FF
|
||||
|
||||
$Have\Max Total XP Remaning to Start
|
||||
Note=This will give you 16777215 Total XP Remaning to start with and after your 1st batle will allow you to buy your Max Stats
|
||||
50000401 0000
|
||||
80279221 00FF
|
||||
|
||||
$Play As Character
|
||||
Note=Enable this at the start of a Game, before a next Level, or before a Cutscene to become your chosen option.
|
||||
810E0F9E ????
|
||||
25F9 Alaron
|
||||
2A43 Marari Female
|
||||
2C17 Spirit
|
||||
2CC0 Marari Male
|
||||
2D4A GiantBat
|
||||
2E82 Chaos Trooper
|
||||
3094 Gryphon
|
||||
324D Ogre
|
||||
32CC GiantRat
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
[E48E01F5-E6E51F9B-C:59]
|
||||
Name=Carmageddon 64 (E) (M4) (Eng-Spa-Fre-Ita) [!]
|
||||
|
||||
$Have Everything Unlocked
|
||||
Note=This will unlock Cars, Races, Missions and the in-built Cheat Menu. This will also replace all the Zombies with Dinosaurs. To access Cheat menu options: Pause Game: Use Control Stick, to scroll the Cheat Menu. Press A, to activate Cheats
|
||||
801BE43D 000F
|
||||
|
||||
$Have Infinite\Invunerability
|
||||
81097EAC ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Free Repairs
|
||||
81097EC4 ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Underwater Ability
|
||||
81097EF4 ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Turbo
|
||||
81097E34 ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Mega Turbo
|
||||
81097E4C ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Hot Rod
|
||||
81097E64 ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Turbo Nitrous
|
||||
81097E7C ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Frozen Opponents
|
||||
81097F24 ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Grip-O-Matic Tires
|
||||
8109805C ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Mine Dropping Ability
|
||||
81098118 ????
|
||||
0064 On
|
||||
0000 Off
|
||||
|
||||
$Freeze Timer at 04:59
|
||||
Note=Do not enable until count down to race is finished
|
||||
811BE21E 3A70
|
||||
|
||||
$Max Credits
|
||||
Note=This is also Infinite until disabled
|
||||
811BE29A FFFF
|
||||
|
||||
$Max Kills
|
||||
Note=This will automatically Clear the stage if enabled and go back to the stage menu
|
||||
81094BEE 01F4
|
||||
|
||||
$Have All Groups Completed
|
||||
Note=This gives you all Cups for all Groups.
|
||||
50002801 0000
|
||||
801BE35C 0002
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
[F1642508-BEE60CF6-C:45]
|
||||
Name=Bust-A-Move 3 DX (USA) (Prototype)
|
||||
|
||||
$Always Have\guide line on
|
||||
800558CC 0082
|
||||
|
||||
$Pointer always active
|
||||
D0055BA0 0002
|
||||
80055BA0 0082
|
||||
|
||||
$Play As Select\Player 1
|
||||
800E1E50 00??
|
||||
00 Bubbloon
|
||||
01 Twinkie
|
||||
02 Prettio
|
||||
03 Marina
|
||||
04 Musashi
|
||||
05 Luna
|
||||
06 Jack
|
||||
07 SSB
|
||||
08 Dragoon
|
||||
09 Gnome
|
||||
10 Monkey
|
||||
11 furby? (looks like 2 balloons)
|
||||
12 Blue Gnome
|
||||
13 1 of the two Ballons
|
||||
14 Water under ballons
|
||||
|
||||
$Play As Select\Player 2
|
||||
800E1E58 00??
|
||||
00 Bubbloon
|
||||
01 Twinkie
|
||||
02 Prettio
|
||||
03 Marina
|
||||
04 Musashi
|
||||
05 Luna
|
||||
06 Jack
|
||||
07 SSB
|
||||
08 Dragoon
|
||||
09 Gnome
|
||||
10 Monkey
|
||||
11 furby? (looks like 2 balloons)
|
||||
12 Blue Gnome
|
||||
13 1 of the two Ballons
|
||||
14 Water under ballons
|
||||
|
||||
$Next Bubble Select\Player 1
|
||||
800EBA19 00??
|
||||
00 No Bubble
|
||||
01 Red
|
||||
02 Green
|
||||
03 Blue
|
||||
04 Yellow
|
||||
05 Orange
|
||||
06 Purple
|
||||
07 White
|
||||
08 Black
|
||||
|
||||
$Next Bubble Select\Player 2
|
||||
800EBB09 00??
|
||||
00 No Bubble
|
||||
01 Red
|
||||
02 Green
|
||||
03 Blue
|
||||
04 Yellow
|
||||
05 Orange
|
||||
06 Purple
|
||||
07 White
|
||||
08 Black
|
||||
|
||||
$Press GS Button to Reset Player 2 score to 0
|
||||
8809C5C0 0000
|
||||
8809C5C2 0000
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
[F7AA4F819F41CB4236792A8145684627]
|
||||
Name=Yoshi's Story (CHN) (iQue)
|
||||
|
||||
$Infinite\Health
|
||||
Note=This is for All Yoshis All levels
|
||||
50000804 0000
|
||||
8012FD1F 00??
|
||||
08 Infinite Health
|
||||
09 Infinite Max Health
|
||||
|
||||
$Infinite\Eggs (Once You Get One)
|
||||
Note=This is for All Yoshis All levels
|
||||
8103E52C 2400
|
||||
|
||||
$Infinite\Lives
|
||||
Note=This is for All Yoshis All levels
|
||||
8012FD5F 00FF
|
||||
|
||||
$Press GS Button To Have All Fruit
|
||||
8812F93B 001E
|
||||
|
||||
$Enable All Levels (Trial Mode)
|
||||
8112FDC4 FFFF
|
||||
8112FDC6 FFFF
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
cur_dir="$(readlink -f "$(dirname "$0")")"
|
||||
|
||||
exec "$cur_dir/usr/bin/RMG" \
|
||||
--core-path="$cur_dir/usr/lib/RMG/Core" \
|
||||
--plugin-path="$cur_dir/usr/lib/RMG/Plugin" \
|
||||
--shared-data-path="$cur_dir/usr/share/RMG" \
|
||||
"$@"
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
script_dir="$(dirname "$0")"
|
||||
toplvl_dir="$(realpath "$script_dir/../../")"
|
||||
bin_dir="$toplvl_dir/Bin/AppImage" # RMG should be installed here
|
||||
|
||||
export QMAKE="$(which qmake6)"
|
||||
export EXTRA_QT_PLUGINS="imageformats;iconengines;"
|
||||
export VERSION="$(git describe --tags --always)"
|
||||
export OUTPUT="$bin_dir/../RMG-Portable-Linux64-$VERSION.AppImage"
|
||||
|
||||
if [ ! -f "$script_dir/linuxdeploy-x86_64.AppImage" ]
|
||||
then
|
||||
curl -L https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage \
|
||||
-o "$script_dir/linuxdeploy-x86_64.AppImage"
|
||||
chmod +x "$script_dir/linuxdeploy-x86_64.AppImage"
|
||||
fi
|
||||
|
||||
if [ ! -f "$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage" ]
|
||||
then
|
||||
curl -L https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage \
|
||||
-o "$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage"
|
||||
chmod +x "$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage"
|
||||
fi
|
||||
|
||||
"$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage" --appimage-extract
|
||||
"$script_dir/linuxdeploy-x86_64.AppImage" --appimage-extract
|
||||
|
||||
# delete appimages
|
||||
rm "$script_dir/linuxdeploy-x86_64.AppImage" \
|
||||
"$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage"
|
||||
|
||||
"$(pwd)/squashfs-root/AppRun" \
|
||||
--plugin=qt \
|
||||
--appdir="$bin_dir" \
|
||||
--custom-apprun="$script_dir/AppRun" \
|
||||
--output=appimage \
|
||||
--desktop-file="$bin_dir/usr/share/applications/com.github.Rosalie241.RMG.desktop"
|
||||
@@ -1,51 +1,36 @@
|
||||
# Maintainer: Rosalie Wanders <rosalie@mailbox.org>
|
||||
_pkgname=rmg
|
||||
pkgname=${_pkgname}-git
|
||||
pkgver=git
|
||||
pkgname=rmg
|
||||
pkgver=0.3.9
|
||||
pkgrel=1
|
||||
pkgdesc="Rosalie's Mupen GUI"
|
||||
arch=('x86_64')
|
||||
url="https://github.com/Rosalie241/${_pkgname}"
|
||||
license=('GPLv3')
|
||||
url="https://github.com/Rosalie241/$pkgname"
|
||||
license=('GPL3')
|
||||
|
||||
provides=("$_pkgname")
|
||||
conflicts=("$_pkgname")
|
||||
depends=("hidapi" "libsamplerate" "speexdsp" "minizip" "sdl2" "zlib" "freetype2" "qt6-base" "qt6-svg" "xdg-user-dirs")
|
||||
makedepends=("git" "nasm" "cmake" "ninja")
|
||||
|
||||
depends=("hidapi" "libsamplerate" "minizip" "sdl2" "zlib" "freetype2" "qt5-base" "qt5-svg")
|
||||
makedepends=("git" "pkg-config" "nasm" "cmake" "rustup")
|
||||
|
||||
source=("git+https://github.com/Rosalie241/${_pkgname}.git")
|
||||
source=("git+https://github.com/Rosalie241/$pkgname.git#tag=v$pkgver")
|
||||
sha256sums=('SKIP')
|
||||
|
||||
pkgver()
|
||||
{
|
||||
cd "$_pkgname"
|
||||
|
||||
git describe --tags --always | sed -e 's|^v||;s|-|.|g'
|
||||
}
|
||||
|
||||
prepare()
|
||||
{
|
||||
cd "$srcdir/${_pkgname}"
|
||||
|
||||
mkdir -p build
|
||||
mkdir -p "$srcdir/$pkgname/build"
|
||||
}
|
||||
|
||||
build()
|
||||
{
|
||||
cd "$srcdir/${_pkgname}/build"
|
||||
|
||||
cmake -S "$srcdir/${_pkgname}" -B "$srcdir/${_pkgname}/build" \
|
||||
cmake -S "$srcdir/$pkgname" -B "$srcdir/$pkgname/build" \
|
||||
-DCMAKE_BUILD_TYPE="Release" \
|
||||
-DPORTABLE_INSTALL="OFF" \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-G "Unix Makefiles"
|
||||
make
|
||||
-DNO_RUST="ON" \
|
||||
-G "Ninja"
|
||||
|
||||
cmake --build "$srcdir/$pkgname/build"
|
||||
}
|
||||
|
||||
package()
|
||||
{
|
||||
cd "$srcdir/${_pkgname}/build"
|
||||
|
||||
make install DESTDIR="$pkgdir"
|
||||
cmake --install "$srcdir/$pkgname/build" --prefix="$pkgdir/usr"
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 302 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 57 KiB |
@@ -1,4 +1,5 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<!-- Copyright 2022 Rosalie Wanders -->
|
||||
<component type="desktop">
|
||||
<!--Created with jdAppdataEdit 2.1-->
|
||||
<id>com.github.Rosalie241.RMG</id>
|
||||
@@ -11,20 +12,308 @@
|
||||
<description><p>Rosalie's Mupen GUI is an easy to use yet customizable mupen64plus front-end, allowing you to easily play N64 games.</p></description>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<caption>The Rom Browser</caption>
|
||||
<caption>01 - The Rom Browser</caption>
|
||||
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/RomBrowser.png</image>
|
||||
</screenshot>
|
||||
<screenshot type="default">
|
||||
<caption>During A Game</caption>
|
||||
<caption>02 - During A Game</caption>
|
||||
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/InGame.png</image>
|
||||
</screenshot>
|
||||
<screenshot type="default">
|
||||
<caption>Settings</caption>
|
||||
<caption>03 - Cheats</caption>
|
||||
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/Cheats.png</image>
|
||||
</screenshot>
|
||||
<screenshot type="default">
|
||||
<caption>04 - Settings</caption>
|
||||
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/Settings.png</image>
|
||||
</screenshot>
|
||||
<screenshot type="default">
|
||||
<caption>05 - Input Settings</caption>
|
||||
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/InputSettings.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<description/>
|
||||
<releases>
|
||||
<release version="v0.4.0" date="2023-05-04" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix updater on windows always installing the desktop icon</li>
|
||||
<li>Fix updater on windows not re-launching RMG after installation</li>
|
||||
<li>Fix the speed limiter toggle and speed factor options not working on linux on some systems</li>
|
||||
<li>Fix the 1080 Snowboarding cheats (thank you Gent)</li>
|
||||
<li>Add support for moving the toolbar (changes to the docked position are persistent across application runs)</li>
|
||||
<li>Update GLideN64 and mupen64plus-input-gca</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.3.9" date="2023-04-06" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix "Don't check for updates again" checkbox appearing when requesting an update check through Help -> Check For Updates</li>
|
||||
<li>Add game format, file name, file extension, file size, game I.D. and game region columns to the list view of the ROM browser which can be toggled in the "Show/Hide Columns" menu of the context menu in the list view of the ROM browser (thank you RetraCarteR)</li>
|
||||
<li>Add "Reset Column Sizes" to context menu of the list view of the ROM browser (thank you RetraCarteR)</li>
|
||||
<li>Add "Analog Stick Sensitivity" setting to RMG-Input (thank you JaxonWasTaken)</li>
|
||||
<li>Add "Save Filename Format" setting to the Core tab of the settings dialog</li>
|
||||
<li>Add "Edit Game Input Settings" to the context menu of the ROM browser</li>
|
||||
<li>Add support for 7z files</li>
|
||||
<li>Add progress status to the loading screen in the ROM browser when loading takes more than 5 seconds</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.3.8" date="2023-02-24" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix RMG not having the correct video size in some cases (i.e on a WM where resizing is not allowed to be done by an application)</li>
|
||||
<li>Fix translations not working in GLideN64</li>
|
||||
<li>Add -n/--nogui commandline option</li>
|
||||
<li>Add -d/--debug-messages commandline option</li>
|
||||
<li>Add hotkeys for graphics, audio, RSP and input settings</li>
|
||||
<li>Add hotkey for viewing the log</li>
|
||||
<li>Add SIGINT and SIGTERM handling on linux</li>
|
||||
<li>Add "Check For Updates" to "View" in the toolbar</li>
|
||||
<li>Add information about LLE plugins in the settings dialog</li>
|
||||
<li>Add support for toggling visibility of columns in the ROM browser list view (thank you RetraCarteR)</li>
|
||||
<li>Add date and time to the save state slot items in "Current Save State" menu in the menubar</li>
|
||||
<li>Add date and time to the OSD when selecting a save state slot</li>
|
||||
<li>Add failure messages to the OSD when loading/saving a save state fails</li>
|
||||
<li>Improve updater behavior by checking for an update on startup with at least an hour in-between checks</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.3.7" date="2023-02-19" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix icons not showing up in some cases when migrating from a version before v0.3.6</li>
|
||||
<li>Fix plugin settings not being loaded properly in the settings dialog when migrating from a version before v0.3.6</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.3.6" date="2023-02-19" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix RMG not using xwayland when using wayland (wayland has lots of issues, can be disabled by building with the "-DFORCE_XCB=OFF" option)</li>
|
||||
<li>Fix some non-fatal mupen64plus errors showing a pop-up</li>
|
||||
<li>Fix window not returning to ROM browser when launching a game through the commandline and the plugins aren't ready</li>
|
||||
<li>Add support for Qt stylesheets (place them in the 'user data directory/Styles' directory with the '.qss' extension, they'll show up in "Themes")</li>
|
||||
<li>Add "Icon Theme" setting</li>
|
||||
<li>Add "Speed Factor" to System menu bar</li>
|
||||
<li>Add support for re-ordering columns in the list view of the ROM browser (thank you RetraCarteR)</li>
|
||||
<li>Add AppImage to github releases (this replaces the old portable linux builds on github releases)</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.3.5" date="2023-02-14" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix reset button not working properly in RMG-Input</li>
|
||||
<li>Fix profiles not being deleted properly when clicking on cancel/close in some cases in RMG-Input</li>
|
||||
<li>Fix paraLLEl not logging to the log window</li>
|
||||
<li>Fix paraLLEl's odd window behavior by not saving the window size when emulation ends</li>
|
||||
<li>Fix GLideN64 initializing a noise texture being slow</li>
|
||||
<li>Fix issue where an unbound mapping in RMG-Input would respond to an A controller button press in-game</li>
|
||||
<li>Fix issue where RMG-Input wouldn't save anything but the currently opened profile</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.3.4" date="2023-02-11" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix mapping button size increasing when reloading settings in RMG-Input</li>
|
||||
<li>Fix analog stick mapping in-game when having buttons and axis bound in RMG-Input</li>
|
||||
<li>Fix height mismatch of "Profile" and "Input Device" UI elements in RMG-Input</li>
|
||||
<li>Fix updater script not using the correct path seperators on Windows</li>
|
||||
<li>Fix GLideN64's per game settings being overwritten by the updater on windows (or not being updated on linux)</li>
|
||||
<li>Fix "Automatic" input device not opening controller device when clicking on 'Refresh' in RMG-Input</li>
|
||||
<li>Fix game specific profile having unexpected UI behavior in RMG-Input</li>
|
||||
<li>Fix cancel and close button not working correctly in RMG-Input</li>
|
||||
<li>Fix profile saving not working correctly when having the same profile selected for multiple players in RMG-Input</li>
|
||||
<li>Add "Filter Events Based On Joystick Type For Buttons" setting to RMG-Input</li>
|
||||
<li>Add "Filter Events Based On Joystick Type For Axis" setting to RMG-Input</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.3.3" date="2023-02-09" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Remove "Controller Is Plugged In" checkbox in RMG-Input</li>
|
||||
<li>Remove text from 'Remove' button in RMG-Input</li>
|
||||
<li>Add "None" input device to RMG-Input (replacing the "Controller Is Plugged In" checkbox)</li>
|
||||
<li>Add "Automatic" input device to RMG-Input</li>
|
||||
<li>Add support for creating profiles in RMG-Input</li>
|
||||
<li>Add icons to 'Remove', 'Refresh', 'Reset' and 'Options' buttons in RMG-Input</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.3.2" date="2023-02-06" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix ndd/d64 files in zip files not working when the disk file is inside a subdirectory inside the zip file</li>
|
||||
<li>Fix ndd/d64 files in zip files not working correctly on windows</li>
|
||||
<li>Fix controller image in RMG-Input sometimes being stuck when having a trigger bound to a button</li>
|
||||
<li>Fix trigger mapping in RMG-Input</li>
|
||||
<li>Remove "Invert Axis Mapped To LRZ" setting in RMG-Input</li>
|
||||
<li>Add "Sort Results After Search" ROM Browser setting</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.3.1" date="2023-02-04" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix taking a screenshot not working in some cases</li>
|
||||
<li>Fix some games being unable to save due to having an illegal character in the save filename</li>
|
||||
<li>Fix OSD tab crash in GLideN64</li>
|
||||
<li>Fix an issue where the graphics plugin would show the 64DD IPL as ROM name in the settings even after booting a cartridge</li>
|
||||
<li>Fix "Refresh ROM List" in Hotkeys tab in settings dialog not reverting back to defaults when clicking on 'restore defaults'</li>
|
||||
<li>Fix "Remove Duplicate Keybindings" in settings dialog not behaving correctly in some cases</li>
|
||||
<li>Fix fallback application icons not respecting system icon theme on linux</li>
|
||||
<li>Add support for ndd/d64 files in zip files</li>
|
||||
<li>Add support for using the basename of the ROM filename for covers</li>
|
||||
<li>Add support for binding multiple inputs in RMG-Input</li>
|
||||
<li>Improve behavior of window when launching RMG with a ROM using the commandline</li>
|
||||
<li>Improve behavior of error message when emulation fails</li>
|
||||
<li>Improve behavior of hotkey buttons in settings dialog</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.3.0" date="2023-01-23" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix GLideN64 not being able to load texture packs from relative paths</li>
|
||||
<li>Fix "Save State Slot" keybindings not working in fullscreen</li>
|
||||
<li>Fix deadzone percentage being incorrect when set to 0% in RMG-Input</li>
|
||||
<li>Fix low deadzone value not working in RMG-Input (thank you porcino)</li>
|
||||
<li>Fix toolbar being hidden when ending emulation while in fullscreen</li>
|
||||
<li>Fix zip files with japanese characters in the file name not being able to be opened on windows</li>
|
||||
<li>Fix ROM Browser not returning to a maximized state when ending emulation</li>
|
||||
<li>Fix ROM Browser not opening maximized when closing RMG with it maximized</li>
|
||||
<li>Fix window not being able to be maximized during emulation when scaling is enabled</li>
|
||||
<li>Fix read-only ROM files not being able to be opened on linux</li>
|
||||
<li>Remove "Allow Manual Window Resizing" setting due to it being always enabled</li>
|
||||
<li>Remove Styles tab from settings dialog on windows</li>
|
||||
<li>Add "Play Game with Cartridge" to context menu when a 64DD disk is selected in the ROM Browser</li>
|
||||
<li>Add "Open ROM Directory" to context menu in the ROM Browser</li>
|
||||
<li>Add an On-Screen Display (see the OSD tab in the settings dialog for settings)</li>
|
||||
<li>Add Theme setting to settings dialog (see Interface -> Miscellaneous, this is a replacement for the previous Styles settings)</li>
|
||||
<li>Improve error message when opening a zip file fails</li>
|
||||
<li>Improve tab order and naming in settings dialog</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.9" date="2023-01-03" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix wrong 64DD Disk extension being listed in empty ROM browser</li>
|
||||
<li>Fix memory corruption when having 64DD Disk files</li>
|
||||
<li>Fix possible crash when render window wasn't visible yet</li>
|
||||
<li>Fix RMG changing the current directory on non-portable installs</li>
|
||||
<li>Remove Qt warning messages (you can view them by setting RMG_SHOW_DEBUG_QT_MESSAGES to 1)</li>
|
||||
<li>Change "Choose ROM Directory" to "Change ROM Directory"</li>
|
||||
<li>Add -q/--quit-after-emulation commandline option</li>
|
||||
<li>Add 2 more icons to menubar menus/items</li>
|
||||
<li>Add "Current Save State" tab to Hotkeys tab in settings dialog (this allows you to use a hotkey to change save state slots)</li>
|
||||
<li>Improve behavior of Hotkeys tab in settings dialog</li>
|
||||
<li>Improve behavior of window when exiting RMG while in-game</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.8" date="2023-01-01" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix 'Uniform Size (Grid View)' not being disabled during emulation</li>
|
||||
<li>Fix toolbar not respecting the view setting</li>
|
||||
<li>Fix being stuck at the loading screen when having more ROMs than the ROM search limit</li>
|
||||
<li>Improve error message when opening a ROM fails</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.7" date="2022-12-29" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix core error not showing when the statusbar was hidden</li>
|
||||
<li>Fix .ndd/.64d not being in the empty ROM Browser widget</li>
|
||||
<li>Fix .jpg/.jpeg files not working on covers on Windows</li>
|
||||
<li>Fix updater script not copying subdirectories on Windows (for portable installs)</li>
|
||||
<li>Fix 64DD Disks which required the development IPL not working</li>
|
||||
<li>Fix 64DD Disks showing the wrong internal ROM name (this fix requires clearing the ROM cache)</li>
|
||||
<li>Fix cover filenames allowing invalid characters (they will now be replaced by _)</li>
|
||||
<li>Add more icons to View menu in the menu bar</li>
|
||||
<li>Add 'Uniform Size (Grid View)' to View menu in the menu bar</li>
|
||||
<li>Add smooth scrolling to List View and Grid View</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.6" date="2022-12-28" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix default save state/game directory being incorrect on first run (on non-portable installs)</li>
|
||||
<li>Fix angrylion-rdp-plus not loading settings correctly</li>
|
||||
<li>Fix cheat settings not moving over when renaming a cheat</li>
|
||||
<li>Remove fullscreen resolution combobox from GLideN64 because it did nothing</li>
|
||||
<li>Remove File menu from menu bar</li>
|
||||
<li>Implement disk support without requiring a cartridge</li>
|
||||
<li>Add toolbar</li>
|
||||
<li>Add View menu to menu bar</li>
|
||||
<li>Add Grid view to ROM browser</li>
|
||||
<li>Add icons to all menu bar items</li>
|
||||
<li>Add log dialog</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.5" date="2022-12-14" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix incorrect controller being selected in RMG-Input when having 2 controllers with the same name</li>
|
||||
<li>Fix some UI elements being enabled while the 'Controller Is Plugged In' checkbox is disabled in RMG-Input</li>
|
||||
<li>Fix extra padding being added when having a controller selected and opening RMG-Input</li>
|
||||
<li>Fix creating a new profile in GLideN64</li>
|
||||
<li>Add Z-Trigger visualization in RMG-Input</li>
|
||||
<li>Remove Debugger checkbox in the settings dialog because it did nothing</li>
|
||||
<li>Remove About buttons in the plugin tab of the settings dialog because it did nothing</li>
|
||||
<li>Implement close button on all dialogs</li>
|
||||
<li>Implement custom style support (for Windows only)</li>
|
||||
<li>Implement the ability to remove/reset the main profile in RMG-Input</li>
|
||||
<li>Rename Interface tab in settings dialog to User Interface</li>
|
||||
<li>Migrate to Qt6 (currently the flatpak will remain Qt5)</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.4" date="2022-12-08" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix Discord Rich Presence breaking when opening the settings dialog</li>
|
||||
<li>Fix install update window not showing</li>
|
||||
<li>Fix 'Limit FPS' not working with new RMG-Audio (this disables the 'synchronize audio' option)</li>
|
||||
<li>Implement support for Japanese characters in the ROM header</li>
|
||||
<li>Implement dynamic buffer sizes in the ROM browser cache (this reduces the ROM browser cache size)</li>
|
||||
<li>Add more cheats from Gent</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.3" date="2022-12-05" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Add updater for portable installations</li>
|
||||
<li>Add Discord Rich Presence</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.2" date="2022-12-03" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
|
||||
@@ -4,55 +4,66 @@ Rosalie's Mupen GUI is a free and open-source mupen64plus GUI written in C++.
|
||||
|
||||
It offers a simple-to-use user interface.
|
||||
|
||||
## System Requirements
|
||||
## Download
|
||||
|
||||
* Operating System
|
||||
* Windows Or Linux
|
||||
* CPU
|
||||
* Intel or AMD processor with SSE2 support
|
||||
* RAM
|
||||
* 512MB or more
|
||||
* Graphics card
|
||||
* OpenGL 3.3 capable
|
||||
#### Windows
|
||||
You can download Rosalie's Mupen GUI on 
|
||||
|
||||
#### Linux
|
||||
You can download Rosalie's Mupen GUI on
|
||||
* [Github Releases (AppImage)](https://github.com/Rosalie241/RMG/releases)
|
||||
* [Flathub (Flatpak)](https://flathub.org/apps/details/com.github.Rosalie241.RMG)
|
||||
* [Arch User Repository](https://aur.archlinux.org/packages/rmg)
|
||||
|
||||
## Support
|
||||
|
||||
You can ask for help or report issues on
|
||||
* [Github](https://github.com/Rosalie241/RMG/issues/new)
|
||||
* [Discord](https://discord.gg/k9GuyJ2PpF)
|
||||
|
||||
## License
|
||||
|
||||
Rosalie's Mupen GUI is licensed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html).
|
||||
|
||||
## Showcase
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## Building
|
||||
|
||||
#### Linux
|
||||
* Portable Debian/Ubuntu
|
||||
|
||||
```shell
|
||||
sudo apt-get -y install cmake libhidapi-dev libsamplerate0-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qt5-default build-essential nasm git zip
|
||||
```bash
|
||||
sudo apt-get -y install cmake libhidapi-dev libsamplerate0-dev libspeex-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qt6-base-dev libqt6svg6-dev build-essential nasm git zip ninja-build
|
||||
./Source/Script/Build.sh Release
|
||||
```
|
||||
|
||||
* Portable Fedora
|
||||
```shell
|
||||
sudo dnf install hidapi-devel libsamplerate-devel minizip-compat-devel SDL2-devel freetype-devel mesa-libGL-devel mesa-libGLU-devel zlib-ng-devel binutils-devel speexdsp-devel qt5-qtbase-devel qt5-qtsvg-devel gcc-c++ nasm git
|
||||
./Source/Script/Build.sh Release
|
||||
```bash
|
||||
sudo dnf install hidapi-devel libsamplerate-devel minizip-compat-devel SDL2-devel freetype-devel mesa-libGL-devel mesa-libGLU-devel zlib-ng-devel binutils-devel speexdsp-devel qt6-qtbase-devel qt6-qtsvg-devel gcc-c++ nasm git ninja-build
|
||||
./Source/Script/Build.sh Release
|
||||
```
|
||||
|
||||
When it's done building, executables can be found in `Bin/Release`
|
||||
|
||||
* Installation/Packaging
|
||||
```
|
||||
mkdir build && cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE="Release" -DPORTABLE_INSTALL="OFF" -G "Unix Makefiles"
|
||||
make install
|
||||
```bash
|
||||
export src_dir="$(pwd)"
|
||||
export build_dir="$(pwd)/build"
|
||||
mkdir -p "$build_dir"
|
||||
cmake -S "$src_dir" -B "$build_dir" -DCMAKE_BUILD_TYPE="Release" -DPORTABLE_INSTALL="OFF" -DCMAKE_INSTALL_PREFIX="/usr" -G "Ninja"
|
||||
cmake --build "$build_dir"
|
||||
cmake --install "$build_dir" --prefix="/usr"
|
||||
```
|
||||
|
||||
#### Windows
|
||||
* Download & Install [MSYS2](https://www.msys2.org/)
|
||||
```
|
||||
sudo pacman -S git make mingw-w64-x86_64-cmake mingw-w64-x86_64-freetype mingw-w64-x86_64-gcc mingw-w64-x86_64-hidapi mingw-w64-x86_64-jasper mingw-w64-x86_64-libpng mingw-w64-x86_64-libsamplerate mingw-w64-x86_64-nasm mingw-w64-x86_64-python3-pip mingw-w64-x86_64-python3-pyopenssl mingw-w64-x86_64-qt5 mingw-w64-x86_64-rust mingw-w64-x86_64-SDL2
|
||||
```bash
|
||||
pacman -S --needed make mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-x86_64-hidapi mingw-w64-x86_64-freetype mingw-w64-x86_64-libpng mingw-w64-x86_64-SDL2 mingw-w64-x86_64-qt6 mingw-w64-x86_64-SDL2 mingw-w64-x86_64-hidapi mingw-w64-x86_64-speexdsp mingw-w64-x86_64-libsamplerate mingw-w64-x86_64-nasm mingw-w64-x86_64-minizip git
|
||||
./Source/Script/Build.sh Release
|
||||
```
|
||||
|
||||
When it's done building, executables can be found in `Bin/Release`
|
||||
|
||||
## Support
|
||||
|
||||
Join the [Rosalie's Mupen GUI Discord Server](https://discord.gg/k9GuyJ2PpF) for support
|
||||
|
||||
## License
|
||||
|
||||
Rosalie's Mupen GUI is licensed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html).
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#
|
||||
# 7-Zip CMakeLists.txt
|
||||
#
|
||||
project(7Zip)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(7ZIP_SOURCES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/Bcj2.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/Bra.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/Bra86.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/BraIA64.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/CpuArch.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/Delta.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/Lzma2Dec.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/LzmaDec.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/Ppmd7.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/Ppmd7Dec.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/7zCrc.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/7zCrcOpt.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/Sha256.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/Sha256Opt.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/7zAlloc.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/7zArcIn.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/7zBuf.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/7zBuf2.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/7zDec.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/7zFile.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/C/7zStream.c
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${7ZIP_SOURCES}
|
||||
COMMAND ${CMAKE_COMMAND} -E tar "xvz" "${CMAKE_CURRENT_SOURCE_DIR}/lzma2201.tar.gz"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
add_definitions(-D_7ZIP_PPMD_SUPPPORT -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE)
|
||||
|
||||
add_library(7Zip STATIC ${7ZIP_SOURCES})
|
||||
@@ -0,0 +1,2 @@
|
||||
# 7-Zip SDK v22.01
|
||||
Downloaded from https://www.7-zip.org/sdk.html
|
||||
@@ -5,52 +5,62 @@ include(ExternalProject)
|
||||
|
||||
set(THIRDPARTY_DIR ${CMAKE_BINARY_DIR}/Source/3rdParty)
|
||||
|
||||
find_program(RUST_CARGO cargo)
|
||||
if(${RUST_CARGO} STREQUAL "RUST_CARGO-NOTFOUND")
|
||||
message(WARNING "mupen64plus-input-gca will not be built due to not having cargo installed")
|
||||
set(BUILD_INPUT_GCA "0")
|
||||
else()
|
||||
set(BUILD_INPUT_GCA "1")
|
||||
endif()
|
||||
|
||||
set(M64P_CORE_DIR ${THIRDPARTY_DIR}/mupen64plus-core)
|
||||
if(WIN32)
|
||||
set(SO_EXT "dll")
|
||||
set(GCA_LIB "mupen64plus_input_gca.${SO_EXT}")
|
||||
set(CORE_FILE "mupen64plus.dll")
|
||||
else(WIN32)
|
||||
set(SO_EXT "so")
|
||||
set(GCA_LIB "libmupen64plus_input_gca.${SO_EXT}")
|
||||
set(CORE_FILE "libmupen64plus.so")
|
||||
endif(WIN32)
|
||||
|
||||
set(BASE_CMAKE_CONFIGURE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER})
|
||||
if (USE_CCACHE)
|
||||
set(CMAKE_CONFIGURE_ARGS ${BASE_CMAKE_CONFIGURE_ARGS} -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache)
|
||||
set(MAKE_CC_COMPILER "ccache ${CMAKE_C_COMPILER}")
|
||||
set(MAKE_CXX_COMPILER "ccache ${CMAKE_CXX_COMPILER}")
|
||||
else(USE_CCACHE)
|
||||
set(CMAKE_CONFIGURE_ARGS ${BASE_CMAKE_CONFIGURE_ARGS})
|
||||
set(MAKE_CC_COMPILER "${CMAKE_C_COMPILER}")
|
||||
set(MAKE_CXX_COMPILER "${CMAKE_CXX_COMPILER}")
|
||||
endif(USE_CCACHE)
|
||||
|
||||
if(NOT NO_GIT_CLONE)
|
||||
set(MUPEN64PLUSCORE_URL "https://github.com/mupen64plus/mupen64plus-core")
|
||||
set(MUPEN64PLUSCORE_TAG "f63e1b35063241738d848f73311496b76c8aa918")
|
||||
|
||||
set(MUPEN64PLUSCORE_TAG "d4f3e12db0609158c7b4e0beef2bb950aad0ccb9")
|
||||
|
||||
set(MUPEN64PLUS_RSP_CXD4_URL "https://github.com/mupen64plus/mupen64plus-rsp-cxd4")
|
||||
set(MUPEN64PLUS_RSP_CXD4_TAG "39f79201baa15890c4cbae92f2215a634cc3ee6d")
|
||||
|
||||
|
||||
set(MUPEN64PLUS_RSP_HLE_URL "https://github.com/mupen64plus/mupen64plus-rsp-hle")
|
||||
set(MUPEN64PLUS_RSP_HLE_TAG "88093cb43499eff53d343653cddcae2132af17ef")
|
||||
|
||||
|
||||
set(MUPEN64PLUS_RSP_PARALLEL_URL "https://github.com/Rosalie241/parallel-rsp")
|
||||
set(MUPEN64PLUS_RSP_PARALLEL_TAG "e67cee3131651c3e48343294d94fa68a6f8ec14c")
|
||||
|
||||
set(MUPEN64PLUS_RSP_PARALLEL_TAG "dbecbe3a120e428436c5972fa7b872cfc2c9db3e")
|
||||
|
||||
set(MUPEN64PLUS_INPUT_RAPHNET_URL "https://github.com/raphnet/mupen64plus-input-raphnetraw")
|
||||
set(MUPEN64PLUS_INPUT_RAPHNET_TAG "86112413e98a8648edb11d199673cc24d5799af8")
|
||||
|
||||
set(MUPEN64PLUS_INPUT_GCA_URL "https://github.com/amatho/mupen64plus-input-gca")
|
||||
set(MUPEN64PLUS_INPUT_GCA_TAG "21639fb13dfa797a7c0949ffd9bbda9a3456fc69")
|
||||
|
||||
set(MUPEN64PLUS_INPUT_GCN_URL "https://github.com/Rosalie241/mupen64plus-input-gcn")
|
||||
set(MUPEN64PLUS_INPUT_GCN_TAG "e220115fa8ad223be783c822a251d7e0f873ed4c")
|
||||
|
||||
set(MUPEN64PLUS_GFX_ANGRYLION_URL "https://github.com/Rosalie241/angrylion-rdp-plus")
|
||||
set(MUPEN64PLUS_GFX_ANGRYLION_TAG "9d71074f6b71750e99ad06a713f28a9c32ad15cb")
|
||||
set(MUPEN64PLUS_GFX_ANGRYLION_TAG "670abbc972bd430fa77291b0967dd73128314317")
|
||||
|
||||
set(MUPEN64PLUS_GFX_GLIDEN64_URL "https://github.com/gonetz/GLideN64")
|
||||
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "a2ecb92e954fdc1dd1130b331935f04381b29e28")
|
||||
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "0fee30d010d1feda7d343654871b3dfd05ccab70")
|
||||
|
||||
set(MUPEN64PLUS_GFX_PARALLEL_URL "https://github.com/Rosalie241/parallel-rdp-standalone")
|
||||
set(MUPEN64PLUS_GFX_PARALLEL_TAG "693f607728aca78d94ba5d45b0ce119b4ccbcd8c")
|
||||
set(MUPEN64PLUS_GFX_PARALLEL_TAG "2c2226517c4c8929e08ec944654867e26efe0cf5")
|
||||
|
||||
set(DISCORD_RPC_URL "https://github.com/discord/discord-rpc")
|
||||
set(DISCORD_RPC_TAG "963aa9f3e5ce81a4682c6ca3d136cddda614db33")
|
||||
|
||||
set(IMGUI_URL "https://github.com/ocornut/imgui")
|
||||
set(IMGUI_TAG "d7c8516a4b848c0291e3d75b627c0843f515f591")
|
||||
|
||||
set(SDL_GAMECONTROLLERDB_URL "https://github.com/gabomdq/SDL_GameControllerDB")
|
||||
set(SDL_GAMECONTROLLERDB_TAG "b7e5701da82fc97beeede64d3818ef0f4d015aba")
|
||||
endif(NOT NO_GIT_CLONE)
|
||||
|
||||
ExternalProject_Add(mupen64plus-core
|
||||
@@ -62,7 +72,7 @@ ExternalProject_Add(mupen64plus-core
|
||||
GIT_REPOSITORY ${MUPEN64PLUSCORE_URL}
|
||||
GIT_TAG ${MUPEN64PLUSCORE_TAG}
|
||||
|
||||
BUILD_COMMAND make all OSD=0 NEW_DYNAREC=1 TARGET=${CORE_FILE} DEBUG=$<CONFIG:Debug> KEYBINDINGS=0
|
||||
BUILD_COMMAND make all OSD=0 NEW_DYNAREC=1 TARGET=${CORE_FILE} DEBUG=$<CONFIG:Debug> KEYBINDINGS=0 CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
|
||||
BUILD_IN_SOURCE False
|
||||
|
||||
BINARY_DIR ${M64P_CORE_DIR}/projects/unix
|
||||
@@ -81,7 +91,7 @@ ExternalProject_Add(mupen64plus-rsp-cxd4
|
||||
GIT_REPOSITORY ${MUPEN64PLUS_RSP_CXD4_URL}
|
||||
GIT_TAG ${MUPEN64PLUS_RSP_CXD4_TAG}
|
||||
|
||||
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug> POSTFIX=
|
||||
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug> POSTFIX= CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
|
||||
BUILD_IN_SOURCE False
|
||||
|
||||
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-rsp-cxd4/projects/unix
|
||||
@@ -99,7 +109,7 @@ ExternalProject_Add(mupen64plus-rsp-hle
|
||||
GIT_REPOSITORY ${MUPEN64PLUS_RSP_HLE_URL}
|
||||
GIT_TAG ${MUPEN64PLUS_RSP_HLE_TAG}
|
||||
|
||||
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug>
|
||||
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug> CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
|
||||
BUILD_IN_SOURCE False
|
||||
|
||||
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-rsp-hle/projects/unix
|
||||
@@ -117,7 +127,7 @@ ExternalProject_Add(mupen64plus-rsp-parallel
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_IN_SOURCE True
|
||||
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
CMAKE_ARGS ${CMAKE_CONFIGURE_ARGS}
|
||||
|
||||
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-rsp-parallel/mupen64plus-rsp-parallel.${SO_EXT}
|
||||
DEPENDS mupen64plus-core
|
||||
@@ -132,7 +142,7 @@ ExternalProject_Add(mupen64plus-input-raphnetraw
|
||||
GIT_REPOSITORY ${MUPEN64PLUS_INPUT_RAPHNET_URL}
|
||||
GIT_TAG ${MUPEN64PLUS_INPUT_RAPHNET_TAG}
|
||||
|
||||
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug>
|
||||
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug> CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
|
||||
BUILD_IN_SOURCE False
|
||||
|
||||
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-input-raphnetraw/projects/unix
|
||||
@@ -141,31 +151,29 @@ ExternalProject_Add(mupen64plus-input-raphnetraw
|
||||
DEPENDS mupen64plus-core
|
||||
)
|
||||
|
||||
if (${BUILD_INPUT_GCA} STREQUAL "1")
|
||||
ExternalProject_Add(mupen64plus-input-gca
|
||||
SOURCE_DIR mupen64plus-input-gca/
|
||||
ExternalProject_Add(mupen64plus-input-gcn
|
||||
SOURCE_DIR mupen64plus-input-gcn
|
||||
|
||||
CONFIGURE_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
GIT_REPOSITORY ${MUPEN64PLUS_INPUT_GCN_URL}
|
||||
GIT_TAG ${MUPEN64PLUS_INPUT_GCN_TAG}
|
||||
|
||||
GIT_REPOSITORY ${MUPEN64PLUS_INPUT_GCA_URL}
|
||||
GIT_TAG ${MUPEN64PLUS_INPUT_GCA_TAG}
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_COMMAND cargo build --release --features "m64p_compat"
|
||||
BUILD_IN_SOURCE True
|
||||
BUILD_IN_SOURCE True
|
||||
CMAKE_ARGS ${CMAKE_CONFIGURE_ARGS}
|
||||
|
||||
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-input-gca/target/release/${GCA_LIB}
|
||||
DEPENDS mupen64plus-core
|
||||
)
|
||||
endif()
|
||||
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-input-gcn/mupen64plus-input-gcn.${SO_EXT}
|
||||
DEPENDS mupen64plus-core
|
||||
)
|
||||
|
||||
set(GLIDEN64_DIR "${THIRDPARTY_DIR}/mupen64plus-video-GLideN64")
|
||||
set(GLIDEN64_BUILD_DIR "${GLIDEN64_DIR}/projects/cmake")
|
||||
if (MSYS)
|
||||
set(GLIDEN64_CUSTOM_INI "${GLIDEN64_DIR}/ini/GLideN64.custom.ini")
|
||||
if (WIN32)
|
||||
set(GLIDEN64_LIB "${GLIDEN64_BUILD_DIR}/mupen64plus-video-GLideN64.${SO_EXT}")
|
||||
else()
|
||||
else(WIN32)
|
||||
set(GLIDEN64_LIB "${GLIDEN64_BUILD_DIR}/plugin/${CMAKE_BUILD_TYPE}/mupen64plus-video-GLideN64.${SO_EXT}")
|
||||
endif()
|
||||
endif(WIN32)
|
||||
|
||||
set(GLIDENUI_TRANSLATIONS_LANGS "de;es;fr;it;ja;pl;pt_BR")
|
||||
foreach(LANG ${GLIDENUI_TRANSLATIONS_LANGS})
|
||||
@@ -181,7 +189,7 @@ ExternalProject_Add(mupen64plus-video-angrylion-plus
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_IN_SOURCE True
|
||||
CMAKE_ARGS -DBUILD_MUPEN64PLUS=ON -DBUILD_PROJECT64=OFF -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
CMAKE_ARGS -DBUILD_MUPEN64PLUS=ON -DBUILD_PROJECT64=OFF -DUSE_QT5=OFF ${CMAKE_CONFIGURE_ARGS}
|
||||
|
||||
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-video-angrylion-plus/mupen64plus-video-angrylion-plus.${SO_EXT}
|
||||
DEPENDS mupen64plus-core
|
||||
@@ -196,14 +204,12 @@ ExternalProject_Add(mupen64plus-video-GLideN64
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_IN_SOURCE False
|
||||
CMAKE_ARGS -DMUPENPLUSAPI=ON -DMUPENPLUSAPI_GLIDENUI=ON -DUSE_SYSTEM_LIBS=ON -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
CMAKE_ARGS -DMUPENPLUSAPI=ON -DMUPENPLUSAPI_GLIDENUI=ON -DGLIDENUI_QT6=ON -DUSE_SYSTEM_LIBS=ON ${CMAKE_CONFIGURE_ARGS}
|
||||
|
||||
SOURCE_SUBDIR ./src/
|
||||
BINARY_DIR ${GLIDEN64_BUILD_DIR}
|
||||
|
||||
BUILD_BYPRODUCTS ${GLIDEN64_LIB}
|
||||
BUILD_BYPRODUCTS ${GLIDEN64_DIR}/ini/GLideN64.custom.ini
|
||||
BUILD_BYPRODUCTS ${GLIDENUI_TRANSLATIONS}
|
||||
)
|
||||
|
||||
ExternalProject_Add(mupen64plus-video-parallel
|
||||
@@ -215,12 +221,82 @@ ExternalProject_Add(mupen64plus-video-parallel
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_IN_SOURCE True
|
||||
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
CMAKE_ARGS -DUSE_QT5=OFF ${CMAKE_CONFIGURE_ARGS}
|
||||
|
||||
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-video-parallel/mupen64plus-video-parallel.${SO_EXT}
|
||||
DEPENDS mupen64plus-core
|
||||
)
|
||||
|
||||
if (DISCORD_RPC)
|
||||
ExternalProject_Add(discord-rpc
|
||||
SOURCE_DIR discord-rpc
|
||||
|
||||
GIT_REPOSITORY ${DISCORD_RPC_URL}
|
||||
GIT_TAG ${DISCORD_RPC_TAG}
|
||||
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_IN_SOURCE True
|
||||
CMAKE_ARGS -DBUILD_EXAMPLES=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON ${CMAKE_CONFIGURE_ARGS}
|
||||
|
||||
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/discord-rpc/src/libdiscord-rpc.a
|
||||
)
|
||||
endif(DISCORD_RPC)
|
||||
|
||||
set(IMGUI_DIR ${THIRDPARTY_DIR}/imgui)
|
||||
set(IMGUI_BUILD_DIR ${IMGUI_DIR}/build)
|
||||
set(IMGUI_SOURCES_IN
|
||||
${IMGUI_DIR}/imgui_draw.cpp
|
||||
${IMGUI_DIR}/imgui_tables.cpp
|
||||
${IMGUI_DIR}/imgui_widgets.cpp
|
||||
${IMGUI_DIR}/imgui.cpp
|
||||
${IMGUI_DIR}/backends/imgui_impl_opengl3.cpp
|
||||
${IMGUI_DIR}/backends/imgui_impl_opengl3.h
|
||||
${IMGUI_DIR}/backends/imgui_impl_opengl3_loader.h
|
||||
)
|
||||
set(IMGUI_SOURCES_OUT
|
||||
${IMGUI_BUILD_DIR}/imgui_draw.cpp
|
||||
${IMGUI_BUILD_DIR}/imgui_tables.cpp
|
||||
${IMGUI_BUILD_DIR}/imgui_widgets.cpp
|
||||
${IMGUI_BUILD_DIR}/imgui.cpp
|
||||
${IMGUI_BUILD_DIR}/imgui_impl_opengl3.cpp
|
||||
${IMGUI_BUILD_DIR}/imgui_impl_opengl3.h
|
||||
${IMGUI_BUILD_DIR}/imgui_impl_opengl3_loader.h
|
||||
)
|
||||
ExternalProject_Add(imgui
|
||||
SOURCE_DIR imgui
|
||||
|
||||
GIT_REPOSITORY ${IMGUI_URL}
|
||||
GIT_TAG ${IMGUI_TAG}
|
||||
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E make_directory ${IMGUI_BUILD_DIR}
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} -E copy ${IMGUI_SOURCES_IN} ${IMGUI_BUILD_DIR}
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_BYPRODUCTS ${IMGUI_SOURCES_OUT}
|
||||
)
|
||||
|
||||
set(SDL_GAMECONTROLLERDB_DIR ${THIRDPARTY_DIR}/SDL_GameControllerDB)
|
||||
set(SDL_GAMECONTROLLERDB_BUILD_DIR ${SDL_GAMECONTROLLERDB_DIR}/build)
|
||||
set(SDL_GAMECONTROLLERDB_SOURCES_IN
|
||||
${SDL_GAMECONTROLLERDB_DIR}/gamecontrollerdb.txt
|
||||
)
|
||||
set(SDL_GAMECONTROLLERDB_SOURCES_OUT
|
||||
${SDL_GAMECONTROLLERDB_BUILD_DIR}/gamecontrollerdb.txt
|
||||
)
|
||||
ExternalProject_Add(SDL_GameControllerDB
|
||||
SOURCE_DIR SDL_GameControllerDB
|
||||
|
||||
GIT_REPOSITORY ${SDL_GAMECONTROLLERDB_URL}
|
||||
GIT_TAG ${SDL_GAMECONTROLLERDB_TAG}
|
||||
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E make_directory ${SDL_GAMECONTROLLERDB_BUILD_DIR}
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} -E copy ${SDL_GAMECONTROLLERDB_SOURCES_IN} ${SDL_GAMECONTROLLERDB_SOURCES_OUT}
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_BYPRODUCTS ${SDL_GAMECONTROLLERDB_SOURCES_OUT}
|
||||
)
|
||||
|
||||
ExternalProject_Get_property(mupen64plus-core BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUSCORE_LIB ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
set(MUPEN64PLUSCORE_INI ${M64P_CORE_DIR}/data/mupen64plus.ini PARENT_SCOPE)
|
||||
@@ -237,16 +313,26 @@ set(MUPEN64PLUS_PLUGIN_RSP_PARALLEL ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
ExternalProject_Get_property(mupen64plus-input-raphnetraw BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUS_PLUGIN_INPUT_RAPHNET ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
|
||||
if (${BUILD_INPUT_GCA} STREQUAL "1")
|
||||
ExternalProject_Get_property(mupen64plus-input-gca BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUS_PLUGIN_INPUT_GCA ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
endif()
|
||||
ExternalProject_Get_property(mupen64plus-input-gcn BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUS_PLUGIN_INPUT_GCN ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
|
||||
ExternalProject_Get_property(mupen64plus-video-angrylion-plus BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUS_PLUGIN_GFX_ANGRYLION ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
|
||||
ExternalProject_Get_property(mupen64plus-video-GLideN64 BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUS_PLUGIN_GFX_GLIDEN64 ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
set(MUPEN64PLUS_PLUGIN_GFX_GLIDEN64 ${BUILD_BYPRODUCTS} ${GLIDENUI_TRANSLATIONS} ${GLIDEN64_CUSTOM_INI} PARENT_SCOPE)
|
||||
|
||||
ExternalProject_Get_property(mupen64plus-video-parallel BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUS_PLUGIN_GFX_PARALLEL ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
|
||||
if (DISCORD_RPC)
|
||||
ExternalProject_Get_property(discord-rpc BUILD_BYPRODUCTS)
|
||||
set(DISCORD_RPC_LIB ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
endif(DISCORD_RPC)
|
||||
|
||||
ExternalProject_Get_property(imgui BUILD_BYPRODUCTS)
|
||||
set(IMGUI_SOURCES ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
set(IMGUI_DIR ${THIRDPARTY_DIR}/imgui PARENT_SCOPE)
|
||||
|
||||
ExternalProject_Get_property(SDL_GameControllerDB BUILD_BYPRODUCTS)
|
||||
set(SDL_GAMECONTROLLERDB ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
|
||||
@@ -55,5 +55,5 @@ Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
|
||||
find_package(Qt5 COMPONENTS Gui Widgets Core REQUIRED)
|
||||
find_package(Qt6 COMPONENTS Gui Widgets Core REQUIRED)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SDL2 REQUIRED sdl2)
|
||||
@@ -36,7 +36,7 @@ target_link_libraries(RMG-Audio
|
||||
${SDL2_LIBRARIES}
|
||||
${SPEEX_LIBRARIES}
|
||||
${SAMPLERATE_LIBRARIES}
|
||||
Qt5::Gui Qt5::Widgets
|
||||
Qt6::Gui Qt6::Widgets
|
||||
)
|
||||
|
||||
target_include_directories(RMG-Audio PRIVATE
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
|
||||
using namespace UserInterface;
|
||||
|
||||
MainDialog::MainDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
|
||||
MainDialog::MainDialog(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
this->setupUi(this);
|
||||
this->setWindowIcon(QIcon(":Resource/RMG.png"));
|
||||
|
||||
this->setIconsForEmulationInfoText();
|
||||
|
||||
this->volumeSlider->setValue(CoreSettingsGetIntValue(SettingsID::Audio_Volume));
|
||||
this->muteCheckBox->setChecked(CoreSettingsGetBoolValue(SettingsID::Audio_Muted));
|
||||
|
||||
@@ -38,6 +40,21 @@ MainDialog::~MainDialog()
|
||||
{
|
||||
}
|
||||
|
||||
void MainDialog::setIconsForEmulationInfoText(void)
|
||||
{
|
||||
QLabel* labels[] = {
|
||||
this->infoIconLabel_0
|
||||
};
|
||||
|
||||
QIcon infoIcon = QIcon::fromTheme("information-line");
|
||||
QPixmap infoIconPixmap = infoIcon.pixmap(16, 16);
|
||||
|
||||
for (QLabel* label : labels)
|
||||
{
|
||||
label->setPixmap(infoIconPixmap);
|
||||
}
|
||||
}
|
||||
|
||||
void MainDialog::hideEmulationInfoText(void)
|
||||
{
|
||||
QHBoxLayout *layouts[] = {this->emulationInfoLayout};
|
||||
|
||||
@@ -25,6 +25,7 @@ public:
|
||||
~MainDialog(void);
|
||||
|
||||
private:
|
||||
void setIconsForEmulationInfoText(void);
|
||||
void hideEmulationInfoText(void);
|
||||
|
||||
private slots:
|
||||
|
||||
@@ -324,7 +324,7 @@
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="emulationInfoLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<widget class="QLabel" name="infoIconLabel_0">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -335,7 +335,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="UIResources.qrc">:/Resource/Info.ico</pixmap>
|
||||
<pixmap>:/Resource/Info.ico</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>false</bool>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,6 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>Resource/RMG.png</file>
|
||||
<file>Resource/Info.ico</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -9,6 +9,9 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SDL2 REQUIRED sdl2)
|
||||
pkg_check_modules(MINIZIP REQUIRED minizip)
|
||||
if (WIN32)
|
||||
pkg_check_modules(ICONV REQUIRED iconv)
|
||||
endif(WIN32)
|
||||
|
||||
configure_file(Config.hpp.in Config.hpp)
|
||||
|
||||
@@ -18,8 +21,10 @@ set(RMG_CORE_SOURCES
|
||||
m64p/ConfigApi.cpp
|
||||
m64p/PluginApi.cpp
|
||||
CachedRomHeaderAndSettings.cpp
|
||||
ConvertStringEncoding.cpp
|
||||
Settings/Settings.cpp
|
||||
SpeedLimiter.cpp
|
||||
SpeedFactor.cpp
|
||||
RomSettings.cpp
|
||||
Directories.cpp
|
||||
MediaLoader.cpp
|
||||
@@ -29,10 +34,12 @@ set(RMG_CORE_SOURCES
|
||||
SaveState.cpp
|
||||
Callback.cpp
|
||||
Plugins.cpp
|
||||
Version.cpp
|
||||
Cheats.cpp
|
||||
VidExt.cpp
|
||||
Video.cpp
|
||||
Error.cpp
|
||||
Unzip.cpp
|
||||
Core.cpp
|
||||
Key.cpp
|
||||
Rom.cpp
|
||||
@@ -50,8 +57,15 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
if (DISCORD_RPC)
|
||||
list(APPEND RMG_CORE_SOURCES
|
||||
DiscordRpc.cpp
|
||||
)
|
||||
add_definitions(-DDISCORD_RPC)
|
||||
endif(DISCORD_RPC)
|
||||
|
||||
if (PORTABLE_INSTALL)
|
||||
add_definitions(-DPORTABLE_INSTALL)
|
||||
add_definitions(-DPORTABLE_INSTALL)
|
||||
endif(PORTABLE_INSTALL)
|
||||
|
||||
add_library(RMG-Core STATIC ${RMG_CORE_SOURCES})
|
||||
@@ -61,13 +75,21 @@ if(UNIX)
|
||||
endif(UNIX)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(RMG-Core wsock32 ws2_32)
|
||||
target_link_libraries(RMG-Core wsock32 ws2_32 ${ICONV_LIBRARIES})
|
||||
endif(WIN32)
|
||||
|
||||
target_link_libraries(RMG-Core
|
||||
${MINIZIP_LIBRARIES}
|
||||
7Zip
|
||||
)
|
||||
|
||||
if (DISCORD_RPC)
|
||||
target_link_libraries(RMG-Core
|
||||
${DISCORD_RPC_LIB}
|
||||
)
|
||||
add_dependencies(RMG-Core discord-rpc)
|
||||
endif(DISCORD_RPC)
|
||||
|
||||
target_include_directories(RMG-Core PRIVATE
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
|
||||
@@ -18,16 +18,32 @@
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else // Linux
|
||||
#include <linux/limits.h>
|
||||
#endif // _WIN32
|
||||
|
||||
//
|
||||
// Local Defines
|
||||
//
|
||||
|
||||
#define MAX_FILENAME_LEN 4096
|
||||
#define ROMHEADER_NAME_LEN 21
|
||||
#ifdef _WIN32
|
||||
#define MAX_FILENAME_LEN MAX_PATH
|
||||
#else // Linux
|
||||
#define MAX_FILENAME_LEN PATH_MAX
|
||||
#endif // _WIN32
|
||||
#define ROMHEADER_NAME_LEN 256
|
||||
#define GOODNAME_LEN 256
|
||||
#define MD5_LEN 33
|
||||
#define GAMEID_LEN 5
|
||||
#define REGION_LEN 18
|
||||
|
||||
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCache_03"
|
||||
#ifdef _WIN32
|
||||
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheWindows_06"
|
||||
#else // Linux
|
||||
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheLinux_06"
|
||||
#endif // _WIN32
|
||||
#define CACHE_FILE_ITEMS_MAX 10000
|
||||
|
||||
//
|
||||
@@ -39,6 +55,7 @@ struct l_CacheEntry
|
||||
std::filesystem::path fileName;
|
||||
osal_files_file_time fileTime;
|
||||
|
||||
CoreRomType type;
|
||||
CoreRomHeader header;
|
||||
CoreRomSettings settings;
|
||||
};
|
||||
@@ -88,8 +105,11 @@ void CoreReadRomHeaderAndSettingsCache(void)
|
||||
char magicBuf[sizeof(CACHE_FILE_MAGIC)];
|
||||
wchar_t fileNameBuf[MAX_FILENAME_LEN];
|
||||
char headerNameBuf[ROMHEADER_NAME_LEN];
|
||||
char gameIDBuf[GAMEID_LEN];
|
||||
char regionBuf[REGION_LEN];
|
||||
char goodNameBuf[GOODNAME_LEN];
|
||||
char md5Buf[MD5_LEN];
|
||||
uint32_t size;
|
||||
l_CacheEntry cacheEntry;
|
||||
|
||||
inputStream.open(get_cache_file_name(), std::ios::binary);
|
||||
@@ -108,27 +128,42 @@ void CoreReadRomHeaderAndSettingsCache(void)
|
||||
|
||||
// read all file entries
|
||||
#define FREAD(x) inputStream.read((char*)&x, sizeof(x))
|
||||
#define FREAD_STR(x) inputStream.read((char*)x, sizeof(x))
|
||||
#define FREAD_STR(x, y) inputStream.read((char*)x, y)
|
||||
while (!inputStream.eof())
|
||||
{
|
||||
// reset buffers
|
||||
size = 0;
|
||||
memset(fileNameBuf, 0, sizeof(fileNameBuf));
|
||||
memset(headerNameBuf, 0, sizeof(headerNameBuf));
|
||||
memset(gameIDBuf, 0, sizeof(gameIDBuf));
|
||||
memset(regionBuf, 0, sizeof(regionBuf));
|
||||
memset(goodNameBuf, 0, sizeof(goodNameBuf));
|
||||
memset(md5Buf, 0, sizeof(md5Buf));
|
||||
|
||||
// file info
|
||||
FREAD_STR(fileNameBuf);
|
||||
FREAD(size);
|
||||
FREAD_STR(fileNameBuf, size);
|
||||
cacheEntry.fileName = std::filesystem::path(fileNameBuf);
|
||||
FREAD(cacheEntry.fileTime);
|
||||
// type
|
||||
FREAD(cacheEntry.type);
|
||||
// header
|
||||
FREAD_STR(headerNameBuf);
|
||||
FREAD(size);
|
||||
FREAD_STR(headerNameBuf, size);
|
||||
FREAD(size);
|
||||
FREAD_STR(gameIDBuf, size);
|
||||
FREAD(size);
|
||||
FREAD_STR(regionBuf, size);
|
||||
cacheEntry.header.Name = std::string(headerNameBuf);
|
||||
cacheEntry.header.GameID = std::string(gameIDBuf);
|
||||
cacheEntry.header.Region = std::string(regionBuf);
|
||||
FREAD(cacheEntry.header.CRC1);
|
||||
FREAD(cacheEntry.header.CRC2);
|
||||
// (partial) settings
|
||||
FREAD_STR(goodNameBuf);
|
||||
FREAD_STR(md5Buf);
|
||||
FREAD(size);
|
||||
FREAD_STR(goodNameBuf, size);
|
||||
FREAD(size);
|
||||
FREAD_STR(md5Buf, size);
|
||||
cacheEntry.settings.GoodName = std::string(goodNameBuf);
|
||||
cacheEntry.settings.MD5 = std::string(md5Buf);
|
||||
|
||||
@@ -146,8 +181,11 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
|
||||
std::ofstream outputStream;
|
||||
wchar_t fileNameBuf[MAX_FILENAME_LEN];
|
||||
char headerNameBuf[ROMHEADER_NAME_LEN];
|
||||
char gameIDBuf[GAMEID_LEN];
|
||||
char regionBuf[REGION_LEN];
|
||||
char goodNameBuf[GOODNAME_LEN];
|
||||
char md5Buf[MD5_LEN];
|
||||
uint32_t size;
|
||||
l_CacheEntry cacheEntry;
|
||||
|
||||
// only save cache when the entries have changed
|
||||
@@ -167,33 +205,54 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
|
||||
|
||||
// write each entry in the file
|
||||
#define FWRITE(x) outputStream.write((char*)&x, sizeof(x))
|
||||
#define FWRITE_STR(x) outputStream.write((char*)x, sizeof(x))
|
||||
#define FWRITE_STR(x, y) outputStream.write((char*)x, y)
|
||||
for (auto iter = l_CacheEntries.cbegin(); iter != l_CacheEntries.end(); iter++)
|
||||
{
|
||||
cacheEntry = (*iter);
|
||||
|
||||
// reset buffers
|
||||
size = 0;
|
||||
memset(fileNameBuf, 0, sizeof(fileNameBuf));
|
||||
memset(headerNameBuf, 0, sizeof(headerNameBuf));
|
||||
memset(gameIDBuf, 0, sizeof(gameIDBuf));
|
||||
memset(regionBuf, 0, sizeof(regionBuf));
|
||||
memset(goodNameBuf, 0, sizeof(goodNameBuf));
|
||||
memset(md5Buf, 0, sizeof(md5Buf));
|
||||
|
||||
// copy strings into buffers
|
||||
wcsncpy(fileNameBuf, cacheEntry.fileName.wstring().c_str(), MAX_FILENAME_LEN);
|
||||
strncpy(headerNameBuf, cacheEntry.header.Name.c_str(), sizeof(headerNameBuf));
|
||||
strncpy(gameIDBuf, cacheEntry.header.GameID.c_str(), sizeof(gameIDBuf));
|
||||
strncpy(regionBuf, cacheEntry.header.Region.c_str(), sizeof(regionBuf));
|
||||
strncpy(goodNameBuf, cacheEntry.settings.GoodName.c_str(), sizeof(goodNameBuf));
|
||||
strncpy(md5Buf, cacheEntry.settings.MD5.c_str(), sizeof(md5Buf));
|
||||
|
||||
// file info
|
||||
FWRITE_STR(fileNameBuf);
|
||||
size = cacheEntry.fileName.wstring().size() * sizeof(wchar_t);
|
||||
FWRITE(size);
|
||||
FWRITE_STR(fileNameBuf, size);
|
||||
FWRITE(cacheEntry.fileTime);
|
||||
// type
|
||||
FWRITE(cacheEntry.type);
|
||||
// header
|
||||
FWRITE_STR(headerNameBuf);
|
||||
size = cacheEntry.header.Name.size();
|
||||
FWRITE(size);
|
||||
FWRITE_STR(headerNameBuf, size);
|
||||
size = cacheEntry.header.GameID.size();
|
||||
FWRITE(size);
|
||||
FWRITE_STR(gameIDBuf, size);
|
||||
size = cacheEntry.header.Region.size();
|
||||
FWRITE(size);
|
||||
FWRITE_STR(regionBuf, size);
|
||||
FWRITE(cacheEntry.header.CRC1);
|
||||
FWRITE(cacheEntry.header.CRC2);
|
||||
// (partial) settings
|
||||
FWRITE_STR(goodNameBuf);
|
||||
FWRITE_STR(md5Buf);
|
||||
size = cacheEntry.settings.GoodName.size();
|
||||
FWRITE(size);
|
||||
FWRITE_STR(goodNameBuf, size);
|
||||
size = cacheEntry.settings.MD5.size();
|
||||
FWRITE(size);
|
||||
FWRITE_STR(md5Buf, size);
|
||||
}
|
||||
#undef FWRITE
|
||||
#undef FWRITE_STR
|
||||
@@ -207,7 +266,7 @@ bool CoreHasRomHeaderAndSettingsCached(std::filesystem::path file)
|
||||
return get_cache_entry_iter(file) != l_CacheEntries.end();
|
||||
}
|
||||
|
||||
bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader& header, CoreRomSettings& settings)
|
||||
bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType& type, CoreRomHeader& header, CoreRomSettings& settings)
|
||||
{
|
||||
auto iter = get_cache_entry_iter(file);
|
||||
if (iter == l_CacheEntries.end())
|
||||
@@ -215,12 +274,13 @@ bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader
|
||||
return false;
|
||||
}
|
||||
|
||||
type = (*iter).type;
|
||||
header = (*iter).header;
|
||||
settings = (*iter).settings;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader header, CoreRomSettings settings)
|
||||
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType type, CoreRomHeader header, CoreRomSettings settings)
|
||||
{
|
||||
l_CacheEntry cacheEntry;
|
||||
|
||||
@@ -238,6 +298,7 @@ bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader
|
||||
|
||||
cacheEntry.fileName = file;
|
||||
cacheEntry.fileTime = osal_files_get_file_time(file);
|
||||
cacheEntry.type = type;
|
||||
cacheEntry.header = header;
|
||||
cacheEntry.settings = settings;
|
||||
|
||||
@@ -245,3 +306,10 @@ bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader
|
||||
l_CacheEntriesChanged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CoreClearRomHeaderAndSettingsCache(void)
|
||||
{
|
||||
l_CacheEntries.clear();
|
||||
l_CacheEntriesChanged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "Rom.hpp"
|
||||
#include "RomHeader.hpp"
|
||||
#include "RomSettings.hpp"
|
||||
|
||||
@@ -30,10 +31,14 @@ bool CoreHasRomHeaderAndSettingsCached(std::filesystem::path file);
|
||||
|
||||
// returns whether retrieving the rom header & settings
|
||||
// for given filename succeeds
|
||||
bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader& header, CoreRomSettings& settings);
|
||||
bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType& type, CoreRomHeader& header, CoreRomSettings& settings);
|
||||
|
||||
// returns whether adding cached rom header & settings
|
||||
// for given filename succeeds
|
||||
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader header, CoreRomSettings settings);
|
||||
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType type, CoreRomHeader header, CoreRomSettings settings);
|
||||
|
||||
// returns whether clearing rom header & settings cache
|
||||
// succeeds
|
||||
bool CoreClearRomHeaderAndSettingsCache(void);
|
||||
|
||||
#endif // CORE_CACHEDROMHEADERANDSETTINGS_HPP
|
||||
|
||||
@@ -9,13 +9,18 @@
|
||||
*/
|
||||
#define CORE_INTERNAL
|
||||
#include "Core.hpp"
|
||||
#include "ConvertStringEncoding.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
//
|
||||
// Local Variables
|
||||
//
|
||||
|
||||
static bool l_SetupCallbacks = false;
|
||||
static std::function<void(enum CoreDebugMessageType, std::string)> l_DebugCallbackFunc;
|
||||
static std::function<void(enum CoreDebugMessageType, std::string, std::string)> l_DebugCallbackFunc;
|
||||
static std::function<void(enum CoreStateCallbackType, int)> l_StateCallbackFunc;
|
||||
static bool l_PrintCallbacks = false;
|
||||
|
||||
//
|
||||
// Internal Functions
|
||||
@@ -28,21 +33,51 @@ void CoreDebugCallback(void* context, int level, const char* message)
|
||||
return;
|
||||
}
|
||||
|
||||
l_DebugCallbackFunc((CoreDebugMessageType)level, std::string(message));
|
||||
std::string contextString((const char*)context);
|
||||
std::string messageString(message);
|
||||
|
||||
// convert string encoding accordingly
|
||||
if (messageString.starts_with("IS64:"))
|
||||
{
|
||||
messageString = CoreConvertStringEncoding(message, CoreStringEncoding::EUC_JP);
|
||||
}
|
||||
else
|
||||
{
|
||||
messageString = CoreConvertStringEncoding(message, CoreStringEncoding::Shift_JIS);
|
||||
}
|
||||
|
||||
if (l_PrintCallbacks)
|
||||
{
|
||||
std::cout << contextString << messageString << std::endl;
|
||||
}
|
||||
|
||||
l_DebugCallbackFunc((CoreDebugMessageType)level, contextString, messageString);
|
||||
}
|
||||
|
||||
void CoreStateCallback(void* context, m64p_core_param param, int value)
|
||||
{
|
||||
// TODO
|
||||
if (!l_SetupCallbacks)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
l_StateCallbackFunc((CoreStateCallbackType)param, value);
|
||||
}
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string)> debugCallbackFunc)
|
||||
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string, std::string)> debugCallbackFunc,
|
||||
std::function<void(enum CoreStateCallbackType, int)> stateCallbackFunc)
|
||||
{
|
||||
l_DebugCallbackFunc = debugCallbackFunc;
|
||||
l_StateCallbackFunc = stateCallbackFunc;
|
||||
l_SetupCallbacks = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CoreSetPrintDebugCallback(bool enabled)
|
||||
{
|
||||
l_PrintCallbacks = enabled;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,26 @@ enum class CoreDebugMessageType
|
||||
Verbose = 5
|
||||
};
|
||||
|
||||
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string)> debugCallbackFunc);
|
||||
enum class CoreStateCallbackType
|
||||
{
|
||||
EmulationState = 1,
|
||||
VideoMode,
|
||||
SaveStateSlot,
|
||||
SpeedFactor,
|
||||
SpeedLimiter,
|
||||
VideoSize,
|
||||
AudioVolume,
|
||||
AudioMute,
|
||||
GamesharkInput,
|
||||
SaveStateLoaded,
|
||||
SaveStateSaved,
|
||||
};
|
||||
|
||||
// attempts to setup callbacks with the provided functions
|
||||
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string, std::string)> debugCallbackFunc,
|
||||
std::function<void(enum CoreStateCallbackType, int)> stateCallbackFunc);
|
||||
|
||||
// sets whether the debug callbacks will be printed to stdout
|
||||
void CoreSetPrintDebugCallback(bool enabled);
|
||||
|
||||
#endif // CORE_CALLBACK_HPP
|
||||
|
||||
@@ -717,6 +717,7 @@ bool CoreUpdateCheat(CoreCheat oldCheat, CoreCheat newCheat)
|
||||
CoreRomHeader romHeader;
|
||||
CoreRomSettings romSettings;
|
||||
std::filesystem::path cheatFilePath;
|
||||
CoreCheatOption cheatOption;
|
||||
|
||||
if (!CoreGetCurrentRomHeader(romHeader) ||
|
||||
!CoreGetCurrentRomSettings(romSettings))
|
||||
@@ -726,6 +727,23 @@ bool CoreUpdateCheat(CoreCheat oldCheat, CoreCheat newCheat)
|
||||
|
||||
cheatFilePath = get_user_cheat_file_path(romHeader, romSettings);
|
||||
|
||||
// copy over cheat settings when name has changed
|
||||
if (oldCheat.Name != newCheat.Name)
|
||||
{
|
||||
CoreEnableCheat(newCheat, CoreIsCheatEnabled(oldCheat));
|
||||
|
||||
// only set option to new cheat when
|
||||
// retrieving from old one succeeds
|
||||
if (CoreGetCheatOption(oldCheat, cheatOption))
|
||||
{
|
||||
CoreSetCheatOption(newCheat, cheatOption);
|
||||
}
|
||||
|
||||
// reset old cheat settings
|
||||
CoreEnableCheat(oldCheat, false);
|
||||
CoreResetCheatOption(oldCheat);
|
||||
}
|
||||
|
||||
// try to find old cheat in user cheats,
|
||||
// when it isnt found, it's most likely a system cheat
|
||||
auto iter = find_user_cheat_using_name(oldCheat.Name);
|
||||
@@ -892,6 +910,29 @@ bool CoreGetCheatOption(CoreCheat cheat, CoreCheatOption& option)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CoreResetCheatOption(CoreCheat cheat)
|
||||
{
|
||||
CoreRomSettings romSettings;
|
||||
std::string settingSection;
|
||||
std::string settingKey;
|
||||
|
||||
if (!cheat.HasOptions)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CoreGetCurrentRomSettings(romSettings))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
settingSection = romSettings.MD5 + " Cheats";
|
||||
settingKey = "Cheat \"" + cheat.Name + "\" Option";
|
||||
|
||||
CoreSettingsSetValue(settingSection, settingKey, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CoreApplyCheats(void)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
@@ -136,6 +136,9 @@ bool CoreSetCheatOption(CoreCheat cheat, CoreCheatOption option);
|
||||
// attempts to retrieve the currently's set cheat's option
|
||||
bool CoreGetCheatOption(CoreCheat cheat, CoreCheatOption& option);
|
||||
|
||||
// attempts to reset the cheat option
|
||||
bool CoreResetCheatOption(CoreCheat cheat);
|
||||
|
||||
// attempts to apply the enabled cheats to the currently opened ROM
|
||||
bool CoreApplyCheats(void);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define CORE_VERSION "${GIT_VERSION}"
|
||||
|
||||
#ifndef PORTABLE_INSTALL
|
||||
#define CORE_INSTAlL_PREFIX "${CMAKE_INSTALL_PREFIX}"
|
||||
#define CORE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
|
||||
#endif // PORTABLE_INSTALL
|
||||
|
||||
#endif // CORE_CONFIG_HPP
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define CORE_INTERNAL
|
||||
#include "ConvertStringEncoding.hpp"
|
||||
|
||||
#include "Error.hpp"
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include <iconv.h>
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
std::string CoreConvertStringEncoding(std::string str, CoreStringEncoding encoding)
|
||||
{
|
||||
std::string error;
|
||||
std::string encodingString;
|
||||
|
||||
iconv_t cd;
|
||||
|
||||
char inputBuf[256] = {0};
|
||||
char outputBuf[256] = {0};
|
||||
|
||||
char* inputBufPtr = (char*)str.c_str();
|
||||
char* outputBufPtr = outputBuf;
|
||||
|
||||
size_t inputBufSize = str.size();
|
||||
size_t outputBufSize = sizeof(outputBuf);
|
||||
|
||||
if (encoding == CoreStringEncoding::EUC_JP)
|
||||
{
|
||||
encodingString = "EUC-JP";
|
||||
}
|
||||
else
|
||||
{
|
||||
encodingString = "Shift_JIS";
|
||||
}
|
||||
|
||||
cd = iconv_open("UTF-8//TRANSLIT//IGNORE", encodingString.c_str());
|
||||
if (cd == (iconv_t)-1)
|
||||
{
|
||||
error = "CoreConvertStringEncoding Failed: ";
|
||||
error += "iconv_open Failed: ";
|
||||
error += errno;
|
||||
CoreSetError(error);
|
||||
return str;
|
||||
}
|
||||
|
||||
size_t ret = iconv(cd, &inputBufPtr, &inputBufSize, &outputBufPtr, &outputBufSize);
|
||||
if (ret == -1)
|
||||
{
|
||||
error = "CoreConvertStringEncoding Failed: ";
|
||||
error += "iconv Failed: ";
|
||||
error += errno;
|
||||
CoreSetError(error);
|
||||
|
||||
// reset iconv
|
||||
iconv(cd, nullptr, nullptr, nullptr, nullptr);
|
||||
iconv_close(cd);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// reset iconv
|
||||
iconv(cd, nullptr, nullptr, nullptr, nullptr);
|
||||
iconv_close(cd);
|
||||
|
||||
return std::string(outputBuf);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CORE_CONVERTSTRINGENCODING_HPP
|
||||
#define CORE_CONVERTSTRINGENCODING_HPP
|
||||
#ifdef CORE_INTERNAL
|
||||
|
||||
#include <string>
|
||||
|
||||
enum class CoreStringEncoding : int
|
||||
{
|
||||
EUC_JP = 0,
|
||||
Shift_JIS = 1
|
||||
};
|
||||
|
||||
// attempts to convert the string (which uses encoding) to UTF-8,
|
||||
// on failure, returns original string
|
||||
std::string CoreConvertStringEncoding(std::string str, CoreStringEncoding encoding);
|
||||
|
||||
#endif // CORE_INTERNAL
|
||||
#endif // CORE_CONVERTSTRINGENCODING_HPP
|
||||
@@ -9,35 +9,40 @@
|
||||
*/
|
||||
#define CORE_INTERNAL
|
||||
#include "Core.hpp"
|
||||
|
||||
#ifdef DISCORD_RPC
|
||||
#include "DiscordRpc.hpp"
|
||||
#endif // DISCORD_RPC
|
||||
#include "osal/osal_dynlib.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
#include "m64p/api/version.h"
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
//
|
||||
// Local Variables
|
||||
//
|
||||
|
||||
static osal_dynlib_lib_handle l_CoreLibHandle;
|
||||
static char l_CoreContextString[20];
|
||||
|
||||
//
|
||||
// Local Functions
|
||||
//
|
||||
|
||||
std::string find_core_lib(void)
|
||||
std::filesystem::path find_core_lib(void)
|
||||
{
|
||||
for (const auto& entry : std::filesystem::recursive_directory_iterator(CoreGetCoreDirectory()))
|
||||
{
|
||||
std::string path = entry.path().string();
|
||||
if (path.ends_with(OSAL_DYNLIB_LIB_EXT_STR))
|
||||
std::filesystem::path path = entry.path();
|
||||
if (path.has_extension() &&
|
||||
path.extension() == OSAL_DYNLIB_LIB_EXT_STR)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return std::filesystem::path();
|
||||
}
|
||||
|
||||
bool config_override_user_dirs(void)
|
||||
@@ -74,11 +79,14 @@ bool config_override_user_dirs(void)
|
||||
|
||||
bool CoreInit(void)
|
||||
{
|
||||
std::string error;
|
||||
std::string core_file;
|
||||
m64p_error m64p_ret;
|
||||
std::string error;
|
||||
std::filesystem::path core_file;
|
||||
m64p_error m64p_ret;
|
||||
bool ret = false;
|
||||
|
||||
// initialize context string
|
||||
std::strcpy(l_CoreContextString, "[CORE] ");
|
||||
|
||||
core_file = find_core_lib();
|
||||
if (core_file.empty())
|
||||
{
|
||||
@@ -87,7 +95,7 @@ bool CoreInit(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
l_CoreLibHandle = osal_dynlib_open(core_file.c_str());
|
||||
l_CoreLibHandle = osal_dynlib_open(core_file);
|
||||
if (l_CoreLibHandle == nullptr)
|
||||
{
|
||||
error = "osal_dynlib_open Failed: ";
|
||||
@@ -112,7 +120,7 @@ bool CoreInit(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
m64p_ret = m64p::Core.Startup(FRONTEND_API_VERSION, CoreGetUserConfigDirectory().string().c_str(), CoreGetSharedDataDirectory().string().c_str(), nullptr, CoreDebugCallback, nullptr, CoreStateCallback);
|
||||
m64p_ret = m64p::Core.Startup(FRONTEND_API_VERSION, CoreGetUserConfigDirectory().string().c_str(), CoreGetSharedDataDirectory().string().c_str(), (void*)l_CoreContextString, CoreDebugCallback, nullptr, CoreStateCallback);
|
||||
if (m64p_ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "CoreInit M64P::Core.Startup() Failed: ";
|
||||
@@ -153,6 +161,11 @@ bool CoreInit(void)
|
||||
|
||||
CoreReadRomHeaderAndSettingsCache();
|
||||
|
||||
#ifdef DISCORD_RPC
|
||||
CoreDiscordRpcInit();
|
||||
CoreDiscordRpcUpdate(false);
|
||||
#endif // DISCORD_RPC
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -186,6 +199,10 @@ void CoreShutdown(void)
|
||||
|
||||
CoreSaveRomHeaderAndSettingsCache();
|
||||
|
||||
#ifdef DISCORD_RPC
|
||||
CoreDiscordRpcShutdown();
|
||||
#endif // DISCORD_RPC
|
||||
|
||||
m64p::Core.Unhook();
|
||||
m64p::Config.Unhook();
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "CachedRomHeaderAndSettings.hpp"
|
||||
#include "Settings/Settings.hpp"
|
||||
#include "SpeedLimiter.hpp"
|
||||
#include "SpeedFactor.hpp"
|
||||
#include "RomSettings.hpp"
|
||||
#include "Directories.hpp"
|
||||
#include "MediaLoader.hpp"
|
||||
@@ -22,8 +23,10 @@
|
||||
#include "RomHeader.hpp"
|
||||
#include "Callback.hpp"
|
||||
#include "Plugins.hpp"
|
||||
#include "Version.hpp"
|
||||
#include "Cheats.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "Unzip.hpp"
|
||||
#include "Video.hpp"
|
||||
#include "Key.hpp"
|
||||
#include "Rom.hpp"
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Directories.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "Core.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
@@ -18,6 +18,14 @@
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
|
||||
//
|
||||
// Local Variables
|
||||
//
|
||||
|
||||
static std::filesystem::path l_CorePathOverride;
|
||||
static std::filesystem::path l_PluginPathOverride;
|
||||
static std::filesystem::path l_SharedDataPathOverride;
|
||||
|
||||
//
|
||||
// Local Functions
|
||||
//
|
||||
@@ -123,8 +131,15 @@ std::filesystem::path CoreGetCoreDirectory(void)
|
||||
#ifdef PORTABLE_INSTALL
|
||||
directory = "Core";
|
||||
#else // Not Portable
|
||||
directory = CORE_INSTAlL_PREFIX;
|
||||
directory += "/lib/RMG/Core";
|
||||
if (!l_CorePathOverride.empty())
|
||||
{
|
||||
directory = l_CorePathOverride;
|
||||
}
|
||||
else
|
||||
{
|
||||
directory = CORE_INSTALL_PREFIX;
|
||||
directory += "/lib/RMG/Core";
|
||||
}
|
||||
#endif // PORTABLE_INSTALL
|
||||
return directory;
|
||||
}
|
||||
@@ -135,8 +150,15 @@ std::filesystem::path CoreGetPluginDirectory(void)
|
||||
#ifdef PORTABLE_INSTALL
|
||||
directory = "Plugin";
|
||||
#else // Not Portable
|
||||
directory = CORE_INSTAlL_PREFIX;
|
||||
directory += "/lib/RMG/Plugin";
|
||||
if (!l_PluginPathOverride.empty())
|
||||
{
|
||||
directory = l_PluginPathOverride;
|
||||
}
|
||||
else
|
||||
{
|
||||
directory = CORE_INSTALL_PREFIX;
|
||||
directory += "/lib/RMG/Plugin";
|
||||
}
|
||||
#endif // PORTABLE_INSTALL
|
||||
return directory;
|
||||
}
|
||||
@@ -180,7 +202,7 @@ std::filesystem::path CoreGetDefaultSaveDirectory(void)
|
||||
#ifdef PORTABLE_INSTALL
|
||||
directory = "Save/Game";
|
||||
#else // Not Portable
|
||||
directory = CoreGetUserDataDirectory();
|
||||
directory = CoreGetDefaultUserDataDirectory();
|
||||
directory += "/Save/Game";
|
||||
#endif // PORTABLE_INSTALL
|
||||
return directory;
|
||||
@@ -192,7 +214,7 @@ std::filesystem::path CoreGetDefaultSaveStateDirectory(void)
|
||||
#ifdef PORTABLE_INSTALL
|
||||
directory = "Save/State";
|
||||
#else // Not Portable
|
||||
directory = CoreGetUserDataDirectory();
|
||||
directory = CoreGetDefaultUserDataDirectory();
|
||||
directory += "/Save/State";
|
||||
#endif // PORTABLE_INSTALL
|
||||
return directory;
|
||||
@@ -233,8 +255,15 @@ std::filesystem::path CoreGetSharedDataDirectory(void)
|
||||
#ifdef PORTABLE_INSTALL
|
||||
directory = "Data";
|
||||
#else // Not Portable
|
||||
directory = CORE_INSTAlL_PREFIX;
|
||||
directory += "/share/RMG";
|
||||
if (!l_SharedDataPathOverride.empty())
|
||||
{
|
||||
directory = l_SharedDataPathOverride;
|
||||
}
|
||||
else
|
||||
{
|
||||
directory = CORE_INSTALL_PREFIX;
|
||||
directory += "/share/RMG";
|
||||
}
|
||||
#endif // PORTABLE_INSTALL
|
||||
return directory;
|
||||
}
|
||||
@@ -253,3 +282,20 @@ std::filesystem::path CoreGetScreenshotDirectory(void)
|
||||
{
|
||||
return CoreSettingsGetStringValue(SettingsID::Core_ScreenshotPath);
|
||||
}
|
||||
|
||||
#ifndef PORTABLE_INSTALL
|
||||
void CoreSetCorePathOverride(std::filesystem::path path)
|
||||
{
|
||||
l_CorePathOverride = path;
|
||||
}
|
||||
|
||||
void CoreSetPluginPathOverride(std::filesystem::path path)
|
||||
{
|
||||
l_PluginPathOverride = path;
|
||||
}
|
||||
|
||||
void CoreSetSharedDataPathOverride(std::filesystem::path path)
|
||||
{
|
||||
l_SharedDataPathOverride = path;
|
||||
}
|
||||
#endif // PORTABLE_INSTALL
|
||||
|
||||
@@ -73,4 +73,13 @@ std::filesystem::path CoreGetSaveStateDirectory(void);
|
||||
// screenshots should be located
|
||||
std::filesystem::path CoreGetScreenshotDirectory(void);
|
||||
|
||||
// changes the core path to the given path
|
||||
void CoreSetCorePathOverride(std::filesystem::path path);
|
||||
|
||||
// changes the plugin path to the given path
|
||||
void CoreSetPluginPathOverride(std::filesystem::path path);
|
||||
|
||||
// changes the shared data path to the given path
|
||||
void CoreSetSharedDataPathOverride(std::filesystem::path path);
|
||||
|
||||
#endif // DIRECTORIES_HPP
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Settings/Settings.hpp"
|
||||
#include "DiscordRpc.hpp"
|
||||
#include "RomSettings.hpp"
|
||||
#include "RomHeader.hpp"
|
||||
|
||||
#include <../3rdParty/discord-rpc/include/discord_rpc.h>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <algorithm>
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
void CoreDiscordRpcInit(void)
|
||||
{
|
||||
if (!CoreSettingsGetBoolValue(SettingsID::GUI_DiscordRpc))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Discord_Initialize("801450412280119356", nullptr, 0, "");
|
||||
}
|
||||
|
||||
void CoreDiscordRpcShutdown(void)
|
||||
{
|
||||
Discord_Shutdown();
|
||||
}
|
||||
|
||||
void CoreDiscordRpcUpdate(bool inGame)
|
||||
{
|
||||
std::string smallImageKey;
|
||||
std::string largeImageKey;
|
||||
std::string details;
|
||||
|
||||
if (!CoreSettingsGetBoolValue(SettingsID::GUI_DiscordRpc))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (inGame)
|
||||
{
|
||||
CoreRomSettings romSettings;
|
||||
CoreRomHeader romHeader;
|
||||
|
||||
// make sure we retrieve the rom settings & header
|
||||
if (!CoreGetCurrentRomSettings(romSettings) ||
|
||||
!CoreGetCurrentRomHeader(romHeader))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
smallImageKey = "rmg-icon";
|
||||
largeImageKey = romHeader.Name;
|
||||
details = romSettings.GoodName;
|
||||
|
||||
// replace ' ' with '_' and replace '&' with '_'
|
||||
// also tolower the entire string
|
||||
std::replace(largeImageKey.begin(),largeImageKey.end(),' ','_');
|
||||
std::replace(largeImageKey.begin(),largeImageKey.end(),'&','_');
|
||||
std::transform(largeImageKey.begin(), largeImageKey.end(), largeImageKey.begin(), ::tolower);
|
||||
}
|
||||
else
|
||||
{
|
||||
largeImageKey = "rmg-icon";
|
||||
details = "Not in-game";
|
||||
}
|
||||
|
||||
DiscordRichPresence discordPresence;
|
||||
memset(&discordPresence, 0, sizeof(discordPresence));
|
||||
discordPresence.smallImageKey = smallImageKey.c_str();
|
||||
discordPresence.largeImageKey = largeImageKey.c_str();
|
||||
discordPresence.largeImageText = "Rosalie's Mupen GUI";
|
||||
discordPresence.details = details.c_str();
|
||||
discordPresence.startTimestamp = time(nullptr);
|
||||
|
||||
Discord_UpdatePresence(&discordPresence);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CORE_DISCORDRPC_HPP
|
||||
#define CORE_DISCORDRPC_HPP
|
||||
|
||||
// initializes the discord rpc library
|
||||
void CoreDiscordRpcInit(void);
|
||||
|
||||
// shuts down the discord rpc library
|
||||
void CoreDiscordRpcShutdown(void);
|
||||
|
||||
// updates the state of the discord rpc library
|
||||
void CoreDiscordRpcUpdate(bool inGame);
|
||||
|
||||
#endif // CORE_DISCORDRPC_HPP
|
||||
@@ -16,6 +16,9 @@
|
||||
#include "Cheats.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "Rom.hpp"
|
||||
#ifdef DISCORD_RPC
|
||||
#include "DiscordRpc.hpp"
|
||||
#endif // DISCORD_RPC
|
||||
|
||||
//
|
||||
// Local Functions
|
||||
@@ -51,6 +54,7 @@ static void apply_coresettings_overlay(void)
|
||||
CoreSettingsSetValue(SettingsID::Core_CountPerOp, CoreSettingsGetIntValue(SettingsID::CoreOverlay_CountPerOp));
|
||||
CoreSettingsSetValue(SettingsID::Core_CountPerOpDenomPot, CoreSettingsGetIntValue(SettingsID::CoreOverlay_CountPerOpDenomPot));
|
||||
CoreSettingsSetValue(SettingsID::Core_SiDmaDuration, CoreSettingsGetIntValue(SettingsID::CoreOverlay_SiDmaDuration));
|
||||
CoreSettingsSetValue(SettingsID::Core_SaveFileNameFormat, CoreSettingsGetIntValue(SettingsID::CoreOverLay_SaveFileNameFormat));
|
||||
}
|
||||
|
||||
static void apply_game_coresettings_overlay(void)
|
||||
@@ -87,7 +91,8 @@ static void apply_game_coresettings_overlay(void)
|
||||
bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64ddrom)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
m64p_error ret;
|
||||
CoreRomType type;
|
||||
|
||||
if (!CoreOpenRom(n64rom))
|
||||
{
|
||||
@@ -123,8 +128,20 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
|
||||
return false;
|
||||
}
|
||||
|
||||
// set disk file in media loader
|
||||
CoreMediaLoaderSetDiskFile(n64ddrom);
|
||||
if (!CoreGetRomType(type))
|
||||
{
|
||||
CoreClearCheats();
|
||||
CoreDetachPlugins();
|
||||
CoreApplyPluginSettings();
|
||||
CoreCloseRom();
|
||||
return false;
|
||||
}
|
||||
|
||||
// set disk file in media loader when ROM is a cartridge
|
||||
if (type == CoreRomType::Cartridge)
|
||||
{
|
||||
CoreMediaLoaderSetDiskFile(n64ddrom);
|
||||
}
|
||||
|
||||
// apply core settings overlay
|
||||
apply_coresettings_overlay();
|
||||
@@ -132,6 +149,10 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
|
||||
// apply game core settings overrides
|
||||
apply_game_coresettings_overlay();
|
||||
|
||||
#ifdef DISCORD_RPC
|
||||
CoreDiscordRpcUpdate(true);
|
||||
#endif // DISCORD_RPC
|
||||
|
||||
ret = m64p::Core.DoCommand(M64CMD_EXECUTE, 0, nullptr);
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
@@ -147,6 +168,13 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
|
||||
// restore plugin settings
|
||||
CoreApplyPluginSettings();
|
||||
|
||||
// reset media loader state
|
||||
CoreResetMediaLoader();
|
||||
|
||||
#ifdef DISCORD_RPC
|
||||
CoreDiscordRpcUpdate(false);
|
||||
#endif // DISCORD_RPC
|
||||
|
||||
return ret == M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +139,12 @@ bool CoreSetupMediaLoader(void)
|
||||
return ret == M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
void CoreMediaLoaderSetDiskFile(std::filesystem::path ddRom)
|
||||
void CoreResetMediaLoader(void)
|
||||
{
|
||||
l_DdDiskFile = ddRom;
|
||||
l_DdRomFile = "";
|
||||
}
|
||||
|
||||
void CoreMediaLoaderSetDiskFile(std::filesystem::path disk)
|
||||
{
|
||||
l_DdDiskFile = disk;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
// sets up the medialoader
|
||||
bool CoreSetupMediaLoader(void);
|
||||
|
||||
// resets media loader state
|
||||
void CoreResetMediaLoader(void);
|
||||
|
||||
// sets the media loader disk file
|
||||
void CoreMediaLoaderSetDiskFile(std::filesystem::path ddRom);
|
||||
void CoreMediaLoaderSetDiskFile(std::filesystem::path disk);
|
||||
|
||||
#endif // CORE_MEDIALOADER_HPP
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define CORE_INTERNAL
|
||||
#include "Plugins.hpp"
|
||||
#include "Callback.hpp"
|
||||
#include "Directories.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "Emulation.hpp"
|
||||
@@ -16,11 +18,13 @@
|
||||
|
||||
#include "m64p/PluginApi.hpp"
|
||||
#include "osal/osal_dynlib.hpp"
|
||||
#include "osal/osal_files.hpp"
|
||||
|
||||
#include "m64p/PluginApi.cpp"
|
||||
#include "m64p/Api.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <cstring>
|
||||
|
||||
//
|
||||
// Local Variables
|
||||
@@ -28,6 +32,7 @@
|
||||
|
||||
static m64p::PluginApi l_Plugins[(int)CorePluginType::Input];
|
||||
static std::string l_PluginFiles[(int)CorePluginType::Input];
|
||||
static char l_PluginContext[(int)CorePluginType::Input][20];
|
||||
|
||||
//
|
||||
// Local Functions
|
||||
@@ -101,6 +106,80 @@ std::string get_plugin_type_name(CorePluginType type)
|
||||
return name + " Plugin";
|
||||
}
|
||||
|
||||
std::string get_plugin_context_name(CorePluginType type)
|
||||
{
|
||||
std::string name;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
name = "[UNKNOWN]";
|
||||
break;
|
||||
case CorePluginType::Rsp:
|
||||
name = "[RSP] ";
|
||||
break;
|
||||
case CorePluginType::Gfx:
|
||||
name = "[GFX] ";
|
||||
break;
|
||||
case CorePluginType::Audio:
|
||||
name = "[AUDIO] ";
|
||||
break;
|
||||
case CorePluginType::Input:
|
||||
name = "[INPUT] ";
|
||||
break;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string get_plugin_path(CorePluginType type, std::string settingsValue)
|
||||
{
|
||||
std::string pluginPath;
|
||||
std::string path;
|
||||
std::string typeName;
|
||||
|
||||
// return an empty string when the value is empty
|
||||
if (settingsValue.empty())
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
pluginPath = CoreGetPluginDirectory().string();
|
||||
|
||||
// if the full plugin path is in the settings value,
|
||||
// we know it's the old type
|
||||
if (settingsValue.find(pluginPath) != std::string::npos)
|
||||
{
|
||||
return settingsValue;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CorePluginType::Rsp:
|
||||
typeName = "RSP";
|
||||
break;
|
||||
case CorePluginType::Gfx:
|
||||
typeName = "GFX";
|
||||
break;
|
||||
case CorePluginType::Audio:
|
||||
typeName = "Audio";
|
||||
break;
|
||||
case CorePluginType::Input:
|
||||
typeName = "Input";
|
||||
break;
|
||||
default:
|
||||
return path;
|
||||
}
|
||||
|
||||
path = pluginPath;
|
||||
path += OSAL_FILES_DIR_SEPERATOR_STR;
|
||||
path += typeName;
|
||||
path += OSAL_FILES_DIR_SEPERATOR_STR;
|
||||
path += settingsValue;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
bool apply_plugin_settings(std::string pluginSettings[4])
|
||||
{
|
||||
std::string error;
|
||||
@@ -112,14 +191,16 @@ bool apply_plugin_settings(std::string pluginSettings[4])
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
settingValue = pluginSettings[i];
|
||||
pluginType = (CorePluginType)(i + 1);
|
||||
settingValue = get_plugin_path(pluginType, pluginSettings[i]);
|
||||
if (settingValue.empty() ||
|
||||
!std::filesystem::is_regular_file(settingValue))
|
||||
{ // skip invalid setting value
|
||||
continue;
|
||||
}
|
||||
|
||||
pluginType = (CorePluginType)(i + 1);
|
||||
// copy context string to a c string using strcpy
|
||||
std::strcpy(l_PluginContext[(int)pluginType], get_plugin_context_name(pluginType).c_str());
|
||||
|
||||
if (settingValue != l_PluginFiles[i])
|
||||
{
|
||||
@@ -179,7 +260,7 @@ bool apply_plugin_settings(std::string pluginSettings[4])
|
||||
}
|
||||
|
||||
// attempt to start plugin
|
||||
ret = plugin->Startup(m64p::Core.GetHandle(), nullptr, nullptr);
|
||||
ret = plugin->Startup(m64p::Core.GetHandle(), (void*)l_PluginContext[(int)pluginType], CoreDebugCallback);
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "apply_plugin_settings (";
|
||||
@@ -204,6 +285,78 @@ bool apply_plugin_settings(std::string pluginSettings[4])
|
||||
return true;
|
||||
}
|
||||
|
||||
bool open_plugin_config(CorePluginType type, bool romConfig)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
bool resumeEmulation = false;
|
||||
m64p::PluginApi* plugin;
|
||||
std::string functionName;
|
||||
|
||||
if (!romConfig && !CorePluginsHasConfig(type))
|
||||
{
|
||||
error = "open_plugin_config Failed: ";
|
||||
error += get_plugin_type_name(type);
|
||||
error += " doesn't have the config or config2 function!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
else if (romConfig && !CorePluginsHasROMConfig(type))
|
||||
{
|
||||
error = "open_plugin_config Failed: ";
|
||||
error += get_plugin_type_name(type);
|
||||
error += " doesn't support ROM specific configuration!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// try to pause emulation,
|
||||
// when emulation is running
|
||||
// and try to resume afterwards
|
||||
if (CoreIsEmulationRunning())
|
||||
{
|
||||
// only resume emulation
|
||||
// after running the config function
|
||||
// when pausing succeeds
|
||||
resumeEmulation = CorePauseEmulation();
|
||||
}
|
||||
|
||||
plugin = get_plugin(type);
|
||||
|
||||
// check if the plugin has the Config2
|
||||
// or Config function, the Config2 function
|
||||
// has priority
|
||||
if (plugin->Config2 != nullptr)
|
||||
{
|
||||
ret = plugin->Config2(romConfig ? 1 : 0);
|
||||
functionName = "Config2";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = plugin->Config();
|
||||
functionName = "Config";
|
||||
}
|
||||
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "CorePluginsOpenConfig (";
|
||||
error += get_plugin_type_name(type);
|
||||
error += ")->";
|
||||
error += functionName;
|
||||
error += "() Failed: ";
|
||||
error += m64p::Core.ErrorMessage(ret);
|
||||
CoreSetError(error);
|
||||
}
|
||||
|
||||
// try to resume emulation when needed
|
||||
if (resumeEmulation)
|
||||
{
|
||||
CoreResumeEmulation();
|
||||
}
|
||||
|
||||
return ret == M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
@@ -219,6 +372,7 @@ std::vector<CorePlugin> CoreGetAllPlugins(void)
|
||||
for (const auto& entry : std::filesystem::recursive_directory_iterator(CoreGetPluginDirectory()))
|
||||
{
|
||||
std::string path = entry.path().string();
|
||||
std::string file = entry.path().filename().string();
|
||||
if (!entry.is_directory() &&
|
||||
path.ends_with(OSAL_DYNLIB_LIB_EXT_STR))
|
||||
{
|
||||
@@ -239,7 +393,7 @@ std::vector<CorePlugin> CoreGetAllPlugins(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
CorePlugin corePlugin = {path, plugin_name, plugin_type};
|
||||
CorePlugin corePlugin = {file, plugin_name, plugin_type};
|
||||
plugins.emplace_back(corePlugin);
|
||||
}
|
||||
}
|
||||
@@ -302,52 +456,33 @@ bool CoreArePluginsReady(void)
|
||||
|
||||
bool CorePluginsHasConfig(CorePluginType type)
|
||||
{
|
||||
return get_plugin(type)->Config != nullptr;
|
||||
m64p::PluginApi* plugin;
|
||||
|
||||
plugin = get_plugin(type);
|
||||
|
||||
return plugin->Config != nullptr ||
|
||||
plugin->Config2 != nullptr;
|
||||
}
|
||||
|
||||
bool CorePluginsOpenConfig(CorePluginType type)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
bool resumeEmulation = false;
|
||||
return open_plugin_config(type, false);
|
||||
}
|
||||
|
||||
if (!CorePluginsHasConfig(type))
|
||||
{
|
||||
error = "CorePluginsOpenConfig Failed: ";
|
||||
error += get_plugin_type_name(type);
|
||||
error += " doesn't have config function!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
bool CorePluginsHasROMConfig(CorePluginType type)
|
||||
{
|
||||
m64p::PluginApi* plugin;
|
||||
|
||||
// try to pause emulation,
|
||||
// when emulation is running
|
||||
// and try to resume afterwards
|
||||
if (CoreIsEmulationRunning())
|
||||
{
|
||||
// only resume emulation
|
||||
// after running the config function
|
||||
// when pausing succeeds
|
||||
resumeEmulation = CorePauseEmulation();
|
||||
}
|
||||
plugin = get_plugin(type);
|
||||
|
||||
ret = get_plugin(type)->Config();
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "CorePluginsOpenConfig (";
|
||||
error += get_plugin_type_name(type);
|
||||
error += ")->Config() Failed: ";
|
||||
error += m64p::Core.ErrorMessage(ret);
|
||||
CoreSetError(error);
|
||||
}
|
||||
return plugin->Config2 != nullptr &&
|
||||
plugin->Config2HasRomConfig != nullptr &&
|
||||
plugin->Config2HasRomConfig() > 0;
|
||||
}
|
||||
|
||||
// try to resume emulation when needed
|
||||
if (resumeEmulation)
|
||||
{
|
||||
CoreResumeEmulation();
|
||||
}
|
||||
|
||||
return ret == M64ERR_SUCCESS;
|
||||
bool CorePluginsOpenROMConfig(CorePluginType type)
|
||||
{
|
||||
return open_plugin_config(type, true);
|
||||
}
|
||||
|
||||
bool CoreAttachPlugins(void)
|
||||
|
||||
@@ -52,6 +52,14 @@ bool CorePluginsHasConfig(CorePluginType type);
|
||||
// used plugin of given type
|
||||
bool CorePluginsOpenConfig(CorePluginType type);
|
||||
|
||||
// returns wether the currently used plugin
|
||||
// of the given type has a ROM config GUI
|
||||
bool CorePluginsHasROMConfig(CorePluginType type);
|
||||
|
||||
// opens the ROM config GUI for the currently
|
||||
// used plugin of given type
|
||||
bool CorePluginsOpenROMConfig(CorePluginType type);
|
||||
|
||||
// attaches all used plugins
|
||||
bool CoreAttachPlugins(void);
|
||||
|
||||
|
||||
@@ -8,15 +8,29 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Rom.hpp"
|
||||
#include "Directories.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "MediaLoader.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
#include "RomSettings.hpp"
|
||||
#include "Cheats.hpp"
|
||||
#include "osal/osal_files.hpp"
|
||||
|
||||
// 7-Zip includes
|
||||
#include "../3rdParty/7-Zip/C/7zTypes.h"
|
||||
#include "../3rdParty/7-Zip/C/7z.h"
|
||||
#include "../3rdParty/7-Zip/C/7zAlloc.h"
|
||||
#include "../3rdParty/7-Zip/C/7zBuf.h"
|
||||
#include "../3rdParty/7-Zip/C/7zCrc.h"
|
||||
#include "../3rdParty/7-Zip/C/7zFile.h"
|
||||
#include "../3rdParty/7-Zip/C/7zVersion.h"
|
||||
|
||||
#include <string>
|
||||
#include <unzip.h>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
//
|
||||
// Local Defines
|
||||
@@ -28,31 +42,136 @@
|
||||
// Local Variables
|
||||
//
|
||||
|
||||
static bool l_HasRomOpen = false;
|
||||
static bool l_HasRomOpen = false;
|
||||
static bool l_HasDisk = false;
|
||||
static bool l_HasExtractedDisk = false;
|
||||
static std::filesystem::path l_ExtractedDiskPath;
|
||||
|
||||
//
|
||||
// Local Functions
|
||||
//
|
||||
|
||||
static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
|
||||
static std::string to_lower_str(std::string str)
|
||||
{
|
||||
std::string resultString = str;
|
||||
|
||||
std::transform(resultString.begin(), resultString.end(), resultString.begin(),
|
||||
[](unsigned char c)
|
||||
{
|
||||
return std::tolower(c);
|
||||
}
|
||||
);
|
||||
|
||||
return resultString;
|
||||
}
|
||||
|
||||
static voidpf zlib_filefunc_open(voidpf opaque, const void* filename, int mode)
|
||||
{
|
||||
std::filesystem::path path = *(std::filesystem::path*)filename;
|
||||
|
||||
// we need a static filestream
|
||||
static std::ifstream fileStream;
|
||||
|
||||
// attempt to open file
|
||||
fileStream.open(path, std::ios::binary);
|
||||
if (!fileStream.is_open())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (voidpf)&fileStream;
|
||||
}
|
||||
|
||||
static uLong zlib_filefunc_read(voidpf opaque, voidpf stream, void* buf, uLong size)
|
||||
{
|
||||
std::ifstream* fileStream = (std::ifstream*)stream;
|
||||
fileStream->read((char*)buf, size);
|
||||
return fileStream->fail() ? 0 : size;
|
||||
}
|
||||
|
||||
static ZPOS64_T zlib_filefunc_tell(voidpf opaque, voidpf stream)
|
||||
{
|
||||
std::ifstream* fileStream = (std::ifstream*)stream;
|
||||
return fileStream->tellg();
|
||||
}
|
||||
|
||||
static long zlib_filefunc_seek(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)
|
||||
{
|
||||
std::ifstream* fileStream = (std::ifstream*)stream;
|
||||
std::ios_base::seekdir seekOrigin;
|
||||
|
||||
switch (origin)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case ZLIB_FILEFUNC_SEEK_CUR:
|
||||
seekOrigin = std::ios::cur;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_END:
|
||||
seekOrigin = std::ios::end;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_SET:
|
||||
seekOrigin = std::ios::beg;
|
||||
break;
|
||||
}
|
||||
|
||||
fileStream->seekg(offset, seekOrigin);
|
||||
return fileStream->fail() ? -1 : 0;
|
||||
}
|
||||
|
||||
static int zlib_filefunc_close(voidpf opaque, voidpf stream)
|
||||
{
|
||||
std::ifstream* fileStream = (std::ifstream*)stream;
|
||||
fileStream->close();
|
||||
return fileStream->fail() ? -1 : 0;
|
||||
}
|
||||
|
||||
static int zlib_filefunc_testerror(voidpf opaque, voidpf stream)
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
static bool read_zip_file(std::filesystem::path file, std::filesystem::path* extractedFileName, bool* isDisk, char** buf, int* size)
|
||||
{
|
||||
std::string error;
|
||||
std::fstream fileStream;
|
||||
int fileStreamLen;
|
||||
char* fileStreamBuf;
|
||||
|
||||
unzFile zipFile;
|
||||
unz_global_info zipInfo;
|
||||
unzFile zipFile;
|
||||
unz_global_info64 zipInfo;
|
||||
|
||||
zipFile = unzOpen(file.string().c_str());
|
||||
zlib_filefunc64_def filefuncs;
|
||||
filefuncs.zopen64_file = zlib_filefunc_open;
|
||||
filefuncs.zread_file = zlib_filefunc_read;
|
||||
filefuncs.zwrite_file = nullptr;
|
||||
filefuncs.ztell64_file = zlib_filefunc_tell;
|
||||
filefuncs.zseek64_file = zlib_filefunc_seek;
|
||||
filefuncs.zclose_file = zlib_filefunc_close;
|
||||
filefuncs.zerror_file = zlib_filefunc_testerror;
|
||||
filefuncs.opaque = nullptr;
|
||||
|
||||
zipFile = unzOpen2_64((const void*)&file, &filefuncs);
|
||||
if (zipFile == nullptr)
|
||||
{
|
||||
error = "read_zip_file: unzOpen Failed!";
|
||||
if (errno == 0)
|
||||
{
|
||||
error = "read_zip_file: unzOpen Failed!";
|
||||
}
|
||||
else
|
||||
{
|
||||
error = "read_zip_file: unzOpen Failed: ";
|
||||
error += "failed to open file: ";
|
||||
error += strerror(errno);
|
||||
error += " (";
|
||||
error += std::to_string(errno);
|
||||
error += ")";
|
||||
}
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (unzGetGlobalInfo(zipFile, &zipInfo) != UNZ_OK)
|
||||
if (unzGetGlobalInfo64(zipFile, &zipInfo) != UNZ_OK)
|
||||
{
|
||||
error = "read_zip_file: unzGetGlobalInfo Failed!";
|
||||
CoreSetError(error);
|
||||
@@ -74,9 +193,13 @@ static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
|
||||
// make sure file has supported file format,
|
||||
// if it does, read it in memory
|
||||
std::filesystem::path fileNamePath(fileName);
|
||||
if (fileNamePath.extension() == ".z64" ||
|
||||
fileNamePath.extension() == ".v64" ||
|
||||
fileNamePath.extension() == ".n64")
|
||||
std::string fileExtension = fileNamePath.has_extension() ? fileNamePath.extension().string() : "";
|
||||
fileExtension = to_lower_str(fileExtension);
|
||||
if (fileExtension == ".z64" ||
|
||||
fileExtension == ".v64" ||
|
||||
fileExtension == ".n64" ||
|
||||
fileExtension == ".ndd" ||
|
||||
fileExtension == ".d64")
|
||||
{
|
||||
char* buffer;
|
||||
char* outBuffer;
|
||||
@@ -148,8 +271,10 @@ static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
|
||||
}
|
||||
} while (bytes_read > 0);
|
||||
|
||||
*size = total_bytes_read;
|
||||
*buf = outBuffer;
|
||||
*size = total_bytes_read;
|
||||
*buf = outBuffer;
|
||||
*extractedFileName = fileNamePath;
|
||||
*isDisk = (fileExtension == ".ndd" || fileExtension == ".d64");
|
||||
unzCloseCurrentFile(zipFile);
|
||||
unzClose(zipFile);
|
||||
free(buffer);
|
||||
@@ -178,19 +303,172 @@ static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool read_raw_file(std::filesystem::path file, char** buf, int* size)
|
||||
static bool read_7zip_file(std::filesystem::path file, std::filesystem::path* extractedFileName, bool* isDisk, char** buf, int* size)
|
||||
{
|
||||
std::string error;
|
||||
std::fstream fileStream;
|
||||
int fileStreamLen;
|
||||
char* fileStreamBuf;
|
||||
|
||||
const ISzAlloc alloc = { SzAlloc, SzFree };
|
||||
const size_t bufSize = ((size_t)1 << 18);
|
||||
|
||||
ISzAlloc allocImp;
|
||||
ISzAlloc allocTempImp;
|
||||
|
||||
CFileInStream archiveStream;
|
||||
CLookToRead2 lookStream;
|
||||
CSzArEx db;
|
||||
SRes res;
|
||||
|
||||
// initialize allocator
|
||||
allocImp = alloc;
|
||||
allocTempImp = alloc;
|
||||
|
||||
// try to open file
|
||||
#ifdef _WIN32
|
||||
WRes wres = InFile_OpenW(&archiveStream.file, file.wstring().c_str());
|
||||
#else
|
||||
WRes wres = InFile_Open(&archiveStream.file, file.string().c_str());
|
||||
#endif // _WIN32
|
||||
if (wres != 0)
|
||||
{
|
||||
error = "read_7zip_file Failed: InFile_Open Failed: ";
|
||||
error += std::to_string(wres);
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// create vtables for streams
|
||||
FileInStream_CreateVTable(&archiveStream);
|
||||
archiveStream.wres = 0;
|
||||
LookToRead2_CreateVTable(&lookStream, 0);
|
||||
lookStream.buf = nullptr;
|
||||
|
||||
// allocate memory look reader
|
||||
lookStream.buf = (Byte*)ISzAlloc_Alloc(&allocImp, bufSize);
|
||||
if (lookStream.buf == nullptr)
|
||||
{
|
||||
error = "read_7zip_file Failed: ISzAlloc_Alloc Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// initialize look reader
|
||||
lookStream.bufSize = bufSize;
|
||||
lookStream.realStream = &archiveStream.vt;
|
||||
LookToRead2_Init(&lookStream);
|
||||
|
||||
// initialize CRC table
|
||||
CrcGenerateTable();
|
||||
|
||||
// initialize archive
|
||||
SzArEx_Init(&db);
|
||||
|
||||
// try to open file
|
||||
res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
|
||||
if (res != SZ_OK)
|
||||
{
|
||||
error = "read_7zip_file Failed: SzArEx_Open Failed: ";
|
||||
error += std::to_string(res);
|
||||
CoreSetError(error);
|
||||
SzArEx_Free(&db, &allocImp);
|
||||
ISzAlloc_Free(&allocImp, lookStream.buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < db.NumFiles; i++)
|
||||
{
|
||||
size_t filename_size = 0;
|
||||
uint16_t fileName[PATH_MAX];
|
||||
|
||||
// skip directories
|
||||
if (SzArEx_IsDir(&db, i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip when filename size exceeds our buffer size
|
||||
filename_size = SzArEx_GetFileNameUtf16(&db, i, nullptr);
|
||||
if (filename_size > PATH_MAX)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SzArEx_GetFileNameUtf16(&db, i, fileName);
|
||||
|
||||
std::filesystem::path fileNamePath((char16_t*)fileName);
|
||||
std::string fileExtension = fileNamePath.has_extension() ? fileNamePath.extension().string() : "";
|
||||
fileExtension = to_lower_str(fileExtension);
|
||||
if (fileExtension == ".z64" ||
|
||||
fileExtension == ".v64" ||
|
||||
fileExtension == ".n64" ||
|
||||
fileExtension == ".ndd" ||
|
||||
fileExtension == ".d64")
|
||||
{
|
||||
uint32_t blockIndex = 0xFFFFFFFF;
|
||||
uint8_t* outBuffer = nullptr;
|
||||
size_t outBufferSize = 0;
|
||||
size_t offset = 0;
|
||||
size_t outSizeProcessed = 0;
|
||||
|
||||
res = SzArEx_Extract(&db, &lookStream.vt, i,
|
||||
&blockIndex, &outBuffer, &outBufferSize,
|
||||
&offset, &outSizeProcessed,
|
||||
&allocImp, &allocTempImp);
|
||||
if (res != SZ_OK)
|
||||
{
|
||||
error = "read_7zip_file Failed: SzArEx_Extract Failed: ";
|
||||
error += std::to_string(res);
|
||||
CoreSetError(error);
|
||||
|
||||
SzArEx_Free(&db, &allocImp);
|
||||
ISzAlloc_Free(&allocImp, lookStream.buf);
|
||||
File_Close(&archiveStream.file);
|
||||
ISzAlloc_Free(&allocImp, outBuffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
*size = outSizeProcessed;
|
||||
// we have to memcpy it into buf, otherwise
|
||||
// the free() in CoreOpenRom() crashes
|
||||
*buf = (char*)malloc(outSizeProcessed);
|
||||
memcpy(*buf, (outBuffer + offset), outSizeProcessed);
|
||||
*extractedFileName = fileNamePath;
|
||||
*isDisk = (fileExtension == ".ndd" || fileExtension == ".d64");
|
||||
|
||||
SzArEx_Free(&db, &allocImp);
|
||||
ISzAlloc_Free(&allocImp, lookStream.buf);
|
||||
File_Close(&archiveStream.file);
|
||||
ISzAlloc_Free(&allocImp, outBuffer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup
|
||||
SzArEx_Free(&db, &allocImp);
|
||||
ISzAlloc_Free(&allocImp, lookStream.buf);
|
||||
File_Close(&archiveStream.file);
|
||||
|
||||
error = "read_7zip_file Failed: no valid ROMs found in 7zip!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool read_raw_file(std::filesystem::path file, char** buf, int* size)
|
||||
{
|
||||
std::string error;
|
||||
std::ifstream fileStream;
|
||||
int fileStreamLen;
|
||||
char* fileStreamBuf;
|
||||
|
||||
// attempt to open file
|
||||
fileStream.open(file);
|
||||
fileStream.open(file, std::ios::binary);
|
||||
if (!fileStream.is_open())
|
||||
{
|
||||
error = "read_raw_file Failed: ";
|
||||
error += "failed to open file!";
|
||||
error += "failed to open file: ";
|
||||
error += strerror(errno);
|
||||
error += " (";
|
||||
error += std::to_string(errno);
|
||||
error += ")";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
@@ -222,6 +500,31 @@ static bool read_raw_file(std::filesystem::path file, char** buf, int* size)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_file(std::filesystem::path file, char* buf, int size)
|
||||
{
|
||||
std::string error;
|
||||
std::ofstream fileStream;
|
||||
|
||||
// attempt to open file
|
||||
fileStream.open(file, std::ios::binary);
|
||||
if (!fileStream.is_open())
|
||||
{
|
||||
error = "write_file Failed: ";
|
||||
error += "failed to open file: ";
|
||||
error += strerror(errno);
|
||||
error += " (";
|
||||
error += std::to_string(errno);
|
||||
error += ")";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// write buffer to file
|
||||
fileStream.write(buf, size);
|
||||
fileStream.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
@@ -230,8 +533,9 @@ bool CoreOpenRom(std::filesystem::path file)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
char* buf;
|
||||
int buf_size;
|
||||
char* buf = nullptr;
|
||||
int buf_size = 0;
|
||||
std::string file_extension;
|
||||
|
||||
if (!m64p::Core.IsHooked())
|
||||
{
|
||||
@@ -246,12 +550,78 @@ bool CoreOpenRom(std::filesystem::path file)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.has_extension() && file.extension() == ".zip")
|
||||
file_extension = file.has_extension() ? file.extension().string() : "";
|
||||
file_extension = to_lower_str(file_extension);
|
||||
|
||||
if (file_extension == ".zip" ||
|
||||
file_extension == ".7z")
|
||||
{
|
||||
if (!read_zip_file(file, &buf, &buf_size))
|
||||
std::filesystem::path extracted_file;
|
||||
bool is_disk = false;
|
||||
|
||||
if (file_extension == ".zip")
|
||||
{
|
||||
return false;
|
||||
if (!read_zip_file(file, &extracted_file, &is_disk, &buf, &buf_size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!read_7zip_file(file, &extracted_file, &is_disk, &buf, &buf_size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_disk)
|
||||
{
|
||||
std::filesystem::path disk_file;
|
||||
disk_file = CoreGetUserCacheDirectory();
|
||||
disk_file += "/extracted_disks/";
|
||||
disk_file += extracted_file.filename();
|
||||
|
||||
// attempt to create extraction directory
|
||||
try
|
||||
{
|
||||
if (!std::filesystem::exists(disk_file.parent_path()))
|
||||
{
|
||||
if (!std::filesystem::create_directory(disk_file.parent_path()))
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = "CoreOpenRom Failed: ";
|
||||
error += "Failed to create \"";
|
||||
error += disk_file.parent_path().string();
|
||||
error += "\"!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// attempt to write temporary file
|
||||
if (!write_file(disk_file, buf, buf_size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CoreMediaLoaderSetDiskFile(disk_file);
|
||||
|
||||
l_ExtractedDiskPath = disk_file;
|
||||
}
|
||||
|
||||
l_HasDisk = is_disk;
|
||||
l_HasExtractedDisk = is_disk;
|
||||
}
|
||||
else if (file_extension == ".d64" ||
|
||||
file_extension == ".ndd")
|
||||
{
|
||||
CoreMediaLoaderSetDiskFile(file);
|
||||
l_HasDisk = true;
|
||||
l_HasExtractedDisk = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -259,17 +629,29 @@ bool CoreOpenRom(std::filesystem::path file)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
l_HasDisk = false;
|
||||
l_HasExtractedDisk = false;
|
||||
}
|
||||
|
||||
if (l_HasDisk)
|
||||
{
|
||||
ret = m64p::Core.DoCommand(M64CMD_DISK_OPEN, 0, nullptr);
|
||||
error = "CoreOpenRom: m64p::Core.DoCommand(M64CMD_DISK_OPEN) Failed: ";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = m64p::Core.DoCommand(M64CMD_ROM_OPEN, buf_size, buf);
|
||||
error = "CoreOpenRom: m64p::Core.DoCommand(M64CMD_ROM_OPEN) Failed: ";
|
||||
free(buf);
|
||||
}
|
||||
|
||||
ret = m64p::Core.DoCommand(M64CMD_ROM_OPEN, buf_size, buf);
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "CoreOpenRom: m64p::Core.DoCommand(M64CMD_ROM_OPEN) Failed: ";
|
||||
error += m64p::Core.ErrorMessage(ret);
|
||||
CoreSetError(error);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
l_HasRomOpen = (ret == M64ERR_SUCCESS);
|
||||
|
||||
if (l_HasRomOpen)
|
||||
@@ -288,6 +670,22 @@ bool CoreHasRomOpen(void)
|
||||
return l_HasRomOpen;
|
||||
}
|
||||
|
||||
bool CoreGetRomType(CoreRomType& type)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
if (!l_HasRomOpen)
|
||||
{
|
||||
error = "CoreGetRomType Failed: ";
|
||||
error += "cannot retrieve ROM type when no ROM has been opened!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
type = l_HasDisk ? CoreRomType::Disk : CoreRomType::Cartridge;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CoreCloseRom(void)
|
||||
{
|
||||
std::string error;
|
||||
@@ -311,10 +709,19 @@ bool CoreCloseRom(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = m64p::Core.DoCommand(M64CMD_ROM_CLOSE, 0, nullptr);
|
||||
if (l_HasDisk)
|
||||
{
|
||||
ret = m64p::Core.DoCommand(M64CMD_DISK_CLOSE, 0, nullptr);
|
||||
error = "CoreCloseRom: m64p::Core.DoCommand(M64CMD_DISK_CLOSE) Failed: ";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = m64p::Core.DoCommand(M64CMD_ROM_CLOSE, 0, nullptr);
|
||||
error = "CoreCloseRom: m64p::Core.DoCommand(M64CMD_ROM_CLOSE) Failed: ";
|
||||
}
|
||||
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "CoreCloseRom: m64p::Core.DoCommand(M64CMD_ROM_CLOSE) Failed: ";
|
||||
error += m64p::Core.ErrorMessage(ret);
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
@@ -323,6 +730,32 @@ bool CoreCloseRom(void)
|
||||
// clear default ROM settings
|
||||
CoreClearCurrentDefaultRomSettings();
|
||||
|
||||
// if removing the temporary extracted disk file
|
||||
// fails, then we shouldn't break the state of
|
||||
// whether we currently have an open ROM/disk,
|
||||
// so we can safely say the ROM/disk isn't open
|
||||
// anymore here
|
||||
l_HasRomOpen = false;
|
||||
|
||||
// attempt to clean temporary extracted disk file
|
||||
if (l_HasExtractedDisk)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!std::filesystem::remove(l_ExtractedDiskPath))
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = "CoreCloseRom: Failed to remove \"";
|
||||
error += l_ExtractedDiskPath.string();
|
||||
error += "\"!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -12,12 +12,21 @@
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
enum class CoreRomType
|
||||
{
|
||||
Cartridge = 0,
|
||||
Disk = 1
|
||||
};
|
||||
|
||||
// opens the given file as ROM
|
||||
bool CoreOpenRom(std::filesystem::path file);
|
||||
|
||||
// returns whether core has a ROM opened
|
||||
bool CoreHasRomOpen(void);
|
||||
|
||||
// attempts to retrieve the ROM type
|
||||
bool CoreGetRomType(CoreRomType& type);
|
||||
|
||||
// closes ROM
|
||||
bool CoreCloseRom(void);
|
||||
|
||||
|
||||
@@ -13,12 +13,105 @@
|
||||
#include <arpa/inet.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#define CORE_INTERNAL
|
||||
#include "RomHeader.hpp"
|
||||
#include "ConvertStringEncoding.hpp"
|
||||
#include "Emulation.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "Rom.hpp"
|
||||
|
||||
//
|
||||
// Local Functions
|
||||
//
|
||||
|
||||
static std::string get_gameid_from_header(m64p_rom_header header)
|
||||
{
|
||||
std::string gameID;
|
||||
|
||||
if (header.Manufacturer_ID == 0)
|
||||
{
|
||||
return "????";
|
||||
}
|
||||
|
||||
gameID.push_back(char(ntohl(header.Manufacturer_ID)));
|
||||
gameID.push_back(char(header.Cartridge_ID % 256));
|
||||
gameID.push_back(char(header.Cartridge_ID / 256));
|
||||
gameID.push_back(char(header.Country_code));
|
||||
|
||||
return gameID;
|
||||
}
|
||||
|
||||
static std::string get_region_from_countrycode(char countryCode)
|
||||
{
|
||||
std::string region;
|
||||
|
||||
switch (countryCode)
|
||||
{
|
||||
case 'A':
|
||||
region = "Region-Free";
|
||||
break;
|
||||
case 'B':
|
||||
region = "Brazil";
|
||||
break;
|
||||
case 'C':
|
||||
region = "China";
|
||||
break;
|
||||
case 'D':
|
||||
region = "Germany";
|
||||
break;
|
||||
case 'E':
|
||||
region = "North America";
|
||||
break;
|
||||
case 'F':
|
||||
region = "France";
|
||||
break;
|
||||
case 'G':
|
||||
region = "Gateway 64 (NTSC)";
|
||||
break;
|
||||
case 'H':
|
||||
region = "Netherlands";
|
||||
break;
|
||||
case 'I':
|
||||
region = "Italy";
|
||||
break;
|
||||
case 'J':
|
||||
region = "Japan";
|
||||
break;
|
||||
case 'K':
|
||||
region = "Korea";
|
||||
break;
|
||||
case 'L':
|
||||
region = "Gateway 64 (PAL)";
|
||||
break;
|
||||
case 'N':
|
||||
region = "Canada";
|
||||
break;
|
||||
case 'P':
|
||||
case 'X':
|
||||
region = "Europe/Australia";
|
||||
break;
|
||||
case 'S':
|
||||
region = "Spain";
|
||||
break;
|
||||
case 'U':
|
||||
region = "Australia";
|
||||
break;
|
||||
case 'W':
|
||||
region = "Scandanavia";
|
||||
break;
|
||||
case 'Y':
|
||||
case 'Z':
|
||||
region = "Europe";
|
||||
break;
|
||||
default:
|
||||
region = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
@@ -46,6 +139,9 @@ bool CoreGetCurrentRomHeader(CoreRomHeader& header)
|
||||
header.CRC1 = ntohl(m64p_header.CRC1);
|
||||
header.CRC2 = ntohl(m64p_header.CRC2);
|
||||
header.CountryCode = m64p_header.Country_code;
|
||||
header.Name = std::string((char*)m64p_header.Name);
|
||||
header.Name = CoreConvertStringEncoding((char*)m64p_header.Name, CoreStringEncoding::Shift_JIS);
|
||||
header.GameID = get_gameid_from_header(m64p_header);
|
||||
header.Region = get_region_from_countrycode((char)header.CountryCode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ struct CoreRomHeader
|
||||
uint32_t CRC2;
|
||||
uint32_t CountryCode;
|
||||
std::string Name;
|
||||
std::string GameID;
|
||||
std::string Region;
|
||||
};
|
||||
|
||||
// retrieves the currently opened ROM header
|
||||
|
||||
@@ -7,13 +7,16 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define CORE_INTERNAL
|
||||
#include "RomSettings.hpp"
|
||||
#include "Emulation.hpp"
|
||||
#include "RomHeader.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "Rom.hpp"
|
||||
|
||||
#include "Settings/Settings.hpp"
|
||||
#include "ConvertStringEncoding.hpp"
|
||||
|
||||
//
|
||||
// Local Variables
|
||||
@@ -46,7 +49,7 @@ bool CoreGetCurrentRomSettings(CoreRomSettings& settings)
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.GoodName = std::string(m64p_settings.goodname);
|
||||
settings.GoodName = CoreConvertStringEncoding(m64p_settings.goodname, CoreStringEncoding::Shift_JIS);
|
||||
settings.MD5 = std::string(m64p_settings.MD5);
|
||||
settings.SaveType = m64p_settings.savetype;
|
||||
settings.DisableExtraMem = m64p_settings.disableextramem;
|
||||
|
||||
@@ -8,10 +8,33 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "SaveState.hpp"
|
||||
#include "Directories.hpp"
|
||||
#include "RomSettings.hpp"
|
||||
#include "RomHeader.hpp"
|
||||
#include "Error.hpp"
|
||||
|
||||
#include "Settings/Settings.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
//
|
||||
// Local Functions
|
||||
//
|
||||
|
||||
// replaces all occurences of any chars in replace with c inside str
|
||||
static void str_replace_chars(std::string& str, const std::string replace, const char c)
|
||||
{
|
||||
for (int i = 0; i < str.size(); i++)
|
||||
{
|
||||
char str_char = str.at(i);
|
||||
if (replace.find(str_char) != std::string::npos)
|
||||
{
|
||||
str.at(i) = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
@@ -59,6 +82,92 @@ int CoreGetSaveStateSlot(void)
|
||||
return slot;
|
||||
}
|
||||
|
||||
bool CoreGetSaveStatePath(int slot, std::filesystem::path& path)
|
||||
{
|
||||
// TODO: this should probably be an API function
|
||||
// in mupen64plus-core instead
|
||||
|
||||
std::filesystem::path saveStatePath;
|
||||
std::filesystem::path oldSaveStatePath;
|
||||
std::string saveStateFileName;
|
||||
std::filesystem::path saveStateExtension;
|
||||
CoreRomHeader romHeader;
|
||||
CoreRomSettings romSettings;
|
||||
|
||||
// attempt to retrieve the current
|
||||
// rom header and settings
|
||||
if (!CoreGetCurrentRomHeader(romHeader) ||
|
||||
!CoreGetCurrentRomSettings(romSettings))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// retrieve save state directory
|
||||
saveStatePath = CoreGetSaveStateDirectory();
|
||||
saveStatePath += "/";
|
||||
|
||||
// construct extension
|
||||
saveStateExtension = ".st";
|
||||
saveStateExtension += std::to_string(slot);
|
||||
|
||||
// construct old save state path
|
||||
oldSaveStatePath = saveStatePath;
|
||||
oldSaveStatePath += romSettings.GoodName;
|
||||
oldSaveStatePath += saveStateExtension;
|
||||
|
||||
// use old filename if it exists
|
||||
if (std::filesystem::is_regular_file(oldSaveStatePath))
|
||||
{
|
||||
path = oldSaveStatePath;
|
||||
return true;
|
||||
}
|
||||
|
||||
// else use new filename
|
||||
int format = CoreSettingsGetIntValue(SettingsID::Core_SaveFileNameFormat);
|
||||
if (format == 0)
|
||||
{
|
||||
saveStatePath += romHeader.Name;
|
||||
saveStatePath += saveStateExtension;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (romSettings.GoodName.find("(unknown rom)") == std::string::npos)
|
||||
{
|
||||
if (romSettings.GoodName.size() < 32)
|
||||
{
|
||||
saveStatePath += romSettings.GoodName;
|
||||
}
|
||||
else
|
||||
{
|
||||
saveStatePath += romSettings.GoodName.substr(0, 32);
|
||||
}
|
||||
}
|
||||
else if (!romHeader.Name.empty())
|
||||
{
|
||||
saveStatePath += romHeader.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
saveStatePath += "unknown";
|
||||
}
|
||||
saveStatePath += "-";
|
||||
saveStatePath += romSettings.MD5.substr(0, 8);
|
||||
saveStatePath += saveStateExtension;
|
||||
}
|
||||
|
||||
// retrieve filename from path
|
||||
saveStateFileName = saveStatePath.filename().string();
|
||||
|
||||
// sanitize filename
|
||||
str_replace_chars(saveStateFileName, ":<>\"/\\|?*", '_');
|
||||
|
||||
// replace filename in path
|
||||
saveStatePath.replace_filename(saveStateFileName);
|
||||
|
||||
path = saveStatePath;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CoreSaveState(void)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
@@ -19,6 +19,10 @@ bool CoreSetSaveStateSlot(int slot);
|
||||
// returns -1 on error
|
||||
int CoreGetSaveStateSlot(void);
|
||||
|
||||
// retrieves the file path for
|
||||
// the save state in the given slot
|
||||
bool CoreGetSaveStatePath(int slot, std::filesystem::path& path);
|
||||
|
||||
// saves state
|
||||
bool CoreSaveState(void);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "Settings.hpp"
|
||||
|
||||
#include "Directories.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "Version.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "m64p/api/m64p_types.h"
|
||||
@@ -122,6 +122,7 @@ static std::vector<std::string> l_keyList;
|
||||
#define SETTING_SECTION_GB SETTING_SECTION_CORE " Gameboy"
|
||||
#define SETTING_SECTION_M64P "Core"
|
||||
#define SETTING_SECTION_AUDIO SETTING_SECTION_GUI " - Audio Plugin"
|
||||
#define SETTING_SECTION_INPUT SETTING_SECTION_GUI " - Input Plugin"
|
||||
|
||||
// retrieves l_Setting from settingId
|
||||
static l_Setting get_setting(SettingsID settingId)
|
||||
@@ -140,9 +141,6 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::GUI_SettingsDialogHeight:
|
||||
setting = {SETTING_SECTION_GUI, "SettingsDialogHeight", 0};
|
||||
break;
|
||||
case SettingsID::GUI_AllowManualResizing:
|
||||
setting = {SETTING_SECTION_GUI, "AllowManualResizing", true};
|
||||
break;
|
||||
case SettingsID::GUI_HideCursorInEmulation:
|
||||
setting = {SETTING_SECTION_GUI, "HideCursorInEmulation", false};
|
||||
break;
|
||||
@@ -161,43 +159,88 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::GUI_AutomaticFullscreen:
|
||||
setting = {SETTING_SECTION_GUI, "AutomaticFullscreen", false};
|
||||
break;
|
||||
case SettingsID::GUI_ShowVerboseLogMessages:
|
||||
setting = {SETTING_SECTION_GUI, "ShowVerboseLogMessages", false};
|
||||
break;
|
||||
case SettingsID::GUI_OnScreenDisplayEnabled:
|
||||
setting = {SETTING_SECTION_GUI, "OnScreenDisplayEnabled", true};
|
||||
break;
|
||||
case SettingsID::GUI_OnScreenDisplayLocation:
|
||||
setting = {SETTING_SECTION_GUI, "OnScreenDisplayLocation", 0};
|
||||
break;
|
||||
case SettingsID::GUI_OnScreenDisplayPaddingX:
|
||||
setting = {SETTING_SECTION_GUI, "OnScreenDisplayPaddingX", 20};
|
||||
break;
|
||||
case SettingsID::GUI_OnScreenDisplayPaddingY:
|
||||
setting = {SETTING_SECTION_GUI, "OnScreenDisplayPaddingY", 20};
|
||||
break;
|
||||
case SettingsID::GUI_OnScreenDisplayOpacity:
|
||||
setting = {SETTING_SECTION_GUI, "OnScreenDisplayOpacity", 0.5f};
|
||||
break;
|
||||
case SettingsID::GUI_OnScreenDisplayDuration:
|
||||
setting = {SETTING_SECTION_GUI, "OnScreenDisplayDuration", 3};
|
||||
break;
|
||||
case SettingsID::GUI_Toolbar:
|
||||
setting = {SETTING_SECTION_GUI, "Toolbar", true};
|
||||
break;
|
||||
case SettingsID::GUI_ToolbarArea:
|
||||
setting = {SETTING_SECTION_GUI, "ToolbarArea", 0};
|
||||
break;
|
||||
case SettingsID::GUI_StatusBar:
|
||||
setting = {SETTING_SECTION_GUI, "StatusBar", true};
|
||||
break;
|
||||
case SettingsID::GUI_Theme:
|
||||
setting = {SETTING_SECTION_GUI, "Theme", "Native"};
|
||||
break;
|
||||
case SettingsID::GUI_IconTheme:
|
||||
setting = {SETTING_SECTION_GUI, "IconTheme", "Automatic"};
|
||||
break;
|
||||
case SettingsID::GUI_CheckForUpdates:
|
||||
setting = {SETTING_SECTION_GUI, "CheckForUpdates", true};
|
||||
break;
|
||||
case SettingsID::GUI_LastUpdateCheck:
|
||||
setting = {SETTING_SECTION_GUI, "LastUpdateCheck", ""};
|
||||
break;
|
||||
case SettingsID::GUI_DiscordRpc:
|
||||
setting = {SETTING_SECTION_GUI, "DiscordRpc", true};
|
||||
break;
|
||||
case SettingsID::GUI_Version:
|
||||
setting = {SETTING_SECTION_GUI, "Version", CORE_VERSION};
|
||||
setting = {SETTING_SECTION_GUI, "Version", CoreGetVersion()};
|
||||
break;
|
||||
|
||||
case SettingsID::Core_GFX_Plugin:
|
||||
setting = {SETTING_SECTION_CORE, "GFX_Plugin",
|
||||
#ifdef _WIN32
|
||||
CoreGetPluginDirectory().string() + "\\GFX\\mupen64plus-video-GLideN64.dll",
|
||||
"mupen64plus-video-GLideN64.dll",
|
||||
#else
|
||||
CoreGetPluginDirectory().string() + "/GFX/mupen64plus-video-GLideN64.so",
|
||||
"mupen64plus-video-GLideN64.so",
|
||||
#endif // _WIN32
|
||||
};
|
||||
break;
|
||||
case SettingsID::Core_AUDIO_Plugin:
|
||||
setting = {SETTING_SECTION_CORE, "AUDIO_Plugin",
|
||||
#ifdef _WIN32
|
||||
CoreGetPluginDirectory().string() + "\\Audio\\RMG-Audio.dll",
|
||||
"RMG-Audio.dll",
|
||||
#else
|
||||
CoreGetPluginDirectory().string() + "/Audio/RMG-Audio.so",
|
||||
"RMG-Audio.so",
|
||||
#endif // _WIN32
|
||||
};
|
||||
break;
|
||||
case SettingsID::Core_INPUT_Plugin:
|
||||
setting = {SETTING_SECTION_CORE, "INPUT_Plugin",
|
||||
#ifdef _WIN32
|
||||
CoreGetPluginDirectory().string() + "\\Input\\RMG-Input.dll",
|
||||
"RMG-Input.dll",
|
||||
#else
|
||||
CoreGetPluginDirectory().string() + "/Input/RMG-Input.so",
|
||||
"RMG-Input.so",
|
||||
#endif // _WIN32
|
||||
};
|
||||
break;
|
||||
case SettingsID::Core_RSP_Plugin:
|
||||
setting = {SETTING_SECTION_CORE, "RSP_Plugin",
|
||||
#ifdef _WIN32
|
||||
CoreGetPluginDirectory().string() + "\\RSP\\mupen64plus-rsp-hle.dll",
|
||||
"mupen64plus-rsp-hle.dll",
|
||||
#else
|
||||
CoreGetPluginDirectory().string() + "/RSP/mupen64plus-rsp-hle.so",
|
||||
"mupen64plus-rsp-hle.so",
|
||||
#endif // _WIN32
|
||||
};
|
||||
break;
|
||||
@@ -237,6 +280,9 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::Core_SiDmaDuration:
|
||||
setting = {SETTING_SECTION_M64P, "SiDmaDuration", -1};
|
||||
break;
|
||||
case SettingsID::Core_SaveFileNameFormat:
|
||||
setting = {SETTING_SECTION_M64P, "SaveFilenameFormat", 1};
|
||||
break;
|
||||
|
||||
case SettingsID::CoreOverlay_RandomizeInterrupt:
|
||||
setting = {SETTING_SECTION_OVERLAY, "RandomizeInterrupt", true};
|
||||
@@ -259,6 +305,9 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::CoreOverlay_SiDmaDuration:
|
||||
setting = {SETTING_SECTION_OVERLAY, "SiDmaDuration", -1};
|
||||
break;
|
||||
case SettingsID::CoreOverLay_SaveFileNameFormat:
|
||||
setting = {SETTING_SECTION_OVERLAY, "SaveFilenameFormat", 1};
|
||||
break;
|
||||
|
||||
case SettingsID::Core_ScreenshotPath:
|
||||
setting = {SETTING_SECTION_M64P, "ScreenshotPath", CoreGetDefaultScreenshotDirectory(), "", true};
|
||||
@@ -353,17 +402,14 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::KeyBinding_RemoveDuplicates:
|
||||
setting = {SETTING_SECTION_KEYBIND, "RemoveDuplicates", true};
|
||||
break;
|
||||
case SettingsID::KeyBinding_OpenROM:
|
||||
setting = {SETTING_SECTION_KEYBIND, "OpenROM", "Ctrl+O"};
|
||||
case SettingsID::KeyBinding_StartROM:
|
||||
setting = {SETTING_SECTION_KEYBIND, "StartROM", "Ctrl+O"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_OpenCombo:
|
||||
setting = {SETTING_SECTION_KEYBIND, "OpenCombo", "Ctrl+Shift+O"};
|
||||
case SettingsID::KeyBinding_StartCombo:
|
||||
setting = {SETTING_SECTION_KEYBIND, "StartCombo", "Ctrl+Shift+O"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_StartEmulation:
|
||||
setting = {SETTING_SECTION_KEYBIND, "StartEmulation", "F11"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_EndEmulation:
|
||||
setting = {SETTING_SECTION_KEYBIND, "EndEmulation", "F12"};
|
||||
case SettingsID::KeyBinding_Shutdown:
|
||||
setting = {SETTING_SECTION_KEYBIND, "Shutdown", "F12"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_RefreshROMList:
|
||||
setting = {SETTING_SECTION_KEYBIND, "RefreshROMList", "F5"};
|
||||
@@ -380,14 +426,47 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::KeyBinding_Resume:
|
||||
setting = {SETTING_SECTION_KEYBIND, "Resume", "F2"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_GenerateBitmap:
|
||||
setting = {SETTING_SECTION_KEYBIND, "GenerateBitmap", "F3"};
|
||||
case SettingsID::KeyBinding_Screenshot:
|
||||
setting = {SETTING_SECTION_KEYBIND, "Screenshot", "F3"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_LimitFPS:
|
||||
setting = {SETTING_SECTION_KEYBIND, "LimitFPS", "F4"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SwapDisk:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SwapDisk", "Ctrl+D"};
|
||||
case SettingsID::KeyBinding_SpeedFactor25:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor25", "Alt+0"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SpeedFactor50:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor50", "Alt+1"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SpeedFactor75:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor75", "Alt+2"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SpeedFactor100:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor100", "Alt+3"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SpeedFactor125:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor125", "Alt+4"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SpeedFactor150:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor150", "Alt+5"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SpeedFactor175:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor175", "Alt+6"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SpeedFactor200:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor200", "Alt+7"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SpeedFactor225:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor225", "Alt+8"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SpeedFactor250:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor250", "Alt+9"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SpeedFactor275:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor275", "Alt+["};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SpeedFactor300:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor300", "Alt+]"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveState:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveState", "F5"};
|
||||
@@ -407,9 +486,54 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::KeyBinding_GSButton:
|
||||
setting = {SETTING_SECTION_KEYBIND, "GSButton", "F9"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot0:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot0", "Ctrl+0"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot1:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot1", "Ctrl+1"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot2:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot2", "Ctrl+2"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot3:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot3", "Ctrl+3"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot4:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot4", "Ctrl+4"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot5:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot5", "Ctrl+5"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot6:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot6", "Ctrl+6"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot7:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot7", "Ctrl+7"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot8:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot8", "Ctrl+8"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot9:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot9", "Ctrl+9"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_Fullscreen:
|
||||
setting = {SETTING_SECTION_KEYBIND, "Fullscreen", "Alt+Return"};
|
||||
break;
|
||||
case SettingsID::Keybinding_ViewLog:
|
||||
setting = {SETTING_SECTION_KEYBIND, "ViewLog", "Ctrl+L"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_GraphicsSettings:
|
||||
setting = {SETTING_SECTION_KEYBIND, "GraphicsSettings", "Ctrl+G"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_AudioSettings:
|
||||
setting = {SETTING_SECTION_KEYBIND, "AudioSettings", "Ctrl+A"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_RspSettings:
|
||||
setting = {SETTING_SECTION_KEYBIND, "RspSettings", "Ctrl+R"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_InputSettings:
|
||||
setting = {SETTING_SECTION_KEYBIND, "InputSettings", "Ctrl+I"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_Settings:
|
||||
setting = {SETTING_SECTION_KEYBIND, "Settings", "Ctrl+T"};
|
||||
break;
|
||||
@@ -420,17 +544,44 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::RomBrowser_Geometry:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "Geometry", ""};
|
||||
break;
|
||||
case SettingsID::RomBrowser_Maximized:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "Maximized", false};
|
||||
break;
|
||||
case SettingsID::RomBrowser_Recursive:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "Recursive", true};
|
||||
break;
|
||||
case SettingsID::RomBrowser_MaxItems:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "MaxItems", 250};
|
||||
break;
|
||||
case SettingsID::RomBrowser_Columns:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "Columns", std::vector<int>({0, 1, 2})};
|
||||
case SettingsID::RomBrowser_ColumnVisibility:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ColumnVisibility", std::vector<int>({1, 1, 1, 0, 0, 0, 0, 0, 0})};
|
||||
break;
|
||||
case SettingsID::RomBrowser_ColumnOrder:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ColumnOrder", std::vector<int>({0, 1, 2, 3, 4, 5, 6, 7, 8})};
|
||||
break;
|
||||
case SettingsID::RomBrowser_ColumnSizes:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ColumnSizes", std::vector<int>({0, 250, 1, 100, 2, 100})};
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ColumnSizes", std::vector<int>({-1, -1, -1, -1, -1, -1, -1, -1, -1})};
|
||||
break;
|
||||
case SettingsID::RomBrowser_SortAfterSearch:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "SortAfterSearch", true};
|
||||
break;
|
||||
case SettingsID::RomBrowser_ViewMode:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ViewMode", 0};
|
||||
break;
|
||||
case SettingsID::RomBrowser_ListViewSortSection:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ListViewSortSection", 0};
|
||||
break;
|
||||
case SettingsID::RomBrowser_ListViewSortOrder:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ListViewSortOrder", 0};
|
||||
break;
|
||||
case SettingsID::RomBrowser_GridViewIconWidth:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "GridViewIconWidth", 180};
|
||||
break;
|
||||
case SettingsID::RomBrowser_GridViewIconHeight:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "GridViewIconHeight", 126};
|
||||
break;
|
||||
case SettingsID::RomBrowser_GridViewUniformItemSizes:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "GridViewUniformItemSizes", true};
|
||||
break;
|
||||
|
||||
case SettingsID::Settings_HasForceUsedSetOnce:
|
||||
@@ -462,9 +613,18 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
setting = {SETTING_SECTION_AUDIO, "Muted", false};
|
||||
break;
|
||||
case SettingsID::Audio_Synchronize:
|
||||
setting = {SETTING_SECTION_AUDIO, "Synchronize", true};
|
||||
setting = {SETTING_SECTION_AUDIO, "Synchronize", false};
|
||||
break;
|
||||
|
||||
case SettingsID::Input_Profiles:
|
||||
setting = {SETTING_SECTION_INPUT, "Profiles", ""};
|
||||
break;
|
||||
case SettingsID::Input_UseProfile:
|
||||
setting = {"", "UseProfile"};
|
||||
break;
|
||||
case SettingsID::Input_UseGameProfile:
|
||||
setting = {"", "UseGameProfile"};
|
||||
break;
|
||||
case SettingsID::Input_PluggedIn:
|
||||
setting = {"", "PluggedIn"};
|
||||
break;
|
||||
@@ -480,6 +640,9 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::Input_Deadzone:
|
||||
setting = {"", "Deadzone"};
|
||||
break;
|
||||
case SettingsID::Input_Sensitivity:
|
||||
setting = {"", "Sensitivity"};
|
||||
break;
|
||||
case SettingsID::Input_Pak:
|
||||
setting = {"", "Pak"};
|
||||
break;
|
||||
@@ -492,8 +655,11 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::Input_RemoveDuplicateMappings:
|
||||
setting = {"", "RemoveDuplicateMappings"};
|
||||
break;
|
||||
case SettingsID::Input_InvertAxis:
|
||||
setting = {"", "InvertAxis"};
|
||||
case SettingsID::Input_FilterEventsForButtons:
|
||||
setting = {"", "FilterEventsForButtons"};
|
||||
break;
|
||||
case SettingsID::Input_FilterEventsForAxis:
|
||||
setting = {"", "FilterEventsForAxis"};
|
||||
break;
|
||||
case SettingsID::Input_A_InputType:
|
||||
setting = {"", "A_InputType"};
|
||||
@@ -917,6 +1083,94 @@ static bool config_option_default_set(std::string section, std::string key, m64p
|
||||
return ret == M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static bool int_list_to_string(std::vector<int> intList, std::string& string)
|
||||
{
|
||||
for (int i = 0; i < intList.size(); i++)
|
||||
{
|
||||
int num = intList.at(i);
|
||||
string += std::to_string(num);
|
||||
|
||||
// don't add seperator at end
|
||||
// of the list
|
||||
if (i < (intList.size() - 1))
|
||||
{
|
||||
string += ";";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool string_to_int_list(std::string string, std::vector<int>& intList)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
// split string by ';'
|
||||
// and append list with each item
|
||||
std::stringstream value_str_stream(string);
|
||||
std::string tmp_str;
|
||||
while (std::getline(value_str_stream, tmp_str, ';'))
|
||||
{
|
||||
try
|
||||
{
|
||||
intList.emplace_back(std::stoi(tmp_str));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = "string_to_int_list: std::stroi threw an exception!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool string_list_to_string(std::vector<std::string> stringList, std::string& string)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
for (int i = 0; i < stringList.size(); i++)
|
||||
{
|
||||
std::string str = stringList.at(i);
|
||||
|
||||
// ensure the string doesn't contain
|
||||
// the separator character
|
||||
if (str.find(";") != std::string::npos)
|
||||
{
|
||||
error = "string_list_to_string: string cannot contain ';'!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
string += str;
|
||||
|
||||
// don't add separator at end
|
||||
// of the list
|
||||
if (i < (stringList.size() - 1))
|
||||
{
|
||||
string += ";";
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool string_to_string_list(std::string string, std::vector<std::string>& stringList)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
// split string by ';'
|
||||
// and append list with each item
|
||||
std::stringstream value_str_stream(string);
|
||||
std::string tmp_str;
|
||||
while (std::getline(value_str_stream, tmp_str, ';'))
|
||||
{
|
||||
stringList.emplace_back(tmp_str);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
@@ -951,7 +1205,7 @@ bool CoreSettingsUpgrade(void)
|
||||
|
||||
// we don't need to do anything
|
||||
// when the core version and the settings version match
|
||||
if (settingsVersion == CORE_VERSION)
|
||||
if (settingsVersion == CoreGetVersion())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -972,11 +1226,27 @@ bool CoreSettingsUpgrade(void)
|
||||
CoreSettingsSetValue(SettingsID::Core_ScreenshotPath, CoreGetDefaultScreenshotDirectory());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (settingsVersion == "v0.2.1" ||
|
||||
settingsVersion == "v0.2.2" ||
|
||||
settingsVersion == "v0.2.3")
|
||||
{
|
||||
// sadly when introducing the new RMG-Audio based on mupen64plus-audio-sdl
|
||||
// 1) sync audio seems to cause crackling for some users
|
||||
// 2) sync audio breaks the 'Limit FPS' option
|
||||
// so to fix those issues, we'll disable the sync audio option
|
||||
// if it's enabled
|
||||
if (CoreSettingsGetBoolValue(SettingsID::Audio_Synchronize))
|
||||
{
|
||||
CoreSettingsSetValue(SettingsID::Audio_Synchronize, false);
|
||||
}
|
||||
}
|
||||
|
||||
// save core version
|
||||
return CoreSettingsSetValue(SettingsID::GUI_Version, std::string(CORE_VERSION));
|
||||
CoreSettingsSetValue(SettingsID::GUI_Version, CoreGetVersion());
|
||||
CoreSettingsSave();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CoreSettingsSetupDefaults(void)
|
||||
@@ -1015,7 +1285,7 @@ bool CoreSettingsSetupDefaults(void)
|
||||
ret = config_option_default_set(setting.Section, setting.Key, M64TYPE_BOOL, &setting.DefaultValue.boolValue, setting.Description.c_str());
|
||||
break;
|
||||
case M64TYPE_FLOAT:
|
||||
ret = config_option_default_set(setting.Section, setting.Key, M64TYPE_FLOAT, &setting.DefaultValue.intValue, setting.Description.c_str());
|
||||
ret = config_option_default_set(setting.Section, setting.Key, M64TYPE_FLOAT, &setting.DefaultValue.floatValue, setting.Description.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1038,6 +1308,27 @@ bool CoreSettingsSectionExists(std::string section)
|
||||
return config_section_exists(section);
|
||||
}
|
||||
|
||||
bool CoreSettingsRevertSection(std::string section)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
|
||||
if (!m64p::Config.IsHooked())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = m64p::Config.RevertChanges(section.c_str());
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "CoreSettingsRevertSection m64p::Config.RevertChanges() Failed: ";
|
||||
error = m64p::Core.ErrorMessage(ret);
|
||||
CoreSetError(error);
|
||||
}
|
||||
|
||||
return ret == M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
bool CoreSettingsDeleteSection(std::string section)
|
||||
{
|
||||
std::string error;
|
||||
@@ -1099,10 +1390,19 @@ bool CoreSettingsSetValue(SettingsID settingId, std::string value)
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::vector<int> value)
|
||||
{
|
||||
std::string value_str;
|
||||
for (const int& num : value)
|
||||
if (!int_list_to_string(value, value_str))
|
||||
{
|
||||
value_str += std::to_string(num);
|
||||
value_str += ";";
|
||||
return false;
|
||||
}
|
||||
return CoreSettingsSetValue(settingId, value_str);
|
||||
}
|
||||
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::vector<std::string> value)
|
||||
{
|
||||
std::string value_str;
|
||||
if (!string_list_to_string(value, value_str))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return CoreSettingsSetValue(settingId, value_str);
|
||||
}
|
||||
@@ -1135,10 +1435,19 @@ bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::string
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::vector<int> value)
|
||||
{
|
||||
std::string value_str;
|
||||
for (const int& num : value)
|
||||
if (!int_list_to_string(value, value_str))
|
||||
{
|
||||
value_str += std::to_string(num);
|
||||
value_str += ";";
|
||||
return false;
|
||||
}
|
||||
return CoreSettingsSetValue(settingId, section, value_str);
|
||||
}
|
||||
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::vector<std::string> value)
|
||||
{
|
||||
std::string value_str;
|
||||
if (!string_list_to_string(value, value_str))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return CoreSettingsSetValue(settingId, section, value_str);
|
||||
}
|
||||
@@ -1167,10 +1476,19 @@ bool CoreSettingsSetValue(std::string section, std::string key, std::string valu
|
||||
bool CoreSettingsSetValue(std::string section, std::string key, std::vector<int> value)
|
||||
{
|
||||
std::string value_str;
|
||||
for (const int& num : value)
|
||||
if (!int_list_to_string(value, value_str))
|
||||
{
|
||||
value_str += std::to_string(num);
|
||||
value_str += ";";
|
||||
return false;
|
||||
}
|
||||
return CoreSettingsSetValue(section, key, value_str);
|
||||
}
|
||||
|
||||
bool CoreSettingsSetValue(std::string section, std::string key, std::vector<std::string> value)
|
||||
{
|
||||
std::string value_str;
|
||||
if (!string_list_to_string(value, value_str))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return CoreSettingsSetValue(section, key, value_str);
|
||||
}
|
||||
@@ -1243,6 +1561,12 @@ std::vector<int> CoreSettingsGetIntListValue(SettingsID settingId)
|
||||
return CoreSettingsGetIntListValue(settingId, setting.Section);
|
||||
}
|
||||
|
||||
std::vector<std::string> CoreSettingsGetStringListValue(SettingsID settingId)
|
||||
{
|
||||
l_Setting setting = get_setting(settingId);
|
||||
return CoreSettingsGetStringListValue(settingId, setting.Section);
|
||||
}
|
||||
|
||||
int CoreSettingsGetIntValue(SettingsID settingId, std::string section)
|
||||
{
|
||||
l_Setting setting = get_setting(settingId);
|
||||
@@ -1283,25 +1607,31 @@ std::vector<int> CoreSettingsGetIntListValue(SettingsID settingId, std::string s
|
||||
std::string value_str;
|
||||
value_str = CoreSettingsGetStringValue(settingId, section);
|
||||
|
||||
// split string by ';'
|
||||
// and append list with each item
|
||||
std::stringstream value_str_stream(value_str);
|
||||
std::string tmp_str;
|
||||
while (std::getline(value_str_stream, tmp_str, ';'))
|
||||
if (!string_to_int_list(value_str, value))
|
||||
{
|
||||
try
|
||||
{
|
||||
value.emplace_back(std::stoi(tmp_str));
|
||||
}
|
||||
catch (...)
|
||||
{ // ignore exception
|
||||
continue;
|
||||
}
|
||||
return std::vector<int>();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
std::vector<std::string> CoreSettingsGetStringListValue(SettingsID settingId, std::string section)
|
||||
{
|
||||
l_Setting setting = get_setting(settingId);
|
||||
std::vector<std::string> value;
|
||||
|
||||
std::string value_str;
|
||||
value_str = CoreSettingsGetStringValue(settingId, section);
|
||||
|
||||
if (!string_to_string_list(value_str, value))
|
||||
{
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
int CoreSettingsGetIntValue(std::string section, std::string key, int defaultValue)
|
||||
{
|
||||
int value = defaultValue;
|
||||
@@ -1330,27 +1660,31 @@ std::string CoreSettingsGetStringValue(std::string section, std::string key)
|
||||
return std::string(value);
|
||||
}
|
||||
|
||||
std::vector<int> CoreSettingsGetIntListValue(std::string section, std::string key, std::vector<int> defaultValue)
|
||||
std::vector<int> CoreSettingsGetIntListValue(std::string section, std::string key)
|
||||
{
|
||||
std::vector<int> value;
|
||||
|
||||
std::string value_str;
|
||||
value_str = CoreSettingsGetStringValue(section, key);
|
||||
|
||||
// split string by ';'
|
||||
// and append list with each item
|
||||
std::stringstream value_str_stream(value_str);
|
||||
std::string tmp_str;
|
||||
while (std::getline(value_str_stream, tmp_str, ';'))
|
||||
if (!string_to_int_list(value_str, value))
|
||||
{
|
||||
try
|
||||
{
|
||||
value.emplace_back(std::stoi(tmp_str));
|
||||
}
|
||||
catch (...)
|
||||
{ // ignore exception
|
||||
continue;
|
||||
}
|
||||
return std::vector<int>();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
std::vector<std::string> CoreSettingsGetStringListValue(std::string section, std::string key)
|
||||
{
|
||||
std::vector<std::string> value;
|
||||
|
||||
std::string value_str;
|
||||
value_str = CoreSettingsGetStringValue(section, key);
|
||||
|
||||
if (!string_to_string_list(value_str, value))
|
||||
{
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
@@ -27,6 +27,9 @@ bool CoreSettingsSetupDefaults(void);
|
||||
// returns whether a section exists
|
||||
bool CoreSettingsSectionExists(std::string section);
|
||||
|
||||
// reverts section to the one from the settings
|
||||
bool CoreSettingsRevertSection(std::string section);
|
||||
|
||||
// deletes given section
|
||||
bool CoreSettingsDeleteSection(std::string section);
|
||||
|
||||
@@ -43,6 +46,8 @@ bool CoreSettingsSetValue(SettingsID settingId, float value);
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string value);
|
||||
// sets setting as int list value
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::vector<int> value);
|
||||
// sets setting as string list value
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::vector<std::string> value);
|
||||
|
||||
// sets setting in section as int value
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string section, int value);
|
||||
@@ -54,6 +59,8 @@ bool CoreSettingsSetValue(SettingsID settingId, std::string section, float value
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::string value);
|
||||
// sets setting in section as int list value
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::vector<int> value);
|
||||
// sets setting as section as string list value
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::vector<std::string> value);
|
||||
|
||||
#ifdef CORE_INTERNAL
|
||||
// sets key in section as int value
|
||||
@@ -66,6 +73,8 @@ bool CoreSettingsSetValue(std::string section, std::string key, float value);
|
||||
bool CoreSettingsSetValue(std::string section, std::string key, std::string value);
|
||||
// sets key in section as int list value
|
||||
bool CoreSettingsSetValue(std::string section, std::string key, std::vector<int> value);
|
||||
// sets key in section as string list value
|
||||
bool CoreSettingsSetValue(std::string section, std::string key, std::vector<std::string> value);
|
||||
#endif // CORE_INTERNAL
|
||||
|
||||
// retrieves default setting as int
|
||||
@@ -78,6 +87,8 @@ float CoreSettingsGetDefaultFloatValue(SettingsID settingId);
|
||||
std::string CoreSettingsGetDefaultStringValue(SettingsID settingId);
|
||||
// retrieves default setting as int list
|
||||
std::vector<int> CoreSettingsGetDefaultIntListValue(SettingsID settingId);
|
||||
// retrieves default setting as string list
|
||||
std::vector<std::string> CoreSettingsGetDefaultStringListValue(SettingsID settingId);
|
||||
|
||||
// retrieves setting as int
|
||||
int CoreSettingsGetIntValue(SettingsID settingId);
|
||||
@@ -89,6 +100,8 @@ float CoreSettingsGetFloatValue(SettingsID settingId);
|
||||
std::string CoreSettingsGetStringValue(SettingsID settingId);
|
||||
// retrieves setting as int list
|
||||
std::vector<int> CoreSettingsGetIntListValue(SettingsID settingId);
|
||||
// retrieves setting as string list
|
||||
std::vector<std::string> CoreSettingsGetStringListValue(SettingsID settingId);
|
||||
|
||||
// retrieves setting in section as int
|
||||
int CoreSettingsGetIntValue(SettingsID settingId, std::string section);
|
||||
@@ -100,6 +113,8 @@ float CoreSettingsGetFloatValue(SettingsID settingId, std::string section);
|
||||
std::string CoreSettingsGetStringValue(SettingsID settingId, std::string section);
|
||||
// retrieves setting in section as int list
|
||||
std::vector<int> CoreSettingsGetIntListValue(SettingsID settingId, std::string section);
|
||||
// retrieves setting in section as string list
|
||||
std::vector<std::string> CoreSettingsGetStringListValue(SettingsID settingId, std::string section);
|
||||
|
||||
#ifdef CORE_INTERNAL
|
||||
// retrieves key in section as int
|
||||
@@ -112,6 +127,8 @@ float CoreSettingsGetFloatValue(std::string section, std::string key, float defa
|
||||
std::string CoreSettingsGetStringValue(std::string section, std::string key);
|
||||
// retrieves key in section as int list
|
||||
std::vector<int> CoreSettingsGetIntListValue(std::string section, std::string key);
|
||||
// retrieves key in section as string list
|
||||
std::vector<std::string> CoreSettingsGetStringListValue(std::string section, std::string key);
|
||||
#endif // CORE_INTERNAL
|
||||
|
||||
#endif // CORE_SETTINGS_HPP
|
||||
|
||||
@@ -6,15 +6,29 @@ enum class SettingsID
|
||||
// GUI Settings
|
||||
GUI_SettingsDialogWidth = 0,
|
||||
GUI_SettingsDialogHeight,
|
||||
GUI_AllowManualResizing,
|
||||
GUI_HideCursorInEmulation,
|
||||
GUI_HideCursorInFullscreenEmulation,
|
||||
GUI_StatusbarMessageDuration,
|
||||
GUI_PauseEmulationOnFocusLoss,
|
||||
GUI_ResumeEmulationOnFocus,
|
||||
GUI_AutomaticFullscreen,
|
||||
GUI_ShowVerboseLogMessages,
|
||||
GUI_OnScreenDisplayEnabled,
|
||||
GUI_OnScreenDisplayLocation,
|
||||
GUI_OnScreenDisplayPaddingX,
|
||||
GUI_OnScreenDisplayPaddingY,
|
||||
GUI_OnScreenDisplayOpacity,
|
||||
GUI_OnScreenDisplayDuration,
|
||||
GUI_Toolbar,
|
||||
GUI_ToolbarArea,
|
||||
GUI_StatusBar,
|
||||
GUI_Theme,
|
||||
GUI_IconTheme,
|
||||
GUI_CheckForUpdates,
|
||||
GUI_LastUpdateCheck,
|
||||
GUI_DiscordRpc,
|
||||
GUI_Version,
|
||||
|
||||
|
||||
// Core Plugin Settings
|
||||
Core_GFX_Plugin,
|
||||
Core_AUDIO_Plugin,
|
||||
@@ -51,6 +65,7 @@ enum class SettingsID
|
||||
Core_CountPerOp,
|
||||
Core_CountPerOpDenomPot,
|
||||
Core_SiDmaDuration,
|
||||
Core_SaveFileNameFormat,
|
||||
|
||||
// (mupen64plus) Overlay Core Settings
|
||||
CoreOverlay_RandomizeInterrupt,
|
||||
@@ -60,6 +75,7 @@ enum class SettingsID
|
||||
CoreOverlay_CountPerOp,
|
||||
CoreOverlay_CountPerOpDenomPot,
|
||||
CoreOverlay_SiDmaDuration,
|
||||
CoreOverLay_SaveFileNameFormat,
|
||||
|
||||
// (mupen64plus) Core Directory Settings
|
||||
Core_ScreenshotPath,
|
||||
@@ -87,35 +103,69 @@ enum class SettingsID
|
||||
|
||||
// GUI KeyBindings
|
||||
KeyBinding_RemoveDuplicates,
|
||||
KeyBinding_OpenROM,
|
||||
KeyBinding_OpenCombo,
|
||||
KeyBinding_StartEmulation,
|
||||
KeyBinding_EndEmulation,
|
||||
KeyBinding_StartROM,
|
||||
KeyBinding_StartCombo,
|
||||
KeyBinding_Shutdown,
|
||||
KeyBinding_RefreshROMList,
|
||||
KeyBinding_Exit,
|
||||
KeyBinding_SoftReset,
|
||||
KeyBinding_HardReset,
|
||||
KeyBinding_Resume,
|
||||
KeyBinding_GenerateBitmap,
|
||||
KeyBinding_Screenshot,
|
||||
KeyBinding_LimitFPS,
|
||||
KeyBinding_SwapDisk,
|
||||
KeyBinding_SpeedFactor25,
|
||||
KeyBinding_SpeedFactor50,
|
||||
KeyBinding_SpeedFactor75,
|
||||
KeyBinding_SpeedFactor100,
|
||||
KeyBinding_SpeedFactor125,
|
||||
KeyBinding_SpeedFactor150,
|
||||
KeyBinding_SpeedFactor175,
|
||||
KeyBinding_SpeedFactor200,
|
||||
KeyBinding_SpeedFactor225,
|
||||
KeyBinding_SpeedFactor250,
|
||||
KeyBinding_SpeedFactor275,
|
||||
KeyBinding_SpeedFactor300,
|
||||
KeyBinding_SaveState,
|
||||
KeyBinding_SaveAs,
|
||||
KeyBinding_LoadState,
|
||||
KeyBinding_Load,
|
||||
KeyBinding_Cheats,
|
||||
KeyBinding_GSButton,
|
||||
KeyBinding_SaveStateSlot0,
|
||||
KeyBinding_SaveStateSlot1,
|
||||
KeyBinding_SaveStateSlot2,
|
||||
KeyBinding_SaveStateSlot3,
|
||||
KeyBinding_SaveStateSlot4,
|
||||
KeyBinding_SaveStateSlot5,
|
||||
KeyBinding_SaveStateSlot6,
|
||||
KeyBinding_SaveStateSlot7,
|
||||
KeyBinding_SaveStateSlot8,
|
||||
KeyBinding_SaveStateSlot9,
|
||||
KeyBinding_Fullscreen,
|
||||
Keybinding_ViewLog,
|
||||
KeyBinding_GraphicsSettings,
|
||||
KeyBinding_AudioSettings,
|
||||
KeyBinding_RspSettings,
|
||||
KeyBinding_InputSettings,
|
||||
KeyBinding_Settings,
|
||||
|
||||
// RomBrowser Settings
|
||||
RomBrowser_Directory,
|
||||
RomBrowser_Geometry,
|
||||
RomBrowser_Maximized,
|
||||
RomBrowser_Recursive,
|
||||
RomBrowser_MaxItems,
|
||||
RomBrowser_Columns,
|
||||
RomBrowser_ColumnVisibility,
|
||||
RomBrowser_ColumnOrder,
|
||||
RomBrowser_ColumnSizes,
|
||||
|
||||
RomBrowser_SortAfterSearch,
|
||||
RomBrowser_ViewMode,
|
||||
RomBrowser_ListViewSortSection,
|
||||
RomBrowser_ListViewSortOrder,
|
||||
RomBrowser_GridViewIconWidth,
|
||||
RomBrowser_GridViewIconHeight,
|
||||
RomBrowser_GridViewUniformItemSizes,
|
||||
|
||||
// Settings Settings
|
||||
Settings_HasForceUsedSetOnce,
|
||||
|
||||
@@ -131,16 +181,21 @@ enum class SettingsID
|
||||
Audio_Synchronize,
|
||||
|
||||
// Input Plugin Settings
|
||||
Input_Profiles,
|
||||
Input_UseProfile,
|
||||
Input_UseGameProfile,
|
||||
Input_PluggedIn,
|
||||
Input_DeviceType,
|
||||
Input_DeviceName,
|
||||
Input_DeviceNum,
|
||||
Input_Deadzone,
|
||||
Input_Sensitivity,
|
||||
Input_Pak,
|
||||
Input_GameboyRom,
|
||||
Input_GameboySave,
|
||||
Input_RemoveDuplicateMappings,
|
||||
Input_InvertAxis,
|
||||
Input_FilterEventsForButtons,
|
||||
Input_FilterEventsForAxis,
|
||||
Input_A_InputType,
|
||||
Input_A_Name,
|
||||
Input_A_Data,
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "SpeedFactor.hpp"
|
||||
#include "Error.hpp"
|
||||
|
||||
#include "m64p/Api.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
int CoreGetSpeedFactor(void)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
int value = 0;
|
||||
|
||||
if (!m64p::Core.IsHooked())
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
|
||||
ret = m64p::Core.DoCommand(M64CMD_CORE_STATE_QUERY, M64CORE_SPEED_FACTOR, &value);
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "CoreGetSpeedFactor: m64p::Core.DoCommand(M64CMD_CORE_STATE_QUERY) Failed: ";
|
||||
error += m64p::Core.ErrorMessage(ret);
|
||||
CoreSetError(error);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool CoreSetSpeedFactor(int factor)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
int value = factor;
|
||||
|
||||
if (!m64p::Core.IsHooked())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = m64p::Core.DoCommand(M64CMD_CORE_STATE_SET, M64CORE_SPEED_FACTOR, &value);
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "CoreSetSpeedFactor: m64p::Core.DoCommand(M64CMD_CORE_STATE_SET) Failed: ";
|
||||
error += m64p::Core.ErrorMessage(ret);
|
||||
CoreSetError(error);
|
||||
}
|
||||
|
||||
return ret == M64ERR_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CORE_SPEEDFACTOR_HPP
|
||||
#define CORE_SPEEDFACTOR_HPP
|
||||
|
||||
// returns the current speed factor
|
||||
int CoreGetSpeedFactor(void);
|
||||
|
||||
// sets the speed factor
|
||||
bool CoreSetSpeedFactor(int factor);
|
||||
|
||||
#endif // CORE_SPEEDFACTOR_HPP
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Unzip.hpp"
|
||||
#include "Error.hpp"
|
||||
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <unzip.h>
|
||||
|
||||
//
|
||||
// Local Defines
|
||||
//
|
||||
|
||||
#define UNZIP_READ_SIZE 67108860 /* 64 MiB */
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
bool CoreUnzip(std::filesystem::path file, std::filesystem::path path)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
unzFile zipFile;
|
||||
unz_global_info zipInfo;
|
||||
std::ofstream outputStream;
|
||||
char* read_buffer = (char*)malloc(UNZIP_READ_SIZE);
|
||||
size_t bytes_read = 0;
|
||||
|
||||
if (read_buffer == nullptr)
|
||||
{
|
||||
error = "CoreUnzip: malloc Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
zipFile = unzOpen(file.string().c_str());
|
||||
if (zipFile == nullptr)
|
||||
{
|
||||
free(read_buffer);
|
||||
error = "CoreUnzip: unzOpen Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (unzGetGlobalInfo(zipFile, &zipInfo) != UNZ_OK)
|
||||
{
|
||||
free(read_buffer);
|
||||
error = "CoreUnzip: unzGetGlobalInfo Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < zipInfo.number_entry; i++)
|
||||
{
|
||||
unz_file_info fileInfo;
|
||||
char fileName[PATH_MAX];
|
||||
std::filesystem::path targetPath;
|
||||
|
||||
// ensure we can retrieve the current file info
|
||||
if (unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, PATH_MAX, nullptr, 0, nullptr, 0) != UNZ_OK)
|
||||
{
|
||||
free(read_buffer);
|
||||
unzClose(zipFile);
|
||||
error = "CoreUnzip: unzGetCurrentFileInfo Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
targetPath = path;
|
||||
targetPath += "/";
|
||||
targetPath += fileName;
|
||||
|
||||
if (targetPath.string().ends_with("/"))
|
||||
{ // directory
|
||||
try
|
||||
{
|
||||
if (!std::filesystem::is_directory(targetPath) &&
|
||||
!std::filesystem::create_directory(targetPath))
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
free(read_buffer);
|
||||
unzClose(zipFile);
|
||||
error = "CoreUnzip: std::filesystem::create_directory(";
|
||||
error += targetPath.string();
|
||||
error += ") Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // file
|
||||
if (unzOpenCurrentFile(zipFile) != UNZ_OK)
|
||||
{
|
||||
free(read_buffer);
|
||||
unzClose(zipFile);
|
||||
error = "CoreUnzip: unzOpenCurrentFile Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
outputStream.open(targetPath, std::ios::trunc | std::ios::binary);
|
||||
if (!outputStream.is_open())
|
||||
{
|
||||
free(read_buffer);
|
||||
unzCloseCurrentFile(zipFile);
|
||||
unzClose(zipFile);
|
||||
error = "CoreUnzip: failed to open file!";
|
||||
error += targetPath.string();
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
bytes_read = unzReadCurrentFile(zipFile, read_buffer, UNZIP_READ_SIZE);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
free(read_buffer);
|
||||
unzCloseCurrentFile(zipFile);
|
||||
unzClose(zipFile);
|
||||
error = "CoreUnzip: unzReadCurrentFile Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{ // write data to file
|
||||
outputStream.write(read_buffer, bytes_read);
|
||||
}
|
||||
} while (bytes_read > 0);
|
||||
|
||||
outputStream.close();
|
||||
unzCloseCurrentFile(zipFile);
|
||||
}
|
||||
|
||||
// break when we've iterated over all entries
|
||||
if ((i + 1) >= zipInfo.number_entry)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// move to next file
|
||||
if (unzGoToNextFile(zipFile) != UNZ_OK)
|
||||
{
|
||||
free(read_buffer);
|
||||
unzClose(zipFile);
|
||||
error = "CoreUnzip: unzGoToNextFile Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
unzClose(zipFile);
|
||||
free(read_buffer);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CORE_UNZIP_HPP
|
||||
#define CORE_UNZIP_HPP
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
// attempts to unzip the file to path
|
||||
bool CoreUnzip(std::filesystem::path file, std::filesystem::path path);
|
||||
|
||||
#endif // CORE_UNZIP_HPP
|
||||
@@ -7,10 +7,14 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
QTableView
|
||||
#include "Version.hpp"
|
||||
#include "Config.hpp"
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
std::string CoreGetVersion(void)
|
||||
{
|
||||
border: none;
|
||||
color: #0096d3;
|
||||
selection-color: #FFFFFF;
|
||||
selection-background-color: #0096d3;
|
||||
return std::string(CORE_VERSION);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CORE_VERSION_HPP
|
||||
#define CORE_VERSION_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
// returns the current RMG-Core version (as string)
|
||||
std::string CoreGetVersion(void);
|
||||
|
||||
#endif // CORE_VERSION_HPP
|
||||
@@ -28,6 +28,8 @@ bool PluginApi::Hook(m64p_dynlib_handle handle)
|
||||
HOOK_FUNC(handle, Plugin, Startup);
|
||||
HOOK_FUNC(handle, Plugin, Shutdown);
|
||||
HOOK_FUNC_OPT(handle, Plugin, Config);
|
||||
HOOK_FUNC_OPT(handle, Plugin, Config2);
|
||||
HOOK_FUNC_OPT(handle, Plugin, Config2HasRomConfig);
|
||||
HOOK_FUNC(handle, Plugin, GetVersion);
|
||||
|
||||
this->handle = handle;
|
||||
@@ -40,6 +42,8 @@ bool PluginApi::Unhook(void)
|
||||
UNHOOK_FUNC(Plugin, Startup);
|
||||
UNHOOK_FUNC(Plugin, Shutdown);
|
||||
UNHOOK_FUNC(Plugin, Config);
|
||||
UNHOOK_FUNC(Plugin, Config2);
|
||||
UNHOOK_FUNC(Plugin, Config2HasRomConfig);
|
||||
UNHOOK_FUNC(Plugin, GetVersion);
|
||||
|
||||
this->handle = nullptr;
|
||||
|
||||
@@ -34,6 +34,8 @@ class PluginApi
|
||||
ptr_PluginStartup Startup;
|
||||
ptr_PluginShutdown Shutdown;
|
||||
ptr_PluginConfig Config;
|
||||
ptr_PluginConfig2 Config2;
|
||||
ptr_PluginConfig2HasRomConfig Config2HasRomConfig;
|
||||
ptr_PluginGetVersion GetVersion;
|
||||
|
||||
private:
|
||||
|
||||
@@ -21,6 +21,29 @@ typedef m64p_error (*ptr_PluginConfig)(void);
|
||||
EXPORT m64p_error CALL PluginConfig(void);
|
||||
#endif
|
||||
|
||||
/* PluginConfig2(int romConfig)
|
||||
*
|
||||
* This optional function opens a configuration GUI for the plugin
|
||||
* https://github.com/mupen64plus/mupen64plus-core/pull/774
|
||||
*
|
||||
* romConfig argument determines if it should open the ROM specific config
|
||||
*/
|
||||
typedef m64p_error (*ptr_PluginConfig2)(int);
|
||||
#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES)
|
||||
EXPORT m64p_error CALL PluginConfig2(int);
|
||||
#endif
|
||||
|
||||
/* PluginConfig2HasRomConfig(void)
|
||||
*
|
||||
* This optional function returns wether the plugin supports ROM specific config
|
||||
* using PluginConfig2
|
||||
*
|
||||
*/
|
||||
typedef int (*ptr_PluginConfig2HasRomConfig)(void);
|
||||
#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES)
|
||||
EXPORT int CALL PluginConfig2HasRomConfig(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -168,7 +168,9 @@ typedef enum {
|
||||
M64CMD_NETPLAY_GET_VERSION,
|
||||
M64CMD_NETPLAY_CLOSE,
|
||||
M64CMD_PIF_OPEN,
|
||||
M64CMD_ROM_SET_SETTINGS
|
||||
M64CMD_ROM_SET_SETTINGS,
|
||||
M64CMD_DISK_OPEN,
|
||||
M64CMD_DISK_CLOSE
|
||||
} m64p_command;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define OSAL_DYNLIB_HPP
|
||||
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
@@ -25,11 +26,11 @@ typedef void* osal_dynlib_lib_sym;
|
||||
|
||||
// returns library handle for given filename,
|
||||
// return nullptr when invalid library
|
||||
osal_dynlib_lib_handle osal_dynlib_open(const char *);
|
||||
osal_dynlib_lib_handle osal_dynlib_open(std::filesystem::path path);
|
||||
|
||||
// retrieves symbol handle for given library
|
||||
// handle, returns nullptr when not found
|
||||
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle, const char *);
|
||||
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle, const char* symbol);
|
||||
|
||||
// closes library handle
|
||||
void osal_dynlib_close(osal_dynlib_lib_handle);
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
osal_dynlib_lib_handle osal_dynlib_open(const char* file)
|
||||
osal_dynlib_lib_handle osal_dynlib_open(std::filesystem::path path)
|
||||
{
|
||||
return dlopen(file, RTLD_LAZY);
|
||||
return dlopen(path.string().c_str(), RTLD_LAZY);
|
||||
}
|
||||
|
||||
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle handle, const char *sym)
|
||||
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle handle, const char* symbol)
|
||||
{
|
||||
return dlsym(handle, sym);
|
||||
return dlsym(handle, symbol);
|
||||
}
|
||||
|
||||
void osal_dynlib_close(osal_dynlib_lib_handle handle)
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
*/
|
||||
#include "osal_dynlib.hpp"
|
||||
|
||||
osal_dynlib_lib_handle osal_dynlib_open(const char* file)
|
||||
osal_dynlib_lib_handle osal_dynlib_open(std::filesystem::path path)
|
||||
{
|
||||
return LoadLibrary(file);
|
||||
return LoadLibraryW(path.wstring().c_str());
|
||||
}
|
||||
|
||||
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle handle, const char *sym)
|
||||
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle handle, const char* symbol)
|
||||
{
|
||||
return GetProcAddress(handle, sym);
|
||||
return GetProcAddress(handle, symbol);
|
||||
}
|
||||
|
||||
void osal_dynlib_close(osal_dynlib_lib_handle handle)
|
||||
|
||||
@@ -17,8 +17,9 @@ osal_files_file_time osal_files_get_file_time(std::filesystem::path file)
|
||||
BOOL ret;
|
||||
HANDLE file_handle;
|
||||
FILETIME file_time;
|
||||
ULARGE_INTEGER ularge_int;
|
||||
|
||||
file_handle = CreateFileA(file.string().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
file_handle = CreateFileW(file.wstring().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (file_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return -1;
|
||||
@@ -36,7 +37,8 @@ osal_files_file_time osal_files_get_file_time(std::filesystem::path file)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// this is probably incorrect but it doesn't matter
|
||||
// for our use-case
|
||||
return file_time.dwLowDateTime + file_time.dwHighDateTime;
|
||||
ularge_int.LowPart = file_time.dwLowDateTime;
|
||||
ularge_int.HighPart = file_time.dwHighDateTime;
|
||||
|
||||
return ularge_int.QuadPart;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ set(CMAKE_AUTOUIC ON)
|
||||
# disable lib prefix
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
find_package(Qt5 COMPONENTS Gui Widgets Core Svg REQUIRED)
|
||||
find_package(Qt6 COMPONENTS Gui Widgets Core Svg REQUIRED)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SDL2 REQUIRED sdl2)
|
||||
@@ -17,7 +17,9 @@ set(RMG_INPUT_SOURCES
|
||||
UserInterface/Widget/ControllerWidget.ui
|
||||
UserInterface/Widget/ControllerWidget.cpp
|
||||
UserInterface/Widget/ControllerImageWidget.cpp
|
||||
UserInterface/Widget/CustomButton.cpp
|
||||
UserInterface/Widget/MappingButton.cpp
|
||||
UserInterface/Widget/AddMappingButton.cpp
|
||||
UserInterface/Widget/RemoveMappingButton.cpp
|
||||
UserInterface/EventFilter.cpp
|
||||
UserInterface/OptionsDialog.ui
|
||||
UserInterface/OptionsDialog.cpp
|
||||
@@ -41,4 +43,4 @@ target_include_directories(RMG-Input PRIVATE
|
||||
${SDL2_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(RMG-Input Qt5::Gui Qt5::Widgets Qt5::Svg)
|
||||
target_link_libraries(RMG-Input Qt6::Gui Qt6::Widgets Qt6::Svg)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
using namespace UserInterface;
|
||||
|
||||
MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
|
||||
MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread, bool romConfig) : QDialog(parent)
|
||||
{
|
||||
this->setupUi(this);
|
||||
this->setWindowIcon(QIcon(":Resource/RMG.png"));
|
||||
@@ -41,7 +41,8 @@ MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread) : QDialog(
|
||||
for (int i = 0; i < this->tabWidget->count(); i++)
|
||||
{
|
||||
Widget::ControllerWidget* widget = new Widget::ControllerWidget(this, this->eventFilter);
|
||||
widget->SetSettingsSection("Rosalie's Mupen GUI - Input Plugin Profile " + QString::number(i));
|
||||
widget->SetOnlyLoadGameProfile(romConfig);
|
||||
widget->SetSettingsSection("Player " + QString::number(i + 1), "Rosalie's Mupen GUI - Input Plugin Profile " + QString::number(i));
|
||||
widget->LoadSettings();
|
||||
this->tabWidget->widget(i)->layout()->addWidget(widget);
|
||||
controllerWidgets.push_back(widget);
|
||||
@@ -49,12 +50,19 @@ MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread) : QDialog(
|
||||
&MainDialog::on_ControllerWidget_CurrentInputDeviceChanged);
|
||||
connect(widget, &Widget::ControllerWidget::RefreshInputDevicesButtonClicked, this,
|
||||
&MainDialog::on_ControllerWidget_RefreshInputDevicesButtonClicked);
|
||||
connect(widget, &Widget::ControllerWidget::UserProfileAdded, this,
|
||||
&MainDialog::on_ControllerWidget_UserProfileAdded);
|
||||
connect(widget, &Widget::ControllerWidget::UserProfileRemoved, this,
|
||||
&MainDialog::on_ControllerWidget_UserProfileRemoved);
|
||||
}
|
||||
|
||||
// always add keyboard device
|
||||
for (auto& controllerWidget : this->controllerWidgets)
|
||||
{
|
||||
controllerWidget->AddInputDevice("Keyboard", -1);
|
||||
controllerWidget->AddInputDevice("None", (int)InputDeviceType::None);
|
||||
controllerWidget->AddInputDevice("Automatic", (int)InputDeviceType::Automatic);
|
||||
controllerWidget->AddInputDevice("Keyboard", (int)InputDeviceType::Keyboard);
|
||||
controllerWidget->SetInitialized(true);
|
||||
}
|
||||
|
||||
// fill device list at least once
|
||||
@@ -90,30 +98,50 @@ void MainDialog::openInputDevice(QString deviceName, int deviceNum)
|
||||
{
|
||||
SDL_JoystickID joystickId;
|
||||
Widget::ControllerWidget* controllerWidget;
|
||||
controllerWidget = controllerWidgets.at(this->tabWidget->currentIndex());
|
||||
controllerWidget = this->controllerWidgets.at(this->tabWidget->currentIndex());
|
||||
|
||||
// we don't need to open a keyboard
|
||||
if (deviceNum == -1)
|
||||
if (deviceNum == (int)InputDeviceType::None ||
|
||||
deviceNum == (int)InputDeviceType::Keyboard)
|
||||
{
|
||||
currentDeviceName = "";
|
||||
currentDeviceNum = -1;
|
||||
controllerWidget->SetCurrentJoystickID(-1);
|
||||
this->currentDeviceName = "";
|
||||
this->currentDeviceNum = deviceNum;
|
||||
controllerWidget->SetCurrentJoystickID(this->currentDeviceNum);
|
||||
return;
|
||||
}
|
||||
|
||||
// handle automatic mode
|
||||
if (deviceNum == (int)InputDeviceType::Automatic)
|
||||
{
|
||||
int currentIndex = this->tabWidget->currentIndex();
|
||||
if (currentIndex < this->inputDeviceList.size())
|
||||
{ // use device when there's one
|
||||
deviceNum = this->inputDeviceList.at(currentIndex).deviceNum;
|
||||
}
|
||||
else
|
||||
{ // no device found, fallback to keyboard
|
||||
this->currentDeviceName = "";
|
||||
this->currentDeviceNum = (int)InputDeviceType::Keyboard;
|
||||
controllerWidget->SetCurrentJoystickID(this->currentDeviceNum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (SDL_IsGameController(deviceNum) == SDL_TRUE)
|
||||
{
|
||||
currentJoystick = nullptr;
|
||||
currentController = SDL_GameControllerOpen(deviceNum);
|
||||
this->currentJoystick = nullptr;
|
||||
this->currentController = SDL_GameControllerOpen(deviceNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentJoystick = SDL_JoystickOpen(deviceNum);
|
||||
currentController = nullptr;
|
||||
this->currentJoystick = SDL_JoystickOpen(deviceNum);
|
||||
this->currentController = nullptr;
|
||||
}
|
||||
currentDeviceNum = deviceNum;
|
||||
|
||||
this->currentDeviceNum = deviceNum;
|
||||
joystickId = SDL_JoystickGetDeviceInstanceID(deviceNum);
|
||||
controllerWidget->SetCurrentJoystickID(joystickId);
|
||||
controllerWidget->SetIsCurrentJoystickGameController(currentController != nullptr);
|
||||
}
|
||||
|
||||
void MainDialog::closeInputDevice()
|
||||
@@ -193,8 +221,9 @@ void MainDialog::on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget*
|
||||
this->closeInputDevice();
|
||||
|
||||
// only open device,
|
||||
// when it's not a keyboard
|
||||
if (deviceNum != -1)
|
||||
// when needed
|
||||
if (deviceNum != (int)InputDeviceType::None &&
|
||||
deviceNum != (int)InputDeviceType::Keyboard)
|
||||
{
|
||||
this->openInputDevice(deviceName, deviceNum);
|
||||
}
|
||||
@@ -212,21 +241,54 @@ void MainDialog::on_ControllerWidget_RefreshInputDevicesButtonClicked()
|
||||
this->sdlThread->SetAction(SDLThreadAction::GetInputDevices);
|
||||
}
|
||||
|
||||
void MainDialog::on_ControllerWidget_UserProfileAdded(QString name, QString section)
|
||||
{
|
||||
for (auto& controllerWidget : this->controllerWidgets)
|
||||
{
|
||||
controllerWidget->AddUserProfile(name, section);
|
||||
}
|
||||
}
|
||||
|
||||
void MainDialog::on_ControllerWidget_UserProfileRemoved(QString name, QString section)
|
||||
{
|
||||
for (auto& controllerWidget : this->controllerWidgets)
|
||||
{
|
||||
controllerWidget->RemoveUserProfile(name, section);
|
||||
}
|
||||
}
|
||||
|
||||
void MainDialog::on_tabWidget_currentChanged(int index)
|
||||
{
|
||||
QString deviceName;
|
||||
int deviceNum;
|
||||
int deviceNum;
|
||||
Widget::ControllerWidget* controllerWidget;
|
||||
|
||||
Widget::ControllerWidget* controllerWidget = controllerWidgets.at(index);
|
||||
// save previous tab's user profile
|
||||
if (previousTabWidgetIndex != -1 &&
|
||||
previousTabWidgetIndex != index)
|
||||
{
|
||||
controllerWidget = controllerWidgets.at(previousTabWidgetIndex);
|
||||
controllerWidget->SaveUserProfileSettings();
|
||||
}
|
||||
|
||||
// update previous index
|
||||
previousTabWidgetIndex = index;
|
||||
|
||||
// prepare switched tab
|
||||
controllerWidget = controllerWidgets.at(index);
|
||||
controllerWidget->ClearControllerImage();
|
||||
|
||||
this->closeInputDevice();
|
||||
|
||||
// re-load user profile settings
|
||||
controllerWidget->LoadUserProfileSettings();
|
||||
|
||||
// retrieve current input device
|
||||
controllerWidget->GetCurrentInputDevice(deviceName, deviceNum);
|
||||
|
||||
// only open device,
|
||||
// when it's not a keyboard
|
||||
if (deviceNum != -1)
|
||||
// only open device when needed
|
||||
if (deviceNum != (int)InputDeviceType::None &&
|
||||
deviceNum != (int)InputDeviceType::Keyboard)
|
||||
{
|
||||
this->openInputDevice(deviceName, deviceNum);
|
||||
}
|
||||
@@ -309,19 +371,37 @@ void MainDialog::on_EventFilter_KeyReleased(QKeyEvent *event)
|
||||
SDL_PeepEvents(&sdlEvent, 1, SDL_ADDEVENT, 0, 0);
|
||||
}
|
||||
|
||||
void MainDialog::on_buttonBox_clicked(QAbstractButton *button)
|
||||
void MainDialog::accept(void)
|
||||
{
|
||||
QPushButton *pushButton = (QPushButton *)button;
|
||||
QPushButton *okButton = this->buttonBox->button(QDialogButtonBox::Ok);
|
||||
Widget::ControllerWidget* controllerWidget;
|
||||
int currentIndex = this->tabWidget->currentIndex();
|
||||
|
||||
if (pushButton == okButton)
|
||||
for (int i = 0; i < this->controllerWidgets.count(); i++)
|
||||
{
|
||||
for (auto& controllerWidget : this->controllerWidgets)
|
||||
if (i != currentIndex)
|
||||
{
|
||||
controllerWidget = this->controllerWidgets.at(i);
|
||||
controllerWidget->SaveSettings();
|
||||
}
|
||||
|
||||
CoreSettingsSave();
|
||||
}
|
||||
|
||||
// the widget which has focus should be saved last
|
||||
controllerWidget = this->controllerWidgets.at(currentIndex);
|
||||
controllerWidget->SaveSettings();
|
||||
|
||||
CoreSettingsSave();
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void MainDialog::reject(void)
|
||||
{
|
||||
for (auto& controllerWidget : this->controllerWidgets)
|
||||
{
|
||||
controllerWidget->RevertSettings();
|
||||
}
|
||||
|
||||
CoreSettingsSave();
|
||||
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ private:
|
||||
QString deviceName;
|
||||
int deviceNum;
|
||||
|
||||
bool operator== (inputDevice_t other)
|
||||
bool operator== (inputDevice_t other) const
|
||||
{
|
||||
return other.deviceNum == deviceNum &&
|
||||
other.deviceName == deviceName;
|
||||
@@ -43,11 +43,13 @@ private:
|
||||
bool updatingDeviceList = false;
|
||||
|
||||
QList<Widget::ControllerWidget*> controllerWidgets;
|
||||
SDL_Joystick* currentJoystick = nullptr;
|
||||
SDL_Joystick* currentJoystick = nullptr;
|
||||
SDL_GameController* currentController = nullptr;
|
||||
QString currentDeviceName;
|
||||
int currentDeviceNum = 0;
|
||||
|
||||
int previousTabWidgetIndex = 0;
|
||||
|
||||
EventFilter* eventFilter;
|
||||
|
||||
void addInputDevice(QString, int);
|
||||
@@ -57,7 +59,7 @@ private:
|
||||
void closeInputDevice();
|
||||
|
||||
public:
|
||||
MainDialog(QWidget *parent, Thread::SDLThread*);
|
||||
MainDialog(QWidget *parent, Thread::SDLThread*, bool);
|
||||
~MainDialog(void);
|
||||
|
||||
public slots:
|
||||
@@ -65,7 +67,10 @@ public slots:
|
||||
|
||||
void on_ControllerWidget_CurrentInputDeviceChanged(ControllerWidget*, QString, int);
|
||||
void on_ControllerWidget_RefreshInputDevicesButtonClicked();
|
||||
|
||||
|
||||
void on_ControllerWidget_UserProfileAdded(QString, QString);
|
||||
void on_ControllerWidget_UserProfileRemoved(QString, QString);
|
||||
|
||||
void on_tabWidget_currentChanged(int);
|
||||
|
||||
void on_SDLThread_DeviceFound(QString, int);
|
||||
@@ -75,7 +80,8 @@ private slots:
|
||||
void on_EventFilter_KeyPressed(QKeyEvent *);
|
||||
void on_EventFilter_KeyReleased(QKeyEvent *);
|
||||
|
||||
void on_buttonBox_clicked(QAbstractButton *);
|
||||
void accept(void) Q_DECL_OVERRIDE;
|
||||
void reject(void) Q_DECL_OVERRIDE;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,15 @@ OptionsDialog::OptionsDialog(QWidget* parent, OptionsDialogSettings settings) :
|
||||
{
|
||||
this->setupUi(this);
|
||||
|
||||
this->setIconsForEmulationInfoText();
|
||||
|
||||
this->controllerPakComboBox->setCurrentIndex(settings.ControllerPak);
|
||||
this->gameboyRomLineEdit->setText(QString::fromStdString(settings.GameboyRom));
|
||||
this->gameboySaveLineEdit->setText(QString::fromStdString(settings.GameboySave));
|
||||
this->removeDuplicateMappingsCheckbox->setChecked(settings.RemoveDuplicateMappings);
|
||||
this->invertAxisCheckBox->setChecked(settings.InvertAxis);
|
||||
this->filterEventsForButtonsCheckBox->setChecked(settings.FilterEventsForButtons);
|
||||
this->filterEventsForAxisCheckBox->setChecked(settings.FilterEventsForAxis);
|
||||
|
||||
if (!CoreIsEmulationRunning() && !CoreIsEmulationPaused())
|
||||
{
|
||||
this->hideEmulationInfoText();
|
||||
@@ -39,6 +43,21 @@ OptionsDialogSettings OptionsDialog::GetSettings()
|
||||
return this->settings;
|
||||
}
|
||||
|
||||
void OptionsDialog::setIconsForEmulationInfoText(void)
|
||||
{
|
||||
QLabel* labels[] = {
|
||||
this->infoIconLabel_0
|
||||
};
|
||||
|
||||
QIcon infoIcon = QIcon::fromTheme("information-line");
|
||||
QPixmap infoIconPixmap = infoIcon.pixmap(16, 16);
|
||||
|
||||
for (QLabel* label : labels)
|
||||
{
|
||||
label->setPixmap(infoIconPixmap);
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsDialog::hideEmulationInfoText(void)
|
||||
{
|
||||
QHBoxLayout *layouts[] = {this->emulationInfoLayout_1};
|
||||
@@ -66,7 +85,8 @@ void OptionsDialog::on_buttonBox_clicked(QAbstractButton *button)
|
||||
this->settings.GameboyRom = this->gameboyRomLineEdit->text().toStdString();
|
||||
this->settings.GameboySave = this->gameboySaveLineEdit->text().toStdString();
|
||||
this->settings.RemoveDuplicateMappings = this->removeDuplicateMappingsCheckbox->isChecked();
|
||||
this->settings.InvertAxis = this->invertAxisCheckBox->isChecked();
|
||||
this->settings.FilterEventsForButtons = this->filterEventsForButtonsCheckBox->isChecked();
|
||||
this->settings.FilterEventsForAxis = this->filterEventsForAxisCheckBox->isChecked();
|
||||
}
|
||||
|
||||
this->accept();
|
||||
|
||||
@@ -24,7 +24,8 @@ struct OptionsDialogSettings
|
||||
|
||||
// UI settings
|
||||
bool RemoveDuplicateMappings = false;
|
||||
bool InvertAxis = false;
|
||||
bool FilterEventsForButtons = true;
|
||||
bool FilterEventsForAxis = true;
|
||||
};
|
||||
|
||||
namespace UserInterface
|
||||
@@ -43,6 +44,7 @@ private:
|
||||
bool hasSaved = false;
|
||||
OptionsDialogSettings settings;
|
||||
|
||||
void setIconsForEmulationInfoText(void);
|
||||
void hideEmulationInfoText(void);
|
||||
|
||||
private slots:
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="emulationInfoLayout_1">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<widget class="QLabel" name="infoIconLabel_0">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -162,7 +162,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="UIResources.qrc">:/Resource/Info.ico</pixmap>
|
||||
<pixmap>:/Resource/Info.ico</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>false</bool>
|
||||
@@ -203,9 +203,16 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="invertAxisCheckBox">
|
||||
<widget class="QCheckBox" name="filterEventsForButtonsCheckBox">
|
||||
<property name="text">
|
||||
<string>Invert Axes Mapped To LRZ</string>
|
||||
<string>Filter Events Based On Joystick Type For Buttons</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="filterEventsForAxisCheckBox">
|
||||
<property name="text">
|
||||
<string>Filter Events Based On Joystick Type For Axis</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
|
||||
id="svg21"
|
||||
sodipodi:docname="Controller.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -23,15 +23,17 @@
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.28240146"
|
||||
inkscape:cx="-426.69751"
|
||||
inkscape:cy="3454.3023"
|
||||
inkscape:zoom="0.070600365"
|
||||
inkscape:cx="6019.7989"
|
||||
inkscape:cy="1600.5583"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg21" />
|
||||
inkscape:current-layer="layer2"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:deskcolor="#d1d1d1" />
|
||||
<path
|
||||
id="Dark-Grey-Background"
|
||||
serif:id="Dark Grey Background"
|
||||
@@ -111,4 +113,39 @@
|
||||
style="fill:#ec3f21"
|
||||
id="circle18" />
|
||||
</g>
|
||||
</svg>
|
||||
<g
|
||||
id="layer2"
|
||||
inkscape:label="Z-Button"
|
||||
style="display:inline;opacity:1;stroke-width:1;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
transform="matrix(50.366966,0,0,50.366966,3240.0678,-579.56452)"><g
|
||||
id="layer2-0"
|
||||
inkscape:label="Z-Button"
|
||||
style="clip-rule:evenodd;display:inline;fill-rule:evenodd;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:2;stroke-dasharray:none;paint-order:markers stroke fill"><rect
|
||||
style="clip-rule:evenodd;display:inline;opacity:1;fill:#5c5c5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.999999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;image-rendering:auto"
|
||||
id="rect1917-0-4"
|
||||
width="11.478539"
|
||||
height="16.72587"
|
||||
x="-32.517441"
|
||||
y="86.256668"
|
||||
ry="3.4675589"
|
||||
inkscape:label="btnZ-outline"
|
||||
class="theme-button"
|
||||
ojd-button="Z" /><rect
|
||||
style="display:inline;opacity:1;fill:#bcbdbf;fill-opacity:1;stroke:none;stroke-width:0.960842;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;image-rendering:auto"
|
||||
id="rect1917-8"
|
||||
width="10.956328"
|
||||
height="16.177647"
|
||||
x="-32.225891"
|
||||
y="86.523468"
|
||||
ry="3.3539019"
|
||||
inkscape:label="btnZ"
|
||||
class="theme-button"
|
||||
ojd-button="Z" /><g
|
||||
aria-label="Z"
|
||||
style="font-style:normal;font-weight:normal;font-size:5.73478px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;clip-rule:evenodd;display:inline;opacity:1;fill:#56575b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.751267;stroke-linejoin:round;stroke-miterlimit:2;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
id="text1921-7"
|
||||
transform="matrix(1.3310888,0,0,1.3310888,-67.459296,-40.853038)"><path
|
||||
d="m 28.805176,99.685474 h 3.514231 v 0.652446 l -2.242948,2.71338 h 2.307352 v 0.81485 h -3.64304 v -0.65244 l 2.242948,-2.71338 h -2.178543 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#56575b;fill-opacity:1;stroke-width:0.751267;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
id="path2008-2"
|
||||
inkscape:connector-curvature="0" /></g></g></g></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
@@ -8,7 +8,7 @@
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
|
||||
id="svg21"
|
||||
sodipodi:docname="Controller_NoAnalogStick.svg"
|
||||
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -23,15 +23,17 @@
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.14120073"
|
||||
inkscape:cx="2549.5619"
|
||||
inkscape:cy="3325.0536"
|
||||
inkscape:zoom="0.099843994"
|
||||
inkscape:cx="2829.4141"
|
||||
inkscape:cy="3475.4219"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1007"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg21" />
|
||||
inkscape:current-layer="svg21"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:deskcolor="#d1d1d1" />
|
||||
<path
|
||||
id="Dark-Grey-Background"
|
||||
serif:id="Dark Grey Background"
|
||||
@@ -101,4 +103,36 @@
|
||||
style="fill:#ec3f21"
|
||||
id="circle18" />
|
||||
</g>
|
||||
</svg>
|
||||
<g
|
||||
id="layer2"
|
||||
inkscape:label="Z-Button"
|
||||
style="display:inline;opacity:1;stroke-width:1;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
transform="matrix(50.366966,0,0,50.366966,3240.0678,-579.56452)"><rect
|
||||
style="clip-rule:evenodd;display:inline;opacity:1;fill:#5c5c5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.999999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;image-rendering:auto"
|
||||
id="rect1917-0"
|
||||
width="11.478539"
|
||||
height="16.72587"
|
||||
x="-32.517441"
|
||||
y="86.256668"
|
||||
ry="3.4675589"
|
||||
inkscape:label="btnZ-outline"
|
||||
class="theme-button"
|
||||
ojd-button="Z" /><rect
|
||||
style="display:inline;opacity:1;fill:#bcbdbf;fill-opacity:1;stroke:none;stroke-width:0.960842;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;image-rendering:auto"
|
||||
id="rect1917"
|
||||
width="10.956328"
|
||||
height="16.177647"
|
||||
x="-32.225891"
|
||||
y="86.523468"
|
||||
ry="3.3539019"
|
||||
inkscape:label="btnZ"
|
||||
class="theme-button"
|
||||
ojd-button="Z" /><g
|
||||
aria-label="Z"
|
||||
style="font-style:normal;font-weight:normal;font-size:5.73478px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;clip-rule:evenodd;display:inline;opacity:1;fill:#56575b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.751267;stroke-linejoin:round;stroke-miterlimit:2;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
id="text1921"
|
||||
transform="matrix(1.3310888,0,0,1.3310888,-67.459296,-40.853038)"><path
|
||||
d="m 28.805176,99.685474 h 3.514231 v 0.652446 l -2.242948,2.71338 h 2.307352 v 0.81485 h -3.64304 v -0.65244 l 2.242948,-2.71338 h -2.178543 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#56575b;fill-opacity:1;stroke-width:0.751267;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
id="path2008"
|
||||
inkscape:connector-curvature="0" /></g></g></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="6939.9795"
|
||||
height="6772.564"
|
||||
viewBox="0 0 6939.9795 6772.564"
|
||||
version="1.1"
|
||||
xml:space="preserve"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
|
||||
id="svg21"
|
||||
sodipodi:docname="Controller_Pressed_ZTrigger.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs25" /><sodipodi:namedview
|
||||
id="namedview23"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.099843994"
|
||||
inkscape:cx="2468.8516"
|
||||
inkscape:cy="3856.0156"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg21"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:deskcolor="#d1d1d1" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<g
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
|
||||
id="g5916"
|
||||
transform="matrix(1.0882331,0,0,1.0882331,512.32815,1416.6572)"><circle
|
||||
style="opacity:0.62;fill:#ececec;fill-rule:evenodd;stroke-width:0.280377"
|
||||
id="path42"
|
||||
cx="1267.6501"
|
||||
cy="2546.3296"
|
||||
r="180.5985" /></g></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -15,7 +15,7 @@
|
||||
<file>Resource/Controller_Pressed_Start.svg</file>
|
||||
<file>Resource/Controller_Pressed_LeftTrigger.svg</file>
|
||||
<file>Resource/Controller_Pressed_RightTrigger.svg</file>
|
||||
<file>Resource/Controller_Pressed_ZTrigger.svg</file>
|
||||
<file>Resource/RMG.png</file>
|
||||
<file>Resource/Info.ico</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "AddMappingButton.hpp"
|
||||
#include "ControllerWidget.hpp"
|
||||
#include "MappingButton.hpp"
|
||||
|
||||
using namespace UserInterface::Widget;
|
||||
|
||||
AddMappingButton::AddMappingButton(QWidget* parent) : QPushButton(parent)
|
||||
{
|
||||
}
|
||||
|
||||
AddMappingButton::~AddMappingButton()
|
||||
{
|
||||
}
|
||||
|
||||
void AddMappingButton::Initialize(ControllerWidget* widget, MappingButton* button)
|
||||
{
|
||||
this->controllerWidget = widget;
|
||||
this->mappingButton = button;
|
||||
|
||||
connect(this, &QPushButton::released, [=]
|
||||
{
|
||||
emit this->controllerWidget->on_AddMappingButton_Released(this->mappingButton);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef ADDMAPPINGBUTTON_HPP
|
||||
#define ADDMAPPINGBUTTON_HPP
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
namespace Widget
|
||||
{
|
||||
|
||||
// we can't include ControllerWidget.hpp
|
||||
// because that header includes this header,
|
||||
// so forward-declare it to prevent issues
|
||||
class ControllerWidget;
|
||||
class MappingButton;
|
||||
|
||||
class AddMappingButton : public QPushButton
|
||||
{
|
||||
private:
|
||||
ControllerWidget* controllerWidget = nullptr;
|
||||
MappingButton* mappingButton = nullptr;
|
||||
|
||||
public:
|
||||
AddMappingButton(QWidget* parent);
|
||||
~AddMappingButton();
|
||||
|
||||
void Initialize(ControllerWidget* widget, MappingButton* button);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ADDMAPPINGBUTTON_HPP
|
||||
@@ -10,8 +10,8 @@
|
||||
#include "ControllerImageWidget.hpp"
|
||||
|
||||
#include <QSvgRenderer>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <QPainter>
|
||||
#include <QResizeEvent>
|
||||
|
||||
@@ -62,6 +62,15 @@ void ControllerImageWidget::SetDeadzone(int value)
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerImageWidget::SetSensitivity(int value)
|
||||
{
|
||||
if (this->sensitivityValue != value)
|
||||
{
|
||||
this->sensitivityValue = value;
|
||||
this->needImageUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerImageWidget::ClearControllerState()
|
||||
{
|
||||
// reset button state
|
||||
@@ -125,6 +134,7 @@ void ControllerImageWidget::paintEvent(QPaintEvent *event)
|
||||
{ N64ControllerButton::CButtonRight, ":Resource/Controller_Pressed_CButtonRight.svg" },
|
||||
{ N64ControllerButton::LeftTrigger, ":Resource/Controller_Pressed_LeftTrigger.svg" },
|
||||
{ N64ControllerButton::RightTrigger, ":Resource/Controller_Pressed_RightTrigger.svg" },
|
||||
{ N64ControllerButton::ZTrigger, ":Resource/Controller_Pressed_ZTrigger.svg" }
|
||||
};
|
||||
|
||||
static const QString baseImageUri = ":Resource/Controller_NoAnalogStick.svg";
|
||||
@@ -152,27 +162,35 @@ void ControllerImageWidget::paintEvent(QPaintEvent *event)
|
||||
renderer.setAspectRatioMode(Qt::AspectRatioMode::KeepAspectRatio);
|
||||
|
||||
QRectF rectF = renderer.viewBoxF();
|
||||
double offsetx = 0, offsety = 0;
|
||||
const int width = rectF.width();
|
||||
const int height = rectF.height();
|
||||
// we'll move the analog stick by a percentage
|
||||
// of the total width/height from the image
|
||||
const double maxOffsety = ((double)(height * 0.12265f) / 2);
|
||||
const double maxOffsetx = maxOffsety;
|
||||
const double dist = sqrt(pow(this->xAxisState, 2) + pow(this->yAxisState, 2));
|
||||
const double absoluteMaxOffset = ((double)(height * 0.12265f) / 2);
|
||||
// slope as in line gradient
|
||||
const double offsetSlope = absoluteMaxOffset / 100;
|
||||
// take sensitivity into account
|
||||
const double sensitivityFactor = this->sensitivityValue / 100.0;
|
||||
const double sensitivityAdjustedMaxOffset = absoluteMaxOffset * std::min(sensitivityFactor, 1.0);
|
||||
double offsetDeadzone = this->deadzoneValue * sensitivityFactor * offsetSlope;
|
||||
int offsetx = this->xAxisState * sensitivityFactor * offsetSlope;
|
||||
int offsety = this->yAxisState * sensitivityFactor * offsetSlope;
|
||||
const double offsetDist = sqrt(pow(offsetx, 2) + pow(offsety, 2));
|
||||
|
||||
// take deadzone into account
|
||||
if (dist > this->deadzoneValue)
|
||||
// deadzone grows with sensitivity such that the deadzone
|
||||
// is always a percentage of the real stick range
|
||||
if (offsetDist <= offsetDeadzone)
|
||||
{
|
||||
offsetx = (maxOffsetx / 100 * this->xAxisState);
|
||||
offsety = (maxOffsety / 100 * this->yAxisState);
|
||||
offsetx = 0;
|
||||
offsety = 0;
|
||||
}
|
||||
|
||||
// take circle range into account
|
||||
if (dist > 100)
|
||||
if (offsetDist > sensitivityAdjustedMaxOffset)
|
||||
{
|
||||
offsetx = (maxOffsetx / 100 * (this->xAxisState / dist * 100));
|
||||
offsety = (maxOffsety / 100 * (this->yAxisState / dist * 100));
|
||||
offsetx = (offsetx / offsetDist) * sensitivityAdjustedMaxOffset;
|
||||
offsety = (offsety / offsetDist) * sensitivityAdjustedMaxOffset;
|
||||
}
|
||||
|
||||
// adjust rect with offset
|
||||
|
||||
@@ -31,6 +31,8 @@ private:
|
||||
int yAxisState = 0;
|
||||
// deadzone value, 0-100
|
||||
int deadzoneValue = 0;
|
||||
// sensitivity value, 25-175
|
||||
int sensitivityValue = 100;
|
||||
|
||||
bool needImageUpdate = false;
|
||||
public:
|
||||
@@ -41,6 +43,7 @@ public:
|
||||
void SetXAxisState(int xAxis);
|
||||
void SetYAxisState(int yAxis);
|
||||
void SetDeadzone(int value);
|
||||
void SetSensitivity(int value);
|
||||
|
||||
void ClearControllerState();
|
||||
void UpdateImage();
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef CONTROLLERWIDGET_H
|
||||
#define CONTROLLERWIDGET_H
|
||||
|
||||
#include "CustomButton.hpp"
|
||||
#include "MappingButton.hpp"
|
||||
#include "ControllerImageWidget.hpp"
|
||||
|
||||
#include "UserInterface/EventFilter.hpp"
|
||||
@@ -34,28 +34,35 @@ class ControllerWidget : public QWidget, Ui::ControllerWidget
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
bool initialized = false;
|
||||
QString settingsSection;
|
||||
|
||||
QString gameSection;
|
||||
|
||||
OptionsDialogSettings optionsDialogSettings;
|
||||
|
||||
QList<QString> inputDeviceNameList;
|
||||
CustomButton* currentButton = nullptr;
|
||||
MappingButton* currentButton = nullptr;
|
||||
bool addMappingToButton = false;
|
||||
|
||||
QList<QString> profiles;
|
||||
QList<QString> removedProfiles;
|
||||
QList<QString> addedProfiles;
|
||||
|
||||
struct buttonWidgetMapping
|
||||
{
|
||||
enum N64ControllerButton button;
|
||||
CustomButton* buttonWidget;
|
||||
MappingButton* buttonWidget;
|
||||
};
|
||||
|
||||
struct axisWidgetMapping
|
||||
{
|
||||
enum InputAxisDirection direction;
|
||||
CustomButton* buttonWidget;
|
||||
MappingButton* buttonWidget;
|
||||
};
|
||||
|
||||
struct buttonSettingMapping
|
||||
{
|
||||
CustomButton* button;
|
||||
MappingButton* button;
|
||||
SettingsID inputTypeSettingsId;
|
||||
SettingsID nameSettingsId;
|
||||
SettingsID dataSettingsId;
|
||||
@@ -65,11 +72,11 @@ private:
|
||||
QList<buttonWidgetMapping> buttonWidgetMappings;
|
||||
QList<axisWidgetMapping> joystickWidgetMappings;
|
||||
QList<buttonSettingMapping> buttonSettingMappings;
|
||||
QList<CustomButton*> setupButtonWidgets;
|
||||
int currentSetupButtonWidgetIndex = 0;
|
||||
bool currentInSetup = false;
|
||||
QList<MappingButton*> setupButtonWidgets;
|
||||
|
||||
void initializeButtons();
|
||||
void initializeMappingButtons();
|
||||
void initializeProfileButtons();
|
||||
void initializeMiscButtons();
|
||||
|
||||
bool isCurrentDeviceKeyboard();
|
||||
bool isCurrentDeviceNotFound();
|
||||
@@ -77,11 +84,27 @@ private:
|
||||
void disableAllChildren();
|
||||
void enableAllChildren();
|
||||
|
||||
void removeDuplicates(CustomButton* button);
|
||||
void removeDuplicates(MappingButton* button);
|
||||
|
||||
QString getCurrentSettingsSection();
|
||||
|
||||
SDL_JoystickID currentJoystickId = -1;
|
||||
QString getUserProfileSectionName(QString profile);
|
||||
|
||||
bool isSectionUserProfile(QString section);
|
||||
bool isSectionGameProfile(QString section);
|
||||
|
||||
void setPluggedIn(bool value);
|
||||
|
||||
bool hasAnyGameSettingChanged(void);
|
||||
|
||||
void showErrorMessage(QString text, QString details = "");
|
||||
|
||||
SDL_JoystickID currentJoystickId = -1;
|
||||
bool isCurrentJoystickGameController = false;
|
||||
|
||||
int previousProfileComboBoxIndex = -1;
|
||||
|
||||
bool onlyLoadGameProfile = false;
|
||||
|
||||
public:
|
||||
ControllerWidget(QWidget* parent, EventFilter* eventFilter);
|
||||
@@ -97,40 +120,60 @@ public:
|
||||
void GetCurrentInputDevice(QString& deviceName, int& deviceNum, bool ignoreDeviceNotFound = false);
|
||||
bool IsPluggedIn();
|
||||
|
||||
void SetSettingsSection(QString section);
|
||||
void SetOnlyLoadGameProfile(bool value);
|
||||
|
||||
void SetSettingsSection(QString profile, QString section);
|
||||
void SetInitialized(bool value);
|
||||
|
||||
void LoadSettings();
|
||||
void LoadSettings(QString section);
|
||||
void LoadSettings(QString section, bool loadUserProfile = false);
|
||||
void LoadUserProfileSettings();
|
||||
|
||||
void SaveDefaultSettings();
|
||||
void SaveSettings();
|
||||
void SaveUserProfileSettings();
|
||||
void SaveSettings(QString section);
|
||||
|
||||
void RevertSettings();
|
||||
|
||||
void SetCurrentJoystickID(SDL_JoystickID joystickId);
|
||||
void SetIsCurrentJoystickGameController(bool isGameController);
|
||||
|
||||
void AddUserProfile(QString name, QString section);
|
||||
void RemoveUserProfile(QString name, QString section);
|
||||
|
||||
private slots:
|
||||
void on_deadZoneSlider_valueChanged(int value);
|
||||
void on_analogStickSensitivitySlider_valueChanged(int value);
|
||||
|
||||
void on_profileComboBox_currentIndexChanged(int value);
|
||||
|
||||
void on_inputDeviceComboBox_currentIndexChanged(int value);
|
||||
void on_inputDeviceRefreshButton_clicked();
|
||||
|
||||
void on_controllerPluggedCheckBox_toggled(bool value);
|
||||
|
||||
void on_addProfileButton_clicked();
|
||||
void on_removeProfileButton_clicked();
|
||||
void on_setupButton_clicked();
|
||||
|
||||
void on_resetButton_clicked();
|
||||
void on_optionsButton_clicked();
|
||||
|
||||
public slots:
|
||||
void on_CustomButton_released(CustomButton* button);
|
||||
void on_CustomButton_TimerFinished(CustomButton* button);
|
||||
void on_CustomButton_DataSet(CustomButton* button);
|
||||
void on_MappingButton_Released(MappingButton* button);
|
||||
void on_MappingButton_TimerFinished(MappingButton* button);
|
||||
void on_MappingButton_DataSet(MappingButton* button);
|
||||
|
||||
void on_AddMappingButton_Released(MappingButton* button);
|
||||
void on_RemoveMappingButton_Released(MappingButton* button);
|
||||
|
||||
void on_MainDialog_SdlEvent(SDL_Event* event);
|
||||
void on_MainDialog_SdlEventPollFinished();
|
||||
|
||||
signals:
|
||||
void CurrentInputDeviceChanged(ControllerWidget* widget, QString deviceName, int deviceNum);
|
||||
void RefreshInputDevicesButtonClicked();
|
||||
|
||||
void UserProfileAdded(QString name, QString section);
|
||||
void UserProfileRemoved(QString name, QString section);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||