Compare commits

...

206 Commits

Author SHA1 Message Date
Zephyron 57cf5a0daf build: bump VulkanHeaders minimum version
- Update required VulkanHeaders from 1.4.307 to 1.4.313
- Ensures compatibility with newer Vulkan development packages

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-27 13:59:49 +10:00
Zephyron 020492f1fa chore: update vcpkg baseline
- Update vcpkg builtin-baseline from c82f74 to bc99451
- Provides newer Boost libraries with io_context support
- Ensures consistent Boost ASIO compatibility across platforms

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-27 13:58:58 +10:00
Zephyron 21ca0b3119 fix: update deprecated boost::asio::io_service to io_context
Updates UDP client and related test files to use boost::asio::io_context
instead of the deprecated io_service. This change is required for compatibility
with newer versions of Boost ASIO, which has renamed the class.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-27 13:57:27 +10:00
Zephyron 58401f5b39 fix: remove invalid WSAEBUSY Windows socket error code
- Fixes Windows compilation error by removing the WSAEBUSY case in TranslateNativeError.
- This error code does not exist in the Windows Sockets API as documented in the Microsoft documentation, but was incorrectly included in the Windows-specific error handling code.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-27 13:38:35 +10:00
Zephyron 1ad69f3545 Update submodules: SDL, vcpkg, and Vulkan-Headers
- Update SDL to fix pipewire-related compile error
  - Removes need to hardcode -DSDL_PIPEWIRE=OFF in toolchain
- Update vcpkg to latest version
- Update Vulkan-Headers to latest version

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-27 13:27:21 +10:00
Zephyron 48eed78d1a socket: Implement missing errno values and improve network error handling
Add support for missing errno values needed by TOTK:
- Add BUSY (16) for "Device or resource busy" errors
- Add NOTSOCK (88) for "Socket operation on non-socket" errors

Improvements:
- Update TranslateNativeError on both Windows and Unix to handle new error codes
- Change socket error logging for NOTSOCK from WARNING to DEBUG level
- Fix formatting in Unix errno translation code
- Update shader storage buffer tracking range to accommodate TOTK buffers
- Add hex format to storage buffer logging for easier comparison with bias range
- Change storage buffer tracking log level from WARNING to DEBUG

These changes help prevent error messages in games
that use network features not fully implemented in the emulator yet.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-25 14:38:28 +10:00
Zephyron 5f962dd1c6 android: Update Vulkan Validation Layer to 1.4.309.0
Updates the Android Vulkan Validation Layer (VVL) from version 1.4.304.1
to 1.4.309.0. This ensures compatibility with the latest Vulkan specification
and provides improved validation capabilities for the Android build.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-22 17:12:54 +10:00
Zephyron 25abfe36a3 android: Update build configuration and package identifiers
Updates the Android build configuration with several important changes:

- Change application ID from com.antutu.ABenchMark to org.citron.citron_emu
- Upgrade CMake version from 3.31.6 to 4.0.1
- Update Android Gradle plugin from 8.9.0 to 8.9.2
- Add CMAKE_POLICY_VERSION_MINIMUM=3.5 to CMake arguments
- Keep Kotlin version at 1.9.20

These changes align the Android package identifier with the Citron project
and update build tool versions to ensure compatibility with modern Android
development requirements.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-22 16:58:55 +10:00
Zephyron 2f57a35d2d video_core/vulkan: Fix callback variable shadowing in async shader compilation
Resolves a variable shadowing issue in AsyncCompileShader where the callback
lambda parameter was shadowing the outer callback variable. This was causing
compilation warnings/errors in Android Studio. The fix:

- Renames the outer callback variable to 'outer_callback'
- Renames the inner lambda callback parameters to 'inner_callback'
- Maintains consistent naming across all error handling paths

This change improves code clarity and eliminates compiler warnings while
maintaining the same functionality for async shader compilation.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-22 16:57:57 +10:00
Zephyron 66bdd6ed27 video_core: Add fallback handling for failed storage buffer lookups
Implements a more robust error handling approach when storage buffer lookups
fail in the buffer cache. Instead of returning a null binding, the code now:

- Provides a fallback buffer with safe default values
- Implements warning rate limiting to prevent log spam
- Tracks warning counts per cbuf_index
- Logs detailed debug information periodically

This change helps prevent potential crashes when storage buffer lookups fail
while still maintaining visibility into the issue through strategic logging.

The fallback mechanism uses a safe static address and a reasonable buffer
size (16KB) to handle cases where the normal GPU to CPU address translation
fails.

Also updates copyright headers to include citron Emulator Project.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-22 16:56:59 +10:00
Zephyron ff9c61e7c7 video_core: Improve texture cache memory management to prevent leaks
Implement several improvements to the texture cache memory management system
to address memory leaks that occur in memory-intensive games like TOTK
(Title ID 0100F2C0115B6000). These changes prevent the gradual memory
increase that eventually leads to crashes or undefined behavior.

Key improvements:
- Enhance garbage collection with more aggressive cleanup thresholds
- Add emergency resource cleanup for persistent high memory usage
- Improve DeleteImage to ensure proper resource deallocation
- Make DelayedDestructionRing thread-safe with proper mutex protection
- Track consecutive high-memory frames to detect potential leaks
- Add emergency cleanup mechanism for extreme memory pressure situations
- Use proper type casting in std::max to fix compilation errors

This should significantly improve stability during extended gameplay
sessions with memory-intensive titles.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-20 17:39:14 +10:00
Zephyron e72d695115 feat(services): Implement nn::socket, nn::nifm, and nn::nim networking services
Add Nintendo Switch network service implementations to support modders
working with network functionality in their game modifications:

- Add nn::socket utilities including InetAton and Connect functions
- Implement sockaddr/in_addr structures matching official Nintendo APIs
- Add nn::nifm networking interface services with IsNetworkAvailable and SubmitNetworkRequest
- Implement nn::nim network installation management services
- Fix BSD socket implementation to properly handle proxy packets
- Add Service_BSD log category for better debugging

