Compare commits

...

481 Commits

Author SHA1 Message Date
Stenzek 0e49ce71da
GPU: Refactor display presentation workflow
Adds the ability to set overlays, and fixes postfx with prerotation.
2025-01-18 01:36:05 +10:00
Stenzek 01db85fa62
System: Add fatal error shutdown path
Switch to a null backend and shut down the system instead of crashing.
2025-01-17 20:56:55 +10:00
Stenzek 155e365855
GPU: Split backend into Backend+Presenter 2025-01-17 20:37:32 +10:00
Stenzek 5dc045eabd
System: Allow host to set async worker count
For regtest.
2025-01-17 20:22:30 +10:00
Stenzek feeb8d9e56
CI: Fix Flatpak manifest URL 2025-01-17 20:22:03 +10:00
Stenzek fbb63a81a8
FullscreenUI: Change default background and add Strobe 2025-01-17 16:05:24 +10:00
Stenzek 7deaaa8b26
FullscreenUI: Use ImGui dialogs for boot failure 2025-01-17 14:30:22 +10:00
Stenzek e554456a00
System: Fix blank display on pause-on-start 2025-01-17 14:20:37 +10:00
Stenzek 3be4f1983d
GPU: Fix playback of VRAM updates during draws 2025-01-17 13:22:40 +10:00
Stenzek bf7ca1951e
Qt: Fix game list search box oversizing 2025-01-17 12:56:06 +10:00
Anderson Cardoso 2957f55450
Atualização Português do Brasil (#3356)
Atualizado para a última versão
2025-01-17 13:56:32 +10:00
Stenzek 092b2803c5
GPU/HW: Flipping the mask bit test should flush 2025-01-16 23:50:40 +10:00
Stenzek cd8a160d8d
GPU/HW: Clear alpha channel in opaque replacements
This is the value for bit15 in the framebuffer. Silent Hill
needs it to be zero, I'm not aware of anything that needs
specific values yet. If it did, we'd need a different dumping
technique.
2025-01-16 23:25:24 +10:00
Stenzek a0c075e079
CI/Flatpak: Bump to SDL2 2.30.11
Apparently I forgot to do this.
2025-01-16 22:13:04 +10:00
Stenzek add76c267a
Achievements: Fix request spam downloading own badge icon 2025-01-16 22:13:02 +10:00
Stenzek c4a7456689
GPU/SW: Use no_unique_address for potentially-unused varyings 2025-01-16 22:13:02 +10:00
Stenzek 804b8ff777
CDROM: Remove redundant min() 2025-01-16 21:45:34 +10:00
Stenzek 10de915ae0
System: Remove 'sync_to_host_with_vsync'
Disabling the throttler with threaded rendering just leads to the CPU
thread pushing multiple frames, and getting backpressured from the GPU
thread. In other words, input lag.
2025-01-16 21:45:30 +10:00
Stenzek 074a8a2653
GPUThread: Fix input OSD with threaded rendering off 2025-01-16 21:38:45 +10:00
Stenzek f6f709bcc5
System: Fix vsync preventing fast forward/turbo 2025-01-16 21:14:21 +10:00
Stenzek 0507054675
Common: Add vector rsize() 2025-01-16 21:01:30 +10:00
Stenzek 93771981a6
FullscreenUI: Add sort alphabetically option to cheat page 2025-01-16 13:47:09 +10:00
Stenzek 79245b6cd6
FullscreenUI: Make footer text background semitransparent 2025-01-16 01:14:22 +10:00
Stenzek 57f3fee28c
Common: Further optimize alltrue()/allfalse() on ARM 2025-01-16 00:43:33 +10:00
Stenzek 0189e1ef81
Common: Fix vector allfalse() on ARM32 2025-01-15 23:53:48 +10:00
Stenzek 45b500bc2c
GPU/HW: Fix draw call count spiking in some scenarios 2025-01-15 22:50:29 +10:00
Stenzek 3687697d0e
CPU/CodeCache: Only reset used portion of buffer
Saves writing 48MB every reset.
2025-01-15 21:02:56 +10:00
Stenzek 1952869cdc
Cheats: Author field should be exported 2025-01-15 21:02:56 +10:00
Daniel Nylander 68d9971171
Updated Swedish translation (#3355) 2025-01-15 21:02:40 +10:00
Stenzek 050bda8cd2
FullscreenUI: Fix scroll reset on resume state popup 2025-01-14 21:07:00 +10:00
Stenzek 135d99ac17
FullscreenUI: Fix incorrect help text 2025-01-14 21:07:00 +10:00
Stenzek 7973a91438
FullscreenUI: Make menu item backgrounds slightly transparent
Blends with background.
2025-01-14 21:07:00 +10:00
Stenzek 2e95667ec2
Qt: Fix returning to desktop mode from Big Picture 2025-01-14 20:51:13 +10:00
Stenzek bbb1befa43
RegTest: Build fix 2025-01-14 20:51:13 +10:00
Stenzek 2fd89403f8
FullscreenUI: Name landing icon files after action 2025-01-14 19:05:18 +10:00
Stenzek 3130e16438
FullscreenUI: Add user-selectable backgrounds 2025-01-14 18:59:42 +10:00
Stenzek ccb2b61444
FullscreenUI: Fix incorrect back button 2025-01-14 16:33:24 +10:00
Stenzek 1aa1b5a7ec
Qt: Make main toolbar editable 2025-01-14 16:33:24 +10:00
Anderson Cardoso 6a6d36267d
Atualização Português do Brasil (#3354)
Atualizado para a última versão.
2025-01-14 13:53:37 +10:00
Stenzek 880c76da24
Qt: Fix columns being hidden after editing cheats 2025-01-14 13:53:09 +10:00
Stenzek 3a13806f73
Hotkeys: Fix Toggle OSD hotkey 2025-01-14 13:49:49 +10:00
Stenzek 88e18a8659
Image: Fix crash on loading corrupted JPEG file 2025-01-14 13:29:14 +10:00
Stenzek da1590ed5f
Qt: Fix cheats sort button tooltip 2025-01-13 23:49:59 +10:00
Stenzek 6db1dbbe02
GameList: Don't return nonexistant path on icon extract fail 2025-01-13 23:49:09 +10:00
Stenzek 33c0674a9f
Qt: Remove unused struct 2025-01-13 23:18:52 +10:00
Stenzek 5aa23fa6dc
CI: Only pin to major version of actions 2025-01-13 22:50:39 +10:00
Stenzek 991405ce06
Qt: Add search and sorting to cheat list 2025-01-13 22:45:59 +10:00
Stenzek 0dc257abe4
System: Set time constraints for GPU thread on MacOS
Fixes erratic frame times.
2025-01-13 19:51:35 +10:00
Stenzek d3854d095e
AnalogController: Use variant vibration icon for large motor 2025-01-13 19:49:56 +10:00
Stenzek dc58d85b51
Data: PromptFont additions by KamFretoZ 2025-01-13 19:47:43 +10:00
Stenzek f6c7681ef0
ImGuiOverlays: Double buffer input OSD and add vibration 2025-01-13 16:49:31 +10:00
Stenzek dd7fd32501
Controller: Add GetVibrationMotorState() 2025-01-13 16:49:14 +10:00
Stenzek aaf2a4b614
InputManager: Adjust scope of constants 2025-01-13 16:35:40 +10:00
Stenzek 3476140ba2
GPUThread: Add BeginASyncBufferCall() 2025-01-13 16:08:20 +10:00
Stenzek 462a4a3b50
Controller: Refactor so that GetControllerInfo() can't return null 2025-01-13 16:07:43 +10:00
Stenzek 062776c1c7
ImGuiManager: Map left stick to dpad 2025-01-13 14:28:39 +10:00
Stenzek c45e59fe22
SDLInputSource: Arrays to std::array and forward generic axis 2025-01-13 14:28:28 +10:00
Stenzek 21aef088ed
XInputSource: Arrays to std::array and forward generic axis 2025-01-13 14:25:51 +10:00
Stenzek 9d3c56fe6c
ImGuiManager: Fix data races in input forwarding 2025-01-13 13:52:07 +10:00
Stenzek 17e8930e94
ImGuiManager: Pack state based on thread access 2025-01-13 13:33:15 +10:00
Stenzek 3621705933
Achievements: Ensure loading old states behave the same as new 2025-01-13 13:13:15 +10:00
Stenzek 8f39dbb464
Achievements: Fix race condition invalidating images 2025-01-13 13:03:41 +10:00
Stenzek 2f854de9d0
Qt: Invalidate FSUI cover cache when cover changed 2025-01-13 12:54:18 +10:00
Stenzek 738c96ffb3
FullscreenUI: Fix slot disappearing after delete in save state menu 2025-01-13 12:44:11 +10:00
Stenzek ea82dacb0e
FullscreenUI: Fix a couple of GPU thread race conditions
State saving/loading, memory card state read on shutdown.
2025-01-13 12:44:06 +10:00
Stenzek a422e06628
Qt: Fix incorrect InitialSortOrderRole use 2025-01-12 21:44:05 +10:00
Stenzek d3ee12d358
Achievements: Login error notification should be translatable 2025-01-12 19:16:22 +10:00
Stenzek 19ee37cd10
FullscreenUI: Render notifications on top of OSD 2025-01-12 19:14:59 +10:00
Stenzek 035762af94
System: Fix subimage change OSD message 2025-01-12 19:03:53 +10:00
Stenzek be7cff5964
CDROM: Fix loading of subimage SBI files 2025-01-12 19:03:48 +10:00
Stenzek e4dea69713
System: Drop state load OSD duration to quick 2025-01-12 17:50:33 +10:00
Stenzek e43d7046ba
Achievements: Attempt relogin on system boot
And display an error notification if login fails, instead of
invalidating the token.
2025-01-12 17:50:33 +10:00
Stenzek 0f76543685
Achivements: Set rc_client log level from host log level 2025-01-12 16:54:58 +10:00
Stenzek ce0689687c
Qt: Fix editing first controller preset 2025-01-12 02:09:55 +10:00
Stenzek c43533f8d8
FullscreenUI: Extend achievement overlays to screen margins
Fixes overlays getting caught in rounded corners on Android.
2025-01-12 01:02:58 +10:00
Stenzek ab790ed54b
Common: Fix ARM32 build (again) 2025-01-12 00:25:48 +10:00
Stenzek ee1da343ab
GPU/HW: Use default initialization for BatchConfig
Reduce the risk of below...
2025-01-12 00:03:45 +10:00
Stenzek 9779cee934
GPU/HW: Ensure texture window bits are initialized
Fixes broken rendering after loading state or switching renderer in some
games, e.g. GTA2.
2025-01-12 00:03:18 +10:00
Stenzek 9c35b0e76d
FullscreenUI: Get rid of Timer global 2025-01-11 23:32:21 +10:00
Stenzek 36590f3c71
InputManager: Fix crash on controller connect on Windows 2025-01-11 23:29:55 +10:00
Stenzek 6785285f31
Qt: Fix game list toolbar/view menu desync 2025-01-11 23:29:40 +10:00
Stenzek 54780d4fbf
Qt: Fix fullscreen state stuck after exit 2025-01-11 21:37:39 +10:00
Stenzek 348e33562e
Qt: Fix BP start/stop menu item after first activation 2025-01-11 21:34:20 +10:00
Stenzek 234e1f721f
FullscreenUI: Improve controller settings page
- Add 'Clear Bindings' menu item.
- Show icons in controller types.
- Add confirmation to Reset Settings.
2025-01-11 21:29:04 +10:00
Stenzek d6ce322eba
Controller: Use additional icons 2025-01-11 20:51:16 +10:00
Stenzek 9971b9e059
Data: Update PromptFont with KamFretoZ's changes 2025-01-11 20:41:26 +10:00
Stenzek e6c0725656
InputManager: Hold lock while manipulating devices/sources
Since we're enumerating on the GPU thread now, need to protect it.
2025-01-11 20:28:00 +10:00
Stenzek d3bee3ce67
Qt: Rename 'Input Profile' to 'Controller Preset'
Hopefully more noob-proof?
2025-01-11 20:25:12 +10:00
Stenzek e4c11aa905
Qt: Separate controller settings to global and profiles 2025-01-11 20:25:11 +10:00
Stenzek 2d63b34d48
Qt: Add icons/decorations to input devices 2025-01-11 20:25:11 +10:00
Stenzek 2298227054
FullscreenUI: Add binding of vibration motors 2025-01-11 20:25:11 +10:00
Stenzek 6f9caa6b12
InputManager: Add proper binds for vibration motors
Instead of the janky "vibration capabilities" flag.

Fixes the "Clear Mappings" button not applying to vibration motors.
2025-01-11 20:25:11 +10:00
Stenzek 13b85728a0
Qt: Refactor input device/motor tracking
Remove multiple sources of truth.
2025-01-11 20:25:11 +10:00
Stenzek 844287b722
FullscreenUI: Fix scrollbar on choice dialog at some screen sizes
e.g. game list right click
2025-01-11 20:25:11 +10:00
Stenzek 4b0bb9f70d
FullscreenUI: Increase input dialog padding
Way too small.
2025-01-11 20:13:53 +10:00
Stenzek 4af5e96ff6
Controller: Remove analog-mode-start OSD message
It's arguably not very useful, and the sticks are mapped to the
dpad in digital mode anyway.
2025-01-11 15:15:01 +10:00
Stenzek 440aaf2644
FullscreenUI: Modernize achievement popup a bit 2025-01-11 15:07:17 +10:00
Stenzek 05b0b03fd6
Cheats: Order special characters before alpha characters 2025-01-11 12:51:33 +10:00
Stenzek 93a7e7cef5
Cheats: Add bounds check to 5107/5147 2025-01-11 12:40:46 +10:00
Anderson Cardoso c98dbb9d9e
Atualização Português do Brasil (#3353)
Atualizado para a última versão.
2025-01-11 12:37:16 +10:00
PugsyMAME a26cac18e9
Cheats: Added register cheat types 5107 & 5147 (#3352)
This is new cheat type uses the general purpose cheat registers in a relative easy method to allow arrays of arrays cheats to be quickly created and will also cut down massively on cheats. For instance this method allows the following 15 cheats for Vandal Hearts II which would otherwise need 18886 separate cheats to replicate:

#Technique Slot Modifier\[MASTER] Select Slot Number for following cheats to act on (1 - 1349)
518500F1 001CF3C3
514500F2 0000000F
514500F3 0000????
514500F4 0000D0D0
OptionRange = 1:1349
#Technique Slot Modifier\Select Weapon
510700F1 000000??
OptionRange = 0x00:0xFF
#Technique Slot Modifier\Technique 1 Learned
510700F1 00020001
#Technique Slot Modifier\Select Technique 1
510700F1 000300??
OptionRange = 0x00:0xFF
#Technique Slot Modifier\Technique 2 Learned
510700F1 00040001
#Technique Slot Modifier\Select Technique 2
510700F1 000500??
OptionRange = 0x00:0xFF
#Technique Slot Modifier\Technique 3 Learned
510700F1 00060001
#Technique Slot Modifier\Select Technique 3
510700F1 000700??
OptionRange = 0x00:0xFF
#Technique Slot Modifier\Technique 4 Learned
510700F1 00080001
#Technique Slot Modifier\Select Technique 4
510700F1 000900??
OptionRange = 0x00:0xFF
#Technique Slot Modifier\Technique 5 Learned
510700F1 000A0001
#Technique Slot Modifier\Select Technique 5
510700F1 000B00??
OptionRange = 0x00:0xFF
#Technique Slot Modifier\Technique 6 Learned
510700F1 000C0001
#Technique Slot Modifier\Select Technique 6
510700F1 000D00??
OptionRange = 0x00:0xFF
#Technique Slot Modifier\100% (Max) Technique Learned
510700F1 000E0064
2025-01-11 12:37:03 +10:00
Stenzek ea4e756512
Data: Update SDL Game Controller DB 2025-01-10 20:44:04 +10:00
Stenzek ee33044f3d
InputManager: Fix SDL sub-options not copying to profile 2025-01-10 20:42:17 +10:00
Stenzek 7ac4a85765
InputManager: Fix per-bind sensitivity/deadzone not copying to profile 2025-01-10 20:14:21 +10:00
Stenzek ccfc60ec94
GPU/HW: Remove extra barrier on VRAM download
Seems to work around download texture corruption on AMD/Vulkan/Windows.
2025-01-10 20:06:56 +10:00
Stenzek 18c90718c6
GPU/SW: Skip pixel load if none preserved
~12% performance improvement on Cortex-A35.
2025-01-10 18:46:05 +10:00
Stenzek 1320d9b456
Common: Use __builtin_shufflevector() for NEON blend() 2025-01-10 17:12:45 +10:00
Stenzek 29934d62c4
System: Improve rewind behaviour
- Fix crash when rewinding before first state is saved.
- Always save a rewind state immediately after normal save state load.
- Don't toss the last rewind state when rewinding, that way there is
  always at least one state to rewind to.
2025-01-09 23:46:06 +10:00
Stenzek d25cffebd5
GPU/HW: Disable depth testing with semitransparency
But provide an option to enable it.
2025-01-09 21:45:14 +10:00
Stenzek d9c9b3038d
GPU/HW: Fix ROV depth being written with semitransparency 2025-01-09 21:21:12 +10:00
Stenzek 7d2898b94c
GPU/HW: Exclude 2D polygons from depth buffer
Fixes UI getting obscured in Kingsley's Adventure.
2025-01-09 21:21:12 +10:00
Stenzek 1c9b9ca37a
GPUThread: Restore context after backend creation
Might help with random VRAM loss? I can't seem to reproduce it now..
2025-01-09 21:21:12 +10:00
Stenzek 40589dcd93
Settings: Add advanced option to set delay for max CD speedup
Affects both seeks and reads.
2025-01-09 21:21:12 +10:00
Stenzek 4449ae7904
Settings: Rearrange fields to avoid padding 2025-01-09 21:21:12 +10:00
Stenzek 9b339d4bff
PostProcessing: Remove StageCount key for game settings
Potentially removes the ini file if it's otherwise empty.
2025-01-09 21:21:12 +10:00
Stenzek 2b4e60a5bf
FullscreenUI: Fix loading screen font 2025-01-09 21:21:12 +10:00
Stenzek bed3dd6950
FullscreenUI: Use span for DrawIntListSetting() 2025-01-09 17:54:12 +10:00
Stenzek b76ebd2a7b
FullscreenUI: Fix scrollbar rounding in choice dialogs 2025-01-09 17:53:52 +10:00
Stenzek 561397a53c
CDROM: Add 'maximum' read speedup option
"Instant" seek is now renamed to Maximum as well, for consistency.
2025-01-09 15:23:47 +10:00
Anderson Cardoso 0ad0859e9d
Atualização Português do Brasil (#3351)
Atualizado para a última versão
2025-01-09 15:23:25 +10:00
Stenzek fc8fbd8f08
Qt: Disable shared memcard settings outside of shared mode 2025-01-08 16:36:05 +10:00
Stenzek 08a3c31bff
CMake: Fix scmversion PRE_BUILD warning 2025-01-08 15:34:21 +10:00
Stenzek 87743c776d
FullscreenUI: Fix crash reloading postfx shaders 2025-01-08 15:29:56 +10:00
Stenzek 45afc8f7b1
OpenGLDevice: Add map-based stream buffer paths
MapAndSync ends up around 25% faster on ancient Mali drivers without
ARB_buffer_storage support.
2025-01-08 14:14:06 +10:00
Stenzek 1daa60c64d
GPU: Use tristrips for presentation as well 2025-01-08 00:14:15 +10:00
Stenzek 670dc461c1
GPU/HW: Slight re-shuffling of field offsets
Free up some bits in the middle.
2025-01-07 23:20:26 +10:00
Stenzek 0030bc2699
GPUDevice: Ensure 16 byte minimum UBO alignment 2025-01-07 23:20:25 +10:00
Stenzek 4c801c3ff3
GPUDevice: Move size-matches check into ResizeTexture() 2025-01-07 23:20:25 +10:00
Stenzek b9186139d0
GPU/HW: Use sized tristrips instead of fullscreen quads 2025-01-07 23:20:25 +10:00
Stenzek 9bc5ffe091
Common: Add Vector4i xyxy(Vector2i) 2025-01-07 23:20:25 +10:00
Stenzek 1063c3da7f
Qt: Add 'Enable Touchpad' to Controller Settings
Have to shuffle a few other things around to fit in 768p.
2025-01-07 13:42:45 +10:00
Stenzek 0a124ee839
SDLInputSource: Support forwarding touchpad to pointer 2025-01-07 13:40:42 +10:00
Stenzek 2b7b3d8729
SDLInputSource: Allow inverting pad axes
Not really sure where this would happen, but whatever.
2025-01-07 13:01:37 +10:00
Stenzek dacbb7c718
Qt: Behaviour -> Behavior
US English is used everywhere else, consistency > *.
2025-01-07 12:50:48 +10:00
Stenzek 6318223f58
Qt: Remove Apperance/Update settings from Game Properties 2025-01-07 12:48:27 +10:00
Stenzek 092e819a07
ImGuiFullscreen: Move texture loading to async tasks
Two threads instead of one, speeds things up a bit.
2025-01-07 12:40:08 +10:00
Stenzek cae1ddc971
GPU: Ensure batches are flushed before presenting frame
Fixes occasional assertion failing when using the debugger.
2025-01-07 12:28:15 +10:00
Stenzek dc9cdddd4c
Qt: Add zst/xz GPU dumps to file filter 2025-01-06 21:18:13 +10:00
Stenzek 0960160589
System: Don't check for subchannel with GPU dump 2025-01-06 21:17:27 +10:00
Stenzek 1765590a6f
Qt: Add 'Disable Window Rounded Corners' option 2025-01-05 16:39:57 +10:00
Stenzek 9f41ef9eac
Scripts: Add release commit generation script 2025-01-05 16:00:15 +10:00
Stenzek 5ee069fc63
FullscreenUI: Add option to display PS buttons instead of Xbox 2025-01-05 16:00:15 +10:00
Stenzek 4d6124d41b
Platform: Fix AppImage dbus library mismatch 2025-01-05 14:08:22 +10:00
Stenzek a5d90c0b22
Deps: Bump to SDL2 2.30.11 2025-01-04 21:18:34 +10:00
Stenzek 6043b2331f
Platform: Fix incorrect dbus shared library name
Fixes screensaver inhibit on Linux.
2025-01-04 21:14:46 +10:00
Stenzek 886040b257
Qt: Display 'No Image' instead of 0x0 in status 2025-01-04 19:21:47 +10:00
Stenzek 8353a33e89
X11Tools: Fix refresh rate query failing with XLib handle 2025-01-04 18:35:15 +10:00
Stenzek 076f4a6293
Qt: Fix delay in progress dialog opening
Applies to updater, verify, etc.
2025-01-04 16:59:33 +10:00
Stenzek 920f25427e
Qt: Simplify Fullscreen UI state tracking
Fixes application closing if the system was shut down while fullscreen.
2025-01-04 16:09:35 +10:00
Stenzek 78ccbc710c
Cheats: Fix error while exporting 2025-01-04 12:52:26 +10:00
Anderson Cardoso 548f1da5af
Atualização Português do Brasil (#3350) 2025-01-04 12:51:08 +10:00
Stenzek 9054801341
ImGuiManager: Update viewport and display size
Fixes the single frame of incorrect draw size when resizing
the window with the Big Picture UI.
2025-01-03 20:16:38 +10:00
Stenzek 80855090d5
Qt: Rewrite cover loading/generation
This was always wrong, QPixmaps shouldn't be manipulated outside of
the UI thread, and it used to crash in debug builds.

Also uses a placeholder image instead of a black image while covers
are loading/generating.
2025-01-03 20:16:38 +10:00
Stenzek db14824d61
System: Use task queue for saving states/screenshots/gpudumps
System shutdown no longer needs to block. Gets rid of the slight
hitch when shutting down and saving state with the Big Picture UI.
2025-01-03 20:16:38 +10:00
Stenzek 547601559c
Common: Add TaskQueue class 2025-01-03 20:16:37 +10:00
Stenzek 52e6e8ff1e
PostProcessing: Compile warning fix 2025-01-03 18:19:12 +10:00
Stenzek f9bb413a40
Qt: Enable clear button on hotkey search 2025-01-03 15:28:43 +10:00
Stenzek dda10d3576
Qt: Add search box to hotkey settings 2025-01-03 14:58:50 +10:00
Stenzek b2c8d25638
GPUBackend: Only display CPU thread blocked messages if queueing 2025-01-03 14:49:53 +10:00
Stenzek 88cd086633
Cheats: Eliminate extra newlines during code editing 2025-01-03 13:36:58 +10:00
Daniel Nylander e096827df8
Updated Swedish translation (#3349) 2025-01-03 13:36:40 +10:00
Stenzek e08dda0a0a
CPU: Declare state with constinit 2025-01-02 21:42:41 +10:00
Stenzek 87e367076d
PostProcessing: Get rid of Timer global 2025-01-02 21:40:01 +10:00
Stenzek ba15a76d7b
ImGuiManager: Pack state in struct 2025-01-02 21:33:53 +10:00
Stenzek d3fe1dfc2c
ImGuiManager: Separate debug and OSD fonts
Don't need to rasterize the former if it's not used, and saves blowing
up the debug window font size if the OSD scale is not 100%.
2025-01-02 21:25:25 +10:00
Stenzek fc5553a8c7
GTE: Improve reverse transform freecam
Transform the move direction, that way it behaves more FPS-camera like.
2025-01-02 20:56:22 +10:00
Stenzek 90cb266886
Common: Small tidy-up and constexpr-ify GSMatrix4x4 2025-01-02 20:52:19 +10:00
Stenzek 83b4757788
Qt: Controller Test should be disabled while running 2025-01-02 02:11:50 +10:00
Stenzek 08cd649187
InputManager: Fix pointer-bound bind movement
i.e. psmouse

Regression from c4e0e7fade
2025-01-02 02:10:31 +10:00
Stenzek cd873eb6c1
GTE: Add 'Reverse Transform Order' option to freecam 2025-01-02 02:09:02 +10:00
Stenzek 3a64c5e4b3
FullscreenUI: Improve field alignment in achievements login 2025-01-02 01:07:18 +10:00
Stenzek b21312867b
FullscreenUI: Fix popup sizes for postfx settings 2025-01-02 01:07:11 +10:00
Stenzek 179e2f1999
FullscrenUI: Fix field spacing scaling in game list view 2025-01-02 00:52:40 +10:00
Stenzek 0fdf984b71
GTE: Disable freecam on Android
Freecam is disabled on Android because there's no windowed UI for it.
And because users can't be trusted to not crash games and complain.
2025-01-02 00:38:29 +10:00
Stenzek e036318559
Qt: Add 'Controller Test' to tools menu 2025-01-02 00:31:15 +10:00
Stenzek c11468b9f1
Qt: Drop log messages if rate is too high
Prevents the application locking up and memory usage going bananas
if log messages do end up spammed at crazy rates.
2025-01-02 00:14:11 +10:00
Stenzek 37e5e64ddc
System: Move state display updates to call sites
Fixes black frames when changing settings with runahead/rewind enabled.
2025-01-01 23:05:08 +10:00
Stenzek f3b7686457
System: Fix crash with memory save states + renderer switch 2025-01-01 22:55:31 +10:00
Stenzek 5ac5a1d246
Hotkeys: Fix resolution scale with memory save states 2025-01-01 22:02:55 +10:00
Stenzek 1d63648d68
Qt: Forward text input to aux render windows
Fixes text input in freecam window.
2025-01-01 22:02:55 +10:00
Stenzek dcd439e7d8
GTE: Add 'Free Camera' feature 2025-01-01 22:02:55 +10:00
Stenzek 22202f1607
Common: Fix vector blend32() and dot() on SSE2 2025-01-01 22:02:55 +10:00
Stenzek d0e1efb1fd
Common: Add more GSMatrix ops 2025-01-01 21:28:16 +10:00
Stenzek f51dda3e66
GPUDevice: Allow this-frame pooled textures when not uploading data
It won't break the render pass.
2025-01-01 19:38:48 +10:00
Stenzek a08acdb93a
System: Improve texture recycling when changing rewind/runahead settings
Fix suprious failures when changing rewind settings when low on VRAM.
2025-01-01 19:33:01 +10:00
Stenzek 8605722cdf
GameDB: GTA does not support analog mode 2025-01-01 17:15:19 +10:00
Stenzek 57be62ffd1
FullscreenUI: Remove a couple of untranslated titles 2025-01-01 14:28:05 +10:00
Stenzek 884459d1cf
FullscreenUI: Fade alpha change when switching to postfx settings 2025-01-01 14:25:56 +10:00
Stenzek ffef0c2e38
CPU/CodeCache: Don't compile invalid jumps via block links 2025-01-01 14:10:55 +10:00
Stenzek d69d25431e
VulkanDevice: Hopefully fix init under Vulkan 1.0 drivers 2024-12-31 23:43:38 +10:00
Stenzek f25302c847
CPU/Recompiler: Actually use fetch ticks for uncached EXP1 2024-12-31 17:29:40 +10:00
Stenzek 34f2600f99
CPU/Recompiler: Fix ICache update codegen on RISCV64 2024-12-31 16:12:19 +10:00
Stenzek 4c08c716c4
CPU/Recompiler: Fix dispatcher crash on RISCV64 2024-12-31 15:33:34 +10:00
Stenzek a4b359672c
Common: Switch fastjmp.cpp asm to tabs
Consistency.
2024-12-31 15:33:17 +10:00
Stenzek 79b0533df2
Common: Fix RISC-V/64 fastjmp buffer size 2024-12-31 15:30:26 +10:00
Stenzek b76618fdf4
System: Should call PGXP Reset not Initialize() in InternalReset() 2024-12-31 15:24:36 +10:00
Stenzek 1bf076c74f
VulkanDevice: Fix crash on shutdown if swapchain creation fails 2024-12-31 15:10:55 +10:00
Stenzek e0877c1922
System: Add IsUsingPS2BIOS() 2024-12-31 14:58:31 +10:00
Stenzek 69826f2101
FullscreenUI: Fix incorrect section for Deinterlacing Mode 2024-12-31 14:15:42 +10:00
Stenzek a3645f3173
GameDB: Gokujou Parodius Da! Deluxe Pack 2024-12-31 14:13:49 +10:00
Stenzek 7228f6f1cf
System: Don't fail startup if cpuinfo init fails 2024-12-30 18:11:56 +10:00
Stenzek 3c5db39ee4
GPU/SW: Remove polygon size checks from backend
It's already checked before the draw is handed off.
2024-12-30 18:11:52 +10:00
Stenzek 4d4523dc04
GPU: Use same early culling rules for lines as polygons 2024-12-30 18:11:52 +10:00
Stenzek c5bd4101b3
GPU: Refactor and simplify deinterlacing
Both HW and SW deal with half-height buffers coming in now.
2024-12-30 14:36:17 +10:00
Stenzek 9cd9042563
CMake: Fix RISC-V building with LLVM 2024-12-30 02:58:16 +10:00
Stenzek 4e928d7ce1
Common: Work around LLVM LTO inline asm issue
LLVM bug 61991.
2024-12-30 02:57:22 +10:00
Stenzek d65ae6ce00
Scripts: Add cross-compiled AppImage generator 2024-12-30 02:09:32 +10:00
Stenzek 401582bb2b
PlatformMisc: Load libdbus at runtime
The static library can't link to the ARM binary when cross-compiling.
2024-12-30 01:57:08 +10:00
Stenzek a08bd43000
CMake: Fix incorrect message for cache line size 2024-12-30 01:57:08 +10:00
Stenzek 156b3f989b
Scripts: Add Linux cross-compile deps script 2024-12-30 01:57:07 +10:00
Stenzek 9cba1decad
GPU/HW: Compiler warning fix 2024-12-29 22:34:39 +10:00
Stenzek 468c907fd6
Cheats: Compiler warning fix 2024-12-29 22:34:31 +10:00
Stenzek d4e393f1a8
Common: Fix write overflow with nosimd vector 2024-12-29 22:34:14 +10:00
Stenzek ab107722f7
Scripts: Add -only-download option to Linux deps 2024-12-29 20:21:34 +10:00
Stenzek 242561debf
CPU/Recompiler: Align dispatchers and JIT blocks
A couple of percent difference if we're lucky. Practically probably <1%.
2024-12-29 18:11:58 +10:00
Stenzek 82a843c121
RegTest: Log state and RAM hashes on exit
Useful for checking determinism.
2024-12-29 17:25:55 +10:00
Stenzek 1ed9e609a5
RegTest: Support replaying GPU dumps 2024-12-29 17:25:55 +10:00
Stenzek b7832e609f
GPU/HW: Vectorize flipped sprite handling 2024-12-29 17:25:55 +10:00
Stenzek 1a211e0a21
GPU/HW: Fix mask bit regression from FF8 fix
Fixes overbright polygons appearing in Silent Hill.
2024-12-29 17:25:54 +10:00
Stenzek 0e6ade067c
FileSystem: Add error reporting to DeleteDirectory() 2024-12-29 17:25:54 +10:00
Stenzek 5c3abb490d
Common: Fix vector sse2_max_u16()
Fixes UV clamping in SSE2 build, e.g. Jumping Flash.
2024-12-29 13:56:10 +10:00
Stenzek 799f5bdf97
GPU: Assume vertex commands are 8-byte aligned 2024-12-28 20:24:22 +10:00
Stenzek 8c807118c0
GPUDevice: End timer on command flush
Fixes incorrect GPU usage readings in OpenGL, D3D11 is still
problematic, at least on AMD.
2024-12-28 20:24:21 +10:00
Stenzek 7bb0c7d1fb
InputManager: Fix pointer scale loading 2024-12-28 20:24:21 +10:00
Stenzek c2589461e9
GPU/HW: Remove extra debug group pop 2024-12-28 20:24:21 +10:00
Stenzek 74fd217afb
GPU/HW: Always update/load/save CLUT
We have the headroom with multithreading now, and it prevents issues
saving/loading state in loading screens in some games.
2024-12-28 20:24:21 +10:00
Stenzek 25b0bb752a
GPU/HW: Try truncating culled vertices
What is this monstrosity? Final Fantasy VIII relies on X coordinates
being truncated during scanline drawing, with negative coordinates
becoming positive and vice versa. Fortunately the bits that we need
are consistent across the entire polygon, so we can get away with
truncating the vertices. However, we can't do this to all vertices,
because other game's vertices break in various ways. For example,
+1024 becomes -1024, which is a valid vertex position as the ending
coordinate is exclusive. Therefore, 1024 is never truncated, only
1023. Luckily, FF8's vertices get culled as they do not intersect
with the clip rectangle, so we can do this fixup only when culled,
and everything seems happy.
2024-12-28 20:24:21 +10:00
Stenzek c99625e4c3
GPU: Move vertex culling to GPU thread
i.e. push all primitives through unless they are oversized, which the
GPU will definitely skip.

Needed because of coordinate truncation in Final Fantasy VIII, these
scenes will now render correctly with the software renderer again.
2024-12-28 20:24:09 +10:00
Stenzek 58b0ccf3fc
Common: Add 2D vector formatters 2024-12-28 19:59:25 +10:00
Stenzek 69ed6e5e58
Hotkeys: Screenshot should not be present on Android
Since it saves to app-private, users would complain that the app is
using too much data.
2024-12-27 19:39:23 +10:00
Stenzek 2da692b341
CPU/Recompiler: Swap bl{x,r} for b{x,r} on ARM
Not a subroutine call.
2024-12-27 15:02:40 +10:00
Stenzek 2a8cfc7922
CPU/CodeCache: Simplify code LUT addressing
One more instruction on x86/ARM32, no additional instructions on ARM64.

Worth it so that the application doesn't crash if the game jumps to an
invalid PC. Note that the lower 2 bits are truncated, so an unaligned
jump will round down to the closest instruction. Obviously not correct,
but if a game ends up doing this, it's a lost cause anyway.
2024-12-27 15:02:40 +10:00
Stenzek 4e5b4ba071
CPU: Fix AdEL/IBE on instruction fetch
CAUSE and EPC were swapped for the latter.
2024-12-27 15:02:40 +10:00
Stenzek 4b34825afd
CPU/CodeCache: Remove InstructionInfo pc field
No longer needed since oldrecs are gone.
2024-12-27 15:02:40 +10:00
Stenzek ce71b168c3
CPU/CodeCache: Add static to a couple of missing functions 2024-12-27 15:02:40 +10:00
Stenzek a44dd1882f
RegTest: Update CLI help 2024-12-27 15:02:40 +10:00
Anderson Cardoso 7b9664d6f2
Atualização Português do Brasil (#3348)
Atualizado para a última versão.
2024-12-27 15:02:31 +10:00
Stenzek 9921d2074c
Achievements: Fix serialization on Linux 2024-12-26 18:00:29 +10:00
Stenzek 5c83bbe5c5
FullscreenUI: Slight tidy-up to achievements login dialog 2024-12-26 18:00:29 +10:00
Stenzek 272aa4f933
ImGuiManager: Add Begin/EndTextInput() 2024-12-26 18:00:29 +10:00
Stenzek 55c5e17fdc
GameDB: Driver 2 settings 2024-12-26 18:00:29 +10:00
Stenzek 750dd1cb87
dep/rcheevos: Bump to 3a91a58 2024-12-26 15:00:55 +10:00
Stenzek fa993849f7
Qt: Update English/Plural strings 2024-12-26 01:58:24 +10:00
Stenzek 6903abba55
CDROM: Adjust missed INT1 sector behaviour
Max Power Racing and C3 Racing are slow with their DMAs out,
and get confused when an additional INT1 comes inbetween reading
the sector header and data.

Fixes these games crashing during loading. 5000 cycles is more in
line with what the real mech would do anyway, it's pretty slow.
2024-12-26 01:55:55 +10:00
Stenzek 0528ce567c
Achievement: Fix glitchy fade indicator animation 2024-12-25 23:01:58 +10:00
Stenzek 00eb54cd15
Achievements: Refactor state serialization
Fix load failures, and eliminate the buffer copy.
2024-12-25 22:23:09 +10:00
Stenzek d360564cef
GameList: Fix lock not re-acquired on failure 2024-12-25 21:55:19 +10:00
Stenzek 8c2fe430d8
GPU/TextureCache: Apply 'Dump Replaced Textures' option to backgrounds too 2024-12-25 15:53:53 +10:00
Stenzek b03127b206
GPU: Move background dumping to HW+GPU thread
And only dump when the mask bit check is not enabled.

The replacements are gated by the mask bit check anyway, so there's
no point dumping anything that can't be replaced.
2024-12-25 15:53:53 +10:00
Stenzek 6f3e9913f5
GPU/HW: Fix VRAM write dumping only first row
Still has race conditions.
2024-12-25 15:53:53 +10:00
Stenzek dd180f2fd6
System: Fix dump VRAM writes not updating on GPU thread 2024-12-25 15:53:53 +10:00
Stenzek b33aa31db8
FullscreenUI: Update translation strings
I always forget to do this...
2024-12-25 15:53:46 +10:00
Stenzek 8f6db2c8fa
Qt: Add missing icon to System Display 2024-12-25 15:13:50 +10:00
Stenzek b81c87958f
Qt: Fix F3 getting intercepted when game/FSUI active 2024-12-25 15:11:40 +10:00
Stenzek d010f768c4
FullscreenUI: Fix smooth scrolling in game/state/etc lists 2024-12-25 15:02:09 +10:00
Stenzek ad7318f5f9
FullscreenUI: Fix spacing in game list 2024-12-25 14:37:26 +10:00
Stenzek e7ff547f1b
GameDB: Street Fighter games
Disable upscaling because they use a stupidly large UV range and
relies on junk texels not being sampled, which happens at 1x.

That and they're 2D anyway.
2024-12-25 14:25:55 +10:00
Stenzek 0565320036
ImGuiFullscreen: Enable smooth scrolling for file/choice selectors 2024-12-24 13:54:23 +10:00
Stenzek c4e0e7fade
InputManager: Fix mouse-mapped axes getting stuck
Regression from f0deab2.
2024-12-24 13:52:04 +10:00
Stenzek dc18ce2c2a
System: Warn if fastmem mode is not optimal 2024-12-24 13:16:37 +10:00
Stenzek f4265edb2d
SmallString: Add append_vformat() 2024-12-24 13:16:12 +10:00
Stenzek 86d78e5eca
GPU/TextureCache: Only use shader bilinear for initial pagefill
Make bilinear replacements behave the same as nearest.
2024-12-24 13:05:38 +10:00
Stenzek 33083cfae1
Settings: Add missing bitfield width 2024-12-24 01:21:07 +10:00
Stenzek 00278fa905
PIO: Fix failure to load state with different cart type 2024-12-24 00:24:37 +10:00
Stenzek b8fa97e1a7
GPU: Fix sprite texture filtering with TC enabled 2024-12-24 00:24:37 +10:00
Stenzek 89f11095bc
CPU: GTE completion cycle should be reset/serialized
Yay more determinism breakage...
2024-12-24 00:24:37 +10:00
Stenzek 9f73e690ad
CPU: Debug mode flag should be updated on state load 2024-12-24 00:24:36 +10:00
Stenzek ac05c35292
CPU: Fix DCIC not being cleared on reset
Stops interpreter mode being unintentionally forced after
restarting some games.
2024-12-24 00:24:36 +10:00
Stenzek 18c509a679
CPU/Recompiler: Exit block early on DCIC/BPCM change
Fixes booting Xplorer cartridge with recompiler.
2024-12-24 00:24:36 +10:00
Stenzek 307bd86b72
SPU: Fix determinism loss when loading state where IRQs differ 2024-12-24 00:24:36 +10:00
Anderson Cardoso 2aa466d1c6
Atualização Português do Brasil (#3347)
Atualizado para a última versão.
2024-12-24 00:24:23 +10:00
Stenzek 9a22ac3c70
GPU/HW: Download VRAM when enabling sw-for-readbacks 2024-12-23 17:55:47 +10:00
Stenzek 8e254c4baf
GPUBackend: Fix VRAM loss with runahead/rewind 2024-12-23 17:55:33 +10:00
Stenzek f3f99f7eac
FullscreenUI: Support renderer swapping without restart 2024-12-23 14:37:38 +10:00
Stenzek 406cd1b6a1
Qt: Shuffle a couple of graphics options
Save a tiny bit of vertical space.
2024-12-23 14:24:17 +10:00
Stenzek 9e04b0bf55
GPU/TextureCache: Add 'Always Track Uploads' option 2024-12-23 13:52:23 +10:00
Stenzek a8361f985e
GPU: CLUT should not be saved on CPU thread memory state 2024-12-22 16:48:45 +10:00
Stenzek 7f1ebd3767
PageFaultHandler: Warning fix 2024-12-22 16:48:45 +10:00
Stenzek 448009f4ef
CPU/CodeCache: Fastmem RAM faults are always writes 2024-12-22 16:48:45 +10:00
Stenzek 515a4d07fb
System: Fix pre-frame sleep getting stuck 2024-12-22 16:48:45 +10:00
Stenzek 0b4e302c22
GPU: Implement PGXP for lines 2024-12-22 16:48:45 +10:00
Stenzek b81287efd2
GPUBackend: Remove duplicate num_vertices 2024-12-22 16:48:45 +10:00
Stenzek 9b62632951
Achievements: Re-add NeedsIdleUpdate()
Forgot I needed this on Android..
2024-12-22 16:48:24 +10:00
Anderson Cardoso 556a53e564
Fix Typo in Russian tr (#3346) 2024-12-22 16:48:00 +10:00
Stenzek a919fa71aa
GameDB: PGXP-CPU for Wipeout games
Improves sprite jitter.
2024-12-21 23:08:09 +10:00
Stenzek 080d30bf0c
GPU: Slightly adjust PAL active range
Gets the PAR closer to the expected value of 59/94 with a divider of 4.
2024-12-21 23:05:30 +10:00
Stenzek ad980a7004
GPU: Fix 480i resolution display in OSD 2024-12-21 22:20:41 +10:00
Stenzek 0aa89ec7b0
System: Fix some GPU settings not updating 2024-12-21 18:29:56 +10:00
Stenzek 9b97bd5924
Packaging: Add scripts to include libc/libstdc++ in AppImage 2024-12-21 18:29:56 +10:00
Stenzek e1bd5690ac
Misc: Slightly reduce include pollution from settings.h 2024-12-21 15:28:27 +10:00
Stenzek 01dfc9ae51
GameDB: PGXP-CPU for Muppet Monster Adventure 2024-12-21 14:54:37 +10:00
Stenzek 62285dcf33
Settings: Split into GPU and main settings
That way the GPU thread copy doesn't need fields it never touches.
2024-12-21 14:53:15 +10:00
Stenzek 6b754e6759
FullscreenUI: Fix CPU/GPU thread race on achievements toggle 2024-12-21 14:40:24 +10:00
Stenzek 26db661a05
GPU: Remove global indirection 2024-12-21 14:35:12 +10:00
Stenzek c4b0430d5e
System: Remove unused SetExpansionROM() 2024-12-19 23:32:15 +10:00
Stenzek 7826c258b0
System: Frame step after runahead
Makes it behave as expected.
2024-12-19 23:32:15 +10:00
Stenzek 2d659fc3eb
GPU: Move backend work off CPU thread 2024-12-19 23:32:15 +10:00
Stenzek 831c982f3b
System: Rewrite memory save state handling
Makes it more friendly to GPU thread.
2024-12-19 22:42:28 +10:00
Stenzek 6993e6c31f
GPU/SW: Fix double draws of polyline vertices 2024-12-19 22:42:02 +10:00
Stenzek 10e2079ee4
CPU/Recompiler: Don't use far code for mtc0 cache check
Redundant for a few instructions.
2024-12-19 18:44:08 +10:00
Stenzek fe1fa765f7
CPU/Recompiler: Don't back up value to stack in mtc0
Fixes misaligned stack that could crash in log messages.
2024-12-19 18:44:08 +10:00
Stenzek 568667753d
CPU/CodeCache: Avoid log calls in faults outside of JIT code
Could be in other functions that are unsafe to call log functions from.
2024-12-19 18:44:08 +10:00
Stenzek 7116a80435
Common: Add RESTRICT macro
Gotta coerce the compiler into generating better code.
2024-12-19 16:50:03 +10:00
Stenzek 31c1cfa650
Achievements: Remove unused NeedsIdleUpdate() 2024-12-19 12:46:59 +10:00
Stenzek 2f5bdc9651
GameDB: Crash Team Racing supports JogCon 2024-12-19 12:43:02 +10:00
Stenzek 7442ec2f19
JogCon: Implement command 0x44 2024-12-19 12:42:01 +10:00
Daniel Nylander fa2442deaf
Updating Swedish translation (#3345)
* Updated Swedish translation
2024-12-19 12:06:06 +10:00
Anderson Cardoso 8df2a2c446
Atualização Português do Brasil (#3344)
Atualizado para última versão
2024-12-17 14:28:15 +10:00
Stenzek f010d81652
ISOReader: Add XA and raw extraction modes 2024-12-17 14:19:41 +10:00
Stenzek b68370dff7
Mouse: Move s8 clamp to after subtraction
Stops the mouse from accumulating long distances which are applied
over several frames. Seems to "feel" slightly better.
2024-12-16 01:53:03 +10:00
Stenzek cc52320dfe
FullscreenUI: Update translation string list 2024-12-16 01:30:20 +10:00
Daniel Nylander 4216eef420
Updated Swedish translation (#3343) 2024-12-16 01:29:24 +10:00
Stenzek 585b13fbd9
GameDB: Remove AnalogController from Point Blank 2
Apparently it does not support it. Not that you'd be using anything
other than a lightgun ;)
2024-12-16 01:28:04 +10:00
Stenzek b634eecd21
System: Allow separate configuration for multi-disc games 2024-12-16 01:22:48 +10:00
Stenzek 23c221be01
GameDB: Fix serial for Dino Crisis (Japan) 2024-12-16 01:20:22 +10:00
Stenzek edfeffd820
GameDB: Hash for Aquanaut's Holiday 2024-12-16 01:20:10 +10:00
Stenzek fda10a6978
FullscreenUI: Remove legacy 'Enable Cheats' option
It did nothing.
2024-12-16 01:02:04 +10:00
Stenzek 43af57d735
System: Fix UpdateGTEAspectRatio() during initialization 2024-12-15 22:12:43 +10:00
Stenzek 1f1a664908
InputManager: Add missing call to UpdateHostMouseMode() 2024-12-15 22:12:43 +10:00
Stenzek 6e2223b517
OpenGLDevice: Fix surfaceless context switch 2024-12-15 22:09:21 +10:00
Stenzek fbb411a946
OpenGLDevice: Blacklist fbfetch on PowerVR as well
Apparently it's broken, and I don't have any devices with this chip
so I can't find a potential workaround anyway.
2024-12-15 22:07:47 +10:00
Stenzek 4e1e07a93c
Qt: Shrink BIOS settings page height
Move open/refresh buttons.
2024-12-15 16:09:02 +10:00
Stenzek 9d52e27e16
CPU/Recompiler: Use condition select for ICache updates
Tidy ~4% perf boost.
2024-12-15 16:00:25 +10:00
Stenzek 666fee2df7
GameDB: Enable ICache for Crash 3
Sound effects during the intro can be lost if the CPU runs too fast.
2024-12-15 15:16:53 +10:00
Stenzek 2603ce5976
GameDB: Merge all 8 discs of Tokimeki Memorial 2 2024-12-15 15:09:48 +10:00
Stenzek 03e24637af
Qt: Simplify Host::CommitBaseSettingChanges() 2024-12-15 13:00:08 +10:00
Stenzek d00627b44b
GameDB: Alnam no Kiba - Juuzoku Juuni Shinto Densetsu 2024-12-15 12:59:51 +10:00
Stenzek 5e21234966
Qt: Fix deadlock in Game Properties -> Post-Processing 2024-12-15 12:59:30 +10:00
Stenzek 90e9634c19
FullscreenUI: Enable DrawStringListSetting() 2024-12-14 18:07:33 +10:00
Stenzek c0c2e69b59
CPU/Recompiler: Document ARM32 code size
Yikes, it's huge..
2024-12-14 16:43:29 +10:00
Stenzek 5cbb6b6163
Qt: Purge unused {start,stop}dumpingAudio 2024-12-14 16:00:13 +10:00
Stenzek e91ae5f1b9
GPU/HW: Only compile page texture shaders if TC is enabled
Knocks about 1/4 off the total pipelines with the default config.
2024-12-14 15:56:46 +10:00
Stenzek dcaee9b87e
Qt: Add ISO Browser to Tools menu 2024-12-14 14:10:07 +10:00
Stenzek 726aa67d1b
CPU/CodeCache: Only cache EXP1 blocks up to 0x1F060000
Neither cart type has code mapped above this address.

Saves ~91MB of memory.
2024-12-14 14:10:06 +10:00
Anderson Cardoso b99fb22522
Atualização Português do Brasil (#3342)
atualizado para a última versão
2024-12-14 13:47:46 +10:00
Stenzek b832dfbb3a
CDROM: Zero out seek start/end after read 2024-12-14 13:47:20 +10:00
Stenzek c25c0067af
CDROM: Handle repeated SeekL to same target
Fixes more lockups in Resident Evil 3.
2024-12-14 13:36:20 +10:00
Stenzek e683c89770
CPU/Recompiler: Fix ICache updates on ARM32 2024-12-14 01:05:42 +10:00
Stenzek 5687dd22bd
PIO: Add basic flash cartridge support 2024-12-13 23:22:57 +10:00
Stenzek 2f6eaa1d43
CPU/Interpreter: Address ICache lines in words
Might help on ARM32, because no unaligned access.

Otherwise, ~23% perf boost in debug builds. But this is pretty
meaningless.
2024-12-13 23:22:57 +10:00
Stenzek 0dbab167a8
GameDB: Disable widescreen in Fear Effect
FMV backgrounds.
2024-12-13 23:22:57 +10:00
Stenzek ceef778891
GameDB: Disable multitap for Fear Effect games 2024-12-13 18:41:00 +10:00
Stenzek 25ffc5a248
GameDatabase: Warn if multitap enabled on unsupported game
Fear Effect sends a multitap read command, but doesn't know how to
handle it. There's probably others.

Also add a DisableMultitap trait for these games to force it off.
2024-12-13 18:41:00 +10:00
Stenzek 50fbaf90e6
Qt: Add debug menu options for log sinks/timestamps 2024-12-13 18:08:44 +10:00
Stenzek 8f19912c64
GPU/ShaderGen: Use sample instead of load at 1x as well
Consistency. Mali ends up ever-so-slightly faster with sample versus
texel loads, apparently.

Also fixes compile errors when using texture filtering on GLSL ES.
2024-12-13 14:36:21 +10:00
Stenzek db848d1381
System: Remove redundant GameDB lookup 2024-12-12 17:43:00 +10:00
Stenzek 5577328f35
Controller: Allow !compatsettings to always start in analog mode 2024-12-12 17:42:37 +10:00
Stenzek 99f133223c
CPU/Recompiler: Create block links for self-looping blocks
This way invalidation will rewrite the jump back to the compiler.
Otherwise a SMC block can end up looping itself indefinitely.

Might help with Spyro 2/3. I can't seem to make them crash anymore.
2024-12-12 16:28:51 +10:00
Stenzek 2e805d56dd
CPU/CodeCache: Always backpatch KSEG2 writes 2024-12-12 16:24:54 +10:00
Stenzek c3a2156c79
CPU/CodeCache: Fix event kicking for Cached Interpreter 2024-12-12 16:24:19 +10:00
Stenzek cdcf05a878
CPU/Recompiler: Only truncate block for future writes
If we overwrite an instruction that has already executed, it
should invalidate the block next time.
2024-12-12 16:23:32 +10:00
Stenzek e507fdcb1f
System: Load state before calling OnSystemStarted()
Needed for transitent state cleanup on Android.
2024-12-11 22:04:21 +10:00
Stenzek d8af8e4a60
GPU/HW: Fix possibly-stale display with MSAA+Show VRAM 2024-12-11 22:04:21 +10:00
Stenzek 9743ce01a0
OpenGLDevice: Support GLES 3.0
Android emulator still doesn't have GLES 3.1...
2024-12-11 22:04:21 +10:00
Stenzek 69947fb907
GPU/TextureCache: Look for replacements outside of subdirectory
i.e. old setups that do not have the `replacements` subdirectory.
2024-12-11 15:02:55 +10:00
Stenzek d871c17f3f
Settings: Set sprite texture filter on reset 2024-12-11 14:54:26 +10:00
Stenzek 5eac1e4800
VulkanDevice: Blacklist FSI on AMD Windows
Yay for random GPU resets, it's fine on NVIDIA.
2024-12-11 12:46:25 +10:00
Stenzek 1edcc8c0ac
System: Merge system taints with state taints on load 2024-12-10 20:19:27 +10:00
Stenzek cc567d9498
Cheats: Fix hash-suffixed files incorrectly loading 2024-12-10 20:19:26 +10:00
Stenzek e137d3b5c7
Common: Fix rectangle rempty() on ARM32 2024-12-10 16:49:45 +10:00
Stenzek 5767397231
Qt: Remove 'Enable Cheats' from Console Settings
This was moved to Game Properties ages ago.
2024-12-10 13:19:08 +10:00
Stenzek 0bb83f6fd7
OpenGLDevice: Fix inverted cache file lock 2024-12-10 13:17:06 +10:00
Stenzek 1e839224e8
CDROM: Fix physical disc reading without SubQ on Linux 2024-12-10 02:28:02 +10:00
Stenzek 2e6deca76f
FileSystem: Don't use POSIX locks on Android
Requires SDK 24, and it's pointless anyway.
2024-12-10 02:26:54 +10:00
Stenzek b814666134
CPU/Recompiler: Fix ARM32 build (again) 2024-12-10 02:26:45 +10:00
Stenzek 1bea8817f1
Host: Add ConfirmMessageAsync() 2024-12-10 02:26:45 +10:00
Stenzek 42535591bc
HTTPDownloader: Log errors on request failure 2024-12-10 02:26:45 +10:00
Stenzek a1928de4d0
ImGuiOverlays: Pack SaveStateSelectorUI state 2024-12-09 15:35:07 +10:00
Stenzek 8bb013540d
GameDB: Remove redundant codes sections 2024-12-09 15:32:31 +10:00
Stenzek 09ba2ed181
GameDB: Remove duplicate code entries 2024-12-09 15:25:48 +10:00
Stenzek 765a46fc88
FullscreenUI: Pack state in struct 2024-12-09 15:02:05 +10:00
Stenzek 53c08c52ed
ImGuiFullscreen: Pack state in struct 2024-12-09 15:01:57 +10:00
Stenzek 5d7cb6c5dc
System: Move state compression/writing to worker thread
Reduce hitches when saving.
2024-12-09 14:16:55 +10:00
Stenzek a4af88bc52
GameDB: More PSX.EXE hashes 2024-12-09 13:50:47 +10:00
Stenzek 31d953dac2
System: Prevent memcard blocking resume state save
Because otherwise you end up with a stale/old resume state, which is
arguably worse.
2024-12-09 13:42:41 +10:00
Stenzek 9b0a906297
GameDB: Add more missing hash entries 2024-12-08 19:45:28 +10:00
Stenzek 5bf7227790
CPU/CodeCache: Use code buffer section on Android 2024-12-08 19:44:27 +10:00
Stenzek 1adf36ccb2
Build: Fix out-of-tree CMake scmversion extraction on Windows 2024-12-08 19:44:27 +10:00
Stenzek b6eb41e2cf
Qt: Improve binding widget tooltip 2024-12-08 19:44:27 +10:00
Stenzek 2999f15d7a
StringUtil: Add UTF-16 encoding/decoding functions 2024-12-08 19:44:27 +10:00
Stenzek 7f3687de81
Common: Report assertion failure/panic message for Android 2024-12-08 14:19:25 +10:00
Stenzek 3a661a1c3d
Cheats: Move file clearing into core
Needed for Android.
2024-12-08 02:58:50 +10:00
Stenzek d5432da082
Settings: Disable runahead/rewind in Safe Mode 2024-12-08 02:58:50 +10:00
Stenzek f9155e5ce7
Settings: Fix incorrect data type for rewind slots 2024-12-08 02:58:50 +10:00
Stenzek 5725a0360b
GPU: Use A1BGR5 format for SW/HashCache if available 2024-12-06 18:28:09 +10:00
Stenzek 8c5fadafba
GPUTexture: Add A1BGR5 format
Needed for GLES, since RGB5A1 + BGRA + REV isn't listed as
a valid format.
2024-12-06 18:28:09 +10:00
Stenzek dbba8deb4b
Packaging: Fix path in pkgbuild/spec 2024-12-06 18:28:09 +10:00
Anderson Cardoso c3a9ab3cc8
Atualização Português do Brasil (#3341)
Atualizado para a última versão
2024-12-06 18:27:58 +10:00
Stenzek f0c456893c
GPUDevice: Support pre-rotating swap chains 2024-12-06 15:38:51 +10:00
Stenzek acf04ed67a
GPUDevice: Use row-major matrix packing
With column vectors. mul() turns into dot products instead of madds.
2024-12-06 15:10:15 +10:00
Stenzek e22d67f4aa
GSVector: Add 4x4 matrix class 2024-12-06 15:10:15 +10:00
Stenzek 9c327af280
GPUDevice: Typedef auto-recycled texture 2024-12-06 15:10:15 +10:00
Stenzek 52feb1a37d
PostProcessing: Improve compile error reporting 2024-12-06 15:10:15 +10:00
Stenzek c9c4307871
FileSystem: Android build fix 2024-12-06 15:10:15 +10:00
Stenzek 042a2d72f7
Threading: Add IsCallingThread() to ThreadHandle 2024-12-06 15:10:15 +10:00
Stenzek 5c4d95fd51
Settings: Add missing GPU feature disables 2024-12-06 15:07:56 +10:00
Stenzek 6d080c1a3f
GPU: Fix additional GL_POP() causing validation errors 2024-12-06 14:51:57 +10:00
Stenzek 3670c131e3
Qt: Hook up extract button in ISO browser 2024-12-05 18:59:32 +10:00
Stenzek ea632665c1
Qt: Fix possible game settings save error with sliders 2024-12-05 18:57:35 +10:00
Stenzek 0c7636b3c3
System: Add missing safe mode disable messages 2024-12-05 17:04:09 +10:00
Stenzek 541985fb70
Qt: Add ISO Browser 2024-12-05 16:30:21 +10:00
Stenzek 58f5d7e1ba
Qt: Fix missing status message on delayed progress show 2024-12-05 16:30:21 +10:00
Stenzek e9644c7eeb
ISOReader: Add file extraction helpers 2024-12-05 16:30:21 +10:00
Víctor "IlDucci 20df4ec14e
Spanish (Spain) update 2024/12/03 (#3340)
Translation of latest changes.
2024-12-05 16:30:09 +10:00
Stenzek fe3b4154b7
PostProcessing: Fix crash on UI open with OpenGL 2024-12-03 22:35:49 +10:00
Stenzek 3ca2579882
Qt: Add additional early SSE4.1 check on Windows
reshadefx uses roundss in std::unordered_map initializers, no other way
to stop this. If it's not reshade, it'll probably be something else.
2024-12-03 19:13:35 +10:00
Stenzek 84a1e209ea
OpenGLDevice: Lock pipeline cache on Linux
Prevents multiple processes from trampling on one another.
2024-12-03 17:35:07 +10:00
Stenzek 04e472d088
FileSystem: Add non-blocking option to POSIXLock 2024-12-03 17:29:47 +10:00
Stenzek d93c713fb7
FileSystem: Make POSIXLock moveable 2024-12-03 17:29:47 +10:00
Stenzek 5b6e3a952c
System: Reset code cache on fastmem mode change
Fixes excess backpatching and potential crashes when changing mode.
2024-12-03 17:29:47 +10:00
Stenzek 0a2facfaeb
Settings: Don't enable fastmem without recompiler
Don't need to bother allocating memory otherwise.
2024-12-03 16:54:42 +10:00
Stenzek d3ceda0c5b
CPU/CodeCache: Improve block host size heuristics
Codegen is much better these days, especially with NewRec.
2024-12-03 16:54:28 +10:00
Stenzek 9a5ee3aae6
Qt: Fix horizontal scrollbar showing in summary track list 2024-12-03 16:16:38 +10:00
Anderson Cardoso 03eb4a6bf9
Atualização Português do Brasil (#3339) 2024-12-03 14:45:36 +10:00
Stenzek 25063d4018
Achievements: Fix overlay stacking 2024-12-03 14:13:04 +10:00
Stenzek 14ff89d0c0
MetalDevice: Fix incorrect pixel format for RGB5A1 2024-12-03 13:28:19 +10:00
Stenzek 297165d1ee
Deps: Fix MacOS build 2024-12-03 13:21:01 +10:00
Stenzek cbc22a89f7
GPU/HW: Fix TC + SW-For-Readbacks combo 2024-12-02 20:45:02 +10:00
Stenzek ac79e43cc0
Deps: Bump versions
- Qt to 6.8.1.
- Harfbuzz to 10.1.0.
- libzip to 11.11.2.
2024-12-02 20:45:02 +10:00
Stenzek 3959c83bd4
GPU/TextureCache: Fix split writes not dumping 2024-12-02 20:12:40 +10:00
Stenzek 22edf23269
GPU: Fix parameter logging of some commands 2024-12-02 17:24:18 +10:00
Stenzek 6756c96fa2
CDROM: Improve SeekL -> ReadN timing
See comments - Mech stops at target Data - 2, or SubQ target.
2024-12-02 17:24:16 +10:00
Stenzek 71e1032605
GameDB: Army Men: Sarge's Heroes 2024-12-02 17:24:15 +10:00
Stenzek 2f70d1bd9c
CPU: Write trace log to data directory 2024-12-01 23:21:33 +10:00
Stenzek e9848a6182
Misc: Collapse more niche log channels 2024-12-01 23:21:33 +10:00
Stenzek 9df59713da
GPUDevice: Put debug messages/scopes behind conditions
And completely compile them out in Release builds.

Gets Devel close to Release in terms of performance.
2024-12-01 23:21:33 +10:00
Stenzek 0faa9cf650
Build: Add Devel configuration
Gets you debug assertions and logging, while still producing an
optimized executable.
2024-12-01 23:21:33 +10:00
Stenzek 2a7625e67c
CI: Add workflow dispatch triggers for all jobs
Useful for running just one platform on a branch.
2024-12-01 23:21:13 +10:00
Stenzek 4aa9857c53
Qt: Fix fallback binding layout not including motors 2024-12-01 21:17:54 +10:00
Stenzek aff623b772
GameDB: JogCon games 2024-12-01 21:17:54 +10:00
Stenzek 7c627a8c83
Controller: Add JogCon
This is probably wrong, but I have no way of testing it with an actual
force feedback wheel.

PRs welcome to improve it further.
2024-12-01 21:17:54 +10:00
Stenzek f9c125c1a1
InputManager: Add ForceFeedbackDevice interface 2024-12-01 21:08:52 +10:00
Stenzek d7d028ac5c
GameDB: Recompiler ICache for Resident Evil 3
CD code gets super screwed up and sends multiple commands without
waiting for them to finish.
2024-12-01 18:16:59 +10:00
Stenzek b87c6dde6c
CDROM: More logging tidy-up 2024-12-01 18:15:42 +10:00
Stenzek 4fe3e1147d
Controller: Add GetPortDisplayName() that takes pad index 2024-12-01 17:47:55 +10:00
Stenzek 9fc9f4b9e9
Settings: Fix hash cache fields not being compared 2024-12-01 16:53:29 +10:00
Stenzek 00132c6070
AnalogController: Fix more log spam 2024-12-01 14:49:38 +10:00
Stenzek 9c2244f40e
Qt: CustomizeWindowHint should be set for no-close-button 2024-12-01 14:39:26 +10:00
Stenzek 42c5f9169f
CI: Merge all packaging scripts to one directory 2024-12-01 14:39:26 +10:00
Stenzek c6746e76f1
CPU/Intepreter: Raise #RI on invalid COP0 move 2024-12-01 14:27:24 +10:00
Stenzek 62414b0c4c
CPU/Interpreter: IBE should not set BD/BT
Apparently. Nothing relies on this. :P
2024-12-01 14:27:24 +10:00
Stenzek 67041d217b
Qt: Improve shortcuts
- CTRL/+, CTRL/- no longer show in menu for zooming, but still activate.
- CTRL+O will open a new disc/game from file.
- F5 will refresh the game list (i.e. scan for new games).
- F3/CTRL+F will send focus to the game list search box.
- Pressing Enter in the search box will send focus to the first game
  list row.
- ALT+ENTER in the game list will open Game Properties.
2024-12-01 14:27:24 +10:00
Stenzek 145ad2db27
GameList: Fix scanning of ELF files 2024-12-01 13:10:20 +10:00
Stenzek 9dec34c8c0
Settings: Disable texture replacements if TC disabled
Stops replacements being enumerated in the software renderer as well.
2024-11-30 14:42:51 +10:00
Stenzek f1435dcf67
Settings: Bump maximum hash cache size
Hopefully mobile will be okay with it.. I know Adreno GL
craps out around 8,000 texture objects.
2024-11-30 14:36:07 +10:00
Stenzek 53008eb34a
GPU/HW: Allow use of RGB5A1 for texture cache
Reduces bandwidth and storage requirements by 50%.
2024-11-30 14:36:07 +10:00
Stenzek c6e2235ee2
GPU/HW: Vectorize texture conversion routines
~100% speed up for RGBA8, ~50% for RGB5A1.
2024-11-30 14:36:07 +10:00
Stenzek fa4dc381ed
GPUDevice: Rename RGBA5551 to RGB5A1
And fix the incorrect format for Vulkan.
2024-11-30 14:36:07 +10:00
Stenzek dfacf9e8db
VulkanDevice: Only create swap chain framebuffer without dynamic rendering 2024-11-30 01:09:41 +10:00
Stenzek ee750b44e3
Settings: Normalize texture replacment option titles 2024-11-30 01:09:41 +10:00
Stenzek 0f51472d64
Misc: Android build fix 2024-11-30 01:09:41 +10:00
Stenzek b7fff840c8
System: Move thread name init to host
Prevents funky thread names for regtest on Linux.
2024-11-29 21:21:27 +10:00
Stenzek cbc16bee9e
GPU: Display scanout resolution regardless of crop mode 2024-11-29 21:05:01 +10:00
Stenzek b059cda8d5
Achievements: Pack state in struct 2024-11-29 20:13:37 +10:00
Stenzek aafc029682
Misc: Un-namespace Timer 2024-11-29 20:13:37 +10:00
Stenzek ae18db9271
RegTest: Use filename instead of database title 2024-11-29 19:10:21 +10:00
Stenzek 682ba71319
GPU: Fix aspect ratio with Show VRAM enabled 2024-11-29 18:36:32 +10:00
Stenzek d5b9b54a69
GPU/SW: Vectorize VRAM writes/copies 2024-11-29 18:05:52 +10:00
Stenzek 19eee76aec
AnalogController: Reduce log spam 2024-11-29 17:30:53 +10:00
Stenzek 6cbfab6eca
MetalDevice: Warning fix 2024-11-29 17:13:21 +10:00
Stenzek 9970944da2
Achievements: Add encryption of login tokens in ini
Super simple key derived from the machine's UUID.

The idea isn't to provide a ton of security, but prevent users from
accidentially exposing their tokens when sharing their ini for debugging
purposes.

The use of the machine UUID is disabled in portable mode for those who
actually move it between computers. Instead, the key is derived from the
username alone, which is trivially computable.
2024-11-29 17:13:21 +10:00
Stenzek 5401dc8d52
Settings: Add EmuFolders::IsRunningInPortableMode() 2024-11-29 17:06:40 +10:00
Stenzek ff3214b8f7
SmallString: Add span helpers 2024-11-29 17:06:20 +10:00
Stenzek d3246deb77
ThirdParty: Add aes.cpp 2024-11-29 17:06:06 +10:00
Stenzek 83274c7e3b
ThirdParty/SmallVector: Compile fixes 2024-11-29 17:05:18 +10:00
Stenzek b39f1558ec
StringUtil: Add Base64 decode/encode functions 2024-11-29 17:05:02 +10:00
Stenzek c0b4627c11
StringUtil: Drop old MacOS workaround 2024-11-29 15:25:36 +10:00
Stenzek bbe6612b25
Common: Add SHA256Digest 2024-11-29 15:20:33 +10:00
Stenzek da501b9294
StringUtil: Add ParseFixedHexString() 2024-11-29 15:04:25 +10:00
Stenzek 2e31a40dda
Qt: Zero spacer size hints in Graphics Settings
Fixes the window size changing depending on which tab is selected.
2024-11-29 14:06:22 +10:00
Stenzek dac5dd562b
HTTPDownloader: Improve error reporting
Give something human-readable when an error occurs.
2024-11-29 14:00:55 +10:00
Stenzek 6d72a48708
Qt: Disable All Enhancements -> Safe Mode in Debug menu 2024-11-29 13:20:50 +10:00
Stenzek 3ed6cc2ba8
GameList: Fix crash loading custom language options 2024-11-29 13:17:07 +10:00
Stenzek 6be242449b
AnalogController: Simplify rumble config
And fix some variables not being saved to state, yay determinism issues.
2024-11-29 13:11:25 +10:00
Stenzek eeee1e691a
Cheats: Support importing native format
Compared to only replacing the .cht file.
2024-11-29 13:10:59 +10:00
Stenzek 208e6c4b35
Cheats: Strip whitespace from code names 2024-11-29 12:49:51 +10:00
Anderson Cardoso c4d4a7a774
Fix Missing Flag (#3338)
* Atualização Português do Brasil

Atualizado para a última versão.

* Flag fix

Added reference for the missing flag Spanish Latin America

* Update Flag

As discussed in discord with @Hipnosis183 told us that is better change to Mexico flag instead for his lang option.
2024-11-29 12:49:33 +10:00
Daniel Nylander 73dc52ac98
Adding Swedish flags to UI (#3337)
* Updated Swedish translation

* Updating Swedish translation

Now I feel happy with it for some time.

* Adding Swedish flags

* Adding Swedish flags from Wikipedia 

Source https://sv.wikipedia.org/wiki/Fil:Sweden_flag_orb_icon.svg

* Final update for Swedish translation
2024-11-29 12:49:16 +10:00
Stenzek cd216d91db
Qt: Re-enable download button on update failure 2024-11-28 01:07:40 +10:00
Anderson Cardoso 2e0825a363
Atualização Português do Brasil (#3336)
Atualizado para a última versão.
2024-11-28 01:05:37 +10:00
Daniel Nylander b81d6718f4
Updated Swedish translation (#3335)
* Updated Swedish translation

* Updating Swedish translation

Now I feel happy with it for some time.
2024-11-28 01:05:30 +10:00
433 changed files with 43262 additions and 22605 deletions

View File

@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-22.04
timeout-minutes: 120
steps:
- uses: actions/checkout@v4.1.1
- uses: actions/checkout@v4
with:
fetch-depth: 0

View File

@ -2,6 +2,7 @@ name: 🐧 Linux AppImage
on:
workflow_call:
workflow_dispatch:
jobs:
linux-x64-appimage-build:
@ -9,16 +10,16 @@ jobs:
runs-on: ubuntu-22.04
timeout-minutes: 120
steps:
- uses: actions/checkout@v4.1.6
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Packages
run: scripts/appimage/install-packages.sh
run: scripts/packaging/appimage/install-packages.sh
- name: Cache Dependencies
id: cache-deps
uses: actions/cache@v4.0.2
uses: actions/cache@v4
with:
path: ~/deps
key: deps ${{ hashFiles('scripts/deps/build-dependencies-linux.sh', 'scripts/deps/build-ffmpeg-linux.sh') }}
@ -66,10 +67,10 @@ jobs:
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_PREFIX_PATH="$HOME/deps" -DCMAKE_C_COMPILER=clang-18 -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_EXE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_MODULE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_SHARED_LINKER_FLAGS_INIT="-fuse-ld=lld" ..
cmake --build . --parallel
cd ..
scripts/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64
scripts/packaging/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64
- name: Upload Qt AppImage
uses: actions/upload-artifact@v4.3.3
uses: actions/upload-artifact@v4
with:
name: "linux-x64-appimage"
path: "DuckStation-x64.AppImage"
@ -80,16 +81,16 @@ jobs:
runs-on: ubuntu-22.04
timeout-minutes: 120
steps:
- uses: actions/checkout@v4.1.6
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Packages
run: scripts/appimage/install-packages.sh
run: scripts/packaging/appimage/install-packages.sh
- name: Cache Dependencies
id: cache-deps
uses: actions/cache@v4.0.2
uses: actions/cache@v4
with:
path: ~/deps
key: deps ${{ hashFiles('scripts/deps/build-dependencies-linux.sh', 'scripts/deps/build-ffmpeg-linux.sh') }}
@ -137,10 +138,10 @@ jobs:
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DDISABLE_SSE4=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_PREFIX_PATH="$HOME/deps" -DCMAKE_C_COMPILER=clang-18 -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_EXE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_MODULE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_SHARED_LINKER_FLAGS_INIT="-fuse-ld=lld" ..
cmake --build . --parallel
cd ..
scripts/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64-SSE2
scripts/packaging/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64-SSE2
- name: Upload Qt AppImage
uses: actions/upload-artifact@v4.3.3
uses: actions/upload-artifact@v4
with:
name: "linux-x64-sse2-appimage"
path: "DuckStation-x64-SSE2.AppImage"

View File

@ -11,6 +11,7 @@ on:
required: false
type: string
default: "stable"
workflow_dispatch:
jobs:
linux-flatpak-build:
@ -21,7 +22,7 @@ jobs:
options: --privileged
timeout-minutes: 120
steps:
- uses: actions/checkout@v4.1.6
- uses: actions/checkout@v4
with:
fetch-depth: 0
set-safe-directory: ${{ env.GITHUB_WORKSPACE }}
@ -59,21 +60,21 @@ jobs:
- name: Generate AppStream XML
run: |
scripts/generate-metainfo.sh scripts/flatpak
cat scripts/flatpak/org.duckstation.DuckStation.metainfo.xml
scripts/packaging/generate-metainfo.sh scripts/packaging/flatpak
cat scripts/packaging/flatpak/org.duckstation.DuckStation.metainfo.xml
- name: Validate AppStream XML
run: flatpak-builder-lint appstream scripts/flatpak/org.duckstation.DuckStation.metainfo.xml
run: flatpak-builder-lint appstream scripts/packaging/flatpak/org.duckstation.DuckStation.metainfo.xml
- name: Validate Manifest
run: flatpak-builder-lint manifest scripts/flatpak/org.duckstation.DuckStation.yaml
run: flatpak-builder-lint manifest scripts/packaging/flatpak/org.duckstation.DuckStation.yaml
- name: Build Flatpak
uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
with:
bundle: duckstation-x64.flatpak
upload-artifact: false
manifest-path: scripts/flatpak/org.duckstation.DuckStation.yaml
manifest-path: scripts/packaging/flatpak/org.duckstation.DuckStation.yaml
arch: x86_64
build-bundle: true
verbose: true
@ -81,7 +82,7 @@ jobs:
branch: stable
cache: true
restore-cache: true
cache-key: flatpak-x64-${{ hashFiles('scripts/flatpak/**/*.yaml') }}
cache-key: flatpak-x64-${{ hashFiles('scripts/packaging/flatpak/**/*.yaml') }}
- name: Validate Build
run: |
@ -106,7 +107,7 @@ jobs:
build-log-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- name: Upload Flatpak
uses: actions/upload-artifact@v4.3.3
uses: actions/upload-artifact@v4
with:
name: "linux-flatpak"
path: "duckstation-x64.flatpak"

View File

@ -2,6 +2,7 @@ name: 🍎 MacOS
on:
workflow_call:
workflow_dispatch:
jobs:
macos-build:
@ -9,12 +10,12 @@ jobs:
runs-on: macos-14
timeout-minutes: 120
steps:
- uses: actions/checkout@v4.1.6
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Use Xcode 15.4
run: sudo xcode-select -s /Applications/Xcode_15.4.app
- name: Use Xcode 16.1
run: sudo xcode-select -s /Applications/Xcode_16.1.app
- name: Install packages
shell: bash
@ -23,7 +24,7 @@ jobs:
- name: Cache Dependencies
id: cache-deps-mac
uses: actions/cache@v4.0.2
uses: actions/cache@v4
with:
path: ~/deps
key: deps-mac ${{ hashFiles('scripts/deps/build-dependencies-mac.sh') }}
@ -72,7 +73,7 @@ jobs:
zip -r duckstation-mac-release.zip DuckStation.app/
- name: Upload MacOS .app
uses: actions/upload-artifact@v4.3.3
uses: actions/upload-artifact@v4
with:
name: "macos"
path: "build/duckstation-mac-release.zip"

View File

@ -1,6 +1,7 @@
name: Automated Builds
on:
workflow_dispatch:
pull_request:
paths-ignore:
- '**.md'
@ -38,7 +39,7 @@ jobs:
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev'
steps:
- name: Download Artifacts
uses: actions/download-artifact@v4.1.7
uses: actions/download-artifact@v4
with:
path: ./artifacts/

View File

@ -8,13 +8,13 @@ jobs:
runs-on: windows-2022
timeout-minutes: 120
steps:
- uses: actions/checkout@v4.1.6
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Cache Dependencies
id: cache-deps
uses: actions/cache@v4.0.2
uses: actions/cache@v4
with:
path: |
dep/msvc/deps-arm64
@ -30,7 +30,7 @@ jobs:
- name: Upload Cache Files
if: steps.cache-deps.outputs.cache-hit == 'true'
uses: actions/upload-artifact@v4.3.3
uses: actions/upload-artifact@v4
with:
name: "windows"
path: "deps-*.zip"

View File

@ -2,6 +2,7 @@ name: 💻 Windows
on:
workflow_call:
workflow_dispatch:
jobs:
windows-x64-build:
@ -9,13 +10,13 @@ jobs:
runs-on: windows-2022
timeout-minutes: 120
steps:
- uses: actions/checkout@v4.1.6
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Cache Dependencies
id: cache-deps
uses: actions/cache@v4.0.2
uses: actions/cache@v4
with:
path: |
dep/msvc/deps-arm64
@ -96,7 +97,7 @@ jobs:
"C:\Program Files\7-Zip\7z.exe" a -r duckstation-windows-x64-release.zip ./bin/x64/*
- name: Upload x64 Release Artifact
uses: actions/upload-artifact@v4.3.3
uses: actions/upload-artifact@v4
with:
name: "windows-x64"
path: "duckstation-windows-x64-release*.zip"
@ -107,13 +108,13 @@ jobs:
runs-on: windows-2022
timeout-minutes: 120
steps:
- uses: actions/checkout@v4.1.6
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Cache Dependencies
id: cache-deps
uses: actions/cache@v4.0.2
uses: actions/cache@v4
with:
path: |
dep/msvc/deps-arm64
@ -194,7 +195,7 @@ jobs:
"C:\Program Files\7-Zip\7z.exe" a -r duckstation-windows-x64-sse2-release.zip ./bin/x64/*
- name: Upload x64 Release Artifact
uses: actions/upload-artifact@v4.3.3
uses: actions/upload-artifact@v4
with:
name: "windows-x64-sse2"
path: "duckstation-windows-x64-sse2-release*.zip"
@ -205,14 +206,14 @@ jobs:
runs-on: windows-2022
timeout-minutes: 120
steps:
- uses: actions/checkout@v4.1.6
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
- name: Cache Dependencies
id: cache-deps
uses: actions/cache@v4.0.2
uses: actions/cache@v4
with:
path: |
dep/msvc/deps-arm64
@ -293,7 +294,7 @@ jobs:
"C:\Program Files\7-Zip\7z.exe" a -r duckstation-windows-arm64-release.zip ./bin/ARM64/*
- name: Upload ARM64 Release Artifact
uses: actions/upload-artifact@v4.3.3
uses: actions/upload-artifact@v4
with:
name: "windows-arm64"
path: "duckstation-windows-arm64-release*.zip"

View File

@ -42,10 +42,6 @@ if(LINUX OR BSD)
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
endif()
# Set _DEBUG macro for Debug builds.
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
# Release build optimizations for MSVC.
if(MSVC)
add_definitions("/D_CRT_SECURE_NO_WARNINGS")
@ -59,14 +55,18 @@ if(MSVC)
# RelWithDebInfo is set to Ob1 instead of Ob2.
string(REPLACE "/Ob1" "/Ob2" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Ob1" "/Ob2" CMAKE_C_FLAGS_DEVEL "${CMAKE_C_FLAGS_DEVEL}")
string(REPLACE "/Ob1" "/Ob2" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Ob1" "/Ob2" CMAKE_CXX_FLAGS_DEVEL "${CMAKE_CXX_FLAGS_DEVEL}")
# Disable incremental linking in RelWithDebInfo.
string(REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_DEVEL "${CMAKE_EXE_LINKER_FLAGS_DEVEL}")
# COMDAT folding/remove unused functions.
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /OPT:REF /OPT:ICF")
set(CMAKE_EXE_LINKER_FLAGS_DEVEL "${CMAKE_EXE_LINKER_FLAGS_DEVEL} /OPT:REF /OPT:ICF")
endif()
# Warning disables.

View File

@ -16,3 +16,17 @@ endif()
if(APPLE)
option(SKIP_POSTPROCESS_BUNDLE "Disable bundle post-processing, including Qt additions" OFF)
endif()
# Set _DEBUG macro for Debug builds.
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
# Create the Devel build type based on RelWithDebInfo.
set(CMAKE_C_FLAGS_DEVEL "${CMAKE_C_FLAGS_RELWITHDEBINFO} -D_DEVEL" CACHE STRING "Flags used by the C compiler during DEVEL builds." FORCE)
set(CMAKE_CXX_FLAGS_DEVEL "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -D_DEVEL" CACHE STRING "Flags used by the CXX compiler during DEVEL builds." FORCE)
set(CMAKE_EXE_LINKER_FLAGS_DEVEL "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used for the linker during DEVEL builds." FORCE)
set(CMAKE_MODULE_LINKER_FLAGS_DEVEL "${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used by the linker during the creation of modules during DEVEL builds." FORCE)
set(CMAKE_SHARED_LINKER_FLAGS_DEVEL "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used by the linker during the creation of shared libraries during DEVEL builds." FORCE)
set(CMAKE_STATIC_LINKER_FLAGS_DEVEL "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used by the linker during the creation of static libraries during DEVEL builds." FORCE)
list(APPEND CMAKE_CONFIGURATION_TYPES "Devel")
mark_as_advanced(CMAKE_C_FLAGS_DEVEL CMAKE_CXX_FLAGS_DEVEL CMAKE_EXE_LINKER_FLAGS_DEVEL CMAKE_MODULE_LINKER_FLAGS_DEVEL CMAKE_SHARED_LINKER_FLAGS_DEVEL CMAKE_STATIC_LINKER_FLAGS_DEVEL)

View File

@ -92,17 +92,22 @@ function(detect_architecture)
elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "riscv64")
message(STATUS "Building RISC-V 64 binaries.")
set(CPU_ARCH_RISCV64 TRUE PARENT_SCOPE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -finline-atomics" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -finline-atomics" PARENT_SCOPE)
# Still need this, apparently.
link_libraries("-latomic")
# Don't want function calls for atomics.
if(COMPILER_GCC)
set(EXTRA_CFLAGS "${EXTRA_CFLAGS} -finline-atomics")
# Still need this, apparently.
link_libraries("-latomic")
endif()
if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
# Frame pointers generate an annoying amount of code on leaf functions.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fomit-frame-pointer" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer" PARENT_SCOPE)
set(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fomit-frame-pointer")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS}" PARENT_SCOPE)
else()
message(FATAL_ERROR "Unknown system processor: ${CMAKE_SYSTEM_PROCESSOR}")
endif()
@ -121,8 +126,8 @@ function(detect_page_size)
return()
endif()
if(HOST_MIN_PAGE_SIZE OR HOST_MAX_PAGE_SIZE)
if(NOT HOST_MIN_PAGE_SIZE OR NOT HOST_MAX_PAGE_SIZE)
if(DEFINED HOST_MIN_PAGE_SIZE OR DEFINED HOST_MAX_PAGE_SIZE)
if(NOT DEFINED HOST_MIN_PAGE_SIZE OR NOT DEFINED HOST_MAX_PAGE_SIZE)
message(FATAL_ERROR "Both HOST_MIN_PAGE_SIZE and HOST_MAX_PAGE_SIZE must be defined.")
endif()
return()
@ -172,7 +177,7 @@ function(detect_cache_line_size)
endif()
if(CMAKE_CROSSCOMPILING)
message(WARNING "Cross-compiling and can't determine page size, assuming default.")
message(WARNING "Cross-compiling and can't determine cache line size, assuming default.")
return()
endif()

Binary file not shown.

View File

@ -0,0 +1,9 @@
void main()
{
// Radial gradient at (0.6, 0.4), moving horizontally slowly
float r1 = length(v_tex0 - vec2(0.6, 0.4));
float r2 = length(v_tex0 - vec2(0.61, 0.41));
float r = mix(r1, r2, sin(u_time / 5.0));
vec3 bg_color = vec3(0.1, 0.1, 0.6) * (1.0f - r);
o_col0 = vec4(bg_color, 1.0);
}

View File

@ -0,0 +1,10 @@
void main()
{
vec2 uv = v_tex0 * 2.0 - 1.0;
uv.x *= u_display_size.x / u_display_size.y;
vec2 center = vec2(cos(u_time * 0.2) * 1.5, (sin(u_time * 0.2) * 0.2) * 0.5 + 1.2);
float dist = length(uv - center);
float gradient = smoothstep(0.0, 1.0, dist);
o_col0 = vec4(mix(vec3(0.5, 0.5, 0.9), vec3(0.05, 0.05, 0.2), gradient), 1.0);
}

View File

@ -0,0 +1,30 @@
const float PI = 3.14159265359;
const float SCALE = 150.0;
const float LENGTH = 7.5;
// https://www.shadertoy.com/view/Xt23Ry
float rand(float co) {
return fract(sin(co * 91.3458) * 47453.5453);
}
vec3 background(vec2 pos) {
// Radial gradient at (0.6, 0.4).
float r = length(pos - vec2(0.6, 0.4));
return vec3(r * 0.1);
}
// Inspired by https://www.shadertoy.com/view/Wtl3D7
vec3 trails(vec2 pos, vec3 bg_color, vec3 fg_color) {
float cdist = length(pos) * SCALE;
float rv = rand(ceil(cdist));
float rotation = u_time * rv * 0.005;
float nangle = atan(pos.y, pos.x) / PI;
float intensity = smoothstep(rv, rv - 1.5, fract(nangle + rotation + rv * 0.1) * LENGTH) * step(0.1, cdist / SCALE);
return mix(bg_color, fg_color * rv, intensity);
}
void main() {
vec3 bg_color = background(v_tex0);
vec3 fg_color = vec3(0.7, 0.7, 1.5);
o_col0 = vec4(trails(v_tex0, bg_color, fg_color), 1.0);
}

View File

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 202 KiB

View File

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -109,6 +109,9 @@
03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,
03000000710100001904000000000000,Amazon Luna Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b8,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b4,rightstick:b7,rightx:a3,righty:a4,start:b6,x:b3,y:b2,platform:Windows,
0300000008100000e501000000000000,Anbernic Game Pad,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000020500000913000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000373500000710000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000373500004610000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000830500000160000000000000,Arcade,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b4,platform:Windows,
03000000120c0000100e000000000000,Armor 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
@ -173,8 +176,6 @@
030000004f04000020b3000000000000,Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
03000000bd12000002e0000000000000,Dual Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
03000000ff1100003133000000000000,DualForce,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b1,platform:Windows,
030000008f0e00000910000000000000,DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
03000000317300000100000000000000,DualShock 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
030000006f0e00003001000000000000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000fc0400000250000000000000,Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
03000000bc2000000091000000000000,EasySMX Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
@ -244,6 +245,7 @@
03000000f025000031c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000f0250000c383000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000f0250000c483000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000d11800000094000000000000,Google Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
030000004f04000026b3000000000000,GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
0300000079000000d418000000000000,GPD Win,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000c6240000025b000000000000,GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@ -270,8 +272,8 @@
030000000d0f00005100000000000000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f00008800000000000000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
030000000d0f00008700000000000000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000000d0f00008800000000000000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
030000000d0f00008700000000000000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@ -323,6 +325,7 @@
030000000d0f0000c100000000000000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000f600000000000000,Horipad Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f00009601000000000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b15,paddle2:b5,paddle3:b19,paddle4:b18,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows,
03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows,
@ -485,18 +488,13 @@
030000006f0e00000901000000000000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00008901000000000000,PDP Realmz Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000008f0e00004100000000000000,PlaySega,a:b1,b:b0,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b4,y:b3,platform:Windows,
03000000666600006706000000000000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows,
03000000e30500009605000000000000,PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000632500002306000000000000,PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
03000000f0250000c183000000000000,PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d9040000160f000000000000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000011a7000000000000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000dd62000015a7000000000000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000012a7000000000000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000013a7000000000000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d62000003340000000000000,PowerA OPS Pro Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000d62000002640000000000000,PowerA OPS Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
0300000062060000d570000000000000,PowerA PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000014a7000000000000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@ -595,6 +593,7 @@
030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
03000000790000008f18000000000000,Rapoo Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
0300000032150000a602000000000000,Razer Huntsman V3 Pro,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b12,dpright:b13,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000f8270000bf0b000000000000,Razer Kishi,a:b6,b:b7,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b12,leftstick:b19,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b13,rightstick:b20,righttrigger:b15,rightx:a3,righty:a4,start:b17,x:b9,y:b10,platform:Windows,
03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@ -679,13 +678,21 @@
03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
030000008b2800000300000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
030000008f0e00000910000000000000,Sony DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
03000000317300000100000000000000,Sony DualShock 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000666600006706000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows,
03000000e30500009605000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
030000004c050000da0c000000000000,Sony PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000632500002306000000000000,Sony PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
03000000f0250000c183000000000000,Sony PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d9040000160f000000000000,Sony PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000ff000000cb01000000000000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
030000004c0500003713000000000000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000341a00000208000000000000,Speedlink 6555,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00000908000000000000,Speedlink 6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000380700001722000000000000,Speedlink Competition Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,platform:Windows,
030000008f0e00000800000000000000,Speedlink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000c01100000591000000000000,Speedlink Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000d11800000094000000000000,Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
03000000de280000fc11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000de280000ff11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
@ -695,7 +702,6 @@
03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows,
03000000790000001c18000000000000,STK 7024X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000380700003847000000000000,Street Fighter Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows,
030000001f08000001e4000000000000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000790000000418000000000000,Super Famicom Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
@ -710,17 +716,18 @@
03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
03000000ba2200000701000000000000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b2,platform:Windows,
03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,
03000000790000002601000000000000,TGZ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
03000000790000001c18000000000000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000790000002601000000000000,TGZ Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
03000000591c00002400000000000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
03000000591c00002600000000000000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,start:b7,x:b3,y:b0,platform:Windows,
030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
030000004f04000023b3000000000000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004f0400000ed0000000000000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004f04000008d0000000000000,ThrustMaster Ferrari 150 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004f0400000ed0000000000000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004f04000008d0000000000000,Thrustmaster Ferrari 150 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows,
030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
030000004f04000003d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004f04000009d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000004f04000003d0000000000000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004f04000009d0000000000000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d04000088ca000000000000,Thunderpad,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
03000000666600000288000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000666600000488000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
@ -748,6 +755,7 @@
03000000bd12000012d0000000000000,USB Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
03000000ff1100004133000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000632500002305000000000000,USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000882800000305000000000000,V5 Game Pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,x:b2,y:b3,platform:Windows,
03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
@ -812,7 +820,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000004f18000000000000,ZDT Android Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000120c00000500000000000000,Zeroplus Adapter,a:b2,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows,
03000000120c0000101e000000000000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000882800000305000000000000,V5 GAME PAD,a:b0,b:b1,x:b2,y:b3,guide:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows
# Mac OS X
030000008f0e00000300000009010000,2 In 1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
@ -877,7 +884,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,
0300000008100000e501000019040000,Anbernic Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
0300000008100000e501000019040000,Anbernic Handheld,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000373500004610000001000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
@ -890,7 +898,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000008a3500000201000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000008a3500000202000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
030000008a3500000402000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000008a3500000302000000010000,Backbone One PlayStationÆ Edition,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
030000008a3500000302000000010000,Backbone One PlayStation Edition,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
@ -913,6 +921,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000006f0e00000102000000000000,GameStop Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000ff1100003133000007010000,GameWare PC Control Pad,a:b2,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Mac OS X,
03000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000280400000140000000020000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000008f0e00000300000007010000,GreenAsia Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X,
@ -924,8 +933,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000341a00000302000014010000,Hori Fighting Stick Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00008800000000010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00008700000000010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000000d0f00008800000000010000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00008700000000010000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X,
030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
@ -989,11 +998,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,
030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000790000001c18000000010000,PB Tails Choc,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000006f0e00000901000002010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000666600006706000088020000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X,
030000004c050000da0c000000010000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
030000004c0500003713000000010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000d620000011a7000000020000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000d620000011a7000010050000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
@ -1011,7 +1018,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000005e040000e002000001000000,PXN P30 Pro Mobile,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000222c00000225000000010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000222c00000225000000010000,Qanba Dragon Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000222c00000020000000010000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000009b2800005600000020020000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Mac OS X,
030000009b2800008000000022020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Mac OS X,
@ -1044,9 +1051,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,
03000000bc2000000155000000010000,SNK NEOGEO Arcade Stick Pro,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b2,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b0,y:b3,platform:Mac OS X,
030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000666600006706000088020000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X,
030000004c050000da0c000000010000,Sony PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
030000004c0500003713000000010000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
@ -1065,7 +1075,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X,
030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,
030000004f0400000ed0000000020000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004f0400000ed0000000020000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,
03000000571d00002100000021000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Mac OS X,
03000000bd12000015d0000000010000,Tomee Retro Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
@ -1103,14 +1113,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000022050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000022050000,Xbox Wireless Controller,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Mac OS X,
03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
# Linux
03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000631000000010000,8BitDo Adapter 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,
03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
@ -1199,7 +1210,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000491900000204000021000000,Amazon Fire Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,
05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
0300000008100000e501000001010000,Anbernic Gamepad,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Linux,
0300000008100000e501000001010000,Anbernic Handheld,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Linux,
03000000020500000913000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000373500000710000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000373500004610000001000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
@ -1239,6 +1253,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,
03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,
03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
030000005e0400008e02000002010000,Data Frog S80,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,
03000000791d00000103000010010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000c11100000191000011010000,EasySMX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
@ -1271,8 +1286,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
190000004b4800000010000001010000,GO-Advance Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b13,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b16,righttrigger:b15,start:b17,x:b2,y:b3,platform:Linux,
190000004b4800000011000000010000,GO-Super Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b2,y:b3,platform:Linux,
03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d11800000094000011010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
05000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400008e02000001010000,GPD Win Max 2 (6800U) Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400008e02000001010000,GPD Win Max 2 6800U Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000280400000140000000010000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000008f0e00000610000000010000,GreenAsia Electronics Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,
@ -1286,12 +1303,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00008400000011010000,Hori Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00005001000009040000,Hori Fighting Commander Octa Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00008500000010010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00003701000013010000,Hori Fighting Stick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b3,y:b2,platform:Linux,
030000000d0f00008800000011010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00008700000011010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000000d0f00008800000011010000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00008700000011010000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00004d00000011010000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@ -1308,7 +1325,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00008501000015010000,Hori Switch Split Pad Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00006e00000011010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f0000c100000011010000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00006700000001010000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000000d0f0000f600000001000000,Horipad Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
@ -1331,6 +1348,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000632500007505000011010000,Ipega PG 9099,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
0500000049190000030400001b010000,Ipega PG9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000491900000204000000000000,Ipega PG9118,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000300f00001101000010010000,Jess Tech Colour Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
03000000300f00001001000010010000,Jess Tech Dual Analog Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000ba2200002010000001010000,Jess Technology Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
@ -1369,7 +1387,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000380700001647000010040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000380700003847000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000120c00000500000000010000,Manta Dualshock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000120c00000500000000010000,Manta DualShock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
030000008f0e00001330000010010000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
03000000790000004318000010010000,Mayflash GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
@ -1420,10 +1438,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000c62400001a89000000010000,MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000f70600000100000000010000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Linux,
030000006f0e00001311000011010000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Linux,
030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006b140000010c000010010000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000853200000706000012010000,Nacon GC-100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux,
@ -1452,8 +1473,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b8,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500001720000001800000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
03000000550900001472000011010000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
05000000550900001472000001000000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
030000004b120000014d000000010000,NYKO Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
19000000010000000100000001010000,ODROID Go 2,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
@ -1478,10 +1499,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000666600006706000000010000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,
030000004c050000da0c000011010000,PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000d9040000160f000000010000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d620000011a7000011010000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@ -1500,6 +1517,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000b20000001010000,PowerA Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000540000001010000,PowerA Advantage Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000250900000017000010010000,PS/SS/N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux,
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
@ -1519,6 +1537,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
060000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
030000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
@ -1535,18 +1554,20 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000004c050000e60c000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
030000004c050000f20d000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000004c050000f20d000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
050000004c050000e60c000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
050000004c050000f20d000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,
03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000222c00001220000011010000,Qanba Drone 2 Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000222c00001020000011010000,Qanba Drone 2 Arcade Joystick (PS5),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000222c00000225000011010000,Qanba Dragon Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000222c00000025000011010000,Qanba Dragon Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000222c00001220000011010000,Qanba Drone 2 Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000222c00001020000011010000,Qanba Drone 2 Arcade Joystick PS5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux,
03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000009b2800000300000001010000,Raphnet 4nes4snes,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,
030000009b2800004200000001010000,Raphnet Dual NES Adapter,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux,
0300132d9b2800006500000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
@ -1570,6 +1591,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000321500000b10000011010000,Razer Wolverine PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000000d0f0000c100000010010000,Retro Bit Legacy16,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b12,leftshoulder:b4,lefttrigger:b6,misc1:b13,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f0000c100000072056800,Retro Bit Legacy16,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:+a4,misc1:b11,rightshoulder:b10,righttrigger:+a5,start:b6,x:b3,y:b2,platform:Linux,
03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux,
0300000003040000c197000011010000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,
190000004b4800000111000000010000,RetroGame Joypad,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
@ -1584,10 +1607,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000a306000023f6000011010000,Saitek Cyborg V1 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000a306000023f6000011010000,Saitek Cyborg PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux,
03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux,
03000000a30600000cff000010010000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux,
03000000a30600000d5f000010010000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,
03000000a30600000c04000011010000,Saitek P2900,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,
03000000a306000018f5000010010000,Saitek P3200 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
@ -1612,12 +1636,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000341a00000908000010010000,SL6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000004b2900000430000011000000,Snakebyte Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000004c050000cc09000001000000,Sony DualShock 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000666600006706000000010000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,
030000004c050000da0c000011010000,Sony PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000d9040000160f000000010000,Sony PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000ff000000cb01000010010000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
030000004c0500003713000011010000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000250900000500000000010000,Sony PS2 pad with SmartJoy Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
05000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
@ -1647,7 +1673,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000e40a00000307000011010000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux,
03000000e40a00000207000011010000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux,
03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Linux,
03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000591c00002400000010010000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
03000000591c00002600000010010000,THEGamepad,a:b2,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,
030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
@ -1696,10 +1722,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00001503000000020000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400008e02000000010000,Xbox 360 EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000a102000014010000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
0000000058626f782047616d65706100,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400000202000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
030000005e0400008e02000072050000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00001304000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000ffff0000ffff000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
0000000058626f782047616d65706100,Xbox Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400000a0b000005040000,Xbox One Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@ -1711,8 +1738,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e040000ea02000011050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000ea02000015050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000ea02000016050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@ -1830,7 +1859,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
63396666386564393334393236386630,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
63633435623263373466343461646430,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
32333634613735616163326165323731,Amazon Luna Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
4c696e757820342e31392e3137322077,Anbernic Gamepad,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Android,
4c696e757820342e31392e3137322077,Anbernic Handheld,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Android,
417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android,
35643263313264386134376362363435,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,start:b6,platform:Android,
32353831643566306563643065356239,Atari VCS Modern Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
@ -1844,6 +1873,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
34323662653333636330306631326233,Google Nexus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
35383633353935396534393230616564,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
476f6f676c65204c4c43205374616469,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
5374616469614e3848532d6532633400,Google Stadia Controller,a:b0,b:b1,back:b15,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
05000000d6020000e5890000dfff3f80,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,platform:Android,
66633030656131663837396562323935,Hori Battle,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
@ -1917,9 +1948,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
39383335313438623439373538343266,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b16,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,x:b1,y:b19,platform:Android,
4f5559412047616d6520436f6e74726f,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b6,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b19,platform:Android,
506572666f726d616e63652044657369,PDP PS3 Rock Candy Controller,a:b1,b:b17,back:h0.2,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android,
62653335326261303663356263626339,PlayStation Classic Controller,a:b19,b:b1,back:b17,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b3,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android,
536f6e7920496e746572616374697665,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
576972656c65737320436f6e74726f6c,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
61653962353232366130326530363061,Pokken,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,rightshoulder:b20,righttrigger:b10,start:b18,x:b0,y:b2,platform:Android,
32666633663735353234363064386132,PS2,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a3,righty:a2,start:b30,x:b24,y:b21,platform:Android,
050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
@ -1947,7 +1975,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
050000004c050000e60c0000fffe3f80,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,platform:Android,
050000004c050000e60c0000fffe3f80,PS5 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b2,y:b17,platform:Android,
050000004c050000e60c0000ffff3f00,PS5 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
@ -1988,10 +2016,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
38376662666661636265313264613039,SNES,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android,
5346432f555342205061640000000000,SNES Adapter,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android,
5553422047616d657061642000000000,SNES Controller,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
62653335326261303663356263626339,Sony PlayStation Classic Controller,a:b19,b:b1,back:b17,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b3,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android,
536f6e7920496e746572616374697665,Sony PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
576972656c65737320436f6e74726f6c,Sony PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
63303964303462366136616266653561,Sony PSP,a:b21,b:b22,back:b27,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b23,y:b24,platform:Android,
63376637643462343766333462383235,Sony Vita,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a3,righty:a4,start:b18,x:b0,y:b2,platform:Android,
476f6f676c65204c4c43205374616469,Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
5374616469614e3848532d6532633400,Stadia Controller,a:b0,b:b1,back:b15,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
0500000011010000201400000f7e0f00,SteelSeries Nimbus,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,x:b19,y:b2,platform:Android,
@ -2001,7 +2030,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
62363434353532386238336663643836,TGZ Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
37323236633763666465316365313236,THEC64 Joystick,a:b21,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b27,x:b23,y:b24,platform:Android,
38346162326232346533316164363336,THEGamepad,a:b23,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b24,y:b21,platform:Android,
050000004f0400000ed00000fffe3f00,ThrustMaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000004f0400000ed00000fffe3f00,Thrustmaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
5477696e20555342204a6f7973746963,Twin Joystick,a:b22,b:b21,back:b28,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,
30623739343039643830333266346439,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
31643365666432386133346639383937,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.88 111.24"><defs><style>.cls-1{fill:#fec901;fill-rule:evenodd;}.cls-2{fill:#010101;}</style></defs><title>risk</title><path d="M2.5,85l43-74.41h0a22.59,22.59,0,0,1,8-8.35,15.72,15.72,0,0,1,16,0,22.52,22.52,0,0,1,7.93,8.38l.23.44,42.08,73.07a20.91,20.91,0,0,1,3,10.84A16.44,16.44,0,0,1,121,102.4a15.45,15.45,0,0,1-5.74,6,21,21,0,0,1-11.35,2.78v0H17.7c-.21,0-.43,0-.64,0a19,19,0,0,1-7.83-1.74,15.83,15.83,0,0,1-6.65-5.72A16.26,16.26,0,0,1,0,95.18a21.66,21.66,0,0,1,2.2-9.62c.1-.2.2-.4.31-.59Z"/><path class="cls-1" d="M9.09,88.78l43-74.38c5.22-8.94,13.49-9.2,18.81,0l42.32,73.49c4.12,6.79,2.41,15.9-9.31,15.72H17.7C9.78,103.79,5,97.44,9.09,88.78Z"/><path class="cls-2" d="M57.55,83.15a5.47,5.47,0,0,1,5.85-1.22,5.65,5.65,0,0,1,2,1.3A5.49,5.49,0,0,1,67,86.77a5.12,5.12,0,0,1-.08,1.4,5.22,5.22,0,0,1-.42,1.34,5.51,5.51,0,0,1-5.2,3.25,5.63,5.63,0,0,1-2.26-.53,5.51,5.51,0,0,1-2.81-2.92A6,6,0,0,1,55.9,88a5.28,5.28,0,0,1,0-1.31h0a6,6,0,0,1,.56-2,4.6,4.6,0,0,1,1.14-1.56Zm8.12-10.21c-.19,4.78-8.28,4.78-8.46,0-.82-8.19-2.92-27.63-2.85-35.32.07-2.37,2-3.78,4.55-4.31a11.65,11.65,0,0,1,2.48-.25,12.54,12.54,0,0,1,2.5.25c2.59.56,4.63,2,4.63,4.43V38l-2.84,35Z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -339,3 +339,17 @@
#define ICON_PF_SOUND "\xE2\x8D\xA5"
#define ICON_PF_PICTURE "\xE2\x8D\xA6"
#define ICON_PF_CIRCLE "\xE2\x8D\x89"
#define ICON_PF_VIBRATION "\xE2\x88\x9A"
#define ICON_PF_VIBRATION_L "\xE2\x88\x9B"
#define ICON_PF_JOGCON_CONTROLLER "\xE2\x91\x86"
#define ICON_PF_POPN_CONTROLLER "\xE2\x8A\xBF"
#define ICON_PF_POPN_BL "\xE2\x8B\x80"
#define ICON_PF_POPN_BR "\xE2\x8B\x81"
#define ICON_PF_POPN_GL "\xE2\x8B\x82"
#define ICON_PF_POPN_GR "\xE2\x8B\x83"
#define ICON_PF_POPN_YL "\xE2\x8B\x84"
#define ICON_PF_POPN_YR "\xE2\x8B\x85"
#define ICON_PF_POPN_WL "\xE2\x8B\x86"
#define ICON_PF_POPN_WR "\xE2\x8B\x87"
#define ICON_PF_POPN_R "\xE2\x8B\x88"
#define ICON_PF_NAVIGATION_BACK "\xE2\x8F\x8C"

View File

@ -82,4 +82,9 @@
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="$(Configuration.Contains(Devel))">
<ClCompile>
<PreprocessorDefinitions>_DEVEL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
</Project>

View File

@ -57,6 +57,14 @@
<Configuration>Release-Clang</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Devel-Clang|ARM64">
<Configuration>Devel-Clang</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Devel-Clang|x64">
<Configuration>Devel-Clang</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">

View File

@ -93,6 +93,7 @@ enum {
RC_CONSOLE_NINTENDO_DSI = 78,
RC_CONSOLE_TI83 = 79,
RC_CONSOLE_UZEBOX = 80,
RC_CONSOLE_FAMICOM_DISK_SYSTEM = 81,
RC_CONSOLE_HUBS = 100,
RC_CONSOLE_EVENTS = 101,

View File

@ -46,7 +46,6 @@ typedef struct rc_runtime_trigger_t {
rc_memref_t* invalid_memref;
uint8_t md5[16];
int32_t serialized_size;
uint8_t owns_memrefs;
}
rc_runtime_trigger_t;
@ -58,16 +57,13 @@ typedef struct rc_runtime_lboard_t {
rc_memref_t* invalid_memref;
uint8_t md5[16];
uint32_t serialized_size;
uint8_t owns_memrefs;
}
rc_runtime_lboard_t;
typedef struct rc_runtime_richpresence_t {
rc_richpresence_t* richpresence;
void* buffer;
struct rc_runtime_richpresence_t* previous;
uint8_t md5[16];
uint8_t owns_memrefs;
}
rc_runtime_richpresence_t;
@ -82,11 +78,7 @@ typedef struct rc_runtime_t {
rc_runtime_richpresence_t* richpresence;
rc_memref_t* memrefs;
rc_memref_t** next_memref;
rc_value_t* variables;
rc_value_t** next_variable;
struct rc_memrefs_t* memrefs;
uint8_t owns_self;
}

View File

@ -29,7 +29,7 @@ typedef struct rc_value_t rc_value_t;
* num_bytes is greater than 1, the value is read in little-endian from
* memory.
*/
typedef uint32_t(RC_CCONV *rc_peek_t)(uint32_t address, uint32_t num_bytes, void* ud);
typedef uint32_t(RC_CCONV* rc_peek_t)(uint32_t address, uint32_t num_bytes, void* ud);
/*****************************************************************************\
| Memory References |
@ -70,15 +70,14 @@ typedef struct rc_memref_value_t {
/* The last differing value of this memory reference. */
uint32_t prior;
/* The size of the value. */
/* The size of the value. (RC_MEMSIZE_*) */
uint8_t size;
/* True if the value changed this frame. */
uint8_t changed;
/* The value type of the value (for variables) */
/* The value type of the value. (RC_VALUE_TYPE_*) */
uint8_t type;
/* True if the reference will be used in indirection.
* NOTE: This is actually a property of the rc_memref_t, but we put it here to save space */
uint8_t is_indirect;
/* The type of memref (RC_MEMREF_TYPE_*) */
uint8_t memref_type;
}
rc_memref_value_t;
@ -88,9 +87,6 @@ struct rc_memref_t {
/* The memory address of this variable. */
uint32_t address;
/* The next memory reference in the chain. */
rc_memref_t* next;
};
/*****************************************************************************\
@ -125,11 +121,14 @@ typedef struct rc_operand_t {
int luafunc;
} value;
/* specifies which member of the value union is being used */
/* specifies which member of the value union is being used (RC_OPERAND_*) */
uint8_t type;
/* the actual RC_MEMSIZE of the operand - memref.size may differ */
/* the RC_MEMSIZE of the operand specified in the condition definition - memref.size may differ */
uint8_t size;
/* specifies how to read the memref for some types (RC_OPERAND_*) */
uint8_t memref_access_type;
}
rc_operand_t;
@ -141,23 +140,16 @@ RC_EXPORT int RC_CCONV rc_operand_is_memref(const rc_operand_t* operand);
/* types */
enum {
/* NOTE: this enum is ordered to optimize the switch statements in rc_test_condset_internal. the values may change between releases */
/* non-combining conditions (third switch) */
RC_CONDITION_STANDARD, /* this should always be 0 */
RC_CONDITION_PAUSE_IF,
RC_CONDITION_RESET_IF,
RC_CONDITION_MEASURED_IF,
RC_CONDITION_TRIGGER,
RC_CONDITION_MEASURED, /* measured also appears in the first switch, so place it at the border between them */
/* modifiers (first switch) */
RC_CONDITION_ADD_SOURCE, /* everything from this point on affects the condition after it */
RC_CONDITION_MEASURED,
RC_CONDITION_ADD_SOURCE,
RC_CONDITION_SUB_SOURCE,
RC_CONDITION_ADD_ADDRESS,
RC_CONDITION_REMEMBER,
/* logic flags (second switch) */
RC_CONDITION_ADD_HITS,
RC_CONDITION_SUB_HITS,
RC_CONDITION_RESET_NEXT_IF,
@ -180,7 +172,10 @@ enum {
RC_OPERATOR_XOR,
RC_OPERATOR_MOD,
RC_OPERATOR_ADD,
RC_OPERATOR_SUB
RC_OPERATOR_SUB,
RC_OPERATOR_SUB_PARENT, /* internal use */
RC_OPERATOR_INDIRECT_READ /* internal use */
};
typedef struct rc_condition_t rc_condition_t;
@ -204,9 +199,6 @@ struct rc_condition_t {
/* The comparison operator to use. (RC_OPERATOR_*) */
uint8_t oper; /* operator is a reserved word in C++. */
/* Set if the condition needs to processed as part of the "check if paused" pass. (bool) */
uint8_t pause;
/* Whether or not the condition evaluated true on the last check. (bool) */
uint8_t is_true;
@ -224,17 +216,32 @@ struct rc_condset_t {
/* The next condition set in the chain. */
rc_condset_t* next;
/* The list of conditions in this condition set. */
/* The first condition in this condition set. Then follow ->next chain. */
rc_condition_t* conditions;
/* True if any condition in the set is a pause condition. */
uint8_t has_pause;
/* The number of pause conditions in this condition set. */
/* The first pause condition is at "this + RC_ALIGN(sizeof(this)). */
uint16_t num_pause_conditions;
/* The number of reset conditions in this condition set. */
uint16_t num_reset_conditions;
/* The number of hittarget conditions in this condition set. */
uint16_t num_hittarget_conditions;
/* The number of non-hittarget measured conditions in this condition set. */
uint16_t num_measured_conditions;
/* The number of other conditions in this condition set. */
uint16_t num_other_conditions;
/* The number of indirect conditions in this condition set. */
uint16_t num_indirect_conditions;
/* True if any condition in the set is a pause condition. */
uint8_t has_pause; /* DEPRECATED - just check num_pause_conditions != 0 */
/* True if the set is currently paused. */
uint8_t is_paused;
/* True if the set has indirect memory references. */
uint8_t has_indirect_memrefs;
};
/*****************************************************************************\
@ -259,9 +266,6 @@ struct rc_trigger_t {
/* The list of sub condition sets in this test. */
rc_condset_t* alternative;
/* The memory references required by the trigger. */
rc_memref_t* memrefs;
/* The current state of the MEASURED condition. */
uint32_t measured_value;
@ -274,11 +278,11 @@ struct rc_trigger_t {
/* True if at least one condition has a non-zero hit count */
uint8_t has_hits;
/* True if at least one condition has a non-zero required hit count */
uint8_t has_required_hits;
/* True if the measured value should be displayed as a percentage */
uint8_t measured_as_percent;
/* True if the trigger has its own rc_memrefs_t */
uint8_t has_memrefs;
};
RC_EXPORT int RC_CCONV rc_trigger_size(const char* memaddr);
@ -297,11 +301,11 @@ struct rc_value_t {
/* The current value of the variable. */
rc_memref_value_t value;
/* The list of conditions to evaluate. */
rc_condset_t* conditions;
/* True if the value has its own rc_memrefs_t */
uint8_t has_memrefs;
/* The memory references required by the variable. */
rc_memref_t* memrefs;
/* The list of possible values (traverse next chain, pick max). */
rc_condset_t* conditions;
/* The name of the variable. */
const char* name;
@ -335,9 +339,9 @@ struct rc_lboard_t {
rc_trigger_t cancel;
rc_value_t value;
rc_value_t* progress;
rc_memref_t* memrefs;
uint8_t state;
uint8_t has_memrefs;
};
RC_EXPORT int RC_CCONV rc_lboard_size(const char* memaddr);
@ -406,7 +410,7 @@ struct rc_richpresence_display_part_t {
rc_richpresence_display_part_t* next;
const char* text;
rc_richpresence_lookup_t* lookup;
rc_memref_value_t *value;
rc_operand_t value;
uint8_t display_type;
};
@ -416,13 +420,14 @@ struct rc_richpresence_display_t {
rc_trigger_t trigger;
rc_richpresence_display_t* next;
rc_richpresence_display_part_t* display;
uint8_t has_required_hits;
};
struct rc_richpresence_t {
rc_richpresence_display_t* first_display;
rc_richpresence_lookup_t* first_lookup;
rc_memref_t* memrefs;
rc_value_t* variables;
rc_value_t* values;
uint8_t has_memrefs;
};
RC_EXPORT int RC_CCONV rc_richpresence_size(const char* script);

View File

@ -48,6 +48,10 @@
<ClInclude Include="src\rc_version.h" />
<ClInclude Include="src\rhash\md5.h" />
</ItemGroup>
<ItemGroup>
<Natvis Include="src\rcheevos\rc_runtime_types.natvis" />
<Natvis Include="src\rc_client_types.natvis" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}</ProjectGuid>
</PropertyGroup>

View File

@ -138,4 +138,10 @@
<Filter>include</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Natvis Include="src\rc_client_types.natvis" />
<Natvis Include="src\rcheevos\rc_runtime_types.natvis">
<Filter>rcheevos</Filter>
</Natvis>
</ItemGroup>
</Project>

View File

@ -91,6 +91,70 @@ static void rc_client_award_achievement_retry(rc_client_scheduled_callback_data_
static int rc_client_is_award_achievement_pending(const rc_client_t* client, uint32_t achievement_id);
static void rc_client_submit_leaderboard_entry_retry(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now);
/* ===== natvis extensions ===== */
typedef struct __rc_client_achievement_state_enum_t { uint8_t value; } __rc_client_achievement_state_enum_t;
typedef struct __rc_client_achievement_category_enum_t { uint8_t value; } __rc_client_achievement_category_enum_t;
typedef struct __rc_client_achievement_type_enum_t { uint8_t value; } __rc_client_achievement_type_enum_t;
typedef struct __rc_client_achievement_bucket_enum_t { uint8_t value; } __rc_client_achievement_bucket_enum_t;
typedef struct __rc_client_achievement_unlocked_enum_t { uint8_t value; } __rc_client_achievement_unlocked_enum_t;
typedef struct __rc_client_leaderboard_state_enum_t { uint8_t value; } __rc_client_leaderboard_state_enum_t;
typedef struct __rc_client_leaderboard_format_enum_t { uint8_t value; } __rc_client_leaderboard_format_enum_t;
typedef struct __rc_client_log_level_enum_t { uint8_t value; } __rc_client_log_level_enum_t;
typedef struct __rc_client_event_type_enum_t { uint8_t value; } __rc_client_event_type_enum_t;
typedef struct __rc_client_load_game_state_enum_t { uint8_t value; } __rc_client_load_game_state_enum_t;
typedef struct __rc_client_user_state_enum_t { uint8_t value; } __rc_client_user_state_enum_t;
typedef struct __rc_client_mastery_state_enum_t { uint8_t value; } __rc_client_mastery_state_enum_t;
typedef struct __rc_client_spectator_mode_enum_t { uint8_t value; } __rc_client_spectator_mode_enum_t;
typedef struct __rc_client_disconnect_enum_t { uint8_t value; } __rc_client_disconnect_enum_t;
typedef struct __rc_client_leaderboard_tracker_list_t { rc_client_leaderboard_tracker_info_t* first; } __rc_client_leaderboard_tracker_list_t;
typedef struct __rc_client_subset_info_list_t { rc_client_subset_info_t* first; } __rc_client_subset_info_list_t;
typedef struct __rc_client_media_hash_list_t { rc_client_media_hash_t* first; } __rc_client_media_hash_list_t;
typedef struct __rc_client_subset_info_achievements_list_t { rc_client_subset_info_t info; } __rc_client_subset_info_achievements_list_t;
typedef struct __rc_client_subset_info_leaderboards_list_t { rc_client_subset_info_t info; } __rc_client_subset_info_leaderboards_list_t;
typedef struct __rc_client_scheduled_callback_list_t { rc_client_state_t state; } __rc_client_scheduled_callback_list_t;
typedef struct __rc_client_game_hash_list_t { rc_client_t client; } __rc_client_game_hash_list_t;
static void rc_client_natvis_helper(const rc_client_event_t* event, rc_client_t* client)
{
struct natvis_extensions {
__rc_client_achievement_state_enum_t achievement_state;
__rc_client_achievement_category_enum_t achievement_category;
__rc_client_achievement_type_enum_t achievement_type;
__rc_client_achievement_bucket_enum_t achievement_bucket;
__rc_client_achievement_unlocked_enum_t achievement_unlocked;
__rc_client_leaderboard_state_enum_t leaderboard_state;
__rc_client_leaderboard_format_enum_t leaderboard_format;
__rc_client_log_level_enum_t log_level;
__rc_client_event_type_enum_t event_type;
__rc_client_load_game_state_enum_t load_game_state;
__rc_client_user_state_enum_t user_state;
__rc_client_mastery_state_enum_t mastery_state;
__rc_client_spectator_mode_enum_t spectator_mode;
__rc_client_disconnect_enum_t disconnect;
__rc_client_leaderboard_tracker_list_t leaderboard_tracker_list;
__rc_client_subset_info_list_t subset_info_list;
__rc_client_media_hash_list_t media_hash_list;
__rc_client_subset_info_achievements_list_t subset_info_achievements_list;
__rc_client_subset_info_leaderboards_list_t subset_info_leaderboards_list;
__rc_client_scheduled_callback_list_t scheduled_callback_list;
__rc_client_game_hash_list_t client_game_hash_list;
} natvis;
memset(&natvis, 0, sizeof(natvis));
(void)event;
(void)client;
/* this code should never be executed. it just ensures these constants get defined for
* the natvis VisualStudio extension as they're not used directly in the code. */
natvis.achievement_type.value = RC_CLIENT_ACHIEVEMENT_TYPE_STANDARD;
natvis.achievement_type.value = RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE;
natvis.achievement_type.value = RC_CLIENT_ACHIEVEMENT_TYPE_PROGRESSION;
natvis.achievement_type.value = RC_CLIENT_ACHIEVEMENT_TYPE_WIN;
natvis.achievement_category.value = RC_CLIENT_ACHIEVEMENT_CATEGORY_NONE;
natvis.event_type.value = RC_CLIENT_EVENT_TYPE_NONE;
}
/* ===== Construction/Destruction ===== */
static void rc_client_dummy_event_handler(const rc_client_event_t* event, rc_client_t* client)
@ -110,6 +174,7 @@ rc_client_t* rc_client_create(rc_client_read_memory_func_t read_memory_function,
client->callbacks.read_memory = read_memory_function;
client->callbacks.server_call = server_call_function;
client->callbacks.event_handler = rc_client_natvis_helper;
client->callbacks.event_handler = rc_client_dummy_event_handler;
rc_client_set_legacy_peek(client, RC_CLIENT_LEGACY_PEEK_AUTO);
rc_client_set_get_time_millisecs_function(client, NULL);
@ -180,7 +245,7 @@ static void rc_client_log_message_va(const rc_client_t* client, const char* form
if (client->callbacks.log_call) {
char buffer[2048];
#ifdef __STDC_WANT_SECURE_LIB__
#ifdef __STDC_SECURE_LIB__
vsprintf_s(buffer, sizeof(buffer), format, args);
#elif __STDC_VERSION__ >= 199901L /* vsnprintf requires c99 */
vsnprintf(buffer, sizeof(buffer), format, args);
@ -1071,27 +1136,23 @@ static void rc_client_validate_addresses(rc_client_game_info_t* game, rc_client_
uint32_t total_count = 0;
uint32_t invalid_count = 0;
rc_memref_t** last_memref = &game->runtime.memrefs;
rc_memref_t* memref = game->runtime.memrefs;
for (; memref; memref = memref->next) {
if (!memref->value.is_indirect) {
total_count++;
rc_memref_list_t* memref_list = &game->runtime.memrefs->memrefs;
for (; memref_list; memref_list = memref_list->next) {
rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_end = memref + memref_list->count;
total_count += memref_list->count;
for (; memref < memref_end; ++memref) {
if (memref->address > max_address ||
client->callbacks.read_memory(memref->address, buffer, 1, client) == 0) {
/* invalid address, remove from chain so we don't have to evaluate it in the future.
* it's still there, so anything referencing it will always fetch 0. */
*last_memref = memref->next;
client->callbacks.read_memory(memref->address, buffer, 1, client) == 0) {
memref->value.type = RC_VALUE_TYPE_NONE;
rc_client_invalidate_memref_achievements(game, client, memref);
rc_client_invalidate_memref_leaderboards(game, client, memref);
invalid_count++;
continue;
}
}
last_memref = &memref->next;
}
game->max_valid_address = max_address;
@ -1654,9 +1715,10 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
rc_client_achievement_info_t* achievement;
rc_client_achievement_info_t* scan;
rc_buffer_t* buffer;
rc_parse_state_t parse;
rc_preparse_state_t preparse;
const char* memaddr;
size_t size;
rc_trigger_t* trigger;
int trigger_size;
subset->achievements = NULL;
@ -1686,11 +1748,11 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
+ sizeof(rc_trigger_t) + sizeof(rc_condset_t) * 2 /* trigger container */
+ sizeof(rc_condition_t) * 8 /* assume average trigger length of 8 conditions */
+ sizeof(rc_client_achievement_info_t);
rc_buffer_reserve(&load_state->game->buffer, size * num_achievements);
buffer = &load_state->game->buffer;
rc_buffer_reserve(buffer, size * num_achievements);
/* allocate the achievement array */
size = sizeof(rc_client_achievement_info_t) * num_achievements;
buffer = &load_state->game->buffer;
achievement = achievements = rc_buffer_alloc(buffer, size);
memset(achievements, 0, size);
@ -1713,7 +1775,12 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
memaddr = read->definition;
rc_runtime_checksum(memaddr, achievement->md5);
trigger_size = rc_trigger_size(memaddr);
rc_init_preparse_state(&preparse, NULL, 0);
preparse.parse.existing_memrefs = load_state->game->runtime.memrefs;
trigger = RC_ALLOC(rc_trigger_t, &preparse.parse);
rc_parse_trigger_internal(trigger, &memaddr, &preparse.parse);
trigger_size = preparse.parse.offset;
if (trigger_size < 0) {
RC_CLIENT_LOG_WARN_FORMATTED(load_state->client, "Parse error %d processing achievement %u", trigger_size, read->id);
achievement->public_.state = RC_CLIENT_ACHIEVEMENT_STATE_DISABLED;
@ -1721,23 +1788,22 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
}
else {
/* populate the item, using the communal memrefs pool */
rc_init_parse_state(&parse, rc_buffer_reserve(buffer, trigger_size), NULL, 0);
parse.first_memref = &load_state->game->runtime.memrefs;
parse.variables = &load_state->game->runtime.variables;
achievement->trigger = RC_ALLOC(rc_trigger_t, &parse);
rc_parse_trigger_internal(achievement->trigger, &memaddr, &parse);
rc_reset_parse_state(&preparse.parse, rc_buffer_reserve(buffer, trigger_size), NULL, 0);
rc_preparse_reserve_memrefs(&preparse, load_state->game->runtime.memrefs);
achievement->trigger = RC_ALLOC(rc_trigger_t, &preparse.parse);
memaddr = read->definition;
rc_parse_trigger_internal(achievement->trigger, &memaddr, &preparse.parse);
if (parse.offset < 0) {
RC_CLIENT_LOG_WARN_FORMATTED(load_state->client, "Parse error %d processing achievement %u", parse.offset, read->id);
if (preparse.parse.offset < 0) {
RC_CLIENT_LOG_WARN_FORMATTED(load_state->client, "Parse error %d processing achievement %u", preparse.parse.offset, read->id);
achievement->public_.state = RC_CLIENT_ACHIEVEMENT_STATE_DISABLED;
achievement->public_.bucket = RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED;
}
else {
rc_buffer_consume(buffer, parse.buffer, (uint8_t*)parse.buffer + parse.offset);
achievement->trigger->memrefs = NULL; /* memrefs managed by runtime */
rc_buffer_consume(buffer, preparse.parse.buffer, (uint8_t*)preparse.parse.buffer + preparse.parse.offset);
}
rc_destroy_parse_state(&parse);
rc_destroy_preparse_state(&preparse);
}
achievement->created_time = read->created;
@ -1801,10 +1867,11 @@ static void rc_client_copy_leaderboards(rc_client_load_state_t* load_state,
rc_client_leaderboard_info_t* leaderboards;
rc_client_leaderboard_info_t* leaderboard;
rc_buffer_t* buffer;
rc_parse_state_t parse;
rc_preparse_state_t preparse;
const char* memaddr;
const char* ptr;
size_t size;
rc_lboard_t* lboard;
int lboard_size;
subset->leaderboards = NULL;
@ -1854,29 +1921,32 @@ static void rc_client_copy_leaderboards(rc_client_load_state_t* load_state,
leaderboard->value_djb2 = hash;
}
lboard_size = rc_lboard_size(memaddr);
rc_init_preparse_state(&preparse, NULL, 0);
preparse.parse.existing_memrefs = load_state->game->runtime.memrefs;
lboard = RC_ALLOC(rc_lboard_t, &preparse.parse);
rc_parse_lboard_internal(lboard, memaddr, &preparse.parse);
lboard_size = preparse.parse.offset;
if (lboard_size < 0) {
RC_CLIENT_LOG_WARN_FORMATTED(load_state->client, "Parse error %d processing leaderboard %u", lboard_size, read->id);
leaderboard->public_.state = RC_CLIENT_LEADERBOARD_STATE_DISABLED;
}
else {
/* populate the item, using the communal memrefs pool */
rc_init_parse_state(&parse, rc_buffer_reserve(buffer, lboard_size), NULL, 0);
parse.first_memref = &load_state->game->runtime.memrefs;
parse.variables = &load_state->game->runtime.variables;
leaderboard->lboard = RC_ALLOC(rc_lboard_t, &parse);
rc_parse_lboard_internal(leaderboard->lboard, memaddr, &parse);
rc_reset_parse_state(&preparse.parse, rc_buffer_reserve(buffer, lboard_size), NULL, 0);
rc_preparse_reserve_memrefs(&preparse, load_state->game->runtime.memrefs);
leaderboard->lboard = RC_ALLOC(rc_lboard_t, &preparse.parse);
rc_parse_lboard_internal(leaderboard->lboard, memaddr, &preparse.parse);
if (parse.offset < 0) {
RC_CLIENT_LOG_WARN_FORMATTED(load_state->client, "Parse error %d processing leaderboard %u", parse.offset, read->id);
if (preparse.parse.offset < 0) {
RC_CLIENT_LOG_WARN_FORMATTED(load_state->client, "Parse error %d processing leaderboard %u", preparse.parse.offset, read->id);
leaderboard->public_.state = RC_CLIENT_LEADERBOARD_STATE_DISABLED;
}
else {
rc_buffer_consume(buffer, parse.buffer, (uint8_t*)parse.buffer + parse.offset);
leaderboard->lboard->memrefs = NULL; /* memrefs managed by runtime */
rc_buffer_consume(buffer, preparse.parse.buffer, (uint8_t*)preparse.parse.buffer + preparse.parse.offset);
}
rc_destroy_parse_state(&parse);
rc_destroy_preparse_state(&preparse);
}
++leaderboard;
@ -4801,22 +4871,11 @@ void rc_client_set_read_memory_function(rc_client_t* client, rc_client_read_memo
static void rc_client_invalidate_processing_memref(rc_client_t* client)
{
rc_memref_t** next_memref = &client->game->runtime.memrefs;
rc_memref_t* memref;
/* if processing_memref is not set, this occurred following a pointer chain. ignore it. */
if (!client->state.processing_memref)
return;
/* invalid memref. remove from chain so we don't have to evaluate it in the future.
* it's still there, so anything referencing it will always fetch the current value. */
while ((memref = *next_memref) != NULL) {
if (memref == client->state.processing_memref) {
*next_memref = memref->next;
break;
}
next_memref = &memref->next;
}
client->state.processing_memref->value.type = RC_VALUE_TYPE_NONE;
rc_client_invalidate_memref_achievements(client->game, client, client->state.processing_memref);
rc_client_invalidate_memref_leaderboards(client->game, client, client->state.processing_memref);
@ -4924,31 +4983,57 @@ int rc_client_is_processing_required(rc_client_t* client)
return (client->game->runtime.richpresence && client->game->runtime.richpresence->richpresence);
}
static void rc_client_update_memref_values(rc_client_t* client)
{
rc_memref_t* memref = client->game->runtime.memrefs;
uint32_t value;
static void rc_client_update_memref_values(rc_client_t* client) {
rc_memrefs_t* memrefs = client->game->runtime.memrefs;
rc_memref_list_t* memref_list;
rc_modified_memref_list_t* modified_memref_list;
int invalidated_memref = 0;
for (; memref; memref = memref->next) {
if (memref->value.is_indirect)
continue;
memref_list = &memrefs->memrefs;
do {
rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_stop = memref + memref_list->count;
uint32_t value;
client->state.processing_memref = memref;
for (; memref < memref_stop; ++memref) {
if (memref->value.type == RC_VALUE_TYPE_NONE)
continue;
value = rc_peek_value(memref->address, memref->value.size, client->state.legacy_peek, client);
/* if processing_memref is set, and the memory read fails, all dependent achievements will be disabled */
client->state.processing_memref = memref;
if (client->state.processing_memref) {
rc_update_memref_value(&memref->value, value);
value = rc_peek_value(memref->address, memref->value.size, client->state.legacy_peek, client);
if (client->state.processing_memref) {
rc_update_memref_value(&memref->value, value);
}
else {
/* if the peek function cleared the processing_memref, the memref was invalidated */
invalidated_memref = 1;
}
}
else {
/* if the peek function cleared the processing_memref, the memref was invalidated */
invalidated_memref = 1;
}
}
memref_list = memref_list->next;
} while (memref_list);
client->state.processing_memref = NULL;
modified_memref_list = &memrefs->modified_memrefs;
if (modified_memref_list->count) {
do {
rc_modified_memref_t* modified_memref = modified_memref_list->items;
const rc_modified_memref_t* modified_memref_stop = modified_memref + modified_memref_list->count;
for (; modified_memref < modified_memref_stop; ++modified_memref)
rc_update_memref_value(&modified_memref->memref.value, rc_get_modified_memref_value(modified_memref, client->state.legacy_peek, client));
modified_memref_list = modified_memref_list->next;
} while (modified_memref_list);
}
if (client->game->runtime.richpresence && client->game->runtime.richpresence->richpresence)
rc_update_values(client->game->runtime.richpresence->richpresence->values, client->state.legacy_peek, client, NULL);
if (invalidated_memref)
rc_client_update_active_achievements(client->game);
}
@ -5362,7 +5447,6 @@ void rc_client_do_frame(rc_client_t* client)
rc_client_reset_pending_events(client);
rc_client_update_memref_values(client);
rc_update_variables(client->game->runtime.variables, client->state.legacy_peek, client, NULL);
client->game->progress_tracker.progress = 0.0;
for (subset = client->game->subsets; subset; subset = subset->next) {
@ -5534,9 +5618,8 @@ static void rc_client_reset_richpresence(rc_client_t* client)
static void rc_client_reset_variables(rc_client_t* client)
{
rc_value_t* variable = client->game->runtime.variables;
for (; variable; variable = variable->next)
rc_reset_value(variable);
if (client->game->runtime.richpresence && client->game->runtime.richpresence->richpresence)
rc_reset_values(client->game->runtime.richpresence->richpresence->values);
}
static void rc_client_reset_all(rc_client_t* client)

View File

@ -6,6 +6,24 @@
#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
/* ===== natvis extensions ===== */
typedef struct __rc_client_raintegration_event_enum_t { uint8_t value; } __rc_client_raintegration_event_enum_t;
static void rc_client_raintegration_natvis_helper(void)
{
struct natvis_extensions {
__rc_client_raintegration_event_enum_t raintegration_event_type;
} natvis;
natvis.raintegration_event_type.value = RC_CLIENT_RAINTEGRATION_EVENT_TYPE_NONE;
natvis.raintegration_event_type.value = RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED;
natvis.raintegration_event_type.value = RC_CLIENT_RAINTEGRATION_EVENT_HARDCORE_CHANGED;
natvis.raintegration_event_type.value = RC_CLIENT_RAINTEGRATION_EVENT_PAUSE;
natvis.raintegration_event_type.value = RC_CLIENT_RAINTEGRATION_EVENT_MENU_CHANGED;
}
/* ============================= */
static void rc_client_raintegration_load_dll(rc_client_t* client,
const wchar_t* search_directory, rc_client_callback_t callback, void* callback_userdata)
{
@ -89,6 +107,9 @@ static void rc_client_raintegration_load_dll(rc_client_t* client,
FreeLibrary(hDLL);
callback(RC_ABORTED, "One or more required exports was not found in RA_Integration.dll", client, callback_userdata);
/* dummy reference to natvis helper to ensure extensions get compiled in. */
raintegration->shutdown = rc_client_raintegration_natvis_helper;
}
else {
rc_mutex_lock(&client->state.mutex);

View File

@ -0,0 +1,394 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!-- https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2022 -->
<!-- https://learn.microsoft.com/en-us/visualstudio/debugger/format-specifiers-in-cpp?view=vs-2022 -->
<Type Name="rc_client_user_t">
<DisplayString>{{display_name={display_name,s} score={score}}}</DisplayString>
</Type>
<Type Name="rc_client_game_t">
<DisplayString>{{title={title,s} id={id}}}</DisplayString>
</Type>
<Type Name="rc_client_subset_t">
<DisplayString>{{title={title,s} id={id}}}</DisplayString>
</Type>
<Type Name="__rc_client_achievement_state_enum_t">
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_STATE_INACTIVE">{RC_CLIENT_ACHIEVEMENT_STATE_INACTIVE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE">{RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED">{RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_STATE_DISABLED">{RC_CLIENT_ACHIEVEMENT_STATE_DISABLED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_achievement_category_enum_t">
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_CATEGORY_NONE">{RC_CLIENT_ACHIEVEMENT_CATEGORY_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE">{RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_CATEGORY_UNOFFICIAL">{RC_CLIENT_ACHIEVEMENT_CATEGORY_UNOFFICIAL}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL">{RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_achievement_type_enum_t">
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_TYPE_STANDARD">{RC_CLIENT_ACHIEVEMENT_TYPE_STANDARD}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE">{RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_TYPE_PROGRESSION">{RC_CLIENT_ACHIEVEMENT_TYPE_PROGRESSION}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_TYPE_WIN">{RC_CLIENT_ACHIEVEMENT_TYPE_WIN}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_achievement_bucket_enum_t">
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_UNKNOWN">{RC_CLIENT_ACHIEVEMENT_BUCKET_UNKNOWN}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_LOCKED">{RC_CLIENT_ACHIEVEMENT_BUCKET_LOCKED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_UNLOCKED">{RC_CLIENT_ACHIEVEMENT_BUCKET_UNLOCKED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED">{RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_UNOFFICIAL">{RC_CLIENT_ACHIEVEMENT_BUCKET_UNOFFICIAL}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_RECENTLY_UNLOCKED">{RC_CLIENT_ACHIEVEMENT_BUCKET_RECENTLY_UNLOCKED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_ACTIVE_CHALLENGE">{RC_CLIENT_ACHIEVEMENT_BUCKET_ACTIVE_CHALLENGE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED">{RC_CLIENT_ACHIEVEMENT_BUCKET_ALMOST_THERE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_UNSYNCED">{RC_CLIENT_ACHIEVEMENT_BUCKET_UNSYNCED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_achievement_unlocked_enum_t">
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_UNLOCKED_NONE">{RC_CLIENT_ACHIEVEMENT_UNLOCKED_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE">{RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_UNLOCKED_HARDCORE">{RC_CLIENT_ACHIEVEMENT_UNLOCKED_HARDCORE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_UNLOCKED_BOTH">{RC_CLIENT_ACHIEVEMENT_UNLOCKED_BOTH}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_achievement_t">
<DisplayString>{{title={title,s} id={id}}}</DisplayString>
<Expand>
<Item Name="title">title</Item>
<Item Name="description">description</Item>
<Item Name="points">points</Item>
<Item Name="id">id</Item>
<Item Name="state">*((__rc_client_achievement_state_enum_t*)&amp;state)</Item>
<Item Name="type">*((__rc_client_achievement_type_enum_t*)&amp;state)</Item>
<Item Name="category">*((__rc_client_achievement_category_enum_t*)&amp;category)</Item>
<Item Name="bucket">*((__rc_client_achievement_state_enum_t*)&amp;bucket)</Item>
<Item Name="unlocked">*((__rc_client_achievement_unlocked_enum_t*)&amp;unlocked)</Item>
</Expand>
</Type>
<Type Name="rc_client_achievement_bucket_t">
<DisplayString>{{label={label,s} count={num_achievements}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>num_achievements</Size>
<ValueNode>achievements[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="rc_client_achievement_list_t">
<DisplayString>{{count={num_buckets}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>num_buckets</Size>
<ValueNode>buckets[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="__rc_client_leaderboard_state_enum_t">
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_STATE_INACTIVE">{RC_CLIENT_LEADERBOARD_STATE_INACTIVE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_STATE_ACTIVE">{RC_CLIENT_LEADERBOARD_STATE_ACTIVE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_STATE_TRACKING">{RC_CLIENT_LEADERBOARD_STATE_TRACKING}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_STATE_DISABLED">{RC_CLIENT_LEADERBOARD_STATE_DISABLED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_leaderboard_format_enum_t">
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_FORMAT_TIME">{RC_CLIENT_LEADERBOARD_FORMAT_TIME}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_FORMAT_SCORE">{RC_CLIENT_LEADERBOARD_FORMAT_SCORE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_FORMAT_VALUE">{RC_CLIENT_LEADERBOARD_FORMAT_VALUE}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_leaderboard_t">
<DisplayString>{{title={title,s} id={id}}}</DisplayString>
<Expand>
<Item Name="title">title</Item>
<Item Name="description">description</Item>
<Item Name="tracker_value">tracker_value</Item>
<Item Name="id">id</Item>
<Item Name="state">*((__rc_client_leaderboard_state_enum_t*)&amp;state)</Item>
<Item Name="format">*((__rc_client_leaderboard_format_enum_t*)&amp;format)</Item>
<Item Name="lower_is_better">*((__rc_bool_enum_t*)&amp;lower_is_better)</Item>
</Expand>
</Type>
<Type Name="rc_client_leaderboard_bucket_t">
<DisplayString>{{label={label,s} count={num_leaderboards}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>num_leaderboards</Size>
<ValueNode>leaderboards[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="rc_client_leaderboard_list_t">
<DisplayString>{{count={num_buckets}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>num_buckets</Size>
<ValueNode>buckets[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="rc_client_leaderboard_scoreboard_entry_t">
<DisplayString>{{rank={rank} score={score,s} username={username}}}</DisplayString>
</Type>
<Type Name="rc_client_leaderboard_scoreboard_t">
<DisplayString>{{leaderboard_id={leaderboard_id} num_entries={num_entries}}}</DisplayString>
<Expand>
<Item Name="leaderboard_id">leaderboard_id</Item>
<Item Name="submitted_score">submitted_score</Item>
<Item Name="best_score">best_score</Item>
<Item Name="new_rank">new_rank</Item>
<Item Name="num_entries">num_entries</Item>
<IndexListItems>
<Size>num_top_entries</Size>
<ValueNode>top_entries[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="__rc_client_event_type_enum_t">
<DisplayString Condition="value==RC_CLIENT_EVENT_TYPE_NONE">{RC_CLIENT_EVENT_TYPE_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_ACHIEVEMENT_TRIGGERED">{RC_CLIENT_EVENT_ACHIEVEMENT_TRIGGERED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_STARTED">{RC_CLIENT_EVENT_LEADERBOARD_STARTED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_FAILED">{RC_CLIENT_EVENT_LEADERBOARD_FAILED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_SUBMITTED">{RC_CLIENT_EVENT_LEADERBOARD_SUBMITTED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW">{RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_HIDE">{RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_HIDE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_SHOW">{RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_SHOW}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_HIDE">{RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_HIDE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_UPDATE">{RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_UPDATE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_TRACKER_SHOW">{RC_CLIENT_EVENT_LEADERBOARD_TRACKER_SHOW}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_TRACKER_HIDE">{RC_CLIENT_EVENT_LEADERBOARD_TRACKER_HIDE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_TRACKER_UPDATE">{RC_CLIENT_EVENT_LEADERBOARD_TRACKER_UPDATE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_SCOREBOARD">{RC_CLIENT_EVENT_LEADERBOARD_SCOREBOARD}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_RESET">{RC_CLIENT_EVENT_RESET}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_GAME_COMPLETED">{RC_CLIENT_EVENT_GAME_COMPLETED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_SERVER_ERROR">{RC_CLIENT_EVENT_SERVER_ERROR}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_DISCONNECTED">{RC_CLIENT_EVENT_DISCONNECTED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_RECONNECTED">{RC_CLIENT_EVENT_RECONNECTED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_event_t">
<DisplayString>{{type={*((__rc_client_event_type_enum_t*)&amp;type)}}}</DisplayString>
<Expand>
<Item Name="type">*((__rc_client_event_type_enum_t*)&amp;type)</Item>
<Item Condition="type==RC_CLIENT_EVENT_ACHIEVEMENT_TRIGGERED" Name="achievement">*achievement</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_STARTED" Name="leaderboard">*leaderboard</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_FAILED" Name="leaderboard">*leaderboard</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_SUBMITTED" Name="leaderboard">*leaderboard</Item>
<Item Condition="type==RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW" Name="achievement">*achievement</Item>
<Item Condition="type==RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_HIDE" Name="achievement">*achievement</Item>
<Item Condition="type==RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_SHOW" Name="achievement">*achievement</Item>
<Item Condition="type==RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_HIDE" Name="achievement">*achievement</Item>
<Item Condition="type==RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_UPDATE" Name="achievement">*achievement</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_TRACKER_SHOW" Name="leaderboard_tracker">*leaderboard_tracker</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_TRACKER_HIDE" Name="leaderboard_tracker">*leaderboard_tracker</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_TRACKER_UPDATE" Name="leaderboard_tracker">*leaderboard_tracker</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_SCOREBOARD" Name="leaderboard_scoreboard">*leaderboard_scoreboard</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_SCOREBOARD" Name="leaderboard">*leaderboard</Item>
<Item Condition="type==RC_CLIENT_EVENT_SERVER_ERROR" Name="server_error">*server_error</Item>
</Expand>
</Type>
<Type Name="__rc_client_subset_info_achievements_list_t">
<DisplayString>{{count={info.public_.num_achievements}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>info.public_.num_achievements</Size>
<ValueNode>info.achievements[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="__rc_client_subset_info_leaderboards_list_t">
<DisplayString>{{count={info.public_.num_leaderboards}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>info.public_.num_leaderboards</Size>
<ValueNode>info.leaderboards[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="__rc_client_mastery_state_enum_t">
<DisplayString Condition="value==RC_CLIENT_MASTERY_STATE_NONE">{RC_CLIENT_MASTERY_STATE_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_MASTERY_STATE_PENDING">{RC_CLIENT_MASTERY_STATE_PENDING}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_MASTERY_STATE_SHOWN">{RC_CLIENT_MASTERY_STATE_SHOWN}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_subset_info_t">
<DisplayString>{{title={public_.title,s} id={public_.id}}}</DisplayString>
<Expand>
<Item Name="public_">public_</Item>
<Item Name="active">*((__rc_bool_enum_t*)&amp;active)</Item>
<Item Name="mastery">*((__rc_client_mastery_state_enum_t*)&amp;mastery)</Item>
<Item Name="achievements">*((__rc_client_subset_info_achievements_list_t*)this)</Item>
<Item Name="leaderboards">*((__rc_client_subset_info_leaderboards_list_t*)this)</Item>
</Expand>
</Type>
<Type Name="__rc_client_leaderboard_tracker_list_t">
<DisplayString Condition="first==0">{{NULL}}</DisplayString>
<DisplayString>{(void**)&amp;first,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="__rc_client_subset_info_list_t">
<DisplayString Condition="first==0">{{NULL}}</DisplayString>
<DisplayString>{(void**)&amp;first,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="__rc_client_media_hash_list_t">
<DisplayString Condition="first==0">{{NULL}}</DisplayString>
<DisplayString>{(void**)&amp;first,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="rc_client_achievement_info_t">
<DisplayString>{{title={public_.title,s} id={public_.id}}}</DisplayString>
</Type>
<Type Name="rc_client_leaderboard_info_t">
<DisplayString>{{title={public_.title,s} id={public_.id}}}</DisplayString>
</Type>
<Type Name="rc_client_game_info_t">
<DisplayString>{{title={public_.title,s} id={public_.id}}}</DisplayString>
<Expand>
<Item Name="public_">public_</Item>
<Item Name="subsets">*((__rc_client_subset_info_list_t*)&amp;subsets)</Item>
<Item Name="media_hash">*((__rc_client_media_hash_list_t*)&amp;media_hash)</Item>
<Item Name="leaderboard_trackers">*((__rc_client_leaderboard_tracker_list_t*)&amp;leaderboard_trackers)</Item>
<Item Name="progress_tracker">progress_tracker</Item>
<Item Name="runtime">runtime</Item>
</Expand>
</Type>
<Type Name="rc_client_game_hash_t">
<DisplayString>{{hash={hash,s} game_id={game_id}}}</DisplayString>
</Type>
<Type Name="__rc_client_game_hash_list_t">
<DisplayString>{client.hashes}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>client.hashes</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="__rc_client_load_game_state_enum_t">
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_NONE">{RC_CLIENT_LOAD_GAME_STATE_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_IDENTIFYING_GAME">{RC_CLIENT_LOAD_GAME_STATE_IDENTIFYING_GAME}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_AWAIT_LOGIN">{RC_CLIENT_LOAD_GAME_STATE_AWAIT_LOGIN}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_FETCHING_GAME_DATA">{RC_CLIENT_LOAD_GAME_STATE_FETCHING_GAME_DATA}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_STARTING_SESSION">{RC_CLIENT_LOAD_GAME_STATE_STARTING_SESSION}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_DONE">{RC_CLIENT_LOAD_GAME_STATE_DONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_ABORTED">{RC_CLIENT_LOAD_GAME_STATE_ABORTED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_load_state_t">
<Expand>
<Item Name="progress">*((__rc_client_load_game_state_enum_t*)&amp;progress)</Item>
<Item Name="game">*game</Item>
<Item Name="subset">subset</Item>
<Item Name="hash">*hash</Item>
<Item Name="pending_media">pending_media</Item>
<Item Name="start_session_response">start_session_response</Item>
<Item Name="outstanding_requests">(int)outstanding_requests</Item>
</Expand>
</Type>
<Type Name="rc_client_scheduled_callback_data_t">
<DisplayString>{{when={when} callback={callback,na}}}</DisplayString>
</Type>
<Type Name="__rc_client_scheduled_callback_list_t">
<DisplayString>{state.scheduled_callbacks}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>state.scheduled_callbacks</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="__rc_client_log_level_enum_t">
<DisplayString Condition="value==RC_CLIENT_LOG_LEVEL_NONE">{RC_CLIENT_LOG_LEVEL_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOG_LEVEL_ERROR">{RC_CLIENT_LOG_LEVEL_ERROR}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOG_LEVEL_WARN">{RC_CLIENT_LOG_LEVEL_WARN}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOG_LEVEL_INFO">{RC_CLIENT_LOG_LEVEL_INFO}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOG_LEVEL_VERBOSE">{RC_CLIENT_LOG_LEVEL_VERBOSE}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_user_state_enum_t">
<DisplayString Condition="value==RC_CLIENT_USER_STATE_NONE">{RC_CLIENT_USER_STATE_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_USER_STATE_LOGIN_REQUESTED">{RC_CLIENT_USER_STATE_LOGIN_REQUESTED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_USER_STATE_LOGGED_IN">{RC_CLIENT_USER_STATE_LOGGED_IN}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_spectator_mode_enum_t">
<DisplayString Condition="value==RC_CLIENT_SPECTATOR_MODE_OFF">{RC_CLIENT_SPECTATOR_MODE_OFF}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_SPECTATOR_MODE_ON">{RC_CLIENT_SPECTATOR_MODE_ON}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_SPECTATOR_MODE_LOCKED">{RC_CLIENT_SPECTATOR_MODE_LOCKED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_disconnect_enum_t">
<DisplayString Condition="value==RC_CLIENT_DISCONNECT_HIDDEN">{RC_CLIENT_DISCONNECT_HIDDEN}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_DISCONNECT_VISIBLE">{RC_CLIENT_DISCONNECT_VISIBLE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_DISCONNECT_SHOW_PENDING">{RC_CLIENT_DISCONNECT_SHOW_PENDING}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_DISCONNECT_HIDE_PENDING">{RC_CLIENT_DISCONNECT_HIDE_PENDING}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_DISCONNECT_VISIBLE|RC_CLIENT_DISCONNECT_HIDE_PENDING">{RC_CLIENT_DISCONNECT_VISIBLE|RC_CLIENT_DISCONNECT_HIDE_PENDING}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_state_t">
<Expand>
<Item Name="hardcore">*((__rc_bool_enum_t*)&amp;hardcore)</Item>
<Item Name="unofficial_enabled">*((__rc_bool_enum_t*)&amp;unofficial_enabled)</Item>
<Item Name="encore_mode">*((__rc_bool_enum_t*)&amp;encore_mode)</Item>
<Item Name="spectator_mode">*((__rc_client_spectator_mode_enum_t*)&amp;spectator_mode)</Item>
<Item Name="disconnect">*((__rc_client_disconnect_enum_t*)&amp;disconnect)</Item>
<Item Name="log_level">*((__rc_client_log_level_enum_t*)&amp;log_level)</Item>
<Item Name="user">*((__rc_client_user_state_enum_t*)&amp;user)</Item>
<Item Name="scheduled_callbacks">*((__rc_client_scheduled_callback_list_t*)this)</Item>
<Item Name="load">load</Item>
</Expand>
</Type>
<Type Name="rc_client_t">
<Expand>
<Item Name="game">game</Item>
<Item Name="hashes">*((__rc_client_game_hash_list_t*)&amp;hashes)</Item>
<Item Name="user">user</Item>
<Item Name="callbacks">callbacks</Item>
<Item Name="state">state</Item>
</Expand>
</Type>
<Type Name="rc_client_raintegration_menu_t">
<DisplayString>{{count={num_items}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>num_items</Size>
<ValueNode>items[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="__rc_client_raintegration_event_enum_t">
<DisplayString Condition="value==RC_CLIENT_RAINTEGRATION_EVENT_TYPE_NONE">{RC_CLIENT_RAINTEGRATION_EVENT_TYPE_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED">{RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_RAINTEGRATION_EVENT_HARDCORE_CHANGED">{RC_CLIENT_RAINTEGRATION_EVENT_HARDCORE_CHANGED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_RAINTEGRATION_EVENT_PAUSE">{RC_CLIENT_RAINTEGRATION_EVENT_PAUSE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_RAINTEGRATION_EVENT_MENU_CHANGED">{RC_CLIENT_RAINTEGRATION_EVENT_MENU_CHANGED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_raintegration_event_t">
<DisplayString>{{type={*((__rc_client_raintegration_event_enum_t*)&amp;type)}}}</DisplayString>
<Expand>
<Item Name="type">*((__rc_client_raintegration_event_enum_t*)&amp;type)</Item>
<Item Condition="type==RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED" Name="menu_item">menu_item</Item>
</Expand>
</Type>
</AutoVisualizer>

View File

@ -1,5 +1,15 @@
#if !defined(RC_NO_THREADS) && !defined(_WIN32) && !defined(GEKKO) && !defined(_3DS) && (!defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE - 0) < 500)
/* We'll want to use pthread_mutexattr_settype/PTHREAD_MUTEX_RECURSIVE, but glibc only conditionally exposes pthread_mutexattr_settype and PTHREAD_MUTEX_RECURSIVE depending on feature flags
* Defining _XOPEN_SOURCE must be done at the top of the source file, before including any headers
* pthread_mutexattr_settype/PTHREAD_MUTEX_RECURSIVE are specified the Single UNIX Specification (Version 2, 1997), along with POSIX later on (IEEE Standard 1003.1-2008), so should cover practically any pthread implementation
*/
#undef _XOPEN_SOURCE
#define _XOPEN_SOURCE 500
#endif
#include "rc_compat.h"
#include <assert.h>
#include <ctype.h>
#include <stdarg.h>
@ -58,7 +68,7 @@ int rc_snprintf(char* buffer, size_t size, const char* format, ...)
va_start(args, format);
#ifdef __STDC_WANT_SECURE_LIB__
#ifdef __STDC_SECURE_LIB__
result = vsprintf_s(buffer, size, format, args);
#else
/* assume buffer is large enough and ignore size */
@ -73,7 +83,7 @@ int rc_snprintf(char* buffer, size_t size, const char* format, ...)
#endif
#ifndef __STDC_WANT_SECURE_LIB__
#ifndef __STDC_SECURE_LIB__
struct tm* rc_gmtime_s(struct tm* buf, const time_t* timer)
{
@ -88,61 +98,138 @@ struct tm* rc_gmtime_s(struct tm* buf, const time_t* timer)
#if defined(_WIN32)
/* https://gist.github.com/roxlu/1c1af99f92bafff9d8d9 */
/* https://learn.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c */
/* implementation largely taken from https://github.com/libsdl-org/SDL/blob/0fc3574/src/thread/windows/SDL_sysmutex.c */
#if defined(WINVER) && WINVER >= 0x0600
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
void rc_mutex_init(rc_mutex_t* mutex)
{
/* default security, not owned by calling thread, unnamed */
mutex->handle = CreateMutex(NULL, FALSE, NULL);
InitializeSRWLock(&mutex->srw_lock);
/* https://learn.microsoft.com/en-us/windows/win32/procthread/thread-handles-and-identifiers */
/* thread ids are never 0 */
mutex->owner = 0;
mutex->count = 0;
}
void rc_mutex_destroy(rc_mutex_t* mutex)
{
CloseHandle(mutex->handle);
/* Nothing to do here */
(void)mutex;
}
void rc_mutex_lock(rc_mutex_t* mutex)
{
WaitForSingleObject(mutex->handle, 0xFFFFFFFF);
DWORD current_thread = GetCurrentThreadId();
if (mutex->owner == current_thread) {
++mutex->count;
assert(mutex->count > 0);
}
else {
AcquireSRWLockExclusive(&mutex->srw_lock);
assert(mutex->owner == 0 && mutex->count == 0);
mutex->owner = current_thread;
mutex->count = 1;
}
}
void rc_mutex_unlock(rc_mutex_t* mutex)
{
ReleaseMutex(mutex->handle);
if (mutex->owner == GetCurrentThreadId()) {
assert(mutex->count > 0);
if (--mutex->count == 0) {
mutex->owner = 0;
ReleaseSRWLockExclusive(&mutex->srw_lock);
}
}
else {
assert(!"Tried to unlock unowned mutex");
}
}
#else
void rc_mutex_init(rc_mutex_t* mutex)
{
InitializeCriticalSection(&mutex->critical_section);
}
void rc_mutex_destroy(rc_mutex_t* mutex)
{
DeleteCriticalSection(&mutex->critical_section);
}
void rc_mutex_lock(rc_mutex_t* mutex)
{
EnterCriticalSection(&mutex->critical_section);
}
void rc_mutex_unlock(rc_mutex_t* mutex)
{
LeaveCriticalSection(&mutex->critical_section);
}
#endif
#elif defined(GEKKO)
/* https://github.com/libretro/RetroArch/pull/16116 */
void rc_mutex_init(rc_mutex_t* mutex)
{
LWP_MutexInit(mutex, NULL);
/* LWP_MutexInit has the handle passed by reference */
/* Other LWP_Mutex* calls have the handle passed by value */
LWP_MutexInit(&mutex->handle, 1);
}
void rc_mutex_destroy(rc_mutex_t* mutex)
{
LWP_MutexDestroy(mutex);
LWP_MutexDestroy(mutex->handle);
}
void rc_mutex_lock(rc_mutex_t* mutex)
{
LWP_MutexLock(mutex);
LWP_MutexLock(mutex->handle);
}
void rc_mutex_unlock(rc_mutex_t* mutex)
{
LWP_MutexUnlock(mutex);
LWP_MutexUnlock(mutex->handle);
}
#elif defined(_3DS)
void rc_mutex_init(rc_mutex_t* mutex)
{
RecursiveLock_Init(mutex);
}
void rc_mutex_destroy(rc_mutex_t* mutex)
{
/* Nothing to do here */
(void)mutex;
}
void rc_mutex_lock(rc_mutex_t* mutex)
{
RecursiveLock_Lock(mutex);
}
void rc_mutex_unlock(rc_mutex_t* mutex)
{
RecursiveLock_Unlock(mutex);
}
#else
void rc_mutex_init(rc_mutex_t* mutex)
{
pthread_mutex_init(mutex, NULL);
/* Define the mutex as recursive, for consistent semantics against other rc_mutex_t implementations */
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(mutex, &attr);
pthread_mutexattr_destroy(&attr);
}
void rc_mutex_destroy(rc_mutex_t* mutex)

View File

@ -1,6 +1,13 @@
#ifndef RC_COMPAT_H
#define RC_COMPAT_H
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif
#include "rc_export.h"
#include <stdio.h>
@ -58,7 +65,7 @@ RC_BEGIN_C_DECLS
#endif /* __STDC_VERSION__ < 199901L */
#ifndef __STDC_WANT_SECURE_LIB__
#ifndef __STDC_SECURE_LIB__
/* _CRT_SECURE_NO_WARNINGS redefinitions */
#define strcpy_s(dest, sz, src) strcpy(dest, src)
#define sscanf_s sscanf
@ -77,10 +84,27 @@ RC_BEGIN_C_DECLS
#define rc_mutex_lock(mutex)
#define rc_mutex_unlock(mutex)
#else
#ifdef _WIN32
#if defined(_WIN32)
typedef struct rc_mutex_t {
#if defined(WINVER) && WINVER >= 0x0600
/* Windows Vista and later can use a slim reader/writer (SRW) lock */
SRWLOCK srw_lock;
/* Current thread owner needs to be tracked (for recursive mutex usage) */
DWORD owner;
DWORD count;
#else
/* Pre-Vista must use a critical section */
CRITICAL_SECTION critical_section;
#endif
} rc_mutex_t;
#elif defined(GEKKO)
#include <ogcsys.h>
typedef struct rc_mutex_t {
void* handle; /* HANDLE is defined as "void*" */
mutex_t handle;
} rc_mutex_t;
#elif defined(_3DS)
#include <3ds/synchronization.h>
typedef RecursiveLock rc_mutex_t;
#else
#include <pthread.h>
typedef pthread_mutex_t rc_mutex_t;

View File

@ -124,7 +124,7 @@ static const rc_disallowed_setting_t _rc_disallowed_neocd_settings[] = {
};
static const rc_disallowed_setting_t _rc_disallowed_pcsx_rearmed_settings[] = {
{ "pcsx_rearmed_psxclock", "<55" },
{ "pcsx_rearmed_psxclock", ",!auto,<55" },
{ "pcsx_rearmed_region", "pal" },
{ NULL, NULL }
};
@ -202,14 +202,14 @@ static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
{ NULL, NULL }
};
static int rc_libretro_string_equal_nocase_wildcard(const char* test, const char* value) {
static int rc_libretro_string_equal_nocase_wildcard(const char* test, const char* match) {
char c1, c2;
while ((c1 = *test++)) {
if (tolower(c1) != tolower(c2 = *value++) && c2 != '?')
if (tolower(c1) != tolower(c2 = *match++) && c2 != '?')
return (c2 == '*');
}
return (*value == '\0');
return (*match == '\0');
}
static int rc_libretro_numeric_less_than(const char* test, const char* value) {
@ -218,7 +218,50 @@ static int rc_libretro_numeric_less_than(const char* test, const char* value) {
return (test_num < value_num);
}
static int rc_libretro_match_token(const char* val, const char* token, size_t size, int* result) {
if (*token == '!') {
/* !X => if X is a match, it's explicitly allowed. match with result = false */
if (rc_libretro_match_token(val, token + 1, size - 1, result)) {
*result = 0;
return 1;
}
}
if (*token == '<') {
/* if val < token, match with result = true */
char buffer[128];
memcpy(buffer, token + 1, size - 1);
buffer[size - 1] = '\0';
if (rc_libretro_numeric_less_than(val, buffer)) {
*result = 1;
return 1;
}
}
if (memcmp(token, val, size) == 0 && val[size] == 0) {
/* exact match, match with result = true */
*result = 1;
return 1;
}
else {
/* check for case insensitive match */
char buffer[128];
memcpy(buffer, token, size);
buffer[size] = '\0';
if (rc_libretro_string_equal_nocase_wildcard(val, buffer)) {
/* case insensitive match, match with result = true */
*result = 1;
return 1;
}
}
/* no match */
return 0;
}
static int rc_libretro_match_value(const char* val, const char* match) {
int result = 0;
/* if value starts with a comma, it's a CSV list of potential matches */
if (*match == ',') {
do {
@ -229,33 +272,23 @@ static int rc_libretro_match_value(const char* val, const char* match) {
++match;
size = match - ptr;
if (val[size] == '\0') {
if (memcmp(ptr, val, size) == 0) {
return 1;
}
else {
char buffer[128];
memcpy(buffer, ptr, size);
buffer[size] = '\0';
if (rc_libretro_string_equal_nocase_wildcard(buffer, val))
return 1;
}
}
} while (*match == ',');
if (rc_libretro_match_token(val, ptr, size, &result))
return result;
return 0;
} while (*match == ',');
}
else {
/* a leading exclamation point means the provided value(s) are not forbidden (are allowed) */
if (*match == '!')
return !rc_libretro_match_value(val, &match[1]);
/* just a single value, attempt to match it */
if (rc_libretro_match_token(val, match, strlen(match), &result))
return result;
}
/* a leading exclamation point means the provided value(s) are not forbidden (are allowed) */
if (*match == '!')
return !rc_libretro_match_value(val, &match[1]);
/* a leading less tahn means the provided value is the minimum allowed */
if (*match == '<')
return rc_libretro_numeric_less_than(val, &match[1]);
/* just a single value, attempt to match it */
return rc_libretro_string_equal_nocase_wildcard(val, match);
/* value did not match filters, assume it's allowed */
return 0;
}
int rc_libretro_is_setting_allowed(const rc_disallowed_setting_t* disallowed_settings, const char* setting, const char* value) {

View File

@ -38,6 +38,9 @@ void rc_buffer_destroy(rc_buffer_t* buffer)
total += (int)(chunk->end - chunk->start);
wasted += (int)(chunk->end - chunk->write);
++count;
#endif
#ifdef DEBUG_BUFFERS
printf("< free %p.%p\n", (void*)buffer, (void*)chunk);
#endif
free(chunk);
chunk = next;
@ -70,6 +73,10 @@ uint8_t* rc_buffer_reserve(rc_buffer_t* buffer, size_t amount)
if (!chunk->next)
break;
#ifdef DEBUG_BUFFERS
printf("> alloc %p.%p\n", (void*)buffer, (void*)chunk->next);
#endif
chunk->next->start = (uint8_t*)chunk->next + chunk_header_size;
chunk->next->write = chunk->next->start;
chunk->next->end = (uint8_t*)chunk->next + alloc_size;

View File

@ -35,11 +35,11 @@ void* rc_alloc(void* pointer, int32_t* offset, uint32_t size, uint32_t alignment
if (pointer != 0) {
/* valid buffer, grab the next chunk */
ptr = (void*)((char*)pointer + *offset);
ptr = (void*)((uint8_t*)pointer + *offset);
}
else if (scratch != 0 && scratch_object_pointer_offset < sizeof(scratch->objs)) {
/* only allocate one instance of each object type (indentified by scratch_object_pointer_offset) */
void** scratch_object_pointer = (void**)((char*)&scratch->objs + scratch_object_pointer_offset);
void** scratch_object_pointer = (void**)((uint8_t*)&scratch->objs + scratch_object_pointer_offset);
ptr = *scratch_object_pointer;
if (!ptr) {
int32_t used;
@ -94,22 +94,223 @@ char* rc_alloc_str(rc_parse_state_t* parse, const char* text, size_t length) {
return ptr;
}
void rc_init_preparse_state(rc_preparse_state_t* preparse, lua_State* L, int funcs_ndx)
{
rc_init_parse_state(&preparse->parse, NULL, L, funcs_ndx);
rc_init_parse_state_memrefs(&preparse->parse, &preparse->memrefs);
}
void rc_destroy_preparse_state(rc_preparse_state_t* preparse)
{
rc_destroy_parse_state(&preparse->parse);
}
void rc_preparse_alloc_memrefs(rc_memrefs_t* memrefs, rc_preparse_state_t* preparse)
{
const uint32_t num_memrefs = rc_memrefs_count_memrefs(&preparse->memrefs);
const uint32_t num_modified_memrefs = rc_memrefs_count_modified_memrefs(&preparse->memrefs);
if (preparse->parse.offset < 0)
return;
if (memrefs) {
memset(memrefs, 0, sizeof(*memrefs));
preparse->parse.memrefs = memrefs;
}
if (num_memrefs) {
rc_memref_t* memref_items = RC_ALLOC_ARRAY(rc_memref_t, num_memrefs, &preparse->parse);
if (memrefs) {
memrefs->memrefs.capacity = num_memrefs;
memrefs->memrefs.items = memref_items;
}
}
if (num_modified_memrefs) {
rc_modified_memref_t* modified_memref_items =
RC_ALLOC_ARRAY(rc_modified_memref_t, num_modified_memrefs, &preparse->parse);
if (memrefs) {
memrefs->modified_memrefs.capacity = num_modified_memrefs;
memrefs->modified_memrefs.items = modified_memref_items;
}
}
/* when preparsing, this structure will be allocated at the end. when it's allocated earlier
* in the buffer, it could be followed by something aligned at 8 bytes. force the offset to
* an 8-byte boundary */
if (!memrefs) {
rc_alloc(preparse->parse.buffer, &preparse->parse.offset, 0, 8, &preparse->parse.scratch, 0);
}
}
static uint32_t rc_preparse_array_size(uint32_t needed, uint32_t minimum)
{
while (minimum < needed)
minimum <<= 1;
return minimum;
}
void rc_preparse_reserve_memrefs(rc_preparse_state_t* preparse, rc_memrefs_t* memrefs)
{
uint32_t num_memrefs = rc_memrefs_count_memrefs(&preparse->memrefs);
uint32_t num_modified_memrefs = rc_memrefs_count_modified_memrefs(&preparse->memrefs);
uint32_t available;
if (preparse->parse.offset < 0)
return;
if (num_memrefs) {
rc_memref_list_t* memref_list = &memrefs->memrefs;
while (memref_list->count == memref_list->capacity) {
if (!memref_list->next)
break;
memref_list = memref_list->next;
}
available = memref_list->capacity - memref_list->count;
if (available < num_memrefs) {
rc_memref_list_t* new_memref_list = (rc_memref_list_t*)calloc(1, sizeof(rc_memref_list_t));
if (!new_memref_list)
return;
new_memref_list->capacity = rc_preparse_array_size(num_memrefs - available, 16);
new_memref_list->items = (rc_memref_t*)malloc(new_memref_list->capacity * sizeof(rc_memref_t));
new_memref_list->allocated = 1;
memref_list->next = new_memref_list;
}
}
if (num_modified_memrefs) {
rc_modified_memref_list_t* modified_memref_list = &memrefs->modified_memrefs;
while (modified_memref_list->count == modified_memref_list->capacity) {
if (!modified_memref_list->next)
break;
modified_memref_list = modified_memref_list->next;
}
available = modified_memref_list->capacity - modified_memref_list->count;
if (available < num_modified_memrefs) {
rc_modified_memref_list_t* new_modified_memref_list = (rc_modified_memref_list_t*)calloc(1, sizeof(rc_modified_memref_list_t));
if (!new_modified_memref_list)
return;
new_modified_memref_list->capacity = rc_preparse_array_size(num_modified_memrefs - available, 8);
new_modified_memref_list->items = (rc_modified_memref_t*)malloc(new_modified_memref_list->capacity * sizeof(rc_modified_memref_t));
new_modified_memref_list->allocated = 1;
modified_memref_list->next = new_modified_memref_list;
}
}
preparse->parse.memrefs = memrefs;
}
static void rc_preparse_sync_operand(rc_operand_t* operand, rc_parse_state_t* parse, const rc_memrefs_t* memrefs)
{
if (rc_operand_is_memref(operand) || rc_operand_is_recall(operand)) {
const rc_memref_t* src_memref = operand->value.memref;
if (src_memref->value.memref_type == RC_MEMREF_TYPE_MODIFIED_MEMREF) {
const rc_modified_memref_list_t* modified_memref_list = &memrefs->modified_memrefs;
for (; modified_memref_list; modified_memref_list = modified_memref_list->next) {
const rc_modified_memref_t* modified_memref = modified_memref_list->items;
const rc_modified_memref_t* modified_memref_end = modified_memref + modified_memref_list->count;
for (; modified_memref < modified_memref_end; ++modified_memref) {
if ((const rc_modified_memref_t*)src_memref == modified_memref) {
rc_modified_memref_t* dst_modified_memref = rc_alloc_modified_memref(parse, modified_memref->memref.value.size,
&modified_memref->parent, modified_memref->modifier_type, &modified_memref->modifier);
operand->value.memref = &dst_modified_memref->memref;
return;
}
}
}
}
else {
const rc_memref_list_t* memref_list = &memrefs->memrefs;
for (; memref_list; memref_list = memref_list->next) {
const rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_end = memref + memref_list->count;
for (; memref < memref_end; ++memref) {
if (src_memref == memref) {
operand->value.memref = rc_alloc_memref(parse, memref->address, memref->value.size);
return;
}
}
}
}
}
}
void rc_preparse_copy_memrefs(rc_parse_state_t* parse, rc_memrefs_t* memrefs)
{
const rc_memref_list_t* memref_list = &memrefs->memrefs;
const rc_modified_memref_list_t* modified_memref_list = &memrefs->modified_memrefs;
for (; memref_list; memref_list = memref_list->next) {
const rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_end = memref + memref_list->count;
for (; memref < memref_end; ++memref)
rc_alloc_memref(parse, memref->address, memref->value.size);
}
for (; modified_memref_list; modified_memref_list = modified_memref_list->next) {
rc_modified_memref_t* modified_memref = modified_memref_list->items;
const rc_modified_memref_t* modified_memref_end = modified_memref + modified_memref_list->count;
for (; modified_memref < modified_memref_end; ++modified_memref) {
rc_preparse_sync_operand(&modified_memref->parent, parse, memrefs);
rc_preparse_sync_operand(&modified_memref->modifier, parse, memrefs);
rc_alloc_modified_memref(parse, modified_memref->memref.value.size,
&modified_memref->parent, modified_memref->modifier_type, &modified_memref->modifier);
}
}
}
void rc_reset_parse_state(rc_parse_state_t* parse, void* buffer, lua_State* L, int funcs_ndx)
{
#ifndef RC_DISABLE_LUA
parse->L = L;
parse->funcs_ndx = funcs_ndx;
#else
(void)L;
(void)funcs_ndx;
#endif
parse->buffer = buffer;
parse->offset = 0;
parse->memrefs = NULL;
parse->existing_memrefs = NULL;
parse->variables = NULL;
parse->measured_target = 0;
parse->lines_read = 0;
parse->addsource_oper = RC_OPERATOR_NONE;
parse->addsource_parent.type = RC_OPERAND_NONE;
parse->indirect_parent.type = RC_OPERAND_NONE;
parse->remember.type = RC_OPERAND_NONE;
parse->is_value = 0;
parse->has_required_hits = 0;
parse->measured_as_percent = 0;
parse->scratch.strings = NULL;
}
void rc_init_parse_state(rc_parse_state_t* parse, void* buffer, lua_State* L, int funcs_ndx)
{
/* could use memset here, but rc_parse_state_t contains a 512 byte buffer that doesn't need to be initialized */
parse->offset = 0;
parse->L = L;
parse->funcs_ndx = funcs_ndx;
parse->buffer = buffer;
parse->scratch.strings = NULL;
rc_buffer_init(&parse->scratch.buffer);
memset(&parse->scratch.objs, 0, sizeof(parse->scratch.objs));
parse->first_memref = 0;
parse->variables = 0;
parse->measured_target = 0;
parse->lines_read = 0;
parse->has_required_hits = 0;
parse->measured_as_percent = 0;
rc_reset_parse_state(parse, buffer, L, funcs_ndx);
}
void rc_destroy_parse_state(rc_parse_state_t* parse)

View File

@ -1,6 +1,7 @@
#include "rc_internal.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
static int rc_test_condition_compare(uint32_t value1, uint32_t value2, uint8_t oper) {
@ -15,7 +16,7 @@ static int rc_test_condition_compare(uint32_t value1, uint32_t value2, uint8_t o
}
}
static char rc_condition_determine_comparator(const rc_condition_t* self) {
static uint8_t rc_condition_determine_comparator(const rc_condition_t* self) {
switch (self->oper) {
case RC_OPERATOR_EQ:
case RC_OPERATOR_NE:
@ -31,7 +32,8 @@ static char rc_condition_determine_comparator(const rc_condition_t* self) {
}
if ((self->operand1.type == RC_OPERAND_ADDRESS || self->operand1.type == RC_OPERAND_DELTA) &&
!self->operand1.value.memref->value.is_indirect && !rc_operand_is_float(&self->operand1)) {
/* TODO: allow modified memref comparisons */
self->operand1.value.memref->value.memref_type == RC_MEMREF_TYPE_MEMREF && !rc_operand_is_float(&self->operand1)) {
/* left side is an integer memory reference */
int needs_translate = (self->operand1.size != self->operand1.value.memref->value.size);
@ -43,7 +45,7 @@ static char rc_condition_determine_comparator(const rc_condition_t* self) {
return needs_translate ? RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED : RC_PROCESSING_COMPARE_DELTA_TO_CONST;
}
else if ((self->operand2.type == RC_OPERAND_ADDRESS || self->operand2.type == RC_OPERAND_DELTA) &&
!self->operand2.value.memref->value.is_indirect && !rc_operand_is_float(&self->operand2)) {
self->operand2.value.memref->value.memref_type == RC_MEMREF_TYPE_MEMREF && !rc_operand_is_float(&self->operand2)) {
/* right side is an integer memory reference */
const int is_same_memref = (self->operand1.value.memref == self->operand2.value.memref);
needs_translate |= (self->operand2.size != self->operand2.value.memref->value.size);
@ -161,17 +163,45 @@ static int rc_parse_operator(const char** memaddr) {
}
}
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, uint8_t is_indirect) {
rc_condition_t* self;
void rc_condition_convert_to_operand(const rc_condition_t* condition, rc_operand_t* operand, rc_parse_state_t* parse) {
if (condition->oper == RC_OPERATOR_NONE) {
if (operand != &condition->operand1)
memcpy(operand, &condition->operand1, sizeof(*operand));
}
else {
uint8_t new_size = RC_MEMSIZE_32_BITS;
if (rc_operand_is_float(&condition->operand1) || rc_operand_is_float(&condition->operand2))
new_size = RC_MEMSIZE_FLOAT;
/* NOTE: this makes the operand include the modification, but we have to also
* leave the modification in the condition so the condition reflects the actual
* definition. This doesn't affect the evaluation logic since this method is only
* called for combining conditions and Measured, and the Measured handling function
* ignores the operator assuming it's been handled by a modified memref chain */
operand->value.memref = (rc_memref_t*)rc_alloc_modified_memref(parse,
new_size, &condition->operand1, condition->oper, &condition->operand2);
/* not actually an address, just a non-delta memref read */
operand->type = operand->memref_access_type = RC_OPERAND_ADDRESS;
operand->size = new_size;
}
}
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse) {
rc_condition_t * self = RC_ALLOC(rc_condition_t, parse);
rc_parse_condition_internal(self, memaddr, parse);
return (parse->offset < 0) ? NULL : self;
}
void rc_parse_condition_internal(rc_condition_t* self, const char** memaddr, rc_parse_state_t* parse) {
const char* aux;
int result;
int can_modify = 0;
aux = *memaddr;
self = RC_ALLOC(rc_condition_t, parse);
self->current_hits = 0;
self->is_true = 0;
self->pause = 0;
self->optimized_comparator = RC_PROCESSING_COMPARE_DEFAULT;
if (*aux != 0 && aux[1] == ':') {
@ -194,8 +224,11 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
parse->measured_as_percent = 1;
self->type = RC_CONDITION_MEASURED;
break;
/* e f h j l s u v w x y */
default: parse->offset = RC_INVALID_CONDITION_TYPE; return 0;
default:
parse->offset = RC_INVALID_CONDITION_TYPE;
return;
}
aux += 2;
@ -204,79 +237,63 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
self->type = RC_CONDITION_STANDARD;
}
result = rc_parse_operand(&self->operand1, &aux, is_indirect, parse);
result = rc_parse_operand(&self->operand1, &aux, parse);
if (result < 0) {
parse->offset = result;
return 0;
return;
}
result = rc_parse_operator(&aux);
if (result < 0) {
parse->offset = result;
return 0;
return;
}
self->oper = (char)result;
switch (self->oper) {
case RC_OPERATOR_NONE:
/* non-modifying statements must have a second operand */
if (!can_modify) {
/* measured does not require a second operand when used in a value */
if (self->type != RC_CONDITION_MEASURED) {
parse->offset = RC_INVALID_OPERATOR;
return 0;
}
self->oper = (uint8_t)result;
if (self->oper == RC_OPERATOR_NONE) {
/* non-modifying statements must have a second operand */
if (!can_modify) {
/* measured does not require a second operand when used in a value */
if (self->type != RC_CONDITION_MEASURED) {
parse->offset = RC_INVALID_OPERATOR;
return;
}
}
/* provide dummy operand of '1' and no required hits */
self->operand2.type = RC_OPERAND_CONST;
self->operand2.value.num = 1;
self->required_hits = 0;
*memaddr = aux;
return self;
/* provide dummy operand of '1' and no required hits */
rc_operand_set_const(&self->operand2, 1);
self->required_hits = 0;
*memaddr = aux;
return;
}
case RC_OPERATOR_MULT:
case RC_OPERATOR_DIV:
case RC_OPERATOR_AND:
case RC_OPERATOR_XOR:
case RC_OPERATOR_MOD:
case RC_OPERATOR_ADD:
case RC_OPERATOR_SUB:
/* modifying operators are only valid on modifying statements */
if (can_modify)
if (can_modify && !rc_operator_is_modifying(self->oper)) {
/* comparison operators are not valid on modifying statements */
switch (self->type) {
case RC_CONDITION_ADD_SOURCE:
case RC_CONDITION_SUB_SOURCE:
case RC_CONDITION_ADD_ADDRESS:
case RC_CONDITION_REMEMBER:
/* prevent parse errors on legacy achievements where a condition was present before changing the type */
self->oper = RC_OPERATOR_NONE;
break;
/* fallthrough */
default:
/* comparison operators are not valid on modifying statements */
if (can_modify) {
switch (self->type) {
case RC_CONDITION_ADD_SOURCE:
case RC_CONDITION_SUB_SOURCE:
case RC_CONDITION_ADD_ADDRESS:
case RC_CONDITION_REMEMBER:
/* prevent parse errors on legacy achievements where a condition was present before changing the type */
self->oper = RC_OPERATOR_NONE;
break;
default:
parse->offset = RC_INVALID_OPERATOR;
return 0;
}
}
break;
default:
parse->offset = RC_INVALID_OPERATOR;
return;
}
}
result = rc_parse_operand(&self->operand2, &aux, is_indirect, parse);
result = rc_parse_operand(&self->operand2, &aux, parse);
if (result < 0) {
parse->offset = result;
return 0;
return;
}
if (self->oper == RC_OPERATOR_NONE) {
/* if operator is none, explicitly clear out the right side */
self->operand2.type = RC_OPERAND_CONST;
self->operand2.value.num = 0;
rc_operand_set_const(&self->operand2, 0);
}
if (*aux == '(') {
@ -285,7 +302,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
if (end == aux || *end != ')') {
parse->offset = RC_INVALID_REQUIRED_HITS;
return 0;
return;
}
/* if operator is none, explicitly clear out the required hits */
@ -302,7 +319,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
if (end == aux || *end != '.') {
parse->offset = RC_INVALID_REQUIRED_HITS;
return 0;
return;
}
/* if operator is none, explicitly clear out the required hits */
@ -321,7 +338,140 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
self->optimized_comparator = rc_condition_determine_comparator(self);
*memaddr = aux;
return self;
}
void rc_condition_update_parse_state(rc_condition_t* condition, rc_parse_state_t* parse) {
/* type of values in the chain are determined by the parent.
* the last element of a chain is determined by the operand
*
* 1 + 1.5 + 1.75 + 1.0 => (int)1 + (int)1 + (int)1 + (float)1 = (float)4.0
* 1.0 + 1.5 + 1.75 + 1.0 => (float)1.0 + (float)1.5 + (float)1.75 + (float)1.0 = (float)5.25
* 1.0 + 1.5 + 1.75 + 1 => (float)1.0 + (float)1.5 + (float)1.75 + (int)1 = (int)5
*/
switch (condition->type) {
case RC_CONDITION_ADD_ADDRESS:
if (condition->oper != RC_OPERAND_NONE)
rc_condition_convert_to_operand(condition, &parse->indirect_parent, parse);
else
memcpy(&parse->indirect_parent, &condition->operand1, sizeof(parse->indirect_parent));
break;
case RC_CONDITION_ADD_SOURCE:
if (parse->addsource_parent.type == RC_OPERAND_NONE) {
rc_condition_convert_to_operand(condition, &parse->addsource_parent, parse);
}
else {
rc_operand_t cond_operand;
/* type determined by parent */
const uint8_t new_size = rc_operand_is_float(&parse->addsource_parent) ? RC_MEMSIZE_FLOAT : RC_MEMSIZE_32_BITS;
rc_condition_convert_to_operand(condition, &cond_operand, parse);
rc_operand_addsource(&cond_operand, parse, new_size);
memcpy(&parse->addsource_parent, &cond_operand, sizeof(cond_operand));
}
parse->addsource_oper = RC_OPERATOR_ADD;
parse->indirect_parent.type = RC_OPERAND_NONE;
break;
case RC_CONDITION_SUB_SOURCE:
if (parse->addsource_parent.type == RC_OPERAND_NONE) {
rc_condition_convert_to_operand(condition, &parse->addsource_parent, parse);
parse->addsource_oper = RC_OPERATOR_SUB_PARENT;
}
else {
rc_operand_t cond_operand;
/* type determined by parent */
const uint8_t new_size = rc_operand_is_float(&parse->addsource_parent) ? RC_MEMSIZE_FLOAT : RC_MEMSIZE_32_BITS;
if (parse->addsource_oper == RC_OPERATOR_ADD && !rc_operand_is_memref(&parse->addsource_parent)) {
/* if the previous element was a constant we have to turn it into a memref by adding zero */
rc_modified_memref_t* memref;
rc_operand_t zero;
rc_operand_set_const(&zero, 0);
memref = rc_alloc_modified_memref(parse,
parse->addsource_parent.size, &parse->addsource_parent, RC_OPERATOR_ADD, &zero);
parse->addsource_parent.value.memref = (rc_memref_t*)memref;
parse->addsource_parent.type = RC_OPERAND_ADDRESS;
}
else if (parse->addsource_oper == RC_OPERATOR_SUB_PARENT) {
/* if the previous element was also a SubSource, we have to insert a 0 and start subtracting from there */
rc_modified_memref_t* negate;
rc_operand_t zero;
if (rc_operand_is_float(&parse->addsource_parent))
rc_operand_set_float_const(&zero, 0.0);
else
rc_operand_set_const(&zero, 0);
negate = rc_alloc_modified_memref(parse, new_size, &parse->addsource_parent, RC_OPERATOR_SUB_PARENT, &zero);
parse->addsource_parent.value.memref = (rc_memref_t*)negate;
parse->addsource_parent.size = zero.size;
}
/* subtract the condition from the chain */
parse->addsource_oper = rc_operand_is_memref(&parse->addsource_parent) ? RC_OPERATOR_SUB : RC_OPERATOR_SUB_PARENT;
rc_condition_convert_to_operand(condition, &cond_operand, parse);
rc_operand_addsource(&cond_operand, parse, new_size);
memcpy(&parse->addsource_parent, &cond_operand, sizeof(cond_operand));
/* indicate the next value can be added to the chain */
parse->addsource_oper = RC_OPERATOR_ADD;
}
parse->indirect_parent.type = RC_OPERAND_NONE;
break;
case RC_CONDITION_REMEMBER:
rc_condition_convert_to_operand(condition, &condition->operand1, parse);
if (parse->addsource_parent.type != RC_OPERAND_NONE) {
/* type determined by leaf */
rc_operand_addsource(&condition->operand1, parse, condition->operand1.size);
}
memcpy(&parse->remember, &condition->operand1, sizeof(parse->remember));
parse->addsource_parent.type = RC_OPERAND_NONE;
parse->indirect_parent.type = RC_OPERAND_NONE;
break;
case RC_CONDITION_MEASURED:
/* Measured condition can have modifiers in values */
if (parse->is_value) {
switch (condition->oper) {
case RC_OPERATOR_AND:
case RC_OPERATOR_XOR:
case RC_OPERATOR_DIV:
case RC_OPERATOR_MULT:
case RC_OPERATOR_MOD:
case RC_OPERATOR_ADD:
case RC_OPERATOR_SUB:
rc_condition_convert_to_operand(condition, &condition->operand1, parse);
break;
default:
break;
}
}
/* fallthrough */ /* to default */
default:
if (parse->addsource_parent.type != RC_OPERAND_NONE) {
/* type determined by leaf */
rc_operand_addsource(&condition->operand1, parse, condition->operand1.size);
if (parse->buffer)
condition->optimized_comparator = rc_condition_determine_comparator(condition);
}
parse->addsource_parent.type = RC_OPERAND_NONE;
parse->indirect_parent.type = RC_OPERAND_NONE;
break;
}
}
int rc_condition_is_combining(const rc_condition_t* self) {
@ -500,41 +650,35 @@ static int rc_test_condition_compare_delta_to_memref_transformed(rc_condition_t*
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state) {
rc_typed_value_t value1, value2;
if (eval_state->add_value.type != RC_VALUE_TYPE_NONE) {
/* if there's an accumulator, we can't use the optimized comparators */
rc_evaluate_operand(&value1, &self->operand1, eval_state);
rc_typed_value_add(&value1, &eval_state->add_value);
} else {
/* use an optimized comparator whenever possible */
switch (self->optimized_comparator) {
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST:
return rc_test_condition_compare_memref_to_const(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA:
return rc_test_condition_compare_memref_to_delta(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF:
return rc_test_condition_compare_memref_to_memref(self);
case RC_PROCESSING_COMPARE_DELTA_TO_CONST:
return rc_test_condition_compare_delta_to_const(self);
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF:
return rc_test_condition_compare_delta_to_memref(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED:
return rc_test_condition_compare_memref_to_const_transformed(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED:
return rc_test_condition_compare_memref_to_delta_transformed(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED:
return rc_test_condition_compare_memref_to_memref_transformed(self);
case RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED:
return rc_test_condition_compare_delta_to_const_transformed(self);
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED:
return rc_test_condition_compare_delta_to_memref_transformed(self);
case RC_PROCESSING_COMPARE_ALWAYS_TRUE:
return 1;
case RC_PROCESSING_COMPARE_ALWAYS_FALSE:
return 0;
default:
rc_evaluate_operand(&value1, &self->operand1, eval_state);
break;
}
/* use an optimized comparator whenever possible */
switch (self->optimized_comparator) {
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST:
return rc_test_condition_compare_memref_to_const(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA:
return rc_test_condition_compare_memref_to_delta(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF:
return rc_test_condition_compare_memref_to_memref(self);
case RC_PROCESSING_COMPARE_DELTA_TO_CONST:
return rc_test_condition_compare_delta_to_const(self);
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF:
return rc_test_condition_compare_delta_to_memref(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED:
return rc_test_condition_compare_memref_to_const_transformed(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED:
return rc_test_condition_compare_memref_to_delta_transformed(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED:
return rc_test_condition_compare_memref_to_memref_transformed(self);
case RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED:
return rc_test_condition_compare_delta_to_const_transformed(self);
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED:
return rc_test_condition_compare_delta_to_memref_transformed(self);
case RC_PROCESSING_COMPARE_ALWAYS_TRUE:
return 1;
case RC_PROCESSING_COMPARE_ALWAYS_FALSE:
return 0;
default:
rc_evaluate_operand(&value1, &self->operand1, eval_state);
break;
}
rc_evaluate_operand(&value2, &self->operand2, eval_state);
@ -548,38 +692,5 @@ void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self,
rc_evaluate_operand(value, &self->operand1, eval_state);
rc_evaluate_operand(&amount, &self->operand2, eval_state);
switch (self->oper) {
case RC_OPERATOR_MULT:
rc_typed_value_multiply(value, &amount);
break;
case RC_OPERATOR_DIV:
rc_typed_value_divide(value, &amount);
break;
case RC_OPERATOR_AND:
rc_typed_value_convert(value, RC_VALUE_TYPE_UNSIGNED);
rc_typed_value_convert(&amount, RC_VALUE_TYPE_UNSIGNED);
value->value.u32 &= amount.value.u32;
break;
case RC_OPERATOR_XOR:
rc_typed_value_convert(value, RC_VALUE_TYPE_UNSIGNED);
rc_typed_value_convert(&amount, RC_VALUE_TYPE_UNSIGNED);
value->value.u32 ^= amount.value.u32;
break;
case RC_OPERATOR_MOD:
rc_typed_value_modulus(value, &amount);
break;
case RC_OPERATOR_ADD:
rc_typed_value_add(value, &amount);
break;
case RC_OPERATOR_SUB:
rc_typed_value_negate(&amount);
rc_typed_value_add(value, &amount);
break;
}
rc_typed_value_combine(value, &amount, self->oper);
}

File diff suppressed because it is too large Load Diff

View File

@ -72,6 +72,9 @@ const char* rc_console_name(uint32_t console_id)
case RC_CONSOLE_FAIRCHILD_CHANNEL_F:
return "Fairchild Channel F";
case RC_CONSOLE_FAMICOM_DISK_SYSTEM:
return "Famicom Disk System";
case RC_CONSOLE_FM_TOWNS:
return "FM Towns";
@ -380,14 +383,18 @@ static const rc_memory_regions_t rc_memory_regions_colecovision = { _rc_memory_r
/* ===== Commodore 64 ===== */
/* https://www.c64-wiki.com/wiki/Memory_Map */
/* https://sta.c64.org/cbm64mem.html */
/* NOTE: Several blocks of C64 memory can be bank-switched for ROM data (see https://www.c64-wiki.com/wiki/Bank_Switching).
* Achievement triggers rely on values changing, so we don't really need to look at the ROM data.
* The achievement logic assumes the RAM data is always present in the bankable blocks. As such,
* clients providing memory to achievements should always return the RAM values at the queried address. */
static const rc_memory_region_t _rc_memory_regions_c64[] = {
{ 0x000000U, 0x0003FFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Kernel RAM" },
{ 0x000400U, 0x0007FFU, 0x000400U, RC_MEMORY_TYPE_VIDEO_RAM, "Screen RAM" },
{ 0x000800U, 0x009FFFU, 0x000800U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* BASIC Program Storage Area */
{ 0x00A000U, 0x00BFFFU, 0x00A000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* Machine Language Storage Area / BASIC ROM Area */
{ 0x00C000U, 0x00CFFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* Machine Language Storage Area */
{ 0x00D000U, 0x00DFFFU, 0x00D000U, RC_MEMORY_TYPE_SYSTEM_RAM, "I/O Area" }, /* also Character ROM */
{ 0x00E000U, 0x00FFFFU, 0x00E000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* Machine Language Storage Area / Kernal ROM */
{ 0x000800U, 0x009FFFU, 0x000800U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* BASIC area. $8000-$9FFF can bank to cartridge ROM */
{ 0x00A000U, 0x00BFFFU, 0x00A000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* can bank to BASIC ROM or cartridge ROM */
{ 0x00C000U, 0x00CFFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
{ 0x00D000U, 0x00DFFFU, 0x00D000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* can bank to I/O Area or character ROM */
{ 0x00E000U, 0x00FFFFU, 0x00E000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* can bank to kernel ROM */
};
static const rc_memory_regions_t rc_memory_regions_c64 = { _rc_memory_regions_c64, 7 };
@ -423,6 +430,24 @@ static const rc_memory_region_t _rc_memory_regions_fairchild_channel_f[] = {
};
static const rc_memory_regions_t rc_memory_regions_fairchild_channel_f = { _rc_memory_regions_fairchild_channel_f, 4 };
/* ===== Famicon Disk System ===== */
/* https://fms.komkon.org/EMUL8/NES.html */
static const rc_memory_region_t _rc_memory_regions_famicom_disk_system[] = {
{ 0x0000U, 0x07FFU, 0x0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
{ 0x0800U, 0x0FFFU, 0x0000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirror RAM" }, /* duplicates memory from $0000-$07FF */
{ 0x1000U, 0x17FFU, 0x0000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirror RAM" }, /* duplicates memory from $0000-$07FF */
{ 0x1800U, 0x1FFFU, 0x0000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirror RAM" }, /* duplicates memory from $0000-$07FF */
{ 0x2000U, 0x2007U, 0x2000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "PPU Register" },
{ 0x2008U, 0x3FFFU, 0x2008U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirrored PPU Register" }, /* repeats every 8 bytes */
{ 0x4000U, 0x4017U, 0x4000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "APU and I/O register" },
{ 0x4018U, 0x401FU, 0x4018U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "APU and I/O test register" },
{ 0x4020U, 0x40FFU, 0x4020U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "FDS I/O registers"},
{ 0x4100U, 0x5FFFU, 0x4100U, RC_MEMORY_TYPE_READONLY, "Cartridge data"}, /* varies by mapper */
{ 0x6000U, 0xDFFFU, 0x6000U, RC_MEMORY_TYPE_SYSTEM_RAM, "FDS RAM"},
{ 0xE000U, 0xFFFFU, 0xE000U, RC_MEMORY_TYPE_READONLY, "FDS BIOS ROM"},
};
static const rc_memory_regions_t rc_memory_regions_famicom_disk_system = { _rc_memory_regions_famicom_disk_system, 12 };
/* ===== GameBoy / MegaDuck ===== */
static const rc_memory_region_t _rc_memory_regions_gameboy[] = {
{ 0x000000U, 0x0000FFU, 0x000000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Interrupt vector" },
@ -694,18 +719,6 @@ static const rc_memory_region_t _rc_memory_regions_nes[] = {
{ 0x4020U, 0x5FFFU, 0x4020U, RC_MEMORY_TYPE_READONLY, "Cartridge data"}, /* varies by mapper */
{ 0x6000U, 0x7FFFU, 0x6000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM"},
{ 0x8000U, 0xFFFFU, 0x8000U, RC_MEMORY_TYPE_READONLY, "Cartridge ROM"},
/* NOTE: these are the correct mappings for FDS: https://fms.komkon.org/EMUL8/NES.html
* 0x6000-0xDFFF is RAM on the FDS system and 0xE000-0xFFFF is FDS BIOS.
* If the core implements a memory map, we should still be able to translate the addresses
* correctly as we only use the classifications when a memory map is not provided
{ 0x4020U, 0x40FFU, 0x4020U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "FDS I/O registers"},
{ 0x4100U, 0x5FFFU, 0x4100U, RC_MEMORY_TYPE_READONLY, "Cartridge data"}, // varies by mapper
{ 0x6000U, 0xDFFFU, 0x6000U, RC_MEMORY_TYPE_SYSTEM_RAM, "FDS RAM"},
{ 0xE000U, 0xFFFFU, 0xE000U, RC_MEMORY_TYPE_READONLY, "FDS BIOS ROM"},
*/
};
static const rc_memory_regions_t rc_memory_regions_nes = { _rc_memory_regions_nes, 11 };
@ -868,10 +881,18 @@ static const rc_memory_regions_t rc_memory_regions_scv = { _rc_memory_regions_sc
/* ===== Super Nintendo ===== */
/* https://en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_map#LoROM */
static const rc_memory_region_t _rc_memory_regions_snes[] = {
{ 0x000000U, 0x01FFFFU, 0x7E0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
{ 0x020000U, 0x03FFFFU, 0xFE0000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" }
{ 0x000000U, 0x01FFFFU, 0x07E0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
/* Cartridge RAM here could be in a variety of places in SNES memory, depending on the ROM type.
* Due to this, we place Cartridge RAM outside of the possible native addressing space.
* Note that this also covers SA-1 BW-RAM (which is exposed as RETRO_MEMORY_SAVE_RAM for libretro).
*/
{ 0x020000U, 0x09FFFFU, 0x1000000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" },
/* I-RAM on the SA-1 is normally at 0x003000. However, this address typically just has a mirror of System RAM for other ROM types.
* To avoid conflicts, don't use 0x003000, instead map it outside of the possible native addressing space.
*/
{ 0x0A0000U, 0x0A07FFU, 0x1080000U, RC_MEMORY_TYPE_SYSTEM_RAM, "I-RAM (SA-1)" }
};
static const rc_memory_regions_t rc_memory_regions_snes = { _rc_memory_regions_snes, 2 };
static const rc_memory_regions_t rc_memory_regions_snes = { _rc_memory_regions_snes, 3 };
/* ===== Thomson TO8 ===== */
/* https://github.com/mamedev/mame/blob/master/src/mame/drivers/thomson.cpp#L1617 */
@ -1046,7 +1067,10 @@ const rc_memory_regions_t* rc_console_memory_regions(uint32_t console_id)
case RC_CONSOLE_FAIRCHILD_CHANNEL_F:
return &rc_memory_regions_fairchild_channel_f;
case RC_CONSOLE_FAMICOM_DISK_SYSTEM:
return &rc_memory_regions_famicom_disk_system;
case RC_CONSOLE_GAMEBOY:
return &rc_memory_regions_gameboy;

View File

@ -29,7 +29,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_START;
rc_parse_trigger_internal(&self->start, &memaddr, parse);
self->start.memrefs = 0;
}
}
else if ((memaddr[0] == 'c' || memaddr[0] == 'C') &&
@ -44,7 +43,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_CANCEL;
rc_parse_trigger_internal(&self->cancel, &memaddr, parse);
self->cancel.memrefs = 0;
}
}
else if ((memaddr[0] == 's' || memaddr[0] == 'S') &&
@ -59,7 +57,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_SUBMIT;
rc_parse_trigger_internal(&self->submit, &memaddr, parse);
self->submit.memrefs = 0;
}
}
else if ((memaddr[0] == 'v' || memaddr[0] == 'V') &&
@ -74,7 +71,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_VALUE;
rc_parse_value_internal(&self->value, &memaddr, parse);
self->value.memrefs = 0;
}
}
else if ((memaddr[0] == 'p' || memaddr[0] == 'P') &&
@ -91,7 +87,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
self->progress = RC_ALLOC(rc_value_t, parse);
rc_parse_value_internal(self->progress, &memaddr, parse);
self->progress->memrefs = 0;
}
}
@ -130,44 +125,55 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
}
self->state = RC_LBOARD_STATE_WAITING;
self->has_memrefs = 0;
}
int rc_lboard_size(const char* memaddr) {
rc_lboard_t* self;
rc_parse_state_t parse;
rc_memref_t* first_memref;
rc_init_parse_state(&parse, 0, 0, 0);
rc_init_parse_state_memrefs(&parse, &first_memref);
rc_lboard_with_memrefs_t* lboard;
rc_preparse_state_t preparse;
rc_init_preparse_state(&preparse, NULL, 0);
self = RC_ALLOC(rc_lboard_t, &parse);
rc_parse_lboard_internal(self, memaddr, &parse);
lboard = RC_ALLOC(rc_lboard_with_memrefs_t, &preparse.parse);
rc_parse_lboard_internal(&lboard->lboard, memaddr, &preparse.parse);
rc_preparse_alloc_memrefs(NULL, &preparse);
rc_destroy_parse_state(&parse);
return parse.offset;
rc_destroy_preparse_state(&preparse);
return preparse.parse.offset;
}
rc_lboard_t* rc_parse_lboard(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx) {
rc_lboard_t* self;
rc_parse_state_t parse;
rc_lboard_with_memrefs_t* lboard;
rc_preparse_state_t preparse;
if (!buffer || !memaddr)
return 0;
rc_init_parse_state(&parse, buffer, L, funcs_ndx);
rc_init_preparse_state(&preparse, L, funcs_ndx);
lboard = RC_ALLOC(rc_lboard_with_memrefs_t, &preparse.parse);
rc_parse_lboard_internal(&lboard->lboard, memaddr, &preparse.parse);
self = RC_ALLOC(rc_lboard_t, &parse);
rc_init_parse_state_memrefs(&parse, &self->memrefs);
rc_reset_parse_state(&preparse.parse, buffer, L, funcs_ndx);
lboard = RC_ALLOC(rc_lboard_with_memrefs_t, &preparse.parse);
rc_preparse_alloc_memrefs(&lboard->memrefs, &preparse);
rc_parse_lboard_internal(self, memaddr, &parse);
rc_parse_lboard_internal(&lboard->lboard, memaddr, &preparse.parse);
lboard->lboard.has_memrefs = 1;
rc_destroy_parse_state(&parse);
return (parse.offset >= 0) ? self : 0;
rc_destroy_preparse_state(&preparse);
return (preparse.parse.offset >= 0) ? &lboard->lboard : NULL;
}
static void rc_update_lboard_memrefs(rc_lboard_t* self, rc_peek_t peek, void* ud) {
if (self->has_memrefs) {
rc_lboard_with_memrefs_t* lboard = (rc_lboard_with_memrefs_t*)self;
rc_update_memref_values(&lboard->memrefs, peek, ud);
}
}
int rc_evaluate_lboard(rc_lboard_t* self, int32_t* value, rc_peek_t peek, void* peek_ud, lua_State* L) {
int start_ok, cancel_ok, submit_ok;
rc_update_memref_values(self->memrefs, peek, peek_ud);
rc_update_lboard_memrefs(self, peek, peek_ud);
if (self->state == RC_LBOARD_STATE_INACTIVE || self->state == RC_LBOARD_STATE_DISABLED)
return RC_LBOARD_STATE_INACTIVE;

View File

@ -6,41 +6,232 @@
#define MEMREF_PLACEHOLDER_ADDRESS 0xFFFFFFFF
rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, uint32_t address, uint8_t size, uint8_t is_indirect) {
rc_memref_t** next_memref;
rc_memref_t* memref;
rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, uint32_t address, uint8_t size) {
rc_memref_list_t* memref_list = NULL;
rc_memref_t* memref = NULL;
int i;
if (!is_indirect) {
/* attempt to find an existing memref that can be shared */
next_memref = parse->first_memref;
while (*next_memref) {
memref = *next_memref;
if (!memref->value.is_indirect && memref->address == address && memref->value.size == size)
return memref;
for (i = 0; i < 2; i++) {
if (i == 0) {
if (!parse->existing_memrefs)
continue;
next_memref = &memref->next;
memref_list = &parse->existing_memrefs->memrefs;
}
else {
memref_list = &parse->memrefs->memrefs;
}
/* no match found, create a new entry */
memref = RC_ALLOC_SCRATCH(rc_memref_t, parse);
*next_memref = memref;
do
{
const rc_memref_t* memref_stop;
memref = memref_list->items;
memref_stop = memref + memref_list->count;
for (; memref < memref_stop; ++memref) {
if (memref->address == address && memref->value.size == size)
return memref;
}
if (!memref_list->next)
break;
memref_list = memref_list->next;
} while (1);
}
else {
/* indirect references always create a new entry because we can't guarantee that the
* indirection amount will be the same between references. because they aren't shared,
* don't bother putting them in the chain.
*/
memref = RC_ALLOC(rc_memref_t, parse);
/* no match found, find a place to put the new entry */
memref_list = &parse->memrefs->memrefs;
while (memref_list->count == memref_list->capacity && memref_list->next)
memref_list = memref_list->next;
/* create a new entry */
if (memref_list->count < memref_list->capacity) {
memref = &memref_list->items[memref_list->count++];
} else {
const int32_t old_offset = parse->offset;
if (memref_list->capacity != 0) {
memref_list = memref_list->next = RC_ALLOC_SCRATCH(rc_memref_list_t, parse);
memref_list->next = NULL;
}
memref_list->items = RC_ALLOC_ARRAY_SCRATCH(rc_memref_t, 8, parse);
memref_list->count = 1;
memref_list->capacity = 8;
memref_list->allocated = 0;
memref = memref_list->items;
/* in preparse mode, don't count this memory, we'll do a single allocation once we have
* the final total */
if (!parse->buffer)
parse->offset = old_offset;
}
memset(memref, 0, sizeof(*memref));
memref->address = address;
memref->value.memref_type = RC_MEMREF_TYPE_MEMREF;
memref->value.type = RC_VALUE_TYPE_UNSIGNED;
memref->value.size = size;
memref->value.is_indirect = is_indirect;
memref->address = address;
return memref;
}
rc_modified_memref_t* rc_alloc_modified_memref(rc_parse_state_t* parse, uint8_t size, const rc_operand_t* parent,
uint8_t modifier_type, const rc_operand_t* modifier) {
rc_modified_memref_list_t* modified_memref_list = NULL;
rc_modified_memref_t* modified_memref = NULL;
int i = 0;
for (i = 0; i < 2; i++) {
if (i == 0) {
if (!parse->existing_memrefs)
continue;
modified_memref_list = &parse->existing_memrefs->modified_memrefs;
}
else {
modified_memref_list = &parse->memrefs->modified_memrefs;
}
do {
const rc_modified_memref_t* memref_stop;
modified_memref = modified_memref_list->items;
memref_stop = modified_memref + modified_memref_list->count;
for (; modified_memref < memref_stop; ++modified_memref) {
if (modified_memref->memref.value.size == size &&
modified_memref->modifier_type == modifier_type &&
rc_operands_are_equal(&modified_memref->parent, parent) &&
rc_operands_are_equal(&modified_memref->modifier, modifier)) {
return modified_memref;
}
}
if (!modified_memref_list->next)
break;
modified_memref_list = modified_memref_list->next;
} while (1);
}
/* no match found, find a place to put the new entry */
modified_memref_list = &parse->memrefs->modified_memrefs;
while (modified_memref_list->count == modified_memref_list->capacity && modified_memref_list->next)
modified_memref_list = modified_memref_list->next;
/* create a new entry */
if (modified_memref_list->count < modified_memref_list->capacity) {
modified_memref = &modified_memref_list->items[modified_memref_list->count++];
} else {
const int32_t old_offset = parse->offset;
if (modified_memref_list->capacity != 0) {
modified_memref_list = modified_memref_list->next = RC_ALLOC_SCRATCH(rc_modified_memref_list_t, parse);
modified_memref_list->next = NULL;
}
modified_memref_list->items = RC_ALLOC_ARRAY_SCRATCH(rc_modified_memref_t, 8, parse);
modified_memref_list->count = 1;
modified_memref_list->capacity = 8;
modified_memref_list->allocated = 0;
modified_memref = modified_memref_list->items;
/* in preparse mode, don't count this memory, we'll do a single allocation once we have
* the final total */
if (!parse->buffer)
parse->offset = old_offset;
}
memset(modified_memref, 0, sizeof(*modified_memref));
modified_memref->memref.value.memref_type = RC_MEMREF_TYPE_MODIFIED_MEMREF;
modified_memref->memref.value.size = size;
modified_memref->memref.value.type = (size == RC_MEMSIZE_FLOAT) ? RC_VALUE_TYPE_FLOAT : RC_VALUE_TYPE_UNSIGNED;
memcpy(&modified_memref->parent, parent, sizeof(modified_memref->parent));
memcpy(&modified_memref->modifier, modifier, sizeof(modified_memref->modifier));
modified_memref->modifier_type = modifier_type;
modified_memref->memref.address = rc_operand_is_memref(modifier) ? modifier->value.memref->address : modifier->value.num;
return modified_memref;
}
void rc_memrefs_init(rc_memrefs_t* memrefs)
{
memset(memrefs, 0, sizeof(*memrefs));
memrefs->memrefs.capacity = 32;
memrefs->memrefs.items =
(rc_memref_t*)malloc(memrefs->memrefs.capacity * sizeof(rc_memref_t));
memrefs->memrefs.allocated = 1;
memrefs->modified_memrefs.capacity = 16;
memrefs->modified_memrefs.items =
(rc_modified_memref_t*)malloc(memrefs->modified_memrefs.capacity * sizeof(rc_modified_memref_t));
memrefs->modified_memrefs.allocated = 1;
}
void rc_memrefs_destroy(rc_memrefs_t* memrefs)
{
rc_memref_list_t* memref_list = &memrefs->memrefs;
rc_modified_memref_list_t* modified_memref_list = &memrefs->modified_memrefs;
do {
rc_memref_list_t* current_memref_list = memref_list;
memref_list = memref_list->next;
if (current_memref_list->allocated) {
if (current_memref_list->items)
free(current_memref_list->items);
if (current_memref_list != &memrefs->memrefs)
free(current_memref_list);
}
} while (memref_list);
do {
rc_modified_memref_list_t* current_modified_memref_list = modified_memref_list;
modified_memref_list = modified_memref_list->next;
if (current_modified_memref_list->allocated) {
if (current_modified_memref_list->items)
free(current_modified_memref_list->items);
if (current_modified_memref_list != &memrefs->modified_memrefs)
free(current_modified_memref_list);
}
} while (modified_memref_list);
free(memrefs);
}
uint32_t rc_memrefs_count_memrefs(const rc_memrefs_t* memrefs)
{
uint32_t count = 0;
const rc_memref_list_t* memref_list = &memrefs->memrefs;
while (memref_list) {
count += memref_list->count;
memref_list = memref_list->next;
}
return count;
}
uint32_t rc_memrefs_count_modified_memrefs(const rc_memrefs_t* memrefs)
{
uint32_t count = 0;
const rc_modified_memref_list_t* modified_memref_list = &memrefs->modified_memrefs;
while (modified_memref_list) {
count += modified_memref_list->count;
modified_memref_list = modified_memref_list->next;
}
return count;
}
int rc_parse_memref(const char** memaddr, uint8_t* size, uint32_t* address) {
const char* aux = *memaddr;
char* end;
@ -77,7 +268,12 @@ int rc_parse_memref(const char** memaddr, uint8_t* size, uint32_t* address) {
/* case 'y': case 'Y': 64 bit? */
/* case 'z': case 'Z': 128 bit? */
case '0': case '1': case '2': case '3': case '4':
case '0':
if (*aux == 'x') /* user mistyped an extra 0x: 0x0xabcd */
return RC_INVALID_MEMORY_OPERAND;
/* fallthrough */
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
@ -485,19 +681,12 @@ void rc_update_memref_value(rc_memref_value_t* memref, uint32_t new_value) {
}
}
void rc_update_memref_values(rc_memref_t* memref, rc_peek_t peek, void* ud) {
while (memref) {
/* indirect memory references are not shared and will be updated in rc_get_memref_value */
if (!memref->value.is_indirect)
rc_update_memref_value(&memref->value, rc_peek_value(memref->address, memref->value.size, peek, ud));
void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memrefs_t* memrefs)
{
if (memrefs)
memset(memrefs, 0, sizeof(*memrefs));
memref = memref->next;
}
}
void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memref_t** memrefs) {
parse->first_memref = memrefs;
*memrefs = 0;
parse->memrefs = memrefs;
}
static uint32_t rc_get_memref_value_value(const rc_memref_value_t* memref, int operand_type) {
@ -520,12 +709,68 @@ static uint32_t rc_get_memref_value_value(const rc_memref_value_t* memref, int o
}
}
uint32_t rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state) {
/* if this is an indirect reference, handle the indirection. */
if (memref->value.is_indirect) {
const uint32_t new_address = memref->address + eval_state->add_address;
rc_update_memref_value(&memref->value, rc_peek_value(new_address, memref->value.size, eval_state->peek, eval_state->peek_userdata));
void rc_get_memref_value(rc_typed_value_t* value, rc_memref_t* memref, int operand_type) {
value->type = memref->value.type;
value->value.u32 = rc_get_memref_value_value(&memref->value, operand_type);
}
uint32_t rc_get_modified_memref_value(const rc_modified_memref_t* memref, rc_peek_t peek, void* ud) {
rc_typed_value_t value, modifier;
rc_evaluate_operand(&value, &memref->parent, NULL);
rc_evaluate_operand(&modifier, &memref->modifier, NULL);
switch (memref->modifier_type) {
case RC_OPERATOR_INDIRECT_READ:
rc_typed_value_add(&value, &modifier);
rc_typed_value_convert(&value, RC_VALUE_TYPE_UNSIGNED);
value.value.u32 = rc_peek_value(value.value.u32, memref->memref.value.size, peek, ud);
value.type = memref->memref.value.type;
break;
case RC_OPERATOR_SUB_PARENT:
rc_typed_value_negate(&value);
rc_typed_value_add(&value, &modifier);
rc_typed_value_convert(&value, memref->memref.value.type);
break;
default:
rc_typed_value_combine(&value, &modifier, memref->modifier_type);
rc_typed_value_convert(&value, memref->memref.value.type);
break;
}
return rc_get_memref_value_value(&memref->value, operand_type);
return value.value.u32;
}
void rc_update_memref_values(rc_memrefs_t* memrefs, rc_peek_t peek, void* ud) {
rc_memref_list_t* memref_list;
rc_modified_memref_list_t* modified_memref_list;
memref_list = &memrefs->memrefs;
do
{
rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_stop = memref + memref_list->count;
for (; memref < memref_stop; ++memref) {
if (memref->value.type != RC_VALUE_TYPE_NONE)
rc_update_memref_value(&memref->value, rc_peek_value(memref->address, memref->value.size, peek, ud));
}
memref_list = memref_list->next;
} while (memref_list);
modified_memref_list = &memrefs->modified_memrefs;
if (modified_memref_list->count) {
do {
rc_modified_memref_t* modified_memref = modified_memref_list->items;
const rc_modified_memref_t* modified_memref_stop = modified_memref + modified_memref_list->count;
for (; modified_memref < modified_memref_stop; ++modified_memref)
rc_update_memref_value(&modified_memref->memref.value, rc_get_modified_memref_value(modified_memref, peek, ud));
modified_memref_list = modified_memref_list->next;
} while (modified_memref_list);
}
}

View File

@ -61,11 +61,13 @@ static int rc_parse_operand_lua(rc_operand_t* self, const char** memaddr, rc_par
#endif /* RC_DISABLE_LUA */
self->type = RC_OPERAND_LUA;
self->size = RC_MEMSIZE_32_BITS;
self->memref_access_type = RC_OPERAND_ADDRESS;
*memaddr = aux;
return RC_OK;
}
static int rc_parse_operand_variable(rc_operand_t* self, const char** memaddr) {
static int rc_parse_operand_variable(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse) {
const char* aux = *memaddr;
size_t i;
char varName[RC_VALUE_MAX_NAME_LENGTH + 1] = { 0 };
@ -86,6 +88,15 @@ static int rc_parse_operand_variable(rc_operand_t* self, const char** memaddr) {
++aux;
if (strcmp(varName, "recall") == 0) {
if (parse->remember.type == RC_OPERAND_NONE) {
self->value.memref = NULL;
self->size = RC_MEMSIZE_32_BITS;
self->memref_access_type = RC_OPERAND_ADDRESS;
}
else {
memcpy(self, &parse->remember, sizeof(*self));
self->memref_access_type = self->type;
}
self->type = RC_OPERAND_RECALL;
}
else { /* process named variable when feature is available.*/
@ -96,7 +107,7 @@ static int rc_parse_operand_variable(rc_operand_t* self, const char** memaddr) {
return RC_OK;
}
static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse, uint8_t is_indirect) {
static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse) {
const char* aux = *memaddr;
uint32_t address;
uint8_t size;
@ -128,6 +139,8 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
break;
}
self->memref_access_type = self->type;
ret = rc_parse_memref(&aux, &self->size, &address);
if (ret != RC_OK)
return ret;
@ -137,13 +150,28 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
/* if the shared size differs from the requested size and it's a prior operation, we
* have to check to make sure both sizes use the same mask, or the prior value may be
* updated when bits outside the mask are modified, which would make it look like the
* current value once the mask is applied. if the mask differs, create a new
* current value once the mask is applied. if the mask differs, create a new
* non-shared record for tracking the prior data. */
if (rc_memref_mask(size) != rc_memref_mask(self->size))
size = self->size;
}
self->value.memref = rc_alloc_memref(parse, address, size, is_indirect);
if (parse->indirect_parent.type != RC_OPERAND_NONE) {
if (parse->indirect_parent.type == RC_OPERAND_CONST) {
self->value.memref = rc_alloc_memref(parse, address + parse->indirect_parent.value.num, size);
}
else {
rc_operand_t offset;
rc_operand_set_const(&offset, address);
self->value.memref = (rc_memref_t*)rc_alloc_modified_memref(parse,
size, &parse->indirect_parent, RC_OPERATOR_INDIRECT_READ, &offset);
}
}
else {
self->value.memref = rc_alloc_memref(parse, address, size);
}
if (parse->offset < 0)
return parse->offset;
@ -151,7 +179,7 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
return RC_OK;
}
int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indirect, rc_parse_state_t* parse) {
int rc_parse_operand(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse) {
const char* aux = *memaddr;
char* end;
int ret;
@ -159,8 +187,6 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
int negative;
int allow_decimal = 0;
self->size = RC_MEMSIZE_32_BITS;
switch (*aux) {
case 'h': case 'H': /* hex constant */
if (aux[2] == 'x' || aux[2] == 'X') {
@ -175,15 +201,14 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
if (value > 0xffffffffU)
value = 0xffffffffU;
self->type = RC_OPERAND_CONST;
self->value.num = (unsigned)value;
rc_operand_set_const(self, (unsigned)value);
aux = end;
break;
case 'f': case 'F': /* floating point constant */
if (isalpha((unsigned char)aux[1])) {
ret = rc_parse_operand_memory(self, &aux, parse, is_indirect);
ret = rc_parse_operand_memory(self, &aux, parse);
if (ret < 0)
return ret;
@ -211,6 +236,7 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
/* custom parser for decimal values to ignore locale */
unsigned long shift = 1;
unsigned long fraction = 0;
double dbl_val;
aux = end + 1;
if (*aux < '0' || *aux > '9')
@ -231,19 +257,19 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
/* non-zero fractional part, convert to double and merge in integer portion */
const double dbl_fraction = ((double)fraction) / ((double)shift);
if (negative)
self->value.dbl = ((double)(-((long)value))) - dbl_fraction;
dbl_val = ((double)(-((long)value))) - dbl_fraction;
else
self->value.dbl = (double)value + dbl_fraction;
dbl_val = (double)value + dbl_fraction;
}
else {
/* fractional part is 0, just convert the integer portion */
if (negative)
self->value.dbl = (double)(-((long)value));
dbl_val = (double)(-((long)value));
else
self->value.dbl = (double)value;
dbl_val = (double)value;
}
self->type = RC_OPERAND_FP;
rc_operand_set_float_const(self, dbl_val);
}
else {
/* not a floating point value, make sure something was read and advance the read pointer */
@ -255,17 +281,15 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
if (value > 0x7fffffffU)
value = 0x7fffffffU;
self->type = RC_OPERAND_CONST;
if (negative)
self->value.num = (unsigned)(-((long)value));
rc_operand_set_const(self, (unsigned)(-((long)value)));
else
self->value.num = (unsigned)value;
rc_operand_set_const(self, (unsigned)value);
}
break;
case '{': /* variable */
++aux;
ret = rc_parse_operand_variable(self, &aux);
ret = rc_parse_operand_variable(self, &aux, parse);
if (ret < 0)
return ret;
@ -275,7 +299,7 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
if (aux[1] == 'x' || aux[1] == 'X') { /* hex integer constant */
/* fallthrough */ /* to default */
default:
ret = rc_parse_operand_memory(self, &aux, parse, is_indirect);
ret = rc_parse_operand_memory(self, &aux, parse);
if (ret < 0)
return ret;
@ -292,8 +316,7 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
if (value > 0xffffffffU)
value = 0xffffffffU;
self->type = RC_OPERAND_CONST;
self->value.num = (unsigned)value;
rc_operand_set_const(self, (unsigned)value);
aux = end;
break;
@ -332,8 +355,74 @@ static int rc_luapeek(lua_State* L) {
#endif /* RC_DISABLE_LUA */
int rc_operand_is_float_memref(const rc_operand_t* self) {
switch (self->size) {
void rc_operand_set_const(rc_operand_t* self, uint32_t value) {
self->size = RC_MEMSIZE_32_BITS;
self->type = RC_OPERAND_CONST;
self->memref_access_type = RC_OPERAND_NONE;
self->value.num = value;
}
void rc_operand_set_float_const(rc_operand_t* self, double value) {
self->size = RC_MEMSIZE_FLOAT;
self->type = RC_OPERAND_FP;
self->memref_access_type = RC_OPERAND_NONE;
self->value.dbl = value;
}
int rc_operands_are_equal(const rc_operand_t* left, const rc_operand_t* right) {
if (left->type != right->type)
return 0;
switch (left->type) {
case RC_OPERAND_CONST:
return (left->value.num == right->value.num);
case RC_OPERAND_FP:
return (left->value.dbl == right->value.dbl);
case RC_OPERAND_RECALL:
return 1;
default:
break;
}
/* comparing two memrefs - look for exact matches on type and size */
if (left->size != right->size || left->value.memref->value.memref_type != right->value.memref->value.memref_type)
return 0;
switch (left->value.memref->value.memref_type) {
case RC_MEMREF_TYPE_MODIFIED_MEMREF:
{
const rc_modified_memref_t* left_memref = (const rc_modified_memref_t*)left->value.memref;
const rc_modified_memref_t* right_memref = (const rc_modified_memref_t*)right->value.memref;
return (left_memref->modifier_type == right_memref->modifier_type &&
rc_operands_are_equal(&left_memref->parent, &right_memref->parent) &&
rc_operands_are_equal(&left_memref->modifier, &right_memref->modifier));
}
default:
return (left->value.memref->address == right->value.memref->address &&
left->value.memref->value.size == right->value.memref->value.size);
}
}
int rc_operator_is_modifying(int oper) {
switch (oper) {
case RC_OPERATOR_AND:
case RC_OPERATOR_XOR:
case RC_OPERATOR_DIV:
case RC_OPERATOR_MULT:
case RC_OPERATOR_MOD:
case RC_OPERATOR_ADD:
case RC_OPERATOR_SUB:
case RC_OPERATOR_NONE: /* NONE operator implies "* 1" */
return 1;
default:
return 0;
}
}
static int rc_memsize_is_float(uint8_t size) {
switch (size) {
case RC_MEMSIZE_FLOAT:
case RC_MEMSIZE_FLOAT_BE:
case RC_MEMSIZE_DOUBLE32:
@ -347,8 +436,24 @@ int rc_operand_is_float_memref(const rc_operand_t* self) {
}
}
int rc_operand_is_memref(const rc_operand_t* self) {
switch (self->type) {
int rc_operand_is_float_memref(const rc_operand_t* self) {
if (!rc_operand_is_memref(self))
return 0;
if (self->type == RC_OPERAND_RECALL)
return rc_memsize_is_float(self->memref_access_type);
if (self->value.memref->value.memref_type == RC_MEMREF_TYPE_MODIFIED_MEMREF) {
const rc_modified_memref_t* memref = (const rc_modified_memref_t*)self->value.memref;
if (memref->modifier_type != RC_OPERATOR_INDIRECT_READ)
return rc_memsize_is_float(self->value.memref->value.size);
}
return rc_memsize_is_float(self->size);
}
int rc_operand_type_is_memref(uint8_t type) {
switch (type) {
case RC_OPERAND_CONST:
case RC_OPERAND_FP:
case RC_OPERAND_LUA:
@ -360,6 +465,10 @@ int rc_operand_is_memref(const rc_operand_t* self) {
}
}
int rc_operand_is_memref(const rc_operand_t* self) {
return rc_operand_type_is_memref(self->type);
}
int rc_operand_is_recall(const rc_operand_t* self) {
switch (self->type) {
case RC_OPERAND_RECALL:
@ -377,7 +486,7 @@ int rc_operand_is_float(const rc_operand_t* self) {
return rc_operand_is_float_memref(self);
}
uint32_t rc_transform_operand_value(uint32_t value, const rc_operand_t* self) {
static uint32_t rc_transform_operand_value(uint32_t value, const rc_operand_t* self) {
switch (self->type)
{
case RC_OPERAND_BCD:
@ -465,7 +574,44 @@ uint32_t rc_transform_operand_value(uint32_t value, const rc_operand_t* self) {
return value;
}
void rc_evaluate_operand(rc_typed_value_t* result, rc_operand_t* self, rc_eval_state_t* eval_state) {
void rc_operand_addsource(rc_operand_t* self, rc_parse_state_t* parse, uint8_t new_size) {
rc_modified_memref_t* modified_memref;
if (rc_operand_is_memref(&parse->addsource_parent)) {
rc_operand_t modifier;
if ((self->type == RC_OPERAND_DELTA || self->type == RC_OPERAND_PRIOR) &&
self->type == parse->addsource_parent.type) {
/* if adding prev(x) and prev(y), just add x and y and take the prev of that */
memcpy(&modifier, self, sizeof(modifier));
modifier.type = parse->addsource_parent.type = RC_OPERAND_ADDRESS;
modified_memref = rc_alloc_modified_memref(parse,
new_size, &parse->addsource_parent, parse->addsource_oper, &modifier);
}
else {
modified_memref = rc_alloc_modified_memref(parse,
new_size, &parse->addsource_parent, parse->addsource_oper, self);
}
}
else {
/* N + A => A + N */
/* -N + A => A - N */
modified_memref = rc_alloc_modified_memref(parse,
new_size, &parse->addsource_parent, parse->addsource_oper, self);
}
self->value.memref = (rc_memref_t*)modified_memref;
/* if adding a constant, change the type to be address (current value) */
if (!rc_operand_is_memref(self))
self->type = self->memref_access_type = RC_OPERAND_ADDRESS;
/* result of an AddSource operation is always a 32-bit integer (even if parent or modifier is a float) */
self->size = RC_MEMSIZE_32_BITS;
}
void rc_evaluate_operand(rc_typed_value_t* result, const rc_operand_t* self, rc_eval_state_t* eval_state) {
#ifndef RC_DISABLE_LUA
rc_luapeek_t luapeek;
#endif /* RC_DISABLE_LUA */
@ -510,16 +656,28 @@ void rc_evaluate_operand(rc_typed_value_t* result, rc_operand_t* self, rc_eval_s
#endif /* RC_DISABLE_LUA */
break;
case RC_OPERAND_RECALL:
result->type = eval_state->recall_value.type;
result->value = eval_state->recall_value.value;
return;
case RC_OPERAND_RECALL:
if (!rc_operand_type_is_memref(self->memref_access_type)) {
rc_operand_t recall;
memcpy(&recall, self, sizeof(recall));
recall.type = self->memref_access_type;
rc_evaluate_operand(result, &recall, eval_state);
return;
}
if (!self->value.memref) {
result->type = RC_VALUE_TYPE_UNSIGNED;
result->value.u32 = 0;
return;
}
rc_get_memref_value(result, self->value.memref, self->memref_access_type);
break;
default:
result->type = RC_VALUE_TYPE_UNSIGNED;
result->value.u32 = rc_get_memref_value(self->value.memref, self->type, eval_state);
rc_get_memref_value(result, self->value.memref, self->type);
break;
}

View File

@ -13,27 +13,115 @@ typedef struct rc_scratch_string {
}
rc_scratch_string_t;
#define RC_ALLOW_ALIGN(T) struct __align_ ## T { char ch; T t; };
typedef struct rc_modified_memref_t {
rc_memref_t memref; /* for compatibility with rc_operand_t.value.memref */
rc_operand_t parent; /* The parent memref this memref is derived from (type will always be a memref type) */
rc_operand_t modifier; /* The modifier to apply to the parent. */
uint8_t modifier_type; /* How to apply the modifier to the parent. (RC_OPERATOR_*) */
}
rc_modified_memref_t;
typedef struct rc_memref_list_t {
rc_memref_t* items;
struct rc_memref_list_t* next;
uint16_t count;
uint16_t capacity;
uint8_t allocated;
} rc_memref_list_t;
typedef struct rc_modified_memref_list_t {
rc_modified_memref_t* items;
struct rc_modified_memref_list_t* next;
uint16_t count;
uint16_t capacity;
uint8_t allocated;
} rc_modified_memref_list_t;
typedef struct rc_memrefs_t {
rc_memref_list_t memrefs;
rc_modified_memref_list_t modified_memrefs;
} rc_memrefs_t;
typedef struct rc_trigger_with_memrefs_t {
rc_trigger_t trigger;
rc_memrefs_t memrefs;
} rc_trigger_with_memrefs_t;
typedef struct rc_lboard_with_memrefs_t {
rc_lboard_t lboard;
rc_memrefs_t memrefs;
} rc_lboard_with_memrefs_t;
typedef struct rc_richpresence_with_memrefs_t {
rc_richpresence_t richpresence;
rc_memrefs_t memrefs;
} rc_richpresence_with_memrefs_t;
typedef struct rc_value_with_memrefs_t {
rc_value_t value;
rc_memrefs_t memrefs;
} rc_value_with_memrefs_t;
/* enum helpers for natvis expansion. Have to use a struct to define the mapping,
* and a single field to allow the conditional logic to switch on the value */
typedef struct __rc_bool_enum_t { uint8_t value; } __rc_bool_enum_t;
typedef struct __rc_memsize_enum_t { uint8_t value; } __rc_memsize_enum_t;
typedef struct __rc_memsize_enum_func_t { uint8_t value; } __rc_memsize_enum_func_t;
typedef struct __rc_operand_enum_t { uint8_t value; } __rc_operand_enum_t;
typedef struct __rc_value_type_enum_t { uint8_t value; } __rc_value_type_enum_t;
typedef struct __rc_memref_type_enum_t { uint8_t value; } __rc_memref_type_enum_t;
typedef struct __rc_condition_enum_t { uint8_t value; } __rc_condition_enum_t;
typedef struct __rc_condition_enum_str_t { uint8_t value; } __rc_condition_enum_str_t;
typedef struct __rc_condset_list_t { rc_condset_t* first_condset; } __rc_condset_list_t;
typedef struct __rc_operator_enum_t { uint8_t value; } __rc_operator_enum_t;
typedef struct __rc_operator_enum_str_t { uint8_t value; } __rc_operator_enum_str_t;
typedef struct __rc_operand_memref_t { rc_operand_t operand; } __rc_operand_memref_t; /* requires &rc_operand_t to be the same as &rc_operand_t.value.memref */
typedef struct __rc_value_list_t { rc_value_t* first_value; } __rc_value_list_t;
typedef struct __rc_trigger_state_enum_t { uint8_t value; } __rc_trigger_state_enum_t;
typedef struct __rc_lboard_state_enum_t { uint8_t value; } __rc_lboard_state_enum_t;
typedef struct __rc_richpresence_display_list_t { rc_richpresence_display_t* first_display; } __rc_richpresence_display_list_t;
typedef struct __rc_richpresence_display_part_list_t { rc_richpresence_display_part_t* display; } __rc_richpresence_display_part_list_t;
typedef struct __rc_richpresence_lookup_list_t { rc_richpresence_lookup_t* first_lookup; } __rc_richpresence_lookup_list_t;
typedef struct __rc_format_enum_t { uint8_t value; } __rc_format_enum_t;
#define RC_ALLOW_ALIGN(T) struct __align_ ## T { uint8_t ch; T t; };
RC_ALLOW_ALIGN(rc_condition_t)
RC_ALLOW_ALIGN(rc_condset_t)
RC_ALLOW_ALIGN(rc_modified_memref_t)
RC_ALLOW_ALIGN(rc_lboard_t)
RC_ALLOW_ALIGN(rc_lboard_with_memrefs_t)
RC_ALLOW_ALIGN(rc_memref_t)
RC_ALLOW_ALIGN(rc_memref_list_t)
RC_ALLOW_ALIGN(rc_memrefs_t)
RC_ALLOW_ALIGN(rc_modified_memref_list_t)
RC_ALLOW_ALIGN(rc_operand_t)
RC_ALLOW_ALIGN(rc_richpresence_t)
RC_ALLOW_ALIGN(rc_richpresence_display_t)
RC_ALLOW_ALIGN(rc_richpresence_display_part_t)
RC_ALLOW_ALIGN(rc_richpresence_lookup_t)
RC_ALLOW_ALIGN(rc_richpresence_lookup_item_t)
RC_ALLOW_ALIGN(rc_richpresence_with_memrefs_t)
RC_ALLOW_ALIGN(rc_scratch_string_t)
RC_ALLOW_ALIGN(rc_trigger_t)
RC_ALLOW_ALIGN(rc_trigger_with_memrefs_t)
RC_ALLOW_ALIGN(rc_value_t)
RC_ALLOW_ALIGN(rc_value_with_memrefs_t)
RC_ALLOW_ALIGN(char)
#define RC_ALIGNOF(T) (sizeof(struct __align_ ## T) - sizeof(T))
#define RC_OFFSETOF(o, t) (int)((char*)&(o.t) - (char*)&(o))
#define RC_OFFSETOF(o, t) (int)((uint8_t*)&(o.t) - (uint8_t*)&(o))
#define RC_ALLOC(t, p) ((t*)rc_alloc((p)->buffer, &(p)->offset, sizeof(t), RC_ALIGNOF(t), &(p)->scratch, RC_OFFSETOF((p)->scratch.objs, __ ## t)))
#define RC_ALLOC_SCRATCH(t, p) ((t*)rc_alloc_scratch((p)->buffer, &(p)->offset, sizeof(t), RC_ALIGNOF(t), &(p)->scratch, RC_OFFSETOF((p)->scratch.objs, __ ## t)))
#define RC_ALLOC_ARRAY(t, n, p) ((t*)rc_alloc((p)->buffer, &(p)->offset, (n) * sizeof(t), RC_ALIGNOF(t), &(p)->scratch, RC_OFFSETOF((p)->scratch.objs, __ ## t)))
#define RC_ALLOC_ARRAY_SCRATCH(t, n, p) ((t*)rc_alloc_scratch((p)->buffer, &(p)->offset, (n) * sizeof(t), RC_ALIGNOF(t), &(p)->scratch, RC_OFFSETOF((p)->scratch.objs, __ ## t)))
#define RC_ALLOC_WITH_TRAILING(container_type, trailing_type, trailing_field, trailing_count, parse) ((container_type*)rc_alloc(\
(parse)->buffer, &(parse)->offset, \
RC_OFFSETOF((*(container_type*)NULL),trailing_field) + trailing_count * sizeof(trailing_type), \
RC_ALIGNOF(container_type), &(parse)->scratch, 0))
#define RC_GET_TRAILING(container_pointer, container_type, trailing_type, trailing_field) (trailing_type*)(&((container_type*)(container_pointer))->trailing_field)
/* force alignment to 4 bytes on 32-bit systems, or 8 bytes on 64-bit systems */
#define RC_ALIGN(n) (((n) + (sizeof(void*)-1)) & ~(sizeof(void*)-1))
@ -45,17 +133,49 @@ typedef struct {
struct objs {
rc_condition_t* __rc_condition_t;
rc_condset_t* __rc_condset_t;
rc_modified_memref_t* __rc_modified_memref_t;
rc_lboard_t* __rc_lboard_t;
rc_lboard_with_memrefs_t* __rc_lboard_with_memrefs_t;
rc_memref_t* __rc_memref_t;
rc_memref_list_t* __rc_memref_list_t;
rc_memrefs_t* __rc_memrefs_t;
rc_modified_memref_list_t* __rc_modified_memref_list_t;
rc_operand_t* __rc_operand_t;
rc_richpresence_t* __rc_richpresence_t;
rc_richpresence_display_t* __rc_richpresence_display_t;
rc_richpresence_display_part_t* __rc_richpresence_display_part_t;
rc_richpresence_lookup_t* __rc_richpresence_lookup_t;
rc_richpresence_lookup_item_t* __rc_richpresence_lookup_item_t;
rc_richpresence_with_memrefs_t* __rc_richpresence_with_memrefs_t;
rc_scratch_string_t __rc_scratch_string_t;
rc_trigger_t* __rc_trigger_t;
rc_trigger_with_memrefs_t* __rc_trigger_with_memrefs_t;
rc_value_t* __rc_value_t;
rc_value_with_memrefs_t* __rc_value_with_memrefs_t;
/* these fields aren't actually used by the code, but they force the
* virtual enum wrapper types to exist so natvis can use them */
union {
__rc_bool_enum_t boolean;
__rc_memsize_enum_t memsize;
__rc_memsize_enum_func_t memsize_func;
__rc_operand_enum_t operand;
__rc_value_type_enum_t value_type;
__rc_memref_type_enum_t memref_type;
__rc_condition_enum_t condition;
__rc_condition_enum_str_t condition_str;
__rc_condset_list_t condset_list;
__rc_operator_enum_t oper;
__rc_operator_enum_str_t oper_str;
__rc_operand_memref_t operand_memref;
__rc_value_list_t value_list;
__rc_trigger_state_enum_t trigger_state;
__rc_lboard_state_enum_t lboard_state;
__rc_richpresence_display_list_t richpresence_display_list;
__rc_richpresence_display_part_list_t richpresence_display_part_list;
__rc_richpresence_lookup_list_t richpresence_lookup_list;
__rc_format_enum_t format;
} natvis_extension;
} objs;
}
rc_scratch_t;
@ -78,72 +198,128 @@ typedef struct {
}
rc_typed_value_t;
enum {
RC_MEMREF_TYPE_MEMREF, /* rc_memref_t */
RC_MEMREF_TYPE_MODIFIED_MEMREF, /* rc_modified_memref_t */
RC_MEMREF_TYPE_VALUE /* rc_value_t */
};
#define RC_MEASURED_UNKNOWN 0xFFFFFFFF
#define RC_OPERAND_NONE 0xFF
typedef struct {
rc_typed_value_t add_value;/* AddSource/SubSource */
int32_t add_hits; /* AddHits */
uint32_t add_address; /* AddAddress */
/* memory accessors */
rc_peek_t peek;
void* peek_userdata;
#ifndef RC_DISABLE_LUA
lua_State* L;
#endif
rc_typed_value_t measured_value; /* Measured */
rc_typed_value_t recall_value; /* Set by RC_CONDITION_REMEMBER */
uint8_t was_reset; /* ResetIf triggered */
uint8_t has_hits; /* one of more hit counts is non-zero */
uint8_t primed; /* true if all non-Trigger conditions are true */
/* processing state */
rc_typed_value_t measured_value; /* captured Measured value */
int32_t add_hits; /* AddHits/SubHits accumulator */
uint8_t is_true; /* true if all conditions are true */
uint8_t is_primed; /* true if all non-Trigger conditions are true */
uint8_t is_paused; /* true if one or more PauseIf conditions is true */
uint8_t can_measure; /* false if the measured value should be ignored */
uint8_t measured_from_hits; /* true if the measured_value came from a condition's hit count */
uint8_t was_cond_reset; /* ResetNextIf triggered */
uint8_t and_next; /* true if the previous condition was AndNext true */
uint8_t or_next; /* true if the previous condition was OrNext true */
uint8_t reset_next; /* true if the previous condition was ResetNextIf true */
uint8_t stop_processing; /* true to abort the processing loop */
/* result state */
uint8_t has_hits; /* true if one of more hit counts is non-zero */
uint8_t was_reset; /* true if one or more ResetIf conditions is true */
uint8_t was_cond_reset; /* true if one or more ResetNextIf conditions is true */
/* control settings */
uint8_t can_short_curcuit; /* allows logic processing to stop as soon as a false condition is encountered */
}
rc_eval_state_t;
typedef struct {
int32_t offset;
#ifndef RC_DISABLE_LUA
lua_State* L;
int funcs_ndx;
#endif
void* buffer;
rc_scratch_t scratch;
rc_memref_t** first_memref;
rc_memrefs_t* memrefs;
rc_memrefs_t* existing_memrefs;
rc_value_t** variables;
uint32_t measured_target;
int lines_read;
rc_operand_t addsource_parent;
rc_operand_t indirect_parent;
rc_operand_t remember;
uint8_t addsource_oper;
uint8_t is_value;
uint8_t has_required_hits;
uint8_t measured_as_percent;
}
rc_parse_state_t;
typedef struct rc_preparse_state_t {
rc_parse_state_t parse;
rc_memrefs_t memrefs;
} rc_preparse_state_t;
void rc_init_parse_state(rc_parse_state_t* parse, void* buffer, lua_State* L, int funcs_ndx);
void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memref_t** memrefs);
void rc_init_parse_state_variables(rc_parse_state_t* parse, rc_value_t** variables);
void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memrefs_t* memrefs);
void rc_reset_parse_state(rc_parse_state_t* parse, void* buffer, lua_State* L, int funcs_ndx);
void rc_destroy_parse_state(rc_parse_state_t* parse);
void rc_init_preparse_state(rc_preparse_state_t* preparse, lua_State* L, int funcs_ndx);
void rc_preparse_alloc_memrefs(rc_memrefs_t* memrefs, rc_preparse_state_t* preparse);
void rc_preparse_reserve_memrefs(rc_preparse_state_t* preparse, rc_memrefs_t* memrefs);
void rc_preparse_copy_memrefs(rc_parse_state_t* parse, rc_memrefs_t* memrefs);
void rc_destroy_preparse_state(rc_preparse_state_t *preparse);
void rc_copy_memrefs_into_parse_state(rc_parse_state_t* parse, rc_memref_t* memrefs);
void rc_sync_operand(rc_operand_t* operand, rc_parse_state_t* parse, const rc_memref_t* memrefs);
void* rc_alloc(void* pointer, int32_t* offset, uint32_t size, uint32_t alignment, rc_scratch_t* scratch, uint32_t scratch_object_pointer_offset);
void* rc_alloc_scratch(void* pointer, int32_t* offset, uint32_t size, uint32_t alignment, rc_scratch_t* scratch, uint32_t scratch_object_pointer_offset);
char* rc_alloc_str(rc_parse_state_t* parse, const char* text, size_t length);
rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, uint32_t address, uint8_t size, uint8_t is_indirect);
rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, uint32_t address, uint8_t size);
rc_modified_memref_t* rc_alloc_modified_memref(rc_parse_state_t* parse, uint8_t size, const rc_operand_t* parent,
uint8_t modifier_type, const rc_operand_t* modifier);
int rc_parse_memref(const char** memaddr, uint8_t* size, uint32_t* address);
void rc_update_memref_values(rc_memref_t* memref, rc_peek_t peek, void* ud);
void rc_update_memref_values(rc_memrefs_t* memrefs, rc_peek_t peek, void* ud);
void rc_update_memref_value(rc_memref_value_t* memref, uint32_t value);
uint32_t rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state);
void rc_get_memref_value(rc_typed_value_t* value, rc_memref_t* memref, int operand_type);
uint32_t rc_get_modified_memref_value(const rc_modified_memref_t* memref, rc_peek_t peek, void* ud);
uint8_t rc_memref_shared_size(uint8_t size);
uint32_t rc_memref_mask(uint8_t size);
void rc_transform_memref_value(rc_typed_value_t* value, uint8_t size);
uint32_t rc_peek_value(uint32_t address, uint8_t size, rc_peek_t peek, void* ud);
void rc_memrefs_init(rc_memrefs_t* memrefs);
void rc_memrefs_destroy(rc_memrefs_t* memrefs);
uint32_t rc_memrefs_count_memrefs(const rc_memrefs_t* memrefs);
uint32_t rc_memrefs_count_modified_memrefs(const rc_memrefs_t* memrefs);
void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_parse_state_t* parse);
int rc_trigger_state_active(int state);
rc_memrefs_t* rc_trigger_get_memrefs(rc_trigger_t* self);
rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, int is_value);
typedef struct rc_condset_with_trailing_conditions_t {
rc_condset_t condset;
rc_condition_t conditions[2];
} rc_condset_with_trailing_conditions_t;
RC_ALLOW_ALIGN(rc_condset_with_trailing_conditions_t)
rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse);
int rc_test_condset(rc_condset_t* self, rc_eval_state_t* eval_state);
void rc_reset_condset(rc_condset_t* self);
rc_condition_t* rc_condset_get_conditions(rc_condset_t* self);
enum {
RC_PROCESSING_COMPARE_DEFAULT = 0,
@ -161,24 +337,35 @@ enum {
RC_PROCESSING_COMPARE_ALWAYS_FALSE
};
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, uint8_t is_indirect);
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse);
void rc_parse_condition_internal(rc_condition_t* self, const char** memaddr, rc_parse_state_t* parse);
void rc_condition_update_parse_state(rc_condition_t* condition, rc_parse_state_t* parse);
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state);
void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self, rc_eval_state_t* eval_state);
int rc_condition_is_combining(const rc_condition_t* self);
void rc_condition_convert_to_operand(const rc_condition_t* condition, rc_operand_t* operand, rc_parse_state_t* parse);
int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indirect, rc_parse_state_t* parse);
void rc_evaluate_operand(rc_typed_value_t* value, rc_operand_t* self, rc_eval_state_t* eval_state);
int rc_parse_operand(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse);
void rc_evaluate_operand(rc_typed_value_t* value, const rc_operand_t* self, rc_eval_state_t* eval_state);
int rc_operator_is_modifying(int oper);
int rc_operand_is_float_memref(const rc_operand_t* self);
int rc_operand_is_float(const rc_operand_t* self);
int rc_operand_is_recall(const rc_operand_t* self);
int rc_operand_type_is_memref(uint8_t type);
int rc_operands_are_equal(const rc_operand_t* left, const rc_operand_t* right);
void rc_operand_addsource(rc_operand_t* self, rc_parse_state_t* parse, uint8_t new_size);
void rc_operand_set_const(rc_operand_t* self, uint32_t value);
void rc_operand_set_float_const(rc_operand_t* self, double value);
int rc_is_valid_variable_character(char ch, int is_first);
void rc_parse_value_internal(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse);
int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
void rc_reset_value(rc_value_t* self);
int rc_value_from_hits(rc_value_t* self);
rc_value_t* rc_alloc_helper_variable(const char* memaddr, size_t memaddr_len, rc_parse_state_t* parse);
void rc_update_variables(rc_value_t* variable, rc_peek_t peek, void* ud, lua_State* L);
rc_value_t* rc_alloc_variable(const char* memaddr, size_t memaddr_len, rc_parse_state_t* parse);
uint32_t rc_count_values(const rc_value_t* values);
void rc_update_values(rc_value_t* values, rc_peek_t peek, void* ud, lua_State* L);
void rc_reset_values(rc_value_t* values);
void rc_typed_value_convert(rc_typed_value_t* value, char new_type);
void rc_typed_value_add(rc_typed_value_t* value, const rc_typed_value_t* amount);
@ -187,6 +374,7 @@ void rc_typed_value_divide(rc_typed_value_t* value, const rc_typed_value_t* amou
void rc_typed_value_modulus(rc_typed_value_t* value, const rc_typed_value_t* amount);
void rc_typed_value_negate(rc_typed_value_t* value);
int rc_typed_value_compare(const rc_typed_value_t* value1, const rc_typed_value_t* value2, char oper);
void rc_typed_value_combine(rc_typed_value_t* value, rc_typed_value_t* amount, uint8_t oper);
void rc_typed_value_from_memref_value(rc_typed_value_t* value, const rc_memref_value_t* memref);
int rc_format_typed_value(char* buffer, size_t size, const rc_typed_value_t* value, int format);
@ -195,6 +383,11 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
int rc_lboard_state_active(int state);
void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script, rc_parse_state_t* parse);
rc_memrefs_t* rc_richpresence_get_memrefs(rc_richpresence_t* self);
void rc_reset_richpresence_triggers(rc_richpresence_t* self);
int rc_validate_memrefs(const rc_memrefs_t* memrefs, char result[], const size_t result_size, uint32_t max_address);
int rc_validate_memrefs_for_console(const rc_memrefs_t* memrefs, char result[], const size_t result_size, uint32_t console_id);
RC_END_C_DECLS

View File

@ -0,0 +1,539 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!-- https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2022 -->
<!-- https://learn.microsoft.com/en-us/visualstudio/debugger/format-specifiers-in-cpp?view=vs-2022 -->
<Type Name="rc_typed_value_t">
<DisplayString Condition="type==RC_VALUE_TYPE_UNSIGNED">{value.u32} (RC_VALUE_TYPE_UNSIGNED)</DisplayString>
<DisplayString Condition="type==RC_VALUE_TYPE_FLOAT">{value.f32} (RC_VALUE_TYPE_FLOAT)</DisplayString>
<DisplayString Condition="type==RC_VALUE_TYPE_SIGNED">{value.i32} (RC_VALUE_TYPE_SIGNED)</DisplayString>
<DisplayString Condition="type==RC_VALUE_TYPE_NONE">none (RC_VALUE_TYPE_NONE)</DisplayString>
<DisplayString>{value.i32} (unknown)</DisplayString>
</Type>
<Type Name="__rc_bool_enum_t">
<DisplayString Condition="value==0">false</DisplayString>
<DisplayString Condition="value==1">true</DisplayString>
<DisplayString>true ({value})</DisplayString>
</Type>
<Type Name="__rc_memsize_enum_t">
<DisplayString Condition="value==RC_MEMSIZE_8_BITS">{RC_MEMSIZE_8_BITS}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_16_BITS">{RC_MEMSIZE_16_BITS}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_24_BITS">{RC_MEMSIZE_24_BITS}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_32_BITS">{RC_MEMSIZE_32_BITS}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_LOW">{RC_MEMSIZE_LOW}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_HIGH">{RC_MEMSIZE_HIGH}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_0">{RC_MEMSIZE_BIT_0}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_1">{RC_MEMSIZE_BIT_1}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_2">{RC_MEMSIZE_BIT_2}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_3">{RC_MEMSIZE_BIT_3}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_4">{RC_MEMSIZE_BIT_4}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_5">{RC_MEMSIZE_BIT_5}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_6">{RC_MEMSIZE_BIT_6}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_7">{RC_MEMSIZE_BIT_7}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BITCOUNT">{RC_MEMSIZE_BITCOUNT}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_16_BITS_BE">{RC_MEMSIZE_16_BITS_BE}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_24_BITS_BE">{RC_MEMSIZE_24_BITS_BE}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_32_BITS_BE">{RC_MEMSIZE_32_BITS_BE}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_FLOAT">{RC_MEMSIZE_FLOAT}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_MBF32">{RC_MEMSIZE_MBF32}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_MBF32_LE">{RC_MEMSIZE_MBF32_LE}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_FLOAT_BE">{RC_MEMSIZE_FLOAT_BE}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_DOUBLE32">{RC_MEMSIZE_DOUBLE32}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_DOUBLE32_BE">{RC_MEMSIZE_DOUBLE32_BE}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_VARIABLE">{RC_MEMSIZE_VARIABLE}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_value_type_enum_t">
<DisplayString Condition="value==RC_VALUE_TYPE_NONE">{RC_VALUE_TYPE_NONE}</DisplayString>
<DisplayString Condition="value==RC_VALUE_TYPE_UNSIGNED">{RC_VALUE_TYPE_UNSIGNED}</DisplayString>
<DisplayString Condition="value==RC_VALUE_TYPE_SIGNED">{RC_VALUE_TYPE_SIGNED}</DisplayString>
<DisplayString Condition="value==RC_VALUE_TYPE_FLOAT">{RC_VALUE_TYPE_FLOAT}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_memref_type_enum_t">
<DisplayString Condition="value==RC_MEMREF_TYPE_MEMREF">{RC_MEMREF_TYPE_MEMREF}</DisplayString>
<DisplayString Condition="value==RC_MEMREF_TYPE_MODIFIED_MEMREF">{RC_MEMREF_TYPE_MODIFIED_MEMREF}</DisplayString>
<DisplayString Condition="value==RC_MEMREF_TYPE_VALUE">RC_MEMREF_TYPE_VALUE</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_memsize_enum_func_t">
<DisplayString Condition="value==RC_MEMSIZE_8_BITS">byte</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_16_BITS">word</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_24_BITS">tbyte</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_32_BITS">dword</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_LOW">lower4</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_HIGH">upper4</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_0">bit0</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_1">bit1</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_2">bit2</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_3">bit3</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_4">bit4</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_5">bit5</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_6">bit6</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_7">bit7</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BITCOUNT">bitcount</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_16_BITS_BE">word_be</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_24_BITS_BE">tbyte_be</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_32_BITS_BE">dword_be</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_FLOAT">float</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_MBF32">mbf32</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_MBF32_LE">mbf32_le</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_FLOAT_BE">float_be</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_DOUBLE32">double32</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_DOUBLE32_BE">double32_be</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_VARIABLE">var</DisplayString>
<DisplayString>unknown</DisplayString>
</Type>
<Type Name="rc_memref_value_t">
<DisplayString Condition="type==RC_VALUE_TYPE_FLOAT">{{value={(float)*((float*)&amp;value)} prior={(float)*((float*)&amp;prior)}}}</DisplayString>
<DisplayString Condition="type==RC_VALUE_TYPE_SIGNED">{{value={(int)value} prior={(int)prior}}}</DisplayString>
<DisplayString>{{value={value,x} prior={prior,x}}}</DisplayString>
<Expand>
<Item Name="value">value</Item>
<Item Name="prior">prior</Item>
<Item Name="size">*((__rc_memsize_enum_t*)&amp;size)</Item>
<Item Name="changed">*((__rc_bool_enum_t*)&amp;changed)</Item>
<Item Name="type">*((__rc_value_type_enum_t*)&amp;type)</Item>
<Item Name="memref_type">*((__rc_memref_type_enum_t*)&amp;memref_type)</Item>
</Expand>
</Type>
<Type Name="rc_memref_t">
<DisplayString Condition="value.memref_type==RC_MEMREF_TYPE_MODIFIED_MEMREF">{*(rc_modified_memref_t*)&amp;value}</DisplayString>
<DisplayString Condition="value.memref_type==RC_MEMREF_TYPE_VALUE">{*(rc_value_t*)&amp;value}</DisplayString>
<DisplayString Condition="value.size==RC_MEMSIZE_VARIABLE">var</DisplayString>
<DisplayString>{*((__rc_memsize_enum_func_t*)&amp;value.size)}({address,x})</DisplayString>
<Expand>
<Item Name="[rc_modified_memref_t]" Condition="value.memref_type==RC_MEMREF_TYPE_MODIFIED_MEMREF">(rc_modified_memref_t*)&amp;value</Item>
<Item Name="value">value</Item>
<Item Name="address">address</Item>
</Expand>
</Type>
<Type Name="rc_memref_list_t">
<DisplayString>{{count = {count}}}</DisplayString>
<Expand>
<Item Name="next" Condition="next!=0">next</Item>
<Item Name="count">count</Item>
<Item Name="capacity">capacity</Item>
<ArrayItems>
<Size>count</Size>
<ValuePointer>items</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="__rc_operand_memref_t">
<DisplayString Condition="operand.value.memref->value.memref_type==RC_MEMREF_TYPE_MODIFIED_MEMREF">... {*((__rc_memsize_enum_func_t*)&amp;operand.size)} {operand.value.memref->address,x}</DisplayString>
<DisplayString Condition="operand.value.memref->value.memref_type==RC_MEMREF_TYPE_VALUE">value {((rc_value_t*)operand.value.memref)->name,s}</DisplayString>
<DisplayString>{*((__rc_memsize_enum_func_t*)&amp;operand.size)} {operand.value.memref->address,x}</DisplayString>
<Expand>
<Item Name="[rc_modified_memref_t]" Condition="operand.value.memref->value.memref_type==RC_MEMREF_TYPE_MODIFIED_MEMREF">(rc_modified_memref_t*)&amp;operand.value</Item>
<Item Name="value">operand.value.memref->value</Item>
<Item Name="address">operand.value.memref->address</Item>
</Expand>
</Type>
<Type Name="__rc_operand_enum_t">
<DisplayString Condition="value==RC_OPERAND_ADDRESS">{RC_OPERAND_ADDRESS}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_DELTA">{RC_OPERAND_DELTA}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_CONST">{RC_OPERAND_CONST}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_FP">{RC_OPERAND_FP}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_LUA">{RC_OPERAND_LUA}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_PRIOR">{RC_OPERAND_PRIOR}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_BCD">{RC_OPERAND_BCD}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_INVERTED">{RC_OPERAND_INVERTED}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_RECALL">{RC_OPERAND_RECALL}</DisplayString>
<DisplayString Condition="value==0xFF">RC_OPERAND_NONE (255)</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_operand_t">
<DisplayString Condition="type==RC_OPERAND_ADDRESS">{{{*(__rc_operand_memref_t*)&amp;value.memref}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_DELTA">{{delta {*(__rc_operand_memref_t*)&amp;value.memref}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_PRIOR">{{prior {*(__rc_operand_memref_t*)&amp;value.memref}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_BCD">{{bcd {*(__rc_operand_memref_t*)&amp;value.memref}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_INVERTED">{{inverted {*(__rc_operand_memref_t*)&amp;value.memref}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_CONST &amp;&amp; value.num &gt; 0xFFFF0000">{{value {(int)value.num}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_CONST &amp;&amp; value.num &gt; 0x01000000">{{value {value.num,x}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_CONST">{{value {value.num}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_FP">{{value {value.dbl}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_RECALL">{{recall}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_LUA">{{lua @{value.luafunc}}}</DisplayString>
<DisplayString Condition="type==0xFF">{{none}}</DisplayString>
<DisplayString>{{unknown}}</DisplayString>
<Expand>
<Item Name="value" Condition="type==RC_OPERAND_CONST">value.num</Item>
<Item Name="value" Condition="type==RC_OPERAND_FP">value.dbl</Item>
<Item Name="value" Condition="type==RC_OPERAND_RECALL &amp;&amp; memref_access_type==RC_OPERAND_CONST">value.num</Item>
<Item Name="value" Condition="type==RC_OPERAND_RECALL &amp;&amp; memref_access_type==RC_OPERAND_FP">value.dbl</Item>
<Item Name="value" Condition="type!=RC_OPERAND_CONST &amp;&amp; type!=RC_OPERAND_FP &amp;&amp; value.memref==0">value.memref</Item>
<Item Name="value" Condition="type!=RC_OPERAND_CONST &amp;&amp; type!=RC_OPERAND_FP &amp;&amp; ((rc_memref_t*)value.memref)->value.memref_type!=RC_MEMREF_TYPE_MODIFIED_MEMREF">value.memref</Item>
<Item Name="value" Condition="type!=RC_OPERAND_CONST &amp;&amp; type!=RC_OPERAND_FP &amp;&amp; ((rc_memref_t*)value.memref)->value.memref_type==RC_MEMREF_TYPE_MODIFIED_MEMREF">(rc_modified_memref_t*)value.memref</Item>
<Item Name="type">*((__rc_operand_enum_t*)&amp;type)</Item>
<Item Name="size">*((__rc_memsize_enum_t*)&amp;size)</Item>
<Item Name="memref_access_type">*((__rc_operand_enum_t*)&amp;memref_access_type)</Item>
</Expand>
</Type>
<Type Name="__rc_condition_enum_t">
<DisplayString Condition="value==RC_CONDITION_STANDARD">{RC_CONDITION_STANDARD}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_PAUSE_IF">{RC_CONDITION_PAUSE_IF}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_RESET_IF">{RC_CONDITION_RESET_IF}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_MEASURED_IF">{RC_CONDITION_MEASURED_IF}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_TRIGGER">{RC_CONDITION_TRIGGER}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_MEASURED">{RC_CONDITION_MEASURED}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_ADD_SOURCE">{RC_CONDITION_ADD_SOURCE}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_SUB_SOURCE">{RC_CONDITION_SUB_SOURCE}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_ADD_ADDRESS">{RC_CONDITION_ADD_ADDRESS}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_REMEMBER">{RC_CONDITION_REMEMBER}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_ADD_HITS">{RC_CONDITION_ADD_HITS}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_SUB_HITS">{RC_CONDITION_SUB_HITS}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_RESET_NEXT_IF">{RC_CONDITION_RESET_NEXT_IF}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_AND_NEXT">{RC_CONDITION_AND_NEXT}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_OR_NEXT">{RC_CONDITION_OR_NEXT}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_condition_enum_str_t">
<DisplayString Condition="value==RC_CONDITION_STANDARD"></DisplayString>
<DisplayString Condition="value==RC_CONDITION_PAUSE_IF">PauseIf </DisplayString>
<DisplayString Condition="value==RC_CONDITION_RESET_IF">ResetIf </DisplayString>
<DisplayString Condition="value==RC_CONDITION_MEASURED_IF">MeasuredIf </DisplayString>
<DisplayString Condition="value==RC_CONDITION_TRIGGER">Trigger </DisplayString>
<DisplayString Condition="value==RC_CONDITION_MEASURED">Measured </DisplayString>
<DisplayString Condition="value==RC_CONDITION_ADD_SOURCE">AddSource </DisplayString>
<DisplayString Condition="value==RC_CONDITION_SUB_SOURCE">SubSource </DisplayString>
<DisplayString Condition="value==RC_CONDITION_ADD_ADDRESS">AddAddress </DisplayString>
<DisplayString Condition="value==RC_CONDITION_REMEMBER">Remember </DisplayString>
<DisplayString Condition="value==RC_CONDITION_ADD_HITS">AddHits </DisplayString>
<DisplayString Condition="value==RC_CONDITION_SUB_HITS">SubHits </DisplayString>
<DisplayString Condition="value==RC_CONDITION_RESET_NEXT_IF">ResetNextIf </DisplayString>
<DisplayString Condition="value==RC_CONDITION_AND_NEXT">AndNext </DisplayString>
<DisplayString Condition="value==RC_CONDITION_OR_NEXT">OrNext </DisplayString>
<DisplayString>{value} </DisplayString>
</Type>
<Type Name="__rc_operator_enum_t">
<DisplayString Condition="value==RC_OPERATOR_EQ">{RC_OPERATOR_EQ}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_LT">{RC_OPERATOR_LT}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_LE">{RC_OPERATOR_LE}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_GT">{RC_OPERATOR_GT}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_GE">{RC_OPERATOR_GE}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_NE">{RC_OPERATOR_NE}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_NONE">{RC_OPERATOR_NONE}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_MULT">{RC_OPERATOR_MULT}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_DIV">{RC_OPERATOR_DIV}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_AND">{RC_OPERATOR_AND}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_XOR">{RC_OPERATOR_XOR}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_MOD">{RC_OPERATOR_MOD}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_ADD">{RC_OPERATOR_ADD}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_SUB">{RC_OPERATOR_SUB}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_SUB_PARENT">{RC_OPERATOR_SUB_PARENT}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_INDIRECT_READ">{RC_OPERATOR_INDIRECT_READ}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_operator_enum_str_t">
<DisplayString Condition="value==RC_OPERATOR_EQ">==</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_LT">&lt;</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_LE">&lt;=</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_GT">&gt;</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_GE">&gt;=</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_NE">!=</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_NONE"> </DisplayString>
<DisplayString Condition="value==RC_OPERATOR_MULT">*</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_DIV">/</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_AND">&amp;</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_XOR">^</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_MOD">%</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_ADD">+</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_SUB">-</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_SUB_PARENT">subtracted from</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_INDIRECT_READ">$</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_condition_t">
<DisplayString Condition="oper==RC_OPERATOR_NONE &amp;&amp; required_hits==0">{*((__rc_condition_enum_str_t*)&amp;type)} {operand1}</DisplayString>
<DisplayString Condition="oper==RC_OPERATOR_NONE">{*((__rc_condition_enum_str_t*)&amp;type)} {operand1} ({required_hits})</DisplayString>
<DisplayString Condition="required_hits==0">{*((__rc_condition_enum_str_t*)&amp;type)} {operand1} {*((__rc_operator_enum_str_t*)&amp;oper)} {operand2}</DisplayString>
<DisplayString>{*((__rc_condition_enum_str_t*)&amp;type)} {operand1} {*((__rc_operator_enum_str_t*)&amp;oper)} {operand2} ({required_hits})</DisplayString>
<Expand>
<Item Name="type">*((__rc_condition_enum_t*)&amp;type)</Item>
<Item Name="operand1">operand1</Item>
<Item Name="oper">*((__rc_operator_enum_t*)&amp;oper)</Item>
<Item Name="operand2">operand2</Item>
<Item Name="required_hits">required_hits</Item>
<Item Name="current_hits">current_hits</Item>
<Item Name="next">next</Item>
</Expand>
</Type>
<Type Name="rc_condset_t">
<DisplayString>{{count={num_pause_conditions+num_reset_conditions+num_hittarget_conditions+num_measured_conditions+num_other_conditions+num_indirect_conditions}}}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>conditions</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="__rc_condset_list_t">
<DisplayString Condition="first_condset==0">{{}}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first_condset</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="rc_modified_memref_t">
<DisplayString Condition="modifier_type==RC_OPERATOR_INDIRECT_READ">$({parent} + {modifier})</DisplayString>
<DisplayString Condition="modifier_type==RC_OPERATOR_SUB_PARENT">({modifier} - {parent})</DisplayString>
<DisplayString>({parent} {*((__rc_operator_enum_str_t*)&amp;modifier_type)} {modifier})</DisplayString>
<Expand>
<Item Name="value">memref.value</Item>
<Item Name="parent">parent</Item>
<Item Name="modifier_type">*((__rc_operator_enum_t*)&amp;modifier_type)</Item>
<Item Name="modifier">modifier</Item>
</Expand>
</Type>
<Type Name="rc_modified_memref_list_t">
<DisplayString>{{count = {count}}}</DisplayString>
<Expand>
<Item Name="next" Condition="next!=0">next</Item>
<Item Name="count">count</Item>
<Item Name="capacity">capacity</Item>
<ArrayItems>
<Size>count</Size>
<ValuePointer>items</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="__rc_trigger_state_enum_t">
<DisplayString Condition="value==RC_TRIGGER_STATE_INACTIVE">{RC_TRIGGER_STATE_INACTIVE}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_WAITING">{RC_TRIGGER_STATE_WAITING}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_ACTIVE">{RC_TRIGGER_STATE_ACTIVE}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_PAUSED">{RC_TRIGGER_STATE_PAUSED}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_RESET">{RC_TRIGGER_STATE_RESET}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_TRIGGERED">{RC_TRIGGER_STATE_TRIGGERED}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_PRIMED">{RC_TRIGGER_STATE_PRIMED}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_DISABLED">{RC_TRIGGER_STATE_DISABLED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_trigger_t">
<Expand>
<Item Name="state">*((__rc_trigger_state_enum_t*)&amp;state)</Item>
<Item Name="has_hits">*((__rc_bool_enum_t*)&amp;has_hits)</Item>
<Item Name="measured_as_percent">*((__rc_bool_enum_t*)&amp;measured_as_percent)</Item>
<Item Name="requirement">requirement</Item>
<Item Name="alternative">*((__rc_condset_list_t*)&amp;alternative)</Item>
</Expand>
</Type>
<Type Name="rc_value_t">
<DisplayString>{value} {name,s}</DisplayString>
<Expand>
<Item Name="value">value</Item>
<Item Name="conditions">conditions</Item>
<Item Name="name">name</Item>
</Expand>
</Type>
<Type Name="rc_value_list_t">
<DisplayString>{{count = {count}}}</DisplayString>
<Expand>
<Item Name="count">count</Item>
<Item Name="capacity">capacity</Item>
<ArrayItems>
<Size>count</Size>
<ValuePointer>items</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="__rc_lboard_state_enum_t">
<DisplayString Condition="value==RC_LBOARD_STATE_INACTIVE">{RC_LBOARD_STATE_INACTIVE}</DisplayString>
<DisplayString Condition="value==RC_LBOARD_STATE_WAITING">{RC_LBOARD_STATE_WAITING}</DisplayString>
<DisplayString Condition="value==RC_LBOARD_STATE_ACTIVE">{RC_LBOARD_STATE_ACTIVE}</DisplayString>
<DisplayString Condition="value==RC_LBOARD_STATE_STARTED">{RC_LBOARD_STATE_STARTED}</DisplayString>
<DisplayString Condition="value==RC_LBOARD_STATE_CANCELED">{RC_LBOARD_STATE_CANCELED}</DisplayString>
<DisplayString Condition="value==RC_LBOARD_STATE_TRIGGERED">{RC_LBOARD_STATE_TRIGGERED}</DisplayString>
<DisplayString Condition="value==RC_LBOARD_STATE_DISABLED">{RC_LBOARD_STATE_DISABLED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_lboard_t">
<Expand>
<Item Name="state">*((__rc_lboard_state_enum_t*)&amp;state)</Item>
<Item Name="start">start</Item>
<Item Name="submit">submit</Item>
<Item Name="cancel">cancel</Item>
<Item Name="value">value</Item>
</Expand>
</Type>
<Type Name="__rc_format_enum_t">
<DisplayString Condition="value==RC_FORMAT_FRAMES">{RC_FORMAT_FRAMES}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_SECONDS">{RC_FORMAT_SECONDS}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_CENTISECS">{RC_FORMAT_CENTISECS}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_SCORE">{RC_FORMAT_SCORE}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_VALUE">{RC_FORMAT_VALUE}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_MINUTES">{RC_FORMAT_MINUTES}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_SECONDS_AS_MINUTES">{RC_FORMAT_SECONDS_AS_MINUTES}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FLOAT1">{RC_FORMAT_FLOAT1}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FLOAT2">{RC_FORMAT_FLOAT2}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FLOAT3">{RC_FORMAT_FLOAT3}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FLOAT4">{RC_FORMAT_FLOAT4}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FLOAT5">{RC_FORMAT_FLOAT5}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FLOAT6">{RC_FORMAT_FLOAT6}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FIXED1">{RC_FORMAT_FIXED1}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FIXED2">{RC_FORMAT_FIXED2}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FIXED3">{RC_FORMAT_FIXED3}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_TENS">{RC_FORMAT_TENS}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_HUNDREDS">{RC_FORMAT_HUNDREDS}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_THOUSANDS">{RC_FORMAT_THOUSANDS}</DisplayString>
<DisplayString Condition="value==101">RC_FORMAT_STRING (101)</DisplayString>
<DisplayString Condition="value==102">RC_FORMAT_LOOKUP (102)</DisplayString>
<DisplayString Condition="value==103">RC_FORMAT_UNKNOWN_MACRO (103)</DisplayString>
<DisplayString Condition="value==104">RC_FORMAT_ASCIICHAR (104)</DisplayString>
<DisplayString Condition="value==105">RC_FORMAT_UNICODECHAR (105)</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_richpresence_display_part_t">
<DisplayString Condition="display_type==101">{text,s}</DisplayString>
<DisplayString Condition="display_type==103">[Unknown macro]{text,sb}</DisplayString>
<DisplayString Condition="lookup==0">@{text,sb}({value,na})</DisplayString>
<DisplayString>@{lookup->name,sb}({value,na})</DisplayString>
<Expand>
<Item Name="text" Condition="display_type==101||display_type==103">text</Item>
<Item Name="lookup" Condition="display_type!=101&amp;&amp;display_type!=103">lookup</Item>
<Item Name="value" Condition="display_type!=101&amp;&amp;display_type!=103">value</Item>
<Item Name="display_type">*((__rc_format_enum_t*)&amp;display_type)</Item>
</Expand>
</Type>
<Type Name="__rc_richpresence_display_part_list_t">
<DisplayString Condition="display->next->next!=0">{display,na} {display->next,na} {display->next->next,na}</DisplayString>
<DisplayString Condition="display->next!=0">{display,na} {display->next,na}</DisplayString>
<DisplayString>{display,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>display</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="rc_richpresence_display_t">
<Expand>
<Item Name="displays">*((__rc_richpresence_display_part_list_t*)&amp;display)</Item>
<Item Name="trigger">trigger</Item>
</Expand>
</Type>
<Type Name="__rc_richpresence_display_list_t">
<DisplayString Condition="first_display==0">{{NULL}}</DisplayString>
<DisplayString>{(void*)&amp;first_display,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first_display</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="rc_richpresence_lookup_item_t">
<DisplayString Condition="first==last">{first}: {label,na}</DisplayString>
<DisplayString>{first}-{last}: {label,na}</DisplayString>
</Type>
<Type Name="rc_richpresence_lookup_t">
<DisplayString>{name,na}</DisplayString>
<Expand>
<Item Name="name">name</Item>
<Item Name="format">*((__rc_format_enum_t*)&amp;format)</Item>
<Item Name="default_label" Condition="format>101">default_label</Item>
<TreeItems>
<HeadPointer>root</HeadPointer>
<LeftPointer>left</LeftPointer>
<RightPointer>right</RightPointer>
<ValueNode>this</ValueNode>
</TreeItems>
</Expand>
</Type>
<Type Name="__rc_richpresence_lookup_list_t">
<DisplayString Condition="first_lookup==0">{{NULL}}</DisplayString>
<DisplayString>{(void*)&amp;first_lookup,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first_lookup</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="rc_richpresence_t">
<Expand>
<Item Name="displays">((__rc_richpresence_display_list_t*)&amp;first_display)</Item>
<Item Name="lookups">((__rc_richpresence_lookup_list_t*)&amp;first_lookup)</Item>
</Expand>
</Type>
<Type Name="__rc_value_list_t">
<DisplayString Condition="first_value==0">{{NULL}}</DisplayString>
<DisplayString>{(void*)&amp;first_value,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first_value</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="rc_parse_state_t">
<DisplayString>{{offset={offset} addsource_parent={addsource_parent} indirect_parent={indirect_parent}}}</DisplayString>
<Expand>
<Item Name="offset">offset</Item>
<Item Name="memrefs">memrefs</Item>
<Item Name="existing_memrefs">existing_memrefs</Item>
<Item Name="variables" Condition="variables==0">variables</Item>
<Item Name="variables" Condition="variables!=0">((__rc_value_list_t*)&amp;variables)</Item>
<Item Name="addsource_parent">addsource_parent</Item>
<Item Name="addsource_oper">*((__rc_operator_enum_t*)&amp;addsource_oper)</Item>
<Item Name="indirect_parent">indirect_parent</Item>
<Item Name="remember">remember</Item>
<Item Name="is_value">*((__rc_bool_enum_t*)&amp;is_value)</Item>
<Item Name="has_required_hits">*((__rc_bool_enum_t*)&amp;has_required_hits)</Item>
<Item Name="measured_as_percent">*((__rc_bool_enum_t*)&amp;measured_as_percent)</Item>
</Expand>
</Type>
<Type Name="rc_buffer_chunk_t">
<DisplayString>{{used={write-start} size={end-start}}}</DisplayString>
<Expand>
<Item Name="[size]">end-start</Item>
<Item Name="[used]">write-start</Item>
<Item Name="[available]">end-write</Item>
<Item Name="next">next</Item>
</Expand>
</Type>
<Type Name="rc_buffer_t">
<DisplayString></DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>&amp;chunk</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="__rc_runtime_trigger_list_t">
<DisplayString>{{count={runtime.trigger_count}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>runtime.trigger_count</Size>
<ValueNode>runtime.triggers[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="__rc_runtime_lboard_list_t">
<DisplayString>{{count={runtime.lboard_count}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>runtime.lboard_count</Size>
<ValueNode>runtime.lboards[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="rc_runtime_t">
<DisplayString>{{trigger_count={trigger_count} lboard_count={lboard_count}}}</DisplayString>
<Expand>
<Item Name="triggers">*((__rc_runtime_trigger_list_t*)this)</Item>
<Item Name="lboards">*((__rc_runtime_lboard_list_t*)this)</Item>
<Item Name="richpresence">richpresence</Item>
<Item Name="memrefs">memrefs</Item>
</Expand>
</Type>
</AutoVisualizer>

View File

@ -17,6 +17,7 @@ static int rc_validate_memref(const rc_memref_t* memref, char result[], const si
switch (console_id) {
case RC_CONSOLE_NINTENDO:
case RC_CONSOLE_FAMICOM_DISK_SYSTEM:
if (memref->address >= 0x0800 && memref->address <= 0x1FFF) {
snprintf(result, result_size, "Mirror RAM may not be exposed by emulator (address %04X)", memref->address);
return 0;
@ -42,14 +43,19 @@ static int rc_validate_memref(const rc_memref_t* memref, char result[], const si
return 1;
}
int rc_validate_memrefs(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t max_address)
int rc_validate_memrefs(const rc_memrefs_t* memrefs, char result[], const size_t result_size, uint32_t max_address)
{
while (memref) {
if (!rc_validate_memref(memref, result, result_size, 0, max_address))
return 0;
const rc_memref_list_t* memref_list = &memrefs->memrefs;
do {
const rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_stop = memref + memref_list->count;
for (; memref < memref_stop; ++memref) {
if (!rc_validate_memref(memref, result, result_size, 0, max_address))
return 0;
}
memref = memref->next;
}
memref_list = memref_list->next;
} while (memref_list);
return 1;
}
@ -64,15 +70,22 @@ static uint32_t rc_console_max_address(uint32_t console_id)
return 0xFFFFFFFF;
}
int rc_validate_memrefs_for_console(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t console_id)
int rc_validate_memrefs_for_console(const rc_memrefs_t* memrefs, char result[], const size_t result_size, uint32_t console_id)
{
const uint32_t max_address = rc_console_max_address(console_id);
while (memref) {
if (!rc_validate_memref(memref, result, result_size, console_id, max_address))
return 0;
const rc_memref_list_t* memref_list = &memrefs->memrefs;
do
{
const rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_stop = memref + memref_list->count;
for (; memref < memref_stop; ++memref)
{
if (!rc_validate_memref(memref, result, result_size, console_id, max_address))
return 0;
}
memref = memref->next;
}
memref_list = memref_list->next;
} while (memref_list);
return 1;
}
@ -104,6 +117,7 @@ static uint32_t rc_max_value(const rc_operand_t* operand)
return 8;
case RC_MEMSIZE_8_BITS:
/* NOTE: BCD should max out at 0x99, but because each digit can be 15, it actually maxes at 15*10 + 15 */
return (operand->type == RC_OPERAND_BCD) ? 165 : 0xFF;
case RC_MEMSIZE_16_BITS:
@ -160,10 +174,18 @@ static uint32_t rc_scale_value(uint32_t value, uint8_t oper, const rc_operand_t*
case RC_OPERATOR_SUB:
{
if (operand->type == RC_OPERAND_CONST)
return value - operand->value.num;
else if (value > rc_max_value(operand))
return value - rc_max_value(operand);
const uint32_t op_max = (operand->type == RC_OPERAND_CONST) ? operand->value.num : rc_max_value(operand);
if (value > op_max)
return value - op_max;
return 0xFFFFFFFF;
}
case RC_OPERATOR_SUB_PARENT:
{
const uint32_t op_max = (operand->type == RC_OPERAND_CONST) ? operand->value.num : rc_max_value(operand);
if (op_max > value)
return op_max - value;
return 0xFFFFFFFF;
}
@ -173,6 +195,17 @@ static uint32_t rc_scale_value(uint32_t value, uint8_t oper, const rc_operand_t*
}
}
static uint32_t rc_max_chain_value(const rc_operand_t* operand)
{
if (rc_operand_is_memref(operand) && operand->value.memref->value.memref_type == RC_MEMREF_TYPE_MODIFIED_MEMREF) {
const rc_modified_memref_t* modified_memref = (const rc_modified_memref_t*)operand->value.memref;
const uint32_t op_max = rc_max_chain_value(&modified_memref->parent);
return rc_scale_value(op_max, modified_memref->modifier_type, &modified_memref->modifier);
}
return rc_max_value(operand);
}
static int rc_validate_get_condition_index(const rc_condset_t* condset, const rc_condition_t* condition)
{
int index = 1;
@ -256,18 +289,14 @@ static int rc_validate_range(uint32_t min_val, uint32_t max_val, char oper, uint
return 1;
}
int rc_validate_condset_internal(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t console_id, uint32_t max_address)
static int rc_validate_condset_internal(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t console_id, uint32_t max_address)
{
const rc_condition_t* cond;
char buffer[128];
uint32_t max_val;
int index = 1;
unsigned long long add_source_max = 0;
int in_add_hits = 0;
int in_add_address = 0;
int is_combining = 0;
int remember_used = 0;
int remember_used_in_pause = 0;
if (!condset) {
*result = '\0';
@ -275,10 +304,8 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
}
for (cond = condset->conditions; cond; cond = cond->next, ++index) {
uint32_t max = rc_max_value(&cond->operand1);
const int is_memref1 = rc_operand_is_memref(&cond->operand1);
const int is_memref2 = rc_operand_is_memref(&cond->operand2);
const int uses_recall = rc_operand_is_recall(&cond->operand1) || rc_operand_is_recall(&cond->operand2);
if (!in_add_address) {
if (is_memref1 && !rc_validate_memref(cond->operand1.value.memref, buffer, sizeof(buffer), console_id, max_address)) {
@ -294,39 +321,24 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
in_add_address = 0;
}
if (!remember_used && uses_recall) {
if (!cond->pause && condset->has_pause) {
/* pause conditions will be processed before non-pause conditions.
* scan forward for any remembers in yet-to-be-processed pause conditions */
const rc_condition_t* cond_rem_pause_check = cond->next;
for (; cond_rem_pause_check; cond_rem_pause_check = cond_rem_pause_check->next) {
if (cond_rem_pause_check->type == RC_CONDITION_REMEMBER && cond_rem_pause_check->pause) {
remember_used = 1; /* do not set remember_used_in_pause here because we don't know at which poing in the pause processing this remember is occurring. */
break;
}
}
}
if (!remember_used) {
if (rc_operand_is_recall(&cond->operand1)) {
if (rc_operand_type_is_memref(cond->operand1.memref_access_type) && !cond->operand1.value.memref) {
snprintf(result, result_size, "Condition %d: Recall used before Remember", index);
return 0;
}
}
else if (cond->pause && uses_recall && !remember_used_in_pause) {
snprintf(result, result_size, "Condition %d: Recall used in Pause processing before Remember was used in Pause processing", index);
return 0;
if (rc_operand_is_recall(&cond->operand2)) {
if (rc_operand_type_is_memref(cond->operand2.memref_access_type) && !cond->operand2.value.memref) {
snprintf(result, result_size, "Condition %d: Recall used before Remember", index);
return 0;
}
}
switch (cond->type) {
case RC_CONDITION_ADD_SOURCE:
max = rc_scale_value(max, cond->oper, &cond->operand2);
add_source_max += max;
is_combining = 1;
continue;
case RC_CONDITION_SUB_SOURCE:
max = rc_scale_value(max, cond->oper, &cond->operand2);
if (add_source_max < max) /* potential underflow - may be expected */
add_source_max = 0xFFFFFFFF;
case RC_CONDITION_REMEMBER:
is_combining = 1;
continue;
@ -339,12 +351,6 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
is_combining = 1;
continue;
case RC_CONDITION_REMEMBER:
is_combining = 1;
remember_used = 1;
remember_used_in_pause += cond->pause;
continue;
case RC_CONDITION_ADD_HITS:
case RC_CONDITION_SUB_HITS:
in_add_hits = 1;
@ -377,18 +383,11 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
break;
}
/* if we're in an add source chain, check for overflow */
if (add_source_max) {
const unsigned long long overflow = add_source_max + max;
if (overflow > 0xFFFFFFFFUL)
max = 0xFFFFFFFF;
else
max += (unsigned)add_source_max;
}
/* check for comparing two differently sized memrefs */
max_val = rc_max_value(&cond->operand2);
if (max_val != max && add_source_max == 0 && is_memref1 && is_memref2) {
if (is_memref1 && is_memref2 &&
cond->operand1.value.memref->value.memref_type == RC_MEMREF_TYPE_MEMREF &&
cond->operand2.value.memref->value.memref_type == RC_MEMREF_TYPE_MEMREF &&
rc_max_value(&cond->operand1) != rc_max_value(&cond->operand2)) {
snprintf(result, result_size, "Condition %d: Comparing different memory sizes", index);
return 0;
}
@ -396,19 +395,23 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
if (is_memref1 && rc_operand_is_float(&cond->operand1)) {
/* if left side is a float, right side will be converted to a float, so don't do range validation */
}
else if (is_memref1 || is_memref2 || add_source_max) {
/* if either side is a memref, or there's a running add source chain, check for impossible comparisons */
else if (is_memref1 || is_memref2) {
/* if either side is a memref, check for impossible comparisons */
const size_t prefix_length = snprintf(result, result_size, "Condition %d: ", index);
const rc_operand_t* operand1 = &cond->operand1;
const rc_operand_t* operand2 = &cond->operand2;
uint8_t oper = cond->oper;
uint32_t max = rc_max_chain_value(operand1);
uint32_t max_val = rc_max_value(operand2);
uint32_t min_val;
if (!is_memref1 && !add_source_max) {
if (!is_memref1) {
/* pretend constant was on right side */
operand1 = &cond->operand2;
operand2 = &cond->operand1;
max = max_val;
max_val = max;
max = rc_max_value(&cond->operand2);
switch (oper) {
case RC_OPERATOR_LT: oper = RC_OPERATOR_GT; break;
case RC_OPERATOR_LE: oper = RC_OPERATOR_GE; break;
@ -426,8 +429,7 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
min_val = (int)operand2->value.dbl;
/* cannot compare an integer memory reference to a non-integral floating point value */
if (!add_source_max && !rc_operand_is_float_memref(operand1) &&
(float)min_val != operand2->value.dbl) {
if (!rc_operand_is_float_memref(operand1) && (float)min_val != operand2->value.dbl) {
switch (oper) {
case RC_OPERATOR_EQ:
snprintf(result + prefix_length, result_size - prefix_length, "Comparison is never true");
@ -455,8 +457,6 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
if (!rc_validate_range(min_val, max_val, oper, max, result + prefix_length, result_size - prefix_length))
return 0;
}
add_source_max = 0;
}
if (is_combining) {
@ -697,24 +697,6 @@ static int rc_validate_comparison_overlap(int comparison1, uint32_t value1, int
return RC_OVERLAP_NONE;
}
static int rc_validate_are_operands_equal(const rc_operand_t* oper1, const rc_operand_t* oper2)
{
if (oper1->type != oper2->type)
return 0;
switch (oper1->type)
{
case RC_OPERAND_CONST:
return (oper1->value.num == oper2->value.num);
case RC_OPERAND_FP:
return (oper1->value.dbl == oper2->value.dbl);
case RC_OPERAND_RECALL:
return (oper2->type == RC_OPERAND_RECALL);
default:
return (oper1->value.memref->address == oper2->value.memref->address && oper1->size == oper2->size);
}
}
static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, const rc_condset_t* compare_conditions,
const char* prefix, const char* compare_prefix, char result[], const size_t result_size)
{
@ -736,7 +718,7 @@ static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, co
for (condition = conditions->conditions; condition != NULL; condition = condition->next)
{
condition_chain_start = condition;
while (rc_condition_is_combining(condition))
while (condition && rc_condition_is_combining(condition))
condition = condition->next;
if (!condition)
break;
@ -787,14 +769,14 @@ static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, co
if (compare_condition->type != condition_chain_iter->type ||
compare_condition->oper != condition_chain_iter->oper ||
compare_condition->required_hits != condition_chain_iter->required_hits ||
!rc_validate_are_operands_equal(&compare_condition->operand1, &condition_chain_iter->operand1))
!rc_operands_are_equal(&compare_condition->operand1, &condition_chain_iter->operand1))
{
chain_matches = 0;
break;
}
if (compare_condition->oper != RC_OPERATOR_NONE &&
!rc_validate_are_operands_equal(&compare_condition->operand2, &condition_chain_iter->operand2))
!rc_operands_are_equal(&compare_condition->operand2, &condition_chain_iter->operand2))
{
chain_matches = 0;
break;

View File

@ -7,13 +7,9 @@
RC_BEGIN_C_DECLS
int rc_validate_memrefs(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t max_address);
int rc_validate_condset(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t max_address);
int rc_validate_trigger(const rc_trigger_t* trigger, char result[], const size_t result_size, uint32_t max_address);
int rc_validate_memrefs_for_console(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t console_id);
int rc_validate_condset_for_console(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t console_id);
int rc_validate_trigger_for_console(const rc_trigger_t* trigger, char result[], const size_t result_size, uint32_t console_id);

View File

@ -13,29 +13,67 @@ enum {
RC_FORMAT_UNICODECHAR = 105
};
static rc_memref_value_t* rc_alloc_helper_variable_memref_value(const char* memaddr, int memaddr_len, rc_parse_state_t* parse) {
const char* end;
rc_value_t* variable;
uint32_t address;
uint8_t size;
static void rc_alloc_helper_variable_memref_value(rc_richpresence_display_part_t* part, const char* memaddr, int memaddr_len, rc_parse_state_t* parse) {
rc_preparse_state_t preparse;
const char* test_memaddr = memaddr;
rc_condset_t* condset;
rc_value_t* value;
int32_t size;
/* single memory reference lookups without a modifier flag can be handled without a variable */
end = memaddr;
if (rc_parse_memref(&end, &size, &address) == RC_OK) {
/* make sure the entire memaddr was consumed. if not, there's an operator and it's a comparison, not a memory reference */
if (end == &memaddr[memaddr_len]) {
/* if it's not a derived size, we can reference the memref directly */
if (rc_memref_shared_size(size) == size)
return &rc_alloc_memref(parse, address, size, 0)->value;
part->value.type = RC_OPERAND_NONE;
/* if the expression can be represented as just a memory reference, do so */
rc_init_preparse_state(&preparse, NULL, 0);
preparse.parse.existing_memrefs = parse->memrefs;
value = RC_ALLOC(rc_value_t, &preparse.parse);
rc_parse_value_internal(value, &test_memaddr, &preparse.parse);
size = preparse.parse.offset;
if (size < 0) {
parse->offset = size;
rc_destroy_preparse_state(&preparse);
return;
}
/* ensure new needed memrefs are allocated in the primary buffer */
rc_preparse_copy_memrefs(parse, &preparse.memrefs);
/* parse the value into the scratch buffer so we can look at it */
rc_reset_parse_state(&preparse.parse, rc_buffer_alloc(&preparse.parse.scratch.buffer, (size_t)size), NULL, 0);
preparse.parse.memrefs = parse->memrefs;
preparse.parse.existing_memrefs = parse->existing_memrefs;
value = RC_ALLOC(rc_value_t, &preparse.parse);
test_memaddr = memaddr;
rc_parse_value_internal(value, &test_memaddr, &preparse.parse);
condset = value->conditions;
if (condset && !condset->next) {
/* single value - if it's only "measured" and "indirect" conditions, we can simplify to a memref */
if (condset->num_measured_conditions &&
!condset->num_pause_conditions && !condset->num_reset_conditions &&
!condset->num_other_conditions && !condset->num_hittarget_conditions) {
rc_condition_t* condition = condset->conditions;
for (; condition; condition = condition->next) {
if (condition->type == RC_CONDITION_MEASURED && condition->required_hits == 0) {
memcpy(&part->value, &condition->operand1, sizeof(condition->operand1));
break;
}
}
}
}
/* not a simple memory reference, need to create a variable */
variable = rc_alloc_helper_variable(memaddr, memaddr_len, parse);
if (!variable)
return NULL;
rc_destroy_preparse_state(&preparse);
return &variable->value;
/* could not express value with just a memory reference, create a helper variable */
if (part->value.type == RC_OPERAND_NONE) {
value = rc_alloc_variable(memaddr, memaddr_len, parse);
if (value) {
part->value.value.memref = (rc_memref_t*)&value->value;
part->value.type = RC_OPERAND_ADDRESS;
part->value.size = RC_MEMSIZE_32_BITS;
part->value.memref_access_type = RC_OPERAND_ADDRESS;
}
}
}
static const char* rc_parse_line(const char* line, const char** end, rc_parse_state_t* parse) {
@ -220,7 +258,7 @@ static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const c
part->text = rc_alloc_str(parse, in, (int)(ptr - in));
}
else if (part->display_type != RC_FORMAT_UNKNOWN_MACRO) {
part->value = rc_alloc_helper_variable_memref_value(line, (int)(ptr - line), parse);
rc_alloc_helper_variable_memref_value(part, line, (int)(ptr - line), parse);
if (parse->offset < 0)
return 0;
@ -468,6 +506,8 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
int display_line = 0;
int chars;
self->values = NULL;
/* special case for empty script to return 1 line read */
if (!*script) {
parse->lines_read = 1;
@ -558,11 +598,20 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
*nextdisplay = rc_parse_richpresence_display_internal(ptr + 1, endline, parse, firstlookup);
if (parse->offset < 0)
return;
trigger = &((*nextdisplay)->trigger);
rc_parse_trigger_internal(trigger, &line, parse);
trigger->memrefs = 0;
if (parse->offset < 0)
return;
if (line != ptr) {
/* incomplete read */
parse->offset = RC_INVALID_OPERATOR;
return;
}
(*nextdisplay)->has_required_hits = parse->has_required_hits;
if (parse->buffer)
nextdisplay = &((*nextdisplay)->next);
}
@ -593,6 +642,7 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
/* finalize */
*nextdisplay = 0;
self->has_memrefs = 0;
if (!hasdisplay && parse->offset > 0) {
parse->offset = RC_MISSING_DISPLAY_STRING;
@ -600,22 +650,20 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
}
int rc_richpresence_size_lines(const char* script, int* lines_read) {
rc_richpresence_t* self;
rc_parse_state_t parse;
rc_memref_t* first_memref;
rc_value_t* variables;
rc_init_parse_state(&parse, 0, 0, 0);
rc_init_parse_state_memrefs(&parse, &first_memref);
rc_init_parse_state_variables(&parse, &variables);
rc_richpresence_with_memrefs_t* richpresence;
rc_preparse_state_t preparse;
rc_init_preparse_state(&preparse, NULL, 0);
self = RC_ALLOC(rc_richpresence_t, &parse);
rc_parse_richpresence_internal(self, script, &parse);
richpresence = RC_ALLOC(rc_richpresence_with_memrefs_t, &preparse.parse);
preparse.parse.variables = &richpresence->richpresence.values;
rc_parse_richpresence_internal(&richpresence->richpresence, script, &preparse.parse);
rc_preparse_alloc_memrefs(NULL, &preparse);
if (lines_read)
*lines_read = parse.lines_read;
*lines_read = preparse.parse.lines_read;
rc_destroy_parse_state(&parse);
return parse.offset;
rc_destroy_preparse_state(&preparse);
return preparse.parse.offset;
}
int rc_richpresence_size(const char* script) {
@ -623,32 +671,53 @@ int rc_richpresence_size(const char* script) {
}
rc_richpresence_t* rc_parse_richpresence(void* buffer, const char* script, lua_State* L, int funcs_ndx) {
rc_richpresence_t* self;
rc_parse_state_t parse;
rc_richpresence_with_memrefs_t* richpresence;
rc_preparse_state_t preparse;
if (!buffer || !script)
return NULL;
rc_init_parse_state(&parse, buffer, L, funcs_ndx);
rc_init_preparse_state(&preparse, L, funcs_ndx);
richpresence = RC_ALLOC(rc_richpresence_with_memrefs_t, &preparse.parse);
preparse.parse.variables = &richpresence->richpresence.values;
rc_parse_richpresence_internal(&richpresence->richpresence, script, &preparse.parse);
self = RC_ALLOC(rc_richpresence_t, &parse);
rc_init_parse_state_memrefs(&parse, &self->memrefs);
rc_init_parse_state_variables(&parse, &self->variables);
rc_reset_parse_state(&preparse.parse, buffer, L, funcs_ndx);
richpresence = RC_ALLOC(rc_richpresence_with_memrefs_t, &preparse.parse);
preparse.parse.variables = &richpresence->richpresence.values;
rc_preparse_alloc_memrefs(&richpresence->memrefs, &preparse);
rc_parse_richpresence_internal(self, script, &parse);
rc_parse_richpresence_internal(&richpresence->richpresence, script, &preparse.parse);
richpresence->richpresence.has_memrefs = 1;
rc_destroy_parse_state(&parse);
return (parse.offset >= 0) ? self : NULL;
rc_destroy_preparse_state(&preparse);
return (preparse.parse.offset >= 0) ? &richpresence->richpresence : NULL;
}
static void rc_update_richpresence_memrefs(rc_richpresence_t* self, rc_peek_t peek, void* ud) {
if (self->has_memrefs) {
rc_richpresence_with_memrefs_t* richpresence = (rc_richpresence_with_memrefs_t*)self;
rc_update_memref_values(&richpresence->memrefs, peek, ud);
}
}
rc_memrefs_t* rc_richpresence_get_memrefs(rc_richpresence_t* self) {
if (self->has_memrefs) {
rc_richpresence_with_memrefs_t* richpresence = (rc_richpresence_with_memrefs_t*)self;
return &richpresence->memrefs;
}
return NULL;
}
void rc_update_richpresence(rc_richpresence_t* richpresence, rc_peek_t peek, void* peek_ud, lua_State* L) {
rc_richpresence_display_t* display;
rc_update_memref_values(richpresence->memrefs, peek, peek_ud);
rc_update_variables(richpresence->variables, peek, peek_ud, L);
rc_update_richpresence_memrefs(richpresence, peek, peek_ud);
rc_update_values(richpresence->values, peek, peek_ud, L);
for (display = richpresence->first_display; display; display = display->next) {
if (display->trigger.has_required_hits)
if (display->has_required_hits)
rc_test_trigger(&display->trigger, peek, peek_ud, L);
}
}
@ -671,7 +740,7 @@ static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part
break;
case RC_FORMAT_LOOKUP:
rc_typed_value_from_memref_value(&value, part->value);
rc_evaluate_operand(&value, &part->value, NULL);
rc_typed_value_convert(&value, RC_VALUE_TYPE_UNSIGNED);
text = part->lookup->default_label;
@ -698,7 +767,7 @@ static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part
value.type = RC_VALUE_TYPE_UNSIGNED;
do {
value.value.u32 = part->value->value;
rc_evaluate_operand(&value, &part->value, NULL);
if (value.value.u32 == 0) {
/* null terminator - skip over remaining character macros */
while (part->next && part->next->display_type == RC_FORMAT_ASCIICHAR)
@ -725,7 +794,7 @@ static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part
value.type = RC_VALUE_TYPE_UNSIGNED;
do {
value.value.u32 = part->value->value;
rc_evaluate_operand(&value, &part->value, NULL);
if (value.value.u32 == 0) {
/* null terminator - skip over remaining character macros */
while (part->next && part->next->display_type == RC_FORMAT_UNICODECHAR)
@ -770,7 +839,7 @@ static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part
break;
default:
rc_typed_value_from_memref_value(&value, part->value);
rc_evaluate_operand(&value, &part->value, NULL);
chars = rc_format_typed_value(tmp, sizeof(tmp), &value, part->display_type);
text = tmp;
break;
@ -806,7 +875,7 @@ int rc_get_richpresence_display_string(rc_richpresence_t* richpresence, char* bu
return rc_evaluate_richpresence_display(display->display, buffer, buffersize);
/* triggers with required hits will be updated in rc_update_richpresence */
if (!display->trigger.has_required_hits)
if (!display->has_required_hits)
rc_test_trigger(&display->trigger, peek, peek_ud, L);
/* if we've found a valid condition, process it */
@ -823,15 +892,16 @@ int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, size
return rc_get_richpresence_display_string(richpresence, buffer, buffersize, peek, peek_ud, L);
}
void rc_reset_richpresence(rc_richpresence_t* self) {
void rc_reset_richpresence_triggers(rc_richpresence_t* self) {
rc_richpresence_display_t* display;
rc_value_t* variable;
for (display = self->first_display; display; display = display->next)
rc_reset_trigger(&display->trigger);
}
for (variable = self->variables; variable; variable = variable->next)
rc_reset_value(variable);
void rc_reset_richpresence(rc_richpresence_t* self) {
rc_reset_richpresence_triggers(self);
rc_reset_values(self->values);
}
static int rc_get_richpresence_strings_has_string(const char** buffer, size_t written, const char* search) {

View File

@ -9,8 +9,34 @@
#define RC_RICHPRESENCE_DISPLAY_BUFFER_SIZE 256
/* ===== natvis extensions ===== */
typedef struct __rc_runtime_trigger_list_t { rc_runtime_t runtime; } __rc_runtime_trigger_list_t;
typedef struct __rc_runtime_lboard_list_t { rc_runtime_t runtime; } __rc_runtime_lboard_list_t;
static void rc_runtime_natvis_helper(const rc_runtime_event_t* runtime_event)
{
struct natvis_extensions {
__rc_runtime_trigger_list_t trigger_list;
__rc_runtime_lboard_list_t lboard_list;
} natvis;
memset(&natvis, 0, sizeof(natvis));
(void)runtime_event;
natvis.lboard_list.runtime.lboard_count = 0;
}
/* ============================= */
rc_runtime_t* rc_runtime_alloc(void) {
rc_runtime_t* self = malloc(sizeof(rc_runtime_t));
rc_runtime_t* self;
/* create a reference to rc_runtime_natvis_helper so the extensions get compiled in. */
rc_runtime_event_handler_t unused = &rc_runtime_natvis_helper;
(void)unused;
self = malloc(sizeof(rc_runtime_t));
if (self) {
rc_runtime_init(self);
@ -22,16 +48,19 @@ rc_runtime_t* rc_runtime_alloc(void) {
void rc_runtime_init(rc_runtime_t* self) {
memset(self, 0, sizeof(rc_runtime_t));
self->next_memref = &self->memrefs;
self->next_variable = &self->variables;
self->memrefs = (rc_memrefs_t*)malloc(sizeof(*self->memrefs));
rc_memrefs_init(self->memrefs);
}
void rc_runtime_destroy(rc_runtime_t* self) {
uint32_t i;
if (self->triggers) {
for (i = 0; i < self->trigger_count; ++i)
free(self->triggers[i].buffer);
for (i = 0; i < self->trigger_count; ++i) {
if (self->triggers[i].buffer)
free(self->triggers[i].buffer);
}
free(self->triggers);
self->triggers = NULL;
@ -40,8 +69,10 @@ void rc_runtime_destroy(rc_runtime_t* self) {
}
if (self->lboards) {
for (i = 0; i < self->lboard_count; ++i)
free(self->lboards[i].buffer);
for (i = 0; i < self->lboard_count; ++i) {
if (self->lboards[i].buffer)
free(self->lboards[i].buffer);
}
free(self->lboards);
self->lboards = NULL;
@ -49,20 +80,17 @@ void rc_runtime_destroy(rc_runtime_t* self) {
self->lboard_count = self->lboard_capacity = 0;
}
while (self->richpresence) {
rc_runtime_richpresence_t* previous = self->richpresence->previous;
free(self->richpresence->buffer);
if (self->richpresence) {
if (self->richpresence->buffer)
free(self->richpresence->buffer);
free(self->richpresence);
self->richpresence = previous;
}
self->next_memref = 0;
self->memrefs = 0;
if (self->memrefs)
rc_memrefs_destroy(self->memrefs);
if (self->owns_self) {
if (self->owns_self)
free(self);
}
}
void rc_runtime_checksum(const char* memaddr, uint8_t* md5) {
@ -72,45 +100,12 @@ void rc_runtime_checksum(const char* memaddr, uint8_t* md5) {
md5_finish(&state, md5);
}
static char rc_runtime_allocated_memrefs(rc_runtime_t* self) {
char owns_memref = 0;
/* if at least one memref was allocated within the object, we can't free the buffer when the object is deactivated */
if (*self->next_memref != NULL) {
owns_memref = 1;
/* advance through the new memrefs so we're ready for the next allocation */
do {
self->next_memref = &(*self->next_memref)->next;
} while (*self->next_memref != NULL);
}
/* if at least one variable was allocated within the object, we can't free the buffer when the object is deactivated */
if (*self->next_variable != NULL) {
owns_memref = 1;
/* advance through the new variables so we're ready for the next allocation */
do {
self->next_variable = &(*self->next_variable)->next;
} while (*self->next_variable != NULL);
}
return owns_memref;
}
static void rc_runtime_deactivate_trigger_by_index(rc_runtime_t* self, uint32_t index) {
if (self->triggers[index].owns_memrefs) {
/* if the trigger has one or more memrefs in its buffer, we can't free the buffer.
* just null out the trigger so the runtime processor will skip it
*/
rc_reset_trigger(self->triggers[index].trigger);
self->triggers[index].trigger = NULL;
}
else {
/* trigger doesn't own any memrefs, go ahead and free it, then replace it with the last trigger */
free(self->triggers[index].buffer);
/* free the trigger, then replace it with the last trigger */
free(self->triggers[index].buffer);
if (--self->trigger_count > index)
memcpy(&self->triggers[index], &self->triggers[self->trigger_count], sizeof(rc_runtime_trigger_t));
}
if (--self->trigger_count > index)
memcpy(&self->triggers[index], &self->triggers[self->trigger_count], sizeof(rc_runtime_trigger_t));
}
void rc_runtime_deactivate_achievement(rc_runtime_t* self, uint32_t id) {
@ -126,7 +121,8 @@ int rc_runtime_activate_achievement(rc_runtime_t* self, uint32_t id, const char*
void* trigger_buffer;
rc_trigger_t* trigger;
rc_runtime_trigger_t* runtime_trigger;
rc_parse_state_t parse;
rc_preparse_state_t preparse;
const char* preparse_memaddr = memaddr;
uint8_t md5[16];
int32_t size;
uint32_t i;
@ -169,7 +165,12 @@ int rc_runtime_activate_achievement(rc_runtime_t* self, uint32_t id, const char*
}
/* item has not been previously registered, determine how much space we need for it, and allocate it */
size = rc_trigger_size(memaddr);
rc_init_preparse_state(&preparse, NULL, 0);
preparse.parse.existing_memrefs = self->memrefs;
trigger = RC_ALLOC(rc_trigger_t, &preparse.parse);
rc_parse_trigger_internal(trigger, &preparse_memaddr, &preparse.parse);
size = preparse.parse.offset;
if (size < 0)
return size;
@ -178,16 +179,15 @@ int rc_runtime_activate_achievement(rc_runtime_t* self, uint32_t id, const char*
return RC_OUT_OF_MEMORY;
/* populate the item, using the communal memrefs pool */
rc_init_parse_state(&parse, trigger_buffer, L, funcs_idx);
parse.first_memref = &self->memrefs;
trigger = RC_ALLOC(rc_trigger_t, &parse);
rc_parse_trigger_internal(trigger, &memaddr, &parse);
rc_destroy_parse_state(&parse);
rc_reset_parse_state(&preparse.parse, trigger_buffer, L, funcs_idx);
rc_preparse_reserve_memrefs(&preparse, self->memrefs);
trigger = RC_ALLOC(rc_trigger_t, &preparse.parse);
rc_parse_trigger_internal(trigger, &memaddr, &preparse.parse);
rc_destroy_preparse_state(&preparse);
if (parse.offset < 0) {
if (preparse.parse.offset < 0) {
free(trigger_buffer);
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
return parse.offset;
return preparse.parse.offset;
}
/* grow the trigger buffer if necessary */
@ -200,7 +200,6 @@ int rc_runtime_activate_achievement(rc_runtime_t* self, uint32_t id, const char*
if (!self->triggers) {
free(trigger_buffer);
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
return RC_OUT_OF_MEMORY;
}
}
@ -213,11 +212,9 @@ int rc_runtime_activate_achievement(rc_runtime_t* self, uint32_t id, const char*
runtime_trigger->invalid_memref = NULL;
memcpy(runtime_trigger->md5, md5, 16);
runtime_trigger->serialized_size = 0;
runtime_trigger->owns_memrefs = rc_runtime_allocated_memrefs(self);
++self->trigger_count;
/* reset it, and return it */
trigger->memrefs = NULL;
rc_reset_trigger(trigger);
return RC_OK;
}
@ -285,20 +282,11 @@ int rc_runtime_format_achievement_measured(const rc_runtime_t* runtime, uint32_t
}
static void rc_runtime_deactivate_lboard_by_index(rc_runtime_t* self, uint32_t index) {
if (self->lboards[index].owns_memrefs) {
/* if the lboard has one or more memrefs in its buffer, we can't free the buffer.
* just null out the lboard so the runtime processor will skip it
*/
rc_reset_lboard(self->lboards[index].lboard);
self->lboards[index].lboard = NULL;
}
else {
/* lboard doesn't own any memrefs, go ahead and free it, then replace it with the last lboard */
free(self->lboards[index].buffer);
/* free the lboard, then replace it with the last lboard */
free(self->lboards[index].buffer);
if (--self->lboard_count > index)
memcpy(&self->lboards[index], &self->lboards[self->lboard_count], sizeof(rc_runtime_lboard_t));
}
if (--self->lboard_count > index)
memcpy(&self->lboards[index], &self->lboards[self->lboard_count], sizeof(rc_runtime_lboard_t));
}
void rc_runtime_deactivate_lboard(rc_runtime_t* self, uint32_t id) {
@ -314,7 +302,7 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, uint32_t id, const char* mema
void* lboard_buffer;
uint8_t md5[16];
rc_lboard_t* lboard;
rc_parse_state_t parse;
rc_preparse_state_t preparse;
rc_runtime_lboard_t* runtime_lboard;
int size;
uint32_t i;
@ -357,7 +345,12 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, uint32_t id, const char* mema
}
/* item has not been previously registered, determine how much space we need for it, and allocate it */
size = rc_lboard_size(memaddr);
rc_init_preparse_state(&preparse, NULL, 0);
preparse.parse.existing_memrefs = self->memrefs;
lboard = RC_ALLOC(rc_lboard_t, &preparse.parse);
rc_parse_lboard_internal(lboard, memaddr, &preparse.parse);
size = preparse.parse.offset;
if (size < 0)
return size;
@ -366,16 +359,15 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, uint32_t id, const char* mema
return RC_OUT_OF_MEMORY;
/* populate the item, using the communal memrefs pool */
rc_init_parse_state(&parse, lboard_buffer, L, funcs_idx);
lboard = RC_ALLOC(rc_lboard_t, &parse);
parse.first_memref = &self->memrefs;
rc_parse_lboard_internal(lboard, memaddr, &parse);
rc_destroy_parse_state(&parse);
rc_reset_parse_state(&preparse.parse, lboard_buffer, L, funcs_idx);
rc_preparse_reserve_memrefs(&preparse, self->memrefs);
lboard = RC_ALLOC(rc_lboard_t, &preparse.parse);
rc_parse_lboard_internal(lboard, memaddr, &preparse.parse);
rc_destroy_preparse_state(&preparse);
if (parse.offset < 0) {
if (preparse.parse.offset < 0) {
free(lboard_buffer);
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
return parse.offset;
return preparse.parse.offset;
}
/* grow the lboard buffer if necessary */
@ -388,7 +380,6 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, uint32_t id, const char* mema
if (!self->lboards) {
free(lboard_buffer);
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
return RC_OUT_OF_MEMORY;
}
}
@ -402,10 +393,8 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, uint32_t id, const char* mema
runtime_lboard->invalid_memref = NULL;
memcpy(runtime_lboard->md5, md5, 16);
runtime_lboard->serialized_size = 0;
runtime_lboard->owns_memrefs = rc_runtime_allocated_memrefs(self);
/* reset it, and return it */
lboard->memrefs = NULL;
rc_reset_lboard(lboard);
return RC_OK;
}
@ -429,9 +418,7 @@ int rc_runtime_format_lboard_value(char* buffer, int size, int32_t value, int fo
int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua_State* L, int funcs_idx) {
rc_richpresence_t* richpresence;
rc_runtime_richpresence_t* previous;
rc_runtime_richpresence_t** previous_ptr;
rc_parse_state_t parse;
rc_preparse_state_t preparse;
uint8_t md5[16];
int size;
@ -441,47 +428,29 @@ int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua
rc_runtime_checksum(script, md5);
/* look for existing match */
previous_ptr = NULL;
previous = self->richpresence;
while (previous) {
if (previous && self->richpresence->richpresence && memcmp(self->richpresence->md5, md5, 16) == 0) {
/* unchanged. reset all of the conditions */
rc_reset_richpresence(self->richpresence->richpresence);
if (self->richpresence && self->richpresence->richpresence && memcmp(self->richpresence->md5, md5, 16) == 0) {
/* unchanged. reset all of the conditions */
rc_reset_richpresence(self->richpresence->richpresence);
/* move to front of linked list*/
if (previous_ptr) {
*previous_ptr = previous->previous;
if (!self->richpresence->owns_memrefs) {
free(self->richpresence->buffer);
previous->previous = self->richpresence->previous;
}
else {
previous->previous = self->richpresence;
}
self->richpresence = previous;
}
/* return success*/
return RC_OK;
}
previous_ptr = &previous->previous;
previous = previous->previous;
/* return success*/
return RC_OK;
}
/* no existing match found, parse script */
size = rc_richpresence_size(script);
rc_init_preparse_state(&preparse, NULL, 0);
preparse.parse.existing_memrefs = self->memrefs;
richpresence = RC_ALLOC(rc_richpresence_t, &preparse.parse);
preparse.parse.variables = &richpresence->values;
rc_parse_richpresence_internal(richpresence, script, &preparse.parse);
size = preparse.parse.offset;
if (size < 0)
return size;
/* if the previous script doesn't have any memrefs, free it */
previous = self->richpresence;
if (previous) {
if (!previous->owns_memrefs) {
free(previous->buffer);
previous = previous->previous;
}
/* if there's a previous script, free it */
if (self->richpresence) {
free(self->richpresence->buffer);
free(self->richpresence);
}
/* allocate and process the new script */
@ -489,34 +458,26 @@ int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua
if (!self->richpresence)
return RC_OUT_OF_MEMORY;
self->richpresence->previous = previous;
self->richpresence->owns_memrefs = 0;
memcpy(self->richpresence->md5, md5, sizeof(md5));
self->richpresence->buffer = malloc(size);
self->richpresence->buffer = malloc(size);
if (!self->richpresence->buffer)
return RC_OUT_OF_MEMORY;
rc_init_parse_state(&parse, self->richpresence->buffer, L, funcs_idx);
self->richpresence->richpresence = richpresence = RC_ALLOC(rc_richpresence_t, &parse);
parse.first_memref = &self->memrefs;
parse.variables = &self->variables;
rc_parse_richpresence_internal(richpresence, script, &parse);
rc_destroy_parse_state(&parse);
rc_reset_parse_state(&preparse.parse, self->richpresence->buffer, L, funcs_idx);
rc_preparse_reserve_memrefs(&preparse, self->memrefs);
richpresence = RC_ALLOC(rc_richpresence_t, &preparse.parse);
preparse.parse.variables = &richpresence->values;
rc_parse_richpresence_internal(richpresence, script, &preparse.parse);
rc_destroy_preparse_state(&preparse);
if (parse.offset < 0) {
if (preparse.parse.offset < 0) {
free(self->richpresence->buffer);
free(self->richpresence);
self->richpresence = previous;
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
return parse.offset;
self->richpresence = NULL;
return preparse.parse.offset;
}
self->richpresence->owns_memrefs = rc_runtime_allocated_memrefs(self);
richpresence->memrefs = NULL;
richpresence->variables = NULL;
if (!richpresence->first_display || !richpresence->first_display->display) {
/* non-existant rich presence */
self->richpresence->richpresence = NULL;
@ -524,6 +485,7 @@ int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua
else {
/* reset all of the conditions */
rc_reset_richpresence(richpresence);
self->richpresence->richpresence = richpresence;
}
return RC_OK;
@ -555,7 +517,6 @@ void rc_runtime_do_frame(rc_runtime_t* self, rc_runtime_event_handler_t event_ha
runtime_event.value = 0;
rc_update_memref_values(self->memrefs, peek, ud);
rc_update_variables(self->variables, peek, ud, L);
for (i = self->trigger_count - 1; i >= 0; --i) {
rc_trigger_t* trigger = self->triggers[i].trigger;
@ -725,7 +686,6 @@ void rc_runtime_do_frame(rc_runtime_t* self, rc_runtime_event_handler_t event_ha
}
void rc_runtime_reset(rc_runtime_t* self) {
rc_value_t* variable;
uint32_t i;
for (i = 0; i < self->trigger_count; ++i) {
@ -740,9 +700,6 @@ void rc_runtime_reset(rc_runtime_t* self) {
if (self->richpresence && self->richpresence->richpresence)
rc_reset_richpresence(self->richpresence->richpresence);
for (variable = self->variables; variable; variable = variable->next)
rc_reset_value(variable);
}
static int rc_condset_contains_memref(const rc_condset_t* condset, const rc_memref_t* memref) {
@ -826,47 +783,41 @@ static void rc_runtime_invalidate_memref(rc_runtime_t* self, rc_memref_t* memref
}
void rc_runtime_invalidate_address(rc_runtime_t* self, uint32_t address) {
rc_memref_t** last_memref = &self->memrefs;
rc_memref_t* memref = self->memrefs;
rc_memref_list_t* memref_list = &self->memrefs->memrefs;
do {
rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_stop = memref + memref_list->count;
while (memref) {
if (memref->address == address && !memref->value.is_indirect) {
/* remove the invalid memref from the chain so we don't try to evaluate it in the future.
* it's still there, so anything referencing it will continue to fetch 0.
*/
*last_memref = memref->next;
rc_runtime_invalidate_memref(self, memref);
break;
for (; memref < memref_stop; ++memref) {
if (memref->address == address) {
memref->value.type = RC_VALUE_TYPE_NONE;
rc_runtime_invalidate_memref(self, memref);
}
}
last_memref = &memref->next;
memref = *last_memref;
}
memref_list = memref_list->next;
} while (memref_list);
}
void rc_runtime_validate_addresses(rc_runtime_t* self, rc_runtime_event_handler_t event_handler,
rc_runtime_validate_address_t validate_handler) {
rc_memref_t** last_memref = &self->memrefs;
rc_memref_t* memref = self->memrefs;
int num_invalid = 0;
rc_memref_list_t* memref_list = &self->memrefs->memrefs;
do {
rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_stop = memref + memref_list->count;
while (memref) {
if (!memref->value.is_indirect && !validate_handler(memref->address)) {
/* remove the invalid memref from the chain so we don't try to evaluate it in the future.
* it's still there, so anything referencing it will continue to fetch 0.
*/
*last_memref = memref->next;
for (; memref < memref_stop; ++memref) {
if (!validate_handler(memref->address)) {
memref->value.type = RC_VALUE_TYPE_NONE;
rc_runtime_invalidate_memref(self, memref);
rc_runtime_invalidate_memref(self, memref);
++num_invalid;
}
else {
last_memref = &memref->next;
++num_invalid;
}
}
memref = *last_memref;
}
memref_list = memref_list->next;
} while (memref_list);
if (num_invalid) {
rc_runtime_event_t runtime_event;

View File

@ -127,11 +127,7 @@ static void rc_runtime_progress_init(rc_runtime_progress_t* progress, const rc_r
static int rc_runtime_progress_write_memrefs(rc_runtime_progress_t* progress)
{
rc_memref_t* memref;
uint32_t count = 0;
for (memref = progress->runtime->memrefs; memref; memref = memref->next)
++count;
uint32_t count = rc_memrefs_count_memrefs(progress->runtime->memrefs);
if (count == 0)
return RC_OK;
@ -145,15 +141,24 @@ static int rc_runtime_progress_write_memrefs(rc_runtime_progress_t* progress)
}
else {
uint32_t flags = 0;
for (memref = progress->runtime->memrefs; memref; memref = memref->next) {
flags = memref->value.size;
if (memref->value.changed)
flags |= RC_MEMREF_FLAG_CHANGED_THIS_FRAME;
const rc_memref_list_t* memref_list = &progress->runtime->memrefs->memrefs;
const rc_memref_t* memref;
rc_runtime_progress_write_uint(progress, memref->address);
rc_runtime_progress_write_uint(progress, flags);
rc_runtime_progress_write_uint(progress, memref->value.value);
rc_runtime_progress_write_uint(progress, memref->value.prior);
for (; memref_list; memref_list = memref_list->next) {
const rc_memref_t* memref_end;
memref = memref_list->items;
memref_end = memref + memref_list->count;
for (; memref < memref_end; ++memref) {
flags = memref->value.size;
if (memref->value.changed)
flags |= RC_MEMREF_FLAG_CHANGED_THIS_FRAME;
rc_runtime_progress_write_uint(progress, memref->address);
rc_runtime_progress_write_uint(progress, flags);
rc_runtime_progress_write_uint(progress, memref->value.value);
rc_runtime_progress_write_uint(progress, memref->value.prior);
}
}
}
@ -162,13 +167,77 @@ static int rc_runtime_progress_write_memrefs(rc_runtime_progress_t* progress)
return RC_OK;
}
static void rc_runtime_progress_update_modified_memrefs(rc_runtime_progress_t* progress)
{
rc_typed_value_t value, prior_value, modifier, prior_modifier;
rc_modified_memref_list_t* modified_memref_list;
rc_modified_memref_t* modified_memref;
rc_operand_t prior_parent_operand, prior_modifier_operand;
rc_memref_t prior_parent_memref, prior_modifier_memref;
modified_memref_list = &progress->runtime->memrefs->modified_memrefs;
for (; modified_memref_list; modified_memref_list = modified_memref_list->next) {
const rc_modified_memref_t* modified_memref_end;
modified_memref = modified_memref_list->items;
modified_memref_end = modified_memref + modified_memref_list->count;
for (; modified_memref < modified_memref_end; ++modified_memref) {
modified_memref->memref.value.changed = 0;
/* indirect memref values are stored in conditions */
if (modified_memref->modifier_type == RC_OPERATOR_INDIRECT_READ)
continue;
/* non-indirect memref values can be reconstructed from the parents */
memcpy(&prior_parent_operand, &modified_memref->parent, sizeof(prior_parent_operand));
if (rc_operand_is_memref(&prior_parent_operand)) {
memcpy(&prior_parent_memref, modified_memref->parent.value.memref, sizeof(prior_parent_memref));
prior_parent_memref.value.value = prior_parent_memref.value.prior;
modified_memref->memref.value.changed |= prior_parent_memref.value.changed;
prior_parent_operand.value.memref = &prior_parent_memref;
}
memcpy(&prior_modifier_operand, &modified_memref->modifier, sizeof(prior_modifier_operand));
if (rc_operand_is_memref(&prior_modifier_operand)) {
memcpy(&prior_modifier_memref, modified_memref->modifier.value.memref, sizeof(prior_modifier_memref));
prior_modifier_memref.value.value = prior_modifier_memref.value.prior;
modified_memref->memref.value.changed |= prior_modifier_memref.value.changed;
prior_modifier_operand.value.memref = &prior_modifier_memref;
}
rc_evaluate_operand(&value, &modified_memref->parent, NULL);
rc_evaluate_operand(&modifier, &modified_memref->modifier, NULL);
rc_evaluate_operand(&prior_value, &prior_parent_operand, NULL);
rc_evaluate_operand(&prior_modifier, &prior_modifier_operand, NULL);
if (modified_memref->modifier_type == RC_OPERATOR_SUB_PARENT) {
rc_typed_value_negate(&value);
rc_typed_value_add(&value, &modifier);
rc_typed_value_negate(&prior_value);
rc_typed_value_add(&prior_value, &prior_modifier);
}
else {
rc_typed_value_combine(&value, &modifier, modified_memref->modifier_type);
rc_typed_value_combine(&prior_value, &prior_modifier, modified_memref->modifier_type);
}
rc_typed_value_convert(&value, modified_memref->memref.value.type);
modified_memref->memref.value.value = value.value.u32;
rc_typed_value_convert(&prior_value, modified_memref->memref.value.type);
modified_memref->memref.value.prior = prior_value.value.u32;
}
}
}
static int rc_runtime_progress_read_memrefs(rc_runtime_progress_t* progress)
{
uint32_t entries;
uint32_t address, flags, value, prior;
uint8_t size;
rc_memref_list_t* unmatched_memref_list = &progress->runtime->memrefs->memrefs;
rc_memref_t* first_unmatched_memref = unmatched_memref_list->items;
rc_memref_t* memref;
rc_memref_t* first_unmatched_memref = progress->runtime->memrefs;
/* re-read the chunk size to determine how many memrefs are present */
progress->offset -= 4;
@ -183,24 +252,46 @@ static int rc_runtime_progress_read_memrefs(rc_runtime_progress_t* progress)
size = flags & 0xFF;
memref = first_unmatched_memref;
while (memref) {
if (memref->address == address && memref->value.size == size) {
memref->value.value = value;
memref->value.changed = (flags & RC_MEMREF_FLAG_CHANGED_THIS_FRAME) ? 1 : 0;
memref->value.prior = prior;
if (memref->address == address && memref->value.size == size) {
memref->value.value = value;
memref->value.changed = (flags & RC_MEMREF_FLAG_CHANGED_THIS_FRAME) ? 1 : 0;
memref->value.prior = prior;
if (memref == first_unmatched_memref)
first_unmatched_memref = memref->next;
break;
first_unmatched_memref++;
if (first_unmatched_memref >= unmatched_memref_list->items + unmatched_memref_list->count) {
unmatched_memref_list = unmatched_memref_list->next;
if (!unmatched_memref_list)
break;
first_unmatched_memref = unmatched_memref_list->items;
}
}
else {
rc_memref_list_t* memref_list = unmatched_memref_list;
do {
++memref;
if (memref >= memref_list->items + memref_list->count) {
memref_list = memref_list->next;
if (!memref_list)
break;
memref = memref->next;
memref = memref_list->items;
}
if (memref->address == address && memref->value.size == size) {
memref->value.value = value;
memref->value.changed = (flags & RC_MEMREF_FLAG_CHANGED_THIS_FRAME) ? 1 : 0;
memref->value.prior = prior;
break;
}
} while (1);
}
--entries;
}
rc_runtime_progress_update_modified_memrefs(progress);
return RC_OK;
}
@ -215,7 +306,10 @@ static int rc_runtime_progress_is_indirect_memref(rc_operand_t* oper)
return 0;
default:
return oper->value.memref->value.is_indirect;
if (oper->value.memref->value.memref_type != RC_MEMREF_TYPE_MODIFIED_MEMREF)
return 0;
return ((const rc_modified_memref_t*)oper->value.memref)->modifier_type == RC_OPERATOR_INDIRECT_READ;
}
}
@ -317,8 +411,8 @@ static uint32_t rc_runtime_progress_should_serialize_variable_condset(const rc_c
{
const rc_condition_t* condition;
/* predetermined presence of pause flag or indirect memrefs - must serialize */
if (conditions->has_pause || conditions->has_indirect_memrefs)
/* predetermined presence of pause flag - must serialize */
if (conditions->has_pause)
return RC_VAR_FLAG_HAS_COND_DATA;
/* if any conditions has required hits, must serialize */
@ -358,12 +452,15 @@ static int rc_runtime_progress_write_variable(rc_runtime_progress_t* progress, c
static int rc_runtime_progress_write_variables(rc_runtime_progress_t* progress)
{
uint32_t count = 0;
const rc_value_t* variable;
uint32_t count;
const rc_value_t* value;
int result;
for (variable = progress->runtime->variables; variable; variable = variable->next)
++count;
if (!progress->runtime->richpresence || !progress->runtime->richpresence->richpresence)
return RC_OK;
value = progress->runtime->richpresence->richpresence->values;
count = rc_count_values(value);
if (count == 0)
return RC_OK;
@ -374,14 +471,14 @@ static int rc_runtime_progress_write_variables(rc_runtime_progress_t* progress)
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_VARIABLES);
rc_runtime_progress_write_uint(progress, count);
for (variable = progress->runtime->variables; variable; variable = variable->next) {
uint32_t djb2 = rc_djb2(variable->name);
for (; value; value = value->next) {
const uint32_t djb2 = rc_djb2(value->name);
if (progress->offset + 16 > progress->buffer_size)
return RC_INSUFFICIENT_BUFFER;
rc_runtime_progress_write_uint(progress, djb2);
result = rc_runtime_progress_write_variable(progress, variable);
result = rc_runtime_progress_write_variable(progress, value);
if (result != RC_OK)
return result;
}
@ -418,19 +515,20 @@ static int rc_runtime_progress_read_variables(rc_runtime_progress_t* progress)
};
struct rc_pending_value_t local_pending_variables[32];
struct rc_pending_value_t* pending_variables;
rc_value_t* variable;
rc_value_t* value;
uint32_t count, serialized_count;
int result;
uint32_t i;
int32_t i;
serialized_count = rc_runtime_progress_read_uint(progress);
if (serialized_count == 0)
return RC_OK;
count = 0;
for (variable = progress->runtime->variables; variable; variable = variable->next)
++count;
if (!progress->runtime->richpresence || !progress->runtime->richpresence->richpresence)
return RC_OK;
value = progress->runtime->richpresence->richpresence->values;
count = rc_count_values(value);
if (count == 0)
return RC_OK;
@ -443,22 +541,22 @@ static int rc_runtime_progress_read_variables(rc_runtime_progress_t* progress)
return RC_OUT_OF_MEMORY;
}
count = 0;
for (variable = progress->runtime->variables; variable; variable = variable->next) {
pending_variables[count].variable = variable;
pending_variables[count].djb2 = rc_djb2(variable->name);
++count;
i = (int32_t)count;
for (; value; value = value->next) {
--i;
pending_variables[i].variable = value;
pending_variables[i].djb2 = rc_djb2(value->name);
}
result = RC_OK;
for (; serialized_count > 0 && result == RC_OK; --serialized_count) {
uint32_t djb2 = rc_runtime_progress_read_uint(progress);
for (i = 0; i < count; ++i) {
for (i = (int32_t)count - 1; i >= 0; --i) {
if (pending_variables[i].djb2 == djb2) {
variable = pending_variables[i].variable;
result = rc_runtime_progress_read_variable(progress, variable);
value = pending_variables[i].variable;
result = rc_runtime_progress_read_variable(progress, value);
if (result == RC_OK) {
if (i < count - 1)
if (i < (int32_t)count - 1)
memcpy(&pending_variables[i], &pending_variables[count - 1], sizeof(struct rc_pending_value_t));
count--;
}
@ -742,7 +840,7 @@ static int rc_runtime_progress_read_rich_presence(rc_runtime_progress_t* progres
return RC_OK;
if (!rc_runtime_progress_match_md5(progress, progress->runtime->richpresence->md5)) {
rc_reset_richpresence(progress->runtime->richpresence->richpresence);
rc_reset_richpresence_triggers(progress->runtime->richpresence->richpresence);
return RC_OK;
}
@ -958,7 +1056,7 @@ int rc_runtime_deserialize_progress_sized(rc_runtime_t* runtime, const uint8_t*
}
if (!seen_rich_presence && runtime->richpresence && runtime->richpresence->richpresence)
rc_reset_richpresence(runtime->richpresence->richpresence);
rc_reset_richpresence_triggers(runtime->richpresence->richpresence);
}
return result;

View File

@ -16,21 +16,20 @@ void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_pars
parse->measured_as_percent = 0;
if (*aux == 's' || *aux == 'S') {
self->requirement = 0;
self->requirement = NULL;
}
else {
self->requirement = rc_parse_condset(&aux, parse, 0);
self->requirement = rc_parse_condset(&aux, parse);
if (parse->offset < 0) {
if (parse->offset < 0)
return;
}
self->requirement->next = 0;
self->requirement->next = NULL;
}
while (*aux == 's' || *aux == 'S') {
aux++;
*next = rc_parse_condset(&aux, parse, 0);
*next = rc_parse_condset(&aux, parse);
if (parse->offset < 0) {
return;
@ -39,7 +38,7 @@ void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_pars
next = &(*next)->next;
}
*next = 0;
*next = NULL;
*memaddr = aux;
self->measured_target = parse->measured_target;
@ -47,39 +46,46 @@ void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_pars
self->measured_as_percent = parse->measured_as_percent;
self->state = RC_TRIGGER_STATE_WAITING;
self->has_hits = 0;
self->has_required_hits = parse->has_required_hits;
self->has_memrefs = 0;
}
int rc_trigger_size(const char* memaddr) {
rc_trigger_t* self;
rc_parse_state_t parse;
rc_memref_t* memrefs;
rc_init_parse_state(&parse, 0, 0, 0);
rc_init_parse_state_memrefs(&parse, &memrefs);
rc_trigger_with_memrefs_t* trigger;
rc_preparse_state_t preparse;
rc_init_preparse_state(&preparse, NULL, 0);
self = RC_ALLOC(rc_trigger_t, &parse);
rc_parse_trigger_internal(self, &memaddr, &parse);
trigger = RC_ALLOC(rc_trigger_with_memrefs_t, &preparse.parse);
rc_parse_trigger_internal(&trigger->trigger, &memaddr, &preparse.parse);
rc_preparse_alloc_memrefs(NULL, &preparse);
rc_destroy_parse_state(&parse);
return parse.offset;
rc_destroy_preparse_state(&preparse);
return preparse.parse.offset;
}
rc_trigger_t* rc_parse_trigger(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx) {
rc_trigger_t* self;
rc_parse_state_t parse;
rc_trigger_with_memrefs_t* trigger;
rc_preparse_state_t preparse;
const char* preparse_memaddr = memaddr;
if (!buffer || !memaddr)
return NULL;
rc_init_parse_state(&parse, buffer, L, funcs_ndx);
/* first pass : determine how many memrefs are needed */
rc_init_preparse_state(&preparse, L, funcs_ndx);
trigger = RC_ALLOC(rc_trigger_with_memrefs_t, &preparse.parse);
rc_parse_trigger_internal(&trigger->trigger, &preparse_memaddr, &preparse.parse);
self = RC_ALLOC(rc_trigger_t, &parse);
rc_init_parse_state_memrefs(&parse, &self->memrefs);
/* allocate the trigger and memrefs */
rc_reset_parse_state(&preparse.parse, buffer, L, funcs_ndx);
trigger = RC_ALLOC(rc_trigger_with_memrefs_t, &preparse.parse);
rc_preparse_alloc_memrefs(&trigger->memrefs, &preparse);
rc_parse_trigger_internal(self, &memaddr, &parse);
/* parse the trigger */
rc_parse_trigger_internal(&trigger->trigger, &memaddr, &preparse.parse);
trigger->trigger.has_memrefs = 1;
rc_destroy_parse_state(&parse);
return (parse.offset >= 0) ? self : NULL;
rc_destroy_preparse_state(&preparse);
return (preparse.parse.offset >= 0) ? &trigger->trigger : NULL;
}
int rc_trigger_state_active(int state)
@ -124,9 +130,27 @@ static void rc_reset_trigger_hitcounts(rc_trigger_t* self) {
}
}
static void rc_update_trigger_memrefs(rc_trigger_t* self, rc_peek_t peek, void* ud) {
if (self->has_memrefs) {
rc_trigger_with_memrefs_t* trigger = (rc_trigger_with_memrefs_t*)self;
rc_update_memref_values(&trigger->memrefs, peek, ud);
}
}
rc_memrefs_t* rc_trigger_get_memrefs(rc_trigger_t* self) {
if (self->has_memrefs) {
rc_trigger_with_memrefs_t* trigger = (rc_trigger_with_memrefs_t*)self;
return &trigger->memrefs;
}
return NULL;
}
int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State* L) {
rc_eval_state_t eval_state;
rc_condset_t* condset;
rc_typed_value_t measured_value;
int measured_from_hits = 0;
int ret;
char is_paused;
char is_primed;
@ -143,7 +167,7 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
case RC_TRIGGER_STATE_INACTIVE:
/* not yet active. update the memrefs so deltas are correct when it becomes active, then return INACTIVE */
rc_update_memref_values(self->memrefs, peek, ud);
rc_update_trigger_memrefs(self, peek, ud);
return RC_TRIGGER_STATE_INACTIVE;
default:
@ -151,18 +175,29 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
}
/* update the memory references */
rc_update_memref_values(self->memrefs, peek, ud);
rc_update_trigger_memrefs(self, peek, ud);
/* process the trigger */
memset(&eval_state, 0, sizeof(eval_state));
eval_state.peek = peek;
eval_state.peek_userdata = ud;
#ifndef RC_DISABLE_LUA
eval_state.L = L;
#else
(void)L;
#endif
measured_value.type = RC_VALUE_TYPE_NONE;
if (self->requirement != NULL) {
ret = rc_test_condset(self->requirement, &eval_state);
is_paused = self->requirement->is_paused;
is_primed = eval_state.primed;
is_paused = eval_state.is_paused;
is_primed = eval_state.is_primed;
if (eval_state.measured_value.type != RC_VALUE_TYPE_NONE) {
memcpy(&measured_value, &eval_state.measured_value, sizeof(measured_value));
measured_from_hits = eval_state.measured_from_hits;
}
} else {
ret = 1;
is_paused = 0;
@ -177,8 +212,17 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
do {
sub |= rc_test_condset(condset, &eval_state);
sub_paused &= condset->is_paused;
sub_primed |= eval_state.primed;
sub_paused &= eval_state.is_paused;
sub_primed |= eval_state.is_primed;
if (eval_state.measured_value.type != RC_VALUE_TYPE_NONE) {
/* if no previous Measured value was captured, or the new one is greater, keep the new one */
if (measured_value.type == RC_VALUE_TYPE_NONE ||
rc_typed_value_compare(&eval_state.measured_value, &measured_value, RC_OPERATOR_GT)) {
memcpy(&measured_value, &eval_state.measured_value, sizeof(measured_value));
measured_from_hits = eval_state.measured_from_hits;
}
}
condset = condset->next;
} while (condset);
@ -193,15 +237,15 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
/* if paused, the measured value may not be captured, keep the old value */
if (!is_paused) {
rc_typed_value_convert(&eval_state.measured_value, RC_VALUE_TYPE_UNSIGNED);
self->measured_value = eval_state.measured_value.value.u32;
rc_typed_value_convert(&measured_value, RC_VALUE_TYPE_UNSIGNED);
self->measured_value = measured_value.value.u32;
}
/* if any ResetIf condition was true, reset the hit counts */
if (eval_state.was_reset) {
/* if the measured value came from a hit count, reset it. do this before calling
* rc_reset_trigger_hitcounts in case we need to call rc_condset_is_measured_from_hitcount */
if (eval_state.measured_from_hits) {
if (measured_from_hits) {
self->measured_value = 0;
}
else if (is_paused && self->measured_value) {

View File

@ -5,8 +5,6 @@
#include <float.h> /* FLT_EPSILON */
#include <math.h> /* fmod */
int rc_is_valid_variable_character(char ch, int is_first) {
if (is_first) {
if (!isalpha((unsigned char)ch))
@ -27,7 +25,7 @@ static void rc_parse_cond_value(rc_value_t* self, const char** memaddr, rc_parse
do
{
parse->measured_target = 0; /* passing is_value=1 should prevent any conflicts, but clear it out anyway */
*next_clause = rc_parse_condset(memaddr, parse, 1);
*next_clause = rc_parse_condset(memaddr, parse);
if (parse->offset < 0) {
return;
}
@ -52,174 +50,238 @@ static void rc_parse_cond_value(rc_value_t* self, const char** memaddr, rc_parse
(*next_clause)->next = 0;
}
void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
static void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
rc_condset_with_trailing_conditions_t* condset_with_conditions;
rc_condition_t** next;
rc_condset_t** next_clause;
rc_condset_t* condset;
rc_condition_t local_cond;
rc_condition_t* cond;
uint32_t num_measured_conditions;
char buffer[64] = "A:";
const char* buffer_ptr;
char* ptr;
char c;
/* convert legacy format into condset */
self->conditions = RC_ALLOC(rc_condset_t, parse);
memset(self->conditions, 0, sizeof(rc_condset_t));
next_clause = &self->conditions;
do {
num_measured_conditions = 0;
next = &self->conditions->conditions;
next_clause = &self->conditions->next;
for (;; ++(*memaddr)) {
buffer[0] = 'A'; /* reset to AddSource */
ptr = &buffer[2];
/* extract the next clause */
for (;; ++(*memaddr)) {
switch (**memaddr) {
case '_': /* add next */
case '$': /* maximum of */
case '\0': /* end of string */
case ':': /* end of leaderboard clause */
case ')': /* end of rich presence macro */
*ptr = '\0';
break;
case '*':
*ptr++ = '*';
buffer_ptr = *memaddr + 1;
if (*buffer_ptr == '-') {
buffer[0] = 'B'; /* change to SubSource */
++(*memaddr); /* don't copy sign */
++buffer_ptr; /* ignore sign when doing floating point check */
}
else if (*buffer_ptr == '+') {
++buffer_ptr; /* ignore sign when doing floating point check */
}
/* if it looks like a floating point number, add the 'f' prefix */
while (isdigit((unsigned char)*buffer_ptr))
++buffer_ptr;
if (*buffer_ptr == '.')
*ptr++ = 'f';
continue;
default:
*ptr++ = **memaddr;
continue;
/* count the number of joiners and add one to determine the number of clauses. */
num_measured_conditions = 1;
buffer_ptr = *memaddr;
while ((c = *buffer_ptr++) && c != '$') {
if (c == '_') {
++num_measured_conditions;
buffer[0] = 'A'; /* reset to AddSource */
}
else if (c == '*' && *buffer_ptr == '-') {
/* multiplication by a negative number will convert to SubSource */
++buffer_ptr;
buffer[0] = 'B';
}
break;
}
/* process the clause */
buffer_ptr = buffer;
cond = rc_parse_condition(&buffer_ptr, parse, 0);
/* if last condition is SubSource, we'll need to add a dummy condition for the Measured */
if (buffer[0] == 'B')
++num_measured_conditions;
condset_with_conditions = RC_ALLOC_WITH_TRAILING(rc_condset_with_trailing_conditions_t,
rc_condition_t, conditions, num_measured_conditions, parse);
if (parse->offset < 0)
return;
if (*buffer_ptr) {
/* whatever we copied as a single condition was not fully consumed */
parse->offset = RC_INVALID_COMPARISON;
return;
}
condset = (rc_condset_t*)condset_with_conditions;
memset(condset, 0, sizeof(*condset));
condset->num_measured_conditions = num_measured_conditions;
cond = &condset_with_conditions->conditions[0];
next = &condset->conditions;
for (;; ++(*memaddr)) {
buffer[0] = 'A'; /* reset to AddSource */
ptr = &buffer[2];
/* extract the next clause */
for (;; ++(*memaddr)) {
switch (**memaddr) {
case '_': /* add next */
case '$': /* maximum of */
case '\0': /* end of string */
case ':': /* end of leaderboard clause */
case ')': /* end of rich presence macro */
*ptr = '\0';
break;
case '*':
*ptr++ = '*';
buffer_ptr = *memaddr + 1;
if (*buffer_ptr == '-') {
buffer[0] = 'B'; /* change to SubSource */
++(*memaddr); /* don't copy sign */
++buffer_ptr; /* ignore sign when doing floating point check */
}
else if (*buffer_ptr == '+') {
++buffer_ptr; /* ignore sign when doing floating point check */
}
/* if it looks like a floating point number, add the 'f' prefix */
while (isdigit((unsigned char)*buffer_ptr))
++buffer_ptr;
if (*buffer_ptr == '.')
*ptr++ = 'f';
continue;
default:
*ptr++ = **memaddr;
continue;
}
switch (cond->oper) {
case RC_OPERATOR_MULT:
case RC_OPERATOR_DIV:
case RC_OPERATOR_AND:
case RC_OPERATOR_XOR:
case RC_OPERATOR_MOD:
case RC_OPERATOR_ADD:
case RC_OPERATOR_SUB:
case RC_OPERATOR_NONE:
break;
}
default:
/* process the clause */
if (!parse->buffer)
cond = &local_cond;
buffer_ptr = buffer;
rc_parse_condition_internal(cond, &buffer_ptr, parse);
if (parse->offset < 0)
return;
if (*buffer_ptr) {
/* whatever we copied as a single condition was not fully consumed */
parse->offset = RC_INVALID_COMPARISON;
return;
}
if (!rc_operator_is_modifying(cond->oper)) {
parse->offset = RC_INVALID_OPERATOR;
return;
}
}
*next = cond;
if (**memaddr == '_') {
/* add next */
*next = cond;
next = &cond->next;
continue;
if (**memaddr != '_') /* add next */
break;
rc_condition_update_parse_state(cond, parse);
++cond;
}
/* end of clause */
if (cond->type == RC_CONDITION_SUB_SOURCE) {
/* cannot change SubSource to Measured. add a dummy condition */
next = &cond->next;
rc_condition_update_parse_state(cond, parse);
if (parse->buffer)
++cond;
buffer_ptr = "A:0";
cond = rc_parse_condition(&buffer_ptr, parse, 0);
rc_parse_condition_internal(cond, &buffer_ptr, parse);
*next = cond;
next = &cond->next;
}
/* convert final AddSource condition to Measured */
cond->type = RC_CONDITION_MEASURED;
cond->next = 0;
cond->next = NULL;
rc_condition_update_parse_state(cond, parse);
/* finalize clause */
*next_clause = condset;
next_clause = &condset->next;
if (**memaddr != '$') {
/* end of valid string */
*next_clause = 0;
*next_clause = NULL;
break;
}
/* max of ($), start a new clause */
*next_clause = RC_ALLOC(rc_condset_t, parse);
if (parse->buffer) /* don't clear in sizing mode or pointer will break */
memset(*next_clause, 0, sizeof(rc_condset_t));
next = &(*next_clause)->conditions;
next_clause = &(*next_clause)->next;
}
++(*memaddr);
} while (1);
}
void rc_parse_value_internal(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
const uint8_t was_value = parse->is_value;
const rc_condition_t* condition;
parse->is_value = 1;
/* if it starts with a condition flag (M: A: B: C:), parse the conditions */
if ((*memaddr)[1] == ':') {
if ((*memaddr)[1] == ':')
rc_parse_cond_value(self, memaddr, parse);
}
else {
else
rc_parse_legacy_value(self, memaddr, parse);
if (parse->offset >= 0 && parse->buffer) {
self->name = "(unnamed)";
self->value.value = self->value.prior = 0;
self->value.memref_type = RC_MEMREF_TYPE_VALUE;
self->value.changed = 0;
self->has_memrefs = 0;
for (condition = self->conditions->conditions; condition; condition = condition->next) {
if (condition->type == RC_CONDITION_MEASURED) {
if (rc_operand_is_float(&condition->operand1)) {
self->value.size = RC_MEMSIZE_FLOAT;
self->value.type = RC_VALUE_TYPE_FLOAT;
}
else {
self->value.size = RC_MEMSIZE_32_BITS;
self->value.type = RC_VALUE_TYPE_UNSIGNED;
}
break;
}
}
}
self->name = "(unnamed)";
self->value.value = self->value.prior = 0;
self->value.changed = 0;
self->next = 0;
parse->is_value = was_value;
}
int rc_value_size(const char* memaddr) {
rc_value_t* self;
rc_parse_state_t parse;
rc_memref_t* first_memref;
rc_init_parse_state(&parse, 0, 0, 0);
rc_init_parse_state_memrefs(&parse, &first_memref);
rc_value_with_memrefs_t* value;
rc_preparse_state_t preparse;
rc_init_preparse_state(&preparse, NULL, 0);
self = RC_ALLOC(rc_value_t, &parse);
rc_parse_value_internal(self, &memaddr, &parse);
value = RC_ALLOC(rc_value_with_memrefs_t, &preparse.parse);
rc_parse_value_internal(&value->value, &memaddr, &preparse.parse);
rc_preparse_alloc_memrefs(NULL, &preparse);
rc_destroy_parse_state(&parse);
return parse.offset;
rc_destroy_preparse_state(&preparse);
return preparse.parse.offset;
}
rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx) {
rc_value_t* self;
rc_parse_state_t parse;
rc_value_with_memrefs_t* value;
rc_preparse_state_t preparse;
const char* preparse_memaddr = memaddr;
if (!buffer || !memaddr)
return NULL;
rc_init_parse_state(&parse, buffer, L, funcs_ndx);
rc_init_preparse_state(&preparse, L, funcs_ndx);
value = RC_ALLOC(rc_value_with_memrefs_t, &preparse.parse);
rc_parse_value_internal(&value->value, &preparse_memaddr, &preparse.parse);
self = RC_ALLOC(rc_value_t, &parse);
rc_init_parse_state_memrefs(&parse, &self->memrefs);
rc_reset_parse_state(&preparse.parse, buffer, L, funcs_ndx);
value = RC_ALLOC(rc_value_with_memrefs_t, &preparse.parse);
rc_preparse_alloc_memrefs(&value->memrefs, &preparse);
rc_parse_value_internal(self, &memaddr, &parse);
rc_parse_value_internal(&value->value, &memaddr, &preparse.parse);
value->value.has_memrefs = 1;
rc_destroy_parse_state(&parse);
return (parse.offset >= 0) ? self : NULL;
rc_destroy_preparse_state(&preparse);
return (preparse.parse.offset >= 0) ? &value->value : NULL;
}
static void rc_update_value_memrefs(rc_value_t* self, rc_peek_t peek, void* ud) {
if (self->has_memrefs) {
rc_value_with_memrefs_t* value = (rc_value_with_memrefs_t*)self;
rc_update_memref_values(&value->memrefs, peek, ud);
}
}
int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t peek, void* ud, lua_State* L) {
@ -227,7 +289,7 @@ int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t
rc_condset_t* condset;
int valid = 0;
rc_update_memref_values(self->memrefs, peek, ud);
rc_update_value_memrefs(self, peek, ud);
value->value.i32 = 0;
value->type = RC_VALUE_TYPE_SIGNED;
@ -236,7 +298,11 @@ int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t
memset(&eval_state, 0, sizeof(eval_state));
eval_state.peek = peek;
eval_state.peek_userdata = ud;
#ifndef RC_DISABLE_LUA
eval_state.L = L;
#else
(void)L;
#endif
rc_test_condset(condset, &eval_state);
@ -248,25 +314,21 @@ int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t
* NOTE: ResetIf only affects the current condset when used in values!
*/
rc_reset_condset(condset);
/* if the measured value came from a hit count, reset it too */
if (eval_state.measured_from_hits) {
eval_state.measured_value.value.u32 = 0;
eval_state.measured_value.type = RC_VALUE_TYPE_UNSIGNED;
}
}
if (!valid) {
/* capture the first valid measurement */
memcpy(value, &eval_state.measured_value, sizeof(*value));
valid = 1;
}
else {
/* multiple condsets are currently only used for the MAX_OF operation.
* only keep the condset's value if it's higher than the current highest value.
*/
if (rc_typed_value_compare(&eval_state.measured_value, value, RC_OPERATOR_GT))
if (eval_state.measured_value.type != RC_VALUE_TYPE_NONE) {
if (!valid) {
/* capture the first valid measurement, which may be negative */
memcpy(value, &eval_state.measured_value, sizeof(*value));
valid = 1;
}
else {
/* multiple condsets are currently only used for the MAX_OF operation.
* only keep the condset's value if it's higher than the current highest value.
*/
if (rc_typed_value_compare(&eval_state.measured_value, value, RC_OPERATOR_GT))
memcpy(value, &eval_state.measured_value, sizeof(*value));
}
}
}
@ -317,84 +379,81 @@ int rc_value_from_hits(rc_value_t* self)
return 0;
}
void rc_init_parse_state_variables(rc_parse_state_t* parse, rc_value_t** variables) {
parse->variables = variables;
*variables = 0;
}
rc_value_t* rc_alloc_helper_variable(const char* memaddr, size_t memaddr_len, rc_parse_state_t* parse)
{
rc_value_t** variables = parse->variables;
rc_value_t* rc_alloc_variable(const char* memaddr, size_t memaddr_len, rc_parse_state_t* parse) {
rc_value_t** value_ptr = parse->variables;
rc_value_t* value;
const char* name;
uint32_t measured_target;
while ((value = *variables) != NULL) {
if (!value_ptr)
return NULL;
while (*value_ptr) {
value = *value_ptr;
if (strncmp(value->name, memaddr, memaddr_len) == 0 && value->name[memaddr_len] == 0)
return value;
variables = &value->next;
value_ptr = &value->next;
}
value = RC_ALLOC_SCRATCH(rc_value_t, parse);
memset(&value->value, 0, sizeof(value->value));
value->value.size = RC_MEMSIZE_VARIABLE;
value->memrefs = NULL;
/* capture name before calling parse as parse will update memaddr pointer */
name = rc_alloc_str(parse, memaddr, memaddr_len);
if (!name)
return NULL;
/* no match found, create a new entry */
value = RC_ALLOC_SCRATCH(rc_value_t, parse);
memset(value, 0, sizeof(value->value));
value->value.size = RC_MEMSIZE_VARIABLE;
value->next = NULL;
/* the helper variable likely has a Measured condition. capture the current measured_target so we can restore it
* after generating the variable so the variable's Measured target doesn't conflict with the rest of the trigger. */
measured_target = parse->measured_target;
/* disable variable resolution when defining a variable to prevent infinite recursion */
variables = parse->variables;
parse->variables = NULL;
rc_parse_value_internal(value, &memaddr, parse);
parse->variables = variables;
/* restore the measured target */
parse->measured_target = measured_target;
/* store name after calling parse as parse will set name to (unnamed) */
value->name = name;
/* append the new variable to the end of the list (have to re-evaluate in case any others were added) */
while (*variables != NULL)
variables = &(*variables)->next;
*variables = value;
*value_ptr = value;
return value;
}
void rc_update_variables(rc_value_t* variable, rc_peek_t peek, void* ud, lua_State* L) {
uint32_t rc_count_values(const rc_value_t* values) {
uint32_t count = 0;
while (values) {
++count;
values = values->next;
}
return count;
}
void rc_update_values(rc_value_t* values, rc_peek_t peek, void* ud, lua_State* L) {
rc_typed_value_t result;
while (variable) {
if (rc_evaluate_value_typed(variable, &result, peek, ud, L)) {
rc_value_t* value = values;
for (; value; value = value->next) {
if (rc_evaluate_value_typed(value, &result, peek, ud, L)) {
/* store the raw bytes and type to be restored by rc_typed_value_from_memref_value */
rc_update_memref_value(&variable->value, result.value.u32);
variable->value.type = result.type;
rc_update_memref_value(&value->value, result.value.u32);
value->value.type = result.type;
}
variable = variable->next;
}
}
void rc_typed_value_from_memref_value(rc_typed_value_t* value, const rc_memref_value_t* memref) {
value->value.u32 = memref->value;
void rc_reset_values(rc_value_t* values) {
rc_value_t* value = values;
if (memref->size == RC_MEMSIZE_VARIABLE) {
/* a variable can be any of the supported types, but the raw data was copied into u32 */
value->type = memref->type;
}
else {
/* not a variable, only u32 is supported */
value->type = RC_VALUE_TYPE_UNSIGNED;
}
for (; value; value = value->next)
rc_reset_value(value);
}
void rc_typed_value_from_memref_value(rc_typed_value_t* value, const rc_memref_value_t* memref) {
/* raw value is always u32, type can mark it as something else */
value->value.u32 = memref->value;
value->type = memref->type;
}
void rc_typed_value_convert(rc_typed_value_t* value, char new_type) {
@ -483,8 +542,12 @@ void rc_typed_value_negate(rc_typed_value_t* value) {
void rc_typed_value_add(rc_typed_value_t* value, const rc_typed_value_t* amount) {
rc_typed_value_t converted;
if (amount->type != value->type && value->type != RC_VALUE_TYPE_NONE)
amount = rc_typed_value_convert_into(&converted, amount, value->type);
if (amount->type != value->type && value->type != RC_VALUE_TYPE_NONE) {
if (amount->type == RC_VALUE_TYPE_FLOAT)
rc_typed_value_convert(value, RC_VALUE_TYPE_FLOAT);
else
amount = rc_typed_value_convert_into(&converted, amount, value->type);
}
switch (value->type)
{
@ -651,56 +714,56 @@ void rc_typed_value_modulus(rc_typed_value_t* value, const rc_typed_value_t* amo
switch (amount->type)
{
case RC_VALUE_TYPE_UNSIGNED:
if (amount->value.u32 == 0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
case RC_VALUE_TYPE_UNSIGNED:
if (amount->value.u32 == 0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
switch (value->type) {
case RC_VALUE_TYPE_UNSIGNED: /* integer math */
value->value.u32 %= amount->value.u32;
return;
case RC_VALUE_TYPE_SIGNED: /* integer math */
value->value.i32 %= (int)amount->value.u32;
return;
case RC_VALUE_TYPE_FLOAT:
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
switch (value->type) {
case RC_VALUE_TYPE_UNSIGNED: /* integer math */
value->value.u32 %= amount->value.u32;
return;
case RC_VALUE_TYPE_SIGNED: /* integer math */
value->value.i32 %= (int)amount->value.u32;
return;
case RC_VALUE_TYPE_FLOAT:
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
break;
case RC_VALUE_TYPE_SIGNED:
if (amount->value.i32 == 0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
switch (value->type) {
case RC_VALUE_TYPE_SIGNED: /* integer math */
value->value.i32 %= amount->value.i32;
return;
case RC_VALUE_TYPE_UNSIGNED: /* integer math */
value->value.u32 %= (unsigned)amount->value.i32;
return;
case RC_VALUE_TYPE_FLOAT:
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
break;
case RC_VALUE_TYPE_FLOAT:
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
break;
case RC_VALUE_TYPE_SIGNED:
if (amount->value.i32 == 0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
switch (value->type) {
case RC_VALUE_TYPE_SIGNED: /* integer math */
value->value.i32 %= amount->value.i32;
return;
case RC_VALUE_TYPE_UNSIGNED: /* integer math */
value->value.u32 %= (unsigned)amount->value.i32;
return;
case RC_VALUE_TYPE_FLOAT:
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
break;
case RC_VALUE_TYPE_FLOAT:
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
if (amount->value.f32 == 0.0) { /* divide by zero */
@ -712,6 +775,44 @@ void rc_typed_value_modulus(rc_typed_value_t* value, const rc_typed_value_t* amo
value->value.f32 = (float)fmod(value->value.f32, amount->value.f32);
}
void rc_typed_value_combine(rc_typed_value_t* value, rc_typed_value_t* amount, uint8_t oper) {
switch (oper) {
case RC_OPERATOR_MULT:
rc_typed_value_multiply(value, amount);
break;
case RC_OPERATOR_DIV:
rc_typed_value_divide(value, amount);
break;
case RC_OPERATOR_AND:
rc_typed_value_convert(value, RC_VALUE_TYPE_UNSIGNED);
rc_typed_value_convert(amount, RC_VALUE_TYPE_UNSIGNED);
value->value.u32 &= amount->value.u32;
break;
case RC_OPERATOR_XOR:
rc_typed_value_convert(value, RC_VALUE_TYPE_UNSIGNED);
rc_typed_value_convert(amount, RC_VALUE_TYPE_UNSIGNED);
value->value.u32 ^= amount->value.u32;
break;
case RC_OPERATOR_MOD:
rc_typed_value_modulus(value, amount);
break;
case RC_OPERATOR_ADD:
rc_typed_value_add(value, amount);
break;
case RC_OPERATOR_SUB:
rc_typed_value_negate(amount);
rc_typed_value_add(value, amount);
break;
}
}
static int rc_typed_value_compare_floats(float f1, float f2, char oper) {
if (f1 == f2) {
/* exactly equal */

View File

@ -77,7 +77,7 @@ static void* filereader_open(const char* path)
return NULL;
}
#if defined(__STDC_WANT_SECURE_LIB__)
#if defined(__STDC_SECURE_LIB__)
/* have to use _SH_DENYNO because some cores lock the file while its loaded */
fp = _wfsopen(wpath, L"rb", _SH_DENYNO);
#else
@ -90,7 +90,7 @@ static void* filereader_open(const char* path)
#else /* !WINVER >= 0x0500 */
static void* filereader_open(const char* path)
{
#if defined(__STDC_WANT_SECURE_LIB__)
#if defined(__STDC_SECURE_LIB__)
#if defined(WINVER)
/* have to use _SH_DENYNO because some cores lock the file while its loaded */
return _fsopen(path, "rb", _SH_DENYNO);
@ -99,7 +99,7 @@ static void* filereader_open(const char* path)
fopen_s(&fp, path, "rb");
return fp;
#endif
#else /* !__STDC_WANT_SECURE_LIB__ */
#else /* !__STDC_SECURE_LIB__ */
return fopen(path, "rb");
#endif
}
@ -2513,6 +2513,7 @@ int rc_hash_generate_from_buffer(char hash[33], uint32_t console_id, const uint8
case RC_CONSOLE_ATARI_LYNX:
return rc_hash_lynx(hash, buffer, buffer_size);
case RC_CONSOLE_FAMICOM_DISK_SYSTEM:
case RC_CONSOLE_NINTENDO:
return rc_hash_nes(hash, buffer, buffer_size);
@ -2818,6 +2819,7 @@ int rc_hash_generate_from_file(char hash[33], uint32_t console_id, const char* p
case RC_CONSOLE_ARDUBOY:
case RC_CONSOLE_ATARI_7800:
case RC_CONSOLE_ATARI_LYNX:
case RC_CONSOLE_FAMICOM_DISK_SYSTEM:
case RC_CONSOLE_NINTENDO:
case RC_CONSOLE_PC_ENGINE:
case RC_CONSOLE_SUPER_CASSETTEVISION:
@ -3015,7 +3017,11 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
break;
case 'a':
if (rc_path_compare_extension(ext, "a78"))
if (rc_path_compare_extension(ext, "a26"))
{
iterator->consoles[0] = RC_CONSOLE_ATARI_2600;
}
else if (rc_path_compare_extension(ext, "a78"))
{
iterator->consoles[0] = RC_CONSOLE_ATARI_7800;
}
@ -3157,7 +3163,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
}
else if (rc_path_compare_extension(ext, "fds"))
{
iterator->consoles[0] = RC_CONSOLE_NINTENDO;
iterator->consoles[0] = RC_CONSOLE_FAMICOM_DISK_SYSTEM;
}
else if (rc_path_compare_extension(ext, "fd"))
{

View File

@ -67,6 +67,8 @@ Global
DebugFast|x64 = DebugFast|x64
DebugFast-Clang|ARM64 = DebugFast-Clang|ARM64
DebugFast-Clang|x64 = DebugFast-Clang|x64
Devel-Clang|ARM64 = Devel-Clang|ARM64
Devel-Clang|x64 = Devel-Clang|x64
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release-Clang|ARM64 = Release-Clang|ARM64
@ -79,6 +81,44 @@ Global
ReleaseLTCG-Clang-SSE2|x64 = ReleaseLTCG-Clang-SSE2|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|x64.ActiveCfg = Debug|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|x64.Build.0 = Debug|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|ARM64.Build.0 = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|x64.ActiveCfg = Debug-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|x64.Build.0 = Debug-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|x64.ActiveCfg = Debug-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|x64.Build.0 = Debug-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|x64.ActiveCfg = DebugFast|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|x64.Build.0 = DebugFast|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|x64.ActiveCfg = Release|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|x64.Build.0 = Release|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|ARM64.Build.0 = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|x64.ActiveCfg = Release-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|x64.Build.0 = Release-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|ARM64.Build.0 = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|x64.ActiveCfg = ReleaseLTCG-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|x64.Build.0 = ReleaseLTCG-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|x64.ActiveCfg = ReleaseLTCG-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|x64.Build.0 = ReleaseLTCG-Clang-SSE2|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.Debug|x64.ActiveCfg = Debug|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Debug|x64.Build.0 = Debug|x64
@ -96,6 +136,10 @@ Global
{43540154-9E1E-409C-834F-B84BE5621388}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{43540154-9E1E-409C-834F-B84BE5621388}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.Release|x64.ActiveCfg = Release|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Release|x64.Build.0 = Release|x64
@ -130,6 +174,10 @@ Global
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Release|x64.ActiveCfg = Release|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Release|x64.Build.0 = Release|x64
@ -164,6 +212,10 @@ Global
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.Release|x64.ActiveCfg = Release|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.Release|x64.Build.0 = Release|x64
@ -198,6 +250,10 @@ Global
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Release|x64.ActiveCfg = Release|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Release|x64.Build.0 = Release|x64
@ -232,6 +288,10 @@ Global
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Release|x64.ActiveCfg = Release|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Release|x64.Build.0 = Release|x64
@ -249,40 +309,6 @@ Global
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseLTCG-Clang-SSE2|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseLTCG-Clang-SSE2|x64.ActiveCfg = ReleaseLTCG-Clang-SSE2|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseLTCG-Clang-SSE2|x64.Build.0 = ReleaseLTCG-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|x64.ActiveCfg = Debug|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|x64.Build.0 = Debug|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|ARM64.Build.0 = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|x64.ActiveCfg = Debug-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|x64.Build.0 = Debug-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|x64.ActiveCfg = Debug-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|x64.Build.0 = Debug-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|x64.ActiveCfg = DebugFast|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|x64.Build.0 = DebugFast|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|x64.ActiveCfg = Release|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|x64.Build.0 = Release|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|ARM64.Build.0 = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|x64.ActiveCfg = Release-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|x64.Build.0 = Release-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|ARM64.Build.0 = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|x64.ActiveCfg = ReleaseLTCG-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|x64.Build.0 = ReleaseLTCG-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|x64.ActiveCfg = ReleaseLTCG-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|x64.Build.0 = ReleaseLTCG-Clang-SSE2|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Debug|x64.ActiveCfg = Debug|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Debug|x64.Build.0 = Debug|x64
@ -300,6 +326,10 @@ Global
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Release|x64.ActiveCfg = Release|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Release|x64.Build.0 = Release|x64
@ -334,6 +364,10 @@ Global
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Release|x64.ActiveCfg = Release|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Release|x64.Build.0 = Release|x64
@ -368,6 +402,10 @@ Global
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Release|x64.ActiveCfg = Release|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Release|x64.Build.0 = Release|x64
@ -402,6 +440,10 @@ Global
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Release|x64.ActiveCfg = Release|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Release|x64.Build.0 = Release|x64
@ -436,6 +478,10 @@ Global
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Release|x64.ActiveCfg = Release|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Release|x64.Build.0 = Release|x64
@ -470,6 +516,10 @@ Global
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Release|x64.ActiveCfg = Release|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Release|x64.Build.0 = Release|x64
@ -497,6 +547,8 @@ Global
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.DebugFast|x64.ActiveCfg = DebugFast|x64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Release|x64.ActiveCfg = Release|x64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@ -524,6 +576,10 @@ Global
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Release|x64.ActiveCfg = Release|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Release|x64.Build.0 = Release|x64
@ -551,6 +607,8 @@ Global
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.DebugFast|x64.ActiveCfg = DebugFast|x64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Release|x64.ActiveCfg = Release|x64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@ -576,6 +634,9 @@ Global
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Release|x64.ActiveCfg = Release|x64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@ -605,6 +666,10 @@ Global
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Release|x64.ActiveCfg = Release|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Release|x64.Build.0 = Release|x64
@ -633,6 +698,8 @@ Global
{3029310E-4211-4C87-801A-72E130A648EF}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{3029310E-4211-4C87-801A-72E130A648EF}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{3029310E-4211-4C87-801A-72E130A648EF}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{3029310E-4211-4C87-801A-72E130A648EF}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{3029310E-4211-4C87-801A-72E130A648EF}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{3029310E-4211-4C87-801A-72E130A648EF}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{3029310E-4211-4C87-801A-72E130A648EF}.Release|x64.ActiveCfg = Release|x64
{3029310E-4211-4C87-801A-72E130A648EF}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@ -661,6 +728,10 @@ Global
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|x64.ActiveCfg = Release|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|x64.Build.0 = Release|x64
@ -695,6 +766,10 @@ Global
{8BE398E6-B882-4248-9065-FECC8728E038}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{8BE398E6-B882-4248-9065-FECC8728E038}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{8BE398E6-B882-4248-9065-FECC8728E038}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{8BE398E6-B882-4248-9065-FECC8728E038}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{8BE398E6-B882-4248-9065-FECC8728E038}.Release|x64.ActiveCfg = Release|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.Release|x64.Build.0 = Release|x64
@ -729,6 +804,10 @@ Global
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Release|x64.ActiveCfg = Release|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Release|x64.Build.0 = Release|x64
@ -761,6 +840,9 @@ Global
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Release|x64.ActiveCfg = Release|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@ -788,6 +870,10 @@ Global
{F351C4D8-594A-4850-B77B-3C1249812CCE}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Release|x64.ActiveCfg = Release|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Release|x64.Build.0 = Release|x64
@ -822,6 +908,10 @@ Global
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Release|x64.ActiveCfg = Release|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Release|x64.Build.0 = Release|x64
@ -856,6 +946,10 @@ Global
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|x64.ActiveCfg = Release|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|x64.Build.0 = Release|x64

View File

@ -23,7 +23,7 @@ OS2Version: 0
OS2_WeightWidthSlopeOnly: 0
OS2_UseTypoMetrics: 0
CreationTime: 1544355305
ModificationTime: 1712653578
ModificationTime: 1736751870
PfmFamily: 33
TTFWeight: 400
TTFWidth: 5
@ -65,7 +65,7 @@ NameList: AGL For New Fonts
DisplaySize: -48
AntiAlias: 1
FitToEm: 0
WinInfo: 8816 38 14
WinInfo: 8360 38 14
BeginPrivate: 8
BlueValues 29 [0 0 380 380 490 490 660 660]
OtherBlues 39 [-210 -210 -180 -180 -160 -160 280 280]
@ -77,7 +77,7 @@ StemSnapV 13 [140 180 200]
ForceBold 4 true
EndPrivate
TeXData: 1 0 0 335544 167772 111848 513802 1048576 111848 783286 444596 497025 792723 393216 433062 380633 303038 157286 324010 404750 52429 2506097 1059062 262144
BeginChars: 1114112 731
BeginChars: 1114112 733
StartChar: exclam
Encoding: 33 33 0
@ -19511,40 +19511,40 @@ VStem: 92.5596 41.7305<171.236 408.764> 189.39 149.051<176.142 403.858> 699.66 1
LayerCount: 2
Fore
SplineSet
500 600.610351562 m 1
671.459960938 600.610351562 810.610351562 461.459960938 810.610351562 290 c 0
810.610351562 118.540039062 671.459960938 -20.6103515625 500 -20.6103515625 c 0
328.540039062 -20.6103515625 189.389648438 118.540039062 189.389648438 290 c 0
189.389648438 461.459960938 328.540039062 600.610351562 500 600.610351562 c 1
699.66015625 102.129882812 m 1
699.66015625 167.830078125 l 1
456.870117188 167.830078125 l 1
456.870117188 463.459960938 l 1
338.440429688 463.459960938 l 1
338.440429688 102.129882812 l 1
699.66015625 102.129882812 l 1
500 -117.440429688 m 0
445 -117.440429688 391.639648438 -106.66015625 341.400390625 -85.41015625 c 0
292.879882812 -64.8896484375 249.309570312 -35.509765625 211.900390625 1.900390625 c 0
174.490234375 39.3095703125 145.110351562 82.8798828125 124.58984375 131.400390625 c 0
103.33984375 181.639648438 92.5595703125 235.009765625 92.5595703125 290 c 0
92.5595703125 344.990234375 103.33984375 398.360351562 124.58984375 448.599609375 c 0
145.110351562 497.120117188 174.490234375 540.690429688 211.900390625 578.099609375 c 0
249.309570312 615.509765625 292.879882812 644.889648438 341.400390625 665.41015625 c 0
391.639648438 686.66015625 445.009765625 697.440429688 500 697.440429688 c 0
554.990234375 697.440429688 608.360351562 686.66015625 658.599609375 665.41015625 c 0
707.120117188 644.889648438 750.690429688 615.509765625 788.099609375 578.099609375 c 0
825.509765625 540.690429688 854.889648438 497.120117188 875.41015625 448.599609375 c 0
896.66015625 398.360351562 907.440429688 344.990234375 907.440429688 290 c 0
907.440429688 235.009765625 896.66015625 181.639648438 875.41015625 131.400390625 c 0
854.889648438 82.8798828125 825.509765625 39.3095703125 788.099609375 1.900390625 c 0
750.690429688 -35.509765625 707.120117188 -64.8896484375 658.599609375 -85.41015625 c 0
608.360351562 -106.66015625 554.990234375 -117.440429688 500 -117.440429688 c 0
500 655.709960938 m 0
298.349609375 655.709960938 134.290039062 491.66015625 134.290039062 290 c 0
134.290039062 88.33984375 298.33984375 -75.7099609375 500 -75.7099609375 c 0
701.66015625 -75.7099609375 865.709960938 88.349609375 865.709960938 290 c 0
865.709960938 491.650390625 701.66015625 655.709960938 500 655.709960938 c 0
500 600.610351562 m 5
671.459960938 600.610351562 810.610351562 461.459960938 810.610351562 290 c 4
810.610351562 118.540039062 671.459960938 -20.6103515625 500 -20.6103515625 c 4
328.540039062 -20.6103515625 189.389648438 118.540039062 189.389648438 290 c 4
189.389648438 461.459960938 328.540039062 600.610351562 500 600.610351562 c 5
699.66015625 102.129882812 m 5
699.66015625 167.830078125 l 5
456.870117188 167.830078125 l 5
456.870117188 463.459960938 l 5
338.440429688 463.459960938 l 5
338.440429688 102.129882812 l 5
699.66015625 102.129882812 l 5
500 -117.440429688 m 4
445 -117.440429688 391.639648438 -106.66015625 341.400390625 -85.41015625 c 4
292.879882812 -64.8896484375 249.309570312 -35.509765625 211.900390625 1.900390625 c 4
174.490234375 39.3095703125 145.110351562 82.8798828125 124.58984375 131.400390625 c 4
103.33984375 181.639648438 92.5595703125 235.009765625 92.5595703125 290 c 4
92.5595703125 344.990234375 103.33984375 398.360351562 124.58984375 448.599609375 c 4
145.110351562 497.120117188 174.490234375 540.690429688 211.900390625 578.099609375 c 4
249.309570312 615.509765625 292.879882812 644.889648438 341.400390625 665.41015625 c 4
391.639648438 686.66015625 445.009765625 697.440429688 500 697.440429688 c 4
554.990234375 697.440429688 608.360351562 686.66015625 658.599609375 665.41015625 c 4
707.120117188 644.889648438 750.690429688 615.509765625 788.099609375 578.099609375 c 4
825.509765625 540.690429688 854.889648438 497.120117188 875.41015625 448.599609375 c 4
896.66015625 398.360351562 907.440429688 344.990234375 907.440429688 290 c 4
907.440429688 235.009765625 896.66015625 181.639648438 875.41015625 131.400390625 c 4
854.889648438 82.8798828125 825.509765625 39.3095703125 788.099609375 1.900390625 c 4
750.690429688 -35.509765625 707.120117188 -64.8896484375 658.599609375 -85.41015625 c 4
608.360351562 -106.66015625 554.990234375 -117.440429688 500 -117.440429688 c 4
500 655.709960938 m 4
298.349609375 655.709960938 134.290039062 491.66015625 134.290039062 290 c 4
134.290039062 88.33984375 298.33984375 -75.7099609375 500 -75.7099609375 c 4
701.66015625 -75.7099609375 865.709960938 88.349609375 865.709960938 290 c 4
865.709960938 491.650390625 701.66015625 655.709960938 500 655.709960938 c 4
EndSplineSet
Validated: 5
EndChar
@ -30101,7 +30101,7 @@ SplineSet
79 -59.400390625 120 -102.200195312 170.799804688 -102.200195312 c 2
838.200195312 -102.200195312 l 2
EndSplineSet
Validated: 524321
Validated: 33
EndChar
StartChar: uni23F6
@ -30171,7 +30171,7 @@ SplineSet
79 -59.400390625 120 -102.200195312 170.799804688 -102.200195312 c 2
838.200195312 -102.200195312 l 1
EndSplineSet
Validated: 524321
Validated: 33
EndChar
StartChar: uni23F7
@ -35271,5 +35271,218 @@ SplineSet
EndSplineSet
Validated: 1
EndChar
StartChar: uni2446
Encoding: 9286 9286 731
Width: 1000
HStem: 98.667 78.666<441.304 558.479> 298.667 80.666<211.095 321.99 686.039 796.635> 364 81.333<440.808 559.266> 544.667 80.666<210.809 321.868 685.514 796.925>
VStem: 104 80<406.859 516.049> 326.667 80<269.844 311.038> 349.333 80<429.563 517.407> 578.667 80<424.535 517.66> 593.333 80.667<270.25 314.708> 824 80<406.439 515.845>
LayerCount: 2
Fore
SplineSet
869.333007812 361.333007812 m 1x9840
887.333007812 310.666992188 925.333007812 194 915.333007812 116.666992188 c 0
902 10.6669921875 842.666992188 -30.6669921875 836 -35.3330078125 c 0
832 -38.6669921875 827.333007812 -40 822 -41.3330078125 c 0
812 -43.3330078125 802 -44 792 -44 c 0
770.666992188 -44 750 -39.3330078125 732.666992188 -30.6669921875 c 0
708 -18.6669921875 690 1.3330078125 676 30 c 0
654 76 656 148 662 194.666992188 c 1
661.333007812 194 658.666992188 194.666992188 655.333007812 195.333007812 c 0
627.333007812 138 568 98.6669921875 500 98.6669921875 c 0
431.333007812 98.6669921875 372 138.666992188 344 196 c 0
340 195.333007812 336 194 334.666992188 194.666992188 c 1
342.666992188 135.333007812 344.666992188 73.3330078125 324 30 c 0
310 1.3330078125 291.333007812 -18.6669921875 267.333007812 -30.6669921875 c 0
241.333007812 -43.3330078125 210 -46.6669921875 178 -40.6669921875 c 0
172.666992188 -40 168 -38 164 -35.3330078125 c 0
157.333007812 -31.3330078125 98 10.6669921875 84.6669921875 116.666992188 c 0
74.6669921875 199.333007812 116 323.333007812 133.333007812 369.333007812 c 1
114.666992188 396 104 428 104 462.666992188 c 0
104 552 176.666992188 625.333007812 266.666992188 625.333007812 c 0
299.333007812 625.333007812 329.333007812 615.333007812 354.666992188 599.333007812 c 1
385.333007812 646 436 677.333007812 492.666992188 681.333007812 c 0
557.333007812 685.333007812 619.333007812 653.333007812 655.333007812 600 c 1
680.666992188 615.333007812 710 624.666992188 741.333007812 624.666992188 c 0
830.666992188 624.666992188 904 552 904 462 c 0
904 424 891.333007812 389.333007812 869.333007812 361.333007812 c 1x9840
741.333007812 544.666992188 m 0
695.333007812 544.666992188 658.666992188 507.333007812 658.666992188 462 c 0
658.666992188 416.666992188 696 379.333007812 741.333007812 379.333007812 c 0xd940
786.666992188 379.333007812 824 416.666992188 824 462 c 0
824 507.333007812 786.666992188 544.666992188 741.333007812 544.666992188 c 0
498 601.333007812 m 0
459.333007812 598.666992188 426 572.666992188 411.333007812 536.666992188 c 0
422.666992188 514.666992188 429.333007812 489.333007812 429.333007812 462.666992188 c 0
429.333007812 450.666992188 428 439.333007812 426 428.666992188 c 1
448 439.333007812 473.333007812 445.333007812 500 445.333007812 c 0xbb40
530.666992188 445.333007812 558.666992188 437.333007812 583.333007812 424 c 1
580 436 578.666992188 448.666992188 578.666992188 462 c 0
578.666992188 490 585.333007812 516 598 539.333007812 c 0
580 579.333007812 540 604 498 601.333007812 c 0
266.666992188 544.666992188 m 0
220.666992188 544.666992188 184 507.333007812 184 462 c 0
184 416.666992188 221.333007812 379.333007812 266.666992188 379.333007812 c 0xda40
312 379.333007812 349.333007812 416.666992188 349.333007812 462 c 0
349.333007812 507.333007812 312 544.666992188 266.666992188 544.666992188 c 0
305.333007812 270 m 2
310.666992188 271.333007812 318.666992188 273.333007812 326.666992188 274 c 0xdc40
326.666992188 287.333007812 328 300 331.333007812 312 c 1
311.333007812 303.333007812 290 298.666992188 266.666992188 298.666992188 c 0
240.666992188 298.666992188 216 305.333007812 194 316 c 1
174.666992188 259.333007812 152.666992188 176 159.333007812 123.333007812 c 0
164 82.6669921875 178 56 189.333007812 39.3330078125 c 0
198.666992188 26.6669921875 216 20.6669921875 230.666992188 28 c 1
234 29.3330078125 244 34.6669921875 254 56 c 0
273.333007812 96 260 180 255.333007812 212 c 2
255.333007812 212.666992188 l 2
251.333007812 236.666992188 267.333007812 259.333007812 293.333007812 266.666992188 c 2
305.333007812 270 l 2
500 177.333007812 m 0
551.333007812 177.333007812 593.333007812 219.333007812 593.333007812 270.666992188 c 0
593.333007812 322 551.333007812 364 500 364 c 0xbcc0
448.666992188 364 406.666992188 322 406.666992188 270.666992188 c 0
406.666992188 219.333007812 448.666992188 177.333007812 500 177.333007812 c 0
840.666992188 123.333007812 m 0
846.666992188 174.666992188 826 256 808 311.333007812 c 1
788 302.666992188 765.333007812 297.333007812 742 297.333007812 c 0
715.333007812 297.333007812 690 304 668 315.333007812 c 1
671.333007812 302 673.333007812 288 674 274 c 0
684 273.333007812 694.666992188 271.333007812 701.333007812 268 c 2
708.666992188 264.666992188 l 2
729.333007812 254.666992188 741.333007812 234.666992188 738 213.333007812 c 2
738 212 l 2
734 183.333007812 726.666992188 95.3330078125 746 55.3330078125 c 0
756 34 766 29.3330078125 769.333007812 27.3330078125 c 1
784 20.6669921875 801.333007812 26 810.666992188 39.3330078125 c 0
822 56 835.333007812 82.6669921875 840.666992188 123.333007812 c 0
EndSplineSet
Validated: 524321
EndChar
StartChar: uni221B
Encoding: 8731 8731 732
Width: 1000
HStem: -209.992 21.2588<741.927 862.934> -160.664 62.5283<723.687 881.174> 85.9395 69.8691<723.687 780.459> 183.879 21.2588<741.929 862.934>
VStem: 594.865 21.2588<-62.9303 58.0754> 644.194 75.9316<-81.1715 76.316> 904.145 56.5225<-89.7754 -64.665> 988.736 21.2598<-62.9292 58.0743>
LayerCount: 2
Fore
SplineSet
133.1953125 240.114257812 m 1
128.731445312 224.2734375 135.630859375 215.740234375 135.630859375 215.740234375 c 1
158.787109375 176.336914062 l 1
148.629882812 119.875976562 174.627929688 78.4345703125 190.466796875 57.7236328125 c 0
206.305664062 37.001953125 310.713867188 -99.0751953125 323.712890625 -114.518554688 c 0
336.711914062 -129.954101562 389.11328125 -183.991210938 445.583984375 -142.953125 c 0
502.044921875 -101.926757812 483.362304688 -32.052734375 483.362304688 -32.052734375 c 1
459.1875 57.931640625 l 1
589.7890625 74.3857421875 547.140625 186.911132812 547.140625 186.911132812 c 1
601.831054688 241.602539062 l 1
601.831054688 241.602539062 714.356445312 198.951171875 730.811523438 329.545898438 c 1
820.79296875 305.37890625 l 1
820.79296875 305.37890625 890.669921875 286.688476562 931.6953125 343.159179688 c 0
972.721679688 399.619140625 918.696289062 452.03125 903.262695312 465.030273438 c 0
887.829101562 478.029296875 751.73828125 582.424804688 731.018554688 598.275390625 c 0
710.296875 614.114257812 668.864257812 640.114257812 612.404296875 629.965820312 c 1
573.001953125 653.122070312 l 1
573.001953125 653.122070312 564.466796875 660.03125 548.627929688 655.55859375 c 2
548.627929688 655.55859375 543.954101562 661.450195312 532.172851562 654.5390625 c 0
520.391601562 647.627929688 493.986328125 630.569335938 477.126953125 596.651367188 c 1
477.126953125 596.651367188 474.28515625 591.78125 480.166015625 586.296875 c 1
480.166015625 586.296875 474.078125 568.424804688 482.6015625 555.021484375 c 0
491.13671875 541.616210938 501.688476562 524.559570312 501.688476562 524.559570312 c 1
264.205078125 287.03125 l 1
264.205078125 287.03125 247.146484375 297.59375 233.741210938 306.119140625 c 0
220.337890625 314.654296875 202.465820312 308.553710938 202.465820312 308.553710938 c 1
196.981445312 314.444335938 192.1015625 311.604492188 192.1015625 311.604492188 c 1
158.18359375 294.744140625 141.125 268.340820312 134.213867188 256.559570312 c 0
127.3046875 244.786132812 133.1953125 240.114257812 133.1953125 240.114257812 c 1
829.455078125 781.646484375 m 1
829.455078125 781.645507812 l 1
792.041015625 795.248046875 760.869140625 792.16796875 741.635742188 772.922851562 c 0
733.508789062 764.796875 733.508789062 751.620117188 741.635742188 743.482421875 c 0
749.764648438 735.364257812 762.939453125 735.354492188 771.069335938 743.482421875 c 0
777.907226562 750.30859375 794.809570312 749.956054688 815.208007812 742.526367188 c 0
841.3828125 732.993164062 871.2109375 712.708007812 897.041015625 686.876953125 c 0
952.763671875 631.153320312 967.78125 575.046875 953.635742188 560.903320312 c 0
945.508789062 552.776367188 945.508789062 539.599609375 953.635742188 531.4609375 c 0
957.70703125 527.401367188 963.024414062 525.373046875 968.352539062 525.373046875 c 0
973.680664062 525.373046875 979 527.401367188 983.067382812 531.47265625 c 0
1019.61816406 568.0234375 995.288085938 647.485351562 926.47265625 716.319335938 c 0
896.052734375 746.73046875 861.592773438 769.926757812 829.455078125 781.646484375 c 1
748.963867188 663.739257812 m 1
748.96484375 663.73828125 l 1
755.135742188 669.899414062 792.102539062 663.115234375 832.69140625 622.525390625 c 0
873.270507812 581.946289062 880.076171875 544.970703125 873.904296875 538.798828125 c 0
865.788085938 530.669921875 865.788085938 517.484375 873.915039062 509.357421875 c 0
877.984375 505.297851562 883.303710938 503.268554688 888.631835938 503.268554688 c 0
893.958984375 503.268554688 899.2890625 505.297851562 903.356445312 509.3671875 c 0
932.717773438 538.74609375 915.375976562 598.71484375 862.123046875 651.959960938 c 0
808.888671875 705.224609375 748.888671875 722.555664062 719.528320312 693.184570312 c 0
711.401367188 685.056640625 711.401367188 671.879882812 719.528320312 663.743164062 c 0
727.661132812 655.600585938 740.825195312 655.62109375 748.963867188 663.739257812 c 1
213.166015625 -210 m 1
231.399414062 -210 247.083984375 -204.524414062 258.532226562 -193.078125 c 0
266.661132812 -184.94921875 266.661132812 -171.772460938 258.532226562 -163.635742188 c 0
250.403320312 -155.497070312 237.227539062 -155.506835938 229.098632812 -163.635742188 c 0
214.944335938 -177.799804688 158.858398438 -162.770507812 103.127929688 -107.0390625 c 0
77.3056640625 -81.208984375 57.01171875 -51.380859375 47.478515625 -25.2060546875 c 0
40.046875 -4.818359375 39.6826171875 12.095703125 46.5205078125 18.931640625 c 0
54.6494140625 27.0595703125 54.6494140625 40.2353515625 46.5205078125 48.3740234375 c 0
38.3935546875 56.5126953125 25.2177734375 56.5009765625 17.0888671875 48.3740234375 c 0
-2.1630859375 29.1337890625 -5.2548828125 -2.056640625 8.3583984375 -39.4521484375 c 0
20.06640625 -71.5888671875 43.2763671875 -106.049804688 73.6953125 -136.470703125 c 0
120.946289062 -183.729492188 173.2109375 -210.008789062 213.166015625 -210 c 1
138.03515625 -72.1201171875 m 1
160.764648438 -94.8388671875 186.5859375 -112.198242188 210.741210938 -120.9921875 c 0
223.53125 -125.655273438 234.375976562 -127.456054688 243.53515625 -127.456054688 c 0
262.7890625 -127.456054688 274.487304688 -119.473632812 280.627929688 -113.333007812 c 0
288.744140625 -105.204101562 288.744140625 -92.017578125 280.6171875 -83.890625 c 0
272.490234375 -75.7744140625 259.302734375 -75.7626953125 251.17578125 -83.890625 c 0
248.990234375 -86.1083984375 240.174804688 -87.408203125 224.979492188 -81.880859375 c 0
206.673828125 -75.2099609375 185.711914062 -60.921875 167.458007812 -42.67578125 c 0
149.212890625 -24.4306640625 134.924804688 -3.458984375 128.252929688 14.845703125 c 0
122.7265625 30.01953125 124.02734375 38.8251953125 126.245117188 41.041015625 c 0
134.374023438 49.16796875 134.374023438 62.34375 126.245117188 70.4833984375 c 0
118.116210938 78.6220703125 104.940429688 78.6103515625 96.8134765625 70.4833984375 c 0
87.748046875 61.4169921875 74.6875 40.279296875 89.1416015625 0.5966796875 c 0
97.9560546875 -23.5703125 115.315429688 -49.400390625 138.03515625 -72.1201171875 c 1
802.430664062 155.80859375 m 0
715.083007812 155.80859375 644.194335938 84.919921875 644.194335938 -2.427734375 c 0
644.194335938 -89.775390625 715.083007812 -160.6640625 802.430664062 -160.6640625 c 0
889.778320312 -160.6640625 960.666992188 -89.775390625 960.666992188 -2.427734375 c 0
960.666992188 84.919921875 889.778320312 155.80859375 802.430664062 155.80859375 c 0
904.14453125 -98.1357421875 m 1
720.125976562 -98.1357421875 l 1
720.125976562 85.939453125 l 1
780.458984375 85.939453125 l 1
780.458984375 -64.6650390625 l 1
904.14453125 -64.6650390625 l 1
904.14453125 -98.1357421875 l 1
802.430664062 -209.9921875 m 0
830.4453125 -209.9921875 857.633789062 -204.500976562 883.227539062 -193.674804688 c 0
907.9453125 -183.221679688 930.141601562 -168.25390625 949.19921875 -149.196289062 c 0
968.2578125 -130.138671875 983.224609375 -107.942382812 993.678710938 -83.2236328125 c 0
1004.50390625 -57.6298828125 1009.99609375 -30.44140625 1009.99609375 -2.427734375 c 0
1009.99609375 25.5869140625 1004.50390625 52.775390625 993.678710938 78.369140625 c 0
983.224609375 103.087890625 968.2578125 125.284179688 949.19921875 144.341796875 c 0
930.141601562 163.399414062 907.9453125 178.3671875 883.227539062 188.8203125 c 0
857.6328125 199.646484375 830.4453125 205.137695312 802.430664062 205.137695312 c 0
774.416015625 205.137695312 747.227539062 199.646484375 721.633789062 188.8203125 c 0
696.916015625 178.3671875 674.719726562 163.399414062 655.662109375 144.341796875 c 0
636.603515625 125.284179688 621.63671875 103.087890625 611.182617188 78.369140625 c 0
600.357421875 52.775390625 594.865234375 25.5869140625 594.865234375 -2.427734375 c 0
594.865234375 -30.44140625 600.357421875 -57.6298828125 611.182617188 -83.2236328125 c 0
621.63671875 -107.942382812 636.603515625 -130.138671875 655.662109375 -149.196289062 c 0
674.719726562 -168.25390625 696.916015625 -183.221679688 721.633789062 -193.674804688 c 0
747.228515625 -204.500976562 774.411132812 -209.9921875 802.430664062 -209.9921875 c 0
802.430664062 183.87890625 m 0
905.1640625 183.87890625 988.736328125 100.299804688 988.736328125 -2.427734375 c 0
988.736328125 -105.155273438 905.1640625 -188.733398438 802.430664062 -188.733398438 c 0
699.697265625 -188.733398438 616.124023438 -105.161132812 616.124023438 -2.427734375 c 0
616.124023438 100.305664062 699.703125 183.87890625 802.430664062 183.87890625 c 0
EndSplineSet
Validated: 524325
EndChar
EndChars
EndSplineFont

View File

@ -1,5 +0,0 @@
set(CMAKE_C_COMPILER /usr/bin/clang-16)
set(CMAKE_CXX_COMPILER /usr/bin/clang++-16)
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld")
set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld")
set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld")

View File

@ -0,0 +1,519 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0
set -e
if [ "$#" -lt 4 ]; then
echo "Syntax: $0 [-system-freetype] [-system-harfbuzz] [-system-libjpeg] [-system-libpng] [-system-libwebp] [-system-libzip] [-system-zstd] [-system-qt] [-skip-download] [-skip-cleanup] [-only-download] <host directory> <cross architecture> <cross chroot> <output directory>"
exit 1
fi
for arg in "$@"; do
if [ "$arg" == "-system-freetype" ]; then
echo "Skipping building FreeType."
SKIP_FREETYPE=true
shift
elif [ "$arg" == "-system-harfbuzz" ]; then
echo "Skipping building HarfBuzz."
SKIP_HARFBUZZ=true
shift
elif [ "$arg" == "-system-libjpeg" ]; then
echo "Skipping building libjpeg."
SKIP_LIBJPEG=true
shift
elif [ "$arg" == "-system-libpng" ]; then
echo "Skipping building libpng."
SKIP_LIBPNG=true
shift
elif [ "$arg" == "-system-libwebp" ]; then
echo "Skipping building libwebp."
SKIP_LIBWEBP=true
shift
elif [ "$arg" == "-system-libzip" ]; then
echo "Skipping building libzip."
SKIP_LIBZIP=true
shift
elif [ "$arg" == "-system-zstd" ]; then
echo "Skipping building zstd."
SKIP_ZSTD=true
shift
elif [ "$arg" == "-system-qt" ]; then
echo "Skipping building Qt."
SKIP_QT=true
shift
elif [ "$arg" == "-skip-download" ]; then
echo "Not downloading sources."
SKIP_DOWNLOAD=true
shift
elif [ "$arg" == "-skip-cleanup" ]; then
echo "Not removing build directory."
SKIP_CLEANUP=true
shift
elif [ "$arg" == "-only-download" ]; then
echo "Only downloading sources."
ONLY_DOWNLOAD=true
shift
fi
done
SCRIPTDIR=$(realpath $(dirname "${BASH_SOURCE[0]}"))
NPROCS="$(getconf _NPROCESSORS_ONLN)"
HOSTDIR="$1"
if [ "${HOSTDIR:0:1}" != "/" ]; then
HOSTDIR="$PWD/$HOSTDIR"
fi
CROSSARCH="$2"
SYSROOTDIR="$3"
if [ "${SYSROOTDIR:0:1}" != "/" ]; then
SYSROOTDIR="$PWD/$SYSROOTDIR"
fi
INSTALLDIR="$4"
if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
TOOLCHAINFILE="$INSTALLDIR/toolchain.cmake"
CMAKE_COMMON=(
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_TOOLCHAIN_FILE="$TOOLCHAINFILE"
-DCMAKE_PREFIX_PATH="$INSTALLDIR"
-DCMAKE_INSTALL_PREFIX="$INSTALLDIR"
)
# TODO: Pull all of this from the main file.
FREETYPE=2.13.3
HARFBUZZ=10.1.0
LIBBACKTRACE=86885d14049fab06ef8a33aac51664230ca09200
LIBJPEGTURBO=3.0.4
LIBPNG=1.6.44
LIBWEBP=1.4.0
LIBZIP=1.11.2
SDL2=2.30.11
QT=6.8.1
ZSTD=1.5.6
CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
DISCORD_RPC=144f3a3f1209994d8d9e8a87964a989cb9911c1e
LUNASVG=9af1ac7b90658a279b372add52d6f77a4ebb482c
SHADERC=1c0d3d18819aa75ec74f1fbd9ff0461e1b69a4d6
SOUNDTOUCH=463ade388f3a51da078dc9ed062bf28e4ba29da7
SPIRV_CROSS=vulkan-sdk-1.3.290.0
mkdir -p "${INSTALLDIR}"
mkdir -p deps-build
cd deps-build
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.tar.gz" \
-O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL2/SDL2-$SDL2.tar.gz" \
-o "cpuinfo-$CPUINFO.tar.gz" "https://github.com/stenzek/cpuinfo/archive/$CPUINFO.tar.gz" \
-o "discord-rpc-$DISCORD_RPC.tar.gz" "https://github.com/stenzek/discord-rpc/archive/$DISCORD_RPC.tar.gz" \
-o "lunasvg-$LUNASVG.tar.gz" "https://github.com/stenzek/lunasvg/archive/$LUNASVG.tar.gz" \
-o "shaderc-$SHADERC.tar.gz" "https://github.com/stenzek/shaderc/archive/$SHADERC.tar.gz" \
-o "soundtouch-$SOUNDTOUCH.tar.gz" "https://github.com/stenzek/soundtouch/archive/$SOUNDTOUCH.tar.gz"
fi
cat > SHASUMS <<EOF
baf8aebd22002b762d803ba0e1e389b6b4415159334e9d34bba1a938f6de8ce6 $LIBBACKTRACE.tar.gz
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f SDL2-$SDL2.tar.gz
e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz
3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz
3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz
3826d86f8a13564be1c047ac105041a3c5d0dc0bf826fe47cc582fe17a2ce7b1 shaderc-$SHADERC.tar.gz
fe45c2af99f6102d2704277d392c1c83b55180a70bfd17fb888cc84a54b70573 soundtouch-$SOUNDTOUCH.tar.gz
EOF
if [ "$SKIP_FREETYPE" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download"
fi
cat >> SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
EOF
fi
if [ "$SKIP_HARFBUZZ" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz"
fi
cat >> SHASUMS <<EOF
c758fdce8587641b00403ee0df2cd5d30cbea7803d43c65fddd76224f7b49b88 harfbuzz-$HARFBUZZ.tar.gz
EOF
fi
if [ "$SKIP_LIBJPEG" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz"
fi
cat >> SHASUMS <<EOF
99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b libjpeg-turbo-$LIBJPEGTURBO.tar.gz
EOF
fi
if [ "$SKIP_LIBPNG" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz"
fi
cat >> SHASUMS <<EOF
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
EOF
fi
if [ "$SKIP_LIBWEBP" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz"
fi
cat >> SHASUMS <<EOF
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
EOF
fi
if [ "$SKIP_LIBZIP" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -O "https://github.com/nih-at/libzip/releases/download/v$LIBZIP/libzip-$LIBZIP.tar.xz"
fi
cat >> SHASUMS <<EOF
5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz
EOF
fi
if [ "$SKIP_ZSTD" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz"
fi
cat >> SHASUMS <<EOF
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
EOF
fi
if [ "$SKIP_QT" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz"
fi
cat >> SHASUMS <<EOF
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
2226fbde4e2ddd12f8bf4b239c8f38fd706a54e789e63467dfddc77129eca203 qtwayland-everywhere-src-$QT.tar.xz
EOF
fi
shasum -a 256 --check SHASUMS
# Have to clone with git, because it does version detection.
if [ "$SKIP_DOWNLOAD" != true ]; then
if [ ! -d "SPIRV-Cross" ]; then
git clone https://github.com/KhronosGroup/SPIRV-Cross/ -b $SPIRV_CROSS --depth 1
fi
fi
# Only downloading sources?
if [ "$ONLY_DOWNLOAD" == true ]; then
exit 0
fi
# Stop pkg-config picking up host files.
export PKG_CONFIG_PATH=${SYSROOTDIR}/usr/lib/${CROSSARCH}-linux-gnu/pkgconfig:${SYSROOTDIR}/usr/lib/pkgconfig:${SYSROOTDIR}/usr/share/pkgconfig
export PKG_CONFIG_SYSROOT_DIR=${SYSROOTDIR}
# Generate cmake toolchain file.
cat > "$TOOLCHAINFILE" << EOF
set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR ${CROSSARCH})
set(CMAKE_C_COMPILER "/usr/bin/${CROSSARCH}-linux-gnu-gcc")
set(CMAKE_C_COMPILER_TARGET "${CROSSARCH}-linux-gnu")
set(CMAKE_C_COMPILER_AR "/usr/bin/${CROSSARCH}-linux-gnu-ar")
set(CMAKE_C_COMPILER_RANLIB "/usr/bin/${CROSSARCH}-linux-gnu-ranlib")
set(CMAKE_CXX_COMPILER "/usr/bin/${CROSSARCH}-linux-gnu-g++")
set(CMAKE_CXX_COMPILER_TARGET "${CROSSARCH}-linux-gnu")
set(CMAKE_CXX_COMPILER_AR "/usr/bin/${CROSSARCH}-linux-gnu-ar")
set(CMAKE_CXX_COMPILER_RANLIB "/usr/bin/${CROSSARCH}-linux-gnu-ranlib")
set(CMAKE_FIND_ROOT_PATH "${INSTALLDIR};${SYSROOTDIR}")
set(CMAKE_SYSROOT "${SYSROOTDIR}")
set(CMAKE_PKG_CONFIG_PC_PATH "${PKG_CONFIG_PATH}")
set(CMAKE_PKG_CONFIG_SYSROOT_DIR "${PKG_CONFIG_SYSROOT_DIR}")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
EOF
# NOTE: Must be a shared library because otherwise aarch64 libgcc symbols are missing when building with clang.
echo "Building libbacktrace..."
rm -fr "libbacktrace-$LIBBACKTRACE"
tar xf "$LIBBACKTRACE.tar.gz"
cd "libbacktrace-$LIBBACKTRACE"
./configure --prefix="$INSTALLDIR" --build=x86_64-linux-gnu --host="${CROSSARCH}-linux-gnu" --with-pic --enable-shared --disable-static
make
make install
cd ..
if [ "$SKIP_LIBPNG" != true ]; then
echo "Building libpng..."
rm -fr "libpng-$LIBPNG"
tar xf "libpng-$LIBPNG.tar.xz"
cd "libpng-$LIBPNG"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DPNG_TESTS=OFF -DPNG_STATIC=OFF -DPNG_SHARED=ON -DPNG_TOOLS=OFF -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
fi
if [ "$SKIP_LIBJPEG" != true ]; then
echo "Building libjpeg..."
rm -fr "libjpeg-turbo-$LIBJPEGTURBO"
tar xf "libjpeg-turbo-$LIBJPEGTURBO.tar.gz"
cd "libjpeg-turbo-$LIBJPEGTURBO"
cmake "${CMAKE_COMMON[@]}" -DENABLE_STATIC=OFF -DENABLE_SHARED=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
fi
if [ "$SKIP_ZSTD" != true ]; then
echo "Building Zstandard..."
rm -fr "zstd-$ZSTD"
tar xf "zstd-$ZSTD.tar.gz"
cd "zstd-$ZSTD"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake
cmake --build build --parallel
ninja -C build install
cd ..
fi
if [ "$SKIP_LIBWEBP" != true ]; then
echo "Building WebP..."
rm -fr "libwebp-$LIBWEBP"
tar xf "libwebp-$LIBWEBP.tar.gz"
cd "libwebp-$LIBWEBP"
cmake "${CMAKE_COMMON[@]}" -B build -G Ninja \
-DWEBP_BUILD_ANIM_UTILS=OFF -DWEBP_BUILD_CWEBP=OFF -DWEBP_BUILD_DWEBP=OFF -DWEBP_BUILD_GIF2WEBP=OFF -DWEBP_BUILD_IMG2WEBP=OFF \
-DWEBP_BUILD_VWEBP=OFF -DWEBP_BUILD_WEBPINFO=OFF -DWEBP_BUILD_WEBPMUX=OFF -DWEBP_BUILD_EXTRAS=OFF -DBUILD_SHARED_LIBS=ON
cmake --build build --parallel
ninja -C build install
cd ..
fi
if [ "$SKIP_LIBZIP" != true ]; then
echo "Building libzip..."
rm -fr "libzip-$LIBZIP"
tar xf "libzip-$LIBZIP.tar.xz"
cd "libzip-$LIBZIP"
cmake "${CMAKE_COMMON[@]}" -B build -G Ninja \
-DENABLE_COMMONCRYPTO=OFF -DENABLE_GNUTLS=OFF -DENABLE_MBEDTLS=OFF -DENABLE_OPENSSL=OFF -DENABLE_WINDOWS_CRYPTO=OFF \
-DENABLE_BZIP2=OFF -DENABLE_LZMA=OFF -DENABLE_ZSTD=ON -DBUILD_SHARED_LIBS=ON -DLIBZIP_DO_INSTALL=ON \
-DBUILD_TOOLS=OFF -DBUILD_REGRESS=OFF -DBUILD_OSSFUZZ=OFF -DBUILD_EXAMPLES=OFF -DBUILD_DOC=OFF
cmake --build build --parallel
ninja -C build install
cd ..
fi
if [ "$SKIP_FREETYPE" != true ]; then
if [ "$SKIP_HARFBUZZ" != true ]; then
echo "Building FreeType without HarfBuzz..."
rm -fr "freetype-$FREETYPE"
tar xf "freetype-$FREETYPE.tar.xz"
cd "freetype-$FREETYPE"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=ON -DFT_REQUIRE_PNG=ON -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_DISABLE_HARFBUZZ=TRUE -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building HarfBuzz..."
rm -fr "harfbuzz-$HARFBUZZ"
tar xf "harfbuzz-$HARFBUZZ.tar.gz"
cd "harfbuzz-$HARFBUZZ"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DHB_BUILD_UTILS=OFF -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
fi
echo "Building FreeType with HarfBuzz..."
rm -fr "freetype-$FREETYPE"
tar xf "freetype-$FREETYPE.tar.xz"
cd "freetype-$FREETYPE"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=ON -DFT_REQUIRE_PNG=ON -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_REQUIRE_HARFBUZZ=TRUE -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
fi
echo "Building SDL2..."
rm -fr "SDL2-$SDL2"
tar xf "SDL2-$SDL2.tar.gz"
cd "SDL2-$SDL2"
# needed because -Isystem with chroot/usr/include breaks
patch -p1 < "$SCRIPTDIR/sdl2-disable-isystem.patch"
cmake -B build "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
if [ "$SKIP_QT" != true ]; then
# Couple notes:
# -fontconfig is needed otherwise Qt Widgets render only boxes.
# -qt-doubleconversion avoids a dependency on libdouble-conversion.
# ICU avoids pulling in a bunch of large libraries, and hopefully we can get away without it.
# OpenGL is needed to render window decorations in Wayland, apparently.
# dbus-runtime and linked off to avoid a relocation error (different to host.. probably should change that).
echo "Building Qt Base..."
rm -fr "qtbase-everywhere-src-$QT"
tar xf "qtbase-everywhere-src-$QT.tar.xz"
cd "qtbase-everywhere-src-$QT"
patch -p1 < "$SCRIPTDIR/qtbase-disable-pcre2-jit.patch"
mkdir build
cd build
../configure -prefix "$INSTALLDIR" -extprefix "$INSTALLDIR" -qt-host-path "$HOSTDIR" -release -dbus runtime -gui -widgets -fontconfig -qt-doubleconversion -ssl -openssl-runtime -opengl desktop -qpa xcb,wayland -xkbcommon -xcb -gtk -- -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAINFILE" -DFEATURE_cups=OFF -DFEATURE_dbus=ON -DFEATURE_dbus_linked=OFF -DFEATURE_icu=OFF -DFEATURE_sql=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
cmake --build . --parallel
ninja install
cd ../../
echo "Building Qt SVG..."
rm -fr "qtsvg-everywhere-src-$QT"
tar xf "qtsvg-everywhere-src-$QT.tar.xz"
cd "qtsvg-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR"
cmake --build . --parallel
ninja install
cd ../../
echo "Building Qt Image Formats..."
rm -fr "qtimageformats-everywhere-src-$QT"
tar xf "qtimageformats-everywhere-src-$QT.tar.xz"
cd "qtimageformats-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DFEATURE_system_webp=ON
cmake --build . --parallel
ninja install
cd ../../
echo "Building Qt Wayland..."
rm -fr "qtwayland-everywhere-src-$QT"
tar xf "qtwayland-everywhere-src-$QT.tar.xz"
cd "qtwayland-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DFEATURE_wayland_server=OFF
cmake --build . --parallel
ninja install
cd ../../
echo "Installing Qt Tools..."
rm -fr "qttools-everywhere-src-$QT"
tar xf "qttools-everywhere-src-$QT.tar.xz"
cd "qttools-everywhere-src-$QT"
# Force disable clang scanning, it gets very confused.
patch -u configure.cmake <<EOF
--- configure.cmake
+++ configure.cmake
@@ -14,12 +14,12 @@
# Presumably because 6.0 ClangConfig.cmake files are not good enough?
# In any case explicitly request a minimum version of 8.x for now, otherwise
# building with CMake will fail at compilation time.
-qt_find_package(WrapLibClang 8 PROVIDED_TARGETS WrapLibClang::WrapLibClang)
+#qt_find_package(WrapLibClang 8 PROVIDED_TARGETS WrapLibClang::WrapLibClang)
# special case end
-if(TARGET WrapLibClang::WrapLibClang)
- set(TEST_libclang "ON" CACHE BOOL "Required libclang version found." FORCE)
-endif()
+#if(TARGET WrapLibClang::WrapLibClang)
+# set(TEST_libclang "ON" CACHE BOOL "Required libclang version found." FORCE)
+#endif()
EOF
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=ON -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
cmake --build . --parallel
ninja install
cd ../../
echo "Installing Qt Translations..."
rm -fr "qttranslations-everywhere-src-$QT"
tar xf "qttranslations-everywhere-src-$QT.tar.xz"
cd "qttranslations-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR"
cmake --build . --parallel
ninja install
cd ../../
fi
echo "Building shaderc..."
rm -fr "shaderc-$SHADERC"
tar xf "shaderc-$SHADERC.tar.gz"
cd "shaderc-$SHADERC"
cmake "${CMAKE_COMMON[@]}" -DSHADERC_SKIP_TESTS=ON -DSHADERC_SKIP_EXAMPLES=ON -DSHADERC_SKIP_COPYRIGHT_CHECK=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building SPIRV-Cross..."
cd SPIRV-Cross
rm -fr build
cmake "${CMAKE_COMMON[@]}" -DSPIRV_CROSS_SHARED=ON -DSPIRV_CROSS_STATIC=OFF -DSPIRV_CROSS_CLI=OFF -DSPIRV_CROSS_ENABLE_TESTS=OFF -DSPIRV_CROSS_ENABLE_GLSL=ON -DSPIRV_CROSS_ENABLE_HLSL=OFF -DSPIRV_CROSS_ENABLE_MSL=OFF -DSPIRV_CROSS_ENABLE_CPP=OFF -DSPIRV_CROSS_ENABLE_REFLECT=OFF -DSPIRV_CROSS_ENABLE_C_API=ON -DSPIRV_CROSS_ENABLE_UTIL=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building cpuinfo..."
rm -fr "cpuinfo-$CPUINFO"
tar xf "cpuinfo-$CPUINFO.tar.gz"
cd "cpuinfo-$CPUINFO"
cmake "${CMAKE_COMMON[@]}" -DCPUINFO_LIBRARY_TYPE=shared -DCPUINFO_RUNTIME_TYPE=shared -DCPUINFO_LOG_LEVEL=error -DCPUINFO_LOG_TO_STDIO=ON -DCPUINFO_BUILD_TOOLS=OFF -DCPUINFO_BUILD_UNIT_TESTS=OFF -DCPUINFO_BUILD_MOCK_TESTS=OFF -DCPUINFO_BUILD_BENCHMARKS=OFF -DUSE_SYSTEM_LIBS=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building discord-rpc..."
rm -fr "discord-rpc-$DISCORD_RPC"
tar xf "discord-rpc-$DISCORD_RPC.tar.gz"
cd "discord-rpc-$DISCORD_RPC"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building lunasvg..."
rm -fr "lunasvg-$LUNASVG"
tar xf "lunasvg-$LUNASVG.tar.gz"
cd "lunasvg-$LUNASVG"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DLUNASVG_BUILD_EXAMPLES=OFF -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building soundtouch..."
rm -fr "soundtouch-$SOUNDTOUCH"
tar xf "soundtouch-$SOUNDTOUCH.tar.gz"
cd "soundtouch-$SOUNDTOUCH"
cmake "${CMAKE_COMMON[@]}" -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
if [ "$SKIP_CLEANUP" != true ]; then
echo "Cleaning up..."
cd ..
rm -fr deps-build
fi

View File

@ -6,7 +6,7 @@
set -e
if [ "$#" -lt 1 ]; then
echo "Syntax: $0 [-system-freetype] [-system-harfbuzz] [-system-libjpeg] [-system-libpng] [-system-libwebp] [-system-libzip] [-system-zstd] [-system-qt] [-skip-download] [-skip-cleanup] <output directory>"
echo "Syntax: $0 [-system-freetype] [-system-harfbuzz] [-system-libjpeg] [-system-libpng] [-system-libwebp] [-system-libzip] [-system-zstd] [-system-qt] [-skip-download] [-skip-cleanup] [-only-download] <output directory>"
exit 1
fi
@ -51,6 +51,10 @@ for arg in "$@"; do
echo "Not removing build directory."
SKIP_CLEANUP=true
shift
elif [ "$arg" == "-only-download" ]; then
echo "Only downloading sources."
ONLY_DOWNLOAD=true
shift
fi
done
@ -62,14 +66,14 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
fi
FREETYPE=2.13.3
HARFBUZZ=10.0.1
HARFBUZZ=10.1.0
LIBBACKTRACE=86885d14049fab06ef8a33aac51664230ca09200
LIBJPEGTURBO=3.0.4
LIBPNG=1.6.44
LIBWEBP=1.4.0
LIBZIP=1.11.1
SDL2=2.30.9
QT=6.8.0
LIBZIP=1.11.2
SDL2=2.30.11
QT=6.8.1
ZSTD=1.5.6
CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
@ -95,7 +99,7 @@ fi
cat > SHASUMS <<EOF
baf8aebd22002b762d803ba0e1e389b6b4415159334e9d34bba1a938f6de8ce6 $LIBBACKTRACE.tar.gz
24b574f71c87a763f50704bbb630cbe38298d544a1f890f099a4696b1d6beba4 SDL2-$SDL2.tar.gz
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f SDL2-$SDL2.tar.gz
e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz
3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz
3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz
@ -116,7 +120,7 @@ if [ "$SKIP_HARFBUZZ" != true ]; then
curl -C - -L -o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz"
fi
cat >> SHASUMS <<EOF
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
c758fdce8587641b00403ee0df2cd5d30cbea7803d43c65fddd76224f7b49b88 harfbuzz-$HARFBUZZ.tar.gz
EOF
fi
if [ "$SKIP_LIBJPEG" != true ]; then
@ -148,7 +152,7 @@ if [ "$SKIP_LIBZIP" != true ]; then
curl -C - -L -O "https://github.com/nih-at/libzip/releases/download/v$LIBZIP/libzip-$LIBZIP.tar.xz"
fi
cat >> SHASUMS <<EOF
721e0e4e851073b508c243fd75eda04e4c5006158a900441de10ce274cc3b633 libzip-$LIBZIP.tar.xz
5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz
EOF
fi
if [ "$SKIP_ZSTD" != true ]; then
@ -170,12 +174,12 @@ if [ "$SKIP_QT" != true ]; then
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz"
fi
cat >> SHASUMS <<EOF
1bad481710aa27f872de6c9f72651f89a6107f0077003d0ebfcc9fd15cba3c75 qtbase-everywhere-src-$QT.tar.xz
595bf8557b91e1f8ebc726f1e09868a3c7e610ff5045068f2d4ea2428c49a5d4 qtimageformats-everywhere-src-$QT.tar.xz
cf7a593d5e520f8177240610d9e55d5b75b0887fe5f385554ff64377f1646199 qtsvg-everywhere-src-$QT.tar.xz
403115d8268503c6cc6e43310c8ae28eb9e605072a5d04e4a2de8b6af39981f7 qttools-everywhere-src-$QT.tar.xz
84bf2b67c243cd0c50a08acd7bfa9df2b1965028511815c1b6b65a0687437cb6 qttranslations-everywhere-src-$QT.tar.xz
175758591638ebf1c6fbb66ac11c7fa0eb8d4ed52e9243cc59075d06a6a2060a qtwayland-everywhere-src-$QT.tar.xz
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
2226fbde4e2ddd12f8bf4b239c8f38fd706a54e789e63467dfddc77129eca203 qtwayland-everywhere-src-$QT.tar.xz
EOF
fi
@ -188,6 +192,11 @@ if [ "$SKIP_DOWNLOAD" != true ]; then
fi
fi
# Only downloading sources?
if [ "$ONLY_DOWNLOAD" == true ]; then
exit 0
fi
echo "Building libbacktrace..."
rm -fr "libbacktrace-$LIBBACKTRACE"
tar xf "$LIBBACKTRACE.tar.gz"

View File

@ -37,16 +37,16 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
fi
FREETYPE=2.13.3
HARFBUZZ=10.0.1
SDL2=2.30.9
HARFBUZZ=10.1.0
SDL2=2.30.11
ZSTD=1.5.6
LIBPNG=1.6.44
LIBJPEGTURBO=3.0.4
LIBWEBP=1.4.0
LIBZIP=1.11.1
FFMPEG=7.0.2
LIBZIP=1.11.2
FFMPEG=7.1
MOLTENVK=1.2.9
QT=6.8.0
QT=6.8.1
CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
DISCORD_RPC=144f3a3f1209994d8d9e8a87964a989cb9911c1e
@ -73,22 +73,28 @@ CMAKE_ARCH_X64=-DCMAKE_OSX_ARCHITECTURES="x86_64"
CMAKE_ARCH_ARM64=-DCMAKE_OSX_ARCHITECTURES="arm64"
CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
# SBOM generation appears to be broken on MacOS, and I can't be arsed to debug it.
CMAKE_COMMON_QT=(
-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
-DQT_GENERATE_SBOM=OFF
)
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
c758fdce8587641b00403ee0df2cd5d30cbea7803d43c65fddd76224f7b49b88 harfbuzz-$HARFBUZZ.tar.gz
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b libjpeg-turbo-$LIBJPEGTURBO.tar.gz
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
721e0e4e851073b508c243fd75eda04e4c5006158a900441de10ce274cc3b633 libzip-$LIBZIP.tar.xz
24b574f71c87a763f50704bbb630cbe38298d544a1f890f099a4696b1d6beba4 SDL2-$SDL2.tar.gz
5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f SDL2-$SDL2.tar.gz
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
8646515b638a3ad303e23af6a3587734447cb8fc0a0c064ecdb8e95c4fd8b389 ffmpeg-$FFMPEG.tar.xz
40973d44970dbc83ef302b0609f2e74982be2d85916dd2ee7472d30678a7abe6 ffmpeg-$FFMPEG.tar.xz
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
1bad481710aa27f872de6c9f72651f89a6107f0077003d0ebfcc9fd15cba3c75 qtbase-everywhere-src-$QT.tar.xz
595bf8557b91e1f8ebc726f1e09868a3c7e610ff5045068f2d4ea2428c49a5d4 qtimageformats-everywhere-src-$QT.tar.xz
cf7a593d5e520f8177240610d9e55d5b75b0887fe5f385554ff64377f1646199 qtsvg-everywhere-src-$QT.tar.xz
403115d8268503c6cc6e43310c8ae28eb9e605072a5d04e4a2de8b6af39981f7 qttools-everywhere-src-$QT.tar.xz
84bf2b67c243cd0c50a08acd7bfa9df2b1965028511815c1b6b65a0687437cb6 qttranslations-everywhere-src-$QT.tar.xz
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz
3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz
3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz
@ -301,7 +307,7 @@ patch -u src/tools/macdeployqt/shared/shared.cpp <<EOF
// Platforminputcontext plugins if QtGui is in use
EOF
cmake -B build "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_dbus=OFF -DFEATURE_framework=OFF -DFEATURE_icu=OFF -DFEATURE_opengl=OFF -DFEATURE_sql=OFF -DFEATURE_gssapi=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
cmake -B build "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}" -DFEATURE_dbus=OFF -DFEATURE_framework=OFF -DFEATURE_icu=OFF -DFEATURE_opengl=OFF -DFEATURE_sql=OFF -DFEATURE_gssapi=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
make -C build "-j$NPROCS"
make -C build install
cd ..
@ -312,7 +318,7 @@ tar xf "qtsvg-everywhere-src-$QT.tar.xz"
cd "qtsvg-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL"
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}"
make "-j$NPROCS"
make install
cd ../..
@ -323,7 +329,7 @@ tar xf "qtimageformats-everywhere-src-$QT.tar.xz"
cd "qtimageformats-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_system_webp=ON
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}" -DFEATURE_system_webp=ON
make "-j$NPROCS"
make install
cd ../..
@ -334,7 +340,7 @@ tar xf "qttools-everywhere-src-$QT.tar.xz"
cd "qttools-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=ON -DFEATURE_kmap2qmap=OFF -DFEATURE_linguist=ON -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=ON -DFEATURE_kmap2qmap=OFF -DFEATURE_linguist=ON -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
make "-j$NPROCS"
make install
cd ../..
@ -345,7 +351,7 @@ tar xf "qttranslations-everywhere-src-$QT.tar.xz"
cd "qttranslations-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL"
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}"
make "-j$NPROCS"
make install
cd ../..

View File

@ -46,14 +46,14 @@ echo INSTALLDIR=%INSTALLDIR%
cd "%BUILDDIR%"
set FREETYPE=2.13.3
set HARFBUZZ=10.0.1
set HARFBUZZ=10.1.0
set LIBJPEGTURBO=3.0.4
set LIBPNG=1644
set QT=6.8.0
set QT=6.8.1
set QTMINOR=6.8
set SDL2=2.30.9
set SDL2=2.30.11
set WEBP=1.4.0
set LIBZIP=1.11.1
set LIBZIP=1.11.2
set ZLIB=1.3.1
set ZLIBSHORT=131
set ZSTD=1.5.6
@ -68,20 +68,20 @@ set DXCOMPILER=1.8.2407.12
set DXAGILITY=1.614.1
call :downloadfile "freetype-%FREETYPE%.tar.gz" "https://download.savannah.gnu.org/releases/freetype/freetype-%FREETYPE%.tar.gz" 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" f93ff7ec6f2fcb9242256976a7e6d1da2588b5e57a559fb71a025b74bd1f5539 || goto error
call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" 7d7571a1faa1898b69888716dfdea0e4d466f1a5cf518e6aa626df2242bbadbe || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" ec855bcd815b4b63d0c958c42c2923311c656227d6e0c1ae1e721406d346444b || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" c3b41915341d853b6374cf93f1fcced2c8e4be9360f29c656960e1d0d15046a3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 809081a7bdf7e48262fbe9437e4e756df6ad2649433e803c4040026e650d7c91 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 89f1ef4595f68c3d34c63a7c1c4ce475e701e103f0473f3fd0718a2e5234de6e || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 3f813f49d6d28c532dc4b104084f60ff382337f184698fcd6e70ab9efad977c1 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 91c33d9946279c9c613b02e52a33df610cc01d13ea6e321b4c4d8ee708b9a03e || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" a0b3e7ac5f708042683ff0f22e069bdf75563540c615f9854ecc9bc8913e2488 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" c65a89140f5d68137ffec67d631ec97002fb37077d9b4eb4ee45cbec39b1c38a || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 30a8e7773e1f274557e049a97f158b808f344247da03ae5240e4956c81d51cd5 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" c0e6fa52a62ba11efd30262290dc6970947aef32e0cc294ee50e9005ceac092a || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" 6b2a43837005e1c23fdfee532b78f806863e412d2089b9c42b49ab08cbcd7665 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 675f144b11f8ab2424b64bed8ccdca5d3f35b9326046fa7a883925dd180f0651 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
call :downloadfile "cpuinfo-%CPUINFO%.zip" "https://github.com/pytorch/cpuinfo/archive/%CPUINFO%.zip" 13146ae7983d767a678dd01b0d6af591e77cec82babd41264b9164ab808d7d41 || goto error
call :downloadfile "discord-rpc-%DISCORD_RPC%.zip" "https://github.com/stenzek/discord-rpc/archive/%DISCORD_RPC%.zip" 61e185e75d37b360c314125bcdf4697192d15e2d5209db3306ed6cd736d508b3 || goto error

View File

@ -44,14 +44,14 @@ set "PATH=%PATH%;%INSTALLDIR%\bin"
cd "%BUILDDIR%"
set FREETYPE=2.13.3
set HARFBUZZ=10.0.1
set HARFBUZZ=10.1.0
set LIBJPEGTURBO=3.0.4
set LIBPNG=1644
set QT=6.8.0
set QT=6.8.1
set QTMINOR=6.8
set SDL2=2.30.9
set SDL2=2.30.11
set WEBP=1.4.0
set LIBZIP=1.11.1
set LIBZIP=1.11.2
set ZLIB=1.3.1
set ZLIBSHORT=131
set ZSTD=1.5.6
@ -66,20 +66,20 @@ set DXCOMPILER=1.8.2407.12
set DXAGILITY=1.614.1
call :downloadfile "freetype-%FREETYPE%.tar.gz" "https://download.savannah.gnu.org/releases/freetype/freetype-%FREETYPE%.tar.gz" 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" f93ff7ec6f2fcb9242256976a7e6d1da2588b5e57a559fb71a025b74bd1f5539 || goto error
call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" 7d7571a1faa1898b69888716dfdea0e4d466f1a5cf518e6aa626df2242bbadbe || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" ec855bcd815b4b63d0c958c42c2923311c656227d6e0c1ae1e721406d346444b || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" c3b41915341d853b6374cf93f1fcced2c8e4be9360f29c656960e1d0d15046a3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 809081a7bdf7e48262fbe9437e4e756df6ad2649433e803c4040026e650d7c91 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 89f1ef4595f68c3d34c63a7c1c4ce475e701e103f0473f3fd0718a2e5234de6e || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 3f813f49d6d28c532dc4b104084f60ff382337f184698fcd6e70ab9efad977c1 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 91c33d9946279c9c613b02e52a33df610cc01d13ea6e321b4c4d8ee708b9a03e || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" a0b3e7ac5f708042683ff0f22e069bdf75563540c615f9854ecc9bc8913e2488 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" c65a89140f5d68137ffec67d631ec97002fb37077d9b4eb4ee45cbec39b1c38a || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 30a8e7773e1f274557e049a97f158b808f344247da03ae5240e4956c81d51cd5 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" c0e6fa52a62ba11efd30262290dc6970947aef32e0cc294ee50e9005ceac092a || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" 6b2a43837005e1c23fdfee532b78f806863e412d2089b9c42b49ab08cbcd7665 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 675f144b11f8ab2424b64bed8ccdca5d3f35b9326046fa7a883925dd180f0651 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
call :downloadfile "cpuinfo-%CPUINFO%.zip" "https://github.com/pytorch/cpuinfo/archive/%CPUINFO%.zip" 13146ae7983d767a678dd01b0d6af591e77cec82babd41264b9164ab808d7d41 || goto error
call :downloadfile "discord-rpc-%DISCORD_RPC%.zip" "https://github.com/stenzek/discord-rpc/archive/%DISCORD_RPC%.zip" 61e185e75d37b360c314125bcdf4697192d15e2d5209db3306ed6cd736d508b3 || goto error

View File

@ -0,0 +1,13 @@
--- a/CMakeLists.txt 2024-12-29 21:34:43.219279282 +1000
+++ b/CMakeLists.txt 2024-12-29 21:34:59.495612349 +1000
@@ -3047,10 +3047,6 @@
listtostr(EXTRA_CFLAGS _EXTRA_CFLAGS)
set(EXTRA_CFLAGS ${_EXTRA_CFLAGS})
-if(USE_GCC OR USE_CLANG)
- string(REGEX REPLACE "(^| )-I" "\\1 -isystem" EXTRA_CFLAGS "${EXTRA_CFLAGS}")
-endif()
-
# Compat helpers for the configuration files
if(EXISTS "${PROJECT_SOURCE_DIR}/VERSION.txt")

View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
echo "Syntax: $0 <commit range, start..end>"
exit 1
fi
IFS="
"
printf "## Commits\n"
for i in $(git log --oneline --reverse "$1"); do
printf -- "- %s\n" "$i"
done

View File

@ -0,0 +1,21 @@
#! /usr/bin/env bash
# autogenerated by linuxdeploy
# make sure errors in sourced scripts will cause this script to stop
set -e
this_dir="$(readlink -f "$(dirname "$0")")"
# generated by linuxdeploy-plugin-qt
# try to make Qt apps more "native looking" on Gtk-based desktops, if possible
# see https://github.com/AppImage/AppImageKit/issues/977#issue-462374883
case "${XDG_CURRENT_DESKTOP}" in
*GNOME*|*gnome*|*XFCE*)
export QT_QPA_PLATFORMTHEME=gtk3
;;
esac
exec "$this_dir"/AppRun.wrapped "$@"

View File

@ -0,0 +1,29 @@
#!/usr/bin/env bash
REQUIRED_GLIBC_VERSION="__REQ_GLIBC_VERSION__"
this_dir="$(readlink -f "$(dirname "$0")")"
APPBIN="${this_dir}/usr/bin/__APPNAME__"
RUNTIME_DIR="${this_dir}/libc-runtime"
LOADER_BIN="${this_dir}/usr/bin/ld-linux"
GLIBC_VERSION=$(ldd --version | head -1 | sed -e 's/.* \([0-9.]\)/\1/')
echo "Detected glibc version ${GLIBC_VERSION}."
if [[ -z "${GLIBC_VERSION}" || ! "${GLIBC_VERSION}" < "${REQUIRED_GLIBC_VERSION}" ]]; then
echo "Using system libc/libstdc++."
exec "${APPBIN}" "$@"
fi
echo "Using bundled libc/libstdc++ from ${RUNTIME_DIR}."
if [ -z "$LD_LIBRARY_PATH" ]; then
export LD_LIBRARY_PATH="${RUNTIME_DIR}"
else
export LD_LIBRARY_PATH="${RUNTIME_DIR}:${LD_LIBRARY_PATH}"
fi
exec "${LOADER_BIN}" "${APPBIN}" "$@"

View File

@ -0,0 +1,81 @@
#!/usr/bin/env bash
set -e
function retry_command {
# Package servers tend to be unreliable at times..
# Retry a bunch of times.
local RETRIES=10
for i in $(seq 1 "$RETRIES"); do
"$@" && break
if [ "$i" == "$RETRIES" ]; then
echo "Command \"$@\" failed after ${RETRIES} retries."
exit 1
fi
done
}
this_dir="$(readlink -f "$(dirname "$0")")"
if [ "$#" -ne 5 ]; then
echo "Syntax: $0 <path to AppDir> <.deb arch> <triple> <ubuntu mirror> <binary to run>"
echo "e.g. $0 DuckStation.AppDir amd64 x86_64-linux-gnu https://archive.ubuntu.com/ubuntu/ duckstation-qt"
exit 1
fi
APPDIR=$1
DEBARCH=$2
TRIPLE=$3
MIRROR=$4
APPNAME=$5
LIBC_PACKAGE_URL="${MIRROR}/pool/main/g/glibc/libc6_2.35-0ubuntu3.8_${DEBARCH}.deb"
LIBGCCS_PACKAGE_URL="${MIRROR}/pool/main/g/gcc-12/libgcc-s1_12.3.0-1ubuntu1~22.04_${DEBARCH}.deb"
LIBSTDCXX_PACKAGE_URL="${MIRROR}/pool/main/g/gcc-12/libstdc++6_12.3.0-1ubuntu1~22.04_${DEBARCH}.deb"
GLIBC_VERSION=2.35
mkdir "temp"
cd "temp"
retry_command wget -O "libc.deb" "${LIBC_PACKAGE_URL}"
retry_command wget -O "libgccs.deb" "${LIBGCCS_PACKAGE_URL}"
retry_command wget -O "libstdc++.deb" "${LIBSTDCXX_PACKAGE_URL}"
dpkg -x "libc.deb" .
dpkg -x "libgccs.deb" .
dpkg -x "libstdc++.deb" .
# Copy everything into AppDir
RUNTIME="${APPDIR}/libc-runtime"
mkdir -p "${RUNTIME}"
# libc.so.6 and friends
cd "lib/${TRIPLE}"
cp -v * "${RUNTIME}"
cd ../../
# libstdc++
cd "usr/lib/${TRIPLE}"
cp -v * "${RUNTIME}" || true
cd ../../..
# done with temps now
cd ..
rm -fr temp
# Not risking mixing resolvers...
cd "${RUNTIME}"
rm -vf libnss_*
# Move ld-linux.so.2 into the binary directory so we can preserve arg0's directory
mv -v "ld-linux-"*.so.* "${APPDIR}/usr/bin/ld-linux"
# Set up the replacement apprun script
cd "${APPDIR}"
rm -f AppRun.wrapped
cp "${this_dir}/inject-libc-apprun.sh" AppRun.wrapped
sed -i -e "s/__APPNAME__/${APPNAME}/" AppRun.wrapped
sed -i -e "s/__REQ_GLIBC_VERSION__/${GLIBC_VERSION}/" AppRun.wrapped
echo Done.

View File

@ -127,8 +127,8 @@ DEPLOY_PLATFORM_THEMES="1" \
QMAKE="$DEPSDIR/bin/qmake" \
NO_STRIP="1" \
$LINUXDEPLOY --plugin qt --appdir="$OUTDIR" --executable="$BUILDDIR/bin/duckstation-qt" ${EXTRA_LIBS_ARGS[@]} \
--desktop-file="$ROOTDIR/scripts/org.duckstation.DuckStation.desktop" \
--icon-file="$ROOTDIR/scripts/org.duckstation.DuckStation.png" \
--desktop-file="$ROOTDIR/scripts/packaging/org.duckstation.DuckStation.desktop" \
--icon-file="$ROOTDIR/scripts/packaging/org.duckstation.DuckStation.png" \
echo "Copying resources into AppDir..."
cp -a "$BUILDDIR/bin/resources" "$OUTDIR/usr/bin"

View File

@ -0,0 +1,334 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
function retry_command {
# Package servers tend to be unreliable at times..
# Retry a bunch of times.
local RETRIES=10
for i in $(seq 1 "$RETRIES"); do
"$@" && break
if [ "$i" == "$RETRIES" ]; then
echo "Command \"$@\" failed after ${RETRIES} retries."
exit 1
fi
done
}
if [ "$1" == "-inject-libc" ]; then
echo "Injecting libc/libstdc++"
INJECT_LIBC=true
shift
fi
if [ "$#" -ne 5 ]; then
echo "Syntax: $0 [-inject-libc] <target arch> <path to build directory> <deps prefix> <chroot dir> <output name>"
exit 1
fi
ARCH=$1
BUILDDIR=$2
DEPSDIR=$3
CHROOTDIR=$4
NAME=$5
BINARY=duckstation-qt
APPDIRNAME=DuckStation.AppDir
STRIP=llvm-strip
TRIPLE="${ARCH}-linux-gnu"
declare -a SYSLIBS=(
"libatk-1.0.so.0"
"libatk-bridge-2.0.so.0"
"libatspi.so.0"
"libblkid.so.1"
"libbrotlicommon.so.1"
"libbrotlidec.so.1"
"libbsd.so.0"
"libcairo-gobject.so.2"
"libcairo.so.2"
"libcap.so.2"
"libcrypto.so.3"
"libcurl.so.4"
"libdatrie.so.1"
"libdbus-1.so.3"
"libdeflate.so.0"
"libepoxy.so.0"
"libffi.so.8"
"libgcrypt.so.20"
"libgdk-3.so.0"
"libgdk_pixbuf-2.0.so.0"
"libgio-2.0.so.0"
"libglib-2.0.so.0"
"libgmodule-2.0.so.0"
"libgnutls.so.30"
"libgobject-2.0.so.0"
"libgraphite2.so.3"
"libgssapi_krb5.so.2"
"libgtk-3.so.0"
"libhogweed.so.6"
"libidn2.so.0"
"libjbig.so.0"
"libk5crypto.so.3"
"libkeyutils.so.1"
"libkrb5.so.3"
"libkrb5support.so.0"
"liblber-2.5.so.0"
"libldap-2.5.so.0"
"liblz4.so.1"
"liblzma.so.5"
"libmd.so.0"
"libmount.so.1"
"libnettle.so.8"
"libnghttp2.so.14"
"libp11-kit.so.0"
"libpango-1.0.so.0"
"libpangocairo-1.0.so.0"
"libpangoft2-1.0.so.0"
"libpcre2-16.so.0"
"libpcre2-8.so.0"
"libpcre.so.3"
"libpixman-1.so.0"
"libpsl.so.5"
"librtmp.so.1"
"libsasl2.so.2"
"libselinux.so.1"
"libssh.so.4"
"libssl.so.3"
"libsystemd.so.0"
"libtasn1.so.6"
"libtiff.so.5"
"libudev.so.1"
"libunistring.so.2"
"libXau.so.6"
"libxcb-cursor.so.0"
"libxcb-glx.so.0"
"libxcb-icccm.so.4"
"libxcb-image.so.0"
"libxcb-keysyms.so.1"
"libxcb-randr.so.0"
"libxcb-render.so.0"
"libxcb-render-util.so.0"
"libxcb-shape.so.0"
"libxcb-shm.so.0"
"libxcb-sync.so.1"
"libxcb-util.so.1"
"libxcb-xfixes.so.0"
"libxcb-xkb.so.1"
"libXcomposite.so.1"
"libXcursor.so.1"
"libXdamage.so.1"
"libXdmcp.so.6"
"libXext.so.6"
"libXfixes.so.3"
"libXinerama.so.1"
"libXi.so.6"
"libxkbcommon.so.0"
"libxkbcommon-x11.so.0"
"libXrandr.so.2"
"libXrender.so.1"
)
declare -a DEPLIBS=(
"libbacktrace.so.0"
"libfreetype.so.6"
"libharfbuzz.so"
"libjpeg.so.62"
"libpng16.so.16"
"libSDL2-2.0.so.0"
"libsharpyuv.so.0"
"libwebpdemux.so.2"
"libwebpmux.so.3"
"libwebp.so.7"
"libzip.so.5"
"libzstd.so.1"
"libcpuinfo.so"
"libdiscord-rpc.so"
"liblunasvg.so"
"libshaderc_ds.so"
"libsoundtouch.so.2"
"libspirv-cross-c-shared.so.0"
#"libavcodec.so.61"
#"libavformat.so.61"
#"libavutil.so.59"
#"libswscale.so.8"
#"libswresample.so.5"
#"libva-drm.so.2"
#"libva.so.2"
)
declare -a QTLIBS=(
"libQt6Core.so.6"
"libQt6DBus.so.6"
"libQt6Gui.so.6"
"libQt6OpenGL.so.6"
"libQt6Svg.so.6"
"libQt6WaylandClient.so.6"
"libQt6WaylandEglClientHwIntegration.so.6"
"libQt6Widgets.so.6"
"libQt6XcbQpa.so.6"
)
declare -a QTPLUGINS=(
"plugins/iconengines"
"plugins/imageformats"
"plugins/platforminputcontexts"
"plugins/platforms"
"plugins/platformthemes"
"plugins/wayland-decoration-client"
"plugins/wayland-graphics-integration-client"
"plugins/wayland-shell-integration"
"plugins/xcbglintegrations"
)
set -e
IFS="
"
APPIMAGETOOL=./appimagetool-x86_64
APPIMAGERUNTIME=./runtime-${ARCH}
PATCHELF=patchelf
if [ ! -f "$APPIMAGETOOL" ]; then
retry_command wget -O "$APPIMAGETOOL" https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x "$APPIMAGETOOL"
fi
if [ ! -f "$APPIMAGERUNTIME" ]; then
retry_command wget -O "$APPIMAGERUNTIME" https://github.com/stenzek/type2-runtime/releases/download/continuous/runtime-${ARCH}
fi
OUTDIR=$(realpath "./$APPDIRNAME")
rm -fr "$OUTDIR"
mkdir "$OUTDIR"
mkdir -p "$OUTDIR/usr/bin" "$OUTDIR/usr/lib"
echo "Copying binary and resources..."
cp -a "$BUILDDIR/bin/$BINARY" "$BUILDDIR/bin/resources" "$BUILDDIR/bin/translations" "$OUTDIR/usr/bin"
# Currently we leave the main binary unstripped, uncomment if this is not desired.
# NOTE: Strip must come before patchelf, otherwise shit breaks.
$STRIP "$OUTDIR/usr/bin/$BINARY"
# Patch RPATH so the binary goes hunting for shared libraries in the AppDir instead of system.
echo "Patching RPATH in ${BINARY}..."
patchelf --set-rpath '$ORIGIN/../lib' "$OUTDIR/usr/bin/$BINARY"
# Libraries we pull in from the system.
echo "Copying system libraries..."
for lib in "${SYSLIBS[@]}"; do
blib=$(basename "$lib")
echo "$CHROOTDIR/lib/$TRIPLE/$lib"
if [ -f "$CHROOTDIR/lib/$TRIPLE/$lib" ]; then
cp "$CHROOTDIR/lib/$TRIPLE/$lib" "$OUTDIR/usr/lib/$blib"
elif [ -f "$CHROOTDIR/usr/lib/$TRIPLE/$lib" ]; then
cp "$CHROOTDIR/usr/lib/$TRIPLE/$lib" "$OUTDIR/usr/lib/$blib"
elif [ -f "$CHROOTDIR/lib/$lib" ]; then
cp "$CHROOTDIR/lib/$lib" "$OUTDIR/usr/lib/$blib"
elif [ -f "$CHROOTDIR/usr/lib/$lib" ]; then
cp "$CHROOTDIR/usr/lib/$lib" "$OUTDIR/usr/lib/$blib"
else
echo "*** Failed to find '$blib'"
exit 1
fi
$STRIP $OUTDIR/usr/lib/$blib
done
echo "Copying local libraries..."
for lib in "${DEPLIBS[@]}"; do
blib=$(basename "$lib")
echo "$DEPSDIR/lib/$lib"
if [ -f "$DEPSDIR/lib/$lib" ]; then
cp "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib/$blib"
else
echo "*** Failed to find '$blib'"
exit 1
fi
$STRIP "$OUTDIR/usr/lib/$blib"
done
echo "Copying Qt libraries..."
for lib in "${QTLIBS[@]}"; do
cp -avL "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib"
$STRIP "$OUTDIR/usr/lib/$lib"
done
echo "Copying Qt plugins..."
mkdir -p $OUTDIR/usr/lib/plugins
for plugin in "${QTPLUGINS[@]}"; do
mkdir -p "$OUTDIR/usr/lib/$plugin"
cp -avL "$DEPSDIR/$plugin/"*.so "$OUTDIR/usr/lib/$plugin/"
done
for so in $(find $OUTDIR/usr/lib/plugins -iname '*.so'); do
# This is ../../ because it's usually plugins/group/name.so
echo "Patching RPATH in ${so}..."
patchelf --set-rpath '$ORIGIN/../..' "$so"
$STRIP "$so"
done
for so in $(find $OUTDIR/usr/lib -maxdepth 1); do
if [ -f "$so" ]; then
echo "Patching RPATH in ${so}"
patchelf --set-rpath '$ORIGIN' "$so"
fi
done
echo "Creating qt.conf..."
cat > "$OUTDIR/usr/bin/qt.conf" << EOF
[Paths]
Plugins = ../lib/plugins
EOF
# Copy desktop/icon
echo "Copying desktop/icon..."
mkdir -p "$OUTDIR/usr/share/applications"
mkdir -p "$OUTDIR/usr/share/icons/hicolor/512x512/apps"
cp -v "$SCRIPTDIR/../org.duckstation.DuckStation.desktop" "$OUTDIR/usr/share/applications"
cp -v "$SCRIPTDIR/../org.duckstation.DuckStation.png" "$OUTDIR/usr/share/icons/hicolor/512x512/apps"
ln -s "usr/share/applications/org.duckstation.DuckStation.desktop" "$OUTDIR"
ln -s "usr/share/icons/hicolor/512x512/apps/org.duckstation.DuckStation.png" "$OUTDIR"
# Generate AppStream meta-info.
echo "Generating AppStream metainfo..."
mkdir -p "$OUTDIR/usr/share/metainfo"
"$SCRIPTDIR/../generate-metainfo.sh" "$OUTDIR/usr/share/metainfo"
# Copy AppRun
cp "$SCRIPTDIR/apprun-cross.sh" "$OUTDIR/AppRun"
chmod +x "$OUTDIR/AppRun"
ln -s "usr/bin/$BINARY" "$OUTDIR/AppRun.wrapped"
# Copy in AppRun hooks.
echo "Copying AppRun hooks..."
mkdir -p "$OUTDIR/apprun-hooks"
for hookpath in "$SCRIPTDIR/apprun-hooks"/*; do
hookname=$(basename "$hookpath")
cp -v "$hookpath" "$OUTDIR/apprun-hooks/$hookname"
sed -i -e 's/exec /source "$this_dir"\/apprun-hooks\/"'"$hookname"'"\nexec /' "$OUTDIR/AppRun"
done
# Optionally inject libc
if [ "$INJECT_LIBC" == true ]; then
echo "Injecting libc/libc++..."
if [ "$ARCH" == "aarch64" ]; then
DEBARCH="arm64"
else
echo "Unknown arch for libc injection."
exit 1
fi
"$SCRIPTDIR/inject-libc.sh" "$OUTDIR" "$DEBARCH" "$TRIPLE" "https://ports.ubuntu.com" "$BINARY"
fi
echo "Generating AppImage..."
rm -f "$NAME.AppImage"
"$APPIMAGETOOL" -v --runtime-file "$APPIMAGERUNTIME" "$OUTDIR" "$NAME.AppImage"

View File

@ -120,8 +120,8 @@ package() {
install -Dm755 scripts/packaging/duckstation-qt "${pkgdir}/usr/bin/duckstation-qt"
# install desktop file and icon
install -Dm644 scripts/${_desktopname}.desktop "${pkgdir}/usr/share/applications/${_desktopname}.desktop"
install -Dm644 scripts/${_desktopname}.png "${pkgdir}/usr/share/icons/hicolor/512x512/apps/${_desktopname}.png"
install -Dm644 scripts/packaging/${_desktopname}.desktop "${pkgdir}/usr/share/applications/${_desktopname}.desktop"
install -Dm644 scripts/packaging/${_desktopname}.png "${pkgdir}/usr/share/icons/hicolor/512x512/apps/${_desktopname}.png"
# install license
install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"

View File

@ -71,8 +71,8 @@ ninja -C build %{?_smp_mflags}
rm -fr %{buildroot}
ninja -C build install
install -Dm755 scripts/packaging/duckstation-qt %{buildroot}/usr/bin/duckstation-qt
install -Dm644 scripts/org.duckstation.DuckStation.png %{buildroot}/usr/share/icons/hicolor/512x512/apps/org.duckstation.DuckStation.png
install -Dm644 scripts/org.duckstation.DuckStation.desktop %{buildroot}/usr/share/applications/org.duckstation.DuckStation.desktop
install -Dm644 scripts/packaging/org.duckstation.DuckStation.png %{buildroot}/usr/share/icons/hicolor/512x512/apps/org.duckstation.DuckStation.png
install -Dm644 scripts/packaging/org.duckstation.DuckStation.desktop %{buildroot}/usr/share/applications/org.duckstation.DuckStation.desktop
%files
%license LICENSE

View File

@ -26,7 +26,7 @@ build-options:
sources:
- type: git
url: "https://github.com/nih-at/libzip.git"
commit: "9c8b818a1de143a4a8ee445351fb8f92115e33e1"
commit: "64b62d6b1a686a1b0bac1b6b9dcb635be0499afb"
cleanup:
- /bin
- /include

View File

@ -14,8 +14,8 @@ build-options:
strip: true
sources:
- type: archive
url: "https://github.com/libsdl-org/SDL/releases/download/release-2.30.9/SDL2-2.30.9.tar.gz"
sha256: "24b574f71c87a763f50704bbb630cbe38298d544a1f890f099a4696b1d6beba4"
url: "https://github.com/libsdl-org/SDL/releases/download/release-2.30.11/SDL2-2.30.11.tar.gz"
sha256: "8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f"
cleanup:
- /bin
- /include

View File

@ -80,21 +80,21 @@ modules:
- "-DCMAKE_SHARED_LINKER_FLAGS_INIT=-fuse-ld=lld"
sources:
- type: dir
path: ../..
path: ../../..
post-install:
# Manually copy desktop file/metadata, it's not done as part of the regular build.
- >-
install -Dm644
"${FLATPAK_BUILDER_BUILDDIR}/scripts/org.duckstation.DuckStation.png"
"${FLATPAK_BUILDER_BUILDDIR}/scripts/packaging/org.duckstation.DuckStation.png"
"${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/org.duckstation.DuckStation.png"
- >-
install -Dm644
"${FLATPAK_BUILDER_BUILDDIR}/scripts/org.duckstation.DuckStation.desktop"
"${FLATPAK_BUILDER_BUILDDIR}/scripts/packaging/org.duckstation.DuckStation.desktop"
"${FLATPAK_DEST}/share/applications/org.duckstation.DuckStation.desktop"
- >-
install -Dm644
"${FLATPAK_BUILDER_BUILDDIR}/scripts/flatpak/org.duckstation.DuckStation.metainfo.xml"
"${FLATPAK_BUILDER_BUILDDIR}/scripts/packaging/flatpak/org.duckstation.DuckStation.metainfo.xml"
"${FLATPAK_DEST}/share/metainfo/org.duckstation.DuckStation.metainfo.xml"
# Ensure ffmpeg-full mount point exists.

View File

@ -31,6 +31,6 @@
<release version="@GIT_VERSION@" date="@GIT_DATE@" />
</releases>
<custom>
<value key="flathub::manifest">https://raw.githubusercontent.com/stenzek/duckstation/@GIT_HASH@/scripts/flatpak/org.duckstation.DuckStation.yaml</value>
<value key="flathub::manifest">https://raw.githubusercontent.com/stenzek/duckstation/@GIT_HASH@/scripts/packaging/flatpak/org.duckstation.DuckStation.yaml</value>
</custom>
</component>

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

@ -6,13 +6,12 @@ import subprocess
import multiprocessing
from functools import partial
def is_game_path(path):
idx = path.rfind('.')
if idx < 0:
return False
extension = path[idx + 1:].strip().lower()
return extension in ["cue", "chd"]
def is_game_path(path:str):
lpath = path.lower()
for extension in ["cue", "chd", "psxgpu", "psxgpu.zst", "psxgpu.xz"]:
if path.endswith(extension):
return True
return False
def run_regression_test(runner, destdir, dump_interval, frames, renderer, cargs, gamepath):
@ -31,8 +30,10 @@ def run_regression_test(runner, destdir, dump_interval, frames, renderer, cargs,
return os.path.basename(gamepath)
def run_regression_tests(runner, gamedir, destdir, dump_interval, frames, parallel, renderer, cargs):
paths = glob.glob(gamedir + "/*.*", recursive=True)
def run_regression_tests(runner, gamedirs, destdir, dump_interval, frames, parallel, renderer, cargs):
paths = []
for gamedir in gamedirs:
paths += glob.glob(os.path.realpath(gamedir) + "/*.*", recursive=True)
gamepaths = list(filter(is_game_path, paths))
try:
@ -64,7 +65,7 @@ def run_regression_tests(runner, gamedir, destdir, dump_interval, frames, parall
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate frame dump images for regression tests")
parser.add_argument("-runner", action="store", required=True, help="Path to DuckStation regression test runner")
parser.add_argument("-gamedir", action="store", required=True, help="Directory containing game images")
parser.add_argument("-gamedir", action="append", required=True, help="Directory containing game images")
parser.add_argument("-destdir", action="store", required=True, help="Base directory to dump frames to")
parser.add_argument("-dumpinterval", action="store", type=int, default=600, help="Interval to dump frames at")
parser.add_argument("-frames", action="store", type=int, default=36000, help="Number of frames to run")
@ -86,7 +87,7 @@ if __name__ == "__main__":
if (args.cpu is not None):
cargs += ["-cpu", args.cpu]
if not run_regression_tests(args.runner, os.path.realpath(args.gamedir), os.path.realpath(args.destdir), args.dumpinterval, args.frames, args.parallel, args.renderer, cargs):
if not run_regression_tests(args.runner, args.gamedir, os.path.realpath(args.destdir), args.dumpinterval, args.frames, args.parallel, args.renderer, cargs):
sys.exit(1)
else:
sys.exit(0)

View File

@ -4,6 +4,7 @@ add_executable(common-tests
gsvector_yuvtorgb_test.cpp
path_tests.cpp
rectangle_tests.cpp
sha256_tests.cpp
string_tests.cpp
)

View File

@ -7,6 +7,7 @@
<ClCompile Include="file_system_tests.cpp" />
<ClCompile Include="path_tests.cpp" />
<ClCompile Include="rectangle_tests.cpp" />
<ClCompile Include="sha256_tests.cpp" />
<ClCompile Include="string_tests.cpp" />
<ClCompile Include="gsvector_yuvtorgb_test.cpp" />
</ItemGroup>

View File

@ -8,5 +8,6 @@
<ClCompile Include="path_tests.cpp" />
<ClCompile Include="string_tests.cpp" />
<ClCompile Include="gsvector_yuvtorgb_test.cpp" />
<ClCompile Include="sha256_tests.cpp" />
</ItemGroup>
</Project>

View File

@ -78,3 +78,59 @@ TEST(Rectangle, RelationalOperators)
ASSERT_FALSE(r1.eq(r2));
}
TEST(Rectangle, ValidRectangles)
{
static constexpr GSVector4i cases[] = {
GSVector4i::cxpr(1, 2, 3, 4),
GSVector4i::cxpr(-5, -10, -1, -2),
GSVector4i::cxpr(0, 0, 1, 1),
GSVector4i::cxpr(100, 200, 300, 400),
GSVector4i::cxpr(-1000, -2000, 500, 600),
GSVector4i::cxpr(5, 10, 6, 12),
GSVector4i::cxpr(-10, -20, -5, -15),
GSVector4i::cxpr(-5, 0, 5, 10),
GSVector4i::cxpr(-100, -200, 100, 200),
GSVector4i::cxpr(-1, -2, 0, 1),
};
for (GSVector4i tcase : cases)
{
ASSERT_TRUE(tcase.rvalid());
ASSERT_FALSE(tcase.rempty());
}
}
TEST(Rectangle, InvalidRectangles)
{
static constexpr GSVector4i cases[] = {
// left < right but not top < bottom
GSVector4i::cxpr(1, 4, 3, 2),
GSVector4i::cxpr(-5, -2, -1, -10),
GSVector4i::cxpr(0, 1, 1, 0),
GSVector4i::cxpr(100, 400, 300, 200),
GSVector4i::cxpr(-1000, 600, 500, -2000),
GSVector4i::cxpr(5, 12, 6, 10),
GSVector4i::cxpr(-10, -15, -5, -20),
GSVector4i::cxpr(-5, 10, 5, 0),
GSVector4i::cxpr(-100, 200, 100, -200),
GSVector4i::cxpr(-1, 1, 0, -2),
// not left < right but top < bottom
GSVector4i::cxpr(3, 2, 1, 4),
GSVector4i::cxpr(-1, -10, -5, -2),
GSVector4i::cxpr(1, 0, 0, 1),
GSVector4i::cxpr(300, 200, 100, 400),
GSVector4i::cxpr(500, -2000, -1000, 600),
GSVector4i::cxpr(6, 10, 5, 12),
GSVector4i::cxpr(-5, -20, -10, -15),
GSVector4i::cxpr(5, 0, -5, 10),
GSVector4i::cxpr(100, -200, -100, 200),
GSVector4i::cxpr(0, -2, -1, 1),
};
for (GSVector4i tcase : cases)
{
ASSERT_FALSE(tcase.rvalid());
ASSERT_TRUE(tcase.rempty());
}
}

View File

@ -0,0 +1,34 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "common/sha256_digest.h"
#include <gtest/gtest.h>
TEST(SHA256Digest, Simple)
{
// https://github.com/B-Con/crypto-algorithms/blob/master/sha256_test.c
static constexpr const char text1[] = "abc";
static constexpr const char text2[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
static constexpr const char text3[] = "aaaaaaaaaa";
static constexpr SHA256Digest::Digest hash1 = {{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40,
0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17,
0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}};
static constexpr SHA256Digest::Digest hash2 = {{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26,
0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff,
0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}};
static constexpr SHA256Digest::Digest hash3 = {{0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7,
0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97,
0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}};
ASSERT_EQ(SHA256Digest::GetDigest(text1, std::size(text1) - 1), hash1);
ASSERT_EQ(SHA256Digest::GetDigest(text2, std::size(text2) - 1), hash2);
SHA256Digest ldigest;
for (u32 i = 0; i < 100000; i++)
ldigest.Update(text3, std::size(text3) - 1);
ASSERT_EQ(ldigest.Final(), hash3);
}

View File

@ -33,3 +33,41 @@ TEST(StringUtil, EllipsiseInPlace)
StringUtil::EllipsiseInPlace(s, 10, "...");
ASSERT_EQ(s, "Hello");
}
TEST(StringUtil, Base64EncodeDecode)
{
struct TestCase
{
const char* hexString;
const char* base64String;
};
static const TestCase testCases[] = {
{"33326a6f646933326a68663937683732383368", "MzJqb2RpMzJqaGY5N2g3MjgzaA=="},
{"32753965333268756979386672677537366967723839683432703075693132393065755c5d0931325c335c31323439303438753839333272",
"MnU5ZTMyaHVpeThmcmd1NzZpZ3I4OWg0MnAwdWkxMjkwZXVcXQkxMlwzXDEyNDkwNDh1ODkzMnI="},
{"3332726a33323738676838666233326830393233386637683938323139", "MzJyajMyNzhnaDhmYjMyaDA5MjM4ZjdoOTgyMTk="},
{"9956967BE9C96E10B27FF8897A5B768A2F4B103CE934718D020FE6B5B770", "mVaWe+nJbhCyf/iJelt2ii9LEDzpNHGNAg/mtbdw"},
{"BC94251814827A5D503D62D5EE6CBAB0FD55D2E2FCEDBB2261D6010084B95DD648766D8983F03AFA3908956D8201E26BB09FE52B515A61A9E"
"1D3ADC207BD9E622128F22929CDED456B595A410F7168B0BA6370289E6291E38E47C18278561C79A7297C21D23C06BB2F694DC2F65FAAF994"
"59E3FC14B1FA415A3320AF00ACE54C00BE",
"vJQlGBSCel1QPWLV7my6sP1V0uL87bsiYdYBAIS5XdZIdm2Jg/A6+jkIlW2CAeJrsJ/"
"lK1FaYanh063CB72eYiEo8ikpze1Fa1laQQ9xaLC6Y3AonmKR445HwYJ4Vhx5pyl8IdI8BrsvaU3C9l+q+ZRZ4/wUsfpBWjMgrwCs5UwAvg=="},
{"192B42CB0F66F69BE8A5", "GStCyw9m9pvopQ=="},
{"38ABD400F3BB6960EB60C056719B5362", "OKvUAPO7aWDrYMBWcZtTYg=="},
{"776FAB27DC7F8DA86F298D55B69F8C278D53871F8CBCCF", "d2+rJ9x/jahvKY1Vtp+MJ41Thx+MvM8="},
{"B1ED3EA2E35EE69C7E16707B05042A", "se0+ouNe5px+FnB7BQQq"},
};
for (const TestCase& tc : testCases)
{
std::optional<std::vector<u8>> bytes = StringUtil::DecodeHex(tc.hexString);
ASSERT_TRUE(bytes.has_value());
std::string encoded_b64 = StringUtil::EncodeBase64(bytes.value());
ASSERT_EQ(encoded_b64, tc.base64String);
std::optional<std::vector<u8>> dbytes = StringUtil::DecodeBase64(tc.base64String);
ASSERT_TRUE(dbytes.has_value());
ASSERT_EQ(dbytes.value(), bytes.value());
}
}

View File

@ -50,12 +50,18 @@ add_library(common
settings_interface.h
sha1_digest.cpp
sha1_digest.h
sha256_digest.cpp
sha256_digest.h
small_string.cpp
small_string.h
string_util.cpp
string_util.h
thirdparty/SmallVector.cpp
thirdparty/SmallVector.h
thirdparty/aes.cpp
thirdparty/aes.h
task_queue.cpp
task_queue.h
threading.cpp
threading.h
timer.cpp

View File

@ -3,15 +3,17 @@
#include "assert.h"
#include "crash_handler.h"
#include <cstdio>
#include <cstdlib>
#include <mutex>
#if defined(_WIN32)
#ifdef _WIN32
#include "windows_headers.h"
#include <intrin.h>
#include <tlhelp32.h>
#endif
#include <mutex>
#ifdef __clang__
#pragma clang diagnostic ignored "-Winvalid-noreturn"
@ -19,9 +21,8 @@
static std::mutex s_AssertFailedMutex;
static inline void FreezeThreads(void** ppHandle)
static HANDLE FreezeThreads()
{
#if defined(_WIN32)
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
@ -43,17 +44,12 @@ static inline void FreezeThreads(void** ppHandle)
}
}
*ppHandle = (void*)hSnapshot;
#else
*ppHandle = nullptr;
#endif
return hSnapshot;
}
static inline void ResumeThreads(void* pHandle)
static void ResumeThreads(HANDLE hSnapshot)
{
#if defined(_WIN32)
HANDLE hSnapshot = (HANDLE)pHandle;
if (pHandle != INVALID_HANDLE_VALUE)
if (hSnapshot != INVALID_HANDLE_VALUE)
{
THREADENTRY32 threadEntry;
if (Thread32First(hSnapshot, &threadEntry))
@ -73,21 +69,42 @@ static inline void ResumeThreads(void* pHandle)
}
CloseHandle(hSnapshot);
}
}
#else
#ifdef __ANDROID__
// Define as a weak symbol for ancient devices that don't have it.
extern "C" __attribute__((weak)) void android_set_abort_message(const char*);
#endif
[[noreturn]] ALWAYS_INLINE static void AbortWithMessage(const char* szMsg)
{
#ifndef __ANDROID__
std::fputs(szMsg, stderr);
CrashHandler::WriteDumpForCaller();
std::fputs("Aborting application.\n", stderr);
std::fflush(stderr);
std::abort();
#else
if (&android_set_abort_message)
android_set_abort_message(szMsg);
std::abort();
#endif
}
#endif // _WIN32
void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine)
{
std::lock_guard<std::mutex> guard(s_AssertFailedMutex);
void* pHandle;
FreezeThreads(&pHandle);
char szMsg[512];
std::snprintf(szMsg, sizeof(szMsg), "%s in function %s (%s:%u)\n", szMessage, szFunction, szFile, uLine);
#if defined(_WIN32)
std::unique_lock lock(s_AssertFailedMutex);
HANDLE pHandle = FreezeThreads();
SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), szMsg, static_cast<DWORD>(std::strlen(szMsg)), NULL, NULL);
OutputDebugStringA(szMsg);
@ -107,28 +124,22 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
CrashHandler::WriteDumpForCaller();
TerminateProcess(GetCurrentProcess(), 0xBAADC0DE);
}
#else
std::fputs(szMsg, stderr);
CrashHandler::WriteDumpForCaller();
std::fputs("Aborting application.\n", stderr);
std::fflush(stderr);
std::abort();
#endif
ResumeThreads(pHandle);
#else
AbortWithMessage(szMsg);
#endif
}
[[noreturn]] void Y_OnPanicReached(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine)
{
std::lock_guard<std::mutex> guard(s_AssertFailedMutex);
void* pHandle;
FreezeThreads(&pHandle);
char szMsg[512];
std::snprintf(szMsg, sizeof(szMsg), "%s in function %s (%s:%u)\n", szMessage, szFunction, szFile, uLine);
#if defined(_WIN32)
std::unique_lock guard(s_AssertFailedMutex);
HANDLE pHandle = FreezeThreads();
SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), szMsg, static_cast<DWORD>(std::strlen(szMsg)), NULL, NULL);
OutputDebugStringA(szMsg);
@ -145,13 +156,9 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
CrashHandler::WriteDumpForCaller();
TerminateProcess(GetCurrentProcess(), 0xBAADC0DE);
#else
std::fputs(szMsg, stderr);
CrashHandler::WriteDumpForCaller();
std::fputs("Aborting application.\n", stderr);
std::fflush(stderr);
std::abort();
#endif
ResumeThreads(pHandle);
#else
AbortWithMessage(szMsg);
#endif
}

View File

@ -9,27 +9,31 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
[[noreturn]] void Y_OnPanicReached(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine);
#define Assert(expr) \
if (!(expr)) \
do \
{ \
Y_OnAssertFailed("Assertion failed: '" #expr "'", __FUNCTION__, __FILE__, __LINE__); \
}
if (!(expr)) \
Y_OnAssertFailed("Assertion failed: '" #expr "'", __FUNCTION__, __FILE__, __LINE__); \
} while (0)
#define AssertMsg(expr, msg) \
if (!(expr)) \
do \
{ \
Y_OnAssertFailed("Assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \
}
if (!(expr)) \
Y_OnAssertFailed("Assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \
} while (0)
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
#define DebugAssert(expr) \
if (!(expr)) \
do \
{ \
Y_OnAssertFailed("Debug assertion failed: '" #expr "'", __FUNCTION__, __FILE__, __LINE__); \
}
if (!(expr)) \
Y_OnAssertFailed("Debug assertion failed: '" #expr "'", __FUNCTION__, __FILE__, __LINE__); \
} while (0)
#define DebugAssertMsg(expr, msg) \
if (!(expr)) \
do \
{ \
Y_OnAssertFailed("Debug assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \
}
if (!(expr)) \
Y_OnAssertFailed("Debug assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \
} while (0)
#else
#define DebugAssert(expr)
#define DebugAssertMsg(expr, msg)
@ -41,7 +45,7 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
// Kills the application, indicating a pure function call that should not have happened.
#define PureCall() Y_OnPanicReached("PureCall encountered", __FUNCTION__, __FILE__, __LINE__)
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
// Kills the application, indicating that code that was never supposed to be reached has been executed.
#define UnreachableCode() Y_OnPanicReached("Unreachable code reached", __FUNCTION__, __FILE__, __LINE__)
#else

View File

@ -36,13 +36,16 @@
<ClInclude Include="scoped_guard.h" />
<ClInclude Include="settings_interface.h" />
<ClInclude Include="sha1_digest.h" />
<ClInclude Include="sha256_digest.h" />
<ClInclude Include="small_string.h" />
<ClInclude Include="heterogeneous_containers.h" />
<ClInclude Include="binary_reader_writer.h" />
<ClInclude Include="string_util.h" />
<ClInclude Include="thirdparty\aes.h" />
<ClInclude Include="thirdparty\SmallVector.h" />
<ClInclude Include="thirdparty\StackWalker.h" />
<ClInclude Include="threading.h" />
<ClInclude Include="task_queue.h" />
<ClInclude Include="timer.h" />
<ClInclude Include="types.h" />
<ClInclude Include="minizip_helpers.h" />
@ -64,12 +67,15 @@
<ClCompile Include="perf_scope.cpp" />
<ClCompile Include="progress_callback.cpp" />
<ClCompile Include="sha1_digest.cpp" />
<ClCompile Include="sha256_digest.cpp" />
<ClCompile Include="small_string.cpp" />
<ClCompile Include="binary_reader_writer.cpp" />
<ClCompile Include="string_util.cpp" />
<ClCompile Include="thirdparty\aes.cpp" />
<ClCompile Include="thirdparty\SmallVector.cpp" />
<ClCompile Include="thirdparty\StackWalker.cpp" />
<ClCompile Include="threading.cpp" />
<ClCompile Include="task_queue.cpp" />
<ClCompile Include="timer.cpp" />
</ItemGroup>
<ItemGroup>

View File

@ -50,6 +50,9 @@
<ClInclude Include="gsvector_nosimd.h" />
<ClInclude Include="ryml_helpers.h" />
<ClInclude Include="log_channels.h" />
<ClInclude Include="sha256_digest.h" />
<ClInclude Include="thirdparty\aes.h" />
<ClInclude Include="task_queue.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="small_string.cpp" />
@ -78,6 +81,9 @@
<ClCompile Include="dynamic_library.cpp" />
<ClCompile Include="binary_reader_writer.cpp" />
<ClCompile Include="gsvector.cpp" />
<ClCompile Include="sha256_digest.cpp" />
<ClCompile Include="thirdparty\aes.cpp" />
<ClCompile Include="task_queue.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="bitfield.natvis" />

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