diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2016-04-06 15:56:01 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2016-04-06 15:56:01 +0200 |
commit | 5ac80f5ed0dfff50af05d064401c37f88a28f894 (patch) | |
tree | 6a69aaf5fff871b2531ca2dcf70ac4a0bd53b33a | |
parent | ba64bc2432e1c903bfd99477d31736db227171b7 (diff) |
proto/ft: don't make games think opentrack is running after it quits
Some background:
Our dll's for freetrack and npclient protocols don't support indication
whether opentrack is running or not. Worse yet, they're whitelisted on
Arma's anticheat system so we can't modify them at arbitrary times.
It's possible to run multiple opentrack instances at a time and we can't
have multiple instances stepping upon each other's toes. It's kind of
pointless to run multiple sessions but hey.
Implementation:
Guard with a mutex against multiple instances. Only the first instance
(that uses the freetrack protocol at all) gets to control whether the
dll's are accessible.
Remove the registry keys after either freetrack protocol exits or
software exits, but only if we're the first opentrack instance running
freetrack protocol at all.
Issue: #332
-rwxr-xr-x[-rw-r--r--] | proto-ft/ftnoir_protocol_ft.cpp | 42 | ||||
-rwxr-xr-x[-rw-r--r--] | proto-ft/ftnoir_protocol_ft.h | 16 | ||||
-rwxr-xr-x | proto-ft/mutex.cpp | 64 |
3 files changed, 107 insertions, 15 deletions
diff --git a/proto-ft/ftnoir_protocol_ft.cpp b/proto-ft/ftnoir_protocol_ft.cpp index 05253174..134ffc53 100644..100755 --- a/proto-ft/ftnoir_protocol_ft.cpp +++ b/proto-ft/ftnoir_protocol_ft.cpp @@ -16,6 +16,7 @@ FTNoIR_Protocol::FTNoIR_Protocol() : viewsStop(nullptr), intGameID(0) { + runonce_check->try_runonce(); } FTNoIR_Protocol::~FTNoIR_Protocol() @@ -27,6 +28,7 @@ FTNoIR_Protocol::~FTNoIR_Protocol() dummyTrackIR.terminate(); dummyTrackIR.kill(); dummyTrackIR.waitForFinished(50); + runonce_check->try_exit(); } void FTNoIR_Protocol::pose(const double* headpose) { @@ -108,44 +110,54 @@ void FTNoIR_Protocol::start_tirviews() { } void FTNoIR_Protocol::start_dummy() { - - QString program = QCoreApplication::applicationDirPath() + "/TrackIR.exe"; dummyTrackIR.setProgram("\"" + program + "\""); dummyTrackIR.start(); } -bool FTNoIR_Protocol::correct() +void FTNoIR_Protocol::set_protocols(bool ft, bool npclient) { + const QString program_dir = QCoreApplication::applicationDirPath() + "/"; + // Registry settings (in HK_USER) - QSettings settings("Freetrack", "FreetrackClient"); - QSettings settingsTIR("NaturalPoint", "NATURALPOINT\\NPClient Location"); + QSettings settings_ft("Freetrack", "FreetrackClient"); + QSettings settings_npclient("NaturalPoint", "NATURALPOINT\\NPClient Location"); + + if (ft) + settings_ft.setValue("Path", program_dir); + else + settings_ft.setValue("Path", ""); + + if (npclient) + settings_npclient.setValue("Path", program_dir); + else + settings_npclient.setValue("Path", ""); +} +bool FTNoIR_Protocol::correct() +{ if (!shm.success()) return false; - QString aLocation = QCoreApplication::applicationDirPath() + "/"; + bool use_ft = false, use_npclient = false; switch (s.intUsedInterface) { case 0: - // Use both interfaces - settings.setValue( "Path" , aLocation ); - settingsTIR.setValue( "Path" , aLocation ); + use_ft = true; + use_npclient = true; break; case 1: - // Use FreeTrack, disable TrackIR - settings.setValue( "Path" , aLocation ); - settingsTIR.setValue( "Path" , "" ); + use_ft = true; break; case 2: - // Use TrackIR, disable FreeTrack - settings.setValue( "Path" , "" ); - settingsTIR.setValue( "Path" , aLocation ); + use_npclient = true; break; default: break; } + set_protocols(use_ft, use_npclient); + if (s.useTIRViews) { start_tirviews(); } diff --git a/proto-ft/ftnoir_protocol_ft.h b/proto-ft/ftnoir_protocol_ft.h index 9cf16f03..8940e5d8 100644..100755 --- a/proto-ft/ftnoir_protocol_ft.h +++ b/proto-ft/ftnoir_protocol_ft.h @@ -21,6 +21,8 @@ #include "opentrack-compat/shm.h" #include "opentrack-compat/options.hpp" #include "freetrackclient/fttypes.h" +#include <memory> + using namespace options; struct settings : opts { @@ -36,6 +38,15 @@ struct settings : opts { typedef void (__stdcall *importTIRViewsStart)(void); typedef void (__stdcall *importTIRViewsStop)(void); +// for runonce, see mutex.cpp +struct runonce +{ + virtual void try_runonce() = 0; + virtual void try_exit() = 0; + virtual bool is_first_run() = 0; + virtual ~runonce() {} +}; + class FTNoIR_Protocol : public IProtocol { public: @@ -61,9 +72,14 @@ private: QString connected_game; QMutex game_name_mutex; + static std::unique_ptr<runonce> runonce_check; + static inline double getRadsFromDegrees(double degrees) { return degrees * 0.017453; } void start_tirviews(); void start_dummy(); + +public: + static void set_protocols(bool ft, bool npclient); }; class FTControls: public IProtocolDialog diff --git a/proto-ft/mutex.cpp b/proto-ft/mutex.cpp new file mode 100755 index 00000000..0d50c9bd --- /dev/null +++ b/proto-ft/mutex.cpp @@ -0,0 +1,64 @@ +#include "ftnoir_protocol_ft.h" +#include <windows.h> + +class check_for_first_run : public runonce +{ + bool checked_for_first_run; + bool is_first_instance; + +public: + bool is_first_run() override + { + return checked_for_first_run && is_first_instance; + } + + void try_runonce() override + { + constexpr const char* name = "opentrack-freetrack-runonce"; + + if (checked_for_first_run) + return; + + // just leak it, no issue + HANDLE h = CreateMutexA(nullptr, false, name); + + switch (WaitForSingleObject(h, 0)) + { + case WAIT_OBJECT_0: + is_first_instance = true; + checked_for_first_run = true; + break; + case WAIT_TIMEOUT: + checked_for_first_run = true; + break; + default: + checked_for_first_run = false; + break; + } + + if (checked_for_first_run && !is_first_instance) + CloseHandle(h); + + qDebug() << "ft runonce:" << "first-run" << is_first_instance << "checked" << checked_for_first_run; + } + + void try_exit() override + { + if (is_first_instance) + { + qDebug() << "ft runonce: removing registry keys"; + FTNoIR_Protocol::set_protocols(false, false); + } + } + +public: + check_for_first_run() : checked_for_first_run(false), is_first_instance(false) + { + } + ~check_for_first_run() + { + try_exit(); + } +}; + +std::unique_ptr<runonce> FTNoIR_Protocol::runonce_check = std::unique_ptr<runonce>(static_cast<runonce*>(new check_for_first_run())); |