These changes provide crucial networking API support for modders like
MaxLastBreath and projects like NX Optimizer (https://www.nxoptimizer.com/)
that need to hook into Nintendo's network services for code injection mods.
This implementation follows the official documentation at SwitchBrew and
enables proper network connectivity in modded games.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-20 15:35:25 +10:00
Zephyron 0cdd546152 externals: Update Vulkan dependencies to latest versions
Update Vulkan-Headers, Vulkan-Utility-Libraries, VulkanMemoryAllocator, and vcpkg submodules to their latest versions to ensure compatibility with newer Vulkan features and improve rendering performance.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-19 13:26:01 +10:00
Zephyron 3205c9b691 fix(vulkan): address compiler warnings for Linux
- Fix variable shadowing in ShaderManager constructor by renaming parameter
- Remove unused variables in vk_texture_manager.cpp to avoid warnings
- Fix int conversion warning in syscall return value

These changes fix build errors when using certain optimized compile flags for Linux.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-18 14:26:04 +10:00
Zephyron f1e169e060 fix: correct implementation of present interval 0 for unlocked FPS
Fixes issues in commit bbd3253169 that could cause
crashes and deadlocks. The feature now works as intended, allowing games using
present interval 0 to run with truly unlocked FPS.

This ensures proper functionality of dynamic framerate mods like UltraCam
by MaxLastBreath (https://www.nxoptimizer.com/) without stability problems.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-18 10:11:16 +10:00
Zephyron 278486d059 feat: add CPU clock rate slider to settings
Implement a slider in the CPU settings tab to adjust the BASE_CLOCK_RATE
up to 1,785 MHz (Switch's official maximum clock rate). Default remains
at 1,020 MHz.

This change:
- Adds UI slider and spinbox to configure_cpu.ui with range 500-1785 MHz
- Makes BASE_CLOCK_RATE dynamic by reading from settings
- Modifies WallClock to handle dynamic clock rate changes
- Updates APM controller to properly set the clock rate
- Changes clock rate settings category from Core to CPU

The user can now easily adjust the CPU clock rate to improve performance
or manage thermals and power consumption.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-16 22:02:10 +10:00
Zephyron bbd3253169 feat: add option to respect present interval 0 as unlocked FPS
When enabled, this feature allows games using present interval 0 to run with
truly unlocked FPS, matching actual hardware behavior more accurately.

Previously, Citron would cap present interval 0 at 120FPS to conserve battery,
but this prevented proper functionality of dynamic framerate mods like UltraCam
by MaxLastBreath (https://www.nxoptimizer.com/).

The setting is disabled by default to maintain the current behavior for most users.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-16 19:28:15 +10:00
Zephyron a1f3414bde service/sockets: Implement network services for new firmware versions
This commit implements various network services required for newer firmware
versions. Key changes include:

- Add bsd:nu service for firmware 15.0.0+ with proper event handling
- Add bsdcfg implementation with complete interface declarations
- Add dns:priv and ethc (c/i) services
- Register all new services in the service manager
- Extend BSD implementation with additional socket operations
- Remove room_network instance variable in favor of system.GetRoomNetwork()
- Fix kernel event creation by using ServiceContext in all appropriate places
- Update build system to include new source files

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-15 17:19:53 +10:00
Zephyron 175a427c27 refactor(vulkan): remove depth buffer workarounds and excessive logging
- Remove special handling for reversed depth scenarios that were added for Civilization 7
- Remove excessive logging in Vulkan renderer
- Update Discord client ID
- Update Vulkan-related external dependencies

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-14 22:02:29 +10:00
Zephyron 18def48dfe feat(video_core): Fix Linux compilation issues in Hybrid Memory Manager
- Added missing <thread> header for std::thread usage
- Added <fcntl.h> for O_CLOEXEC and O_NONBLOCK definitions
- Fixed struct initialization order in uffdio_copy to match declaration order

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-12 17:50:39 +10:00
Zephyron a4088f3a1e Add Windows support to Hybrid Memory Manager
This commit adds Windows-specific implementation of the fault-managed memory
system, providing similar functionality to the existing Linux/Android implementation.

Key changes:
- Added Windows-specific memory management using VirtualAlloc/VirtualFree
- Implemented Windows vectored exception handler for page fault handling
- Added proper memory protection and page fault handling on Windows
- Updated memory snapshot functionality to work on Windows
- Added proper cleanup of Windows-specific resources
- Fixed type conversion issues in memory management code
- Added proper error handling for Windows memory operations
- Fixed VRAM Memory Layout Mode to allow up to 12Gb

The implementation uses Windows-specific APIs:
- VirtualAlloc/VirtualFree for memory management
- AddVectoredExceptionHandler for page fault handling
- VirtualProtect for memory protection management

This change maintains feature parity with the Linux/Android implementation
while using Windows-native APIs for better performance and reliability.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-12 16:15:51 +10:00
Zephyron b66b3ca639 nvn(fix): Optimize shader performance by enhancing NVN bias settings
Improve GPU storage buffer detection and memory access patterns:
- Expand NVN bias address range (0x100-0x800 vs 0x110-0x610)
- Increase alignment from 16 to 32 bytes for optimal memory access
- Raise default alignment from 8 to 16 bytes for non-biased addresses
- Refactor bias handling code for better readability
- Add detailed performance-related comments

These changes help identify more storage buffers within shaders and
ensure memory accesses are better aligned, which improves overall
shader compilation and execution performance.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-12 15:14:14 +10:00
Zephyron 3a1c178711 Revert "nvn: Optimize shader performance by enhancing NVN bias settings"
This reverts commit 19febba866.
2025-04-12 15:12:19 +10:00
Zephyron 964bbf489a feat(video_core): Implement HybridMemory for advanced Vulkan memory management
Adds a new cross-platform memory management system with enhanced capabilities:
- Fault-managed memory allocation for Linux/Android platforms
- Memory snapshot and differential snapshot support
- Predictive memory reuse tracking for optimized access patterns
- Vulkan compute buffer integration
- User-configurable settings for enabling features

The system integrates with the existing Vulkan renderer to provide more
efficient memory handling, especially for compute-intensive workloads.

Co-authored-by: boss.sfc <boss.sfc@citron-emu.org>
Co-committed-by: boss.sfc <boss.sfc@citron-emu.org>
Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-10 20:22:00 +10:00
Zephyron 19febba866 nvn: Optimize shader performance by enhancing NVN bias settings
Improve GPU storage buffer detection and memory access patterns:
- Expand NVN bias address range (0x100-0x800 vs 0x110-0x610)
- Increase alignment from 16 to 32 bytes for optimal memory access
- Raise default alignment from 8 to 16 bytes for non-biased addresses
- Refactor bias handling code for better readability
- Add detailed performance-related comments

These changes help identify more storage buffers within shaders and
ensure memory accesses are better aligned, which improves overall
shader compilation and execution performance.

Update Vulkan dependencies to their latest versions.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-05 00:46:51 +10:00
Zephyron 0dac3c1dbd renderer/friend: Improve reversed depth handling and Friend service
This commit makes two significant improvements:

1. Vulkan renderer:
   - Detect and properly handle reversed depth buffers (clear_depth < 0.5)
   - Force depth write enable when needed with reversed depth
   - Use GREATER_OR_EQUAL comparison for reversed depth scenarios
   - Fix transparency issues in games like Civilization 7 by adjusting blend factors
   - Add detailed logging for depth buffer operations

2. Friend service:
   - Implement previously stubbed functions including EnsureFriendListAvailable
     and EnsureBlockedUserListAvailable
   - Add proper event signaling to prevent games from hanging
   - Implement Cancel function for improved compatibility
   - Update copyright notice for the Citron project

These changes improve compatibility with modern games using reversed depth
buffers and prevent hangs in titles that rely on Friend service functionality.

Co-authored-by: m33ts4k0z <m33ts4k0z@citron-emu.org>
Co-committed-by: m33ts4k0z <m33ts4k0z@citron-emu.org>
Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-04-03 16:17:55 +10:00
Zephyron 5d952717ff video_core: Enhance Vulkan shader compilation with async threading system
Implement a robust asynchronous shader compilation system inspired by commit
1fd5fefcb1. This enhancement provides:

- True multi-threaded shader compilation with atomic status tracking
- Persistent disk caching for faster shader loading
- Command queue system for background processing
- Integration with Citron's scheduler for better resource management
- Parallel shader loading to reduce startup times
- Improved error handling and recovery mechanisms

These changes significantly reduce shader compilation stuttering and improve
overall performance when using asynchronous shaders. The implementation
maintains compatibility with Citron's existing architecture while adding
more robust threading capabilities.

Co-authored-by: boss.sfc <boss.sfc@citron-emu.org>
Co-committed-by: boss.sfc <boss.sfc@citron-emu.org>
Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-31 21:01:01 +10:00
Zephyron b25c7653e6 feat(vulkan): implement enhanced texture and shader management
This commit adds improved Vulkan functionality to the Citron emulator:

- Add thread-safe texture management with automatic error recovery
- Implement shader caching with validation support
- Add robust error handling for Vulkan operations
- Implement platform-specific initialization for Windows, Linux, and Android

These enhancements improve stability when handling texture loading errors
and provide better recovery mechanisms for Vulkan failures.

Co-authored-by: boss.sfc <boss.sfc@citron-emu.org>
Co-committed-by: boss.sfc <boss.sfc@citron-emu.org>
Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-28 18:25:36 +10:00
Zephyron edfb500ee7 build: fix linux compilation
- Removes unnecessary \ from Copyright Line Causing Linux Builds To Fail

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-28 14:54:54 +10:00
Zephyron ebfc9d8347 memory: Implement enhanced memory management system
Add a flexible memory region management system that provides:
- Memory region type classification (System, Graphics, IO, Binary)
- Memory region permission management (executable, writable)
- Binary base address randomization for ASLR
- Dynamic memory mapping capabilities

Credit: boss.smc@citron-emu.org
Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-27 23:25:24 +10:00
Zephyron 1fd5fefcb1 WIP: Enhance shader compilation performance and control
This commit adds new settings and optimizations for shader compilation:

- Add new settings:
  - use_enhanced_shader_building: Enable enhanced shader compilation
  - shader_compilation_priority: Control shader compilation priority

- Improve shader compilation performance:
  - Optimize worker thread allocation based on CPU cores
  - Add smarter async shader compilation heuristics
  - Prioritize vertex and fragment shader compilation
  - Add performance tracking and logging

- Add performance monitoring:
  - Track shader compilation times
  - Log slow shader compilations
  - Monitor async shader compilation statistics

This is a work in progress commit. Further optimizations and refinements
will be needed based on testing and feedback.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-27 20:56:23 +10:00
Zephyron 55dc3f8ec1 Update external dependency URLs and versions
- Change SDL2 bundled version from 2.32.0 to 2.28.2
- Downgrade clang-format version from 18 to 15
- Replace citron-emu.org URLs with GitHub mirror URLs:
  - Update clang-format download URL to use yuzu-mirror repository
  - Update package base URL for external dependencies

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-25 20:30:33 +10:00
Zephyron 7edbccbdc9 Revert "Update submodule URLs from yuzu-mirror to Citron repositories"
This reverts commit d1b7aebe8c.
2025-03-25 17:45:50 +10:00
Zephyron e06526cbbc Update Vulkan-related dependencies and vcpkg
- Update Vulkan-Headers from cacef303 to 78c35974
- Update VulkanMemoryAllocator from c788c521 to 29b35ea4
- Update vcpkg from e40d24cb to a7d06b3a

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-21 17:23:02 +10:00
Zephyron 0448d8146f Update controller udev rules with consistent vendor ID formatting
- Add copyright notice for citron Emulator Project
- Standardize Nintendo vendor ID format to uppercase (057E) in Bluetooth controller rules
- Maintain same permissions and access settings for all controllers

REF: 6ead429195

Reviewed-on: http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu/pulls/106
Co-authored-by: deftdawg <deftdawg@noreply.localhost>
Co-committed-by: deftdawg <deftdawg@noreply.localhost>
Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-21 17:13:06 +10:00
Zephyron 98c515871e ui: Disable the Kiosk (Quest) Mode configuration option
This commit disables the "Kiosk (Quest) Mode" checkbox in the debug configuration
UI by setting it to non-interactive and adding a tooltip indicating that the
feature has been disabled.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-20 18:49:00 +10:00
Zephyron 278ac75a37 ui: Disable the Auto-Stub configuration option
This commit disables the "Enable Auto-Stub" checkbox in the debug configuration
UI by setting it to non-interactive and adding a tooltip indicating that the
feature has been disabled.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-17 14:02:15 +10:00
Zephyron ec402a0510 feat(build): Add host system detection for Android cross-compilation
- Modify CMakeLists.txt to detect whether the host system is Windows or Linux
- Set VCPKG_HOST_TRIPLET dynamically to either "x64-windows" or "x64-linux" based on CMAKE_HOST_SYSTEM_NAME
- Previously, the host triplet was hardcoded to "x64-windows", which prevented proper building on Linux hosts

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-17 12:26:35 +10:00
Zephyron 8cb6e6d5d4 Revert "Android: Implement TLB optimization to prevent deadlocks and improve performance"
This reverts commit 21594b73aa.
2025-03-17 12:20:38 +10:00
Zephyron 51800e249b service/ssl: Register ssl:s service to fix game hangs
Added registration for the 'ssl:s' service using the same implementation as
the regular 'ssl' service. This fixes issues with certain titles that hang indefinitely while
waiting for this service to become available.

The issue appears in logs as:
"Server is not registered! service=ssl:s"
"Waiting for service ssl:s to become available"

This is a simple fix that reuses the existing SSL implementation instead of
creating a separate one, as both services share the same functionality.

This commit enhances the Multiplayer Function

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-16 19:33:00 +10:00
Zephyron 21594b73aa Android: Implement TLB optimization to prevent deadlocks and improve performance
This commit addresses critical TLB (Translation Lookaside Buffer) issues on Android by implementing several optimizations:

- Add new BufferCacheAccelerator to manage memory range overlap detection
- Implement TLB-aware memory barriers to prevent unnecessary invalidations
- Add a TLB caching system to avoid redundant flushing operations
- Create a counter to limit outstanding memory operations and prevent TLB thrashing
- Implement TLB prefetching for better memory access patterns
- Add targeted memory barriers for more precise synchronization

These changes significantly reduce the likelihood of the "0.0 FPS deadlock" issue on Android devices by maintaining a more stable TLB state and preventing cache thrashing.

TODO: Merge & Adapt Camille LaVey's TLB Method To Further Improve
Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-14 18:56:16 +10:00
Zephyron d869045b77 build: Move PGO configuration to earlier in CMakeLists.txt
The Profile-Guided Optimization configuration was previously placed at the
end of the CMakeLists.txt file, after all targets were already defined.
This was causing the PGO flags to have no effect on the build process.

This commit moves the PGO configuration to immediately after the initial
compiler flags setup and before any targets are defined, ensuring that
all targets will properly receive the PGO instrumentation or optimization
flags when those options are enabled.

This allows both CITRON_ENABLE_PGO_INSTRUMENT and CITRON_ENABLE_PGO_OPTIMIZE
to function correctly for all build targets.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-13 17:03:21 +10:00
Zephyron f2931c7566 vulkan: Implement AMD driver workaround for logic operations
- Added conditional check for AMD graphics drivers
- Automatically disable logic operations when float vertex attributes
  are present to work around driver quirks
- Maintain original logic op state to preserve emulator behavior
- Prepare dynamic state management infrastructure for future
  OpenGL implementation changes

OpenGL implementation will follow in subsequent commits.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-13 16:30:23 +10:00
Zephyron 12c63997d2 core(base_clock_rate): Revert Back To 1,020 MHz
- This Commit Accidentally Slipped By In A Previous Commit (dad8859679)
- This Has Caused Many Errors & Networking Issues Particularly On Android
- Now Uses Safe, Default 1.02 GHz

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-13 16:10:04 +10:00
Zephyron 1023125be5 android: Add mandatory firmware and title.keys setup steps
- Downgrade Kotlin and Android plugin versions to ensure build compatibility.
- Add setup steps for title.keys installation and mandatory firmware setup.
- Persist auto-generated keys to improve emulator compatibility.
- Update key manager to write derived keys to filesystem.
- Implement UI handling for mandatory firmware installation checks.
2025-03-13 16:04:11 +10:00
Zephyron dad8859679 android: Update build system and optimize ARM NCE implementation
- Update Kotlin from 1.9.20 to 2.1.20-RC2
- Upgrade Java version from 17 to 21
- Update Android Gradle plugin from 8.1.2 to 8.9.0
- Update Gradle wrapper from 8.10.2 to 8.11.1
- Update NDK version to 29.0.13113456 rc1
- Update all Android dependencies to latest versions
- Simplify ARM NCE implementation by removing custom TLB handling
- Improve alignment and access fault handling
- Update hardware BASE_CLOCK_RATE from 1.02GHz to 1.785GHz
- Add citron Emulator Project copyright notices

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-03-11 20:48:51 +10:00
Zephyron 834cc89548 externals: Update Vulkan and vcpkg submodules
Update the following external dependencies:
- Vulkan-Headers: 0f0cfd8 → cacef303
- Vulkan-Utility-Libraries: 50563f4 → bc3a4d9f
- vcpkg: cd1099f4 → e40d24cb

This commit updates the external dependencies to their latest
compatible versions to ensure we're using up-to-date libraries.
2025-03-11 15:47:53 +10:00
vampiric_x 38b259d099 Fix a few strings 2025-03-10 23:16:30 +01:00
vampiric_x e7e9453667 android: Initial multiplayer support
And give room owners mod access on both Android and QT
2025-03-10 22:37:56 +01:00
Zephyron ae75413cc3 Remove quickstart guide references to address legal concerns
- Removed "Open Quickstart Guide" menu item and associated functions
- Replaced ROM loading error popup containing quickstart guide links
  with a neutral disclaimer stating the software is provided as-is
  without warranty or support
- This change helps minimize legal liability by avoiding
  specific instructional content while directing users to community
  resources for assistance
2025-03-09 22:23:54 +10:00
Zephyron 6a31da5905 cmake: Add Profile-Guided Optimization (PGO) support
Adds support for Profile-Guided Optimization builds on both Windows (MSVC)
and Linux (GCC/Clang) platforms. This allows for performance optimizations
based on real usage patterns.

For MSVC:
- Adds /GL and /LTCG:PGINSTRUMENT flags for instrumentation
- Adds /GL and /LTCG:PGOPTIMIZE flags for optimization

For GCC:
- Adds -fprofile-generate flags for instrumentation
- Adds -fprofile-use flags for optimization

For Clang:
- Adds -fprofile-instr-generate flags for instrumentation
- Adds -fprofile-instr-use flags for optimization

Controlled by two new CMake options:
- CITRON_ENABLE_PGO_INSTRUMENT: Enable instrumentation build
- CITRON_ENABLE_PGO_OPTIMIZE: Enable optimization build

Updated submodules:
- Vulkan-Headers to 0f0cfd8
- Vulkan-Utility-Libraries to 50563f4
- vcpkg to cd1099f
2025-03-07 20:23:23 +10:00
Zephyron a5125d008a revert 78b0080b96
revert TLB: Parallel Page Table Walk Logic Implementation
2025-03-06 06:44:38 +00:00
Zephyron b24dd921aa revert 31694994f2
revert arm_nce: Hash TLB to MLP L2 Update
2025-03-06 06:44:06 +00:00
Zephyron 9a65205dba revert ee3d858935
revert Follow Up Of the previous commit with the update of TLB update
2025-03-06 06:43:37 +00:00
Zephyron af4f08be33 revert 6565055865
revert Fix: Core_Memory logging and ARM_NCE Mutex logging
2025-03-06 06:42:48 +00:00
Zephyron 0d0963d32f revert 90a8165f77
revert Added: Core_Memory to filter logging class
2025-03-06 06:42:30 +00:00
Zephyron 4491127f52 revert 031c635095
revert arm: corrected declarations
2025-03-06 06:41:01 +00:00
Zephyron c304afe2b3 revert 78b0080b96
revert TLB: Parallel Page Table Walk Logic Implementation
2025-03-06 06:40:24 +00:00
Zephyron b8240b4214 revert 644ed69285
revert arm:
2025-03-06 06:40:17 +00:00
Zephyron 91487f6d96 revert 3554f55fc9
revert TLB Update
2025-03-06 06:39:49 +00:00
CamilleLaVey 031c635095 arm: corrected declarations 2025-03-05 11:12:44 -04:00
CamilleLaVey 90a8165f77 Added: Core_Memory to filter logging class 2025-03-05 01:31:22 -04:00
CamilleLaVey 6565055865 Fix: Core_Memory logging and ARM_NCE Mutex logging 2025-03-05 00:25:31 -04:00
CamilleLaVey ee3d858935 Follow Up Of the previous commit with the update of TLB update 2025-03-04 22:50:01 -04:00
CamilleLaVey 31694994f2 arm_nce: Hash TLB to MLP L2 Update 2025-03-04 22:28:03 -04:00
CamilleLaVey 4197fa84a0 revert e4342324fe
revert Changes of the previous commits
2025-03-04 02:33:14 +00:00
CamilleLaVey e4342324fe Changes of the previous commits 2025-03-03 21:49:07 -04:00
CamilleLaVey 78b0080b96 TLB: Parallel Page Table Walk Logic Implementation 2025-03-03 21:44:56 -04:00
CamilleLaVey 644ed69285 arm: 2025-03-03 21:23:13 -04:00
CamilleLaVey 3554f55fc9 TLB Update 2025-03-03 20:55:08 -04:00
Zephyron dc9532b4d1 Revert "CMake: Enable C++ latest and coroutines for MSVC builds"
This reverts commit 1308e2b935.
2025-03-03 17:13:29 +10:00
Zephyron 1308e2b935 CMake: Enable C++ latest and coroutines for MSVC builds
Add /std:c++latest and /await compiler flags for MSVC builds to enable
the latest C++ features and coroutine support.
2025-03-03 16:35:57 +10:00
Zephyron 5caecd8151 Android: Remove redundant firmware check
Remove duplicate firmware presence check in EmulationActivity. The
isFirmwareAvailable() check already handles this functionality, making
checkFirmwarePresence() redundant.
2025-03-03 16:35:18 +10:00
Zephyron dc9fbcc893 Android: Downgrade build dependencies and SDK versions
- Revert Android Gradle plugin from 8.8.1 to 8.1.2
- Downgrade Kotlin version from 2.1.20-RC to 1.9.20
- Lower Java/JVM target from 21 to 17
- Reduce CMake version from 3.31.5 to 3.22.1
- Update various Android dependencies to stable versions:
  - Navigation Safe Args plugin to 2.6.0
  - ktlint to 0.47.1
  - Play Publisher plugin to 3.8.6
- Remove custom APK naming scheme
- Fix CMake boolean arguments (OFF -> 0)
- Remove citron copyright header
2025-03-03 16:34:35 +10:00
Zephyron b1d5d4e5be Update external dependencies
- Update Vulkan-Utility-Libraries submodule to 5f41f2a
- Update vcpkg submodule to efb1e74
2025-03-03 16:33:01 +10:00
CamilleLaVey f0d8daf755 revert cbb9a35166
revert Re-Enabled Vulkan Functions disabled on Adreno to improve compatibility and performance and check further issues within the current changes.
2025-03-03 04:00:13 +00:00
CamilleLaVey cbb9a35166 Re-Enabled Vulkan Functions disabled on Adreno to improve compatibility and performance and check further issues within the current changes. 2025-03-02 23:17:43 -04:00
Zephyron cfe437aacf arm: Improve TLB implementation and fault handling in NCE
This commit enhances the Translation Lookaside Buffer (TLB) implementation
in the ARM Native Code Execution (NCE) component to increase stability,
particularly on Android devices. The changes prioritize robustness and
error recovery over performance optimizations.

Key improvements:
- Replace set-associative TLB with a simpler linear search implementation
- Implement a basic LRU replacement policy for TLB entries
- Add validation checks for memory addresses before TLB insertion
- Ensure proper page alignment for guest and host addresses
- Enhance alignment fault handling with instruction skipping as fallback
- Add comprehensive debug logging for memory access errors
- Improve error recovery in guest memory access scenarios

These changes should significantly reduce crashes during emulation on
Android devices by gracefully handling memory access edge cases that
previously resulted in hard crashes.

Co-Authored-By: Camille LaVey <camillelavey@citron-emu.org>
Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-02-28 17:11:07 +10:00
Zephyron 9b293c3a98 shader_recompiler: Implement vertex count lookup for Geometry stage
Add proper handling of input topologies in the Geometry stage for all three
shader backends (GLASM, GLSL, SPIRV). This implementation uses a lookup table
approach to determine vertex counts based on input topology type (Points,
Lines, LinesAdjacency, Triangles, TrianglesAdjacency) and shifts the vertex
count by 16 bits as required by the invocation info format.

Additional changes:
- Fixed TessellationControl and TessellationEval stages to properly break
  after emitting code
- Added proper header include for runtime_info.h in GLASM backend
- Improved code documentation with clear commenting patterns

This change ensures accurate geometry shader behavior across all backends,
improving compatibility with games that rely on proper vertex count reporting.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
2025-02-28 17:08:27 +10:00
Zephyron 84e5fbc089 feat: Make firmware mandatory for title launching
This commit implements a requirement for firmware to be installed before titles
can be launched, similar to how keys are required.

Changes include:
- Add IsFirmwareAvailable method to KeyManager to check for essential keys
- Add CheckFirmwarePresence method to verify actual firmware files (NCAs)
- Add firmware checks in game loading process for both desktop and Android
- Add error messages when firmware is missing
- Add strings for firmware-related error messages

The implementation checks for both essential keys and the presence of system
applets like Mii Edit and Home Menu to ensure proper firmware is installed.
Games will not launch if firmware is missing, and users will be shown an
appropriate error message.
2025-02-28 16:15:10 +10:00
Zephyron a442078ee4 feat: Remove autogenerated key functionality
This commit removes the functionality that automatically generates and writes
keys to *_autogenerated files. The key derivation logic is preserved, but
derived keys are now only stored in memory and not written to disk.

Changes include:
- Remove loading from *_autogenerated key files
- Make WriteKeyToFile a no-op function
- Remove all file writing operations in SetKey methods
- Remove file writing for keyblobs and other derived keys
- Update copyright notices

This change improves security by not storing derived keys on disk and
simplifies the key management system.
2025-02-28 15:27:12 +10:00
Zephyron cc610ad9b6 renderer: Disable async presentation due to crashes
- Disable async presentation by default on both Android and desktop platforms due to stability issues.
2025-02-27 13:19:08 +10:00
Zephyron 5a65f9a094 Update external dependencies
- Vulkan-Utility-Libraries: 6be00ca → 2d8f273
- FFmpeg: d161604 → 99e2af4
- vcpkg: 9a7a33f → 23b33f5
2025-02-27 13:08:19 +10:00
Zephyron 5ca1f0e365 core/arm/nce: Implement TLB caching system
Adds a software TLB cache to improve memory access performance in the NCE
(Native Code Execution) system. Key changes include:

- Implement set-associative TLB with 64 sets and 8 ways
- Add TLB lookup before memory access in HandleGuestAccessFault
- Implement LRU replacement policy with access frequency consideration
- Add thread context caching to reduce overhead
- Add proper synchronization with mutex locks
- Add helper functions for TLB management (lookup, insert, invalidate)

This change should improve performance by reducing redundant memory
translations and providing faster access to frequently used pages.
2025-02-25 18:37:14 +10:00
Zephyron a36baad0f0 externals: Update submodule versions
- vcpkg: 37d46ed → 9a7a33f
- Vulkan-Headers: 234c4b7 → 952f776
- Vulkan-Utility-Libraries: fe7a09b → 6be00ca
- ffmpeg: 9c1294e → d161604
2025-02-25 18:34:32 +10:00
Zephyron ed115d3f72 Revert "settings: Enable auto-stub by default"
This reverts commit 7903415fa4.
2025-02-24 19:05:05 +10:00
Zephyron d9619b7eed vulkan: Improve memory allocation robustness
Enhances the Vulkan memory allocator with better OOM handling and memory
alignment:

* Add memory recovery by cleaning up empty allocations before failing
* Implement proper fallback to non-device-local memory
* Simplify memory alignment handling for different vendors
* Add better error logging for allocation failures
* Add IsEmpty() helper to track unused allocations
* Fix alignment requirements for Adreno (4KB) vs other vendors

These changes improve the robustness of memory allocation, particularly
in low-memory situations, and streamline vendor-specific alignment
requirements.
2025-02-22 19:08:42 +10:00
Zephyron dbe5bf1d18 android: Update build dependencies and configurations
Updates various build dependencies and configurations for the Android build:

* Upgrade Android Gradle Plugin to 8.8.1
* Update Kotlin to 2.1.20-RC
* Upgrade NDK to 28.0.13004108
* Update target/compile SDK to Android 35
* Upgrade Java/Kotlin target to JVM 21
* Enable additional release optimizations (shrinkResources, proguard-android-optimize)
* Update CMake to 3.31.5
* Update various AndroidX and support library dependencies
* Change CMake boolean flags from 0/1 to OFF/ON
* Update ktlint to 0.51.1 and related plugins

This commit modernizes the Android build system and enables additional
optimizations for release builds.
2025-02-22 19:07:53 +10:00
Zephyron 7903415fa4 settings: Enable auto-stub by default
Changes the default value of use_auto_stub from false to true in the settings.
This setting controls whether unimplemented functions should be automatically
stubbed during execution.
2025-02-22 19:07:16 +10:00
Zephyron 3bb4d97e9e cmake: Optimize Android VVL download logic
Improve the Vulkan Validation Layer (VVL) download logic for Android by checking
for the final library file instead of just the zip archive. This prevents
unnecessary re-downloads and extractions when the library is already in place.

The check now looks for libVkLayer_khronos_validation.so in the final
destination path before attempting to download and extract the archive.
2025-02-22 19:06:05 +10:00
Zephyron a41f7b7a56 feat: Add AnTuTu to license verification for Android app 2025-02-22 10:05:27 +10:00
Zephyron 18f8a0f997 Add license verification for Android app
Implements a LicenseVerifier class to ensure app integrity and license compliance:
- Verifies the app's package name matches the official release
- Validates app signature against official release signature
- Allows debug and EA (Early Access) builds
- Shows violation dialog and exits if verification fails
- Enforces GPLv3 license compliance for modified versions

This helps prevent unauthorized modified versions from being distributed
without source code, as required by the GPLv3 license.
2025-02-21 18:46:48 +10:00
Zephyron 4d50d2ba16 Revert "audio: refactor SDL2 sink implementation"
This reverts commit 3aa9c0d151.
2025-02-20 16:54:43 +10:00
Zephyron 0576d40bf0 Remove redundant TranslateIPv4 function
Remove the TranslateIPv4 function that converts in_addr to IPv4Address, as it
appears to be unused or redundant. The functionality might be handled elsewhere
in the codebase or no longer needed.
2025-02-19 19:53:35 +10:00
Zephyron 6917530ba5 Updated submodule discord-rpc to commit 20cc99aeffa08a4834f156b6ab49ed68618cf94a 2025-02-19 15:19:47 +10:00
Zephyron 43495b6045 network: Improve network interface handling and address resolution
- Return loopback address (127.0.0.1) when no network interface is selected
- Improve IPv4 address string conversion and handling
- Add explicit handling for "None" network interface selection
- Change IsAnyInternetRequestAccepted logging from ERROR to DEBUG
- Simplify internet request acceptance check to assume availability

This change makes the network interface handling more robust by providing
fallback behaviors and improving address resolution. It also reduces
unnecessary error logging for expected scenarios.
2025-02-17 21:59:15 +10:00
Zephyron c5e480e55d feat: Add Home Menu launch support and system improvements
This commit adds support for launching the system Home Menu and implements
several system-level improvements:

- Add Home Menu launch functionality through new UI action
- Implement shutdown/reboot sequence handlers in GlobalStateController
- Add support for reserved region extra size in page tables
- Enhance audio controller with output management
- Expand parental control service capabilities
- Add profile service improvements for user management

Technical changes:
- Add OnHomeMenu() handler to launch QLaunch system applet
- Implement m_alias_region_extra_size tracking in page tables
- Add new CreateProcessFlag for reserved region extra size
- Expand audio controller interface with output management
- Add self-controller methods to various services
- Implement play timer and profile service improvements

The changes primarily focus on system menu integration and core service
improvements to better support system functionality.
2025-02-17 17:33:10 +10:00
Zephyron 1c9e17496b texture_cache: Add equality operators for ImageInfo and ImageViewInfo
- Add operator== to ImageInfo and ImageViewInfo classes to enable direct equality comparisons. The implementations use std::tie to perform member-wise comparisons of all relevant fields in a safe and efficient manner.

This allows for easier comparison of texture cache entries and view
information, which can be useful for cache management and debugging.
2025-02-16 18:30:50 +10:00
Zephyron 7730d14b4a build: upgrade fmt and SDL2
Update fmt library to version 11.0.2 and make necessary adjustments:
- Replace fmt/format.h includes with fmt/ranges.h
- Add const qualifiers to formatter::format functions
- Update CMake to require fmt version 11

Additional dependency updates:
- Update SDL2 bundled version from 2.28.2 to 2.32.0
- Update catch2 to version 3.8.0
- Update vcpkg baseline to c82f74667287d3dc386bce81e44964370c91a289
2025-02-16 13:38:05 +10:00
Zephyron 677b8f476a service/am: Implement SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled
- Removes STUBBED designation as implementation is now complete
- Changes log level from WARNING to DEBUG
- Properly sets the exit request flag under lock protection
2025-02-16 12:02:52 +10:00
Zephyron 5cbde61d3c service/am: Implement CreateManagedDisplaySeparableLayer
- Removes STUBBED designation as implementation is now complete
- Changes log level from WARNING to DEBUG
- Adds proper locking when accessing the display layer manager
- Fixes parameter alignment in function declaration
2025-02-16 12:01:27 +10:00
Zephyron 33a1996ca4 service/nvnflinger: Unstub GetNativeHandle
Removes the STUBBED designation from GetNativeHandle in IHOSBinderDriver
as the implementation is now complete. Changes the log level from WARNING
to DEBUG to reflect this status.

The function properly handles binder ID validation and returns the
appropriate handle as documented in switchbrew.
2025-02-16 11:59:08 +10:00
Zephyron a7af4d001b service/vi: Improve OpenDisplay validation
Updates the OpenDisplay function in IApplicationDisplayService to properly
validate display names. Instead of only accepting "Default", now validates
against all known valid display names: "Default", "External", "Edid",
"Internal", and "Null".

- Changes log level from WARNING to DEBUG since this is no longer stubbed
- Adds proper validation for all valid display names
- Returns ResultOperationFailed for invalid display names
- Improves logging by including the requested display name
2025-02-16 11:57:23 +10:00
Zephyron ef884ce39c service/aoc: Implement CheckAddOnContentMountStatus
Implements the CheckAddOnContentMountStatus command for the aoc:u service.
This function checks whether add-on content (DLC) is currently mounted.

Currently returns false as we don't yet track mounted content state.
Changed log level from WARNING to DEBUG since this is no longer stubbed.
2025-02-16 11:55:13 +10:00
Zephyron 1aad9fd4e3 revert f45f339ef9
revert deps: update SDL2 and FFmpeg versions

Update bundled dependencies to their latest stable versions:
- SDL2: 2.28.2 -> 2.30.12
- FFmpeg: 6.0 -> 6.1.2

Also add citron copyright header to FFmpeg CMakeLists.txt
2025-02-13 11:48:41 +00:00
Zephyron f45f339ef9 deps: update SDL2 and FFmpeg versions
Update bundled dependencies to their latest stable versions:
- SDL2: 2.28.2 -> 2.30.12
- FFmpeg: 6.0 -> 6.1.2

Also add citron copyright header to FFmpeg CMakeLists.txt
2025-02-12 17:59:32 +10:00
Zephyron 298e797592 Update external dependencies
Updated the following submodules to their latest versions:
- vcpkg: 74ec888 → 33e9c99
- cpp-httplib: a609330 → 39a64fb
- cpp-jwt: 10ef573 → 4a970bc
- discord-rpc: 20cc99a → 2acd05a
- enet: 39a72ab → 657eaf9
- libusb: c060e9c → de38189
- oaknut: 9d09110 → 94c726c
- opus: 101a71e → 734aed0
- simpleini: 382ddbb → 6048871
2025-02-12 15:58:47 +10:00
Zephyron 8bfafb4755 build: Update NASM and clang-format versions, fix download URLs
- Update NASM version from 2.16.01 to 2.16.03
- Change NASM download URL to use official nasm.us source
- Update clang-format version from 15 to 18
- Update compatibility list and clang-format download URLs to use citron-emu.org

Thanks to Mangax for suggesting these updates.
2025-02-11 19:25:59 +10:00
Zephyron 33d54e595f cmake: update Qt configuration and externals URL
- Simplify Qt version selection to always use 6.8.2 instead of conditional versions
- Update bundled externals URL to use git.citron-emu.org/Citron
- Update MSVC toolchain references from 2019 to 2022 for Qt paths

This change streamlines Qt version management and updates the infrastructure
to use newer MSVC toolchain paths.
2025-02-10 19:55:16 +10:00
Zephyron 13ada2d705
cmake: Use Qt 6.7.3 for MSVC builds
Forces Qt 6.7.3 for MSVC builds while keeping 6.8.2 for other platforms.
This fixes Windows compilation issues with newer Qt versions.
2025-02-09 18:57:35 +10:00
Zephyron 8bf4660bac
android: Disable RAM Overlay By Default
- TODO
2025-02-09 18:51:20 +10:00
Zephyron b07751ed43
android: Update build toolchain to NDK 28 and Java 21
Update Android build configuration to use the latest NDK version 28.0.13004108
and Java JDK 21. This includes:

- Updating ndkVersion from 26.3.11579264 to 28.0.13004108
- Upgrading Java compatibility from Java 17 to Java 21
- Setting Kotlin JVM target from 17 to 21

These changes modernize the Android build toolchain and ensure compatibility
with the latest development tools.
2025-02-09 18:24:45 +10:00
Zephyron b3c60b4cbe
vulkan: Rename resolve_image to resolve_image_holder
Fix Android compilation with latest NDK (28.0.13004108) and Java JDK 21 by
renaming the resolve_image variable to resolve_image_holder to avoid potential
naming conflicts. This change helps maintain compatibility with the updated
build toolchain while keeping the core functionality intact.

The change affects the MSAA image copy operation in the Vulkan texture cache
implementation.
2025-02-09 18:22:36 +10:00
Zephyron dcf6f9a071
Revert "Replace yuzu identifiers with citron"
This reverts commit d4ad55ed21.
2025-02-09 18:19:08 +10:00
Zephyron b42a0fb227
network: Fix 0.0 FPS bug on Android (Part 2)
- Add network interface enumeration support for Android
- Implement fallback loopback interface when no interfaces are detected
- Add ability to force offline mode on critical network errors
- Improve socket initialization with better error handling
- Add socket state tracking (domain, type, protocol)
- Make translation functions static and mark as maybe_unused
- Add detailed logging for network initialization failures

Part 2 of the Android FPS bug fix focuses on network resilience,
particularly handling cases where network initialization fails.
Instead of hanging the emulator, it now gracefully falls back to
offline mode and provides better diagnostic information.
2025-02-09 15:44:43 +10:00
Zephyron 5af4803e42
common: Enhance memory mapping safety and debugging
- Reduce max_memory_size from 512GB to 1GB for safer allocation limits
- Add memory operation logging for debugging purposes
- Implement MapMemory() with additional safety checks and large allocation handling
- Add validation checks for memory mappings
- Introduce chunked allocation strategy for large memory requests
- Add detailed error logging for memory operations
2025-02-09 15:40:24 +10:00
Zephyron becaf850ab
Update Qt and Vulkan Headers versions
- Update VulkanHeaders requirement from 1.4.304.1 to 1.4.307
- Update Qt download version from 6.7.3 to 6.8.2
2025-02-09 15:38:41 +10:00
Zephyron d4ad55ed21
Replace yuzu identifiers with citron
Update magic numbers and default identifiers across codebase:
- UUID default value
- Thread magic number
- Amiibo name
- Vulkan cache magic number
- Shader cache magic number
2025-02-09 12:07:50 +10:00
Zephyron 6e16a8db1c
service/nvdrv: Implement NVGPU_GPU_IOCTL_NUM_VSMS
- Add IoctlNumVsms struct definition
- Implement ioctl 0x13 to return number of SM units (2 for Tegra X1)
2025-02-09 11:43:08 +10:00
Zephyron 384a18927b
service/friend: Clean up friend service implementation
- Remove unused function stubs
- Improve GetCompletionEvent implementation
- Clean up response builder naming
2025-02-09 11:40:46 +10:00
Zephyron 76716b5248
service/audio: Clean up audio controller implementation
- Remove Unknown5000 function and related debug commands
- Fix incorrect service name in log message
2025-02-09 11:39:16 +10:00
Zephyron 6917a22a2c
service/acc: Clean up account service implementation
- Remove unused function stubs
- Add version information comments
- Add clang-format markers
- Remove duplicate TrySelectUserWithoutInteraction function
- Fix formatting and code style
2025-02-09 11:36:58 +10:00
Zephyron 646af3c143
Downgrade Qt version from 6.8.2 to 6.7.3
- Changes the downloaded Qt version from 6.8.2 to 6.7.3 when not using system Qt.
- This rolls back to a more stable release version of Qt.
2025-02-09 11:33:06 +10:00
Zephyron d1b7aebe8c
Update submodule URLs from yuzu-mirror to Citron repositories
Change the remote URLs for the following submodules to point to Citron's Git server:
- dynarmic
- discord-rpc
- sirit
- mbedtls
- breakpad
- oaknut

This migrates these dependencies from yuzu-mirror GitHub repositories to
Citron's self-hosted Git server while maintaining the same codebase.
2025-02-09 11:31:40 +10:00
Zephyron d783806b1e
service/friend: implement additional friend service functions
- Add implementations for previously stubbed functions:
  * Cancel - Handle operation cancellation
  * RequestSyncFriendList - Friend list synchronization
  * GetUserPresenceView - User presence information
  * LoadUserSetting - User settings loading
- Improve GetCompletionEvent implementation:
  * Add proper event signaling
  * Use clearer variable names
  * Improve debug logging
- Enhance logging messages:
  * Add more descriptive debug messages
  * Include user ID in presence view logging
  * Use consistent naming in response builders
- Fix response builder formatting for consistency

These changes improve the friend service implementation by adding
support for more friend-related functionality while enhancing
the debugging experience through better logging and code
organization.
2025-02-08 20:39:47 +10:00
Zephyron 268d322d7f
service/audio: implement Unknown5000 and add debug commands
- Add Unknown5000 implementation to create duplicate controller interface
- Add new debug-related command handlers:
  * OverrideDefaultTargetForDebug (50001)
  * SetForceOverrideExternalDeviceNameForDebug (50003)
  * ClearForceOverrideExternalDeviceNameForDebug (50004)
- Add proper debug logging for interface creation
- Update header with new function declaration
- Fix missing commas in function registration array

These changes improve the audio controller implementation by
adding support for interface duplication and debug override
functionality. The implementation maintains proper interface
lifetime management using SharedFrom.
2025-02-08 20:35:38 +10:00
Zephyron 92b70b31e0
service/nim: implement CreateServerInterface2 and improve logging
- Add CreateServerInterface2 implementation for NIM_ECA service
- Change log level from WARNING to DEBUG for CreateServerInterface
- Add descriptive log message for server interface creation
- Maintain consistent interface creation pattern between both versions
- Fix missing comma in function registration array

These changes improve the NIM service implementation by adding
support for the newer server interface creation method while
making logging more appropriate for stubbed functions.
2025-02-08 20:28:25 +10:00
Zephyron 4792ba752e
service/mm: add missing vector include and update copyright
- Add missing <vector> include for std::vector usage
- Add Citron copyright notice
- Maintain existing include ordering

This is a minor cleanup change to ensure proper header inclusion
and copyright attribution.
2025-02-08 20:24:09 +10:00
Zephyron b8fe6b6f7c
service/acc: implement Nintendo Account integration and cleanup
- Add Nintendo Account related implementations:
  * GetNintendoAccountId
  * GetNintendoAccountUserResourceCache
  * IsLinkedWithNintendoAccount
  * StoreSaveDataThumbnailApplication
- Improve version handling:
  * Add proper firmware version comments
  * Implement deprecated and new TrySelectUserWithoutInteraction
  * Update service interface versioning
- Clean up code organization:
  * Remove redundant clang-format markers
  * Fix constructor formatting
  * Improve error handling in InitializeApplicationInfoBase
  * Add proper debug logging
  * Update copyright headers
- Add proper documentation for buffer types and sizes

These changes improve Nintendo Account integration support while
cleaning up the codebase and improving version compatibility
handling. The implementation provides stubs for network-related
functionality to allow applications to proceed while proper
integration is developed.
2025-02-08 20:21:47 +10:00
Zephyron 0acfbc5fa1
service/nifm: implement additional network interface functions
- Add implementations for previously stubbed functions:
  * EnumerateNetworkInterfaces
  * EnumerateNetworkProfiles
  * ConfirmSystemAvailability
  * SetBackgroundRequestEnabled
- Add proper debug logging for new implementations
- Update header with new function declarations
- Add Citron copyright notice
- Improve response builder naming for clarity

These implementations return success status with empty results
to allow applications to proceed while proper network interface
management is developed. Debug logging has been added to track
usage of these functions.
2025-02-08 19:58:19 +10:00
Zephyron e3128c6e98
service/sm: improve service manager implementation
- Reorder error codes to match numerical order
- Rename RegisterClient to Initialize in service registration
  to match actual function name
- Update function declaration order in header to match implementation
- Improve QueryPointerBufferSize implementation:
  * Add proper documentation comment
  * Use constexpr for maximum transfer memory size
  * Use std::numeric_limits where appropriate
  * Improve debug logging message
  * Use meaningful constant name

These changes improve code organization and clarity while making
the service manager interface more consistent with Nintendo's
official naming conventions.
2025-02-08 19:50:28 +10:00
Zephyron b89a85e228
service/set: improve settings handling and update serial number
- Update default console serial number prefix from "YUZ" to "CIT"
- Improve GetSettingsItemValueImpl template implementation:
  * Add proper buffer management using std::vector
  * Fix potential buffer overflow issues
  * Use clearer variable naming
  * Add proper size handling with actual_size
  * Use memcpy for safer data copying

These changes improve the safety of settings handling while
updating the emulator's identity to use the Citron prefix
instead of yuzu's.
2025-02-08 19:45:27 +10:00
Zephyron cc48197448
service/hid: reorganize gesture-related functions
- Move SetGestureOutputRanges function registration to be with other
  gesture-related functions (next to ActivateGesture)
- Move SetGestureOutputRanges implementation to be with other
  gesture-related implementations
- Change log level from WARNING to DEBUG for SetGestureOutputRanges
- Move function declaration to private section with other IPC handlers
- Update function ordering to match service registration order

These changes improve code organization by grouping related
functionality together and maintain consistency between the
interface registration and implementation ordering.
2025-02-08 19:39:53 +10:00
Zephyron 0010882f36
service: fix typo in NPNS GetStateChangeEvent function name
Fix spelling of "GetStateChangeEvent" function name in both INpnsSystem
and INpnsUser interfaces. The function was incorrectly spelled as
"GetStateChangeEVent" with a capital 'V'.
2025-02-08 19:35:59 +10:00
Zephyron 28350f7af8
android: optimize build settings and remove x86_64 support
- Enable resource shrinking for release builds
- Disable JNI debugging in release builds
- Switch to optimized proguard configuration file
- Remove x86_64 ABI support
- Fix syntax error in dependencies block
- Update build optimization flags:
  * Enable shrinkResources
  * Use proguard-android-optimize.txt
  * Disable JNI debugging for release builds

These changes improve the release build optimization and reduce
APK size by removing x86_64 support and enabling additional
resource optimization features. The build configuration is also
cleaned up by fixing a syntax error and using more aggressive
optimization settings.
2025-02-08 19:33:53 +10:00
Zephyron 7ecb890a16
common: improve host memory mapping validation
- Add maximum memory size limit of 512GB (Overkill)
- Implement additional safety checks for memory mapping:
  * Validate non-zero addresses
  * Verify address alignment
  * Add length validation against maximum size
- Remove redundant assertion for host_offset alignment
- Remove potentially problematic mapping verification
- Improve error logging for invalid mapping attempts

These changes enhance memory safety by adding proper bounds
checking and validation before performing memory mappings,
while removing a potentially problematic post-mapping
verification step.
2025-02-08 19:32:06 +10:00
Zephyron c31768ec15
core: improve nvdrv and buffer queue implementations
Buffer Queue Changes:
- Add assertion for buffer state in free slots
- Improve error handling for buffer dequeuing
- Add buffer count validation checks
- Update log levels for better diagnostics

NVDRV Changes:
- Add host1x reference to nvhost_nvdec_common
- Improve ioctl error reporting with more detailed messages
- Reorder function declarations in nvhost_ctrl_gpu
- Add stub for unimplemented ioctl command 0x13
- Clean up initialization of boolean flags

These changes improve error handling and debugging capabilities
while adding additional safety checks for buffer management.
The nvdrv interface is also made more robust with better error
reporting and proper hardware access patterns.
2025-02-08 19:29:49 +10:00
Zephyron 227db142e2
sockets: reorder errno values numerically
Reorder the Errno enum values to be in ascending numerical order,
moving NOMEM (12) to be between AGAIN (11) and INVAL (22). This
improves readability and makes it easier to verify completeness
of the error code list.
2025-02-08 19:21:47 +10:00
Zephyron 3aa9c0d151
audio: refactor SDL2 sink implementation
- Move SDLSinkStream class definition to header file
- Add additional error checking for SDL audio device availability
- Limit audio channels to stereo
- Add format verification and warning messages
- Improve audio device initialization with better error handling
- Rename device variable to audio_device_id for clarity
- Add running state flag
- Update copyright header to include citron

This refactoring improves error handling and provides better debug
information when audio device initialization fails. The implementation
is now more robust and provides clearer feedback for troubleshooting
audio issues.
2025-02-08 19:19:52 +10:00
Zephyron 7b6495aced
build: update dependencies and relax version requirements
- Update Vulkan validation layers to 1.4.304.1
- Update Qt to 6.8.2
- Remove strict version requirements for various dependencies
- Update Vulkan-Headers, VulkanMemoryAllocator, and vcpkg submodules
- Reorganize discord-rpc compile options

This change makes the build system more flexible by removing unnecessary
version constraints while ensuring compatibility with newer versions of
key dependencies.
2025-02-08 19:13:51 +10:00
Zephyron d4eca46bba
frontend: Remove telemetry popup and default to disabled
Removes the telemetry opt-in popup dialog and defaults telemetry to disabled.
The ShowTelemetryCallout function is simplified to just:
- Set telemetry to disabled by default
- Apply the setting
- Mark the callout as shown to prevent future popups

This change ensures user privacy by defaulting to no telemetry collection
without requiring user interaction.
2025-02-05 15:13:10 +10:00
Zephyron df1ae19742
discord: Increase game icon resolution to 256x256
Update the tinfoil.media URL requests to fetch game icons at 256x256 resolution
instead of 128x128, providing higher quality game icons in Discord Rich Presence.
2025-02-04 20:28:16 +10:00
Zephyron 4cc01f6c71
audio_core/renderer: Add compressor and splitter support for Rev13
Implement new audio features available in AudioRenderer Revision 13:

- Add AudioRendererRevision enum to track version-specific features
- Implement CompressorEffect with statistics tracking support
- Add SplitterDestination with previous volume reset functionality
- Add version checks for feature compatibility

The compressor provides dynamic range compression with configurable
parameters and optional statistics tracking. The splitter improvements
allow for more flexible volume management between audio transitions.

These changes maintain compatibility with older revisions while enabling
new features in Rev13.
2025-02-04 16:32:59 +10:00
Zephyron 89ecb641f1
api_version: Update Atmosphere version and add citron copyright
Update the Atmosphere release version minor number from 0 to 8 to match
newer firmware versions. Also add copyright notice for citron Emulator
Project.

This change maintains compatibility with newer system versions while
preserving the existing version number format.
2025-02-04 16:26:57 +10:00
Zephyron 3857e6afe9
vulkan: Add Samsung driver workarounds
Add workarounds for Samsung Xclipse GPUs:

- Disable extendedDynamicState3ColorBlendEquation as it is broken in Samsung
  drivers, similar to AMD drivers
- Add Samsung's proprietary driver to the validated driver list for clock
  boosting
- Fix log message to indicate both AMD and Samsung drivers have broken
  color blend equation support

Remove stray logical OR operator from validated_driver condition.
2025-02-04 16:12:07 +10:00
Zephyron 42f44a0c09
Restore original Citra copyright dates in SPDX headers
Update SPDX copyright headers to restore original 2014 Citra Emulator Project
attribution, replacing incorrect 2025 Citron references in:
- bootmanager.cpp
- configure_touch_from_button.cpp
- game_list.cpp
- main.cpp
2025-02-04 14:49:27 +10:00
Zephyron 94c4ef8946
video_core/vulkan: Improve texture format conversion handling
Refactors and improves the texture format conversion system in the Vulkan
renderer:

- Adds proper sRGB to linear conversion for depth formats
- Improves shader accuracy for ABGR8 SRGB to D24S8 conversion
- Adds gamma correction and proper depth range clamping
- Moves GetSupportedFormat implementation to header
- Cleans up format conversion switch statement
- Removes redundant format conversion paths

The changes improve accuracy when converting between color and depth
formats, particularly for sRGB sources. The shader improvements ensure
proper gamma correction and depth range handling.

Technical changes:
- Improves sRGB to linear conversion in fragment shader
- Adds proper depth value clamping
- Consolidates format conversion logic
- Removes duplicate GetSupportedFormat implementation
2025-02-03 17:17:22 +10:00
Zephyron 14065ae7cb
kernel/svc: Refactor UnmapProcessCodeMemory validation
Improve the validation logic in UnmapProcessCodeMemory by:

- Add missing size validation check at the start
- Reorganize validation checks into logical groups
- Simplify error handling using R_UNLESS macros
- Remove redundant page table range check
- Add copyright notice for Citron Emulator Project
- Add ResultInvalidSize constant definition

The changes make the validation code more concise and easier to follow
while maintaining the same validation requirements. Error handling is now
more consistent with other SVC implementations.
2025-02-03 16:13:21 +10:00
Zephyron 9eb32d2d85
android: Reorganize and categorize gradle dependencies
Improve organization of app dependencies in build.gradle.kts by grouping them
into logical categories:

- AndroidX Core & UI components
- AndroidX Navigation
- AndroidX Lifecycle
- AndroidX Other components
- Kotlin dependencies
- Third party libraries

This change makes the dependencies section more maintainable and easier to
understand by providing clear visual separation between different types of
dependencies. No actual dependency versions were changed.

Also fixes minor formatting in runGitCommand function.
2025-02-03 16:11:47 +10:00
Zephyron 71e652123b
memory: Improve debug logging and validation in InvalidateNCE
Add more detailed debug logging and validation to the InvalidateNCE function:

- Add entry debug log showing NCE invalidation request details
- Add upfront validation of memory region before proceeding
- Add debug logs for rasterizer and separate heap handling cases
- Add warning logs for invalid address ranges and failed invalidations
- Improve error message formatting and clarity
- Group related operations with descriptive comments

These changes make it easier to debug NCE invalidation issues by providing
more visibility into the validation steps and failure cases.
2025-02-03 16:10:34 +10:00
Zephyron ddd5e7e887
vulkan: Implement native MSAA resolve in texture cache
Implements hardware-accelerated MSAA resolve functionality in the Vulkan
texture cache instead of relying on compute shaders. This change:

- Adds proper MSAA to non-MSAA image copy support using VkResolveImage
- Creates temporary resolve images with appropriate memory allocation
- Handles format compatibility checks with proper fallback to compute
- Manages image layout transitions and memory barriers
- Preserves existing compute shader fallback for unsupported formats

The implementation follows Vulkan best practices for MSAA resolve
operations and should provide better performance for supported formats.
2025-02-02 15:22:45 +10:00
Zephyron 6b9c239fbd
Remove firmware decryption warning dialog
Removes the warning message box that appears when encryption keys are missing.
The check for keys is still performed but no longer displays a popup to the
user. The firmware version and menu state updates are still maintained.
2025-02-02 15:20:50 +10:00
Zephyron cf43fd8038
vulkan: Add 4KB memory alignment for AMD and Qualcomm drivers
Adds special handling for memory allocation size on AMD and Qualcomm (Adreno)
drivers by aligning allocations to 4KB boundaries. This fixes potential memory
allocation issues on these drivers where unaligned allocations may fail or
cause undefined behavior.

Affected drivers:
- AMD Proprietary (AMDVLK)
- AMD Open Source (RADV)
- Qualcomm Proprietary (Adreno)
2025-02-02 12:07:43 +10:00
Zephyron a1cbcee7ab
vulkan: Fix parameter naming consistency for Android compilation
Renames 'size' parameter to 'length' in IsValidMapping() methods to avoid
conflicts with Android NDK macros that define 'size'. This fixes compilation
issues on Android platforms where the 'size' macro is defined.
2025-02-02 12:06:07 +10:00
Zephyron 19ce9d695e
fix: compilation errors with Qt and Discord RPC
- Downgrade Qt version from 6.8.1 to 6.7.3 as 6.8.1 is not yet widely available
- Add USE_DISCORD_PRESENCE check around discord-rpc compile options to prevent
  build errors when Discord integration is disabled
2025-02-02 09:20:11 +10:00
Zephyron 44944c4d80
video_core: Add new shader format conversion pipelines
Adds several new shader-based format conversion pipelines to support additional
texture formats and operations:

- RGBA8 to BGRA8 conversion
- YUV420/RGB conversions
- BC7 to RGBA8 decompression
- ASTC HDR to RGBA16F decompression
- RGBA16F to RGBA8 conversion
- Temporal dithering
- Dynamic resolution scaling

Updates the texture cache runtime to handle these new conversion paths and adds
helper functions to check format compatibility for dithering and scaling
operations.

The changes include:
- New shader files and CMake entries
- Additional conversion pipeline setup in BlitImageHelper
- Extended format conversion logic in TextureCacheRuntime
- New format compatibility check helpers
2025-02-01 23:08:34 +10:00
Zephyron 8bda64895f
cmake: Update Qt download configuration and aqtinstall version
- Switch from specific Qt modules to downloading all modules using '-m all'
- Update aqtinstall version from v3.1.18 to v3.2.0

This change allows for a more complete Qt installation and uses a newer
version of the aqtinstall tool.
2025-02-01 22:00:12 +10:00
Zephyron f4b9e54b22
common/nvdrv: improve memory validation and error handling
Implements several improvements to memory handling and validation:

- host_memory: Add IsValidMapping() and IsDirectMappingEnabled() methods to
  validate memory access
- host_memory: Fix virtual base offset calculation to use proper pointer
  arithmetic
- host_memory: Add size field to track allocation size
- nvhost_ctrl_gpu: Return InvalidState instead of InvalidValue for TPC mask
  buffer size validation
- Update copyright year for citron

The changes improve memory safety by adding explicit validation checks and
fixing pointer arithmetic in the virtual memory implementation.
2025-02-01 21:50:33 +10:00
Zephyron 70a9f20ae1
common: add missing <memory> include in common_types.h
Adds missing <memory> header include in common_types.h. This header is
needed for std::unique_ptr and other smart pointer types that may be used
by code including this header.
2025-02-01 21:47:55 +10:00
Zephyron 076d0e618d
build: update Qt to 6.8.1 and add permissive flag for discord-rpc
Updates the Qt dependency from 6.7.3 to 6.8.1 when downloading Qt.
Adds -fpermissive compile flag for discord-rpc target to fix build issues.
2025-02-01 21:47:03 +10:00
Zephyron ecc32958ec
nvdrv: Add GetTpcMasks2 support and improve memory mapping validation
This commit makes two main changes:

1. Adds support for GetTpcMasks2 (ioctl 0x13) in nvhost_ctrl_gpu:
- Implements new GetTpcMasks2 method to handle TPC mask queries
- Adds IoctlGetTpcMasks structure to store mask parameters
- Returns conservative single TPC configuration for compatibility

2. Enhances memory mapping validation in HostMemory:
- Adds verification check after memory mapping operations
- Improves error handling for direct mapped address enabling
- Adds logging for mapping and direct address failures

Additional changes:
- Updates copyright headers to include citron Emulator Project
- Improves error handling and validation in several paths
- Adds debug logging for TPC mask operations

This improves GPU virtualization support and memory mapping reliability.
2025-02-01 19:48:11 +10:00
Zephyron e8bbdbce42
externals: Update Vulkan and related dependencies
Update the following external dependencies:
- Vulkan-Headers e43027a -> 39f924b
- Vulkan-Utility-Libraries 8ec8482 -> fe7a09b
- VulkanMemoryAllocator 7ab8483 -> 72c309a
- libadrenotools 5cd3f5c -> 8fae8ce
- vcpkg 2b8927f -> 2ded45c
2025-02-01 19:44:36 +10:00
Zephyron 0216eaa071
feat: Add RAM usage overlay and improve thermal display
- Add new RAM usage overlay showing current/max memory usage with color gradient
- Simplify thermal overlay to show temperature in C/F with color indication
- Add SHOW_RAM_OVERLAY boolean setting (disabled by default in UI)
- Set default values for thermal overlay and black backgrounds to true
- Update copyright headers to include Citron Emulator Project

The RAM overlay displays native heap usage with color gradient from green
(low usage) to red (high usage). The thermal display was simplified to show
just temperatures while maintaining the color indication based on system
thermal status.
2025-02-01 19:18:35 +10:00
Zephyron 137034ca2c
qt: Update citron logo in About dialog
Updates the 256x256 citron logo displayed in the Help -> About dialog to
match current branding guidelines.
2025-02-01 16:59:32 +10:00
Zephyron 8f76ef2579
video_core: Add sRGB to D24S8 depth-stencil conversion support
Implements conversion from sRGB color formats to D24S8 depth-stencil format
in the Vulkan renderer. This change includes:

- New fragment shader convert_abgr8_srgb_to_d24s8.frag that handles proper
  sRGB to linear conversion before depth calculation
- Added shader to CMake build system
- Extended BlitImageHelper with new conversion pipeline and methods
- Updated texture cache to handle sRGB to D24S8 format conversion paths

The conversion properly handles sRGB color space by first converting to
linear space before calculating luminance values for the depth component,
while preserving alpha channel data for the stencil component.
2025-02-01 16:57:49 +10:00
Zephyron 4e8d00f034
string_util: Replace deprecated wstring_convert with direct UTF conversions
Removes usage of std::wstring_convert and std::codecvt_utf8_utf16 which are
deprecated since C++17. Implements direct UTF conversions for:

- UTF16ToUTF8: Manual conversion with proper surrogate pair handling
- UTF8ToUTF16: Direct conversion supporting full Unicode range
- UTF8ToUTF32: New implementation with proper code point extraction

The new implementations are more robust and handle edge cases better while
avoiding deprecated functionality. Windows-specific code paths remain unchanged
using the existing UTF16W conversions.

This change improves maintainability and removes compiler warnings about
deprecated features while maintaining full Unicode support.
2025-02-01 12:27:03 +10:00
Zephyron f638922129
common: Improve error handling in host memory management
Add proper error handling and recovery mechanisms for memory mapping
operations instead of using assertions.
2025-02-01 11:45:40 +10:00
Zephyron a96216ff35
Android: Update build configuration for Android 15
Update build configuration to support Android 15 (API 35) devices and
optimize build settings for better compatibility.
2025-02-01 11:44:39 +10:00
Zephyron 6ab82e8eeb
service: Implement rebootless system update stubs and types
Adds initial support for rebootless system update related functionality:

- Add system archive title IDs for ApplicationBlackList, RebootlessSystemUpdateVersion,
  and ContentActionTable
- Add NS service result codes for system update operations
- Implement stubs for ISystemUpdateControl::SetupToReceiveSystemUpdate and
  RequestCheckLatestUpdateIncludesRebootlessUpdate
- Add RebootlessSystemUpdateVersion settings type and implement
  GetRebootlessSystemUpdateVersion in SET service
- Fix GetSettingsItemValueImpl template implementation

This provides basic infrastructure for handling system updates, particularly
the rebootless update feature, though actual update functionality remains
stubbed.
2025-01-30 22:10:08 +10:00
vampiric_x 733721f0a1 android: Fix non-scrollable legal disclaimer on setup 2025-01-30 01:59:00 +01:00
Zephyron 613099703a
kernel/svc: Implement InitialProcessIdRange and improve process exit handling
- Replace stubbed InitialProcessIdRange implementation with proper bounds (1-0x50)
- Add handle and info_sub_id validation for InitialProcessIdRange
- Replace process exit ASSERT with graceful error handling and logging
- Add try-catch block around system.Exit() for safer shutdown
- Add atomic header inclusion for binder.h

This improves system call reliability by properly implementing process ID
range checks and adding safer process exit handling with proper error logging.
2025-01-29 13:17:07 +10:00
Zephyron 9a3d4f0489
ui: Update repository URLs to git.citron-emu.org
Updates all GitHub repository URLs to point to the new self-hosted Git instance
at git.citron-emu.org. This includes:

- Links in the About dialog UI and translations
- Android app string resources
- Documentation/wiki links
- Source code comments

The website URL (citron-emu.org) and support links remain unchanged.
2025-01-28 17:33:57 +10:00
Zephyron 8c630a8bea
network: Add NOMEM errno handling for socket operations
Implements support for ENOMEM (errno 12) across the network stack:
- Added NOMEM to Network::Errno enum
- Added NOMEM = 12 to sockets Errno enum
- Added translation case in sockets_translate.cpp

This is the first step towards addressing the 0.0 FPS bug that occurs
when the system runs out of memory during socket operations. Previously,
these operations would trigger an unimplemented assertion, causing the
emulator to halt. Now the error will be properly propagated to the guest
application.
2025-01-28 16:20:54 +10:00
Zephyron 2e4db14bc1
qt: Replace deprecated stateChanged with checkStateChanged
Updates QCheckBox signal connections to use checkStateChanged instead of
the deprecated stateChanged signal. This change affects:

- qt_controller.cpp
- configure_filesystem.cpp
- configure_input.cpp
- configure_input_advanced.cpp
- configure_system.cpp
- configure_ui.cpp
- shared_widget.cpp

Also updates lambda signatures to use Qt::CheckState instead of int for
the state parameter where needed.
2025-01-27 15:36:29 +10:00
Zephyron c36151d6e3
vulkan: Relax VRAM allocation limits for better stability
Adjusts VRAM allocation strategy to be more conservative while maintaining
performance:

- Increases reserve memory from 1/8th to 1/4th (max 2GB) for discrete GPUs
- Increases base memory limit from 6GB to 8GB
- Doubles resolution scaling memory from 1GB to 2GB per scale factor
- Reduces system memory reservation from 8GB to 4GB for integrated GPUs
- Increases maximum memory limit from 4GB to 6GB for integrated GPUs

These changes help prevent memory leaks while still providing adequate
VRAM for optimal performance.
2025-01-27 15:34:00 +10:00
Zephyron 33f8cd0c7e deps: Update Vulkan dependencies and remove fmt version constraint
- Update Vulkan-Headers to e43027a (1.4.306)
- Update Vulkan-Utility-Libraries to 8ec8482
- Update vcpkg to 2b8927f
- Remove version constraint for fmt package requirement
- Update VulkanHeaders version requirement to 1.4.306

This updates several external dependencies to their latest versions and
removes the specific version requirement for fmt while maintaining the
REQUIRED flag. The Vulkan-Headers version requirement is updated to match
the new submodule version.
2025-01-27 13:25:16 +10:00
Zephyron c5a2689cef android: Update Gradle and Java version requirements
Updates Android build configuration to use newer versions:
- Upgrade Java/JVM target from 17 to 21
- Update Android Gradle Plugin from 8.1.2 to 8.8.0

These changes modernize the Android build system to use the latest LTS
version of Java and the most recent stable Android Gradle Plugin.
This enables access to newer language features and build optimizations
while maintaining compatibility with modern Android development tools.
2025-01-27 00:47:43 +10:00
Zephyron f380744c61 android: Fix compilation by adding missing log.h include
Adds missing include for common/logging/log.h in gpu.h which was causing
compilation failures on Android. This header is needed for logging
functionality used in GPU-related operations.

The include was previously indirectly available through other headers,
but making it explicit improves code clarity and prevents potential
future compilation issues.
2025-01-27 00:46:46 +10:00
Zephyron b7e11d3724 service: Implement GPU error handling IPC commands for AM
Implements several IPC commands in IApplicationFunctions related to GPU error
handling and system events:

- EnableApplicationAllThreadDumpOnCrash (cmd 124)
- SetDelayTimeToAbortOnGpuError (cmd 131)
- TryPopFromNotificationStorageChannel (cmd 151)
- SetHdcpAuthenticationActivated (cmd 170)
- GetLaunchRequiredVersion (cmd 180)
- UpgradeLaunchRequiredVersion (cmd 181)

Also adds the LaunchRequiredVersion struct definition to the header file.
These are currently stubbed implementations that log warnings when called.

REFS: switchbrew.org/wiki/Applet_Manager_services#GetGpuErrorDetectedSystemEvent
2025-01-27 00:45:27 +10:00
Zephyron be191f740a buffer_cache: Simplify storage buffer binding logic
Reverts overly restrictive storage buffer validation and size calculation
that was causing rendering issues in The Legend of Zelda: Tears of the
Kingdom, particularly in underground/depth areas. The simplified approach:

- Uses GetMemoryLayoutSize() instead of manual page probing
- Removes unnecessary 4GB memory bounds validation
- Streamlines address translation and alignment handling

This fixes numerous reported cases of missing or corrupted rendering in
TOTK's underground areas where storage buffer operations are heavily used
for depth-related effects.
2025-01-26 16:13:05 +10:00
Zephyron a5d62fa4ec nvnflinger: Implement reference counting for binder objects
Implements proper reference counting for binder objects based on the official
documentation. This adds both weak and strong reference counting support to
the IBinder interface and its implementations (BufferQueueProducer and
BufferQueueConsumer).

The implementation follows the documented behavior where:
- type 0 affects weak references
- type 1 affects strong references
- During initialization: {addval=1, type=0} followed by {addval=1, type=1}
- For onFirstRef: {addval=1, type=1}
- For onLastStrongRef: {addval=-1, type=1}

Reference counters are implemented using std::atomic to ensure thread safety.

REFS: switchbrew.org/wiki/Nvnflinger_services#AdjustRefcount
2025-01-26 14:21:36 +10:00
Zephyron a6063bbd64 service: vi: Implement missing IApplicationDisplayService functions
Implements missing functions and improves permission handling in the VI
(Visual Interface) IApplicationDisplayService based on official documentation.

Key changes:
- Add session type enum to properly handle vi:u/vi:s/vi:m permissions
- Implement GetIndirectLayerImageCropMap for handling cropped layer images
- Implement GetDisplayVsyncEventForDebug for debug vsync event handling
- Add proper permission checks for GetSystemDisplayService and GetManagerDisplayService
- Improve AppletResourceUserId validation in OpenLayer
- Clean up logging and error handling

The changes follow the official documentation for permission handling:
- vi:u sessions can only use GetRelayService
- vi:s sessions can use everything except GetManagerDisplayService
- vi:m sessions can use all commands

REFS: switchbrew.org/wiki/Display_services#IApplicationDisplayService
2025-01-26 13:27:06 +10:00
Zephyron 924c06d88f Revert "core/hle: Reorganize ErrorModule enum numerically"
This reverts commit b55be320b7.
2025-01-25 18:24:30 +10:00
Zephyron b55be320b7 core/hle: Reorganize ErrorModule enum numerically
Reorganizes the ErrorModule enum in result.h by grouping error codes into
numerical ranges with descriptive comments. This improves readability and
makes it easier to:

- Find specific modules by their number
- See which numbers are used/unused in each range
- Understand the overall distribution of module numbers

Also standardizes naming conventions across modules and fixes some
inconsistent casing (e.g. FS -> Fs, HDCP -> Hdcp).

REFS: switchbrew.org/w/index.php?title=Error_codes
2025-01-25 18:02:43 +10:00
Zephyron 5ba970b574 service: sm: Update to match official IPC interface
Updates the SM service implementation to better match the official
"nn::sm::detail::IUserInterface" interface. Key changes include:

- Replace Initialize with RegisterClient command (cmd 0)
- Add DetachClient command implementation (cmd 4)
- Update service name handling to use u64-encoded names
- Add proper PID descriptor handling for RegisterClient/DetachClient
- Add ResultNotAllowed error code
- Update handler registration for both CMIF and TIPC

This brings the implementation closer to the official documentation while
maintaining compatibility with existing code.

Refs: switchbrew.org/wiki/Services_API#sm:
2025-01-25 15:20:01 +10:00
Zephyron 58ed33dd9f ui: Remove save states menu and unused help links
Removes the save states menu and unused help menu items as they require
additional research and implementation work. Specifically:

- Remove save states menu and associated actions (Save/Load)
  as proper implementation requires more research
- Remove unused help menu items:
  * Open Mods Page
  * Open Quickstart Guide
  * Open FAQ
- Keep core help functionality (Report Compatibility and About)
- Reorder menu properties for better organization

This change helps maintain a cleaner UI by removing placeholder
features that are not yet ready for implementation.
2025-01-25 14:58:40 +10:00
Zephyron c279df9cfe service: mm: Refactor Memory Management service implementation
Refactors the MM (Memory Management) service implementation with improved:

- Session management using a vector of Session objects instead of global vars
- Type safety with proper enums and member encapsulation
- Error handling with consistent patterns
- Modern C++ features (std::erase_if, std::find_if, emplace_back)
- Logging with detailed debug messages
- Code organization and const correctness

Key changes:
- Add Session class with proper encapsulation
- Add EventClearMode enum (Manual = 0, Auto = 1)
- Update Module enum naming for consistency
- Implement proper session tracking and lookup
- Add detailed parameter logging
- Use modern C++ algorithms for session management

The implementation now properly handles multiple sessions and matches
the documented nn::mmnv::IRequest interface more closely.

Refs: switchbrew.org/wiki/Display_services#mm:u
2025-01-25 14:55:50 +10:00
Zephyron 0adeac26af service: mm: Implement proper parameter handling for MM service
Add proper type definitions and parameter handling for the Memory Management
(mm:u) service based on the Switch documentation:

- Add Module enum for hardware components (CPU, GPU, EMC, etc)
- Add Priority and Setting type definitions as u32
- Add EventClearMode enum for initialization
- Implement proper parameter handling for all IPC calls
- Add detailed logging with parameter values

The Module enum now properly reflects the documented hardware components:
CPU, GPU, EMC, System Bus, Memory Select, and NVIDIA modules (NVDEC,
NVENC, NVJPG).

This makes the implementation match the documented nn::mmnv::IRequest
interface.

Refs: switchbrew.org/wiki/Display_services#mm:u
2025-01-25 14:23:22 +10:00
Zephyron 37677052c1 feat: implement modern dark theme and loading screen redesign
- Redesign loading screen progress bar with gradient animation
- Update loading screen typography using Segoe UI
- Add comprehensive dark theme styling to main window
- Modernize menu, toolbar, and dock widget appearances
2025-01-25 13:50:48 +10:00
Zephyron 774d8d9eba service/nvdrv: Relax GPU validation and improve error handling
Relaxes validation checks in the NVDRV GPU service and improves error notifier
handling to prevent potential hangs. Key changes:

- Remove strict size validation in SetErrorNotifier
- Relax GPFIFO entry count validation to only check for non-zero values
- Add proper error notifier state tracking in GPU class
- Improve debug logging messages

The previous strict validation was causing issues with some games like ACNH.
These changes maintain necessary checks while being more permissive with
edge cases that don't impact functionality.

Technical changes:
- Store error notifier state in GPU class for future implementation
- Remove upper bound check on GPFIFO entries
- Simplify error notifier setup flow

This should resolve hanging issues while maintaining core functionality.
2025-01-21 16:07:44 +10:00
Zephyron d7dc87bbf3 service/nvdrv: Implement stubbed GPU functions
Implements several previously stubbed functions in the NVDRV service:
- Initialize proper transfer memory handling
- Add error notifier configuration
- Implement channel timeout and timeslice management
- Add object context allocation and tracking
- Add GPU interface stubs for new functionality

The changes improve the accuracy of GPU-related operations while maintaining
compatibility with the existing codebase. All functions now properly validate
parameters and handle endianness correctly using _le types.
2025-01-20 18:04:11 +10:00
Zephyron 07024f7ea6 ui: Add Save States menu stubs
Adds UI elements for future save state support:
- New "Save States" menu in the main menubar
- Save and Load action items with keyboard shortcuts
- No functionality implemented yet, just UI stubs
2025-01-20 17:14:46 +10:00
Zephyron 04f9d8b61a shader: Implement EmitInvocationInfo across all backends
- Add proper invocation info handling for tessellation and fragment stages
- Return patch vertices info shifted by 16 bits for tessellation stages
- Return sample mask shifted by 16 bits for fragment stage
- Return standard format (0x00ff0000) for compute and other stages
- Implement consistently across SPIRV, GLSL, and GLASM backends
- Remove stubbed warning message
2025-01-20 17:02:01 +10:00
Zephyron b574aba98b service-am: Handle panic conditions in SetTerminateResult
- Prevents propagation of panic conditions when setting termination results
- Previously, panic error codes could trigger cascading crashes
- Only stores non-error termination results while allowing successful completion
- Fixes crash when applications set panic-related termination codes (0x1A80A)
2025-01-20 16:06:08 +10:00
Zephyron 6d225eb94a service: vi: Remove stubbed warning from GetManagerDisplayService
- The GetManagerDisplayService function in IApplicationDisplayService is fully implemented, so remove the stubbed warning and change the log level to DEBUG to match its implementation status.
2025-01-20 16:03:43 +10:00
Zephyron 5a1a2f3eca fix: update vcpkg baseline to avoid VS2019 build tools
- Updates vcpkg baseline to 7adc2e4d49e8d0efc07a369079faa6bc3dbb90f3 to fix Windows compilation issues by avoiding Visual Studio 2019 build tools and using the latest.
2025-01-19 18:24:53 +10:00
Zephyron d4d3061eb7 arm/video: Fix shader extension and exception handling
Two main changes in this commit:

1. Replace NVIDIA-specific GL_NV_gpu_shader5 extension with the more widely
   supported GL_EXT_shader_explicit_arithmetic_types_float16 in the scaleforce
   shader. This improves compatibility across different GPU vendors.

2. Refactor ARM32 exception handling:
   - Restructure exception cases for better readability
   - Update exception handling to match current Dynarmic API
   - Fix indentation in switch statement
   - Remove AccessViolation case as it's no longer supported in current API

These changes improve shader compatibility and align the exception handling
with the current Dynarmic implementation.
2025-01-18 19:09:03 +10:00
Zephyron 450d80fc81 Remove SPIRV-Tools and SPIRV-Headers submodules temporarily
The SPIRV-Tools and SPIRV-Headers submodules are being temporarily removed
to fix their directory structure. They will be re-added in a follow-up
commit with the correct directory organization.
2025-01-18 17:04:33 +10:00
Zephyron b938893599 memory: Improve null pointer and unmapped memory handling
- Update vcpkg baseline to a42af01b72c28a8e1d7b48107b33e4f286a55ef6
- Add SPIRV-Tools and SPIRV-Headers as submodules
- Update Vulkan-related submodules to latest stable versions
- Improve memory access error handling:
  - Add specific handling for null pointer accesses in ARM32 emulation
  - Return 0 for null pointer reads instead of undefined behavior
  - Silently ignore writes to null pointers
  - Add more detailed error messages distinguishing between null pointer
    access and other unmapped memory errors
  - Treat addresses below 0x1000 as potential null pointer accesses

These changes should provide more graceful handling of null pointer
accesses and improve stability when running games that attempt invalid
memory operations.
2025-01-18 15:20:13 +10:00
vampiric_x 07b949025f Add QT Network package 2025-01-18 02:16:13 +01:00
vampiric_x 913cc27e3a feat(network): Ip input field for multiplayer room creation 2025-01-17 19:03:31 +01:00
Zephyron 3698478977 android: Fix battery temperature reading in EmulationFragment
Replaces the battery temperature reading implementation with a more
compatible approach using ACTION_BATTERY_CHANGED broadcast intent.
This change provides better backwards compatibility and adds proper
error handling for the temperature reading functionality.
2025-01-17 19:59:13 +10:00
Zephyron 382999025a shader_recompiler: Add stubs for CSM/FCSM flow test conditions
Add stub implementations for previously unhandled flow test conditions in the
shader recompiler's IR emitter. These conditions were previously throwing
"Not Implemented" exceptions when encountered.

The following flow test cases are now stubbed:
- FCSM_TR (Fragment Shader Coarse/Fine Mode Test and Reject)
- CSM_TA (Coarse/Fine Mode Test Accept)
- CSM_TR (Coarse/Fine Mode Test and Reject)
- CSM_MX (Coarse/Fine Mode Maximum)
- FCSM_TA (Fragment Shader Coarse/Fine Mode Test Accept)
- FCSM_MX (Fragment Shader Coarse/Fine Mode Maximum)

Currently these stubs:
1. Return false (ir.Imm1(false)) as a placeholder value
2. Log a warning message indicating the stub
3. Allow shaders using these conditions to compile rather than fail

This is a step toward proper implementation of coarse/fine mode shader
operations. The stubs prevent crashes while making it clear which code paths
need full implementation.

Technical notes:
- Removed the previous FCSM_TR implementation that used flag operations
- Added consistent warning messages for tracking stub usage
- Kept within the existing GetFlowTest switch statement structure
2025-01-17 19:28:11 +10:00
Zephyron ee0beea82a Remove x86-64 ISA compatibility flags and toolchain
Remove the x86-64 instruction set architecture (ISA) compatibility flags and
associated toolchain file that were setting CPU architecture compatibility
levels. This simplifies the build system by removing the custom ISA flag
handling and x86-64-v2 option.

Changes:
- Remove x86-64 ISA flags configuration block from CMakeLists.txt
- Delete unused x86-64-toolchain.cmake file
- Remove CITRON_USE_X86_64_V2 option
2025-01-17 15:43:31 +10:00
Zephyron 62de5aa9de Downgrade Android SDK and build tools
- Reduce compileSdkVersion and targetSdk from 35 to 34
- Change NDK version to 26.1.10909125
- Downgrade Android Gradle Plugin from 8.8.0 to 8.1.2
- Add androidx.constraintlayout dependency

These changes improve compatibility with current Android development
environment and add necessary layout support.
2025-01-17 15:16:15 +10:00
vampiric_x 43170513b6 Revert "shader-recompiler: implement FCSM_TR flow test case"
This reverts commit 496b010927.
2025-01-17 01:27:35 +01:00
381 changed files with 9603 additions and 1228 deletions

View File

@ -17,6 +17,45 @@ if (MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /WX-")
endif()
# PGO Configuration
option(CITRON_ENABLE_PGO_INSTRUMENT "Enable Profile-Guided Optimization instrumentation build" OFF)
option(CITRON_ENABLE_PGO_OPTIMIZE "Enable Profile-Guided Optimization optimization build" OFF)
if(MSVC)
if(CITRON_ENABLE_PGO_INSTRUMENT)
string(APPEND CMAKE_CXX_FLAGS_RELEASE " /GL /LTCG:PGINSTRUMENT")
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " /LTCG:PGINSTRUMENT")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " /LTCG:PGINSTRUMENT")
elseif(CITRON_ENABLE_PGO_OPTIMIZE)
string(APPEND CMAKE_CXX_FLAGS_RELEASE " /GL /LTCG:PGOPTIMIZE")
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " /LTCG:PGOPTIMIZE")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " /LTCG:PGOPTIMIZE")
endif()
else()
# GCC and Clang PGO flags
if(CITRON_ENABLE_PGO_INSTRUMENT)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
string(APPEND CMAKE_CXX_FLAGS_RELEASE " -fprofile-instr-generate")
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " -fprofile-instr-generate")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " -fprofile-instr-generate")
else() # GCC
string(APPEND CMAKE_CXX_FLAGS_RELEASE " -fprofile-generate")
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " -fprofile-generate")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " -fprofile-generate")
endif()
elseif(CITRON_ENABLE_PGO_OPTIMIZE)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
string(APPEND CMAKE_CXX_FLAGS_RELEASE " -fprofile-instr-use=default.profdata")
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " -fprofile-instr-use=default.profdata")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " -fprofile-instr-use=default.profdata")
else() # GCC
string(APPEND CMAKE_CXX_FLAGS_RELEASE " -fprofile-use")
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " -fprofile-use")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " -fprofile-use")
endif()
endif()
endif()
# Check if SDL2::SDL2 target exists; if not, create an alias
if (TARGET SDL2::SDL2-static)
add_library(SDL2::SDL2 ALIAS SDL2::SDL2-static)
@ -98,21 +137,22 @@ endif()
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
if (ANDROID AND CITRON_DOWNLOAD_ANDROID_VVL)
set(vvl_version "sdk-1.3.261.1")
set(vvl_version "1.4.309.0")
set(vvl_zip_file "${CMAKE_BINARY_DIR}/externals/vvl-android.zip")
if (NOT EXISTS "${vvl_zip_file}")
set(vvl_lib_path "${CMAKE_CURRENT_SOURCE_DIR}/src/android/app/src/main/jniLibs/arm64-v8a/")
set(vvl_final_lib "${vvl_lib_path}/libVkLayer_khronos_validation.so")
if (NOT EXISTS "${vvl_final_lib}")
# Download and extract validation layer release to externals directory
if (NOT EXISTS "${vvl_zip_file}")
set(vvl_base_url "https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases/download")
file(DOWNLOAD "${vvl_base_url}/${vvl_version}/android-binaries-${vvl_version}-android.zip"
file(DOWNLOAD "${vvl_base_url}/vulkan-sdk-${vvl_version}/android-binaries-${vvl_version}.zip"
"${vvl_zip_file}" SHOW_PROGRESS)
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${vvl_zip_file}"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
endif()
# Copy the arm64 binary to src/android/app/main/jniLibs only if it doesn't exist
set(vvl_lib_path "${CMAKE_CURRENT_SOURCE_DIR}/src/android/app/src/main/jniLibs/arm64-v8a/")
set(vvl_lib_file "${vvl_lib_path}/libVkLayer_khronos_validation.so")
if (NOT EXISTS "${vvl_lib_file}")
# Copy the arm64 binary to src/android/app/main/jniLibs
file(COPY "${CMAKE_BINARY_DIR}/externals/android-binaries-${vvl_version}/arm64-v8a/libVkLayer_khronos_validation.so"
DESTINATION "${vvl_lib_path}")
endif()
@ -129,22 +169,39 @@ if (CITRON_USE_BUNDLED_VCPKG)
if (CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a")
set(VCPKG_TARGET_TRIPLET "arm64-android")
# Detect host system (Windows or Linux)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(VCPKG_HOST_TRIPLET "x64-windows")
else()
set(VCPKG_HOST_TRIPLET "x64-linux")
endif()
# this is to avoid CMake using the host pkg-config to find the host
# libraries when building for Android targets
set(PKG_CONFIG_EXECUTABLE "aarch64-none-linux-android-pkg-config" CACHE FILEPATH "" FORCE)
elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64")
set(VCPKG_TARGET_TRIPLET "x64-android")
# Detect host system (Windows or Linux)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(VCPKG_HOST_TRIPLET "x64-windows")
else()
set(VCPKG_HOST_TRIPLET "x64-linux")
endif()
set(PKG_CONFIG_EXECUTABLE "x86_64-none-linux-android-pkg-config" CACHE FILEPATH "" FORCE)
else()
message(FATAL_ERROR "Unsupported Android architecture ${CMAKE_ANDROID_ARCH_ABI}")
endif()
# Add these lines to ensure proper Android toolchain setup
set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${ANDROID_NDK}/build/cmake/android.toolchain.cmake")
set(VCPKG_CRT_LINKAGE "dynamic")
set(VCPKG_LIBRARY_LINKAGE "static")
endif()
if (MSVC)
set(VCPKG_DOWNLOADS_PATH ${PROJECT_SOURCE_DIR}/externals/vcpkg/downloads)
set(NASM_VERSION "2.16.01")
set(NASM_VERSION "2.16.03")
set(NASM_DESTINATION_PATH ${VCPKG_DOWNLOADS_PATH}/nasm-${NASM_VERSION}-win64.zip)
set(NASM_DOWNLOAD_URL "https://github.com/yuzu-mirror/ext-windows-bin/raw/master/nasm/nasm-${NASM_VERSION}-win64.zip")
set(NASM_DOWNLOAD_URL "https://www.nasm.us/pub/nasm/releasebuilds/${NASM_VERSION}/win64/nasm-${NASM_VERSION}-win64.zip")
if (NOT EXISTS ${NASM_DESTINATION_PATH})
file(DOWNLOAD ${NASM_DOWNLOAD_URL} ${NASM_DESTINATION_PATH} SHOW_PROGRESS STATUS NASM_STATUS)
@ -231,7 +288,7 @@ endif()
if (ENABLE_COMPATIBILITY_LIST_DOWNLOAD AND NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
message(STATUS "Downloading compatibility list for citron...")
file(DOWNLOAD
https://api.yuzu-mirror.org/gamedb/
https://api.citron-emu.org/gamedb/
"${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json" SHOW_PROGRESS)
endif()
if (NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
@ -312,7 +369,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
# Enforce the search mode of non-required packages for better and shorter failure messages
find_package(Boost REQUIRED context)
find_package(enet MODULE)
find_package(fmt 9 REQUIRED)
find_package(fmt 11 REQUIRED)
if (CITRON_USE_LLVM_DEMANGLE)
find_package(LLVM MODULE COMPONENTS Demangle)
endif()
@ -327,7 +384,7 @@ find_package(ZLIB REQUIRED)
find_package(zstd REQUIRED)
if (NOT CITRON_USE_EXTERNAL_VULKAN_HEADERS)
find_package(VulkanHeaders 1.4.304 REQUIRED)
find_package(VulkanHeaders 1.4.313 REQUIRED)
endif()
if (NOT CITRON_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)
@ -335,19 +392,19 @@ if (NOT CITRON_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)
endif()
if (ENABLE_LIBUSB)
find_package(libusb 1.0.24 MODULE)
find_package(libusb MODULE)
endif()
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
find_package(xbyak 6 CONFIG)
find_package(xbyak CONFIG)
endif()
if (ARCHITECTURE_arm64)
find_package(oaknut 2.0.1 CONFIG)
find_package(oaknut CONFIG)
endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
find_package(dynarmic 6.4.0 CONFIG)
find_package(dynarmic CONFIG)
endif()
if (ENABLE_CUBEB)
@ -359,12 +416,12 @@ if (USE_DISCORD_PRESENCE)
endif()
if (ENABLE_WEB_SERVICE)
find_package(cpp-jwt 1.4 CONFIG)
find_package(httplib 0.12 MODULE COMPONENTS OpenSSL)
find_package(cpp-jwt CONFIG)
find_package(httplib MODULE COMPONENTS OpenSSL)
endif()
if (CITRON_TESTS)
find_package(Catch2 3.0.1 REQUIRED)
find_package(Catch2 REQUIRED)
endif()
# boost:asio has functions that require AcceptEx et al
@ -373,11 +430,11 @@ if (MINGW)
endif()
if(ENABLE_OPENSSL)
find_package(OpenSSL 1.1.1 REQUIRED)
find_package(OpenSSL REQUIRED)
endif()
if (UNIX AND NOT APPLE)
find_package(gamemode 1.7 MODULE)
find_package(gamemode MODULE)
endif()
# Please consider this as a stub
@ -416,13 +473,16 @@ endif()
add_subdirectory(externals)
if (USE_DISCORD_PRESENCE)
target_compile_options(discord-rpc PRIVATE -fpermissive)
endif()
if (ENABLE_QT)
if (NOT USE_SYSTEM_QT)
download_qt(6.7.3)
download_qt(6.8.2)
endif()
find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent)
find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent Network)
if (UNIX AND NOT APPLE)
find_package(Qt6 REQUIRED COMPONENTS DBus)
@ -484,7 +544,7 @@ list(APPEND CITRON_QT_COMPONENTS2 Multimedia)
endif()
if (NOT CITRON_USE_BUNDLED_FFMPEG)
# Use system installed FFmpeg
find_package(FFmpeg 4.3 REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS})
find_package(FFmpeg REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS})
endif()
if(ENABLE_QT)
@ -673,36 +733,3 @@ if(ENABLE_QT AND UNIX AND NOT APPLE)
install(FILES "dist/org.citron_emu.citron.metainfo.xml"
DESTINATION "share/metainfo")
endif()
# Set CPU architecture compatibility flags
if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
# Default to x86-64 baseline for maximum compatibility
set(ISA_FLAGS "-march=x86-64")
# Allow override via CMake option
option(CITRON_USE_X86_64_V2 "Enable x86-64-v2 instruction set" OFF)
if(CITRON_USE_X86_64_V2)
set(ISA_FLAGS "-march=x86-64-v2")
endif()
# Set for main project
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ISA_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ISA_FLAGS}")
# Set for vcpkg dependencies
set(VCPKG_CXX_FLAGS "${ISA_FLAGS}")
set(VCPKG_C_FLAGS "${ISA_FLAGS}")
# Set toolchain options for vcpkg
set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/x86-64-toolchain.cmake")
# Ensure we're not getting overridden by system defaults
add_compile_options(${ISA_FLAGS})
# Force disable higher ISA levels
add_compile_definitions(
__x86_64_v3__=0
__x86_64_v4__=0
)
endif()

