Compare commits

...
118 Commits
Author SHA1 Message Date
Tyler Wildingandrefractionpcsx2 7d9ad6daab ci: only fetch tags for releases 2023-07-20 08:38:05 +01:00
Tyler Wildingandrefractionpcsx2 822b166753 ci: one workflow to fix caching issue and simplify releases 2023-07-20 08:38:05 +01:00
PCSX2 BotandConnor McLaughlin 8fad768d39 Qt: Update Base Translation 2023-07-20 12:27:09 +10:00
TellowKrinkleandConnor McLaughlin d46b8390f1 Qt:Mac: Add Qt mac application menu strings
The official Qt translations don't match the rest of macOS for some reason
2023-07-19 13:46:40 +10:00
TellowKrinkleandConnor McLaughlin 4262715590 Qt:Mac: Add CJK font paths 2023-07-19 13:46:40 +10:00
TellowKrinkleandConnor McLaughlin 9818446c7d Qt: Default to system language 2023-07-19 13:46:40 +10:00
TellowKrinkleandConnor McLaughlin 22682e4150 Qt:Mac: Add CFBundleLocalizations tag 2023-07-19 13:46:40 +10:00
TellowKrinkleandConnor McLaughlin 1d63779b7d Qt:Mac: Enable translations 2023-07-19 13:46:40 +10:00
SilentandConnor McLaughlin c82f800794 FileSystem: Use _filelengthi64 to get the file size on Windows 2023-07-19 13:45:46 +10:00
lightningterror d96dea49bf R3000A: Fix Wsign-compare warning. 2023-07-19 03:03:44 +02:00
lightningterror c574c3e08c GS-vk: Fix Wunused-variable warning. 2023-07-19 03:03:44 +02:00
lightningterror e7e6f765b5 GS-hw: Fix Wreorder-ctor warnings. 2023-07-19 03:03:44 +02:00
Silentandrefractionpcsx2 240586875c FileSystem: Make FILE* unique pointers use a functor deleter 2023-07-18 17:24:34 +01:00
PCSX2 Botandlightningterror d6c5903569 PAD: Update to latest controller database. 2023-07-17 23:13:37 +02:00
JordanTheToasterandrefractionpcsx2 55da5cc397 GameDB: Lego Drome Racers blackscreen fix
Fixes lego drome racers having a black screen in hardware mode.
2023-07-17 19:56:32 +01:00
Connor McLaughlinandGitHub 943359e328 CI: Fix incorrect commit message in base translation update 2023-07-17 23:31:02 +10:00
PCSX2 BotandConnor McLaughlin 92c54cc1f8 PAD: Update Base Translation 2023-07-17 23:28:02 +10:00
Stenzek 6ec0b44487 CI: Add daily base translation update 2023-07-17 23:24:37 +10:00
charlesthobeandConnor McLaughlin 85d2ca626f Common: Linux: fix potentially unsafe screensaver inhibitor 2023-07-17 20:11:32 +10:00
solid1353andConnor McLaughlin 68865a2bca Debugger/MemorySearch: search for byte array instead of converting byte array to string 2023-07-17 19:29:39 +10:00
solid1353andConnor McLaughlin 8362e6f435 Debugger Memory Search: add Array of byte type 2023-07-17 19:29:39 +10:00
JordanTheToasterandConnor McLaughlin 3804a58729 GameDB: Naruto Ultimate Ninja Fixes
Fixes for spikey SPS on characters with VU1 clamp extra plus sign.
2023-07-17 19:19:37 +10:00
TellowKrinkleandConnor McLaughlin fbb67a6ee9 Qt:Translation: Remove mnemonics from toolbar strings
They're not useful, and may make translators think they need to add extra characters in parentheses for the mnemonics to be placed on
2023-07-17 19:17:53 +10:00
TellowKrinkleandTellowKrinkle 19d8b59ca7 FSUI: Switch Secondary Light/Dark colors with Strong/Weak
Strong has higher than contrast against the background than the base color (lighter on dark theme, darker on light theme), weak is the opposite.
Previously the light color increased contrast in dark themes, but descreased contrast in light themes, which meant it wasn't suitable for the same things in the respective themes
2023-07-16 22:59:16 -05:00
TellowKrinkleandTellowKrinkle 7ca726492f FSUI: Remove PushSecondaryColor
It's not being used, and this way I can rename some colors to better describe our usage of them
2023-07-16 22:59:16 -05:00
TellowKrinkleandTellowKrinkle 96a43ca254 GS:MTL: Don't dispatch 0-element imgui draws
Metal validation doesn't like them
2023-07-16 22:59:16 -05:00
TellowKrinkleandTellowKrinkle bf34eb32ed FSUI: Fix background colors in light mode 2023-07-16 22:59:16 -05:00
TellowKrinkleandTellowKrinkle 433612cde0 Qt:Mac: Make sure settings windows are raised when requested 2023-07-16 22:12:13 -05:00
lightningterror 807db91140 GS: Bump shader cache version. 2023-07-16 12:45:42 +02:00
lightningterror 7791809224 GS-metal: Fix initialization shader warnings. 2023-07-16 12:45:42 +02:00
lightningterror 9b3d31cd47 GS-vk: Fix initialization shader warnings. 2023-07-16 12:45:42 +02:00
lightningterror 65a3a97ab2 GS-d3d: Fix initialization shader warnings. 2023-07-16 12:45:42 +02:00
lightningterror e3593574b0 GS-ogl: Fix initialization shader warnings. 2023-07-16 12:45:42 +02:00
refractionpcsx2 f81d391546 GS/HW: Use draw for valid height, preload cached size 2023-07-15 23:09:35 +01:00
JordanTheToasterandrefractionpcsx2 bd3b00793a GameDB: Various fixes
Fixes for missing sun in Ford Racing 2 and vertical lines in Digi World Collaboration SP.
2023-07-15 21:26:12 +01:00
kamfretozandConnor McLaughlin 757a72fb57 Qt: More icon treatments 2023-07-15 20:46:19 +10:00
kamfretozandConnor McLaughlin fbbec480af Qt: Add a reminder to New Input Profile dialog 2023-07-15 20:46:19 +10:00
Stenzek ba3b43c66c Qt: Show cheats/patches for all CRCs in game properties
Not just the primary/disc ELF.

