mirror of
https://github.com/Rosalie241/RMG.git
synced 2026-07-17 12:15:30 +02:00
Compare commits
37
Commits
small64-test
...
v0.8.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d1fc16a53 | ||
|
|
9032008a63 | ||
|
|
4788d643da | ||
|
|
e1db6c24b0 | ||
|
|
81f98505ca | ||
|
|
7270e0dfbe | ||
|
|
bc3e3b3f9c | ||
|
|
d7b17cd494 | ||
|
|
e5cd034b4f | ||
|
|
1c6210f964 | ||
|
|
9ce1e45d64 | ||
|
|
be738f0cb7 | ||
|
|
e882e0f22c | ||
|
|
f7a1d0f952 | ||
|
|
6b8990fa1a | ||
|
|
a74cff50f8 | ||
|
|
d4ac45a9c5 | ||
|
|
32aebfec1a | ||
|
|
aee7da8068 | ||
|
|
078361e2e6 | ||
|
|
e0cae9c1a9 | ||
|
|
c8d46ee919 | ||
|
|
c5965b3940 | ||
|
|
affb0ee0ee | ||
|
|
dd6ea4f22a | ||
|
|
006a7c8eff | ||
|
|
5f10f39ac0 | ||
|
|
6e1df7fc79 | ||
|
|
5cab9282e7 | ||
|
|
1c6d8a6f59 | ||
|
|
c43f43e634 | ||
|
|
409aac2caa | ||
|
|
21b187dacc | ||
|
|
a110f48fad | ||
|
|
1f24d20054 | ||
|
|
8e61b79ecf | ||
|
|
f459c456de |
@@ -61,7 +61,7 @@ jobs:
|
||||
path: Bin/*.AppImage
|
||||
|
||||
build-windows:
|
||||
runs-on: windows-2019
|
||||
runs-on: windows-2022
|
||||
strategy:
|
||||
matrix:
|
||||
features: [ ON, OFF ]
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# Maintainer: Rosalie Wanders <rosalie@mailbox.org>
|
||||
pkgname=rmg
|
||||
pkgver=0.7.8
|
||||
pkgrel=1
|
||||
pkgver=0.8.0
|
||||
pkgrel=2
|
||||
pkgdesc="Rosalie's Mupen GUI"
|
||||
arch=('x86_64' 'aarch64')
|
||||
url="https://github.com/Rosalie241/$pkgname"
|
||||
license=('GPL3')
|
||||
|
||||
depends=("hidapi" "libsamplerate" "speexdsp" "minizip" "sdl2" "sdl2_net" "zlib" "freetype2" "qt6-base" "qt6-svg" "qt6-websockets")
|
||||
makedepends=("git" "nasm" "cmake")
|
||||
makedepends=("git" "nasm" "cmake" "vulkan-headers")
|
||||
|
||||
source=("git+https://github.com/Rosalie241/$pkgname.git#tag=v$pkgver")
|
||||
sha256sums=('SKIP')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: RMG
|
||||
Version: 0.7.8
|
||||
Version: 0.8.0
|
||||
Release: %autorelease
|
||||
Summary: Rosalie's Mupen GUI
|
||||
|
||||
|
||||
@@ -29,6 +29,30 @@
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="v0.8.0" date="2025-09-10" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix 64DD games crashing in some cases since v0.7.8</li>
|
||||
<li>Add Windows Vista theme to settings on Windows (thank you RibShark)</li>
|
||||
<li>Add support for the netplay dispatch server</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.7.9" date="2025-05-19" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix netplay allocating UDP packets during emulation</li>
|
||||
<li>Fix 'Game List' and 'Game Grid' UI elements not being disabled during emulation</li>
|
||||
<li>Fix compilation error with newer minizip-ng versions</li>
|
||||
<li>Add search feature to the ROM browser</li>
|
||||
<li>Add crop settings for each side in mupen64plus-video-parallel</li>
|
||||
<li>Change default ROM search limit to 2048</li>
|
||||
<li>Update mupen64plus-video-GLideN64 and mupen64plus-rsp-hle</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.7.8" date="2025-03-23" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
|
||||
@@ -73,9 +73,9 @@ cmake --install "$build_dir" --prefix="/usr"
|
||||
```
|
||||
|
||||
#### Windows
|
||||
* Download & Install [MSYS2](https://www.msys2.org/)
|
||||
* Download & Install [MSYS2](https://www.msys2.org/) (UCRT64)
|
||||
```bash
|
||||
pacman -S --needed make mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-hidapi mingw-w64-ucrt-x86_64-freetype mingw-w64-ucrt-x86_64-libpng mingw-w64-ucrt-x86_64-qt6 mingw-w64-ucrt-x86_64-SDL2 mingw-w64-ucrt-x86_64-SDL2_net mingw-w64-ucrt-x86_64-speexdsp mingw-w64-ucrt-x86_64-libsamplerate mingw-w64-ucrt-x86_64-nasm mingw-w64-ucrt-x86_64-minizip mingw-w64-ucrt-x86_64-vulkan-headers git
|
||||
pacman -S --needed make mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-hidapi mingw-w64-ucrt-x86_64-freetype mingw-w64-ucrt-x86_64-libpng mingw-w64-ucrt-x86_64-qt6 mingw-w64-ucrt-x86_64-SDL2 mingw-w64-ucrt-x86_64-SDL2_net mingw-w64-ucrt-x86_64-speexdsp mingw-w64-ucrt-x86_64-libsamplerate mingw-w64-ucrt-x86_64-libusb mingw-w64-ucrt-x86_64-nasm mingw-w64-ucrt-x86_64-minizip mingw-w64-ucrt-x86_64-vulkan-headers git
|
||||
./Source/Script/Build.sh Release
|
||||
```
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
if(POLICY CMP0025)
|
||||
# detect Apple's Clang
|
||||
cmake_policy(SET CMP0025 NEW)
|
||||
|
||||
+25
-19
@@ -26,26 +26,20 @@ jobs:
|
||||
arch: x64
|
||||
- cc: Clang
|
||||
arch: x86
|
||||
name: Linux / ${{ matrix.cc }} / ${{ matrix.arch }}
|
||||
runs-on: ubuntu-22.04
|
||||
name: Linux / ${{ matrix.cc }} ${{ matrix.arch }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Get build dependencies and arrange the environment
|
||||
run: |
|
||||
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
|
||||
export BUILD_DEPS="libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libsdl1.2-dev libsdl2-dev libvulkan-dev zlib1g-dev"
|
||||
export BUILD_DEPS="libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libsdl2-dev libvulkan-dev zlib1g-dev"
|
||||
./.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
- name: Build and related stuff, backup binaries
|
||||
run: |
|
||||
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
|
||||
export PATH="$(pwd)/.github/workflows/scripts:${PATH}"
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 SDL_CONFIG="sdl-config""
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1"
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 SDL_CONFIG="sdl2-config""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 SDL_CONFIG="sdl-config" POSTFIX="-old""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 SDL_CONFIG="sdl2-config" POSTFIX="-old""
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 POSTFIX="-old""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg
|
||||
- name: Upload artifact
|
||||
if: matrix.cc == 'GCC'
|
||||
@@ -63,12 +57,24 @@ jobs:
|
||||
arch: x64
|
||||
cross: x86_64
|
||||
env: MINGW64
|
||||
gbc: 0
|
||||
- cc: GCC
|
||||
arch: x86
|
||||
cross: i686
|
||||
env: MINGW32
|
||||
name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.arch }}
|
||||
runs-on: windows-2022
|
||||
gbc: 0
|
||||
- cc: GCC
|
||||
arch: x64
|
||||
cross: ucrt-x86_64
|
||||
env: UCRT64
|
||||
gbc: 1
|
||||
- cc: Clang
|
||||
arch: x64
|
||||
cross: clang-x86_64
|
||||
env: CLANG64
|
||||
gbc: 1
|
||||
name: Windows ${{ matrix.arch }} / MSYS2 ${{ matrix.env }} ${{ matrix.cc }}
|
||||
runs-on: windows-2025
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
@@ -82,7 +88,6 @@ jobs:
|
||||
git
|
||||
libtool
|
||||
make
|
||||
mingw-w64-${{ matrix.cross }}-gcc
|
||||
mingw-w64-${{ matrix.cross }}-toolchain
|
||||
mingw-w64-${{ matrix.cross }}-freetype
|
||||
mingw-w64-${{ matrix.cross }}-libpng
|
||||
@@ -93,10 +98,11 @@ jobs:
|
||||
mingw-w64-${{ matrix.cross }}-zlib
|
||||
- name: Build and related stuff, backup binaries
|
||||
run: |
|
||||
if [[ ${{ matrix.gbc }} -eq 1 ]]; then pacman --noconfirm -S --needed mingw-w64-${{ matrix.cross }}-opencv; fi
|
||||
export PATH="$(pwd)/.github/workflows/scripts:${PATH}"
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1"
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 OPENCV=${{ matrix.gbc }}"
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 POSTFIX="-old""
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 OPENCV=${{ matrix.gbc }} POSTFIX="-old""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
- name: Backup dependencies, etc...
|
||||
run: |
|
||||
@@ -114,11 +120,11 @@ jobs:
|
||||
include:
|
||||
- toolset: v143
|
||||
arch: x64
|
||||
vs: 2022
|
||||
vs: 2025
|
||||
- toolset: v141_xp
|
||||
arch: x86
|
||||
vs: 2019
|
||||
name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.arch }}
|
||||
name: Windows ${{ matrix.arch }} / MSVC with ${{ matrix.toolset }}
|
||||
runs-on: windows-${{ matrix.vs }}
|
||||
defaults:
|
||||
run:
|
||||
@@ -131,7 +137,7 @@ jobs:
|
||||
set PATH=%CD%\.github\workflows\scripts;%PATH%
|
||||
set TOOLSET=${{ matrix.toolset }}
|
||||
call ci_msvc_build.cmd ${{ matrix.arch }}
|
||||
ci_msvc_build.cmd ${{ matrix.arch }} newdyn
|
||||
call ci_msvc_build.cmd ${{ matrix.arch }} newdyn
|
||||
- name: Backup dependencies, etc...
|
||||
run: |
|
||||
.\.github\workflows\scripts\ci_backup_msvc_deps.cmd ${{ matrix.arch }} freetype.dll libpng16.dll SDL2.dll SDL2_net.dll zlib.dll
|
||||
|
||||
+25
-19
@@ -19,27 +19,21 @@ jobs:
|
||||
arch: x64
|
||||
- cc: Clang
|
||||
arch: x86
|
||||
name: Linux / ${{ matrix.cc }} / ${{ matrix.arch }}
|
||||
runs-on: ubuntu-22.04
|
||||
name: Linux / ${{ matrix.cc }} ${{ matrix.arch }}
|
||||
runs-on: ubuntu-24.04
|
||||
if: github.repository == 'mupen64plus/mupen64plus-core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Get build dependencies and arrange the environment
|
||||
run: |
|
||||
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
|
||||
export BUILD_DEPS="libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libsdl1.2-dev libsdl2-dev libvulkan-dev zlib1g-dev"
|
||||
export BUILD_DEPS="libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libsdl2-dev libvulkan-dev zlib1g-dev"
|
||||
./.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
- name: Build and related stuff, backup binaries
|
||||
run: |
|
||||
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
|
||||
export PATH="$(pwd)/.github/workflows/scripts:${PATH}"
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 SDL_CONFIG="sdl-config""
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1"
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 SDL_CONFIG="sdl2-config""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 SDL_CONFIG="sdl-config" POSTFIX="-old""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 SDL_CONFIG="sdl2-config" POSTFIX="-old""
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 POSTFIX="-old""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg
|
||||
- name: Upload artifact
|
||||
if: matrix.cc == 'GCC'
|
||||
@@ -57,12 +51,24 @@ jobs:
|
||||
arch: x64
|
||||
cross: x86_64
|
||||
env: MINGW64
|
||||
gbc: 0
|
||||
- cc: GCC
|
||||
arch: x86
|
||||
cross: i686
|
||||
env: MINGW32
|
||||
name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.arch }}
|
||||
runs-on: windows-2022
|
||||
gbc: 0
|
||||
- cc: GCC
|
||||
arch: x64
|
||||
cross: ucrt-x86_64
|
||||
env: UCRT64
|
||||
gbc: 1
|
||||
- cc: Clang
|
||||
arch: x64
|
||||
cross: clang-x86_64
|
||||
env: CLANG64
|
||||
gbc: 1
|
||||
name: Windows ${{ matrix.arch }} / MSYS2 ${{ matrix.env }} ${{ matrix.cc }}
|
||||
runs-on: windows-2025
|
||||
if: github.repository == 'mupen64plus/mupen64plus-core'
|
||||
defaults:
|
||||
run:
|
||||
@@ -77,7 +83,6 @@ jobs:
|
||||
git
|
||||
libtool
|
||||
make
|
||||
mingw-w64-${{ matrix.cross }}-gcc
|
||||
mingw-w64-${{ matrix.cross }}-toolchain
|
||||
mingw-w64-${{ matrix.cross }}-freetype
|
||||
mingw-w64-${{ matrix.cross }}-libpng
|
||||
@@ -88,10 +93,11 @@ jobs:
|
||||
mingw-w64-${{ matrix.cross }}-zlib
|
||||
- name: Build and related stuff, backup binaries
|
||||
run: |
|
||||
if [[ ${{ matrix.gbc }} -eq 1 ]]; then pacman --noconfirm -S --needed mingw-w64-${{ matrix.cross }}-opencv; fi
|
||||
export PATH="$(pwd)/.github/workflows/scripts:${PATH}"
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1"
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 OPENCV=${{ matrix.gbc }}"
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 POSTFIX="-old""
|
||||
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 OPENCV=${{ matrix.gbc }} POSTFIX="-old""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
- name: Backup dependencies, etc...
|
||||
run: |
|
||||
@@ -109,11 +115,11 @@ jobs:
|
||||
include:
|
||||
- toolset: v143
|
||||
arch: x64
|
||||
vs: 2022
|
||||
vs: 2025
|
||||
- toolset: v141_xp
|
||||
arch: x86
|
||||
vs: 2019
|
||||
name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.arch }}
|
||||
name: Windows ${{ matrix.arch }} / MSVC with ${{ matrix.toolset }}
|
||||
runs-on: windows-${{ matrix.vs }}
|
||||
if: github.repository == 'mupen64plus/mupen64plus-core'
|
||||
defaults:
|
||||
@@ -127,7 +133,7 @@ jobs:
|
||||
set PATH=%CD%\.github\workflows\scripts;%PATH%
|
||||
set TOOLSET=${{ matrix.toolset }}
|
||||
call ci_msvc_build.cmd ${{ matrix.arch }}
|
||||
ci_msvc_build.cmd ${{ matrix.arch }} newdyn
|
||||
call ci_msvc_build.cmd ${{ matrix.arch }} newdyn
|
||||
- name: Backup dependencies, etc...
|
||||
run: |
|
||||
.\.github\workflows\scripts\ci_backup_msvc_deps.cmd ${{ matrix.arch }} freetype.dll libpng16.dll SDL2.dll SDL2_net.dll zlib.dll
|
||||
|
||||
@@ -37,7 +37,7 @@ export REPO="${PWD##*/}"
|
||||
if [[ "${REPO}" == "" ]]; then exit 6; fi
|
||||
|
||||
export BIN_OS="$(uname -s | tr [A-Z] [a-z])"
|
||||
if [[ ! -z ${MSYSTEM} ]]; then export BIN_OS="msys2"; fi
|
||||
if [[ ! -z ${MSYSTEM} ]]; then export BIN_OS="msys2-$(echo "${MSYSTEM}" | tr [A-Z] [a-z])"; fi
|
||||
export ENV_NAME="$(uname -s)"
|
||||
export LDD="ldd"
|
||||
export PKG_PATH="usr/local/lib/mupen64plus/"
|
||||
@@ -105,6 +105,7 @@ if [[ -z ${ARTIFACT} ]]; then
|
||||
exit 5
|
||||
else
|
||||
cd pkg
|
||||
if [[ -f "mupen64plus.desktop" ]]; then rm -f mupen64plus.desktop; fi
|
||||
ls -gG "${PKG_PATH}${ARTIFACT}"
|
||||
echo ""
|
||||
${LDD} "${PKG_PATH}${ARTIFACT}" > ldd.log
|
||||
|
||||
+6
-2
@@ -1,12 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e +u
|
||||
|
||||
# NOTE: There is no native "libglew-dev:i386" in Ubuntu 22.04, we will use Debian ones...
|
||||
# NOTE: There is no native "libglew-dev:i386" in Ubuntu 24.04, we will use Debian ones...
|
||||
|
||||
export GLEWVER="$(apt list libglew-dev | grep "amd64" | cut -d ' ' -f2)"
|
||||
export PKGS="$(apt list libglew* | grep "${GLEWVER}" | cut -d '/' -f1)"
|
||||
export DEBSOURCE="http://http.us.debian.org/debian/pool/main/g/glew/"
|
||||
export PKGVER_LS="$(curl -sS ${DEBSOURCE} | grep "${GLEWVER}" | grep "amd64" | cut -d '_' -f2 | sort)"
|
||||
export BUILDP1="$(echo "${GLEWVER}" | cut -d '-' -f1)"
|
||||
export BUILDP2="$(echo "${GLEWVER}" | cut -d '-' -f2)"
|
||||
export GLEWBUILD="${BUILDP1}"
|
||||
if [[ "${GLEWBUILD}" != "${GLEWVER}" ]]; then export GLEWBUILD="${BUILDP1}-${BUILDP2:0:1}"; fi
|
||||
export PKGVER_LS="$(curl -sS ${DEBSOURCE} | grep "${GLEWBUILD}" | grep "amd64" | cut -d '_' -f2 | sort)"
|
||||
if [[ "${PKGVER_LS}" != "" ]]; then
|
||||
for VER in ${PKGVER_LS}; do export PKGVER="${VER}"; done
|
||||
cd /tmp
|
||||
|
||||
+3
-3
@@ -4,7 +4,7 @@ set -e +u
|
||||
if [[ ${#} -lt 2 ]]; then exit 9; fi
|
||||
|
||||
unset ARCH_DEP CC_DEP
|
||||
export BUILD_DEPS_I386="crossbuild-essential-i386 g++${C_GCC_SUFFIX}-i686-linux-gnu gcc${C_GCC_SUFFIX}-i686-linux-gnu libc6-i386"
|
||||
export BUILD_DEPS_I386="crossbuild-essential-i386 g++${C_GCC_SUFFIX}-i686-linux-gnu gcc${C_GCC_SUFFIX}-i686-linux-gnu"
|
||||
export HOTFIX_I386="libatomic1:i386 libgcc-s1:i386 libstdc++6:i386 ${HOTFIX_I386}"
|
||||
export ENV_ARGS="$(echo "${*}" | tr [A-Z] [a-z])"
|
||||
|
||||
@@ -17,7 +17,7 @@ for ARG in ${ENV_ARGS}; do
|
||||
export CC_DEP="g++${C_GCC_SUFFIX} gcc${C_GCC_SUFFIX}"
|
||||
;;
|
||||
multilib )
|
||||
export BUILD_DEPS_I386="g++${C_GCC_SUFFIX}-multilib gcc${C_GCC_SUFFIX}-multilib libc6-dev-i386"
|
||||
export BUILD_DEPS_I386="g++${C_GCC_SUFFIX}-multilib gcc${C_GCC_SUFFIX}-multilib"
|
||||
;;
|
||||
x64 )
|
||||
export ARCH_DEP="x64"
|
||||
@@ -31,9 +31,9 @@ done
|
||||
if [[ -z ${ARCH_DEP} ]]; then exit 8; fi
|
||||
if [[ -z ${CC_DEP} ]]; then exit 7; fi
|
||||
|
||||
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
if [[ "${ARCH_DEP}" == "x86" ]]; then sudo dpkg --add-architecture i386; fi
|
||||
sudo apt-get update
|
||||
sudo apt-mark hold grub-common grub-efi-amd64-bin python3 python3-apt shim-signed
|
||||
sudo apt-get -y install build-essential git nasm pkg-config ${CC_DEP} ${BUILD_DEPS}
|
||||
if [[ "${ARCH_DEP}" == "x86" ]]; then
|
||||
if [[ "${BUILD_DEPS}" != "" ]]; then
|
||||
|
||||
+3
-3
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = git@github.com:mupen64plus/mupen64plus-core.git
|
||||
branch = master
|
||||
commit = e170c409fb006aa38fd02031b5eefab6886ec125
|
||||
parent = 37839b0178b42b57a38a040bbf4e1f410e6952a1
|
||||
commit = c5b1e72be0d2b33c18be48c989e726ac176e7872
|
||||
parent = c8048741165583eaced380e84945764e924df6bf
|
||||
method = merge
|
||||
cmdver = 0.4.6
|
||||
cmdver = 0.4.9
|
||||
|
||||
+4
-4
@@ -339,11 +339,11 @@ LDLIBS += $(LIBPNG_LDLIBS)
|
||||
ifeq ($(OPENCV), 1)
|
||||
# OpenCV lib
|
||||
ifeq ($(origin OPENCV_CFLAGS) $(origin OPENCV_LDLIBS), undefined undefined)
|
||||
ifeq ($(shell $(PKG_CONFIG) --modversion opencv 2>/dev/null),)
|
||||
$(error No OpenCV development libraries found!)
|
||||
ifeq ($(shell $(PKG_CONFIG) --modversion opencv4 2>/dev/null),)
|
||||
$(error No OpenCV 4 development libraries found!)
|
||||
endif
|
||||
OPENCV_CFLAGS += $(shell $(PKG_CONFIG) --cflags opencv)
|
||||
OPENCV_LDLIBS += $(shell $(PKG_CONFIG) --libs opencv)
|
||||
OPENCV_CFLAGS += $(shell $(PKG_CONFIG) --cflags opencv4)
|
||||
OPENCV_LDLIBS += $(shell $(PKG_CONFIG) --libs opencv4)
|
||||
endif
|
||||
CFLAGS += $(OPENCV_CFLAGS)
|
||||
LDLIBS += $(OPENCV_LDLIBS)
|
||||
|
||||
@@ -281,7 +281,7 @@ static db_addr_t
|
||||
db_disasm_insn ( struct r4k_dis_t * state,
|
||||
int insn,
|
||||
db_addr_t loc,
|
||||
bool altfmt )
|
||||
unsigned char altfmt)
|
||||
{
|
||||
char * rel;
|
||||
InstFmt i;
|
||||
|
||||
@@ -24,11 +24,9 @@
|
||||
|
||||
#if defined(WIN32)
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned char bool;
|
||||
#define false 0
|
||||
#define true 1
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ void read_cart_rom(void* opaque, uint32_t address, uint32_t* value)
|
||||
}
|
||||
else
|
||||
{
|
||||
*value = *(uint32_t*)(cart_rom->rom + addr);
|
||||
*value = cart_rom->rom_size == 0 ? 0 : *(uint32_t*)(cart_rom->rom + addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -200,7 +200,7 @@ void init_device(struct device* dev,
|
||||
* use CART unless DD is plugged and the plugged CART is not a combo media (cart+disk),
|
||||
* or rom_size is 0 meaning there's no CART loaded
|
||||
*/
|
||||
uint8_t media = *((uint8_t*)mem_base_u32(base, MM_CART_ROM) + (0x3b ^ S8));
|
||||
uint8_t media = rom_size == 0 ? 0 : *((uint8_t*)mem_base_u32(base, MM_CART_ROM) + (0x3b ^ S8));
|
||||
uint32_t rom_base = (rom_size == 0 || (dd_rom_size > 0 && media != 'C'))
|
||||
? MM_DD_ROM
|
||||
: MM_CART_ROM;
|
||||
|
||||
+2
-2
@@ -4274,7 +4274,7 @@ static void loop_preload(signed char pre[],signed char entry[])
|
||||
// Generate address for load/store instruction
|
||||
static void address_generation(int i,struct regstat *i_regs,signed char entry[])
|
||||
{
|
||||
if(i>=4069) return;
|
||||
if(i>=MAXBLOCK) return;
|
||||
if(itype[i]==LOAD||itype[i]==LOADLR||itype[i]==STORE||itype[i]==STORELR||itype[i]==C1LS) {
|
||||
int ra=0;
|
||||
int agr=AGEN1+(i&1);
|
||||
@@ -4381,7 +4381,7 @@ static void address_generation(int i,struct regstat *i_regs,signed char entry[])
|
||||
}
|
||||
}
|
||||
// Preload constants for next instruction
|
||||
if(i+1>=4096) return;
|
||||
if(i+1>=MAXBLOCK) return;
|
||||
if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS) {
|
||||
int agr,ra;
|
||||
#if (NEW_DYNAREC!=NEW_DYNAREC_X86) && (NEW_DYNAREC!=NEW_DYNAREC_X64)
|
||||
|
||||
@@ -153,7 +153,7 @@ void read_pi_regs(void* opaque, uint32_t address, uint32_t* value)
|
||||
struct pi_controller* pi = (struct pi_controller*)opaque;
|
||||
uint32_t reg = pi_reg(address);
|
||||
|
||||
if (reg < PI_REGS_COUNT)
|
||||
if (reg < PI_REGS_COUNT)
|
||||
*value = pi->regs[reg];
|
||||
|
||||
if (reg == PI_WR_LEN_REG || reg == PI_RD_LEN_REG)
|
||||
|
||||
@@ -104,7 +104,7 @@ void read_vi_regs(void* opaque, uint32_t address, uint32_t* value)
|
||||
/* update current field */
|
||||
vi->regs[VI_CURRENT_REG] = (vi->regs[VI_CURRENT_REG] & (~1)) | vi->field;
|
||||
}
|
||||
|
||||
|
||||
if (reg < VI_REGS_COUNT)
|
||||
{
|
||||
*value = vi->regs[reg];
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
+1
-1
@@ -233,7 +233,7 @@ static m64p_error plugin_connect_gfx(m64p_dynlib_handle plugin_handle)
|
||||
|
||||
static m64p_error plugin_start_gfx(void)
|
||||
{
|
||||
uint8_t media = *((uint8_t*)mem_base_u32(g_mem_base, MM_CART_ROM) + (0x3b ^ S8));
|
||||
uint8_t media = g_rom_size == 0 ? 0 : *((uint8_t*)mem_base_u32(g_mem_base, MM_CART_ROM) + (0x3b ^ S8));
|
||||
|
||||
/* Here we feed 64DD IPL ROM header to GFX plugin if 64DD is present.
|
||||
* We use g_media_loader.get_dd_rom to detect 64DD presence
|
||||
|
||||
@@ -26,18 +26,16 @@ jobs:
|
||||
arch: x64
|
||||
- cc: Clang
|
||||
arch: x86
|
||||
name: Linux / ${{ matrix.cc }} / ${{ matrix.arch }}
|
||||
runs-on: ubuntu-22.04
|
||||
name: Linux / ${{ matrix.cc }} ${{ matrix.arch }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Get build dependencies and arrange the environment
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core
|
||||
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
|
||||
./../mupen64plus-core/.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
- name: Build and related stuff, backup binaries
|
||||
run: |
|
||||
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
|
||||
./../mupen64plus-core/.github/workflows/scripts/ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg
|
||||
- name: Upload artifact
|
||||
if: matrix.cc == 'GCC'
|
||||
@@ -59,8 +57,16 @@ jobs:
|
||||
arch: x86
|
||||
cross: i686
|
||||
env: MINGW32
|
||||
name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.arch }}
|
||||
runs-on: windows-2022
|
||||
- cc: GCC
|
||||
arch: x64
|
||||
cross: ucrt-x86_64
|
||||
env: UCRT64
|
||||
- cc: Clang
|
||||
arch: x64
|
||||
cross: clang-x86_64
|
||||
env: CLANG64
|
||||
name: Windows ${{ matrix.arch }} / MSYS2 ${{ matrix.env }} ${{ matrix.cc }}
|
||||
runs-on: windows-2025
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
@@ -74,7 +80,6 @@ jobs:
|
||||
git
|
||||
libtool
|
||||
make
|
||||
mingw-w64-${{ matrix.cross }}-gcc
|
||||
mingw-w64-${{ matrix.cross }}-toolchain
|
||||
mingw-w64-${{ matrix.cross }}-ntldd
|
||||
- name: Build and related stuff, backup binaries
|
||||
@@ -97,11 +102,11 @@ jobs:
|
||||
include:
|
||||
- toolset: v143
|
||||
arch: x64
|
||||
vs: 2022
|
||||
vs: 2025
|
||||
- toolset: v141_xp
|
||||
arch: x86
|
||||
vs: 2019
|
||||
name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.arch }}
|
||||
name: Windows ${{ matrix.arch }} / MSVC with ${{ matrix.toolset }}
|
||||
runs-on: windows-${{ matrix.vs }}
|
||||
defaults:
|
||||
run:
|
||||
|
||||
@@ -19,19 +19,17 @@ jobs:
|
||||
arch: x64
|
||||
- cc: Clang
|
||||
arch: x86
|
||||
name: Linux / ${{ matrix.cc }} / ${{ matrix.arch }}
|
||||
runs-on: ubuntu-22.04
|
||||
name: Linux / ${{ matrix.cc }} ${{ matrix.arch }}
|
||||
runs-on: ubuntu-24.04
|
||||
if: github.repository == 'mupen64plus/mupen64plus-rsp-hle'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Get build dependencies and arrange the environment
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core
|
||||
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
|
||||
./../mupen64plus-core/.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
- name: Build and related stuff, backup binaries
|
||||
run: |
|
||||
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
|
||||
./../mupen64plus-core/.github/workflows/scripts/ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg
|
||||
- name: Upload artifact
|
||||
if: matrix.cc == 'GCC'
|
||||
@@ -53,8 +51,16 @@ jobs:
|
||||
arch: x86
|
||||
cross: i686
|
||||
env: MINGW32
|
||||
name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.arch }}
|
||||
runs-on: windows-2022
|
||||
- cc: GCC
|
||||
arch: x64
|
||||
cross: ucrt-x86_64
|
||||
env: UCRT64
|
||||
- cc: Clang
|
||||
arch: x64
|
||||
cross: clang-x86_64
|
||||
env: CLANG64
|
||||
name: Windows ${{ matrix.arch }} / MSYS2 ${{ matrix.env }} ${{ matrix.cc }}
|
||||
runs-on: windows-2025
|
||||
if: github.repository == 'mupen64plus/mupen64plus-rsp-hle'
|
||||
defaults:
|
||||
run:
|
||||
@@ -69,7 +75,6 @@ jobs:
|
||||
git
|
||||
libtool
|
||||
make
|
||||
mingw-w64-${{ matrix.cross }}-gcc
|
||||
mingw-w64-${{ matrix.cross }}-toolchain
|
||||
mingw-w64-${{ matrix.cross }}-ntldd
|
||||
- name: Build and related stuff, backup binaries
|
||||
@@ -92,11 +97,11 @@ jobs:
|
||||
include:
|
||||
- toolset: v143
|
||||
arch: x64
|
||||
vs: 2022
|
||||
vs: 2025
|
||||
- toolset: v141_xp
|
||||
arch: x86
|
||||
vs: 2019
|
||||
name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.arch }}
|
||||
name: Windows ${{ matrix.arch }} / MSVC with ${{ matrix.toolset }}
|
||||
runs-on: windows-${{ matrix.vs }}
|
||||
if: github.repository == 'mupen64plus/mupen64plus-rsp-hle'
|
||||
defaults:
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
/projects/unix/_obj*/
|
||||
/projects/unix/mupen64plus-rsp-hle*.so
|
||||
/projects/unix/mupen64plus-rsp-hle*.dll
|
||||
/projects/msvc/Win32/
|
||||
/projects/msvc/x64/
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = git@github.com:/mupen64plus/mupen64plus-rsp-hle.git
|
||||
branch = master
|
||||
commit = 47f8e92e9a8bb9e49195ecfb03e9df0b63add242
|
||||
parent = 23120150f9ddbef13a0690f004c364bb334addfc
|
||||
commit = 80efbed3d737a32114956e149905c304944ebd61
|
||||
parent = 6e1df7fc792cbdee30d31366af395e72a6cde813
|
||||
method = merge
|
||||
cmdver = 0.4.6
|
||||
|
||||
+1
-1
@@ -475,7 +475,7 @@ static void ReorderSubBlock(int16_t *dst, const int16_t *src, const unsigned int
|
||||
unsigned int i;
|
||||
|
||||
/* source and destination sublocks cannot overlap */
|
||||
assert(labs(dst - src) > SUBBLOCK_SIZE);
|
||||
assert(labs(dst - src) >= SUBBLOCK_SIZE);
|
||||
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i)
|
||||
dst[i] = src[table[i]];
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = git@github.com:/gonetz/GLideN64.git
|
||||
branch = master
|
||||
commit = 9f8fc1e4c59c4cdb37112ef0c100158b25c2c1cb
|
||||
parent = 3c615c84599a0ea8624c2deea4c8ba438ce988d6
|
||||
commit = 55c436c706224eae6cd1395b88e083105b7d7834
|
||||
parent = 5cab9282e7a7f1407cde18b6e5d1630f3c156042
|
||||
method = merge
|
||||
cmdver = 0.4.6
|
||||
|
||||
+1
-1
@@ -204,7 +204,7 @@ void GBIInfo::_makeCurrent(MicrocodeInfo * _pCurrent)
|
||||
|
||||
RDP_Init();
|
||||
|
||||
G_TRI1 = G_TRI2 = G_TRIX = G_QUAD = -1; // For correct work of gSPFlushTriangles()
|
||||
G_TRI1 = G_TRI2 = G_TRIX = G_QUAD = G_TRISTRIP = G_TRIFAN = -1; // For correct work of gSPFlushTriangles()
|
||||
gSP.clipRatio = 1U;
|
||||
|
||||
switch (m_pCurrent->type) {
|
||||
|
||||
@@ -53,6 +53,7 @@ void _loadSettings(GlSettings & settings)
|
||||
config.generalEmulation.enableLegacyBlending = settings.value("enableLegacyBlending", config.generalEmulation.enableLegacyBlending).toInt(); //ini only
|
||||
config.generalEmulation.enableHybridFilter = settings.value("enableHybridFilter", config.generalEmulation.enableHybridFilter).toInt(); //ini only
|
||||
config.generalEmulation.enableFragmentDepthWrite = settings.value("enableFragmentDepthWrite", config.generalEmulation.enableFragmentDepthWrite).toInt(); //ini only
|
||||
config.generalEmulation.hacks |= settings.value("hacks", config.generalEmulation.hacks).toInt(); //ini only
|
||||
config.generalEmulation.enableCustomSettings = settings.value("enableCustomSettings", config.generalEmulation.enableCustomSettings).toInt();
|
||||
settings.endGroup();
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ void _loadSettings(QSettings & settings)
|
||||
config.generalEmulation.enableLegacyBlending = settings.value("enableLegacyBlending", config.generalEmulation.enableLegacyBlending).toInt(); //ini only
|
||||
config.generalEmulation.enableHybridFilter = settings.value("enableHybridFilter", config.generalEmulation.enableHybridFilter).toInt(); //ini only
|
||||
config.generalEmulation.enableFragmentDepthWrite = settings.value("enableFragmentDepthWrite", config.generalEmulation.enableFragmentDepthWrite).toInt(); //ini only
|
||||
config.generalEmulation.hacks |= settings.value("hacks", config.generalEmulation.hacks).toInt(); //ini only
|
||||
config.generalEmulation.enableCustomSettings = settings.value("enableCustomSettings", config.generalEmulation.enableCustomSettings).toInt();
|
||||
settings.endGroup();
|
||||
|
||||
|
||||
+1
-1
@@ -193,7 +193,7 @@ void GLInfo::init() {
|
||||
eglImage = (Utils::isEGLExtensionSupported("EGL_KHR_image_base") || Utils::isEGLExtensionSupported("EGL_KHR_image"));
|
||||
ext_fetch_arm = Utils::isExtensionSupported(*this, "GL_ARM_shader_framebuffer_fetch") && !ext_fetch;
|
||||
|
||||
dual_source_blending = !isGLESX || (Utils::isExtensionSupported(*this, "GL_EXT_blend_func_extended") && !isAnyAdreno);
|
||||
dual_source_blending = !isGLESX || ((!isGLES2) && (Utils::isExtensionSupported(*this, "GL_EXT_blend_func_extended") && !isAnyAdreno));
|
||||
anisotropic_filtering = Utils::isExtensionSupported(*this, "GL_EXT_texture_filter_anisotropic");
|
||||
|
||||
#ifdef OS_ANDROID
|
||||
|
||||
@@ -43,6 +43,8 @@ void gSPFlushTriangles()
|
||||
(RSP.nextCmd != G_TRI1) &&
|
||||
(RSP.nextCmd != G_TRI2) &&
|
||||
(RSP.nextCmd != G_TRIX) &&
|
||||
(RSP.nextCmd != G_TRISTRIP) &&
|
||||
(RSP.nextCmd != G_TRIFAN) &&
|
||||
(RSP.nextCmd != G_QUAD)
|
||||
) {
|
||||
dwnd().getDrawer().drawTriangles();
|
||||
|
||||
@@ -396,6 +396,8 @@ void Config_LoadCustomConfig()
|
||||
if (result == M64ERR_SUCCESS) config.generalEmulation.enableLegacyBlending = atoi(value);
|
||||
result = ConfigExternalGetParameter(fileHandle, sectionName, "generalEmulation\\enableFragmentDepthWrite", value, sizeof(value));
|
||||
if (result == M64ERR_SUCCESS) config.generalEmulation.enableFragmentDepthWrite = atoi(value);
|
||||
result = ConfigExternalGetParameter(fileHandle, sectionName, "generalEmulation\\hacks", value, sizeof(value));
|
||||
if (result == M64ERR_SUCCESS) config.generalEmulation.hacks |= atoi(value);
|
||||
|
||||
result = ConfigExternalGetParameter(fileHandle, sectionName, "graphics2D\\correctTexrectCoords", value, sizeof(value));
|
||||
if (result == M64ERR_SUCCESS) config.graphics2D.correctTexrectCoords = atoi(value);
|
||||
|
||||
@@ -170,7 +170,9 @@ struct Vertices7
|
||||
u8 v[7];
|
||||
|
||||
inline bool valid(u8 i) const
|
||||
{ return v[i] < 64; }
|
||||
{
|
||||
return v[i] < 64;
|
||||
}
|
||||
};
|
||||
|
||||
static inline Vertices7 unpackVertices7(u32 w0, u32 w1)
|
||||
@@ -186,8 +188,15 @@ static inline Vertices7 unpackVertices7(u32 w0, u32 w1)
|
||||
return v;
|
||||
}
|
||||
|
||||
struct DeferFlush
|
||||
{
|
||||
~DeferFlush()
|
||||
{ gSPFlushTriangles(); }
|
||||
};
|
||||
|
||||
static void F3DEX3_TriStrip(u32 w0, u32 w1)
|
||||
{
|
||||
DeferFlush flush;
|
||||
Vertices7 vertices = unpackVertices7(w0, w1);
|
||||
// *v1 - v2 - v3, v3 - v2 - v4, v3 - v4 - v5, v5 - v4 - v6, v5 - v6 - v7
|
||||
if (!vertices.valid(0) || !vertices.valid(1) || !vertices.valid(2)) return;
|
||||
@@ -208,6 +217,7 @@ static void F3DEX3_TriStrip(u32 w0, u32 w1)
|
||||
|
||||
static void F3DEX3_TriFan(u32 w0, u32 w1)
|
||||
{
|
||||
DeferFlush flush;
|
||||
Vertices7 vertices = unpackVertices7(w0, w1);
|
||||
// *v1 - v2 - v3, v1 - v3 - v4, v1 - v4 - v5, v1 - v5 - v6, v1 - v6 - v7
|
||||
if (!vertices.valid(0) || !vertices.valid(1) || !vertices.valid(2)) return;
|
||||
@@ -220,7 +230,7 @@ static void F3DEX3_TriFan(u32 w0, u32 w1)
|
||||
gSPTriangle(vertices.v[0], vertices.v[3], vertices.v[4]);
|
||||
|
||||
if (!vertices.valid(5)) return;
|
||||
gSPTriangle(vertices.v[0], vertices.v[3], vertices.v[5]);
|
||||
gSPTriangle(vertices.v[0], vertices.v[4], vertices.v[5]);
|
||||
|
||||
if (!vertices.valid(6)) return;
|
||||
gSPTriangle(vertices.v[0], vertices.v[5], vertices.v[6]);
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = git@github.com:/Rosalie241/parallel-rdp-standalone.git
|
||||
branch = RMG
|
||||
commit = 74a9badf728fcb6a01ceb2ca9668aae5d1f1157c
|
||||
parent = cb2948ec7404a7ee91e08fd5c3acb65c41629856
|
||||
commit = 7d1281997ff5a03378c9dd51fefb164cdb4e7877
|
||||
parent = fddf5eb4a7e99767c4095b34f542098670cdc78b
|
||||
method = merge
|
||||
cmdver = 0.4.6
|
||||
|
||||
@@ -61,17 +61,15 @@ MainDialog::MainDialog(QWidget* parent) : QDialog(parent)
|
||||
}
|
||||
this->resolutionUpscaleComboBox->setCurrentIndex(comboBoxIndex);
|
||||
|
||||
// set deinterlacer combobox
|
||||
this->deinterlacerComboBox->setCurrentIndex(ConfigGetParamBool(configVideoParallel, KEY_DEINTERLACE) ? 1 : 0);
|
||||
|
||||
// set downscaling combobox
|
||||
this->downscalerComboBox->setCurrentIndex(ConfigGetParamInt(configVideoParallel, KEY_DOWNSCALE));
|
||||
|
||||
// set cropOverscan combobox
|
||||
this->cropOverscanSpinBox->setValue(ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROP));
|
||||
|
||||
// set verticalStretch combobox
|
||||
this->verticalStretchSpinBox->setValue(ConfigGetParamInt(configVideoParallel, KEY_VERTICAL_STRETCH));
|
||||
|
||||
this->overscanGroupBox->setChecked(ConfigGetParamBool(configVideoParallel, KEY_OVERSCANCROPENABLE));
|
||||
this->overscanLeftSpinBox->setValue(ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPLEFT));
|
||||
this->overscanRightSpinBox->setValue(ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPRIGHT));
|
||||
this->overscanTopSpinBox->setValue(ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPTOP));
|
||||
this->overscanBottomSpinBox->setValue(ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPBOTTOM));
|
||||
|
||||
this->superSampledDitherCheckBox->setChecked(ConfigGetParamBool(configVideoParallel, KEY_SSDITHER));
|
||||
this->viAaCheckBox->setChecked(ConfigGetParamBool(configVideoParallel, KEY_AA));
|
||||
@@ -127,8 +125,16 @@ void MainDialog::on_buttonBox_clicked(QAbstractButton* button)
|
||||
ConfigSetParameter(configVideoParallel, KEY_DOWNSCALE, M64TYPE_INT, &downscalingValue);
|
||||
|
||||
// cropOverscan
|
||||
int cropOverscanValue = this->cropOverscanSpinBox->value();
|
||||
ConfigSetParameter(configVideoParallel, KEY_OVERSCANCROP, M64TYPE_INT, &cropOverscanValue);
|
||||
int overscanEnabled = this->overscanGroupBox->isChecked();
|
||||
int overscanLeft = this->overscanLeftSpinBox->value();
|
||||
int overscanRight = this->overscanRightSpinBox->value();
|
||||
int overscanTop = this->overscanTopSpinBox->value();
|
||||
int overscanBottom = this->overscanBottomSpinBox->value();
|
||||
ConfigSetParameter(configVideoParallel, KEY_OVERSCANCROPENABLE, M64TYPE_BOOL, &overscanEnabled);
|
||||
ConfigSetParameter(configVideoParallel, KEY_OVERSCANCROPLEFT, M64TYPE_INT, &overscanLeft);
|
||||
ConfigSetParameter(configVideoParallel, KEY_OVERSCANCROPRIGHT, M64TYPE_INT, &overscanRight);
|
||||
ConfigSetParameter(configVideoParallel, KEY_OVERSCANCROPTOP, M64TYPE_INT, &overscanTop);
|
||||
ConfigSetParameter(configVideoParallel, KEY_OVERSCANCROPBOTTOM, M64TYPE_INT, &overscanBottom);
|
||||
|
||||
// verticalStretch
|
||||
int verticalStretchValue = this->verticalStretchSpinBox->value();
|
||||
@@ -167,8 +173,12 @@ void MainDialog::on_buttonBox_clicked(QAbstractButton* button)
|
||||
this->resolutionUpscaleComboBox->setCurrentText("None");
|
||||
this->deinterlacerComboBox->setCurrentIndex(0);
|
||||
this->downscalerComboBox->setCurrentIndex(0);
|
||||
this->cropOverscanSpinBox->setValue(0);
|
||||
this->verticalStretchSpinBox->setValue(0);
|
||||
this->overscanGroupBox->setChecked(false);
|
||||
this->overscanLeftSpinBox->setValue(0);
|
||||
this->overscanRightSpinBox->setValue(0);
|
||||
this->overscanTopSpinBox->setValue(0);
|
||||
this->overscanBottomSpinBox->setValue(0);
|
||||
|
||||
this->superSampledDitherCheckBox->setChecked(true);
|
||||
this->viAaCheckBox->setChecked(true);
|
||||
|
||||
@@ -201,27 +201,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Crop overscan</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="cropOverscanSpinBox">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<property name="bottomMargin">
|
||||
@@ -358,6 +337,53 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="overscanGroupBox">
|
||||
<property name="title">
|
||||
<string>Overscan</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="overscanTopSpinBox">
|
||||
<property name="minimum">
|
||||
<number>-99</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QSpinBox" name="overscanLeftSpinBox">
|
||||
<property name="minimum">
|
||||
<number>-99</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QSpinBox" name="overscanRightSpinBox">
|
||||
<property name="minimum">
|
||||
<number>-99</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="overscanBottomSpinBox">
|
||||
<property name="minimum">
|
||||
<number>-99</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>overscanBottomSpinBox</zorder>
|
||||
<zorder>overscanRightSpinBox</zorder>
|
||||
<zorder>overscanLeftSpinBox</zorder>
|
||||
<zorder>overscanTopSpinBox</zorder>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
|
||||
+10
-2
@@ -181,7 +181,11 @@ EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle _CoreLibHandle, void *Co
|
||||
ConfigSetDefaultBool(configVideoParallel, KEY_DEINTERLACE, 0, "Deinterlacing method. False=Bob, True=Weave");
|
||||
ConfigSetDefaultBool(configVideoParallel, KEY_SSREADBACKS, 0, "Enable superscaling of readbacks when upsampling");
|
||||
ConfigSetDefaultBool(configVideoParallel, KEY_SSDITHER, 1, "Enable superscaling of dithering when upsampling");
|
||||
ConfigSetDefaultInt(configVideoParallel, KEY_OVERSCANCROP, 0, "Amount of overscan pixels to crop on all sides");
|
||||
ConfigSetDefaultInt(configVideoParallel, KEY_OVERSCANCROPLEFT, 0, "Amount of overscan pixels to crop on the left side");
|
||||
ConfigSetDefaultInt(configVideoParallel, KEY_OVERSCANCROPRIGHT, 0, "Amount of overscan pixels to crop on the right side");
|
||||
ConfigSetDefaultInt(configVideoParallel, KEY_OVERSCANCROPTOP, 0, "Amount of overscan pixels to crop on the top side");
|
||||
ConfigSetDefaultInt(configVideoParallel, KEY_OVERSCANCROPBOTTOM, 0, "Amount of overscan pixels to crop on the bottom side");
|
||||
ConfigSetDefaultBool(configVideoParallel, KEY_OVERSCANCROPENABLE, 0, "Whether to enable overscan");
|
||||
ConfigSetDefaultInt(configVideoParallel, KEY_VERTICAL_STRETCH, 0, "Amount of pixels to stretch by vertically. Can fix PAL ports that didn't fill the PAL resolution of 288p (use value of 24 in that case).");
|
||||
ConfigSetDefaultBool(configVideoParallel, KEY_AA, 1, "VI anti-aliasing, smooths polygon edges.");
|
||||
ConfigSetDefaultBool(configVideoParallel, KEY_DIVOT, 1, "Allow VI divot filter, cleans up stray black pixels.");
|
||||
@@ -307,7 +311,11 @@ EXPORT int CALL RomOpen(void)
|
||||
vk_native_tex_rect = ConfigGetParamBool(configVideoParallel, KEY_NATIVETEXTRECT);
|
||||
vk_interlacing = ConfigGetParamBool(configVideoParallel, KEY_DEINTERLACE);
|
||||
vk_downscaling_steps = ConfigGetParamInt(configVideoParallel, KEY_DOWNSCALE);
|
||||
vk_overscan = ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROP);
|
||||
vk_overscan_left = ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPLEFT);
|
||||
vk_overscan_right = ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPRIGHT);
|
||||
vk_overscan_top = ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPTOP);
|
||||
vk_overscan_bottom = ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPBOTTOM);
|
||||
vk_overscan_enable = ConfigGetParamBool(configVideoParallel, KEY_OVERSCANCROPENABLE);
|
||||
vk_vertical_stretch = ConfigGetParamInt(configVideoParallel, KEY_VERTICAL_STRETCH);
|
||||
|
||||
m64p_error netplay_init = ConfigReceiveNetplayConfig(NULL, 0);
|
||||
|
||||
+5
-1
@@ -35,7 +35,11 @@ extern ptr_ConfigSetParameter ConfigSetParameter;
|
||||
#define KEY_WIDESCREEN "WidescreenStretch"
|
||||
#define KEY_SSDITHER "SuperscaledDither"
|
||||
#define KEY_SSREADBACKS "SuperscaledReads"
|
||||
#define KEY_OVERSCANCROP "CropOverscan"
|
||||
#define KEY_OVERSCANCROPLEFT "CropOverscanLeft"
|
||||
#define KEY_OVERSCANCROPRIGHT "CropOverscanRight"
|
||||
#define KEY_OVERSCANCROPTOP "CropOverscanTop"
|
||||
#define KEY_OVERSCANCROPBOTTOM "CropOverscanBottom"
|
||||
#define KEY_OVERSCANCROPENABLE "CropOverscanEnable"
|
||||
#define KEY_VERTICAL_STRETCH "VerticalStretch"
|
||||
#define KEY_DIVOT "Divot"
|
||||
#define KEY_GAMMADITHER "GammaDither"
|
||||
|
||||
+12
-4
@@ -19,9 +19,13 @@ static std::unique_ptr<MupenWSIPlatform> wsi_platform;
|
||||
int32_t vk_rescaling;
|
||||
bool vk_ssreadbacks;
|
||||
bool vk_ssdither;
|
||||
unsigned vk_overscan;
|
||||
unsigned vk_vertical_stretch;
|
||||
unsigned vk_downscaling_steps;
|
||||
uint32_t vk_overscan_left;
|
||||
uint32_t vk_overscan_right;
|
||||
uint32_t vk_overscan_top;
|
||||
uint32_t vk_overscan_bottom;
|
||||
bool vk_overscan_enable;
|
||||
uint32_t vk_vertical_stretch;
|
||||
uint32_t vk_downscaling_steps;
|
||||
bool vk_native_texture_lod;
|
||||
bool vk_native_tex_rect;
|
||||
bool vk_divot_filter, vk_gamma_dither;
|
||||
@@ -180,7 +184,11 @@ static void render_frame(Vulkan::Device &device)
|
||||
opts.blend_previous_frame = vk_interlacing;
|
||||
opts.upscale_deinterlacing = !vk_interlacing;
|
||||
opts.downscale_steps = vk_downscaling_steps;
|
||||
opts.crop_overscan_pixels = vk_overscan;
|
||||
opts.crop_rect.left = vk_overscan_left;
|
||||
opts.crop_rect.right = vk_overscan_right;
|
||||
opts.crop_rect.top = vk_overscan_top;
|
||||
opts.crop_rect.bottom = vk_overscan_bottom;
|
||||
opts.crop_rect.enable = vk_overscan_enable;
|
||||
if (vk_vertical_stretch) {
|
||||
opts.crop_rect.top = vk_vertical_stretch;
|
||||
opts.crop_rect.bottom = vk_vertical_stretch;
|
||||
|
||||
@@ -13,9 +13,13 @@ extern "C"
|
||||
extern bool vk_ssreadbacks;
|
||||
extern bool vk_ssdither;
|
||||
|
||||
extern unsigned vk_overscan;
|
||||
extern unsigned vk_vertical_stretch;
|
||||
extern unsigned vk_downscaling_steps;
|
||||
extern uint32_t vk_overscan_left;
|
||||
extern uint32_t vk_overscan_right;
|
||||
extern uint32_t vk_overscan_top;
|
||||
extern uint32_t vk_overscan_bottom;
|
||||
extern bool vk_overscan_enable;
|
||||
extern uint32_t vk_vertical_stretch;
|
||||
extern uint32_t vk_downscaling_steps;
|
||||
extern bool vk_native_texture_lod;
|
||||
extern bool vk_native_tex_rect;
|
||||
extern bool vk_divot_filter, vk_gamma_dither;
|
||||
|
||||
@@ -24,6 +24,26 @@
|
||||
// Local Functions
|
||||
//
|
||||
|
||||
static std::string get_name_from_headername(uint8_t name[20])
|
||||
{
|
||||
std::string safeName;
|
||||
size_t count = 0;
|
||||
|
||||
// count characters from internal
|
||||
// ROM name, the maximum is 20 so
|
||||
// we can hardcode that safely
|
||||
for (; count < 20; count++)
|
||||
{
|
||||
if (name[count] == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
safeName = std::string(reinterpret_cast<char*>(name), count);
|
||||
return CoreConvertStringEncoding(safeName, CoreStringEncoding::Shift_JIS);
|
||||
}
|
||||
|
||||
static std::string get_gameid_from_header(m64p_rom_header header)
|
||||
{
|
||||
std::string gameID;
|
||||
@@ -171,7 +191,7 @@ CORE_EXPORT bool CoreGetCurrentRomHeader(CoreRomHeader& header)
|
||||
header.CRC1 = ntohl(m64p_header.CRC1);
|
||||
header.CRC2 = ntohl(m64p_header.CRC2);
|
||||
header.CountryCode = m64p_header.Country_code;
|
||||
header.Name = CoreConvertStringEncoding(std::string(reinterpret_cast<char*>(m64p_header.Name), 20), CoreStringEncoding::Shift_JIS);
|
||||
header.Name = get_name_from_headername(m64p_header.Name);
|
||||
header.GameID = get_gameid_from_header(m64p_header);
|
||||
header.Region = get_region_from_countrycode(static_cast<char>(header.CountryCode));
|
||||
header.SystemType = get_systemtype_from_countrycode(header.CountryCode);
|
||||
|
||||
@@ -167,7 +167,10 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
setting = {SETTING_SECTION_NETPLAY, "Nickname", std::string("NetplayUser")};
|
||||
break;
|
||||
case SettingsID::Netplay_ServerJsonUrl:
|
||||
setting = {SETTING_SECTION_NETPLAY, "ServerJsonUrl", std::string("https://m64p.s3.amazonaws.com/servers.json")};
|
||||
setting = {SETTING_SECTION_NETPLAY, "ServerJsonUrl", std::string("")};
|
||||
break;
|
||||
case SettingsID::Netplay_DispatcherUrl:
|
||||
setting = {SETTING_SECTION_NETPLAY, "DispatcherUrl", std::string("https://dispatch.gopher64.com")};
|
||||
break;
|
||||
case SettingsID::Netplay_SelectedServer:
|
||||
setting = {SETTING_SECTION_NETPLAY, "SelectedServer", std::string("")};
|
||||
@@ -497,9 +500,12 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::KeyBinding_Fullscreen:
|
||||
setting = {SETTING_SECTION_KEYBIND, "Fullscreen", std::string("Alt+Return")};
|
||||
break;
|
||||
case SettingsID::Keybinding_ViewLog:
|
||||
case SettingsID::KeyBinding_ViewLog:
|
||||
setting = {SETTING_SECTION_KEYBIND, "ViewLog", std::string("Ctrl+Alt+L")};
|
||||
break;
|
||||
case SettingsID::KeyBinding_ViewSearch:
|
||||
setting = {SETTING_SECTION_KEYBIND, "ViewSearch", std::string("Ctrl+F")};
|
||||
break;
|
||||
case SettingsID::KeyBinding_GraphicsSettings:
|
||||
setting = {SETTING_SECTION_KEYBIND, "GraphicsSettings", std::string("Ctrl+G")};
|
||||
break;
|
||||
@@ -538,7 +544,7 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "Recursive", true};
|
||||
break;
|
||||
case SettingsID::RomBrowser_MaxItems:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "MaxItems", 1024};
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "MaxItems", 2048};
|
||||
break;
|
||||
case SettingsID::RomBrowser_ColumnVisibility:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ColumnVisibility", std::string("1;1;1;0;0;0;0;0;0;")};
|
||||
@@ -1360,7 +1366,7 @@ static void config_listsections_callback(void*, const char* section)
|
||||
l_sectionList.emplace_back(std::string(section));
|
||||
}
|
||||
|
||||
static bool config_section_exists(std::string section)
|
||||
static bool config_section_exists(const std::string& section)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
@@ -1384,7 +1390,7 @@ static bool config_section_exists(std::string section)
|
||||
return std::find(l_sectionList.begin(), l_sectionList.end(), section) != l_sectionList.end();
|
||||
}
|
||||
|
||||
static bool config_section_open(std::string section)
|
||||
static bool config_section_open(const std::string& section)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
@@ -1417,7 +1423,7 @@ static void config_listkeys_callback(void*, const char* key, m64p_type)
|
||||
l_keyList.push_back(std::string(key));
|
||||
}
|
||||
|
||||
static bool config_key_exists(std::string section, std::string key)
|
||||
static bool config_key_exists(const std::string& section, const std::string& key)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
@@ -1446,7 +1452,7 @@ static bool config_key_exists(std::string section, std::string key)
|
||||
return std::find(l_keyList.begin(), l_keyList.end(), key) != l_keyList.end();
|
||||
}
|
||||
|
||||
static bool config_option_set(std::string section, std::string key, m64p_type type, void *value)
|
||||
static bool config_option_set(const std::string& section, const std::string& key, m64p_type type, void *value)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
@@ -1472,7 +1478,7 @@ static bool config_option_set(std::string section, std::string key, m64p_type ty
|
||||
return ret == M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static bool config_option_get(std::string section, std::string key, m64p_type type, void *value, int size)
|
||||
static bool config_option_get(const std::string& section, const std::string& key, m64p_type type, void *value, int size)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
@@ -1505,7 +1511,7 @@ static bool config_option_get(std::string section, std::string key, m64p_type ty
|
||||
return ret == M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static bool config_option_default_set(std::string section, std::string key, m64p_type type, void *value, const char* description)
|
||||
static bool config_option_default_set(const std::string& section, const std::string& key, m64p_type type, void *value, const char* description)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
@@ -1573,7 +1579,7 @@ static bool int_list_to_string(const std::vector<int>& intList, std::string& str
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool string_to_int_list(std::string string, std::vector<int>& intList)
|
||||
static bool string_to_int_list(const std::string& string, std::vector<int>& intList)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
@@ -1628,7 +1634,7 @@ static bool string_list_to_string(const std::vector<std::string>& stringList, st
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool string_to_string_list(std::string string, std::vector<std::string>& stringList)
|
||||
static bool string_to_string_list(const std::string& string, std::vector<std::string>& stringList)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
@@ -1675,6 +1681,10 @@ CORE_EXPORT bool CoreSettingsUpgrade(void)
|
||||
std::string settingsString;
|
||||
|
||||
settingsVersion = CoreSettingsGetStringValue(SettingsID::GUI_Version);
|
||||
if (settingsVersion.size() > 6)
|
||||
{ // strip git prefix
|
||||
settingsVersion = settingsVersion.substr(0, 6);
|
||||
}
|
||||
|
||||
// we don't need to do anything
|
||||
// when the core version and the settings version match
|
||||
@@ -1685,7 +1695,6 @@ CORE_EXPORT bool CoreSettingsUpgrade(void)
|
||||
|
||||
if (settingsVersion.empty())
|
||||
{ // settings version was introduced in >v0.1.5
|
||||
|
||||
#ifndef PORTABLE_INSTALL // only applies to non-portable installs (i.e flatpak)
|
||||
// sadly v0.1.5 introduced an issue,
|
||||
// in v0.1.4 the screenshot directory was set to 'Screenshots',
|
||||
@@ -1716,6 +1725,31 @@ CORE_EXPORT bool CoreSettingsUpgrade(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsVersion == "v0.6.8" ||
|
||||
settingsVersion == "v0.6.9" ||
|
||||
settingsVersion == "v0.7.0" ||
|
||||
settingsVersion == "v0.7.0" ||
|
||||
settingsVersion == "v0.7.1" ||
|
||||
settingsVersion == "v0.7.2" ||
|
||||
settingsVersion == "v0.7.3" ||
|
||||
settingsVersion == "v0.7.4" ||
|
||||
settingsVersion == "v0.7.5" ||
|
||||
settingsVersion == "v0.7.6" ||
|
||||
settingsVersion == "v0.7.7" ||
|
||||
settingsVersion == "v0.7.8" ||
|
||||
settingsVersion == "v0.7.9")
|
||||
{
|
||||
// in v0.8.0 RMG switched to the dispatcher server for netplay,
|
||||
// to keep support for the json file, we only empty that setting
|
||||
// when it is the default value because the default json url
|
||||
// no longer exists
|
||||
settingsString = CoreSettingsGetStringValue(SettingsID::Netplay_ServerJsonUrl);
|
||||
if (settingsString == "https://m64p.s3.amazonaws.com/servers.json")
|
||||
{
|
||||
CoreSettingsSetValue(SettingsID::Netplay_ServerJsonUrl, std::string(""));
|
||||
}
|
||||
}
|
||||
|
||||
// save core version
|
||||
CoreSettingsSetValue(SettingsID::GUI_Version, CoreGetVersion());
|
||||
CoreSettingsSave();
|
||||
|
||||
@@ -45,6 +45,7 @@ enum class SettingsID
|
||||
// Netplay Settings
|
||||
Netplay_Nickname,
|
||||
Netplay_ServerJsonUrl,
|
||||
Netplay_DispatcherUrl,
|
||||
Netplay_SelectedServer,
|
||||
|
||||
// Core Plugin Settings
|
||||
@@ -166,7 +167,8 @@ enum class SettingsID
|
||||
KeyBinding_SaveStateSlot8,
|
||||
KeyBinding_SaveStateSlot9,
|
||||
KeyBinding_Fullscreen,
|
||||
Keybinding_ViewLog,
|
||||
KeyBinding_ViewLog,
|
||||
KeyBinding_ViewSearch,
|
||||
KeyBinding_GraphicsSettings,
|
||||
KeyBinding_AudioSettings,
|
||||
KeyBinding_RspSettings,
|
||||
|
||||
@@ -49,6 +49,7 @@ set(RMG_SOURCES
|
||||
UserInterface/Widget/RomBrowser/RomBrowserLoadingWidget.cpp
|
||||
UserInterface/Widget/RomBrowser/RomBrowserEmptyWidget.cpp
|
||||
UserInterface/Widget/RomBrowser/RomBrowserEmptyWidget.ui
|
||||
UserInterface/Widget/RomBrowser/RomBrowserSearchWidget.cpp
|
||||
UserInterface/Widget/Render/DummyWidget.cpp
|
||||
UserInterface/Widget/Render/OGLWidget.cpp
|
||||
UserInterface/Widget/Render/VKWidget.cpp
|
||||
|
||||
@@ -338,7 +338,7 @@ void AddCheatDialog::accept(void)
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void AddCheatDialog::on_nameLineEdit_textChanged(QString text)
|
||||
void AddCheatDialog::on_nameLineEdit_textChanged(void)
|
||||
{
|
||||
this->validateOkButton();
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class AddCheatDialog : public QDialog, private Ui::AddCheatDialog
|
||||
private slots:
|
||||
void accept(void) Q_DECL_OVERRIDE;
|
||||
|
||||
void on_nameLineEdit_textChanged(QString text);
|
||||
void on_nameLineEdit_textChanged(void);
|
||||
void on_codeTextEdit_textChanged(void);
|
||||
void on_optionsTextEdit_textChanged(void);
|
||||
};
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QPushButton>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QUrlQuery>
|
||||
#include <QFileInfo>
|
||||
#include <QFile>
|
||||
|
||||
@@ -39,6 +41,7 @@ CreateNetplaySessionDialog::CreateNetplaySessionDialog(QWidget *parent, QWebSock
|
||||
this->webSocket = webSocket;
|
||||
connect(this->webSocket, &QWebSocket::textMessageReceived, this, &CreateNetplaySessionDialog::on_webSocket_textMessageReceived);
|
||||
connect(this->webSocket, &QWebSocket::pong, this, &CreateNetplaySessionDialog::on_webSocket_pong);
|
||||
connect(this->webSocket, &QWebSocket::connected, this, &CreateNetplaySessionDialog::on_webSocket_connected);
|
||||
|
||||
// prepare broadcast
|
||||
broadcastSocket.bind(QHostAddress(QHostAddress::AnyIPv4), 0);
|
||||
@@ -96,13 +99,26 @@ CreateNetplaySessionDialog::CreateNetplaySessionDialog(QWidget *parent, QWebSock
|
||||
else if (QUrl(serverUrl).isValid())
|
||||
{
|
||||
QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager(this);
|
||||
connect(networkAccessManager, &QNetworkAccessManager::finished, this, &CreateNetplaySessionDialog::on_networkAccessManager_Finished);
|
||||
connect(networkAccessManager, &QNetworkAccessManager::finished, this, &CreateNetplaySessionDialog::on_jsonServerListDownload_Finished);
|
||||
networkAccessManager->setTransferTimeout(15000);
|
||||
networkAccessManager->get(QNetworkRequest(QUrl(serverUrl)));
|
||||
}
|
||||
}
|
||||
|
||||
this->pingTimerId = this->startTimer(2000);
|
||||
QString dispatcherUrl = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_DispatcherUrl));
|
||||
if (!dispatcherUrl.isEmpty() && QUrl(dispatcherUrl).isValid())
|
||||
{
|
||||
this->dispatcherUrl = dispatcherUrl;
|
||||
|
||||
QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager(this);
|
||||
connect(networkAccessManager, &QNetworkAccessManager::finished, this, &CreateNetplaySessionDialog::on_dispatcherRegionListDownload_Finished);
|
||||
networkAccessManager->setTransferTimeout(15000);
|
||||
|
||||
QNetworkRequest networkRequest(QUrl(this->dispatcherUrl + "/getRegions"));
|
||||
networkRequest.setRawHeader("netplay-id", "RMG");
|
||||
|
||||
networkAccessManager->get(networkRequest);
|
||||
}
|
||||
}
|
||||
|
||||
CreateNetplaySessionDialog::~CreateNetplaySessionDialog(void)
|
||||
@@ -173,6 +189,41 @@ void CreateNetplaySessionDialog::validateCreateButton(void)
|
||||
createButton->setEnabled(this->validate());
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::createSession(void)
|
||||
{
|
||||
QList<QString> plugins = NetplayCommon::GetPluginNames(this->sessionMD5);
|
||||
|
||||
QJsonObject jsonFeatures;
|
||||
jsonFeatures.insert("rsp_plugin", plugins[0]);
|
||||
jsonFeatures.insert("gfx_plugin", plugins[1]);
|
||||
|
||||
QJsonObject json;
|
||||
QJsonObject session;
|
||||
session.insert("room_name", this->sessionNameLineEdit->text());
|
||||
session.insert("password", this->passwordLineEdit->text());
|
||||
session.insert("MD5", this->sessionMD5);
|
||||
session.insert("game_name", this->getGameName(this->sessionGoodName, this->sessionFile));
|
||||
session.insert("features", jsonFeatures);
|
||||
json.insert("type", "request_create_room");
|
||||
json.insert("player_name", this->nickNameLineEdit->text());
|
||||
json.insert("room", session);
|
||||
NetplayCommon::AddCommonJson(json);
|
||||
|
||||
this->webSocket->sendTextMessage(QJsonDocument(json).toJson());
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::toggleUI(bool enable, bool enableCreateButton)
|
||||
{
|
||||
QPushButton* createButton = this->buttonBox->button(QDialogButtonBox::Ok);
|
||||
createButton->setEnabled(enableCreateButton);
|
||||
|
||||
this->serverComboBox->setEnabled(enable);
|
||||
this->sessionNameLineEdit->setReadOnly(!enable);
|
||||
this->passwordLineEdit->setReadOnly(!enable);
|
||||
this->sessionNameLineEdit->setReadOnly(!enable);
|
||||
this->nickNameLineEdit->setReadOnly(!enable);
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::timerEvent(QTimerEvent* event)
|
||||
{
|
||||
if (event->timerId() == this->pingTimerId)
|
||||
@@ -199,14 +250,25 @@ void CreateNetplaySessionDialog::on_webSocket_textMessageReceived(QString messag
|
||||
else
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", json.value("message").toString());
|
||||
this->validateCreateButton();
|
||||
this->toggleUI(true, this->validate());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_webSocket_pong(quint64 elapsedTime, const QByteArray&)
|
||||
{
|
||||
this->pingLineEdit->setText(QString::number(elapsedTime) + " ms");
|
||||
if (!NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->pingLineEdit->setText(QString::number(elapsedTime) + " ms");
|
||||
}
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_webSocket_connected()
|
||||
{
|
||||
if (NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->createSession();
|
||||
}
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_broadcastSocket_readyRead()
|
||||
@@ -215,20 +277,14 @@ void CreateNetplaySessionDialog::on_broadcastSocket_readyRead()
|
||||
{
|
||||
QNetworkDatagram datagram = this->broadcastSocket.receiveDatagram();
|
||||
QByteArray incomingData = datagram.data();
|
||||
QJsonDocument json_doc = QJsonDocument::fromJson(incomingData);
|
||||
QJsonObject json = json_doc.object();
|
||||
QStringList servers = json.keys();
|
||||
|
||||
for (int i = 0; i < servers.size(); i++)
|
||||
{
|
||||
this->serverComboBox->addItem(servers.at(i), json.value(servers.at(i)).toString());
|
||||
}
|
||||
|
||||
NetplayCommon::AddServers(this->serverComboBox, QJsonDocument::fromJson(incomingData));
|
||||
}
|
||||
|
||||
NetplayCommon::RestoreSelectedServer(this->serverComboBox);
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_networkAccessManager_Finished(QNetworkReply* reply)
|
||||
void CreateNetplaySessionDialog::on_jsonServerListDownload_Finished(QNetworkReply* reply)
|
||||
{
|
||||
if (reply->error())
|
||||
{
|
||||
@@ -243,6 +299,55 @@ void CreateNetplaySessionDialog::on_networkAccessManager_Finished(QNetworkReply*
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_dispatcherRegionListDownload_Finished(QNetworkReply* reply)
|
||||
{
|
||||
if (reply->error())
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", "Failed to retrieve region list: " + reply->errorString());
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
NetplayCommon::AddServers(this->serverComboBox,
|
||||
QJsonDocument::fromJson(reply->readAll()), true);
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_dispatcherServerCreate_Finished(QNetworkReply* reply)
|
||||
{
|
||||
if (reply->error())
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", "Failed to create server: " + reply->errorString());
|
||||
reply->deleteLater();
|
||||
this->toggleUI(true, this->validate());
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(reply->readAll());
|
||||
QJsonObject jsonObject = jsonDocument.object();
|
||||
|
||||
if (jsonObject.empty() || jsonObject.keys().empty())
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", "Failed to create server: " + jsonDocument.toJson());
|
||||
reply->deleteLater();
|
||||
this->toggleUI(true, this->validate());
|
||||
return;
|
||||
}
|
||||
|
||||
// first item should be an address
|
||||
QString address = jsonObject[jsonObject.keys().at(0)].toString();
|
||||
if (!NetplayCommon::ConnectToIPv4Server(address, this->webSocket))
|
||||
{
|
||||
QtMessageBox::Error(this, "Failed to find IPv4 address of server");
|
||||
reply->deleteLater();
|
||||
this->toggleUI(true, this->validate());
|
||||
return;
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_serverComboBox_currentIndexChanged(int index)
|
||||
{
|
||||
if (index == -1)
|
||||
@@ -250,10 +355,23 @@ void CreateNetplaySessionDialog::on_serverComboBox_currentIndexChanged(int index
|
||||
return;
|
||||
}
|
||||
|
||||
this->pingLineEdit->setText("Calculating...");
|
||||
bool dispatcher = NetplayCommon::IsServerDispatcher(this->serverComboBox, index);
|
||||
|
||||
if (this->pingTimerId != -1)
|
||||
{
|
||||
this->killTimer(this->pingTimerId);
|
||||
this->pingTimerId = -1;
|
||||
}
|
||||
|
||||
QString address = this->serverComboBox->itemData(index).toString();
|
||||
this->webSocket->open(QUrl(address));
|
||||
this->pingLineEdit->setText(dispatcher ? "N/A" : "Calculating...");
|
||||
|
||||
if (!dispatcher)
|
||||
{
|
||||
this->pingTimerId = this->startTimer(2000);
|
||||
|
||||
QString address = NetplayCommon::GetServerData(this->serverComboBox, index);
|
||||
this->webSocket->open(QUrl(address));
|
||||
}
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_nickNameLineEdit_textChanged(void)
|
||||
@@ -278,7 +396,7 @@ void CreateNetplaySessionDialog::on_romListWidget_OnRomChanged(bool valid)
|
||||
|
||||
void CreateNetplaySessionDialog::accept()
|
||||
{
|
||||
if (!this->webSocket->isValid())
|
||||
if (!NetplayCommon::IsServerDispatcher(this->serverComboBox) && !this->webSocket->isValid())
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", "Connection Failed");
|
||||
return;
|
||||
@@ -290,29 +408,36 @@ void CreateNetplaySessionDialog::accept()
|
||||
return;
|
||||
}
|
||||
|
||||
// store these for use in createSession()
|
||||
this->sessionFile = romData.File;
|
||||
this->sessionMD5 = romData.MD5;
|
||||
this->sessionGoodName = romData.GoodName;
|
||||
|
||||
// disable create button while we're processing the request
|
||||
QPushButton* createButton = this->buttonBox->button(QDialogButtonBox::Ok);
|
||||
createButton->setEnabled(false);
|
||||
this->toggleUI(false, false);
|
||||
|
||||
this->sessionFile = romData.File;
|
||||
if (NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager(this);
|
||||
connect(networkAccessManager, &QNetworkAccessManager::finished, this, &CreateNetplaySessionDialog::on_dispatcherServerCreate_Finished);
|
||||
networkAccessManager->setTransferTimeout(120000);
|
||||
|
||||
QList<QString> plugins = NetplayCommon::GetPluginNames(romData.MD5);
|
||||
QUrl url(this->dispatcherUrl + "/createServer");
|
||||
|
||||
QJsonObject jsonFeatures;
|
||||
jsonFeatures.insert("rsp_plugin", plugins[0]);
|
||||
jsonFeatures.insert("gfx_plugin", plugins[1]);
|
||||
QUrlQuery urlQuery;
|
||||
urlQuery.addQueryItem("region", NetplayCommon::GetServerData(this->serverComboBox));
|
||||
url.setQuery(urlQuery);
|
||||
|
||||
QJsonObject json;
|
||||
QJsonObject session;
|
||||
session.insert("room_name", this->sessionNameLineEdit->text());
|
||||
session.insert("password", this->passwordLineEdit->text());
|
||||
session.insert("MD5", romData.MD5);
|
||||
session.insert("game_name", this->getGameName(romData.GoodName, romData.File));
|
||||
session.insert("features", jsonFeatures);
|
||||
json.insert("type", "request_create_room");
|
||||
json.insert("player_name", this->nickNameLineEdit->text());
|
||||
json.insert("room", session);
|
||||
NetplayCommon::AddCommonJson(json);
|
||||
QNetworkRequest networkRequest(url);
|
||||
networkRequest.setRawHeader("netplay-id", "RMG");
|
||||
networkAccessManager->get(networkRequest);
|
||||
|
||||
this->webSocket->sendTextMessage(QJsonDocument(json).toJson());
|
||||
// creating a server can take a while,
|
||||
// so show a loading screen
|
||||
this->romListWidget->ShowLoading();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->createSession();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,20 +45,32 @@ class CreateNetplaySessionDialog : public QDialog, private Ui::CreateNetplaySess
|
||||
|
||||
QJsonObject sessionJson;
|
||||
QString sessionFile;
|
||||
QString sessionMD5;
|
||||
QString sessionGoodName;
|
||||
|
||||
QString dispatcherUrl;
|
||||
|
||||
QString getGameName(QString goodName, QString file);
|
||||
|
||||
bool validate(void);
|
||||
void validateCreateButton(void);
|
||||
|
||||
void createSession(void);
|
||||
|
||||
void toggleUI(bool enable, bool enableCreateButton);
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE;
|
||||
|
||||
private slots:
|
||||
void on_webSocket_textMessageReceived(QString message);
|
||||
void on_webSocket_pong(quint64 elapsedTime, const QByteArray&);
|
||||
void on_webSocket_connected(void);
|
||||
void on_broadcastSocket_readyRead(void);
|
||||
void on_networkAccessManager_Finished(QNetworkReply* reply);
|
||||
|
||||
void on_jsonServerListDownload_Finished(QNetworkReply* reply);
|
||||
void on_dispatcherRegionListDownload_Finished(QNetworkReply* reply);
|
||||
void on_dispatcherServerCreate_Finished(QNetworkReply* reply);
|
||||
|
||||
void on_serverComboBox_currentIndexChanged(int index);
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<widget class="QLabel" name="pingLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
|
||||
@@ -11,8 +11,11 @@
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QByteArray>
|
||||
#include <QJsonArray>
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
#include <QHostInfo>
|
||||
#include <QUrl>
|
||||
|
||||
#include <RMG-Core/Settings.hpp>
|
||||
#include <RMG-Core/Plugins.hpp>
|
||||
@@ -20,6 +23,9 @@
|
||||
|
||||
using namespace NetplayCommon;
|
||||
|
||||
// register type with qt
|
||||
Q_DECLARE_METATYPE(NetplayServerData);
|
||||
|
||||
void NetplayCommon::AddCommonJson(QJsonObject& json)
|
||||
{
|
||||
QCryptographicHash hash = QCryptographicHash(QCryptographicHash::Sha256);
|
||||
@@ -81,14 +87,36 @@ QList<QString> NetplayCommon::GetPluginNames(QString md5QString)
|
||||
return pluginNames;
|
||||
}
|
||||
|
||||
void NetplayCommon::AddServers(QComboBox* comboBox, QJsonDocument document)
|
||||
void NetplayCommon::AddServers(QComboBox* comboBox, QJsonDocument document, bool dispatcher)
|
||||
{
|
||||
QJsonObject jsonObject = document.object();
|
||||
QStringList jsonServers = jsonObject.keys();
|
||||
|
||||
for (int i = 0; i < jsonServers.size(); i++)
|
||||
if (dispatcher)
|
||||
{
|
||||
comboBox->addItem(jsonServers.at(i), jsonObject.value(jsonServers.at(i)).toString());
|
||||
QJsonArray jsonServers = document.array();
|
||||
|
||||
for (int i = 0; i < jsonServers.size(); i++)
|
||||
{
|
||||
comboBox->addItem(jsonServers.at(i).toString(),
|
||||
QVariant::fromValue<NetplayServerData>(
|
||||
{
|
||||
dispatcher,
|
||||
jsonServers.at(i).toString()
|
||||
}));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QJsonObject jsonObject = document.object();
|
||||
QStringList jsonServers = jsonObject.keys();
|
||||
|
||||
for (int i = 0; i < jsonServers.size(); i++)
|
||||
{
|
||||
comboBox->addItem(jsonServers.at(i),
|
||||
QVariant::fromValue<NetplayServerData>(
|
||||
{
|
||||
dispatcher,
|
||||
jsonObject.value(jsonServers.at(i)).toString()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
NetplayCommon::RestoreSelectedServer(comboBox);
|
||||
@@ -108,3 +136,43 @@ void NetplayCommon::RestoreSelectedServer(QComboBox* comboBox)
|
||||
comboBox->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
bool NetplayCommon::IsServerDispatcher(QComboBox* comboBox, int index)
|
||||
{
|
||||
if (index == -1)
|
||||
{
|
||||
index = comboBox->currentIndex();
|
||||
}
|
||||
|
||||
return comboBox->itemData(index).value<NetplayServerData>().Dispatcher;
|
||||
}
|
||||
|
||||
QString NetplayCommon::GetServerData(QComboBox* comboBox, int index)
|
||||
{
|
||||
if (index == -1)
|
||||
{
|
||||
index = comboBox->currentIndex();
|
||||
}
|
||||
|
||||
return comboBox->itemData(index).value<NetplayServerData>().Data;
|
||||
}
|
||||
|
||||
bool NetplayCommon::ConnectToIPv4Server(QString address, QWebSocket* webSocket)
|
||||
{
|
||||
QUrl addressUrl(address);
|
||||
QHostInfo hostInfo = QHostInfo::fromName(addressUrl.host());
|
||||
|
||||
for (const QHostAddress &resolvedAddr : hostInfo.addresses())
|
||||
{
|
||||
// mupen64plus-core only supports IPv4 (due to SDL2_net)
|
||||
if (resolvedAddr.protocol() == QAbstractSocket::IPv4Protocol)
|
||||
{
|
||||
addressUrl.setHost(resolvedAddr.toString());
|
||||
webSocket->open(addressUrl);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
webSocket->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -12,11 +12,20 @@
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#ifdef NETPLAY
|
||||
#include <QWebSocket>
|
||||
#endif // NETPLAY
|
||||
#include <QComboBox>
|
||||
#include <QString>
|
||||
|
||||
namespace NetplayCommon
|
||||
{
|
||||
struct NetplayServerData
|
||||
{
|
||||
bool Dispatcher;
|
||||
QString Data;
|
||||
};
|
||||
|
||||
#define NETPLAYCOMMON_SESSION_REGEX "[a-zA-Z0-9 ]+"
|
||||
#define NETPLAYCOMMON_NICKNAME_REGEX "[a-zA-Z0-9]+"
|
||||
#define NETPLAYCOMMON_PASSWORD_REGEX "[a-zA-Z0-9,.\\/<>?;:[\\]{}\\-=_+`~!@#$%^&*()]+"
|
||||
@@ -28,10 +37,21 @@ namespace NetplayCommon
|
||||
QList<QString> GetPluginNames(QString md5QString);
|
||||
|
||||
// Adds servers from json to combobox
|
||||
void AddServers(QComboBox* comboBox, QJsonDocument document);
|
||||
void AddServers(QComboBox* comboBox, QJsonDocument document, bool dispatcher = false);
|
||||
|
||||
// Restores previously selected server
|
||||
void RestoreSelectedServer(QComboBox* comboBox);
|
||||
|
||||
// Returns whether server from comboBox is dispatcher
|
||||
bool IsServerDispatcher(QComboBox* comboBox, int index = -1);
|
||||
|
||||
// Returns server data from comboBox
|
||||
QString GetServerData(QComboBox* comboBox, int index = -1);
|
||||
|
||||
#ifdef NETPLAY
|
||||
// Attempts to connect the web socket to the given address using IPv4
|
||||
bool ConnectToIPv4Server(QString address, QWebSocket* webSocket);
|
||||
#endif // #ifdef NETPLAY
|
||||
}
|
||||
|
||||
#endif // NETPLAYCOMMON_HPP
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <QFileDialog>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QUrlQuery>
|
||||
#include <QFile>
|
||||
|
||||
#include <RMG-Core/Settings.hpp>
|
||||
@@ -70,6 +71,11 @@ NetplaySessionBrowserDialog::NetplaySessionBrowserDialog(QWidget *parent, QWebSo
|
||||
this->nickNameLineEdit->setValidator(new QRegularExpressionValidator(re, this));
|
||||
this->nickNameLineEdit->setText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_Nickname)));
|
||||
|
||||
// configure dispatcher network access manager
|
||||
this->dispatcherNetworkAccessManager = new QNetworkAccessManager(this);
|
||||
this->dispatcherNetworkAccessManager->setTransferTimeout(15000);
|
||||
connect(this->dispatcherNetworkAccessManager, &QNetworkAccessManager::finished, this, &NetplaySessionBrowserDialog::on_dispatcherRetrieveServers_Finished);
|
||||
|
||||
// request server list
|
||||
QString serverUrl = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_ServerJsonUrl));
|
||||
if (!serverUrl.isEmpty())
|
||||
@@ -90,15 +96,28 @@ NetplaySessionBrowserDialog::NetplaySessionBrowserDialog(QWidget *parent, QWebSo
|
||||
else if (QUrl(serverUrl).isValid())
|
||||
{
|
||||
QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager(this);
|
||||
connect(networkAccessManager, &QNetworkAccessManager::finished, this, &NetplaySessionBrowserDialog::on_networkAccessManager_Finished);
|
||||
connect(networkAccessManager, &QNetworkAccessManager::finished, this, &NetplaySessionBrowserDialog::on_jsonServerListDownload_Finished);
|
||||
networkAccessManager->setTransferTimeout(15000);
|
||||
networkAccessManager->get(QNetworkRequest(QUrl(serverUrl)));
|
||||
}
|
||||
}
|
||||
|
||||
this->validateJoinButton();
|
||||
QString dispatcherUrl = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_DispatcherUrl));
|
||||
if (!dispatcherUrl.isEmpty() && QUrl(dispatcherUrl).isValid())
|
||||
{
|
||||
this->dispatcherUrl = dispatcherUrl;
|
||||
|
||||
this->pingTimerId = this->startTimer(2000);
|
||||
QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager(this);
|
||||
connect(networkAccessManager, &QNetworkAccessManager::finished, this, &NetplaySessionBrowserDialog::on_dispatcherRegionListDownload_Finished);
|
||||
networkAccessManager->setTransferTimeout(15000);
|
||||
|
||||
QNetworkRequest networkRequest(QUrl(this->dispatcherUrl + "/getRegions"));
|
||||
networkRequest.setRawHeader("netplay-id", "RMG");
|
||||
|
||||
networkAccessManager->get(networkRequest);
|
||||
}
|
||||
|
||||
this->validateJoinButton();
|
||||
}
|
||||
|
||||
NetplaySessionBrowserDialog::~NetplaySessionBrowserDialog(void)
|
||||
@@ -179,6 +198,79 @@ void NetplaySessionBrowserDialog::validateJoinButton(void)
|
||||
joinButton->setEnabled(this->validate());
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::toggleUI(bool enable, bool enableJoinButton)
|
||||
{
|
||||
QPushButton* joinButton = this->buttonBox->button(QDialogButtonBox::Ok);
|
||||
joinButton->setEnabled(enableJoinButton);
|
||||
|
||||
QPushButton* refreshButton = this->buttonBox->button(QDialogButtonBox::RestoreDefaults);
|
||||
refreshButton->setEnabled(enable);
|
||||
|
||||
this->serverComboBox->setEnabled(enable);
|
||||
this->nickNameLineEdit->setReadOnly(!enable);
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::refreshSessions(void)
|
||||
{
|
||||
// disable refresh button while refreshing
|
||||
QPushButton* refreshButton = this->buttonBox->button(QDialogButtonBox::RestoreDefaults);
|
||||
refreshButton->setEnabled(false);
|
||||
|
||||
// disable join button while refreshing
|
||||
QPushButton* joinButton = this->buttonBox->button(QDialogButtonBox::Ok);
|
||||
joinButton->setEnabled(false);
|
||||
|
||||
if (NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->on_serverComboBox_currentIndexChanged(this->serverComboBox->currentIndex());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->on_webSocket_connected();
|
||||
}
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::joinSession(void)
|
||||
{
|
||||
QJsonObject json;
|
||||
QJsonObject session;
|
||||
session.insert("port", sessionData.Port);
|
||||
session.insert("password", this->sessionPassword);
|
||||
session.insert("MD5", this->sessionData.MD5);
|
||||
|
||||
json.insert("type", "request_join_room");
|
||||
json.insert("player_name", this->nickNameLineEdit->text());
|
||||
json.insert("room", session);
|
||||
NetplayCommon::AddCommonJson(json);
|
||||
|
||||
this->webSocket->sendTextMessage(QJsonDocument(json).toJson());
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::resetDispatcherState(void)
|
||||
{
|
||||
if (this->dispatcherTimerId != -1)
|
||||
{
|
||||
this->killTimer(this->dispatcherTimerId);
|
||||
this->dispatcherTimerId = -1;
|
||||
}
|
||||
|
||||
if (this->dispatcherTimeoutTimerId != -1)
|
||||
{
|
||||
this->killTimer(this->dispatcherTimeoutTimerId);
|
||||
this->dispatcherTimeoutTimerId = -1;
|
||||
}
|
||||
|
||||
if (this->dispatcherNetworkReply != nullptr)
|
||||
{
|
||||
this->dispatcherNetworkReply->abort();
|
||||
this->dispatcherNetworkReply = nullptr;
|
||||
}
|
||||
|
||||
this->dispatcherMoveThroughList = false;
|
||||
this->dispatcherJoinSession = false;
|
||||
this->dispatcherAddressListIndex = false;
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (event->timerId() == this->pingTimerId)
|
||||
@@ -188,6 +280,49 @@ void NetplaySessionBrowserDialog::timerEvent(QTimerEvent *event)
|
||||
this->webSocket->ping();
|
||||
}
|
||||
}
|
||||
else if (event->timerId() == this->dispatcherTimerId)
|
||||
{
|
||||
if (this->dispatcherMoveThroughList)
|
||||
{
|
||||
this->dispatcherAddressListIndex++;
|
||||
|
||||
if (this->dispatcherAddressListIndex < this->dispatcherAddressList.size())
|
||||
{
|
||||
QString address = this->dispatcherAddressList.at(this->dispatcherAddressListIndex);
|
||||
|
||||
if (!NetplayCommon::ConnectToIPv4Server(address, this->webSocket))
|
||||
{
|
||||
this->sessionBrowserWidget->Reset();
|
||||
QtMessageBox::Error(this, "Failed to find IPv4 address of server");
|
||||
}
|
||||
|
||||
this->dispatcherMoveThroughList = false;
|
||||
|
||||
// start socket timeout
|
||||
if (this->dispatcherTimeoutTimerId != -1)
|
||||
{
|
||||
this->killTimer(this->dispatcherTimeoutTimerId);
|
||||
this->dispatcherTimeoutTimerId = -1;
|
||||
}
|
||||
|
||||
this->dispatcherTimeoutTimerId = this->startTimer(15000);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->sessionBrowserWidget->RefreshDone();
|
||||
this->resetDispatcherState();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event->timerId() == this->dispatcherTimeoutTimerId)
|
||||
{
|
||||
this->webSocket->close();
|
||||
this->dispatcherMoveThroughList = true;
|
||||
|
||||
this->killTimer(this->dispatcherTimeoutTimerId);
|
||||
this->dispatcherTimeoutTimerId = -1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_webSocket_connected(void)
|
||||
@@ -198,16 +333,20 @@ void NetplaySessionBrowserDialog::on_webSocket_connected(void)
|
||||
return;
|
||||
}
|
||||
|
||||
// disable refresh button while refreshing
|
||||
QPushButton* refreshButton = this->buttonBox->button(QDialogButtonBox::RestoreDefaults);
|
||||
refreshButton->setEnabled(false);
|
||||
bool dispatcher = NetplayCommon::IsServerDispatcher(this->serverComboBox);
|
||||
|
||||
// disable join button while refreshing
|
||||
QPushButton* joinButton = this->buttonBox->button(QDialogButtonBox::Ok);
|
||||
joinButton->setEnabled(false);
|
||||
if (dispatcher && this->dispatcherJoinSession)
|
||||
{
|
||||
this->joinSession();
|
||||
this->dispatcherJoinSession = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// clear sessions
|
||||
this->sessionBrowserWidget->StartRefresh();
|
||||
// clear sessions when we're not using the dispatcher server
|
||||
if (!dispatcher)
|
||||
{
|
||||
this->sessionBrowserWidget->StartRefresh();
|
||||
}
|
||||
|
||||
// request session list from server
|
||||
QJsonObject json;
|
||||
@@ -241,11 +380,15 @@ void NetplaySessionBrowserDialog::on_webSocket_textMessageReceived(QString messa
|
||||
session.value("port").toInt(),
|
||||
session.value("features").toObject().value("cpu_emulator").toString(),
|
||||
session.value("features").toObject().value("rsp_plugin").toString(),
|
||||
session.value("features").toObject().value("gfx_plugin").toString());
|
||||
session.value("features").toObject().value("gfx_plugin").toString(),
|
||||
this->webSocket->requestUrl().toString());
|
||||
}
|
||||
|
||||
// we're done refreshing the sessions
|
||||
this->sessionBrowserWidget->RefreshDone();
|
||||
if (!NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->sessionBrowserWidget->RefreshDone();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -263,19 +406,27 @@ void NetplaySessionBrowserDialog::on_webSocket_textMessageReceived(QString messa
|
||||
else
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", json.value("message").toString());
|
||||
this->validateJoinButton();
|
||||
this->toggleUI(true, this->validate());
|
||||
}
|
||||
}
|
||||
|
||||
this->dispatcherMoveThroughList = true;
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_webSocket_pong(quint64 elapsedTime, const QByteArray&)
|
||||
{
|
||||
this->pingLineEdit->setText(QString::number(elapsedTime) + " ms");
|
||||
if (!NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->pingLineEdit->setText(QString::number(elapsedTime) + " ms");
|
||||
}
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_webSocket_disconnected()
|
||||
{
|
||||
this->sessionBrowserWidget->Reset();
|
||||
if (!NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->sessionBrowserWidget->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_broadcastSocket_readyRead(void)
|
||||
@@ -284,20 +435,14 @@ void NetplaySessionBrowserDialog::on_broadcastSocket_readyRead(void)
|
||||
{
|
||||
QNetworkDatagram datagram = this->broadcastSocket.receiveDatagram();
|
||||
QByteArray incomingData = datagram.data();
|
||||
QJsonDocument json_doc = QJsonDocument::fromJson(incomingData);
|
||||
QJsonObject json = json_doc.object();
|
||||
QStringList servers = json.keys();
|
||||
|
||||
for (int i = 0; i < servers.size(); i++)
|
||||
{
|
||||
this->serverComboBox->addItem(servers.at(i), json.value(servers.at(i)).toString());
|
||||
}
|
||||
NetplayCommon::AddServers(this->serverComboBox, QJsonDocument::fromJson(incomingData));
|
||||
}
|
||||
|
||||
NetplayCommon::RestoreSelectedServer(this->serverComboBox);
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_networkAccessManager_Finished(QNetworkReply* reply)
|
||||
void NetplaySessionBrowserDialog::on_jsonServerListDownload_Finished(QNetworkReply* reply)
|
||||
{
|
||||
if (reply->error())
|
||||
{
|
||||
@@ -313,6 +458,61 @@ void NetplaySessionBrowserDialog::on_networkAccessManager_Finished(QNetworkReply
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_dispatcherRegionListDownload_Finished(QNetworkReply* reply)
|
||||
{
|
||||
if (reply->error())
|
||||
{
|
||||
this->sessionBrowserWidget->Reset();
|
||||
QtMessageBox::Error(this, "Server Error", "Failed to retrieve region list: " + reply->errorString());
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
NetplayCommon::AddServers(this->serverComboBox,
|
||||
QJsonDocument::fromJson(reply->readAll()), true);
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_dispatcherRetrieveServers_Finished(QNetworkReply* reply)
|
||||
{
|
||||
// don't show an error when the request has been aborted
|
||||
if (reply->error() == QNetworkReply::OperationCanceledError)
|
||||
{
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
if (reply->error())
|
||||
{
|
||||
this->sessionBrowserWidget->Reset();
|
||||
QtMessageBox::Error(this, "Server Error", "Failed to retrieve server list: " + reply->errorString());
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(reply->readAll());
|
||||
QJsonObject jsonObject = jsonDocument.object();
|
||||
QStringList jsonKeys = jsonObject.keys();
|
||||
|
||||
this->sessionBrowserWidget->StartRefresh();
|
||||
this->resetDispatcherState();
|
||||
|
||||
// we only care about the addresses
|
||||
this->dispatcherAddressList.clear();
|
||||
for (int i = 0; i < jsonKeys.size(); i++)
|
||||
{
|
||||
QString address = jsonObject[jsonKeys.at(i)].toString();
|
||||
this->dispatcherAddressList.append(address);
|
||||
}
|
||||
|
||||
this->dispatcherAddressListIndex = -1;
|
||||
this->dispatcherMoveThroughList = true;
|
||||
this->dispatcherTimerId = this->startTimer(250);
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_serverComboBox_currentIndexChanged(int index)
|
||||
{
|
||||
QPushButton* refreshButton = this->buttonBox->button(QDialogButtonBox::RestoreDefaults);
|
||||
@@ -323,12 +523,48 @@ void NetplaySessionBrowserDialog::on_serverComboBox_currentIndexChanged(int inde
|
||||
return;
|
||||
}
|
||||
|
||||
this->pingLineEdit->setText("Calculating...");
|
||||
bool dispatcher = NetplayCommon::IsServerDispatcher(this->serverComboBox, index);
|
||||
|
||||
if (this->pingTimerId != -1)
|
||||
{
|
||||
this->killTimer(this->pingTimerId);
|
||||
this->pingTimerId = -1;
|
||||
}
|
||||
|
||||
this->resetDispatcherState();
|
||||
this->pingLineEdit->setText(dispatcher ? "N/A" : "Calculating...");
|
||||
this->sessionBrowserWidget->StartRefresh();
|
||||
|
||||
QString address = this->serverComboBox->itemData(index).toString();
|
||||
this->webSocket->open(QUrl(address));
|
||||
if (dispatcher)
|
||||
{
|
||||
QString region = NetplayCommon::GetServerData(this->serverComboBox, index);
|
||||
|
||||
QUrl url(this->dispatcherUrl + "/getServers");
|
||||
|
||||
QUrlQuery urlQuery;
|
||||
urlQuery.addQueryItem("region", region);
|
||||
url.setQuery(urlQuery);
|
||||
|
||||
QNetworkRequest networkRequest(url);
|
||||
networkRequest.setRawHeader("netplay-id", "RMG");
|
||||
|
||||
// sadly we have to force HTTP/1 here due to a Qt bug,
|
||||
// we abort the connection which sadly in Qt6 causes an error and eventually segfault,
|
||||
// so to workaround this, force HTTP/1 until it's fixed in Qt6
|
||||
//
|
||||
// thank you MapLibre devs for figuring out this issue:
|
||||
// https://github.com/maplibre/maplibre-native/issues/3644
|
||||
networkRequest.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
|
||||
|
||||
this->dispatcherNetworkReply = this->dispatcherNetworkAccessManager->get(networkRequest);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->pingTimerId = this->startTimer(2000);
|
||||
|
||||
QString address = NetplayCommon::GetServerData(this->serverComboBox, index);
|
||||
this->webSocket->open(QUrl(address));
|
||||
}
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_sessionBrowserWidget_OnSessionChanged(bool valid)
|
||||
@@ -353,13 +589,14 @@ void NetplaySessionBrowserDialog::on_buttonBox_clicked(QAbstractButton* button)
|
||||
// refresh session list when refresh button has been pressed
|
||||
if (button == this->buttonBox->button(QDialogButtonBox::RestoreDefaults))
|
||||
{
|
||||
this->on_webSocket_connected();
|
||||
this->refreshSessions();
|
||||
}
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::accept()
|
||||
{
|
||||
if (!this->webSocket->isValid())
|
||||
if (!NetplayCommon::IsServerDispatcher(this->serverComboBox) &&
|
||||
!this->webSocket->isValid())
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", "Connection Failed");
|
||||
return;
|
||||
@@ -373,21 +610,19 @@ void NetplaySessionBrowserDialog::accept()
|
||||
}
|
||||
|
||||
// disable join button while we're processing the request
|
||||
QPushButton* joinButton = this->buttonBox->button(QDialogButtonBox::Ok);
|
||||
joinButton->setEnabled(false);
|
||||
this->toggleUI(false, false);
|
||||
|
||||
// request password when needed
|
||||
QString password;
|
||||
if (sessionData.PasswordProtected)
|
||||
{
|
||||
NetplaySessionPasswordDialog dialog(this);
|
||||
dialog.exec();
|
||||
password = dialog.GetPassword();
|
||||
this->sessionPassword = dialog.GetPassword();
|
||||
|
||||
// do nothing if password is empty
|
||||
if (password.isEmpty())
|
||||
if (this->sessionPassword.isEmpty())
|
||||
{
|
||||
joinButton->setEnabled(true);
|
||||
this->toggleUI(true, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -400,7 +635,7 @@ void NetplaySessionBrowserDialog::accept()
|
||||
details = "Expected RSP Plugin: " + sessionData.RspPlugin + "\n";
|
||||
details += "Current RSP Plugin: " + pluginNames[0];
|
||||
QtMessageBox::Error(this, "RSP Plugin Mismatch", details);
|
||||
joinButton->setEnabled(true);
|
||||
this->toggleUI(true, true);
|
||||
return;
|
||||
}
|
||||
if (sessionData.GfxPlugin != pluginNames[1])
|
||||
@@ -408,7 +643,7 @@ void NetplaySessionBrowserDialog::accept()
|
||||
details = "Expected GFX Plugin: " + sessionData.GfxPlugin + "\n";
|
||||
details += "Current GFX Plugin: " + pluginNames[1];
|
||||
QtMessageBox::Error(this, "GFX Plugin Mismatch", details);
|
||||
joinButton->setEnabled(true);
|
||||
this->toggleUI(true, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -430,21 +665,20 @@ void NetplaySessionBrowserDialog::accept()
|
||||
this->sessionFile = this->showROMDialog(sessionData.GameName, sessionData.MD5);
|
||||
if (this->sessionFile.isEmpty())
|
||||
{
|
||||
joinButton->setEnabled(true);
|
||||
this->toggleUI(true, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject json;
|
||||
QJsonObject session;
|
||||
session.insert("port", sessionData.Port);
|
||||
session.insert("password", password);
|
||||
session.insert("MD5", QString::fromStdString(md5));
|
||||
this->sessionData = sessionData;
|
||||
|
||||
json.insert("type", "request_join_room");
|
||||
json.insert("player_name", this->nickNameLineEdit->text());
|
||||
json.insert("room", session);
|
||||
NetplayCommon::AddCommonJson(json);
|
||||
|
||||
this->webSocket->sendTextMessage(QJsonDocument(json).toJson());
|
||||
if (NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->dispatcherJoinSession = true;
|
||||
this->webSocket->open(sessionData.Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->joinSession();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,15 +43,35 @@ class NetplaySessionBrowserDialog : public QDialog, private Ui::NetplaySessionBr
|
||||
QUdpSocket broadcastSocket;
|
||||
QJsonObject sessionJson;
|
||||
QString sessionFile;
|
||||
QString sessionPassword;
|
||||
NetplaySessionData sessionData;
|
||||
QMap<QString, CoreRomSettings> romData;
|
||||
|
||||
int pingTimerId = -1;
|
||||
int dispatcherTimerId = -1;
|
||||
int dispatcherTimeoutTimerId = -1;
|
||||
|
||||
bool dispatcherMoveThroughList = false;
|
||||
bool dispatcherJoinSession = false;
|
||||
QNetworkAccessManager* dispatcherNetworkAccessManager = nullptr;
|
||||
QNetworkReply* dispatcherNetworkReply = nullptr;
|
||||
QString dispatcherUrl;
|
||||
|
||||
QStringList dispatcherAddressList;
|
||||
int dispatcherAddressListIndex = 0;
|
||||
|
||||
QString showROMDialog(QString name, QString md5);
|
||||
|
||||
bool validate(void);
|
||||
void validateJoinButton(void);
|
||||
|
||||
void toggleUI(bool enable, bool enableJoinButton);
|
||||
|
||||
void refreshSessions(void);
|
||||
void joinSession(void);
|
||||
|
||||
void resetDispatcherState(void);
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE;
|
||||
|
||||
@@ -62,7 +82,10 @@ class NetplaySessionBrowserDialog : public QDialog, private Ui::NetplaySessionBr
|
||||
void on_webSocket_disconnected(void);
|
||||
|
||||
void on_broadcastSocket_readyRead(void);
|
||||
void on_networkAccessManager_Finished(QNetworkReply* reply);
|
||||
void on_jsonServerListDownload_Finished(QNetworkReply* reply);
|
||||
|
||||
void on_dispatcherRegionListDownload_Finished(QNetworkReply* reply);
|
||||
void on_dispatcherRetrieveServers_Finished(QNetworkReply* reply);
|
||||
|
||||
void on_serverComboBox_currentIndexChanged(int index);
|
||||
void on_sessionBrowserWidget_OnSessionChanged(bool valid);
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<widget class="QLabel" name="pingLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
|
||||
@@ -141,7 +141,7 @@ void NetplaySessionDialog::updateCheatsTreeWidget(void)
|
||||
CheatsCommon::AddCheatsToTreeWidget(true, cheatsArray, this->sessionFile, cheats, this->cheatsTreeWidget, true);
|
||||
}
|
||||
|
||||
void NetplaySessionDialog::on_webSocket_textMessageReceived(QString message)
|
||||
void NetplaySessionDialog::on_webSocket_textMessageReceived(const QString& message)
|
||||
{
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(message.toUtf8());
|
||||
QJsonObject json = jsonDocument.object();
|
||||
@@ -225,7 +225,7 @@ void NetplaySessionDialog::on_webSocket_textMessageReceived(QString message)
|
||||
}
|
||||
}
|
||||
|
||||
void NetplaySessionDialog::on_chatLineEdit_textChanged(QString text)
|
||||
void NetplaySessionDialog::on_chatLineEdit_textChanged(const QString& text)
|
||||
{
|
||||
this->sendPushButton->setEnabled(!text.startsWith(' ') && !text.trimmed().isEmpty() && text.size() <= 256);
|
||||
this->sendPushButton->setDefault(this->sendPushButton->isEnabled());
|
||||
|
||||
@@ -47,9 +47,9 @@ class NetplaySessionDialog : public QDialog, private Ui::NetplaySessionDialog
|
||||
void updateCheatsTreeWidget(void);
|
||||
|
||||
private slots:
|
||||
void on_webSocket_textMessageReceived(QString message);
|
||||
void on_webSocket_textMessageReceived(const QString& message);
|
||||
|
||||
void on_chatLineEdit_textChanged(QString text);
|
||||
void on_chatLineEdit_textChanged(const QString& text);
|
||||
void on_sendPushButton_clicked(void);
|
||||
void on_buttonBox_clicked(QAbstractButton* button);
|
||||
|
||||
|
||||
@@ -489,6 +489,10 @@ void SettingsDialog::loadInterfaceGeneralSettings(void)
|
||||
this->themeComboBox->addItem(fileInfo.fileName());
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
this->themeComboBox->insertItem(1,"Windows Vista");
|
||||
#endif
|
||||
|
||||
// select currently chosen theme in UI
|
||||
this->themeComboBox->setCurrentText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::GUI_Theme)));
|
||||
this->iconThemeComboBox->setCurrentText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::GUI_IconTheme)));
|
||||
@@ -558,6 +562,7 @@ void SettingsDialog::loadInterfaceNetplaySettings(void)
|
||||
|
||||
this->netplayNicknameLineEdit->setText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_Nickname)));
|
||||
this->netplayServerUrlLineEdit->setText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_ServerJsonUrl)));
|
||||
this->netplayDispatcherUrlLineEdit->setText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_DispatcherUrl)));
|
||||
}
|
||||
|
||||
void SettingsDialog::loadDefaultCoreSettings(void)
|
||||
@@ -732,6 +737,7 @@ void SettingsDialog::loadDefaultInterfaceNetplaySettings(void)
|
||||
{
|
||||
this->netplayNicknameLineEdit->setText(QString::fromStdString(CoreSettingsGetDefaultStringValue(SettingsID::Netplay_Nickname)));
|
||||
this->netplayServerUrlLineEdit->setText(QString::fromStdString(CoreSettingsGetDefaultStringValue(SettingsID::Netplay_ServerJsonUrl)));
|
||||
this->netplayDispatcherUrlLineEdit->setText(QString::fromStdString(CoreSettingsGetDefaultStringValue(SettingsID::Netplay_DispatcherUrl)));
|
||||
}
|
||||
|
||||
void SettingsDialog::saveSettings(void)
|
||||
@@ -976,6 +982,7 @@ void SettingsDialog::saveInterfaceNetplaySettings(void)
|
||||
{
|
||||
CoreSettingsSetValue(SettingsID::Netplay_Nickname, this->netplayNicknameLineEdit->text().toStdString());
|
||||
CoreSettingsSetValue(SettingsID::Netplay_ServerJsonUrl, this->netplayServerUrlLineEdit->text().toStdString());
|
||||
CoreSettingsSetValue(SettingsID::Netplay_DispatcherUrl, this->netplayDispatcherUrlLineEdit->text().toStdString());
|
||||
}
|
||||
|
||||
void SettingsDialog::commonHotkeySettings(SettingsDialogAction action)
|
||||
@@ -1057,8 +1064,9 @@ void SettingsDialog::commonHotkeySettings(SettingsDialogAction action)
|
||||
std::vector<keybinding> keybindings_View =
|
||||
{
|
||||
{ this->fullscreenKeyButton, SettingsID::KeyBinding_Fullscreen },
|
||||
{ this->logKeyButton, SettingsID::Keybinding_ViewLog },
|
||||
{ this->refreshRomListKeyButton, SettingsID::KeyBinding_RefreshROMList }
|
||||
{ this->logKeyButton, SettingsID::KeyBinding_ViewLog },
|
||||
{ this->refreshRomListKeyButton, SettingsID::KeyBinding_RefreshROMList },
|
||||
{ this->searchKeyButton, SettingsID::KeyBinding_ViewSearch }
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -665,6 +665,27 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_21">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Dispatcher URL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="netplayDispatcherUrlLineEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_19">
|
||||
<property name="orientation">
|
||||
@@ -1681,6 +1702,24 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_122">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_119">
|
||||
<property name="text">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="KeybindButton" name="searchKeyButton">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_16">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -330,6 +330,12 @@ void MainWindow::configureTheme(QApplication* app)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
#ifdef _WIN32
|
||||
else if (theme == "Windows Vista")
|
||||
{
|
||||
app->setStyle(QStyleFactory::create("WindowsVista"));
|
||||
}
|
||||
#endif
|
||||
else if (theme == "Fusion")
|
||||
{
|
||||
app->setPalette(QApplication::style()->standardPalette());
|
||||
@@ -837,6 +843,8 @@ void MainWindow::updateActions(bool inEmulation, bool isPaused)
|
||||
keyBinding = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::KeyBinding_Settings));
|
||||
this->action_Settings_Settings->setShortcut(QKeySequence(keyBinding));
|
||||
|
||||
this->action_View_GameList->setEnabled(!inEmulation);
|
||||
this->action_View_GameGrid->setEnabled(!inEmulation);
|
||||
this->action_View_UniformSize->setEnabled(!inEmulation);
|
||||
keyBinding = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::KeyBinding_Fullscreen));
|
||||
this->action_View_Fullscreen->setEnabled(inEmulation);
|
||||
@@ -844,9 +852,12 @@ void MainWindow::updateActions(bool inEmulation, bool isPaused)
|
||||
keyBinding = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::KeyBinding_RefreshROMList));
|
||||
this->action_View_RefreshRoms->setEnabled(!inEmulation);
|
||||
this->action_View_RefreshRoms->setShortcut(QKeySequence(keyBinding));
|
||||
keyBinding = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Keybinding_ViewLog));
|
||||
keyBinding = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::KeyBinding_ViewLog));
|
||||
this->action_View_Log->setShortcut(QKeySequence(keyBinding));
|
||||
this->action_View_ClearRomCache->setEnabled(!inEmulation);
|
||||
keyBinding = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::KeyBinding_ViewSearch));
|
||||
this->action_View_Search->setShortcut(QKeySequence(keyBinding));
|
||||
this->action_View_Search->setEnabled(!inEmulation);
|
||||
|
||||
#ifdef NETPLAY
|
||||
this->action_Netplay_CreateSession->setEnabled(!inEmulation && this->netplaySessionDialog == nullptr);
|
||||
@@ -1180,6 +1191,7 @@ void MainWindow::connectActionSignals(void)
|
||||
connect(this->action_View_RefreshRoms, &QAction::triggered, this, &MainWindow::on_Action_View_RefreshRoms);
|
||||
connect(this->action_View_ClearRomCache, &QAction::triggered, this, &MainWindow::on_Action_View_ClearRomCache);
|
||||
connect(this->action_View_Log, &QAction::triggered, this, &MainWindow::on_Action_View_Log);
|
||||
connect(this->action_View_Search, &QAction::triggered, this, &MainWindow::on_Action_View_Search);
|
||||
|
||||
connect(this->action_Netplay_CreateSession, &QAction::triggered, this, &MainWindow::on_Action_Netplay_CreateSession);
|
||||
connect(this->action_Netplay_BrowseSessions, &QAction::triggered, this, &MainWindow::on_Action_Netplay_BrowseSessions);
|
||||
@@ -1952,6 +1964,11 @@ void MainWindow::on_Action_View_Log(void)
|
||||
this->logDialog.show();
|
||||
}
|
||||
|
||||
void MainWindow::on_Action_View_Search(void)
|
||||
{
|
||||
this->ui_Widget_RomBrowser->SetToggleSearch();
|
||||
}
|
||||
|
||||
void MainWindow::on_Action_Netplay_CreateSession(void)
|
||||
{
|
||||
#ifdef NETPLAY
|
||||
|
||||
@@ -210,6 +210,7 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
|
||||
void on_Action_View_RefreshRoms(void);
|
||||
void on_Action_View_ClearRomCache(void);
|
||||
void on_Action_View_Log(void);
|
||||
void on_Action_View_Search(void);
|
||||
|
||||
void on_Action_Netplay_CreateSession(void);
|
||||
void on_Action_Netplay_BrowseSessions(void);
|
||||
|
||||
@@ -137,6 +137,8 @@
|
||||
<addaction name="action_View_ClearRomCache"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_View_Log"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_View_Search"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
@@ -633,6 +635,14 @@
|
||||
<string>View Session</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_View_Search">
|
||||
<property name="icon">
|
||||
<iconset theme="search-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="UIResources.qrc"/>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M18.031 16.6168L22.3137 20.8995L20.8995 22.3137L16.6168 18.031C15.0769 19.263 13.124 20 11 20C6.032 20 2 15.968 2 11C2 6.032 6.032 2 11 2C15.968 2 20 6.032 20 11C20 13.124 19.263 15.0769 18.031 16.6168ZM16.0247 15.8748C17.2475 14.6146 18 12.8956 18 11C18 7.1325 14.8675 4 11 4C7.1325 4 4 7.1325 4 11C4 14.8675 7.1325 18 11 18C12.8956 18 14.6146 17.2475 15.8748 16.0247L16.0247 15.8748Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 489 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M18.031 16.6168L22.3137 20.8995L20.8995 22.3137L16.6168 18.031C15.0769 19.263 13.124 20 11 20C6.032 20 2 15.968 2 11C2 6.032 6.032 2 11 2C15.968 2 20 6.032 20 11C20 13.124 19.263 15.0769 18.031 16.6168ZM16.0247 15.8748C17.2475 14.6146 18 12.8956 18 11C18 7.1325 14.8675 4 11 4C7.1325 4 4 7.1325 4 11C4 14.8675 7.1325 18 11 18C12.8956 18 14.6146 17.2475 15.8748 16.0247L16.0247 15.8748Z" fill="#ffffff"></path></svg>
|
||||
|
After Width: | Height: | Size: 504 B |
@@ -31,6 +31,7 @@
|
||||
<file alias="icons/black/svg/shut-down-line.svg">Resource/icons/black/svg/shut-down-line.svg</file>
|
||||
<file alias="icons/black/svg/speed-line.svg">Resource/icons/black/svg/speed-line.svg</file>
|
||||
<file alias="icons/black/svg/tools-line.svg">Resource/icons/black/svg/tools-line.svg</file>
|
||||
<file alias="icons/black/svg/search-line.svg">Resource/icons/black/svg/search-line.svg</file>
|
||||
<file alias="icons/black/svg/server-line.svg">Resource/icons/black/svg/server-line.svg</file>
|
||||
<file alias="icons/black/svg/settings-3-line.svg">Resource/icons/black/svg/settings-3-line.svg</file>
|
||||
<file alias="icons/black/svg/volume-up-line.svg">Resource/icons/black/svg/volume-up-line.svg</file>
|
||||
@@ -63,6 +64,7 @@
|
||||
<file alias="icons/white/svg/shut-down-line.svg">Resource/icons/white/svg/shut-down-line.svg</file>
|
||||
<file alias="icons/white/svg/speed-line.svg">Resource/icons/white/svg/speed-line.svg</file>
|
||||
<file alias="icons/white/svg/tools-line.svg">Resource/icons/white/svg/tools-line.svg</file>
|
||||
<file alias="icons/white/svg/search-line.svg">Resource/icons/white/svg/search-line.svg</file>
|
||||
<file alias="icons/white/svg/server-line.svg">Resource/icons/white/svg/server-line.svg</file>
|
||||
<file alias="icons/white/svg/settings-3-line.svg">Resource/icons/white/svg/settings-3-line.svg</file>
|
||||
<file alias="icons/white/svg/volume-up-line.svg">Resource/icons/white/svg/volume-up-line.svg</file>
|
||||
|
||||
@@ -26,6 +26,11 @@ CreateNetplaySessionWidget::CreateNetplaySessionWidget(QWidget* parent) : QStack
|
||||
this->emptyWidget = new Widget::CreateNetplaySessionEmptyWidget(this);
|
||||
this->addWidget(this->emptyWidget);
|
||||
|
||||
// configure loading widget
|
||||
this->loadingWidget = new Widget::NetplaySessionBrowserLoadingWidget(this, "Creating server");
|
||||
this->loadingWidget->SetWidgetIndex(this->addWidget(this->loadingWidget));
|
||||
connect(this, &QStackedWidget::currentChanged, this->loadingWidget, &NetplaySessionBrowserLoadingWidget::on_NetplaySessionBrowserWidget_currentChanged);
|
||||
|
||||
// configure list widget
|
||||
this->listWidget = new QListWidget(this);
|
||||
this->addWidget(this->listWidget);
|
||||
@@ -66,6 +71,11 @@ void CreateNetplaySessionWidget::RefreshDone(void)
|
||||
}
|
||||
}
|
||||
|
||||
void CreateNetplaySessionWidget::ShowLoading(void)
|
||||
{
|
||||
this->setCurrentWidget(this->loadingWidget);
|
||||
}
|
||||
|
||||
bool CreateNetplaySessionWidget::IsCurrentRomValid()
|
||||
{
|
||||
return this->currentWidget() == this->listWidget &&
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#ifndef CREATENETPLAYSESSIONWIDGET_HPP
|
||||
#define CREATENETPLAYSESSIONWIDGET_HPP
|
||||
|
||||
#include "NetplaySessionBrowserLoadingWidget.hpp"
|
||||
#include "CreateNetplaySessionEmptyWidget.hpp"
|
||||
|
||||
#include <QStackedWidget>
|
||||
@@ -36,14 +37,15 @@ class CreateNetplaySessionWidget : public QStackedWidget
|
||||
~CreateNetplaySessionWidget(void);
|
||||
|
||||
void AddRomData(QString goodName, QString md5, QString file);
|
||||
|
||||
void RefreshDone(void);
|
||||
|
||||
void ShowLoading(void);
|
||||
|
||||
bool IsCurrentRomValid(void);
|
||||
bool GetCurrentRom(NetplayRomData& data);
|
||||
|
||||
private:
|
||||
Widget::CreateNetplaySessionEmptyWidget* emptyWidget = nullptr;
|
||||
Widget::NetplaySessionBrowserLoadingWidget* loadingWidget = nullptr;
|
||||
|
||||
QListWidget* listWidget = nullptr;
|
||||
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
|
||||
using namespace UserInterface::Widget;
|
||||
|
||||
NetplaySessionBrowserLoadingWidget::NetplaySessionBrowserLoadingWidget(QWidget* parent) : QWidget(parent)
|
||||
NetplaySessionBrowserLoadingWidget::NetplaySessionBrowserLoadingWidget(QWidget* parent, QString loadingText) : QWidget(parent)
|
||||
{
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
|
||||
|
||||
this->baseLoadingText = loadingText;
|
||||
this->loadingLabel = new QLabel(this);
|
||||
this->loadingLabel->setText("Loading");
|
||||
this->loadingLabel->setText(this->baseLoadingText);
|
||||
this->loadingLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
|
||||
layout->addWidget(loadingLabel);
|
||||
@@ -66,7 +67,7 @@ void NetplaySessionBrowserLoadingWidget::on_NetplaySessionBrowserWidget_currentC
|
||||
|
||||
void NetplaySessionBrowserLoadingWidget::updateLoadingText()
|
||||
{
|
||||
QString loadingText = "Loading";
|
||||
QString loadingText = this->baseLoadingText;
|
||||
|
||||
if (dotCount <= 3)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ class NetplaySessionBrowserLoadingWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NetplaySessionBrowserLoadingWidget(QWidget* parent);
|
||||
NetplaySessionBrowserLoadingWidget(QWidget* parent, QString loadingText = "Loading");
|
||||
~NetplaySessionBrowserLoadingWidget();
|
||||
|
||||
void SetWidgetIndex(int index);
|
||||
@@ -31,6 +31,7 @@ public slots:
|
||||
void on_NetplaySessionBrowserWidget_currentChanged(int index);
|
||||
|
||||
private:
|
||||
QString baseLoadingText;
|
||||
QLabel* loadingLabel;
|
||||
int loadingLabelTimerId = -1;
|
||||
int widgetIndex = -1;
|
||||
|
||||
@@ -87,7 +87,7 @@ void NetplaySessionBrowserWidget::StartRefresh(void)
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserWidget::AddSessionData(QString name, QString game, QString md5, bool password, int port,
|
||||
QString cpuEmulator, QString rspPlugin, QString gfxPlugin)
|
||||
QString cpuEmulator, QString rspPlugin, QString gfxPlugin, QUrl address)
|
||||
{
|
||||
const NetplaySessionData sessionData =
|
||||
{
|
||||
@@ -98,7 +98,8 @@ void NetplaySessionBrowserWidget::AddSessionData(QString name, QString game, QSt
|
||||
port,
|
||||
cpuEmulator,
|
||||
rspPlugin,
|
||||
gfxPlugin
|
||||
gfxPlugin,
|
||||
address
|
||||
};
|
||||
|
||||
int row = this->tableWidget->rowCount();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <QTableWidgetItem>
|
||||
#include <QStackedWidget>
|
||||
#include <QTableWidget>
|
||||
#include <QUrl>
|
||||
|
||||
// session data
|
||||
struct NetplaySessionData
|
||||
@@ -28,6 +29,7 @@ struct NetplaySessionData
|
||||
QString CpuEmulator;
|
||||
QString RspPlugin;
|
||||
QString GfxPlugin;
|
||||
QUrl Address;
|
||||
};
|
||||
|
||||
namespace UserInterface
|
||||
@@ -47,7 +49,7 @@ class NetplaySessionBrowserWidget : public QStackedWidget
|
||||
void StartRefresh(void);
|
||||
|
||||
void AddSessionData(QString name, QString game, QString md5, bool password, int port,
|
||||
QString cpuEmulator, QString rspPlugin, QString gfxPlugin);
|
||||
QString cpuEmulator, QString rspPlugin, QString gfxPlugin, QUrl address);
|
||||
|
||||
void RefreshDone(void);
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020-2025 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 "RomBrowserSearchWidget.hpp"
|
||||
|
||||
using namespace UserInterface::Widget;
|
||||
|
||||
RomBrowserSearchWidget::RomBrowserSearchWidget(QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
// configure search line edit
|
||||
this->lineEdit = new QLineEdit(this);
|
||||
this->lineEdit->setPlaceholderText("Search games...");
|
||||
connect(this->lineEdit, &QLineEdit::textChanged, this, &RomBrowserSearchWidget::on_lineEdit_textChanged);
|
||||
|
||||
// configure close button
|
||||
this->closeButton = new QPushButton(this);
|
||||
this->closeButton->setText("Close");
|
||||
connect(this->closeButton, &QPushButton::clicked, this, &RomBrowserSearchWidget::on_closeButton_clicked);
|
||||
|
||||
// configure layout
|
||||
this->widgetLayout = new QHBoxLayout(this);
|
||||
this->widgetLayout->addWidget(this->lineEdit);
|
||||
this->widgetLayout->addWidget(this->closeButton);
|
||||
this->setLayout(this->widgetLayout);
|
||||
}
|
||||
|
||||
RomBrowserSearchWidget::~RomBrowserSearchWidget(void)
|
||||
{
|
||||
}
|
||||
|
||||
void RomBrowserSearchWidget::FocusSearchText(void)
|
||||
{
|
||||
this->lineEdit->setFocus();
|
||||
}
|
||||
|
||||
void RomBrowserSearchWidget::ClearSearchTerm(void)
|
||||
{
|
||||
this->lineEdit->setText("");
|
||||
}
|
||||
|
||||
void RomBrowserSearchWidget::on_lineEdit_textChanged(const QString& text)
|
||||
{
|
||||
emit this->SearchTextChanged(text);
|
||||
}
|
||||
|
||||
void RomBrowserSearchWidget::on_closeButton_clicked(void)
|
||||
{
|
||||
this->hide();
|
||||
this->ClearSearchTerm();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020-2025 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 ROMBROWSERSEARCHWIDGET_HPP
|
||||
#define ROMBROWSERSEARCHWIDGET_HPP
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QWidget>
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
namespace Widget
|
||||
{
|
||||
class RomBrowserSearchWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RomBrowserSearchWidget(QWidget* parent);
|
||||
~RomBrowserSearchWidget(void);
|
||||
|
||||
void FocusSearchText(void);
|
||||
void ClearSearchTerm(void);
|
||||
|
||||
signals:
|
||||
void SearchTextChanged(const QString& text);
|
||||
|
||||
private:
|
||||
QHBoxLayout* widgetLayout = nullptr;
|
||||
QLineEdit* lineEdit = nullptr;
|
||||
QPushButton* closeButton = nullptr;
|
||||
|
||||
private slots:
|
||||
void on_lineEdit_textChanged(const QString& text);
|
||||
void on_closeButton_clicked(void);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ROMBROWSERSEARCHWIDGET_HPP
|
||||
@@ -56,11 +56,26 @@ Q_DECLARE_METATYPE(RomBrowserModelData);
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
RomBrowserWidget::RomBrowserWidget(QWidget *parent) : QStackedWidget(parent)
|
||||
RomBrowserWidget::RomBrowserWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
// configure signal types
|
||||
qRegisterMetaType<CoreRomType>("CoreRomType");
|
||||
|
||||
// configure stacked widget
|
||||
this->stackedWidget = new QStackedWidget(this);
|
||||
|
||||
// configure search widget
|
||||
this->searchWidget = new Widget::RomBrowserSearchWidget(this);
|
||||
this->searchWidget->setVisible(false);
|
||||
connect(this->searchWidget, &RomBrowserSearchWidget::SearchTextChanged, this, &RomBrowserWidget::on_searchWidget_SearchTextChanged);
|
||||
|
||||
// configure layout
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->addWidget(this->stackedWidget);
|
||||
layout->addWidget(this->searchWidget);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
this->setLayout(layout);
|
||||
|
||||
// configure rom searcher thread
|
||||
this->romSearcherThread = new Thread::RomSearcherThread(this);
|
||||
connect(this->romSearcherThread, &Thread::RomSearcherThread::RomsFound, this, &RomBrowserWidget::on_RomBrowserThread_RomsFound);
|
||||
@@ -68,21 +83,23 @@ RomBrowserWidget::RomBrowserWidget(QWidget *parent) : QStackedWidget(parent)
|
||||
|
||||
// configure empty widget
|
||||
this->emptyWidget = new Widget::RomBrowserEmptyWidget(this);
|
||||
this->addWidget(this->emptyWidget);
|
||||
this->stackedWidget->addWidget(this->emptyWidget);
|
||||
connect(this->emptyWidget, &RomBrowserEmptyWidget::SelectRomDirectory, this, &RomBrowserWidget::on_Action_ChangeRomDirectory);
|
||||
connect(this->emptyWidget, &RomBrowserEmptyWidget::Refresh, this, &RomBrowserWidget::on_Action_RefreshRomList);
|
||||
connect(this->emptyWidget, &RomBrowserEmptyWidget::FileDropped, this, &RomBrowserWidget::FileDropped);
|
||||
|
||||
// configure loading widget
|
||||
this->loadingWidget = new Widget::RomBrowserLoadingWidget(this);
|
||||
connect(this, &QStackedWidget::currentChanged, this->loadingWidget, &RomBrowserLoadingWidget::on_RomBrowserWidget_currentChanged);
|
||||
connect(this->stackedWidget, &QStackedWidget::currentChanged, this->loadingWidget, &RomBrowserLoadingWidget::on_RomBrowserWidget_currentChanged);
|
||||
connect(this->loadingWidget, &RomBrowserLoadingWidget::FileDropped, this, &RomBrowserWidget::FileDropped);
|
||||
this->loadingWidget->SetWidgetIndex(this->addWidget(this->loadingWidget));
|
||||
this->loadingWidget->SetWidgetIndex(this->stackedWidget->addWidget(this->loadingWidget));
|
||||
|
||||
// configure list view widget
|
||||
this->listViewWidget = new Widget::RomBrowserListViewWidget(this);
|
||||
this->listViewModel = new QStandardItemModel(this);
|
||||
this->listViewWidget->setModel(this->listViewModel);
|
||||
this->listViewProxyModel = new QSortFilterProxyModel(this);
|
||||
this->listViewProxyModel->setSourceModel(this->listViewModel);
|
||||
this->listViewWidget->setModel(this->listViewProxyModel);
|
||||
this->listViewWidget->setFrameStyle(QFrame::NoFrame);
|
||||
this->listViewWidget->setItemDelegate(new NoFocusDelegate(this));
|
||||
this->listViewWidget->setWordWrap(false);
|
||||
@@ -101,7 +118,7 @@ RomBrowserWidget::RomBrowserWidget(QWidget *parent) : QStackedWidget(parent)
|
||||
this->listViewWidget->horizontalHeader()->setSortIndicatorShown(false);
|
||||
this->listViewWidget->horizontalHeader()->setHighlightSections(false);
|
||||
this->listViewWidget->horizontalHeader()->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
|
||||
this->addWidget(this->listViewWidget);
|
||||
this->stackedWidget->addWidget(this->listViewWidget);
|
||||
connect(this->listViewWidget, &QTableView::doubleClicked, this, &RomBrowserWidget::on_DoubleClicked);
|
||||
connect(this->listViewWidget->horizontalHeader(), &QHeaderView::sortIndicatorChanged, this, &RomBrowserWidget::on_listViewWidget_sortIndicatorChanged);
|
||||
connect(this->listViewWidget->horizontalHeader(), &QHeaderView::sectionResized, this, &RomBrowserWidget::on_listViewWidget_sectionResized);
|
||||
@@ -139,7 +156,9 @@ RomBrowserWidget::RomBrowserWidget(QWidget *parent) : QStackedWidget(parent)
|
||||
// configure grid view widget
|
||||
this->gridViewWidget = new Widget::RomBrowserGridViewWidget(this);
|
||||
this->gridViewModel = new QStandardItemModel(this);
|
||||
this->gridViewWidget->setModel(this->gridViewModel);
|
||||
this->gridViewProxyModel = new QSortFilterProxyModel(this);
|
||||
this->gridViewProxyModel->setSourceModel(this->gridViewModel);
|
||||
this->gridViewWidget->setModel(this->gridViewProxyModel);
|
||||
this->gridViewWidget->setFlow(QListView::Flow::LeftToRight);
|
||||
this->gridViewWidget->setResizeMode(QListView::Adjust);
|
||||
#ifndef DRAG_DROP
|
||||
@@ -157,7 +176,7 @@ RomBrowserWidget::RomBrowserWidget(QWidget *parent) : QStackedWidget(parent)
|
||||
int iconWidth = CoreSettingsGetIntValue(SettingsID::RomBrowser_GridViewIconWidth);
|
||||
int iconHeight = CoreSettingsGetIntValue(SettingsID::RomBrowser_GridViewIconHeight);
|
||||
this->gridViewWidget->setIconSize(QSize(iconWidth, iconHeight));
|
||||
this->addWidget(this->gridViewWidget);
|
||||
this->stackedWidget->addWidget(this->gridViewWidget);
|
||||
connect(this->gridViewWidget, &QListView::doubleClicked, this, &RomBrowserWidget::on_DoubleClicked);
|
||||
connect(this->gridViewWidget, &QListView::iconSizeChanged, this, &RomBrowserWidget::on_gridViewWidget_iconSizeChanged);
|
||||
connect(this->gridViewWidget, &Widget::RomBrowserGridViewWidget::ZoomIn, this, &RomBrowserWidget::on_ZoomIn);
|
||||
@@ -279,11 +298,15 @@ void RomBrowserWidget::RefreshRomList(void)
|
||||
QString directory = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::RomBrowser_Directory));
|
||||
if (directory.isEmpty())
|
||||
{
|
||||
this->setCurrentWidget(this->emptyWidget);
|
||||
this->stackedWidget->setCurrentWidget(this->emptyWidget);
|
||||
return;
|
||||
}
|
||||
|
||||
this->setCurrentWidget(this->loadingWidget);
|
||||
this->stackedWidget->setCurrentWidget(this->loadingWidget);
|
||||
|
||||
this->showSearchWidget = this->searchWidget->isVisible();
|
||||
this->searchWidget->hide();
|
||||
|
||||
this->romSearcherTimer.start();
|
||||
|
||||
this->romSearcherThread->SetMaximumFiles(CoreSettingsGetIntValue(SettingsID::RomBrowser_MaxItems));
|
||||
@@ -308,9 +331,9 @@ void RomBrowserWidget::ShowList(void)
|
||||
|
||||
// only change widget now when we're not refreshing
|
||||
if (!this->IsRefreshingRomList() &&
|
||||
this->currentWidget() != this->emptyWidget)
|
||||
this->stackedWidget->currentWidget() != this->emptyWidget)
|
||||
{
|
||||
this->setCurrentWidget(this->listViewWidget);
|
||||
this->stackedWidget->setCurrentWidget(this->listViewWidget);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,9 +343,9 @@ void RomBrowserWidget::ShowGrid(void)
|
||||
|
||||
// only change widget now when we're not refreshing
|
||||
if (!this->IsRefreshingRomList() &&
|
||||
this->currentWidget() != this->emptyWidget)
|
||||
this->stackedWidget->currentWidget() != this->emptyWidget)
|
||||
{
|
||||
this->setCurrentWidget(this->gridViewWidget);
|
||||
this->stackedWidget->setCurrentWidget(this->gridViewWidget);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,7 +353,7 @@ void RomBrowserWidget::SetGridViewUniformSizes(bool value)
|
||||
{
|
||||
// refresh ROM list when we're currently in the grid view
|
||||
// and we're not refreshing already
|
||||
if (this->currentWidget() == this->gridViewWidget &&
|
||||
if (this->stackedWidget->currentWidget() == this->gridViewWidget &&
|
||||
!this->IsRefreshingRomList())
|
||||
{
|
||||
if (this->gridViewWidget->uniformItemSizes() != value)
|
||||
@@ -344,20 +367,46 @@ void RomBrowserWidget::SetGridViewUniformSizes(bool value)
|
||||
this->gridViewWidget->setUniformItemSizes(value);
|
||||
}
|
||||
|
||||
void RomBrowserWidget::SetToggleSearch(void)
|
||||
{
|
||||
const bool show = !this->searchWidget->isVisible();
|
||||
|
||||
// do nothing when not in a valid view
|
||||
QWidget* currentWidget = this->stackedWidget->currentWidget();
|
||||
if (currentWidget == this->loadingWidget ||
|
||||
currentWidget == this->emptyWidget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->searchWidget->setVisible(show);
|
||||
|
||||
if (show)
|
||||
{
|
||||
// set focus when it's being shown
|
||||
this->searchWidget->FocusSearchText();
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset search when hidden
|
||||
this->searchWidget->ClearSearchTerm();
|
||||
}
|
||||
}
|
||||
|
||||
QMap<QString, CoreRomSettings> RomBrowserWidget::GetModelData(void)
|
||||
{
|
||||
QMap<QString, CoreRomSettings> data;
|
||||
QStandardItemModel* model = this->getCurrentModel();
|
||||
QPair<QStandardItemModel*, QSortFilterProxyModel*> model = this->getCurrentModel();
|
||||
RomBrowserModelData modelData;
|
||||
|
||||
if (model == nullptr)
|
||||
if (model.first == nullptr)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
for (int i = 0; i < model->rowCount(); i++)
|
||||
for (int i = 0; i < model.first->rowCount(); i++)
|
||||
{
|
||||
modelData = model->item(i)->data().value<RomBrowserModelData>();
|
||||
modelData = model.first->item(i)->data().value<RomBrowserModelData>();
|
||||
// only add cartridges, 64dd disks aren't supported
|
||||
if (modelData.type == CoreRomType::Cartridge)
|
||||
{
|
||||
@@ -368,9 +417,9 @@ QMap<QString, CoreRomSettings> RomBrowserWidget::GetModelData(void)
|
||||
return data;
|
||||
}
|
||||
|
||||
QStandardItemModel* RomBrowserWidget::getCurrentModel(void)
|
||||
QPair<QStandardItemModel*, QSortFilterProxyModel*> RomBrowserWidget::getCurrentModel(void)
|
||||
{
|
||||
QWidget* currentWidget = this->currentWidget();
|
||||
QWidget* currentWidget = this->stackedWidget->currentWidget();
|
||||
if (currentWidget == this->loadingWidget)
|
||||
{
|
||||
currentWidget = this->currentViewWidget;
|
||||
@@ -378,19 +427,19 @@ QStandardItemModel* RomBrowserWidget::getCurrentModel(void)
|
||||
|
||||
if (currentWidget == this->listViewWidget)
|
||||
{
|
||||
return this->listViewModel;
|
||||
return qMakePair(this->listViewModel, this->listViewProxyModel);
|
||||
}
|
||||
else if (currentWidget == this->gridViewWidget)
|
||||
{
|
||||
return this->gridViewModel;
|
||||
return qMakePair(this->gridViewModel, this->gridViewProxyModel);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return qMakePair(nullptr, nullptr);
|
||||
}
|
||||
|
||||
QAbstractItemView* RomBrowserWidget::getCurrentModelView(void)
|
||||
{
|
||||
QWidget* currentWidget = this->currentWidget();
|
||||
QWidget* currentWidget = this->stackedWidget->currentWidget();
|
||||
if (currentWidget == this->loadingWidget)
|
||||
{
|
||||
currentWidget = this->currentViewWidget;
|
||||
@@ -410,16 +459,16 @@ QAbstractItemView* RomBrowserWidget::getCurrentModelView(void)
|
||||
|
||||
bool RomBrowserWidget::getCurrentData(RomBrowserModelData& data)
|
||||
{
|
||||
QStandardItemModel* model = this->getCurrentModel();
|
||||
QAbstractItemView* view = this->getCurrentModelView();
|
||||
QPair<QStandardItemModel*, QSortFilterProxyModel*> model = this->getCurrentModel();
|
||||
QAbstractItemView* view = this->getCurrentModelView();
|
||||
|
||||
if (model == nullptr || view == nullptr)
|
||||
if (model.first == nullptr || model.second == nullptr || view == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QModelIndex index = view->currentIndex();
|
||||
QStandardItem* item = model->item(index.row(), 0);
|
||||
QModelIndex index = model.second->mapToSource(view->currentIndex());
|
||||
QStandardItem* item = model.first->item(index.row(), 0);
|
||||
|
||||
if (item == nullptr)
|
||||
{
|
||||
@@ -614,7 +663,8 @@ QIcon RomBrowserWidget::getCurrentCover(QString file, CoreRomHeader header, Core
|
||||
void RomBrowserWidget::timerEvent(QTimerEvent* event)
|
||||
{
|
||||
this->killTimer(event->timerId());
|
||||
this->setCurrentWidget(this->currentViewWidget);
|
||||
this->stackedWidget->setCurrentWidget(this->currentViewWidget);
|
||||
this->searchWidget->setVisible(this->showSearchWidget);
|
||||
}
|
||||
|
||||
void RomBrowserWidget::on_DoubleClicked(const QModelIndex& index)
|
||||
@@ -624,9 +674,8 @@ void RomBrowserWidget::on_DoubleClicked(const QModelIndex& index)
|
||||
|
||||
void RomBrowserWidget::customContextMenuRequested(QPoint position)
|
||||
{
|
||||
QStandardItemModel* model = this->getCurrentModel();
|
||||
QAbstractItemView* view = this->getCurrentModelView();
|
||||
if (view == nullptr || model == nullptr)
|
||||
QAbstractItemView* view = this->getCurrentModelView();
|
||||
if (view == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -713,20 +762,20 @@ void RomBrowserWidget::generateColumnsMenu(void)
|
||||
void RomBrowserWidget::generatePlayWithDiskMenu(void)
|
||||
{
|
||||
QAction* playGameWithAction;
|
||||
QStandardItemModel* model = this->getCurrentModel();
|
||||
QPair<QStandardItemModel*, QSortFilterProxyModel*> model = this->getCurrentModel();
|
||||
RomBrowserModelData modelData;
|
||||
int count = 0;
|
||||
|
||||
this->menu_PlayGameWithDisk->clear();
|
||||
|
||||
if (model == nullptr)
|
||||
if (model.first == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < model->rowCount(); i++)
|
||||
for (int i = 0; i < model.first->rowCount(); i++)
|
||||
{
|
||||
modelData = model->item(i)->data().value<RomBrowserModelData>();
|
||||
modelData = model.first->item(i)->data().value<RomBrowserModelData>();
|
||||
if (modelData.type == CoreRomType::Disk)
|
||||
{
|
||||
if (count == 0)
|
||||
@@ -736,8 +785,8 @@ void RomBrowserWidget::generatePlayWithDiskMenu(void)
|
||||
}
|
||||
|
||||
playGameWithAction = new QAction(this);
|
||||
playGameWithAction->setText(model->item(i)->text());
|
||||
playGameWithAction->setData(model->item(i)->data());
|
||||
playGameWithAction->setText(model.first->item(i)->text());
|
||||
playGameWithAction->setData(model.first->item(i)->data());
|
||||
this->menu_PlayGameWithDisk->addAction(playGameWithAction);
|
||||
|
||||
// only add 10 disks to menu,
|
||||
@@ -794,6 +843,19 @@ void RomBrowserWidget::generateStateMenu(void)
|
||||
this->menu_PlayGameWithSlot->setDisabled(this->menu_PlayGameWithSlot->isEmpty());
|
||||
}
|
||||
|
||||
void RomBrowserWidget::on_searchWidget_SearchTextChanged(const QString& text)
|
||||
{
|
||||
// TODO: I should really make a custom data
|
||||
// model at this point to save memory & CPU cycles...
|
||||
this->listViewProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
this->listViewProxyModel->setFilterWildcard(text);
|
||||
this->listViewProxyModel->setFilterKeyColumn(0);
|
||||
|
||||
this->gridViewProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
this->gridViewProxyModel->setFilterWildcard(text);
|
||||
this->gridViewProxyModel->setFilterKeyColumn(0);
|
||||
}
|
||||
|
||||
void RomBrowserWidget::on_listViewWidget_sortIndicatorChanged(int logicalIndex, Qt::SortOrder sortOrder)
|
||||
{
|
||||
CoreSettingsSetValue(SettingsID::RomBrowser_ListViewSortSection, logicalIndex);
|
||||
@@ -910,8 +972,8 @@ void RomBrowserWidget::on_RomBrowserThread_RomsFound(QList<RomSearcherThreadData
|
||||
void RomBrowserWidget::on_RomBrowserThread_Finished(bool canceled)
|
||||
{
|
||||
// sort data
|
||||
this->listViewModel->sort(this->listViewSortSection, (Qt::SortOrder)this->listViewSortOrder);
|
||||
this->gridViewModel->sort(0, Qt::SortOrder::AscendingOrder);
|
||||
this->listViewProxyModel->sort(this->listViewSortSection, (Qt::SortOrder)this->listViewSortOrder);
|
||||
this->gridViewProxyModel->sort(0, Qt::SortOrder::AscendingOrder);
|
||||
|
||||
// retrieve column settings
|
||||
std::vector<int> columnSizes = CoreSettingsGetIntListValue(SettingsID::RomBrowser_ColumnSizes);
|
||||
@@ -1007,7 +1069,7 @@ void RomBrowserWidget::on_RomBrowserThread_Finished(bool canceled)
|
||||
|
||||
if (this->listViewModel->rowCount() == 0)
|
||||
{
|
||||
this->setCurrentWidget(this->emptyWidget);
|
||||
this->stackedWidget->setCurrentWidget(this->emptyWidget);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1020,7 +1082,8 @@ void RomBrowserWidget::on_RomBrowserThread_Finished(bool canceled)
|
||||
return;
|
||||
}
|
||||
|
||||
this->setCurrentWidget(this->currentViewWidget);
|
||||
this->stackedWidget->setCurrentWidget(this->currentViewWidget);
|
||||
this->searchWidget->setVisible(this->showSearchWidget);
|
||||
}
|
||||
|
||||
void RomBrowserWidget::on_Action_PlayGame(void)
|
||||
@@ -1144,9 +1207,9 @@ void RomBrowserWidget::on_Action_SetCoverImage(void)
|
||||
QFileInfo sourceFileInfo;
|
||||
QString coverFile;
|
||||
|
||||
QStandardItemModel* model = this->getCurrentModel();
|
||||
QAbstractItemView* view = this->getCurrentModelView();
|
||||
if (model == nullptr || view == nullptr)
|
||||
QPair<QStandardItemModel*, QSortFilterProxyModel*> model = this->getCurrentModel();
|
||||
QAbstractItemView* view = this->getCurrentModelView();
|
||||
if (model.first == nullptr || model.second == nullptr || view == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1165,9 +1228,9 @@ void RomBrowserWidget::on_Action_SetCoverImage(void)
|
||||
// retrieve file info
|
||||
sourceFileInfo = QFileInfo(sourceFile);
|
||||
|
||||
QModelIndex index = view->currentIndex();
|
||||
QStandardItem* item = model->item(index.row(), index.column());
|
||||
RomBrowserModelData data = model->itemData(index).last().value<RomBrowserModelData>();
|
||||
QModelIndex index = model.second->mapToSource(view->currentIndex());
|
||||
QStandardItem* item = model.first->item(index.row(), index.column());
|
||||
RomBrowserModelData data = model.first->itemData(index).last().value<RomBrowserModelData>();
|
||||
|
||||
// construct new file name (for the cover)
|
||||
QString newFileName = this->coversDirectory;
|
||||
@@ -1203,16 +1266,16 @@ void RomBrowserWidget::on_Action_SetCoverImage(void)
|
||||
|
||||
void RomBrowserWidget::on_Action_RemoveCoverImage(void)
|
||||
{
|
||||
QStandardItemModel* model = this->getCurrentModel();
|
||||
QPair<QStandardItemModel*, QSortFilterProxyModel*> model = this->getCurrentModel();
|
||||
QAbstractItemView* view = this->getCurrentModelView();
|
||||
if (model == nullptr || view == nullptr)
|
||||
if (model.first == nullptr || model.second == nullptr || view == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QModelIndex index = view->currentIndex();
|
||||
QStandardItem* item = model->item(index.row(), index.column());
|
||||
RomBrowserModelData data = model->itemData(index).last().value<RomBrowserModelData>();
|
||||
QModelIndex index = model.second->mapToSource(view->currentIndex());
|
||||
QStandardItem* item = model.first->item(index.row(), index.column());
|
||||
RomBrowserModelData data = model.first->itemData(index).last().value<RomBrowserModelData>();
|
||||
QString coverFile;
|
||||
|
||||
if (!data.coverFile.isEmpty() && QFile::exists(data.coverFile))
|
||||
|
||||
@@ -16,18 +16,22 @@
|
||||
#include "RomBrowserListViewWidget.hpp"
|
||||
#include "RomBrowserGridViewWidget.hpp"
|
||||
#include "RomBrowserLoadingWidget.hpp"
|
||||
#include "RomBrowserSearchWidget.hpp"
|
||||
#include "RomBrowserEmptyWidget.hpp"
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStandardItemModel>
|
||||
#include <QStackedWidget>
|
||||
#include <QGridLayout>
|
||||
#include <QListWidget>
|
||||
#include <QHeaderView>
|
||||
#include <QTableView>
|
||||
#include <QLineEdit>
|
||||
#include <QAction>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QMenu>
|
||||
#include <QPair>
|
||||
#include <QMap>
|
||||
|
||||
// forward declaration of internal struct
|
||||
@@ -37,7 +41,7 @@ namespace UserInterface
|
||||
{
|
||||
namespace Widget
|
||||
{
|
||||
class RomBrowserWidget : public QStackedWidget
|
||||
class RomBrowserWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -53,17 +57,24 @@ class RomBrowserWidget : public QStackedWidget
|
||||
void ShowGrid(void);
|
||||
|
||||
void SetGridViewUniformSizes(bool value);
|
||||
void SetToggleSearch(void);
|
||||
|
||||
QMap<QString, CoreRomSettings> GetModelData(void);
|
||||
|
||||
private:
|
||||
QStackedWidget* stackedWidget = nullptr;
|
||||
Widget::RomBrowserEmptyWidget* emptyWidget = nullptr;
|
||||
Widget::RomBrowserLoadingWidget* loadingWidget = nullptr;
|
||||
|
||||
Widget::RomBrowserListViewWidget* listViewWidget = nullptr;
|
||||
QStandardItemModel* listViewModel = nullptr;
|
||||
QSortFilterProxyModel* listViewProxyModel = nullptr;
|
||||
Widget::RomBrowserGridViewWidget* gridViewWidget = nullptr;
|
||||
QStandardItemModel* gridViewModel = nullptr;
|
||||
QSortFilterProxyModel* gridViewProxyModel = nullptr;
|
||||
|
||||
Widget::RomBrowserSearchWidget* searchWidget = nullptr;
|
||||
bool showSearchWidget = false;
|
||||
|
||||
QWidget* currentViewWidget = nullptr;
|
||||
|
||||
@@ -96,7 +107,7 @@ class RomBrowserWidget : public QStackedWidget
|
||||
|
||||
QString coversDirectory;
|
||||
|
||||
QStandardItemModel* getCurrentModel(void);
|
||||
QPair<QStandardItemModel*, QSortFilterProxyModel*> getCurrentModel(void);
|
||||
QAbstractItemView* getCurrentModelView(void);
|
||||
bool getCurrentData(RomBrowserModelData& data);
|
||||
|
||||
@@ -116,6 +127,8 @@ class RomBrowserWidget : public QStackedWidget
|
||||
void generatePlayWithDiskMenu(void);
|
||||
void generateStateMenu(void);
|
||||
|
||||
void on_searchWidget_SearchTextChanged(const QString& text);
|
||||
|
||||
void on_listViewWidget_sortIndicatorChanged(int logicalIndex, Qt::SortOrder sortOrder);
|
||||
void on_listViewWidget_sectionResized(int logicalIndex, int oldWidth, int newWidth);
|
||||
void on_listViewWidget_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
|
||||
|
||||
Reference in New Issue
Block a user