View File

@ -68,18 +68,18 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out
set(arch_path "mingw_64")
elseif (MSVC)
if ("arm64" IN_LIST ARCHITECTURE)
set(arch_path "msvc2019_arm64")
set(arch_path "msvc2022_arm64")
elseif ("x86_64" IN_LIST ARCHITECTURE)
set(arch_path "msvc2019_64")
set(arch_path "msvc2022_64")
else()
message(FATAL_ERROR "Unsupported bundled Qt architecture. Enable USE_SYSTEM_QT and provide your own.")
endif()
set(arch "win64_${arch_path}")
if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64")
set(host_arch_path "msvc2019_64")
set(host_arch_path "msvc2022_64")
elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "ARM64")
set(host_arch_path "msvc2019_64")
set(host_arch_path "msvc2022_64")
endif()
set(host_arch "win64_${host_arch_path}")
else()
@ -134,12 +134,12 @@ function(download_qt_configuration prefix_out target host type arch arch_path ba
else()
set(prefix "${base_path}/${target}/${arch_path}")
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch}
-m qtmultimedia --archives qttranslations qttools qtsvg qtbase)
-m all)
endif()
if (NOT EXISTS "${prefix}")
message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}")
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.1.18")
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.2.0")
if (WIN32)
set(aqt_path "${base_path}/aqt.exe")
if (NOT EXISTS "${aqt_path}")

