mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-05-23 13:45:49 +00:00
Compare commits
1 Commits
Canary-1.3
...
begone/osx
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37c911b962 |
@@ -1,5 +0,0 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Ryubing Issue Tracker
|
||||
url: https://github.com/Ryubing/Issues/issues/
|
||||
about: "Please use this GitHub repository instead of creating issues on this Forgejo repository. Blank issues should only be used by maintainers and authorized bots. Issues made on this repository can and will be deleted."
|
||||
@@ -1,35 +0,0 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"renovate/config"
|
||||
],
|
||||
"enabledManagers": ["nuget", "github-actions"],
|
||||
"packageRules": [
|
||||
{
|
||||
// require approval for *all* NuGet package updates, not just major versions.
|
||||
"matchDepTypes": "nuget",
|
||||
"dependencyDashboardApproval": true
|
||||
},
|
||||
{
|
||||
// Ignore Gommon for automatic updates. I make breaking changes on minor updates not infrequently.
|
||||
"matchDepNames": "Gommon",
|
||||
"matchDepTypes": "nuget",
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"description": "group Silk.NET packages",
|
||||
"extends": ["renovate/config//groups/silkdotnet.json"],
|
||||
"groupName": "Silk.NET"
|
||||
},
|
||||
{
|
||||
"description": "group OpenTK packages",
|
||||
"extends": ["renovate/config//groups/opentk.json"],
|
||||
"groupName": "OpenTK"
|
||||
},
|
||||
{
|
||||
"description": "group Svg.Controls packages",
|
||||
"extends": ["renovate/config//groups/svgcontrols.json"],
|
||||
"groupName": "Svg.Controls"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
name: Build PR
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- '**'
|
||||
- '!.forgejo/**'
|
||||
- '!*.yml'
|
||||
- '!*.config'
|
||||
- '!*.md'
|
||||
- '.forgejo/workflows/*.yml'
|
||||
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
RELEASE: 0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.platform.name }} (${{ matrix.configuration }})
|
||||
runs-on: docker
|
||||
container:
|
||||
image: ghcr.io/catthehacker/ubuntu:act-latest
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Release]
|
||||
platform:
|
||||
- { name: win-x64, zip_os_name: win_x64 }
|
||||
- { name: win-arm64, zip_os_name: win_arm64 }
|
||||
- { name: linux-x64, zip_os_name: linux_x64 }
|
||||
- { name: linux-arm64, zip_os_name: linux_arm64 }
|
||||
#- { name: osx-x64, zip_os_name: osx_x64 }
|
||||
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Install GLI
|
||||
uses: actions/setup-gli@v1
|
||||
with:
|
||||
token: ${{ secrets.SETUP_GLI_TOKEN }}
|
||||
|
||||
- name: Install 7zip
|
||||
run: |
|
||||
sudo apt update && sudo apt install -y 7zip
|
||||
|
||||
- name: Overwrite csc problem matcher
|
||||
run: echo "::add-matcher::.forgejo/csc.json"
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "result=$(gli get-next-version -c Canary -R)" >> $FORGEJO_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ forgejo.sha }}")" >> $FORGEJO_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Change config filename
|
||||
run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
if: forgejo.event_name == 'pull_request'
|
||||
|
||||
- name: 'Cache: ~/.nuget/packages'
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
~/.nuget/packages
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props') }}
|
||||
|
||||
- name: Build
|
||||
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ steps.version_info.outputs.result }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:ExtraDefineConstants=DISABLE_UPDATER
|
||||
|
||||
- name: Test
|
||||
uses: actions/unstable-commands@v1
|
||||
with:
|
||||
commands: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||
timeout-minutes: 10
|
||||
retry-codes: 139
|
||||
if: matrix.platform.name != 'linux-arm64'
|
||||
|
||||
- name: Publish Ryujinx
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ steps.version_info.outputs.result }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained
|
||||
if: forgejo.event_name == 'pull_request'
|
||||
|
||||
- name: Packing Windows builds
|
||||
if: contains(matrix.platform.name, 'win')
|
||||
run: |
|
||||
7z a artifact/ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-${{ matrix.platform.zip_os_name }}.7z publish
|
||||
shell: bash
|
||||
|
||||
- name: Upload Ryujinx Windows artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-${{ matrix.platform.zip_os_name }}
|
||||
path: artifact
|
||||
if: forgejo.event_name == 'pull_request' && contains(matrix.platform.name, 'win')
|
||||
|
||||
- name: Build AppImage
|
||||
if: forgejo.event_name == 'pull_request' && contains(matrix.platform.name, 'linux')
|
||||
run: |
|
||||
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
|
||||
|
||||
PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||
|
||||
sudo apt update && sudo apt install -y zsync desktop-file-utils appstream libfuse2t64
|
||||
|
||||
mkdir -p tools
|
||||
export PATH="$PATH:$(readlink -f tools)"
|
||||
|
||||
# Setup appimagetool
|
||||
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
chmod +x tools/appimagetool
|
||||
chmod +x distribution/linux/appimage/build-appimage.sh
|
||||
|
||||
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
||||
if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||
ARCH_NAME=x64
|
||||
export ARCH=x86_64
|
||||
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||
ARCH_NAME=arm64
|
||||
export ARCH=aarch64
|
||||
else
|
||||
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
||||
shell: bash
|
||||
|
||||
- name: Upload Ryujinx AppImage artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
if: forgejo.event_name == 'pull_request' && contains(matrix.platform.name, 'linux')
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-${{ matrix.platform.zip_os_name }}-AppImage
|
||||
path: publish_appimage
|
||||
|
||||
build_macos:
|
||||
name: macOS Universal (${{ matrix.configuration }})
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [ Release ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 17
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install GLI
|
||||
uses: actions/setup-gli@v1
|
||||
with:
|
||||
token: ${{ secrets.SETUP_GLI_TOKEN }}
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
gli ghr -R indygreg/apple-platform-rs -p apple-codesign-*-x86_64-unknown-linux-musl.tar.gz -O apple-codesign.tar.gz
|
||||
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
|
||||
rm apple-codesign.tar.gz
|
||||
sudo mv rcodesign /usr/bin/rcodesign
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "result=$(gli get-next-version -c Stable -R)" >> $FORGEJO_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ forgejo.sha }}")" >> $FORGEJO_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Change config filename
|
||||
run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
if: forgejo.event_name == 'pull_request'
|
||||
|
||||
- name: 'Cache: ~/.nuget/packages'
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
~/.nuget/packages
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props') }}
|
||||
|
||||
- name: Publish macOS Ryujinx
|
||||
run: |
|
||||
bash distribution/macos/create_macos_pr_build_ava.sh . publish_tmp publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.result }}" "${{ steps.version_info.outputs.git_short_hash }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||
shell: bash
|
||||
|
||||
- name: Upload Ryujinx artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-macos_universal
|
||||
path: "publish/*.tar.gz"
|
||||
if: forgejo.event_name == 'pull_request'
|
||||
86
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
86
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
name: Bug Report
|
||||
description: File a bug report
|
||||
title: "[Bug]"
|
||||
labels: bug
|
||||
body:
|
||||
- type: textarea
|
||||
id: issue
|
||||
attributes:
|
||||
label: Description of the issue
|
||||
description: What's the issue you encountered?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: Reproduction steps
|
||||
description: How can the issue be reproduced?
|
||||
placeholder: Describe each step as precisely as possible
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: log
|
||||
attributes:
|
||||
label: Log file
|
||||
description: "A log file will help our developers to better diagnose and fix the issue. UPLOAD THE FILE. DO NOT COPY AND PASTE THE FILE'S CONTENT."
|
||||
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. They can also be accessed by opening Ryujinx, then going to File > Open Logs Folder. You can drag and drop the log on to the text area (do not copy paste).
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
label: OS
|
||||
placeholder: "e.g. Windows 10"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: ryujinx-version
|
||||
attributes:
|
||||
label: Ryujinx version
|
||||
placeholder: "e.g. 1.0.470"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: game-version
|
||||
attributes:
|
||||
label: Game version
|
||||
placeholder: "e.g. 1.1.1"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: cpu
|
||||
attributes:
|
||||
label: CPU
|
||||
placeholder: "e.g. i7-6700"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: gpu
|
||||
attributes:
|
||||
label: GPU
|
||||
placeholder: "e.g. NVIDIA RTX 2070"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: ram
|
||||
attributes:
|
||||
label: RAM
|
||||
placeholder: "e.g. 16GB"
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: mods
|
||||
attributes:
|
||||
label: List of applied mods
|
||||
placeholder: You can list applied mods here.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional context?
|
||||
description: |
|
||||
- Additional info about your environment:
|
||||
- Any other information relevant to your issue.
|
||||
validations:
|
||||
required: false
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Ryujinx Discord
|
||||
url: https://discord.gg/N2FmfVc
|
||||
about: This is for development related issues. For support and technical issues, please come to our Discord server.
|
||||
31
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
31
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: Feature Request
|
||||
description: Suggest a new feature for Ryujinx.
|
||||
title: "[Feature Request]"
|
||||
labels: enhancement
|
||||
body:
|
||||
- type: textarea
|
||||
id: overview
|
||||
attributes:
|
||||
label: Overview
|
||||
description: Include the basic, high-level concepts for this feature here.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: details
|
||||
attributes:
|
||||
label: Smaller details
|
||||
description: These may include specific methods of implementation etc.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: request
|
||||
attributes:
|
||||
label: Nature of request
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: feature
|
||||
attributes:
|
||||
label: Why would this feature be useful?
|
||||
validations:
|
||||
required: true
|
||||
26
.github/ISSUE_TEMPLATE/missing_cpu_instruction.yml
vendored
Normal file
26
.github/ISSUE_TEMPLATE/missing_cpu_instruction.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Missing CPU Instruction
|
||||
description: CPU Instruction is missing in Ryujinx.
|
||||
title: "[CPU]"
|
||||
labels: [cpu, not-implemented]
|
||||
body:
|
||||
- type: textarea
|
||||
id: instruction
|
||||
attributes:
|
||||
label: CPU instruction
|
||||
description: What CPU instruction is missing?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: name
|
||||
attributes:
|
||||
label: Instruction name
|
||||
description: Include the name from [armconverter.com](https://armconverter.com/?disasm) or [shell-storm.org](http://shell-storm.org/online/Online-Assembler-and-Disassembler/?arch=arm64&endianness=big&dis_with_raw=True&dis_with_ins=True) in the above code block
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: required
|
||||
attributes:
|
||||
label: Required by
|
||||
description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this instruction.
|
||||
validations:
|
||||
required: true
|
||||
25
.github/ISSUE_TEMPLATE/missing_service_call.yml
vendored
Normal file
25
.github/ISSUE_TEMPLATE/missing_service_call.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Missing Service Call
|
||||
description: Service call is missing in Ryujinx.
|
||||
labels: not-implemented
|
||||
body:
|
||||
- type: textarea
|
||||
id: instruction
|
||||
attributes:
|
||||
label: Service call
|
||||
description: What service call is missing?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: name
|
||||
attributes:
|
||||
label: Service description
|
||||
description: Include the description/explanation from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) in the above code block
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: required
|
||||
attributes:
|
||||
label: Required by
|
||||
description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this service.
|
||||
validations:
|
||||
required: true
|
||||
19
.github/ISSUE_TEMPLATE/missing_shader_instruction.yml
vendored
Normal file
19
.github/ISSUE_TEMPLATE/missing_shader_instruction.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: Missing Shader Instruction
|
||||
description: Shader Instruction is missing in Ryujinx.
|
||||
title: "[GPU]"
|
||||
labels: [gpu, not-implemented]
|
||||
body:
|
||||
- type: textarea
|
||||
id: instruction
|
||||
attributes:
|
||||
label: Shader instruction
|
||||
description: What shader instruction is missing?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: required
|
||||
attributes:
|
||||
label: Required by
|
||||
description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this instruction.
|
||||
validations:
|
||||
required: true
|
||||
0
.forgejo/csc.json → .github/csc.json
vendored
0
.forgejo/csc.json → .github/csc.json
vendored
22
.forgejo/labeler.yml → .github/labeler.yml
vendored
22
.forgejo/labeler.yml → .github/labeler.yml
vendored
@@ -10,10 +10,6 @@ gpu:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.Graphics.*/**', 'src/Spv.Generator/**', 'src/Ryujinx.ShaderTools/**']
|
||||
|
||||
input:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.Input*/**', 'src/Ryujinx/UI/Views/Input/**']
|
||||
|
||||
'graphics-backend:opengl':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'src/Ryujinx.Graphics.OpenGL/**'
|
||||
@@ -22,17 +18,17 @@ input:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.Graphics.Vulkan/**', 'src/Spv.Generator/**']
|
||||
|
||||
'graphics-backend:metal':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.Graphics.Metal/**', 'src/Ryujinx.Graphics.Metal.SharpMetalExtensions/**']
|
||||
|
||||
gui:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.UI.LocaleGenerator/**']
|
||||
- any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.UI.Common/**', 'src/Ryujinx.UI.LocaleGenerator/**']
|
||||
|
||||
'horizon/hle':
|
||||
horizon:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.HLE/**', 'src/Ryujinx.HLE.Generators/**', 'src/Ryujinx.Horizon/**']
|
||||
|
||||
i18n:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['assets/**/*.json', 'src/Ryujinx.UI.LocaleGenerator/**']
|
||||
- any-glob-to-any-file: ['src/Ryujinx.HLE/**', 'src/Ryujinx.Horizon/**']
|
||||
|
||||
kernel:
|
||||
- changed-files:
|
||||
@@ -40,7 +36,7 @@ kernel:
|
||||
|
||||
infra:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['.forgejo/**', 'distribution/**', 'Directory.Packages.props', 'src/Ryujinx.BuildValidationTasks/**']
|
||||
- any-glob-to-any-file: ['.github/**', 'distribution/**', 'Directory.Packages.props', 'src/Ryujinx.BuildValidationTasks/**']
|
||||
|
||||
documentation:
|
||||
- changed-files:
|
||||
@@ -48,4 +44,4 @@ documentation:
|
||||
|
||||
ldn:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.HLE/HOS/Services/Ldn/**', 'src/Ryujinx/UI/Windows/LdnGamesListWindow.*', 'src/Ryujinx/UI/ViewModels/LdnGamesListViewModel.cs']
|
||||
- any-glob-to-any-file: 'src/Ryujinx.HLE/HOS/Services/Ldn/**'
|
||||
168
.github/workflows/build.yml
vendored
Normal file
168
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
name: Build job
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
RYUJINX_BASE_VERSION: "1.2.0"
|
||||
RELEASE: 0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.platform.name }} (${{ matrix.configuration }})
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Debug, Release]
|
||||
platform:
|
||||
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 }
|
||||
- { name: win-arm64, os: windows-latest, zip_os_name: win_arm64 }
|
||||
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
|
||||
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
|
||||
- { name: osx-x64, os: macos-13, zip_os_name: osx_x64 }
|
||||
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Overwrite csc problem matcher
|
||||
run: echo "::add-matcher::.github/csc.json"
|
||||
|
||||
- name: Get git short hash
|
||||
id: git_short_hash
|
||||
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Change config filename
|
||||
run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||
|
||||
- name: Change config filename for macOS
|
||||
run: sed -r -i '' 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os == 'macos-13'
|
||||
|
||||
- name: Build
|
||||
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER
|
||||
|
||||
- name: Test
|
||||
uses: TSRBerry/unstable-commands@v1
|
||||
with:
|
||||
commands: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||
timeout-minutes: 10
|
||||
retry-codes: 139
|
||||
if: matrix.platform.name != 'linux-arm64'
|
||||
|
||||
- name: Publish Ryujinx
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||
|
||||
- name: Set executable bit
|
||||
run: |
|
||||
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest'
|
||||
|
||||
- name: Build AppImage
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||
|
||||
sudo apt install -y zsync desktop-file-utils appstream
|
||||
|
||||
mkdir -p tools
|
||||
export PATH="$PATH:$(readlink -f tools)"
|
||||
|
||||
# Setup appimagetool
|
||||
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
chmod +x tools/appimagetool
|
||||
chmod +x distribution/linux/appimage/build-appimage.sh
|
||||
|
||||
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
||||
if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||
ARCH_NAME=x64
|
||||
export ARCH=x86_64
|
||||
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||
ARCH_NAME=arm64
|
||||
export ARCH=aarch64
|
||||
else
|
||||
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
||||
shell: bash
|
||||
|
||||
- name: Upload Ryujinx artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}
|
||||
path: publish
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||
|
||||
- name: Upload Ryujinx (AppImage) artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest'
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}-AppImage
|
||||
path: publish_appimage
|
||||
|
||||
build_macos:
|
||||
name: macOS Universal (${{ matrix.configuration }})
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [ Debug, Release ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 17
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
|
||||
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
|
||||
rm apple-codesign.tar.gz
|
||||
mv rcodesign $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get git short hash
|
||||
id: git_short_hash
|
||||
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Change config filename
|
||||
run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
- name: Publish macOS Ryujinx
|
||||
run: |
|
||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp publish ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||
|
||||
- name: Upload Ryujinx artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||
path: "publish/*.tar.gz"
|
||||
if: github.event_name == 'pull_request'
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- '.forgejo/**'
|
||||
- '.github/**'
|
||||
- 'docs/**'
|
||||
- 'assets/**'
|
||||
- '*.yml'
|
||||
@@ -25,41 +25,44 @@ env:
|
||||
jobs:
|
||||
release:
|
||||
name: Release for ${{ matrix.platform.name }}
|
||||
runs-on: docker
|
||||
container:
|
||||
image: ${{ matrix.platform.os }}
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
platform:
|
||||
- { name: win-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: win_x64 }
|
||||
- { name: win-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: win_arm64 }
|
||||
- { name: linux-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_x64 }
|
||||
- { name: linux-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_arm64 }
|
||||
- { name: win-x64, os: ubuntu-latest, zip_os_name: win_x64 }
|
||||
#- { name: win-arm64, os: ubuntu-latest, zip_os_name: win_arm64 }
|
||||
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
|
||||
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-dotnet@v5
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Overwrite csc problem matcher
|
||||
run: echo "::add-matcher::.forgejo/csc.json"
|
||||
|
||||
- name: Install GLI
|
||||
uses: actions/setup-gli@v1
|
||||
with:
|
||||
token: ${{ secrets.SETUP_GLI_TOKEN }}
|
||||
run: echo "::add-matcher::.github/csc.json"
|
||||
|
||||
- name: Install 7zip
|
||||
run: |
|
||||
sudo apt update && sudo apt install -y 7zip
|
||||
sudo apt install -y 7zip
|
||||
|
||||
- name: Install gli
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
|
||||
chmod +x gli
|
||||
mv gli $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=$(gli get-next-version -c Canary -R)" >> $FORGEJO_OUTPUT
|
||||
echo "prev_build_version=$(gli get-current-version -c Canary -R)" >> $FORGEJO_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ forgejo.sha }}")" >> $FORGEJO_OUTPUT
|
||||
echo "build_version=$(gli get-next-version -c Canary -R)" >> $GITHUB_OUTPUT
|
||||
echo "prev_build_version=$(gli get-current-version -c Canary -R)" >> $GITHUB_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Configure for release
|
||||
@@ -84,9 +87,12 @@ jobs:
|
||||
pushd publish
|
||||
rm libarmeilleure-jitsupport.dylib
|
||||
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
|
||||
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.7z ../publish
|
||||
popd
|
||||
|
||||
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -r 5 -p release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Packing Linux builds
|
||||
if: contains(matrix.platform.name, 'linux')
|
||||
@@ -95,8 +101,9 @@ jobs:
|
||||
rm libarmeilleure-jitsupport.dylib
|
||||
chmod +x Ryujinx.sh Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||
tar -cJvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.xz ../publish
|
||||
popd
|
||||
|
||||
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -r 5 -p release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz
|
||||
shell: bash
|
||||
|
||||
- name: Build AppImage (Linux)
|
||||
@@ -105,7 +112,7 @@ jobs:
|
||||
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
||||
PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||
|
||||
sudo apt update && sudo apt install -y zsync desktop-file-utils appstream libfuse2t64
|
||||
sudo apt install -y zsync desktop-file-utils appstream
|
||||
|
||||
mkdir -p tools
|
||||
export PATH="$PATH:$(readlink -f tools)"
|
||||
@@ -132,28 +139,17 @@ jobs:
|
||||
pushd publish_appimage
|
||||
mv Ryujinx.AppImage ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
popd
|
||||
|
||||
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -r 5 -p release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
shell: bash
|
||||
|
||||
- name: Create release
|
||||
uses: actions/create-release@v1
|
||||
with:
|
||||
name: "Canary ${{ steps.version_info.outputs.build_version }}"
|
||||
body: "**Full Changelog:** [`${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}`](https://git.ryujinx.app/projects/Ryubing/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }})"
|
||||
repository: "Ryubing/Canary"
|
||||
token: ${{ secrets.RELEASER_TOKEN }}
|
||||
tag_name: ${{ steps.version_info.outputs.build_version }}
|
||||
files: |-
|
||||
release_output/**
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
runs-on: docker
|
||||
container:
|
||||
image: ghcr.io/catthehacker/ubuntu:act-latest
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-dotnet@v5
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
@@ -163,24 +159,33 @@ jobs:
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install GLI
|
||||
uses: actions/setup-gli@v1
|
||||
with:
|
||||
token: ${{ secrets.SETUP_GLI_TOKEN }}
|
||||
- name: Install gli
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
|
||||
chmod +x gli
|
||||
mv gli $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
gli ghr -R indygreg/apple-platform-rs -p apple-codesign-*-x86_64-unknown-linux-musl.tar.gz -O apple-codesign.tar.gz
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
|
||||
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
|
||||
rm apple-codesign.tar.gz
|
||||
mv rcodesign /usr/bin/rcodesign
|
||||
mv rcodesign $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=$(gli get-next-version -c Canary -R)" >> $FORGEJO_OUTPUT
|
||||
echo "prev_build_version=$(gli get-current-version -c Canary -R)" >> $FORGEJO_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ forgejo.sha }}")" >> $FORGEJO_OUTPUT
|
||||
echo "build_version=$(gli get-next-version -c Canary -R)" >> $GITHUB_OUTPUT
|
||||
echo "prev_build_version=$(gli get-current-version -c Canary -R)" >> $GITHUB_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Configure for release
|
||||
@@ -196,53 +201,46 @@ jobs:
|
||||
- name: Publish macOS Ryujinx
|
||||
run: |
|
||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
|
||||
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -r 5 -p publish_ava/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz
|
||||
|
||||
- name: Create release
|
||||
uses: actions/create-release@v1
|
||||
with:
|
||||
name: "Canary ${{ steps.version_info.outputs.build_version }}"
|
||||
body: "**Full Changelog:** [`${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}`](https://git.ryujinx.app/projects/Ryubing/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }})"
|
||||
repository: "Ryubing/Canary"
|
||||
token: ${{ secrets.RELEASER_TOKEN }}
|
||||
tag_name: ${{ steps.version_info.outputs.build_version }}
|
||||
files: |-
|
||||
publish_ava/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz
|
||||
|
||||
post_ci:
|
||||
name: Post CI Steps
|
||||
runs-on: docker
|
||||
container:
|
||||
image: ghcr.io/catthehacker/ubuntu:act-latest
|
||||
create_gitlab_release:
|
||||
name: Create GitLab Release
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- macos_release
|
||||
- release
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install GLI
|
||||
uses: actions/setup-gli@v1
|
||||
with:
|
||||
token: ${{ secrets.SETUP_GLI_TOKEN }}
|
||||
- name: Install gli
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
|
||||
chmod +x gli
|
||||
mv gli $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=$(gli get-next-version -c Canary -R)" >> $FORGEJO_OUTPUT
|
||||
echo "prev_build_version=$(gli get-current-version -c Canary -R)" >> $FORGEJO_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ forgejo.sha }}")" >> $FORGEJO_OUTPUT
|
||||
echo "build_version=$(gli get-next-version -c Canary -R)" >> $GITHUB_OUTPUT
|
||||
echo "prev_build_version=$(gli get-current-version -c Canary -R)" >> $GITHUB_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Create tag
|
||||
run: |
|
||||
gli create-tag -T ${{ secrets.RELEASER_TOKEN }} -P projects/Ryubing -n Canary-${{ steps.version_info.outputs.build_version }} -r ${{ steps.version_info.outputs.git_short_hash }}
|
||||
|
||||
- name: Link to actual source archives for Canary
|
||||
run: |
|
||||
gli canary-release -T ${{ secrets.RELEASER_TOKEN }} -P Ryubing/Canary -r ${{ steps.version_info.outputs.build_version }}
|
||||
gli create-tag -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Canary-${{ steps.version_info.outputs.build_version }} -r ${{ steps.version_info.outputs.git_short_hash }}
|
||||
|
||||
- name: Create release
|
||||
run: |
|
||||
gli create-release-from-generic-package-files -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -r main -t "Canary ${{ steps.version_info.outputs.build_version }}" -b "**Full Changelog:** [${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}](https://git.ryujinx.app/ryubing/ryujinx/-/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }})"
|
||||
|
||||
- name: Send notification webhook
|
||||
run: |
|
||||
gli send-update-message -T ${{ secrets.RELEASER_TOKEN }} -P Ryubing/Canary -t ${{ steps.version_info.outputs.build_version }} -c FF4500 -w ${{ secrets.CANARY_DISCORD_WEBHOOK }} -i https://avatars.githubusercontent.com/u/192939710?s=200&v=4
|
||||
gli send-update-message -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -t ${{ steps.version_info.outputs.build_version }} -c FF4500 -w ${{ secrets.CANARY_DISCORD_WEBHOOK }} -i https://avatars.githubusercontent.com/u/192939710?s=200&v=4
|
||||
|
||||
- name: Notify update server of new builds
|
||||
run: |
|
||||
25
.github/workflows/checks.yml
vendored
Normal file
25
.github/workflows/checks.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Build PR
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- '**'
|
||||
- '!.github/**'
|
||||
- '!*.yml'
|
||||
- '!*.config'
|
||||
- '!*.md'
|
||||
- '.github/workflows/*.yml'
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
checks: write
|
||||
|
||||
concurrency:
|
||||
group: pr-checks-${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
pr_build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
secrets: inherit
|
||||
61
.github/workflows/nightly_pr_comment.yml
vendored
Normal file
61
.github/workflows/nightly_pr_comment.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: Comment PR artifacts links
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ['Build PR']
|
||||
types: [completed]
|
||||
|
||||
jobs:
|
||||
pr_comment:
|
||||
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const {owner, repo} = context.repo;
|
||||
const run_id = ${{github.event.workflow_run.id}};
|
||||
const pull_head_sha = '${{github.event.workflow_run.head_sha}}';
|
||||
|
||||
const issue_number = await (async () => {
|
||||
const pulls = await github.rest.pulls.list({owner, repo});
|
||||
for await (const {data} of github.paginate.iterator(pulls)) {
|
||||
for (const pull of data) {
|
||||
if (pull.head.sha === pull_head_sha) {
|
||||
return pull.number;
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
if (issue_number) {
|
||||
core.info(`Using pull request ${issue_number}`);
|
||||
} else {
|
||||
return core.error(`No matching pull request found`);
|
||||
}
|
||||
|
||||
const {data: {artifacts}} = await github.rest.actions.listWorkflowRunArtifacts({owner, repo, run_id});
|
||||
if (!artifacts.length) {
|
||||
return core.error(`No artifacts found`);
|
||||
}
|
||||
let body = `Download the artifacts for this pull request:\n`;
|
||||
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
|
||||
for (const art of artifacts) {
|
||||
const url = `https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip`;
|
||||
if (art.name.includes('Debug')) {
|
||||
hidden_debug_artifacts += `\n* [${art.name}](${url})`;
|
||||
} else {
|
||||
body += `\n* [${art.name}](${url})`;
|
||||
}
|
||||
}
|
||||
hidden_debug_artifacts += `\n</details>`;
|
||||
body += hidden_debug_artifacts;
|
||||
|
||||
const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number});
|
||||
const existing_comment = comments.find((c) => c.user.login === 'github-actions[bot]');
|
||||
if (existing_comment) {
|
||||
core.info(`Updating comment ${existing_comment.id}`);
|
||||
await github.rest.issues.updateComment({repo, owner, comment_id: existing_comment.id, body});
|
||||
} else {
|
||||
core.info(`Creating a comment`);
|
||||
await github.rest.issues.createComment({repo, owner, issue_number, body});
|
||||
}
|
||||
@@ -5,22 +5,24 @@ on:
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Grab sources to get latest labeler.yml
|
||||
- name: Fetch sources
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# Ensure we pin the source origin as pull_request_target run under forks.
|
||||
fetch-depth: 0
|
||||
repository: projects/Ryubing
|
||||
repository: GreemDev/Ryujinx
|
||||
ref: master
|
||||
|
||||
- name: Update labels based on changes
|
||||
uses: actions/labeler@v6
|
||||
uses: actions/labeler@v5
|
||||
with:
|
||||
repo-token: ${{ secrets.LABELER_TOKEN }}
|
||||
configuration-path: .forgejo/labeler.yml
|
||||
sync-labels: true
|
||||
dot: true
|
||||
@@ -19,20 +19,18 @@ env:
|
||||
jobs:
|
||||
release:
|
||||
name: Release for ${{ matrix.platform.name }}
|
||||
runs-on: docker
|
||||
container:
|
||||
image: ${{ matrix.platform.os }}
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
platform:
|
||||
- { name: win-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: win_x64 }
|
||||
- { name: win-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: win_arm64 }
|
||||
- { name: linux-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_x64 }
|
||||
- { name: linux-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_arm64 }
|
||||
- { name: win-x64, os: ubuntu-latest, zip_os_name: win_x64 }
|
||||
#- { name: win-arm64, os: ubuntu-latest, zip_os_name: win_arm64 }
|
||||
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
|
||||
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-dotnet@v5
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
@@ -43,21 +41,26 @@ jobs:
|
||||
run: |
|
||||
sudo apt install -y 7zip
|
||||
|
||||
- name: Install GLI
|
||||
uses: actions/setup-gli@v1
|
||||
with:
|
||||
token: ${{ secrets.SETUP_GLI_TOKEN }}
|
||||
- name: Install gli
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
|
||||
chmod +x gli
|
||||
mv gli $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
if [ '${{ inputs.is_bugfix_release }}' == 'false' ]; then
|
||||
echo "build_version=$(gli get-next-version -m -c Stable -R)" >> $FORGEJO_OUTPUT
|
||||
echo "build_version=$(gli get-next-version -m -c Stable -R)" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "build_version=$(gli get-next-version -c Stable -R)" >> $FORGEJO_OUTPUT
|
||||
echo "build_version=$(gli get-next-version -c Stable -R)" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
echo "prev_build_version=$(gli get-current-version -c Stable -R)" >> $FORGEJO_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ forgejo.sha }}")" >> $FORGEJO_OUTPUT
|
||||
echo "prev_build_version=$(gli get-current-version -c Stable -R)" >> $GITHUB_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Configure for release
|
||||
@@ -81,9 +84,12 @@ jobs:
|
||||
pushd publish
|
||||
rm libarmeilleure-jitsupport.dylib
|
||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
|
||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.7z ../publish
|
||||
popd
|
||||
|
||||
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -r 5 -p release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Packing Linux builds
|
||||
if: contains(matrix.platform.name, 'linux')
|
||||
@@ -92,9 +98,12 @@ jobs:
|
||||
rm libarmeilleure-jitsupport.dylib
|
||||
chmod +x Ryujinx.sh Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||
tar -cJvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.xz ../publish
|
||||
popd
|
||||
|
||||
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -r 5 -p release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build AppImage (Linux)
|
||||
if: contains(matrix.platform.name, 'linux')
|
||||
@@ -129,25 +138,17 @@ jobs:
|
||||
pushd publish_appimage
|
||||
mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Create release
|
||||
uses: actions/create-release@v1
|
||||
with:
|
||||
name: "${{ steps.version_info.outputs.build_version }}"
|
||||
repository: "projects/Ryubing"
|
||||
token: ${{ secrets.RELEASER_TOKEN }}
|
||||
tag_name: ${{ steps.version_info.outputs.build_version }}
|
||||
files: |-
|
||||
release_output/**
|
||||
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -r 5 -p release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
shell: bash
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-dotnet@v5
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
@@ -157,28 +158,37 @@ jobs:
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install GLI
|
||||
uses: actions/setup-gli@v1
|
||||
with:
|
||||
token: ${{ secrets.SETUP_GLI_TOKEN }}
|
||||
- name: Install gli
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
|
||||
chmod +x gli
|
||||
mv gli $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
gli ghr -R indygreg/apple-platform-rs -p apple-codesign-*-x86_64-unknown-linux-musl.tar.gz -O apple-codesign.tar.gz
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
|
||||
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
|
||||
rm apple-codesign.tar.gz
|
||||
mv rcodesign /usr/bin/rcodesign
|
||||
mv rcodesign $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
if [ '${{ inputs.is_bugfix_release }}' == 'false' ]; then
|
||||
echo "build_version=$(gli get-next-version -m -c Stable -R)" >> $FORGEJO_OUTPUT
|
||||
echo "build_version=$(gli get-next-version -m -c Stable -R)" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "build_version=$(gli get-next-version -c Stable -R)" >> $FORGEJO_OUTPUT
|
||||
echo "build_version=$(gli get-next-version -c Stable -R)" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
echo "prev_build_version=$(gli get-current-version -c Stable -R)" >> $FORGEJO_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ forgejo.sha }}")" >> $FORGEJO_OUTPUT
|
||||
echo "prev_build_version=$(gli get-current-version -c Stable -R)" >> $GITHUB_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Configure for release
|
||||
@@ -191,47 +201,49 @@ jobs:
|
||||
|
||||
- name: Publish macOS Ryujinx
|
||||
run: |
|
||||
bash distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
|
||||
|
||||
- name: Create release
|
||||
uses: actions/create-release@v1
|
||||
with:
|
||||
name: "${{ steps.version_info.outputs.build_version }}"
|
||||
repository: "projects/Ryubing"
|
||||
token: ${{ secrets.RELEASER_TOKEN }}
|
||||
tag_name: ${{ steps.version_info.outputs.build_version }}
|
||||
files: |-
|
||||
publish_ava/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz
|
||||
|
||||
post_ci:
|
||||
name: Post-CI Steps
|
||||
runs-on: ubuntu-latest
|
||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
|
||||
|
||||
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -r 5 -p publish/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz
|
||||
|
||||
create_gitlab_release:
|
||||
name: Create GitLab Release
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- macos_release
|
||||
- release
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install GLI
|
||||
uses: actions/setup-gli@v1
|
||||
with:
|
||||
token: ${{ secrets.SETUP_GLI_TOKEN }}
|
||||
- name: Install gli
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
|
||||
chmod +x gli
|
||||
mv gli $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
if [ '${{ inputs.is_bugfix_release }}' == 'false' ]; then
|
||||
echo "build_version=$(gli get-next-version -m -c Stable -R)" >> $FORGEJO_OUTPUT
|
||||
echo "build_version=$(gli get-next-version -m -c Stable -R)" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "build_version=$(gli get-next-version -c Stable -R)" >> $FORGEJO_OUTPUT
|
||||
echo "build_version=$(gli get-next-version -c Stable -R)" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
echo "prev_build_version=$(gli get-current-version -c Stable -R)" >> $FORGEJO_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ forgejo.sha }}")" >> $FORGEJO_OUTPUT
|
||||
echo "prev_build_version=$(gli get-current-version -c Stable -R)" >> $GITHUB_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
echo "commit_message=$(git log -1 --pretty=%B)" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Create release
|
||||
run: |
|
||||
gli create-release-from-generic-package-files -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -r ${{ steps.version_info.outputs.git_short_hash }} -t "${{ steps.version_info.outputs.build_version }}" -b "msd:${{ steps.version_info.outputs.build_version }}"
|
||||
|
||||
- name: Send notification webhook
|
||||
run: |
|
||||
gli send-update-message -T ${{ secrets.RELEASER_TOKEN }} -P projects/Ryubing -t ${{ steps.version_info.outputs.build_version }} -c 32cd32 -w ${{ secrets.STABLE_DISCORD_WEBHOOK }} -i https://avatars.githubusercontent.com/u/192939710?s=200&v=4
|
||||
gli send-update-message -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -t ${{ steps.version_info.outputs.build_version }} -c 32cd32 -w ${{ secrets.STABLE_DISCORD_WEBHOOK }} -i https://avatars.githubusercontent.com/u/192939710?s=200&v=4
|
||||
|
||||
- name: Notify update server of new builds
|
||||
run: |
|
||||
@@ -3,66 +3,59 @@
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia" Version="11.3.15" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.13" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.15" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.15" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.15" />
|
||||
<PackageVersion Include="SharpCompress" Version="0.48.1" />
|
||||
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.5" />
|
||||
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.5" />
|
||||
<PackageVersion Include="Avalonia" Version="11.3.12" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.12" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.12" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.12" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.12" />
|
||||
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.4" />
|
||||
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.4" />
|
||||
<PackageVersion Include="Microsoft.Build.Framework" Version="17.11.4" />
|
||||
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.12.50" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.12.6" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia" Version="9.6.2" />
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.6.2" />
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.6.2" />
|
||||
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.501.0" />
|
||||
<PackageVersion Include="ppy.SDL3-CS" Version="2025.920.0" />
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
||||
<PackageVersion Include="DynamicData" Version="9.4.31" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.5.1" />
|
||||
<PackageVersion Include="DynamicData" Version="9.4.1" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.5.0" />
|
||||
<PackageVersion Include="Humanizer" Version="2.14.1" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.18.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.3.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
|
||||
<PackageVersion Include="NUnit" Version="3.14.0" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.6.0" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.9.4" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.9.4" />
|
||||
<!-- OpenTk.Audio.OpenAL has moved to OpenTk.Audio -->
|
||||
<!--<PackageVersion Include="OpenTK.Audio" Version="5.0.0-pre.15" />-->
|
||||
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.9.4" />
|
||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.9.4" />
|
||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.8.2" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.8.2" />
|
||||
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.8.2" />
|
||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.2" />
|
||||
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
|
||||
<!-- Ryujinx.Audio.OpenAL.Dependencies is from the original project, last updated 12/30/20 -->
|
||||
<!--<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />-->
|
||||
<PackageVersion Include="Ryujinx.Audio.OpenAL" Version="1.25.1" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.4-build6" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.MoltenVK" Version="1.4.2-ryujinx.3" />
|
||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.133" />
|
||||
<PackageVersion Include="Ryujinx.UpdateClient" Version="2.0.6" />
|
||||
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="2.0.6" />
|
||||
<PackageVersion Include="Gommon" Version="2.8.1.2" />
|
||||
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.2-build3" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.129" />
|
||||
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.44" />
|
||||
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.44" />
|
||||
<PackageVersion Include="Gommon" Version="2.8.0.1" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="Sep" Version="0.14.1" />
|
||||
<PackageVersion Include="Sep" Version="0.11.1" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.23.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.23.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.23.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Win32" Version="2.88.9" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.macOS" Version="2.88.9" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.9" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.15" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.3" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.2" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
26
README.md
26
README.md
@@ -5,10 +5,10 @@
|
||||
</td>
|
||||
<td align="center" width="75%">
|
||||
|
||||
<h1 class="ryu-gradient-text">Ryujinx</h1>
|
||||
# Ryujinx
|
||||
|
||||
[](https://update.ryujinx.app/latest/stable)
|
||||
[](https://update.ryujinx.app/latest/canary)
|
||||
[](https://update.ryujinx.app/latest/stable)
|
||||
[](https://update.ryujinx.app/latest/canary)
|
||||
<br>
|
||||
<a href="https://discord.gg/PEuzjrFXUA">
|
||||
<img src="https://img.shields.io/discord/1294443224030511104?color=5865F2&label=Ryubing&logo=discord&logoColor=white" alt="Discord">
|
||||
@@ -21,7 +21,7 @@
|
||||
Ryujinx is an open-source Nintendo Switch emulator, originally created by gdkchan, written in C#.
|
||||
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
|
||||
It was written from scratch and development on the project began in September 2017.
|
||||
Ryujinx is available on a self-managed <a class="forgejo-gradient-text" href="https://github.com/Ryubing/forgejo" target="_blank">modified Forgejo</a> instance under the <a href="https://git.ryujinx.app/projects/Ryubing/src/branch/master/LICENSE.txt" target="_blank">MIT license</a>.
|
||||
Ryujinx is available on a self-managed GitLab instance under the <a href="https://git.ryujinx.app/ryubing/ryujinx/-/blob/master/LICENSE.txt?ref_type=heads" target="_blank">MIT license</a>.
|
||||
<br />
|
||||
</p>
|
||||
<p align="center">
|
||||
@@ -31,11 +31,11 @@
|
||||
<br>
|
||||
This is not a Ryujinx revival project. This is not a Phoenix project.
|
||||
<br>
|
||||
Guides and documentation can be found on the <a href="https://git.ryujinx.app/projects/Ryubing/wiki/Home">Wiki tab</a>.
|
||||
Guides and documentation can be found on the <a href="https://git.ryujinx.app/groups/ryubing/-/wikis/home">Wiki tab</a>.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://git.ryujinx.app/projects/Ryubing/raw/branch/master/docs/shell.png" alt="Ryujinx example">
|
||||
<img src="https://git.ryujinx.app/ryubing/ryujinx/-/raw/master/docs/shell.png?ref_type=heads&inline=false" alt="Ryujinx example">
|
||||
</p>
|
||||
|
||||
## Usage
|
||||
@@ -49,17 +49,17 @@ Stable builds are made every so often, based on the `master` branch, that then g
|
||||
These stable builds exist so that the end user can get a more **enjoyable and stable experience**.
|
||||
They are released every month or so, to ensure consistent updates, while not being an annoying amount of individual updates to download over the course of that month.
|
||||
|
||||
You can find the stable releases [here](https://git.ryujinx.app/projects/Ryubing/releases).
|
||||
You can find the stable releases [here](https://git.ryujinx.app/ryubing/ryujinx/-/releases).
|
||||
|
||||
Canary builds are compiled automatically for each commit on the `master` branch.
|
||||
While we strive to ensure optimal stability and performance prior to pushing an update, these builds **may be unstable or completely broken**.
|
||||
These canary builds are only recommended for experienced users.
|
||||
|
||||
You can find the canary releases [here](https://git.ryujinx.app/Ryubing/Canary/releases).
|
||||
You can find the canary releases [here](https://git.ryujinx.app/ryubing/canary/-/releases).
|
||||
|
||||
## Documentation
|
||||
|
||||
If you are planning to contribute or just want to learn more about this project please read through our [documentation](https://git.ryujinx.app/projects/Ryubing/src/branch/master/docs/README.md).
|
||||
If you are planning to contribute or just want to learn more about this project please read through our [documentation](docs/README.md).
|
||||
|
||||
## Features
|
||||
|
||||
@@ -105,13 +105,13 @@ If you are planning to contribute or just want to learn more about this project
|
||||
|
||||
## License
|
||||
|
||||
This software is licensed under the terms of the [MIT license](https://git.ryujinx.app/projects/Ryubing/src/branch/master/LICENSE.txt).
|
||||
This software is licensed under the terms of the [MIT license](LICENSE.txt).
|
||||
This project makes use of code authored by the libvpx project, licensed under BSD and the ffmpeg project, licensed under LGPLv3.
|
||||
See [LICENSE.txt](https://git.ryujinx.app/projects/Ryubing/src/branch/master/LICENSE.txt) and [THIRDPARTY.md](https://git.ryujinx.app/projects/Ryubing/src/branch/master/distribution/legal/THIRDPARTY.md) for more details.
|
||||
See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY.md) for more details.
|
||||
|
||||
## Credits
|
||||
|
||||
- [LibHac](https://git.ryujinx.app/projects/LibHac) is used for our file-system.
|
||||
- [LibHac](https://git.ryujinx.app/ryubing/libhac) is used for our file-system.
|
||||
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.
|
||||
- [ldn_mitm](https://github.com/spacemeowx2/ldn_mitm) is used for one of our available multiplayer modes.
|
||||
- [ShellLink](https://github.com/securifybv/ShellLink) is used for Windows shortcut generation.
|
||||
- [ShellLink](https://github.com/securifybv/ShellLink) is used for Windows shortcut generation.
|
||||
16
Ryujinx.sln
16
Ryujinx.sln
@@ -86,11 +86,11 @@ EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
.forgejo\workflows\build.yml = .forgejo\workflows\build.yml
|
||||
.forgejo\workflows\canary.yml = .forgejo\workflows\canary.yml
|
||||
.github\workflows\build.yml = .github\workflows\build.yml
|
||||
.github\workflows\canary.yml = .github\workflows\canary.yml
|
||||
Directory.Packages.props = Directory.Packages.props
|
||||
Directory.Build.props = Directory.Build.props
|
||||
.forgejo\workflows\release.yml = .forgejo\workflows\release.yml
|
||||
.github\workflows\release.yml = .github\workflows\release.yml
|
||||
nuget.config = nuget.config
|
||||
EndProjectSection
|
||||
EndProject
|
||||
@@ -573,16 +573,6 @@ Global
|
||||
{D58FA894-27D5-4EAA-9042-AD422AD82931}.Release|x86.Build.0 = Release|Any CPU
|
||||
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{AC26EFF0-8593-4184-9A09-98E37EFFB32E}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -5,8 +5,8 @@ Ryubing Locales uses a custom format, which uses a file for defining the support
|
||||
Each json file holds the locales for a specific part of the emulator, e.g. the Setup Wizard locales are in `SetupWizard.json`, and each locale entry in the file includes all the supported languages in the same place.
|
||||
|
||||
## Languages
|
||||
In the `/assets/` folder you will find the `Languages.json` file, which defines all the languages supported by the emulator.
|
||||
The file includes a table of the language codes and their language names.
|
||||
in the `/assets/` folder you will find the `Languages.json` file, which defines all the languages supported by the emulator.
|
||||
The file includes a table of the langauge codes and their langauge names.
|
||||
|
||||
#Example of the format for Languages.json
|
||||
{
|
||||
@@ -19,7 +19,7 @@ The file includes a table of the language codes and their language names.
|
||||
}
|
||||
|
||||
## Locales
|
||||
In the `/assets/Locales/` folder you will find the json files, which define all the locales supported by the emulator.
|
||||
in the `/assets/Locales/` folder you will find the json files, which define all the locales supported by the emulator.
|
||||
Each json file holds locales for a specific part of the emulator in a large array of locale objects.
|
||||
Each locale is made up an ID used for lookup and a list of the languages and their matching translations.
|
||||
Any empty string or null value will automatically use the English translation instead in the emulator.
|
||||
|
||||
@@ -1,329 +0,0 @@
|
||||
{
|
||||
"Locales": [
|
||||
{
|
||||
"ID": "InstallFromFileFilePickerTitle",
|
||||
"Translations": {
|
||||
"ar_SA": "حدد ملف XCI أو أرشيف ZIP لتثبيت البرنامج الثابت منه",
|
||||
"de_DE": "Wählen Sie eine XCI-Datei oder ein ZIP-Archiv zur Firmware-Installation aus",
|
||||
"el_GR": "Επιλέξτε ένα αρχείο XCI ή ένα αρχείο ZIP για εγκατάσταση υλικολογισμικού",
|
||||
"en_US": "Select an XCI file or a ZIP archive to install firmware from",
|
||||
"es_ES": "Selecciona un archivo XCI o un archivo ZIP para instalar el firmware",
|
||||
"fr_FR": "Sélectionnez un fichier XCI ou une archive ZIP pour installer le firmware",
|
||||
"he_IL": "בחר קובץ XCI או ארכיון ZIP להתקנת קושחה",
|
||||
"it_IT": "Seleziona un file XCI o un archivio ZIP da cui installare il firmware",
|
||||
"ja_JP": "ファームウェアをインストールする XCI ファイルまたは ZIP アーカイブを選択してください",
|
||||
"ko_KR": "펌웨어를 설치할 XCI 파일 또는 ZIP 아카이브를 선택하세요",
|
||||
"no_NO": "Velg en XCI-fil eller et ZIP-arkiv for å installere fastvare fra",
|
||||
"pl_PL": "Wybierz plik XCI lub archiwum ZIP, z którego chcesz zainstalować firmware",
|
||||
"pt_BR": "Selecione um arquivo XCI ou um arquivo ZIP para instalar o firmware",
|
||||
"ru_RU": "Выберите XCI файл или ZIP-архив для установки прошивки",
|
||||
"sv_SE": "Välj en XCI-fil eller ett ZIP-arkiv för att installera firmware från",
|
||||
"th_TH": "เลือกไฟล์ XCI หรือไฟล์ ZIP เพื่อติดตั้งเฟิร์มแวร์",
|
||||
"tr_TR": "Üretici yazılımını yüklemek için bir XCI dosyası veya ZIP arşivi seçin",
|
||||
"uk_UA": "Виберіть XCI файл або ZIP-архів для встановлення прошивки",
|
||||
"zh_CN": "选择一个用于安装固件的 XCI 文件或 ZIP 压缩包",
|
||||
"zh_TW": "選擇一個用於安裝韌體的 XCI 檔案或 ZIP 壓縮檔"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallFromFolderFilePickerTitle",
|
||||
"Translations": {
|
||||
"ar_SA": "حدد مجلدًا لتثبيت البرنامج الثابت منه",
|
||||
"de_DE": "Wählen Sie einen Ordner aus, um die Firmware zu installieren",
|
||||
"el_GR": "Επιλέξτε έναν φάκελο για να εγκαταστήσετε το firmware από αυτόν",
|
||||
"en_US": "Select a folder to install firmware from",
|
||||
"es_ES": "Selecciona una carpeta para instalar el firmware desde ella",
|
||||
"fr_FR": "Sélectionnez un dossier pour installer le firmware à partir de celui-ci",
|
||||
"he_IL": "בחר תיקיה שממנה תותקן הקושחה",
|
||||
"it_IT": "Seleziona una cartella da cui installare il firmware",
|
||||
"ja_JP": "ファームウェアをインストールするフォルダを選択してください",
|
||||
"ko_KR": "펌웨어를 설치할 폴더를 선택하세요",
|
||||
"no_NO": "Velg en mappe å installere fastvaren fra",
|
||||
"pl_PL": "Wybierz folder, z którego chcesz zainstalować oprogramowanie układowe",
|
||||
"pt_BR": "Selecione uma pasta para instalar o firmware a partir dela",
|
||||
"ru_RU": "Выберите папку, из которой будет установлена прошивка",
|
||||
"sv_SE": "Välj en mapp att installera firmware från",
|
||||
"th_TH": "เลือกโฟลเดอร์เพื่อติดตั้งเฟิร์มแวร์จากโฟลเดอร์นั้น",
|
||||
"tr_TR": "Firmware yüklemek için bir klasör seçin",
|
||||
"uk_UA": "Виберіть папку, з якої буде встановлено прошивку",
|
||||
"zh_CN": "选择一个文件夹以从中安装固件",
|
||||
"zh_TW": "選擇一個資料夾以從中安裝韌體"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerTitle",
|
||||
"Translations": {
|
||||
"ar_SA": "تثبيت البرنامج الثابت {0}",
|
||||
"de_DE": "Installiere Firmware {0}",
|
||||
"el_GR": "Εγκατάσταση Firmware {0}",
|
||||
"en_US": "Install Firmware {0}",
|
||||
"es_ES": "Instalar Firmware {0}",
|
||||
"fr_FR": "Installer le Firmware {0}",
|
||||
"he_IL": "התקן קושחה {0}",
|
||||
"it_IT": "Installa firmware {0}",
|
||||
"ja_JP": "ファームウェア {0} をインストール",
|
||||
"ko_KR": "펌웨어 {0} 설치",
|
||||
"no_NO": "Installer fastvare {0}",
|
||||
"pl_PL": "Zainstaluj Firmware {0}",
|
||||
"pt_BR": "Instalar Firmware {0}",
|
||||
"ru_RU": "Установить прошивку {0}",
|
||||
"sv_SE": "Installera firmware {0}",
|
||||
"th_TH": "ติดตั้งเฟิร์มแวร์ {0}",
|
||||
"tr_TR": "Firmware {0} Yükle",
|
||||
"uk_UA": "Встановити прошивку {0}",
|
||||
"zh_CN": "安装系统固件 {0}",
|
||||
"zh_TW": "安裝韌體 {0}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerMainMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "سيتم تثبيت إصدار النظام {0}.",
|
||||
"de_DE": "Systemversion {0} wird jetzt installiert.",
|
||||
"el_GR": "Θα εγκατασταθεί η έκδοση συστήματος {0}.",
|
||||
"en_US": "System version {0} will be installed.",
|
||||
"es_ES": "Se instalará la versión de sistema {0}.",
|
||||
"fr_FR": "La version {0} du système sera installée.",
|
||||
"he_IL": "גירסת המערכת {0} תותקן.",
|
||||
"it_IT": "La versione del sistema {0} sarà installata.",
|
||||
"ja_JP": "システムバージョン {0} がインストールされます。",
|
||||
"ko_KR": "시스템 버전 {0}이(가) 설치됩니다.",
|
||||
"no_NO": "Systemversjon {0} vil bli installert.",
|
||||
"pl_PL": "Wersja systemu {0} zostanie zainstalowana.",
|
||||
"pt_BR": "A versão do sistema {0} será instalada.",
|
||||
"ru_RU": "Будет установлена версия прошивки {0}.",
|
||||
"sv_SE": "Systemversion {0} kommer att installeras.",
|
||||
"th_TH": "ระบบเวอร์ชั่น {0} ได้รับการติดตั้งเร็วๆ นี้",
|
||||
"tr_TR": "Sistem sürümü {0} yüklenecek.",
|
||||
"uk_UA": "Буде встановлено версію системи {0}.",
|
||||
"zh_CN": "即将安装系统固件版本 {0} 。",
|
||||
"zh_TW": "即將安裝系統韌體版本 {0}。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerSubMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "\n\nهذا سيحل محل إصدار النظام الحالي {0}.",
|
||||
"de_DE": "\n\nDies wird die aktuelle Systemversion {0} ersetzen.",
|
||||
"el_GR": "\n\nΑυτό θα αντικαταστήσει την τρέχουσα έκδοση συστήματος {0}.",
|
||||
"en_US": "\n\nThis will replace the current system version {0}.",
|
||||
"es_ES": "\n\nEsto reemplazará la versión de sistema actual, {0}.",
|
||||
"fr_FR": "\n\nCela remplacera la version actuelle du système {0}.",
|
||||
"he_IL": "\n\nזה יחליף את גרסת המערכת הנוכחית {0}.",
|
||||
"it_IT": "\n\nQuesta sostituirà l'attuale versione del sistema ({0}).",
|
||||
"ja_JP": "\n\n現在のシステムバージョン {0} を置き換えます。",
|
||||
"ko_KR": "\n\n현재 시스템 버전 {0}을(를) 대체합니다.",
|
||||
"no_NO": "\n\nDette erstatter den gjeldende systemversjonen {0}.",
|
||||
"pl_PL": "\n\nZastąpi to obecną wersję systemu {0}.",
|
||||
"pt_BR": "\n\nIsso substituirá a versão do sistema atual {0}.",
|
||||
"ru_RU": "\n\nЭто заменит текущую версию прошивки {0}.",
|
||||
"sv_SE": "\n\nDetta kommer att ersätta aktuella systemversionen {0}.",
|
||||
"th_TH": "\n\nสิ่งนี้จะแทนที่เวอร์ชั่นของระบบเวอร์ชั่นปัจจุบัน {0}.",
|
||||
"tr_TR": "\n\nBu şimdiki sistem sürümünün yerini alacak {0}.",
|
||||
"uk_UA": "\n\nЦе замінить поточну версію системи {0}.",
|
||||
"zh_CN": "\n\n替换当前系统固件版本 {0} 。",
|
||||
"zh_TW": "\n\n這將取代目前的系統韌體版本 {0}。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerConfirmMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "\nهل تريد المتابعة؟",
|
||||
"de_DE": "\n\nMöchtest du fortfahren?",
|
||||
"el_GR": "\n\nΘέλετε να συνεχίσετε;",
|
||||
"en_US": "\n\nDo you want to continue?",
|
||||
"es_ES": "\n\n¿Continuar?",
|
||||
"fr_FR": "\n\nVoulez-vous continuer ?",
|
||||
"he_IL": "\n\nהאם ברצונך להמשיך?",
|
||||
"it_IT": "\n\nVuoi continuare?",
|
||||
"ja_JP": "\n\n続けてよろしいですか?",
|
||||
"ko_KR": "\n\n계속하시겠습니까?",
|
||||
"no_NO": "\n\nVil du fortsette?",
|
||||
"pl_PL": "\n\nCzy chcesz kontynuować?",
|
||||
"pt_BR": "\n\nDeseja continuar?",
|
||||
"ru_RU": "\n\nПродолжить?",
|
||||
"sv_SE": "\n\nVill du fortsätta?",
|
||||
"th_TH": "\n\nคุณต้องการดำเนินการต่อหรือไม่?",
|
||||
"tr_TR": "\n\nDevam etmek istiyor musunuz?",
|
||||
"uk_UA": "\n\nВи хочете продовжити?",
|
||||
"zh_CN": "\n\n是否继续?",
|
||||
"zh_TW": "\n\n您確定要繼續嗎?"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerWaitMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "تثبيت البرنامج الثابت...",
|
||||
"de_DE": "Firmware wird installiert...",
|
||||
"el_GR": "Εγκατάσταση Firmware...",
|
||||
"en_US": "Installing Firmware...",
|
||||
"es_ES": "Instalando Firmware...",
|
||||
"fr_FR": "Installation du Firmware...",
|
||||
"he_IL": "מתקין קושחה...",
|
||||
"it_IT": "Installazione del firmware...",
|
||||
"ja_JP": "ファームウェアをインストール中...",
|
||||
"ko_KR": "펌웨어 설치 중...",
|
||||
"no_NO": "Installerer fastvare...",
|
||||
"pl_PL": "Instalowanie firmware'u...",
|
||||
"pt_BR": "Instalando firmware...",
|
||||
"ru_RU": "Установка прошивки...",
|
||||
"sv_SE": "Installerar firmware...",
|
||||
"th_TH": "กำลังติดตั้งเฟิร์มแวร์...",
|
||||
"tr_TR": "Firmware yükleniyor...",
|
||||
"uk_UA": "Встановлення прошивки...",
|
||||
"zh_CN": "安装系统固件中...",
|
||||
"zh_TW": "正在安裝韌體..."
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerSuccessMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "تم تثبيت إصدار النظام {0} بنجاح.",
|
||||
"de_DE": "Systemversion {0} wurde erfolgreich installiert.",
|
||||
"el_GR": "Η έκδοση συστήματος {0} εγκαταστάθηκε με επιτυχία.",
|
||||
"en_US": "System version {0} successfully installed.",
|
||||
"es_ES": "Versión de sistema {0} instalada con éxito.",
|
||||
"fr_FR": "Version du système {0} installée avec succès.",
|
||||
"he_IL": "גרסת המערכת {0} הותקנה בהצלחה.",
|
||||
"it_IT": "La versione del sistema {0} è stata installata.",
|
||||
"ja_JP": "システムバージョン {0} が正常にインストールされました。",
|
||||
"ko_KR": "시스템 버전 {0}이(가) 설치되었습니다.",
|
||||
"no_NO": "Systemversjon {0} ble installert.",
|
||||
"pl_PL": "Wersja systemu {0} została pomyślnie zainstalowana.",
|
||||
"pt_BR": "Versão do sistema {0} instalada com sucesso.",
|
||||
"ru_RU": "Прошивка версии {0} успешно установлена.",
|
||||
"sv_SE": "Systemversion {0} har installerats.",
|
||||
"th_TH": "ระบบเวอร์ชั่น {0} ติดตั้งเรียบร้อยแล้ว",
|
||||
"tr_TR": "Sistem sürümü {0} başarıyla yüklendi.",
|
||||
"uk_UA": "Версію системи {0} успішно встановлено.",
|
||||
"zh_CN": "成功安装系统固件版本 {0}。",
|
||||
"zh_TW": "成功安裝系統韌體版本 {0}。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerInstalledMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "تم تثبيت البرنامج الثابت {0}",
|
||||
"de_DE": "Firmware {0} wurde installiert",
|
||||
"el_GR": "Το Firmware {0} εγκαταστάθηκε",
|
||||
"en_US": "Firmware {0} was installed",
|
||||
"es_ES": "Se Instaló el Firmware {0}",
|
||||
"fr_FR": "Le firmware {0} a été installé",
|
||||
"he_IL": "הקושחה {0} הותקנה",
|
||||
"it_IT": "Il firmware {0} è stato installato",
|
||||
"ja_JP": "ファームウェア {0} がインストールされました",
|
||||
"ko_KR": "펌웨어 {0}이(가) 설치됨",
|
||||
"no_NO": "fastvare {0} ble installert",
|
||||
"pl_PL": "Firmware {0} został zainstalowany",
|
||||
"pt_BR": "Firmware {0} foi instalado",
|
||||
"ru_RU": "Прошивка {0} была установлена",
|
||||
"sv_SE": "Firmware {0} installerades",
|
||||
"th_TH": "เฟิร์มแวร์ {0} ติดตั้งแล้ว",
|
||||
"tr_TR": "Yazılım {0} yüklendi",
|
||||
"uk_UA": "Встановлено прошивку {0}",
|
||||
"zh_CN": "已安装系统固件 {0}",
|
||||
"zh_TW": "已安裝韌體{0}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerNotInstalledMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "لا يوجد برنامج ثابت مثبت",
|
||||
"de_DE": "Keine Firmware installiert.",
|
||||
"el_GR": "Δεν έχει εγκατασταθεί Firmware.",
|
||||
"en_US": "No Firmware Installed.",
|
||||
"es_ES": "No hay Firmware Instalado.",
|
||||
"fr_FR": "Aucun Firmware Installé.",
|
||||
"he_IL": "לא מותקנת קושחה.",
|
||||
"it_IT": "Nessun firmware installato.",
|
||||
"ja_JP": "ファームウェアがインストールされていません。",
|
||||
"ko_KR": "펌웨어가 설치되어 있지 .않음",
|
||||
"no_NO": "Ingen fastvare installert.",
|
||||
"pl_PL": "Brak Zainstalowanego Firmware'u.",
|
||||
"pt_BR": "Nenhum Firmware Instalado.",
|
||||
"ru_RU": "Прошивка не установлена.",
|
||||
"sv_SE": "Inget firmware installerat.",
|
||||
"th_TH": "ไม่มีการติดตั้งเฟิร์มแวร์",
|
||||
"tr_TR": "Yazılım Yüklü Değil.",
|
||||
"uk_UA": "Прошивка не встановлена.",
|
||||
"zh_CN": "未安装系统固件。",
|
||||
"zh_TW": "未安裝韌體。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerFirmwareNotFound",
|
||||
"Translations": {
|
||||
"ar_SA": "لم يتم العثور على برنامج ثابت للنظام صالح في {0}.",
|
||||
"de_DE": "Es wurde keine gültige System-Firmware gefunden in {0}.",
|
||||
"el_GR": "Δεν βρέθηκε έγκυρο Firmware συστήματος στο {0}.",
|
||||
"en_US": "A valid system firmware was not found in {0}.",
|
||||
"es_ES": "No se pudo encontrar un firmware válido en {0}.",
|
||||
"fr_FR": "Un firmware valide n'a pas été trouvé dans {0}.",
|
||||
"he_IL": "לא נמצאה קושחת מערכת תקפה ב-{0}.",
|
||||
"it_IT": "Un firmware del sistema valido non è stato trovato in {0}.",
|
||||
"ja_JP": "{0} には有効なシステムファームウェアがありません。",
|
||||
"ko_KR": "{0}에서 유효한 시스템 펌웨어를 찾을 수 없습니다.",
|
||||
"no_NO": "En gyldig systemfastvare ble ikke funnet i {0}.",
|
||||
"pl_PL": "Nie znaleziono prawidłowego firmware'u systemowego w {0}.",
|
||||
"pt_BR": "Um firmware de sistema válido não foi encontrado em {0}.",
|
||||
"ru_RU": "Не удалось найти действительную системную прошивку в {0}.",
|
||||
"sv_SE": "Ett giltigt systemfirmware hittades inte i {0}.",
|
||||
"th_TH": "ไม่พบเฟิร์มแวร์ของระบบที่ถูกต้อง {0}.",
|
||||
"tr_TR": "{0} da geçerli bir sistem firmware'i bulunamadı.",
|
||||
"uk_UA": "Дійсна прошивка системи не знайдена в {0}.",
|
||||
"zh_CN": "在路径 {0} 中找不到有效的 Switch 系统固件。",
|
||||
"zh_TW": "在 {0} 中未發現有效的系統韌體。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerEmbeddedMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "هل ترغب في تثبيت البرنامج الثابت المدمج في هذه اللعبة؟ (البرنامج الثابت {0})",
|
||||
"de_DE": "Die in diesem Spiel enthaltene Firmware installieren? (Firmware {0})",
|
||||
"el_GR": "Θα θέλατε να εγκαταστήσετε το Firmware που είναι ενσωματωμένο σε αυτό το παιχνίδι; (Firmware {0})",
|
||||
"en_US": "Would you like to install the firmware embedded in this game? (Firmware {0})",
|
||||
"es_ES": "¿Quieres instalar el firmware incluido en este juego? (Firmware versión {0})",
|
||||
"fr_FR": "Voulez-vous installer le firmware intégré dans ce jeu ? (Firmware {0})",
|
||||
"he_IL": "האם תרצו להתקין את הקושחה המוטמעת במשחק הזה? (קושחה {0})",
|
||||
"it_IT": "Vuoi installare il firmware incluso in questo gioco? (Firmware {0})",
|
||||
"ja_JP": "このゲームに含まれるファームウェアをインストールしてよろしいですか? (ファームウェア {0})",
|
||||
"ko_KR": "이 게임에 포함된 펌웨어를 설치하시겠습니까?(Firmware {0})",
|
||||
"no_NO": "Ønsker du å installere fastvaren innebygd i dette spillet? (Firmware {0})",
|
||||
"pl_PL": "Czy chcesz zainstalować firmware wbudowany w tę grę? (Firmware {0})",
|
||||
"pt_BR": "Gostaria de instalar o firmware incluso neste jogo? (Firmware {0})",
|
||||
"ru_RU": "Хотите установить прошивку, встроенную в эту игру? (Прошивка {0})",
|
||||
"sv_SE": "Vill du installera det firmware som är inbäddat i detta spel? (Firmware {0})",
|
||||
"th_TH": "คุณต้องการติดตั้งเฟิร์มแวร์ที่ฝังอยู่ในเกมนี้หรือไม่? (เฟิร์มแวร์ {0})",
|
||||
"tr_TR": "Bu oyunun içine gömülü olan yazılımı yüklemek ister misiniz? (Firmware {0})",
|
||||
"uk_UA": "Бажаєте встановити прошивку, вбудовану в цю гру? (Прошивка {0})",
|
||||
"zh_CN": "要安装游戏文件中内嵌的系统固件吗?(固件版本 {0})",
|
||||
"zh_TW": "您想安裝遊戲內建的韌體嗎? (韌體 {0})"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerEmbeddedSuccessMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "لم يتم العثور على أي برنامج ثابت مثبت ولكن ريوجينكس كان قادرا على تثبيت البرنامج الثابت {0} من اللعبة المقدمة.\nسيبدأ المحاكي الآن.",
|
||||
"de_DE": "Es wurde keine installierte Firmware gefunden, aber Ryujinx konnte die Firmware {0} aus dem bereitgestellten Spiel installieren.\nRyujinx wird nun gestartet.",
|
||||
"el_GR": "Δεν βρέθηκε εγκατεστημένο υλικολογισμικό, αλλά το Ryujinx κατάφερε να εγκαταστήσει το υλικολογισμικό {0} από το παρεχόμενο παιχνίδι.\nΟ προσομοιωτής θα ξεκινήσει τώρα.",
|
||||
"en_US": "No installed firmware was found but Ryujinx was able to install firmware {0} from the provided game.\nThe emulator will now start.",
|
||||
"es_ES": "No se encontró ningún firmware instalado, pero Ryujinx pudo instalar el firmware {0} del juego proporcionado.\nEl emulador iniciará.",
|
||||
"fr_FR": "Aucun firmware installé n'a été trouvé mais Ryujinx a pu installer le firmware {0} à partir du jeu fourni.\nL'émulateur va maintenant démarrer.",
|
||||
"he_IL": "לא נמצאה קושחה מותקנת אבל ריוג'ינקס הצליח להתקין קושחה {0} מהמשחק שסופק. \nהאמולטור יופעל כעת.",
|
||||
"it_IT": "Non è stato trovato alcun firmware installato, ma Ryujinx è riuscito ad installare il firmware {0} dal gioco fornito.\nL'emulatore si avvierà adesso.",
|
||||
"ja_JP": "ファームウェアがインストールされていませんが, ゲームに含まれるファームウェア {0} をインストールできます.\nエミュレータが開始します。",
|
||||
"ko_KR": "설치된 펌웨어를 찾을 수 없지만 Ryujinx는 제공된 게임에서 펌웨어 {0}을(를) 설치할 수 있습니다.\n이제 에뮬레이터가 시작됩니다.",
|
||||
"no_NO": "Det ble ikke funnet noen installert fastvare, men Ryujinx kunne installere fastvare {0} fra det oppgitte spillet.\nemulatoren vil nå starte.",
|
||||
"pl_PL": "Nie znaleziono zainstalowanego oprogramowania, ale Ryujinx był w stanie zainstalować oprogramowanie {0} z dostarczonej gry.\n\nEmulator uruchomi się teraz.",
|
||||
"pt_BR": "Nenhum firmware instalado foi encontrado, mas o Ryujinx conseguiu instalar o firmware {0} a partir do jogo fornecido.\nO emulador será iniciado agora.",
|
||||
"ru_RU": "Установленной прошивки не было найдено, но Ryujinx удалось установить прошивку {0} из предоставленной игры.\nТеперь запустится эмулятор.",
|
||||
"sv_SE": "Inget installerat firmware hittades men Ryujinx kunde installera firmware {0} från angiven spel.\nEmulatorn kommer nu att startas.",
|
||||
"th_TH": "ไม่พบเฟิร์มแวร์ที่ติดตั้งไว้ แต่ Ryujinx จะติดตั้งเฟิร์มแวร์ได้ {0} จากเกมที่ให้มา\nขณะนี้โปรแกรมจำลองจะเริ่มทำงาน",
|
||||
"tr_TR": "Yüklü bir firmware bulunamadı, ancak Ryujinx sağlanan oyundan firmware {0} yüklemeyi başardı.\nEmülatör şimdi başlatılacak.",
|
||||
"uk_UA": "Встановлену прошивку не знайдено, але Ryujinx вдалося встановити прошивку {0} з наданої гри.\nТепер запуститься емулятор.",
|
||||
"zh_CN": "Ryujinx 模拟器已经从当前游戏文件中安装了系统固件 {0} 。\n模拟器现在可以正常运行了。",
|
||||
"zh_TW": "未找到已安裝的韌體,但 Ryujinx 可以從現有的遊戲安裝韌體{0}。\n模擬器現在可以執行。"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
{
|
||||
"Locales": [
|
||||
{
|
||||
"ID": "InstallFromFileFilePickerTitle",
|
||||
"Translations": {
|
||||
"ar_SA": "حدد ملف KEYS لتثبيت المفاتيح منه",
|
||||
"de_DE": "Wählen Sie eine KEYS-Datei zur Schlüsselinstallation aus",
|
||||
"el_GR": "Επιλέξτε ένα αρχείο KEYS για εγκατάσταση κλειδιών",
|
||||
"en_US": "Select a KEYS file to install keys from",
|
||||
"es_ES": "Selecciona un archivo KEYS para instalar las claves",
|
||||
"fr_FR": "Sélectionnez un fichier KEYS pour installer les clés",
|
||||
"he_IL": "בחר קובץ KEYS להתקנת מפתחות",
|
||||
"it_IT": "Seleziona un file KEYS da cui installare le chiavi",
|
||||
"ja_JP": "キーをインストールする KEYS ファイルを選択してください",
|
||||
"ko_KR": "키를 설치할 KEYS 파일을 선택하세요",
|
||||
"no_NO": "Velg en KEYS-fil for å installere nøkler fra",
|
||||
"pl_PL": "Wybierz plik KEYS, z którego chcesz zainstalować klucze",
|
||||
"pt_BR": "Selecione um arquivo KEYS para instalar as chaves",
|
||||
"ru_RU": "Выберите KEYS файл для установки ключей",
|
||||
"sv_SE": "Välj en KEYS-fil för att installera nycklar från",
|
||||
"th_TH": "เลือกไฟล์ KEYS เพื่อติดตั้งคีย์",
|
||||
"tr_TR": "Anahtarları yüklemek için bir KEYS dosyası seçin",
|
||||
"uk_UA": "Виберіть KEYS файл для встановлення ключів",
|
||||
"zh_CN": "选择一个用于安装密钥的 KEYS 文件",
|
||||
"zh_TW": "選擇一個用於安裝金鑰的 KEYS 檔案"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallFromFolderFilePickerTitle",
|
||||
"Translations": {
|
||||
"ar_SA": "حدد مجلدًا لتثبيت المفاتيح منه",
|
||||
"de_DE": "Wählen Sie einen Ordner aus, um die Schlüssel zu installieren",
|
||||
"el_GR": "Επιλέξτε έναν φάκελο για να εγκαταστήσετε τα κλειδιά",
|
||||
"en_US": "Select a folder to install keys from",
|
||||
"es_ES": "Selecciona una carpeta para instalar las claves",
|
||||
"fr_FR": "Sélectionnez un dossier pour installer les clés",
|
||||
"he_IL": "בחר תיקיה להתקין ממנה את המפתחות",
|
||||
"it_IT": "Seleziona una cartella da cui installare le chiavi",
|
||||
"ja_JP": "キーをインストールするフォルダを選択してください",
|
||||
"ko_KR": "키를 설치할 폴더를 선택하세요",
|
||||
"no_NO": "Velg en mappe å installere nøklene fra",
|
||||
"pl_PL": "Wybierz folder, z którego zainstalować klucze",
|
||||
"pt_BR": "Selecione uma pasta para instalar as chaves",
|
||||
"ru_RU": "Выберите папку, из которой установить ключи",
|
||||
"sv_SE": "Välj en mapp att installera nycklar från",
|
||||
"th_TH": "เลือกโฟลเดอร์เพื่อติดตั้งคีย์",
|
||||
"tr_TR": "Anahtarları yüklemek için bir klasör seçin",
|
||||
"uk_UA": "Виберіть папку, з якої встановити ключі",
|
||||
"zh_CN": "选择一个文件夹以安装密钥",
|
||||
"zh_TW": "選擇一個資料夾以安裝密鑰"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerMainMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "سيتم تثبيت ملف مفاتيح جديد.",
|
||||
"de_DE": "Eine neue Schlüsseldatei wird installiert.",
|
||||
"el_GR": "Ένα νέο αρχείο Κλειδιών θα εγκατασταθεί.",
|
||||
"en_US": "New Keys file will be installed.",
|
||||
"es_ES": "Un nuevo archivo de Claves será instalado.",
|
||||
"fr_FR": "Nouveau fichier de Clés sera installé.",
|
||||
"he_IL": "קובץ מפתחות חדש יותקן.",
|
||||
"it_IT": "Un nuovo file di chiavi sarà installato.",
|
||||
"ja_JP": "新しいキー ファイルがインストールされます。",
|
||||
"ko_KR": "새로운 키 파일이 설치됩니다.",
|
||||
"no_NO": "Ny Keys-fil vil bli installert.",
|
||||
"pl_PL": "Nowy plik kluczy zostanie zainstalowany.",
|
||||
"pt_BR": "O novo arquivo Chaves será instalado.",
|
||||
"ru_RU": "Будут установлены новые ключи.",
|
||||
"sv_SE": "Ny nyckelfil kommer att installeras.",
|
||||
"th_TH": "กำลังติดตั้งไฟล์ Keys ใหม่",
|
||||
"tr_TR": "Yeni anahtar dosyası yüklenecek.",
|
||||
"uk_UA": "Новий файл Ключів буде встановлено.",
|
||||
"zh_CN": "将会安装新密匙文件。",
|
||||
"zh_TW": "將會安裝新增的金鑰檔案。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerSubMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "\n\nقد يحل هذا محل بعض المفاتيح المثبتة حاليًا.",
|
||||
"de_DE": "\n\nDies könnte einige der derzeit installierten Schlüssel ersetzen.",
|
||||
"el_GR": "\n\nΑυτό μπορεί να αντικαταστήσει μερικά από τα τρέχοντα εγκατεστημένα κλειδιά.",
|
||||
"en_US": "\n\nThis may replace some of the current installed Keys.",
|
||||
"es_ES": "\n\nEsto puede reemplazar algunas de las Keys actualmente instaladas.",
|
||||
"fr_FR": "\n\nCela peut remplacer certaines des Clés actuellement installées.",
|
||||
"he_IL": "\n\nזה עשוי להחליף חלק מהמפתחות המותקנים הנוכחיים.",
|
||||
"it_IT": "\n\nAlcune delle chiavi già installate potrebbero essere sovrascritte.",
|
||||
"ja_JP": "\n\nこれにより、現在インストールされているキーの一部が置き換えられる場合があります。",
|
||||
"ko_KR": "\n\n이로 인해 현재 설치된 키 중 일부가 대체될 수 있습니다.",
|
||||
"no_NO": "\n\nDette kan erstatte noen av de nåværende installerte nøklene.",
|
||||
"pl_PL": "\n\nTo może zastąpić niektóre z aktualnie zainstalowanych kluczy.",
|
||||
"pt_BR": "\n\nIsso pode substituir algumas das chaves instaladas atualmente.",
|
||||
"ru_RU": "\n\nЭто может заменить некоторые из текущих установленных ключей.",
|
||||
"sv_SE": "\n\nDetta kan ersätta några av de redan installerade nycklarna.",
|
||||
"th_TH": "\n\nสิ่งนี้อาจทำให้ไฟล์ Keys บางส่วนที่ติดตั้งอยู่ถูกแทนที่",
|
||||
"tr_TR": "\n\nBu, şu anda kurulu olan anahtarların bazılarının yerine geçebilir.",
|
||||
"uk_UA": "\n\nЦе замінить собою поточні файли Ключів.",
|
||||
"zh_CN": "\n\n这也许会替换掉一些当前已安装的密匙。",
|
||||
"zh_TW": "\n\n這將取代部分已安裝的金鑰。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerConfirmInstall",
|
||||
"Translations": {
|
||||
"ar_SA": "\nهل تريد المتابعة؟",
|
||||
"de_DE": "\n\nMöchtest du fortfahren?",
|
||||
"el_GR": "\n\nΘέλετε να συνεχίσετε;",
|
||||
"en_US": "\n\nDo you want to continue?",
|
||||
"es_ES": "\n\n¿Continuar?",
|
||||
"fr_FR": "\n\nVoulez-vous continuer ?",
|
||||
"he_IL": "\n\nהאם ברצונך להמשיך?",
|
||||
"it_IT": "\n\nVuoi continuare?",
|
||||
"ja_JP": "\n\n続けてよろしいですか?",
|
||||
"ko_KR": "\n\n계속하시겠습니까?",
|
||||
"no_NO": "\n\nVil du fortsette?",
|
||||
"pl_PL": "\n\nCzy chcesz kontynuować?",
|
||||
"pt_BR": "\n\nDeseja continuar?",
|
||||
"ru_RU": "\n\nПродолжить?",
|
||||
"sv_SE": "\n\nVill du fortsätta?",
|
||||
"th_TH": "\n\nคุณต้องการดำเนินการต่อหรือไม่?",
|
||||
"tr_TR": "\n\nDevam etmek istiyor musunuz?",
|
||||
"uk_UA": "\n\nВи хочете продовжити?",
|
||||
"zh_CN": "\n\n是否继续?",
|
||||
"zh_TW": "\n\n您確定要繼續嗎?"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerWaitMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "جارٍ تثبيت المفاتيح...",
|
||||
"de_DE": "Schlüssel werden installiert...",
|
||||
"el_GR": "Εγκατάσταση κλειδιών...",
|
||||
"en_US": "Installing Keys...",
|
||||
"es_ES": "Instalando Claves...",
|
||||
"fr_FR": "Installation des Clés...",
|
||||
"he_IL": "מתקין מפתחות...",
|
||||
"it_IT": "Installazione delle chiavi...",
|
||||
"ja_JP": "キーをインストールしています...",
|
||||
"ko_KR": "키 설치 중...",
|
||||
"no_NO": "Installere nøkler...",
|
||||
"pl_PL": "Instalowanie kluczy...",
|
||||
"pt_BR": "Instalando Chaves...",
|
||||
"ru_RU": "Установка ключей...",
|
||||
"sv_SE": "Installerar nycklar...",
|
||||
"th_TH": "กำลังดำเนินการติดตั้ง Keys...",
|
||||
"tr_TR": "Anahtarlar yükleniyor...",
|
||||
"uk_UA": "Встановлення Ключів...",
|
||||
"zh_CN": "安装密匙中。。。",
|
||||
"zh_TW": "正在安裝金鑰。。。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerSuccessMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "تم تثبيت ملف المفاتيح الجديد بنجاح.",
|
||||
"de_DE": "Neue Schlüsseldatei erfolgreich installiert.",
|
||||
"el_GR": "Το νέο αρχείο Κλειδιών εγκαταστάθηκε με επιτυχία.",
|
||||
"en_US": "New Keys file successfully installed.",
|
||||
"es_ES": "Nuevo archivo Keys instalado con éxito.",
|
||||
"fr_FR": "Nouveau fichier de Clés a été installé.",
|
||||
"he_IL": "הקובץ החדש של המפתחות הותקן בהצלחה.",
|
||||
"it_IT": "Nuovo file di chiavi installato con successo.",
|
||||
"ja_JP": "新しいキー ファイルが正常にインストールされました。",
|
||||
"ko_KR": "새로운 키 파일이 성공적으로 설치되었습니다.",
|
||||
"no_NO": "Ny Keys -fil installert.",
|
||||
"pl_PL": "Nowy plik kluczy został pomyślnie zainstalowany.",
|
||||
"pt_BR": "Novo arquivo de chaves instalado com sucesso.",
|
||||
"ru_RU": "Новые ключи успешно установлены.",
|
||||
"sv_SE": "Ny nyckelfil installerades.",
|
||||
"th_TH": "การติดตั้งไฟล์ Keys ใหม่เสร็จสมบูรณ์แล้ว",
|
||||
"tr_TR": "Yeni anahtar dosyası başarıyla yüklendi.",
|
||||
"uk_UA": "Нові ключі встановлено.",
|
||||
"zh_CN": "已成功安装新密匙文件。",
|
||||
"zh_TW": "成功安裝新增的金鑰檔案。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallerInvalidKeysFoundMessage",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "An invalid Keys file was found in {0}.",
|
||||
"es_ES": "Se halló un archivo Keys inválido en {0}.",
|
||||
"fr_FR": "Un fichier de Clés invalide a été trouvé dans {0}.",
|
||||
"he_IL": "",
|
||||
"it_IT": "È stato trovato un file di chiavi non valido in {0}.",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "{0}에서 잘못된 키 파일이 발견.",
|
||||
"no_NO": "En ugyldig Keys-fil ble funnet i {0}.",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "Um arquivo Chaves inválido foi encontrado em {0}.",
|
||||
"ru_RU": "В {0} найден некорректный файл ключей.",
|
||||
"sv_SE": "En ogiltig nyckelfil hittades i {0}.",
|
||||
"th_TH": "พบไฟล์ Keys ที่ไม่ถูกต้องใน {0}.",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Виявлено неправильний файл ключів у теці {0}.",
|
||||
"zh_CN": "在 {0} 发现了一个无效的密匙文件。",
|
||||
"zh_TW": "找到無效的金鑰檔案 {0}。"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
{
|
||||
"Locales": [
|
||||
{
|
||||
"ID": "NoKeysFound",
|
||||
"Translations": {
|
||||
"ar_SA": "المفاتيح غير موجودة.",
|
||||
"de_DE": "Keys nicht gefunden.",
|
||||
"el_GR": "Τα κλειδιά δεν βρέθηκαν.",
|
||||
"en_US": "Keys not found.",
|
||||
"es_ES": "No se encontraron claves.",
|
||||
"fr_FR": "Clés non trouvées.",
|
||||
"he_IL": "המפתחות לא נמצאו.",
|
||||
"it_IT": "Chiavi non trovate.",
|
||||
"ja_JP": "Keys がありません。",
|
||||
"ko_KR": "키를 찾을 수 없음.",
|
||||
"no_NO": "Finner ikke nøkler.",
|
||||
"pl_PL": "Nie znaleziono kluczy.",
|
||||
"pt_BR": "Chaves não encontradas.",
|
||||
"ru_RU": "Ключи не найдены.",
|
||||
"sv_SE": "Nycklarna hittades inte.",
|
||||
"th_TH": "ไม่พบ คีย์",
|
||||
"tr_TR": "Keys bulunamadı.",
|
||||
"uk_UA": "Ключі не знайдено.",
|
||||
"zh_CN": "找不到密钥。",
|
||||
"zh_TW": "找不到金鑰。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "NoKeysFoundDescription",
|
||||
"Translations": {
|
||||
"ar_SA": "لم يتمكن ريوجينكس من العثور على ملف \"prod.keys\" الخاص بك.",
|
||||
"de_DE": "Ryujinx konnte deine \"prod.keys\" Datei nicht finden.",
|
||||
"el_GR": "Το Ryujinx δεν κατάφερε να εντοπίσει το αρχείο \"prod.keys\".",
|
||||
"en_US": "Ryujinx was unable to find your \"prod.keys\" file.",
|
||||
"es_ES": "Ryujinx no pudo encontrar tus \"prod.keys\".",
|
||||
"fr_FR": "Ryujinx n'a pas pu trouver votre fichier \"prod.keys\".",
|
||||
"he_IL": "ריוג'ינקס לא הצליח למצוא את קובץ ה-\"prod.keys\" שלך.",
|
||||
"it_IT": "Ryujinx non è riuscito a trovare il file \"prod.keys\".",
|
||||
"ja_JP": "\"prod.keys\" が見つかりませんでした。",
|
||||
"ko_KR": "Ryujinx가 '\"prod.keys\" 파일을 찾지 못함.",
|
||||
"no_NO": "Ryujinx kunne ikke finne \"prod.keys\" filen din.",
|
||||
"pl_PL": "Ryujinx nie mógł znaleźć twojego pliku \"prod.keys\".",
|
||||
"pt_BR": "Ryujinx não conseguiu encontrar o seu arquivo '\"prod.keys\".",
|
||||
"ru_RU": "Ryujinx не удалось найти ваш \"prod.keys\" файл.",
|
||||
"sv_SE": "Ryujinx kunde inte hitta din \"prod.keys\"-fil.",
|
||||
"th_TH": "Ryujinx ไม่พบไฟล์ '\"prod.keys\" ในเครื่องของคุณ",
|
||||
"tr_TR": "Ryujinx \"prod.keys\" dosyasını bulamadı.",
|
||||
"uk_UA": "Ryujinx не вдалося знайти ваш файл \"prod.keys\".",
|
||||
"zh_CN": "Ryujinx 模拟器找不到“prod.keys”密钥文件。",
|
||||
"zh_TW": "Ryujinx 無法找到您的「prod.keys」檔案。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "NoFirmwareFound",
|
||||
"Translations": {
|
||||
"ar_SA": "لم يتم العثور على البرنامج الثابت",
|
||||
"de_DE": "Firmware nicht gefunden",
|
||||
"el_GR": "Το firmware δε βρέθηκε",
|
||||
"en_US": "Firmware not found",
|
||||
"es_ES": "No se encontró Firmware",
|
||||
"fr_FR": "Firmware introuvable",
|
||||
"he_IL": "קושחה לא נמצאה",
|
||||
"it_IT": "Firmware non trovato",
|
||||
"ja_JP": "ファームウェアがありません",
|
||||
"ko_KR": "펌웨어를 찾을 수 없음",
|
||||
"no_NO": "Fastvare ikke funnet",
|
||||
"pl_PL": "Nie znaleziono firmware'u",
|
||||
"pt_BR": "Firmware não encontrado",
|
||||
"ru_RU": "Прошивка не найдена",
|
||||
"sv_SE": "Firmware hittades inte",
|
||||
"th_TH": "ไม่พบ เฟิร์มแวร์",
|
||||
"tr_TR": "Firmware bulunamadı",
|
||||
"uk_UA": "Прошивка не знайдена",
|
||||
"zh_CN": "未安装系统固件",
|
||||
"zh_TW": "找不到韌體"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "NoFirmwareFoundDescription",
|
||||
"Translations": {
|
||||
"ar_SA": "لم يتمكن ريوجينكس من العثور على أية برامج ثابتة مثبتة.",
|
||||
"de_DE": "Ryujinx konnte keine installierte Firmware finden!",
|
||||
"el_GR": "Το Ryujinx δεν κατάφερε να εντοπίσει κανένα εγκατεστημένο firmware.",
|
||||
"en_US": "Ryujinx was unable to find any firmwares installed.",
|
||||
"es_ES": "Ryujinx no pudo encontrar un firmware instalado.",
|
||||
"fr_FR": "Ryujinx n'a pas trouvé de firmware installé.",
|
||||
"he_IL": "ריוג'ינקס לא הצליחה למצוא קושחה מותקנת.",
|
||||
"it_IT": "Ryujinx non è riuscito a trovare alcun firmware installato.",
|
||||
"ja_JP": "インストールされたファームウェアが見つかりませんでした。",
|
||||
"ko_KR": "Ryujinx가 설치된 펌웨어를 찾을 수 없음.",
|
||||
"no_NO": "Ryujinx kunne ikke finne noen fastvare installert.",
|
||||
"pl_PL": "Ryujinx nie mógł znaleźć żadnego zainstalowanego firmware'u.",
|
||||
"pt_BR": "Ryujinx não conseguiu encontrar nenhum Firmware instalado.",
|
||||
"ru_RU": "Ryujinx не удалось найти ни одной установленной прошивки.",
|
||||
"sv_SE": "Ryujinx kunde inte hitta några installerade firmwares.",
|
||||
"th_TH": "Ryujinx ไม่พบ เฟิร์มแวร์ที่ติดตั้งไว้ในเครื่องของคุณ",
|
||||
"tr_TR": "Ryujinx yüklü herhangi firmware bulamadı.",
|
||||
"uk_UA": "Ryujinx не вдалося знайти жодної встановленої прошивки.",
|
||||
"zh_CN": "Ryujinx 模拟器未安装 Switch 系统固件。",
|
||||
"zh_TW": "Ryujinx 無法找到已安裝的任何韌體。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "FirmwareParsingFailed",
|
||||
"Translations": {
|
||||
"ar_SA": "خطأ في تحليل البرنامج الثابت",
|
||||
"de_DE": "Firmware-Analysierung-Fehler",
|
||||
"el_GR": "Σφάλμα ανάλυσης firmware",
|
||||
"en_US": "Firmware parsing error",
|
||||
"es_ES": "Error al analizar el Firmware",
|
||||
"fr_FR": "Erreur d'analyse du firmware",
|
||||
"he_IL": "שגיאת ניתוח קושחה",
|
||||
"it_IT": "Errore di analisi del firmware",
|
||||
"ja_JP": "ファームウェアのパーズエラー",
|
||||
"ko_KR": "펌웨어 구문 분석 오류",
|
||||
"no_NO": "Fastvare analysefeil",
|
||||
"pl_PL": "Błąd parsowania firmware'u",
|
||||
"pt_BR": "Erro de análise de firmware",
|
||||
"ru_RU": "Ошибка извлечения прошивки",
|
||||
"sv_SE": "Tolkningsfel i firmware",
|
||||
"th_TH": "เกิดข้อผิดพลาดในการวิเคราะห์เฟิร์มแวร์",
|
||||
"tr_TR": "Firmware çözümleme hatası",
|
||||
"uk_UA": "Помилка аналізу прошивки",
|
||||
"zh_CN": "固件文件解析出错",
|
||||
"zh_TW": "韌體解析錯誤"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "FirmwareParsingFailedDescription",
|
||||
"Translations": {
|
||||
"ar_SA": "لم يتمكن ريوجينكس من تحليل البرامج الثابتة المتوفرة. يحدث هذا عادة بسبب المفاتيح القديمة.",
|
||||
"de_DE": "Ryujinx konnte die zu verfügung gestellte Firmware nicht analysieren. Ein möglicher Grund dafür sind veraltete keys.",
|
||||
"el_GR": "Το Ryujinx δεν κατάφερε να αναλύσει το συγκεκριμένο firmware. Αυτό συνήθως οφείλετε σε ξεπερασμένα/παλιά κλειδιά.",
|
||||
"en_US": "Ryujinx was unable to parse the provided firmware. This is usually caused by outdated keys.",
|
||||
"es_ES": "Ryujinx no pudo analizar el firmware. Normalmente esto ocurre debido a keys desfasadas.",
|
||||
"fr_FR": "Ryujinx n'a pas pu analyser le firmware fourni. Cela est généralement dû à des clés obsolètes.",
|
||||
"he_IL": "ריוג'ינקס לא הצליחה לנתח את הקושחה שסופקה. זה נגרם בדרך כלל על ידי מפתחות לא עדכניים.",
|
||||
"it_IT": "Ryujinx non è riuscito ad analizzare il firmware. Questo di solito è causato da chiavi non aggiornate.",
|
||||
"ja_JP": "ファームウェアをパーズできませんでした.通常,古いキーが原因です.",
|
||||
"ko_KR": "Ryujinx가 제공된 펌웨어를 구문 분석하지 못했습니다. 일반적으로 오래된 키로 인해 발생합니다.",
|
||||
"no_NO": "Ryujinx klarte ikke å analysere levert fastvare. Dette er vanligvis forårsaket av utdaterte nøkler.",
|
||||
"pl_PL": "Ryujinx nie był w stanie zparsować dostarczonego firmware'u. Jest to zwykle spowodowane nieaktualnymi kluczami.",
|
||||
"pt_BR": "Ryujinx não conseguiu ler o Firmware fornecido. Geralmente isso é causado por chaves desatualizadas.",
|
||||
"ru_RU": "Ryujinx не удалось распаковать выбранную прошивку. Обычно это вызвано устаревшими ключами.",
|
||||
"sv_SE": "Ryujinx kunde inte tolka angiven firmware. Detta sker oftast med utdaterade nycklar.",
|
||||
"th_TH": "Ryujinx ไม่สามารถวิเคราะห์เฟิร์มแวร์ที่ให้มาได้ ซึ่งมักมีสาเหตุมาจากคีย์ที่เก่าจนเกินไป",
|
||||
"tr_TR": "Ryujinx temin edilen firmware'i çözümleyemedi. Bu durum genellikle güncel olmayan keys'den kaynaklanır.",
|
||||
"uk_UA": "Ryujinx не вдалося проаналізувати прошивку. Зазвичай це спричинено застарілими ключами.",
|
||||
"zh_CN": "Ryujinx 模拟器无法解密当前固件,一般是由于使用了旧版的密钥导致的。",
|
||||
"zh_TW": "Ryujinx 無法解析所提供的韌體。這通常是由於金鑰過時造成的。"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,604 +0,0 @@
|
||||
{
|
||||
"Locales": [
|
||||
{
|
||||
"ID": "ActionsLabel",
|
||||
"Translations": {
|
||||
"ar_SA": "_الإجراءات",
|
||||
"de_DE": "_Aktionen",
|
||||
"el_GR": "_Δράσεις",
|
||||
"en_US": "_Actions",
|
||||
"es_ES": "_Acciones",
|
||||
"fr_FR": null,
|
||||
"he_IL": "_פעולות",
|
||||
"it_IT": "_Azioni",
|
||||
"ja_JP": "アクション(_A)",
|
||||
"ko_KR": "동작(_A)",
|
||||
"no_NO": "_Handlinger",
|
||||
"pl_PL": "_Akcje",
|
||||
"pt_BR": "_Ações",
|
||||
"ru_RU": "_Действия",
|
||||
"sv_SE": "_Åtgärder",
|
||||
"th_TH": "_การดำเนินการ",
|
||||
"tr_TR": "_Eylemler",
|
||||
"uk_UA": "_Дії",
|
||||
"zh_CN": "操作(_A)",
|
||||
"zh_TW": "動作(_A)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallKeysLabel",
|
||||
"Translations": {
|
||||
"ar_SA": "تثبيت المفاتيح",
|
||||
"de_DE": "Schlüssel installieren",
|
||||
"el_GR": "Εγκατάσταση Κλειδιών",
|
||||
"en_US": "Install Keys",
|
||||
"es_ES": "Instalar Claves",
|
||||
"fr_FR": "Installer des Clés",
|
||||
"he_IL": "התקנת מפתחות",
|
||||
"it_IT": "Installa chiavi",
|
||||
"ja_JP": "キーをインストール",
|
||||
"ko_KR": "설치 키",
|
||||
"no_NO": "Installere nøkler",
|
||||
"pl_PL": "Zainstaluj klucze",
|
||||
"pt_BR": "Instalar Chaves",
|
||||
"ru_RU": "Установить ключи",
|
||||
"sv_SE": "Installera nycklar",
|
||||
"th_TH": "ติดตั้ง Keys",
|
||||
"tr_TR": "Anahtarları Yükle",
|
||||
"uk_UA": "Встановити Ключі",
|
||||
"zh_CN": "安装密匙",
|
||||
"zh_TW": "安裝金鑰"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallKeysFromFileButton",
|
||||
"Translations": {
|
||||
"ar_SA": "KEYS...",
|
||||
"de_DE": null,
|
||||
"el_GR": null,
|
||||
"en_US": "KEYS...",
|
||||
"es_ES": null,
|
||||
"fr_FR": null,
|
||||
"he_IL": "KEYS...",
|
||||
"it_IT": null,
|
||||
"ja_JP": null,
|
||||
"ko_KR": null,
|
||||
"no_NO": null,
|
||||
"pl_PL": null,
|
||||
"pt_BR": null,
|
||||
"ru_RU": null,
|
||||
"sv_SE": null,
|
||||
"th_TH": null,
|
||||
"tr_TR": null,
|
||||
"uk_UA": null,
|
||||
"zh_CN": null,
|
||||
"zh_TW": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallKeysFromFolderButton",
|
||||
"Translations": {
|
||||
"ar_SA": "مجلد...",
|
||||
"de_DE": "Verzeichnis...",
|
||||
"el_GR": "Φάκελος...",
|
||||
"en_US": "Folder...",
|
||||
"es_ES": "Carpeta...",
|
||||
"fr_FR": "Dossier...",
|
||||
"he_IL": "תיקייה...",
|
||||
"it_IT": "Cartella...",
|
||||
"ja_JP": "フォルダー...",
|
||||
"ko_KR": "폴더...",
|
||||
"no_NO": "Mappe...",
|
||||
"pl_PL": "Katalog...",
|
||||
"pt_BR": "Diretório...",
|
||||
"ru_RU": "Папка...",
|
||||
"sv_SE": "Katalog...",
|
||||
"th_TH": "โฟลเดอร์...",
|
||||
"tr_TR": "Klasör...",
|
||||
"uk_UA": "Тека...",
|
||||
"zh_CN": "文件夹...",
|
||||
"zh_TW": "資料夾..."
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallFirmwareLabel",
|
||||
"Translations": {
|
||||
"ar_SA": "تثبيت البرنامج الثابت",
|
||||
"de_DE": "Firmware installieren",
|
||||
"el_GR": "Εγκατάσταση Firmware",
|
||||
"en_US": "Install Firmware",
|
||||
"es_ES": "Instalar Firmware",
|
||||
"fr_FR": "Installer le Firmware",
|
||||
"he_IL": "התקן קושחה",
|
||||
"it_IT": "Installa firmware",
|
||||
"ja_JP": "ファームウェアをインストール",
|
||||
"ko_KR": "펌웨어 설치",
|
||||
"no_NO": "Installer fastvare",
|
||||
"pl_PL": "Zainstaluj oprogramowanie",
|
||||
"pt_BR": "Instalar Firmware",
|
||||
"ru_RU": "Установить прошивку",
|
||||
"sv_SE": "Installera firmware",
|
||||
"th_TH": "ติดตั้งเฟิร์มแวร์",
|
||||
"tr_TR": "Yazılım Yükle",
|
||||
"uk_UA": "Встановити прошивку",
|
||||
"zh_CN": "安装系统固件",
|
||||
"zh_TW": "安裝韌體"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallFirmwareFromFileButton",
|
||||
"Translations": {
|
||||
"ar_SA": "XCI أو ZIP...",
|
||||
"de_DE": "XCI oder ZIP...",
|
||||
"el_GR": "XCI ή ZIP...",
|
||||
"en_US": "XCI or ZIP...",
|
||||
"es_ES": "XCI o ZIP...",
|
||||
"fr_FR": "XCI ou ZIP...",
|
||||
"he_IL": "XCI או ZIP...",
|
||||
"it_IT": "XCI o ZIP...",
|
||||
"ja_JP": "XCI または ZIP...",
|
||||
"ko_KR": "XCI 또는 ZIP...",
|
||||
"no_NO": "XCI eller ZIP...",
|
||||
"pl_PL": "XCI lub ZIP...",
|
||||
"pt_BR": "XCI ou ZIP...",
|
||||
"ru_RU": "XCI или ZIP...",
|
||||
"sv_SE": "XCI eller ZIP...",
|
||||
"th_TH": "XCI หรือ ZIP...",
|
||||
"tr_TR": "XCI veya ZIP...",
|
||||
"uk_UA": "XCI або ZIP...",
|
||||
"zh_CN": "XCI 或 ZIP...",
|
||||
"zh_TW": "XCI 或 ZIP..."
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallFirmwareFromFolderButton",
|
||||
"Translations": {
|
||||
"ar_SA": "مجلد...",
|
||||
"de_DE": "Verzeichnis...",
|
||||
"el_GR": "Φάκελος...",
|
||||
"en_US": "Folder...",
|
||||
"es_ES": "Carpeta...",
|
||||
"fr_FR": "Dossier...",
|
||||
"he_IL": "תיקייה...",
|
||||
"it_IT": "Cartella...",
|
||||
"ja_JP": "フォルダー...",
|
||||
"ko_KR": "폴더...",
|
||||
"no_NO": "Mappe...",
|
||||
"pl_PL": "Katalog...",
|
||||
"pt_BR": "Diretório...",
|
||||
"ru_RU": "Папка...",
|
||||
"sv_SE": "Katalog...",
|
||||
"th_TH": "โฟลเดอร์...",
|
||||
"tr_TR": "Klasör...",
|
||||
"uk_UA": "Тека...",
|
||||
"zh_CN": "文件夹...",
|
||||
"zh_TW": "資料夾..."
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "ToolsLabel",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "Werkzeuge",
|
||||
"el_GR": "",
|
||||
"en_US": "Tools",
|
||||
"es_ES": "Herramientas",
|
||||
"fr_FR": "Outils",
|
||||
"he_IL": "",
|
||||
"it_IT": "Strumenti",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "도구",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "Ferramentas",
|
||||
"ru_RU": "Инструменты",
|
||||
"sv_SE": "Verktyg",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "工具",
|
||||
"zh_TW": "工具"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MiiEditorButton",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "Mii-Editor",
|
||||
"el_GR": "",
|
||||
"en_US": "Mii Editor",
|
||||
"es_ES": "Editor de Mii",
|
||||
"fr_FR": "Éditeur de Mii",
|
||||
"he_IL": "",
|
||||
"it_IT": "Editor di Mii",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "Mii 편집기",
|
||||
"no_NO": "Mii-redigerer",
|
||||
"pl_PL": "Edytor Mii",
|
||||
"pt_BR": "Editor de Mii",
|
||||
"ru_RU": "Редактор Mii",
|
||||
"sv_SE": "Mii-redigerare",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Редактор Mii",
|
||||
"zh_CN": "Mii 编辑器",
|
||||
"zh_TW": "Mii 編輯器"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "XCITrimmerButton",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "XCI-Dateien trimmen",
|
||||
"el_GR": "",
|
||||
"en_US": "Trim XCI Files",
|
||||
"es_ES": "Recortar Archivos XCI",
|
||||
"fr_FR": "Réduire les Fichiers XCI",
|
||||
"he_IL": "",
|
||||
"it_IT": "Riduci dimensioni dei file XCI",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "XCI 파일 트리머",
|
||||
"no_NO": "Trim XCI-filer",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "Reduzir Arquivos XCI",
|
||||
"ru_RU": "Обрезать XCI файлы",
|
||||
"sv_SE": "Optimera XCI-filer",
|
||||
"th_TH": "ตัดแต่งไฟล์ XCI",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Обрізати XCI файли",
|
||||
"zh_CN": "瘦身 XCI 文件",
|
||||
"zh_TW": "修剪 XCI 檔案"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "PauseEmulationButton",
|
||||
"Translations": {
|
||||
"ar_SA": "إيقاف التشغيل مؤقتًا",
|
||||
"de_DE": "Emulation pausieren",
|
||||
"el_GR": "Παύση προσομοίωσης",
|
||||
"en_US": "Pause Emulation",
|
||||
"es_ES": "Pausar Emulación",
|
||||
"fr_FR": "Pauser l'Émulation",
|
||||
"he_IL": "השהיית האמולציה",
|
||||
"it_IT": "Pausa emulazione",
|
||||
"ja_JP": "エミュレーション一時停止",
|
||||
"ko_KR": "에뮬레이션 일시중지",
|
||||
"no_NO": "Pause Emulatoren",
|
||||
"pl_PL": "Wstrzymaj emulację",
|
||||
"pt_BR": "Pausar emulação",
|
||||
"ru_RU": "Пауза эмуляции",
|
||||
"sv_SE": "Pausa emuleringen",
|
||||
"th_TH": "พักการจำลอง",
|
||||
"tr_TR": "Emülasyonu Duraklat",
|
||||
"uk_UA": "Пауза емуляції",
|
||||
"zh_CN": "暂停模拟",
|
||||
"zh_TW": "暫停模擬"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "ResumeEmulationButton",
|
||||
"Translations": {
|
||||
"ar_SA": "استئناف المحاكاة",
|
||||
"de_DE": "Emulation fortsetzen",
|
||||
"el_GR": "Συνέχιση προσομοίωσης",
|
||||
"en_US": "Resume Emulation",
|
||||
"es_ES": "Reanudar Emulación",
|
||||
"fr_FR": "Reprendre l'Émulation",
|
||||
"he_IL": "המשך האמולציה",
|
||||
"it_IT": "Riprendi l'emulazione",
|
||||
"ja_JP": "エミュレーション再開",
|
||||
"ko_KR": "에뮬레이션 다시 시작",
|
||||
"no_NO": "Gjenoppta emuleringen",
|
||||
"pl_PL": "Wznów emulację",
|
||||
"pt_BR": "Retomar emulação",
|
||||
"ru_RU": "Продолжить эмуляцию",
|
||||
"sv_SE": "Återuppta emuleringen",
|
||||
"th_TH": "ดำเนินการจำลองต่อ",
|
||||
"tr_TR": "Emülasyonu Sürdür",
|
||||
"uk_UA": "Продовжити емуляцію",
|
||||
"zh_CN": "继续模拟",
|
||||
"zh_TW": "繼續模擬"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "StopEmulationButton",
|
||||
"Translations": {
|
||||
"ar_SA": "إيقاف المحاكاة",
|
||||
"de_DE": "Emulation beenden",
|
||||
"el_GR": "Διακοπή Εξομοίωσης",
|
||||
"en_US": "Stop Emulation",
|
||||
"es_ES": "Detener Emulación",
|
||||
"fr_FR": "Arrêter l'Émulation",
|
||||
"he_IL": "עצור אמולציה",
|
||||
"it_IT": "Arresta l'emulazione",
|
||||
"ja_JP": "エミュレーションを中止",
|
||||
"ko_KR": "에뮬레이션 중지",
|
||||
"no_NO": "Stopp Emulering",
|
||||
"pl_PL": "Zatrzymaj emulację",
|
||||
"pt_BR": "Parar a Emulação",
|
||||
"ru_RU": "Остановить эмуляцию",
|
||||
"sv_SE": "Stoppa emulering",
|
||||
"th_TH": "หยุดการจำลอง",
|
||||
"tr_TR": "Emülasyonu Durdur",
|
||||
"uk_UA": "Зупинити емуляцію",
|
||||
"zh_CN": "停止模拟",
|
||||
"zh_TW": "停止模擬"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "RestartEmulationButton",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "Emulation neustarten",
|
||||
"el_GR": "",
|
||||
"en_US": "Restart Emulation",
|
||||
"es_ES": "Reiniciar Emulación",
|
||||
"fr_FR": "Redémarrer l'Émulation",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "Перезапустить эмуляцию",
|
||||
"sv_SE": "Starta om emulering",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "重启模拟",
|
||||
"zh_TW": "重新啟動模擬"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "ScanAmiiboButton",
|
||||
"Translations": {
|
||||
"ar_SA": "مسح Amiibo",
|
||||
"de_DE": "Amiibo scannen",
|
||||
"el_GR": "Σάρωση Amiibo",
|
||||
"en_US": "Scan Amiibo",
|
||||
"es_ES": "Escanear Amiibo",
|
||||
"fr_FR": "Scanner un Amiibo",
|
||||
"he_IL": "סרוק אמיבו",
|
||||
"it_IT": "Scansiona un Amiibo",
|
||||
"ja_JP": "Amiibo をスキャン",
|
||||
"ko_KR": "Amiibo 스캔",
|
||||
"no_NO": "Skann en Amiibo",
|
||||
"pl_PL": "Skanuj Amiibo",
|
||||
"pt_BR": "Escanear um Amiibo",
|
||||
"ru_RU": "Сканировать Amiibo",
|
||||
"sv_SE": "Skanna en Amiibo",
|
||||
"th_TH": "สแกนหา Amiibo",
|
||||
"tr_TR": "Bir Amiibo Tara",
|
||||
"uk_UA": "Сканувати Amiibo",
|
||||
"zh_CN": "扫描 Amiibo",
|
||||
"zh_TW": "掃描 Amiibo"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "ScanAmiiboFromBinButton",
|
||||
"Translations": {
|
||||
"ar_SA": "مسح Amiibo (.BIN)",
|
||||
"de_DE": "Amiibo scannen (.BIN)",
|
||||
"el_GR": "Σάρωση Amiibo (.BIN)",
|
||||
"en_US": "Scan Amiibo (.BIN)",
|
||||
"es_ES": "Escanear un Amiibo (.BIN)",
|
||||
"fr_FR": "Scanner un Amiibo (.BIN)",
|
||||
"he_IL": "סרוק Amiibo (.BIN)",
|
||||
"it_IT": "Scansiona un Amiibo (.BIN)",
|
||||
"ja_JP": "Amiibo をスキャン (.BIN)",
|
||||
"ko_KR": "Amiibo 스캔 (.BIN)",
|
||||
"no_NO": "Skann en Amiibo (.BIN)",
|
||||
"pl_PL": "Skanuj Amiibo (.BIN)",
|
||||
"pt_BR": "Escaneie um Amiibo (.BIN)",
|
||||
"ru_RU": "Сканировать Amiibo (.BIN)",
|
||||
"sv_SE": "Skanna en Amiibo (.BIN)",
|
||||
"th_TH": "สแกนอามีโบ (.BIN)",
|
||||
"tr_TR": "Amiibo Tara (.BIN)",
|
||||
"uk_UA": "Сканувати Amiibo (.BIN)",
|
||||
"zh_CN": "扫描 Amiibo (.BIN)",
|
||||
"zh_TW": "掃瞄 Amiibo (.BIN)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "ScanSkylanderButton",
|
||||
"Translations": {
|
||||
"ar_SA": "فحص Skylander",
|
||||
"de_DE": "Skylander scannen",
|
||||
"el_GR": "Σάρωση Skylander",
|
||||
"en_US": "Scan Skylander",
|
||||
"es_ES": "Escanear Skylander",
|
||||
"fr_FR": "Scanner un Skylander",
|
||||
"he_IL": "סרוק אמיבו",
|
||||
"it_IT": "Scansiona un Skylander",
|
||||
"ja_JP": "Skylander をスキャン",
|
||||
"ko_KR": "Skylander 스캔",
|
||||
"no_NO": "Skann en Skylander",
|
||||
"pl_PL": "Skanuj Skylander",
|
||||
"pt_BR": "Escanear um Skylander",
|
||||
"ru_RU": "Сканировать Skylander",
|
||||
"sv_SE": "Skanna en Skylander",
|
||||
"th_TH": "สแกนหา Skylander",
|
||||
"tr_TR": "Bir Skylander Tara",
|
||||
"uk_UA": "Сканувати Skylander",
|
||||
"zh_CN": "扫描 Skylander",
|
||||
"zh_TW": "掃描 Skylander"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "RemoveSkylanderButton",
|
||||
"Translations": {
|
||||
"ar_SA": "إزالة Skylander",
|
||||
"de_DE": "Skylander entfernen",
|
||||
"el_GR": "Αφαίρεση Skylander",
|
||||
"en_US": "Remove Skylander",
|
||||
"es_ES": "Eliminar Skylander",
|
||||
"fr_FR": "Supprimer un Skylander",
|
||||
"he_IL": "הסר Skylander",
|
||||
"it_IT": "Rimuovi Skylander",
|
||||
"ja_JP": "Skylander を削除",
|
||||
"ko_KR": "Skylander 제거",
|
||||
"no_NO": "Fjern Skylander",
|
||||
"pl_PL": "Usuń Skylander",
|
||||
"pt_BR": "Remover um Skylander",
|
||||
"ru_RU": "Удалить Skylander",
|
||||
"sv_SE": "Ta bort Skylander",
|
||||
"th_TH": "ลบ Skylander",
|
||||
"tr_TR": "Skylander'ı Kaldır",
|
||||
"uk_UA": "Видалити Skylander",
|
||||
"zh_CN": "移除 Skylander",
|
||||
"zh_TW": "移除 Skylander"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "TakeScreenshotButton",
|
||||
"Translations": {
|
||||
"ar_SA": "أخذ لقطة للشاشة",
|
||||
"de_DE": "Screenshot aufnehmen",
|
||||
"el_GR": "Λήψη Στιγμιότυπου",
|
||||
"en_US": "Take Screenshot",
|
||||
"es_ES": "Captura de Pantalla",
|
||||
"fr_FR": "Prendre une Capture d'Écran",
|
||||
"he_IL": "צלם מסך",
|
||||
"it_IT": "Cattura uno screenshot",
|
||||
"ja_JP": "スクリーンショットを撮影",
|
||||
"ko_KR": "스크린샷 찍기",
|
||||
"no_NO": "Ta skjermbilde",
|
||||
"pl_PL": "Zrób zrzut ekranu",
|
||||
"pt_BR": "Tirar Captura de tela",
|
||||
"ru_RU": "Сделать снимок экрана",
|
||||
"sv_SE": "Ta skärmbild",
|
||||
"th_TH": "ถ่ายภาพหน้าจอ",
|
||||
"tr_TR": "Ekran Görüntüsü Al",
|
||||
"uk_UA": "Зробити знімок екрана",
|
||||
"zh_CN": "保存截屏",
|
||||
"zh_TW": "儲存擷取畫面"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "HideUiButton",
|
||||
"Translations": {
|
||||
"ar_SA": "إخفاء واجهة المستخدم",
|
||||
"de_DE": "Oberfläche ausblenden",
|
||||
"el_GR": "Απόκρυψη UI",
|
||||
"en_US": "Hide UI",
|
||||
"es_ES": "Ocultar Interfaz",
|
||||
"fr_FR": "Masquer l'Interface",
|
||||
"he_IL": "הסתר ממשק משתמש ",
|
||||
"it_IT": "Nascondi l'interfaccia",
|
||||
"ja_JP": "UIを隠す",
|
||||
"ko_KR": "UI 숨기기",
|
||||
"no_NO": "Skjul brukergrensesnitt",
|
||||
"pl_PL": "Ukryj interfejs użytkownika",
|
||||
"pt_BR": "Esconder Interface",
|
||||
"ru_RU": "Скрыть интерфейс",
|
||||
"sv_SE": "Dölj gränssnittet",
|
||||
"th_TH": "ซ่อน UI",
|
||||
"tr_TR": "Arayüzü Gizle",
|
||||
"uk_UA": "Сховати інтерфейс",
|
||||
"zh_CN": "隐藏菜单栏和状态栏",
|
||||
"zh_TW": "隱藏 UI"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "StartRenderDocCaptureButton",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "RenderDoc Frame-Aufnahme starten",
|
||||
"el_GR": "",
|
||||
"en_US": "Start RenderDoc Frame Capture",
|
||||
"es_ES": "Iniciar una captura de fotograma de RenderDoc",
|
||||
"fr_FR": "Démarrer une capture de trame RenderDoc",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "RenderDoc 프레임 캡처 시작",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "Запустить захват кадра RenderDoc",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "启动 RenderDoc 帧捕获",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "EndRenderDocCaptureButton",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "RenderDoc Frame-Aufnahme beenden",
|
||||
"el_GR": "",
|
||||
"en_US": "End RenderDoc Frame Capture",
|
||||
"es_ES": "Detener la captura de fotograma de RenderDoc",
|
||||
"fr_FR": "Arrêter la capture de trame RenderDoc",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "RenderDoc 프레임 캡처 종료",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "Завершить захват кадра RenderDoc",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "结束 RenderDoc 帧捕获",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "DiscardRenderDocCaptureButton",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "RenderDoc Frame-Aufnahme verwerfen",
|
||||
"el_GR": "",
|
||||
"en_US": "Discard RenderDoc Frame Capture",
|
||||
"es_ES": "Descartar la captura de fotograma de RenderDoc",
|
||||
"fr_FR": "Supprimer la capture de trame RenderDoc",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "RenderDoc 프레임 캡처 폐기",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "Отменить захват кадра RenderDoc",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "丢弃 RenderDoc 帧捕获",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "DiscardRenderDocCaptureToolTip",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "Beendet die jetzige RenderDoc Frame-Aufnahme, verwirft sofort das Ergebnis.",
|
||||
"el_GR": "",
|
||||
"en_US": "Ends the currently active RenderDoc Frame Capture, immediately discarding its result.",
|
||||
"es_ES": "Finaliza la captura de fotograma de RenderDoc actualmente activa y descarta inmediatamente su resultado.",
|
||||
"fr_FR": "Met fin à la capture de trame RenderDoc en cours, en supprimant immédiatement son résultat.",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "현재 활성화된 RenderDoc 프레임 캡처를 종료하고 결과를 즉시 폐기합니다.",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "Завершает текущий активный захват кадра RenderDoc и немедленно удаляет его результат.",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "结束当前正在进行的 RenderDoc 帧捕获,并立即丢弃其结果。",
|
||||
"zh_TW": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
{
|
||||
"Locales": [
|
||||
{
|
||||
"ID": "ManageFileTypes",
|
||||
"Translations": {
|
||||
"ar_SA": "إدارة أنواع الملفات",
|
||||
"de_DE": "Dateitypen verwalten",
|
||||
"el_GR": "Διαχείριση τύπων αρχείων",
|
||||
"en_US": "Manage File Types",
|
||||
"es_ES": "Administrar Tipos de Archivo",
|
||||
"fr_FR": "Gérer les Types de Fichiers",
|
||||
"he_IL": "ניהול סוגי קבצים",
|
||||
"it_IT": "Gestisci i tipi di file",
|
||||
"ja_JP": "ファイル形式を管理",
|
||||
"ko_KR": "파일 형식 관리",
|
||||
"no_NO": "Behandle filtyper",
|
||||
"pl_PL": "Zarządzaj rodzajami plików",
|
||||
"pt_BR": "Gerenciar Tipos de Arquivos",
|
||||
"ru_RU": "Управление типами файлов",
|
||||
"sv_SE": "Hantera filtyper",
|
||||
"th_TH": "จัดการประเภทไฟล์",
|
||||
"tr_TR": "Dosya uzantılarını yönet",
|
||||
"uk_UA": "Керувати типами файлів",
|
||||
"zh_CN": "管理文件扩展名",
|
||||
"zh_TW": "管理檔案類型"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "InstallFileTypes",
|
||||
"Translations": {
|
||||
"ar_SA": "تثبيت أنواع الملفات",
|
||||
"de_DE": "Dateitypen installieren",
|
||||
"el_GR": "Εγκαταστήσετε τύπους αρχείων.",
|
||||
"en_US": "Install File Types",
|
||||
"es_ES": "Instalar Tipos de Archivo",
|
||||
"fr_FR": "Installer des Types de Fichiers",
|
||||
"he_IL": "סוגי קבצי התקנה",
|
||||
"it_IT": "Installa i tipi di file",
|
||||
"ja_JP": "ファイル形式をインストール",
|
||||
"ko_KR": "파일 형식 설치",
|
||||
"no_NO": "Installer filtyper",
|
||||
"pl_PL": "Typy plików instalacyjnych",
|
||||
"pt_BR": "Instalar tipos de arquivos",
|
||||
"ru_RU": "Установить типы файлов",
|
||||
"sv_SE": "Installera filtyper",
|
||||
"th_TH": "ติดตั้งประเภทไฟล์",
|
||||
"tr_TR": "Dosya uzantılarını yükle",
|
||||
"uk_UA": "Встановити типи файлів",
|
||||
"zh_CN": "关联文件扩展名",
|
||||
"zh_TW": "安裝檔案類型"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "UninstallFileTypes",
|
||||
"Translations": {
|
||||
"ar_SA": "إزالة أنواع الملفات",
|
||||
"de_DE": "Dateitypen deinstallieren",
|
||||
"el_GR": "Απεγκαταστήσετε τύπους αρχείων",
|
||||
"en_US": "Uninstall File Types",
|
||||
"es_ES": "Desinstalar Tipos de Archivo",
|
||||
"fr_FR": "Désinstaller des Types de Fichiers",
|
||||
"he_IL": "סוגי קבצי הסרה",
|
||||
"it_IT": "Disinstalla i tipi di file",
|
||||
"ja_JP": "ファイル形式をアンインストール",
|
||||
"ko_KR": "파일 형식 제거",
|
||||
"no_NO": "Avinstaller filtyper",
|
||||
"pl_PL": "Typy plików dezinstalacyjnych",
|
||||
"pt_BR": "Desinstalar tipos de arquivos",
|
||||
"ru_RU": "Удалить типы файлов",
|
||||
"sv_SE": "Avinstallera filtyper",
|
||||
"th_TH": "ถอนการติดตั้งประเภทไฟล์",
|
||||
"tr_TR": "Dosya uzantılarını kaldır",
|
||||
"uk_UA": "Видалити типи файлів",
|
||||
"zh_CN": "取消关联扩展名",
|
||||
"zh_TW": "移除檔案類型"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
104
assets/Locales/RenderDoc.json
Normal file
104
assets/Locales/RenderDoc.json
Normal file
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"Locales": [
|
||||
{
|
||||
"ID": "MenuBarActions_StartCapture",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Start RenderDoc Frame Capture",
|
||||
"es_ES": "Iniciar una captura de fotograma de RenderDoc",
|
||||
"fr_FR": "Démarrer une capture de trame RenderDoc",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "RenderDoc 프레임 캡처 시작",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "启动 RenderDoc 帧捕获",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarActions_EndCapture",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "End RenderDoc Frame Capture",
|
||||
"es_ES": "Detener la captura de fotograma de RenderDoc",
|
||||
"fr_FR": "Arrêter la capture de trame RenderDoc",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "RenderDoc 프레임 캡처 종료",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "结束 RenderDoc 帧捕获",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarActions_DiscardCapture",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Discard RenderDoc Frame Capture",
|
||||
"es_ES": "Descartar la captura de fotograma de RenderDoc",
|
||||
"fr_FR": "Supprimer la capture de trame RenderDoc",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "RenderDoc 프레임 캡처 폐기",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "丢弃 RenderDoc 帧捕获",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarActions_DiscardCapture_ToolTip",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Ends the currently active RenderDoc Frame Capture, immediately discarding its result.",
|
||||
"es_ES": "Finaliza la captura de fotograma de RenderDoc actualmente activa y descarta inmediatamente su resultado.",
|
||||
"fr_FR": "Met fin à la capture de trame RenderDoc en cours, en supprimant immédiatement son résultat.",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "현재 활성화된 RenderDoc 프레임 캡처를 종료하고 결과를 즉시 폐기합니다.",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "结束当前正在进行的 RenderDoc 帧捕获,并立即丢弃其结果。",
|
||||
"zh_TW": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"Locales": [
|
||||
{
|
||||
"ID": "FirmwareVersion",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Firmware Version: {0}",
|
||||
"es_ES": "Versión del Firmware: {0}",
|
||||
"fr_FR": "Version du Firmware : {0}",
|
||||
"he_IL": "",
|
||||
"it_IT": "Versione firmware: {0}",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "펌웨어 버전 : {0}",
|
||||
"no_NO": "Fastvareversjon: {0}",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "Versão do Firmware: {0}",
|
||||
"ru_RU": "Версия прошивки: {0}",
|
||||
"sv_SE": "Firmware-version: {0}",
|
||||
"th_TH": "เวอร์ชันเฟิร์มแวร์: {0}",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Версія прошивки: {0}",
|
||||
"zh_CN": "系统固件版本:{0}",
|
||||
"zh_TW": "系統韌體版本: {0}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -22,5 +22,5 @@ chmod +x AppDir/AppRun AppDir/usr/bin/Ryujinx*
|
||||
|
||||
mkdir -p "$OUTDIR"
|
||||
|
||||
appimagetool --appimage-extract-and-run -n --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 21 \
|
||||
AppDir "$OUTDIR"/Ryujinx.AppImage
|
||||
appimagetool -n --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 21 \
|
||||
AppDir "$OUTDIR"/Ryujinx.AppImage
|
||||
|
||||
@@ -47,12 +47,14 @@ def get_new_name(
|
||||
input_component = str(input_dylib_path).replace(str(input_directory), "")[1:]
|
||||
return Path(os.path.join(output_directory, input_component))
|
||||
|
||||
def get_archs(dylib_path: Path) -> list[str]:
|
||||
res = subprocess.check_output([LIPO, "-info", str(dylib_path)]).decode("utf-8")
|
||||
if res.startswith("Non-fat file"):
|
||||
return [res.split(":")[-1].strip()]
|
||||
else:
|
||||
return res.split("are:")[-1].strip().split()
|
||||
|
||||
def is_fat_file(dylib_path: Path) -> str:
|
||||
res = subprocess.check_output([LIPO, "-info", str(dylib_path.absolute())]).decode(
|
||||
"utf-8"
|
||||
)
|
||||
|
||||
return not res.split("\n")[0].startswith("Non-fat file")
|
||||
|
||||
|
||||
def construct_universal_dylib(
|
||||
arm64_input_dylib_path: Path, x86_64_input_dylib_path: Path, output_dylib_path: Path
|
||||
@@ -67,12 +69,11 @@ def construct_universal_dylib(
|
||||
os.path.basename(arm64_input_dylib_path.resolve()), output_dylib_path
|
||||
)
|
||||
else:
|
||||
arm64_archs = get_archs(arm64_input_dylib_path)
|
||||
x86_64_archs = get_archs(x86_64_input_dylib_path) if x86_64_input_dylib_path.exists() else []
|
||||
|
||||
if "arm64" in arm64_archs and "x86_64" in arm64_archs:
|
||||
shutil.copy2(arm64_input_dylib_path, output_dylib_path)
|
||||
elif x86_64_archs:
|
||||
if is_fat_file(arm64_input_dylib_path) or not x86_64_input_dylib_path.exists():
|
||||
with open(output_dylib_path, "wb") as dst:
|
||||
with open(arm64_input_dylib_path, "rb") as src:
|
||||
dst.write(src.read())
|
||||
else:
|
||||
subprocess.check_call(
|
||||
[
|
||||
LIPO,
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$#" -lt 8 ]; then
|
||||
echo "usage <BASE_DIR> <TEMP_DIRECTORY> <OUTPUT_DIRECTORY> <ENTITLEMENTS_FILE_PATH> <VERSION> <SOURCE_REVISION_ID> <CONFIGURATION>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$1"
|
||||
mkdir -p "$2"
|
||||
mkdir -p "$3"
|
||||
|
||||
BASE_DIR=$(readlink -f "$1")
|
||||
TEMP_DIRECTORY=$(readlink -f "$2")
|
||||
OUTPUT_DIRECTORY=$(readlink -f "$3")
|
||||
ENTITLEMENTS_FILE_PATH=$(readlink -f "$4")
|
||||
VERSION=$5
|
||||
SOURCE_REVISION_ID=$6
|
||||
CONFIGURATION=$7
|
||||
|
||||
if [[ "$(uname)" == "Darwin" ]]; then
|
||||
echo "Clearing xattr on all dot undercsore files"
|
||||
find "$BASE_DIR" -type f -name "._*" -exec sh -c '
|
||||
for f; do
|
||||
dir=$(dirname "$f")
|
||||
base=$(basename "$f")
|
||||
orig="$dir/${base#._}"
|
||||
[ -f "$orig" ] && xattr -c "$orig" || true
|
||||
done
|
||||
' sh {} +
|
||||
fi
|
||||
|
||||
RELEASE_TAR_FILE_NAME=ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
|
||||
|
||||
ARM64_APP_BUNDLE="$TEMP_DIRECTORY/output_arm64/Ryujinx.app"
|
||||
X64_APP_BUNDLE="$TEMP_DIRECTORY/output_x64/Ryujinx.app"
|
||||
UNIVERSAL_APP_BUNDLE="$OUTPUT_DIRECTORY/Ryujinx.app"
|
||||
EXECUTABLE_SUB_PATH=Contents/MacOS/Ryujinx
|
||||
|
||||
rm -rf "$TEMP_DIRECTORY"
|
||||
mkdir -p "$TEMP_DIRECTORY"
|
||||
|
||||
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
|
||||
|
||||
dotnet restore
|
||||
dotnet build -c "$CONFIGURATION" src/Ryujinx
|
||||
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx
|
||||
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx
|
||||
|
||||
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
|
||||
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
|
||||
|
||||
# Get rid of libsoundio from arm64 builds as we don't have a arm64 variant
|
||||
# TODO: remove this once done
|
||||
rm -rf "$TEMP_DIRECTORY/publish_arm64/libsoundio.dylib"
|
||||
|
||||
pushd "$BASE_DIR/distribution/macos"
|
||||
./create_app_bundle.sh "$TEMP_DIRECTORY/publish_x64" "$TEMP_DIRECTORY/output_x64" "$ENTITLEMENTS_FILE_PATH"
|
||||
./create_app_bundle.sh "$TEMP_DIRECTORY/publish_arm64" "$TEMP_DIRECTORY/output_arm64" "$ENTITLEMENTS_FILE_PATH"
|
||||
popd
|
||||
|
||||
rm -rf "$UNIVERSAL_APP_BUNDLE"
|
||||
mkdir -p "$OUTPUT_DIRECTORY"
|
||||
|
||||
# Let's copy one of the two different app bundle and remove the executable
|
||||
cp -R "$ARM64_APP_BUNDLE" "$UNIVERSAL_APP_BUNDLE"
|
||||
rm "$UNIVERSAL_APP_BUNDLE/$EXECUTABLE_SUB_PATH"
|
||||
|
||||
# Make its libraries universal
|
||||
python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_APP_BUNDLE" "$X64_APP_BUNDLE" "$UNIVERSAL_APP_BUNDLE" "**/*.dylib"
|
||||
|
||||
if ! [ -x "$(command -v lipo)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v llvm-lipo-17)" ];
|
||||
then
|
||||
LIPO=llvm-lipo
|
||||
else
|
||||
LIPO=llvm-lipo-17
|
||||
fi
|
||||
else
|
||||
LIPO=lipo
|
||||
fi
|
||||
|
||||
# Make the executable universal
|
||||
$LIPO "$ARM64_APP_BUNDLE/$EXECUTABLE_SUB_PATH" "$X64_APP_BUNDLE/$EXECUTABLE_SUB_PATH" -output "$UNIVERSAL_APP_BUNDLE/$EXECUTABLE_SUB_PATH" -create
|
||||
|
||||
# Patch up the Info.plist to have appropriate version
|
||||
sed -r -i.bck "s/\%\%RYUJINX_BUILD_VERSION\%\%/$VERSION/g;" "$UNIVERSAL_APP_BUNDLE/Contents/Info.plist"
|
||||
sed -r -i.bck "s/\%\%RYUJINX_BUILD_GIT_HASH\%\%/$SOURCE_REVISION_ID/g;" "$UNIVERSAL_APP_BUNDLE/Contents/Info.plist"
|
||||
rm "$UNIVERSAL_APP_BUNDLE/Contents/Info.plist.bck"
|
||||
|
||||
# Now sign it
|
||||
if ! [ -x "$(command -v codesign)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v rcodesign)" ];
|
||||
then
|
||||
echo "Cannot find rcodesign on your system, please install rcodesign."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
|
||||
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
|
||||
echo "Using rcodesign for ad-hoc signing"
|
||||
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$UNIVERSAL_APP_BUNDLE"
|
||||
else
|
||||
echo "Using codesign for ad-hoc signing"
|
||||
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f -s - "$UNIVERSAL_APP_BUNDLE"
|
||||
fi
|
||||
|
||||
echo "Creating archive"
|
||||
pushd "$OUTPUT_DIRECTORY"
|
||||
tar --exclude "Ryujinx.app/Contents/MacOS/Ryujinx" -cvf "$RELEASE_TAR_FILE_NAME" Ryujinx.app 1> /dev/null
|
||||
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "Ryujinx.app/Contents/MacOS/Ryujinx" "Ryujinx.app/Contents/MacOS/Ryujinx"
|
||||
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
|
||||
rm "$RELEASE_TAR_FILE_NAME"
|
||||
|
||||
popd
|
||||
|
||||
echo "Done"
|
||||
@@ -1061,7 +1061,6 @@
|
||||
0100BCA016636000,"eBaseball Powerful Pro Yakyuu 2022",gpu;services-horizon;crash,nothing,2024-05-26 23:07:19
|
||||
01001F20100B8000,"Eclipse: Edge of Light",,playable,2020-08-11 23:06:29
|
||||
0100E0A0110F4000,"eCrossminton",,playable,2020-07-11 18:24:27
|
||||
010054601D54C000,"Emio – The Smiling Man: Famicom Detective Club (DEMO)",demo,playable,2026-05-13 18:32:12
|
||||
0100ABE00DB4E000,"Edna & Harvey: Harvey's New Eyes",nvdec,playable,2021-01-26 14:36:08
|
||||
01004F000B716000,"Edna & Harvey: The Breakout – Anniversary Edition",crash;nvdec,ingame,2022-08-01 16:59:56
|
||||
01002550129F0000,"Effie",,playable,2022-10-27 14:36:39
|
||||
@@ -1205,7 +1204,7 @@
|
||||
01003B200E440000,"Five Nights at Freddy's: Sister Location",,playable,2023-10-06 09:00:58
|
||||
010038200E088000,"Flan",crash;regression,ingame,2021-11-17 07:39:28
|
||||
01000A0004C50000,"FLASHBACK™",nvdec,playable,2020-05-14 13:57:29
|
||||
0100C53004C52000,"Flat Heroes",,playable,2026-02-27 17:00:00
|
||||
0100C53004C52000,"Flat Heroes",gpu,ingame,2022-07-26 19:37:37
|
||||
0100B54012798000,"Flatland: Prologue",,playable,2020-12-11 20:41:12
|
||||
0100307004B4C000,"Flinthook",online,playable,2021-03-25 20:42:29
|
||||
010095A004040000,"Flip Wars",services;ldn-untested,ingame,2022-05-02 15:39:18
|
||||
@@ -1395,7 +1394,6 @@
|
||||
0100c3c012718000,"Grand Theft Auto: III – The Definitive Edition",gpu;UE4,ingame,2022-10-31 20:13:52
|
||||
0100182014022000,"Grand Theft Auto: Vice City – The Definitive Edition",gpu;UE4,ingame,2022-10-31 20:13:52
|
||||
010065a014024000,"Grand Theft Auto: San Andreas – The Definitive Edition",gpu;UE4,ingame,2022-10-31 20:13:52
|
||||
0100EB500D92E000,"GROOVE COASTER WAI WAI PARTY!!!!",gpu,ingame,2026-05-13 18:32:12
|
||||
0100822012D76000,"HAAK",gpu,ingame,2023-02-19 14:31:05
|
||||
01007E100EFA8000,"Habroxia",,playable,2020-06-16 23:04:42
|
||||
0100535012974000,"Hades",vulkan,playable,2022-10-05 10:45:21
|
||||
@@ -1834,7 +1832,6 @@
|
||||
010055200E87E000,"Metamorphosis",UE4;audout;gpu;nvdec,ingame,2021-06-16 16:18:11
|
||||
0100D4900E82C000,"Metro 2033 Redux",gpu,ingame,2022-11-09 10:53:13
|
||||
0100F0400E850000,"Metro: Last Light Redux",slow;nvdec;vulkan-backend-bug,ingame,2023-11-01 11:53:52
|
||||
010019A01E2F2000,"Metroid Prime 4: Beyond",,ingame,2026-05-13 18:32:12
|
||||
010012101468C000,"Metroid Prime™ Remastered",gpu;Needs Update;vulkan-backend-bug;opengl-backend-bug,ingame,2024-05-07 22:48:15
|
||||
010093801237C000,"Metroid™ Dread",,playable,2023-11-13 04:02:36
|
||||
0100A1200F20C000,"Midnight Evil",,playable,2022-10-18 22:55:19
|
||||
@@ -1948,7 +1945,6 @@
|
||||
0100C3E00ACAA000,"Mutant Football League: Dynasty Edition",online-broken,playable,2022-08-05 17:01:51
|
||||
01004BE004A86000,"Mutant Mudds Collection",,playable,2022-08-05 17:11:38
|
||||
0100E6B00DEA4000,"Mutant Year Zero: Road to Eden - Deluxe Edition",nvdec;UE4,playable,2022-09-10 13:31:10
|
||||
010037501F864000,"Mute Crimson DX",,ingame,2026-05-13 18:32:12
|
||||
0100161009E5C000,"MX Nitro: Unleashed",,playable,2022-09-27 22:34:33
|
||||
0100218011E7E000,"MX vs ATV All Out",nvdec;UE4;vulkan-backend-bug,playable,2022-10-25 19:51:46
|
||||
0100D940063A0000,"MXGP3 - The Official Motocross Videogame",UE4;gpu;nvdec,ingame,2020-12-16 14:00:20
|
||||
@@ -2272,7 +2268,6 @@
|
||||
010086F0064CE000,"Poi: Explorer Edition",nvdec,playable,2021-01-21 19:32:00
|
||||
0100EB6012FD2000,"Poison Control",,playable,2021-05-16 14:01:54
|
||||
010072400E04A000,"Pokémon Café ReMix",,playable,2021-08-17 20:00:04
|
||||
01005B7008C52800,"Pokémon Champions",Needs Update;services;online-broke,menus,2026-05-13 18:32:12
|
||||
010008c01e742000,"Pokémon Friends",crash;services,menus,2025-07-24 13:32:00
|
||||
01003D200BAA2000,"Pokémon Mystery Dungeon™: Rescue Team DX",mac-bug,playable,2024-01-21 00:16:32
|
||||
01008DB008C2C000,"Pokémon Shield + Pokémon Shield Expansion Pass",deadlock;crash;online-broken;ldn-works;LAN,ingame,2024-08-12 07:20:22
|
||||
@@ -2280,8 +2275,6 @@
|
||||
01009AD008C4C000,"Pokémon: Let's Go, Pikachu! demo",slow;demo,playable,2023-11-26 11:23:20
|
||||
0100000011D90000,"Pokémon™ Brilliant Diamond",gpu;ldn-works,ingame,2024-08-28 13:26:35
|
||||
010018E011D92000,"Pokémon™ Shining Pearl",gpu;ldn-works,ingame,2024-08-28 13:26:35
|
||||
100554023408000,"Pokémon FireRed Version",crashes,nothing,2026-05-13 18:32:12
|
||||
010034D02340E000,"Pokémon LeafGreen Version",crashes,nothing,2026-05-13 18:32:12
|
||||
010015F008C54000,"Pokémon™ HOME",Needs Update;crash;services,menus,2020-12-06 06:01:51
|
||||
01001F5010DFA000,"Pokémon™ Legends: Arceus",gpu;Needs Update;ldn-works,ingame,2024-09-19 10:02:02
|
||||
0100F43008C44000,"Pokémon™ Legends: Z-A",gpu;crash;ldn-works,ingame,2025-11-16 00:30:00
|
||||
@@ -2873,7 +2866,7 @@
|
||||
0100277011F1A000,"Super Mario Bros.™ 35",online-broken,menus,2022-08-07 16:27:25
|
||||
010015100B514000,"Super Mario Bros.™ Wonder",amd-vendor-bug,playable,2024-09-06 13:21:21
|
||||
01009B90006DC000,"Super Mario Maker™ 2",online-broken;ldn-broken,playable,2024-08-25 11:05:19
|
||||
0100000000010000,"Super Mario Odyssey™",nvdec;intel-vendor-bug;mac-bug;amd-vendor-bug,playable,2026-05-13 18:32:12
|
||||
0100000000010000,"Super Mario Odyssey™",nvdec;intel-vendor-bug;mac-bug,playable,2024-08-25 01:32:34
|
||||
010036B0034E4000,"Super Mario Party™",gpu;Needs Update;ldn-works,ingame,2024-06-21 05:10:16
|
||||
0100965017338000,"Super Mario Party Jamboree",mac-bug;gpu,ingame,2025-02-17 02:09:20
|
||||
0100BC0018138000,"Super Mario RPG™",gpu;audio;nvdec,ingame,2024-06-19 17:43:42
|
||||
@@ -3170,8 +3163,6 @@
|
||||
0100E2E00CB14000,"Tokyo School Life",,playable,2022-09-16 20:25:54
|
||||
010024601BB16000,"Tomb Raider I-III Remastered Starring Lara Croft",gpu;opengl,ingame,2024-09-27 12:32:04
|
||||
0100D7F01E49C000,"Tomba! Special Edition",services-horizon,nothing,2024-09-15 21:59:54
|
||||
010051F0207B2000,"Tomodachi Life: Living the Dream",amd-vendor-bug;gpu;intel-vendor-bug;ldn-broken,ingame,2026-05-13 18:32:12
|
||||
0100CA502552A000,"Tomodachi Life: Living the Dream – Welcome Edtion",amd-vendor-bug;demo,playable,2026-05-13 18:32:12
|
||||
0100D400100F8000,"Tonight We Riot",,playable,2021-02-26 15:55:09
|
||||
0100CC00102B4000,"Tony Hawk's™ Pro Skater™ 1 + 2",gpu;Needs Update,ingame,2024-09-24 08:18:14
|
||||
010093F00E818000,"Tools Up!",crash,ingame,2020-07-21 12:58:17
|
||||
|
||||
|
@@ -5,7 +5,8 @@
|
||||
<clear />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
<!-- Only needed when using pre-release versions of Ryujinx.LibHac. -->
|
||||
<add key="LibHacAlpha" value="https://git.ryujinx.app/api/packages/projects/nuget/index.json" />
|
||||
<add key="LibHacAlpha" value="https://git.ryujinx.app/api/v4/projects/17/packages/nuget/index.json" />
|
||||
<add key="Ryujinx.UpdateClient" value="https://git.ryujinx.app/api/v4/projects/71/packages/nuget/index.json" />
|
||||
</packageSources>
|
||||
<packageSourceMapping>
|
||||
<!-- key value for <packageSource> should match key values from <packageSources> element -->
|
||||
@@ -13,6 +14,10 @@
|
||||
<packageSource key="nuget.org">
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
<packageSource key="Ryujinx.UpdateClient">
|
||||
<package pattern="Ryujinx.UpdateClient" />
|
||||
<package pattern="Ryujinx.Systems.Update.Common" />
|
||||
</packageSource>
|
||||
<packageSource key="LibHacAlpha">
|
||||
<package pattern="Ryujinx.LibHac" />
|
||||
</packageSource>
|
||||
|
||||
@@ -16,10 +16,5 @@ namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
/// Enable Rumble
|
||||
/// </summary>
|
||||
public bool EnableRumble { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enable HD Rumble support
|
||||
/// </summary
|
||||
public bool UseHDRumble { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,20 @@ namespace Ryujinx.Common.Helper
|
||||
private static partial nint GetConsoleWindow();
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[LibraryImport("kernel32", SetLastError = true)]
|
||||
[LibraryImport("user32")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static partial bool FreeConsole();
|
||||
private static partial bool ShowWindow(nint hWnd, int nCmdShow);
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[LibraryImport("user32")]
|
||||
private static partial nint GetForegroundWindow();
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[LibraryImport("user32")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static partial bool SetForegroundWindow(nint hWnd);
|
||||
|
||||
public static bool SetConsoleWindowStateSupported => OperatingSystem.IsWindows();
|
||||
public static bool HasConsoleWindow => OperatingSystem.IsWindows() && GetConsoleWindow() != nint.Zero;
|
||||
|
||||
public static void SetConsoleWindowState(bool show)
|
||||
{
|
||||
@@ -34,31 +42,22 @@ namespace Ryujinx.Common.Helper
|
||||
[SupportedOSPlatform("windows")]
|
||||
private static void SetConsoleWindowStateWindows(bool show)
|
||||
{
|
||||
if (show)
|
||||
const int SW_HIDE = 0;
|
||||
const int SW_SHOW = 5;
|
||||
|
||||
nint hWnd = GetConsoleWindow();
|
||||
|
||||
if (hWnd == nint.Zero)
|
||||
{
|
||||
if (GetConsoleWindow() != nint.Zero)
|
||||
{
|
||||
Logger.SetConsoleTargetEnabled(true);
|
||||
}
|
||||
Logger.Warning?.Print(LogClass.Application, "Attempted to show/hide console window but console window does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.SetConsoleTargetEnabled(false);
|
||||
DetachConsole();
|
||||
}
|
||||
SetForegroundWindow(hWnd);
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
private static void DetachConsole()
|
||||
{
|
||||
if (GetConsoleWindow() == nint.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
hWnd = GetForegroundWindow();
|
||||
|
||||
if (!FreeConsole())
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, "Attempted to detach console window but the operation failed");
|
||||
}
|
||||
ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ namespace Ryujinx.Common.Logging
|
||||
ServiceNgct,
|
||||
ServiceNifm,
|
||||
ServiceNim,
|
||||
ServiceNotification,
|
||||
ServiceNs,
|
||||
ServiceNsd,
|
||||
ServiceNtc,
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace Ryujinx.Common.Logging
|
||||
Error,
|
||||
Guest,
|
||||
AccessLog,
|
||||
NetLog,
|
||||
Notice,
|
||||
Trace,
|
||||
}
|
||||
|
||||
@@ -119,7 +119,6 @@ namespace Ryujinx.Common.Logging
|
||||
public static Log? Error { get; private set; }
|
||||
public static Log? Guest { get; private set; }
|
||||
public static Log? AccessLog { get; private set; }
|
||||
public static Log? NetLog { get; private set; }
|
||||
public static Log? Stub { get; private set; }
|
||||
public static Log? Trace { get; private set; }
|
||||
public static Log Notice { get; } // Always enabled
|
||||
@@ -137,7 +136,11 @@ namespace Ryujinx.Common.Logging
|
||||
|
||||
_time = Stopwatch.StartNew();
|
||||
|
||||
SetConsoleTargetEnabled(true);
|
||||
// Logger should log to console by default
|
||||
AddTarget(new AsyncLogTargetWrapper(
|
||||
new ConsoleLogTarget("console"),
|
||||
1000,
|
||||
AsyncLogTargetOverflowAction.Discard));
|
||||
|
||||
Notice = new Log(LogLevel.Notice);
|
||||
|
||||
@@ -170,21 +173,6 @@ namespace Ryujinx.Common.Logging
|
||||
Updated += target.Log;
|
||||
}
|
||||
|
||||
public static void SetConsoleTargetEnabled(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
AddTarget(new AsyncLogTargetWrapper(
|
||||
new ConsoleLogTarget("console"),
|
||||
1000,
|
||||
AsyncLogTargetOverflowAction.Discard));
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveTarget("console");
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveTarget(string target)
|
||||
{
|
||||
ILogTarget logTarget = GetTarget(target);
|
||||
@@ -248,7 +236,6 @@ namespace Ryujinx.Common.Logging
|
||||
case LogLevel.Error : Error = enabled ? new Log(LogLevel.Error) : null; break;
|
||||
case LogLevel.Guest : Guest = enabled ? new Log(LogLevel.Guest) : null; break;
|
||||
case LogLevel.AccessLog : AccessLog = enabled ? new Log(LogLevel.AccessLog) : null; break;
|
||||
case LogLevel.NetLog : NetLog = enabled ? new Log(LogLevel.NetLog) : null; break;
|
||||
case LogLevel.Stub : Stub = enabled ? new Log(LogLevel.Stub) : null; break;
|
||||
case LogLevel.Trace : Trace = enabled ? new Log(LogLevel.Trace) : null; break;
|
||||
case LogLevel.Notice : break;
|
||||
|
||||
@@ -29,8 +29,8 @@ namespace Ryujinx.Common
|
||||
|
||||
public static string GetChangelogUrl(Version currentVersion, Version newVersion) =>
|
||||
IsCanaryBuild
|
||||
? $"https://git.ryujinx.app/projects/Ryubing/compare/Canary-{currentVersion}...Canary-{newVersion}"
|
||||
: $"https://git.ryujinx.app/projects/Ryubing/releases/tag/{newVersion}";
|
||||
? $"https://git.ryujinx.app/ryubing/ryujinx/-/compare/Canary-{currentVersion}...Canary-{newVersion}"
|
||||
: $"https://git.ryujinx.app/ryubing/ryujinx/-/releases/{newVersion}";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@ namespace Ryujinx.Common
|
||||
|
||||
public const string AmiiboTagsUrl = "https://raw.githubusercontent.com/Ryubing/Nfc/refs/heads/main/tags.json";
|
||||
|
||||
public const string FaqWikiUrl = "https://git.ryujinx.app/projects/Ryubing/wiki/FAQ-%26-Troubleshooting";
|
||||
public const string FaqWikiUrl = "https://git.ryujinx.app/ryubing/ryujinx/-/wikis/FAQ-&-Troubleshooting";
|
||||
|
||||
public const string SetupGuideWikiUrl =
|
||||
"https://git.ryujinx.app/projects/Ryubing/wiki/Setup-%26-Configuration-Guide";
|
||||
"https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Setup-&-Configuration-Guide";
|
||||
|
||||
public const string MultiplayerWikiUrl =
|
||||
"https://git.ryujinx.app/projects/Ryubing/wiki/Multiplayer-(LDN-Local-Wireless)-Guide";
|
||||
"https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Multiplayer-(LDN-Local-Wireless)-Guide";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ namespace Ryujinx.Common
|
||||
|
||||
//Mario Franchise
|
||||
"010021d00812a000", // Arcade Archives VS. SUPER MARIO BROS.
|
||||
"01007fe0221d8000", // Hello, Mario!
|
||||
"01006d0017f7a000", // Mario & Luigi: Brothership
|
||||
"010003000e146000", // Mario & Sonic at the Olympic Games Tokyo 2020
|
||||
"010067300059a000", // Mario + Rabbids: Kingdom Battle
|
||||
@@ -71,9 +70,6 @@ namespace Ryujinx.Common
|
||||
"0100bde00862a000", // Mario Tennis Aces
|
||||
"0100b99019412000", // Mario vs. Donkey Kong
|
||||
"010049900f546000", // Super Mario 3D All-Stars
|
||||
"010049900f546001", // Super Mario 3D All-Stars | Super Mario 64
|
||||
"010049900f546002", // Super Mario 3D All-Stars | Super Mario Sunshine
|
||||
"010049900f546003", // Super Mario 3D All-Stars | Super Mario Galaxy
|
||||
"010028600ebda000", // Super Mario 3D World + Bowser's Fury
|
||||
"010049900F546001", // Super Mario 64
|
||||
"0100ea80032ea000", // Super Mario Bros. U Deluxe
|
||||
@@ -111,11 +107,6 @@ namespace Ryujinx.Common
|
||||
"0100187003a36000", // Pokémon: Let's Go Eevee!
|
||||
"010003f003a34000", // Pokémon: Let's Go Pikachu!
|
||||
"0100f43008c44000", // Pokémon Legends: Z-A
|
||||
"0100554023408000", // Pokémon FireRed Version (EN)
|
||||
"01006fa0233f8000", // Pokémon FireRed Version (JP)
|
||||
"0100fd6023430000", // Pokémon LeafGreen Version (DE)
|
||||
"0100f1e0233fa000", // Pokémon LeafGreen Version (JP)
|
||||
"01005b7008c52000", // Pokémon Champions
|
||||
|
||||
//Splatoon Franchise
|
||||
"0100f8f0000a2000", // Splatoon 2 (EU)
|
||||
@@ -125,14 +116,13 @@ namespace Ryujinx.Common
|
||||
"0100ba0018500000", // Splatoon 3: Splatfest World Premiere
|
||||
|
||||
//NSO Membership games
|
||||
"0100d870045b6000", // NES - Nintendo Switch Online
|
||||
"01008d300c50c000", // SNES - Nintendo Switch Online
|
||||
"0100c62011050000", // GB - Nintendo Switch Online
|
||||
"010012f017576000", // GBA - Nintendo Switch Online
|
||||
"0100c9a00ece6000", // N64 - Nintendo Switch Online
|
||||
"0100e0601c632000", // N64 - Nintendo Switch Online 18+
|
||||
"0100d870045b6000", // NES - Nintendo Switch Online
|
||||
"0100b3c014bda000", // SEGA Genesis - Nintendo Switch Online
|
||||
"0100bfc01d976000", // Virtual Boy - Nintendo Switch Online
|
||||
"01008d300c50c000", // SNES - Nintendo Switch Online
|
||||
"0100ccf019c8c000", // F-ZERO 99
|
||||
"0100ad9012510000", // PAC-MAN 99
|
||||
"010040600c5ce000", // Tetris 99
|
||||
@@ -151,17 +141,12 @@ namespace Ryujinx.Common
|
||||
"0100704000B3A000", // Snipperclips
|
||||
"01006a800016e000", // Super Smash Bros. Ultimate
|
||||
"0100a9400c9c2000", // Tokyo Mirage Sessions #FE Encore
|
||||
"0100ca502552a000", // Tomodachi Life: Living the Dream - Welcome Edition
|
||||
"010051f0207b2000", // Tomodachi Life: Living the Dream
|
||||
|
||||
//Bayonetta Franchise
|
||||
"010076f0049a2000", // Bayonetta
|
||||
"01007960049a0000", // Bayonetta 2
|
||||
"01004a4010fea000", // Bayonetta 3
|
||||
"0100cf5010fec000", // Bayonetta Origins: Cereza and the Lost Demon
|
||||
|
||||
// Famicom Detective Club Franchise
|
||||
"010054601d54c000", // Emio - The Smiling Man: Famicom Detective Series (DEMO)
|
||||
|
||||
//Persona Franchise
|
||||
"0100dcd01525a000", // Persona 3 Portable
|
||||
@@ -186,9 +171,7 @@ namespace Ryujinx.Common
|
||||
"0100453019aa8000", // Xenoblade Chronicles: X Definitive Edition
|
||||
|
||||
//Misc Games
|
||||
"01003670066de000", // 36 Fragments of Midnight
|
||||
"010056e00853a000", // A Hat in Time
|
||||
"0100c9f00aaee000", // Ascendence
|
||||
"0100fd1014726000", // Baldurs Gate: Dark Alliance
|
||||
"01008c2019598000", // Bluey: The Video Game
|
||||
"010096f00ff22000", // Borderlands 2: Game of the Year Edition
|
||||
@@ -202,10 +185,8 @@ namespace Ryujinx.Common
|
||||
"010027400cdc6000", // Divinity Original 2 - Definitive Edition
|
||||
"01008c8012920000", // Dying Light Platinum Edition
|
||||
"0100d11013e6a000", // Eschatos
|
||||
"01000490067ae000", // Frederic 2: Evil Strikes Back
|
||||
"01001cc01b2d4000", // Goat Simulator 3
|
||||
"01003620068ea000", // Hand of Fate 2
|
||||
"01007ac00e012000", // HEXAGRAVITY
|
||||
"0100f7e00c70e000", // Hogwarts Legacy
|
||||
"010013c00e930000", // Hollow Knight: Silksong
|
||||
"010085500130a000", // Lego City: Undercover
|
||||
@@ -215,7 +196,6 @@ namespace Ryujinx.Common
|
||||
"0100853015e86000", // No Man's Sky
|
||||
"0100f85014ed0000", // No More Heroes
|
||||
"0100463014ed4000", // No More Heroes 2
|
||||
"0100f7d00a1bc000", // NO THING
|
||||
"0100e570094e8000", // Owlboy
|
||||
"01007bb017812000", // Portal
|
||||
"0100abd01785c000", // Portal 2
|
||||
@@ -224,14 +204,11 @@ namespace Ryujinx.Common
|
||||
"01008e200c5c2000", // Muse Dash
|
||||
"01005ff002e2a000", // Rayman Legends
|
||||
"01007820196a6000", // Red Dead Redemption
|
||||
"01007a800d520000", // REFUNCT
|
||||
"0100e8300a67a000", // Risk
|
||||
"01002f7013224000", // Rune Factory 5
|
||||
"01008d100d43e000", // Saints Row IV
|
||||
"0100de600beee000", // Saints Row: The Third - The Full Package
|
||||
"01001180021fa000", // Shovel Knight: Specter of Torment
|
||||
"010079f00671c000", // Sparkle 2: Evo
|
||||
"010077b00e046000", // Spyro: Reignited Trilogy
|
||||
"0100e1D01eb2e000", // Squeakross: Home Squeak Home
|
||||
"0100e65002bb8000", // Stardew Valley
|
||||
"0100d7a01b7a2000", // Star Wars: Bounty Hunter
|
||||
|
||||
@@ -17,8 +17,7 @@ namespace Ryujinx.Cpu.LightningJit.Cache
|
||||
private static readonly int _pageMask = _pageSize - 1;
|
||||
|
||||
private const int CodeAlignment = 4; // Bytes.
|
||||
// TODO: JIT Cache size should be application dependent, not global.
|
||||
private const int CacheSize = 1024 * (1024 * 1024); // Megabytes * Size of Megabytes (since its in bytes).
|
||||
private const int CacheSize = 256 * 1024 * 1024;
|
||||
|
||||
private static JitCacheInvalidation _jitCacheInvalidator;
|
||||
|
||||
@@ -34,14 +33,6 @@ namespace Ryujinx.Cpu.LightningJit.Cache
|
||||
[SupportedOSPlatform("windows")]
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
public static partial nint FlushInstructionCache(nint hProcess, nint lpAddress, nuint dwSize);
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
[LibraryImport("libSystem.dylib", EntryPoint = "sys_icache_invalidate")]
|
||||
internal static partial void SysICacheInvalidate(nint start, nuint len);
|
||||
|
||||
[SupportedOSPlatform("linux")]
|
||||
[LibraryImport("libgcc_s.so.1", EntryPoint = "__clear_cache")]
|
||||
internal static partial void ClearCache(nint begin, nint end);
|
||||
|
||||
public static void Initialize(IJitMemoryAllocator allocator)
|
||||
{
|
||||
|
||||
@@ -42,7 +42,6 @@ namespace Ryujinx.Graphics.GAL
|
||||
public readonly bool SupportsShaderBallot;
|
||||
public readonly bool SupportsShaderBarrierDivergence;
|
||||
public readonly bool SupportsShaderFloat64;
|
||||
public readonly bool SupportsShaderNonUniformIndexing;
|
||||
public readonly bool SupportsTextureGatherOffsets;
|
||||
public readonly bool SupportsTextureShadowLod;
|
||||
public readonly bool SupportsVertexStoreAndAtomics;
|
||||
@@ -111,7 +110,6 @@ namespace Ryujinx.Graphics.GAL
|
||||
bool supportsShaderBallot,
|
||||
bool supportsShaderBarrierDivergence,
|
||||
bool supportsShaderFloat64,
|
||||
bool supportsShaderNonUniformIndexing,
|
||||
bool supportsTextureGatherOffsets,
|
||||
bool supportsTextureShadowLod,
|
||||
bool supportsVertexStoreAndAtomics,
|
||||
@@ -174,7 +172,6 @@ namespace Ryujinx.Graphics.GAL
|
||||
SupportsShaderBallot = supportsShaderBallot;
|
||||
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
||||
SupportsShaderFloat64 = supportsShaderFloat64;
|
||||
SupportsShaderNonUniformIndexing = supportsShaderNonUniformIndexing;
|
||||
SupportsTextureGatherOffsets = supportsTextureGatherOffsets;
|
||||
SupportsTextureShadowLod = supportsTextureShadowLod;
|
||||
SupportsVertexStoreAndAtomics = supportsVertexStoreAndAtomics;
|
||||
|
||||
@@ -49,9 +49,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
private const int MinCountForDeletion = 32;
|
||||
private const int MaxCapacity = 2048;
|
||||
private const ulong GiB = 1024 * 1024 * 1024;
|
||||
private ulong MaxTextureSizeCapacity = 2 * GiB;
|
||||
private ulong MaxTextureSizeCapacity = 4UL * GiB;
|
||||
private const ulong MinTextureSizeCapacity = 512 * 1024 * 1024;
|
||||
private const ulong DefaultTextureSizeCapacity = 1 * GiB;
|
||||
private const ulong TextureSizeCapacity6GiB = 4 * GiB;
|
||||
private const ulong TextureSizeCapacity8GiB = 6 * GiB;
|
||||
private const ulong TextureSizeCapacity12GiB = 12 * GiB;
|
||||
|
||||
private const float MemoryScaleFactor = 0.50f;
|
||||
private ulong _maxCacheMemoryUsage = DefaultTextureSizeCapacity;
|
||||
@@ -70,22 +73,31 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <remarks>
|
||||
/// If the backend GPU has 0 memory capacity, the cache size defaults to `DefaultTextureSizeCapacity`.
|
||||
///
|
||||
/// Reads the current Device total CPU Memory, to determine the maximum amount of VRAM available. Capped to 50% of Current GPU Memory.
|
||||
/// Reads the current Device total CPU Memory, to determine the maximum amount of Vram available. Capped to 50% of Current GPU Memory.
|
||||
/// </remarks>
|
||||
/// <param name="context">The GPU context that the cache belongs to</param>
|
||||
/// <param name="cpuMemorySize">The amount of physical CPU Memory available on the device.</param>
|
||||
/// <param name="cpuMemorySize">The amount of physical CPU Memory Avaiable on the device.</param>
|
||||
public void Initialize(GpuContext context, ulong cpuMemorySize)
|
||||
{
|
||||
ulong cpuMemorySizeGiB = cpuMemorySize / GiB;
|
||||
ulong MaximumGpuMemoryGiB = context.Capabilities.MaximumGpuMemory / GiB;
|
||||
ulong TextureSizeCapacity = cpuMemorySize - (2 * GiB);
|
||||
|
||||
MaxTextureSizeCapacity =
|
||||
context.Capabilities.MaximumGpuMemory == 0 || cpuMemorySizeGiB < 6 && MaximumGpuMemoryGiB < 6
|
||||
? DefaultTextureSizeCapacity
|
||||
: cpuMemorySizeGiB < 12
|
||||
? TextureSizeCapacity
|
||||
: cpuMemorySize;
|
||||
if (cpuMemorySizeGiB < 6 || context.Capabilities.MaximumGpuMemory == 0)
|
||||
{
|
||||
_maxCacheMemoryUsage = DefaultTextureSizeCapacity;
|
||||
return;
|
||||
}
|
||||
else if (cpuMemorySizeGiB == 6)
|
||||
{
|
||||
MaxTextureSizeCapacity = TextureSizeCapacity6GiB;
|
||||
}
|
||||
else if (cpuMemorySizeGiB == 8)
|
||||
{
|
||||
MaxTextureSizeCapacity = TextureSizeCapacity8GiB;
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxTextureSizeCapacity = TextureSizeCapacity12GiB;
|
||||
}
|
||||
|
||||
ulong cacheMemory = (ulong)(context.Capabilities.MaximumGpuMemory * MemoryScaleFactor);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 7354;
|
||||
private const uint CodeGenVersion = 7353;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
||||
@@ -231,8 +231,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
public bool QueryHostSupportsShaderFloat64() => _context.Capabilities.SupportsShaderFloat64;
|
||||
|
||||
public bool QueryHostSupportsShaderNonUniformIndexing() => _context.Capabilities.SupportsShaderNonUniformIndexing;
|
||||
|
||||
public bool QueryHostSupportsSnormBufferTextureFormat() => _context.Capabilities.SupportsSnormBufferTextureFormat;
|
||||
|
||||
public bool QueryHostSupportsTextureGatherOffsets() => _context.Capabilities.SupportsTextureGatherOffsets;
|
||||
|
||||
@@ -551,7 +551,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
level,
|
||||
x,
|
||||
width,
|
||||
(InternalFormat) format.PixelFormat,
|
||||
format.PixelFormat,
|
||||
mipSize,
|
||||
data);
|
||||
}
|
||||
@@ -579,7 +579,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
layer,
|
||||
width,
|
||||
1,
|
||||
(InternalFormat) format.PixelFormat,
|
||||
format.PixelFormat,
|
||||
mipSize,
|
||||
data);
|
||||
}
|
||||
@@ -609,7 +609,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
(InternalFormat) format.PixelFormat,
|
||||
format.PixelFormat,
|
||||
mipSize,
|
||||
data);
|
||||
}
|
||||
@@ -643,7 +643,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
width,
|
||||
height,
|
||||
1,
|
||||
(InternalFormat) format.PixelFormat,
|
||||
format.PixelFormat,
|
||||
mipSize,
|
||||
data);
|
||||
}
|
||||
@@ -675,7 +675,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
(InternalFormat) format.PixelFormat,
|
||||
format.PixelFormat,
|
||||
mipSize,
|
||||
data);
|
||||
}
|
||||
@@ -744,7 +744,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
level,
|
||||
0,
|
||||
width,
|
||||
(InternalFormat) format.PixelFormat,
|
||||
format.PixelFormat,
|
||||
mipSize,
|
||||
data);
|
||||
}
|
||||
@@ -773,7 +773,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
(InternalFormat) format.PixelFormat,
|
||||
format.PixelFormat,
|
||||
mipSize,
|
||||
data);
|
||||
}
|
||||
@@ -807,7 +807,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
(InternalFormat) format.PixelFormat,
|
||||
format.PixelFormat,
|
||||
mipSize,
|
||||
data);
|
||||
}
|
||||
@@ -843,7 +843,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
(InternalFormat) format.PixelFormat,
|
||||
format.PixelFormat,
|
||||
mipSize / 6,
|
||||
data + faceOffset);
|
||||
}
|
||||
|
||||
@@ -184,7 +184,6 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
|
||||
supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
|
||||
supportsShaderFloat64: true,
|
||||
supportsShaderNonUniformIndexing: false,
|
||||
supportsTextureGatherOffsets: true,
|
||||
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
||||
supportsVertexStoreAndAtomics: true,
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
public void Map(BufferHandle handle, int size)
|
||||
{
|
||||
GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle);
|
||||
nint ptr = GL.MapBufferRange(BufferTarget.CopyWriteBuffer, nint.Zero, size, MapBufferAccessMask.MapReadBit | MapBufferAccessMask.MapPersistentBit);
|
||||
nint ptr = GL.MapBufferRange(BufferTarget.CopyWriteBuffer, nint.Zero, size, BufferAccessMask.MapReadBit | BufferAccessMask.MapPersistentBit);
|
||||
|
||||
_maps[handle] = ptr;
|
||||
}
|
||||
@@ -75,7 +75,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
GL.BindBuffer(BufferTarget.CopyWriteBuffer, _copyBufferHandle);
|
||||
GL.BufferStorage(BufferTarget.CopyWriteBuffer, requiredSize, nint.Zero, BufferStorageFlags.MapReadBit | BufferStorageFlags.MapPersistentBit);
|
||||
|
||||
_bufferMap = GL.MapBufferRange(BufferTarget.CopyWriteBuffer, nint.Zero, requiredSize, MapBufferAccessMask.MapReadBit | MapBufferAccessMask.MapPersistentBit);
|
||||
_bufferMap = GL.MapBufferRange(BufferTarget.CopyWriteBuffer, nint.Zero, requiredSize, BufferAccessMask.MapReadBit | BufferAccessMask.MapPersistentBit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -924,8 +924,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
GL.Disable(EnableCap.CullFace);
|
||||
return;
|
||||
}
|
||||
|
||||
GL.CullFace((TriangleFace) face.Convert());
|
||||
|
||||
GL.CullFace(face.Convert());
|
||||
|
||||
GL.Enable(EnableCap.CullFace);
|
||||
}
|
||||
@@ -1085,12 +1085,12 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
if (frontMode == backMode)
|
||||
{
|
||||
GL.PolygonMode((TriangleFace) MaterialFace.FrontAndBack, frontMode.Convert());
|
||||
GL.PolygonMode(MaterialFace.FrontAndBack, frontMode.Convert());
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.PolygonMode((TriangleFace) MaterialFace.Front, frontMode.Convert());
|
||||
GL.PolygonMode((TriangleFace) MaterialFace.Back, backMode.Convert());
|
||||
GL.PolygonMode(MaterialFace.Front, frontMode.Convert());
|
||||
GL.PolygonMode(MaterialFace.Back, backMode.Convert());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
GL.CompileShader(shaderHandle);
|
||||
break;
|
||||
case TargetLanguage.Spirv:
|
||||
GL.ShaderBinary(1, ref shaderHandle, ShaderBinaryFormat.ShaderBinaryFormatSpirV, shader.BinaryCode, shader.BinaryCode.Length);
|
||||
GL.ShaderBinary(1, ref shaderHandle, (BinaryFormat)All.ShaderBinaryFormatSpirVArb, shader.BinaryCode, shader.BinaryCode.Length);
|
||||
GL.SpecializeShader(shaderHandle, "main", 0, (int[])null, (int[])null);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
||||
GL.BufferStorage(BufferTarget.QueryBuffer, sizeof(long), (nint)(&defaultValue), BufferStorageFlags.MapReadBit | BufferStorageFlags.MapWriteBit | BufferStorageFlags.MapPersistentBit);
|
||||
}
|
||||
|
||||
_bufferMap = GL.MapBufferRange(BufferTarget.QueryBuffer, nint.Zero, sizeof(long), MapBufferAccessMask.MapReadBit | MapBufferAccessMask.MapWriteBit | MapBufferAccessMask.MapPersistentBit);
|
||||
_bufferMap = GL.MapBufferRange(BufferTarget.QueryBuffer, nint.Zero, sizeof(long), BufferAccessMask.MapReadBit | BufferAccessMask.MapWriteBit | BufferAccessMask.MapPersistentBit);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
|
||||
@@ -82,7 +82,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
public bool IsMainFunction { get; private set; }
|
||||
public bool MayHaveReturned { get; set; }
|
||||
public bool WasNonUniformAccessDeclared { get; set; }
|
||||
|
||||
public CodeGenContext(
|
||||
StructuredProgramInfo info,
|
||||
@@ -90,8 +89,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
GeneratorPool<Instruction> instPool,
|
||||
GeneratorPool<LiteralInteger> integerPool) : base(SpirvVersionPacked, instPool, integerPool)
|
||||
{
|
||||
WasNonUniformAccessDeclared = false;
|
||||
|
||||
Info = info;
|
||||
AttributeUsage = parameters.AttributeUsage;
|
||||
Definitions = parameters.Definitions;
|
||||
|
||||
@@ -587,23 +587,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
return OperationResult.Invalid;
|
||||
}
|
||||
|
||||
private static void MarkNonUniform(CodeGenContext context, SpvInstruction inst)
|
||||
{
|
||||
if (context.HostCapabilities.SupportsShaderNonUniformIndexing)
|
||||
{
|
||||
if (!context.WasNonUniformAccessDeclared)
|
||||
{
|
||||
context.AddExtension("SPV_EXT_descriptor_indexing");
|
||||
context.AddCapability(Capability.ShaderNonUniform);
|
||||
context.AddCapability(Capability.SampledImageArrayNonUniformIndexing);
|
||||
context.AddCapability(Capability.StorageImageArrayNonUniformIndexing);
|
||||
}
|
||||
|
||||
context.Decorate(inst, Decoration.NonUniform);
|
||||
context.WasNonUniformAccessDeclared = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static OperationResult GenerateImageAtomic(CodeGenContext context, AstOperation operation)
|
||||
{
|
||||
AstTextureOperation texOp = (AstTextureOperation)operation;
|
||||
@@ -630,7 +613,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
SpvInstruction textureIndex = Src(AggregateType.S32);
|
||||
|
||||
image = context.AccessChain(imagePointerType, image, textureIndex);
|
||||
MarkNonUniform(context, image);
|
||||
}
|
||||
|
||||
int coordsCount = texOp.Type.Dimensions;
|
||||
@@ -701,21 +683,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
|
||||
SpvInstruction image = declaration.Image;
|
||||
bool isIndexed = declaration.IsIndexed;
|
||||
|
||||
if (isIndexed)
|
||||
if (declaration.IsIndexed)
|
||||
{
|
||||
SpvInstruction textureIndex = Src(AggregateType.S32);
|
||||
|
||||
image = context.AccessChain(declaration.ImagePointerType, image, textureIndex);
|
||||
MarkNonUniform(context, image);
|
||||
}
|
||||
|
||||
image = context.Load(declaration.ImageType, image);
|
||||
if (isIndexed)
|
||||
{
|
||||
MarkNonUniform(context, image);
|
||||
}
|
||||
|
||||
int coordsCount = texOp.Type.Dimensions;
|
||||
|
||||
@@ -764,21 +740,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
|
||||
SpvInstruction image = declaration.Image;
|
||||
bool isIndexed = declaration.IsIndexed;
|
||||
|
||||
if (isIndexed)
|
||||
if (declaration.IsIndexed)
|
||||
{
|
||||
SpvInstruction textureIndex = Src(AggregateType.S32);
|
||||
|
||||
image = context.AccessChain(declaration.ImagePointerType, image, textureIndex);
|
||||
MarkNonUniform(context, image);
|
||||
}
|
||||
|
||||
image = context.Load(declaration.ImageType, image);
|
||||
if (isIndexed)
|
||||
{
|
||||
MarkNonUniform(context, image);
|
||||
}
|
||||
|
||||
int coordsCount = texOp.Type.Dimensions;
|
||||
|
||||
@@ -1908,56 +1878,35 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
private static SpvInstruction GenerateSampledImageLoad(CodeGenContext context, AstTextureOperation texOp, SamplerDeclaration declaration, ref int srcIndex)
|
||||
{
|
||||
SpvInstruction image = declaration.Image;
|
||||
bool imageIndexed = declaration.IsIndexed;
|
||||
|
||||
if (imageIndexed)
|
||||
if (declaration.IsIndexed)
|
||||
{
|
||||
SpvInstruction textureIndex = context.Get(AggregateType.S32, texOp.GetSource(srcIndex++));
|
||||
|
||||
image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex);
|
||||
MarkNonUniform(context, image);
|
||||
}
|
||||
|
||||
if (texOp.IsSeparate)
|
||||
{
|
||||
image = context.Load(declaration.ImageType, image);
|
||||
if (imageIndexed)
|
||||
{
|
||||
MarkNonUniform(context, image);
|
||||
}
|
||||
|
||||
SamplerDeclaration samplerDeclaration = context.Samplers[texOp.GetSamplerSetAndBinding()];
|
||||
|
||||
SpvInstruction sampler = samplerDeclaration.Image;
|
||||
bool samplerIndexed = samplerDeclaration.IsIndexed;
|
||||
|
||||
if (samplerIndexed)
|
||||
if (samplerDeclaration.IsIndexed)
|
||||
{
|
||||
SpvInstruction samplerIndex = context.Get(AggregateType.S32, texOp.GetSource(srcIndex++));
|
||||
|
||||
sampler = context.AccessChain(samplerDeclaration.SampledImagePointerType, sampler, samplerIndex);
|
||||
MarkNonUniform(context, sampler);
|
||||
}
|
||||
|
||||
sampler = context.Load(samplerDeclaration.ImageType, sampler);
|
||||
if (samplerIndexed)
|
||||
{
|
||||
MarkNonUniform(context, sampler);
|
||||
}
|
||||
|
||||
image = context.SampledImage(declaration.SampledImageType, image, sampler);
|
||||
if (imageIndexed || samplerIndexed)
|
||||
{
|
||||
MarkNonUniform(context, image);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
image = context.Load(declaration.SampledImageType, image);
|
||||
if (imageIndexed)
|
||||
{
|
||||
MarkNonUniform(context, image);
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
|
||||
@@ -336,10 +336,6 @@ namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool QueryHostSupportsShaderNonUniformIndexing()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host GPU support for signed normalized buffer texture formats.
|
||||
|
||||
@@ -9,7 +9,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
public readonly bool SupportsShaderBallot;
|
||||
public readonly bool SupportsShaderBarrierDivergence;
|
||||
public readonly bool SupportsShaderFloat64;
|
||||
public readonly bool SupportsShaderNonUniformIndexing;
|
||||
public readonly bool SupportsTextureShadowLod;
|
||||
public readonly bool SupportsViewportMask;
|
||||
|
||||
@@ -21,7 +20,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
bool supportsShaderBallot,
|
||||
bool supportsShaderBarrierDivergence,
|
||||
bool supportsShaderFloat64,
|
||||
bool supportsShaderNonUniformIndexing,
|
||||
bool supportsTextureShadowLod,
|
||||
bool supportsViewportMask)
|
||||
{
|
||||
@@ -32,7 +30,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
SupportsShaderBallot = supportsShaderBallot;
|
||||
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
||||
SupportsShaderFloat64 = supportsShaderFloat64;
|
||||
SupportsShaderNonUniformIndexing = supportsShaderNonUniformIndexing;
|
||||
SupportsTextureShadowLod = supportsTextureShadowLod;
|
||||
SupportsViewportMask = supportsViewportMask;
|
||||
}
|
||||
|
||||
@@ -364,7 +364,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
GpuAccessor.QueryHostSupportsShaderBallot(),
|
||||
GpuAccessor.QueryHostSupportsShaderBarrierDivergence(),
|
||||
GpuAccessor.QueryHostSupportsShaderFloat64(),
|
||||
GpuAccessor.QueryHostSupportsShaderNonUniformIndexing(),
|
||||
GpuAccessor.QueryHostSupportsTextureShadowLod(),
|
||||
GpuAccessor.QueryHostSupportsViewportMask());
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
@@ -115,7 +114,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
cbs.AddDependant(this);
|
||||
|
||||
// We need to add a dependency on the command buffer to all objects this object
|
||||
// references as well.
|
||||
// references aswell.
|
||||
if (_referencedObjs != null)
|
||||
{
|
||||
for (int i = 0; i < _referencedObjs.Length; i++)
|
||||
@@ -176,7 +175,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Debug.Assert(_referenceCount >= 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,14 +46,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public static (AccessFlags Access, PipelineStageFlags Stages) GetSubpassAccessSuperset(VulkanRenderer gd)
|
||||
{
|
||||
AccessFlags access = BufferAccess |
|
||||
AccessFlags.ShaderReadBit |
|
||||
AccessFlags.ShaderWriteBit |
|
||||
AccessFlags.ColorAttachmentReadBit |
|
||||
AccessFlags.ColorAttachmentWriteBit |
|
||||
AccessFlags.DepthStencilAttachmentReadBit |
|
||||
AccessFlags.DepthStencilAttachmentWriteBit;
|
||||
|
||||
AccessFlags access = BufferAccess;
|
||||
PipelineStageFlags stages = PipelineStageFlags.AllGraphicsBit;
|
||||
|
||||
if (gd.TransformFeedbackApi != null)
|
||||
|
||||
@@ -16,15 +16,15 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
DescriptorSetLayout[] layouts = new DescriptorSetLayout[setDescriptors.Count];
|
||||
bool[] updateAfterBindFlags = new bool[setDescriptors.Count];
|
||||
|
||||
|
||||
bool isMoltenVk = gd.IsMoltenVk;
|
||||
|
||||
|
||||
for (int setIndex = 0; setIndex < setDescriptors.Count; setIndex++)
|
||||
{
|
||||
ResourceDescriptorCollection rdc = setDescriptors[setIndex];
|
||||
|
||||
ResourceStages activeStages = ResourceStages.None;
|
||||
|
||||
|
||||
if (isMoltenVk)
|
||||
{
|
||||
for (int descIndex = 0; descIndex < rdc.Descriptors.Count; descIndex++)
|
||||
@@ -42,13 +42,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ResourceDescriptor descriptor = rdc.Descriptors[descIndex];
|
||||
ResourceStages stages = descriptor.Stages;
|
||||
|
||||
if (descriptor.Type == ResourceType.StorageBuffer && gd.IsMoltenVk)
|
||||
if (descriptor.Type == ResourceType.StorageBuffer && isMoltenVk)
|
||||
{
|
||||
// There's a bug in MoltenVK where using the same buffer across different stages
|
||||
// There's a bug on MoltenVK where using the same buffer across different stages
|
||||
// causes invalid resource errors, allow the binding on all active stages as workaround.
|
||||
// https://github.com/KhronosGroup/MoltenVK/issues/1870
|
||||
stages = activeStages;
|
||||
}
|
||||
}
|
||||
|
||||
layoutBindings[descIndex] = new DescriptorSetLayoutBinding
|
||||
{
|
||||
|
||||
@@ -15,8 +15,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Image dstImage,
|
||||
TextureCreateInfo srcInfo,
|
||||
TextureCreateInfo dstInfo,
|
||||
TextureCreateInfo srcStorageInfo,
|
||||
TextureCreateInfo dstStorageInfo,
|
||||
Extents2D srcRegion,
|
||||
Extents2D dstRegion,
|
||||
int srcLayer,
|
||||
@@ -42,13 +40,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return (xy1, xy2);
|
||||
}
|
||||
|
||||
static (Offset3D, Offset3D) ClampOffsetsToMip(Offset3D xy1, Offset3D xy2, int mipW, int mipH)
|
||||
{
|
||||
return (
|
||||
new Offset3D(Math.Min(xy1.X, mipW), Math.Min(xy1.Y, mipH), xy1.Z),
|
||||
new Offset3D(Math.Min(xy2.X, mipW), Math.Min(xy2.Y, mipH), xy2.Z));
|
||||
}
|
||||
|
||||
if (srcAspectFlags == 0)
|
||||
{
|
||||
srcAspectFlags = srcInfo.Format.ConvertAspectFlags();
|
||||
@@ -89,14 +80,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
(srcOffsets.Element0, srcOffsets.Element1) = ExtentsToOffset3D(srcRegion, srcInfo.Width, srcInfo.Height, level);
|
||||
(dstOffsets.Element0, dstOffsets.Element1) = ExtentsToOffset3D(dstRegion, dstInfo.Width, dstInfo.Height, level);
|
||||
|
||||
int srcMipW = Math.Max(1, srcStorageInfo.Width >> (int)copySrcLevel);
|
||||
int srcMipH = Math.Max(1, srcStorageInfo.Height >> (int)copySrcLevel);
|
||||
int dstMipW = Math.Max(1, dstStorageInfo.Width >> (int)copyDstLevel);
|
||||
int dstMipH = Math.Max(1, dstStorageInfo.Height >> (int)copyDstLevel);
|
||||
|
||||
(srcOffsets.Element0, srcOffsets.Element1) = ClampOffsetsToMip(srcOffsets.Element0, srcOffsets.Element1, srcMipW, srcMipH);
|
||||
(dstOffsets.Element0, dstOffsets.Element1) = ClampOffsetsToMip(dstOffsets.Element0, dstOffsets.Element1, dstMipW, dstMipH);
|
||||
|
||||
ImageBlit region = new()
|
||||
{
|
||||
SrcSubresource = srcSl,
|
||||
@@ -138,8 +121,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Image dstImage,
|
||||
TextureCreateInfo srcInfo,
|
||||
TextureCreateInfo dstInfo,
|
||||
TextureCreateInfo srcStorageInfo,
|
||||
TextureCreateInfo dstStorageInfo,
|
||||
int srcViewLayer,
|
||||
int dstViewLayer,
|
||||
int srcViewLevel,
|
||||
@@ -170,8 +151,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
dstImage,
|
||||
srcInfo,
|
||||
dstInfo,
|
||||
srcStorageInfo,
|
||||
dstStorageInfo,
|
||||
srcViewLayer,
|
||||
dstViewLayer,
|
||||
srcViewLevel,
|
||||
@@ -207,8 +186,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Image dstImage,
|
||||
TextureCreateInfo srcInfo,
|
||||
TextureCreateInfo dstInfo,
|
||||
TextureCreateInfo srcStorageInfo,
|
||||
TextureCreateInfo dstStorageInfo,
|
||||
int srcViewLayer,
|
||||
int dstViewLayer,
|
||||
int srcViewLevel,
|
||||
@@ -337,14 +314,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
int copyWidth = sizeInBlocks ? BitUtils.DivRoundUp(width, blockWidth) : width;
|
||||
int copyHeight = sizeInBlocks ? BitUtils.DivRoundUp(height, blockHeight) : height;
|
||||
|
||||
int srcMipW = Math.Max(1, srcStorageInfo.Width >> (srcViewLevel + srcLevel + level));
|
||||
int srcMipH = Math.Max(1, srcStorageInfo.Height >> (srcViewLevel + srcLevel + level));
|
||||
int dstMipW = Math.Max(1, dstStorageInfo.Width >> (dstViewLevel + dstLevel + level));
|
||||
int dstMipH = Math.Max(1, dstStorageInfo.Height >> (dstViewLevel + dstLevel + level));
|
||||
|
||||
copyWidth = Math.Min(copyWidth, Math.Min(srcMipW, dstMipW));
|
||||
copyHeight = Math.Min(copyHeight, Math.Min(srcMipH, dstMipH));
|
||||
|
||||
Extent3D extent = new((uint)copyWidth, (uint)copyHeight, (uint)srcDepth);
|
||||
|
||||
if (srcInfo.Samples > 1 && srcInfo.Samples != dstInfo.Samples)
|
||||
|
||||
@@ -67,8 +67,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public VkFormat VkFormat { get; }
|
||||
|
||||
public ImageUsageFlags UsageFlags { get; }
|
||||
|
||||
public unsafe TextureStorage(
|
||||
VulkanRenderer gd,
|
||||
Device device,
|
||||
@@ -95,8 +93,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
SampleCountFlags sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples);
|
||||
|
||||
ImageUsageFlags usage = GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported);
|
||||
UsageFlags = usage;
|
||||
ImageUsageFlags usage = GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported, true);
|
||||
|
||||
ImageCreateFlags flags = ImageCreateFlags.CreateMutableFormatBit | ImageCreateFlags.CreateExtendedUsageBit;
|
||||
|
||||
@@ -162,7 +159,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_imageAuto = new Auto<DisposableImage>(new DisposableImage(_gd.Api, device, _image));
|
||||
|
||||
InitialTransition(ImageLayout.Undefined, ImageLayout.General);
|
||||
InitialTransition(ImageLayout.Preinitialized, ImageLayout.General);
|
||||
}
|
||||
|
||||
_slices = new TextureSliceInfo[levels * _depthOrLayers];
|
||||
@@ -310,7 +307,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
public static ImageUsageFlags GetImageUsage(Format format, in HardwareCapabilities capabilities, bool isMsImageStorageSupported)
|
||||
public static ImageUsageFlags GetImageUsage(Format format, in HardwareCapabilities capabilities, bool isMsImageStorageSupported, bool extendedUsage)
|
||||
{
|
||||
ImageUsageFlags usage = DefaultUsageFlags;
|
||||
|
||||
@@ -323,7 +320,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
usage |= ImageUsageFlags.ColorAttachmentBit;
|
||||
}
|
||||
|
||||
if (format.IsImageCompatible && isMsImageStorageSupported)
|
||||
if ((format.IsImageCompatible && isMsImageStorageSupported) || extendedUsage)
|
||||
{
|
||||
usage |= ImageUsageFlags.StorageBit;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
bool isMsImageStorageSupported = gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample;
|
||||
|
||||
VkFormat format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format, isMsImageStorageSupported);
|
||||
ImageUsageFlags usage = TextureStorage.GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported) & storage.UsageFlags;
|
||||
ImageUsageFlags usage = TextureStorage.GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported, false);
|
||||
|
||||
uint levels = (uint)info.Levels;
|
||||
uint layers = (uint)info.GetLayers();
|
||||
@@ -133,8 +133,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
shaderUsage |= ImageUsageFlags.StorageBit;
|
||||
}
|
||||
|
||||
shaderUsage &= storage.UsageFlags;
|
||||
|
||||
_imageView = CreateImageView(componentMapping, subresourceRange, type, shaderUsage);
|
||||
|
||||
// Framebuffer attachments and storage images requires a identity component mapping.
|
||||
@@ -259,8 +257,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
dstImage,
|
||||
src.Info,
|
||||
dst.Info,
|
||||
src.Storage.Info,
|
||||
dst.Storage.Info,
|
||||
src.FirstLayer,
|
||||
dst.FirstLayer,
|
||||
src.FirstLevel,
|
||||
@@ -314,8 +310,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
dstImage,
|
||||
src.Info,
|
||||
dst.Info,
|
||||
src.Storage.Info,
|
||||
dst.Storage.Info,
|
||||
src.FirstLayer,
|
||||
dst.FirstLayer,
|
||||
src.FirstLevel,
|
||||
@@ -391,8 +385,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
dst.GetImage().Get(cbs).Value,
|
||||
src.Info,
|
||||
dst.Info,
|
||||
src.Storage.Info,
|
||||
dst.Storage.Info,
|
||||
src.FirstLayer,
|
||||
dst.FirstLayer,
|
||||
src.FirstLevel,
|
||||
@@ -418,8 +410,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
dst.GetImage().Get(cbs).Value,
|
||||
src.Info,
|
||||
dst.Info,
|
||||
src.Storage.Info,
|
||||
dst.Storage.Info,
|
||||
srcRegion,
|
||||
dstRegion,
|
||||
src.FirstLayer,
|
||||
@@ -473,8 +463,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
dstImage.Get(cbs).Value,
|
||||
src.Info,
|
||||
dst.Info,
|
||||
src.Storage.Info,
|
||||
dst.Storage.Info,
|
||||
srcRegion,
|
||||
dstRegion,
|
||||
src.FirstLayer,
|
||||
|
||||
@@ -68,7 +68,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
int stride = (_stride + (alignment - 1)) & -alignment;
|
||||
int newSize = (_size / _stride) * stride;
|
||||
|
||||
updater.BindVertexBuffer(cbs, binding, autoBuffer, 0, newSize, (ulong)stride);
|
||||
Buffer buffer = autoBuffer.Get(cbs, 0, newSize).Value;
|
||||
|
||||
updater.BindVertexBuffer(cbs, binding, buffer, 0, (ulong)newSize, (ulong)stride);
|
||||
|
||||
_buffer = autoBuffer;
|
||||
|
||||
@@ -91,7 +93,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (autoBuffer != null)
|
||||
{
|
||||
updater.BindVertexBuffer(cbs, binding, autoBuffer, _offset, _size, (ulong)_stride);
|
||||
int offset = _offset;
|
||||
bool mirrorable = _size <= VertexBufferMaxMirrorable;
|
||||
Buffer buffer = mirrorable ? autoBuffer.GetMirrorable(cbs, ref offset, _size, out _).Value : autoBuffer.Get(cbs, offset, _size).Value;
|
||||
|
||||
updater.BindVertexBuffer(cbs, binding, buffer, (ulong)offset, (ulong)_size, (ulong)_stride);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using VkBuffer = Silk.NET.Vulkan.Buffer;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
@@ -16,10 +15,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly NativeArray<ulong> _sizes;
|
||||
private readonly NativeArray<ulong> _strides;
|
||||
|
||||
private readonly Auto<DisposableBuffer>[] _bufferAutos;
|
||||
private readonly int[] _bufferOffsetsForGet;
|
||||
private readonly int[] _bufferSizesForGet;
|
||||
|
||||
public VertexBufferUpdater(VulkanRenderer gd)
|
||||
{
|
||||
_gd = gd;
|
||||
@@ -28,13 +23,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_offsets = new NativeArray<ulong>(Constants.MaxVertexBuffers);
|
||||
_sizes = new NativeArray<ulong>(Constants.MaxVertexBuffers);
|
||||
_strides = new NativeArray<ulong>(Constants.MaxVertexBuffers);
|
||||
|
||||
_bufferAutos = new Auto<DisposableBuffer>[Constants.MaxVertexBuffers];
|
||||
_bufferOffsetsForGet = new int[Constants.MaxVertexBuffers];
|
||||
_bufferSizesForGet = new int[Constants.MaxVertexBuffers];
|
||||
}
|
||||
|
||||
public void BindVertexBuffer(CommandBufferScoped cbs, uint binding, Auto<DisposableBuffer> autoBuffer, int offset, int size, ulong stride)
|
||||
public void BindVertexBuffer(CommandBufferScoped cbs, uint binding, VkBuffer buffer, ulong offset, ulong size, ulong stride)
|
||||
{
|
||||
if (_count == 0)
|
||||
{
|
||||
@@ -48,11 +39,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
int index = (int)_count;
|
||||
|
||||
_bufferAutos[index] = autoBuffer;
|
||||
_bufferOffsetsForGet[index] = offset;
|
||||
_bufferSizesForGet[index] = size;
|
||||
_offsets[index] = (ulong)offset;
|
||||
_sizes[index] = (ulong)size;
|
||||
_buffers[index] = buffer;
|
||||
_offsets[index] = offset;
|
||||
_sizes[index] = size;
|
||||
_strides[index] = stride;
|
||||
|
||||
_count++;
|
||||
@@ -62,65 +51,23 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
if (_count != 0)
|
||||
{
|
||||
int count = (int)_count;
|
||||
uint baseBinding = _baseBinding;
|
||||
if (_gd.Capabilities.SupportsExtendedDynamicState)
|
||||
{
|
||||
_gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
|
||||
cbs.CommandBuffer,
|
||||
_baseBinding,
|
||||
_count,
|
||||
_buffers.Pointer,
|
||||
_offsets.Pointer,
|
||||
_sizes.Pointer,
|
||||
_strides.Pointer);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, _baseBinding, _count, _buffers.Pointer, _offsets.Pointer);
|
||||
}
|
||||
|
||||
_count = 0;
|
||||
|
||||
Auto<DisposableBuffer>[] autos = ArrayPool<Auto<DisposableBuffer>>.Shared.Rent(count);
|
||||
Span<int> getOffsets = stackalloc int[Constants.MaxVertexBuffers];
|
||||
Span<int> getSizes = stackalloc int[Constants.MaxVertexBuffers];
|
||||
Span<ulong> offsets = stackalloc ulong[Constants.MaxVertexBuffers];
|
||||
Span<ulong> sizes = stackalloc ulong[Constants.MaxVertexBuffers];
|
||||
Span<ulong> strides = stackalloc ulong[Constants.MaxVertexBuffers];
|
||||
Span<VkBuffer> buffers = stackalloc VkBuffer[Constants.MaxVertexBuffers];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
autos[i] = _bufferAutos[i];
|
||||
_bufferAutos[i] = null;
|
||||
getOffsets[i] = _bufferOffsetsForGet[i];
|
||||
getSizes[i] = _bufferSizesForGet[i];
|
||||
offsets[i] = _offsets[i];
|
||||
sizes[i] = _sizes[i];
|
||||
strides[i] = _strides[i];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
buffers[i] = autos[i].Get(cbs, getOffsets[i], getSizes[i]).Value;
|
||||
autos[i] = null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_buffers[i] = buffers[i];
|
||||
_offsets[i] = offsets[i];
|
||||
_sizes[i] = sizes[i];
|
||||
_strides[i] = strides[i];
|
||||
}
|
||||
|
||||
if (_gd.Capabilities.SupportsExtendedDynamicState)
|
||||
{
|
||||
_gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
|
||||
cbs.CommandBuffer,
|
||||
baseBinding,
|
||||
(uint)count,
|
||||
_buffers.Pointer,
|
||||
_offsets.Pointer,
|
||||
_sizes.Pointer,
|
||||
_strides.Pointer);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, baseBinding, (uint)count, _buffers.Pointer, _offsets.Pointer);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<Auto<DisposableBuffer>>.Shared.Return(autos, clearArray: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -494,8 +494,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
UniformBufferStandardLayout = supportedPhysicalDeviceVulkan12Features.UniformBufferStandardLayout,
|
||||
UniformAndStorageBuffer8BitAccess = supportedPhysicalDeviceVulkan12Features.UniformAndStorageBuffer8BitAccess,
|
||||
StorageBuffer8BitAccess = supportedPhysicalDeviceVulkan12Features.StorageBuffer8BitAccess,
|
||||
ShaderSampledImageArrayNonUniformIndexing = supportedPhysicalDeviceVulkan12Features.ShaderSampledImageArrayNonUniformIndexing,
|
||||
ShaderStorageImageArrayNonUniformIndexing = supportedPhysicalDeviceVulkan12Features.ShaderStorageImageArrayNonUniformIndexing,
|
||||
};
|
||||
|
||||
pExtendedFeatures = &featuresVk12;
|
||||
|
||||
@@ -435,8 +435,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState.ExtensionName),
|
||||
features2.Features.MultiViewport && !(IsMoltenVk && Vendor == Vendor.Amd), // Workaround for AMD on MoltenVK issue
|
||||
featuresRobustness2.NullDescriptor || IsMoltenVk,
|
||||
supportsPushDescriptors,
|
||||
IsMoltenVk ? 16 : propertiesPushDescriptor.MaxPushDescriptors, // In case an old version of MoltenVK is used, apply a limit to prevent vertex explosions.
|
||||
supportsPushDescriptors && !IsMoltenVk,
|
||||
propertiesPushDescriptor.MaxPushDescriptors,
|
||||
featuresPrimitiveTopologyListRestart.PrimitiveTopologyListRestart,
|
||||
featuresPrimitiveTopologyListRestart.PrimitiveTopologyPatchListRestart,
|
||||
supportsTransformFeedback,
|
||||
@@ -775,11 +775,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
supportsShaderBallot: false,
|
||||
supportsShaderBarrierDivergence: Vendor != Vendor.Intel,
|
||||
supportsShaderFloat64: Capabilities.SupportsShaderFloat64,
|
||||
|
||||
supportsShaderNonUniformIndexing:
|
||||
featuresVk12.ShaderSampledImageArrayNonUniformIndexing &&
|
||||
featuresVk12.ShaderStorageImageArrayNonUniformIndexing,
|
||||
supportsTextureGatherOffsets: features2.Features.ShaderImageGatherExtended,
|
||||
supportsTextureGatherOffsets: features2.Features.ShaderImageGatherExtended && !IsMoltenVk,
|
||||
supportsTextureShadowLod: false,
|
||||
supportsVertexStoreAndAtomics: features2.Features.VertexPipelineStoresAndAtomics,
|
||||
supportsViewportIndexVertexTessellation: featuresVk12.ShaderOutputViewportIndex,
|
||||
|
||||
@@ -391,12 +391,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
if (_effect != null)
|
||||
{
|
||||
_gd.FlushAllCommands();
|
||||
_gd.CommandBufferPool.Return(
|
||||
cbs,
|
||||
null,
|
||||
[PipelineStageFlags.ColorAttachmentOutputBit],
|
||||
null);
|
||||
_gd.FlushAllCommands();
|
||||
cbs.GetFence().Wait();
|
||||
cbs = _gd.CommandBufferPool.Rent();
|
||||
}
|
||||
@@ -455,8 +455,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ImageLayout.General,
|
||||
ImageLayout.PresentSrcKhr);
|
||||
|
||||
_gd.FlushAllCommands();
|
||||
|
||||
_gd.CommandBufferPool.Return(
|
||||
cbs,
|
||||
[_imageAvailableSemaphores[semaphoreIndex]],
|
||||
|
||||
@@ -14,10 +14,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" >
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
case AppletId.LibAppletOff:
|
||||
return new BrowserApplet();
|
||||
case AppletId.MiiEdit:
|
||||
Logger.Warning?.Print(LogClass.Application, $"Please use the Mii Editor inside Actions/Tools");
|
||||
Logger.Warning?.Print(LogClass.Application, $"Please use the MiiEdit inside File/Open Applet");
|
||||
return new DummyApplet(system);
|
||||
case AppletId.Cabinet:
|
||||
return new CabinetApplet(system);
|
||||
|
||||
@@ -246,21 +246,21 @@ namespace Ryujinx.HLE.HOS
|
||||
public void InitializeServices()
|
||||
{
|
||||
SmRegistry = new SmRegistry();
|
||||
SmServer = new ServerBase(KernelContext, "Sm", () => new IUserInterface(KernelContext, SmRegistry));
|
||||
SmServer = new ServerBase(KernelContext, "SmServer", () => new IUserInterface(KernelContext, SmRegistry));
|
||||
|
||||
// Wait until SM server thread is done with initialization,
|
||||
// only then doing connections to SM is safe.
|
||||
SmServer.InitDone.WaitOne();
|
||||
|
||||
BsdServer = new ServerBase(KernelContext, "Bsd");
|
||||
FsServer = new ServerBase(KernelContext, "Fs");
|
||||
HidServer = new ServerBase(KernelContext, "Hid");
|
||||
NvDrvServer = new ServerBase(KernelContext, "Nv");
|
||||
TimeServer = new ServerBase(KernelContext, "Time");
|
||||
ViServer = new ServerBase(KernelContext, "Vi:u");
|
||||
ViServerM = new ServerBase(KernelContext, "Vi:m");
|
||||
ViServerS = new ServerBase(KernelContext, "Vi:s");
|
||||
LdnServer = new ServerBase(KernelContext, "Ldn");
|
||||
BsdServer = new ServerBase(KernelContext, "BsdServer");
|
||||
FsServer = new ServerBase(KernelContext, "FsServer");
|
||||
HidServer = new ServerBase(KernelContext, "HidServer");
|
||||
NvDrvServer = new ServerBase(KernelContext, "NvservicesServer");
|
||||
TimeServer = new ServerBase(KernelContext, "TimeServer");
|
||||
ViServer = new ServerBase(KernelContext, "ViServerU");
|
||||
ViServerM = new ServerBase(KernelContext, "ViServerM");
|
||||
ViServerS = new ServerBase(KernelContext, "ViServerS");
|
||||
LdnServer = new ServerBase(KernelContext, "LdnServer");
|
||||
|
||||
StartNewServices();
|
||||
}
|
||||
@@ -286,7 +286,7 @@ namespace Ryujinx.HLE.HOS
|
||||
ProcessCreationFlags.Is64Bit |
|
||||
ProcessCreationFlags.PoolPartitionSystem;
|
||||
|
||||
ProcessCreationInfo creationInfo = new(service.Name, 1, 0, 0x8000000, 1, Flags, 0, 0);
|
||||
ProcessCreationInfo creationInfo = new("Service", 1, 0, 0x8000000, 1, Flags, 0, 0);
|
||||
|
||||
uint[] defaultCapabilities =
|
||||
[
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy
|
||||
@@ -45,35 +44,6 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(1)]
|
||||
// PushOutData(object<nn::am::service::IStorage>)
|
||||
public ResultCode PushOutData(ServiceCtx context)
|
||||
{
|
||||
IStorage appletData = GetObject<IStorage>(context, 0);
|
||||
|
||||
if (appletData == null || appletData.Data.Length == 0) // is this necessary?
|
||||
{
|
||||
return ResultCode.NullObject;
|
||||
}
|
||||
|
||||
_appletStandalone.InputData.Enqueue(appletData.Data);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(10)]
|
||||
// ExitProcessAndReturn -> nn::am::service::LibraryAppletInfo
|
||||
public ResultCode ExitProcessAndReturn(ServiceCtx context)
|
||||
{
|
||||
// Exits the LibraryApplet and returns to running the title which launched this LibraryApplet (qlaunch for example).
|
||||
// On success, official sw will enter an infinite loop with sleep-thread value 86400000000000.
|
||||
// Since we don't currently support qlaunch, it's fine to stub it.
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.Service);
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
|
||||
[CommandCmif(11)]
|
||||
// GetLibraryAppletInfo() -> nn::am::service::LibraryAppletInfo
|
||||
@@ -97,8 +67,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
||||
AppletIdentifyInfo appletIdentifyInfo = new()
|
||||
{
|
||||
AppletId = AppletId.QLaunch,
|
||||
// 0x4 padding
|
||||
TitleId = 0x0100000000001000, // qlaunch systemAppletMenu title ID
|
||||
TitleId = 0x0100000000001000,
|
||||
};
|
||||
|
||||
context.ResponseData.WriteStruct(appletIdentifyInfo);
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.HLE.HOS.Services.Caps.Types;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -11,20 +9,16 @@ using System.Security.Cryptography;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Caps
|
||||
{
|
||||
internal class CaptureManager
|
||||
class CaptureManager
|
||||
{
|
||||
public CaptureManager(Switch device)
|
||||
{
|
||||
_ = device;
|
||||
}
|
||||
private readonly string _sdCardPath = FileSystem.VirtualFileSystem.GetSdCardPath();
|
||||
private readonly string _sdCardPath;
|
||||
|
||||
private uint _shimLibraryVersion;
|
||||
|
||||
private const int ScreenshotWidth = 1280;
|
||||
private const int ScreenshotHeight = 720;
|
||||
private const int ScreenshotBytesPerPixel = 4;
|
||||
private const int ScreenshotDataSize = ScreenshotWidth * ScreenshotHeight * ScreenshotBytesPerPixel; // 0x384000
|
||||
public CaptureManager(Switch device)
|
||||
{
|
||||
_sdCardPath = FileSystem.VirtualFileSystem.GetSdCardPath();
|
||||
}
|
||||
|
||||
public ResultCode SetShimLibraryVersion(ServiceCtx context)
|
||||
{
|
||||
@@ -59,94 +53,81 @@ namespace Ryujinx.HLE.HOS.Services.Caps
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
public ResultCode SaveScreenShot(
|
||||
byte[] screenshotData,
|
||||
ulong appletResourceUserId,
|
||||
ulong titleId,
|
||||
out ApplicationAlbumEntry applicationAlbumEntry)
|
||||
public ResultCode SaveScreenShot(byte[] screenshotData, ulong appletResourceUserId, ulong titleId, out ApplicationAlbumEntry applicationAlbumEntry)
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceCaps, new
|
||||
{
|
||||
appletResourceUserId,
|
||||
titleId,
|
||||
screenshotDataLength = screenshotData?.Length ?? 0,
|
||||
});
|
||||
|
||||
applicationAlbumEntry = default;
|
||||
|
||||
if (screenshotData == null || screenshotData.Length == 0)
|
||||
if (screenshotData.Length == 0)
|
||||
{
|
||||
return ResultCode.NullInputBuffer;
|
||||
}
|
||||
|
||||
if (screenshotData.Length < ScreenshotDataSize)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(
|
||||
LogClass.ServiceCaps,
|
||||
$"Invalid screenshot buffer size 0x{screenshotData.Length:X}; expected at least 0x{ScreenshotDataSize:X}.");
|
||||
|
||||
return ResultCode.NullInputBuffer;
|
||||
}
|
||||
|
||||
DateTime currentDateTime = DateTime.Now;
|
||||
|
||||
applicationAlbumEntry = new ApplicationAlbumEntry()
|
||||
{
|
||||
Size = (ulong)Unsafe.SizeOf<ApplicationAlbumEntry>(),
|
||||
TitleId = titleId,
|
||||
AlbumFileDateTime = new AlbumFileDateTime()
|
||||
{
|
||||
Year = (ushort)currentDateTime.Year,
|
||||
Month = (byte)currentDateTime.Month,
|
||||
Day = (byte)currentDateTime.Day,
|
||||
Hour = (byte)currentDateTime.Hour,
|
||||
Minute = (byte)currentDateTime.Minute,
|
||||
Second = (byte)currentDateTime.Second,
|
||||
UniqueId = 0,
|
||||
},
|
||||
AlbumStorage = AlbumStorage.Sd,
|
||||
ContentType = ContentType.Screenshot,
|
||||
Padding = new Array5<byte>(),
|
||||
Unknown0x1f = 1,
|
||||
};
|
||||
|
||||
// NOTE: The hex hash is a HMAC-SHA256 (first 32 bytes) using a hardcoded secret key over the titleId, we can simulate it by hashing the titleId instead.
|
||||
string hash = Convert.ToHexString(SHA256.HashData(BitConverter.GetBytes(titleId)))[..0x20];
|
||||
|
||||
string folderPath = Path.Combine(
|
||||
_sdCardPath,
|
||||
"Nintendo",
|
||||
"Album",
|
||||
currentDateTime.Year.ToString("0000", CultureInfo.InvariantCulture),
|
||||
currentDateTime.Month.ToString("00", CultureInfo.InvariantCulture),
|
||||
currentDateTime.Day.ToString("00", CultureInfo.InvariantCulture));
|
||||
|
||||
string filePath = GenerateFilePath(folderPath, applicationAlbumEntry, currentDateTime, hash);
|
||||
|
||||
_ = Directory.CreateDirectory(folderPath);
|
||||
|
||||
while (File.Exists(filePath))
|
||||
{
|
||||
applicationAlbumEntry.AlbumFileDateTime.UniqueId++;
|
||||
filePath = GenerateFilePath(folderPath, applicationAlbumEntry, currentDateTime, hash);
|
||||
}
|
||||
|
||||
using SKBitmap bitmap = new(new SKImageInfo(ScreenshotWidth, ScreenshotHeight, SKColorType.Rgba8888));
|
||||
|
||||
nint pixels = bitmap.GetPixels();
|
||||
|
||||
if (pixels == 0)
|
||||
/*
|
||||
// NOTE: On our current implementation, appletResourceUserId starts at 0, disable it for now.
|
||||
if (appletResourceUserId == 0)
|
||||
{
|
||||
return ResultCode.InvalidArgument;
|
||||
}
|
||||
*/
|
||||
|
||||
Marshal.Copy(screenshotData, 0, pixels, ScreenshotDataSize);
|
||||
/*
|
||||
// Doesn't occur in our case.
|
||||
if (applicationAlbumEntry == null)
|
||||
{
|
||||
return ResultCode.NullOutputBuffer;
|
||||
}
|
||||
*/
|
||||
|
||||
using SKData data = bitmap.Encode(SKEncodedImageFormat.Jpeg, 80);
|
||||
using FileStream file = File.OpenWrite(filePath);
|
||||
data.SaveTo(file);
|
||||
if (screenshotData.Length >= 0x384000)
|
||||
{
|
||||
DateTime currentDateTime = DateTime.Now;
|
||||
|
||||
return ResultCode.Success;
|
||||
applicationAlbumEntry = new ApplicationAlbumEntry()
|
||||
{
|
||||
Size = (ulong)Unsafe.SizeOf<ApplicationAlbumEntry>(),
|
||||
TitleId = titleId,
|
||||
AlbumFileDateTime = new AlbumFileDateTime()
|
||||
{
|
||||
Year = (ushort)currentDateTime.Year,
|
||||
Month = (byte)currentDateTime.Month,
|
||||
Day = (byte)currentDateTime.Day,
|
||||
Hour = (byte)currentDateTime.Hour,
|
||||
Minute = (byte)currentDateTime.Minute,
|
||||
Second = (byte)currentDateTime.Second,
|
||||
UniqueId = 0,
|
||||
},
|
||||
AlbumStorage = AlbumStorage.Sd,
|
||||
ContentType = ContentType.Screenshot,
|
||||
Padding = new Array5<byte>(),
|
||||
Unknown0x1f = 1,
|
||||
};
|
||||
|
||||
// NOTE: The hex hash is a HMAC-SHA256 (first 32 bytes) using a hardcoded secret key over the titleId, we can simulate it by hashing the titleId instead.
|
||||
string hash = Convert.ToHexString(SHA256.HashData(BitConverter.GetBytes(titleId)))[..0x20];
|
||||
string folderPath = Path.Combine(_sdCardPath, "Nintendo", "Album", currentDateTime.Year.ToString("00"), currentDateTime.Month.ToString("00"), currentDateTime.Day.ToString("00"));
|
||||
string filePath = GenerateFilePath(folderPath, applicationAlbumEntry, currentDateTime, hash);
|
||||
|
||||
// TODO: Handle that using the FS service implementation and return the right error code instead of throwing exceptions.
|
||||
Directory.CreateDirectory(folderPath);
|
||||
|
||||
while (File.Exists(filePath))
|
||||
{
|
||||
applicationAlbumEntry.AlbumFileDateTime.UniqueId++;
|
||||
|
||||
filePath = GenerateFilePath(folderPath, applicationAlbumEntry, currentDateTime, hash);
|
||||
}
|
||||
|
||||
// NOTE: The saved JPEG file doesn't have the limitation in the extra EXIF data.
|
||||
using SKBitmap bitmap = new(new SKImageInfo(1280, 720, SKColorType.Rgba8888));
|
||||
Marshal.Copy(screenshotData, 0, bitmap.GetPixels(), screenshotData.Length);
|
||||
using SKData data = bitmap.Encode(SKEncodedImageFormat.Jpeg, 80);
|
||||
using FileStream file = File.OpenWrite(filePath);
|
||||
data.SaveTo(file);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
return ResultCode.NullInputBuffer;
|
||||
}
|
||||
|
||||
private string GenerateFilePath(string folderPath, ApplicationAlbumEntry applicationAlbumEntry, DateTime currentDateTime, string hash)
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Services.Caps.Types;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Caps
|
||||
{
|
||||
[Service("caps:su")] // 6.0.0+
|
||||
internal class IScreenShotApplicationService : IpcService
|
||||
class IScreenShotApplicationService : IpcService
|
||||
{
|
||||
private const ulong ScreenshotDataSize = 0x384000;
|
||||
private const ulong ApplicationDataSize = 0x404;
|
||||
public IScreenShotApplicationService(ServiceCtx context) { }
|
||||
|
||||
public IScreenShotApplicationService(ServiceCtx context)
|
||||
{
|
||||
_ = context;
|
||||
}
|
||||
[CommandCmif(32)] // 7.0.0+
|
||||
// SetShimLibraryVersion(pid, u64, nn::applet::AppletResourceUserId)
|
||||
public ResultCode SetShimLibraryVersion(ServiceCtx context)
|
||||
@@ -39,15 +33,6 @@ namespace Ryujinx.HLE.HOS.Services.Caps
|
||||
ulong screenshotDataPosition = context.Request.SendBuff[0].Position;
|
||||
ulong screenshotDataSize = context.Request.SendBuff[0].Size;
|
||||
|
||||
if (screenshotDataSize < ScreenshotDataSize)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(
|
||||
LogClass.ServiceCaps,
|
||||
$"Invalid screenshot buffer size 0x{screenshotDataSize:X}; expected at least 0x{ScreenshotDataSize:X}.");
|
||||
|
||||
return ResultCode.NullInputBuffer;
|
||||
}
|
||||
|
||||
byte[] screenshotData = context.Memory.GetSpan(screenshotDataPosition, (int)screenshotDataSize, true).ToArray();
|
||||
|
||||
ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.ActiveApplication.ProgramId, out ApplicationAlbumEntry applicationAlbumEntry);
|
||||
@@ -75,24 +60,6 @@ namespace Ryujinx.HLE.HOS.Services.Caps
|
||||
ulong screenshotDataPosition = context.Request.SendBuff[1].Position;
|
||||
ulong screenshotDataSize = context.Request.SendBuff[1].Size;
|
||||
|
||||
if (applicationDataSize != ApplicationDataSize)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(
|
||||
LogClass.ServiceCaps,
|
||||
$"Invalid ApplicationData size 0x{applicationDataSize:X}; expected 0x{ApplicationDataSize:X}.");
|
||||
|
||||
return ResultCode.InvalidArgument;
|
||||
}
|
||||
|
||||
if (screenshotDataSize < ScreenshotDataSize)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(
|
||||
LogClass.ServiceCaps,
|
||||
$"Invalid screenshot buffer size 0x{screenshotDataSize:X}; expected at least 0x{ScreenshotDataSize:X}.");
|
||||
|
||||
return ResultCode.NullInputBuffer;
|
||||
}
|
||||
|
||||
// TODO: Parse the application data: At 0x00 it's UserData (Size of 0x400), at 0x404 it's a uint UserDataSize (Always empty for now).
|
||||
_ = context.Memory.GetSpan(applicationDataPosition, (int)applicationDataSize).ToArray();
|
||||
|
||||
@@ -121,23 +88,6 @@ namespace Ryujinx.HLE.HOS.Services.Caps
|
||||
ulong screenshotDataPosition = context.Request.SendBuff[1].Position;
|
||||
ulong screenshotDataSize = context.Request.SendBuff[1].Size;
|
||||
|
||||
if (userIdListSize != 0x88)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(
|
||||
LogClass.ServiceCaps,
|
||||
$"Invalid UserIdList size 0x{userIdListSize:X}; expected 0x88.");
|
||||
return ResultCode.InvalidArgument;
|
||||
}
|
||||
|
||||
if (screenshotDataSize < ScreenshotDataSize)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(
|
||||
LogClass.ServiceCaps,
|
||||
$"Invalid screenshot buffer size 0x{screenshotDataSize:X}; expected at least 0x{ScreenshotDataSize:X}.");
|
||||
|
||||
return ResultCode.NullInputBuffer;
|
||||
}
|
||||
|
||||
// TODO: Parse the UserIdList.
|
||||
_ = context.Memory.GetSpan(userIdListPosition, (int)userIdListSize).ToArray();
|
||||
|
||||
|
||||
@@ -584,13 +584,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
|
||||
public bool isAtRest(int playerNumber)
|
||||
{
|
||||
ref NpadInternalState currentNpad = ref _device.Hid.SharedMemory.Npads[playerNumber].InternalState;
|
||||
|
||||
if (currentNpad.StyleSet == NpadStyleTag.None)
|
||||
{
|
||||
return true; // it will always be at rest because it cannot move.
|
||||
}
|
||||
|
||||
ref NpadInternalState currentNpad = ref _device.Hid.SharedMemory.Npads[playerNumber].InternalState;
|
||||
ref SixAxisSensorState storage = ref GetSixAxisSensorLifo(ref currentNpad, false).GetCurrentEntryRef();
|
||||
|
||||
float acceleration = Math.Abs(storage.Acceleration.X)
|
||||
|
||||
@@ -5,6 +5,7 @@ using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Ldn.Types;
|
||||
@@ -14,6 +15,7 @@ using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.Types;
|
||||
using Ryujinx.Horizon.Common;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
@@ -66,11 +68,10 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (localCommunicationId == localCommunicationIdChecked)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn,"CheckLocalCommumicationIdPermission: Checked!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn,"CheckLocalCommumicationIdPermission: Check failed!");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -81,7 +82,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
context.ResponseData.Write((int)NetworkState.Error);
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn,$"GetState: _nifmResultCode = {_nifmResultCode.ToString()}");
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
@@ -113,14 +114,12 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn,$"GetNetworkInfo: _nifmResultCode = {_nifmResultCode.ToString()}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
ResultCode resultCode = GetNetworkInfoImpl(out NetworkInfo networkInfo);
|
||||
if (resultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn,$"GetState: resultCode = {resultCode.ToString()}");
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
@@ -136,22 +135,18 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
if (_state == NetworkState.StationConnected)
|
||||
{
|
||||
networkInfo = _station.NetworkInfo;
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn,"GetNetworkInfoImpl: _station");
|
||||
}
|
||||
else if (_state == NetworkState.AccessPointCreated)
|
||||
{
|
||||
networkInfo = _accessPoint.NetworkInfo;
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn,"GetNetworkInfoImpl: _accessPoint");
|
||||
}
|
||||
else
|
||||
{
|
||||
networkInfo = new NetworkInfo();
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn,"GetNetworkInfoImpl: Invalid state!");
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn,$"GetNetworkInfoImpl: networkInfo = {networkInfo}");
|
||||
|
||||
return ResultCode.InvalidState;
|
||||
}
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn,$"GetNetworkInfoImpl: networkInfo = {networkInfo}");
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
@@ -203,7 +198,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.NetLog?.Print(LogClass.ServiceLdn, $"Console's LDN IP is \"{unicastAddress.Address}\".");
|
||||
Logger.Info?.Print(LogClass.ServiceLdn, $"Console's LDN IP is \"{unicastAddress.Address}\".");
|
||||
|
||||
context.ResponseData.Write(NetworkHelpers.ConvertIpv4Address(unicastAddress.Address));
|
||||
context.ResponseData.Write(NetworkHelpers.ConvertIpv4Address(unicastAddress.IPv4Mask));
|
||||
@@ -211,7 +206,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.NetLog?.Print(LogClass.ServiceLdn, $"LDN obtained proxy IP.");
|
||||
Logger.Info?.Print(LogClass.ServiceLdn, $"LDN obtained proxy IP.");
|
||||
|
||||
context.ResponseData.Write(config.ProxyIp);
|
||||
context.ResponseData.Write(config.ProxySubnetMask);
|
||||
@@ -232,7 +227,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
// NOTE: Returns ResultCode.InvalidArgument if _disconnectReason is null, doesn't occur in our case.
|
||||
|
||||
context.ResponseData.Write((short)_disconnectReason);
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"GetDisconnectReason: {_disconnectReason}");
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
@@ -252,14 +247,12 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"GetSecurityParameter: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
ResultCode resultCode = GetNetworkInfoImpl(out NetworkInfo networkInfo);
|
||||
if (resultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"GetSecurityParameter: resultCode = {resultCode}");
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
@@ -270,8 +263,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
};
|
||||
|
||||
context.ResponseData.WriteStruct(securityParameter);
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"GetSecurityParameter: securityParameter = {securityParameter}");
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
@@ -281,14 +273,12 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"GetNetworkConfig: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
ResultCode resultCode = GetNetworkInfoImpl(out NetworkInfo networkInfo);
|
||||
if (resultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"GetNetworkConfig: resultCode = {resultCode}");
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
@@ -302,8 +292,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
};
|
||||
|
||||
context.ResponseData.WriteStruct(networkConfig);
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"GetNetworkConfig: networkConfig = {networkConfig}");
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
@@ -334,14 +322,12 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"GetNetworkInfoLatestUpdate: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
ResultCode resultCode = GetNetworkInfoImpl(out NetworkInfo networkInfo);
|
||||
if (resultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"GetNetworkInfoLatestUpdate: resultCode = {resultCode}");
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
@@ -392,7 +378,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"ScanImpl: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
@@ -415,7 +400,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (scanFilter.Ssid.Length <= 31)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"ScanImpl: resultCode = {resultCode}");
|
||||
return resultCode;
|
||||
}
|
||||
}
|
||||
@@ -424,13 +408,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (scanFilterFlag > ScanFilterFlag.All)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"ScanImpl: resultCode = {resultCode}");
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
if (_state - 3 >= NetworkState.AccessPoint)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "ScanImpl: Invalid state!");
|
||||
resultCode = ResultCode.InvalidState;
|
||||
}
|
||||
else
|
||||
@@ -455,8 +437,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"ScanImpl: resultCode = {resultCode}");
|
||||
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
@@ -481,7 +462,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
}
|
||||
}
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"ScanInternal: availableGames = {availableGames}");
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
@@ -522,8 +502,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
throw new ArgumentException($"{GetType().FullName}: Protocol value is not 1 or 3!! Protocol value: {protocolValue}");
|
||||
}
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"SetProtocol: protocolValue = {protocolValue}");
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceLdn, new { protocolValue});
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceLdn, $"Protocol value: {protocolValue}");
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
@@ -533,13 +512,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"OpenAccessPoint: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
if (_state != NetworkState.Initialized)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "OpenAccessPoint: Invalid state!");
|
||||
return ResultCode.InvalidState;
|
||||
}
|
||||
|
||||
@@ -561,7 +538,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"CloseAccessPoint: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
@@ -571,7 +547,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "CloseAccessPoint: Invalid state!");
|
||||
return ResultCode.InvalidState;
|
||||
}
|
||||
|
||||
@@ -621,13 +596,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
bool isLocalCommunicationIdValid = CheckLocalCommunicationIdPermission(context, (ulong)networkConfig.IntentId.LocalCommunicationId);
|
||||
if (!isLocalCommunicationIdValid && NetworkClient.NeedsRealId)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "CreateNetworkImpl: Invalid object!");
|
||||
return ResultCode.InvalidObject;
|
||||
}
|
||||
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"CreateNetworkImpl: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
@@ -656,22 +629,16 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
AddressList addressList = MemoryMarshal.Cast<byte, AddressList>(addressListBytes)[0];
|
||||
|
||||
_accessPoint.CreateNetworkPrivate(securityConfig, securityParameter, userConfig, networkConfig, addressList);
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"CreateNetworkImpl: Created private network! " +
|
||||
$"| securityConfig = {securityConfig} | securityParameter = {securityParameter} " +
|
||||
$"| userConfig = {userConfig} | networkConfig = {networkConfig} | addressList = {addressList}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_accessPoint.CreateNetwork(securityConfig, userConfig, networkConfig);
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"CreateNetworkImpl: Created network! " +
|
||||
$"| securityConfig = {securityConfig} | userConfig = {userConfig} | networkConfig = {networkConfig}");
|
||||
}
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "CreateNetworkImpl: Invalid state!");
|
||||
return ResultCode.InvalidState;
|
||||
}
|
||||
}
|
||||
@@ -693,7 +660,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"DestroyNetworkImpl: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
@@ -710,11 +676,9 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
|
||||
CloseAccessPoint();
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "DestroyNetworkImpl: Invalid state!");
|
||||
return ResultCode.InvalidState;
|
||||
}
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "DestroyNetworkImpl: Invalid argument!");
|
||||
return ResultCode.InvalidArgument;
|
||||
}
|
||||
|
||||
@@ -731,17 +695,14 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"RejectImpl: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
if (_state != NetworkState.AccessPointCreated)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "RejectImpl: Invalid state!");
|
||||
return ResultCode.InvalidState; // Must be network host to reject nodes.
|
||||
}
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"RejectImpl: disconnectReason = {disconnectReason} | nodeId = {nodeId}");
|
||||
return NetworkClient.Reject(disconnectReason, nodeId);
|
||||
}
|
||||
|
||||
@@ -753,13 +714,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"SetAdvertiseData: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
if (bufferSize is 0 or > LdnConst.AdvertiseDataSizeMax)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "SetAdvertiseData: Invalid argument!");
|
||||
return ResultCode.InvalidArgument;
|
||||
}
|
||||
|
||||
@@ -768,12 +727,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
byte[] advertiseData = new byte[bufferSize];
|
||||
|
||||
context.Memory.Read(bufferPosition, advertiseData);
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"SetAdvertiseData: advertiseData = {advertiseData}");
|
||||
|
||||
return _accessPoint.SetAdvertiseData(advertiseData);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "SetAdvertiseData: Invalid state!");
|
||||
return ResultCode.InvalidState;
|
||||
}
|
||||
}
|
||||
@@ -786,24 +744,20 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"SetStationAcceptPolicy: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
if (acceptPolicy > AcceptPolicy.WhiteList)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "SetStationAcceptPolicy: Invalid argument!");
|
||||
return ResultCode.InvalidArgument;
|
||||
}
|
||||
|
||||
if (_state is NetworkState.AccessPoint or NetworkState.AccessPointCreated)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"SetStationAcceptPolicy: acceptPolicy = {acceptPolicy}");
|
||||
return _accessPoint.SetStationAcceptPolicy(acceptPolicy);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "SetStationAcceptPolicy: Invalid state!");
|
||||
return ResultCode.InvalidState;
|
||||
}
|
||||
}
|
||||
@@ -814,7 +768,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"AddAcceptFilterEntry: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
@@ -829,7 +782,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"ClearAcceptFilter: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
@@ -844,13 +796,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"OpenStation: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
if (_state != NetworkState.Initialized)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "OpenStation: Invalid state!");
|
||||
return ResultCode.InvalidState;
|
||||
}
|
||||
|
||||
@@ -863,8 +813,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
|
||||
// NOTE: Calls nifm service and returns related result codes.
|
||||
// Since we use our own implementation we can return ResultCode.Success.
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"OpenStation: _station = {_station}");
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
@@ -875,7 +823,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"CloseStation: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
@@ -885,13 +832,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "CloseStation: Invalid state!");
|
||||
return ResultCode.InvalidState;
|
||||
}
|
||||
|
||||
SetState(NetworkState.Initialized);
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "CloseStation: Closed.");
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
@@ -956,13 +901,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
bool isLocalCommunicationIdValid = CheckLocalCommunicationIdPermission(context, (ulong)networkInfo.NetworkId.IntentId.LocalCommunicationId);
|
||||
if (!isLocalCommunicationIdValid && NetworkClient.NeedsRealId)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "ConnectImpl: Invalid object!");
|
||||
return ResultCode.InvalidObject;
|
||||
}
|
||||
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"ConnectImpl: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
@@ -982,7 +925,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_state != NetworkState.Station)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "ConnectImpl: Invalid state!");
|
||||
resultCode = ResultCode.InvalidState;
|
||||
}
|
||||
else
|
||||
@@ -990,16 +932,10 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
if (isPrivate)
|
||||
{
|
||||
resultCode = _station.ConnectPrivate(securityConfig, securityParameter, userConfig, localCommunicationVersion, optionUnknown, networkConfig);
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"ConnectImpl: Private connection established! " +
|
||||
$"| securityConfig = {securityConfig} | securityParameter = {securityParameter} | userConfig = {userConfig} " +
|
||||
$"| localCommunicationVersion = {localCommunicationVersion} | optionUnknown = {optionUnknown} | networkConfig = {networkConfig}");
|
||||
}
|
||||
else
|
||||
{
|
||||
resultCode = _station.Connect(securityConfig, userConfig, localCommunicationVersion, optionUnknown, networkInfo);
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"ConnectImpl: Connection established! " +
|
||||
$"| securityConfig = {securityConfig} | userConfig = {userConfig} " +
|
||||
$"| localCommunicationVersion = {localCommunicationVersion} | optionUnknown = {optionUnknown} | networkConfig = {networkConfig}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1007,8 +943,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
}
|
||||
}
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"ConnectImpl: resultCode = {resultCode}");
|
||||
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
@@ -1023,7 +957,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"DisconnectImpl: _nifmResultCode = {_nifmResultCode}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
@@ -1037,17 +970,14 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
|
||||
_disconnectReason = disconnectReason;
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"DisconnectImpl: _disconnectReason = {_disconnectReason}");
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
CloseStation();
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "DisconnectImpl: Invalid state!");
|
||||
return ResultCode.InvalidState;
|
||||
}
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "DisconnectImpl: Invalid argument!");
|
||||
return ResultCode.InvalidArgument;
|
||||
}
|
||||
|
||||
@@ -1064,7 +994,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"Finalize: _disconnectReason = {_disconnectReason}");
|
||||
return _nifmResultCode;
|
||||
}
|
||||
|
||||
@@ -1081,13 +1010,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
_stateChangeEventHandle = 0;
|
||||
}
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"Finalize: resultCode = {resultCode}");
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
private ResultCode FinalizeImpl(bool isCausedBySystem)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "FinalizeImpl");
|
||||
DisconnectReason disconnectReason;
|
||||
|
||||
switch (_state)
|
||||
@@ -1211,6 +1138,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
NetworkClient.SetGameVersion(context.Device.Processes.ActiveApplication.ApplicationControlProperties.DisplayVersion);
|
||||
|
||||
resultCode = ResultCode.Success;
|
||||
|
||||
_nifmResultCode = resultCode;
|
||||
|
||||
SetState(NetworkState.Initialized);
|
||||
@@ -1224,7 +1152,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
}
|
||||
}
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"InitializeImpl: resultCode = {resultCode}");
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu
|
||||
|
||||
protected override void OnConnected()
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"LDN TCP client connected a new session with Id {Id}");
|
||||
Logger.Info?.PrintMsg(LogClass.ServiceLdn, $"LDN TCP client connected a new session with Id {Id}");
|
||||
|
||||
UpdatePassphraseIfNeeded();
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu
|
||||
|
||||
protected override void OnDisconnected()
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"LDN TCP client disconnected a session with Id {Id}");
|
||||
Logger.Info?.PrintMsg(LogClass.ServiceLdn, $"LDN TCP client disconnected a session with Id {Id}");
|
||||
|
||||
_passphrase = null;
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu
|
||||
|
||||
protected override void OnError(SocketError error)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, $"LDN TCP client caught an error with code {error}");
|
||||
Logger.Info?.PrintMsg(LogClass.ServiceLdn, $"LDN TCP client caught an error with code {error}");
|
||||
|
||||
_error.Set();
|
||||
}
|
||||
@@ -428,7 +428,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.NetLog?.Print(LogClass.ServiceLdn, $"Created a wireless P2P network on port {request.ExternalProxyPort}.");
|
||||
Logger.Info?.Print(LogClass.ServiceLdn, $"Created a wireless P2P network on port {request.ExternalProxyPort}.");
|
||||
_hostedProxy.Start();
|
||||
|
||||
(_, UnicastIPAddressInformation unicastAddress) = NetworkHelpers.GetLocalInterface();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.HLE.HOS.Services.Ldn.Types;
|
||||
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.Types;
|
||||
@@ -37,12 +36,10 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
if (Connected)
|
||||
{
|
||||
_parent.SetState(NetworkState.StationConnected);
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn,$"NetworkChanged: {NetworkInfo}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_parent.SetDisconnectReason(e.DisconnectReasonOrDefault(DisconnectReason.DestroyedByUser));
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn,"NetworkChanged: Disconnected (DestroyedByUser)");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -81,10 +81,8 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public ResultCode UpdateLatest<T>(DatabaseSessionMetadata metadata, T oldMiiData, SourceFlag flag, out T newMiiData) where T : unmanaged, IStoredData<T>
|
||||
public ResultCode UpdateLatest<T>(DatabaseSessionMetadata metadata, IStoredData<T> oldMiiData, SourceFlag flag, IStoredData<T> newMiiData) where T : unmanaged
|
||||
{
|
||||
newMiiData = default;
|
||||
|
||||
if (!flag.HasFlag(SourceFlag.Database))
|
||||
{
|
||||
return ResultCode.NotFound;
|
||||
@@ -108,7 +106,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
||||
|
||||
newMiiData.SetFromStoreData(storeData);
|
||||
|
||||
if (oldMiiData.Equals(newMiiData))
|
||||
if (oldMiiData == newMiiData)
|
||||
{
|
||||
return ResultCode.NotUpdated;
|
||||
}
|
||||
@@ -288,18 +286,6 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
||||
return result;
|
||||
}
|
||||
|
||||
public ResultCode Append(DatabaseSessionMetadata metadata, CharInfo charInfo)
|
||||
{
|
||||
ResultCode result = _miiDatabase.Append(metadata, _utilityImpl, charInfo);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
result = _miiDatabase.SaveDatabase();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ResultCode ConvertCharInfoToCoreData(CharInfo charInfo, out CoreData coreData)
|
||||
{
|
||||
coreData = new CoreData();
|
||||
|
||||
@@ -449,32 +449,6 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public ResultCode Append(DatabaseSessionMetadata metadata, UtilityImpl utilityImpl, CharInfo charInfo)
|
||||
{
|
||||
if (!charInfo.IsValid())
|
||||
{
|
||||
return ResultCode.InvalidCharInfo;
|
||||
}
|
||||
|
||||
if (charInfo.Type == 1)
|
||||
{
|
||||
return ResultCode.InvalidOperationOnSpecialMii;
|
||||
}
|
||||
|
||||
CoreData coreData = new();
|
||||
coreData.SetFromCharInfo(charInfo);
|
||||
|
||||
StoreData storeData;
|
||||
|
||||
do
|
||||
{
|
||||
storeData = StoreData.BuildFromCoreData(utilityImpl, coreData);
|
||||
}
|
||||
while (_database.GetIndexByCreatorId(out _, storeData.CreateId));
|
||||
|
||||
return AddOrReplace(metadata, storeData);
|
||||
}
|
||||
|
||||
public ResultCode Delete(DatabaseSessionMetadata metadata, CreateId createId)
|
||||
{
|
||||
if (!_database.GetIndexByCreatorId(out int index, createId))
|
||||
|
||||
@@ -54,7 +54,9 @@ namespace Ryujinx.HLE.HOS.Services.Mii.StaticService
|
||||
|
||||
protected override ResultCode UpdateLatest(CharInfo oldCharInfo, SourceFlag flag, out CharInfo newCharInfo)
|
||||
{
|
||||
return _database.UpdateLatest(_metadata, oldCharInfo, flag, out newCharInfo);
|
||||
newCharInfo = default;
|
||||
|
||||
return _database.UpdateLatest(_metadata, oldCharInfo, flag, newCharInfo);
|
||||
}
|
||||
|
||||
protected override ResultCode BuildRandom(Age age, Gender gender, Race race, out CharInfo charInfo)
|
||||
@@ -111,14 +113,14 @@ namespace Ryujinx.HLE.HOS.Services.Mii.StaticService
|
||||
|
||||
protected override ResultCode UpdateLatest1(StoreData oldStoreData, SourceFlag flag, out StoreData newStoreData)
|
||||
{
|
||||
newStoreData = default;
|
||||
|
||||
if (!_isSystem)
|
||||
{
|
||||
newStoreData = default;
|
||||
|
||||
return ResultCode.PermissionDenied;
|
||||
}
|
||||
|
||||
return _database.UpdateLatest(_metadata, oldStoreData, flag, out newStoreData);
|
||||
return _database.UpdateLatest(_metadata, oldStoreData, flag, newStoreData);
|
||||
}
|
||||
|
||||
protected override ResultCode FindIndex(CreateId createId, bool isSpecial, out int index)
|
||||
@@ -260,10 +262,5 @@ namespace Ryujinx.HLE.HOS.Services.Mii.StaticService
|
||||
{
|
||||
return _database.ConvertCharInfoToCoreData(charInfo, out coreData);
|
||||
}
|
||||
|
||||
protected override ResultCode Append(CharInfo charInfo)
|
||||
{
|
||||
return _database.Append(_metadata, charInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,15 +340,6 @@ namespace Ryujinx.HLE.HOS.Services.Mii.StaticService
|
||||
return result;
|
||||
}
|
||||
|
||||
[CommandCmif(26)] // 10.2.0+
|
||||
// Append(nn::mii::CharInfo char_info)
|
||||
public ResultCode Append(ServiceCtx context)
|
||||
{
|
||||
CharInfo charInfo = context.RequestData.ReadStruct<CharInfo>();
|
||||
|
||||
return Append(charInfo);
|
||||
}
|
||||
|
||||
private Span<byte> CreateByteSpanFromBuffer(ServiceCtx context, IpcBuffDesc ipcBuff, bool isOutput)
|
||||
{
|
||||
byte[] rawData;
|
||||
@@ -430,7 +421,5 @@ namespace Ryujinx.HLE.HOS.Services.Mii.StaticService
|
||||
protected abstract ResultCode ConvertCoreDataToCharInfo(CoreData coreData, out CharInfo charInfo);
|
||||
|
||||
protected abstract ResultCode ConvertCharInfoToCoreData(CharInfo charInfo, out CoreData coreData);
|
||||
|
||||
protected abstract ResultCode Append(CharInfo charInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Notification
|
||||
{
|
||||
[Service("notif:s")] // 9.0.0+
|
||||
class INotificationServices : IpcService
|
||||
{
|
||||
public INotificationServices(ServiceCtx context) { }
|
||||
|
||||
[CommandCmif(1000)] // 9.0.0+
|
||||
// GetNotificationCount() -> nn::notification::server::INotificationSystemEventAccessor
|
||||
public ResultCode GetNotificationCount(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new INotificationSystemEventAccessor(context));
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(1040)] // 9.0.0+
|
||||
// GetNotificationSendingNotifier() -> nn::notification::server::INotificationSystemEventAccessor
|
||||
public ResultCode GetNotificationSendingNotifier(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new INotificationSystemEventAccessor(context));
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,8 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Notification
|
||||
{
|
||||
[Service("notif:a")] // 9.0.0+
|
||||
class INotificationServicesForApplication : IpcService
|
||||
{
|
||||
public INotificationServicesForApplication(ServiceCtx context) { }
|
||||
|
||||
// Leaving this here since I can never find it: https://switchbrew.org/wiki/Glue_services
|
||||
|
||||
[CommandCmif(520)] // 9.0.0+
|
||||
// ListAlarmSettings(nn::arp::ApplicationCertificate) -> s32 AlarmSettingsCount
|
||||
public ResultCode ListAlarmSettings(ServiceCtx context)
|
||||
{
|
||||
// TO-DO: Currently just returns 0. Should read in an ApplicationCertificate.
|
||||
int alarmSettingsCount = 0;
|
||||
context.ResponseData.Write(alarmSettingsCount);
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(1000)] // 9.0.0+
|
||||
// Initialize(PID-descriptor, u64 pid_reserved)
|
||||
public ResultCode Intialize(ServiceCtx context)
|
||||
{
|
||||
ulong pid = context.Request.HandleDesc.PId;
|
||||
context.RequestData.ReadUInt64(); // pid placeholder, zero
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceNotification, new { pid });
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Notification
|
||||
{
|
||||
[Service("notif:s")] // 9.0.0+
|
||||
class INotificationServicesForSystem : IpcService
|
||||
{
|
||||
public INotificationServicesForSystem(ServiceCtx context) { }
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Horizon.Common;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Notification
|
||||
{
|
||||
class INotificationSystemEventAccessor : IpcService
|
||||
{
|
||||
|
||||
private readonly KEvent _getNotificationSendingNotifierEvent;
|
||||
private int _getNotificationSendingNotifierEventHandle;
|
||||
public INotificationSystemEventAccessor(ServiceCtx context) { }
|
||||
|
||||
[CommandCmif(0)] // 9.0.0+
|
||||
// GetNotificationSendingNotifier() -> nn::notification::server::INotificationSystemEventAccessor
|
||||
public ResultCode GetSystemEvent(ServiceCtx context)
|
||||
{
|
||||
if (_getNotificationSendingNotifierEventHandle == 0)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_getNotificationSendingNotifierEvent.ReadableEvent, out _getNotificationSendingNotifierEventHandle) != Result.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_getNotificationSendingNotifierEventHandle);
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,15 +79,9 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
ProcessCreationFlags.Is64Bit |
|
||||
ProcessCreationFlags.PoolPartitionSystem;
|
||||
|
||||
ProcessCreationInfo creationInfo = new(Name, 1, 0, 0x8000000, 1, Flags, 0, 0);
|
||||
ProcessCreationInfo creationInfo = new("Service", 1, 0, 0x8000000, 1, Flags, 0, 0);
|
||||
|
||||
KernelStatic.StartInitialProcess(context, creationInfo, DefaultCapabilities, 44, () =>
|
||||
{
|
||||
var currentThread = KernelStatic.GetCurrentThread();
|
||||
currentThread.HostThread.Name = $"{{{Name}}}";
|
||||
|
||||
Main();
|
||||
});
|
||||
KernelStatic.StartInitialProcess(context, creationInfo, DefaultCapabilities, 44, Main);
|
||||
}
|
||||
|
||||
private void AddPort(int serverPortHandle, Func<IpcService> objectFactory)
|
||||
|
||||
@@ -17,12 +17,13 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
||||
private static readonly Dictionary<string, Type> _services;
|
||||
|
||||
private readonly SmRegistry _registry;
|
||||
private ServerBase _commonServer;
|
||||
private readonly ServerBase _commonServer;
|
||||
|
||||
private bool _isInitialized;
|
||||
|
||||
public IUserInterface(KernelContext context, SmRegistry registry) : base(registerTipc: true)
|
||||
{
|
||||
_commonServer = new ServerBase(context, "CommonServer");
|
||||
_registry = registry;
|
||||
}
|
||||
|
||||
@@ -96,11 +97,6 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
||||
|
||||
IpcService service = GetServiceInstance(type, context, serviceAttribute.Parameter);
|
||||
|
||||
if (_commonServer is null)
|
||||
{
|
||||
_commonServer = new ServerBase(context.Device.System.KernelContext, "Common");
|
||||
}
|
||||
|
||||
service.TrySetServer(_commonServer);
|
||||
service.Server.AddSessionObj(session.ServerSession, service);
|
||||
}
|
||||
@@ -257,7 +253,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
||||
|
||||
public override void DestroyAtExit()
|
||||
{
|
||||
_commonServer?.Dispose();
|
||||
_commonServer.Dispose();
|
||||
|
||||
base.DestroyAtExit();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ using Ryujinx.HLE.Loaders.Executables;
|
||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Path = System.IO.Path;
|
||||
|
||||
@@ -28,64 +27,17 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
|
||||
private ulong _latestPid;
|
||||
|
||||
private readonly object _pidLock = new();
|
||||
|
||||
#nullable enable
|
||||
public ProcessResult? ActiveApplication
|
||||
public ProcessResult ActiveApplication
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_pidLock)
|
||||
{
|
||||
// Check if _latestPid is still valid
|
||||
if (_latestPid == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!_processesByPid.TryGetValue(_latestPid, out ProcessResult value))
|
||||
throw new RyujinxException(
|
||||
$"The HLE Process map did not have a process with ID {_latestPid}. Are you missing firmware?");
|
||||
|
||||
// Verify process still exists in kernel (authoritative source)
|
||||
if (!_device.System.KernelContext.Processes.TryGetValue(_latestPid, out HOS.Kernel.Process.KProcess? kernelProcess))
|
||||
{
|
||||
// Process no longer exists in kernel, clear stale state
|
||||
Logger.Warning?.Print(LogClass.Loader,
|
||||
$"ActiveApplication PID {_latestPid} no longer exists in kernel, clearing stale state");
|
||||
|
||||
_processesByPid.TryRemove(_latestPid, out _);
|
||||
_latestPid = 0;
|
||||
TitleIDs.CurrentApplication.Value = null;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Verify process still exists in ProcessLoader's dictionary
|
||||
if (_processesByPid.TryGetValue(_latestPid, out ProcessResult? processResult))
|
||||
{
|
||||
// Additional check: verify process state
|
||||
if (kernelProcess.State == HOS.Kernel.Process.ProcessState.Exited ||
|
||||
kernelProcess.State == HOS.Kernel.Process.ProcessState.Exiting)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Loader,
|
||||
$"ActiveApplication PID {_latestPid} is in state {kernelProcess.State}, clearing");
|
||||
|
||||
_processesByPid.TryRemove(_latestPid, out _);
|
||||
_latestPid = 0;
|
||||
TitleIDs.CurrentApplication.Value = null;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return processResult;
|
||||
}
|
||||
|
||||
// Fallback: clear stale PID if not in our dictionary
|
||||
Logger.Warning?.Print(LogClass.Loader,
|
||||
$"ActiveApplication PID {_latestPid} not in ProcessLoader dictionary, clearing");
|
||||
_latestPid = 0;
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
|
||||
public ProcessLoader(Switch device)
|
||||
{
|
||||
@@ -192,7 +144,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
public bool LoadUnpackedNca(string exeFsDirPath, string romFsPath = null)
|
||||
{
|
||||
ProcessResult processResult = new LocalFileSystem(exeFsDirPath).Load(_device, romFsPath);
|
||||
|
||||
|
||||
if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult))
|
||||
{
|
||||
if (processResult.Start(_device))
|
||||
@@ -325,39 +277,5 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears a specific process from the ProcessLoader's tracking.
|
||||
/// This should be called when a process exits or is terminated.
|
||||
/// </summary>
|
||||
/// <param name="pid">The process ID to clear</param>
|
||||
public void ClearProcess(ulong pid)
|
||||
{
|
||||
lock (_pidLock)
|
||||
{
|
||||
if (_processesByPid.TryRemove(pid, out _))
|
||||
{
|
||||
if (_latestPid == pid)
|
||||
{
|
||||
_latestPid = 0;
|
||||
TitleIDs.CurrentApplication.Value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all processes from the ProcessLoader's tracking.
|
||||
/// This should be called during system shutdown.
|
||||
/// </summary>
|
||||
public void ClearAllProcesses()
|
||||
{
|
||||
lock (_pidLock)
|
||||
{
|
||||
_processesByPid.Clear();
|
||||
_latestPid = 0;
|
||||
TitleIDs.CurrentApplication.Value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using LibHac.Ns;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||
using Ryujinx.Horizon.Common;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Processes
|
||||
@@ -51,7 +52,6 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
|
||||
if (metaLoader is not null)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Application,$"metaLoader: {metaLoader}");
|
||||
ulong programId = metaLoader.ProgramId;
|
||||
|
||||
Name = ApplicationControlProperties.Title[(int)titleLanguage].NameString.ToString();
|
||||
@@ -71,15 +71,8 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
ProgramId = programId;
|
||||
ProgramIdText = $"{programId:x16}";
|
||||
Is64Bit = metaLoader.IsProgram64Bit;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application,$"metaLoader is null !!!");
|
||||
ProcessId = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
DiskCacheEnabled = diskCacheEnabled;
|
||||
AllowCodeMemoryForJit = allowCodeMemoryForJit;
|
||||
}
|
||||
|
||||
@@ -27,9 +27,7 @@
|
||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" />
|
||||
<PackageReference Include="MsgPack.Cli" />
|
||||
<PackageReference Include="SkiaSharp" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.Win32" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.macOS" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux" />
|
||||
<PackageReference Include="NetCoreServer" />
|
||||
<PackageReference Include="Open.NAT.Core" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -183,7 +183,6 @@ namespace Ryujinx.HLE
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Processes.ClearAllProcesses();
|
||||
System.Dispose();
|
||||
AudioDeviceDriver.Dispose();
|
||||
FileSystem.Dispose();
|
||||
|
||||
@@ -9,14 +9,12 @@ namespace Ryujinx.Horizon
|
||||
private readonly Action<ServiceTable> _entrypoint;
|
||||
private readonly ServiceTable _serviceTable;
|
||||
private readonly HorizonOptions _options;
|
||||
public readonly string Name;
|
||||
|
||||
internal ServiceEntry(Action<ServiceTable> entrypoint, ServiceTable serviceTable, HorizonOptions options, string name)
|
||||
internal ServiceEntry(Action<ServiceTable> entrypoint, ServiceTable serviceTable, HorizonOptions options)
|
||||
{
|
||||
_entrypoint = entrypoint;
|
||||
_serviceTable = serviceTable;
|
||||
_options = options;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public void Start(ISyscallApi syscallApi, IVirtualMemoryManager addressSpace, IThreadContext threadContext)
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Ryujinx.Horizon
|
||||
|
||||
void RegisterService<T>() where T : IService
|
||||
{
|
||||
entries.Add(new ServiceEntry(T.Main, this, options, typeof(T).Name));
|
||||
entries.Add(new ServiceEntry(T.Main, this, options));
|
||||
}
|
||||
|
||||
RegisterService<ArpMain>();
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Services.Hid;
|
||||
using SDL;
|
||||
using static SDL.SDL3;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages a HID handle of a gamepad to encode and write HD rumble commands for Nin controllers.
|
||||
/// </summary>
|
||||
public unsafe class NpadHdRumble : IDisposable
|
||||
{
|
||||
private readonly SDL_hid_device* _hidHandle;
|
||||
|
||||
private int _globalCount;
|
||||
private ulong _lastWriteTicks;
|
||||
|
||||
private NpadHdRumble(SDL_hid_device* hidHandle)
|
||||
{
|
||||
_hidHandle = hidHandle;
|
||||
}
|
||||
|
||||
public static NpadHdRumble Create(SDL_Gamepad* gamepadHandle)
|
||||
{
|
||||
ushort vendor = SDL_GetGamepadVendor(gamepadHandle);
|
||||
if (vendor != 0x057e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ushort product = SDL_GetGamepadProduct(gamepadHandle);
|
||||
if (!Enum.IsDefined(typeof(HDRumbleSupported), product))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new NpadHdRumble(SDL_hid_open(vendor, product, 0));
|
||||
}
|
||||
|
||||
// Some of the code was translated from https://github.com/MIZUSHIKI/JoyShockLibrary-plus-HDRumble
|
||||
private bool WriteHdRumble(
|
||||
int encLeftLowFreq, int encLeftLowAmp,
|
||||
int encLeftHighFreq, int encLeftHighAmp,
|
||||
int encRightLowFreq, int encRightLowAmp,
|
||||
int encRightHighFreq, int encRightHighAmp)
|
||||
{
|
||||
byte[] buf = new byte[10];
|
||||
|
||||
buf[0] = 0x10;
|
||||
buf[1] = (byte)((++_globalCount) & 0xF);
|
||||
|
||||
buf[2] = (byte)(encLeftHighFreq & 0xFF);
|
||||
buf[3] = (byte)(encLeftHighAmp + ((encLeftHighFreq >> 8) & 0xFF));
|
||||
buf[4] = (byte)(encLeftLowFreq + ((encLeftLowAmp >> 8) & 0xFF));
|
||||
buf[5] = (byte)(encLeftLowAmp & 0xFF);
|
||||
|
||||
buf[6] = (byte)(encRightHighFreq & 0xFF);
|
||||
buf[7] = (byte)(encRightHighAmp + ((encRightHighFreq >> 8) & 0xFF));
|
||||
buf[8] = (byte)(encRightLowFreq + ((encRightLowAmp >> 8) & 0xFF));
|
||||
buf[9] = (byte)(encRightLowAmp & 0xFF);
|
||||
|
||||
if (_globalCount > 0xF)
|
||||
{
|
||||
_globalCount = 0x0;
|
||||
}
|
||||
|
||||
fixed (byte* ptr = buf)
|
||||
{
|
||||
if (SendHDRumble(ptr, (nuint)buf.Length) >= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(SDL_GetError()))
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Hid, SDL_GetError());
|
||||
SDL_ClearError();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static int EncodeLowFreq(float lowFreq)
|
||||
{
|
||||
float lf = Math.Clamp(lowFreq, 40.875885f, 626.286133f);
|
||||
return (int) Math.Round(32 * Math.Log2(lf * 0.1f) - 0x40);
|
||||
}
|
||||
|
||||
private static int EncodeHighFreq(float highFreq)
|
||||
{
|
||||
float hf = Math.Clamp(highFreq, 81.75177f, 1252.572266f);
|
||||
return (int) Math.Round((32 * Math.Log2(hf * 0.1f) - 0x60) * 4);
|
||||
}
|
||||
|
||||
private static int EncodeLowAmp(float rawAmp)
|
||||
{
|
||||
double encodedAmp = 0;
|
||||
|
||||
if (rawAmp is > 0 and < 0.012f)
|
||||
{
|
||||
encodedAmp = 1;
|
||||
}
|
||||
else if (rawAmp is >= 0.012f and < 0.112f)
|
||||
{
|
||||
encodedAmp = 4 * Math.Log2(rawAmp * 110f);
|
||||
}
|
||||
else if (rawAmp is >= 0.112f and < 0.225f)
|
||||
{
|
||||
encodedAmp = 16 * Math.Log2(rawAmp * 17f);
|
||||
}
|
||||
else if (rawAmp is >= 0.225f and <= 1f)
|
||||
{
|
||||
encodedAmp = 32 * Math.Log2(rawAmp * 8.7f);
|
||||
}
|
||||
|
||||
return (int)Math.Floor(encodedAmp / 2.0) + 64;
|
||||
}
|
||||
|
||||
private static int EncodeHighAmp(float rawAmp)
|
||||
{
|
||||
double encodedAmp = 0;
|
||||
|
||||
if (rawAmp is > 0 and < 0.012f)
|
||||
{
|
||||
encodedAmp = 1;
|
||||
}
|
||||
else if (rawAmp is >= 0.012f and < 0.112f)
|
||||
{
|
||||
encodedAmp = 4 * Math.Log2(rawAmp * 110f);
|
||||
}
|
||||
else if (rawAmp is >= 0.112f and < 0.225f)
|
||||
{
|
||||
encodedAmp = 16 * Math.Log2(rawAmp * 17f);
|
||||
}
|
||||
else if (rawAmp is >= 0.225f and <= 1f)
|
||||
{
|
||||
encodedAmp = 32 * Math.Log2(rawAmp * 8.7f);
|
||||
}
|
||||
|
||||
return (int) Math.Round(encodedAmp * 2);
|
||||
}
|
||||
|
||||
public bool HdRumble(VibrationValue left, VibrationValue right)
|
||||
{
|
||||
return WriteHdRumble(EncodeLowFreq(left.FrequencyLow),
|
||||
EncodeLowAmp(left.AmplitudeLow),
|
||||
EncodeHighFreq(left.FrequencyHigh),
|
||||
EncodeHighAmp(left.AmplitudeHigh),
|
||||
EncodeLowFreq(right.FrequencyLow),
|
||||
EncodeLowAmp(right.AmplitudeLow),
|
||||
EncodeHighFreq(right.FrequencyHigh),
|
||||
EncodeHighAmp(right.AmplitudeHigh));
|
||||
}
|
||||
|
||||
private int SendHDRumble(byte* data, nuint length)
|
||||
{
|
||||
int result = 0;
|
||||
ulong currentTicks = SDL_GetTicks();
|
||||
|
||||
// Ditch rumble if we haven't hit the poll-rate yet.
|
||||
// TODO: figure out a better way to do this
|
||||
// While the polling check makes the rumble accurate, it also causes it to miss signals.
|
||||
if ((currentTicks - _lastWriteTicks) < 8) // https://docs.handheldlegend.com/s/progcc-3/doc/lag-comparison-aAR1mV3JLX
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
SDL_LockJoysticks();
|
||||
{
|
||||
// Fun fact: Mario Kart 8 Deluxe sends rumble packets
|
||||
// where the amplitude is zero, but the frequency isn't.
|
||||
result = SDL_hid_write(_hidHandle, data, length);
|
||||
if (result >= 0)
|
||||
{
|
||||
_lastWriteTicks = currentTicks;
|
||||
}
|
||||
}
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
SDL_hid_close(_hidHandle);
|
||||
}
|
||||
}
|
||||
|
||||
public enum HDRumbleSupported : ushort
|
||||
{
|
||||
JoyConLeft = 0x2006,
|
||||
JoyConRight = 0x2007,
|
||||
JoyconPair = 0x2008,
|
||||
ProController = 0x2009,
|
||||
JoyconGrip = 0x200e,
|
||||
Joycon2Right = 0x2066,
|
||||
Joycon2Left = 0x2067,
|
||||
Joycon2Pair = 0x2068,
|
||||
Switch2ProController = 0x2069,
|
||||
GamecubeController = 0x2073
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.HLE.HOS.Services.Hid;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
@@ -77,14 +76,11 @@ namespace Ryujinx.Input.SDL3
|
||||
|
||||
private SDL_Gamepad* _gamepadHandle;
|
||||
|
||||
private NpadHdRumble _hdRumble;
|
||||
|
||||
private float _triggerThreshold;
|
||||
|
||||
public SDL3Gamepad(SDL_Gamepad* gamepadHandle, string driverId)
|
||||
{
|
||||
_gamepadHandle = gamepadHandle;
|
||||
_hdRumble = NpadHdRumble.Create(gamepadHandle);
|
||||
_buttonsUserMapping = new List<ButtonMappingEntry>(20);
|
||||
|
||||
Name = SDL_GetGamepadName(_gamepadHandle);
|
||||
@@ -155,9 +151,7 @@ namespace Ryujinx.Input.SDL3
|
||||
result |= GamepadFeaturesFlag.Led;
|
||||
}
|
||||
SDL_UnlockProperties(propID);
|
||||
|
||||
// NOTE: Do not call SDL_DestroyProperties here. These properties are owned
|
||||
// internally by SDL and are freed when SDL_CloseGamepad is called (in Dispose).
|
||||
SDL_DestroyProperties(propID);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -169,10 +163,6 @@ namespace Ryujinx.Input.SDL3
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && _hdRumble != null)
|
||||
{
|
||||
_hdRumble.Dispose();
|
||||
}
|
||||
if (disposing && _gamepadHandle != null)
|
||||
{
|
||||
SDL_CloseGamepad(_gamepadHandle);
|
||||
@@ -192,17 +182,10 @@ namespace Ryujinx.Input.SDL3
|
||||
_triggerThreshold = triggerThreshold;
|
||||
}
|
||||
|
||||
public bool HDRumble(VibrationValue left, VibrationValue right)
|
||||
{
|
||||
return _hdRumble?.HdRumble(left, right) ?? false;
|
||||
}
|
||||
|
||||
public bool Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
{
|
||||
if ((Features & GamepadFeaturesFlag.Rumble) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return;
|
||||
|
||||
ushort lowFrequencyRaw = (ushort)(lowFrequency * ushort.MaxValue);
|
||||
ushort highFrequencyRaw = (ushort)(highFrequency * ushort.MaxValue);
|
||||
@@ -221,15 +204,6 @@ namespace Ryujinx.Input.SDL3
|
||||
if (!SDL_RumbleGamepad(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs))
|
||||
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(SDL_GetError()))
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Hid, SDL_GetError());
|
||||
SDL_ClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
|
||||
@@ -331,18 +331,28 @@ namespace Ryujinx.Input.SDL3
|
||||
|
||||
public IEnumerable<IGamepad> GetGamepads()
|
||||
{
|
||||
string[] ids;
|
||||
lock (_lock)
|
||||
lock (_gamepadsIds)
|
||||
{
|
||||
ids = _gamepadsIds.Values
|
||||
.Concat(_joyConsIds.Values)
|
||||
.Concat(_linkedJoyConsIds.Values)
|
||||
.ToArray();
|
||||
foreach (var gamepad in _gamepadsIds)
|
||||
{
|
||||
yield return GetGamepad(gamepad.Value);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string id in ids)
|
||||
lock (_joyConsIds)
|
||||
{
|
||||
yield return GetGamepad(id);
|
||||
foreach (var gamepad in _joyConsIds)
|
||||
{
|
||||
yield return GetGamepad(gamepad.Value);
|
||||
}
|
||||
}
|
||||
|
||||
lock (_linkedJoyConsIds)
|
||||
{
|
||||
foreach (var gamepad in _linkedJoyConsIds)
|
||||
{
|
||||
yield return GetGamepad(gamepad.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Services.Hid;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
@@ -62,8 +61,6 @@ namespace Ryujinx.Input.SDL3
|
||||
public GamepadFeaturesFlag Features { get; }
|
||||
|
||||
private SDL_Gamepad* _gamepadHandle;
|
||||
|
||||
private NpadHdRumble _hdRumble;
|
||||
|
||||
private enum JoyConType
|
||||
{
|
||||
@@ -79,7 +76,6 @@ namespace Ryujinx.Input.SDL3
|
||||
public SDL3JoyCon(SDL_Gamepad* gamepadHandle, string driverId)
|
||||
{
|
||||
_gamepadHandle = gamepadHandle;
|
||||
_hdRumble = NpadHdRumble.Create(gamepadHandle);
|
||||
_buttonsUserMapping = new List<ButtonMappingEntry>(10);
|
||||
|
||||
Name = SDL_GetGamepadName(_gamepadHandle);
|
||||
@@ -143,10 +139,6 @@ namespace Ryujinx.Input.SDL3
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && _hdRumble != null)
|
||||
{
|
||||
_hdRumble.Dispose();
|
||||
}
|
||||
if (disposing && _gamepadHandle != null)
|
||||
{
|
||||
SDL_CloseGamepad(_gamepadHandle);
|
||||
@@ -162,20 +154,13 @@ namespace Ryujinx.Input.SDL3
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
// No operations
|
||||
}
|
||||
|
||||
public bool HDRumble(VibrationValue left, VibrationValue right)
|
||||
{
|
||||
return _hdRumble?.HdRumble(left, right) ?? false;
|
||||
|
||||
}
|
||||
|
||||
public bool Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
{
|
||||
if ((Features & GamepadFeaturesFlag.Rumble) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return;
|
||||
|
||||
ushort lowFrequencyRaw = (ushort)(lowFrequency * ushort.MaxValue);
|
||||
ushort highFrequencyRaw = (ushort)(highFrequency * ushort.MaxValue);
|
||||
@@ -194,15 +179,6 @@ namespace Ryujinx.Input.SDL3
|
||||
if (!SDL_RumbleGamepad(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs))
|
||||
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(SDL_GetError()))
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Hid, SDL_GetError());
|
||||
SDL_ClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user