Also get rid of duplicates from the list.
2023-07-15 12:08:53 +10:00
refractionpcsx2 e040b83b2c GS: Fix debug builds 2023-07-15 00:48:33 +01:00
refractionpcsx2 76f4a5b2fe UI: Add controller binding tooltips for additional controls 2023-07-14 13:48:24 +01:00
TellowKrinkleandlightningterror 4f4b9956b3 GS: Reduce cutoff for primid destination alpha 2023-07-14 13:44:08 +02:00
TellowKrinkleandlightningterror ba37a0f3a9 GS:MTL: Allow disabling fbfetch
For testing and stuff
2023-07-14 13:44:08 +02:00
AliandConnor McLaughlin d4acb95d7c Flatpak: Add the talk-name flag for org.freedesktop.Screensaver
This brings the functionality in line with the old Flatpak release. This allows PCSX2 to inhibit the screensaver or screen blanking without needing to touch the mouse/keyboard while the VM is running.
2023-07-14 14:53:05 +10:00
Stenzek 2887baefb8 GS/DX12: Combine GSDevice12 and D3D12Context 2023-07-14 12:21:51 +10:00
Stenzek 9678bf1e2f GS/Vulkan: Combine GSDeviceVK and VKContext
Less indirection.
2023-07-14 12:21:51 +10:00
Stenzek e2fc68ff2d GS/Vulkan: Use VK_EXT_attachment_feedback_loop_layout when supported 2023-07-13 22:35:34 +10:00
refractionpcsx2 4a7b641bc3 GameDB: Add HPO Special for LEGO Batman 2023-07-12 10:28:28 +01:00
refractionpcsx2 719b83bf42 GS: Only clamp tex coords to bounds in hardware. 2023-07-12 10:18:16 +01:00
Goatman13andrefractionpcsx2 f201a2e5dd GameDB: Fix patch for Michigan: Report from Hell 2023-07-11 20:09:29 +01:00
refractionpcsx2 fd6f47f5ca GS/HW: Tempfix alignment problem with texture replacements 2023-07-11 16:07:45 +01:00
Stenzekandrefractionpcsx2 8524fbbaf9 GS/HW: Decompress replacement textures to get alpha min/max 2023-07-11 13:30:47 +01:00
Stenzekandrefractionpcsx2 a371c5b7d0 GS/HW: Calculate alpha values for sources 2023-07-11 02:01:57 +01:00
refractionpcsx2 ef7ce4dfc8 GS/HW: Don't use DATE_one when alpha 128 (1.0) is masked 2023-07-11 02:01:57 +01:00
refractionpcsx2 189f6fa2a3 GS/HW: Calculate target alpha min/max 2023-07-11 02:01:57 +01:00
refractionpcsx2 472f4922bd GS/HW: Improve double half clear for strange strip drawing 2023-07-11 02:01:35 +01:00
SestainandGitHub 8ba2f342df OSD: Input recording overlap fixed (#9211) 2023-07-11 02:01:17 +01:00
JordanTheToasterandrefractionpcsx2 5d6b9d25bd Readme: Update OS requirements
Updates OS requirements to be in line with what we currently support and or the latest Windows in support at the time.
2023-07-10 18:19:02 +01:00
JordanTheToasterandrefractionpcsx2 1231499aaa GameDB: Various fixes
A lot of missing demo serials and some name fixes that bugged me.
2023-07-10 18:19:02 +01:00
Stenzek 9c4788432d GS/HW: Avoid tex-is-fb when incompatible clamp is used 2023-07-10 22:19:47 +10:00
lightningterrorandGitHub 4ded2caa0b GS-ogl: Comment out intel vendor set. (#9203)
Fixes Wunused-but-set-variable warning.
2023-07-10 07:30:15 +02:00
Stenzek 494afb9d43 Linux/CI: Switch to Ubuntu 22.04 and linuxdeploy 2023-07-10 14:16:41 +10:00
refractionpcsx2 c994e4828d Build: Restore old filenames temporarily 2023-07-09 23:18:43 +01:00
refractionpcsx2 e50f12a925 Updater: Make it not care about the Qt extension 2023-07-09 23:18:43 +01:00
refractionpcsx2 df75d70df4 VIF: Add missing internal DMA stall flag 2023-07-09 22:03:23 +01:00
Stenzekandrefractionpcsx2 c5aa04d4eb CI: Remove redundant GUI variables
And adjust release filenames.
2023-07-09 21:14:23 +01:00
Blackbird88andrefractionpcsx2 81ae1ce362 GameDB: NFS UG1 Blending 2023-07-09 17:10:24 +01:00
JordanTheToasterandrefractionpcsx2 e1921e660d GameDB: Various fixes
Fixes for Fifa Street 2 corrupted graphics and Onimusha Warlords.
2023-07-09 16:04:30 +01:00
KrossXandrefractionpcsx2 32aa24f6fd GS: Add fancy downsampling shaders. 2023-07-09 14:04:06 +01:00
refractionpcsx2 7fbc63b8e8 EE/IOP Sync: Optimize EE/IOP sync for more intelligent syncing 2023-07-09 13:53:00 +01:00
refractionpcsx2 443adcdd5b EE/IOP Sync: Calculate IOP interrupt delta after running IOP 2023-07-09 13:53:00 +01:00
refractionpcsx2 05b064d513 IOP/Counters: Fix off by 1 error 2023-07-09 13:53:00 +01:00
refractionpcsx2 b327033333 Counters: Process overflow before Target in case of Target = 0 2023-07-09 13:53:00 +01:00
refractionpcsx2 36c9b68b6c EE/Counters: Update HBlank before recalculating Next Event 2023-07-09 13:53:00 +01:00
refractionpcsx2 7d8d16091e EE/DMA: Try to avoid very small DMA loops 2023-07-09 13:53:00 +01:00
refractionpcsx2 c1c6bde429 Counters: Only schedule an EE interruption if they interrupt 2023-07-09 13:53:00 +01:00
Stenzek 8f0901e7a5 VMManager: Flag BIOS missing error for translation 2023-07-09 21:52:02 +10:00
Stenzek 6edba3820b GameList: Don't repeatedly scan invalid files every startup 2023-07-09 21:52:02 +10:00
Stenzek db1e1bcc1f CDVD: Rewrite ISO parser 2023-07-09 21:52:02 +10:00
Stenzek 51aeaeb508 CDVD: Ignore version information when loading ELF 2023-07-09 21:52:02 +10:00
Stenzek dcd0a1f002 GS/HW: Add render fix for complex moves
And use it to fix Growlanser.
2023-07-09 17:42:21 +10:00
Stenzek 819b61937f GS: Slim down GSState.h includes 2023-07-09 15:34:59 +10:00
Stenzek 9da7628083 GS: Move PCRTC function definitions to GSState.cpp 2023-07-09 15:34:59 +10:00
Ziemasandrefractionpcsx2 c5f47a8db3 mipsanalyst: sign extend 32 bit regs 2023-07-08 18:51:36 +01:00
Stenzek c2786b91ce GS/OGL: Fix sampling from cleared targets
And merge GLLoader into GSDeviceOGL while we're at it.
2023-07-09 00:46:52 +10:00
Stenzek 4290c16997 GS/DX11: Fix sampling from cleared targets 2023-07-09 00:46:52 +10:00
Stenzek 475e90b654 GS/HW: Don't invalidate buffers on partial clear 2023-07-09 00:45:16 +10:00
Stenzek ebb291e06d GS/DX12: Fix targets getting stuck undirtied 2023-07-08 14:33:21 +10:00
Stenzek a2c9069dda GameDB: Add eeCycleRate option
For those pesky games with cache/DMA issues only!
2023-07-08 14:28:30 +10:00
Stenzek 48cfe9ca73 Config: Make SpeedHack a scoped enum
And get rid of the redundant "SpeedHack" suffix on all values.
2023-07-08 14:28:30 +10:00
Stenzek b53e9856b8 USB/usb-mic: Fix buffer handling
- RingBuffer would store a size of zero if you wrote the entire
   the entire buffer in one call.

 - ResetBuffers() should be called before starting the stream,
   otherwise you risk a race where the callback happens before
   the buffer is allocated.

 - Fix incorrect latency being passed into Cubeb.
2023-07-08 14:27:51 +10:00
Stenzek 20420da326 Input/SDL: Don't pass stdio handle to SDL
Apparently on cmake, SDL isn't compiled with stdio support...
2023-07-08 14:21:02 +10:00
bitiutsmandrefractionpcsx2 9162f176a2 GameDB: Fix names 2023-07-07 20:32:36 +01:00
JordanTheToasterandrefractionpcsx2 3c140c2ef4 GameDB: NFS U2 Name fix
Quick fix for an incorrect name for NFS U2
2023-07-07 14:10:17 +01:00
JordanTheToasterandrefractionpcsx2 511d37e7c3 GameDB: X Squad Fixes
Fixes for crusty textures by using Full mipmapping and trilinear filtering.
2023-07-07 12:55:50 +01:00
Stenzek 10a5ea2a29 3rdparty/SDL2: Bump to v2.28.1 2023-07-07 21:06:53 +10:00
Stenzek c049f6814b Input/SDL: Load controller DB after init
Tries to lock a non-existant mutex on Windows otherwise.
2023-07-07 21:06:53 +10:00
Sanjay GovindandConnor McLaughlin 0716abdbf8 USB: Fix DJ Hero Turntable Labels 2023-07-07 17:25:46 +10:00
Stenzek 989f2bbbb0 GameDB: Enable preload frame for Rocky Legends 2023-07-07 12:35:19 +10:00
Stenzekandrefractionpcsx2 45c564749c GS/HW: Improve striped double clear detection
Co-authored-by: refractionpcsx2 <refraction@gmail.com>
2023-07-07 12:35:19 +10:00
Stenzek a62737b244 GS/HW: Be more strict with double half clear detection
And less strict with letting depth mem clears go through.
2023-07-07 12:35:19 +10:00
Stenzek 1fa3111e67 Qt: Sync video capture state 2023-07-07 12:34:58 +10:00
Stenzek 0e78f3f3bc GS: Improve capture robustness
Automatically restart capture on renderer or hardware reset.
2023-07-07 12:34:58 +10:00
Berylskidandrefractionpcsx2 6bf07086a0 GameDB: Various fixes for Armored Core games 2023-07-07 01:41:18 +01:00
JordanTheToasterandrefractionpcsx2 b3f8f4e8ec GameDB: Some fixes
Fixes for Redump lying to me and for a black screen in Giant Robot The Animation.
2023-07-07 00:58:16 +01:00
lightningterror 65ee7e82aa gitignore: Remove no longer used files.
wx era.
2023-07-06 13:16:49 +02:00
lightningterror c78f3b4e24 Savestate: Fix Wsign-compare warning. 2023-07-06 12:58:48 +02:00
lightningterror 51aa7c8ecf GS-hw: Fix warnings.
Wunused-variable,
Wunused-lambda-capture.
2023-07-06 12:58:48 +02:00
Stenzek 64ab92ced6 Qt: Update base translation 2023-07-06 12:30:35 +10:00
Stenzek 8f9f351940 Qt: Don't allow creation of memory cards with invalid names 2023-07-06 12:30:35 +10:00
Stenzek a9a1af7307 FileSystem: Add IsValidFileName()
And associated tests.
2023-07-06 12:30:35 +10:00
Stenzek 5057dfedba Qt: Rename CreateMemoryCardDialog to MemoryCardCreateDialog
Consistency.
2023-07-06 12:30:35 +10:00
Stenzek ecabadbf95 CMake: Use FindWayland from ECM
Fixes previously-broken FindWayland.cmake which had local modifications
that prevented PCSX2 from being compiled on OpenSUSE.
2023-07-06 12:30:05 +10:00
Stenzek 97630039d8 CMake: Bump minimum version to 3.16
Required for ECM FindWayland.
2023-07-06 12:30:05 +10:00
forrvalhallaandrefractionpcsx2 e7f1178469 GameDB: Various fixes
GameDB: Various fixes
2023-07-06 00:42:08 +01:00
Stenzek 87245ef978 GameDB: Add auto flush for Okage 2023-07-05 12:19:58 +10:00
Stenzek 455aa28724 GS/HW: Use minimum UV as a channel shuffle heuristic
Used by Ape Escape 2, Everybody's Tennis/Golf, Okage, and Valkyrie
Profile 2.
2023-07-05 12:19:58 +10:00
JordanTheToasterandrefractionpcsx2 92f70228c9 GameDB: Various fixes 2023-07-04 11:56:04 +01:00
Stenzek 5fa862b346 GS: Fix uninitialized data in deinterlacing 2023-07-04 19:45:48 +10:00
199 changed files with 10368 additions and 8734 deletions
@@ -0,0 +1,28 @@
name: 🌎 Update Base Translation
on:
schedule:
- cron: "0 0 * * *" # Every day at 12am UTC.
workflow_dispatch: # As well as manually.
jobs:
update:
if: github.repository == 'PCSX2/pcsx2'
name: "Update Base Translation"
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Update Base Translation
run: ./.github/workflows/scripts/common/update_base_translation.sh
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
with:
title: "Qt: Update Base Translation"
commit-message: "Qt: Update Base Translation"
committer: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
author: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
body: "Daily update of base translation sources."
branch: update-base-translation
delete-branch: true
+9 -10
View File
@@ -28,14 +28,14 @@ on:
required: false
type: boolean
default: false
detail:
required: false
type: string
default: ""
patches_url:
patchesUrl:
required: false
type: string
default: https://github.com/PCSX2/pcsx2_patches/releases/latest/download
fetchTags:
required: false
type: boolean
default: false
jobs:
build_linux:
@@ -51,9 +51,9 @@ jobs:
# Hackity hack. When running the workflow on a schedule, we don't have the tag,
# it doesn't fetch tags, therefore we don't get a version. So grab them manually.
# actions/checkout elides tags, fetch them primarily for releases
- name: Fetch tags
if: inputs.publish == true
id: fetch-tags
if: ${{ inputs.fetchTags }}
run: git fetch --tags --no-recurse-submodules
- name: Prepare Artifact Metadata
@@ -61,7 +61,6 @@ jobs:
shell: bash
env:
OS: linux
GUI_FRAMEWORK: QT
BUILD_SYSTEM: flatpak
ARCH: ${{ inputs.platform }}
EVENT_NAME: ${{ github.event_name }}
@@ -78,7 +77,7 @@ jobs:
- name: Download patches
run: |
cd bin/resources
aria2c -Z "${{ inputs.patches_url }}/patches.zip"
aria2c -Z "${{ inputs.patchesUrl }}/patches.zip"
- name: Generate AppStream XML
run: |
@@ -98,7 +97,7 @@ jobs:
branch: ${{ inputs.branch }}
cache: true
restore-cache: true
cache-key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} flatpak ${{ hashFiles('.github/workflows/scripts/linux/flatpak/**/*.json') }}
cache-key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} flatpak ${{ hashFiles('.github/workflows/scripts/linux/flatpak/**/*.json') }}
- name: Commit screenshots to OSTree
run: |
+2 -2
View File
@@ -14,7 +14,7 @@ jobs:
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Qt"
jobName: "AppImage Build"
compiler: clang
cmakeflags: ""
buildAppImage: true
@@ -24,7 +24,7 @@ jobs:
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
uses: ./.github/workflows/linux_build_flatpak.yml
with:
jobName: "Qt"
jobName: "Flatpak Build"
compiler: clang
cmakeflags: ""
publish: false
+16 -8
View File
@@ -9,7 +9,7 @@ on:
os:
required: false
type: string
default: ubuntu-20.04
default: ubuntu-22.04
platform:
required: false
type: string
@@ -28,10 +28,14 @@ on:
required: false
type: string
default: ""
patches_url:
patchesUrl:
required: false
type: string
default: https://github.com/PCSX2/pcsx2_patches/releases/latest/download
fetchTags:
required: false
type: boolean
default: false
jobs:
build_linux:
@@ -52,12 +56,16 @@ jobs:
with:
submodules: recursive
# actions/checkout elides tags, fetch them primarily for releases
- name: Fetch Tags
if: ${{ inputs.fetchTags }}
run: git fetch --tags --no-recurse-submodules
- name: Prepare Artifact Metadata
id: artifact-metadata
shell: bash
env:
OS: linux
GUI_FRAMEWORK: QT
ARCH: ${{ inputs.platform }}
EVENT_NAME: ${{ github.event_name }}
PR_TITLE: ${{ github.event.pull_request.title }}
@@ -87,7 +95,7 @@ jobs:
uses: actions/cache@v3
with:
path: ~/deps
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.gui }} deps ${{ hashFiles('.github/workflows/scripts/linux/build-dependencies-qt.sh') }}
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/linux/build-dependencies-qt.sh') }}
- name: Build Dependencies
if: steps.cache-deps.outputs.cache-hit != 'true'
@@ -96,7 +104,7 @@ jobs:
- name: Download patches
run: |
cd bin/resources
aria2c -Z "${{ inputs.patches_url }}/patches.zip"
aria2c -Z "${{ inputs.patchesUrl }}/patches.zip"
- name: Generate CMake
env:
@@ -120,9 +128,9 @@ jobs:
env:
NAME: ${{ steps.artifact-metadata.outputs.artifact-name }}
run: |
.github/workflows/scripts/linux/appimage-qt.sh "$(realpath .)" "$(realpath ./build)" "$HOME/deps" "$NAME"
mkdir -p "$GITHUB_WORKSPACE"/ci-artifacts/
mv "${NAME}.AppImage" "$GITHUB_WORKSPACE"/ci-artifacts/
.github/workflows/scripts/linux/appimage-qt.sh "$(realpath .)" "$(realpath ./build)" "$HOME/deps" "$NAME"
mkdir -p "$GITHUB_WORKSPACE"/ci-artifacts/
mv "${NAME}.AppImage" "$GITHUB_WORKSPACE"/ci-artifacts/
- name: Upload artifact
if: inputs.buildAppImage == true
+16 -19
View File
@@ -10,17 +10,14 @@ on:
required: false
type: string
default: macos-13
platform:
required: false
type: string
default: x64
gui:
required: true
type: string
patches_url:
patchesUrl:
required: false
type: string
default: https://github.com/PCSX2/pcsx2_patches/releases/latest/download
fetchTags:
required: false
type: boolean
default: false
jobs:
build_macos:
@@ -42,6 +39,11 @@ jobs:
with:
submodules: recursive
# actions/checkout elides tags, fetch them primarily for releases
- name: Fetch Tags
if: ${{ inputs.fetchTags }}
run: git fetch --tags --no-recurse-submodules
- name: Use Xcode 14.3.1
run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
@@ -50,8 +52,6 @@ jobs:
shell: bash
env:
OS: macos
GUI_FRAMEWORK: ${{ inputs.gui }}
ARCH: ${{ inputs.platform }}
EVENT_NAME: ${{ github.event_name }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_NUM: ${{ github.event.pull_request.number }}
@@ -60,7 +60,7 @@ jobs:
- name: Install Packages
env:
PLATFORM: ${{ inputs.platform }}
PLATFORM: "x64"
HOMEBREW_NO_INSTALL_CLEANUP: 1
HOMEBREW_NO_ANALYTICS: 1
run: |
@@ -77,18 +77,16 @@ jobs:
uses: actions/cache@v3
with:
path: ~/deps
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.gui }} deps ${{ hashFiles('.github/workflows/scripts/macos/build-dependencies.sh') }}
key: ${{ inputs.os }} deps ${{ hashFiles('.github/workflows/scripts/macos/build-dependencies.sh') }}
- name: Build Dependencies
if: steps.cache-deps.outputs.cache-hit != 'true'
env:
GUI: ${{ inputs.gui }}
run: .github/workflows/scripts/macos/build-dependencies.sh
- name: Download patches
run: |
cd bin/resources
aria2c -Z "${{ inputs.patches_url }}/patches.zip"
aria2c -Z "${{ inputs.patchesUrl }}/patches.zip"
# -- SETUP CCACHE - https://cristianadam.eu/20200113/speeding-up-c-plus-plus-github-actions-using-ccache/
- name: Prepare ccache timestamp
@@ -99,8 +97,8 @@ jobs:
uses: actions/cache@v3
with:
path: .ccache
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.gui }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.gui }} ccache
key: ${{ inputs.os }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
restore-keys: ${{ inputs.os }} ccache
- name: Generate CMake Files
run: |
@@ -133,7 +131,6 @@ jobs:
done
- name: Run Tests
if: inputs.gui == 'Qt'
working-directory: build
run: make -j$(getconf _NPROCESSORS_ONLN) unittests
@@ -149,7 +146,7 @@ jobs:
mv build/pcsx2*/PCSX2.app "$APPNAME.app"
tar --options xz:compression-level=9 -cvJf "${{ steps.artifact-metadata.outputs.artifact-name }}.tar.xz" "$APPNAME.app"
mkdir ci-artifacts
cp "${{ steps.artifact-metadata.outputs.artifact-name }}.tar.xz" ci-artifacts/macOS-${{ inputs.gui }}.tar.xz
cp "${{ steps.artifact-metadata.outputs.artifact-name }}.tar.xz" ci-artifacts/macOS.tar.xz
- name: Upload Artifact
uses: actions/upload-artifact@v3
+1 -2
View File
@@ -14,6 +14,5 @@ jobs:
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
uses: ./.github/workflows/macos_build.yml
with:
jobName: "Qt"
gui: "Qt"
jobName: "MacOS Build"
secrets: inherit
+186
View File
@@ -0,0 +1,186 @@
# Whenever a commit is pushed to master (ideally via a pull-request!)
# this action will create the next release, which means:
# 1. tag master with the proper version
# 2. create a new draft release (pre-released if a nightly build)
# 3. add release notes
name: 🏭 Create Release
on:
push:
branches:
- master
# TODO - future work
# workflow_dispatch:
# inputs:
# isStable:
# description: 'Should it be a stable release?'
# required: true
# default: 'false'
# versionTag:
# description: 'The version to tag with'
# required: true
permissions:
contents: write
jobs:
cut-release:
if: github.repository == 'PCSX2/pcsx2'
runs-on: ubuntu-latest
name: "Create Tag and Release"
steps:
- uses: actions/checkout@v3
# Docs - https://github.com/mathieudutour/github-tag-action
- name: Bump Version and Push Tag
id: tag_version
uses: mathieudutour/github-tag-action@v6.1
with:
github_token: ${{ github.token }}
tag_prefix: v
default_bump: patch
# TODO - we could do this and remove the node.js script, but auto-generated notes only work
# with PRs -- not commits (determine how much we care).
# - name: Create Draft Release
# run: |
# echo "Creating release with tag - ${{ steps.tag_version.outputs.new_tag }}"
# gh release create ${{ steps.tag_version.outputs.new_tag }} --draft --generate-notes -title ${{ steps.tag_version.outputs.new_tag }}
- name: Generate Release Notes
env:
OWNER: PCSX2
REPO: pcsx2
GITHUB_TOKEN: ${{ github.token }}
COMMIT_SHA: ${{ github.SHA }}
run: |
cd ./.github/workflows/scripts/releases/generate-release-notes
npm ci
node index.js
mv ./release-notes.md ${GITHUB_WORKSPACE}/release-notes.md
- name: Create a GitHub Release
uses: softprops/action-gh-release@v1
if: steps.tag_version.outputs.new_tag
with:
body_path: ./release-notes.md
draft: true
prerelease: true
tag_name: ${{ steps.tag_version.outputs.new_tag }}
# Build Everything
# Linux
build_linux_qt:
if: github.repository == 'PCSX2/pcsx2'
needs:
- cut-release
name: "Linux"
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "AppImage Build"
compiler: clang
cmakeflags: ""
buildAppImage: true
fetchTags: true
secrets: inherit
build_linux_flatpak:
if: github.repository == 'PCSX2/pcsx2'
needs:
- cut-release
name: "Linux"
uses: ./.github/workflows/linux_build_flatpak.yml
with:
jobName: "Flatpak Build"
compiler: clang
cmakeflags: ""
branch: "stable"
publish: false
fetchTags: true
secrets: inherit
# Windows
build_windows_qt:
if: github.repository == 'PCSX2/pcsx2'
needs:
- cut-release
name: "Windows"
uses: ./.github/workflows/windows_build_qt.yml
with:
jobName: "Windows Build"
configuration: CMake
buildSystem: cmake
cmakeFlags: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl
fetchTags: true
secrets: inherit
# MacOS
build_macos_qt:
if: github.repository == 'PCSX2/pcsx2'
needs:
- cut-release
name: "MacOS"
uses: ./.github/workflows/macos_build.yml
with:
jobName: "MacOS Build"
fetchTags: true
secrets: inherit
# Upload the Artifacts
upload_artifacts:
if: github.repository == 'PCSX2/pcsx2'
needs:
- build_linux_flatpak
- build_linux_qt
- build_windows_qt
- build_macos_qt
name: "Upload Artifacts"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# actions/checkout elides tags, fetch them primarily for releases
- name: Fetch Tags
run: git fetch --tags --no-recurse-submodules
- name: Prepare Artifact Folder
run: mkdir ./ci-artifacts/
- uses: actions/download-artifact@v3
name: Download all Artifacts
with:
path: ./ci-artifacts/
- name: Display structure of downloaded files
run: ls ./ci-artifacts/
# Prepare artifacts, they are all zips from github!
- name: Prepare Artifacts
working-directory: ./ci-artifacts/
run: for d in *windows*/; do 7z a "${d}asset.7z" ./$d/*; done
# Artifact Naming:
# MacOS: PCSX2-<tag>-macOS-[additional hyphen seperated tags]
# Windows|Linux: PCSX2-<tag>-<windows|linux>-<32bit|64bit>--[additional hyphen seperated tags]
- name: Name and Upload the Release Assets
env:
GITHUB_TOKEN: ${{ github.token }}
SCAN_DIR: ${{ github.WORKSPACE }}/ci-artifacts
OUT_DIR: ${{ github.WORKSPACE }}/ci-artifacts/out
run: |
TAG_VAL=$(git tag --points-at HEAD)
echo "TAG_VAL=${TAG_VAL}"
gh release list --repo PCSX2/pcsx2
mkdir -p ${{ github.WORKSPACE }}/ci-artifacts/out
TAG_VAL=${TAG_VAL} python ./.github/workflows/scripts/releases/rename-release-assets.py
ls ${{ github.WORKSPACE }}/ci-artifacts/out
gh release upload "${TAG_VAL}" ${{ github.WORKSPACE }}/ci-artifacts/out/* --repo PCSX2/pcsx2 --clobber
- name: Publish Release
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
TAG_VAL=$(git tag --points-at HEAD)
echo "TAG_VAL=${TAG_VAL}"
gh release edit ${TAG_VAL} --draft=false --repo PCSX2/pcsx2
-71
View File
@@ -1,71 +0,0 @@
# Whenever a commit is pushed to master (ideally via a pull-request!)
# this action will create the next release, which means:
# 1. tag master with the proper version
# 2. create a new draft release (pre-released if a nightly build)
# 3. add release notes
name: 🏭 Create Release
on:
push:
branches:
- master
# TODO - future work
# workflow_dispatch:
# inputs:
# isStable:
# description: 'Should it be a stable release?'
# required: true
# default: 'false'
# versionTag:
# description: 'The version to tag with'
# required: true
jobs:
cut-release:
if: github.repository == 'PCSX2/pcsx2'
runs-on: ubuntu-latest
name: "Create Tag and Release"
steps:
- uses: actions/checkout@v3
# Docs - https://github.com/mathieudutour/github-tag-action
- name: Bump Version and Push Tag
id: tag_version
uses: mathieudutour/github-tag-action@v6.1
with:
# Workflows cannot trigger other workflows implicitly
# - https://github.community/t/github-actions-workflow-not-triggering-with-tag-push/17053/7
github_token: ${{ secrets.BOT_PAT }}
tag_prefix: v
default_bump: patch
# TODO - we could do this and remove the node.js script, but auto-generated notes only work
# with PRs -- not commits (determine how much we care).
# - name: Create Draft Release
# env:
# GITHUB_TOKEN: ${{ secrets.BOT_PAT }}
# run: |
# echo "Creating release with tag - ${{ steps.tag_version.outputs.new_tag }}"
# gh release create ${{ steps.tag_version.outputs.new_tag }} --draft --generate-notes -title ${{ steps.tag_version.outputs.new_tag }}
- name: Generate Release Notes
env:
OWNER: PCSX2
REPO: pcsx2
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMMIT_SHA: ${{ github.SHA }}
run: |
cd ./.github/workflows/scripts/releases/generate-release-notes
npm ci
node index.js
mv ./release-notes.md ${GITHUB_WORKSPACE}/release-notes.md
- name: Create a GitHub Release
uses: softprops/action-gh-release@v1
if: steps.tag_version.outputs.new_tag
with:
body_path: ./release-notes.md
draft: true
prerelease: true
tag_name: ${{ steps.tag_version.outputs.new_tag }}
-107
View File
@@ -1,107 +0,0 @@
name: 🏭 Release Pipeline
on:
push:
tags:
- v*
jobs:
# Build Everything
# Linux
build_linux_qt:
if: github.repository == 'PCSX2/pcsx2'
name: "Linux"
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Qt"
compiler: clang
cmakeflags: ""
buildAppImage: true
secrets: inherit
build_linux_flatpak:
if: github.repository == 'PCSX2/pcsx2'
name: "Linux"
uses: ./.github/workflows/linux_build_flatpak.yml
with:
jobName: "Flatpak"
compiler: clang
cmakeflags: ""
branch: "stable"
publish: false
secrets: inherit
# Windows
build_windows_qt:
if: github.repository == 'PCSX2/pcsx2'
name: "Windows"
uses: ./.github/workflows/windows_build_qt.yml
with:
jobName: Qt
configuration: CMake
buildSystem: cmake
cmakeFlags: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl
secrets: inherit
# MacOS
build_macos_qt:
if: github.repository == 'PCSX2/pcsx2'
name: "MacOS"
uses: ./.github/workflows/macos_build.yml
with:
jobName: "Qt"
gui: "Qt"
secrets: inherit
# Upload the Artifacts
upload_artifacts:
if: github.repository == 'PCSX2/pcsx2'
needs:
- build_linux_flatpak
- build_linux_qt
- build_windows_qt
- build_macos_qt
name: "Upload Artifacts"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Prepare Artifact Folder
run: mkdir ./ci-artifacts/
- uses: actions/download-artifact@v3
name: Download all Artifacts
with:
path: ./ci-artifacts/
- name: Display structure of downloaded files
run: ls ./ci-artifacts/
# Prepare artifacts, they are all zips from github!
- name: Prepare Artifacts
working-directory: ./ci-artifacts/
run: for d in *windows*/; do 7z a "${d}asset.7z" ./$d/*; done
# Artifact Naming:
# MacOS: PCSX2-<tag>-macOS-[additional hyphen seperated tags]
# Windows|Linux: PCSX2-<tag>-<windows|linux>-<32bit|64bit>--[additional hyphen seperated tags]
- name: Name and Upload the Release Assets
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.REF }}
SCAN_DIR: ${{ github.WORKSPACE }}/ci-artifacts
OUT_DIR: ${{ github.WORKSPACE }}/ci-artifacts/out
run: |
gh release list --repo PCSX2/pcsx2
mkdir -p ${{ github.WORKSPACE }}/ci-artifacts/out
python ./.github/workflows/scripts/releases/rename-release-assets.py
ls ${{ github.WORKSPACE }}/ci-artifacts/out
TAG_VAL=$(echo ${{ github.REF }} | awk -F'refs/tags/' '{print $2}')
gh release upload "${TAG_VAL}" ${{ github.WORKSPACE }}/ci-artifacts/out/* --repo PCSX2/pcsx2 --clobber
- name: Publish Release
env:
GITHUB_TOKEN: ${{ secrets.BOT_PAT }}
run: |
TAG_VAL=$(echo ${{ github.REF }} | awk -F'refs/tags/' '{print $2}')
gh release edit ${TAG_VAL} --draft=false --repo PCSX2/pcsx2
@@ -1,7 +1,7 @@
#!/bin/bash
# Artifact Naming Scheme:
# PCSX2-<OS>-<GUI>-[ARCH]-[SIMD]-[pr\[PR_NUM\]]-[title|sha\[SHA|PR_TITLE\]
# PCSX2-<OS>-Qt-[ARCH]-[SIMD]-[pr\[PR_NUM\]]-[title|sha\[SHA|PR_TITLE\]
# -- limited to 200 chars
# Outputs:
# - artifact-name
@@ -9,7 +9,6 @@
# Inputs as env-vars
# OS
# BUILD_SYSTEM
# GUI_FRAMEWORK
# ARCH
# SIMD
# EVENT_NAME
@@ -20,11 +19,12 @@
NAME=""
if [ "${OS}" == "macos" ]; then
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}"
# MacOS has combined binaries for x64 and ARM64.
NAME="PCSX2-${OS}-Qt"
elif [[ ("${OS}" == "windows" && "$BUILD_SYSTEM" != "cmake") ]]; then
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}-${ARCH}-${SIMD}"
NAME="PCSX2-${OS}-Qt-${ARCH}-${SIMD}"
else
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}-${ARCH}"
NAME="PCSX2-${OS}-Qt-${ARCH}"
fi
# Add cmake if used to differentate it from msbuild builds
@@ -0,0 +1,12 @@
#!/bin/bash
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
source "$SCRIPTDIR/../linux/functions.sh"
set -e
# While we use custom Qt builds for our releases, the Qt6 package will be good enough
# for just updating translations. Saves building it for this action alone.
retry_command sudo apt-get -y install qt6-l10n-tools
PATH=/usr/lib/qt6/bin:$PATH "$SCRIPTDIR/../../../../pcsx2-qt/Translations/update_en_translation.sh"
@@ -1,4 +0,0 @@
#!/bin/sh
APPDIR=$(dirname "$0")
exec "$APPDIR/usr/bin/pcsx2-qt" "$@"
+67 -228
View File
@@ -40,255 +40,94 @@ NAME=$4
BINARY=pcsx2-qt
APPDIRNAME=PCSX2.AppDir
STRIP=llvm-strip-12
STRIP=strip
declare -a SYSLIBS=(
"libaio.so.1"
"libz.so.1"
"libuuid.so.1"
"libapparmor.so.1"
"libblkid.so.1"
"libbsd.so.0"
"libdbus-1.so.3"
"libgcrypt.so.20"
"liblzma.so.5"
"libmount.so.1"
"libnsl.so.1"
"libpcre.so.3"
"libselinux.so.1"
"libsystemd.so.0"
"libudev.so.1"
"libwrap.so.0"
"libharfbuzz.so.0"
"libFLAC.so.8"
"libXau.so.6"
"libXcomposite.so.1"
"libXcursor.so.1"
"libXdamage.so.1"
"libXdmcp.so.6"
"libXext.so.6"
"libXfixes.so.3"
"libXi.so.6"
"libXinerama.so.1"
"libXrandr.so.2"
"libXrender.so.1"
"libXxf86vm.so.1"
"libasyncns.so.0"
"libcrypto.so.1.1"
"libjpeg.so.8"
"liblz4.so.1"
"libogg.so.0"
"libpcap.so.0.8"
"libpng16.so.16"
"libpulse.so.0"
"libsamplerate.so.0"
"libsndfile.so.1"
"libvorbis.so.0"
"libvorbisenc.so.2"
"libxcb.so.1"
"libxcb-cursor.so.0"
"libxcb-render.so.0"
"libxcb-shm.so.0"
"libxkbcommon.so.0"
"libxkbcommon-x11.so.0"
"pulseaudio/libpulsecommon-13.99.so"
"libasound.so.2"
"libfreetype.so.6"
"libpcre2-16.so.0"
"libexpat.so.1"
"libffi.so.7"
"libgraphite2.so.3"
"libresolv.so.2"
"libgpg-error.so.0"
"libpcre2-16.so.0"
"libpng16.so.16"
"libxcb-icccm.so.4"
"libxcb-image.so.0"
"libxcb-keysyms.so.1"
"libxcb-randr.so.0"
"libxcb-render.so.0"
"libxcb-render-util.so.0"
"libxcb-shape.so.0"
"libxcb-sync.so.1"
"libxcb-util.so.1"
"libxcb-xfixes.so.0"
"libxcb-xkb.so.1"
"libevdev.so.2"
"libgudev-1.0.so.0"
"libinput.so.10"
"libjpeg.so.8"
"libmtdev.so.1"
"libpng16.so.16"
"libudev.so.1"
"libuuid.so.1"
"libcurl.so.4"
"libnghttp2.so.14"
"libidn2.so.0"
"librtmp.so.1"
"libssh.so.4"
"libpsl.so.5"
"libssl.so.1.1"
"libnettle.so.7"
"libgnutls.so.30"
"libgssapi_krb5.so.2"
"libldap_r-2.4.so.2"
"liblber-2.4.so.2"
"libbrotlidec.so.1"
"libunistring.so.2"
"libhogweed.so.5"
"libgmp.so.10"
"libp11-kit.so.0"
"libtasn1.so.6"
"libkrb5.so.3"
"libk5crypto.so.3"
"libcom_err.so.2"
"libkrb5support.so.0"
"libsasl2.so.2"
"libgssapi.so.3"
"libbrotlicommon.so.1"
"libkeyutils.so.1"
"libheimntlm.so.0"
"libkrb5.so.26"
"libasn1.so.8"
"libhcrypto.so.4"
"libroken.so.18"
"libwind.so.0"
"libheimbase.so.1"
"libhx509.so.5"
"libsqlite3.so.0"
"libcrypt.so.1"
"libdbus-1.so.3"
)
declare -a DEPLIBS=(
"libSDL2-2.0.so.0"
)
declare -a QTLIBS=(
"libQt6Core.so.6"
"libQt6Gui.so.6"
"libQt6Network.so.6"
"libQt6OpenGL.so.6"
"libQt6Svg.so.6"
"libQt6WaylandClient.so.6"
"libQt6WaylandCompositor.so.6"
declare -a MANUAL_QT_LIBS=(
"libQt6WaylandEglClientHwIntegration.so.6"
"libQt6WaylandEglCompositorHwIntegration.so.6"
"libQt6Widgets.so.6"
"libQt6XcbQpa.so.6"
)
declare -a QTPLUGINS=(
"plugins/iconengines"
"plugins/imageformats"
"plugins/platforms"
#"plugins/platformthemes" # Enable this if we want to ship GTK+ themes at any point.
"plugins/tls"
"plugins/wayland-decoration-client"
"plugins/wayland-graphics-integration-client"
"plugins/wayland-graphics-integration-server"
"plugins/wayland-shell-integration"
"plugins/xcbglintegrations"
declare -a MANUAL_QT_PLUGINS=(
"wayland-decoration-client"
"wayland-graphics-integration-client"
"wayland-shell-integration"
)
set -e
if [ ! -f appimagetool-x86_64.AppImage ]; then
retry_command wget -O appimagetool-x86_64.AppImage https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x appimagetool-x86_64.AppImage
LINUXDEPLOY=./linuxdeploy-x86_64.AppImage
LINUXDEPLOY_PLUGIN_QT=./linuxdeploy-plugin-qt-x86_64.AppImage
APPIMAGETOOL=./appimagetool-x86_64.AppImage
PATCHELF=patchelf
if [ ! -f "$LINUXDEPLOY" ]; then
retry_command wget -O "$LINUXDEPLOY" https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
chmod +x "$LINUXDEPLOY"
fi
if [ ! -f "$LINUXDEPLOY_PLUGIN_QT" ]; then
retry_command wget -O "$LINUXDEPLOY_PLUGIN_QT" https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
chmod +x "$LINUXDEPLOY_PLUGIN_QT"
fi
if [ ! -f "$APPIMAGETOOL" ]; then
retry_command wget -O "$APPIMAGETOOL" https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x "$APPIMAGETOOL"
fi
OUTDIR=$(realpath "./$APPDIRNAME")
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
rm -fr "$OUTDIR"
mkdir "$OUTDIR"
mkdir "$OUTDIR/usr"
echo "Copying binary and resources..."
cp -a "$BUILDDIR/bin" "$OUTDIR/usr"
echo "Copying desktop file..."
cp "$PCSX2DIR/.github/workflows/scripts/linux/pcsx2-qt.desktop" .
cp "$PCSX2DIR/bin/resources/icons/AppIconLarge.png" "PCSX2.png"
# Get rid of unit tests, we don't want them bloating the squashfs.
rm -fv "$OUTDIR"/usr/bin/*_test
echo "Running linuxdeploy to create AppDir..."
EXTRA_QT_PLUGINS="core;gui;network;svg;waylandclient;widgets;xcbqpa" \
EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so" \
QMAKE="$DEPSDIR/bin/qmake" \
$LINUXDEPLOY --plugin qt --appdir="$OUTDIR" --executable="$BUILDDIR/bin/pcsx2-qt" \
--desktop-file="pcsx2-qt.desktop" --icon-file="PCSX2.png"
# Patch RPATH so the binary goes hunting for shared libraries in the AppDir instead of system.
echo "Patching RPATH in ${BINARY}..."
patchelf --set-rpath '$ORIGIN/../lib' "$OUTDIR/usr/bin/$BINARY"
echo "Copying resources into AppDir..."
cp -a "$BUILDDIR/bin/resources" "$OUTDIR/usr/bin"
# Currently we leave the main binary unstripped, uncomment if this is not desired.
#$STRIP "$OUTDIR/usr/bin/$BINARY"
# Libraries we pull in from the system.
echo "Copying system libraries..."
mkdir -p "$OUTDIR/usr/lib" "$OUTDIR/usr/lib/pulseaudio"
for lib in "${SYSLIBS[@]}"; do
blib=$(basename "$lib")
if [ -f "/lib/x86_64-linux-gnu/$lib" ]; then
cp "/lib/x86_64-linux-gnu/$lib" "$OUTDIR/usr/lib/$blib"
elif [ -f "$CHROOT/usr/lib/x86_64-linux-gnu/$lib" ]; then
cp "$CHROOT/usr/lib/x86_64-linux-gnu/$lib" "$OUTDIR/usr/lib/$blib"
elif [ -f "$CHROOT/lib/$lib" ]; then
cp "$CHROOT/lib/$lib" "$OUTDIR/usr/lib/$blib"
elif [ -f "$CHROOT/usr/lib/$lib" ]; then
cp "$CHROOT/usr/lib/$lib" "$OUTDIR/usr/lib/$blib"
else
echo "*** Failed to find '$blib'"
exit 1
fi
$STRIP "$OUTDIR/usr/lib/$blib"
# LinuxDeploy's Qt plugin doesn't include Wayland support. So manually copy in the additional Wayland libraries.
echo "Copying Qt Wayland libraries..."
for lib in "${MANUAL_QT_LIBS[@]}"; do
srcpath="$DEPSDIR/lib/$lib"
dstpath="$OUTDIR/usr/lib/$lib"
echo " $srcpath -> $dstpath"
cp "$srcpath" "$dstpath"
$PATCHELF --set-rpath '$ORIGIN' "$dstpath"
$STRIP "$dstpath"
done
# Dependencies we built, at this point it's just SDL.
echo "Copying dependency libraries..."
for lib in "${DEPLIBS[@]}"; do
blib=$(basename "$lib")
if [ -f "$DEPSDIR/lib/$lib" ]; then
cp "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib/$blib"
else
echo "*** Failed to find '$blib'"
exit 1
fi
# .. and plugins.
echo "Copying Qt Wayland plugins..."
for GROUP in "${MANUAL_QT_PLUGINS[@]}"; do
srcpath="$DEPSDIR/plugins/$GROUP"
dstpath="$OUTDIR/usr/plugins/$GROUP"
echo " $srcpath -> $dstpath"
mkdir -p "$dstpath"
$STRIP "$OUTDIR/usr/lib/$blib"
for srcsopath in $(find "$DEPSDIR/plugins/$GROUP" -iname '*.so'); do
# This is ../../ because it's usually plugins/group/name.so
soname=$(basename "$srcsopath")
dstsopath="$dstpath/$soname"
echo " $srcsopath -> $dstsopath"
cp "$srcsopath" "$dstsopath"
$PATCHELF --set-rpath '$ORIGIN/../../lib:$ORIGIN' "$dstsopath"
$STRIP "$dstsopath"
done
done
echo "Copying Qt libraries..."
for lib in "${QTLIBS[@]}"; do
cp -aL "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib"
$STRIP "$OUTDIR/usr/lib/$lib"
done
# Fix up translations.
rm -fr "$OUTDIR/usr/bin/translations"
mv "$OUTDIR/usr/translations" "$OUTDIR/usr/bin"
cp -a "$BUILDDIR/bin/translations" "$OUTDIR/usr/bin"
echo "Copying Qt plugins..."
mkdir -p "$OUTDIR/usr/lib/plugins"
for plugin in "${QTPLUGINS[@]}"; do
mkdir -p "$OUTDIR/usr/lib/$plugin"
cp -aL "$DEPSDIR/$plugin"/*.so "$OUTDIR/usr/lib/$plugin/"
done
echo "Generating AppImage..."
rm -f "$NAME.AppImage"
$APPIMAGETOOL -v "$OUTDIR" "$NAME.AppImage"
for so in $(find "$OUTDIR/usr/lib/plugins" -iname '*.so'); do
# This is ../../ because it's usually plugins/group/name.so
echo "Patching RPATH in ${so}..."
patchelf --set-rpath '$ORIGIN/../..' "$so"
$STRIP "$so"
done
for so in $(find "$OUTDIR/usr/lib" -maxdepth 1); do
if [ -f "$so" ]; then
echo "Patching RPATH in ${so}"
patchelf --set-rpath '$ORIGIN' "$so"
fi
done
echo "Creating qt.conf..."
cat > "$OUTDIR/usr/bin/qt.conf" << EOF
[Paths]
Plugins = ../lib/plugins
EOF
echo "Copy desktop/icon..."
cp "$PCSX2DIR/bin/resources/icons/AppIconLarge.png" "$OUTDIR/PCSX2.png"
cp "$SCRIPTDIR/pcsx2-qt.desktop" "$OUTDIR/PCSX2.desktop"
cp "$SCRIPTDIR/AppRun-qt" "$OUTDIR/AppRun"
echo "Generate AppImage"
./appimagetool-x86_64.AppImage -v "$OUTDIR" "$NAME.AppImage"
@@ -4,7 +4,7 @@ set -e
INSTALLDIR="$HOME/deps"
NPROCS="$(getconf _NPROCESSORS_ONLN)"
SDL=SDL2-2.26.5
SDL=SDL2-2.28.1
QT=6.5.0
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
@@ -12,7 +12,7 @@ mkdir -p deps-build
cd deps-build
cat > SHASUMS <<EOF
ad8fea3da1be64c83c45b1d363a6b4ba8fd60f5bde3b23ec73855709ec5eabf7 $SDL.tar.gz
4977ceba5c0054dbe6c2f114641aced43ce3bf2b41ea64b6a372d6ba129cb15d $SDL.tar.gz
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
fde1aa7b4fbe64ec1b4fc576a57f4688ad1453d2fab59cbadd948a10a6eaf5ef qtbase-everywhere-src-$QT.tar.xz
64ca7e61f44d51e28bcbb4e0509299b53a9a7e38879e00a7fe91643196067a4f qtsvg-everywhere-src-$QT.tar.xz
@@ -28,8 +28,8 @@
"sources": [
{
"type": "archive",
"url": "https://libsdl.org/release/SDL2-2.26.5.tar.gz",
"sha256": "ad8fea3da1be64c83c45b1d363a6b4ba8fd60f5bde3b23ec73855709ec5eabf7"
"url": "https://libsdl.org/release/SDL2-2.28.1.tar.gz",
"sha256": "4977ceba5c0054dbe6c2f114641aced43ce3bf2b41ea64b6a372d6ba129cb15d"
}
],
"cleanup": [
@@ -22,7 +22,8 @@
"--socket=fallback-x11",
"--socket=wayland",
"--socket=pulseaudio",
"--filesystem=host:ro"
"--filesystem=host:ro",
"--talk-name=org.freedesktop.ScreenSaver"
],
"modules": [
"modules/10-libpcap.json",
@@ -8,14 +8,13 @@ set -e
# Packages - Build and Qt
declare -a BUILD_PACKAGES=(
"build-essential"
"g++"
"git"
"cmake"
"ccache"
"ninja-build"
"libclang-dev" # Qt goes hunting for libclang-11 specifically.
"libclang-11-dev"
"libclang-12-dev"
"patchelf"
"libfuse2"
"libglib2.0-dev"
"libfontconfig1-dev"
"libharfbuzz-dev"
@@ -37,6 +36,7 @@ declare -a BUILD_PACKAGES=(
# Packages - PCSX2
declare -a PCSX2_PACKAGES=(
"extra-cmake-modules"
"libaio-dev"
"libasound2-dev"
"libbz2-dev"
@@ -63,16 +63,12 @@ declare -a PCSX2_PACKAGES=(
"zlib1g-dev"
)
if [ "${COMPILER}" = "gcc" ]; then
BUILD_PACKAGES+=("g++-10")
else
if [ "${COMPILER}" = "clang" ]; then
BUILD_PACKAGES+=("llvm-16" "lld-16" "clang-16")
# Ubuntu 20.04 doesn't ship with LLVM 16, so we need to pull it from the llvm.org repos.
# Ubuntu 22.04 doesn't ship with LLVM 16, so we need to pull it from the llvm.org repos.
retry_command wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-add-repository -n 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-16 main'
retry_command sudo apt-get update
retry_command sudo apt-get install clang-16 lld-16
sudo apt-add-repository -n 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main'
fi
retry_command sudo apt-get -qq update && break
@@ -6,7 +6,7 @@ export MACOSX_DEPLOYMENT_TARGET=10.14
INSTALLDIR="$HOME/deps"
NPROCS="$(getconf _NPROCESSORS_ONLN)"
SDL=SDL2-2.26.5
SDL=SDL2-2.28.1
PNG=1.6.37
JPG=9e
SOUNDTOUCH=soundtouch-2.3.1
@@ -21,7 +21,7 @@ export CFLAGS="-I$INSTALLDIR/include -Os $CFLAGS"
export CXXFLAGS="-I$INSTALLDIR/include -Os $CXXFLAGS"
cat > SHASUMS <<EOF
ad8fea3da1be64c83c45b1d363a6b4ba8fd60f5bde3b23ec73855709ec5eabf7 $SDL.tar.gz
4977ceba5c0054dbe6c2f114641aced43ce3bf2b41ea64b6a372d6ba129cb15d $SDL.tar.gz
505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca libpng-$PNG.tar.xz
4077d6a6a75aeb01884f708919d25934c93305e49f7e3f36db9129320e6f4f3d jpegsrc.v$JPG.tar.gz
6900996607258496ce126924a19fe9d598af9d892cf3f33d1e4daaa9b42ae0b1 $SOUNDTOUCH.tar.gz
@@ -1,7 +1,7 @@
import os
import shutil
tag = os.environ['TAG'].split("refs/tags/")[1]
tag = os.environ['TAG_VAL']
scan_dir = os.environ['SCAN_DIR']
output_dir = os.environ['OUT_DIR']
accepted_exts = ["AppImage", "flatpak", "tar.xz", "7z"]
@@ -13,11 +13,11 @@ for dir_name in os.listdir(scan_dir):
asset_name += "-macos"
elif "linux" in dir_name.lower():
if "flatpak" in dir_name.lower():
asset_name += "-linux-Flatpak-64bit"
asset_name += "-linux-flatpak-x64"
else:
asset_name += "-linux-AppImage-64bit"
asset_name += "-linux-appimage-x64"
elif "windows" in dir_name.lower():
asset_name += "-windows-64bit"
asset_name += "-windows-x64"
else:
continue;
+6 -6
View File
@@ -26,7 +26,7 @@ jobs:
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
uses: ./.github/workflows/windows_build_qt.yml
with:
jobName: Qt
jobName: "MSVC SSE4"
configuration: Release
simd: "SSE4"
secrets: inherit
@@ -37,7 +37,7 @@ jobs:
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
uses: ./.github/workflows/windows_build_qt.yml
with:
jobName: Qt
jobName: "MSVC AVX2"
configuration: Release AVX2
secrets: inherit
@@ -46,7 +46,7 @@ jobs:
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
uses: ./.github/workflows/windows_build_qt.yml
with:
jobName: Qt
jobName: "CMake MSVC"
configuration: CMake
buildSystem: cmake
secrets: inherit
@@ -57,7 +57,7 @@ jobs:
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
uses: ./.github/workflows/windows_build_qt.yml
with:
jobName: Qt Clang
jobName: "Clang SSE4"
configuration: Release Clang
simd: "SSE4"
secrets: inherit
@@ -68,7 +68,7 @@ jobs:
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
uses: ./.github/workflows/windows_build_qt.yml
with:
jobName: Qt Clang
jobName: "Clang AVX2"
configuration: Release Clang AVX2
secrets: inherit
@@ -77,7 +77,7 @@ jobs:
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
uses: ./.github/workflows/windows_build_qt.yml
with:
jobName: Qt Clang
jobName: "CMake Clang"
configuration: CMake
buildSystem: cmake
cmakeFlags: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DPCSX2_EXE_NAME=pcsx2-qt-clang
+11 -3
View File
@@ -37,10 +37,14 @@ on:
required: false
type: string
default: 3rdparty\qt\6.5.0\msvc2022_64
patches_url:
patchesUrl:
required: false
type: string
default: https://github.com/PCSX2/pcsx2_patches/releases/latest/download
fetchTags:
required: false
type: boolean
default: false
jobs:
build_windows_qt:
@@ -57,13 +61,17 @@ jobs:
with:
submodules: recursive
# actions/checkout elides tags, fetch them primarily for releases
- name: Fetch Tags
if: ${{ inputs.fetchTags }}
run: git fetch --tags --no-recurse-submodules
- name: Prepare Artifact Metadata
id: artifact-metadata
shell: bash
env:
OS: windows
BUILD_SYSTEM: ${{ inputs.buildSystem }}
GUI_FRAMEWORK: Qt
ARCH: ${{ inputs.platform }}
SIMD: ${{ inputs.simd }}
EVENT_NAME: ${{ github.event_name }}
@@ -88,7 +96,7 @@ jobs:
shell: cmd
run: |
cd bin/resources
aria2c -Z "${{ inputs.patches_url }}/patches.zip"
aria2c -Z "${{ inputs.patchesUrl }}/patches.zip"
- name: Generate CMake
if: inputs.configuration == 'CMake'
-2
View File
@@ -90,8 +90,6 @@ oprofile_data/
/ipch
!/3rdparty/libjpeg/change.log
/pcsx2/gui/Resources/*.h
!/pcsx2/gui/Resources/EmbeddedImage.h
/tools/bin
.vs
+1 -1
View File
@@ -1,6 +1,6 @@
# Setting it to a range tells it that it supports the features on the newer
# versions as well, avoiding setting policies.
cmake_minimum_required(VERSION 3.12...3.24)
cmake_minimum_required(VERSION 3.16...3.24)
#Enabling this cmake policy gets rid of warnings regarding LTO.
cmake_policy(SET CMP0069 NEW)
+2 -2
View File
@@ -22,7 +22,7 @@ Installers and binaries for both stable and development builds are available fro
| Operating System | CPU | GPU | RAM |
| ------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| - Windows 10 21H2 (1809 or later) (64-bit) <br/> - Ubuntu 20.04/Debian or newer, Arch Linux, or other distro (64-bit) <br/> - macOS 10.14 | - Supports SSE4.1 <br/> - [PassMark Thread Performance](https://www.cpubenchmark.net/CPU_mega_page.html) rating near or greater than 1800<br/> - Two physical cores, with hyperthreading | - Direct3D10 support <br/> - OpenGL 3.x support <br/> - Vulkan 1.1 support <br/> - Metal support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 3000 (Geforce GTX 750, Radeon RX 560, Intel Arc A380) <br/> - 2 GB Video Memory | 4 GB |
| - Windows 10 Version 1809 or later (64-bit) <br/> - Ubuntu 22.04/Debian or newer, Arch Linux, or other distro (64-bit) <br/> - macOS 10.14 | - Supports SSE4.1 <br/> - [PassMark Thread Performance](https://www.cpubenchmark.net/CPU_mega_page.html) rating near or greater than 1800<br/> - Two physical cores, with hyperthreading | - Direct3D10 support <br/> - OpenGL 3.x support <br/> - Vulkan 1.1 support <br/> - Metal support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 3000 (Geforce GTX 750, Radeon RX 560, Intel Arc A380) <br/> - 2 GB Video Memory | 4 GB |
_Note: Recommended Single Thread Performance is based on moderately complex games. Games that pushed the PS2 hardware to its limits will struggle on CPUs at this level. Some release titles and 2D games which underutilized the PS2 hardware may run on CPUs rated as low as 1200. A quick reference for CPU **intensive games**: [Wiki](https://wiki.pcsx2.net/Category:CPU_intensive_games), [Forum](https://forums.pcsx2.net/Thread-LIST-The-Most-CPU-Intensive-Games) and CPU **light** games: [Forum](https://forums.pcsx2.net/Thread-LIST-Games-that-don-t-need-a-strong-CPU-to-emulate)_
@@ -30,7 +30,7 @@ _Note: Recommended Single Thread Performance is based on moderately complex game
| Operating System | CPU | GPU | RAM |
| ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| - Windows 10 21H2 (1809 or later) (64-bit) <br/> - Ubuntu 22.04/Debian or newer, Arch Linux, or other distro (64-bit) <br/> - macOS 10.14 | - Supports AVX2 <br/> - [PassMark Single Thread Performance](https://www.cpubenchmark.net/CPU_mega_page.html) rating near or greater than 2600<br/> - Four physical cores, with or without hyperthreading | - Direct3D12 support <br/> - OpenGL 4.6 support <br/> - Vulkan 1.3 support <br/> - Metal support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 6000 (GeForce GTX 1650, Radeon RX 570) <br/> - 4 GB Video Memory | 8 GB |
| - Windows 10 22H2 (64-bit) <br/> - Ubuntu 23.04/Debian or newer, Arch Linux, or other distro (64-bit) <br/> - macOS 10.14 | - Supports AVX2 <br/> - [PassMark Single Thread Performance](https://www.cpubenchmark.net/CPU_mega_page.html) rating near or greater than 2600<br/> - Four physical cores, with or without hyperthreading | - Direct3D12 support <br/> - OpenGL 4.6 support <br/> - Vulkan 1.3 support <br/> - Metal support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 6000 (GeForce GTX 1650, Radeon RX 570) <br/> - 4 GB Video Memory | 8 GB |
_Note: Recommended GPU is based on 3x Internal, ~1080p resolution requirements. Higher resolutions will require stronger cards; 6x Internal, ~4K resolution will require a [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 12000 (GeForce RTX 2060 Radeon RX 6600 Intel Arc A750). Just like CPU requirements, this is also highly game dependent. A quick reference for GPU **intensive games**: [Wiki](https://wiki.pcsx2.net/Category:GPU_intensive_games)_
File diff suppressed because it is too large Load Diff
+6 -5
View File
@@ -1067,10 +1067,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000631000014010000,8BitDo Pro 2 Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00001030000011010000,8BitDo Pro 2 Wired Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000020000000000000,8BitDo Pro 2 Wired Controller for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
06000000c82d00000020000006010000,8BitDo Pro 2 Wired Controller for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00000631000014010000,8BitDo Pro 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00001030000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000020000000000000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
06000000c82d00000020000006010000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
@@ -1094,7 +1094,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001730000011010000,8BitDo Ultimate a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001730000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001530000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001630000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001130000011010000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
@@ -1252,6 +1252,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d040000d1ca000000000000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+1 -1
View File
@@ -56,7 +56,7 @@ void main(uint3 LocalThreadId : SV_GroupThreadID, uint3 WorkGroupId : SV_GroupID
#endif
// Filter.
AF3 c;
AF3 c = (float4)0.0f;
CasFilter(c.r, c.g, c.b, gxy, const0, const1, sharpenOnly);
OutputTexture[ASU2(gxy)] = AF4(c, 1);
+42
View File
@@ -395,4 +395,46 @@ PS_OUTPUT ps_filter_lottes(PS_INPUT input)
return output;
}
PS_OUTPUT ps_4x_rgss(PS_INPUT input)
{
PS_OUTPUT output;
float2 dxy = float2(ddx(input.t.x), ddy(input.t.y));
float3 color = 0;
float s = 1.0/8.0;
float l = 3.0/8.0;
color += sample_c(input.t + float2( s, l) * dxy).rgb;
color += sample_c(input.t + float2( l,-s) * dxy).rgb;
color += sample_c(input.t + float2(-s,-l) * dxy).rgb;
color += sample_c(input.t + float2(-l, s) * dxy).rgb;
output.c = float4(color * 0.25,1);
return output;
}
PS_OUTPUT ps_automagical_supersampling(PS_INPUT input)
{
PS_OUTPUT output;
float2 ratio = (u_source_size / u_target_size) * 0.5;
float2 steps = floor(ratio);
float3 col = sample_c(input.t).rgb;
float div = 1;
for (float y = 0; y < steps.y; y++)
{
for (float x = 0; x < steps.x; x++)
{
float2 offset = float2(x,y) - ratio * 0.5;
col += sample_c(input.t + offset * u_rcp_source_resolution * 2.0).rgb;
div++;
}
}
output.c = float4(col / div, 1);
return output;
}
#endif
+1 -1
View File
@@ -46,7 +46,7 @@ void main()
AU2 gxy = ARmp8x8(gl_LocalInvocationID.x)+AU2(gl_WorkGroupID.x<<4u,gl_WorkGroupID.y<<4u);
// Filter.
AF4 c;
AF4 c = vec4(0.0f);
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
imageStore(imgDst, ASU2(gxy), c);
gxy.x += 8u;
+5 -3
View File
@@ -367,7 +367,7 @@ uniform ivec2 EMOD;
void ps_yuv()
{
vec4 i = sample_c();
vec4 o;
vec4 o = vec4(0.0f);
mat3 rgb2yuv; // Value from GS manual
rgb2yuv[0] = vec3(0.587, -0.311, -0.419);
@@ -380,7 +380,8 @@ void ps_yuv()
float Cr = float(0xE0)/255.0f * yuv.y + float(0x80)/255.0f;
float Cb = float(0xE0)/255.0f * yuv.z + float(0x80)/255.0f;
switch(EMOD.x) {
switch(EMOD.x)
{
case 0:
o.a = i.a;
break;
@@ -395,7 +396,8 @@ void ps_yuv()
break;
}
switch(EMOD.y) {
switch(EMOD.y)
{
case 0:
o.rgb = i.rgb;
break;
+45
View File
@@ -54,6 +54,11 @@ vec4 sample_c()
return texture(TextureSampler, PSin_t);
}
vec4 sample_c(vec2 uv)
{
return texture(TextureSampler, uv);
}
vec4 ps_crt(uint i)
{
vec4 mask[4] = vec4[4](
@@ -384,4 +389,44 @@ void ps_filter_lottes()
#endif
#ifdef ps_4x_rgss
void ps_4x_rgss()
{
vec2 dxy = vec2(dFdx(PSin_t.x), dFdy(PSin_t.y));
vec3 color = vec3(0);
float s = 1.0/8.0;
float l = 3.0/8.0;
color += sample_c(PSin_t + vec2( s, l) * dxy).rgb;
color += sample_c(PSin_t + vec2( l,-s) * dxy).rgb;
color += sample_c(PSin_t + vec2(-s,-l) * dxy).rgb;
color += sample_c(PSin_t + vec2(-l, s) * dxy).rgb;
SV_Target0 = vec4(color * 0.25,1);
}
#endif
#ifdef ps_automagical_supersampling
void ps_automagical_supersampling()
{
vec2 ratio = (u_source_size / u_target_size) * 0.5;
vec2 steps = floor(ratio);
vec3 col = sample_c(PSin_t).rgb;
float div = 1;
for (float y = 0; y < steps.y; y++)
{
for (float x = 0; x < steps.x; x++)
{
vec2 offset = vec2(x,y) - ratio * 0.5;
col += sample_c(PSin_t + offset * u_rcp_source_resolution * 2.0).rgb;
div++;
}
}
SV_Target0 = vec4(col / div, 1);
}
#endif
#endif
+1 -1
View File
@@ -53,7 +53,7 @@ void main()
AU2 gxy = ARmp8x8(gl_LocalInvocationID.x)+AU2(gl_WorkGroupID.x<<4u,gl_WorkGroupID.y<<4u);
// Filter.
AF4 c;
AF4 c = vec4(0.0f);
CasFilter(c.r, c.g, c.b, gxy, const0, const1, sharpenOnly != 0);
imageStore(imgDst, ASU2(gxy), c);
gxy.x += 8u;
+5 -3
View File
@@ -348,7 +348,7 @@ layout(push_constant) uniform cb10
void ps_yuv()
{
vec4 i = sample_c(v_tex);
vec4 o;
vec4 o = vec4(0.0f);
mat3 rgb2yuv;
rgb2yuv[0] = vec3(0.587, -0.311, -0.419);
@@ -361,7 +361,8 @@ void ps_yuv()
float Cr = float(0xE0)/255.0f * yuv.y + float(0x80)/255.0f;
float Cb = float(0xE0)/255.0f * yuv.z + float(0x80)/255.0f;
switch(EMODA) {
switch(EMODA)
{
case 0:
o.a = i.a;
break;
@@ -376,7 +377,8 @@ void ps_yuv()
break;
}
switch(EMODC) {
switch(EMODC)
{
case 0:
o.rgb = i.rgb;
break;
+40
View File
@@ -359,4 +359,44 @@ void ps_filter_lottes()
#endif
#ifdef ps_4x_rgss
void ps_4x_rgss()
{
vec2 dxy = vec2(dFdx(v_tex.x), dFdy(v_tex.y));
vec3 color = vec3(0);
float s = 1.0/8.0;
float l = 3.0/8.0;
color += sample_c(v_tex + vec2( s, l) * dxy).rgb;
color += sample_c(v_tex + vec2( l,-s) * dxy).rgb;
color += sample_c(v_tex + vec2(-s,-l) * dxy).rgb;
color += sample_c(v_tex + vec2(-l, s) * dxy).rgb;
o_col0 = vec4(color * 0.25,1);
}
#endif
#ifdef ps_automagical_supersampling
void ps_automagical_supersampling()
{
vec2 ratio = (u_source_size / u_target_size) * 0.5;
vec2 steps = floor(ratio);
vec3 col = sample_c(v_tex).rgb;
float div = 1;
for (float y = 0; y < steps.y; y++)
{
for (float x = 0; x < steps.x; x++)
{
vec2 offset = vec2(x,y) - ratio * 0.5;
col += sample_c(v_tex + offset * u_rcp_source_resolution * 2.0).rgb;
div++;
}
}
o_col0 = vec4(col / div, 1);
}
#endif
#endif
+5 -5
View File
@@ -336,12 +336,12 @@ layout(set = 1, binding = 1) uniform texture2D Palette;
#endif
#if PS_FEEDBACK_LOOP_IS_NEEDED
#ifndef DISABLE_TEXTURE_BARRIER
layout(input_attachment_index = 0, set = 2, binding = 0) uniform subpassInput RtSampler;
vec4 sample_from_rt() { return subpassLoad(RtSampler); }
#else
#if defined(DISABLE_TEXTURE_BARRIER) || defined(HAS_FEEDBACK_LOOP_LAYOUT)
layout(set = 2, binding = 0) uniform texture2D RtSampler;
vec4 sample_from_rt() { return texelFetch(RtSampler, ivec2(gl_FragCoord.xy), 0); }
#else
layout(input_attachment_index = 0, set = 2, binding = 0) uniform subpassInput RtSampler;
vec4 sample_from_rt() { return subpassLoad(RtSampler); }
#endif
#endif
@@ -1218,7 +1218,7 @@ void main()
#endif
#if (SW_AD_TO_HW)
vec4 RT = trunc(subpassLoad(RtSampler) * 255.0f + 0.1f);
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
vec4 alpha_blend = vec4(RT.a / 128.0f);
#else
vec4 alpha_blend = vec4(C.a / 128.0f);
-68
View File
@@ -1,68 +0,0 @@
# Try to find Wayland on a Unix system
#
# This will define:
#
# Wayland_FOUND - True if Wayland is found
#
# The following imported targets:
# Wayland::Client - Imported Client
# Wayland::Server - Imported Server
# Wayland::Egl - Imported Egl
# Wayland::Cursor - Imported Cursor
#
# Copyright (c) 2013 Martin Gräßlin <mgraesslin@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
IF (NOT WIN32)
IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES)
# In the cache already
SET(WAYLAND_FIND_QUIETLY TRUE)
ENDIF ()
FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h)
FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h)
FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h)
FIND_PATH(WAYLAND_CURSOR_INCLUDE_DIR NAMES wayland-cursor.h)
FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client)
FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server)
FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl)
FIND_LIBRARY(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor)
include(FindPackageHandleStandardArgs)
# FIND_PACKAGE_HANDLE_STANDARD_ARGS is just meant to find the main package and set package found. Not set variables or find individual libs
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Wayland REQUIRED_VARS
WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR
WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR
WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR
WAYLAND_CURSOR_LIBRARIES WAYLAND_CURSOR_INCLUDE_DIR
)
if (WAYLAND_CLIENT_INCLUDE_DIR AND WAYLAND_CLIENT_LIBRARIES AND NOT TARGET Wayland::Client)
add_library(Wayland::Client UNKNOWN IMPORTED)
set_target_properties(Wayland::Client PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_CLIENT_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_CLIENT_LIBRARIES}")
endif()
if (WAYLAND_SERVER_INCLUDE_DIR AND WAYLAND_SERVER_LIBRARIES AND NOT TARGET Wayland::Server)
add_library(Wayland::Server UNKNOWN IMPORTED)
set_target_properties(Wayland::Server PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_SERVER_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_SERVER_LIBRARIES}")
endif()
if (WAYLAND_EGL_INCLUDE_DIR AND WAYLAND_EGL_LIBRARIES AND NOT TARGET Wayland::Egl)
add_library(Wayland::Egl UNKNOWN IMPORTED)
set_target_properties(Wayland::Egl PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_EGL_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_EGL_LIBRARIES}")
endif()
if (WAYLAND_CURSOR_INCLUDE_DIR AND WAYLAND_CURSOR_LIBRARIES AND NOT TARGET Wayland::Cursor)
add_library(Wayland::Cursor UNKNOWN IMPORTED)
set_target_properties(Wayland::Cursor PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_CURSOR_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_CURSOR_LIBRARIES}")
endif()
MARK_AS_ADVANCED(
WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES
WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES
WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES
WAYLAND_CURSOR_INCLUDE_DIR WAYLAND_CURSOR_LIBRARIES
)
ENDIF ()
+3 -1
View File
@@ -82,7 +82,9 @@ else()
make_imported_target_if_missing(X11::X11 X11)
if(WAYLAND_API)
find_package(Wayland REQUIRED)
find_package(ECM REQUIRED NO_MODULE)
list(APPEND CMAKE_MODULE_PATH "${ECM_MODULE_PATH}")
find_package(Wayland REQUIRED Egl)
endif()
find_package(Libbacktrace)
+2
View File
@@ -30,6 +30,7 @@ target_sources(common PRIVATE
Semaphore.cpp
SettingsWrapper.cpp
StringUtil.cpp
TextureDecompress.cpp
Timer.cpp
ThreadPool.cpp
WAVWriter.cpp
@@ -94,6 +95,7 @@ target_sources(common PRIVATE
SettingsWrapper.h
StringUtil.h
Timer.h
TextureDecompress.h
Threading.h
ThreadPool.h
TraceLog.h
+36 -8
View File
@@ -38,6 +38,7 @@
#if defined(_WIN32)
#include "RedtapeWindows.h"
#include <io.h>
#include <winioctl.h>
#include <share.h>
#include <shlobj.h>
@@ -190,6 +191,27 @@ void Path::SanitizeFileName(std::string* str, bool strip_slashes /* = true */)
#endif
}
bool Path::IsValidFileName(const std::string_view& str, bool allow_slashes)
{
const size_t len = str.length();
size_t pos = 0;
while (pos < len)
{
char32_t ch;
pos += StringUtil::DecodeUTF8(str.data() + pos, pos - len, &ch);
if (!FileSystemCharacterIsSane(ch, !allow_slashes))
return false;
}
#ifdef _WIN32
// Windows: Can't end filename with a period.
if (len > 0 && str.back() == '.')
return false;
#endif
return true;
}
bool Path::IsAbsolute(const std::string_view& path)
{
#ifdef _WIN32
@@ -651,7 +673,7 @@ int FileSystem::OpenFDFile(const char* filename, int flags, int mode, Error* err
FileSystem::ManagedCFilePtr FileSystem::OpenManagedCFile(const char* filename, const char* mode, Error* error)
{
return ManagedCFilePtr(OpenCFile(filename, mode, error), [](std::FILE* fp) { std::fclose(fp); });
return ManagedCFilePtr(OpenCFile(filename, mode, error));
}
std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, Error* error)
@@ -696,7 +718,7 @@ std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, F
FileSystem::ManagedCFilePtr FileSystem::OpenManagedSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, Error* error)
{
return ManagedCFilePtr(OpenSharedCFile(filename, mode, share_mode, error), [](std::FILE* fp) { std::fclose(fp); });
return ManagedCFilePtr(OpenSharedCFile(filename, mode, share_mode, error));
}
int FileSystem::FSeek64(std::FILE* fp, s64 offset, int whence)
@@ -726,6 +748,13 @@ s64 FileSystem::FTell64(std::FILE* fp)
s64 FileSystem::FSize64(std::FILE* fp)
{
#ifdef _WIN32
const int fd = _fileno(fp);
if (fd >= 0)
{
return _filelengthi64(fd);
}
#else
const s64 pos = FTell64(fp);
if (pos >= 0)
{
@@ -736,6 +765,7 @@ s64 FileSystem::FSize64(std::FILE* fp)
return size;
}
}
#endif
return -1;
}
@@ -760,12 +790,11 @@ std::optional<std::vector<u8>> FileSystem::ReadBinaryFile(const char* filename)
std::optional<std::vector<u8>> FileSystem::ReadBinaryFile(std::FILE* fp)
{
std::fseek(fp, 0, SEEK_END);
const long size = std::ftell(fp);
std::fseek(fp, 0, SEEK_SET);
const s64 size = FSize64(fp);
if (size < 0)
return std::nullopt;
std::fseek(fp, 0, SEEK_SET);
std::vector<u8> res(static_cast<size_t>(size));
if (size > 0 && std::fread(res.data(), 1u, static_cast<size_t>(size), fp) != static_cast<size_t>(size))
return std::nullopt;
@@ -784,12 +813,11 @@ std::optional<std::string> FileSystem::ReadFileToString(const char* filename)
std::optional<std::string> FileSystem::ReadFileToString(std::FILE* fp)
{
std::fseek(fp, 0, SEEK_END);
const long size = std::ftell(fp);
std::fseek(fp, 0, SEEK_SET);
const s64 size = FSize64(fp);
if (size < 0)
return std::nullopt;
std::fseek(fp, 0, SEEK_SET);
std::string res;
res.resize(static_cast<size_t>(size));
// NOTE - assumes mode 'rb', for example, this will fail over missing Windows carriage return bytes
+10 -1
View File
@@ -102,8 +102,17 @@ namespace FileSystem
/// Rename file
bool RenamePath(const char* OldPath, const char* NewPath);
/// Deleter functor for managed file pointers
struct FileDeleter
{
void operator()(std::FILE* fp)
{
std::fclose(fp);
}
};
/// open files
using ManagedCFilePtr = std::unique_ptr<std::FILE, void (*)(std::FILE*)>;
using ManagedCFilePtr = std::unique_ptr<std::FILE, FileDeleter>;
ManagedCFilePtr OpenManagedCFile(const char* filename, const char* mode, Error* error = nullptr);
std::FILE* OpenCFile(const char* filename, const char* mode, Error* error = nullptr);
int FSeek64(std::FILE* fp, s64 offset, int whence);
+42 -36
View File
@@ -27,6 +27,7 @@
#include "common/Pcsx2Types.h"
#include "common/General.h"
#include "common/ScopedGuard.h"
#include "common/StringUtil.h"
#include "common/Threading.h"
#include "common/WindowInfo.h"
@@ -70,66 +71,72 @@ std::string GetOSVersionString()
#ifdef DBUS_API
bool ChangeScreenSaverStateDBus(const bool inhibit_requested, const char* program_name, const char* reason)
static bool SetScreensaverInhibitDBus(const bool inhibit_requested, const char* program_name, const char* reason)
{
static dbus_uint32_t s_cookie;
// "error_dbus" doesn't need to be cleared in the end with "dbus_message_unref" at least if there is
// no error set, since calling "dbus_error_free" reinitializes it like "dbus_error_init" after freeing.
const char* bus_method = (inhibit_requested) ? "Inhibit" : "UnInhibit";
DBusError error_dbus;
dbus_error_init(&error_dbus);
DBusConnection* connection = nullptr;
static DBusConnection* s_comparison_connection;
DBusMessage* message = nullptr;
DBusMessage* response = nullptr;
// Initialized here because initializations should be before "goto" statements.
const char* bus_method = (inhibit_requested) ? "Inhibit" : "UnInhibit";
// "dbus_bus_get" gets a pointer to the same connection in libdbus, if exists, without creating a new connection.
// this doesn't need to be deleted, except if there's an error then calling "dbus_connection_unref", to free it,
// might be better so a new connection is established on the next try.
if (!(connection = dbus_bus_get(DBUS_BUS_SESSION, &error_dbus)) || (dbus_error_is_set(&error_dbus)))
goto cleanup;
if (!(message = dbus_message_new_method_call("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver", bus_method)))
goto cleanup;
// Initialize an append iterator for the message, gets freed with the message.
DBusMessageIter message_itr;
ScopedGuard cleanup = [&]() {
if (dbus_error_is_set(&error_dbus))
dbus_error_free(&error_dbus);
if (message)
dbus_message_unref(message);
if (response)
dbus_message_unref(response);
};
dbus_error_init(&error_dbus);
// Calling dbus_bus_get() after the first time returns a pointer to the existing connection.
connection = dbus_bus_get(DBUS_BUS_SESSION, &error_dbus);
if (!connection || (dbus_error_is_set(&error_dbus)))
return false;
if (s_comparison_connection != connection)
{
dbus_connection_set_exit_on_disconnect(connection, false);
s_cookie = 0;
s_comparison_connection = connection;
}
message = dbus_message_new_method_call("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver", bus_method);
if (!message)
return false;
// Initialize an append iterator for the message, gets freed with the message.
dbus_message_iter_init_append(message, &message_itr);
if (inhibit_requested)
{
// Guard against repeat inhibitions which would add extra inhibitors each generating a different cookie.
if (s_cookie)
return false;
// Append process/window name.
if (!dbus_message_iter_append_basic(&message_itr, DBUS_TYPE_STRING, &program_name))
goto cleanup;
return false;
// Append reason for inhibiting the screensaver.
if (!dbus_message_iter_append_basic(&message_itr, DBUS_TYPE_STRING, &reason))
goto cleanup;
return false;
}
else
{
// Only Append the cookie.
if (!dbus_message_iter_append_basic(&message_itr, DBUS_TYPE_UINT32, &s_cookie))
goto cleanup;
return false;
}
// Send message and get response.
if (!(response = dbus_connection_send_with_reply_and_block(connection, message, DBUS_TIMEOUT_USE_DEFAULT, &error_dbus))
|| dbus_error_is_set(&error_dbus))
goto cleanup;
response = dbus_connection_send_with_reply_and_block(connection, message, DBUS_TIMEOUT_USE_DEFAULT, &error_dbus);
if (!response || dbus_error_is_set(&error_dbus))
return false;
s_cookie = 0;
if (inhibit_requested)
{
// Get the cookie from the response message.
if (!dbus_message_get_args(response, &error_dbus, DBUS_TYPE_UINT32, &s_cookie, DBUS_TYPE_INVALID))
goto cleanup;
if (!dbus_message_get_args(response, &error_dbus, DBUS_TYPE_UINT32, &s_cookie, DBUS_TYPE_INVALID) || dbus_error_is_set(&error_dbus))
return false;
}
dbus_message_unref(message);
dbus_message_unref(response);
return true;
cleanup:
if (dbus_error_is_set(&error_dbus))
dbus_error_free(&error_dbus);
if (connection)
dbus_connection_unref(connection);
if (message)
dbus_message_unref(message);
if (response)
dbus_message_unref(response);
return false;
}
#endif
@@ -176,11 +183,10 @@ bool WindowInfo::InhibitScreensaver(const WindowInfo& wi, bool inhibit)
#ifdef DBUS_API
return ChangeScreenSaverStateDBus(inhibit, "PCSX2", "PCSX2 VM is running.");
return SetScreensaverInhibitDBus(inhibit, "PCSX2", "PCSX2 VM is running.");
#else
//ChangeScreenSaverStateDBus
if (s_inhibit_window_info.has_value())
{
// Bit of extra logic here, because wx spams it and we don't want to
+3
View File
@@ -41,6 +41,9 @@ namespace Path
std::string SanitizeFileName(const std::string_view& str, bool strip_slashes = true);
void SanitizeFileName(std::string* str, bool strip_slashes = true);
/// Returns true if the specified filename is valid on this operating system.
bool IsValidFileName(const std::string_view& str, bool allow_slashes = false);
/// Returns true if the specified path is an absolute path (C:\Path on Windows or /path on Unix).
bool IsAbsolute(const std::string_view& path);
+12
View File
@@ -15,6 +15,7 @@
#pragma once
#include "Pcsx2Types.h"
#include <algorithm>
#include <charconv>
#include <cstdarg>
#include <cstddef>
@@ -340,4 +341,15 @@ namespace StringUtil
/// Converts unsigned 128-bit data to string.
std::string U128ToString(const u128& u);
std::string& AppendU128ToString(const u128& u, std::string& s);
template <typename ContainerType>
static inline bool ContainsSubString(const ContainerType& haystack, const std::string_view& needle)
{
using ValueType = typename ContainerType::value_type;
if (needle.empty())
return std::empty(haystack);
return std::search(std::begin(haystack), std::end(haystack), reinterpret_cast<const ValueType*>(needle.data()),
reinterpret_cast<const ValueType*>(needle.data() + needle.length())) != std::end(haystack);
}
} // namespace StringUtil
File diff suppressed because it is too large Load Diff
+199
View File
@@ -0,0 +1,199 @@
// See TextureDecompress.cpp for license info.
#pragma once
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4201) // nonstandard extension used: nameless struct/union
#endif
#include <stdlib.h>
#include <stdint.h>
#include <algorithm>
#include <math.h>
#include <assert.h>
enum BC4Mode
{
BC4_UNORM = 0,
BC4_SNORM = 1
};
enum BC5Mode
{
BC5_UNORM = 0,
BC5_SNORM = 1
};
void DecompressBlockBC1(uint32_t x, uint32_t y, uint32_t stride,
const uint8_t* blockStorage, unsigned char* image);
void DecompressBlockBC2(uint32_t x, uint32_t y, uint32_t stride,
const uint8_t* blockStorage, unsigned char* image);
void DecompressBlockBC3(uint32_t x, uint32_t y, uint32_t stride,
const uint8_t* blockStorage, unsigned char* image);
void DecompressBlockBC4(uint32_t x, uint32_t y, uint32_t stride,
enum BC4Mode mode, const uint8_t* blockStorage, unsigned char* image);
void DecompressBlockBC5(uint32_t x, uint32_t y, uint32_t stride,
enum BC5Mode mode, const uint8_t* blockStorage, unsigned char* image);
namespace bc7decomp
{
enum eNoClamp { cNoClamp };
template <typename S> inline S clamp(S value, S low, S high) { return (value < low) ? low : ((value > high) ? high : value); }
class color_rgba
{
public:
union
{
uint8_t m_comps[4];
struct
{
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
};
inline color_rgba()
{
static_assert(sizeof(*this) == 4, "sizeof(*this) != 4");
}
inline color_rgba(int y)
{
set(y);
}
inline color_rgba(int y, int na)
{
set(y, na);
}
inline color_rgba(int sr, int sg, int sb, int sa)
{
set(sr, sg, sb, sa);
}
inline color_rgba(eNoClamp, int sr, int sg, int sb, int sa)
{
set_noclamp_rgba((uint8_t)sr, (uint8_t)sg, (uint8_t)sb, (uint8_t)sa);
}
inline color_rgba& set_noclamp_y(int y)
{
m_comps[0] = (uint8_t)y;
m_comps[1] = (uint8_t)y;
m_comps[2] = (uint8_t)y;
m_comps[3] = (uint8_t)255;
return *this;
}
inline color_rgba &set_noclamp_rgba(int sr, int sg, int sb, int sa)
{
m_comps[0] = (uint8_t)sr;
m_comps[1] = (uint8_t)sg;
m_comps[2] = (uint8_t)sb;
m_comps[3] = (uint8_t)sa;
return *this;
}
inline color_rgba &set(int y)
{
m_comps[0] = static_cast<uint8_t>(clamp<int>(y, 0, 255));
m_comps[1] = m_comps[0];
m_comps[2] = m_comps[0];
m_comps[3] = 255;
return *this;
}
inline color_rgba &set(int y, int na)
{
m_comps[0] = static_cast<uint8_t>(clamp<int>(y, 0, 255));
m_comps[1] = m_comps[0];
m_comps[2] = m_comps[0];
m_comps[3] = static_cast<uint8_t>(clamp<int>(na, 0, 255));
return *this;
}
inline color_rgba &set(int sr, int sg, int sb, int sa)
{
m_comps[0] = static_cast<uint8_t>(clamp<int>(sr, 0, 255));
m_comps[1] = static_cast<uint8_t>(clamp<int>(sg, 0, 255));
m_comps[2] = static_cast<uint8_t>(clamp<int>(sb, 0, 255));
m_comps[3] = static_cast<uint8_t>(clamp<int>(sa, 0, 255));
return *this;
}
inline color_rgba &set_rgb(int sr, int sg, int sb)
{
m_comps[0] = static_cast<uint8_t>(clamp<int>(sr, 0, 255));
m_comps[1] = static_cast<uint8_t>(clamp<int>(sg, 0, 255));
m_comps[2] = static_cast<uint8_t>(clamp<int>(sb, 0, 255));
return *this;
}
inline color_rgba &set_rgb(const color_rgba &other)
{
r = other.r;
g = other.g;
b = other.b;
return *this;
}
inline const uint8_t &operator[] (uint32_t index) const { assert(index < 4); return m_comps[index]; }
inline uint8_t &operator[] (uint32_t index) { assert(index < 4); return m_comps[index]; }
inline void clear()
{
m_comps[0] = 0;
m_comps[1] = 0;
m_comps[2] = 0;
m_comps[3] = 0;
}
inline bool operator== (const color_rgba &rhs) const
{
if (m_comps[0] != rhs.m_comps[0]) return false;
if (m_comps[1] != rhs.m_comps[1]) return false;
if (m_comps[2] != rhs.m_comps[2]) return false;
if (m_comps[3] != rhs.m_comps[3]) return false;
return true;
}
inline bool operator!= (const color_rgba &rhs) const
{
return !(*this == rhs);
}
inline bool operator<(const color_rgba &rhs) const
{
for (int i = 0; i < 4; i++)
{
if (m_comps[i] < rhs.m_comps[i])
return true;
else if (m_comps[i] != rhs.m_comps[i])
return false;
}
return false;
}
inline int get_601_luma() const { return (19595U * m_comps[0] + 38470U * m_comps[1] + 7471U * m_comps[2] + 32768U) >> 16U; }
inline int get_709_luma() const { return (13938U * m_comps[0] + 46869U * m_comps[1] + 4729U * m_comps[2] + 32768U) >> 16U; }
inline int get_luma(bool luma_601) const { return luma_601 ? get_601_luma() : get_709_luma(); }
static color_rgba comp_min(const color_rgba& a, const color_rgba& b) { return color_rgba(std::min(a[0], b[0]), std::min(a[1], b[1]), std::min(a[2], b[2]), std::min(a[3], b[3])); }
static color_rgba comp_max(const color_rgba& a, const color_rgba& b) { return color_rgba(std::max(a[0], b[0]), std::max(a[1], b[1]), std::max(a[2], b[2]), std::max(a[3], b[3])); }
};
bool unpack_bc7(const void *pBlock, color_rgba *pPixels);
} // namespace bc7decomp
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+2
View File
@@ -69,6 +69,7 @@
<ClCompile Include="StackWalker.cpp" />
<ClCompile Include="StringUtil.cpp" />
<ClCompile Include="SettingsWrapper.cpp" />
<ClCompile Include="TextureDecompress.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="WAVWriter.cpp" />
<ClCompile Include="WindowInfo.cpp" />
@@ -141,6 +142,7 @@
<ClInclude Include="RedtapeWindows.h" />
<ClInclude Include="SafeArray.h" />
<ClInclude Include="ThreadPool.h" />
<ClInclude Include="TextureDecompress.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="WAVWriter.h" />
<ClInclude Include="WindowInfo.h" />
+6
View File
@@ -142,6 +142,9 @@
<ClCompile Include="Assertions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TextureDecompress.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AlignedMalloc.h">
@@ -354,6 +357,9 @@
<ClInclude Include="Error.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TextureDecompress.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Source Files">
+8
View File
@@ -334,6 +334,14 @@ void Host::SetFullscreen(bool enabled)
{
}
void Host::OnCaptureStarted(const std::string& filename)
{
}
void Host::OnCaptureStopped()
{
}
void Host::RequestExit(bool allow_confirm)
{
}
+1 -8
View File
@@ -224,7 +224,6 @@ void AutoUpdaterDialog::getLatestReleaseComplete(QNetworkReply* reply)
bool is_symbols = false;
bool is_avx2 = false;
bool is_sse4 = false;
bool is_qt_asset = false;
bool is_perfect_match = false;
for (const QJsonValue& additional_tag : additional_tags_array)
{
@@ -235,12 +234,6 @@ void AutoUpdaterDialog::getLatestReleaseComplete(QNetworkReply* reply)
is_symbols = true;
break;
}
else if (additional_tag_str.startsWith(QStringLiteral("Qt")))
{
// found a qt build
// Note: The website improperly parses macOS file names, and gives them the tag "Qt.tar" instead of "Qt"
is_qt_asset = true;
}
else if (additional_tag_str == QStringLiteral("SSE4"))
{
is_sse4 = true;
@@ -258,7 +251,7 @@ void AutoUpdaterDialog::getLatestReleaseComplete(QNetworkReply* reply)
#endif
}
if (!is_qt_asset || is_symbols || (!x86caps.hasAVX2 && is_avx2))
if (is_symbols || (!x86caps.hasAVX2 && is_avx2))
{
// skip this asset
continue;
+20 -5
View File
@@ -68,9 +68,6 @@ target_sources(pcsx2-qt PRIVATE
Settings/ControllerSettingsDialog.h
Settings/ControllerSettingsDialog.ui
Settings/ControllerSettingWidgetBinder.h
Settings/CreateMemoryCardDialog.cpp
Settings/CreateMemoryCardDialog.h
Settings/CreateMemoryCardDialog.ui
Settings/DebugSettingsWidget.cpp
Settings/DebugSettingsWidget.h
Settings/DebugSettingsWidget.ui
@@ -114,6 +111,9 @@ target_sources(pcsx2-qt PRIVATE
Settings/MemoryCardConvertDialog.ui
Settings/MemoryCardConvertWorker.cpp
Settings/MemoryCardConvertWorker.h
Settings/MemoryCardCreateDialog.cpp
Settings/MemoryCardCreateDialog.h
Settings/MemoryCardCreateDialog.ui
Settings/MemoryCardSettingsWidget.cpp
Settings/MemoryCardSettingsWidget.h
Settings/MemoryCardSettingsWidget.ui
@@ -204,8 +204,23 @@ if(WIN32)
set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_SOURCE_DIR}/bin/translations")
qt_add_lrelease(pcsx2-qt TS_FILES ${TS_FILES})
elseif(APPLE)
# Hopefully macdeployqt will pick these up.
qt_add_lrelease(pcsx2-qt TS_FILES ${TS_FILES})
qt_add_lrelease(pcsx2-qt TS_FILES ${TS_FILES} QM_FILES_OUTPUT_VARIABLE QM_FILES)
set(PCSX2_MACOS_LOCALIZATIONS)
foreach (TS_FILE IN LISTS TS_FILES)
get_filename_component(TS_FILE_NAME ${TS_FILE} NAME)
set(regex "^pcsx2-qt_([a-zA-Z0-9\\-]+)\\.ts$")
if (TS_FILE_NAME MATCHES ${regex})
string(REGEX REPLACE ${regex} "\\1" language ${TS_FILE_NAME})
string(REPLACE "-" "_" language ${language})
set(PCSX2_MACOS_LOCALIZATIONS "${PCSX2_MACOS_LOCALIZATIONS}\n\t\t<string>${language}</string>")
else()
message(WARNING "Unrecognized ts file ${TS_FILE_NAME}")
endif()
endforeach()
foreach (QM_FILE IN LISTS QM_FILES)
target_sources(pcsx2-qt PRIVATE ${QM_FILE})
set_source_files_properties(${QM_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/translations/)
endforeach()
else()
# TODO: Copy base translations.
qt_add_lrelease(pcsx2-qt TS_FILES ${TS_FILES} QM_FILES_OUTPUT_VARIABLE QM_FILES)
+23 -9
View File
@@ -582,7 +582,7 @@ static std::vector<u32> searchWorker(DebugInterface* cpu, u32 start, u32 end, T
return hitAddresses;
}
static std::vector<u32> searchWorkerString(DebugInterface* cpu, u32 start, u32 end, std::string value)
static std::vector<u32> searchWorkerByteArray(DebugInterface* cpu, u32 start, u32 end, QByteArray value)
{
std::vector<u32> hitAddresses;
for (u32 addr = start; addr < end; addr += 1)
@@ -590,7 +590,7 @@ static std::vector<u32> searchWorkerString(DebugInterface* cpu, u32 start, u32 e
bool hit = true;
for (size_t i = 0; i < value.length(); i++)
{
if (static_cast<char>(cpu->read8(addr + i)) != value[i])
if (cpu->read8(addr + i) != value[i])
{
hit = false;
break;
@@ -624,7 +624,9 @@ std::vector<u32> startWorker(DebugInterface* cpu, int type, u32 start, u32 end,
case 5:
return searchWorker<double>(cpu, start, end, value.toDouble());
case 6:
return searchWorkerString(cpu, start, end, value.toStdString());
return searchWorkerByteArray(cpu, start, end, value.toUtf8());
case 7:
return searchWorkerByteArray(cpu, start, end, QByteArray::fromHex(value.toUtf8()));
default:
Console.Error("Debugger: Unknown type when doing memory search!");
break;
@@ -667,13 +669,24 @@ void CpuWidget::onSearchButtonClicked()
unsigned long long value;
if (searchType < 4)
switch (searchType)
{
value = searchValue.toULongLong(&ok, searchHex ? 16 : 10);
}
else if (searchType != 6)
{
searchValue.toDouble(&ok);
case 0:
case 1:
case 2:
case 3:
value = searchValue.toULongLong(&ok, searchHex ? 16 : 10);
break;
case 4:
case 5:
searchValue.toDouble(&ok);
break;
case 6:
ok = !searchValue.isEmpty();
break;
case 7:
ok = !searchValue.trimmed().isEmpty();
break;
}
if (!ok)
@@ -684,6 +697,7 @@ void CpuWidget::onSearchButtonClicked()
switch (searchType)
{
case 7:
case 6:
case 5:
case 4:
+5
View File
@@ -231,6 +231,11 @@
<string>String</string>
</property>
</item>
<item>
<property name="text">
<string>Array of byte</string>
</property>
</item>
</widget>
</item>
<item row="1" column="2">
+34 -6
View File
@@ -421,6 +421,8 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
connect(thread, &EmuThread::onVMResumed, this, &MainWindow::onVMResumed);
connect(thread, &EmuThread::onVMStopped, this, &MainWindow::onVMStopped);
connect(thread, &EmuThread::onGameChanged, this, &MainWindow::onGameChanged);
connect(thread, &EmuThread::onCaptureStarted, this, &MainWindow::onCaptureStarted);
connect(thread, &EmuThread::onCaptureStopped, this, &MainWindow::onCaptureStopped);
connect(m_ui.actionReset, &QAction::triggered, thread, &EmuThread::resetVM);
connect(m_ui.actionPause, &QAction::toggled, thread, &EmuThread::setVMPaused);
@@ -586,6 +588,10 @@ void MainWindow::onToolsVideoCaptureToggled(bool checked)
if (!s_vm_valid)
return;
// Reset the checked state, we'll get updated by the GS thread.
QSignalBlocker sb(m_ui.actionToolsVideoCapture);
m_ui.actionToolsVideoCapture->setChecked(!checked);
if (!checked)
{
g_emu_thread->endCapture();
@@ -599,15 +605,29 @@ void MainWindow::onToolsVideoCaptureToggled(bool checked)
QString path(QStringLiteral("%1.%2").arg(QString::fromStdString(GSGetBaseVideoFilename())).arg(container));
path = QFileDialog::getSaveFileName(this, tr("Video Capture"), path, filter);
if (path.isEmpty())
{
QSignalBlocker sb(m_ui.actionToolsVideoCapture);
m_ui.actionToolsVideoCapture->setChecked(false);
return;
}
g_emu_thread->beginCapture(path);
}
void MainWindow::onCaptureStarted(const QString& filename)
{
if (!s_vm_valid)
return;
QSignalBlocker sb(m_ui.actionToolsVideoCapture);
m_ui.actionToolsVideoCapture->setChecked(true);
}
void MainWindow::onCaptureStopped()
{
if (!s_vm_valid)
return;
QSignalBlocker sb(m_ui.actionToolsVideoCapture);
m_ui.actionToolsVideoCapture->setChecked(false);
}
void MainWindow::onSettingsTriggeredFromToolbar()
{
if (s_vm_valid)
@@ -2114,7 +2134,11 @@ SettingsDialog* MainWindow::getSettingsDialog()
connect(m_settings_dialog->getInterfaceSettingsWidget(), &InterfaceSettingsWidget::languageChanged, this, [this]() {
// reopen settings dialog after it applies
updateLanguage();
g_main_window->doSettings("Interface");
// If you doSettings now, on macOS, the window will somehow end up underneath the main window that was created above
// Delay it slightly...
QtHost::RunOnUIThread([]{
g_main_window->doSettings("Interface");
});
});
}
@@ -2124,7 +2148,11 @@ SettingsDialog* MainWindow::getSettingsDialog()
void MainWindow::doSettings(const char* category /* = nullptr */)
{
SettingsDialog* dlg = getSettingsDialog();
if (!dlg->isVisible())
if (dlg->isVisible())
{
dlg->raise();
}
else
{
dlg->setModal(false);
dlg->show();
+3
View File
@@ -183,6 +183,9 @@ private Q_SLOTS:
void onGameChanged(const QString& title, const QString& elf_override, const QString& disc_path,
const QString& serial, quint32 disc_crc, quint32 crc);
void onCaptureStarted(const QString& filename);
void onCaptureStopped();
protected:
void showEvent(QShowEvent* event) override;
void closeEvent(QCloseEvent* event) override;
+11 -11
View File
@@ -274,7 +274,7 @@
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">Start &amp;File...</string>
<string comment="In Toolbar">Start File</string>
</property>
</action>
<action name="actionStartDisc">
@@ -292,7 +292,7 @@
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">Start &amp;Disc...</string>
<string comment="In Toolbar">Start Disc</string>
</property>
</action>
<action name="actionStartBios">
@@ -310,7 +310,7 @@
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">Start &amp;BIOS</string>
<string comment="In Toolbar">Start BIOS</string>
</property>
</action>
<action name="actionScanForNewGames">
@@ -346,7 +346,7 @@
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">Shut &amp;Down</string>
<string comment="In Toolbar">Shut Down</string>
</property>
</action>
<action name="actionPowerOffWithoutSaving">
@@ -373,7 +373,7 @@
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">&amp;Reset</string>
<string comment="In Toolbar">Reset</string>
</property>
</action>
<action name="actionPause">
@@ -397,7 +397,7 @@
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">&amp;Pause</string>
<string comment="In Toolbar">Pause</string>
</property>
</action>
<action name="actionToolbarLoadState">
@@ -406,7 +406,7 @@
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">&amp;Load State</string>
<string comment="In Toolbar">Load State</string>
</property>
</action>
<action name="actionToolbarSaveState">
@@ -415,7 +415,7 @@
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">&amp;Save State</string>
<string comment="In Toolbar">Save State</string>
</property>
</action>
<action name="actionExit">
@@ -460,7 +460,7 @@
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">&amp;Controllers</string>
<string comment="In Toolbar">Controllers</string>
</property>
</action>
<action name="actionHotkeySettings">
@@ -635,7 +635,7 @@
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">&amp;Settings</string>
<string comment="In Toolbar">Settings</string>
</property>
<property name="menuRole">
<enum>QAction::PreferencesRole</enum>
@@ -681,7 +681,7 @@
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">&amp;Screenshot</string>
<string comment="In Toolbar">Screenshot</string>
</property>
</action>
<action name="actionMemoryCardSettings">
+10
View File
@@ -1186,6 +1186,16 @@ void Host::SetFullscreen(bool enabled)
g_emu_thread->setFullscreen(enabled, true);
}
void Host::OnCaptureStarted(const std::string& filename)
{
emit g_emu_thread->onCaptureStarted(QString::fromStdString(filename));
}
void Host::OnCaptureStopped()
{
emit g_emu_thread->onCaptureStopped();
}
bool QtHost::InitializeConfig()
{
if (!EmuFolders::InitializeCriticalFolders())
+4
View File
@@ -158,6 +158,10 @@ Q_SIGNALS:
/// Called when achievements are reloaded/refreshed (e.g. game change, login, option change).
void onAchievementsRefreshed(quint32 id, const QString& game_info_string, quint32 total, quint32 points);
/// Called when video capture starts/stops.
void onCaptureStarted(const QString& filename);
void onCaptureStopped();
protected:
void run();
@@ -101,7 +101,10 @@ void ControllerSettingsDialog::onCurrentProfileChanged(int index)
void ControllerSettingsDialog::onNewProfileClicked()
{
const QString profile_name(QInputDialog::getText(this, tr("Create Input Profile"), tr("Enter the name for the new input profile:")));
const QString profile_name(QInputDialog::getText(this, tr("Create Input Profile"),
tr("Custom input profiles are used to override the Shared input profile for specific games.\n"
"To apply a custom input profile to a game, go to its Game Properties, then change the 'Input Profile' on the Summary tab.\n\n"
"Enter the name for the new input profile:")));
if (profile_name.isEmpty())
return;
@@ -1479,6 +1479,16 @@
<string extracomment="Lottes = Timothy Lottes, the creator of the shader filter. Leave as-is. CRT= Cathode Ray Tube, an old type of television technology.">Lottes CRT</string>
</property>
</item>
<item>
<property name="text">
<string>4xRGSS downsampling (4x Rotated Grid SuperSampling)</string>
</property>
</item>
<item>
<property name="text">
<string>NxAGSS downsampling (Nx Automatic Grid SuperSampling)</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
+7 -2
View File
@@ -74,9 +74,14 @@ void InputBindingWidget::initialize(
void InputBindingWidget::updateText()
{
const QString binding_tip(tr("\n\nLeft click to assign a new button\nShift + left click for additional bindings"));
const QString binding_clear_tip(tr("\nRight click to clear binding"));
if (m_bindings.empty())
{
setText(QString());
setToolTip(tr("No bindings registered") + binding_tip);
}
else if (m_bindings.size() > 1)
{
@@ -93,12 +98,12 @@ void InputBindingWidget::updateText()
ss << "\n";
ss << binding;
}
setToolTip(QString::fromStdString(ss.str()));
setToolTip(QString::fromStdString(ss.str()) + binding_tip + binding_clear_tip);
}
else
{
QString binding_text(QString::fromStdString(m_bindings[0]));
setToolTip(binding_text);
setToolTip(binding_text + binding_tip + binding_clear_tip);
// fix up accelerators, and if it's too long, ellipsise it
if (binding_text.contains('&'))
@@ -22,12 +22,12 @@
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QPushButton>
#include "Settings/CreateMemoryCardDialog.h"
#include "Settings/MemoryCardCreateDialog.h"
#include "pcsx2/MemoryCardFile.h"
#include "pcsx2/System.h"
CreateMemoryCardDialog::CreateMemoryCardDialog(QWidget* parent /* = nullptr */)
MemoryCardCreateDialog::MemoryCardCreateDialog(QWidget* parent /* = nullptr */)
: QDialog(parent)
{
m_ui.setupUi(this);
@@ -35,7 +35,7 @@ CreateMemoryCardDialog::CreateMemoryCardDialog(QWidget* parent /* = nullptr */)
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
connect(m_ui.name, &QLineEdit::textChanged, this, &CreateMemoryCardDialog::nameTextChanged);
connect(m_ui.name, &QLineEdit::textChanged, this, &MemoryCardCreateDialog::nameTextChanged);
connect(m_ui.size8MB, &QRadioButton::clicked, this, [this]() { setType(MemoryCardType::File, MemoryCardFileType::PS2_8MB); });
connect(m_ui.size16MB, &QRadioButton::clicked, this, [this]() { setType(MemoryCardType::File, MemoryCardFileType::PS2_16MB); });
@@ -46,9 +46,9 @@ CreateMemoryCardDialog::CreateMemoryCardDialog(QWidget* parent /* = nullptr */)
disconnect(m_ui.buttonBox, &QDialogButtonBox::accepted, this, nullptr);
connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &CreateMemoryCardDialog::createCard);
connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &CreateMemoryCardDialog::close);
connect(m_ui.buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &CreateMemoryCardDialog::restoreDefaults);
connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &MemoryCardCreateDialog::createCard);
connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &MemoryCardCreateDialog::close);
connect(m_ui.buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &MemoryCardCreateDialog::restoreDefaults);
#ifndef _WIN32
m_ui.ntfsCompression->setEnabled(false);
@@ -57,9 +57,9 @@ CreateMemoryCardDialog::CreateMemoryCardDialog(QWidget* parent /* = nullptr */)
updateState();
}
CreateMemoryCardDialog::~CreateMemoryCardDialog() = default;
MemoryCardCreateDialog::~MemoryCardCreateDialog() = default;
void CreateMemoryCardDialog::nameTextChanged()
void MemoryCardCreateDialog::nameTextChanged()
{
QString controlName(m_ui.name->text());
const int cursorPos = m_ui.name->cursorPosition();
@@ -76,14 +76,14 @@ void CreateMemoryCardDialog::nameTextChanged()
updateState();
}
void CreateMemoryCardDialog::setType(MemoryCardType type, MemoryCardFileType fileType)
void MemoryCardCreateDialog::setType(MemoryCardType type, MemoryCardFileType fileType)
{
m_type = type;
m_fileType = fileType;
updateState();
}
void CreateMemoryCardDialog::restoreDefaults()
void MemoryCardCreateDialog::restoreDefaults()
{
setType(MemoryCardType::File, MemoryCardFileType::PS2_8MB);
m_ui.size8MB->setChecked(true);
@@ -94,7 +94,7 @@ void CreateMemoryCardDialog::restoreDefaults()
m_ui.sizeFolder->setChecked(false);
}
void CreateMemoryCardDialog::updateState()
void MemoryCardCreateDialog::updateState()
{
const bool okay = (m_ui.name->text().length() > 0);
@@ -104,30 +104,27 @@ void CreateMemoryCardDialog::updateState()
#endif
}
void CreateMemoryCardDialog::createCard()
void MemoryCardCreateDialog::createCard()
{
QString name(m_ui.name->text());
std::string nameStr;
if (m_fileType == MemoryCardFileType::PS1)
const QString name = m_ui.name->text();
const std::string name_str = QStringLiteral("%1.%2").arg(name)
.arg((m_fileType == MemoryCardFileType::PS1) ? QStringLiteral("mcr") : QStringLiteral("ps2"))
.toStdString();
if (!Path::IsValidFileName(name_str, false))
{
name += QStringLiteral(".mcr");
}
else
{
name += QStringLiteral(".ps2");
QMessageBox::critical(this, tr("Create Memory Card"),
tr("Failed to create the Memory Card, because the name '%1' contains one or more invalid characters.").arg(name));
return;
}
nameStr = name.toStdString();
if (FileMcd_GetCardInfo(nameStr).has_value())
if (FileMcd_GetCardInfo(name_str).has_value())
{
QMessageBox::critical(this, tr("Create Memory Card"),
tr("Failed to create the Memory Card, because another card with the name '%1' already exists.").arg(name));
return;
}
if (!FileMcd_CreateNewCard(nameStr, m_type, m_fileType))
if (!FileMcd_CreateNewCard(name_str, m_type, m_fileType))
{
QMessageBox::critical(this, tr("Create Memory Card"),
tr("Failed to create the Memory Card, the log may contain more information."));
@@ -137,7 +134,7 @@ void CreateMemoryCardDialog::createCard()
#ifdef _WIN32
if (m_ui.ntfsCompression->isChecked() && m_type == MemoryCardType::File)
{
const std::string fullPath(Path::Combine(EmuFolders::MemoryCards, nameStr));
const std::string fullPath(Path::Combine(EmuFolders::MemoryCards, name_str));
FileSystem::SetPathCompression(fullPath.c_str(), true);
}
#endif
@@ -17,17 +17,17 @@
#include <QtWidgets/QDialog>
#include "ui_CreateMemoryCardDialog.h"
#include "ui_MemoryCardCreateDialog.h"
#include "pcsx2/Config.h"
class CreateMemoryCardDialog final : public QDialog
class MemoryCardCreateDialog final : public QDialog
{
Q_OBJECT
public:
explicit CreateMemoryCardDialog(QWidget* parent = nullptr);
~CreateMemoryCardDialog();
explicit MemoryCardCreateDialog(QWidget* parent = nullptr);
~MemoryCardCreateDialog();
private Q_SLOTS:
void nameTextChanged();
@@ -38,7 +38,7 @@ private:
void restoreDefaults();
void updateState();
Ui::CreateMemoryCardDialog m_ui;
Ui::MemoryCardCreateDialog m_ui;
MemoryCardType m_type = MemoryCardType::File;
MemoryCardFileType m_fileType = MemoryCardFileType::PS2_8MB;
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CreateMemoryCardDialog</class>
<widget class="QDialog" name="CreateMemoryCardDialog">
<class>MemoryCardCreateDialog</class>
<widget class="QDialog" name="MemoryCardCreateDialog">
<property name="geometry">
<rect>
<x>0</x>
@@ -285,7 +285,7 @@
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>CreateMemoryCardDialog</receiver>
<receiver>MemoryCardCreateDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
@@ -301,7 +301,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>CreateMemoryCardDialog</receiver>
<receiver>MemoryCardCreateDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
@@ -24,8 +24,8 @@
#include "common/StringUtil.h"
#include "CreateMemoryCardDialog.h"
#include "MemoryCardConvertDialog.h"
#include "MemoryCardCreateDialog.h"
#include "MemoryCardSettingsWidget.h"
#include "QtHost.h"
#include "QtUtils.h"
@@ -186,7 +186,7 @@ void MemoryCardSettingsWidget::ejectSlot(u32 slot)
void MemoryCardSettingsWidget::createCard()
{
CreateMemoryCardDialog dialog(QtUtils::GetRootWidget(this));
MemoryCardCreateDialog dialog(QtUtils::GetRootWidget(this));
if (dialog.exec() == QDialog::Accepted)
refresh();
}
+3 -3
View File
@@ -111,11 +111,11 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
if (isPerGameSettings() && game && game->crc != 0)
{
addWidget(m_game_patch_settings_widget = new GamePatchSettingsWidget(game, this, m_ui.settingsContainer),
tr("Patches"), QStringLiteral("tools-line"),
tr("Patches"), QStringLiteral("band-aid-line"),
tr("<strong>Patches</strong><hr>This section allows you to select optional patches to apply to the game, "
"which may provide performance, visual, or gameplay improvements."));
addWidget(m_game_cheat_settings_widget = new GameCheatSettingsWidget(game, this, m_ui.settingsContainer),
tr("Cheats"), QStringLiteral("flask-line"),
tr("Cheats"), QStringLiteral("cheats-line"),
tr("<strong>Cheats</strong><hr>This section allows you to select which cheats you wish to enable. You "
"cannot enable/disable cheats without labels for old-format pnach files, those will automatically "
"activate if the main cheat enable option is checked."));
@@ -125,7 +125,7 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
if (show_advanced_settings && isPerGameSettings())
{
addWidget(m_game_fix_settings_widget = new GameFixSettingsWidget(this, m_ui.settingsContainer), tr("Game Fixes"),
QStringLiteral("hammer-line"),
QStringLiteral("tools-line"),
tr("<strong>Game Fixes Settings</strong><hr>Game Fixes can work around incorrect emulation in some titles.<br>However, they can "
"also cause problems in games if used incorrectly.<br>It is best to leave them all disabled unless advised otherwise."));
}
+57 -8
View File
@@ -39,6 +39,17 @@
#include <ShlObj.h>
#endif
#if 0
// Qt internal strings we'd like to have translated
QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "Services")
QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "Hide %1")
QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "Hide Others")
QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "Show All")
QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "Preferences...")
QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "Quit %1")
QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "About %1")
#endif
namespace QtHost
{
struct GlyphInfo
@@ -59,6 +70,34 @@ namespace QtHost
static std::vector<QTranslator*> s_translators;
static QString getSystemLanguage() {
std::vector<std::pair<QString, QString>> available = QtHost::GetAvailableLanguageList();
QString locale = QLocale::system().name();
locale.replace('_', '-');
// Can we find an exact match?
for (const std::pair<QString, QString>& entry : available)
{
if (entry.second == locale)
return locale;
}
// How about a partial match?
QStringView lang = QStringView(locale);
lang = lang.left(lang.indexOf('-'));
for (const std::pair<QString, QString>& entry : available)
{
QStringView avail = QStringView(entry.second);
avail = avail.left(avail.indexOf('-'));
if (avail == lang) {
Console.Warning("Couldn't find translation for system language %s, using %s instead",
locale.toStdString().c_str(), entry.second.toStdString().c_str());
return entry.second;
}
}
// No matches :(
Console.Warning("Couldn't find translation for system language %s, using en instead", locale.toStdString().c_str());
return QStringLiteral("en");
}
void QtHost::InstallTranslator()
{
for (QTranslator* translator : s_translators)
@@ -68,11 +107,17 @@ void QtHost::InstallTranslator()
}
s_translators.clear();
const QString language =
QString language =
QString::fromStdString(Host::GetBaseStringSettingValue("UI", "Language", GetDefaultLanguage()));
if (language == QStringLiteral("system"))
language = getSystemLanguage();
// Install the base qt translation first.
#ifdef __APPLE__
const QString base_dir = QStringLiteral("%1/../Resources/translations").arg(qApp->applicationDirPath());
#else
const QString base_dir = QStringLiteral("%1/translations").arg(qApp->applicationDirPath());
#endif
QString base_path = QStringLiteral("%1/qt_%2.qm").arg(base_dir).arg(language);
bool has_base_ts = QFile::exists(base_path);
if (!has_base_ts)
@@ -157,9 +202,12 @@ static std::string QtHost::GetFontPath(const GlyphInfo* gi)
}
else
{
font_path = fmt::format("C:\\Windows\\Fonts\\%s", gi->windows_font_name);
font_path = fmt::format("C:\\Windows\\Fonts\\{}", gi->windows_font_name);
}
}
#elif defined(__APPLE__)
if (gi->mac_font_name)
font_path = fmt::format("/System/Library/Fonts/{}", gi->mac_font_name);
#endif
return font_path;
@@ -167,7 +215,7 @@ static std::string QtHost::GetFontPath(const GlyphInfo* gi)
const char* QtHost::GetDefaultLanguage()
{
return "en";
return "system";
}
s32 Host::Internal::GetTranslatedStringImpl(
@@ -190,6 +238,7 @@ s32 Host::Internal::GetTranslatedStringImpl(
std::vector<std::pair<QString, QString>> QtHost::GetAvailableLanguageList()
{
return {
{QCoreApplication::translate("InterfaceSettingsWidget", "System Language [Default]"), QStringLiteral("system")},
{QStringLiteral("Afrikaans (af-ZA)"), QStringLiteral("af-ZA")},
{QStringLiteral("عربي (ar-SA)"), QStringLiteral("ar-SA")},
{QStringLiteral("Català (ca-ES)"), QStringLiteral("ca-ES")},
@@ -197,7 +246,7 @@ std::vector<std::pair<QString, QString>> QtHost::GetAvailableLanguageList()
{QStringLiteral("Dansk (da-DK)"), QStringLiteral("da-DK")},
{QStringLiteral("Deutsch (de-DE)"), QStringLiteral("de-DE")},
{QStringLiteral("Ελληνικά (el-GR)"), QStringLiteral("el-GR")},
{QStringLiteral("English (en) [Default]"), QStringLiteral("en")},
{QStringLiteral("English (en)"), QStringLiteral("en")},
{QStringLiteral("Español (Hispanoamérica) (es-419)"), QStringLiteral("es-419")},
{QStringLiteral("Español (España) (es-ES)"), QStringLiteral("es-ES")},
{QStringLiteral("فارسی (fa-IR)"), QStringLiteral("fa-IR")},
@@ -286,22 +335,22 @@ static constexpr const QtHost::GlyphInfo s_glyph_info[] = {
{ "uk-UA", nullptr, nullptr, nullptr, s_cyrillic_ranges },
{
"ja-JP", "msgothic.ttc", nullptr, nullptr,
"ja-JP", "msgothic.ttc", nullptr, "ヒラギノ角ゴシック W3.ttc",
// auto update by update_glyph_ranges.py with pcsx2-qt_ja-JP.ts
u"​​□□△△◯◯✕✕、。〜〜ああいいううええおきくぐここささしすせせそそただっつてにのはびびへべほほまみめもややよれわわをんァイウコサソタチッツテニネパビロワワンンーー一一上下不不中中丸丸了了互互今今他他代代仮仮作作使使保保信信修修倍倍値値停停備備像像入入全全公公内内再再出出切切別別利利制制削削副副割割力力加加効効動動勧勧化化十十南南参参反収取取古古可台右右合合同名向向回回固固国国在在報報場場境境壊壊変変外外大大失失奨奨始始字存完完定定実実左左帰帰常常幅幅度度式式張張形形待待後後御御性性情情想想意意感感態態成成投投択択拡拡推推提提換換敗敗数数整整新新方方既既日日明明時時更更書書替最有有期期本本果果検検標標橙橙機機止正毎毎比比況況注注消消港港湾湾準準無無照照状状率率現現璧璧環環生生用用画画異異的的直直知知確確示示種種稿稿空空索索終終緑緑編編績績能能自自般般行行表表製製複複視視覧覧解解言言設設認認語語読読赤赤起起跡跡転転軸軸込込近近追追送送通通速速進進遅遅遊遊適適選選部部長長閉閉開開関関防防限限除除隅隅集集青青非非面面韓韓音音類類香香高高黄黄++??"
},
{
"ko-KR", "malgun.ttf", nullptr, nullptr,
"ko-KR", "malgun.ttf", nullptr, "AppleSDGothicNeo.ttc",
// auto update by update_glyph_ranges.py with pcsx2-qt_ko-KR.ts
u""
},
{
"zh-CN", "msyh.ttc", nullptr, nullptr,
"zh-CN", "msyh.ttc", nullptr, "Hiragino Sans GB.ttc",
// auto update by update_glyph_ranges.py with pcsx2-qt_zh-CN.ts
u"‘’□□△△○○、。一丁三下不与且且世世丢丢两两个个中中丰丰串串为主么义之之乎乎乐乐乘乘也也了了事二于于互互亚些交交产产享享亮亮亲亲人人什什仅仅介介仍从他他代以们们件价任任份份伍伍休休优优会会传传估估伸伸似似但但位住佑佑体体何何余余作作佣佣佳佳使使例例供供侧侧便便俄俄保保信信修修倍倍值值倾倾假假偏偏做做停停储储像像儿儿允允元元充充先光克克免免入入全全六六兰共关关兵典兼兼内内册再写写冲决况况净净准准减减几几出击函函刀刀刃刃分切列列则则创创删删利利别别到到制刷刹刹前前剪剪副副力力功务动助势势勿勿包包化化匹区十十升升半半协协单单南南占卡卫卫印印即即压压原原去去参参及及双反发发取变叠叠口古另另只只可台右右号号各各合吉同后向向吗吗否否含含启启呈呈告告员员味味命命和和哈哈响响哪哪唤唤商商善善器器四四回回因因团团围围国图圈圈在在地地场场址址均均坏坐块块坛坛垂垂型型域域基基堆堆堪堪塔塔填填增增士士声声处处备备复复外外多多够够大大天太失失头头夹夹奇奇奏奏套套奥奥奶奶好好如如始始威威娱娱婴婴媒媒子子字存它它安安完完宏宏官官定定宝实害害家家容容宽宽宿宿寄寄密密富富寸对导导封封射射将将小小少少尔尔尚尚尝尝就就尺尺尼尾局局层层屏屏展展属属崩崩工左巨巨差差己已巴巴希希带帧帮帮常常幅幅幕幕平平并并幸幸序序库底度度延延建建开开异弃弊弊式式引引张张弹强归当录录形形彩彩影影径待很很得得循循微微德德心心必忆志志忙忙快快忽忽态态性性怪怪恢恢息息您您悬悬情情惑惑惯惯意意感感慢慢戏我或或战战截截戳戳户户所扁手手打打托托执执扩扩扫扬扳扳找找技技抑抑抖抗护护拆拆拉拉拍拍拒拒拟拟拦拦择择括括拳拳持持指指按按挑挑挡挡挪挪振振捕捕损损换换据据掌掌排排接接控掩描提插插握握搜搜摇摇撕撕撤撤播播操擎支支收收改改放放故故效效敏敏散散数数整整文文断断斯新方方旋旋无无日日旧旧时时明明易易星映是是显显晕晕普普晰晰暂暂暗暗曲曲更更替最有有服服期期未未本本机机权权杆杆束束条条来来板板极极果果柄柄某某染染查查栅栅标栈栏栏校校样根格格框框案案档档桥桥检检棕棕榜榜模模橙橙次次欧欧止步死死殊殊段段每每比比毫毫水水求求汇汇没没油油法法波波注注泻泻洲洲活活流流浅浅测测浏浏浪浪浮浮海海消消深深混混添添清清港港渲渲游游湖湖湾湾溃溃源源溢溢滑滑满满滤滤演演澳澳激激灰灰灵灵点点烈烈热热焦焦然然煞煞照照片版牌牌牙牙特特状状狂狂独独狼狼猎猎猩猩率率王王玩玩环现班班理理瑞瑞甚甚生生用用由甲电电画画畅畅界界留留略略疤疤登登白百的的皇皇盖盘目目直直相相省省看看真眠着着知知短短石石码码破破础础硬硬确确碌碌磁磁示示神神禁禁离离种种秒秒积称移移程程稍稍稳稳空空突突窗窗立立站站端端符符第第等等筛筛签签简简算算管管类类粉粉粘粘精精糊糊系系素素索索紫紫纠纠红红级级纯纯纳纳纹纹线线组组细终经经绑绑结结绕绕绘给络绝统统继继绪绪续续维维绿缀缓缓编编缩缩网网罗罗置置美美翻翻考考者者而而耗耗耳耳联联肩肩胖胖能能腊腊自自至致舍舍良良色色节节芬芬英英范范荐荐荷荷莱莱获获菜菜萄萄著著葡葡蓝蓝藏藏虑虑虚虚融融行行衡衡补补表表被被裁裂装装西西要要覆覆观观规规视视览觉角角解解触触言言警警计计认认让让议议记记许许论论设访证证诊诊译译试试询询该详语语误误说说请诸读读调调谍谍豹豹负负败账质质贴贴费费赛赛起起超超越越足足跟跟跨跨路路跳跳踏踏踪踪身身车车轨轨转转轮软轴轴轻轻载载较较辅辅辑辑输输辨辨边边达达过过运近还这进进连迟述述追追退适选选逐逐递递通通速造遇遇道道避避那那部部都都配配醒醒采采释释里重量量针针钮钮铁铁铺铺链链销锁锐锐错错键锯镜镜长长门门闭问闲闲间间队队防防阴阴附附陆陆降降限限除除险险随隐隔隔隙隙障障雄雄集集零零雾雾需需震震静静非非靠靠面面韩韩音音顶顶项须顿顿预预频频题题颜额风风饱饱馈馈首首香香马马驱驱验验高高鬼鬼魂魂魔魔麦麦黄黄黑黑默默鼓鼓鼠鼠齐齐齿齿,,??"
},
{
"zh-TW", "msyh.ttc", nullptr, nullptr,
"zh-TW", "msyh.ttc", nullptr, "Hiragino Sans GB.ttc",
// auto update by update_glyph_ranges.py with pcsx2-qt_zh-TW.ts
u""
},
File diff suppressed because it is too large Load Diff
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
OPTS="-tr-function-alias QT_TRANSLATE_NOOP+=TRANSLATE,QT_TRANSLATE_NOOP+=TRANSLATE_SV,QT_TRANSLATE_NOOP+=TRANSLATE_STR,QT_TRANSLATE_N_NOOP3+=TRANSLATE_FMT,QT_TRANSLATE_NOOP+=TRANSLATE_NOOP"
SRCDIRS=$(realpath "$SCRIPTDIR/..")/\ $(realpath "$SCRIPTDIR/../../pcsx2")/
OUTDIR=$(realpath "$SCRIPTDIR")
lupdate $SRCDIRS $OPTS -no-obsolete -source-language en -ts "$OUTDIR/pcsx2-qt_en.ts"
+4 -4
View File
@@ -105,7 +105,7 @@
<ClCompile Include="Settings\BIOSSettingsWidget.cpp" />
<ClCompile Include="Settings\ControllerBindingWidgets.cpp" />
<ClCompile Include="Settings\ControllerGlobalSettingsWidget.cpp" />
<ClCompile Include="Settings\CreateMemoryCardDialog.cpp" />
<ClCompile Include="Settings\MemoryCardCreateDialog.cpp" />
<ClCompile Include="Settings\EmulationSettingsWidget.cpp" />
<ClCompile Include="Settings\GameListSettingsWidget.cpp" />
<ClCompile Include="Settings\GraphicsSettingsWidget.cpp" />
@@ -172,7 +172,7 @@
<QtMoc Include="Settings\GamePatchSettingsWidget.h" />
<ClInclude Include="Settings\HddCreateQt.h" />
<QtMoc Include="Settings\GameSummaryWidget.h" />
<QtMoc Include="Settings\CreateMemoryCardDialog.h" />
<QtMoc Include="Settings\MemoryCardCreateDialog.h" />
<QtMoc Include="Settings\AchievementLoginDialog.h" />
<QtMoc Include="Settings\AchievementSettingsWidget.h" />
<QtMoc Include="GameList\GameListModel.h" />
@@ -212,7 +212,7 @@
<ClCompile Include="$(IntDir)Settings\moc_ControllerBindingWidgets.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_ControllerGlobalSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_ControllerSettingsDialog.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_CreateMemoryCardDialog.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_MemoryCardCreateDialog.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_EmulationSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_GameListSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_GraphicsSettingsWidget.cpp" />
@@ -312,7 +312,7 @@
<QtUi Include="Settings\ControllerGlobalSettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\CreateMemoryCardDialog.ui">
<QtUi Include="Settings\MemoryCardCreateDialog.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\AudioSettingsWidget.ui">
+4 -4
View File
@@ -190,10 +190,10 @@
<ClCompile Include="Settings\AudioSettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_CreateMemoryCardDialog.cpp">
<ClCompile Include="$(IntDir)Settings\moc_MemoryCardCreateDialog.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="Settings\CreateMemoryCardDialog.cpp">
<ClCompile Include="Settings\MemoryCardCreateDialog.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\DEV9DnsHostDialog.cpp">
@@ -423,7 +423,7 @@
<QtMoc Include="Settings\AudioSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\CreateMemoryCardDialog.h">
<QtMoc Include="Settings\MemoryCardCreateDialog.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\DEV9DnsHostDialog.h">
@@ -549,7 +549,7 @@
<QtUi Include="Settings\AudioSettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\CreateMemoryCardDialog.ui">
<QtUi Include="Settings\MemoryCardCreateDialog.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\DEV9DnsHostDialog.ui">
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 26.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="bandaid"
x="0px"
y="0px"
viewBox="0 0 21.6 21.6"
style="enable-background:new 0 0 21.6 21.6"
xml:space="preserve"
sodipodi:docname="band-aid-line-dark.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs8" /><sodipodi:namedview
id="namedview6"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
showgrid="false"
inkscape:zoom="35.231481"
inkscape:cx="10.785808"
inkscape:cy="10.785808"
inkscape:window-width="1920"
inkscape:window-height="956"
inkscape:window-x="0"
inkscape:window-y="42"
inkscape:window-maximized="1"
inkscape:current-layer="bandaid" />
<style
type="text/css"
id="style2">
.st0{fill:#FFFFFF;}
</style>
<path
id="By_Maxihplay"
class="st0"
d="M16.4,10.8L19,8.3c1-1,1-2.7,0-3.8l-1.9-1.9c-0.5-0.5-1.2-0.8-1.9-0.8s-1.4,0.3-1.9,0.8 l-2.5,2.5L8.3,2.6c-1-1-2.7-1-3.8,0L2.6,4.5c-1,1-1,2.7,0,3.8l2.5,2.5l-2.5,2.5c-1,1-1,2.7,0,3.8L4.5,19c0.5,0.5,1.2,0.8,1.9,0.8 s1.4-0.3,1.9-0.8l2.5-2.5l2.5,2.5c1,1,2.7,1,3.8,0l1.9-1.9c1-1,1-2.7,0-3.8L16.4,10.8z M8.4,9.8c0.5,0,0.9,0.4,0.9,0.9 s-0.4,0.9-0.9,0.9s-0.9-0.4-0.9-0.9C7.6,10.2,8,9.8,8.4,9.8z M7.1,17.8c-0.2,0.2-0.5,0.3-0.7,0.3S5.8,18,5.6,17.8L3.8,16 c-0.4-0.4-0.4-1.1,0-1.5L6.3,12l3.3,3.3C9.7,15.3,7.1,17.8,7.1,17.8z M10.8,13.8c-0.5,0-0.9-0.4-0.9-0.9s0.4-0.9,0.9-0.9 s0.9,0.4,0.9,0.9C11.7,13.5,11.3,13.8,10.8,13.8z M10.8,9.1c-0.5,0-0.9-0.4-0.9-0.9s0.4-0.9,0.9-0.9s0.9,0.4,0.9,0.9 S11.3,9.1,10.8,9.1z M13.2,11.5c-0.5,0-0.9-0.4-0.9-0.9s0.4-0.9,0.9-0.9s0.9,0.4,0.9,0.9C14.1,11.1,13.7,11.5,13.2,11.5z M11.9,6.3 l2.5-2.5c0.2-0.2,0.5-0.3,0.7-0.3c0.3,0,0.5,0.1,0.7,0.3l1.9,1.9c0.4,0.4,0.4,1.1,0,1.5l-2.5,2.5L11.9,6.3z"
style="fill:#000000" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="cheats" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1{fill:none;}.cls-2{fill-rule:evenodd;}</style></defs><g id="tela"><g><path class="cls-1" d="M0,0H24V24H0V0Z"/><path d="M2,4c0-.5,.5-1,1-1H21c.5,0,1,.4,1,1v14c0,.5-.5,1-1,1H3c-.5,0-1-.5-1-1h0V4Zm2,1v12H20V5H4Zm1,15h14v2H5v-2Z"/></g></g><g id="by_maxihplay"><path class="cls-2" d="M13.4,6.7c-1.1-1.2-2.6-.9-4,0-1.4-.9-2.9-1.1-4,0-.3,.4-.4,.9-.5,1.4-.2,1.1,.3,2.3,1.1,3.1l3.4,3.5,3.4-3.5c.8-.8,1.3-1.9,1.1-3.1,0-.5-.1-1-.5-1.4Z"/><path d="M17.1,12.2c.6,0,1,.2,1.5,.6,.4,.4,.6,.9,.6,1.5s-.2,1.1-.6,1.5c-.4,.4-.9,.6-1.5,.6s-1.3-.4-1.8-1c-.6,.7-1.2,1-1.8,1s-1.1-.2-1.4-.6c-.4-.4-.6-.9-.6-1.5s.2-1.1,.6-1.5c.4-.4,.9-.6,1.4-.6,.6,0,1.3,.4,1.8,1.1,.6-.8,1.2-1.1,1.8-1.1Zm-3.7,3c.4,0,.8-.3,1.2-.9-.4-.6-.8-.9-1.2-.9-.2,0-.3,0-.5,.1s-.3,.2-.3,.3-.1,.3-.1,.4c0,.2,.1,.5,.3,.6,.1,.3,.3,.4,.6,.4h0Zm3.9,0h.3c.1,0,.2-.1,.3-.1s.1-.1,.1-.2,.1-.2,.1-.3v-.3c0-.2-.1-.5-.3-.6-.2-.2-.4-.3-.7-.3-.4,0-.8,.3-1.2,.9,.6,.6,1,.9,1.4,.9h0Z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g>
<path fill="none" d="M0 0H24V24H0z"/>
<path d="M16 2v2h-1v3.243c0 1.158.251 2.301.736 3.352l4.282 9.276c.347.753.018 1.644-.734 1.99-.197.092-.411.139-.628.139H5.344c-.828 0-1.5-.672-1.5-1.5 0-.217.047-.432.138-.629l4.282-9.276C8.749 9.545 9 8.401 9 7.243V4H8V2h8zm-2.612 8.001h-2.776c-.104.363-.23.721-.374 1.071l-.158.361L6.125 20h11.749l-3.954-8.567c-.214-.464-.392-.943-.532-1.432zM11 7.243c0 .253-.01.506-.029.758h2.058c-.01-.121-.016-.242-.021-.364L13 7.243V4h-2v3.243z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 580 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 2C20.5523 2 21 2.44772 21 3V8C21 8.55228 20.5523 9 20 9H15V22C15 22.5523 14.5523 23 14 23H10C9.44772 23 9 22.5523 9 22V9H3.5C2.94772 9 2.5 8.55228 2.5 8V5.61803C2.5 5.23926 2.714 4.893 3.05279 4.72361L8.5 2H20ZM15 4H8.97214L4.5 6.23607V7H11V21H13V7H15V4ZM19 4H17V7H19V4Z" fill="#000000"></path></svg>

Before

Width:  |  Height:  |  Size: 373 B

@@ -1,61 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="svg5"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
sodipodi:docname="heart-monitor-line-black.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:document-units="px"
showgrid="false"
inkscape:zoom="1.3037281"
inkscape:cx="178.33473"
inkscape:cy="273.8301"
inkscape:window-width="1920"
inkscape:window-height="956"
inkscape:window-x="0"
inkscape:window-y="42"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:none;stroke:#000000;stroke-width:41.8148;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
id="rect234"
width="405.06821"
height="238.85057"
x="53.465897"
y="95.476929" />
<rect
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:14.5739;stroke-linecap:round;stroke-linejoin:round"
id="rect404"
width="305.17819"
height="33.373306"
x="103.41091"
y="400.26862" />
<path
style="fill:none;stroke:#000000;stroke-width:18.3381;stroke-linecap:square;stroke-dasharray:none"
d="M 54.043377,215.32624 H 200.04731 l 38.29399,-66.32716 35.31739,131.80626 44.38011,-76.86859 h 126.75493"
id="path359" />
</g>
</svg>
<?xml version="1.0" encoding="UTF-8"?><svg id="heart" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 467.6 467.6"><defs><style>.cls-1{stroke:#000;stroke-linecap:square;stroke-width:23px;}.cls-1,.cls-2{fill:none;}</style></defs><path id="By_Kam" class="cls-2" d="M0,0H467.6V467.6H0V0Z"/><path id="tela" d="M39,68.2c0-10.8,8.9-19.5,19.3-19.5H409.3c10.7,0,19.3,8.7,19.3,19.5V341c0,10.8-8.9,19.5-19.3,19.5H58.3c-10.7,0-19.3-8.7-19.3-19.4V68.2Zm38.9,19.5v233.8H389.6V87.7H77.9Zm19.5,292.2H370.2v39H97.4v-39Z"/><path id="raio" class="cls-1" d="M55.8,204.1h118l38.3-66.3,35.3,131.8,44.4-76.9h115.8"/></svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 600 B

@@ -1,64 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 24 24"
version="1.1"
id="svg8"
sodipodi:docname="interface-line-black.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs12" />
<sodipodi:namedview
id="namedview10"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
showgrid="false"
inkscape:zoom="22.627417"
inkscape:cx="13.678097"
inkscape:cy="16.30765"
inkscape:window-width="1920"
inkscape:window-height="956"
inkscape:window-x="0"
inkscape:window-y="42"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<path
style="fill:none;stroke:#010101;stroke-width:1.30518;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 6.727468,7.7120958 c 6.477744,0 6.477744,0.045113 6.477744,0.045113"
id="path858" />
<circle
style="fill:none;stroke:#010101;stroke-width:1.26308;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path1155"
cx="15.312269"
cy="7.6872182"
r="1.9730911" />
<circle
style="fill:none;stroke:#010101;stroke-width:1.26308;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path1155-3"
cx="9.0217237"
cy="12.922025"
r="1.9730911" />
<path
style="fill:none;stroke:#010101;stroke-width:1.26308;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 17.36834,12.922025 c -6.299228,0 -6.299228,0 -6.299228,0"
id="path1211" />
<rect
style="fill:none;stroke:#010101;stroke-width:1.60321;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
id="rect899"
width="18.606068"
height="13.961316"
x="2.6969662"
y="3.311192" />
<path
style="fill:none;stroke:#010101;stroke-width:2.13371;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none"
d="M 4.1156628,20.476585 H 19.884335"
id="path1269" />
</svg>
<?xml version="1.0" encoding="UTF-8"?><svg id="interface" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1{stroke-width:1.31px;}.cls-1,.cls-2,.cls-3{fill:none;}.cls-1,.cls-3{stroke:#010101;stroke-linecap:round;stroke-linejoin:round;}.cls-3{stroke-width:1.26px;}</style></defs><g id="tela"><g><path class="cls-2" d="M0,0H24V24H0V0Z"/><path d="M2,4c0-.6,.5-1,1-1H21c.5,0,1,.4,1,1v14c0,.6-.5,1-1,1H3c-.5,0-1-.4-1-1h0V4Zm2,1v12H20V5M5,20h14v2H5v-2Z"/></g></g><g id="guias"><path id="path858" class="cls-1" d="M6.7,8.5h6.5"/><circle id="path1155" class="cls-3" cx="15.3" cy="8.4" r="2"/><circle id="path1155-3" class="cls-3" cx="9" cy="13.7" r="2"/><path id="path1211" class="cls-3" d="M17.3,13.7h-6.3"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 735 B

@@ -22,9 +22,9 @@
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
showgrid="false"
inkscape:zoom="0.84555556"
inkscape:cx="91.655716"
inkscape:cy="449.40867"
inkscape:zoom="0.59789807"
inkscape:cx="71.918613"
inkscape:cy="403.07874"
inkscape:window-width="1920"
inkscape:window-height="956"
inkscape:window-x="0"

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="bandaid" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 21.6 21.6" style="enable-background:new 0 0 21.6 21.6;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<path id="By_Maxihplay" class="st0" d="M16.4,10.8L19,8.3c1-1,1-2.7,0-3.8l-1.9-1.9c-0.5-0.5-1.2-0.8-1.9-0.8s-1.4,0.3-1.9,0.8
l-2.5,2.5L8.3,2.6c-1-1-2.7-1-3.8,0L2.6,4.5c-1,1-1,2.7,0,3.8l2.5,2.5l-2.5,2.5c-1,1-1,2.7,0,3.8L4.5,19c0.5,0.5,1.2,0.8,1.9,0.8
s1.4-0.3,1.9-0.8l2.5-2.5l2.5,2.5c1,1,2.7,1,3.8,0l1.9-1.9c1-1,1-2.7,0-3.8L16.4,10.8z M8.4,9.8c0.5,0,0.9,0.4,0.9,0.9
s-0.4,0.9-0.9,0.9s-0.9-0.4-0.9-0.9C7.6,10.2,8,9.8,8.4,9.8z M7.1,17.8c-0.2,0.2-0.5,0.3-0.7,0.3S5.8,18,5.6,17.8L3.8,16
c-0.4-0.4-0.4-1.1,0-1.5L6.3,12l3.3,3.3C9.7,15.3,7.1,17.8,7.1,17.8z M10.8,13.8c-0.5,0-0.9-0.4-0.9-0.9s0.4-0.9,0.9-0.9
s0.9,0.4,0.9,0.9C11.7,13.5,11.3,13.8,10.8,13.8z M10.8,9.1c-0.5,0-0.9-0.4-0.9-0.9s0.4-0.9,0.9-0.9s0.9,0.4,0.9,0.9
S11.3,9.1,10.8,9.1z M13.2,11.5c-0.5,0-0.9-0.4-0.9-0.9s0.4-0.9,0.9-0.9s0.9,0.4,0.9,0.9C14.1,11.1,13.7,11.5,13.2,11.5z M11.9,6.3
l2.5-2.5c0.2-0.2,0.5-0.3,0.7-0.3c0.3,0,0.5,0.1,0.7,0.3l1.9,1.9c0.4,0.4,0.4,1.1,0,1.5l-2.5,2.5L11.9,6.3z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="cheats" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1,.cls-2{fill:#fff;}.cls-2{fill-rule:evenodd;}.cls-3{fill:none;}</style></defs><g id="tela"><g><path class="cls-3" d="M0,0H24V24H0V0Z"/><path class="cls-1" d="M2,4c0-.5,.5-1,1-1H21c.5,0,1,.4,1,1v14c0,.5-.5,1-1,1H3c-.5,0-1-.5-1-1h0V4Zm2,1v12H20V5H4Zm1,15h14v2H5v-2Z"/></g></g><g id="by_maxihplay"><path class="cls-2" d="M13.4,6.7c-1.1-1.2-2.6-.71-4,.19-1.4-.9-2.9-1.29-4-.19-.3,.4-.4,.9-.5,1.4-.2,1.1,.3,2.3,1.1,3.1l3.4,3.5,3.4-3.5c.8-.8,1.3-1.9,1.1-3.1,0-.5-.1-1-.5-1.4Z"/><path class="cls-1" d="M17.1,12.2c.6,0,1,.2,1.5,.6,.4,.4,.6,.9,.6,1.5s-.2,1.1-.6,1.5c-.4,.4-.9,.6-1.5,.6s-1.3-.4-1.8-1c-.6,.7-1.2,1-1.8,1s-1.1-.2-1.4-.6c-.4-.4-.6-.9-.6-1.5s.2-1.1,.6-1.5c.4-.4,.9-.6,1.4-.6,.6,0,1.3,.4,1.8,1.1,.6-.8,1.2-1.1,1.8-1.1Zm-3.7,3c.4,0,.8-.3,1.2-.9-.4-.6-.8-.9-1.2-.9-.2,0-.3,0-.5,.1s-.3,.2-.3,.3-.1,.3-.1,.4c0,.2,.1,.5,.3,.6,.1,.3,.3,.4,.6,.4h0Zm3.9,0h.3c.1,0,.2-.1,.3-.1s.1-.1,.1-.2,.1-.2,.1-.3v-.3c0-.2-.1-.5-.3-.6-.2-.2-.4-.3-.7-.3-.4,0-.8,.3-1.2,.9,.6,.6,1,.9,1.4,.9h0Z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g>
<path fill="none" d="M0 0H24V24H0z"/>
<path fill="#ffffff" d="M16 2v2h-1v3.243c0 1.158.251 2.301.736 3.352l4.282 9.276c.347.753.018 1.644-.734 1.99-.197.092-.411.139-.628.139H5.344c-.828 0-1.5-.672-1.5-1.5 0-.217.047-.432.138-.629l4.282-9.276C8.749 9.545 9 8.401 9 7.243V4H8V2h8zm-2.612 8.001h-2.776c-.104.363-.23.721-.374 1.071l-.158.361L6.125 20h11.749l-3.954-8.567c-.214-.464-.392-.943-.532-1.432zM11 7.243c0 .253-.01.506-.029.758h2.058c-.01-.121-.016-.242-.021-.364L13 7.243V4h-2v3.243z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 595 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 2C20.5523 2 21 2.44772 21 3V8C21 8.55228 20.5523 9 20 9H15V22C15 22.5523 14.5523 23 14 23H10C9.44772 23 9 22.5523 9 22V9H3.5C2.94772 9 2.5 8.55228 2.5 8V5.61803C2.5 5.23926 2.714 4.893 3.05279 4.72361L8.5 2H20ZM15 4H8.97214L4.5 6.23607V7H11V21H13V7H15V4ZM19 4H17V7H19V4Z" fill="#ffffff"></path></svg>

Before

Width:  |  Height:  |  Size: 373 B

@@ -1,61 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="svg5"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
sodipodi:docname="heart-monitor-line.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:document-units="px"
showgrid="false"
inkscape:zoom="1.3037281"
inkscape:cx="177.5677"
inkscape:cy="273.8301"
inkscape:window-width="1920"
inkscape:window-height="956"
inkscape:window-x="0"
inkscape:window-y="42"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:none;stroke:#ffffff;stroke-width:41.8148;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
id="rect234"
width="405.06821"
height="238.85057"
x="53.465897"
y="95.476929" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:14.5739;stroke-linecap:round;stroke-linejoin:round"
id="rect404"
width="305.17819"
height="33.373306"
x="103.41091"
y="400.26862" />
<path
style="fill:none;stroke:#ffffff;stroke-width:18.3381;stroke-linecap:square;stroke-dasharray:none"
d="M 54.043377,215.32624 H 200.04731 l 38.29399,-66.32716 35.31739,131.80626 44.38011,-76.86859 h 126.75493"
id="path359" />
</g>
</svg>
<?xml version="1.0" encoding="UTF-8"?><svg id="heart" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 467.6 467.6"><defs><style>.cls-1{fill:#fff;}.cls-2,.cls-3{fill:none;}.cls-3{stroke:#fff;stroke-linecap:square;stroke-width:23px;}</style></defs><path id="By_Kam" class="cls-2" d="M0,0H467.6V467.6H0V0Z"/><path id="tela" class="cls-1" d="M39,68.2c0-10.8,8.9-19.5,19.3-19.5H409.3c10.7,0,19.3,8.7,19.3,19.5V341c0,10.8-8.9,19.5-19.3,19.5H58.3c-10.7,0-19.3-8.7-19.3-19.4V68.2Zm38.9,19.5v233.8H389.6V87.7H77.9Zm19.5,292.2H370.2v39H97.4v-39Z"/><path id="raio" class="cls-3" d="M55.8,204.1h118l38.3-66.3,35.3,131.8,44.4-76.9h115.8"/></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 632 B

@@ -1,64 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 24 24"
version="1.1"
id="svg8"
sodipodi:docname="interface-line.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs12" />
<sodipodi:namedview
id="namedview10"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
showgrid="false"
inkscape:zoom="22.627417"
inkscape:cx="13.633903"
inkscape:cy="16.30765"
inkscape:window-width="1920"
inkscape:window-height="956"
inkscape:window-x="0"
inkscape:window-y="42"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<path
style="fill:none;stroke:#fefefe;stroke-width:1.30518;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 6.727468,7.7120958 c 6.477744,0 6.477744,0.045113 6.477744,0.045113"
id="path858" />
<circle
style="fill:none;stroke:#fefefe;stroke-width:1.26308;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path1155"
cx="15.312269"
cy="7.6872182"
r="1.9730911" />
<circle
style="fill:none;stroke:#fefefe;stroke-width:1.26308;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path1155-3"
cx="9.0217237"
cy="12.922025"
r="1.9730911" />
<path
style="fill:none;stroke:#fefefe;stroke-width:1.26308;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 17.36834,12.922025 c -6.299228,0 -6.299228,0 -6.299228,0"
id="path1211" />
<rect
style="fill:none;stroke:#fefefe;stroke-width:1.60321;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
id="rect899"
width="18.606068"
height="13.961316"
x="2.6969662"
y="3.311192" />
<path
style="fill:none;stroke:#fefefe;stroke-width:2.13371;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none"
d="M 4.1156628,20.476585 H 19.884335"
id="path1269" />
</svg>
<?xml version="1.0" encoding="UTF-8"?><svg id="interface" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1{fill:#fff;}.cls-2{stroke-width:1.31px;}.cls-2,.cls-3,.cls-4{fill:none;}.cls-2,.cls-4{stroke:#fff;stroke-linecap:round;stroke-linejoin:round;}.cls-4{stroke-width:1.26px;}</style></defs><g id="tela"><g><path class="cls-3" d="M0,0H24V24H0V0Z"/><path class="cls-1" d="M2,4c0-.6,.5-1,1-1H21c.5,0,1,.4,1,1v14c0,.6-.5,1-1,1H3c-.5,0-1-.4-1-1h0V4Zm2,1v12H20V5M5,20h14v2H5v-2Z"/></g></g><g id="guias"><path id="path858" class="cls-2" d="M6.7,8.5h6.5"/><circle id="path1155" class="cls-4" cx="15.3" cy="8.4" r="2"/><circle id="path1155-3" class="cls-4" cx="9" cy="13.7" r="2"/><path id="path1211" class="cls-4" d="M17.3,13.7h-6.3"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 764 B

+4 -4
View File
@@ -6,7 +6,9 @@
<file>icons/black/svg/arrow-left-right-line.svg</file>
<file>icons/black/svg/artboard-2-line.svg</file>
<file>icons/black/svg/at.svg</file>
<file>icons/black/svg/band-aid-line.svg</file>
<file>icons/black/svg/brush-line.svg</file>
<file>icons/black/svg/cheats-line.svg</file>
<file>icons/black/svg/checkbox-multiple-blank-line.svg</file>
<file>icons/black/svg/chip-line.svg</file>
<file>icons/black/svg/close-line.svg</file>
@@ -28,7 +30,6 @@
<file>icons/black/svg/file-settings-line.svg</file>
<file>icons/black/svg/filter-line.svg</file>
<file>icons/black/svg/flashlight-line.svg</file>
<file>icons/black/svg/flask-line.svg</file>
<file>icons/black/svg/floppy-in-line.svg</file>
<file>icons/black/svg/floppy-out-line.svg</file>
<file>icons/black/svg/folder-add-line.svg</file>
@@ -39,7 +40,6 @@
<file>icons/black/svg/function-line.svg</file>
<file>icons/black/svg/github.svg</file>
<file>icons/black/svg/global-line.svg</file>
<file>icons/black/svg/hammer-line.svg</file>
<file>icons/black/svg/heart-circle-line.svg</file>
<file>icons/black/svg/heart-monitor-line.svg</file>
<file>icons/black/svg/image-fill.svg</file>
@@ -78,7 +78,9 @@
<file>icons/white/svg/arrow-left-right-line.svg</file>
<file>icons/white/svg/artboard-2-line.svg</file>
<file>icons/white/svg/at.svg</file>
<file>icons/white/svg/band-aid-line.svg</file>
<file>icons/white/svg/brush-line.svg</file>
<file>icons/white/svg/cheats-line.svg</file>
<file>icons/white/svg/checkbox-multiple-blank-line.svg</file>
<file>icons/white/svg/chip-line.svg</file>
<file>icons/white/svg/close-line.svg</file>
@@ -100,7 +102,6 @@
<file>icons/white/svg/file-settings-line.svg</file>
<file>icons/white/svg/filter-line.svg</file>
<file>icons/white/svg/flashlight-line.svg</file>
<file>icons/white/svg/flask-line.svg</file>
<file>icons/white/svg/floppy-in-line.svg</file>
<file>icons/white/svg/floppy-out-line.svg</file>
<file>icons/white/svg/folder-add-line.svg</file>
@@ -111,7 +112,6 @@
<file>icons/white/svg/function-line.svg</file>
<file>icons/white/svg/github.svg</file>
<file>icons/white/svg/global-line.svg</file>
<file>icons/white/svg/hammer-line.svg</file>
<file>icons/white/svg/heart-circle-line.svg</file>
<file>icons/white/svg/heart-monitor-line.svg</file>
<file>icons/white/svg/image-fill.svg</file>
+15 -54
View File
@@ -18,8 +18,7 @@
#ifdef ENABLE_ACHIEVEMENTS
#include "Achievements.h"
#include "CDVD/IsoFS/IsoFS.h"
#include "CDVD/IsoFS/IsoFSCDVD.h"
#include "CDVD/CDVD.h"
#include "Elfheader.h"
#include "Host.h"
#include "ImGui/FullscreenUI.h"
@@ -36,6 +35,7 @@
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/FileSystem.h"
#include "common/Error.h"
#include "common/General.h"
#include "common/HTTPDownloader.h"
#include "common/MD5Digest.h"
@@ -121,7 +121,6 @@ namespace Achievements
static void GetLbInfoCallback(s32 status_code, const std::string& content_type, Common::HTTPDownloader::Request::Data data);
static void GetPatches(u32 game_id);
static std::string_view GetELFNameForHash(const std::string& elf_path);
static std::optional<std::vector<u8>> ReadELFFromCurrentDisc(const std::string& elf_path);
static std::string GetGameHash();
static void SetChallengeMode(bool enabled);
static void SendGetGameId();
@@ -1356,47 +1355,6 @@ std::string_view Achievements::GetELFNameForHash(const std::string& elf_path)
return std::string_view(elf_path).substr(start, end - start);
}
std::optional<std::vector<u8>> Achievements::ReadELFFromCurrentDisc(const std::string& elf_path)
{
std::optional<std::vector<u8>> ret;
// ELF suffix hack. Taken from CDVD::loadElf
// MLB2k6 has an elf whose suffix is actually ;2
std::string filepath(elf_path);
const std::string::size_type semi_pos = filepath.rfind(';');
if (semi_pos != std::string::npos && std::string_view(filepath).substr(semi_pos) != ";1")
{
Console.Warning(fmt::format("(Achievements) Non-conforming version suffix ({}) detected and replaced.", elf_path));
filepath.erase(semi_pos);
filepath += ";1";
}
IsoFSCDVD isofs;
IsoFile file(isofs);
Error error;
if (!file.open(filepath, &error))
{
Console.Error(fmt::format("(Achievements) Failed to open ELF '{}' on disc: {}", elf_path, error.GetDescription()));
return ret;
}
const u32 size = file.getLength();
ret = std::vector<u8>();
ret->resize(size);
if (size > 0)
{
const s32 bytes_read = file.read(ret->data(), static_cast<s32>(size));
if (bytes_read != static_cast<s32>(size))
{
Console.Error(fmt::format("(Achievements) Only read {} of {} bytes of ELF '{}'", bytes_read, size, elf_path));
ret.reset();
}
}
return ret;
}
std::string Achievements::GetGameHash()
{
const std::string elf_path = VMManager::GetDiscELF();
@@ -1404,34 +1362,37 @@ std::string Achievements::GetGameHash()
return {};
// this.. really shouldn't be invalid
const std::string_view name_for_hash(GetELFNameForHash(elf_path));
const std::string_view name_for_hash = GetELFNameForHash(elf_path);
if (name_for_hash.empty())
return {};
std::optional<std::vector<u8>> elf_data(ReadELFFromCurrentDisc(elf_path));
if (!elf_data.has_value())
ElfObject elfo;
Error error;
if (!cdvdLoadElf(&elfo, elf_path, false, &error))
{
Console.Error(fmt::format("(Achievements) Failed to read ELF '{}' on disc: {}", elf_path, error.GetDescription()));
return {};
}
// See rcheevos hash.c - rc_hash_ps2().
const u32 MAX_HASH_SIZE = 64 * 1024 * 1024;
const u32 hash_size = std::min<u32>(static_cast<u32>(elf_data->size()), MAX_HASH_SIZE);
pxAssert(hash_size <= elf_data->size());
const u32 hash_size = std::min<u32>(elfo.GetSize(), MAX_HASH_SIZE);
pxAssert(hash_size <= elfo.GetSize());
MD5Digest digest;
if (!name_for_hash.empty())
digest.Update(name_for_hash.data(), static_cast<u32>(name_for_hash.size()));
if (hash_size > 0)
digest.Update(elf_data->data(), hash_size);
digest.Update(elfo.GetData().data(), hash_size);
u8 hash[16];
digest.Final(hash);
std::string hash_str(
const std::string hash_str =
StringUtil::StdStringFromFormat("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", hash[0], hash[1], hash[2],
hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]));
hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]);
Console.WriteLn("Hash for '%.*s' (%zu bytes, %u bytes hashed): %s", static_cast<int>(name_for_hash.size()), name_for_hash.data(),
elf_data->size(), hash_size, hash_str.c_str());
Console.WriteLn(fmt::format("Hash for '{}' ({} bytes, {} bytes hashed): {}", name_for_hash, elfo.GetSize(), hash_size, hash_str));
return hash_str;
}
+95 -75
View File
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@@ -14,6 +14,17 @@
*/
#include "PrecompiledHeader.h"
#include "CDVD/CDVD.h"
#include "CDVD/Ps1CD.h"
#include "CDVD/CDVD_internal.h"
#include "CDVD/IsoReader.h"
#include "CDVD/IsoFileFormats.h"
#include "GS.h"
#include "Elfheader.h"
#include "ps2/BiosTools.h"
#include "Recording/InputRecording.h"
#include "Host.h"
#include "R3000A.h"
#include "Common.h"
#include "IopHw.h"
@@ -21,25 +32,15 @@
#include "VMManager.h"
#include "Sio.h"
#include <cctype>
#include <ctime>
#include <memory>
#include "common/Error.h"
#include "common/FileSystem.h"
#include "common/Path.h"
#include "common/StringUtil.h"
#include "common/Threading.h"
#include "Ps1CD.h"
#include "CDVD.h"
#include "CDVD_internal.h"
#include "IsoFileFormats.h"
#include "GS.h" // for gsVideoMode
#include "Elfheader.h"
#include "ps2/BiosTools.h"
#include "Recording/InputRecording.h"
#include "Host.h"
#include <cctype>
#include <ctime>
#include <memory>
cdvdStruct cdvd;
@@ -383,49 +384,72 @@ s32 cdvdWriteConfig(const u8* config)
return 0;
}
bool cdvdLoadElf(ElfObject* elfo, std::string elfpath, bool isPSXElf, Error* error)
static bool cdvdUncheckedLoadDiscElf(ElfObject* elfo, IsoReader& isor, const std::string_view& elfpath, bool isPSXElf, Error* error)
{
// Strip out cdrom: prefix, and any leading slashes.
size_t start_pos = (elfpath[5] == '0') ? 7 : 6;
while (start_pos < elfpath.size() && (elfpath[start_pos] == '\\' || elfpath[start_pos] == '/'))
start_pos++;
// Strip out any version information. Some games use ;2 (MLB2k6), others put multiple versions in
// (Syphon Filter Omega Strain). The PS2 BIOS appears to ignore the suffix entirely, so we'll do
// the same, and hope that no games actually have multiple ELFs with different versions.
// Previous notes:
// Mimic PS2 behavior!
// Much trial-and-error with changing the ISOFS and BOOT2 contents of an image have shown that
// the PS2 BIOS performs the peculiar task of *ignoring* the version info from the parsed BOOT2
// filename *and* the ISOFS, when loading the game's ELF image. What this means is:
//
// 1. a valid PS2 ELF can have any version (ISOFS), and the version need not match the one in SYSTEM.CNF.
// 2. the version info on the file in the BOOT2 parameter of SYSTEM.CNF can be missing, 10 chars long,
// or anything else. Its all ignored.
// 3. Games loading their own files do *not* exhibit this behavior; likely due to using newer IOP modules
// or lower level filesystem APIs (fortunately that doesn't affect us).
//
size_t length = elfpath.length() - start_pos;
const size_t semi_pos = elfpath.find(';', start_pos);
if (semi_pos != std::string::npos)
length = semi_pos - start_pos;
std::string iso_filename(elfpath.substr(start_pos, length));
DevCon.WriteLn(fmt::format("cvdLoadElf(): '{}' -> '{}' in ISO.", elfpath, iso_filename));
if (iso_filename.empty())
{
Error::SetString(error, "ISO filename is empty.");
return false;
}
return elfo->OpenIsoFile(std::move(iso_filename), isor, isPSXElf, error);
}
bool cdvdLoadElf(ElfObject* elfo, const std::string_view& elfpath, bool isPSXElf, Error* error)
{
if (StringUtil::StartsWith(elfpath, "host:"))
{
std::string host_filename(elfpath.substr(5));
if (!elfo->OpenFile(host_filename, isPSXElf, error))
return elfo->OpenFile(host_filename, isPSXElf, error);
}
else if (StringUtil::StartsWith(elfpath, "cdrom:") || StringUtil::StartsWith(elfpath, "cdrom0:"))
{
IsoReader isor;
if (!isor.Open(error))
return false;
return cdvdLoadDiscElf(elfo, isor, elfpath, isPSXElf, error);
}
else
{
// Mimic PS2 behavior!
// Much trial-and-error with changing the ISOFS and BOOT2 contents of an image have shown that
// the PS2 BIOS performs the peculiar task of *ignoring* the version info from the parsed BOOT2
// filename *and* the ISOFS, when loading the game's ELF image. What this means is:
//
// 1. a valid PS2 ELF can have any version (ISOFS), and the version need not match the one in SYSTEM.CNF.
// 2. the version info on the file in the BOOT2 parameter of SYSTEM.CNF can be missing, 10 chars long,
// or anything else. Its all ignored.
// 3. Games loading their own files do *not* exhibit this behavior; likely due to using newer IOP modules
// or lower level filesystem APIs (fortunately that doesn't affect us).
//
// FIXME: Properly mimicing this behavior is troublesome since we need to add support for "ignoring"
// version information when doing file searches. I'll add this later. For now, assuming a ;1 should
// be sufficient (no known games have their ELF binary as anything but version ;1)
const std::string::size_type semi_pos = elfpath.rfind(';');
if (semi_pos != std::string::npos && std::string_view(elfpath).substr(semi_pos) != ";1")
{
Console.WriteLn(Color_Blue, "(LoadELF) Non-conforming version suffix (%s) detected and replaced.", elfpath.c_str());
elfpath.erase(semi_pos);
elfpath += ";1";
}
// Fix cdrom:path, the iso reader doesn't like it.
if (StringUtil::StartsWith(elfpath, "cdrom:") && elfpath[6] != '\\' && elfpath[6] != '/')
elfpath.insert(6, 1, '\\');
IsoFSCDVD isofs;
IsoFile file(isofs);
if (!file.open(elfpath, error) || !elfo->OpenIsoFile(elfpath, file, isPSXElf, error))
return false;
Console.Error(fmt::format("cdvdLoadElf(): Unknown device in ELF path '{}'", elfpath));
return false;
}
}
return true;
bool cdvdLoadDiscElf(ElfObject* elfo, IsoReader& isor, const std::string_view& elfpath, bool isPSXElf, Error* error)
{
if (!StringUtil::StartsWith(elfpath, "cdrom:") && !StringUtil::StartsWith(elfpath, "cdrom0:"))
return false;
return cdvdUncheckedLoadDiscElf(elfo, isor, elfpath, isPSXElf, error);
}
u32 cdvdGetElfCRC(const std::string& path)
@@ -437,65 +461,57 @@ u32 cdvdGetElfCRC(const std::string& path)
return elfo.GetCRC();
}
static CDVDDiscType GetPS2ElfName(std::string* name, std::string* version)
static CDVDDiscType GetPS2ElfName(IsoReader& isor, std::string* name, std::string* version, Error* error)
{
CDVDDiscType retype = CDVDDiscType::Other;
name->clear();
version->clear();
Error error;
IsoFSCDVD isofs;
IsoFile file(isofs);
if (!file.open("SYSTEM.CNF;1", &error))
{
Console.Error(fmt::format("(GetElfName) Failed to open SYSTEM.CNF: {}", error.GetDescription()));
return CDVDDiscType::Other;
}
const int size = file.getLength();
if (size == 0)
std::vector<u8> data;
if (!isor.ReadFile("SYSTEM.CNF", &data, error))
return CDVDDiscType::Other;
while (!file.eof())
const std::vector<std::string_view> lines =
StringUtil::SplitString(std::string_view(reinterpret_cast<const char*>(data.data()), data.size()), '\n');
for (size_t lineno = 0; lineno < lines.size(); lineno++)
{
const std::string line(file.readLine());
const std::string_view line = StringUtil::StripWhitespace(lines[lineno]);
std::string_view key, value;
if (!StringUtil::ParseAssignmentString(line, &key, &value))
continue;
if (value.empty() && file.getLength() != file.getSeekPos())
{ // Some games have a character on the last line of the file, don't print the error in those cases.
// Some games have a character on the last line of the file, don't print the error in those cases.
if (value.empty() && (lineno == (lines.size() - 1)))
{
Console.Warning("(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:");
Console.Indent().WriteLn(line);
Console.Indent().WriteLn(std::string(line));
continue;
}
if (key == "BOOT2")
{
Console.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PS2 Disc = {}", value));
DevCon.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PS2 Disc = {}", value));
*name = value;
retype = CDVDDiscType::PS2Disc;
}
else if (key == "BOOT")
{
Console.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PSX/PSone Disc = {}", value));
DevCon.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PSX/PSone Disc = {}", value));
*name = value;
retype = CDVDDiscType::PS1Disc;
}
else if (key == "VMODE")
{
Console.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Disc region type = {}", value));
DevCon.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Disc region type = {}", value));
}
else if (key == "VER")
{
Console.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Software version = {}", value));
DevCon.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Software version = {}", value));
*version = value;
}
}
if (retype == CDVDDiscType::Other)
Console.Error("(GetElfName) Disc image is *not* a PlayStation or PS2 game!");
Error::SetString(error, "Disc image is *not* a PlayStation or PS2 game");
return retype;
}
@@ -554,8 +570,13 @@ static std::string ExecutablePathToSerial(const std::string& path)
void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, u32* out_crc,
CDVDDiscType* out_disc_type)
{
Error error;
IsoReader isor;
std::string elfpath, version;
const CDVDDiscType disc_type = GetPS2ElfName(&elfpath, &version);
CDVDDiscType disc_type = CDVDDiscType::Other;
if (!isor.Open(&error) || (disc_type = GetPS2ElfName(isor, &elfpath, &version, &error)) == CDVDDiscType::Other)
Console.Error(fmt::format("Failed to get ELF name: {}", error.GetDescription()));
// Don't bother parsing it if we don't need the CRC.
if (out_crc)
@@ -564,10 +585,9 @@ void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::st
if (disc_type == CDVDDiscType::PS2Disc || disc_type == CDVDDiscType::PS1Disc)
{
Error error;
ElfObject elfo;
const bool isPSXElf = (disc_type == CDVDDiscType::PS1Disc);
if (!cdvdLoadElf(&elfo, elfpath, isPSXElf, &error))
if (!cdvdLoadDiscElf(&elfo, isor, elfpath, isPSXElf, &error))
Console.Error(fmt::format("Failed to load ELF info for {}: {}", elfpath, error.GetDescription()));
else
crc = elfo.GetCRC();
+3 -1
View File
@@ -23,6 +23,7 @@
class Error;
class ElfObject;
class IsoReader;
#define btoi(b) ((b) / 16 * 10 + (b) % 16) /* BCD to u_char */
#define itob(i) ((i) / 10 * 16 + (i) % 10) /* u_char to BCD */
@@ -190,7 +191,8 @@ extern void cdvdWrite(u8 key, u8 rt);
extern void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, u32* out_crc,
CDVDDiscType* out_disc_type);
extern u32 cdvdGetElfCRC(const std::string& path);
extern bool cdvdLoadElf(ElfObject* elfo, std::string filename, bool isPSXElf, Error* error);
extern bool cdvdLoadElf(ElfObject* elfo, const std::string_view& elfpath, bool isPSXElf, Error* error);
extern bool cdvdLoadDiscElf(ElfObject* elfo, IsoReader& isor, const std::string_view& elfpath, bool isPSXElf, Error* error);
extern s32 cdvdCtrlTrayOpen();
extern s32 cdvdCtrlTrayClose();
+2
View File
@@ -15,6 +15,8 @@
#pragma once
#include "Common.h"
/*
Interrupts - values are flag bits.
+34 -36
View File
@@ -16,29 +16,29 @@
#include "PrecompiledHeader.h"
#define ENABLE_TIMESTAMPS
#include <ctype.h>
#include <time.h>
#include <exception>
#include <memory>
#include "fmt/core.h"
#include "IsoFS/IsoFS.h"
#include "IsoFS/IsoFSCDVD.h"
#include "IsoFileFormats.h"
#include "common/Assertions.h"
#include "common/FileSystem.h"
#include "common/Path.h"
#include "common/StringUtil.h"
#include "CDVD/CDVDcommon.h"
#include "CDVD/IsoReader.h"
#include "CDVD/IsoFileFormats.h"
#include "DebugTools/SymbolMap.h"
#include "Config.h"
#include "Host.h"
#include "IconsFontAwesome5.h"
CDVD_API* CDVD = NULL;
#include "common/Assertions.h"
#include "common/FileSystem.h"
#include "common/Path.h"
#include "common/StringUtil.h"
#include <ctype.h>
#include <exception>
#include <memory>
#include <time.h>
#include "fmt/core.h"
#define ENABLE_TIMESTAMPS
CDVD_API* CDVD = nullptr;
// ----------------------------------------------------------------------------
// diskTypeCached
@@ -71,37 +71,35 @@ static void CheckNullCDVD()
//
static int CheckDiskTypeFS(int baseType)
{
IsoFSCDVD isofs;
IsoDirectory rootdir(isofs);
if (rootdir.OpenRootDirectory())
IsoReader isor;
if (isor.Open())
{
if (IsoFile file(isofs); file.open(rootdir, "SYSTEM.CNF;1"))
std::vector<u8> data;
if (isor.ReadFile("SYSTEM.CNF", &data))
{
const int size = file.getLength();
const std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size + 1);
file.read(buffer.get(), size);
buffer[size] = '\0';
char* pos = strstr(buffer.get(), "BOOT2");
if (pos == NULL)
if (StringUtil::ContainsSubString(data, "BOOT2"))
{
pos = strstr(buffer.get(), "BOOT");
if (pos == NULL)
return CDVD_TYPE_ILLEGAL;
// PS2 DVD/CD.
return (baseType == CDVD_TYPE_DETCTCD) ? CDVD_TYPE_PS2CD : CDVD_TYPE_PS2DVD;
}
if (StringUtil::ContainsSubString(data, "BOOT"))
{
// PSX CD.
return CDVD_TYPE_PSCD;
}
return (baseType == CDVD_TYPE_DETCTCD) ? CDVD_TYPE_PS2CD : CDVD_TYPE_PS2DVD;
return CDVD_TYPE_ILLEGAL;
}
// PS2 Linux disc 2, doesn't have a System.CNF or a normal ELF
if (rootdir.Exists("P2L_0100.02;1"))
if (isor.FileExists("P2L_0100.02"))
return CDVD_TYPE_PS2DVD;
if (rootdir.Exists("PSX.EXE;1"))
if (isor.FileExists("PSX.EXE"))
return CDVD_TYPE_PSCD;
if (rootdir.Exists("VIDEO_TS/VIDEO_TS.IFO;1"))
if (isor.FileExists("VIDEO_TS/VIDEO_TS.IFO"))
return CDVD_TYPE_DVDV;
}
-60
View File
@@ -1,60 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include <optional>
#include <string_view>
#include <vector>
class Error;
enum IsoFS_Type
{
FStype_ISO9660 = 1,
FStype_Joliet = 2,
};
class IsoDirectory final
{
public:
SectorSource& internalReader;
std::vector<IsoFileDescriptor> files;
IsoFS_Type m_fstype = FStype_ISO9660;
public:
IsoDirectory(SectorSource& r);
~IsoDirectory();
bool OpenRootDirectory(Error* error = nullptr);
bool Open(const IsoFileDescriptor& directoryEntry, Error* error = nullptr);
std::string FStype_ToString() const;
SectorSource& GetReader() const { return internalReader; }
bool Exists(const std::string_view& filePath) const;
bool IsFile(const std::string_view& filePath) const;
bool IsDir(const std::string_view& filePath) const;
u32 GetFileSize(const std::string_view& filePath) const;
std::optional<IsoFileDescriptor> FindFile(const std::string_view& filePath) const;
protected:
const IsoFileDescriptor& GetEntry(size_t index) const;
int GetIndexOf(const std::string_view& fileName) const;
};
-322
View File
@@ -1,322 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "IsoFS.h"
#include "IsoFile.h"
#include "common/Assertions.h"
#include "common/Error.h"
#include "common/FileSystem.h"
#include "common/Path.h"
#include "common/StringUtil.h"
#include <memory>
//////////////////////////////////////////////////////////////////////////
// IsoDirectory
//////////////////////////////////////////////////////////////////////////
//u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL
//u8 volID[5]; // "CD001"
std::string IsoDirectory::FStype_ToString() const
{
switch (m_fstype)
{
case FStype_ISO9660:
return "ISO9660";
case FStype_Joliet:
return "Joliet";
}
return StringUtil::StdStringFromFormat("Unrecognized Code (0x%x)", m_fstype);
}
// Used to load the Root directory from an image
IsoDirectory::IsoDirectory(SectorSource& r)
: internalReader(r)
{
}
IsoDirectory::~IsoDirectory() = default;
bool IsoDirectory::OpenRootDirectory(Error* error /* = nullptr */)
{
IsoFileDescriptor rootDirEntry;
bool isValid = false;
bool done = false;
uint i = 16;
m_fstype = FStype_ISO9660;
while (!done)
{
u8 sector[2048];
// If this fails, we're not reading an iso, or it's bad.
if (!internalReader.readSector(sector, i))
break;
if (memcmp(&sector[1], "CD001", 5) == 0)
{
switch (sector[0])
{
case 0:
DevCon.WriteLn(Color_Green, "(IsoFS) Block 0x%x: Boot partition info.", i);
break;
case 1:
DevCon.WriteLn("(IsoFS) Block 0x%x: Primary partition info.", i);
rootDirEntry.Load(sector + 156, 38);
isValid = true;
break;
case 2:
// Probably means Joliet (long filenames support), which PCSX2 doesn't care about.
DevCon.WriteLn(Color_Green, "(IsoFS) Block 0x%x: Extended partition info.", i);
m_fstype = FStype_Joliet;
break;
case 0xff:
// Null terminator. End of partition information.
done = true;
break;
default:
Console.Error("(IsoFS) Unknown partition type ID=%d, encountered at block 0x%x", sector[0], i);
break;
}
}
else
{
sector[9] = 0;
Console.Error("(IsoFS) Invalid partition descriptor encountered at block 0x%x: '%s'", i, &sector[1]);
break; // if no valid root partition was found, an exception will be thrown below.
}
++i;
}
if (!isValid)
{
Error::SetString(error, "IsoFS could not find the root directory on the ISO image.");
return false;
}
DevCon.WriteLn("(IsoFS) Filesystem is %s", FStype_ToString().c_str());
return Open(rootDirEntry);
}
// Used to load a specific directory from a file descriptor
bool IsoDirectory::Open(const IsoFileDescriptor& directoryEntry, Error* error /* = nullptr */)
{
// parse directory sector
IsoFile dataStream(internalReader, directoryEntry);
files.clear();
uint remainingSize = directoryEntry.size;
u8 b[257];
while (remainingSize >= 4) // hm hack :P
{
b[0] = dataStream.read<u8>();
if (b[0] == 0)
{
break; // or continue?
}
remainingSize -= b[0];
dataStream.read(b + 1, b[0] - 1);
auto isoFile = IsoFileDescriptor(b, b[0]);
files.push_back(isoFile);
const std::string::size_type semi_pos = isoFile.name.rfind(';');
if (semi_pos != std::string::npos && std::string_view(isoFile.name).substr(semi_pos) != ";1")
{
const std::string origName = isoFile.name;
isoFile.name.erase(semi_pos);
isoFile.name += ";1";
Console.WriteLn("(IsoFS) Non-conforming version suffix (%s) detected. Creating 'hard-linked' entry (%s)",origName.c_str(), isoFile.name.c_str());
files.push_back(isoFile);
}
}
b[0] = 0;
return true;
}
const IsoFileDescriptor& IsoDirectory::GetEntry(size_t index) const
{
return files[index];
}
int IsoDirectory::GetIndexOf(const std::string_view& fileName) const
{
for (unsigned int i = 0; i < files.size(); i++)
{
if (files[i].name == fileName)
return i;
}
return -1;
}
std::optional<IsoFileDescriptor> IsoDirectory::FindFile(const std::string_view& filePath) const
{
if (filePath.empty())
return std::nullopt;
// DOS-style parser should work fine for ISO 9660 path names. Only practical difference
// is case sensitivity, and that won't matter for path splitting.
std::vector<std::string_view> parts(Path::SplitWindowsPath(filePath));
const IsoDirectory* dir = this;
IsoDirectory subdir(internalReader);
// walk through path ("." and ".." entries are in the directories themselves, so even if the
// path included . and/or .., it still works)
// ignore the device (cdrom0:\)
const bool has_device = (parts.front().back() == ':');
for (size_t index = has_device ? 1 : 0; index < (parts.size() - 1); index++)
{
const int subdir_index = GetIndexOf(parts[index]);
if (subdir_index < 0)
return std::nullopt;
const IsoFileDescriptor& subdir_entry = GetEntry(static_cast<size_t>(index));
if (subdir_entry.IsFile() || !subdir.Open(subdir_entry, nullptr))
return std::nullopt;
dir = &subdir;
}
const int file_index = dir->GetIndexOf(parts.back());
if (file_index < 0)
return std::nullopt;
return GetEntry(static_cast<size_t>(file_index));
}
bool IsoDirectory::Exists(const std::string_view& filePath) const
{
if (filePath.empty())
return false;
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
return fd.has_value();
}
bool IsoDirectory::IsFile(const std::string_view& filePath) const
{
if (filePath.empty())
return false;
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
if (fd.has_value())
return false;
return ((fd->flags & 2) != 2);
}
bool IsoDirectory::IsDir(const std::string_view& filePath) const
{
if (filePath.empty())
return false;
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
if (fd.has_value())
return false;
return ((fd->flags & 2) == 2);
}
u32 IsoDirectory::GetFileSize(const std::string_view& filePath) const
{
if (filePath.empty())
return 0;
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
if (fd.has_value())
return 0;
return fd->size;
}
IsoFileDescriptor::IsoFileDescriptor()
: lba(0)
, size(0)
, flags(0)
{
memset(&date, 0, sizeof(date));
}
IsoFileDescriptor::IsoFileDescriptor(const u8* data, int length)
{
Load(data, length);
}
void IsoFileDescriptor::Load(const u8* data, int length)
{
lba = (u32&)data[2];
size = (u32&)data[10];
date.year = data[18] + 1900;
date.month = data[19];
date.day = data[20];
date.hour = data[21];
date.minute = data[22];
date.second = data[23];
date.gmtOffset = data[24];
flags = data[25];
int fileNameLength = data[32];
if (fileNameLength == 1)
{
u8 c = data[33];
switch (c)
{
case 0:
name = ".";
break;
case 1:
name = "..";
break;
default:
name = static_cast<char>(c);
break;
}
}
else
{
// copy string and up-convert from ascii to wxChar
const u8* fnsrc = data + 33;
name.assign(reinterpret_cast<const char*>(fnsrc), fileNameLength);
}
}
-25
View File
@@ -1,25 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
class IsoFile;
class IsoDirectory;
struct IsoFileDescriptor;
#include "SectorSource.h"
#include "IsoFileDescriptor.h"
#include "IsoDirectory.h"
#include "IsoFile.h"
-37
View File
@@ -1,37 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "IsoFSCDVD.h"
#include "CDVD/CDVDcommon.h"
IsoFSCDVD::IsoFSCDVD()
{
}
bool IsoFSCDVD::readSector(unsigned char* buffer, int lba)
{
return DoCDVDreadSector(buffer, lba, CDVD_MODE_2048) >= 0;
}
int IsoFSCDVD::getNumSectors()
{
cdvdTD td;
CDVD->getTD(0, &td);
return td.lsn;
}
-31
View File
@@ -1,31 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdio.h>
#include "SectorSource.h"
class IsoFSCDVD final : public SectorSource
{
public:
IsoFSCDVD();
virtual ~IsoFSCDVD() = default;
virtual bool readSector(unsigned char* buffer, int lba);
virtual int getNumSectors();
};
-262
View File
@@ -1,262 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "common/Assertions.h"
#include "common/Error.h"
#include "IsoFS.h"
#include "IsoFile.h"
#include <cstdio>
IsoFile::IsoFile(SectorSource& reader)
: internalReader(reader)
{
}
IsoFile::~IsoFile() = default;
IsoFile::IsoFile(SectorSource& reader, const IsoFileDescriptor& fileEntry)
: internalReader(reader)
, fileEntry(fileEntry)
{
Init();
}
void IsoFile::Init()
{
//pxAssertDev( fileEntry.IsFile(), "IsoFile Error: Filename points to a directory." );
currentSectorNumber = fileEntry.lba;
currentOffset = 0;
sectorOffset = 0;
maxOffset = fileEntry.size;
if (maxOffset > 0)
internalReader.readSector(currentSector, currentSectorNumber);
}
bool IsoFile::open(const IsoDirectory& dir, const std::string_view& filename, Error* error /*= nullptr*/)
{
const std::optional<IsoFileDescriptor> fd(dir.FindFile(filename));
if (!fd.has_value())
{
Error::SetString(error, fmt::format("Failed to find file '{}'", filename));
return false;
}
fileEntry = std::move(fd.value());
Init();
return true;
}
bool IsoFile::open(const std::string_view& filename, Error* error /*= nullptr*/)
{
IsoDirectory dir(internalReader);
if (!dir.OpenRootDirectory(error))
return false;
return open(dir, filename, error);
}
u32 IsoFile::seek(u32 absoffset)
{
u32 endOffset = absoffset;
int oldSectorNumber = currentSectorNumber;
int newSectorNumber = fileEntry.lba + (int)(endOffset / sectorLength);
if (oldSectorNumber != newSectorNumber)
{
internalReader.readSector(currentSector, newSectorNumber);
}
currentOffset = endOffset;
currentSectorNumber = newSectorNumber;
sectorOffset = (int)(currentOffset % sectorLength);
return currentOffset;
}
// Returns the new offset in the file. Out-of-bounds seeks are automatically truncated at 0
// and fileLength.
u32 IsoFile::seek(s64 offset, int mode)
{
switch (mode)
{
case SEEK_SET:
pxAssertDev(offset >= 0 && offset <= (s64)ULONG_MAX, "Invalid seek position from start.");
return seek(offset);
case SEEK_CUR:
// truncate negative values to zero, and positive values to 4gb
return seek(std::min(std::max<s64>(0, (s64)currentOffset + offset), (s64)ULONG_MAX));
case SEEK_END:
// truncate negative values to zero, and positive values to 4gb
return seek(std::min(std::max<s64>(0, (s64)fileEntry.size + offset), (s64)ULONG_MAX));
jNO_DEFAULT;
}
return 0; // unreachable
}
void IsoFile::reset()
{
seek(0);
}
// Returns the number of bytes actually skipped.
s32 IsoFile::skip(s32 n)
{
s32 oldOffset = currentOffset;
if (n < 0)
return 0;
seek(currentOffset + n);
return currentOffset - oldOffset;
}
u32 IsoFile::getSeekPos() const
{
return currentOffset;
}
bool IsoFile::eof() const
{
return (currentOffset == maxOffset);
}
// loads the current sector index into the CurrentSector buffer.
void IsoFile::makeDataAvailable()
{
if (sectorOffset >= sectorLength)
{
currentSectorNumber++;
internalReader.readSector(currentSector, currentSectorNumber);
sectorOffset -= sectorLength;
}
}
u8 IsoFile::readByte()
{
if (currentOffset >= maxOffset)
return 0;
makeDataAvailable();
currentOffset++;
return currentSector[sectorOffset++];
}
// Reads data from a single sector at a time. Reads cannot cross sector boundaries.
int IsoFile::internalRead(void* dest, int off, int len)
{
if (len > 0)
{
size_t slen = len;
if (slen > (maxOffset - currentOffset))
{
slen = (int)(maxOffset - currentOffset);
}
memcpy((u8*)dest + off, currentSector + sectorOffset, slen);
sectorOffset += slen;
currentOffset += slen;
return slen;
}
return 0;
}
// returns the number of bytes actually read.
s32 IsoFile::read(void* dest, s32 len)
{
pxAssert(dest != NULL);
pxAssert(len >= 0); // should we silent-fail on negative length reads? prolly not...
if (len <= 0)
return 0;
int off = 0;
int totalLength = 0;
int firstSector = internalRead(dest, off, std::min(len, sectorLength - sectorOffset));
off += firstSector;
len -= firstSector;
totalLength += firstSector;
// Read whole sectors
while ((len >= sectorLength) && (currentOffset < maxOffset))
{
makeDataAvailable();
int n = internalRead(dest, off, sectorLength);
off += n;
len -= n;
totalLength += n;
}
// Read remaining, if any
if (len > 0)
{
makeDataAvailable();
int lastSector = internalRead(dest, off, len);
totalLength += lastSector;
}
return totalLength;
}
// Reads data until it reaches a newline character (either \n, \r, or ASCII-Z). The caller is
// responsible for handling files with DOS-style newlines (CR/LF pairs), if needed. The resulting
// string has no newlines.
//
// Read data is unformatted 8 bit / Ascii. If the source file is known to be UTF8, use the fromUTF8()
// conversion helper provided by PCSX2 utility classes.
//
std::string IsoFile::readLine()
{
std::string s;
s.reserve(512);
while (!eof())
{
u8 c = read<u8>();
if ((c == '\n') || (c == '\r') || (c == 0))
break;
s += c;
}
return s;
}
u32 IsoFile::getLength()
{
return maxOffset;
}
const IsoFileDescriptor& IsoFile::getEntry()
{
return fileEntry;
}
-83
View File
@@ -1,83 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "IsoFileDescriptor.h"
#include "SectorSource.h"
#include "common/Pcsx2Defs.h"
#include <string_view>
class Error;
class IsoFile final
{
public:
static const int sectorLength = 2048;
protected:
SectorSource& internalReader;
IsoFileDescriptor fileEntry = {};
u32 currentOffset = 0;
u32 maxOffset = 0;
int currentSectorNumber = 0;
int sectorOffset = 0;
u8 currentSector[sectorLength];
public:
IsoFile(SectorSource& reader);
IsoFile(SectorSource& reader, const IsoFileDescriptor& fileEntry);
~IsoFile();
bool open(const IsoDirectory& dir, const std::string_view& filename, Error* error = nullptr);
bool open(const std::string_view& filename, Error* error = nullptr);
u32 seek(u32 absoffset);
u32 seek(s64 offset, int mode);
void reset();
s32 skip(s32 n);
u32 getSeekPos() const;
u32 getLength();
bool eof() const;
const IsoFileDescriptor& getEntry();
u8 readByte();
s32 read(void* dest, s32 len);
std::string readLine();
// Tool to read a specific value type, including structs.
template <class T>
T read()
{
if (sizeof(T) == 1)
return (T)readByte();
else
{
T t;
read((u8*)&t, sizeof(t));
return t;
}
}
protected:
void makeDataAvailable();
int internalRead(void* dest, int off, int len);
void Init();
};
-47
View File
@@ -1,47 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include <string>
struct IsoFileDescriptor
{
struct FileDate // not 1:1 with iso9660 date struct
{
s32 year;
u8 month;
u8 day;
u8 hour;
u8 minute;
u8 second;
u8 gmtOffset; // Offset from Greenwich Mean Time in number of 15 min intervals from -48 (West) to + 52 (East)
} date;
u32 lba;
u32 size;
int flags;
std::string name;
IsoFileDescriptor();
IsoFileDescriptor(const u8* data, int length);
void Load(const u8* data, int length);
bool IsFile() const { return !(flags & 2); }
bool IsDir() const { return !IsFile(); }
};
-24
View File
@@ -1,24 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
class SectorSource
{
public:
virtual int getNumSectors() = 0;
virtual bool readSector(unsigned char* buffer, int lba) = 0;
virtual ~SectorSource() = default;
};
+315
View File
@@ -0,0 +1,315 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "CDVD/CDVDcommon.h"
#include "CDVD/IsoReader.h"
#include "common/Assertions.h"
#include "common/Error.h"
#include "common/StringUtil.h"
#include "fmt/format.h"
#include <cctype>
IsoReader::IsoReader() = default;
IsoReader::~IsoReader() = default;
bool IsoReader::Open(Error* error)
{
if (!ReadPVD(error))
return false;
return true;
}
bool IsoReader::ReadSector(u8* buf, u32 lsn, Error* error)
{
if (DoCDVDreadSector(buf, lsn, CDVD_MODE_2048) != 0)
{
Error::SetString(error, fmt::format("Failed to read sector LSN #{}", lsn));
return false;
}
return true;
}
bool IsoReader::ReadPVD(Error* error)
{
// volume descriptor start at sector 16
static constexpr u32 START_SECTOR = 16;
// try only a maximum of 256 volume descriptors
for (u32 i = 0; i < 256; i++)
{
u8 buffer[SECTOR_SIZE];
if (!ReadSector(buffer, START_SECTOR + i, error))
return false;
const ISOVolumeDescriptorHeader* header = reinterpret_cast<ISOVolumeDescriptorHeader*>(buffer);
if (std::memcmp(header->standard_identifier, "CD001", 5) != 0)
continue;
else if (header->type_code != 1)
continue;
else if (header->type_code == 255)
break;
std::memcpy(&m_pvd, buffer, sizeof(ISOPrimaryVolumeDescriptor));
DevCon.WriteLn(fmt::format("ISOReader: PVD found at index {}", i));
return true;
}
Error::SetString(error, "Failed to find the Primary Volume Descriptor.");
return false;
}
std::optional<IsoReader::ISODirectoryEntry> IsoReader::LocateFile(const std::string_view& path, Error* error)
{
const ISODirectoryEntry* root_de = reinterpret_cast<const ISODirectoryEntry*>(m_pvd.root_directory_entry);
if (path.empty() || path == "/" || path == "\\")
{
// locating the root directory
return *root_de;
}
// start at the root directory
u8 sector_buffer[SECTOR_SIZE];
return LocateFile(path, sector_buffer, root_de->location_le, root_de->length_le, error);
}
std::string_view IsoReader::GetDirectoryEntryFileName(const u8* sector, u32 de_sector_offset)
{
const ISODirectoryEntry* de = reinterpret_cast<const ISODirectoryEntry*>(sector + de_sector_offset);
if ((sizeof(ISODirectoryEntry) + de->filename_length) > de->entry_length ||
(sizeof(ISODirectoryEntry) + de->filename_length + de_sector_offset) > SECTOR_SIZE)
{
return std::string_view();
}
const char* str = reinterpret_cast<const char*>(sector + de_sector_offset + sizeof(ISODirectoryEntry));
if (de->filename_length == 1)
{
if (str[0] == '\0')
return ".";
else if (str[0] == '\1')
return "..";
}
// Strip any version information like the PS2 BIOS does.
u32 length_without_version = 0;
for (; length_without_version < de->filename_length; length_without_version++)
{
if (str[length_without_version] == ';' || str[length_without_version] == '\0')
break;
}
return std::string_view(str, length_without_version);
}
std::optional<IsoReader::ISODirectoryEntry> IsoReader::LocateFile(
const std::string_view& path, u8* sector_buffer, u32 directory_record_lba, u32 directory_record_size, Error* error)
{
if (directory_record_size == 0)
{
Error::SetString(error, fmt::format("Directory entry record size 0 while looking for '{}'", path));
return std::nullopt;
}
// strip any leading slashes
size_t path_component_start = 0;
while (path_component_start < path.length() &&
(path[path_component_start] == '/' || path[path_component_start] == '\\'))
{
path_component_start++;
}
size_t path_component_length = 0;
while ((path_component_start + path_component_length) < path.length() &&
path[path_component_start + path_component_length] != '/' &&
path[path_component_start + path_component_length] != '\\')
{
path_component_length++;
}
const std::string_view path_component = path.substr(path_component_start, path_component_length);
if (path_component.empty())
{
Error::SetString(error, fmt::format("Empty path component in {}", path));
return std::nullopt;
}
// start reading directory entries
const u32 num_sectors = (directory_record_size + (SECTOR_SIZE - 1)) / SECTOR_SIZE;
for (u32 i = 0; i < num_sectors; i++)
{
if (!ReadSector(sector_buffer, directory_record_lba + i, error))
return std::nullopt;
u32 sector_offset = 0;
while ((sector_offset + sizeof(ISODirectoryEntry)) < SECTOR_SIZE)
{
const ISODirectoryEntry* de = reinterpret_cast<const ISODirectoryEntry*>(&sector_buffer[sector_offset]);
if (de->entry_length < sizeof(ISODirectoryEntry))
break;
const std::string_view de_filename = GetDirectoryEntryFileName(sector_buffer, sector_offset);
sector_offset += de->entry_length;
// Empty file would be pretty strange..
if (de_filename.empty() || de_filename == "." || de_filename == "..")
continue;
if (!StringUtil::compareNoCase(de_filename, path_component))
continue;
// found it. is this the file we're looking for?
if ((path_component_start + path_component_length) == path.length())
return *de;
// if it is a directory, recurse into it
if (de->flags & ISODirectoryEntryFlag_Directory)
{
return LocateFile(path.substr(path_component_start + path_component_length), sector_buffer,
de->location_le, de->length_le, error);
}
// we're looking for a directory but got a file
Error::SetString(error, fmt::format("Looking for directory '{}' but got file", path_component));
return std::nullopt;
}
}
Error::SetString(error, fmt::format("Path component '{}' not found", path_component));
return std::nullopt;
}
std::vector<std::string> IsoReader::GetFilesInDirectory(const std::string_view& path, Error* error)
{
std::string base_path(path);
u32 directory_record_lsn;
u32 directory_record_length;
if (base_path.empty())
{
// root directory
const ISODirectoryEntry* root_de = reinterpret_cast<const ISODirectoryEntry*>(m_pvd.root_directory_entry);
directory_record_lsn = root_de->location_le;
directory_record_length = root_de->length_le;
}
else
{
auto directory_de = LocateFile(base_path, error);
if (!directory_de.has_value())
return {};
if ((directory_de->flags & ISODirectoryEntryFlag_Directory) == 0)
{
Error::SetString(error, fmt::format("Path '{}' is not a directory, can't list", path));
return {};
}
directory_record_lsn = directory_de->location_le;
directory_record_length = directory_de->length_le;
if (base_path[base_path.size() - 1] != '/')
base_path += '/';
}
// start reading directory entries
const u32 num_sectors = (directory_record_length + (SECTOR_SIZE - 1)) / SECTOR_SIZE;
std::vector<std::string> files;
u8 sector_buffer[SECTOR_SIZE];
for (u32 i = 0; i < num_sectors; i++)
{
if (!ReadSector(sector_buffer, directory_record_lsn + i, error))
break;
u32 sector_offset = 0;
while ((sector_offset + sizeof(ISODirectoryEntry)) < SECTOR_SIZE)
{
const ISODirectoryEntry* de = reinterpret_cast<const ISODirectoryEntry*>(&sector_buffer[sector_offset]);
if (de->entry_length < sizeof(ISODirectoryEntry))
break;
const std::string_view de_filename = GetDirectoryEntryFileName(sector_buffer, sector_offset);
sector_offset += de->entry_length;
// Empty file would be pretty strange..
if (de_filename.empty() || de_filename == "." || de_filename == "..")
continue;
files.push_back(fmt::format("{}/{}", base_path, de_filename));
}
}
return files;
}
bool IsoReader::FileExists(const std::string_view& path, Error* error)
{
auto de = LocateFile(path, error);
if (!de)
return false;
return (de->flags & ISODirectoryEntryFlag_Directory) == 0;
}
bool IsoReader::DirectoryExists(const std::string_view& path, Error* error)
{
auto de = LocateFile(path, error);
if (!de)
return false;
return (de->flags & ISODirectoryEntryFlag_Directory) == ISODirectoryEntryFlag_Directory;
}
bool IsoReader::ReadFile(const std::string_view& path, std::vector<u8>* data, Error* error)
{
auto de = LocateFile(path, error);
if (!de)
return false;
return ReadFile(de.value(), data, error);
}
bool IsoReader::ReadFile(const ISODirectoryEntry& de, std::vector<u8>* data, Error* error /*= nullptr*/)
{
if (de.flags & ISODirectoryEntryFlag_Directory)
{
Error::SetString(error, "File is a directory");
return false;
}
if (de.length_le == 0)
{
data->clear();
return true;
}
static_assert(sizeof(size_t) == sizeof(u64));
const u32 num_sectors = (de.length_le + (SECTOR_SIZE - 1)) / SECTOR_SIZE;
data->resize(num_sectors * static_cast<u64>(SECTOR_SIZE));
for (u32 i = 0, lsn = de.location_le; i < num_sectors; i++, lsn++)
{
if (!ReadSector(data->data() + (i * SECTOR_SIZE), lsn, error))
return false;
}
// Might not be sector aligned, so reduce it back.
data->resize(de.length_le);
return true;
}

Some files were not shown because too many files have changed in this diff Show More