View File

@ -1,5 +0,0 @@
# Rename this file to x86-64-toolchain.cmake
# Set baseline x86-64 flags for maximum compatibility
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=x86-64" CACHE STRING "C flags")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64" CACHE STRING "C++ flags")

View File

@ -1,4 +1,5 @@
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
# SPDX-FileCopyrightText: 2025 citron Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
# Allow systemd-logind to manage user access to hidraw with this file
@ -7,13 +8,13 @@
# Switch Pro Controller (USB/Bluetooth)
KERNEL=="hidraw*", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="2009", MODE="0660", TAG+="uaccess"
KERNEL=="hidraw*", KERNELS=="*057e:2009*", MODE="0660", TAG+="uaccess"
KERNEL=="hidraw*", KERNELS=="*057E:2009*", MODE="0660", TAG+="uaccess"
# Joy-Con L (Bluetooth)
KERNEL=="hidraw*", KERNELS=="*057e:2006*", MODE="0660", TAG+="uaccess"
KERNEL=="hidraw*", KERNELS=="*057E:2006*", MODE="0660", TAG+="uaccess"
# Joy-Con R (Bluetooth)
KERNEL=="hidraw*", KERNELS=="*057e:2007*", MODE="0660", TAG+="uaccess"
KERNEL=="hidraw*", KERNELS=="*057E:2007*", MODE="0660", TAG+="uaccess"
# Joy-Con Charging Grip (USB)
KERNEL=="hidraw*", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="200e", MODE="0660", TAG+="uaccess"

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;موقعنا&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;رماز المصدر&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;المساهمون&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;الرخصة&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;موقعنا&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;رماز المصدر&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;المساهمون&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;الرخصة&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ This would ban both their forum username and their IP address.</source>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6074,7 +6074,7 @@ Please, only use this feature to install updates and DLC.</source>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation>Mii تحرير التطبيق الصغير</translation>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Pàgina web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Codi Font&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contribuïdors&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Llicència&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Pàgina web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Codi Font&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contribuïdors&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Llicència&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -407,7 +407,7 @@ This would ban both their forum username and their IP address.</source>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6111,7 +6111,7 @@ Si us plau, utilitzi aquesta funció només per a instal·lar actualitzacions i
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Webové stránky&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Zdrojový kód&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Přispěvatelé&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licence&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Webové stránky&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Zdrojový kód&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Přispěvatelé&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licence&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -407,7 +407,7 @@ This would ban both their forum username and their IP address.</source>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6095,7 +6095,7 @@ Tuto funkci prosím používejte pouze k instalaci aktualizací a DLC.</translat
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;Netsted&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kildekode&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Bidragsydere&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licens&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;Netsted&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kildekode&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Bidragsydere&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licens&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ Dette vil bandlyse både vedkommendes forum-brugernavn og IP-adresse.</translati
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6101,7 +6101,7 @@ Please, only use this feature to install updates and DLC.</source>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Webseite&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Quellcode&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Mitwirkende&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lizenz&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Webseite&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Quellcode&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Mitwirkende&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lizenz&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -408,7 +408,7 @@ Dies würde deren Forum-Benutzernamen und deren IP-Adresse sperren.</translation
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6121,7 +6121,7 @@ Bitte nutze diese Funktion nur zum Installieren von Updates und DLC.</translatio
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation>Mii-Edit-Applet</translation>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Ιστοσελίδα&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Πηγαίος Κώδικας&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Συνεργάτες&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;/span&gt;Άδεια&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Ιστοσελίδα&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Πηγαίος Κώδικας&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Συνεργάτες&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;/span&gt;Άδεια&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ This would ban both their forum username and their IP address.</source>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6097,7 +6097,7 @@ Please, only use this feature to install updates and DLC.</source>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Página web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Código fuente&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contribuidores&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licencia&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Página web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Código fuente&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contribuidores&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licencia&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation>Editor de Mii</translation>
</message>
<message>
@ -6167,7 +6167,7 @@ Por favor, utiliza esta función sólo para instalar actualizaciones y DLCs.</tr
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation>Applet de Editor de Mii</translation>
</message>
<message>

