summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Gallet <clement.gallet@ens-lyon.org>2021-09-28 13:18:28 +0200
committerClément Gallet <clement.gallet@ens-lyon.org>2021-09-28 13:18:28 +0200
commitaf2e3ed7b0b4bd23b87d57d9d2873572ebc1c678 (patch)
treec6f315eda3f83a1217a2f914a35b00b22e4057f0
parent025dfb68f4d67e00fb695fbfb7c5f7c26528bca1 (diff)
parentfbe386dbf7a76ec4ecb438dd7379bfa8d23a4f74 (diff)
Merge branch 'master' into hollowknighthollowknight
-rw-r--r--CHANGELOG.md14
-rw-r--r--README.md4
-rw-r--r--debian/changelog55
-rw-r--r--debian/compat1
-rw-r--r--debian/control2
-rw-r--r--docs/guides/wsl.md2
-rw-r--r--libTAS.xcodeproj/project.pbxproj155
-rw-r--r--libTAS.xcodeproj/project.xcworkspace/xcuserdata/clement.xcuserdatad/UserInterfaceState.xcuserstatebin218021 -> 222716 bytes
-rw-r--r--libTAS.xcodeproj/xcshareddata/xcschemes/libTAS.xcscheme20
-rw-r--r--libTAS.xcodeproj/xcuserdata/clement.xcuserdatad/xcschemes/xcschememanagement.plist7
-rw-r--r--src/dyld_func_lookup_helper/dyld_func_lookup_helper.cpp7
-rw-r--r--src/dyld_func_lookup_helper/dyld_func_lookup_helper.h6
-rw-r--r--src/external/vulkan_core.h2
-rw-r--r--src/library/GameHacks.cpp26
-rw-r--r--src/library/GameHacks.h19
-rwxr-xr-xsrc/library/ScreenCapture.cpp4
-rw-r--r--src/library/audio/AudioSource.cpp12
-rw-r--r--src/library/audio/alsa/pcm.cpp9
-rw-r--r--src/library/audio/sdl/sdlaudio.cpp5
-rw-r--r--src/library/dlhook.cpp141
-rw-r--r--src/library/inputs/xkeyboardlayout.cpp38
-rw-r--r--src/library/main.cpp4
-rw-r--r--src/library/openglwrappers.h4
-rw-r--r--src/library/pthreadwrappers.cpp75
-rw-r--r--src/library/renderhud/RenderHUD_Base_MacOS.cpp1
-rw-r--r--src/library/renderhud/RenderHUD_GL.cpp28
-rw-r--r--src/library/renderhud/RenderHUD_GL.h4
-rw-r--r--src/library/renderhud/RenderHUD_SDL2_renderer.cpp3
-rw-r--r--src/library/sdl/sdldynapi.cpp5
-rw-r--r--src/library/sdl/sdlhooks.h1
-rw-r--r--src/library/steam/steamapi.cpp10
-rw-r--r--src/library/steam/steamapiinternal.cpp67
-rw-r--r--src/library/steam/steamapiinternal.h34
-rw-r--r--src/library/systemwrappers.cpp2
-rw-r--r--src/library/timewrappers.cpp46
-rw-r--r--src/program/Config.cpp8
-rw-r--r--src/program/Config.h11
-rw-r--r--src/program/Context.h5
-rw-r--r--src/program/GameThread.cpp121
-rw-r--r--src/program/KeyMappingQuartz.mm4
-rw-r--r--src/program/KeyMappingXcb.cpp14
-rw-r--r--src/program/main.cpp75
-rw-r--r--src/program/ui/ControllerTabWindow.cpp2
-rw-r--r--src/program/ui/ControllerTabWindow.h3
-rw-r--r--src/program/ui/ControllerWidget.cpp2
-rw-r--r--src/program/ui/ControllerWidget.h2
-rw-r--r--src/program/ui/EncodeWindow.cpp6
-rw-r--r--src/program/ui/ErrorChecking.cpp35
-rw-r--r--src/program/ui/InputEditorView.cpp1
-rw-r--r--src/program/ui/InputEditorView.h3
-rw-r--r--src/program/ui/InputEditorWindow.cpp1
-rw-r--r--src/program/ui/InputEditorWindow.h3
-rw-r--r--src/program/ui/InputWindow.cpp1
-rw-r--r--src/program/ui/InputWindow.h3
-rw-r--r--src/program/ui/MainWindow.cpp108
-rw-r--r--src/program/ui/MainWindow.h37
-rw-r--r--src/program/ui/PointerScanWindow.cpp3
-rw-r--r--src/program/ui/PointerScanWindow.h3
-rw-r--r--src/program/ui/RamSearchWindow.cpp3
-rw-r--r--src/program/ui/RamSearchWindow.h4
-rw-r--r--src/program/ui/RamWatchEditWindow.cpp2
-rw-r--r--src/program/ui/RamWatchEditWindow.h3
-rw-r--r--src/program/ui/RamWatchWindow.cpp3
-rw-r--r--src/program/ui/RamWatchWindow.h7
-rw-r--r--src/program/ui/TimeTraceWindow.cpp5
-rw-r--r--src/program/ui/TimeTraceWindow.h3
-rw-r--r--src/shared/SharedConfig.h3
-rw-r--r--src/shared/sockethelpers.cpp5
-rw-r--r--src/shared/version.h2
69 files changed, 990 insertions, 314 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3bf44aea..17acdf2d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,19 @@
## [Unreleased]
### Added
+* Implement SteamInternal_FindOrCreateUserInterface()
+
+### Changed
+### Fixed
+
+* Fix variable RNG seed in Papers Please (#422)
+* Fix some keys with modifiers that are mapped to keys from another layout
+* Fix ALSA underrun support (fix #426)
+* Fix SDL2 hooking when different library name
+
+## [1.4.2] - 2021-07-06
+### Added
+
* Add the execution permission if possible
* Show a specific message when user specify a script as game executable
* Add lua scripting
@@ -22,6 +35,7 @@
* Input editor: Prevent users from setting blank input labels
* Ram Watch: Add intermediate addresses for pointer chain
* Lua: add line and ellipse drawing
+* Advance time for .NET speed checks (#303)
### Changed
diff --git a/README.md b/README.md
index d5586cf4..aa8f2fe7 100644
--- a/README.md
+++ b/README.md
@@ -80,7 +80,9 @@ Be careful that you must compile your code in the same arch as the game. If you
If you have an amd64 system and you want to run both i386 or amd64 games, you can install libTAS 32-bit library together with the amd64 build. To do that, you can build using `./build.sh --with-i386`, which will produce an additional `libtas32.so` (32-bit) library together with amd64 builds of `libTAS` GUI and `libtas.so` library.
-You will need the 32-bit version of libraries `libX11`, `libX11-xcb`, `libasound`, `libavutil`, `libswresample`, `liblz4-1`, the 32-bit version of the headers for `libavutil`, `libswresample`, and also librairies `libfreetype` and `libfontconfig` for the HUD feature. You will also need your compiler to be able to cross-compile, by installing `g++-multilib` if using g++ compiler. When running a game, libTAS will choose automatically the right `libtas.so` library based on the game arch.
+You will need the 32-bit version of libraries `libX11`, `libX11-xcb`, `libasound`, `libavutil`, `libswresample`, the 32-bit version of the headers for `libavutil`, `libswresample`, and also librairies `libfreetype` and `libfontconfig` for the HUD feature. You will also need your compiler to be able to cross-compile, by installing `g++-multilib` if using g++ compiler. When running a game, libTAS will choose automatically the right `libtas.so` library based on the game arch.
+
+* Deb: `apt-get install libx11-6:i386 libx11-xcb1:i386 libasound2:i386 libavutil56:i386 libavutil-dev:i386 libswresample-dev:i386 libswresample3:i386 libfreetype6:i386 libfontconfig1:i386`
## Run
diff --git a/debian/changelog b/debian/changelog
index 1ac9abe3..12c24cbe 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,58 @@
+libtas (1.4.2) unstable; urgency=medium
+
+ * Add the execution permission if possible
+ * Show a specific message when user specify a script as game executable
+ * Add lua scripting
+ * Check for gdb presence
+ * Use vdpau-va-gl for vdpau software rendering (#390)
+ * Implement multiple SDL audio devices
+ * Clicking the first column seeks to frame in input editor
+ * Lua memory read and write float/double
+ * Basic MacOS support
+ * Input editor: option to disable autoscroll (#182)
+ * Input editor: option to seeks to current frame after rewind (#134)
+ * Input editor: show state invalidation as gray area when threads changed
+ * Add setting to not load movie metadata
+ * Input editor: pasting while selecting a range repeats the paste frames in range
+ * Allow games to use the native Steam API
+ * Implement SDL_GetWindowFromID() (#409)
+ * Implement more X*LookupString() functions
+ * Check for socket file removal errors
+ * Input editor: Prevent users from setting blank input labels
+ * Ram Watch: Add intermediate addresses for pointer chain
+ * Lua: add line and ellipse drawing
+ * Advance time for .NET speed checks (#303)
+ * Remove "save screen" option (always on)
+ * Change again the threshold for triggering a non-draw frame
+ * Don't scroll input editor when rewinding (#381)
+ * Raise the limit of thread number in states
+ * State loading doesn't write zeros on zero pages, preventing allocations
+ * Switch input mapping to tabs
+ * Optimize UI refresh with timer
+ * Switch OpenGL OSD using shaders. Adds transparency.
+ * Exit the game if the socket connection is lost
+ * Fix ram watch offset parsing
+ * Disable Start and attach gdb for wine games
+ * Fix SDL_Lock/UnlockAudio that can be called multiple times (#385)
+ * Remove keyboard_support setting (#386)
+ * Correctly handle opening of /dev/input/event|jsdev with writing flag
+ * Fix pitch for OpenAL
+ * Fix some labels in the input editor being truncated
+ * Set timezone to UTC+0
+ * Send low-level window closing event even if game uses SDL (#395)
+ * snd_pcm_writei() should block until all frames can be played
+ * Fix controller inputs when controller window has focus
+ * Add modifier to SDL key event (#405)
+ * Handle savestates from previous execution that were performed after game
+ exiting (because forked savestate) (#407)
+ * Fix and improve SDL2_renderer HUD (#410)
+ * Fix "OSD on encodes" being broken
+ * Fix the method to detect the game's `SDL_DYNAPI_entry` symbol
+ * Input editor: Allow modifiers when adding a new column
+ * Ram Watch: Fix the definition of base address of file
+
+ -- clement <clement.gallet@ens-lyon.org> Tue, 06 Jul 2021 11:47:22 +0200
+
libtas (1.4.1) unstable; urgency=medium
* Savestates can be compressed
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index ec635144..00000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/debian/control b/debian/control
index 8722d15e..f4c37a2a 100644
--- a/debian/control
+++ b/debian/control
@@ -2,7 +2,7 @@ Source: libtas
Section: unknown
Priority: optional
Maintainer: Clement Gallet <clement.gallet@ens-lyon.org>
-Build-Depends: debhelper (>= 9), libx11-dev, qtbase5-dev (>= 5.6.0), libsdl2-dev, libxcb1-dev, libxcb-keysyms1-dev, libxcb-xkb-dev, libasound2-dev, libavutil-dev, liblua5.3-dev, libswresample-dev, libfreetype6-dev, libfontconfig1-dev
+Build-Depends: debhelper-compat (= 10), libx11-dev, qtbase5-dev (>= 5.6.0), libsdl2-dev, libxcb1-dev, libxcb-keysyms1-dev, libxcb-xkb-dev, libasound2-dev, libavutil-dev, liblua5.3-dev, libswresample-dev, libfreetype6-dev, libfontconfig1-dev
Standards-Version: 3.9.8
Homepage: https://github.com/clementgallet/libTAS
diff --git a/docs/guides/wsl.md b/docs/guides/wsl.md
index 0fd7ab86..6ed20d7f 100644
--- a/docs/guides/wsl.md
+++ b/docs/guides/wsl.md
@@ -40,7 +40,7 @@ Things you will need to download:
* [Ubuntu](https://www.microsoft.com/store/apps/9n6svws3rx71)
* [vcxsrv](https://sourceforge.net/projects/vcxsrv/)
-* [libTAS](../)
+* [libTAS](https://github.com/clementgallet/libTAS/releases)
And of course, you will need a game that runs on Linux. Otherwise you need to
use wine, which, aside from adding yet another layer in our approach, will
diff --git a/libTAS.xcodeproj/project.pbxproj b/libTAS.xcodeproj/project.pbxproj
index bba52458..d4154d46 100644
--- a/libTAS.xcodeproj/project.pbxproj
+++ b/libTAS.xcodeproj/project.pbxproj
@@ -7,6 +7,11 @@
objects = {
/* Begin PBXBuildFile section */
+ B29F5260263C6CD60087D1A7 /* libtas.dylib in Copy Files */ = {isa = PBXBuildFile; fileRef = EB18D18625DAE57000A40A10 /* libtas.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
+ B29F5261263C6CDA0087D1A7 /* libdyld_func_lookup_helper.dylib in Copy Files */ = {isa = PBXBuildFile; fileRef = B2E6D48E263B0DEA00D79778 /* libdyld_func_lookup_helper.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
+ B2E6D495263B0DF100D79778 /* dyld_func_lookup_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2B761A6263B082100C28B70 /* dyld_func_lookup_helper.cpp */; };
+ B2E6D499263B0DF700D79778 /* dylib1.o in Frameworks */ = {isa = PBXBuildFile; fileRef = EBC20F9725E57DDE008A406C /* dylib1.o */; };
+ B2E6D49D263B0E0000D79778 /* libdyld_func_lookup_helper.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B2E6D48E263B0DEA00D79778 /* libdyld_func_lookup_helper.dylib */; };
EB36F78D25F0F60800833793 /* RenderHUD_Base_MacOS.h in Headers */ = {isa = PBXBuildFile; fileRef = EB36F78B25F0F60800833793 /* RenderHUD_Base_MacOS.h */; };
EB36F78E25F0F60800833793 /* RenderHUD_Base_MacOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EB36F78C25F0F60800833793 /* RenderHUD_Base_MacOS.cpp */; };
EB36F78F25F0FE0900833793 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB79949825E5DED90011078F /* CoreFoundation.framework */; };
@@ -15,7 +20,6 @@
EB79949725E5DE810011078F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB79949625E5DE810011078F /* CoreGraphics.framework */; };
EB79949925E5DEDA0011078F /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB79949825E5DED90011078F /* CoreFoundation.framework */; };
EBC20F9625E568A1008A406C /* openglwrappers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBED812525CC8F3C00951619 /* openglwrappers.cpp */; };
- EBC20F9825E57DDE008A406C /* dylib1.o in Frameworks */ = {isa = PBXBuildFile; fileRef = EBC20F9725E57DDE008A406C /* dylib1.o */; };
EBC20FAE25E58354008A406C /* AutoSave.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBED81D325CC8F3C00951619 /* AutoSave.cpp */; };
EBC20FAF25E58354008A406C /* Config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBED81D625CC8F3C00951619 /* Config.cpp */; };
EBC20FB025E58354008A406C /* GameLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBED81D925CC8F3C00951619 /* GameLoop.cpp */; };
@@ -110,6 +114,8 @@
EBDA73A725E6C8EE007DD9B8 /* QtCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EBDA73A625E6C8EE007DD9B8 /* QtCore.framework */; };
EBDA73AA25E6C908007DD9B8 /* QtGui.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EBDA73A825E6C908007DD9B8 /* QtGui.framework */; };
EBDA73AB25E6C908007DD9B8 /* QtWidgets.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EBDA73A925E6C908007DD9B8 /* QtWidgets.framework */; };
+ EBE36ACC265FF4E800B7B065 /* BaseAddresses.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBE36ACA265FF4E800B7B065 /* BaseAddresses.cpp */; };
+ EBE36ACD265FF4E800B7B065 /* MemLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBE36ACB265FF4E800B7B065 /* MemLayout.cpp */; };
EBED828725CC902A00951619 /* backtrace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBED80A825CC8F3C00951619 /* backtrace.cpp */; };
EBED828825CC902A00951619 /* BusyLoopDetection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBED80AA25CC8F3C00951619 /* BusyLoopDetection.cpp */; };
EBED828925CC902A00951619 /* DeterministicTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBED80C325CC8F3C00951619 /* DeterministicTimer.cpp */; };
@@ -245,7 +251,25 @@
};
/* End PBXBuildRule section */
+/* Begin PBXCopyFilesBuildPhase section */
+ B29F525F263C6CBF0087D1A7 /* Copy Files */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 6;
+ files = (
+ B29F5261263C6CDA0087D1A7 /* libdyld_func_lookup_helper.dylib in Copy Files */,
+ B29F5260263C6CD60087D1A7 /* libtas.dylib in Copy Files */,
+ );
+ name = "Copy Files";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
/* Begin PBXFileReference section */
+ B2B761A6263B082100C28B70 /* dyld_func_lookup_helper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = dyld_func_lookup_helper.cpp; sourceTree = "<group>"; };
+ B2B761A7263B082100C28B70 /* dyld_func_lookup_helper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dyld_func_lookup_helper.h; sourceTree = "<group>"; };
+ B2E6D48E263B0DEA00D79778 /* libdyld_func_lookup_helper.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdyld_func_lookup_helper.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
EB18D18625DAE57000A40A10 /* libtas.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libtas.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
EB1F440125F7E71300E18895 /* keysymdesc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = keysymdesc.h; sourceTree = "<group>"; };
EB36F78B25F0F60800833793 /* RenderHUD_Base_MacOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderHUD_Base_MacOS.h; sourceTree = "<group>"; };
@@ -282,6 +306,10 @@
EBDA73A625E6C8EE007DD9B8 /* QtCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QtCore.framework; path = ../../Qt/5.15.2/clang_64/lib/QtCore.framework; sourceTree = "<group>"; };
EBDA73A825E6C908007DD9B8 /* QtGui.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QtGui.framework; path = ../../Qt/5.15.2/clang_64/lib/QtGui.framework; sourceTree = "<group>"; };
EBDA73A925E6C908007DD9B8 /* QtWidgets.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QtWidgets.framework; path = ../../Qt/5.15.2/clang_64/lib/QtWidgets.framework; sourceTree = "<group>"; };
+ EBE36ACA265FF4E800B7B065 /* BaseAddresses.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BaseAddresses.cpp; sourceTree = "<group>"; };
+ EBE36ACB265FF4E800B7B065 /* MemLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemLayout.cpp; sourceTree = "<group>"; };
+ EBE36ACE265FF4F500B7B065 /* BaseAddresses.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BaseAddresses.h; sourceTree = "<group>"; };
+ EBE36ACF265FF4F500B7B065 /* MemLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MemLayout.h; sourceTree = "<group>"; };
EBED807025CC8F3C00951619 /* cubeb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cubeb.h; sourceTree = "<group>"; };
EBED807125CC8F3C00951619 /* lz4.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = lz4.cpp; sourceTree = "<group>"; };
EBED807225CC8F3C00951619 /* lz4.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lz4.h; sourceTree = "<group>"; };
@@ -667,6 +695,14 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
+ B2E6D48C263B0DEA00D79778 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B2E6D499263B0DF700D79778 /* dylib1.o in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
EBC20F9A25E582ED008A406C /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -685,11 +721,11 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ B2E6D49D263B0E0000D79778 /* libdyld_func_lookup_helper.dylib in Frameworks */,
EBEF72A125F6E11700FEF4D6 /* AudioToolbox.framework in Frameworks */,
EB36F79225F0FE0900833793 /* CoreText.framework in Frameworks */,
EB36F78F25F0FE0900833793 /* CoreFoundation.framework in Frameworks */,
EB36F79025F0FE0900833793 /* CoreGraphics.framework in Frameworks */,
- EBC20F9825E57DDE008A406C /* dylib1.o in Frameworks */,
EBC93BBD25DE929600C84DF4 /* OpenGL.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -697,6 +733,15 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ B2B761A5263B07FF00C28B70 /* dyld_func_lookup_helper */ = {
+ isa = PBXGroup;
+ children = (
+ B2B761A6263B082100C28B70 /* dyld_func_lookup_helper.cpp */,
+ B2B761A7263B082100C28B70 /* dyld_func_lookup_helper.h */,
+ );
+ path = dyld_func_lookup_helper;
+ sourceTree = "<group>";
+ };
EBBDFCF525CEF089005F26EE /* Frameworks */ = {
isa = PBXGroup;
children = (
@@ -726,12 +771,14 @@
EBBDFCF525CEF089005F26EE /* Frameworks */,
EB18D18625DAE57000A40A10 /* libtas.dylib */,
EBC20F9D25E582ED008A406C /* libTAS.app */,
+ B2E6D48E263B0DEA00D79778 /* libdyld_func_lookup_helper.dylib */,
);
sourceTree = "<group>";
};
EBED806E25CC8F3C00951619 /* src */ = {
isa = PBXGroup;
children = (
+ B2B761A5263B07FF00C28B70 /* dyld_func_lookup_helper */,
EBED806F25CC8F3C00951619 /* external */,
EBED808325CC8F3C00951619 /* library */,
EBED81D225CC8F3C00951619 /* program */,
@@ -1240,6 +1287,10 @@
EBED81FB25CC8F3C00951619 /* IRamWatchDetailed.h */,
EBED81FC25CC8F3C00951619 /* MemSection.cpp */,
EBDA73A225E6C3E6007DD9B8 /* MemAccess.cpp */,
+ EBE36ACA265FF4E800B7B065 /* BaseAddresses.cpp */,
+ EBE36ACE265FF4F500B7B065 /* BaseAddresses.h */,
+ EBE36ACF265FF4F500B7B065 /* MemLayout.h */,
+ EBE36ACB265FF4E800B7B065 /* MemLayout.cpp */,
EBDA73A125E6C3E6007DD9B8 /* MemAccess.h */,
EBED81FD25CC8F3C00951619 /* MemSection.h */,
EBED81FE25CC8F3C00951619 /* RamWatch.cpp */,
@@ -1332,6 +1383,13 @@
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
+ B2E6D48A263B0DEA00D79778 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
EBED824B25CC8F5C00951619 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -1347,6 +1405,23 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
+ B2E6D48D263B0DEA00D79778 /* dyld_func_lookup_helper */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B2E6D491263B0DEA00D79778 /* Build configuration list for PBXNativeTarget "dyld_func_lookup_helper" */;
+ buildPhases = (
+ B2E6D48A263B0DEA00D79778 /* Headers */,
+ B2E6D48B263B0DEA00D79778 /* Sources */,
+ B2E6D48C263B0DEA00D79778 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dyld_func_lookup_helper;
+ productName = dyld_func_lookup_helper;
+ productReference = B2E6D48E263B0DEA00D79778 /* libdyld_func_lookup_helper.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
EBC20F9C25E582ED008A406C /* libTAS */ = {
isa = PBXNativeTarget;
buildConfigurationList = EBC20FAB25E582EF008A406C /* Build configuration list for PBXNativeTarget "libTAS" */;
@@ -1354,6 +1429,7 @@
EBC20F9925E582ED008A406C /* Sources */,
EBC20F9A25E582ED008A406C /* Frameworks */,
EBC20F9B25E582ED008A406C /* Resources */,
+ B29F525F263C6CBF0087D1A7 /* Copy Files */,
);
buildRules = (
EBC20FF425E585CB008A406C /* PBXBuildRule */,
@@ -1391,6 +1467,9 @@
LastUpgradeCheck = 1010;
ORGANIZATIONNAME = "Clément";
TargetAttributes = {
+ B2E6D48D263B0DEA00D79778 = {
+ CreatedOnToolsVersion = 12.4;
+ };
EBC20F9C25E582ED008A406C = {
CreatedOnToolsVersion = 10.1;
SystemCapabilities = {
@@ -1419,6 +1498,7 @@
targets = (
EBED824E25CC8F5C00951619 /* tas */,
EBC20F9C25E582ED008A406C /* libTAS */,
+ B2E6D48D263B0DEA00D79778 /* dyld_func_lookup_helper */,
);
};
/* End PBXProject section */
@@ -1434,11 +1514,20 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
+ B2E6D48B263B0DEA00D79778 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B2E6D495263B0DF100D79778 /* dyld_func_lookup_helper.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
EBC20F9925E582ED008A406C /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EBC2101025E58755008A406C /* GameEvents.h in Sources */,
+ EBE36ACC265FF4E800B7B065 /* BaseAddresses.cpp in Sources */,
EBC2101125E58755008A406C /* GameLoop.h in Sources */,
EBC20FF525E5871B008A406C /* AnnotationsWindow.h in Sources */,
EBC20FF625E5871B008A406C /* AutoSaveWindow.h in Sources */,
@@ -1462,6 +1551,7 @@
EBC2100825E5871B008A406C /* qtutils.h in Sources */,
EBC2100925E5871B008A406C /* RamSearchModel.h in Sources */,
EBC2100A25E5871B008A406C /* RamSearchWindow.h in Sources */,
+ EBE36ACD265FF4E800B7B065 /* MemLayout.cpp in Sources */,
EBC2100B25E5871B008A406C /* RamWatchEditWindow.h in Sources */,
EBC2100C25E5871B008A406C /* RamWatchModel.h in Sources */,
EBC2100D25E5871B008A406C /* RamWatchWindow.h in Sources */,
@@ -1655,6 +1745,40 @@
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
+ B2E6D48F263B0DEA00D79778 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CODE_SIGN_IDENTITY = libtas;
+ CODE_SIGN_STYLE = Manual;
+ DEVELOPMENT_TEAM = clementgallet;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ EXECUTABLE_PREFIX = lib;
+ MACOSX_DEPLOYMENT_TARGET = 10.7;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ };
+ name = Debug;
+ };
+ B2E6D490263B0DEA00D79778 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CODE_SIGN_IDENTITY = libtas;
+ CODE_SIGN_STYLE = Manual;
+ DEVELOPMENT_TEAM = clementgallet;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ EXECUTABLE_PREFIX = lib;
+ MACOSX_DEPLOYMENT_TARGET = 10.7;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ };
+ name = Release;
+ };
EBC20FAC25E582EF008A406C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -1677,6 +1801,7 @@
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
+ "@executable_path",
);
LIBRARY_SEARCH_PATHS = (
"/usr/local/opt/lua\\@5.3/lib",
@@ -1711,6 +1836,7 @@
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
+ "@executable_path",
);
LIBRARY_SEARCH_PATHS = (
"/usr/local/opt/lua\\@5.3/lib",
@@ -1845,6 +1971,7 @@
DEVELOPMENT_TEAM = clementgallet;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
EXECUTABLE_PREFIX = lib;
GCC_PREPROCESSOR_DEFINITIONS = (
"__THROW=",
@@ -1854,11 +1981,18 @@
);
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
HEADER_SEARCH_PATHS = /usr/local/include;
+ LD_RUNPATH_SEARCH_PATHS = "@loader_path";
LIBRARY_SEARCH_PATHS = /usr/local/lib;
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-fno-stack-protector",
);
+ OTHER_LDFLAGS = (
+ "-Xlinker",
+ "-U",
+ "-Xlinker",
+ _dlopen_from,
+ );
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
@@ -1877,6 +2011,7 @@
DEVELOPMENT_TEAM = clementgallet;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
EXECUTABLE_PREFIX = lib;
GCC_PREPROCESSOR_DEFINITIONS = (
"__THROW=",
@@ -1886,11 +2021,18 @@
);
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
HEADER_SEARCH_PATHS = /usr/local/include;
+ LD_RUNPATH_SEARCH_PATHS = "@loader_path";
LIBRARY_SEARCH_PATHS = /usr/local/lib;
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-fno-stack-protector",
);
+ OTHER_LDFLAGS = (
+ "-Xlinker",
+ "-U",
+ "-Xlinker",
+ _dlopen_from,
+ );
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
@@ -1901,6 +2043,15 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
+ B2E6D491263B0DEA00D79778 /* Build configuration list for PBXNativeTarget "dyld_func_lookup_helper" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B2E6D48F263B0DEA00D79778 /* Debug */,
+ B2E6D490263B0DEA00D79778 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Debug;
+ };
EBC20FAB25E582EF008A406C /* Build configuration list for PBXNativeTarget "libTAS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
diff --git a/libTAS.xcodeproj/project.xcworkspace/xcuserdata/clement.xcuserdatad/UserInterfaceState.xcuserstate b/libTAS.xcodeproj/project.xcworkspace/xcuserdata/clement.xcuserdatad/UserInterfaceState.xcuserstate
index 57c2c641..441ddbcb 100644
--- a/libTAS.xcodeproj/project.xcworkspace/xcuserdata/clement.xcuserdatad/UserInterfaceState.xcuserstate
+++ b/libTAS.xcodeproj/project.xcworkspace/xcuserdata/clement.xcuserdatad/UserInterfaceState.xcuserstate
Binary files differ
diff --git a/libTAS.xcodeproj/xcshareddata/xcschemes/libTAS.xcscheme b/libTAS.xcodeproj/xcshareddata/xcschemes/libTAS.xcscheme
index fe269f3a..92709314 100644
--- a/libTAS.xcodeproj/xcshareddata/xcschemes/libTAS.xcscheme
+++ b/libTAS.xcodeproj/xcshareddata/xcschemes/libTAS.xcscheme
@@ -1,10 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
- version = "1.3">
+ version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
+ <PostActions>
+ <ExecutionAction
+ ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
+ <ActionContent
+ title = "Run Script"
+ scriptText = "# Type a script or drag a script file from your workspace to insert its path.&#10;mv ${TARGET_BUILD_DIR}/libtas.dylib ${TARGET_BUILD_DIR}/libTAS.app/Contents/MacOS/&#10;mv ${TARGET_BUILD_DIR}/libdyld_func_lookup_helper.dylib ${TARGET_BUILD_DIR}/libTAS.app/Contents/MacOS/&#10;">
+ <EnvironmentBuildable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "EBED824E25CC8F5C00951619"
+ BuildableName = "libtas.dylib"
+ BlueprintName = "tas"
+ ReferencedContainer = "container:libTAS.xcodeproj">
+ </BuildableReference>
+ </EnvironmentBuildable>
+ </ActionContent>
+ </ExecutionAction>
+ </PostActions>
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
diff --git a/libTAS.xcodeproj/xcuserdata/clement.xcuserdatad/xcschemes/xcschememanagement.plist b/libTAS.xcodeproj/xcuserdata/clement.xcuserdatad/xcschemes/xcschememanagement.plist
index e58df608..5908bcf4 100644
--- a/libTAS.xcodeproj/xcuserdata/clement.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/libTAS.xcodeproj/xcuserdata/clement.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -4,6 +4,11 @@
<dict>
<key>SchemeUserState</key>
<dict>
+ <key>dyld_func_lookup_helper.xcscheme_^#shared#^_</key>
+ <dict>
+ <key>orderHint</key>
+ <integer>1</integer>
+ </dict>
<key>eazeaz.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
@@ -12,7 +17,7 @@
<key>libTAS.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
- <integer>1</integer>
+ <integer>0</integer>
</dict>
<key>libtas.so.xcscheme_^#shared#^_</key>
<dict>
diff --git a/src/dyld_func_lookup_helper/dyld_func_lookup_helper.cpp b/src/dyld_func_lookup_helper/dyld_func_lookup_helper.cpp
new file mode 100644
index 00000000..20d90bde
--- /dev/null
+++ b/src/dyld_func_lookup_helper/dyld_func_lookup_helper.cpp
@@ -0,0 +1,7 @@
+#include "dyld_func_lookup_helper.h"
+
+extern "C" int _dyld_func_lookup(const char *name, void **address);
+
+int dyld_func_lookup_helper(const char *name, void **address) {
+ return _dyld_func_lookup(name, address);
+}
diff --git a/src/dyld_func_lookup_helper/dyld_func_lookup_helper.h b/src/dyld_func_lookup_helper/dyld_func_lookup_helper.h
new file mode 100644
index 00000000..206e8d38
--- /dev/null
+++ b/src/dyld_func_lookup_helper/dyld_func_lookup_helper.h
@@ -0,0 +1,6 @@
+#ifndef dyld_func_lookup_helper_h
+#define dyld_func_lookup_helper_h
+
+int dyld_func_lookup_helper(const char *name, void **address);
+
+#endif /* dyld_func_lookup_helper_h */
diff --git a/src/external/vulkan_core.h b/src/external/vulkan_core.h
index 9a259ee4..1ace77e8 100644
--- a/src/external/vulkan_core.h
+++ b/src/external/vulkan_core.h
@@ -17,6 +17,8 @@
extern "C" {
#endif
+#include <stddef.h>
+
#define VK_VERSION_1_0 1
diff --git a/src/library/GameHacks.cpp b/src/library/GameHacks.cpp
index 94a60381..674c93d6 100644
--- a/src/library/GameHacks.cpp
+++ b/src/library/GameHacks.cpp
@@ -22,7 +22,9 @@
namespace libtas {
-static bool unity = false;
+bool GameHacks::unity = false;
+bool GameHacks::coreclr = false;
+pid_t GameHacks::finalizer_pid = 0;
void GameHacks::setUnity()
{
@@ -35,4 +37,26 @@ bool GameHacks::isUnity()
return unity;
}
+void GameHacks::setCoreclr()
+{
+ debuglogstdio(LCF_HOOK | LCF_ERROR, " detected coreclr");
+ coreclr = true;
+}
+
+bool GameHacks::hasCoreclr()
+{
+ return coreclr;
+}
+
+void GameHacks::setFinalizerThread(pid_t pid)
+{
+ debuglogstdio(LCF_HOOK | LCF_ERROR, " set finalizer to %d", pid);
+ finalizer_pid = pid;
+}
+
+pid_t GameHacks::getFinalizerThread()
+{
+ return finalizer_pid;
+}
+
}
diff --git a/src/library/GameHacks.h b/src/library/GameHacks.h
index f110278c..e931fb5d 100644
--- a/src/library/GameHacks.h
+++ b/src/library/GameHacks.h
@@ -20,6 +20,8 @@
#ifndef LIBTAS_GAMEHACKS_H_INCLUDED
#define LIBTAS_GAMEHACKS_H_INCLUDED
+#include <sys/types.h>
+
namespace libtas {
class GameHacks
@@ -28,6 +30,23 @@ class GameHacks
static void setUnity();
static bool isUnity();
+
+ /* Regsiter that the game linked `libcoreclr.so` library */
+ static void setCoreclr();
+
+ /* Returns if the game linked `libcoreclr.so` library */
+ static bool hasCoreclr();
+
+ /* Regsiter the pid of the .NET finalizer thread */
+ static void setFinalizerThread(pid_t pid);
+
+ /* Get the pid of the .NET finalizer thread, or 0 */
+ static pid_t getFinalizerThread();
+
+ private:
+ static bool unity;
+ static bool coreclr;
+ static pid_t finalizer_pid;
};
}
diff --git a/src/library/ScreenCapture.cpp b/src/library/ScreenCapture.cpp
index 8b53f1a9..fb59f690 100755
--- a/src/library/ScreenCapture.cpp
+++ b/src/library/ScreenCapture.cpp
@@ -42,8 +42,8 @@
#include <GL/gl.h>
#include <GL/glext.h>
#elif defined(__APPLE__) && defined(__MACH__)
-#include <OpenGL/gl.h>
-#include <OpenGL/glext.h>
+#include <OpenGL/gl3.h>
+#include <OpenGL/gl3ext.h>
#endif
diff --git a/src/library/audio/AudioSource.cpp b/src/library/audio/AudioSource.cpp
index ce4683b9..46df82db 100644
--- a/src/library/audio/AudioSource.cpp
+++ b/src/library/audio/AudioSource.cpp
@@ -284,10 +284,8 @@ int AudioSource::mixWith( struct timespec ticks, uint8_t* outSamples, int outByt
audioConverter->queueSamples(begSamples, availableSamples);
}
- if (remainingSamples == availableSamples) {
- finalIndex = i;
- finalPos = loopbuf->loop_point_beg + availableSamples;
- }
+ finalIndex = i;
+ finalPos = loopbuf->loop_point_beg + availableSamples;
remainingSamples -= availableSamples;
}
}
@@ -301,10 +299,8 @@ int AudioSource::mixWith( struct timespec ticks, uint8_t* outSamples, int outByt
audioConverter->queueSamples(begSamples, availableSamples);
}
- if (remainingSamples == availableSamples) {
- finalIndex = i;
- finalPos = availableSamples;
- }
+ finalIndex = i;
+ finalPos = availableSamples;
remainingSamples -= availableSamples;
}
}
diff --git a/src/library/audio/alsa/pcm.cpp b/src/library/audio/alsa/pcm.cpp
index c88085b4..b49e64fd 100644
--- a/src/library/audio/alsa/pcm.cpp
+++ b/src/library/audio/alsa/pcm.cpp
@@ -345,8 +345,8 @@ int snd_pcm_hw_params_can_pause(const snd_pcm_hw_params_t *params)
int snd_pcm_pause(snd_pcm_t *pcm, int enable)
{
if (GlobalState::isNative()) {
- LINK_NAMESPACE_GLOBAL(snd_pcm_state);
- return orig::snd_pcm_state(pcm);
+ LINK_NAMESPACE_GLOBAL(snd_pcm_pause);
+ return orig::snd_pcm_pause(pcm, enable);
}
DEBUGLOGCALL(LCF_SOUND);
@@ -616,6 +616,11 @@ snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_ufr
source->state = AudioSource::SOURCE_PLAYING;
}
+ if (source->state == AudioSource::SOURCE_UNDERRUN) {
+ /* Underrun */
+ return -EPIPE;
+ }
+
if (source->state != AudioSource::SOURCE_PLAYING) {
return -EBADFD;
}
diff --git a/src/library/audio/sdl/sdlaudio.cpp b/src/library/audio/sdl/sdlaudio.cpp
index ed178649..e776f2c6 100644
--- a/src/library/audio/sdl/sdlaudio.cpp
+++ b/src/library/audio/sdl/sdlaudio.cpp
@@ -466,7 +466,10 @@ void SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
/* Override */ void SDL_CloseAudioDevice(SDL_AudioDeviceID dev)
{
- DEBUGLOGCALL(LCF_SDL | LCF_SOUND);
+ debuglogstdio(LCF_SDL | LCF_SOUND, "%s called with dev %d", __func__, dev);
+
+ if (dev == 0 || dev >= MAX_SDL_SOURCES)
+ return;
std::lock_guard<std::mutex> lock(audiocontext.mutex);
/* Remove the source from the audio context */
diff --git a/src/library/dlhook.cpp b/src/library/dlhook.cpp
index 7579f001..eca8833f 100644
--- a/src/library/dlhook.cpp
+++ b/src/library/dlhook.cpp
@@ -31,6 +31,7 @@
#include "backtrace.h"
#include "GameHacks.h"
#include <sys/stat.h>
+#include "../dyld_func_lookup_helper/dyld_func_lookup_helper.h"
namespace libtas {
@@ -67,8 +68,14 @@ void add_lib(const char* library)
DEFINE_ORIG_POINTER(dlopen)
DEFINE_ORIG_POINTER(dlsym)
+#if defined(__APPLE__) && defined(__MACH__)
+/* dlopen_from is like dlopen, except it takes an extra argument specifying the "true" caller address.
+ * it is marked as weak so that libTAS will still work if it's not present. */
+extern "C" void *dlopen_from(const char *file, int mode, void *callerAddr) __attribute__((weak));
+#endif
+
__attribute__((noipa)) void *dlopen(const char *file, int mode) __THROW {
- const void *const callerAddr = __builtin_extract_return_addr(__builtin_return_address(0));
+ void *const callerAddr = __builtin_extract_return_addr(__builtin_return_address(0));
if (!orig::dlopen) {
#ifdef __unix__
@@ -77,7 +84,7 @@ __attribute__((noipa)) void *dlopen(const char *file, int mode) __THROW {
orig::dlopen = reinterpret_cast<decltype(orig::dlopen)>(_dl_sym(RTLD_NEXT, "dlopen", reinterpret_cast<void*>(dlopen)));
#elif defined(__APPLE__) && defined(__MACH__)
/* Using the convenient function to locate a dyld function pointer */
- _dyld_func_lookup("__dyld_dlopen", reinterpret_cast<void**>(&orig::dlopen));
+ dyld_func_lookup_helper("__dyld_dlopen", reinterpret_cast<void**>(&orig::dlopen));
#endif
}
@@ -98,76 +105,87 @@ __attribute__((noipa)) void *dlopen(const char *file, int mode) __THROW {
debuglogstdio(LCF_HOOK, "%s call with file %s", __func__, (file!=nullptr)?file:"<NULL>");
void *result = nullptr;
+#if defined(__APPLE__) && defined(__MACH__)
+ if (dlopen_from) {
+ result = dlopen_from(file, mode, reinterpret_cast<void*>(callerAddr));
+
+ if (result != nullptr) {
+ add_lib(file);
+ }
+ } else
+#endif
+ {
#ifdef __unix__
- if (file != nullptr && file[0] != '\0' && std::strchr(file, '/') == nullptr) {
- /* Path should be searched using search paths, so let's
- * manually check the paths in the correct order...
- */
- Dl_info info;
- if (dladdr(callerAddr, &info)) {
- /* Get the dynamic library name of our caller */
- const char *dlname = info.dli_fname;
- {
- struct stat dlstat, exestat;
- if (stat(dlname, &dlstat) == 0 &&
- stat("/proc/self/exe", &exestat) == 0 &&
- dlstat.st_dev == exestat.st_dev &&
- dlstat.st_ino == exestat.st_ino) {
- /* Unless being called from the main executable */
- dlname = nullptr;
+ if (file != nullptr && file[0] != '\0' && std::strchr(file, '/') == nullptr) {
+ /* Path should be searched using search paths, so let's
+ * manually check the paths in the correct order...
+ */
+ Dl_info info;
+ if (dladdr(callerAddr, &info)) {
+ /* Get the dynamic library name of our caller */
+ const char *dlname = info.dli_fname;
+ {
+ struct stat dlstat, exestat;
+ if (stat(dlname, &dlstat) == 0 &&
+ stat("/proc/self/exe", &exestat) == 0 &&
+ dlstat.st_dev == exestat.st_dev &&
+ dlstat.st_ino == exestat.st_ino) {
+ /* Unless being called from the main executable */
+ dlname = nullptr;
+ }
}
- }
- /* Open object of caller */
- void *caller = orig::dlopen(dlname, RTLD_LAZY | RTLD_NOLOAD);
- if (caller != nullptr) {
- Dl_serinfo size;
- if (dlinfo(caller, RTLD_DI_SERINFOSIZE, &size) == 0) {
- auto *paths = reinterpret_cast<Dl_serinfo *>(new char[size.dls_size]);
- *paths = size;
-
- /* Get ordered list of search paths for this object */
- if (dlinfo(caller, RTLD_DI_SERINFO, paths) == 0) {
- for (unsigned i = 0; i != paths->dls_cnt; ++i) {
- const char *name = paths->dls_serpath[i].dls_name;
- /* Probably can't happen, just being safe... */
- if (name == nullptr || name[0] == '\0')
- continue;
- std::string path(name);
- /* Note that this guaranteed / prevents
- * recursive search path lookup
- */
- if (path.back() != '/')
- path += '/';
- path += file;
-
- result = orig::dlopen(path.c_str(), mode);
- if (result != nullptr) {
- debuglogstdio(LCF_HOOK, " Found at %s", name);
- add_lib(path.c_str());
- break;
+ /* Open object of caller */
+ void *caller = orig::dlopen(dlname, RTLD_LAZY | RTLD_NOLOAD);
+ if (caller != nullptr) {
+ Dl_serinfo size;
+ if (dlinfo(caller, RTLD_DI_SERINFOSIZE, &size) == 0) {
+ auto *paths = reinterpret_cast<Dl_serinfo *>(new char[size.dls_size]);
+ *paths = size;
+
+ /* Get ordered list of search paths for this object */
+ if (dlinfo(caller, RTLD_DI_SERINFO, paths) == 0) {
+ for (unsigned i = 0; i != paths->dls_cnt; ++i) {
+ const char *name = paths->dls_serpath[i].dls_name;
+ /* Probably can't happen, just being safe... */
+ if (name == nullptr || name[0] == '\0')
+ continue;
+ std::string path(name);
+ /* Note that this guaranteed / prevents
+ * recursive search path lookup
+ */
+ if (path.back() != '/')
+ path += '/';
+ path += file;
+
+ result = orig::dlopen(path.c_str(), mode);
+ if (result != nullptr) {
+ debuglogstdio(LCF_HOOK, " Found at %s", name);
+ add_lib(path.c_str());
+ break;
+ }
}
}
+
+ delete [] reinterpret_cast<char *>(paths);
}
- delete [] reinterpret_cast<char *>(paths);
+ dlclose(caller);
}
-
- dlclose(caller);
}
}
- }
#endif
- if (result == nullptr) {
- /* Path is empty (referring to the main program), relative to
- * the cwd, absolute, or failed search path lookup above, so
- * try looking it up normally.
- */
- result = orig::dlopen(file, mode);
+ if (result == nullptr) {
+ /* Path is empty (referring to the main program), relative to
+ * the cwd, absolute, or failed search path lookup above, so
+ * try looking it up normally.
+ */
+ result = orig::dlopen(file, mode);
- if (result != nullptr)
- add_lib(file);
+ if (result != nullptr)
+ add_lib(file);
+ }
}
#ifdef __linux__
@@ -187,6 +205,9 @@ __attribute__((noipa)) void *dlopen(const char *file, int mode) __THROW {
}
#endif
+ if (result && file && std::strstr(file, "libcoreclr.so") != nullptr)
+ GameHacks::setCoreclr();
+
return result;
}
@@ -220,7 +241,7 @@ void *dlsym(void *handle, const char *name) __THROW {
orig::dlsym = reinterpret_cast<decltype(orig::dlsym)>(_dl_sym(RTLD_NEXT, "dlsym", reinterpret_cast<void*>(dlsym)));
#elif defined(__APPLE__) && defined(__MACH__)
/* Using the convenient function to locate a dyld function pointer */
- _dyld_func_lookup("__dyld_dlsym", reinterpret_cast<void**>(&orig::dlsym));
+ dyld_func_lookup_helper("__dyld_dlsym", reinterpret_cast<void**>(&orig::dlsym));
#endif
}
diff --git a/src/library/inputs/xkeyboardlayout.cpp b/src/library/inputs/xkeyboardlayout.cpp
index 688c3334..e73e0f89 100644
--- a/src/library/inputs/xkeyboardlayout.cpp
+++ b/src/library/inputs/xkeyboardlayout.cpp
@@ -180,7 +180,9 @@ static const char Xlib_default_char[256] = {
debuglogstdio(LCF_KEYBOARD, "%s called with keycode %d", __func__, event_struct->keycode);
// printBacktrace();
KeyCode keycode = event_struct->keycode;
- *keysym_return = Xlib_default_keymap[keycode];
+ if (keysym_return) {
+ *keysym_return = Xlib_default_keymap[keycode];
+ }
if (buffer_return && (bytes_buffer > 0)) {
char c = Xlib_default_char[keycode];
if (c == '\0') {
@@ -196,23 +198,26 @@ static const char Xlib_default_char[256] = {
{
debuglogstdio(LCF_KEYBOARD, "%s called with keycode %d", __func__, event->keycode);
KeyCode keycode = event->keycode;
- *keysym_return = Xlib_default_keymap[keycode];
+ KeySym keysym = Xlib_default_keymap[keycode];
/* Return if no associated keysym */
- if (*keysym_return == NoSymbol) {
+ if (keysym == NoSymbol) {
*status_return = XLookupNone;
return 0;
}
+ if (keysym_return)
+ *keysym_return = keysym;
+
char c = Xlib_default_char[keycode];
/* Return if no associated string */
if (c == '\0') {
- *status_return = XLookupKeySym;
+ *status_return = keysym_return ? XLookupKeySym : XLookupNone;
return 0;
}
- *status_return = XLookupBoth;
+ *status_return = keysym_return ? XLookupBoth : XLookupChars;
if (buffer_return && (bytes_buffer > 0)) {
buffer_return[0] = c;
return 1;
@@ -224,23 +229,27 @@ static const char Xlib_default_char[256] = {
{
debuglogstdio(LCF_KEYBOARD, "%s called with keycode %d", __func__, event->keycode);
KeyCode keycode = event->keycode;
- *keysym_return = Xlib_default_keymap[keycode];
+ KeySym keysym = Xlib_default_keymap[keycode];
/* Return if no associated keysym */
- if (*keysym_return == NoSymbol) {
+ if (keysym == NoSymbol) {
*status_return = XLookupNone;
return 0;
}
+ if (keysym_return) {
+ *keysym_return = keysym;
+ }
+
char c = Xlib_default_char[keycode];
/* Return if no associated string */
if (c == '\0') {
- *status_return = XLookupKeySym;
+ *status_return = keysym_return ? XLookupKeySym : XLookupNone;
return 0;
}
- *status_return = XLookupBoth;
+ *status_return = keysym_return ? XLookupBoth : XLookupChars;
if (buffer_return && (wchars_buffer > 0)) {
buffer_return[0] = c;
return 1;
@@ -252,23 +261,26 @@ static const char Xlib_default_char[256] = {
{
debuglogstdio(LCF_KEYBOARD, "%s called with keycode %d", __func__, event->keycode);
KeyCode keycode = event->keycode;
- *keysym_return = Xlib_default_keymap[keycode];
+ KeySym keysym = Xlib_default_keymap[keycode];
/* Return if no associated keysym */
- if (*keysym_return == NoSymbol) {
+ if (keysym == NoSymbol) {
*status_return = XLookupNone;
return 0;
}
+
+ if (keysym_return)
+ *keysym_return = keysym;
char c = Xlib_default_char[keycode];
/* Return if no associated string */
if (c == '\0') {
- *status_return = XLookupKeySym;
+ *status_return = keysym_return ? XLookupKeySym : XLookupNone;
return 0;
}
- *status_return = XLookupBoth;
+ *status_return = keysym_return ? XLookupBoth : XLookupChars;
if (buffer_return && (bytes_buffer > 0)) {
buffer_return[0] = c;
return 1;
diff --git a/src/library/main.cpp b/src/library/main.cpp
index 1446e9d4..35f5fc3a 100644
--- a/src/library/main.cpp
+++ b/src/library/main.cpp
@@ -160,6 +160,10 @@ void __attribute__((constructor)) init(void)
message = receiveMessage();
}
+ if (shared_config.sigint_upon_launch) {
+ raise(SIGINT);
+ }
+
/* Set the frame count to the initial frame count */
framecount = shared_config.initial_framecount;
diff --git a/src/library/openglwrappers.h b/src/library/openglwrappers.h
index 80f97348..9ff6444d 100644
--- a/src/library/openglwrappers.h
+++ b/src/library/openglwrappers.h
@@ -26,8 +26,8 @@
#include <GL/gl.h>
#include <GL/glext.h>
#elif defined(__APPLE__) && defined(__MACH__)
-#include <OpenGL/gl.h>
-#include <OpenGL/glext.h>
+#include <OpenGL/gl3.h>
+#include <OpenGL/gl3ext.h>
#endif
namespace libtas {
diff --git a/src/library/pthreadwrappers.cpp b/src/library/pthreadwrappers.cpp
index 0c37e04f..88604f52 100644
--- a/src/library/pthreadwrappers.cpp
+++ b/src/library/pthreadwrappers.cpp
@@ -27,6 +27,7 @@
#include "backtrace.h"
#include "hook.h"
#include "timewrappers.h" // gettimeofday()
+#include "GameHacks.h"
#include <errno.h>
#include <unistd.h>
@@ -140,41 +141,41 @@ static void *pthread_start(void *arg)
debuglogstdio(LCF_THREAD, "End of thread code");
+ if (shared_config.recycle_threads) {
#ifdef __linux__
- /* Because we recycle this thread, we must unset all TLS values
- * and call destructors ourselves. First, we unset the values
- * from the older, pthread_key_create()-based implementation
- * of TLS.
- */
- clear_pthread_keys();
- /* Next we deal with the newer linker-based TLS
- * implementation accessed via thread_local in C11/C++11
- * and later. For that, first we need to run any C++
- * destructors for values in thread-local storage, using
- * an internal libc function.
- */
- __call_tls_dtors();
- /* Next, we clean up any libc state in thread-local storage,
- * using an internal libc function.
- */
- __libc_thread_freeres();
- /* Finally, we reset all thread-local storage back to its
- * initial value, using a third internal libc function.
- * This is architecture-specific; it works on 32-bit and
- * 64-bit x86, but not on all Linux architectures. See
- * above, where this function is declared.
- */
- _dl_allocate_tls_init(thread->pthread_id);
- /* This has just reset any libTAS thread-local storage
- * for this thread. Most libTAS TLS is either transient
- * anyway, or irrelevant while the thread is waiting
- * to be recycled. But one value is important:
- * we need to fix ThreadManager::current_thread .
- */
+ /* Because we recycle this thread, we must unset all TLS values
+ * and call destructors ourselves. First, we unset the values
+ * from the older, pthread_key_create()-based implementation
+ * of TLS.
+ */
+ clear_pthread_keys();
+ /* Next we deal with the newer linker-based TLS
+ * implementation accessed via thread_local in C11/C++11
+ * and later. For that, first we need to run any C++
+ * destructors for values in thread-local storage, using
+ * an internal libc function.
+ */
+ __call_tls_dtors();
+ /* Next, we clean up any libc state in thread-local storage,
+ * using an internal libc function.
+ */
+ __libc_thread_freeres();
+ /* Finally, we reset all thread-local storage back to its
+ * initial value, using a third internal libc function.
+ * This is architecture-specific; it works on 32-bit and
+ * 64-bit x86, but not on all Linux architectures. See
+ * above, where this function is declared.
+ */
+ _dl_allocate_tls_init(thread->pthread_id);
+ /* This has just reset any libTAS thread-local storage
+ * for this thread. Most libTAS TLS is either transient
+ * anyway, or irrelevant while the thread is waiting
+ * to be recycled. But one value is important:
+ * we need to fix ThreadManager::current_thread .
+ */
+ ThreadManager::setCurrentThread(thread);
#endif
-
- ThreadManager::setCurrentThread(thread);
-
+ }
ThreadManager::threadExit(ret);
/* Thread is now in zombie state until it is detached */
@@ -752,6 +753,14 @@ int pthread_setname_np (const char *name)
GlobalState::setNoLog(true);
}
+ if (strcmp(name, ".NET Finalizer") == 0) {
+#ifdef __unix__
+ GameHacks::setFinalizerThread(ThreadManager::getThreadTid(target_thread));
+#elif defined(__APPLE__) && defined(__MACH__)
+ GameHacks::setFinalizerThread(ThreadManager::getThreadTid());
+#endif
+ }
+
if (shared_config.game_specific_sync & SharedConfig::GC_SYNC_CELESTE) {
if ((strcmp(name, "OVERWORLD_LOADE") == 0) ||
(strcmp(name, "LEVEL_LOADER") == 0) ||
diff --git a/src/library/renderhud/RenderHUD_Base_MacOS.cpp b/src/library/renderhud/RenderHUD_Base_MacOS.cpp
index 5c4252fb..6c1cf849 100644
--- a/src/library/renderhud/RenderHUD_Base_MacOS.cpp
+++ b/src/library/renderhud/RenderHUD_Base_MacOS.cpp
@@ -26,6 +26,7 @@
#include <CoreFoundation/CoreFoundation.h>
#include <CoreGraphics/CoreGraphics.h>
//#include "../global.h" // shared_config
+#include "../ScreenCapture.h"
namespace libtas {
diff --git a/src/library/renderhud/RenderHUD_GL.cpp b/src/library/renderhud/RenderHUD_GL.cpp
index d884acc2..2e8c7d7b 100644
--- a/src/library/renderhud/RenderHUD_GL.cpp
+++ b/src/library/renderhud/RenderHUD_GL.cpp
@@ -60,6 +60,8 @@ DECLARE_ORIG_POINTER(glDeleteBuffers)
DECLARE_ORIG_POINTER(glDeleteVertexArrays)
DECLARE_ORIG_POINTER(glDeleteProgram)
DECLARE_ORIG_POINTER(glEnable)
+DECLARE_ORIG_POINTER(glDisable)
+DECLARE_ORIG_POINTER(glIsEnabled)
DECLARE_ORIG_POINTER(glBlendFunc)
GLuint RenderHUD_GL::texture = 0;
@@ -121,8 +123,6 @@ void RenderHUD_GL::init()
GLint res;
/* Get previous active texture */
- GLint oldTex;
- orig::glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
GLint oldActiveTex;
orig::glGetIntegerv(GL_ACTIVE_TEXTURE, &oldActiveTex);
@@ -137,6 +137,12 @@ void RenderHUD_GL::init()
if ((error = orig::glGetError()) != GL_NO_ERROR)
debuglogstdio(LCF_WINDOW | LCF_OGL | LCF_ERROR, "glGenTextures failed with error %d", error);
+ if (oldActiveTex != 0) {
+ orig::glActiveTexture(oldActiveTex);
+ if ((error = orig::glGetError()) != GL_NO_ERROR)
+ debuglogstdio(LCF_WINDOW | LCF_OGL | LCF_ERROR, "glActiveTexture failed with error %d", error);
+ }
+
/* Create buffers */
orig::glGenBuffers(1, &vbo);
orig::glGenBuffers(1, &ebo);
@@ -236,18 +242,6 @@ void RenderHUD_GL::init()
orig::glDeleteShader(vertexShaderID);
orig::glDeleteShader(fragmentShaderID);
-
- /* Restore previous active texture */
- if (oldTex != 0) {
- orig::glBindTexture(GL_TEXTURE_2D, oldTex);
- if ((error = orig::glGetError()) != GL_NO_ERROR)
- debuglogstdio(LCF_WINDOW | LCF_OGL | LCF_ERROR, "glBindTexture failed with error %d", error);
- }
- if (oldActiveTex != 0) {
- orig::glActiveTexture(oldActiveTex);
- if ((error = orig::glGetError()) != GL_NO_ERROR)
- debuglogstdio(LCF_WINDOW | LCF_OGL | LCF_ERROR, "glActiveTexture failed with error %d", error);
- }
}
}
@@ -282,6 +276,8 @@ void RenderHUD_GL::renderSurface(std::unique_ptr<SurfaceARGB> surf, int x, int y
RenderHUD_GL::init();
LINK_NAMESPACE(glEnable, "GL");
+ LINK_NAMESPACE(glDisable, "GL");
+ LINK_NAMESPACE(glIsEnabled, "GL");
LINK_NAMESPACE(glBlendFunc, "GL");
LINK_NAMESPACE(glBindTexture, "GL");
LINK_NAMESPACE(glTexImage2D, "GL");
@@ -297,6 +293,7 @@ void RenderHUD_GL::renderSurface(std::unique_ptr<SurfaceARGB> surf, int x, int y
GLenum error;
orig::glGetError();
+ GLboolean isBlend = orig::glIsEnabled(GL_BLEND);
orig::glEnable(GL_BLEND);
orig::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -391,6 +388,9 @@ void RenderHUD_GL::renderSurface(std::unique_ptr<SurfaceARGB> surf, int x, int y
orig::glUseProgram(oldProgram);
if ((error = orig::glGetError()) != GL_NO_ERROR)
debuglogstdio(LCF_WINDOW | LCF_OGL | LCF_ERROR, "glUseProgram failed with error %d", error);
+
+ if (!isBlend)
+ orig::glDisable(GL_BLEND);
}
}
diff --git a/src/library/renderhud/RenderHUD_GL.h b/src/library/renderhud/RenderHUD_GL.h
index 952c2bd3..c5f434a8 100644
--- a/src/library/renderhud/RenderHUD_GL.h
+++ b/src/library/renderhud/RenderHUD_GL.h
@@ -33,8 +33,8 @@
#include <GL/gl.h>
#include <GL/glext.h>
#elif defined(__APPLE__) && defined(__MACH__)
-#include <OpenGL/gl.h>
-#include <OpenGL/glext.h>
+#include <OpenGL/gl3.h>
+#include <OpenGL/gl3ext.h>
#endif
namespace libtas {
diff --git a/src/library/renderhud/RenderHUD_SDL2_renderer.cpp b/src/library/renderhud/RenderHUD_SDL2_renderer.cpp
index bc74482c..b4ce8994 100644
--- a/src/library/renderhud/RenderHUD_SDL2_renderer.cpp
+++ b/src/library/renderhud/RenderHUD_SDL2_renderer.cpp
@@ -30,6 +30,7 @@ DECLARE_ORIG_POINTER(SDL_DestroyTexture)
DECLARE_ORIG_POINTER(SDL_LockTexture)
DECLARE_ORIG_POINTER(SDL_UnlockTexture)
DECLARE_ORIG_POINTER(SDL_RenderCopy)
+DECLARE_ORIG_POINTER(SDL_SetTextureBlendMode)
RenderHUD_SDL2_renderer::~RenderHUD_SDL2_renderer()
{
@@ -49,6 +50,7 @@ void RenderHUD_SDL2_renderer::renderSurface(std::unique_ptr<SurfaceARGB> surf, i
LINK_NAMESPACE_SDL2(SDL_LockTexture);
LINK_NAMESPACE_SDL2(SDL_UnlockTexture);
LINK_NAMESPACE_SDL2(SDL_RenderCopy);
+ LINK_NAMESPACE_SDL2(SDL_SetTextureBlendMode);
GlobalNative gn;
@@ -58,6 +60,7 @@ void RenderHUD_SDL2_renderer::renderSurface(std::unique_ptr<SurfaceARGB> surf, i
orig::SDL_DestroyTexture(texture);
texture = orig::SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, surf->w, surf->h);
+ orig::SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
tex_w = surf->w;
tex_h = surf->h;
}
diff --git a/src/library/sdl/sdldynapi.cpp b/src/library/sdl/sdldynapi.cpp
index 7f61884f..ae820d53 100644
--- a/src/library/sdl/sdldynapi.cpp
+++ b/src/library/sdl/sdldynapi.cpp
@@ -90,8 +90,11 @@ enum {
/* We cannot call any SDL functions until dynapi is setup, including the
* get_sdlversion in LINK_NAMESPACE_SDLX. However, dynapi was not
* introduced until 2.0.2, so we can assume SDL2 for now.
+ *
+ * We don't use the full library name, because it is supposed to be already
+ * accessible. Some games or frameworks don't use the exact library name.
*/
- LINK_NAMESPACE_SDL2(SDL_DYNAPI_entry);
+ LINK_NAMESPACE_FULLNAME(SDL_DYNAPI_entry, "libSDL2");
if (!orig::SDL_DYNAPI_entry) {
debuglogstdio(LCF_SDL | LCF_ERROR, "Could not find the original SDL_DYNAPI_entry function!");
diff --git a/src/library/sdl/sdlhooks.h b/src/library/sdl/sdlhooks.h
index 2414e5a8..d9c9f9aa 100644
--- a/src/library/sdl/sdlhooks.h
+++ b/src/library/sdl/sdlhooks.h
@@ -184,6 +184,7 @@ SDL_LINK(SDL_CreateTexture)
SDL_LINK(SDL_CreateTextureFromSurface)
SDL_LINK(SDL_LockTexture)
SDL_LINK(SDL_UnlockTexture)
+SDL_LINK(SDL_SetTextureBlendMode)
SDL_LINK(SDL_LockSurface)
SDL_LINK(SDL_UnlockSurface)
SDL_LINK(SDL_UpdateWindowSurface)
diff --git a/src/library/steam/steamapi.cpp b/src/library/steam/steamapi.cpp
index 32cafef3..1894ea33 100644
--- a/src/library/steam/steamapi.cpp
+++ b/src/library/steam/steamapi.cpp
@@ -309,7 +309,7 @@ void SteamAPI_RunCallbacks()
{
DEBUGLOGCALL(LCF_STEAM);
if (shared_config.virtual_steam)
- CCallbackManager::Run();
+ return CCallbackManager::Run();
LINK_NAMESPACE(SteamAPI_RunCallbacks, "steam_api");
return orig::SteamAPI_RunCallbacks();
@@ -319,7 +319,7 @@ void SteamAPI_RegisterCallback( CCallbackBase *pCallback, enum steam_callback_ty
{
debuglogstdio(LCF_STEAM, "%s called with type %d", __func__, iCallback);
if (shared_config.virtual_steam)
- CCallbackManager::RegisterCallback(pCallback, iCallback);
+ return CCallbackManager::RegisterCallback(pCallback, iCallback);
LINK_NAMESPACE(SteamAPI_RegisterCallback, "steam_api");
return orig::SteamAPI_RegisterCallback(pCallback, iCallback);
@@ -329,7 +329,7 @@ void SteamAPI_UnregisterCallback( CCallbackBase *pCallback )
{
DEBUGLOGCALL(LCF_STEAM);
if (shared_config.virtual_steam)
- CCallbackManager::UnregisterCallback(pCallback);
+ return CCallbackManager::UnregisterCallback(pCallback);
LINK_NAMESPACE(SteamAPI_UnregisterCallback, "steam_api");
return orig::SteamAPI_UnregisterCallback(pCallback);
@@ -339,7 +339,7 @@ void SteamAPI_RegisterCallResult( CCallbackBase *pCallback, SteamAPICall_t hAPIC
{
DEBUGLOGCALL(LCF_STEAM);
if (shared_config.virtual_steam)
- CCallbackManager::RegisterApiCallResult(pCallback, hAPICall);
+ return CCallbackManager::RegisterApiCallResult(pCallback, hAPICall);
LINK_NAMESPACE(SteamAPI_RegisterCallResult, "steam_api");
return orig::SteamAPI_RegisterCallResult(pCallback, hAPICall);
@@ -349,7 +349,7 @@ void SteamAPI_UnregisterCallResult( CCallbackBase *pCallback, SteamAPICall_t hAP
{
DEBUGLOGCALL(LCF_STEAM);
if (shared_config.virtual_steam)
- CCallbackManager::UnregisterApiCallResult(pCallback, hAPICall);
+ return CCallbackManager::UnregisterApiCallResult(pCallback, hAPICall);
LINK_NAMESPACE(SteamAPI_UnregisterCallResult, "steam_api");
return orig::SteamAPI_UnregisterCallResult(pCallback, hAPICall);
diff --git a/src/library/steam/steamapiinternal.cpp b/src/library/steam/steamapiinternal.cpp
index fe15aa0a..2475db99 100644
--- a/src/library/steam/steamapiinternal.cpp
+++ b/src/library/steam/steamapiinternal.cpp
@@ -30,6 +30,7 @@ DEFINE_ORIG_POINTER(SteamAPI_GetHSteamUser)
DEFINE_ORIG_POINTER(SteamAPI_GetHSteamPipe)
DEFINE_ORIG_POINTER(SteamInternal_ContextInit)
DEFINE_ORIG_POINTER(SteamInternal_CreateInterface)
+DEFINE_ORIG_POINTER(SteamInternal_FindOrCreateUserInterface)
DEFINE_ORIG_POINTER(_ZN16CSteamAPIContext4InitEv)
HSteamUser SteamAPI_GetHSteamUser()
@@ -56,30 +57,25 @@ HSteamPipe SteamAPI_GetHSteamPipe()
return true;
}
-void * SteamInternal_ContextInit( void *pContextInitData )
+CSteamAPIContext* SteamInternal_ContextInit( CSteamAPIContextInitData *data )
{
DEBUGLOGCALL(LCF_STEAM);
if (!shared_config.virtual_steam) {
LINK_NAMESPACE(SteamInternal_ContextInit, "steam_api");
- return orig::SteamInternal_ContextInit(pContextInitData);
+ return orig::SteamInternal_ContextInit(data);
}
- static CSteamAPIContext context;
- GlobalNoLog gnl;
- context.m_pSteamClient = SteamClient();
- context.m_pSteamUser = SteamUser();
- context.m_pSteamUserStats = SteamUserStats();
- context.m_pSteamUtils = SteamUtils();
- context.m_pSteamRemoteStorage = SteamRemoteStorage();
- context.m_pSteamApps = SteamApps();
- context.m_pSteamFriends = SteamFriends();
- context.m_pSteamScreenshots = SteamScreenshots();
- context.m_pSteamUGC = SteamUGC();
- context.m_pSteamMatchmaking = SteamMatchmaking();
- context.m_pSteamMatchmakingServers = SteamMatchmakingServers();
- context.m_pSteamHTTP = SteamHTTP();
- context.m_pSteamNetworking = SteamNetworking();
- return &context;
+ /* Should be incremented on API/GameServer Init/Shutdown. */
+ const uintptr_t ifaces_stale_cnt = 1;
+ if (data->ifaces_stale_cnt != ifaces_stale_cnt)
+ {
+ if (data->callback)
+ data->callback(&data->ctx);
+
+ data->ifaces_stale_cnt = ifaces_stale_cnt;
+ }
+
+ return &data->ctx;
}
void * SteamInternal_CreateInterface( const char *ver )
@@ -107,6 +103,31 @@ void * SteamInternal_CreateInterface( const char *ver )
return nullptr;
}
+void * SteamInternal_FindOrCreateUserInterface(HSteamUser steam_user, const char *version)
+{
+ debuglogstdio(LCF_STEAM, "%s called with version %s", __func__, version);
+ if (!shared_config.virtual_steam) {
+ LINK_NAMESPACE(SteamInternal_FindOrCreateUserInterface, "steam_api");
+ return orig::SteamInternal_FindOrCreateUserInterface(steam_user, version);
+ }
+
+ /* The expected return from this function is a pointer to a C++ class with
+ * specific virtual functions. The format of our argument is the name
+ * of the corresponding C function that has already been hooked to return
+ * the correct value, followed by some numbers that are probably used for
+ * version checking. As a quick hack, just lookup the symbol and call it.
+ */
+ std::string symbol = version;
+ /* Strip numbers at the end */
+ auto end = symbol.find_last_not_of("0123456789");
+ if (end != std::string::npos)
+ symbol.resize(end + 1);
+ void *(*func)() = reinterpret_cast<void *(*)()>(dlsym(RTLD_DEFAULT, symbol.c_str()));
+ if (func)
+ return func();
+ return nullptr;
+}
+
bool _ZN16CSteamAPIContext4InitEv(CSteamAPIContext* context)
{
DEBUGLOGCALL(LCF_STEAM);
@@ -128,6 +149,16 @@ bool _ZN16CSteamAPIContext4InitEv(CSteamAPIContext* context)
context->m_pSteamMatchmaking = SteamMatchmaking();
context->m_pSteamMatchmakingServers = SteamMatchmakingServers();
context->m_pSteamHTTP = SteamHTTP();
+ context->m_pSteamNetworking = SteamNetworking();
+ context->m_pController = SteamController();
+ context->m_pSteamAppList = nullptr;
+ context->m_pSteamMusic = nullptr;
+ context->m_pSteamMusicRemote = nullptr;
+ context->m_pSteamHTMLSurface = nullptr;
+ context->m_pSteamInventory = nullptr;
+ context->m_pSteamVideo = nullptr;
+ context->m_pSteamParentalSettings = nullptr;
+
return true;
}
diff --git a/src/library/steam/steamapiinternal.h b/src/library/steam/steamapiinternal.h
index 50a38dd9..af95324c 100644
--- a/src/library/steam/steamapiinternal.h
+++ b/src/library/steam/steamapiinternal.h
@@ -25,19 +25,6 @@
namespace libtas {
-OVERRIDE HSteamUser SteamAPI_GetHSteamUser();
-OVERRIDE HSteamPipe SteamAPI_GetHSteamPipe();
-OVERRIDE void * SteamInternal_ContextInit( void *pContextInitData );
-OVERRIDE void * SteamInternal_CreateInterface( const char *ver );
-
-typedef void ISteamAppList;
-typedef void ISteamMusic;
-typedef void ISteamMusicRemote;
-typedef void ISteamHTMLSurface;
-typedef void ISteamInventory;
-typedef void ISteamVideo;
-typedef void ISteamParentalSettings;
-
// CSteamAPIContext encapsulates the Steamworks API global accessors into
// a single object. This is DEPRECATED and only remains for compatibility.
class CSteamAPIContext
@@ -66,6 +53,27 @@ public:
ISteamParentalSettings *m_pSteamParentalSettings;
};
+struct CSteamAPIContextInitData
+{
+ void (*callback)(CSteamAPIContext *ctx);
+ uintptr_t ifaces_stale_cnt;
+ CSteamAPIContext ctx;
+};
+
+OVERRIDE HSteamUser SteamAPI_GetHSteamUser();
+OVERRIDE HSteamPipe SteamAPI_GetHSteamPipe();
+OVERRIDE CSteamAPIContext* SteamInternal_ContextInit( CSteamAPIContextInitData *pContextInitData );
+OVERRIDE void * SteamInternal_CreateInterface( const char *ver );
+OVERRIDE void * SteamInternal_FindOrCreateUserInterface(HSteamUser steam_user, const char *version);
+
+typedef void ISteamAppList;
+typedef void ISteamMusic;
+typedef void ISteamMusicRemote;
+typedef void ISteamHTMLSurface;
+typedef void ISteamInventory;
+typedef void ISteamVideo;
+typedef void ISteamParentalSettings;
+
/* Override method CSteamAPIContext::Init() */
OVERRIDE bool _ZN16CSteamAPIContext4InitEv(CSteamAPIContext* context);
diff --git a/src/library/systemwrappers.cpp b/src/library/systemwrappers.cpp
index cac7fd50..62f04988 100644
--- a/src/library/systemwrappers.cpp
+++ b/src/library/systemwrappers.cpp
@@ -51,7 +51,7 @@ DEFINE_ORIG_POINTER(fork)
void* return_address = __builtin_return_address(0);
char** symbols = backtrace_symbols(&return_address, 1);
if (symbols != nullptr) {
- if (strstr(symbols[0], "libhl.so"))
+ if (strstr(symbols[0], "libhl.so") || strstr(symbols[0], "PapersPlease(+0x"))
pid = 1234;
free(symbols);
}
diff --git a/src/library/timewrappers.cpp b/src/library/timewrappers.cpp
index ed738f24..fa8c2fdc 100644
--- a/src/library/timewrappers.cpp
+++ b/src/library/timewrappers.cpp
@@ -24,6 +24,8 @@
#include "DeterministicTimer.h"
#include "GlobalState.h"
#include "../shared/SharedConfig.h"
+#include "GameHacks.h"
+#include <execinfo.h>
namespace libtas {
@@ -66,6 +68,50 @@ DEFINE_ORIG_POINTER(clock_gettime)
}
DEBUGLOGCALL(LCF_TIMEGET | LCF_FREQUENT);
+
+ /* .NET coreclr computes several speed chekcs at startup.
+ * Because we don't advance time, it causes a softlock.
+ * In this specific case, we advance time to account for this.
+ * Getting the caller function is very costly, so we only do it when
+ * `libcoreclr.so` has been linked, and on first frame. */
+ if (framecount < 4 && GameHacks::hasCoreclr()) {
+
+ /* .NET coreclr computes at startup how much time does a `yield` takes
+ * in the Finalizer thread.
+ * <https://github.com/dotnet/runtime/blob/140120290aaaffb40e90e8ece982b4f0170c6700/src/coreclr/vm/yieldprocessornormalized.cpp#L46>
+ */
+ if (GameHacks::getFinalizerThread() == ThreadManager::getThreadTid()) {
+ void* return_address = __builtin_return_address(0);
+ char** symbols = backtrace_symbols(&return_address, 1);
+ debuglogstdio(LCF_TIMEGET | LCF_ERROR, " getting call symbol: %s", symbols[0]);
+ if (symbols != nullptr) {
+ if (strstr(symbols[0], "libcoreclr.so")) {
+ debuglogstdio(LCF_TIMEGET | LCF_FREQUENT | LCF_ERROR, " special advance coreclr yield");
+ struct timespec ts = {0, 1000000};
+ detTimer.addDelay(ts);
+ }
+ free(symbols);
+ }
+ }
+
+ /* .NET coreclr computes at startup how much time does process id and TLS take
+ * <https://github.com/dotnet/runtime/blob/140120290aaaffb40e90e8ece982b4f0170c6700/src/coreclr/System.Private.CoreLib/src/System/Threading/ProcessorIdCache.cs#L58>
+ */
+ if (ThreadManager::isMainThread()) {
+ void* return_address = __builtin_return_address(0);
+ char** symbols = backtrace_symbols(&return_address, 1);
+ debuglogstdio(LCF_TIMEGET | LCF_ERROR, " getting call symbol: %s", symbols[0]);
+ if (symbols != nullptr) {
+ if (strstr(symbols[0], "libSystem.Native.so")) {
+ debuglogstdio(LCF_TIMEGET | LCF_FREQUENT | LCF_ERROR, " special advance coreclr TLS");
+ struct timespec ts = {0, 1000000};
+ detTimer.addDelay(ts);
+ }
+ free(symbols);
+ }
+ }
+ }
+
*tp = detTimer.getTicks(SharedConfig::TIMETYPE_CLOCKGETTIME);
debuglogstdio(LCF_TIMEGET | LCF_FREQUENT, " returning %d.%09d", tp->tv_sec, tp->tv_nsec);
diff --git a/src/program/Config.cpp b/src/program/Config.cpp
index a0b578f8..2f5893f4 100644
--- a/src/program/Config.cpp
+++ b/src/program/Config.cpp
@@ -58,6 +58,8 @@ void Config::save(const std::string& gamepath) {
}
general_settings.endArray();
+ general_settings.setValue("debugger", debugger);
+
/* Open the preferences for the game */
QSettings settings(iniPath(gamepath), QSettings::IniFormat);
settings.setFallbacksEnabled(false);
@@ -174,6 +176,12 @@ void Config::load(const std::string& gamepath) {
}
general_settings.endArray();
+#ifdef __unix__
+ debugger = general_settings.value("debugger", debugger).toInt();
+#elif defined(__APPLE__) && defined(__MACH__)
+ debugger = DEBUGGER_LLDB;
+#endif
+
if (gamepath.empty())
return;
diff --git a/src/program/Config.h b/src/program/Config.h
index d0f7c852..a1daa1ff 100644
--- a/src/program/Config.h
+++ b/src/program/Config.h
@@ -130,6 +130,17 @@ public:
/* Load a game-specific config from the config file */
void load(const std::string& gamepath);
+ enum Debugger {
+ DEBUGGER_GDB = 0,
+ DEBUGGER_LLDB = 1,
+ };
+
+#ifdef __unix__
+ int debugger = DEBUGGER_GDB;
+#elif defined(__APPLE__) && defined(__MACH__)
+ int debugger = DEBUGGER_LLDB;
+#endif
+
private:
QString iniPath(const std::string& gamepath) const;
};
diff --git a/src/program/Context.h b/src/program/Context.h
index ed5cf8b7..40f59e0a 100644
--- a/src/program/Context.h
+++ b/src/program/Context.h
@@ -82,9 +82,12 @@ struct Context {
/* config */
Config config;
- /* Absolute path of libTAS.so */
+ /* Absolute path of libtas.so */
std::string libtaspath;
+ /* Absolute path of libtas32.so */
+ std::string libtas32path;
+
/* Absolute path of the game executable */
std::string gamepath;
diff --git a/src/program/GameThread.cpp b/src/program/GameThread.cpp
index be47f42d..1a13820d 100644
--- a/src/program/GameThread.cpp
+++ b/src/program/GameThread.cpp
@@ -95,9 +95,7 @@ void GameThread::launch(Context *context)
/* Switch to libtas32.so if required */
if (((gameArch == BT_ELF32) || (gameArch == BT_PE32)) && (libtasArch == BT_ELF64)) {
- std::string libname("libtas.so");
- size_t pos = context->libtaspath.find(libname);
- context->libtaspath.replace(pos, libname.length(), "libtas32.so");
+ context->libtaspath = context->libtas32path;
/* libtas32.so presence was already checked in ui/ErrorChecking.cpp */
libtasArch = extractBinaryType(context->libtaspath);
}
@@ -189,11 +187,17 @@ void GameThread::launch(Context *context)
}
else {
if (context->attach_gdb) {
-#ifdef __unix__
- std::string cmd = "which gdb";
-#elif defined(__APPLE__) && defined(__MACH__)
- std::string cmd = "which lldb";
-#endif
+ std::string cmd;
+
+ switch (context->config.debugger) {
+ case Config::DEBUGGER_GDB:
+ cmd = "which gdb";
+ break;
+ case Config::DEBUGGER_LLDB:
+ cmd = "which lldb";
+ break;
+ }
+
FILE *output = popen(cmd.c_str(), "r");
std::array<char,256> buf;
fgets(buf.data(), buf.size(), output);
@@ -204,57 +208,68 @@ void GameThread::launch(Context *context)
arg_list.push_back(dbgpath);
/* Push debugger arguments */
-#ifdef __unix__
- arg_list.push_back("-q");
- arg_list.push_back("-ex");
-
- /* LD_PRELOAD must be set inside a gdb
- * command to be effective */
- std::string ldpreloadstr = "set exec-wrapper env 'LD_PRELOAD=";
- ldpreloadstr += context->libtaspath;
- if (!context->old_ld_preload.empty()) {
- ldpreloadstr += ":";
- ldpreloadstr += context->old_ld_preload;
+ switch (context->config.debugger) {
+ case Config::DEBUGGER_GDB: {
+ arg_list.push_back("-q");
+ arg_list.push_back("-ex");
+
+ /* LD_PRELOAD must be set inside a gdb
+ * command to be effective */
+ std::string ldpreloadstr = "set exec-wrapper env 'LD_PRELOAD=";
+ ldpreloadstr += context->libtaspath;
+ if (!context->old_ld_preload.empty()) {
+ ldpreloadstr += ":";
+ ldpreloadstr += context->old_ld_preload;
+ }
+ ldpreloadstr += "'";
+ arg_list.push_back(ldpreloadstr);
+
+ /* We are using SIGSYS and SIGXFSZ for savestates, so don't
+ * print and pause when one signal is sent *
+ * Signals SIGPWR SIGXCPU SIG35 and SIG36 are used a lot in some games */
+ arg_list.push_back("-ex");
+ arg_list.push_back("handle SIGSYS SIGXFSZ SIGUSR1 SIGUSR2 SIGPWR SIGXCPU SIG35 SIG36 nostop noprint");
+ arg_list.push_back("-ex");
+ arg_list.push_back("run");
+ arg_list.push_back("--args");
+
+ break;
}
- ldpreloadstr += "'";
- arg_list.push_back(ldpreloadstr);
-
- /* We are using SIGSYS and SIGXFSZ for savestates, so don't
- * print and pause when one signal is sent *
- * Signals SIGPWR SIGXCPU SIG35 and SIG36 are used a lot in some games */
- arg_list.push_back("-ex");
- arg_list.push_back("handle SIGSYS SIGXFSZ SIGUSR1 SIGUSR2 SIGPWR SIGXCPU SIG35 SIG36 nostop noprint");
- arg_list.push_back("-ex");
- arg_list.push_back("run");
- arg_list.push_back("--args");
+ case Config::DEBUGGER_LLDB: {
+ arg_list.push_back("-o");
+ /* LD_PRELOAD/DYLD_INSERT_LIBRARIES must be set inside an lldb
+ * command to be effective */
+#ifdef __unix__
+ std::string ldpreloadstr = "set se target.env-vars 'LD_PRELOAD=";
#elif defined(__APPLE__) && defined(__MACH__)
+ std::string ldpreloadstr = "set se target.env-vars 'DYLD_INSERT_LIBRARIES=";
+#endif
+ ldpreloadstr += context->libtaspath;
+ if (!context->old_ld_preload.empty()) {
+ ldpreloadstr += ":";
+ ldpreloadstr += context->old_ld_preload;
+ }
+ ldpreloadstr += "'";
+ arg_list.push_back(ldpreloadstr);
- arg_list.push_back("-o");
+#if defined(__APPLE__) && defined(__MACH__)
+ arg_list.push_back("-o");
+ arg_list.push_back("set se target.env-vars 'DYLD_FORCE_FLAT_NAMESPACE=1'");
+#endif
- /* DYLD_INSERT_LIBRARIES must be set inside a lldb
- * command to be effective */
- std::string ldpreloadstr = "set se target.env-vars 'DYLD_INSERT_LIBRARIES=";
- ldpreloadstr += context->libtaspath;
- if (!context->old_ld_preload.empty()) {
- ldpreloadstr += ":";
- ldpreloadstr += context->old_ld_preload;
+ /* We are using SIGSYS and SIGXFSZ for savestates, so don't
+ * print and pause when one signal is sent */
+ arg_list.push_back("-o");
+ arg_list.push_back("run");
+ /* Signal handling cannot be performed in llvm before the process has started */
+// arg_list.push_back("-o");
+// arg_list.push_back("process handle -n false -p false -s false SIGSYS SIGXFSZ SIGUSR1 SIGUSR2 SIGXCPU");
+ arg_list.push_back("--");
+
+ break;
+ }
}
- ldpreloadstr += "'";
- arg_list.push_back(ldpreloadstr);
-
- arg_list.push_back("-o");
- arg_list.push_back("set se target.env-vars 'DYLD_FORCE_FLAT_NAMESPACE=1'");
-
- /* We are using SIGSYS and SIGXFSZ for savestates, so don't
- * print and pause when one signal is sent */
- arg_list.push_back("-o");
- arg_list.push_back("run");
- /* Signal handling cannot be performed in llvm before the process has started */
-// arg_list.push_back("-o");
-// arg_list.push_back("process handle -n false -p false -s false SIGSYS SIGXFSZ SIGUSR1 SIGUSR2 SIGXCPU");
- arg_list.push_back("--");
-#endif
}
/* Tell SDL >= 2.0.2 to let us override functions even if it is statically linked.
diff --git a/src/program/KeyMappingQuartz.mm b/src/program/KeyMappingQuartz.mm
index f76e6cf1..d8ba3d28 100644
--- a/src/program/KeyMappingQuartz.mm
+++ b/src/program/KeyMappingQuartz.mm
@@ -416,7 +416,7 @@ void KeyMappingQuartz::initKeyboardLayout()
keyboard_layout[kc] = char_to_xcb_keycode[t].keysym;
/* Check if we have a description string of the key */
- const char* str = KEYSYM_TO_DESC_MISC(si.value);
+ const char* str = KEYSYM_TO_DESC_MISC(keyboard_layout[kc]);
if (str) {
/* Insert key in the misc list */
SingleInput si;
@@ -435,7 +435,7 @@ void KeyMappingQuartz::initKeyboardLayout()
keyboard_layout[kc] = (ch & 0xff);
/* Check if we have a description string of the key */
- const char* str = KEYSYM_TO_DESC_LATIN(si.value);
+ const char* str = KEYSYM_TO_DESC_LATIN(keyboard_layout[kc]);
if (str) {
/* Insert key in the ascii list */
SingleInput si;
diff --git a/src/program/KeyMappingXcb.cpp b/src/program/KeyMappingXcb.cpp
index 52f5c3d7..6c72dfd3 100644
--- a/src/program/KeyMappingXcb.cpp
+++ b/src/program/KeyMappingXcb.cpp
@@ -169,14 +169,24 @@ void KeyMappingXcb::base_keysyms()
xcb_get_keyboard_mapping_cookie_t keyboard_mapping_cookie = xcb_get_keyboard_mapping(conn, min_keycode, max_keycode - min_keycode + 1);
xcb_get_keyboard_mapping_reply_t* keyboard_mapping = xcb_get_keyboard_mapping_reply(conn, keyboard_mapping_cookie, nullptr);
xcb_keysym_t* keyboard_keysyms = xcb_get_keyboard_mapping_keysyms(keyboard_mapping);
+ int keysym_length = xcb_get_keyboard_mapping_keysyms_length(keyboard_mapping);
- for (int kc=0; kc<xcb_get_keyboard_mapping_keysyms_length(keyboard_mapping); kc+=keyboard_mapping->keysyms_per_keycode) {
+ for (int kc=0; kc<keysym_length; kc+=keyboard_mapping->keysyms_per_keycode) {
for (int k=0; k<keyboard_mapping->keysyms_per_keycode; k++) {
xcb_keysym_t ks = keyboard_keysyms[kc + k];
if (ks == XCB_NO_SYMBOL) continue;
- keysym_mapping[ks] = keyboard_keysyms[kc];
+ /* Some modifiers switch my azerty layout into qwerty, so we
+ * prioritize keysyms that are mapped to themselves. */
+
+ if (ks == keyboard_keysyms[kc])
+ keysym_mapping[ks] = ks;
+ else {
+ if (keysym_mapping.find(ks) == keysym_mapping.end()) {
+ keysym_mapping[ks] = keyboard_keysyms[kc];
+ }
+ }
}
}
diff --git a/src/program/main.cpp b/src/program/main.cpp
index d3990f48..f1e77281 100644
--- a/src/program/main.cpp
+++ b/src/program/main.cpp
@@ -64,6 +64,8 @@ static void print_usage(void)
std::cout << " -r, --read MOVIE Play game inputs from MOVIE file" << std::endl;
std::cout << " -w, --write MOVIE Record game inputs into the specified MOVIE file" << std::endl;
std::cout << " -n, --non-interactive Don't offer any interactive choice, so that it can run headless" << std::endl;
+ std::cout << " --libtas-so-path Path to libtas.so (equivalent to setting LIBTAS_SO_PATH)" << std::endl;
+ std::cout << " --libtas32-so-path Path to libtas32.so (equivalent to setting LIBTAS32_SO_PATH)" << std::endl;
std::cout << " -h, --help Show this message" << std::endl;
}
@@ -95,6 +97,8 @@ int main(int argc, char **argv)
{"write", required_argument, nullptr, 'w'},
{"dump", required_argument, nullptr, 'd'},
{"non-interactive", no_argument, nullptr, 'n'},
+ {"libtas-so-path", required_argument, nullptr, 'p'},
+ {"libtas32-so-path", required_argument, nullptr, 'P'},
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0}
};
@@ -122,6 +126,18 @@ int main(int argc, char **argv)
case 'n':
context.interactive = false;
break;
+ case 'p':
+ abspath = realpath_nonexist(optarg);
+ if (!abspath.empty()) {
+ context.libtaspath = abspath;
+ }
+ break;
+ case 'P':
+ abspath = realpath_nonexist(optarg);
+ if (!abspath.empty()) {
+ context.libtas32path = abspath;
+ }
+ break;
case '?':
std::cout << "Unknown option character" << std::endl;
break;
@@ -194,24 +210,55 @@ int main(int argc, char **argv)
context.config.km = new KeyMappingQuartz(nullptr);
#endif
- /* libTAS.so path */
+ /* libtas.so path */
/* TODO: Not portable! */
+ if (context.libtaspath.empty()) {
+ char *libtaspath_from_env = getenv("LIBTAS_SO_PATH");
+ if (libtaspath_from_env) {
+ abspath = realpath_nonexist(libtaspath_from_env);
+ if (!abspath.empty()) {
+ context.libtaspath = abspath;
+ }
+ }
+ }
+ if (context.libtaspath.empty()) {
#ifdef __unix__
- ssize_t count = readlink( "/proc/self/exe", buf, PATH_MAX );
- std::string binpath = std::string( buf, (count > 0) ? count : 0 );
- char* binpathptr = const_cast<char*>(binpath.c_str());
- context.libtaspath = dirname(binpathptr);
- context.libtaspath += "/libtas.so";
+ ssize_t count = readlink( "/proc/self/exe", buf, PATH_MAX );
+ std::string binpath = std::string( buf, (count > 0) ? count : 0 );
+ char* binpathptr = const_cast<char*>(binpath.c_str());
+ context.libtaspath = dirname(binpathptr);
+ context.libtaspath += "/libtas.so";
#elif defined(__APPLE__) && defined(__MACH__)
- uint32_t size = 4096;
- if (_NSGetExecutablePath(buf, &size) == 0)
- context.libtaspath = dirname(buf);
- else {
- std::cerr << "Could not get path of libTAS executable" << std::endl;
- exit(0);
- }
- context.libtaspath += "/libtas.dylib";
+ uint32_t size = 4096;
+ if (_NSGetExecutablePath(buf, &size) == 0)
+ context.libtaspath = dirname(buf);
+ else {
+ std::cerr << "Could not get path of libTAS executable" << std::endl;
+ exit(0);
+ }
+ context.libtaspath += "/libtas.dylib";
#endif
+ }
+
+ /* libtas32.so path */
+ if (context.libtas32path.empty()) {
+ char *libtas32path_from_env = getenv("LIBTAS32_SO_PATH");
+ if (libtas32path_from_env) {
+ abspath = realpath_nonexist(libtas32path_from_env);
+ if (!abspath.empty()) {
+ context.libtas32path = abspath;
+ }
+ }
+ }
+ if (context.libtas32path.empty()) {
+ std::string lib32path = context.libtaspath;
+ std::string libname("libtas.so");
+ size_t pos = context.libtaspath.find(libname);
+ if (pos != std::string::npos) {
+ lib32path.replace(pos, libname.length(), "libtas32.so");
+ context.libtas32path = lib32path;
+ }
+ }
/* Create the working directories */
char *path = getenv("XDG_CONFIG_HOME");
diff --git a/src/program/ui/ControllerTabWindow.cpp b/src/program/ui/ControllerTabWindow.cpp
index 2a0b430e..66b6f69e 100644
--- a/src/program/ui/ControllerTabWindow.cpp
+++ b/src/program/ui/ControllerTabWindow.cpp
@@ -24,6 +24,8 @@
#include <QtWidgets/QLabel>
#include "ControllerTabWindow.h"
+#include "ControllerAxisWidget.h"
+#include "ControllerWidget.h"
#include "../GameLoop.h"
#include "../GameEvents.h"
#include "MainWindow.h"
diff --git a/src/program/ui/ControllerTabWindow.h b/src/program/ui/ControllerTabWindow.h
index 58aa2f26..17887ae1 100644
--- a/src/program/ui/ControllerTabWindow.h
+++ b/src/program/ui/ControllerTabWindow.h
@@ -25,10 +25,11 @@
#include <QtWidgets/QSpinBox>
#include <QtWidgets/QSlider>
-#include "ControllerWidget.h"
#include "../Context.h"
#include "../../shared/AllInputs.h"
+class ControllerWidget;
+
class ControllerTabWindow : public QDialog {
Q_OBJECT
diff --git a/src/program/ui/ControllerWidget.cpp b/src/program/ui/ControllerWidget.cpp
index 90458f30..ea4f3a41 100644
--- a/src/program/ui/ControllerWidget.cpp
+++ b/src/program/ui/ControllerWidget.cpp
@@ -24,7 +24,7 @@
#include <QtWidgets/QLabel>
#include "ControllerWidget.h"
-// #include "../../shared/AllInputs.h"
+#include "ControllerAxisWidget.h"
ControllerWidget::ControllerWidget(QWidget *parent) : QWidget(parent)
{
diff --git a/src/program/ui/ControllerWidget.h b/src/program/ui/ControllerWidget.h
index 5abd92e4..b1a865b1 100644
--- a/src/program/ui/ControllerWidget.h
+++ b/src/program/ui/ControllerWidget.h
@@ -25,7 +25,7 @@
#include <QtWidgets/QSpinBox>
#include <QtWidgets/QSlider>
-#include "ControllerAxisWidget.h"
+class ControllerAxisWidget;
class ControllerWidget : public QWidget {
Q_OBJECT
diff --git a/src/program/ui/EncodeWindow.cpp b/src/program/ui/EncodeWindow.cpp
index b2555c76..01e9e553 100644
--- a/src/program/ui/EncodeWindow.cpp
+++ b/src/program/ui/EncodeWindow.cpp
@@ -137,7 +137,11 @@ void EncodeWindow::update_config()
ffmpegOptions->setText(context->config.ffmpegoptions.c_str());
/* Set video framerate */
- videoFramerate->setValue(context->config.sc.video_framerate);
+ videoFramerate->setEnabled(context->config.sc.variable_framerate);
+ if (context->config.sc.variable_framerate)
+ videoFramerate->setValue(context->config.sc.video_framerate);
+ else
+ videoFramerate->setValue(0);
if (context->config.ffmpegoptions.empty()) {
slotUpdate();
diff --git a/src/program/ui/ErrorChecking.cpp b/src/program/ui/ErrorChecking.cpp
index 0a1241cb..817b9e89 100644
--- a/src/program/ui/ErrorChecking.cpp
+++ b/src/program/ui/ErrorChecking.cpp
@@ -125,7 +125,7 @@ bool ErrorChecking::checkArchType(Context* context)
/* Checking that the libtas.so library path is correct */
if (access(context->libtaspath.c_str(), F_OK) != 0) {
- critical(QString("libtas.so library at %1 was not found. Make sure that the file libtas.so is in the same directory as libTAS file").arg(context->libtaspath.c_str()), context->interactive);
+ critical(QString("libtas.so library at %1 was not found. Make sure that the libtas.so file is in the same directory as the libTAS executable").arg(context->libtaspath.c_str()), context->interactive);
return false;
}
@@ -163,15 +163,14 @@ bool ErrorChecking::checkArchType(Context* context)
/* Check for a possible libtas alternate file */
if (((gameArch == BT_ELF32) || (gameArch == BT_PE32)) && (libtasArch == BT_ELF64)) {
- std::string lib32path = context->libtaspath;
- std::string libname("libtas.so");
- size_t pos = context->libtaspath.find(libname);
- lib32path.replace(pos, libname.length(), "libtas32.so");
-
- /* Checking that libtas32.so exists */
- if (access(lib32path.c_str(), F_OK) == 0) {
- /* Just in case, check the arch */
- libtasArch = extractBinaryType(lib32path);
+ if (context->libtas32path.empty()) {
+ critical(QString("Trying to launch a 32-bit game with a 64-bit build of libTAS, but libTAS couldn't guess the path to libtas32.so. Use --libtas32-so-path (see --help)"), context->interactive);
+ return false;
+ } else if (access(context->libtas32path.c_str(), F_OK) != 0) {
+ critical(QString("Trying to launch a 32-bit game with a 64-bit build of libTAS, but no libtas32.so library could be found at %1. Make sure that libTAS was built with dual-arch support and that the libtas32.so file is in the same directory as the libTAS executable").arg(context->libtas32path.c_str()), context->interactive);
+ return false;
+ } else {
+ libtasArch = extractBinaryType(context->libtas32path);
}
}
@@ -201,19 +200,29 @@ bool ErrorChecking::checkArchType(Context* context)
/* Check for gdb presence in case of Start and attach gdb */
if (context->attach_gdb) {
- std::string cmd = "which gdb";
+ std::string cmd;
+
+ switch (context->config.debugger) {
+ case Config::DEBUGGER_GDB:
+ cmd = "which gdb";
+ break;
+ case Config::DEBUGGER_LLDB:
+ cmd = "which lldb";
+ break;
+ }
+
FILE *output = popen(cmd.c_str(), "r");
if (output != NULL) {
std::array<char,256> buf;
fgets(buf.data(), buf.size(), output);
int ret = pclose(output);
if (ret != 0) {
- critical(QString("Trying to start a game with attached gdb, but gdb cannot be found"), context->interactive);
+ critical(QString("Trying to start a game with attached debugger, but debugger cannot be found"), context->interactive);
return false;
}
}
else {
- critical(QString("Coundn't popen to locate gdb"), context->interactive);
+ critical(QString("Coundn't popen to locate debugger"), context->interactive);
return false;
}
}
diff --git a/src/program/ui/InputEditorView.cpp b/src/program/ui/InputEditorView.cpp
index 5e2a85fa..3b5ec420 100644
--- a/src/program/ui/InputEditorView.cpp
+++ b/src/program/ui/InputEditorView.cpp
@@ -25,6 +25,7 @@
#include <stdint.h>
#include "InputEditorView.h"
+#include "InputEditorModel.h"
#include "MainWindow.h"
#include "qtutils.h"
diff --git a/src/program/ui/InputEditorView.h b/src/program/ui/InputEditorView.h
index 5596cf8e..92e4a374 100644
--- a/src/program/ui/InputEditorView.h
+++ b/src/program/ui/InputEditorView.h
@@ -23,10 +23,11 @@
#include <QtWidgets/QTableView>
#include <QtWidgets/QMenu>
-#include "InputEditorModel.h"
#include "../Context.h"
#include "KeyPressedDialog.h"
+class InputEditorModel;
+
class InputEditorView : public QTableView {
Q_OBJECT
diff --git a/src/program/ui/InputEditorWindow.cpp b/src/program/ui/InputEditorWindow.cpp
index 78fca430..10ca3e92 100644
--- a/src/program/ui/InputEditorWindow.cpp
+++ b/src/program/ui/InputEditorWindow.cpp
@@ -22,6 +22,7 @@
#include <QtWidgets/QMenu>
#include "InputEditorWindow.h"
+#include "InputEditorView.h"
#include "MainWindow.h"
InputEditorWindow::InputEditorWindow(Context* c, QWidget *parent) : QMainWindow(parent), context(c)
diff --git a/src/program/ui/InputEditorWindow.h b/src/program/ui/InputEditorWindow.h
index 8f3c0c03..f315f96f 100644
--- a/src/program/ui/InputEditorWindow.h
+++ b/src/program/ui/InputEditorWindow.h
@@ -23,9 +23,10 @@
#include <QtWidgets/QDialog>
#include <QtWidgets/QMainWindow>
-#include "InputEditorView.h"
#include "../Context.h"
+class InputEditorView;
+
class InputEditorWindow : public QMainWindow {
Q_OBJECT
diff --git a/src/program/ui/InputWindow.cpp b/src/program/ui/InputWindow.cpp
index 354c8082..f77728ca 100644
--- a/src/program/ui/InputWindow.cpp
+++ b/src/program/ui/InputWindow.cpp
@@ -26,6 +26,7 @@
#include <QtWidgets/QTabWidget>
#include "InputWindow.h"
+#include "KeyPressedDialog.h"
InputWindow::InputWindow(Context* c, QWidget *parent) : QDialog(parent), context(c)
{
diff --git a/src/program/ui/InputWindow.h b/src/program/ui/InputWindow.h
index ca5a5c10..25b9d10b 100644
--- a/src/program/ui/InputWindow.h
+++ b/src/program/ui/InputWindow.h
@@ -25,9 +25,10 @@
#include <QtWidgets/QTableWidget>
#include "../Context.h"
-#include "KeyPressedDialog.h"
#include "../KeyMapping.h"
+class KeyPressedDialog;
+
class InputWindow : public QDialog {
Q_OBJECT
public:
diff --git a/src/program/ui/MainWindow.cpp b/src/program/ui/MainWindow.cpp
index 5afd0822..87c4191a 100644
--- a/src/program/ui/MainWindow.cpp
+++ b/src/program/ui/MainWindow.cpp
@@ -31,6 +31,22 @@
#include <QtCore/QTimer>
#include "MainWindow.h"
+#include "EncodeWindow.h"
+#include "ExecutableWindow.h"
+#include "InputWindow.h"
+#include "ControllerTabWindow.h"
+#include "GameInfoWindow.h"
+#include "GameSpecificWindow.h"
+#include "RamSearchWindow.h"
+#include "RamWatchWindow.h"
+#include "InputEditorWindow.h"
+#include "InputEditorView.h"
+#include "InputEditorModel.h"
+#include "OsdWindow.h"
+#include "AnnotationsWindow.h"
+#include "AutoSaveWindow.h"
+#include "TimeTraceWindow.h"
+#include "TimeTraceModel.h"
#include "../movie/MovieFile.h"
#include "ErrorChecking.h"
#include "../../shared/version.h"
@@ -193,12 +209,32 @@ MainWindow::MainWindow(Context* c) : QMainWindow(), context(c)
/* Buttons */
launchButton = new QPushButton(tr("Start"));
- connect(launchButton, &QAbstractButton::clicked, this, &MainWindow::slotLaunch);
+ connect(launchButton, &QAbstractButton::clicked, this, [this] { MainWindow::slotLaunch(false); });
disabledWidgetsOnStart.append(launchButton);
- launchGdbButton = new QPushButton(tr("Start and attach gdb"));
- connect(launchGdbButton, &QAbstractButton::clicked, this, &MainWindow::slotLaunch);
- disabledWidgetsOnStart.append(launchGdbButton);
+ launchGdbButton = new QToolButton();
+ launchGdbButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
+
+ launchGdbAction = new QAction(tr("Launch with GDB"), this);
+ launchLldbAction = new QAction(tr("Launch with LLDB"), this);
+
+ connect(launchGdbAction, &QAction::triggered, this, &MainWindow::slotLaunchGdb);
+ connect(launchLldbAction, &QAction::triggered, this, &MainWindow::slotLaunchLldb);
+
+ /* launchGdbButton is a special case, it's explicitly disabled along with
+ * all the other widgets on launch
+ */
+ //disabledWidgetsOnStart.append(launchGdbButton);
+
+#ifdef __unix__
+ launchGdbButton->setPopupMode(QToolButton::MenuButtonPopup);
+
+ QMenu *launchGdbButtonMenu = new QMenu();
+ launchGdbButton->setMenu(launchGdbButtonMenu);
+
+ launchGdbButtonMenu->addAction(launchGdbAction);
+ launchGdbButtonMenu->addAction(launchLldbAction);
+#endif
stopButton = new QPushButton(tr("Stop"));
connect(stopButton, &QAbstractButton::clicked, this, &MainWindow::slotStop);
@@ -344,7 +380,7 @@ MainWindow::MainWindow(Context* c) : QMainWindow(), context(c)
if (!context->interactive) {
slotPause(false);
slotFastForward(true);
- slotLaunch();
+ slotLaunch(false);
}
}
@@ -784,6 +820,11 @@ void MainWindow::createMenus()
debugMenu->addSeparator();
+ sigintAction = debugMenu->addAction(tr("Raise SIGINT upon game launch (if debugging)"));
+ sigintAction->setCheckable(true);
+
+ debugMenu->addSeparator();
+
debugMenu->addActions(loggingOutputGroup->actions());
disabledActionsOnStart.append(loggingOutputGroup->actions());
@@ -881,6 +922,8 @@ void MainWindow::updateStatus()
initialTimeSec->setValue(context->config.sc.initial_time_sec);
initialTimeNsec->setValue(context->config.sc.initial_time_nsec);
+ launchGdbButton->setEnabled(true);
+
if (context->config.sc.av_dumping) {
context->config.sc.av_dumping = false;
configEncodeAction->setEnabled(true);
@@ -913,6 +956,8 @@ void MainWindow::updateStatus()
fpsDenField->setEnabled(false);
}
+ launchGdbButton->setEnabled(false);
+
movieBox->setCheckable(false);
if (context->config.sc.recording == SharedConfig::NO_RECORDING) {
movieBox->setEnabled(false);
@@ -1238,6 +1283,15 @@ void MainWindow::updateUIFromConfig()
setRadioFromList(movieEndGroup, context->config.on_movie_end);
+ switch (context->config.debugger) {
+ case Config::DEBUGGER_GDB:
+ launchGdbButton->setDefaultAction(launchGdbAction);
+ break;
+ case Config::DEBUGGER_LLDB:
+ launchGdbButton->setDefaultAction(launchLldbAction);
+ break;
+ }
+
updateStatusBar();
}
@@ -1263,12 +1317,25 @@ void MainWindow::updateStatusBar()
}
}
-void MainWindow::slotLaunch()
+void MainWindow::slotLaunchGdb() {
+ context->config.debugger = Config::DEBUGGER_GDB;
+ launchGdbButton->setDefaultAction(launchGdbAction);
+
+ slotLaunch(true);
+}
+
+void MainWindow::slotLaunchLldb() {
+ context->config.debugger = Config::DEBUGGER_LLDB;
+ launchGdbButton->setDefaultAction(launchLldbAction);
+
+ slotLaunch(true);
+}
+
+void MainWindow::slotLaunch(bool attach_gdb)
{
/* Do we attach gdb ? */
- QPushButton* button = static_cast<QPushButton*>(sender());
- context->attach_gdb = (button == launchGdbButton);
+ context->attach_gdb = attach_gdb;
if (context->status != Context::INACTIVE)
return;
@@ -1291,6 +1358,8 @@ void MainWindow::slotLaunch()
setListFromRadio(loggingOutputGroup, context->config.sc.logging_status);
+ context->config.sc.sigint_upon_launch = context->attach_gdb && sigintAction->isChecked();
+
context->config.sc.mouse_support = mouseAction->isChecked();
setListFromRadio(joystickGroup, context->config.sc.nb_controllers);
@@ -1334,8 +1403,20 @@ void MainWindow::slotLaunch()
void MainWindow::slotStop()
{
if (context->status == Context::QUITTING) {
- /* Terminate the game process */
- kill(context->game_pid, SIGKILL);
+ if (context->game_pid != 0) {
+ /* Terminate the game process */
+ kill(context->game_pid, SIGKILL);
+ } else {
+ /* In this case, the game has closed (because game_pid has been set
+ * to 0 by loopExit) yet status is still QUITTING, because status
+ * depends on whether fork_pid is alive, not the game itself.
+ *
+ * So in this case, the game process and the forked process have
+ * different pids (which can happen with gdb, for example) and the
+ * game process has quit, but the forked process has not.
+ */
+ kill(context->fork_pid, SIGKILL);
+ }
return;
}
@@ -1606,8 +1687,13 @@ void MainWindow::slotMovieEnd()
setListFromRadio(movieEndGroup, context->config.on_movie_end);
}
+void MainWindow::slotVariableFramerate(bool checked)
+{
+ context->config.sc.variable_framerate = checked;
+ encodeWindow->update_config();
+}
+
BOOLSLOT(slotAutoRestart, context->config.auto_restart)
-BOOLSLOT(slotVariableFramerate, context->config.sc.variable_framerate)
BOOLSLOT(slotMouseMode, context->config.sc.mouse_mode_relative)
BOOLSLOT(slotMouseWarp, context->config.mouse_warp)
BOOLSLOT(slotMouseGameWarp, context->config.sc.mouse_prevent_warp)
diff --git a/src/program/ui/MainWindow.h b/src/program/ui/MainWindow.h
index 6952f386..cbb87bf9 100644
--- a/src/program/ui/MainWindow.h
+++ b/src/program/ui/MainWindow.h
@@ -31,6 +31,7 @@
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QComboBox>
+#include <QtWidgets/QToolButton>
#include <QtCore/QElapsedTimer>
#include <QtCore/QTimer>
#include <forward_list>
@@ -40,24 +41,25 @@
#include "config.h"
#endif
-#include "EncodeWindow.h"
-#include "ExecutableWindow.h"
-#include "InputWindow.h"
-#include "ControllerTabWindow.h"
-#include "GameInfoWindow.h"
-#include "GameSpecificWindow.h"
-#include "RamSearchWindow.h"
-#include "RamWatchWindow.h"
-#include "InputEditorWindow.h"
-#include "OsdWindow.h"
-#include "AnnotationsWindow.h"
-#include "AutoSaveWindow.h"
-#include "TimeTraceWindow.h"
#include "../GameLoop.h"
#include "../Context.h"
#include <thread>
+class EncodeWindow;
+class InputWindow;
+class ExecutableWindow;
+class ControllerTabWindow;
+class GameInfoWindow;
+class GameSpecificWindow;
+class RamSearchWindow;
+class RamWatchWindow;
+class InputEditorWindow;
+class OsdWindow;
+class AnnotationsWindow;
+class AutoSaveWindow;
+class TimeTraceWindow;
+
class MainWindow : public QMainWindow
{
Q_OBJECT
@@ -122,6 +124,7 @@ public:
QActionGroup *asyncGroup;
QActionGroup *debugStateGroup;
+ QAction *sigintAction;
QActionGroup *loggingOutputGroup;
QActionGroup *loggingPrintGroup;
QActionGroup *loggingExcludeGroup;
@@ -168,7 +171,9 @@ public:
QSpinBox *initialTimeNsec;
QPushButton *launchButton;
- QPushButton *launchGdbButton;
+ QToolButton *launchGdbButton;
+ QAction *launchGdbAction;
+ QAction *launchLldbAction;
QPushButton *stopButton;
QGroupBox *movieBox;
@@ -235,7 +240,9 @@ private slots:
/* Update framerate values */
void updateFramerate();
- void slotLaunch();
+ void slotLaunchGdb();
+ void slotLaunchLldb();
+ void slotLaunch(bool attach_gdb);
void slotStop();
void slotBrowseGamePath();
void slotGamePathChanged();
diff --git a/src/program/ui/PointerScanWindow.cpp b/src/program/ui/PointerScanWindow.cpp
index 4cfcd8f8..3349de18 100644
--- a/src/program/ui/PointerScanWindow.cpp
+++ b/src/program/ui/PointerScanWindow.cpp
@@ -28,6 +28,9 @@
#include <QtWidgets/QMessageBox>
#include "PointerScanWindow.h"
+#include "PointerScanModel.h"
+#include "RamWatchWindow.h"
+#include "RamWatchEditWindow.h"
#include "MainWindow.h"
#include "../ramsearch/CompareEnums.h"
#include "../ramsearch/IRamWatchDetailed.h"
diff --git a/src/program/ui/PointerScanWindow.h b/src/program/ui/PointerScanWindow.h
index f93f7ac9..3ebe2fe2 100644
--- a/src/program/ui/PointerScanWindow.h
+++ b/src/program/ui/PointerScanWindow.h
@@ -31,9 +31,10 @@
#include <QtCore/QSortFilterProxyModel>
#include <memory>
-#include "PointerScanModel.h"
#include "../Context.h"
+class PointerScanModel;
+
class PointerScanWindow : public QDialog {
Q_OBJECT
diff --git a/src/program/ui/RamSearchWindow.cpp b/src/program/ui/RamSearchWindow.cpp
index 05055e22..8d2d5426 100644
--- a/src/program/ui/RamSearchWindow.cpp
+++ b/src/program/ui/RamSearchWindow.cpp
@@ -28,6 +28,9 @@
#include <QtWidgets/QMessageBox>
#include "RamSearchWindow.h"
+#include "RamSearchModel.h"
+#include "RamWatchWindow.h"
+#include "RamWatchEditWindow.h"
#include "MainWindow.h"
#include "../ramsearch/CompareEnums.h"
diff --git a/src/program/ui/RamSearchWindow.h b/src/program/ui/RamSearchWindow.h
index 830d429a..a03c31de 100644
--- a/src/program/ui/RamSearchWindow.h
+++ b/src/program/ui/RamSearchWindow.h
@@ -30,8 +30,10 @@
#include <QtWidgets/QLabel>
#include <memory>
-#include "RamSearchModel.h"
#include "../Context.h"
+#include "../ramsearch/CompareEnums.h"
+
+class RamSearchModel;
class RamSearchWindow : public QDialog {
Q_OBJECT
diff --git a/src/program/ui/RamWatchEditWindow.cpp b/src/program/ui/RamWatchEditWindow.cpp
index 4a5c8dcc..064f6733 100644
--- a/src/program/ui/RamWatchEditWindow.cpp
+++ b/src/program/ui/RamWatchEditWindow.cpp
@@ -27,6 +27,8 @@
#include <stdint.h>
#include "RamWatchEditWindow.h"
+#include "../ramsearch/RamWatch.h"
+#include "../ramsearch/IRamWatchDetailed.h"
#include "../ramsearch/RamWatchDetailed.h"
RamWatchEditWindow::RamWatchEditWindow(QWidget *parent) : QDialog(parent)
diff --git a/src/program/ui/RamWatchEditWindow.h b/src/program/ui/RamWatchEditWindow.h
index 2f4ecb3e..a6f8c742 100644
--- a/src/program/ui/RamWatchEditWindow.h
+++ b/src/program/ui/RamWatchEditWindow.h
@@ -31,7 +31,8 @@
#include <memory> // std::unique_ptr
#include "../ramsearch/IRamWatchDetailed.h"
-#include "../ramsearch/RamWatch.h"
+
+class RamWatch;
class RamWatchEditWindow : public QDialog {
Q_OBJECT
diff --git a/src/program/ui/RamWatchWindow.cpp b/src/program/ui/RamWatchWindow.cpp
index b6bc8b27..5d05709f 100644
--- a/src/program/ui/RamWatchWindow.cpp
+++ b/src/program/ui/RamWatchWindow.cpp
@@ -26,6 +26,9 @@
#include <QtWidgets/QFileDialog>
#include "RamWatchWindow.h"
+#include "RamWatchModel.h"
+#include "RamWatchEditWindow.h"
+#include "PointerScanWindow.h"
RamWatchWindow::RamWatchWindow(Context* c, QWidget *parent) : QDialog(parent), context(c)
{
diff --git a/src/program/ui/RamWatchWindow.h b/src/program/ui/RamWatchWindow.h
index 919fd977..f359096c 100644
--- a/src/program/ui/RamWatchWindow.h
+++ b/src/program/ui/RamWatchWindow.h
@@ -23,11 +23,12 @@
#include <QtWidgets/QDialog>
#include <QtWidgets/QTableView>
-#include "RamWatchModel.h"
-#include "RamWatchEditWindow.h"
-#include "PointerScanWindow.h"
#include "../Context.h"
+class RamWatchEditWindow;
+class PointerScanWindow;
+class RamWatchModel;
+
class RamWatchWindow : public QDialog {
Q_OBJECT
diff --git a/src/program/ui/TimeTraceWindow.cpp b/src/program/ui/TimeTraceWindow.cpp
index 33289272..edf5c9e6 100644
--- a/src/program/ui/TimeTraceWindow.cpp
+++ b/src/program/ui/TimeTraceWindow.cpp
@@ -27,10 +27,7 @@
#include <QtWidgets/QMessageBox>
#include "TimeTraceWindow.h"
-// #include "MainWindow.h"
-// #include "../ramsearch/CompareEnums.h"
-// #include "../ramsearch/IRamWatchDetailed.h"
-// #include "../ramsearch/RamWatchDetailed.h"
+#include "TimeTraceModel.h"
TimeTraceWindow::TimeTraceWindow(Context* c, QWidget *parent) : QDialog(parent), context(c)
{
diff --git a/src/program/ui/TimeTraceWindow.h b/src/program/ui/TimeTraceWindow.h
index a3980fcf..6cd77b3d 100644
--- a/src/program/ui/TimeTraceWindow.h
+++ b/src/program/ui/TimeTraceWindow.h
@@ -27,9 +27,10 @@
#include <QtCore/QItemSelection>
#include <memory>
-#include "TimeTraceModel.h"
#include "../Context.h"
+class TimeTraceModel;
+
class TimeTraceWindow : public QDialog {
Q_OBJECT
diff --git a/src/shared/SharedConfig.h b/src/shared/SharedConfig.h
index d0c6a620..0dc8e1e7 100644
--- a/src/shared/SharedConfig.h
+++ b/src/shared/SharedConfig.h
@@ -295,6 +295,9 @@ struct __attribute__((packed, aligned(8))) SharedConfig {
/* Send stack traces of all time calls to libTAS program */
bool time_trace = false;
+
+ /* Call raise(SIGINT) in libtas::init */
+ bool sigint_upon_launch = false;
};
#endif
diff --git a/src/shared/sockethelpers.cpp b/src/shared/sockethelpers.cpp
index b89445a4..5c4b2195 100644
--- a/src/shared/sockethelpers.cpp
+++ b/src/shared/sockethelpers.cpp
@@ -79,6 +79,11 @@ bool initSocketProgram(void)
} else {
return false;
}
+ tim.tv_nsec *= 1.5;
+ if (tim.tv_nsec >= 1000000000) {
+ tim.tv_sec++;
+ tim.tv_nsec -= 1000000000;
+ }
}
std::cout << "Attempt " << retry + 1 << ": Connected." << std::endl;
diff --git a/src/shared/version.h b/src/shared/version.h
index 14b7669b..ae13cb37 100644
--- a/src/shared/version.h
+++ b/src/shared/version.h
@@ -22,6 +22,6 @@
static const int MAJORVERSION = 1;
static const int MINORVERSION = 4;
-static const int PATCHVERSION = 1;
+static const int PATCHVERSION = 2;
#endif