View File

@ -40,8 +40,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="118"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Nettisivu&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lähdekoodi&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lahjoittajat&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lisenssi&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Nettisivu&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lähdekoodi&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lahjoittajat&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lisenssi&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="134"/>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Site Web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Code Source&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributeurs&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licence&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Site Web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Code Source&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributeurs&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licence&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -410,7 +410,7 @@ Cela bannirait à la fois son nom d&apos;utilisateur du forum et son adresse IP.
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation>Édition de Mii</translation>
</message>
<message>
@ -6160,7 +6160,7 @@ Veuillez n&apos;utiliser cette fonctionnalité que pour installer des mises à j
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation>Applet de l&apos;éditeur Mii</translation>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Weboldal&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Forráskód&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Közreműködők&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licensz&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Weboldal&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Forráskód&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Közreműködők&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licensz&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ Ez kitiltaná a fórum felhasználóneve és az IP címe alapján.</translation>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation>Mii szerkesztés</translation>
</message>
<message>
@ -6134,7 +6134,7 @@ Kérjük, csak frissítések és DLC-k telepítéséhez használd ezt a funkció
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation>Mii szerkesztő applet</translation>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Situs web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kode Sumber&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kontributor&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lisensi&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Situs web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kode Sumber&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kontributor&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lisensi&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ Ini akan melarang nama pengguna forum mereka dan alamat IP mereka.</translation>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation>Ubah Mii</translation>
</message>
<message>
@ -6154,7 +6154,7 @@ Please, only use this feature to install updates and DLC.</source>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Sito web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Codice sorgente&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributori&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licenza&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Sito web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Codice sorgente&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributori&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licenza&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP.</trans
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6130,7 +6130,7 @@ Configurazione &amp;gt; Web.</translation>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation>Editor dei Mii</translation>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;ウェブサイト&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;ソースコード&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;貢献者&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;ライセンス&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;ウェブサイト&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;ソースコード&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;貢献者&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;ライセンス&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ This would ban both their forum username and their IP address.</source>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6116,7 +6116,7 @@ Please, only use this feature to install updates and DLC.</source>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation>Mii </translation>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;웹사이트&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;소스 코드&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;기여자&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;라이센스&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;웹사이트&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;소스 코드&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;기여자&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;라이센스&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ This would ban both their forum username and their IP address.</source>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6115,7 +6115,7 @@ Please, only use this feature to install updates and DLC.</source>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Nettside&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kildekode&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Bidragsytere&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lisens&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Nettside&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kildekode&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Bidragsytere&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lisens&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ Dette vil bannlyse både deres forum brukernavn og deres IP adresse.</translatio
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6120,7 +6120,7 @@ Bruk kun denne funksjonen til å installere oppdateringer og DLC.</translation>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Broncode&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Bijdragers&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licentie&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Broncode&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Bijdragers&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licentie&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ Dit zou zowel hun forum gebruikersnaam als hun IP-adres verbannen.</translation>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6108,7 +6108,7 @@ Gebruik deze functie alleen om updates en DLC te installeren.</translation>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Strona&lt;/span&gt;&lt;/a&gt;I&lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kod Źródłowy&lt;/span&gt;&lt;/a&gt;I&lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kontrybutorzy&lt;/span&gt;&lt;/a&gt;I&lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licencja&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Strona&lt;/span&gt;&lt;/a&gt;I&lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kod Źródłowy&lt;/span&gt;&lt;/a&gt;I&lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kontrybutorzy&lt;/span&gt;&lt;/a&gt;I&lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licencja&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ To zbanuje jego/jej nick na forum, oraz jego/jej adres IP.</translation>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6111,7 +6111,7 @@ Proszę, używaj tej funkcji tylko do instalowania łatek i DLC.</translation>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Site&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Código-fonte&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Colaboradores&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licença&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Site&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Código-fonte&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Colaboradores&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licença&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ Isto banirá tanto o nome de usuário do fórum como o endereço IP.</translatio
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation>Editar Mii</translation>
</message>
<message>
@ -6169,7 +6169,7 @@ Por favor, use esse recurso apenas para instalar atualizações e DLCs.</transla
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation>Miniaplicativo Editor de Mii</translation>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>Site | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Código fonte | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contribuidores&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licença&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>Site | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Código fonte | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contribuidores&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licença&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ Isto banirá tanto o nome de usuário do fórum como o endereço IP.</translatio
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation>Editar Mii</translation>
</message>
<message>
@ -6152,7 +6152,7 @@ Por favor, use esse recurso apenas para instalar atualizações e DLC.</translat
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation>Applet Editor de Miis</translation>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Веб-сайт&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Исходный код&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Контрибьюторы&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Лицензия&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Веб-сайт&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Исходный код&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Контрибьюторы&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Лицензия&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ This would ban both their forum username and their IP address.</source>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation>Mii редактор</translation>
</message>
<message>
@ -6165,8 +6165,8 @@ Please, only use this feature to install updates and DLC.</source>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<translation>Mii Edit Applet</translation>
<source>Mii Editor Applet</source>
<translation>Mii Editor Applet</translation>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4452"/>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Hemsida&lt;/span&gt;&lt;/a&gt;I&lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Källkod&lt;/span&gt;&lt;/a&gt;I&lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Bidragsgivare&lt;/span&gt;&lt;/a&gt;I&lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licens&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Hemsida&lt;/span&gt;&lt;/a&gt;I&lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Källkod&lt;/span&gt;&lt;/a&gt;I&lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Bidragsgivare&lt;/span&gt;&lt;/a&gt;I&lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Licens&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ Detta kommer bannlysa både dennes användarnamn på forum samt IP-adress.</tran
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6090,7 +6090,7 @@ Please, only use this feature to install updates and DLC.</source>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kaynak Kodu&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Katkıda Bulunanlar&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lisans&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Kaynak Kodu&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Katkıda Bulunanlar&lt;/span&gt;&lt;/a&gt;|&lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Lisans&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ Bu işlem onların hem forum kullanıcı adını hem de IP adresini banlar.</tra
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6112,7 +6112,7 @@ Lütfen bu özelliği sadece güncelleme ve DLC yüklemek için kullanın.</tran
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Веб-сайт&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Першокод&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Вкладники&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Ліцензія&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Веб-сайт&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Першокод&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Вкладники&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Ліцензія&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ This would ban both their forum username and their IP address.</source>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6124,7 +6124,7 @@ Please, only use this feature to install updates and DLC.</source>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Trang web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Mã nguồn&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Người đóng góp&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Giấy phép&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Trang web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Mã nguồn&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Người đóng góp&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Giấy phép&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ Việc này sẽ ban tên người dùng trên diễn đàn và IP của họ lu
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6117,7 +6117,7 @@ Vui lòng, chỉ sử dụng tính năng này để cài đặt các bản cập
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Trang web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Mã nguồn&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Đóng góp&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Giấy phép&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Trang web&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Mã nguồn&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Đóng góp&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Giấy phép&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,7 +409,7 @@ This would ban both their forum username and their IP address.</source>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<source>Mii Editor</source>
<translation type="unfinished"/>
</message>
<message>
@ -6117,7 +6117,7 @@ Vui lòng, chỉ sử dụng tính năng này để cài các bản cập nhật
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation type="unfinished"/>
</message>
<message>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;官方网站&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;源代码&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;贡献者&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;许可证&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;官方网站&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;源代码&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;贡献者&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;许可证&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,8 +409,8 @@ This would ban both their forum username and their IP address.</source>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<translation>Mii Edit</translation>
<source>Mii Editor</source>
<translation>Mii Editor</translation>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="38"/>
@ -6165,8 +6165,8 @@ Please, only use this feature to install updates and DLC.</source>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<translation>Mii Edit </translation>
<source>Mii Editor Applet</source>
<translation>Mii Editor </translation>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4452"/>

View File

@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;官網&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;原始碼&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;貢獻者&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/citron-emu/citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;許可證&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://citron-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;官網&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;原始碼&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;貢獻者&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;許可證&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
@ -409,8 +409,8 @@ This would ban both their forum username and their IP address.</source>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="37"/>
<source>Mii Edit</source>
<translation>Mii Edit</translation>
<source>Mii Editor</source>
<translation>Mii Editor</translation>
</message>
<message>
<location filename="../../src/citron/configuration/shared_translation.cpp" line="38"/>
@ -6161,7 +6161,7 @@ Please, only use this feature to install updates and DLC.</source>
</message>
<message>
<location filename="../../src/citron/main.cpp" line="4451"/>
<source>Mii Edit Applet</source>
<source>Mii Editor Applet</source>
<translation>Mii </translation>
</message>
<message>

View File

@ -25,13 +25,13 @@ SPDX-License-Identifier: CC0-1.0
<keyword>emulator</keyword>
</keywords>
<url type="homepage">https://citron-emu.org/</url>
<url type="bugtracker">https://github.com/citron-emu/citron/issues</url>
<url type="bugtracker">https://git.citron-emu.org/Citron/Citron/issues</url>
<url type="faq">https://citron-emu.org/wiki/faq/</url>
<url type="help">https://citron-emu.org/wiki/home/</url>
<url type="donation">https://citron-emu.org/donate/</url>
<url type="translate">https://www.transifex.com/projects/p/citron</url>
<url type="contact">https://community.citra-emu.org/</url>
<url type="vcs-browser">https://github.com/citron-emu/citron</url>
<url type="vcs-browser">https://git.citron-emu.org/Citron/Citron</url>
<url type="contribute">https://citron-emu.org/wiki/contributing/</url>
<launchable type="desktop-id">org.citron_emu.citron.desktop</launchable>
<provides>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 12 KiB

2
externals/SDL vendored

@ -1 +1 @@
Subproject commit cc016b0046d563287f0aa9f09b958b5e70d43696
Subproject commit 2359383fc187386204c3bb22de89655a494cd128

@ -1 +1 @@
Subproject commit d4a196d8c84e032d27f999adcea3075517c1c97f
Subproject commit e2e53a724677f6eba8ff0ce1ccb64ee321785cbd

@ -1 +1 @@
Subproject commit 5a88b6042edb8f03eefc8de73bd73a899989373f
Subproject commit 4e246c56ec5afb5ad66b9b04374d39ac04675c8e

@ -1 +1 @@
Subproject commit f74c2d906f1537114fe0c0d855d5d27db91898cb
Subproject commit 539c0a8d8e3733c9f25ea9a184c85c77504f1653

@ -1 +1 @@
Subproject commit a609330e4c6374f741d3b369269f7848255e1954
Subproject commit 39a64fb4e7e42216f14f0ec51ccc5fa85e651432

2
externals/cpp-jwt vendored

@ -1 +1 @@
Subproject commit 10ef5735d842b31025f1257ae78899f50a40fb14
Subproject commit 4a970bc302d671476122cbc6b43cc89fbf4a96ec

2
externals/enet vendored

@ -1 +1 @@
Subproject commit 39a72ab1990014eb399cee9d538fd529df99c6a0
Subproject commit 657eaf97d9d335917c58484a4a4b5e03838ebd8e

@ -1 +1 @@
Subproject commit 9c1294eaddb88cb0e044c675ccae059a85fc9c6c
Subproject commit 99e2af4e7837ca09b97d93a562dc12947179fc48

@ -1 +1 @@
Subproject commit 5cd3f5c5ceea6d9e9d435ccdd922d9b99e55d10b
Subproject commit 8fae8ce254dfc1344527e05301e43f37dea2df80

@ -1 +1 @@
Subproject commit c060e9ce30ac2e3ffb49d94209c4dae77b6642f7
Subproject commit de38189e8014fa393f4d8c1d9d3fdf5e2a95899d

2
externals/oaknut vendored

@ -1 +1 @@
Subproject commit 9d091109deb445bc6e9289c6195a282b7c993d49
Subproject commit 94c726ce0338b054eb8cb5ea91de8fe6c19f4392

2
externals/opus vendored

@ -1 +1 @@
Subproject commit 101a71e03bbf860aaafb7090a0e440675cb27660
Subproject commit 734aed05d09af3d2690f8cb5aafa97f052746daf

2
externals/simpleini vendored

@ -1 +1 @@
Subproject commit 382ddbb4b92c0b26aa1b32cefba2002119a5b1f2
Subproject commit 6048871ea9ee0ec24be5bd099d161a10567d7dc2

2
externals/vcpkg vendored

@ -1 +1 @@
Subproject commit d4f3e122069912636c123b7ece673f6e01513cea
Subproject commit 96d5fb3de135b86d7222c53f2352ca92827a156b

View File

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
import android.annotation.SuppressLint
@ -28,19 +29,19 @@ android {
namespace = "org.citron.citron_emu"
compileSdkVersion = "android-35"
ndkVersion = "27.2.12479018" // "28.0.12433566 rc1"// "28.0.12674087 rc2" // "26.1.10909125"
ndkVersion = "29.0.13113456 rc1" // "26.1.10909125"
buildFeatures {
viewBinding = true
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
kotlinOptions {
jvmTarget = "17"
jvmTarget = "21"
}
packaging {
@ -56,6 +57,7 @@ android {
// TODO If this is ever modified, change application_id in strings.xml
applicationId = "org.citron.citron_emu"
minSdk = 30
//noinspection EditedTargetSdkVersion
targetSdk = 35
versionName = getGitVersion()
@ -103,10 +105,10 @@ android {
signingConfigs.getByName("default")
}
resValue("string", "app_name_suffixed", "citron")
resValue("string", "app_name_suffixed", "Citron")
isDefault = true
isShrinkResources = true
isMinifyEnabled = true
isShrinkResources = true
isJniDebuggable = false
isDebuggable = false
proguardFiles(
@ -118,9 +120,8 @@ android {
// builds a release build that doesn't need signing
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
register("relWithDebInfo") {
resValue("string", "app_name_suffixed", "citron Debug Release")
resValue("string", "app_name_suffixed", "Citron Debug Release")
signingConfig = signingConfigs.getByName("default")
isMinifyEnabled = true
isDebuggable = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
@ -135,7 +136,7 @@ android {
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
debug {
signingConfig = signingConfigs.getByName("default")
resValue("string", "app_name_suffixed", "citron Debug")
resValue("string", "app_name_suffixed", "Citron Debug")
isDebuggable = true
isJniDebuggable = true
versionNameSuffix = "-debug"
@ -148,7 +149,7 @@ android {
create("mainline") {
isDefault = true
dimension = "version"
buildConfigField("Boolean", "PREMIUM", "true") // Spoof EA Version
buildConfigField("Boolean", "PREMIUM", "true")
}
create("ea") {
@ -160,7 +161,7 @@ android {
externalNativeBuild {
cmake {
version = "3.22.1"
version = "4.0.1"
path = file("../../../CMakeLists.txt")
}
}
@ -177,16 +178,18 @@ android {
"-DCITRON_USE_BUNDLED_VCPKG=ON",
"-DCITRON_USE_BUNDLED_FFMPEG=ON",
"-DCITRON_ENABLE_LTO=ON",
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON",
"-DCMAKE_POLICY_VERSION_MINIMUM=3.5"
)
abiFilters("arm64-v8a")
abiFilters("arm64-v8a") // , "x86_64")
}
}
}
}
tasks.create<Delete>("ktlintReset") { // Deprecated, Still Works.
tasks.create<Delete>("ktlintReset") {
delete(File(buildDir.path + File.separator + "intermediates/ktLint"))
}
@ -204,7 +207,7 @@ ktlint {
version.set("0.47.1")
android.set(true)
ignoreFailures.set(false)
disabledRules.set( // Deprecated, Still Works.
disabledRules.set(
setOf(
"no-wildcard-imports",
"package-name",

View File

@ -22,3 +22,10 @@
-dontwarn java.beans.Introspector
-dontwarn java.beans.VetoableChangeListener
-dontwarn java.beans.VetoableChangeSupport
# LicenseVerifier protection
-keep class org.citron.citron_emu.utils.LicenseVerifier { *; }
-keepnames class org.citron.citron_emu.utils.LicenseVerifier
-dontskipnonpubliclibraryclasses
-dontoptimize
-dontpreverify

View File

@ -14,6 +14,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<application

View File

@ -21,6 +21,8 @@ import org.citron.citron_emu.utils.Log
import org.citron.citron_emu.model.InstallResult
import org.citron.citron_emu.model.Patch
import org.citron.citron_emu.model.GameVerificationResult
import org.citron.citron_emu.network.NetPlayManager
import java.net.NetworkInterface
/**
* Class which contains methods that interact
@ -242,6 +244,27 @@ object NativeLibrary {
return coreErrorAlertResult
}
@Keep
@JvmStatic
fun addNetPlayMessage(type: Int, message: String) {
val emulationActivity = sEmulationActivity.get()
if (emulationActivity != null) {
emulationActivity.addNetPlayMessages(type, message)
}
else {
NetPlayManager.addNetPlayMessage(type, message)
}
}
@Keep
@JvmStatic
fun clearChat() {
NetPlayManager.clearChat()
}
external fun netPlayInit()
@Keep
@JvmStatic
fun exitEmulationActivity(resultCode: Int) {
@ -459,4 +482,29 @@ object NativeLibrary {
* Checks if all necessary keys are present for decryption
*/
external fun areKeysPresent(): Boolean
fun getNetworkInterfaces(): Array<String> {
val interfaceList = mutableListOf<String>()
try {
NetworkInterface.getNetworkInterfaces()?.toList()?.forEach { iface ->
if (iface.isUp && !iface.isLoopback) {
iface.inetAddresses.toList()
.filterNot { it.isLoopbackAddress }
.forEach { addr ->
interfaceList.add("${iface.name};${addr.hostAddress}")
}
}
}
} catch (e: Exception) {
Log.error("[NativeLibrary] Failed to enumerate network interfaces: ${e.message}")
}
// Always ensure we have at least a loopback interface
if (interfaceList.isEmpty()) {
Log.warning("[NativeLibrary] No interfaces found, adding loopback fallback")
interfaceList.add("lo;127.0.0.1")
}
return interfaceList.toTypedArray()
}
}

View File

@ -4,6 +4,7 @@
package org.citron.citron_emu.activities
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.app.PendingIntent
import android.app.PictureInPictureParams
import android.app.RemoteAction
@ -39,12 +40,14 @@ import org.citron.citron_emu.NativeLibrary
import org.citron.citron_emu.R
import org.citron.citron_emu.CitronApplication
import org.citron.citron_emu.databinding.ActivityEmulationBinding
import org.citron.citron_emu.dialogs.NetPlayDialog
import org.citron.citron_emu.features.input.NativeInput
import org.citron.citron_emu.features.settings.model.BooleanSetting
import org.citron.citron_emu.features.settings.model.IntSetting
import org.citron.citron_emu.features.settings.model.Settings
import org.citron.citron_emu.model.EmulationViewModel
import org.citron.citron_emu.model.Game
import org.citron.citron_emu.network.NetPlayManager
import org.citron.citron_emu.utils.InputHandler
import org.citron.citron_emu.utils.Log
import org.citron.citron_emu.utils.MemoryUtil
@ -52,6 +55,7 @@ import org.citron.citron_emu.utils.NativeConfig
import org.citron.citron_emu.utils.NfcReader
import org.citron.citron_emu.utils.ParamPackage
import org.citron.citron_emu.utils.ThemeHelper
import org.citron.citron_emu.utils.LicenseVerifier
import java.text.NumberFormat
import kotlin.math.roundToInt
@ -79,6 +83,22 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
super.onCreate(savedInstanceState)
// Check if firmware is available
if (!NativeLibrary.isFirmwareAvailable()) {
AlertDialog.Builder(this)
.setTitle(R.string.firmware_missing_title)
.setMessage(R.string.firmware_missing_message)
.setPositiveButton(R.string.ok) { _, _ ->
finish()
}
.setCancelable(false)
.show()
return
}
// Add license verification at the start
LicenseVerifier.verifyLicense(this)
InputHandler.updateControllerData()
val players = NativeConfig.getInputSettings(true)
var hasConfiguredControllers = false
@ -405,6 +425,16 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
setPictureInPictureParams(pictureInPictureParamsBuilder.build())
}
fun displayMultiplayerDialog() {
val dialog = NetPlayDialog(this)
dialog.show()
}
fun addNetPlayMessages(type: Int, msg: String) {
NetPlayManager.addNetPlayMessage(type, msg)
}
private var pictureInPictureReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
if (intent.action == actionPlay) {

View File

@ -31,7 +31,7 @@ class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
override fun bind(model: SetupPage) {
if (model.stepCompleted.invoke() == StepState.COMPLETE) {
binding.buttonAction.setVisible(visible = false, gone = false)
binding.textConfirmation.setVisible(true)
binding.textConfirmation?.setVisible(true)
}
binding.icon.setImageDrawable(
@ -68,7 +68,7 @@ class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
override fun onStepCompleted() {
ViewUtils.hideView(binding.buttonAction, 200)
ViewUtils.showView(binding.textConfirmation, 200)
binding.textConfirmation?.let { ViewUtils.showView(it, 200) }
ViewModelProvider(activity)[HomeViewModel::class.java].setShouldPageForward(true)
}
}

View File

@ -0,0 +1,133 @@
package org.citron.citron_emu.dialogs
import android.content.Context
import android.content.res.Configuration
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import org.citron.citron_emu.R
import org.citron.citron_emu.databinding.DialogChatBinding
import org.citron.citron_emu.databinding.ItemChatMessageBinding
import org.citron.citron_emu.network.NetPlayManager
import java.text.SimpleDateFormat
import java.util.*
class ChatMessage(
val nickname: String, // This is the common name youll see on private servers
val username: String, // Username is the community/forum username
val message: String,
val timestamp: String = SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date())
) {
}
class ChatDialog(context: Context) : BottomSheetDialog(context) {
private lateinit var binding: DialogChatBinding
private lateinit var chatAdapter: ChatAdapter
private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DialogChatBinding.inflate(LayoutInflater.from(context))
setContentView(binding.root)
NetPlayManager.setChatOpen(true)
setupRecyclerView()
behavior.state = BottomSheetBehavior.STATE_EXPANDED
behavior.state = BottomSheetBehavior.STATE_EXPANDED
behavior.skipCollapsed = context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
handler.post {
chatAdapter.notifyDataSetChanged()
binding.chatRecyclerView.post {
scrollToBottom()
}
}
NetPlayManager.setOnMessageReceivedListener { type, message ->
handler.post {
chatAdapter.notifyDataSetChanged()
scrollToBottom()
}
}
binding.sendButton.setOnClickListener {
val message = binding.chatInput.text.toString()
if (message.isNotBlank()) {
sendMessage(message)
binding.chatInput.text?.clear()
}
}
}
override fun dismiss() {
NetPlayManager.setChatOpen(false)
super.dismiss()
}
private fun sendMessage(message: String) {
val username = NetPlayManager.getUsername(context)
NetPlayManager.netPlaySendMessage(message)
val chatMessage = ChatMessage(
nickname = username,
username = "",
message = message,
timestamp = SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date())
)
NetPlayManager.addChatMessage(chatMessage)
chatAdapter.notifyDataSetChanged()
scrollToBottom()
}
private fun setupRecyclerView() {
chatAdapter = ChatAdapter(NetPlayManager.getChatMessages())
binding.chatRecyclerView.layoutManager = LinearLayoutManager(context).apply {
stackFromEnd = true
}
binding.chatRecyclerView.adapter = chatAdapter
}
private fun scrollToBottom() {
binding.chatRecyclerView.scrollToPosition(chatAdapter.itemCount - 1)
}
}
class ChatAdapter(private val messages: List<ChatMessage>) :
RecyclerView.Adapter<ChatAdapter.ChatViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatViewHolder {
val binding = ItemChatMessageBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return ChatViewHolder(binding)
}
override fun getItemCount(): Int = messages.size
override fun onBindViewHolder(holder: ChatViewHolder, position: Int) {
holder.bind(messages[position])
}
inner class ChatViewHolder(private val binding: ItemChatMessageBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(message: ChatMessage) {
binding.usernameText.text = message.nickname
binding.messageText.text = message.message
binding.userIcon.setImageResource(when (message.nickname) {
"System" -> R.drawable.ic_system
else -> R.drawable.ic_user
})
}
}
}

View File

@ -0,0 +1,397 @@
// Copyright 2024 Mandarine Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citron.citron_emu.dialogs
import android.content.Context
import org.citron.citron_emu.R
import android.content.res.Configuration
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.citron.citron_emu.CitronApplication
import org.citron.citron_emu.databinding.DialogMultiplayerConnectBinding
import org.citron.citron_emu.databinding.DialogMultiplayerLobbyBinding
import org.citron.citron_emu.databinding.DialogMultiplayerRoomBinding
import org.citron.citron_emu.databinding.ItemBanListBinding
import org.citron.citron_emu.databinding.ItemButtonNetplayBinding
import org.citron.citron_emu.databinding.ItemTextNetplayBinding
import org.citron.citron_emu.utils.CompatUtils
import org.citron.citron_emu.network.NetPlayManager
class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
private lateinit var adapter: NetPlayAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
behavior.state = BottomSheetBehavior.STATE_EXPANDED
behavior.skipCollapsed = context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
when {
NetPlayManager.netPlayIsJoined() -> DialogMultiplayerLobbyBinding.inflate(layoutInflater)
.apply {
setContentView(root)
adapter = NetPlayAdapter()
listMultiplayer.layoutManager = LinearLayoutManager(context)
listMultiplayer.adapter = adapter
adapter.loadMultiplayerMenu()
btnLeave.setOnClickListener {
NetPlayManager.netPlayLeaveRoom()
dismiss()
}
btnChat.setOnClickListener {
ChatDialog(context).show()
}
refreshAdapterItems()
btnModeration.visibility = if (NetPlayManager.netPlayIsModerator()) View.VISIBLE else View.GONE
btnModeration.setOnClickListener {
showModerationDialog()
}
}
else -> {
DialogMultiplayerConnectBinding.inflate(layoutInflater).apply {
setContentView(root)
btnCreate.setOnClickListener {
showNetPlayInputDialog(true)
dismiss()
}
btnJoin.setOnClickListener {
showNetPlayInputDialog(false)
dismiss()
}
}
}
}
}
data class NetPlayItems(
val option: Int,
val name: String,
val type: Int,
val id: Int = 0
) {
companion object {
const val MULTIPLAYER_ROOM_TEXT = 1
const val MULTIPLAYER_ROOM_MEMBER = 2
const val MULTIPLAYER_SEPARATOR = 3
const val MULTIPLAYER_ROOM_COUNT = 4
const val TYPE_BUTTON = 0
const val TYPE_TEXT = 1
const val TYPE_SEPARATOR = 2
}
}
inner class NetPlayAdapter : RecyclerView.Adapter<NetPlayAdapter.NetPlayViewHolder>() {
val netPlayItems = mutableListOf<NetPlayItems>()
abstract inner class NetPlayViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
init {
itemView.setOnClickListener(this)
}
abstract fun bind(item: NetPlayItems)
}
inner class TextViewHolder(private val binding: ItemTextNetplayBinding) : NetPlayViewHolder(binding.root) {
private lateinit var netPlayItem: NetPlayItems
override fun onClick(clicked: View) {}
override fun bind(item: NetPlayItems) {
netPlayItem = item
binding.itemTextNetplayName.text = item.name
binding.itemIcon.apply {
val iconRes = when (item.option) {
NetPlayItems.MULTIPLAYER_ROOM_TEXT -> R.drawable.ic_system
NetPlayItems.MULTIPLAYER_ROOM_COUNT -> R.drawable.ic_joined
else -> 0
}
visibility = if (iconRes != 0) {
setImageResource(iconRes)
View.VISIBLE
} else View.GONE
}
}
}
inner class ButtonViewHolder(private val binding: ItemButtonNetplayBinding) : NetPlayViewHolder(binding.root) {
private lateinit var netPlayItems: NetPlayItems
private val isModerator = NetPlayManager.netPlayIsModerator()
init {
binding.itemButtonMore.apply {
visibility = View.VISIBLE
setOnClickListener { showPopupMenu(it) }
}
}
override fun onClick(clicked: View) {}
private fun showPopupMenu(view: View) {
PopupMenu(view.context, view).apply {
menuInflater.inflate(R.menu.menu_netplay_member, menu)
menu.findItem(R.id.action_kick).isEnabled = isModerator &&
netPlayItems.name != NetPlayManager.getUsername(context)
menu.findItem(R.id.action_ban).isEnabled = isModerator &&
netPlayItems.name != NetPlayManager.getUsername(context)
setOnMenuItemClickListener { item ->
if (item.itemId == R.id.action_kick) {
NetPlayManager.netPlayKickUser(netPlayItems.name)
true
} else if (item.itemId == R.id.action_ban) {
NetPlayManager.netPlayBanUser(netPlayItems.name)
true
} else false
}
show()
}
}
override fun bind(item: NetPlayItems) {
netPlayItems = item
binding.itemButtonNetplayName.text = netPlayItems.name
}
}
fun loadMultiplayerMenu() {
val infos = NetPlayManager.netPlayRoomInfo()
if (infos.isNotEmpty()) {
val roomInfo = infos[0].split("|")
netPlayItems.add(NetPlayItems(NetPlayItems.MULTIPLAYER_ROOM_TEXT, roomInfo[0], NetPlayItems.TYPE_TEXT))
netPlayItems.add(NetPlayItems(NetPlayItems.MULTIPLAYER_ROOM_COUNT, "${infos.size - 1}/${roomInfo[1]}", NetPlayItems.TYPE_TEXT))
netPlayItems.add(NetPlayItems(NetPlayItems.MULTIPLAYER_SEPARATOR, "", NetPlayItems.TYPE_SEPARATOR))
for (i in 1 until infos.size) {
netPlayItems.add(NetPlayItems(NetPlayItems.MULTIPLAYER_ROOM_MEMBER, infos[i], NetPlayItems.TYPE_BUTTON))
}
}
}
override fun getItemViewType(position: Int) = netPlayItems[position].type
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NetPlayViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
NetPlayItems.TYPE_TEXT -> TextViewHolder(ItemTextNetplayBinding.inflate(inflater, parent, false))
NetPlayItems.TYPE_BUTTON -> ButtonViewHolder(ItemButtonNetplayBinding.inflate(inflater, parent, false))
NetPlayItems.TYPE_SEPARATOR -> object : NetPlayViewHolder(inflater.inflate(R.layout.item_separator_netplay, parent, false)) {
override fun bind(item: NetPlayItems) {}
override fun onClick(clicked: View) {}
}
else -> throw IllegalStateException("Unsupported view type")
}
}
override fun onBindViewHolder(holder: NetPlayViewHolder, position: Int) {
holder.bind(netPlayItems[position])
}
override fun getItemCount() = netPlayItems.size
}
fun refreshAdapterItems() {
val handler = Handler(Looper.getMainLooper())
NetPlayManager.setOnAdapterRefreshListener() { type, msg ->
handler.post {
adapter.netPlayItems.clear()
adapter.loadMultiplayerMenu()
adapter.notifyDataSetChanged()
}
}
}
private fun showNetPlayInputDialog(isCreateRoom: Boolean) {
val activity = CompatUtils.findActivity(context)
val dialog = BottomSheetDialog(activity)
dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
dialog.behavior.skipCollapsed = context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
val binding = DialogMultiplayerRoomBinding.inflate(LayoutInflater.from(activity))
dialog.setContentView(binding.root)
binding.textTitle.text = activity.getString(
if (isCreateRoom) R.string.multiplayer_create_room
else R.string.multiplayer_join_room
)
binding.ipAddress.setText(
if (isCreateRoom) NetPlayManager.getIpAddressByWifi(activity)
else NetPlayManager.getRoomAddress(activity)
)
binding.ipPort.setText(NetPlayManager.getRoomPort(activity))
binding.username.setText(NetPlayManager.getUsername(activity))
binding.roomName.visibility = if (isCreateRoom) View.VISIBLE else View.GONE
binding.maxPlayersContainer.visibility = if (isCreateRoom) View.VISIBLE else View.GONE
binding.maxPlayersLabel.text = context.getString(R.string.multiplayer_max_players_value, binding.maxPlayers.value.toInt())
binding.maxPlayers.addOnChangeListener { _, value, _ ->
binding.maxPlayersLabel.text = context.getString(R.string.multiplayer_max_players_value, value.toInt())
}
binding.btnConfirm.setOnClickListener {
binding.btnConfirm.isEnabled = false
binding.btnConfirm.text = activity.getString(R.string.disabled_button_text)
val ipAddress = binding.ipAddress.text.toString()
val username = binding.username.text.toString()
val portStr = binding.ipPort.text.toString()
val password = binding.password.text.toString()
val port = portStr.toIntOrNull() ?: run {
Toast.makeText(activity, R.string.multiplayer_port_invalid, Toast.LENGTH_LONG).show()
binding.btnConfirm.isEnabled = true
binding.btnConfirm.text = activity.getString(R.string.original_button_text)
return@setOnClickListener
}
val roomName = binding.roomName.text.toString()
val maxPlayers = binding.maxPlayers.value.toInt()
if (isCreateRoom && (roomName.length !in 3..20)) {
Toast.makeText(activity, R.string.multiplayer_room_name_invalid, Toast.LENGTH_LONG).show()
binding.btnConfirm.isEnabled = true
binding.btnConfirm.text = activity.getString(R.string.original_button_text)
return@setOnClickListener
}
if (ipAddress.length < 7 || username.length < 5) {
Toast.makeText(activity, R.string.multiplayer_input_invalid, Toast.LENGTH_LONG).show()
binding.btnConfirm.isEnabled = true
binding.btnConfirm.text = activity.getString(R.string.original_button_text)
} else {
Handler(Looper.getMainLooper()).post {
val result = if (isCreateRoom) {
NetPlayManager.netPlayCreateRoom(ipAddress, port, username, password, roomName, maxPlayers)
} else {
NetPlayManager.netPlayJoinRoom(ipAddress, port, username, password)
}
if (result == 0) {
NetPlayManager.setUsername(activity, username)
NetPlayManager.setRoomPort(activity, portStr)
if (!isCreateRoom) NetPlayManager.setRoomAddress(activity, ipAddress)
Toast.makeText(
CitronApplication.appContext,
if (isCreateRoom) R.string.multiplayer_create_room_success
else R.string.multiplayer_join_room_success,
Toast.LENGTH_LONG
).show()
dialog.dismiss()
} else {
Toast.makeText(activity, R.string.multiplayer_could_not_connect, Toast.LENGTH_LONG).show()
binding.btnConfirm.isEnabled = true
binding.btnConfirm.text = activity.getString(R.string.original_button_text)
}
}
}
}
dialog.show()
}
private fun showModerationDialog() {
val activity = CompatUtils.findActivity(context)
val dialog = MaterialAlertDialogBuilder(activity)
dialog.setTitle(R.string.multiplayer_moderation_title)
val banList = NetPlayManager.getBanList()
if (banList.isEmpty()) {
dialog.setMessage(R.string.multiplayer_no_bans)
dialog.setPositiveButton(R.string.ok, null)
dialog.show()
return
}
val view = LayoutInflater.from(context).inflate(R.layout.dialog_ban_list, null)
val recyclerView = view.findViewById<RecyclerView>(R.id.ban_list_recycler)
recyclerView.layoutManager = LinearLayoutManager(context)
lateinit var adapter: BanListAdapter
val onUnban: (String) -> Unit = { bannedItem ->
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.multiplayer_unban_title)
.setMessage(activity.getString(R.string.multiplayer_unban_message, bannedItem))
.setPositiveButton(R.string.multiplayer_unban) { _, _ ->
NetPlayManager.netPlayUnbanUser(bannedItem)
adapter.removeBan(bannedItem)
}
.setNegativeButton(R.string.cancel, null)
.show()
}
adapter = BanListAdapter(banList, onUnban)
recyclerView.adapter = adapter
dialog.setView(view)
dialog.setPositiveButton(R.string.ok, null)
dialog.show()
}
private class BanListAdapter(
banList: List<String>,
private val onUnban: (String) -> Unit
) : RecyclerView.Adapter<BanListAdapter.ViewHolder>() {
private val usernameBans = banList.filter { !it.contains(".") }.toMutableList()
private val ipBans = banList.filter { it.contains(".") }.toMutableList()
class ViewHolder(val binding: ItemBanListBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemBanListBinding.inflate(
LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val isUsername = position < usernameBans.size
val item = if (isUsername) usernameBans[position] else ipBans[position - usernameBans.size]
holder.binding.apply {
banText.text = item
icon.setImageResource(if (isUsername) R.drawable.ic_user else R.drawable.ic_ip)
btnUnban.setOnClickListener { onUnban(item) }
}
}
override fun getItemCount() = usernameBans.size + ipBans.size
fun removeBan(bannedItem: String) {
val position = if (bannedItem.contains(".")) {
ipBans.indexOf(bannedItem).let { if (it >= 0) it + usernameBans.size else it }
} else {
usernameBans.indexOf(bannedItem)
}
if (position >= 0) {
if (bannedItem.contains(".")) {
ipBans.remove(bannedItem)
} else {
usernameBans.remove(bannedItem)
}
notifyItemRemoved(position)
}
}
}
}

View File

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: 2025 Citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.citron.citron_emu.features.settings.model
@ -17,6 +18,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
RENDERER_DEBUG("debug"),
RENDERER_ENHANCED_SHADER_BUILDING("use_enhanced_shader_building"),
PICTURE_IN_PICTURE("picture_in_picture"),
USE_CUSTOM_RTC("custom_rtc_enabled"),
BLACK_BACKGROUNDS("black_backgrounds"),
@ -27,6 +29,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
SHOW_INPUT_OVERLAY("show_input_overlay"),
TOUCHSCREEN("touchscreen"),
SHOW_THERMAL_OVERLAY("show_thermal_overlay"),
SHOW_RAM_OVERLAY("show_ram_overlay"),
USE_AUTO_STUB("use_auto_stub");
override fun getBoolean(needsGlobal: Boolean): Boolean =

View File

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: 2025 Citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.citron.citron_emu.fragments
@ -7,10 +8,15 @@ import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.graphics.Color
import android.net.Uri
import android.os.BatteryManager
import android.os.Bundle
import android.os.Debug
import android.os.Handler
import android.os.Looper
import android.os.PowerManager
@ -65,6 +71,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private var emulationActivity: EmulationActivity? = null
private var perfStatsUpdater: (() -> Unit)? = null
private var thermalStatsUpdater: (() -> Unit)? = null
private var ramStatsUpdater: (() -> Unit)? = null
private var _binding: FragmentEmulationBinding? = null
private val binding get() = _binding!!
@ -80,6 +87,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private lateinit var powerManager: PowerManager
private val ramStatsUpdateHandler = Handler(Looper.myLooper()!!)
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is EmulationActivity) {
@ -262,6 +271,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
true
}
R.id.menu_multiplayer -> {
emulationActivity?.displayMultiplayerDialog()
true
}
R.id.menu_controls -> {
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
null,
@ -373,6 +389,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
// Setup overlays
updateShowFpsOverlay()
updateThermalOverlay()
updateRamOverlay()
}
}
emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) {
@ -467,6 +484,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
override fun onDestroyView() {
super.onDestroyView()
if (ramStatsUpdater != null) {
ramStatsUpdateHandler.removeCallbacks(ramStatsUpdater!!)
}
_binding = null
}
@ -531,7 +551,27 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
if (emulationViewModel.emulationStarted.value &&
!emulationViewModel.isEmulationStopping.value
) {
val temperature = getBatteryTemperature(requireContext())
updateThermalOverlay(temperature)
thermalStatsUpdateHandler.postDelayed(thermalStatsUpdater!!, 1000)
}
}
thermalStatsUpdateHandler.post(thermalStatsUpdater!!)
} else {
if (thermalStatsUpdater != null) {
thermalStatsUpdateHandler.removeCallbacks(thermalStatsUpdater!!)
}
}
}
private fun updateThermalOverlay(temperature: Float) {
if (BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean() &&
emulationViewModel.emulationStarted.value &&
!emulationViewModel.isEmulationStopping.value
) {
// Get thermal status for color
val thermalStatus = when (powerManager.currentThermalStatus) {
PowerManager.THERMAL_STATUS_NONE -> 0f
PowerManager.THERMAL_STATUS_LIGHT -> 0.25f
PowerManager.THERMAL_STATUS_MODERATE -> 0.5f
PowerManager.THERMAL_STATUS_SEVERE -> 0.75f
@ -541,56 +581,56 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
else -> 0f
}
// Get temperature from battery thermal sensor
val temperature = try {
val process = Runtime.getRuntime().exec("cat /sys/class/power_supply/battery/temp")
val reader = process.inputStream.bufferedReader()
val temp = reader.readLine().toFloat() / 10f // Convert from decidegrees to degrees
reader.close()
temp
} catch (e: Exception) {
0f
}
// Convert to Fahrenheit
val fahrenheit = (temperature * 9f / 5f) + 32f
if (_binding != null) {
// Color interpolation based on temperature (green at 30°C, red at 45°C)
val normalizedTemp = ((temperature - 30f) / 15f).coerceIn(0f, 1f)
val red = (normalizedTemp * 255).toInt()
val green = ((1f - normalizedTemp) * 255).toInt()
// Color based on thermal status (green to red)
val red = (thermalStatus * 255).toInt()
val green = ((1f - thermalStatus) * 255).toInt()
val color = android.graphics.Color.rgb(red, green, 0)
// Create a modern progress bar using block elements
val progressBarLength = 12
val filledBars = (thermalStatus * progressBarLength).toInt()
val progressBar = buildString {
append("") // Left border
repeat(filledBars) { append("") }
repeat(progressBarLength - filledBars) { append("") }
append("") // Right border
// Add percentage
append(" ")
append(String.format("%3d%%", (thermalStatus * 100).toInt()))
}
binding.showThermalsText.setTextColor(color)
binding.showThermalsText.text = String.format(
"%s\n%.1f°C • %.1f°F",
progressBar,
temperature,
fahrenheit
binding.showThermalsText.text = String.format("%.1f°C • %.1f°F", temperature, fahrenheit)
}
}
private fun updateRamOverlay() {
val showOverlay = BooleanSetting.SHOW_RAM_OVERLAY.getBoolean()
binding.showRamText.setVisible(showOverlay)
if (showOverlay) {
ramStatsUpdater = {
if (emulationViewModel.emulationStarted.value &&
!emulationViewModel.isEmulationStopping.value
) {
val runtime = Runtime.getRuntime()
val nativeHeapSize = Debug.getNativeHeapSize()
val nativeHeapFreeSize = Debug.getNativeHeapFreeSize()
val nativeHeapUsed = nativeHeapSize - nativeHeapFreeSize
val usedMemInMB = nativeHeapUsed / 1048576L
val maxMemInMB = nativeHeapSize / 1048576L
val percentUsed = (nativeHeapUsed.toFloat() / nativeHeapSize.toFloat() * 100f)
// Color interpolation from green to red based on usage percentage
val normalizedUsage = (percentUsed / 100f).coerceIn(0f, 1f)
val red = (normalizedUsage * 255).toInt()
val green = ((1f - normalizedUsage) * 255).toInt()
val color = Color.rgb(red, green, 0)
binding.showRamText.setTextColor(color)
binding.showRamText.text = String.format(
"\nRAM: %d/%d MB (%.1f%%)",
usedMemInMB,
maxMemInMB,
percentUsed
)
}
thermalStatsUpdateHandler.postDelayed(thermalStatsUpdater!!, 1000)
ramStatsUpdateHandler.postDelayed(ramStatsUpdater!!, 1000)
}
}
thermalStatsUpdateHandler.post(thermalStatsUpdater!!)
ramStatsUpdateHandler.post(ramStatsUpdater!!)
} else {
if (thermalStatsUpdater != null) {
thermalStatsUpdateHandler.removeCallbacks(thermalStatsUpdater!!)
if (ramStatsUpdater != null) {
ramStatsUpdateHandler.removeCallbacks(ramStatsUpdater!!)
}
}
}
@ -724,6 +764,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
findItem(R.id.thermal_indicator).isChecked =
BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()
findItem(R.id.ram_meter).apply {
isChecked = BooleanSetting.SHOW_RAM_OVERLAY.getBoolean()
isEnabled = false // This grays out the option
}
findItem(R.id.menu_rel_stick_center).isChecked =
BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()
findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean()
@ -750,6 +794,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
true
}
R.id.ram_meter -> {
// Do nothing since it's disabled
true
}
R.id.menu_edit_overlay -> {
binding.drawerLayout.close()
binding.surfaceInputOverlay.requestFocus()
@ -1095,4 +1144,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private val perfStatsUpdateHandler = Handler(Looper.myLooper()!!)
private val thermalStatsUpdateHandler = Handler(Looper.myLooper()!!)
}
private fun getBatteryTemperature(context: Context): Float {
try {
val batteryIntent = context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
// Temperature in tenths of a degree Celsius
val temperature = batteryIntent?.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) ?: 0
// Convert to degrees Celsius
return temperature / 10.0f
} catch (e: Exception) {
Log.error("[EmulationFragment] Failed to get battery temperature: ${e.message}")
return 0.0f
}
}
}

View File

@ -119,6 +119,16 @@ class HomeSettingsFragment : Fragment() {
driverViewModel.selectedDriverTitle
)
)
add(
HomeSetting(
R.string.multiplayer,
R.string.multiplayer_description,
R.drawable.ic_multiplayer,
{
val action = mainActivity.displayMultiplayerDialog()
},
)
)
add(
HomeSetting(
R.string.applets,

View File

@ -180,6 +180,62 @@ class SetupFragment : Fragment() {
}
)
)
// Add title.keys installation page
add(
SetupPage(
R.drawable.ic_key,
R.string.install_title_keys,
R.string.install_title_keys_description,
R.drawable.ic_add,
true,
R.string.select_keys,
{
titleKeyCallback = it
getTitleKey.launch(arrayOf("*/*"))
},
true,
R.string.install_title_keys_warning,
R.string.install_title_keys_warning_description,
R.string.install_title_keys_warning_help,
{
val file = File(DirectoryInitialization.userDirectory + "/keys/title.keys")
if (file.exists()) {
StepState.COMPLETE
} else {
StepState.INCOMPLETE
}
}
)
)
// Add firmware installation page (mandatory)
add(
SetupPage(
R.drawable.ic_key,
R.string.install_firmware,
R.string.install_firmware_description,
R.drawable.ic_add,
true,
R.string.select_firmware,
{
firmwareCallback = it
getFirmware.launch(arrayOf("application/zip"))
},
true,
R.string.install_firmware_warning,
R.string.install_firmware_warning_description,
R.string.install_firmware_warning_help,
{
if (NativeLibrary.isFirmwareAvailable()) {
StepState.COMPLETE
} else {
StepState.INCOMPLETE
}
}
)
)
add(
SetupPage(
R.drawable.ic_controller,
@ -268,6 +324,18 @@ class SetupFragment : Fragment() {
return@setOnClickListener
}
// Special handling for firmware page - don't allow skipping
if (currentPage.titleId == R.string.install_firmware && !NativeLibrary.isFirmwareAvailable()) {
SetupWarningDialogFragment.newInstance(
currentPage.warningTitleId,
currentPage.warningDescriptionId,
currentPage.warningHelpLinkId,
index,
allowSkip = false
).show(childFragmentManager, SetupWarningDialogFragment.TAG)
return@setOnClickListener
}
if (!hasBeenWarned[index]) {
SetupWarningDialogFragment.newInstance(
currentPage.warningTitleId,
@ -346,6 +414,30 @@ class SetupFragment : Fragment() {
}
}
private lateinit var titleKeyCallback: SetupCallback
val getTitleKey =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result != null) {
mainActivity.processTitleKey(result)
titleKeyCallback.onStepCompleted()
}
}
private lateinit var firmwareCallback: SetupCallback
val getFirmware =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result != null) {
mainActivity.getFirmware.launch(arrayOf("application/zip"))
binding.root.postDelayed({
if (NativeLibrary.isFirmwareAvailable()) {
firmwareCallback.onStepCompleted()
}
}, 1000)
}
}
private lateinit var gamesDirCallback: SetupCallback
val getGamesDirectory =

View File

@ -17,6 +17,7 @@ class SetupWarningDialogFragment : DialogFragment() {
private var descriptionId: Int = 0
private var helpLinkId: Int = 0
private var page: Int = 0
private var allowSkip: Boolean = true
private lateinit var setupFragment: SetupFragment
@ -26,17 +27,24 @@ class SetupWarningDialogFragment : DialogFragment() {
descriptionId = requireArguments().getInt(DESCRIPTION)
helpLinkId = requireArguments().getInt(HELP_LINK)
page = requireArguments().getInt(PAGE)
allowSkip = requireArguments().getBoolean(ALLOW_SKIP, true)
setupFragment = requireParentFragment() as SetupFragment
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = MaterialAlertDialogBuilder(requireContext())
.setPositiveButton(R.string.warning_skip) { _: DialogInterface?, _: Int ->
if (allowSkip) {
builder.setPositiveButton(R.string.warning_skip) { _: DialogInterface?, _: Int ->
setupFragment.pageForward()
setupFragment.setPageWarned(page)
}
.setNegativeButton(R.string.warning_cancel, null)
builder.setNegativeButton(R.string.warning_cancel, null)
} else {
// For mandatory steps, only show an OK button that dismisses the dialog
builder.setPositiveButton(R.string.ok, null)
}
if (titleId != 0) {
builder.setTitle(titleId)
@ -48,7 +56,7 @@ class SetupWarningDialogFragment : DialogFragment() {
}
if (helpLinkId != 0) {
builder.setNeutralButton(R.string.warning_help) { _: DialogInterface?, _: Int ->
val helpLink = resources.getString(R.string.install_prod_keys_warning_help)
val helpLink = resources.getString(helpLinkId)
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(helpLink))
startActivity(intent)
}
@ -64,12 +72,14 @@ class SetupWarningDialogFragment : DialogFragment() {
private const val DESCRIPTION = "Description"
private const val HELP_LINK = "HelpLink"
private const val PAGE = "Page"
private const val ALLOW_SKIP = "AllowSkip"
fun newInstance(
titleId: Int,
descriptionId: Int,
helpLinkId: Int,
page: Int
page: Int,
allowSkip: Boolean = true
): SetupWarningDialogFragment {
val dialog = SetupWarningDialogFragment()
val bundle = Bundle()
@ -78,6 +88,7 @@ class SetupWarningDialogFragment : DialogFragment() {
putInt(DESCRIPTION, descriptionId)
putInt(HELP_LINK, helpLinkId)
putInt(PAGE, page)
putBoolean(ALLOW_SKIP, allowSkip)
}
dialog.arguments = bundle
return dialog

View File

@ -0,0 +1,222 @@
// Copyright 2024 Mandarine Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citron.citron_emu.network
import android.app.Activity
import android.content.Context
import android.net.wifi.WifiManager
import android.os.Handler
import android.os.Looper
import android.text.format.Formatter
import android.widget.Toast
import androidx.preference.PreferenceManager
import org.citron.citron_emu.CitronApplication
import org.citron.citron_emu.R
import org.citron.citron_emu.dialogs.ChatMessage
object NetPlayManager {
external fun netPlayCreateRoom(ipAddress: String, port: Int, username: String, password: String, roomName: String, maxPlayers: Int): Int
external fun netPlayJoinRoom(ipAddress: String, port: Int, username: String, password: String): Int
external fun netPlayRoomInfo(): Array<String>
external fun netPlayIsJoined(): Boolean
external fun netPlayIsHostedRoom(): Boolean
external fun netPlaySendMessage(msg: String)
external fun netPlayKickUser(username: String)
external fun netPlayLeaveRoom()
external fun netPlayIsModerator(): Boolean
external fun netPlayGetBanList(): Array<String>
external fun netPlayBanUser(username: String)
external fun netPlayUnbanUser(username: String)
private var messageListener: ((Int, String) -> Unit)? = null
private var adapterRefreshListener: ((Int, String) -> Unit)? = null
fun setOnMessageReceivedListener(listener: (Int, String) -> Unit) {
messageListener = listener
}
fun setOnAdapterRefreshListener(listener: (Int, String) -> Unit) {
adapterRefreshListener = listener
}
fun getUsername(activity: Context): String { val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
val name = "Citron${(Math.random() * 100).toInt()}"
return prefs.getString("NetPlayUsername", name) ?: name
}
fun setUsername(activity: Activity, name: String) {
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
prefs.edit().putString("NetPlayUsername", name).apply()
}
fun getRoomAddress(activity: Activity): String {
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
val address = getIpAddressByWifi(activity)
return prefs.getString("NetPlayRoomAddress", address) ?: address
}
fun setRoomAddress(activity: Activity, address: String) {
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
prefs.edit().putString("NetPlayRoomAddress", address).apply()
}
fun getRoomPort(activity: Activity): String {
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
return prefs.getString("NetPlayRoomPort", "24872") ?: "24872"
}
fun setRoomPort(activity: Activity, port: String) {
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
prefs.edit().putString("NetPlayRoomPort", port).apply()
}
private val chatMessages = mutableListOf<ChatMessage>()
private var isChatOpen = false
fun addChatMessage(message: ChatMessage) {
chatMessages.add(message)
}
fun getChatMessages(): List<ChatMessage> = chatMessages
fun clearChat() {
chatMessages.clear()
}
fun setChatOpen(isOpen: Boolean) {
isChatOpen = isOpen
}
fun addNetPlayMessage(type: Int, msg: String) {
val context = CitronApplication.appContext
val message = formatNetPlayStatus(context, type, msg)
when (type) {
NetPlayStatus.CHAT_MESSAGE -> {
val parts = msg.split(":", limit = 2)
if (parts.size == 2) {
val nickname = parts[0].trim()
val chatMessage = parts[1].trim()
addChatMessage(ChatMessage(
nickname = nickname,
username = "",
message = chatMessage
))
}
}
NetPlayStatus.MEMBER_JOIN,
NetPlayStatus.MEMBER_LEAVE,
NetPlayStatus.MEMBER_KICKED,
NetPlayStatus.MEMBER_BANNED -> {
addChatMessage(ChatMessage(
nickname = "System",
username = "",
message = message
))
}
}
Handler(Looper.getMainLooper()).post {
if (!isChatOpen) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}
messageListener?.invoke(type, msg)
adapterRefreshListener?.invoke(type, msg)
}
private fun formatNetPlayStatus(context: Context, type: Int, msg: String): String {
return when (type) {
NetPlayStatus.NETWORK_ERROR -> context.getString(R.string.multiplayer_network_error)
NetPlayStatus.LOST_CONNECTION -> context.getString(R.string.multiplayer_lost_connection)
NetPlayStatus.NAME_COLLISION -> context.getString(R.string.multiplayer_name_collision)
NetPlayStatus.MAC_COLLISION -> context.getString(R.string.multiplayer_mac_collision)
NetPlayStatus.CONSOLE_ID_COLLISION -> context.getString(R.string.multiplayer_console_id_collision)
NetPlayStatus.WRONG_VERSION -> context.getString(R.string.multiplayer_wrong_version)
NetPlayStatus.WRONG_PASSWORD -> context.getString(R.string.multiplayer_wrong_password)
NetPlayStatus.COULD_NOT_CONNECT -> context.getString(R.string.multiplayer_could_not_connect)
NetPlayStatus.ROOM_IS_FULL -> context.getString(R.string.multiplayer_room_is_full)
NetPlayStatus.HOST_BANNED -> context.getString(R.string.multiplayer_host_banned)
NetPlayStatus.PERMISSION_DENIED -> context.getString(R.string.multiplayer_permission_denied)
NetPlayStatus.NO_SUCH_USER -> context.getString(R.string.multiplayer_no_such_user)
NetPlayStatus.ALREADY_IN_ROOM -> context.getString(R.string.multiplayer_already_in_room)
NetPlayStatus.CREATE_ROOM_ERROR -> context.getString(R.string.multiplayer_create_room_error)
NetPlayStatus.HOST_KICKED -> context.getString(R.string.multiplayer_host_kicked)
NetPlayStatus.UNKNOWN_ERROR -> context.getString(R.string.multiplayer_unknown_error)
NetPlayStatus.ROOM_UNINITIALIZED -> context.getString(R.string.multiplayer_room_uninitialized)
NetPlayStatus.ROOM_IDLE -> context.getString(R.string.multiplayer_room_idle)
NetPlayStatus.ROOM_JOINING -> context.getString(R.string.multiplayer_room_joining)
NetPlayStatus.ROOM_JOINED -> context.getString(R.string.multiplayer_room_joined)
NetPlayStatus.ROOM_MODERATOR -> context.getString(R.string.multiplayer_room_moderator)
NetPlayStatus.MEMBER_JOIN -> context.getString(R.string.multiplayer_member_join, msg)
NetPlayStatus.MEMBER_LEAVE -> context.getString(R.string.multiplayer_member_leave, msg)
NetPlayStatus.MEMBER_KICKED -> context.getString(R.string.multiplayer_member_kicked, msg)
NetPlayStatus.MEMBER_BANNED -> context.getString(R.string.multiplayer_member_banned, msg)
NetPlayStatus.ADDRESS_UNBANNED -> context.getString(R.string.multiplayer_address_unbanned)
NetPlayStatus.CHAT_MESSAGE -> msg
else -> ""
}
}
fun getIpAddressByWifi(activity: Activity): String {
var ipAddress = 0
val wifiManager = activity.getSystemService(WifiManager::class.java)
val wifiInfo = wifiManager.connectionInfo
if (wifiInfo != null) {
ipAddress = wifiInfo.ipAddress
}
if (ipAddress == 0) {
val dhcpInfo = wifiManager.dhcpInfo
if (dhcpInfo != null) {
ipAddress = dhcpInfo.ipAddress
}
}
return if (ipAddress == 0) {
"192.168.0.1"
} else {
Formatter.formatIpAddress(ipAddress)
}
}
fun getBanList(): List<String> {
return netPlayGetBanList().toList()
}
object NetPlayStatus {
const val NO_ERROR = 0
const val NETWORK_ERROR = 1
const val LOST_CONNECTION = 2
const val NAME_COLLISION = 3
const val MAC_COLLISION = 4
const val CONSOLE_ID_COLLISION = 5
const val WRONG_VERSION = 6
const val WRONG_PASSWORD = 7
const val COULD_NOT_CONNECT = 8
const val ROOM_IS_FULL = 9
const val HOST_BANNED = 10
const val PERMISSION_DENIED = 11
const val NO_SUCH_USER = 12
const val ALREADY_IN_ROOM = 13
const val CREATE_ROOM_ERROR = 14
const val HOST_KICKED = 15
const val UNKNOWN_ERROR = 16
const val ROOM_UNINITIALIZED = 17
const val ROOM_IDLE = 18
const val ROOM_JOINING = 19
const val ROOM_JOINED = 20
const val ROOM_MODERATOR = 21
const val MEMBER_JOIN = 22
const val MEMBER_LEAVE = 23
const val MEMBER_KICKED = 24
const val MEMBER_BANNED = 25
const val ADDRESS_UNBANNED = 26
const val CHAT_MESSAGE = 27
}
}

View File

@ -31,6 +31,7 @@ import org.citron.citron_emu.HomeNavigationDirections
import org.citron.citron_emu.NativeLibrary
import org.citron.citron_emu.R
import org.citron.citron_emu.databinding.ActivityMainBinding
import org.citron.citron_emu.dialogs.NetPlayDialog
import org.citron.citron_emu.features.settings.model.Settings
import org.citron.citron_emu.fragments.AddGameFolderDialogFragment
import org.citron.citron_emu.fragments.ProgressDialogFragment
@ -68,6 +69,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
ThemeHelper.setTheme(this)
NativeLibrary.netPlayInit()
super.onCreate(savedInstanceState)
@ -157,6 +159,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
setInsets()
}
fun displayMultiplayerDialog() {
val dialog = NetPlayDialog(this)
dialog.show()
}
private fun checkKeys() {
if (!NativeLibrary.areKeysPresent()) {
MessageDialogFragment.newInstance(
@ -370,6 +377,57 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
return false
}
val getTitleKey =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result != null) {
processTitleKey(result)
}
}
fun processTitleKey(result: Uri): Boolean {
if (FileUtil.getExtension(result) != "keys") {
MessageDialogFragment.newInstance(
this,
titleId = R.string.reading_keys_failure,
descriptionId = R.string.install_title_keys_failure_extension_description
).show(supportFragmentManager, MessageDialogFragment.TAG)
return false
}
contentResolver.takePersistableUriPermission(
result,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
if (FileUtil.copyUriToInternalStorage(
result,
dstPath,
"title.keys"
) != null
) {
if (NativeLibrary.reloadKeys()) {
Toast.makeText(
applicationContext,
R.string.install_keys_success,
Toast.LENGTH_SHORT
).show()
homeViewModel.setCheckKeys(true)
gamesViewModel.reloadGames(true)
return true
} else {
MessageDialogFragment.newInstance(
this,
titleId = R.string.invalid_keys_error,
descriptionId = R.string.install_keys_failure_description,
helpLinkId = R.string.dumping_keys_quickstart_link
).show(supportFragmentManager, MessageDialogFragment.TAG)
return false
}
}
return false
}
val getFirmware =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result == null) {

View File

@ -0,0 +1,19 @@
// Copyright 2024 Mandarine Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citron.citron_emu.utils
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
object CompatUtils {
fun findActivity(context: Context): Activity {
return when (context) {
is Activity -> context
is ContextWrapper -> findActivity(context.baseContext)
else -> throw IllegalArgumentException("Context is not an Activity")
}
}
}

View File

@ -0,0 +1,74 @@
package org.citron.citron_emu.utils
import android.app.Activity
import android.app.AlertDialog
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.pm.PackageManager
import android.content.pm.Signature
import android.os.Build
import android.os.Process
import kotlin.system.exitProcess
object LicenseVerifier {
private const val EXPECTED_PACKAGE = "org.citron.citron_emu"
private const val ALTERNATE_PACKAGE = "com.miHoYo.Yuanshen"
private const val ALTERNATE_PACKAGE_2 = "com.antutu.ABenchMark"
private const val OFFICIAL_HASH = "308202e4308201cc020101300d06092a864886f70d010105050030373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b30090603550406130255533020170d3231303831383138303335305a180f32303531303831313138303335305a30373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b300906035504061302555330820122300d06092a864886f70d01010105000382010f003082010a0282010100803b4ba8d352ed0475a8442032eadb75ea0a865a0c310c59970bc5f011f162733941a17bac932e060a7f6b00e1d87e640d87951753ee396893769a6e4a60baddc2bf896cd46d5a08c8321879b955eeb6d9f43908029ec6e938433432c5a1ba19da26d8b3dba39f919695626fba5c412b4aba03d85f0246e79af54d6d57347aa6b5095fe916a34262e7060ef4d3f436e7ce03093757fb719b7e72267402289b0fd819673ee44b5aee23237be8e46be08df64b42de09be6090c49d6d0d7d301f0729e25c67eae2d862a87db0aa19db25ba291aae60c7740e0b745af0f1f236dadeb81fe29104a0731eb9091249a94bb56a90239b6496977ebaf1d98b6fa9f679cd0203010001300d06092a864886f70d01010505000382010100784d8e8d28b11bbdb09b5d9e7b8b4fac0d6defd2703d43da63ad4702af76f6ac700f5dcc2f480fbbf6fb664daa64132b36eb7a7880ade5be12919a14c8816b5c1da06870344902680e8ace430705d0a08158d44a3dc710fff6d60b6eb5eff4056bb7d462dafed5b8533c815988805c9f529ef1b70c7c10f1e225eded6db08f847ae805d8b37c174fa0b42cbab1053acb629711e60ce469de383173e714ae2ea76a975169785d1dbe330f803f7f12dd6616703dbaae4d4c327c5174bee83f83635e06f8634cf49d63ba5c3a4f865572740cf9e720e7df1d48fd7a4a2a651d7bb9f40d1cc6b6680b384827a6ea2a44cc1e5168218637fc5da0c3739caca8d21a1d"
fun verifyLicense(activity: Activity) {
val currentPackage = activity.packageName
val isDebugBuild = currentPackage.endsWith(".debug")
val isEaBuild = currentPackage.endsWith(".ea")
// Check package name
if (!isDebugBuild && !isEaBuild &&
currentPackage != EXPECTED_PACKAGE &&
currentPackage != ALTERNATE_PACKAGE &&
currentPackage != ALTERNATE_PACKAGE_2) {
showViolationDialog(activity)
return
}
try {
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
activity.packageManager.getPackageInfo(
currentPackage,
PackageManager.PackageInfoFlags.of(PackageManager.GET_SIGNATURES.toLong())
)
} else {
@Suppress("DEPRECATION")
activity.packageManager.getPackageInfo(currentPackage, PackageManager.GET_SIGNATURES)
}
if (!verifySignature(packageInfo.signatures)) {
showViolationDialog(activity)
}
} catch (e: Exception) {
showViolationDialog(activity)
}
}
private fun verifySignature(signatures: Array<Signature>?): Boolean {
if (signatures == null || signatures.isEmpty()) return false
val currentSignature = signatures[0].toCharsString()
return currentSignature == OFFICIAL_HASH
}
private fun showViolationDialog(activity: Activity) {
AlertDialog.Builder(activity)
.setTitle("License Violation")
.setMessage("This appears to be a modified version of Citron Emulator. " +
"Redistributing modified versions without source code violates the GPLv3 License. " +
"The application will now close.")
.setCancelable(false)
.setPositiveButton("Exit") { _, _ ->
activity.finish()
Process.killProcess(Process.myPid())
exitProcess(1)
}
.show()
}
}

View File

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: 2025 Citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@ -51,7 +52,7 @@ struct Values {
Settings::Setting<s32> theme{linkage, 0, "theme", Settings::Category::Android};
Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android};
Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds",
Settings::Setting<bool> black_backgrounds{linkage, true, "black_backgrounds",
Settings::Category::Android};
// Input/performance overlay settings
@ -67,7 +68,9 @@ struct Values {
Settings::Category::Overlay};
Settings::Setting<bool> show_performance_overlay{linkage, true, "show_performance_overlay",
Settings::Category::Overlay};
Settings::Setting<bool> show_thermal_overlay{linkage, false, "show_thermal_overlay",
Settings::Setting<bool> show_thermal_overlay{linkage, true, "show_thermal_overlay",
Settings::Category::Overlay};
Settings::Setting<bool> show_ram_overlay{linkage, false, "show_ram_overlay",
Settings::Category::Overlay};
Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay",
Settings::Category::Overlay};

View File

@ -20,6 +20,7 @@
#include <frontend_common/content_manager.h>
#include <jni.h>
#include "common/android/multiplayer/multiplayer.h"
#include "common/android/android_common.h"
#include "common/android/id_cache.h"
#include "common/detached_tasks.h"
@ -870,4 +871,83 @@ jboolean Java_org_citron_citron_1emu_NativeLibrary_areKeysPresent(JNIEnv* env, j
return ContentManager::AreKeysPresent();
}
JNIEXPORT jint JNICALL Java_org_citron_citron_1emu_network_NetPlayManager_netPlayCreateRoom(
JNIEnv* env, [[maybe_unused]] jobject obj, jstring ipaddress, jint port,
jstring username, jstring password, jstring room_name, jint max_players) {
return static_cast<jint>(
NetPlayCreateRoom(Common::Android::GetJString(env, ipaddress), port,
Common::Android::GetJString(env, username), Common::Android::GetJString(env, password),
Common::Android::GetJString(env, room_name), max_players));
}
JNIEXPORT jint JNICALL Java_org_citron_citron_1emu_network_NetPlayManager_netPlayJoinRoom(
JNIEnv* env, [[maybe_unused]] jobject obj, jstring ipaddress, jint port,
jstring username, jstring password) {
return static_cast<jint>(
NetPlayJoinRoom(Common::Android::GetJString(env, ipaddress), port,
Common::Android::GetJString(env, username), Common::Android::GetJString(env, password)));
}
JNIEXPORT jobjectArray JNICALL
Java_org_citron_citron_1emu_network_NetPlayManager_netPlayRoomInfo(
JNIEnv* env, [[maybe_unused]] jobject obj) {
return Common::Android::ToJStringArray(env, NetPlayRoomInfo());
}
JNIEXPORT jboolean JNICALL
Java_org_citron_citron_1emu_network_NetPlayManager_netPlayIsJoined(
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
return NetPlayIsJoined();
}
JNIEXPORT jboolean JNICALL
Java_org_citron_citron_1emu_network_NetPlayManager_netPlayIsHostedRoom(
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
return NetPlayIsHostedRoom();
}
JNIEXPORT void JNICALL
Java_org_citron_citron_1emu_network_NetPlayManager_netPlaySendMessage(
JNIEnv* env, [[maybe_unused]] jobject obj, jstring msg) {
NetPlaySendMessage(Common::Android::GetJString(env, msg));
}
JNIEXPORT void JNICALL Java_org_citron_citron_1emu_network_NetPlayManager_netPlayKickUser(
JNIEnv* env, [[maybe_unused]] jobject obj, jstring username) {
NetPlayKickUser(Common::Android::GetJString(env, username));
}
JNIEXPORT void JNICALL Java_org_citron_citron_1emu_network_NetPlayManager_netPlayLeaveRoom(
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
NetPlayLeaveRoom();
}
JNIEXPORT jboolean JNICALL
Java_org_citron_citron_1emu_network_NetPlayManager_netPlayIsModerator(
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
return NetPlayIsModerator();
}
JNIEXPORT jobjectArray JNICALL
Java_org_citron_citron_1emu_network_NetPlayManager_netPlayGetBanList(
JNIEnv* env, [[maybe_unused]] jobject obj) {
return Common::Android::ToJStringArray(env, NetPlayGetBanList());
}
JNIEXPORT void JNICALL Java_org_citron_citron_1emu_network_NetPlayManager_netPlayBanUser(
JNIEnv* env, [[maybe_unused]] jobject obj, jstring username) {
NetPlayBanUser(Common::Android::GetJString(env, username));
}
JNIEXPORT void JNICALL Java_org_citron_citron_1emu_network_NetPlayManager_netPlayUnbanUser(
JNIEnv* env, [[maybe_unused]] jobject obj, jstring username) {
NetPlayUnbanUser(Common::Android::GetJString(env, username));
}
JNIEXPORT void JNICALL
Java_org_citron_citron_1emu_NativeLibrary_netPlayInit(
JNIEnv* env, [[maybe_unused]] jobject obj) {
NetworkInit(&EmulationSession::GetInstance().System().GetRoomNetwork());
}
} // extern "C"

View File

@ -0,0 +1,31 @@
#include "core/crypto/key_manager.h"
#include "core/hle/service/am/am.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/content_archive.h"
#include "core/system.h"
extern "C" {
JNIEXPORT jboolean JNICALL Java_org_citron_citron_1emu_NativeLibrary_isFirmwareAvailable(
JNIEnv* env, jobject obj) {
return Core::Crypto::KeyManager::Instance().IsFirmwareAvailable();
}
JNIEXPORT jboolean JNICALL Java_org_citron_citron_1emu_NativeLibrary_checkFirmwarePresence(
JNIEnv* env, jobject obj) {
constexpr u64 MiiEditId = 0x0100000000001009; // Mii Edit applet ID
constexpr u64 QLaunchId = 0x0100000000001000; // Home Menu applet ID
auto& system = Core::System::GetInstance();
auto bis_system = system.GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
return false;
}
auto mii_applet_nca = bis_system->GetEntry(MiiEditId, FileSys::ContentRecordType::Program);
auto qlaunch_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program);
return (mii_applet_nca != nullptr && qlaunch_nca != nullptr);
}
} // extern "C"

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorPrimary"
android:pathData="M1,9l2,2c4.97,-4.97 13.03,-4.97 18,0l2,-2C16.93,2.93 7.08,2.93 1,9zM9,17l3,3 3,-3c-1.65,-1.66 -4.34,-1.66 -6,0zM5,13l2,2c2.76,-2.76 7.24,-2.76 10,0l2,-2C15.14,9.14 8.87,9.14 5,13z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v2h8v-2h5c1.1,0 1.99,-0.9 1.99,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,17L3,17L3,5h18v12z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

View File

@ -34,29 +34,42 @@
android:gravity="center"
android:textColor="?attr/colorOnSurface"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/text_description"
app:layout_constraintBottom_toTopOf="@+id/scroll_description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_weight="2"
tools:text="@string/welcome" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_description"
style="@style/TextAppearance.Material3.TitleLarge"
<ScrollView
android:id="@+id/scroll_description"
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
android:textSize="20sp"
android:paddingHorizontal="16dp"
android:fillViewport="true"
android:scrollbars="vertical"
android:fadeScrollbars="false"
android:clipToPadding="false"
android:scrollbarStyle="outsideOverlay"
app:layout_constraintBottom_toTopOf="@+id/button_action"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_title"
app:layout_constraintVertical_weight="2"
app:layout_constraintVertical_weight="2">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_description"
style="@style/TextAppearance.Material3.TitleLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="16dp"
android:paddingVertical="16dp"
android:textAlignment="center"
android:textSize="20sp"
app:lineHeight="30sp"
tools:text="@string/welcome_description" />
</ScrollView>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_confirmation"
style="@style/TextAppearance.Material3.TitleLarge"
@ -72,7 +85,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_description"
app:layout_constraintTop_toBottomOf="@+id/scroll_description"
app:layout_constraintVertical_weight="1"
app:lineHeight="30sp" />
@ -88,7 +101,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_description"
app:layout_constraintTop_toBottomOf="@+id/scroll_description"
tools:text="Get started" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/ban_list_recycler"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"/>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:gravity="center"
app:strokeWidth="0dp"
app:cardCornerRadius="24dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="?colorSurface">
<View
android:layout_width="128dp"
android:layout_height="4dp"
android:layout_marginVertical="8dp"
android:backgroundTint="?colorSurfaceVariant" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</androidx.core.widget.NestedScrollView>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<TextView
android:id="@+id/text_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/chat"
android:textAppearance="?attr/textAppearanceHeadline6"
android:gravity="center"
android:layout_marginBottom="16dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/chat_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginBottom="16dp"
android:transcriptMode="alwaysScroll" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/type_message">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/chat_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:imeOptions="actionSend" />
</com.google.android.material.textfield.TextInputLayout>
<ImageButton
android:id="@+id/send_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="bottom"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_send"
android:contentDescription="@string/send_message" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:id="@+id/drag_handle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/text_title"
android:text="@string/multiplayer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceHeadline6"
android:gravity="center"
android:layout_marginTop="4dp"
android:textColor="?attr/colorOnSurface" />
<ImageView
android:layout_width="140dp"
android:layout_height="140dp"
android:layout_gravity="center"
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp"
android:src="@drawable/ic_network"
app:tint="?attr/colorPrimary" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="8dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_join"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/multiplayer_join_room"
app:icon="@drawable/ic_install"
app:cornerRadius="16dp" />
<Space
android:layout_width="16dp"
android:layout_height="match_parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_create"
style="@style/Widget.Material3.Button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/multiplayer_create_room"
app:icon="@drawable/ic_add"
app:cornerRadius="16dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,75 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:id="@+id/drag_handle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/text_title"
android:text="@string/multiplayer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceHeadline6"
android:gravity="center"
android:layout_marginTop="4dp"
android:textColor="?attr/colorOnSurface" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_multiplayer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="8dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_chat"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="8dp"
android:enabled="true"
android:text="@string/multiplayer_chat"
app:icon="@drawable/ic_chat"
app:cornerRadius="16dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_moderation"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="8dp"
android:enabled="true"
android:text="@string/multiplayer_moderation"
app:cornerRadius="16dp"
app:icon="@drawable/ic_user" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_leave"
style="@style/Widget.Material3.Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/multiplayer_exit_room"
app:icon="@drawable/ic_exit"
app:cornerRadius="16dp" />
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@ -0,0 +1,119 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:clipToPadding="false"
android:clipChildren="false"
android:elevation="4dp">
<TextView
android:id="@+id/textTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceHeadline6"
android:gravity="center"
android:paddingBottom="8dp"
android:textColor="?attr/colorOnSurface" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/multiplayer_ip_address"
android:padding="8dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/ip_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/multiplayer_ip_port"
android:padding="8dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/ip_port"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/multiplayer_username"
android:padding="8dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/multiplayer_password"
android:padding="8dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/multiplayer_room_name"
android:padding="8dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/room_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:id="@+id/max_players_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.slider.Slider
android:id="@+id/max_players"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:value="8"
android:valueFrom="2"
android:valueTo="16"
android:stepSize="1" />
<TextView
android:id="@+id/max_players_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/multiplayer_max_players_value" />
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/ok"
android:layout_gravity="center" />
</LinearLayout>
</ScrollView>

View File

@ -171,6 +171,21 @@
</FrameLayout>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/show_ram_text"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="24dp"
android:clickable="false"
android:focusable="false"
android:textColor="@android:color/white"
android:shadowColor="@android:color/black"
android:shadowRadius="3"
android:layout_below="@id/show_fps_text"
tools:ignore="RtlHardcoded" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_user"
android:layout_marginEnd="16dp"/>
<TextView
android:id="@+id/ban_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_unban"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/multiplayer_unban"/>
</LinearLayout>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="8dp">
<TextView
android:id="@+id/item_button_netplay_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?attr/textAppearanceBodyLarge" />
<ImageButton
android:id="@+id/item_button_more"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/multiplayer_more_options"
android:src="@drawable/ic_more_vert"
android:padding="12dp" />
</LinearLayout>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp">
<ImageView
android:id="@+id/user_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="8dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/username_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold" />
<TextView
android:id="@+id/message_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/timestamp_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp">
<TextView
android:id="@+id/item_button_netplay_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:id="@+id/item_button_netplay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/multiplayer_kick_member"/>
<ImageButton
android:id="@+id/item_button_more"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_more_vert"/>
</LinearLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"/>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp">
<ImageView
android:id="@+id/item_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"/>
<TextView
android:id="@+id/item_text_netplay_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.divider.MaterialDivider
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="8dp" />

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="12dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/item_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"
app:tint="?attr/colorPrimary" />
<TextView
android:id="@+id/item_text_netplay_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?attr/textAppearanceBodyLarge" />
</LinearLayout>

View File

@ -18,7 +18,7 @@
app:layout_constraintHeight_min="110dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="spread"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintWidth_max="220dp"
app:layout_constraintWidth_min="110dp"
app:layout_constraintVertical_weight="3"
@ -28,65 +28,56 @@
android:id="@+id/text_title"
style="@style/TextAppearance.Material3.DisplaySmall"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textColor="?attr/colorOnSurface"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/text_description"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toTopOf="@+id/scroll_description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/icon"
app:layout_constraintVertical_weight="1.3"
tools:text="@string/welcome" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_description"
style="@style/TextAppearance.Material3.TitleLarge"
<ScrollView
android:id="@+id/scroll_description"
android:layout_width="0dp"
android:layout_height="0dp"
android:textAlignment="center"
android:textSize="20sp"
android:paddingHorizontal="16dp"
android:fillViewport="true"
android:scrollbars="vertical"
android:fadeScrollbars="false"
android:clipToPadding="false"
android:scrollbarStyle="outsideOverlay"
android:paddingVertical="8dp"
app:layout_constraintBottom_toTopOf="@+id/button_action"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_title"
app:layout_constraintVertical_weight="2"
app:layout_constraintVertical_weight="2">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_description"
style="@style/TextAppearance.Material3.TitleLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="16dp"
android:textAlignment="center"
android:textSize="20sp"
app:lineHeight="30sp"
tools:text="@string/welcome_description" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_confirmation"
style="@style/TextAppearance.Material3.TitleLarge"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:paddingHorizontal="16dp"
android:paddingTop="24dp"
android:textAlignment="center"
android:textSize="30sp"
android:visibility="invisible"
android:text="@string/step_complete"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_description"
app:layout_constraintVertical_weight="1"
app:lineHeight="30sp" />
</ScrollView>
<com.google.android.material.button.MaterialButton
android:id="@+id/button_action"
android:layout_width="wrap_content"
android:layout_height="56dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="48dp"
android:textSize="20sp"
app:iconGravity="end"
app:iconSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_description"
tools:text="Get started" />
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="12dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/item_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"
app:tint="?attr/colorPrimary" />
<TextView
android:id="@+id/item_text_netplay_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?attr/textAppearanceBodyLarge" />
</LinearLayout>

View File

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<menu xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:ignore="ExtraText">
<item
android:id="@+id/menu_pause_emulation"
@ -21,6 +23,12 @@
android:icon="@drawable/ic_controller"
android:title="@string/preferences_controls" />
<item
android:id="@+id/menu_multiplayer"
android:icon="@drawable/ic_multiplayer"
android:title="@string/multiplayer" />
<item
android:id="@+id/menu_overlay_controls"
android:icon="@drawable/ic_overlay"

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_kick"
android:title="@string/multiplayer_kick_member"
android:enabled="false" />
<item
android:id="@+id/action_ban"
android:title="@string/multiplayer_ban"
android:enabled="false" />
</menu>

View File

@ -11,6 +11,11 @@
android:title="@string/emulation_thermal_indicator"
android:checkable="true" />
<item
android:id="@+id/ram_meter"
android:title="@string/emulation_ram_meter"
android:checkable="true" />
<item
android:id="@+id/menu_edit_overlay"
android:title="@string/emulation_touch_overlay_edit" />

View File

@ -137,7 +137,7 @@
<string name="about_app_description">محاكي سويتش مفتوح المصدر</string>
<string name="contributors">المساهمين</string>
<string name="contributors_description">مصنوع من فريق يوزو</string>
<string name="contributors_link">https://github.com/citron-emu/citron/graphs/contributors</string>
<string name="contributors_link">https://git.citron-emu.org/Citron/Citron/graphs/contributors</string>
<string name="licenses_description">المشاريع التي تجعل تطبيق يوزو لنظام أندرويد ممكنًا</string>
<string name="build">البناء</string>
<string name="user_data">بيانات المستخدم</string>
@ -151,7 +151,7 @@
<string name="user_data_export_cancelled">تم إلغاء التصدير</string>
<string name="support_link">https://discord.gg/u77vRWY</string>
<string name="website_link">https://citron-emu.org/</string>
<string name="github_link">https://github.com/citron-emu</string>
<string name="github_link">https://git.citron-emu.org</string>
<!-- Early access upgrade strings -->
<string name="early_access">الوصول المبكر</string>

View File

@ -103,12 +103,12 @@
<string name="about_app_description">ئیمۆلیتەرێکی سەرچاوە-کراوەی سویچ</string>
<string name="contributors">بەشداربووان</string>
<string name="contributors_description">دروستکراوە لەگەڵ \u2764 لەلایەن تیمەکەی یوزو</string>
<string name="contributors_link">https://github.com/citron-emu/citron/graphs/contributors</string>
<string name="contributors_link">https://git.citron-emu.org/Citron/Citron/graphs/contributors</string>
<string name="licenses_description">ئەو پڕۆژانەی کە یوزوی بۆ ئەندرۆید ڕەخساند</string>
<string name="build">بونیات</string>
<string name="support_link">https://discord.gg/u77vRWY</string>
<string name="website_link">https://citron-emu.org/</string>
<string name="github_link">https://github.com/citron-emu</string>
<string name="github_link">https://git.citron-emu.org</string>
<!-- Early access upgrade strings -->
<string name="early_access">بەزوویی دەسپێگەشتن</string>

View File

@ -86,7 +86,7 @@
<string name="about_app_description">Open-source Switch emulátor</string>
<string name="contributors">Přispěvatelé</string>
<string name="contributors_description">Vyrobeno s \u2764 od citron týmu</string>
<string name="contributors_link">https://github.com/citron-emu/citron/graphs/contributors</string>
<string name="contributors_link">https://git.citron-emu.org/Citron/Citron/graphs/contributors</string>
<string name="build">Číslo sestavení</string>
<string name="user_data">Uživatelská data</string>
<string name="exporting_user_data">Exportování uživatelských dat...</string>
@ -98,7 +98,7 @@
<string name="user_data_export_cancelled">Export zrušen</string>
<string name="support_link">https://discord.gg/u77vRWY</string>
<string name="website_link">https://citron-emu.org/</string>
<string name="github_link">https://github.com/citron-emu</string>
<string name="github_link">https://git.citron-emu.org</string>
<string name="play_store_link">https://play.google.com/store/apps/details?id=org.citron.citron_emu.ea</string>
<string name="no_manual_installation">Žádná manuální instalace</string>

View File

@ -122,7 +122,7 @@ Wirklich fortfahren?</string>
<string name="about_app_description">Ein quelloffener Switch-Emulator</string>
<string name="contributors">Beitragende</string>
<string name="contributors_description">Gemacht mit \u2764 vom citron Team</string>
<string name="contributors_link">https://github.com/citron-emu/citron/graphs/contributors</string>
<string name="contributors_link">https://git.citron-emu.org/Citron/Citron/graphs/contributors</string>
<string name="licenses_description">Projekte, die citron für Android möglich machen </string>
<string name="build">Build</string>
<string name="user_data">Nutzerdaten</string>
@ -133,7 +133,7 @@ Wirklich fortfahren?</string>
<string name="user_data_export_cancelled">Export abgebrochen</string>
<string name="support_link">https://discord.gg/u77vRWY</string>
<string name="website_link">https://citron-emu.org/</string>
<string name="github_link">https://github.com/citron-emu</string>
<string name="github_link">https://git.citron-emu.org</string>
<!-- Early access upgrade strings -->
<string name="early_access">Early Access</string>

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