From dba936c0838ff9288a1520e349a9a6e9ae2b0a77 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 03:18:02 -0500 Subject: [PATCH 01/21] Cleanup some whitespace Mostly trailing whitespace at the end of lines --- .../src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp | 78 ++++++++--------- .../src/ACRE2Arma/common/pbo/fileloader.hpp | 2 +- extensions/src/ACRE2Core/AcreDsp.cpp | 2 +- extensions/src/ACRE2Core/FilterGain.cpp | 2 +- extensions/src/ACRE2Core/FilterPosition.cpp | 84 +++++++++---------- extensions/src/ACRE2Core/FilterVolume.cpp | 2 +- extensions/src/ACRE2Core/KeyHandlerEngine.cpp | 2 +- extensions/src/ACRE2Core/KeyHandlerEngine.h | 2 +- extensions/src/ACRE2Core/NamedPipeServer.cpp | 35 ++++---- extensions/src/ACRE2Core/RpcEngine.cpp | 1 - extensions/src/ACRE2Core/Self.h | 2 +- extensions/src/ACRE2Core/SoundMixdownEffect.h | 2 +- extensions/src/ACRE2Core/SoundMixer.h | 2 +- extensions/src/ACRE2Core/SoundMonoEffect.h | 2 +- extensions/src/ACRE2Shared/TextMessage.cpp | 22 ++--- 15 files changed, 119 insertions(+), 121 deletions(-) diff --git a/extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp b/extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp index d130d00c2..0cd71b81f 100644 --- a/extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp +++ b/extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp @@ -9,8 +9,8 @@ #include #include "shlobj.h" #include "Shlwapi.h" -#include -#include +#include +#include #include #include @@ -37,7 +37,7 @@ void ClosePipe(); extern "C" { __declspec (dllexport) void __stdcall RVExtensionVersion(char *output, int outputSize); - __declspec(dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function); + __declspec(dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function); }; void __stdcall RVExtensionVersion(char *output, int outputSize) { @@ -57,7 +57,7 @@ inline std::string get_cmdline() { inline std::string get_path(std::string filepath) { char drive[_MAX_DRIVE]; char dir [_MAX_DIR]; - + _splitpath( filepath.c_str(), drive, @@ -106,7 +106,7 @@ inline std::string find_mod_file(std::string filename) { std::string path = std::string(drive) + std::string(dir) + "\\" + filename; if (!PathFileExistsA(path.c_str())) { - // No mod path was set, it means they used the mod config. It *DOES* mean it relative to a folder in our path at least. + // No mod path was set, it means they used the mod config. It *DOES* mean it relative to a folder in our path at least. // So, we just search all the local folders WIN32_FIND_DATAA data; @@ -133,7 +133,7 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) { size_t id_length = 1; std::string functionStr = std::string(function); - + if (functionStr.length() > 1) { if (isdigit(functionStr.substr(1, 1).c_str()[0])) { id_length = 2; @@ -149,21 +149,21 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) int command = atoi(id.c_str()); switch(command) { - + case PIPE_COMMAND_WRITE: { if (writeConnected) { if (params.length() > 0) { DWORD cbWritten; BOOL ret; //DEBUG("Writing [%s] to pipe [%d]\n", params.c_str(), hPipe); - - // Send a message to the pipe server. - ret = WriteFile( - writeHandle, // pipe handle - params.c_str(), // message - params.length(), // message length - &cbWritten, // bytes written - NULL); // not overlapped + + // Send a message to the pipe server. + ret = WriteFile( + writeHandle, // pipe handle + params.c_str(), // message + params.length(), // message length + &cbWritten, // bytes written + NULL); // not overlapped if (cbWritten != params.length()) { FlushFileBuffers(writeHandle); //printf("FLUSHING!\n"); @@ -235,28 +235,28 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) } std::string fromPipeName = FROM_PIPENAME_TS; std::string toPipeName = TO_PIPENAME_TS; - + if (readHandle != INVALID_HANDLE_VALUE) { CloseHandle(readHandle); readConnected = false; } if (!readConnected) { while (tries < 1) { - readHandle = CreateFileA( - fromPipeName.c_str(), // pipe name - GENERIC_READ | GENERIC_WRITE, - 0, // no sharing + readHandle = CreateFileA( + fromPipeName.c_str(), // pipe name + GENERIC_READ | GENERIC_WRITE, + 0, // no sharing NULL, // default security attributes - OPEN_EXISTING, // opens existing pipe - 0, // default attributes - NULL); // no template file + OPEN_EXISTING, // opens existing pipe + 0, // default attributes + NULL); // no template file if (readHandle != INVALID_HANDLE_VALUE) { DWORD dwModeRead = PIPE_NOWAIT | PIPE_READMODE_MESSAGE; - ret = SetNamedPipeHandleState( - readHandle, // pipe handle - &dwModeRead, // new pipe mode - NULL, // don't set maximum bytes - NULL); // don't set maximum time + ret = SetNamedPipeHandleState( + readHandle, // pipe handle + &dwModeRead, // new pipe mode + NULL, // don't set maximum bytes + NULL); // don't set maximum time if ( ! ret) { //printf("READ PIPE MODE ERROR: %d\n", GetLastError()); sprintf(output, "Read SetNamedPipeHandleState WinErrCode: %d", GetLastError()); @@ -288,22 +288,22 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) if (!writeConnected) { tries = 0; while (tries < 1) { - writeHandle = CreateFileA( - toPipeName.c_str(), // pipe name + writeHandle = CreateFileA( + toPipeName.c_str(), // pipe name GENERIC_WRITE | GENERIC_READ, - 0, // no sharing + 0, // no sharing NULL, // default security attributes - OPEN_EXISTING, // opens existing pipe - 0, // default attributes - NULL); // no template file + OPEN_EXISTING, // opens existing pipe + 0, // default attributes + NULL); // no template file if (writeHandle != INVALID_HANDLE_VALUE) { DWORD dwModeWrite = PIPE_READMODE_MESSAGE; - ret = SetNamedPipeHandleState( - writeHandle, // pipe handle - &dwModeWrite, // new pipe mode - NULL, // don't set maximum bytes - NULL); // don't set maximum time + ret = SetNamedPipeHandleState( + writeHandle, // pipe handle + &dwModeWrite, // new pipe mode + NULL, // don't set maximum bytes + NULL); // don't set maximum time if ( ! ret) { //printf("WRITE PIPE MODE ERROR: %d\n", GetLastError()); sprintf(output, "Write SetNamedPipeHandleState WinErrCode: %d", GetLastError()); diff --git a/extensions/src/ACRE2Arma/common/pbo/fileloader.hpp b/extensions/src/ACRE2Arma/common/pbo/fileloader.hpp index 1e013f0b5..190dd7aac 100644 --- a/extensions/src/ACRE2Arma/common/pbo/fileloader.hpp +++ b/extensions/src/ACRE2Arma/common/pbo/fileloader.hpp @@ -106,4 +106,4 @@ namespace acre { }; }; } -} \ No newline at end of file +} diff --git a/extensions/src/ACRE2Core/AcreDsp.cpp b/extensions/src/ACRE2Core/AcreDsp.cpp index 5c0b11c3c..3e9febdd3 100644 --- a/extensions/src/ACRE2Core/AcreDsp.cpp +++ b/extensions/src/ACRE2Core/AcreDsp.cpp @@ -26,4 +26,4 @@ namespace Dsp { } } } -} \ No newline at end of file +} diff --git a/extensions/src/ACRE2Core/FilterGain.cpp b/extensions/src/ACRE2Core/FilterGain.cpp index 6b69add2e..a3cd610f5 100644 --- a/extensions/src/ACRE2Core/FilterGain.cpp +++ b/extensions/src/ACRE2Core/FilterGain.cpp @@ -28,4 +28,4 @@ CFilterGain::CFilterGain(void) CFilterGain::~CFilterGain(void) { -} \ No newline at end of file +} diff --git a/extensions/src/ACRE2Core/FilterPosition.cpp b/extensions/src/ACRE2Core/FilterPosition.cpp index 49db8551b..c025f5247 100644 --- a/extensions/src/ACRE2Core/FilterPosition.cpp +++ b/extensions/src/ACRE2Core/FilterPosition.cpp @@ -28,7 +28,7 @@ acre::Result CFilterPosition::process(short* samples, int sampleCount, int chann X3DAUDIO_VECTOR speaker_position; X3DAUDIO_VECTOR vector_listenerDirection; X3DAUDIO_VECTOR vector_speakerDirection; - + //LOCK(player); //LOCK(CEngine::getInstance()->getSelf()); float killCoef; @@ -49,7 +49,7 @@ acre::Result CFilterPosition::process(short* samples, int sampleCount, int chann this->p_IsInitialized = TRUE; } - + if (CAcreSettings::getInstance()->getDisablePosition()) return acre::Result::ok; @@ -115,7 +115,7 @@ acre::Result CFilterPosition::process(short* samples, int sampleCount, int chann Emitter.CurveDistanceScaler = 1.0f; Emitter.pVolumeCurve = (X3DAUDIO_DISTANCE_CURVE *)&distanceCurve; } - + Emitter.DopplerScaler = 1.0f; Emitter.ChannelRadius = 1.0f; @@ -127,8 +127,8 @@ acre::Result CFilterPosition::process(short* samples, int sampleCount, int chann Emitter.pCone = &emitterCone; //Listener.pCone = &emitterCone; - - + + Emitter.InnerRadius = 2.0f; Emitter.InnerRadiusAngle = X3DAUDIO_PI/4.0f; @@ -140,10 +140,10 @@ acre::Result CFilterPosition::process(short* samples, int sampleCount, int chann Listener.OrientFront = vector_listenerDirection; Listener.OrientTop = listener_topVec; Listener.Position = listener_position; - + //UNLOCK(CEngine::getInstance()->getSelf()); //UNLOCK(player); - + X3DAudioCalculate(this->p_X3DInstance, &Listener, &Emitter, X3DAUDIO_CALCULATE_MATRIX | X3DAUDIO_CALCULATE_EMITTER_ANGLE, @@ -156,7 +156,7 @@ acre::Result CFilterPosition::process(short* samples, int sampleCount, int chann sprintf(mAppend, "%f, ", Matrix[i]); matrixVals.append(std::string(mAppend)); } - + TRACE("MATRIX: %s", matrixVals.c_str()); */ TRACE("matrix: c:[%d], %f, %f, %f", channels, Matrix[0], Matrix[1], (Matrix[0] + Matrix[1]));// +Matrix[2] + Matrix[3] + Matrix[4] + Matrix[5])); @@ -265,75 +265,75 @@ unsigned int CFilterPosition::getChannelMask(const unsigned int channelMask) { switch(channelMask) { case TS_SPEAKER_FRONT_LEFT: LOG("Found: %08x", SPEAKER_FRONT_LEFT); - returnValue = SPEAKER_FRONT_LEFT; + returnValue = SPEAKER_FRONT_LEFT; break; case TS_SPEAKER_FRONT_RIGHT: LOG("Found: %08x", SPEAKER_FRONT_RIGHT); - returnValue = SPEAKER_FRONT_RIGHT; + returnValue = SPEAKER_FRONT_RIGHT; break; - case TS_SPEAKER_FRONT_CENTER: + case TS_SPEAKER_FRONT_CENTER: LOG("Found: %08x", SPEAKER_FRONT_CENTER); - returnValue = SPEAKER_FRONT_CENTER; + returnValue = SPEAKER_FRONT_CENTER; break; - case TS_SPEAKER_LOW_FREQUENCY: + case TS_SPEAKER_LOW_FREQUENCY: LOG("Found: %08x", SPEAKER_LOW_FREQUENCY); - returnValue = SPEAKER_LOW_FREQUENCY; + returnValue = SPEAKER_LOW_FREQUENCY; break; - case TS_SPEAKER_BACK_LEFT: + case TS_SPEAKER_BACK_LEFT: LOG("Found: %08x", SPEAKER_BACK_LEFT); - returnValue = SPEAKER_BACK_LEFT; + returnValue = SPEAKER_BACK_LEFT; break; - case TS_SPEAKER_BACK_RIGHT: + case TS_SPEAKER_BACK_RIGHT: LOG("Found: %08x", SPEAKER_BACK_RIGHT); - returnValue = SPEAKER_BACK_RIGHT; + returnValue = SPEAKER_BACK_RIGHT; break; - case TS_SPEAKER_FRONT_LEFT_OF_CENTER: + case TS_SPEAKER_FRONT_LEFT_OF_CENTER: LOG("Found: %08x", SPEAKER_FRONT_LEFT_OF_CENTER); - returnValue = SPEAKER_FRONT_LEFT_OF_CENTER; + returnValue = SPEAKER_FRONT_LEFT_OF_CENTER; break; - case TS_SPEAKER_FRONT_RIGHT_OF_CENTER: + case TS_SPEAKER_FRONT_RIGHT_OF_CENTER: LOG("Found: %08x", SPEAKER_FRONT_RIGHT_OF_CENTER); - returnValue = SPEAKER_FRONT_RIGHT_OF_CENTER; + returnValue = SPEAKER_FRONT_RIGHT_OF_CENTER; break; - case TS_SPEAKER_BACK_CENTER: + case TS_SPEAKER_BACK_CENTER: LOG("Found: %08x", SPEAKER_BACK_CENTER); - returnValue = SPEAKER_BACK_CENTER; + returnValue = SPEAKER_BACK_CENTER; break; - case TS_SPEAKER_SIDE_LEFT: + case TS_SPEAKER_SIDE_LEFT: LOG("Found: %08x", SPEAKER_SIDE_LEFT); - returnValue = SPEAKER_SIDE_LEFT; + returnValue = SPEAKER_SIDE_LEFT; break; - case TS_SPEAKER_SIDE_RIGHT: + case TS_SPEAKER_SIDE_RIGHT: LOG("Found: %08x", SPEAKER_SIDE_RIGHT); - returnValue = SPEAKER_SIDE_RIGHT; + returnValue = SPEAKER_SIDE_RIGHT; break; - case TS_SPEAKER_TOP_CENTER: + case TS_SPEAKER_TOP_CENTER: LOG("Found: %08x", SPEAKER_TOP_CENTER); - returnValue = SPEAKER_TOP_CENTER; + returnValue = SPEAKER_TOP_CENTER; break; - case TS_SPEAKER_TOP_FRONT_LEFT: + case TS_SPEAKER_TOP_FRONT_LEFT: LOG("Found: %08x", SPEAKER_TOP_FRONT_LEFT); - returnValue = SPEAKER_TOP_FRONT_LEFT; + returnValue = SPEAKER_TOP_FRONT_LEFT; break; - case TS_SPEAKER_TOP_FRONT_CENTER: + case TS_SPEAKER_TOP_FRONT_CENTER: LOG("Found: %08x", SPEAKER_TOP_FRONT_CENTER); - returnValue = SPEAKER_TOP_FRONT_CENTER; + returnValue = SPEAKER_TOP_FRONT_CENTER; break; - case TS_SPEAKER_TOP_FRONT_RIGHT: + case TS_SPEAKER_TOP_FRONT_RIGHT: LOG("Found: %08x", SPEAKER_TOP_FRONT_RIGHT); - returnValue = SPEAKER_TOP_FRONT_RIGHT; + returnValue = SPEAKER_TOP_FRONT_RIGHT; break; - case TS_SPEAKER_TOP_BACK_LEFT: + case TS_SPEAKER_TOP_BACK_LEFT: LOG("Found: %08x", SPEAKER_TOP_BACK_LEFT); - returnValue = SPEAKER_TOP_BACK_LEFT; + returnValue = SPEAKER_TOP_BACK_LEFT; break; - case TS_SPEAKER_TOP_BACK_CENTER: + case TS_SPEAKER_TOP_BACK_CENTER: LOG("Found: %08x", SPEAKER_TOP_BACK_CENTER); - returnValue = SPEAKER_TOP_BACK_CENTER; + returnValue = SPEAKER_TOP_BACK_CENTER; break; - case TS_SPEAKER_TOP_BACK_RIGHT: + case TS_SPEAKER_TOP_BACK_RIGHT: LOG("Found: %08x", SPEAKER_TOP_BACK_RIGHT); - returnValue = SPEAKER_TOP_BACK_RIGHT; + returnValue = SPEAKER_TOP_BACK_RIGHT; break; } LOG("Mask Return: %08x", returnValue); diff --git a/extensions/src/ACRE2Core/FilterVolume.cpp b/extensions/src/ACRE2Core/FilterVolume.cpp index 2f901367b..a38ab8980 100644 --- a/extensions/src/ACRE2Core/FilterVolume.cpp +++ b/extensions/src/ACRE2Core/FilterVolume.cpp @@ -40,4 +40,4 @@ CFilterVolume::CFilterVolume(void) CFilterVolume::~CFilterVolume(void) { -} \ No newline at end of file +} diff --git a/extensions/src/ACRE2Core/KeyHandlerEngine.cpp b/extensions/src/ACRE2Core/KeyHandlerEngine.cpp index 53c8af1b9..006d17e30 100644 --- a/extensions/src/ACRE2Core/KeyHandlerEngine.cpp +++ b/extensions/src/ACRE2Core/KeyHandlerEngine.cpp @@ -122,4 +122,4 @@ acre::Result CKeyHandlerEngine::clearKeybinds( void ) { this->unlock(); return acre::Result::ok; } -*/ \ No newline at end of file +*/ diff --git a/extensions/src/ACRE2Core/KeyHandlerEngine.h b/extensions/src/ACRE2Core/KeyHandlerEngine.h index f13c9b3a1..de6af59a2 100644 --- a/extensions/src/ACRE2Core/KeyHandlerEngine.h +++ b/extensions/src/ACRE2Core/KeyHandlerEngine.h @@ -46,4 +46,4 @@ class CKeyHandlerEngine : public CLockable { concurrency::concurrent_unordered_map m_keyMap; std::thread m_keyboardReadThread; }; -*/ \ No newline at end of file +*/ diff --git a/extensions/src/ACRE2Core/NamedPipeServer.cpp b/extensions/src/ACRE2Core/NamedPipeServer.cpp index 2da726fc6..544e7c0cc 100644 --- a/extensions/src/ACRE2Core/NamedPipeServer.cpp +++ b/extensions/src/ACRE2Core/NamedPipeServer.cpp @@ -40,8 +40,8 @@ acre::Result CNamedPipeServer::initialize() { while (tryAgain) { writeHandle = CreateNamedPipeA( this->getFromPipeName().c_str(), // name of the pipe - PIPE_ACCESS_DUPLEX, - PIPE_TYPE_MESSAGE | // message-type pipe + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | // message-type pipe PIPE_READMODE_MESSAGE, // send data as message PIPE_UNLIMITED_INSTANCES, 4096, // no outbound buffer @@ -51,7 +51,7 @@ acre::Result CNamedPipeServer::initialize() { ); if (writeHandle == INVALID_HANDLE_VALUE) { char errstr[1024]; - + _snprintf_s(errstr, sizeof(errstr), "Conflicting game write pipe detected, could not create pipe!\nERROR CODE: %d", GetLastError()); int ret = MessageBoxA(NULL, errstr, "ACRE Error", MB_RETRYCANCEL | MB_ICONEXCLAMATION); if (ret != IDRETRY) { @@ -70,11 +70,11 @@ acre::Result CNamedPipeServer::initialize() { while (tryAgain) { readHandle = CreateNamedPipeA( this->getToPipeName().c_str(), // name of the pipe - PIPE_ACCESS_DUPLEX, - PIPE_TYPE_MESSAGE | // message-type pipe + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | // message-type pipe PIPE_NOWAIT | // Depricated but fuck it, it is simpler. PIPE_READMODE_MESSAGE, // send data as message - PIPE_UNLIMITED_INSTANCES, + PIPE_UNLIMITED_INSTANCES, 4096, // no outbound buffer 4096, // no inbound buffer 0, // use default wait time @@ -82,7 +82,7 @@ acre::Result CNamedPipeServer::initialize() { ); if (readHandle == INVALID_HANDLE_VALUE) { char errstr[1024]; - + _snprintf_s(errstr, sizeof(errstr), "Conflicting game read pipe detected, could not create pipe!\nERROR CODE: %d", GetLastError()); int ret = MessageBoxA(NULL, errstr, "ACRE Error", MB_RETRYCANCEL | MB_ICONEXCLAMATION); if (ret != IDRETRY) { @@ -93,7 +93,6 @@ acre::Result CNamedPipeServer::initialize() { tryAgain = false; } } - this->setPipeHandleRead(readHandle); this->setPipeHandleWrite(writeHandle); @@ -142,11 +141,11 @@ acre::Result CNamedPipeServer::shutdown(void) { } acre::Result CNamedPipeServer::sendLoop() { +#ifdef WIN32 while (!this->getShuttingDown()) { - do { ConnectNamedPipe(this->m_PipeHandleWrite, NULL); - if (GetLastError() == ERROR_PIPE_CONNECTED) { + if (GetLastError() == ERROR_PIPE_CONNECTED) { LOG("Client write connected"); CEngine::getInstance()->getSoundEngine()->onClientGameConnected(); this->setConnectedWrite(true); @@ -179,12 +178,12 @@ acre::Result CNamedPipeServer::sendLoop() { // send it and free it //LOCK(this); this->lock(); - const bool ret = WriteFile( - this->m_PipeHandleWrite, // pipe handle - msg->getData(), // message - size, // message length - &cbWritten, // bytes written - NULL); // not overlapped + const bool ret = WriteFile( + this->m_PipeHandleWrite, // pipe handle + msg->getData(), // message + size, // message length + &cbWritten, // bytes written + NULL); // not overlapped this->unlock(); if (!ret) { @@ -217,12 +216,12 @@ acre::Result CNamedPipeServer::readLoop() { LOG("LocalAlloc() failed: %d", GetLastError()); } /* - this->validTSServers.insert(std::string("enter a ts3 server id here")); + this->validTSServers.insert(std::string("enter a ts3 server id here")); */ while (!this->getShuttingDown()) { //this->checkServer(); bool ret = ConnectNamedPipe(this->m_PipeHandleRead, NULL); - if (GetLastError() == ERROR_PIPE_CONNECTED) { + if (GetLastError() == ERROR_PIPE_CONNECTED) { LOG("Client read connected"); CEngine::getInstance()->getClient()->updateShouldSwitchChannel(false); CEngine::getInstance()->getClient()->unMuteAll(); diff --git a/extensions/src/ACRE2Core/RpcEngine.cpp b/extensions/src/ACRE2Core/RpcEngine.cpp index 1c79b9bee..5c8af3217 100644 --- a/extensions/src/ACRE2Core/RpcEngine.cpp +++ b/extensions/src/ACRE2Core/RpcEngine.cpp @@ -67,7 +67,6 @@ acre::Result CRpcEngine::runProcedure(IServer *const serverInstance, IMessage *m } acre::Result CRpcEngine::runProcedure(IServer *const serverInstance, IMessage *msg, const bool entrant) { - if (msg == nullptr) { return acre::Result::error; } else if (msg->getProcedureName() == nullptr) { diff --git a/extensions/src/ACRE2Core/Self.h b/extensions/src/ACRE2Core/Self.h index 34c8f22a9..89455246b 100644 --- a/extensions/src/ACRE2Core/Self.h +++ b/extensions/src/ACRE2Core/Self.h @@ -18,4 +18,4 @@ class CSelf : public CPlayer { DECLARE_MEMBER(acre::CurveModel, CurveModel); DECLARE_MEMBER(BOOL, Speaking); DECLARE_MEMBER(int, CurrentLanguageId); -}; \ No newline at end of file +}; diff --git a/extensions/src/ACRE2Core/SoundMixdownEffect.h b/extensions/src/ACRE2Core/SoundMixdownEffect.h index b46d67bda..12c5d027a 100644 --- a/extensions/src/ACRE2Core/SoundMixdownEffect.h +++ b/extensions/src/ACRE2Core/SoundMixdownEffect.h @@ -15,4 +15,4 @@ class CSoundMixdownEffect : public CLockable { virtual void process(short* samples, int sampleCount, int channels, const unsigned int speakerMask) = 0; void setParam(std::string paramName, float value) { paramMap[paramName] = value; }; float getParam(std::string paramName) { return paramMap[paramName]; }; -}; \ No newline at end of file +}; diff --git a/extensions/src/ACRE2Core/SoundMixer.h b/extensions/src/ACRE2Core/SoundMixer.h index 4e5df254c..b946ef521 100644 --- a/extensions/src/ACRE2Core/SoundMixer.h +++ b/extensions/src/ACRE2Core/SoundMixer.h @@ -21,4 +21,4 @@ class CSoundMixer : public CLockable { bool releaseChannel(CSoundChannelMono *releaseChannel); void mixDown(short* samples, int sampleCount, int channels, const unsigned int speakerMask); -}; \ No newline at end of file +}; diff --git a/extensions/src/ACRE2Core/SoundMonoEffect.h b/extensions/src/ACRE2Core/SoundMonoEffect.h index 881d066ae..93375828e 100644 --- a/extensions/src/ACRE2Core/SoundMonoEffect.h +++ b/extensions/src/ACRE2Core/SoundMonoEffect.h @@ -21,4 +21,4 @@ class CSoundMonoEffect : public CLockable { return 0.0f; } }; -}; \ No newline at end of file +}; diff --git a/extensions/src/ACRE2Shared/TextMessage.cpp b/extensions/src/ACRE2Shared/TextMessage.cpp index 9382ffb41..2896c4afd 100644 --- a/extensions/src/ACRE2Shared/TextMessage.cpp +++ b/extensions/src/ACRE2Shared/TextMessage.cpp @@ -27,7 +27,7 @@ acre::Result CTextMessage::parse(char *const value, const size_t len) { this->m_IsValid = false; return acre::Result::error; } - + this->m_DataPtr = (char *)LocalAlloc(0, length); memcpy(this->m_DataPtr, value, length); this->m_DataPtr[length-1] = 0x00; @@ -49,7 +49,7 @@ acre::Result CTextMessage::parse(char *const value, const size_t len) { // now parse parameters..if there are any if (pos == (this->m_Data->length() - 1)) { - this->m_IsValid = true; + this->m_IsValid = true; return acre::Result::ok; } @@ -64,7 +64,7 @@ acre::Result CTextMessage::parse(char *const value, const size_t len) { this->m_Parameters[x] = new std::string(t.substr(0, t.find(",")).c_str()); pParamCount += 1; } else if (t.find(",") == std::string::npos) { - this->m_IsValid = true; + this->m_IsValid = true; this->m_Parameters[x] = new std::string(t.substr(0, t.length())); pParamCount += 1; break; @@ -82,7 +82,7 @@ acre::Result CTextMessage::parse(char *const value, const size_t len) { this->m_ParameterCount = pParamCount; this->m_IsValid = true; - + //this->setLength((uint32_t)this->m_Data->size()); return acre::Result::ok; @@ -130,7 +130,7 @@ const unsigned char *const CTextMessage::getParameter(uint32_t index) const { } CTextMessage::~CTextMessage(void) { - + for (uint32_t x = 0; x < TEXTMESSAGE_MAX_PARAMETER_COUNT; x++) { if (this->m_Parameters[x]) { delete this->m_Parameters[x]; @@ -164,7 +164,7 @@ IMessage *CTextMessage::formatNewMessage(const char * const procedureName, const LOG("procedureName was null"); return nullptr; } - + char *finalBuffer = (char *)LocalAlloc(LPTR, TEXTMESSAGE_BUFSIZE); if (buffer == nullptr) { LOG("LocalAlloc() failed: %d", GetLastError()); @@ -195,18 +195,18 @@ IMessage *CTextMessage::formatNewMessage(const char * const procedureName, const IMessage *CTextMessage::createNewMessage(char *procedureName, ... ) { va_list va; - + if (!procedureName) { LOG("procedureName was null"); return nullptr; } - + char *buffer = (char *)LocalAlloc(LPTR, TEXTMESSAGE_BUFSIZE); if (buffer == nullptr) { LOG("LocalAlloc() failed: %d", GetLastError()); return nullptr; } - + buffer[0] = 0x00; _snprintf_s(buffer, TEXTMESSAGE_BUFSIZE, TEXTMESSAGE_BUFSIZE - 1, "%s:", procedureName); @@ -221,7 +221,7 @@ IMessage *CTextMessage::createNewMessage(char *procedureName, ... ) { buffer = (char *)LocalReAlloc(buffer, strlen(buffer) + 1, LMEM_MOVEABLE); CTextMessage *msg = new CTextMessage(buffer, strlen(buffer) + 1); - + if (!msg->isValid()) { LOG("ERR: msg was invalid"); delete msg; @@ -233,6 +233,6 @@ IMessage *CTextMessage::createNewMessage(char *procedureName, ... ) { return((IMessage *)msg); } -uint32_t CTextMessage::getParameterCount() const { +uint32_t CTextMessage::getParameterCount() const { return this->m_ParameterCount; } From f791e31505eb38ff623743e6241a1dbd0dae9c3d Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 03:22:28 -0500 Subject: [PATCH 02/21] Make some syntactic changes for other compilers Make some of the first steps to be able to build parts of ACRE on other platforms (such as GCC). Mostly, this amounts to differences in preprocessors, and some builtins. --- extensions/src/ACRE2Core/AcreDsp.cpp | 2 +- extensions/src/ACRE2Core/AcreDsp.h | 2 +- extensions/src/ACRE2Mumble/MumbleClient.cpp | 2 +- extensions/src/ACRE2Shared/Log.h | 2 +- extensions/src/ACRE2Shared/Macros.h | 16 ++++++++-------- extensions/src/ACRE2Shared/_CONSTANTS.h | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/extensions/src/ACRE2Core/AcreDsp.cpp b/extensions/src/ACRE2Core/AcreDsp.cpp index 3e9febdd3..0f56149b5 100644 --- a/extensions/src/ACRE2Core/AcreDsp.cpp +++ b/extensions/src/ACRE2Core/AcreDsp.cpp @@ -9,7 +9,7 @@ namespace Dsp { const static float c2 = (float)((int)(c1 / 3)) + 1; const static float c3 = 1.f / c1; - float random = ((float)rand() / (float)(RAND_MAX + 1)); + float random = ((float)rand() / ((float)RAND_MAX + 1)); float noise = (2.f * ((random * c2) + (random * c2) + (random * c2)) - 3.f * (c2 - 1.f)) * c3; return noise; diff --git a/extensions/src/ACRE2Core/AcreDsp.h b/extensions/src/ACRE2Core/AcreDsp.h index bccd879f0..73f46f0fb 100644 --- a/extensions/src/ACRE2Core/AcreDsp.h +++ b/extensions/src/ACRE2Core/AcreDsp.h @@ -1,5 +1,5 @@ #pragma once -#include "DspFilters\Dsp.h" +#include "DspFilters/Dsp.h" #define PINK_NOISE_NUM_STAGES 3 #define PI_2 1.57079632679489661923f diff --git a/extensions/src/ACRE2Mumble/MumbleClient.cpp b/extensions/src/ACRE2Mumble/MumbleClient.cpp index d883b6076..d8c904ca5 100644 --- a/extensions/src/ACRE2Mumble/MumbleClient.cpp +++ b/extensions/src/ACRE2Mumble/MumbleClient.cpp @@ -324,7 +324,7 @@ uint64_t CMumbleClient::findChannelByNames(std::vector details_) { } for (std::int32_t idx = 0U; idx < channelCount; idx++) { - channelId = *channelList + idx; + channelId = *(channelList + idx); const char *channelName = nullptr; if (mumAPI.getChannelName(pluginID, activeConnection, channelId, &channelName) == MUMBLE_STATUS_OK) { diff --git a/extensions/src/ACRE2Shared/Log.h b/extensions/src/ACRE2Shared/Log.h index 173e18f82..7aec1c480 100644 --- a/extensions/src/ACRE2Shared/Log.h +++ b/extensions/src/ACRE2Shared/Log.h @@ -48,7 +48,7 @@ namespace acre { #ifdef _TRACE #define LOG(...) g_Log->Write(acre::LogLevel::Info, __FUNCTION__, __LINE__, __VA_ARGS__, NULL) #else - #define LOG(...) g_Log->Write(acre::LogLevel::Info, NULL, NULL, __VA_ARGS__, NULL) + #define LOG(...) g_Log->Write(acre::LogLevel::Info, NULL, 0, __VA_ARGS__, NULL) #endif #ifdef _TRACE diff --git a/extensions/src/ACRE2Shared/Macros.h b/extensions/src/ACRE2Shared/Macros.h index 308ebfef2..3d6c3ee34 100644 --- a/extensions/src/ACRE2Shared/Macros.h +++ b/extensions/src/ACRE2Shared/Macros.h @@ -34,7 +34,7 @@ #define DECLARE_MEMBER_SET(type, name) \ - virtual inline void set##name(##type value) { this->m_##name = value; } + virtual inline void set##name(type value) { this->m_##name = value; } #define DECLARE_MEMBER_GET(type, name) \ virtual inline type get##name() { return this->m_##name; } @@ -73,7 +73,7 @@ protected: \ #define DECLARE_INTERFACE_MEMBER_SET(type, name) \ - virtual void set##name(##type value) = 0; + virtual void set##name(type value) = 0; #define DECLARE_INTERFACE_MEMBER_GET(type, name) \ virtual type get##name() = 0; @@ -90,21 +90,21 @@ public: \ DECLARE_INTERFACE_MEMBER_GET(type, name) -#define RPC_FUNCTION(name) class name## : public IRpcFunction { \ +#define RPC_FUNCTION(name) class name : public IRpcFunction { \ public: \ - name##() : m_Name(STR(name)) {} \ - ~##name(){ } \ + name(){ this->m_Name = STR(name); } \ + ~name(){ } \ acre::Result call(IServer *vServer, IMessage *vMessage) #define CREATE_ITERATOR(type, name, from) \ type name = from; \ - type##::iterator iter_##name; + type::iterator iter_##name; #define DO_ITERATOR(type,name,from) \ CREATE_ITERATOR(type,name,from) \ - for (iter_##name = name##.begin(); \ - iter_##name != name##.end(); \ + for (iter_##name = name.begin(); \ + iter_##name != name.end(); \ iter_##name++ ) #define WAIT_IF_VALID(handle, wait) if (handle != INVALID_HANDLE_VALUE) { \ diff --git a/extensions/src/ACRE2Shared/_CONSTANTS.h b/extensions/src/ACRE2Shared/_CONSTANTS.h index cd8f2e9c6..87b07efd7 100644 --- a/extensions/src/ACRE2Shared/_CONSTANTS.h +++ b/extensions/src/ACRE2Shared/_CONSTANTS.h @@ -42,7 +42,7 @@ #define ACRE_COMMAND_KEYWORD "ACRE2" #define ACRE_VERSION QUOTE(ACRE_VERSION_MAJOR.ACRE_VERSION_MINOR.ACRE_VERSION_SUBMINOR.ACRE_VERSION_BUILD) -#define ACRE_VERSION_METADATA "Version: "QUOTE(ACRE_VERSION_MAJOR)"."QUOTE(ACRE_VERSION_MINOR)"."QUOTE(ACRE_VERSION_SUBMINOR)"."QUOTE(ACRE_VERSION_BUILD) +#define ACRE_VERSION_METADATA "Version: " QUOTE(ACRE_VERSION_MAJOR) "." QUOTE(ACRE_VERSION_MINOR) "." QUOTE(ACRE_VERSION_SUBMINOR) "." QUOTE(ACRE_VERSION_BUILD) /// warning disablers From 9bb69483ff33b9827bd84e0ecdfd7b0dd36431e4 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 03:29:52 -0500 Subject: [PATCH 03/21] Update CMakelists for Linux compatibility This allows ACRE2Core, ACRE2Shared, and ACRE2Wine to be built under Linux toolchains. We gate DirectX inclusion to Windows only; on Linux, we include FAudio as a drop in replacement for x3daudio. .pdb debugging symbols generated on the Windows build are not copied on Linux. PIC has been flipped on for Shared and Core on Linux. ACRE2Arma, ACRE2TS, ACRE2Steam, and the utility modules are not built on Linux, and it doesn't really make sense for them to be. --- extensions/CMakeLists.txt | 45 +++++++++++++++-------- extensions/src/ACRE2Core/CMakeLists.txt | 4 ++ extensions/src/ACRE2Mumble/CMakeLists.txt | 32 +++++++++++++--- extensions/src/ACRE2Shared/CMakeLists.txt | 4 ++ 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/extensions/CMakeLists.txt b/extensions/CMakeLists.txt index 03d9dc0f2..b5e2e6556 100644 --- a/extensions/CMakeLists.txt +++ b/extensions/CMakeLists.txt @@ -9,11 +9,13 @@ option(USE_STATIC_LINKING "USE_STATIC_LINKING" ON) set(CMAKE_BUILD_TYPE "RelWithDebInfo") -find_package(DirectX) -if(DirectX_FOUND) - message("Found DirectX") -else() - message(FATAL_ERROR "DirectX NOT FOUND") +if (WIN32) + find_package(DirectX) + if(DirectX_FOUND) + message("Found DirectX") + else() + message(FATAL_ERROR "DirectX NOT FOUND") + endif() endif() if(USE_STATIC_LINKING) @@ -35,13 +37,21 @@ set(CMAKE_CL_64 ${USE_64BIT_BUILD}) if(USE_64BIT_BUILD) message("INFO: Building 64-bit projects") set(ACRE_ARCH "x64") - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build/win64/") - link_directories("${DirectX_ROOT_DIR}/lib/x64") + if(WIN32) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build/win64/") + link_directories("${DirectX_ROOT_DIR}/lib/x64") + else() + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build/x86_64-linux-gnu/") + endif() else() message("INFO: Building 32-bit projects") set(ACRE_ARCH "x86") - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build/win32/") - link_directories("${DirectX_ROOT_DIR}/lib/x86") + if(WIN32) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build/win32/") + link_directories("${DirectX_ROOT_DIR}/lib/x86") + else() + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build/i686-linux-gnu/") + endif() endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -65,12 +75,15 @@ include_directories(src/ACRE2Core) add_subdirectory(src/ACRE2Shared) add_subdirectory(src/ACRE2Core) -add_subdirectory(src/ACRE2Arma) -add_subdirectory(src/ACRE2Steam) - -add_subdirectory(src/ACRE2TS) add_subdirectory(src/ACRE2Mumble) -#Extras -add_subdirectory(src/Wav2B64) -#add_subdirectory(src/ACRE2DistortionTestPlugin) +if (WIN32) + add_subdirectory(src/ACRE2Arma) + add_subdirectory(src/ACRE2Steam) + + add_subdirectory(src/ACRE2TS) + + #Extras + add_subdirectory(src/Wav2B64) + #add_subdirectory(src/ACRE2DistortionTestPlugin) +endif() diff --git a/extensions/src/ACRE2Core/CMakeLists.txt b/extensions/src/ACRE2Core/CMakeLists.txt index 3f7489a8e..5732364bb 100644 --- a/extensions/src/ACRE2Core/CMakeLists.txt +++ b/extensions/src/ACRE2Core/CMakeLists.txt @@ -8,5 +8,9 @@ file(GLOB SOURCES *.h *.hpp *.c *.cpp) file(GLOB DSP_SOURCES DspFilters/*.h DspFilters/*.hpp DspFilters/*.c DspFilters/*.cpp) add_library( ${ACRE_NAME} STATIC ${SOURCES} ${GLOBAL_SOURCES} ${DSP_SOURCES}) +if(NOT WIN32) + set_property(TARGET ${ACRE_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) + target_link_libraries(${ACRE_NAME} tbb) +endif() target_link_libraries( ${ACRE_NAME} ACRE2Shared) set_target_properties(${ACRE_NAME} PROPERTIES FOLDER ACRE2) diff --git a/extensions/src/ACRE2Mumble/CMakeLists.txt b/extensions/src/ACRE2Mumble/CMakeLists.txt index 26a5ab283..8967ae86b 100644 --- a/extensions/src/ACRE2Mumble/CMakeLists.txt +++ b/extensions/src/ACRE2Mumble/CMakeLists.txt @@ -11,21 +11,41 @@ file(GLOB_RECURSE SOURCES *.h *.hpp *.c *.cpp *.asm mumble_includes/*) include_directories(mumble_includes) add_library( ${ACRE_NAME} MODULE ${SOURCES} ${GLOBAL_SOURCES}) -target_link_libraries(${ACRE_NAME} ACRE2Core ACRE2Shared x3daudio) -set_target_properties(${ACRE_NAME} PROPERTIES FOLDER ACRE2 LINK_FLAGS -SAFESEH:NO) +if(WIN32) + target_link_libraries(${ACRE_NAME} ACRE2Core ACRE2Shared x3daudio) + set_target_properties(${ACRE_NAME} PROPERTIES FOLDER ACRE2 LINK_FLAGS -SAFESEH:NO) +else() + target_link_libraries(${ACRE_NAME} ACRE2Core ACRE2Shared FAudio) +endif() target_compile_features(${ACRE_NAME} PRIVATE cxx_std_17) # Copy and rename -if(USE_64BIT_BUILD) - set(FINAL_DLL_NAME acre2_win64.dll) +if(WIN32) + if(USE_64BIT_BUILD) + set(FINAL_DLL_NAME acre2_win64.dll) + else() + set(FINAL_DLL_NAME acre2_win32.dll) + endif() else() - set(FINAL_DLL_NAME acre2_win32.dll) + if(USE_64BIT_BUILD) + set(FINAL_DLL_NAME acre2_x64.so) + else() + set(FINAL_DLL_NAME acre2_x86.so) + endif() endif() add_custom_command(TARGET ${ACRE_NAME} POST_BUILD # Copy DLL to plugins COMMAND ${CMAKE_COMMAND} -E copy $ ${PROJECT_SOURCE_DIR}/../plugin/mumble/${FINAL_DLL_NAME} # Copy PDB to symbols - COMMAND ${CMAKE_COMMAND} -E copy $/${ACRE_NAME}.pdb ${PROJECT_SOURCE_DIR}/../symbols/${ACRE_ARCH}/${ACRE_NAME}.pdb + COMMAND_EXPAND_LISTS ) + +if(WIN32) + add_custom_command(TARGET ${ACRE_NAME} POST_BUILD + # Copy PDB to symbols + COMMAND ${CMAKE_COMMAND} -E copy $/${ACRE_NAME}.pdb ${PROJECT_SOURCE_DIR}/../symbols/${ACRE_ARCH}/${ACRE_NAME}.pdb + COMMAND_EXPAND_LISTS + ) +endif() diff --git a/extensions/src/ACRE2Shared/CMakeLists.txt b/extensions/src/ACRE2Shared/CMakeLists.txt index 79007c67d..eccb92df9 100644 --- a/extensions/src/ACRE2Shared/CMakeLists.txt +++ b/extensions/src/ACRE2Shared/CMakeLists.txt @@ -9,3 +9,7 @@ file(GLOB SOURCES *.h *.hpp *.c *.cpp) add_library( ${ACRE_NAME} STATIC ${SOURCES} ${GLOBAL_SOURCES}) target_link_libraries( ${ACRE_NAME}) set_target_properties(${ACRE_NAME} PROPERTIES FOLDER ACRE2) + +if (NOT WIN32) +set_property(TARGET ${ACRE_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) +endif() From 8a2833f4da4c7efbe9f351001e33568af410024b Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 03:34:56 -0500 Subject: [PATCH 04/21] Extend compat.h to provide Linux compat types Some Windows types and functions have been aliased for compilation on Linux. --- extensions/src/ACRE2Shared/compat.h | 48 ++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/extensions/src/ACRE2Shared/compat.h b/extensions/src/ACRE2Shared/compat.h index 7ab7d6cac..52106fcac 100644 --- a/extensions/src/ACRE2Shared/compat.h +++ b/extensions/src/ACRE2Shared/compat.h @@ -10,13 +10,18 @@ #pragma warning(disable : 4366) -#define _WINSOCKAPI_ -#define NOMINMAX -#include -#include +#ifdef WIN32 + #define _WINSOCKAPI_ + #define NOMINMAX + #include + #include + #include +#endif + #include -#include #include +#include +#include #ifdef _ACRE_DEBUG_HEAP #define _CRTDBG_MAP_ALLOC @@ -30,14 +35,14 @@ #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "advapi32.lib") - #ifdef _WIN64 + #ifdef _WIN64 #pragma comment(lib, "..\\..\\ACRE2Shared\\bin\\ACRE2Shared_x64.lib") #else #pragma comment(lib, "..\\..\\ACRE2Shared\\bin\\ACRE2Shared_x86.lib") #endif #ifndef _NOCORE - #ifdef _WIN64 + #ifdef _WIN64 #pragma comment(lib, "..\\..\\ACRE2Core\\bin\\ACRE2Core_x64.lib") #else #pragma comment(lib, "..\\..\\ACRE2Core\\bin\\ACRE2Core_x86.lib") @@ -46,4 +51,31 @@ #endif */ //#include "Exception.h" -#include "_CONSTANTS.h" \ No newline at end of file +#include "_CONSTANTS.h" + +#ifdef WIN32 +#define PATH_SEPARATOR "\\" + +#else + +#include +#include +#include + +#define PATH_SEPARATOR "/" + +#define TRUE true +#define FALSE false +typedef int BOOL; +typedef uint32_t DWORD; + +#define MAXSHORT SHRT_MAX +#define MINSHORT SHRT_MIN + +#define LocalAlloc(x, y) calloc(1, y) +#define LocalFree free +#define LocalReAlloc(x, y, z) realloc(x, y) +#define GetLastError() errno +#define Sleep(x) usleep(x * 1000) + +#endif From 51c07371a536db747e52812393bbb127d02d5c4d Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 03:36:39 -0500 Subject: [PATCH 05/21] Provide FAudio/x3daudio compatibility on Linux FilterPosition relies on x3daudio to do positional transformations. On Linux, we can use FAudio as an (almost) drop-in replacement. --- extensions/src/ACRE2Core/FilterPosition.cpp | 8 +++++++- extensions/src/ACRE2Core/FilterPosition.h | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/extensions/src/ACRE2Core/FilterPosition.cpp b/extensions/src/ACRE2Core/FilterPosition.cpp index c025f5247..60562d09d 100644 --- a/extensions/src/ACRE2Core/FilterPosition.cpp +++ b/extensions/src/ACRE2Core/FilterPosition.cpp @@ -7,7 +7,9 @@ #include "Log.h" #include +#ifdef WIN32 #pragma comment(lib, "x3daudio.lib") +#endif #define MAX_FALLOFF_DISTANCE 75 #define MAX_FALLOFF_RANGE 150 @@ -69,7 +71,7 @@ acre::Result CFilterPosition::process(short* samples, int sampleCount, int chann Emitter.OrientFront = vector_speakerDirection; Emitter.OrientTop = this->getUpVector(vector_speakerDirection); - Emitter.Velocity = X3DAUDIO_VECTOR( 0, 0, 0 ); + Emitter.Velocity = X3DAUDIO_VECTOR(); Emitter.ChannelCount = 1; if (params->getParam("isWorld") == POSITIONAL_EFFECT_ISWORLD) { @@ -211,12 +213,16 @@ X3DAUDIO_VECTOR CFilterPosition::getUpVector(X3DAUDIO_VECTOR inVector) { CFilterPosition::CFilterPosition(void) { +#ifdef WIN32 CoInitializeEx(NULL, NULL); +#endif this->p_IsInitialized = FALSE; } CFilterPosition::~CFilterPosition(void) { +#ifdef WIN32 CoUninitialize(); +#endif } /* diff --git a/extensions/src/ACRE2Core/FilterPosition.h b/extensions/src/ACRE2Core/FilterPosition.h index 2ee1cb1e9..cf4cd2086 100644 --- a/extensions/src/ACRE2Core/FilterPosition.h +++ b/extensions/src/ACRE2Core/FilterPosition.h @@ -5,7 +5,25 @@ #include "Macros.h" #include "SoundMixdownEffect.h" +#ifdef WIN32 #include +#else +#include +#define X3DAUDIO_CALCULATE_EMITTER_ANGLE F3DAUDIO_CALCULATE_EMITTER_ANGLE +#define X3DAUDIO_CALCULATE_MATRIX F3DAUDIO_CALCULATE_MATRIX +#define X3DAUDIO_CONE F3DAUDIO_CONE +#define X3DAUDIO_DISTANCE_CURVE F3DAUDIO_DISTANCE_CURVE +#define X3DAUDIO_DISTANCE_CURVE_POINT F3DAUDIO_DISTANCE_CURVE_POINT +#define X3DAUDIO_DSP_SETTINGS F3DAUDIO_DSP_SETTINGS +#define X3DAUDIO_EMITTER F3DAUDIO_EMITTER +#define X3DAUDIO_HANDLE F3DAUDIO_HANDLE +#define X3DAUDIO_LISTENER F3DAUDIO_LISTENER +#define X3DAUDIO_PI F3DAUDIO_PI +#define X3DAUDIO_VECTOR F3DAUDIO_VECTOR +#define X3DAudioCalculate F3DAudioCalculate +#define X3DAudioInitialize F3DAudioInitialize +#define X3DAUDIO_SPEED_OF_SOUND 343.5 +#endif class CFilterPosition { From a986200f9129a602415267de566f490573ea4654 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 03:39:01 -0500 Subject: [PATCH 06/21] Alias tbb concurrency modules on Linux Intel TBB is available as a library on Linux, under the `tbb` namespace, rather than the `concurrency` namespace as on Windows. --- extensions/src/ACRE2Core/NamedPipeServer.h | 9 ++++++++- extensions/src/ACRE2Core/SoundMixdownEffect.h | 6 ++++++ extensions/src/ACRE2Core/SoundMixer.h | 5 +++++ extensions/src/ACRE2Core/SoundMonoEffect.h | 6 ++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/extensions/src/ACRE2Core/NamedPipeServer.h b/extensions/src/ACRE2Core/NamedPipeServer.h index 65314ca91..355fd82e6 100644 --- a/extensions/src/ACRE2Core/NamedPipeServer.h +++ b/extensions/src/ACRE2Core/NamedPipeServer.h @@ -4,8 +4,15 @@ #include "Types.h" #include "IMessage.h" #include "IServer.h" +#include "AcreSettings.h" +#ifdef WIN32 #include +#else +#include +namespace concurrency = tbb; +#endif + #include #include #include @@ -61,7 +68,7 @@ class CNamedPipeServer : public IServer, public CLockable { bool m_shuttingDown; private: - Concurrency::concurrent_queue m_sendQueue; + concurrency::concurrent_queue m_sendQueue; std::thread m_readThread; std::thread m_sendThread; PSECURITY_ATTRIBUTES m_PipeSecurity; diff --git a/extensions/src/ACRE2Core/SoundMixdownEffect.h b/extensions/src/ACRE2Core/SoundMixdownEffect.h index 12c5d027a..e51116afe 100644 --- a/extensions/src/ACRE2Core/SoundMixdownEffect.h +++ b/extensions/src/ACRE2Core/SoundMixdownEffect.h @@ -4,7 +4,13 @@ #include "Lockable.h" #include #include + +#ifdef WIN32 #include +#else +#include +namespace concurrency = tbb; +#endif class CSoundMixdownEffect : public CLockable { private: diff --git a/extensions/src/ACRE2Core/SoundMixer.h b/extensions/src/ACRE2Core/SoundMixer.h index b946ef521..a7d815972 100644 --- a/extensions/src/ACRE2Core/SoundMixer.h +++ b/extensions/src/ACRE2Core/SoundMixer.h @@ -6,7 +6,12 @@ #include "SoundMonoChannel.h" #include +#ifdef WIN32 #include +#else +#include +namespace concurrency = tbb; +#endif class CSoundMixer : public CLockable { private: diff --git a/extensions/src/ACRE2Core/SoundMonoEffect.h b/extensions/src/ACRE2Core/SoundMonoEffect.h index 93375828e..eb092813e 100644 --- a/extensions/src/ACRE2Core/SoundMonoEffect.h +++ b/extensions/src/ACRE2Core/SoundMonoEffect.h @@ -4,7 +4,13 @@ #include "Lockable.h" #include #include + +#ifdef WIN32 #include +#else +#include +namespace concurrency = tbb; +#endif class CSoundMonoEffect : public CLockable { private: From 34ab3c693d8cf9e0d1477918372e296032561ccc Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 03:43:17 -0500 Subject: [PATCH 07/21] Update paths when building on Linux ACRE's config file will be stored in $XDG_CONFIG_HOME (~/.config), as per the XDG standard. Temporary files are stored in /tmp/acre-${USER}, and logs in $XDG_DATA_HOME (~/.local/share). This tends to be Linux desktop users expect. --- extensions/src/ACRE2Core/Engine.cpp | 17 +++++++++++++++-- extensions/src/ACRE2Core/SoundPlayback.cpp | 4 ++-- extensions/src/ACRE2Mumble/MumbleClient.cpp | 17 +++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/extensions/src/ACRE2Core/Engine.cpp b/extensions/src/ACRE2Core/Engine.cpp index d8f329c75..dc157b672 100644 --- a/extensions/src/ACRE2Core/Engine.cpp +++ b/extensions/src/ACRE2Core/Engine.cpp @@ -29,21 +29,34 @@ #include "setSelectableVoiceCurve.h" #include "setSetting.h" #include "setChannelDetails.h" + +#ifdef WIN32 #include +#else +#include +#endif acre::Result CEngine::initialize(IClient *client, IServer *externalServer, std::string fromPipeName, std::string toPipeName) { if (!g_Log) { std::string acrePluginLog{"acre2_plugin.log"}; +#ifdef WIN32 std::array appDataPath{""}; if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, appDataPath.data()))) { acrePluginLog = std::string(appDataPath.data()) + "\\Arma 3\\" + acrePluginLog; } +#else + if (getenv("XDG_DATA_HOME")) { + acrePluginLog = std::string(getenv("XDG_DATA_HOME")) + "/" + acrePluginLog; + } else { + acrePluginLog = std::string(getenv("HOME")) + "/.local/share/" + acrePluginLog; + } +#endif g_Log = (Log *) new Log(acrePluginLog.c_str()); LOG("* Logging engine initialized."); } - LOG("Configuration Path: {%s\\acre2.ini}", client->getConfigFilePath().c_str()); - CAcreSettings::getInstance()->load(client->getConfigFilePath() + "\\acre2.ini"); + LOG("Configuration Path: {%s%sacre2.ini}", client->getConfigFilePath().c_str(), PATH_SEPARATOR); + CAcreSettings::getInstance()->load(client->getConfigFilePath() + PATH_SEPARATOR + "acre2.ini"); this->setClient(client); this->setExternalServer(externalServer); diff --git a/extensions/src/ACRE2Core/SoundPlayback.cpp b/extensions/src/ACRE2Core/SoundPlayback.cpp index 9ddd09085..dbb043e9a 100644 --- a/extensions/src/ACRE2Core/SoundPlayback.cpp +++ b/extensions/src/ACRE2Core/SoundPlayback.cpp @@ -35,7 +35,7 @@ acre::Result CSoundPlayback::loadSound(std::string id) { std::string tempPath = CEngine::getInstance()->getClient()->getTempFilePath(); - tempPath += "\\"; + tempPath += PATH_SEPARATOR; tempPath += id; std::ofstream out(tempPath, std::ios::out | std::ios::binary); if (!out.is_open()) { @@ -52,7 +52,7 @@ acre::Result CSoundPlayback::loadSound(std::string id) { acre::Result CSoundPlayback::playSound(std::string id, acre::vec3_fp32_t position, acre::vec3_fp32_t direction, float volume, bool isWorld) { std::string tempPath = CEngine::getInstance()->getClient()->getTempFilePath(); - tempPath += "\\"; + tempPath += PATH_SEPARATOR; tempPath += id; CWave waveFile; if (waveFile.Load(tempPath)) { diff --git a/extensions/src/ACRE2Mumble/MumbleClient.cpp b/extensions/src/ACRE2Mumble/MumbleClient.cpp index d8c904ca5..d194e7e03 100644 --- a/extensions/src/ACRE2Mumble/MumbleClient.cpp +++ b/extensions/src/ACRE2Mumble/MumbleClient.cpp @@ -218,15 +218,24 @@ std::string CMumbleClient::getUniqueId() { } std::string CMumbleClient::getConfigFilePath(void) { +#ifdef WIN32 std::string tempFolder = ".\\acre"; if (!PathFileExistsA(tempFolder.c_str()) && !CreateDirectoryA(tempFolder.c_str(), nullptr)) { LOG("ERROR: UNABLE TO CREATE TEMP DIR"); } return tempFolder; +#else + if (getenv("XDG_CONFIG_HOME")) { + return std::string(getenv("XDG_CONFIG_HOME")); + } else { + return std::string(getenv("HOME")) + "/.config"; + } +#endif } std::string CMumbleClient::getTempFilePath(void) { +#ifdef WIN32 char tempPath[MAX_PATH - 14]; GetTempPathA(sizeof(tempPath), tempPath); std::string tempFolder = std::string(tempPath); @@ -236,6 +245,14 @@ std::string CMumbleClient::getTempFilePath(void) { } return tempFolder; +#else + std::string dirname = std::string("/tmp/acre-") + getenv("USER"); + int result = mkdir(dirname.c_str(), 0755); + if (result == -1 && errno != EEXIST) { + LOG("ERROR: UNABLE TO CREATE TEMP DIR"); + } + return dirname; +#endif } acre::Result CMumbleClient::microphoneOpen(bool status_) { From af178c9f09345025eabab2c3b2e83d9f0555adf1 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 03:50:22 -0500 Subject: [PATCH 08/21] Make Wave build on Linux --- extensions/src/ACRE2Core/Wave.cpp | 6 +++++- extensions/src/ACRE2Core/Wave.h | 25 ++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/extensions/src/ACRE2Core/Wave.cpp b/extensions/src/ACRE2Core/Wave.cpp index 2c595dcd8..a60f3f0f2 100644 --- a/extensions/src/ACRE2Core/Wave.cpp +++ b/extensions/src/ACRE2Core/Wave.cpp @@ -1,6 +1,10 @@ +#ifdef WIN32 #include -#include #include +#else +#include +#endif +#include #include "Wave.h" #include "math.h" #include diff --git a/extensions/src/ACRE2Core/Wave.h b/extensions/src/ACRE2Core/Wave.h index 60a717477..3fc59ede3 100644 --- a/extensions/src/ACRE2Core/Wave.h +++ b/extensions/src/ACRE2Core/Wave.h @@ -1,12 +1,31 @@ #pragma once -#include +#include + +#ifdef WIN32 #include -#include -#include #include "Mmsystem.h" +#endif + +#include #include +#ifdef __linux__ +#define BYTE unsigned char +#define LPBYTE unsigned char* +#define SHORT short +#define HWAVEOUT void* +typedef struct wavehdr_tag { + char* lpData; + DWORD dwBufferLength; + DWORD dwBytesRecorded; + DWORD* dwUser; + DWORD dwFlags; + DWORD dwLoops; + struct wavehdr_tag *lpNext; + DWORD* reserved; +} WAVEHDR, *LPWAVEHDR; +#endif typedef struct __WAVEDESCR { From bec0e9961fb0be8dc08f0e0d95ffd79d965fcfab Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 03:53:04 -0500 Subject: [PATCH 09/21] Build Log, TextMessage, ini on Linux Replace some Windows specific string functions with cross-compatible ones, and don't try to pop up message boxes on Linux. --- extensions/src/ACRE2Shared/Log.cpp | 12 +++++++++++- extensions/src/ACRE2Shared/Log.h | 2 +- extensions/src/ACRE2Shared/TextMessage.cpp | 20 ++++++++++---------- extensions/src/ACRE2Shared/ini.cpp | 8 ++++++-- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/extensions/src/ACRE2Shared/Log.cpp b/extensions/src/ACRE2Shared/Log.cpp index 617957ba8..9dd5070a1 100644 --- a/extensions/src/ACRE2Shared/Log.cpp +++ b/extensions/src/ACRE2Shared/Log.cpp @@ -4,6 +4,12 @@ #include #include +#ifdef __linux +#include +#include +#define strncat(x, y, z) strncat(x, y, z - 1) +#endif + Log *g_Log = nullptr; Log::Log(const char * const logFile) { @@ -23,7 +29,7 @@ Log::~Log(void) { logOutput.close(); } } -size_t Log::Write(const acre::LogLevel msgType, char *function, const uint32_t line, const char *format, ...) { +size_t Log::Write(const acre::LogLevel msgType, const char *function, const uint32_t line, const char *format, ...) { char buffer[4097], tbuffer[1024]; va_list va; @@ -72,9 +78,11 @@ size_t Log::Write(const acre::LogLevel msgType, char *function, const uint32_t l // test debug, print it too printf("%s", buffer); +#ifdef WIN32 if (msgType == acre::LogLevel::Error) { MessageBoxA(NULL, buffer, "CRITICAL ERROR", MB_OK); } +#endif return(ret); } @@ -87,7 +95,9 @@ size_t Log::PopMessage(const acre::LogLevel msgType, const char *format, ...) { int32_t ret = vsnprintf(buffer, 4096, format, va); va_end(va); +#ifdef WIN32 ret = MessageBoxA(NULL, buffer, "Log Message", MB_ICONINFORMATION | MB_OK); +#endif return(ret); } diff --git a/extensions/src/ACRE2Shared/Log.h b/extensions/src/ACRE2Shared/Log.h index 7aec1c480..3ffb0c8c9 100644 --- a/extensions/src/ACRE2Shared/Log.h +++ b/extensions/src/ACRE2Shared/Log.h @@ -67,7 +67,7 @@ class Log { Log(const char *const logFile); ~Log(void); - size_t Write(const acre::LogLevel msgType, char *function, const uint32_t line, const char *format, ...); + size_t Write(const acre::LogLevel msgType, const char *function, const uint32_t line, const char *format, ...); size_t PopMessage(const acre::LogLevel msgType, const char *format, ...); std::ofstream logOutput; diff --git a/extensions/src/ACRE2Shared/TextMessage.cpp b/extensions/src/ACRE2Shared/TextMessage.cpp index 2896c4afd..eff486d49 100644 --- a/extensions/src/ACRE2Shared/TextMessage.cpp +++ b/extensions/src/ACRE2Shared/TextMessage.cpp @@ -170,15 +170,15 @@ IMessage *CTextMessage::formatNewMessage(const char * const procedureName, const LOG("LocalAlloc() failed: %d", GetLastError()); return nullptr; } - + buffer[0] = 0x00; - _snprintf_s(finalBuffer, TEXTMESSAGE_BUFSIZE, TEXTMESSAGE_BUFSIZE-1, "%s:", procedureName); - + snprintf(finalBuffer, TEXTMESSAGE_BUFSIZE, "%s:", procedureName); + va_start(va, format); - vsprintf_s(buffer, sizeof(buffer), format, va); + vsprintf(buffer, format, va); va_end(va); - strcat_s(finalBuffer, TEXTMESSAGE_BUFSIZE, buffer); + strncat(finalBuffer, buffer, TEXTMESSAGE_BUFSIZE - strlen(finalBuffer)); CTextMessage *msg = new CTextMessage(finalBuffer, strlen(finalBuffer) + 1); @@ -208,14 +208,14 @@ IMessage *CTextMessage::createNewMessage(char *procedureName, ... ) { } buffer[0] = 0x00; - _snprintf_s(buffer, TEXTMESSAGE_BUFSIZE, TEXTMESSAGE_BUFSIZE - 1, "%s:", procedureName); - + snprintf(buffer, TEXTMESSAGE_BUFSIZE, "%s:", procedureName); + va_start(va, procedureName); char *ptr = va_arg( va, char * ); while (ptr != nullptr) { - strcat_s(buffer, TEXTMESSAGE_BUFSIZE, ptr); - strcat_s(buffer, TEXTMESSAGE_BUFSIZE, ","); - ptr = va_arg( va, char * ); + strncat(buffer, ptr, TEXTMESSAGE_BUFSIZE - strlen(buffer)); + strncat(buffer, ",", TEXTMESSAGE_BUFSIZE - strlen(buffer)); + ptr = va_arg( va, char * ); } va_end(va); diff --git a/extensions/src/ACRE2Shared/ini.cpp b/extensions/src/ACRE2Shared/ini.cpp index be46aa9df..f2e0528e1 100644 --- a/extensions/src/ACRE2Shared/ini.cpp +++ b/extensions/src/ACRE2Shared/ini.cpp @@ -110,7 +110,7 @@ int ini_parse_file(FILE* file, end = find_char_or_comment(start + 1, ']'); if (*end == ']') { *end = '\0'; - strncpy_s(section, MAX_SECTION, start + 1, sizeof(section)); + strncpy(section, start + 1, sizeof(section)); *prev_name = '\0'; } else if (!error) { @@ -134,7 +134,7 @@ int ini_parse_file(FILE* file, rstrip(value); /* Valid name[=:]value pair found, call handler */ - strncpy_s(prev_name, MAX_NAME, name, sizeof(prev_name)); + strncpy(prev_name, name, sizeof(prev_name)); if (!handler(user, section, name, value) && !error) error = lineno; } @@ -164,7 +164,11 @@ int ini_parse(const char* filename, { FILE* file; int error; +#ifdef WIN32 fopen_s(&file, filename, "r"); +#else + file = fopen(filename, "r"); +#endif if (!file) return -1; error = ini_parse_file(file, handler, user); From 891ef0832c6b57091a76ab270d387c09d534c075 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 03:54:09 -0500 Subject: [PATCH 10/21] Wrap Windows includes in platform checks An unused sddl.h include has also been removed --- extensions/src/ACRE2Core/getClientID.h | 1 - extensions/src/ACRE2Mumble/MumbleClient.cpp | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/src/ACRE2Core/getClientID.h b/extensions/src/ACRE2Core/getClientID.h index b1f678c5a..f9c6d9bdf 100644 --- a/extensions/src/ACRE2Core/getClientID.h +++ b/extensions/src/ACRE2Core/getClientID.h @@ -5,7 +5,6 @@ #include "Macros.h" #include "Log.h" #include "IRpcFunction.h" -#include #include "IServer.h" #include "Engine.h" diff --git a/extensions/src/ACRE2Mumble/MumbleClient.cpp b/extensions/src/ACRE2Mumble/MumbleClient.cpp index d194e7e03..81678e9b8 100644 --- a/extensions/src/ACRE2Mumble/MumbleClient.cpp +++ b/extensions/src/ACRE2Mumble/MumbleClient.cpp @@ -3,12 +3,17 @@ #include "Log.h" #include "MumbleClient.h" #include "MumbleFunctions.h" -#include "Shlwapi.h" #include "Types.h" #include "compat.h" + +#ifdef WIN32 +#include "Shlwapi.h" #include "shlobj.h" #pragma comment(lib, "Shlwapi.lib") +#else +#include +#endif static constexpr std::int32_t invalid_mumble_channel = -1; constexpr char default_mumble_channel[] = "ACRE"; From c984069f9e1b7e9fac653338c6d3fc4d75494ba2 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 03:55:14 -0500 Subject: [PATCH 11/21] Use clock_gettime on Linux --- extensions/src/ACRE2Core/ping.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/extensions/src/ACRE2Core/ping.h b/extensions/src/ACRE2Core/ping.h index ab53984a6..128d59762 100644 --- a/extensions/src/ACRE2Core/ping.h +++ b/extensions/src/ACRE2Core/ping.h @@ -10,8 +10,14 @@ volatile DWORD g_pingTime; RPC_FUNCTION(ping) { +#ifdef WIN32 g_pingTime = clock() / CLOCKS_PER_SEC; - vServer->sendMessage(CTextMessage::formatNewMessage("pong", "%f,", g_pingTime)); +#else + timespec t; + clock_gettime(CLOCK_MONOTONIC_RAW, &t); + g_pingTime = t.tv_sec; +#endif + vServer->sendMessage(CTextMessage::formatNewMessage("pong", "%f,", (float) g_pingTime)); return acre::Result::ok; } public: From 8def7451be99a7b50632023ca4587f0d01d8a138 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 04:00:40 -0500 Subject: [PATCH 12/21] Do not load AcreSettings in constructor If the default path baked into the constructor is not the same as one that is later loaded, the user will end up with two config files! Only one will be used. There is no need to load the config file in the constructor, however. Hardcoded defaults are already set, and users of the class all load config files explicitly. --- extensions/src/ACRE2Core/AcreSettings.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/src/ACRE2Core/AcreSettings.cpp b/extensions/src/ACRE2Core/AcreSettings.cpp index 090770e7f..bc7068ca3 100644 --- a/extensions/src/ACRE2Core/AcreSettings.cpp +++ b/extensions/src/ACRE2Core/AcreSettings.cpp @@ -71,7 +71,6 @@ CAcreSettings::CAcreSettings() : { // Set defaults! //LOG("Config Singleton Initialized"); - this->load(); } From a8957d9b50985502038999bef3cbd22962130925 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Thu, 25 Aug 2022 04:08:27 -0500 Subject: [PATCH 13/21] Reimplement NamedPipeServer on Linux This is the most involved change in this changeset. On Linux, Arma runs under WINE, but Mumble is native. There's no (known to me) way to do IPC between WINE processes and native processes; WINE makes it (purposefully?) difficult. It may be possible to use Windows 10+ Unix socket compatibility (if WINE supports it), or some other mechanism. But this solution uses a simple duplex network socket listening on localhost, with a default port of 19141. The Mumble side is responsible for setting up the server, and the Arma side connects. ACRE uses Windows named pipes in "message" mode, which means rather than a stream of bytes, senders send a stream of messages and receivers receive whole messages, not partial messages. This is not the case with a TCP socket, and so a simple length encoding is used. Whenever a sender has a message to send, they first send a four byte unsigned integer that is the length of the message to come, and the receiver first reads exactly four bytes, decodes the length of the message, then reads exactly that many bytes. The code is written to be tolerant (as in: will not crash, and will simply drop the connection and wait for the otherside to reconnect) to network faults and partial sends/receives. However, given that the client and server are on the same networking stack, conditions are ideal: sends and receives should match up exactly, and faults should be impossible. Since the port chosen could conflict with another server, possibly another instance of Mumble/Acre/Arma, it is configurable. On the Mumble side, it can be configured in the ACRE config file. On the Arma side, it will be specified as a CBA setting and passed in to the extension via a parameter to callExtension. --- extensions/src/ACRE2Core/AcreSettings.cpp | 9 + extensions/src/ACRE2Core/AcreSettings.h | 4 + extensions/src/ACRE2Core/NamedPipeServer.cpp | 335 +++++++++++++++++-- extensions/src/ACRE2Core/NamedPipeServer.h | 14 +- 4 files changed, 336 insertions(+), 26 deletions(-) diff --git a/extensions/src/ACRE2Core/AcreSettings.cpp b/extensions/src/ACRE2Core/AcreSettings.cpp index bc7068ca3..d515cc517 100644 --- a/extensions/src/ACRE2Core/AcreSettings.cpp +++ b/extensions/src/ACRE2Core/AcreSettings.cpp @@ -16,6 +16,9 @@ acre::Result CAcreSettings::save(std::string filename) { iniFile << "premixGlobalVolume = " << this->m_PremixGlobalVolume << ";\n"; iniFile << "disableUnmuteClients = " << (this->m_DisableUnmuteClients ? "true" : "false") << ";\n"; iniFile << "disableChannelSwitch = " << (this->m_DisableChannelSwitch ? "true" : "false") << ";\n"; +#ifdef __linux__ + iniFile << "wineSocketPort = " << (this->m_WineSocketPort) << ";\n"; +#endif //LOG("Config Save: %f,%f", m_GlobalVolume, m_PremixGlobalVolume); iniFile.flush(); @@ -41,6 +44,9 @@ acre::Result CAcreSettings::load(std::string filename) { this->m_PremixGlobalVolume = (float)config.GetReal("acre2", "premixGlobalVolume", 1.0f); this->m_DisableUnmuteClients = config.GetBoolean("acre2", "disableUnmuteClients", false); this->m_DisableChannelSwitch = config.GetBoolean("acre2", "disableChannelSwitch", false); +#ifdef __linux__ + this->m_WineSocketPort = config.GetInteger("acre2", "wineSocketPort", 19141); +#endif //LOG("Config Load: %f,%f", m_GlobalVolume, m_PremixGlobalVolume); this->m_Path = filename; @@ -58,6 +64,9 @@ acre::Result CAcreSettings::load() { } CAcreSettings::CAcreSettings() : +#ifdef __linux__ + m_WineSocketPort(19141), +#endif m_GlobalVolume(1.0f), m_PremixGlobalVolume(1.0f), m_DisablePosition(false), diff --git a/extensions/src/ACRE2Core/AcreSettings.h b/extensions/src/ACRE2Core/AcreSettings.h index 6cc84c8b7..a10a81a70 100644 --- a/extensions/src/ACRE2Core/AcreSettings.h +++ b/extensions/src/ACRE2Core/AcreSettings.h @@ -31,5 +31,9 @@ class CAcreSettings : DECLARE_MEMBER(bool, DisableChannelSwitch); DECLARE_MEMBER(bool, EnableAudioTest); +#ifdef __linux__ + DECLARE_MEMBER(uint16_t, WineSocketPort); +#endif + DECLARE_MEMBER(std::string, Path); }; diff --git a/extensions/src/ACRE2Core/NamedPipeServer.cpp b/extensions/src/ACRE2Core/NamedPipeServer.cpp index 544e7c0cc..bf50750bf 100644 --- a/extensions/src/ACRE2Core/NamedPipeServer.cpp +++ b/extensions/src/ACRE2Core/NamedPipeServer.cpp @@ -1,29 +1,62 @@ #include "NamedPipeServer.h" #include "TextMessage.h" -#include #include "Log.h" #include "Engine.h" +#ifdef WIN32 +#include +#else +#include +#include +#include +#include +#endif - +#ifdef WIN32 +typedef clock_t walltime_t; +#else +typedef timespec walltime_t; +#endif CNamedPipeServer::CNamedPipeServer(std::string fromPipeName, std::string toPipeName) { this->setConnectedWrite(false); this->setConnectedRead(false); - this->setPipeHandleWrite(INVALID_HANDLE_VALUE); - this->setPipeHandleRead(INVALID_HANDLE_VALUE); this->setShuttingDown(false); +#ifdef WIN32 + this->setPipeHandleWrite(INVALID_HANDLE_VALUE); + this->setPipeHandleRead(INVALID_HANDLE_VALUE); this->setFromPipeName(fromPipeName); this->setToPipeName(toPipeName); - +#endif } CNamedPipeServer::~CNamedPipeServer( void ) { this->shutdown(); } +walltime_t getMonotime() { +#ifdef WIN32 + return clock(); +#else + walltime_t ret; + clock_gettime(CLOCK_MONOTONIC_RAW, &ret); + return ret; +#endif +} + +long diffMonotime(walltime_t current, walltime_t previous) { +#ifdef WIN32 + return ((current - previous) * 1000) / CLOCKS_PER_SEC; +#else + time_t s = (current.tv_sec - previous.tv_sec); + time_t ms = (time_t) ((current.tv_nsec - previous.tv_nsec) / 1000000); + return s * 1000 + ms; +#endif +} + acre::Result CNamedPipeServer::initialize() { +#ifdef WIN32 HANDLE writeHandle, readHandle; SECURITY_DESCRIPTOR sd; @@ -31,12 +64,14 @@ acre::Result CNamedPipeServer::initialize() { if (!SetSecurityDescriptorDacl(&sd, TRUE, nullptr, FALSE)) { LOG("SetSecurityDescriptorDacl Error : %u", GetLastError()); } if (!SetSecurityDescriptorControl(&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED)) { LOG("SetSecurityDescriptorControl Error : %u", GetLastError()); } SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), &sd, true }; +#endif // open our pipe handle, then kick up a thread to monitor it and add shit to our queue // this end LISTENS and CREATES the pipe LOG("Opening game pipe..."); bool tryAgain = true; +#ifdef WIN32 while (tryAgain) { writeHandle = CreateNamedPipeA( this->getFromPipeName().c_str(), // name of the pipe @@ -100,17 +135,49 @@ acre::Result CNamedPipeServer::initialize() { this->m_sendThread = std::thread(&CNamedPipeServer::sendLoop, this); this->m_readThread = std::thread(&CNamedPipeServer::readLoop, this); +#else + this->m_sockFD = socket(AF_INET, SOCK_STREAM, 0); + + const struct sockaddr_in listenAddr = { + .sin_family = AF_INET, + .sin_port = htons(acreListenPort), + .sin_addr = { + htonl(INADDR_LOOPBACK) + } + }; + + int param = 1; + setsockopt(this->m_sockFD, SOL_SOCKET, SO_REUSEADDR, ¶m, sizeof(int)); + int ret = bind(this->m_sockFD, (struct sockaddr *) &listenAddr, sizeof(listenAddr)); + + if(ret) { + LOG("Could not bind to port %d, error %d", acreListenPort, errno); + return acre::Result::error; + } + + LOG("Bound on port %d", acreListenPort); + + ret = listen(this->m_sockFD, 1); + if (ret) { + LOG("Could not listen on port %d, error %d", acreListenPort, errno); + return acre::Result::error; + } + + this->m_readThread = std::thread(&CNamedPipeServer::readLoop, this); + this->m_sendThread = std::thread(&CNamedPipeServer::sendLoop, this); +#endif + return acre::Result::ok; } acre::Result CNamedPipeServer::shutdown(void) { - HANDLE hPipe; - this->setShuttingDown(true); this->setConnectedWrite(false); this->setConnectedRead(false); - + +#ifdef WIN32 + HANDLE hPipe; //Wake the synchronous named pipe //Called from the same process but from a different thread hPipe = CreateFile(this->getToPipeName().c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); @@ -118,18 +185,24 @@ acre::Result CNamedPipeServer::shutdown(void) { DisconnectNamedPipe(hPipe); CloseHandle(hPipe); } +#else + ::shutdown(this->m_sockFD, SHUT_RDWR); + close(this->m_sockFD); +#endif // Read should initiate the full shutdown, so we wait for him to die first and we only wake him. if (this->m_readThread.joinable()) { this->m_readThread.join(); } +#ifdef WIN32 // Now we wake the write pipe just in case. hPipe = CreateFile(this->getFromPipeName().c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); if (hPipe != INVALID_HANDLE_VALUE) { DisconnectNamedPipe(hPipe); CloseHandle(hPipe); } +#endif if (this->m_sendThread.joinable()) { this->m_sendThread.join(); @@ -156,13 +229,13 @@ acre::Result CNamedPipeServer::sendLoop() { } } while (!this->getConnectedWrite() && !this->getShuttingDown()); - clock_t lastTick = clock() / CLOCKS_PER_SEC; + walltime_t lastTick = getMonotime(); while (this->getConnectedWrite()) { if (this->getShuttingDown()) break; - clock_t tick = clock() / CLOCKS_PER_SEC; - if (tick - lastTick > (PIPE_TIMEOUT / 1000)) { + walltime_t tick = getMonotime(); + if (diffMonotime(tick, lastTick) > PIPE_TIMEOUT) { LOG("No send message for %d seconds, disconnecting", (PIPE_TIMEOUT / 1000)); this->setConnectedWrite(false); break; @@ -171,8 +244,8 @@ acre::Result CNamedPipeServer::sendLoop() { IMessage *msg = nullptr; if (this->m_sendQueue.try_pop(msg)) { if (msg != nullptr) { - lastTick = clock() / CLOCKS_PER_SEC; - const DWORD size = (DWORD)strlen((char *)msg->getData()) + 1; + lastTick = getMonotime(); + const DWORD size = (uint32_t)strlen((char *)msg->getData()) + 1; if (size > 3) { DWORD cbWritten = 0; // send it and free it @@ -206,9 +279,69 @@ acre::Result CNamedPipeServer::sendLoop() { TRACE("Sending thread terminating"); return acre::Result::ok; +#else + ssize_t bufferHead, len; + while (!this->getShuttingDown()) { + CEngine::getInstance()->getSoundEngine()->onClientGameConnected(); + while(!this->getConnectedWrite() && !this->getShuttingDown()) { + Sleep(1); + } + + walltime_t lastTick = getMonotime(); + while (this->getConnectedWrite()) { + if (this->getShuttingDown()) { + break; + } + + walltime_t tick = getMonotime(); + if (diffMonotime(tick, lastTick) > PIPE_TIMEOUT) { + LOG("No send message for %d seconds, disconnecting", (PIPE_TIMEOUT / 1000)); + this->setConnectedWrite(false); + break; + } + + IMessage *msg = nullptr; + if (this->m_sendQueue.try_pop(msg)) { + if (msg != nullptr) { + lastTick = getMonotime(); + const uint32_t msgSize = (uint32_t)strlen((char *)msg->getData()); + const uint32_t size = msgSize + 4; + char writeBuffer[size]; + strncpy(writeBuffer + 4, (char *)msg->getData(), strlen((char *) msg->getData())); + writeBuffer[0] = (char) (msgSize >> 24); + writeBuffer[1] = (char) (msgSize >> 16); + writeBuffer[2] = (char) (msgSize >> 8); + writeBuffer[3] = (char) (msgSize); + if (size > 3) { + //LOCK(this); + this->lock(); + bufferHead = 0; + while (bufferHead < size) { + len = write(this->m_clientFD, writeBuffer + bufferHead, size - bufferHead); + bufferHead += len; + if (len == -1) { + LOG("Error when writing to socket: %d", errno); + this->setConnectedWrite(false); + }; + }; + this->unlock(); + } + delete msg; + } + } + Sleep(1); + } + LOG("Write loop disconnected"); + Sleep(1); + } + TRACE("Sending thread terminating"); + + return acre::Result::ok; +#endif } acre::Result CNamedPipeServer::readLoop() { +#ifdef WIN32 DWORD cbRead; char *mBuffer = (char *)LocalAlloc(LMEM_FIXED, BUFSIZE); @@ -233,16 +366,16 @@ acre::Result CNamedPipeServer::readLoop() { continue; } - clock_t lastTick = clock() / CLOCKS_PER_SEC; + walltime_t lastTick = getMonotime(); while (this->getConnectedRead()) { //this->checkServer(); if (this->getShuttingDown()) { break; } - const clock_t tick = clock() / CLOCKS_PER_SEC; + walltime_t tick = getMonotime(); //LOG("[%d] - [%d] = [%d] vs. [%d]", tick, lastTick, (tick - lastTick),(PIPE_TIMEOUT / 1000)); - if (tick - lastTick > (PIPE_TIMEOUT / 1000)) { + if (diffMonotime(tick, lastTick) > PIPE_TIMEOUT) { LOG("No read message for %d seconds, disconnecting", (PIPE_TIMEOUT / 1000)); this->setConnectedWrite(false); this->setConnectedRead(false); @@ -273,12 +406,12 @@ acre::Result CNamedPipeServer::readLoop() { // Do not free msg, this is deleted inside runProcedure() CEngine::getInstance()->getRpcEngine()->runProcedure(this, msg); - lastTick = clock() / CLOCKS_PER_SEC; + lastTick = getMonotime(); //TRACE("tick [%d], [%s]",lastTick, msg->getData()); } // wait 1ms for new msg so we dont hog cpu cycles } while (!ret); - //ret = ConnectNamedPipe(this->getPipeHandle(), NULL); + //ret = ConnectNamedPipe(this->getPipeHandle(), NULL); Sleep(1); } // Kill the write pipe along with ourselves, because we master shutdown/startup @@ -292,28 +425,177 @@ acre::Result CNamedPipeServer::readLoop() { CEngine::getInstance()->getSoundEngine()->onClientGameDisconnected(); LOG("Client disconnected"); CEngine::getInstance()->getClient()->unMuteAll(); - + // Clear the send queue since client disconnected this->m_sendQueue.clear(); - - // send an event that we have disconnected + + // send an event that we have disconnected if (CEngine::getInstance()->getExternalServer()->getConnected()) { CEngine::getInstance()->getExternalServer()->sendMessage( - CTextMessage::formatNewMessage("ext_reset", + CTextMessage::formatNewMessage("ext_reset", "%d,", CEngine::getInstance()->getSelf()->getId() - ) + ) ); - } + } Sleep(1); } - + if (mBuffer) LocalFree(mBuffer); TRACE("Receiving thread terminating"); return acre::Result::ok; +#else + char *mBuffer = (char *)calloc(1, BUFSIZE); + if (mBuffer == nullptr) { + LOG("calloc failed: %d", errno); + } + + LOG("starting read loop"); + + ssize_t bufferHead; + ssize_t len; + unsigned char lengthBuffer[4]; + fd_set readfds; + + while (!this->getShuttingDown()) { + FD_ZERO(&readfds); + FD_SET(this->m_sockFD, &readfds); + struct timeval tv = { + .tv_sec = 0, + .tv_usec = 50000 + }; + + if (select(this->m_sockFD + 1, &readfds, NULL, NULL, &tv) == 0) { + continue; + } + + this->m_clientFD = accept(this->m_sockFD, NULL, NULL); + if (this->m_clientFD != -1) { + LOG("Client connected"); + CEngine::getInstance()->getClient()->updateShouldSwitchChannel(false); + CEngine::getInstance()->getClient()->unMuteAll(); + CEngine::getInstance()->getSoundEngine()->onClientGameConnected(); + this->setConnectedRead(true); + this->setConnectedWrite(true); + } else { + this->setConnectedRead(false); + this->setConnectedWrite(false); + Sleep(1); + + continue; + } + walltime_t lastTick = getMonotime(); + while (this->getConnectedRead()) { + if (this->getShuttingDown()) { + break; + } + + walltime_t tick = getMonotime(); + if (diffMonotime(tick, lastTick) > PIPE_TIMEOUT) { + LOG("No read message for %d seconds, disconnecting", (PIPE_TIMEOUT / 1000)); + this->setConnectedWrite(false); + this->setConnectedRead(false); + break; + } + + //Run channel switch to server channel + if (CEngine::getInstance()->getClient()->shouldSwitchChannel()) { + CEngine::getInstance()->getClient()->moveToServerChannel(); + } + + // Read exactly four bytes for the message length + bufferHead = 0; + while(bufferHead < 4) { + len = read(this->m_clientFD, (&lengthBuffer) + bufferHead, 4 - bufferHead); + if (len == 0) { + this->setConnectedRead(false); + goto clientClose; + } else if (len == -1) { + LOG("Error when reading from socket: %d", errno); + this->setConnectedRead(false); + goto clientClose; + }; + bufferHead += len; + }; + uint32_t messageLength = (lengthBuffer[0] << 24) + (lengthBuffer[1] << 16) + (lengthBuffer[2] << 8) + lengthBuffer[3]; + + if (messageLength > BUFSIZE - 1) { + LOG("Received too-large message with size %d", messageLength); + this->setConnectedWrite(false); + this->setConnectedRead(false); + break; + } + + mBuffer[messageLength] = 0x00; + + bufferHead = 0; + while(bufferHead < messageLength) { + len = read(this->m_clientFD, (mBuffer) + bufferHead, messageLength - bufferHead); + if (len == 0) { + this->setConnectedRead(false); + goto clientClose; + } else if (len == -1) { + LOG("Error when reading from socket: %d", errno); + this->setConnectedRead(false); + goto clientClose; + }; + bufferHead += len; + }; + + // handle the packet and run it + mBuffer[messageLength] = 0x00; + //LOG("READ: %s", (char *)mBuffer); + IMessage *const msg = new CTextMessage((char *)mBuffer, messageLength); + TRACE("got and parsed message [%s]", msg->getData()); + if (msg != nullptr && msg->getProcedureName()) { + + // Do not free msg, this is deleted inside runProcedure() + CEngine::getInstance()->getRpcEngine()->runProcedure(this, msg); + + lastTick = getMonotime(); + //TRACE("tick [%d], [%s]",lastTick, msg->getData()); + } + // wait 1ms for new msg so we dont hog cpu cycles + Sleep(1); + } + +clientClose: + this->setConnectedWrite(false); + this->setConnectedRead(false); + close(this->m_clientFD); + + //Run channel switch to original channel + CEngine::getInstance()->getClient()->moveToPreviousChannel(); + CEngine::getInstance()->getSoundEngine()->onClientGameDisconnected(); + LOG("Client disconnected"); + CEngine::getInstance()->getClient()->unMuteAll(); + + // Clear the send queue since client disconnected + this->m_sendQueue.clear(); + + // send an event that we have disconnected + if (CEngine::getInstance()->getExternalServer()->getConnected()) { + CEngine::getInstance()->getExternalServer()->sendMessage( + CTextMessage::formatNewMessage("ext_reset", + "%d,", + CEngine::getInstance()->getSelf()->getId() + ) + ); + } + Sleep(1); + } + + if (mBuffer) { + free(mBuffer); + } + + TRACE("Receiving thread terminating"); + + return acre::Result::ok; +#endif } acre::Result CNamedPipeServer::sendMessage( IMessage *message ) { @@ -329,8 +611,11 @@ acre::Result CNamedPipeServer::sendMessage( IMessage *message ) { acre::Result CNamedPipeServer::checkServer( void ) { std::string uniqueId = CEngine::getInstance()->getClient()->getUniqueId(); if (uniqueId != "" && this->validTSServers.find(uniqueId) == this->validTSServers.end()) { +#ifdef WIN32 MessageBoxA(NULL, "This server is NOT registered for ACRE2 testing! Please remove the plugin! Teamspeak will now close.", "ACRE Error", MB_OK | MB_ICONEXCLAMATION); TerminateProcess(GetCurrentProcess(), 0); +#else +#endif } return acre::Result::ok; } diff --git a/extensions/src/ACRE2Core/NamedPipeServer.h b/extensions/src/ACRE2Core/NamedPipeServer.h index 355fd82e6..07a35142e 100644 --- a/extensions/src/ACRE2Core/NamedPipeServer.h +++ b/extensions/src/ACRE2Core/NamedPipeServer.h @@ -41,10 +41,12 @@ class CNamedPipeServer : public IServer, public CLockable { char *currentServerId; +#ifdef WIN32 DECLARE_MEMBER(HANDLE, PipeHandleRead); DECLARE_MEMBER(HANDLE, PipeHandleWrite); DECLARE_MEMBER(std::string, FromPipeName); DECLARE_MEMBER(std::string, ToPipeName); +#endif inline void setConnectedWrite(const bool value) { m_connectedWrite = value; } inline bool getConnectedWrite() const { return m_connectedWrite; } @@ -71,6 +73,16 @@ class CNamedPipeServer : public IServer, public CLockable { concurrency::concurrent_queue m_sendQueue; std::thread m_readThread; std::thread m_sendThread; - PSECURITY_ATTRIBUTES m_PipeSecurity; std::set validTSServers; +#ifdef WIN32 + PSECURITY_ATTRIBUTES m_PipeSecurity; +#else + int m_sockFD; + int m_clientFD; +#endif + +#ifdef __linux + uint16_t acreListenPort = CAcreSettings::getInstance()->getWineSocketPort(); +#endif + }; From b2b9b17620fbe82291e15d06ab49645ca00299e4 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Sat, 27 Aug 2022 23:46:13 -0500 Subject: [PATCH 14/21] Modify arma2ts to use sockets if running in Wine When running in Wine, ACRE2Arma.dll will mirror the changes to NamedPipeServer.cpp for Linux; instead of using named pipes, it will connect to the socket opened on the other side. A helper function has been added to detect if running under Wine, by checking for a function Wine defines in ntdll. --- addons/sys_core/initSettings.sqf | 12 + addons/sys_io/fnc_server.sqf | 6 +- .../src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp | 316 ++++++++++++++++++ extensions/src/ACRE2Shared/wine.h | 15 + 4 files changed, 348 insertions(+), 1 deletion(-) create mode 100644 extensions/src/ACRE2Shared/wine.h diff --git a/addons/sys_core/initSettings.sqf b/addons/sys_core/initSettings.sqf index 8aa04a81c..981be8386 100644 --- a/addons/sys_core/initSettings.sqf +++ b/addons/sys_core/initSettings.sqf @@ -154,6 +154,18 @@ {[_this] call FUNC(setRevealToAI)} ] call CBA_fnc_addSetting; +if ("ACRE2Arma" callExtension "99" == "1") then { + // Wine Socket Port + [ + QGVAR(wineSocketPort), + "EDITBOX", + ["Wine Socket Port", "(Linux only) What port should ACRE2 try to connect to Mumble on?"], + "ACRE2 Wine", + "19141", + false + ] call CBA_fnc_addSetting; +}; + // Notification Settings - not yet implemented /*[ QGVAR(incomingTransmissionNotification), diff --git a/addons/sys_io/fnc_server.sqf b/addons/sys_io/fnc_server.sqf index 34a45fb43..217930d9c 100644 --- a/addons/sys_io/fnc_server.sqf +++ b/addons/sys_io/fnc_server.sqf @@ -23,7 +23,11 @@ DFUNC(connectionFnc) = { LOG("ATEEEMPTING TO OPEN PIPE!"); // acre_player sideChat "OPEN PIPE"; GVAR(pongTime) = diag_tickTime; - GVAR(pipeCode) = "ACRE2Arma" callExtension "0ts"; // Connect String + extensionParameter = "0"; + if (!isNil {EGVAR(sys_core,wineSocketPort)}) then { + extensionParameter = "0p" + EGVAR(sys_core,wineSocketPort); + }; + GVAR(pipeCode) = "ACRE2Arma" callExtension extensionParameter; // Connect String // acre_player sideChat format["RESULT: %1", GVAR(pipeCode)]; if (GVAR(pipeCode) != "1") then { if (time > 15) then { diff --git a/extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp b/extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp index 0cd71b81f..bb18b7bfd 100644 --- a/extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp +++ b/extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp @@ -14,18 +14,29 @@ #include #include +#include +#include +#include +#include "wine.h" + #pragma comment(lib, "shlwapi.lib") +#pragma comment(lib, "Ws2_32.lib") #define PIPE_COMMAND_OPEN 0 #define PIPE_COMMAND_CLOSE 1 #define PIPE_COMMAND_WRITE 2 #define PIPE_COMMAND_READ 3 #define PIPE_COMMAND_RESET 4 +#define COMMAND_IS_WINE 99 + +#define WINE_SOCKET_PORT "19141" #define FROM_PIPENAME_TS "\\\\.\\pipe\\acre_comm_pipe_fromTS" #define TO_PIPENAME_TS "\\\\.\\pipe\\acre_comm_pipe_toTS" +char isWine; +SOCKET wineSocket = INVALID_SOCKET; HANDLE writeHandle = INVALID_HANDLE_VALUE; HANDLE readHandle = INVALID_HANDLE_VALUE; @@ -34,6 +45,9 @@ BOOL writeConnected, readConnected; void ClosePipe(); +void CloseWineSocket(); +void __stdcall runCommandWine(char* output, int outputSize, int command, std::string params); +void __stdcall runCommand(char* output, int outputSize, int command, std::string params); extern "C" { __declspec (dllexport) void __stdcall RVExtensionVersion(char *output, int outputSize); @@ -148,6 +162,14 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) int command = atoi(id.c_str()); + if (detectWine()) { + runCommandWine(output, outputSize, command, params); + } else { + runCommand(output, outputSize, command, params); + } +} + +void __stdcall runCommand(char* output, int outputSize, int command, std::string params) { switch(command) { case PIPE_COMMAND_WRITE: { @@ -345,6 +367,289 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) readHandle = INVALID_HANDLE_VALUE; return; } + case COMMAND_IS_WINE: { + strncpy(output,"0",outputSize); + return; + } + default: + return; + } +} + +void __stdcall runCommandWine(char* output, int outputSize, int command, std::string params) { + switch(command) { + case PIPE_COMMAND_WRITE: { + if (writeConnected) { + size_t size = params.length() + 4; + char* messageBuffer = (char*)calloc(size, sizeof(char)); + messageBuffer[0] = (char) (params.length() >> 24); + messageBuffer[1] = (char) (params.length() >> 16); + messageBuffer[2] = (char) (params.length() >> 8); + messageBuffer[3] = (char) (params.length()); + + strncpy(messageBuffer + 4, params.c_str(), params.length()); + + int written = 0; + while (written < size) { + int len = send( + wineSocket, + messageBuffer + written, + size - written, + 0 + ); + if (len == SOCKET_ERROR) { + if (WSAGetLastError() != WSAEWOULDBLOCK) { + sprintf(output, "send failed with error: %d\n", WSAGetLastError()); + CloseWineSocket(); + return; + } + } else { + written += len; + } + + if (written < size) { + fd_set socketSet; + FD_ZERO(&socketSet); + FD_SET(wineSocket, &socketSet); + + timeval timeout = { 0, 15000L }; + int iResult = select(1, NULL, &socketSet, NULL, NULL); + if (iResult == SOCKET_ERROR) { + sprintf(output, "select failed with error: %d\n", WSAGetLastError()); + CloseWineSocket(); + if (messageBuffer) { + free(messageBuffer); + } + return; + } + } + } + + if (messageBuffer) { + free(messageBuffer); + } + strncpy(output,"1",outputSize); + } else { + if (wineSocket != INVALID_SOCKET) { + CloseWineSocket(); + } + strncpy(output,"-1",outputSize); + } + + return; + } + + case PIPE_COMMAND_READ: { + if (readConnected) { + DWORD cbRead; + char lengthBuffer[4]; + constexpr size_t read_length = 4097U; + char value[read_length]; // Allocate on stack to delegate memory management to compiler, + // allows up to 4096 char string (+1 to ensure NUL terminated), like initial version + + cbRead = recv(wineSocket, lengthBuffer, 4, 0); + if (cbRead == SOCKET_ERROR) { + if (WSAGetLastError() == WSAEWOULDBLOCK) { + strncpy(output, "_JERR_NULL", outputSize); + } else { + strncpy(output, "_JERR_FALSE", outputSize); + CloseWineSocket(); + } + } else if (cbRead != 0) { + // If we receive some bytes, that means we're in the middle of a "message" + // + // Since there's no logic to stitch together a message from multiple calls into + // this command, there are two cases from here on out: + // Either we read the complete message, + // or the socket gets closed, possibly after a timeout + fd_set socketSet; + FD_ZERO(&socketSet); + FD_SET(wineSocket, &socketSet); + // 15 ms timeout + timeval timeout = { 0, 15000L }; + + while (cbRead < 4) { + int iResult = select(1, &socketSet, NULL, NULL, &timeout); + if (iResult == 0 || iResult == SOCKET_ERROR) { + strncpy(output, "_JERR_FALSE", outputSize); + CloseWineSocket(); + return; + } + + int len = recv(wineSocket, lengthBuffer + cbRead, 4 - cbRead, 0); + if (len == 0) { + strncpy(output, "_JERR_FALSE", outputSize); + CloseWineSocket(); + return; + } + + cbRead += len; + }; + + DWORD messageLength = ((unsigned char) lengthBuffer[0] << 24) + + ((unsigned char) lengthBuffer[1] << 16) + + ((unsigned char) lengthBuffer[2] << 8) + + (unsigned char) lengthBuffer[3]; + if (messageLength > outputSize) { + strncpy(output, "_JERR_FALSE", outputSize); + CloseWineSocket(); + return; + } + + cbRead = 0; + while (cbRead < messageLength) { + int len = recv(wineSocket, value + cbRead, messageLength - cbRead, 0); + + if (len == SOCKET_ERROR) { + if (WSAGetLastError() != WSAEWOULDBLOCK) { + strncpy(output, "_JERR_FALSE", outputSize); + CloseWineSocket(); + return; + } + } else if (len == 0) { + strncpy(output, "_JERR_FALSE", outputSize); + CloseWineSocket(); + return; + } else { + cbRead += len; + } + + if (cbRead < messageLength) { + int iResult = select(1, &socketSet, NULL, NULL, &timeout); + if (iResult == 0 || iResult == SOCKET_ERROR) { + strncpy(output, "_JERR_FALSE", outputSize); + CloseWineSocket(); + return; + } + } + } + + if (cbRead >= (size_t)outputSize) { + // Prevent buffer overflow + cbRead = outputSize - 1U; + } + + // Ensure NUL terminated string (required by strncpy) + value[cbRead] = '\0'; + + strncpy(output, value, cbRead + 1); + } else { + CloseWineSocket(); + strncpy(output, "_JERR_FALSE", outputSize); + } + } else { + CloseWineSocket(); + strncpy(output, "_JERR_NOCONNECT", outputSize); + } + return; + } + + case PIPE_COMMAND_OPEN: { + if (readConnected) { + CloseWineSocket(); + } + wineSocket = INVALID_SOCKET; + + WSADATA wsaData; + struct addrinfo *result = NULL, *ptr = NULL, hints; + char recvbuf[4096]; + int iResult; + + iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if (iResult != 0) { + sprintf(output, "WSA startup failed with error: %d", iResult); + return; + } + + ZeroMemory( &hints, sizeof(hints) ); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + const char * port; + if (params.length() > 0) { + port = params.c_str() + 1; + } else { + port = WINE_SOCKET_PORT; + } + + // Resolve the server address and port + iResult = getaddrinfo("localhost", port, &hints, &result); + if ( iResult != 0 ) { + sprintf(output, "getaddrinfo failed with error: %d\n", iResult); + WSACleanup(); + return; + } + + // Attempt to connect to an address until one succeeds + for(ptr = result ; ptr != NULL ; ptr = ptr -> ai_next) { + // Create a SOCKET for connecting to server + wineSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); + if (wineSocket == INVALID_SOCKET) { + sprintf(output, "socket failed with error: %ld\n", WSAGetLastError()); + WSACleanup(); + return; + } + + u_long argp = 1; + iResult = ioctlsocket(wineSocket, FIONBIO, &argp); + if (iResult != NO_ERROR) { + sprintf(output, "ioctlsocket failed with error: %ld\n", iResult); + return; + } + + // Connect to server. + iResult = connect( wineSocket, ptr->ai_addr, (int)ptr->ai_addrlen); + if (iResult == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) { + CloseWineSocket(); + continue; + } + + fd_set socketSet; + FD_ZERO(&socketSet); + FD_SET(wineSocket, &socketSet); + + timeval timeout = { 0, 15000L }; + + iResult = select(1, NULL, &socketSet, NULL, &timeout); + if (iResult == SOCKET_ERROR) { + sprintf(output, "select failed with error: %d\n", WSAGetLastError()); + CloseWineSocket(); + WSACleanup(); + break; + } else if (iResult == 0) { + wineSocket = INVALID_SOCKET; + continue; + } + break; + } + + freeaddrinfo(result); + + + if (wineSocket == INVALID_SOCKET) { + WSACleanup(); + strncpy(output,"0",outputSize); + } else { + readConnected = true; + writeConnected = true; + strncpy(output,"1",outputSize); + } + + return; + } + + case PIPE_COMMAND_CLOSE: + case PIPE_COMMAND_RESET: { + CloseWineSocket(); + return; + } + + case COMMAND_IS_WINE: { + strncpy(output,"1",outputSize); + return; + } + default: return; } @@ -369,12 +674,23 @@ void ClosePipe() { readConnected = FALSE; } +void CloseWineSocket() { + if (wineSocket != INVALID_SOCKET) { + closesocket(wineSocket); + wineSocket = INVALID_SOCKET; + } + writeConnected = FALSE; + readConnected = FALSE; +} + void Init(void) { //g_Log = (Log *)new Log("ACRE2Arma.log"); //LOG("* Logging engine initialized."); writeConnected = FALSE; readConnected = FALSE; + + isWine = detectWine(); } void Cleanup(void) { diff --git a/extensions/src/ACRE2Shared/wine.h b/extensions/src/ACRE2Shared/wine.h new file mode 100644 index 000000000..c42842843 --- /dev/null +++ b/extensions/src/ACRE2Shared/wine.h @@ -0,0 +1,15 @@ +#pragma once + +inline bool detectWine() { + FARPROC pwine_get_version; + HMODULE hntdll = GetModuleHandle("ntdll.dll"); + if(hntdll) { + if(GetProcAddress(hntdll, "wine_get_version")) { + return 1; + } else { + return 0; + } + } else { + return 0; + } +} From 4ff349d45f4bac153e4fa452a067bd216b132e05 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Sun, 28 Aug 2022 03:00:52 -0500 Subject: [PATCH 15/21] Add a Linux build job to CI Also, publish the resulting Linux/Mumble plugin --- .github/workflows/release.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f0ec9263d..7211c00df 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -109,6 +109,30 @@ jobs: symbols retention-days: 1 + compile-linux: + if: github.repository == 'IDI-Systems/acre2' && ! contains(github.event.head_commit.message, '[ci skip]') + runs-on: ubuntu-latest + steps: + - name: Checkout the source code + uses: actions/checkout@v2 + - name: Install Packages + run: | + sudo apt update + sudo DEBIAN_FRONTEND=noninteractive apt install -y libfaudio-dev libtbb-dev + - name: Build Extensions + run: | + mkdir -p extensions/build + cd extensions/build + cmake -DUSE_64BIT_BUILD=ON .. + make -j + - name: Upload Artifact + uses: actions/upload-artifact@v2 + with: + name: acre2-extensions-linux + path: | + plugin + retention-days: 1 + publish-test: needs: [build, compile] if: github.event_name == 'workflow_dispatch' @@ -123,6 +147,7 @@ jobs: mv acre2-extensions-*/*.dll @acre2/ mv acre2-extensions-*/extras/*.exe @acre2/extras/ mkdir @acre2/plugin && cp -r acre2-extensions-*/plugin/* @acre2/plugin/ # mv can't merge directories + cp -r acre2-extensions-linux/mumble @acre2/plugin || true mkdir symbols && mv acre2-extensions-*/symbols/* . echo "::group::Archive build" zip -r acre2_${{ needs.build.outputs.VERSION }}${{ github.event.inputs.label }}.zip @acre2 @@ -171,6 +196,7 @@ jobs: mv acre2-extensions-*/*.dll @acre2/ mv acre2-extensions-*/extras/*.exe @acre2/extras/ mkdir @acre2/plugin && cp -r acre2-extensions-*/plugin/* @acre2/plugin/ # mv can't merge directories + cp -r acre2-extensions-linux/mumble @acre2/plugin || true mkdir symbols && mv acre2-extensions-*/symbols/* . echo "::group::Archive build" zip -r acre2_${{ needs.build.outputs.VERSION }}.zip @acre2 @@ -229,6 +255,7 @@ jobs: mv acre2-extensions-*/*.dll @acre2/ mv acre2-extensions-*/extras/*.exe @acre2/extras/ mkdir @acre2/plugin && cp -r acre2-extensions-*/plugin/* @acre2/plugin/ # mv can't merge directories + cp -r acre2-extensions-linux/mumble @acre2/plugin || true mkdir symbols && mv acre2-extensions-*/symbols/* . echo "::group::Archive build" zip -r acre2_${{ needs.build.outputs.VERSION }}.zip @acre2 From 61ea0418a5f4cac0442293c67538f7a906301ca9 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Sun, 28 Aug 2022 20:45:22 -0500 Subject: [PATCH 16/21] Fix arma2ts to detect Wine once on start This is how I intended it, but during a rewrite/rebase it got screwed up. --- extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp b/extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp index bb18b7bfd..dbdfbb21a 100644 --- a/extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp +++ b/extensions/src/ACRE2Arma/arma2ts/CallExt_DllMain.cpp @@ -162,7 +162,7 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) int command = atoi(id.c_str()); - if (detectWine()) { + if (isWine) { runCommandWine(output, outputSize, command, params); } else { runCommand(output, outputSize, command, params); From da36155ae29adc9c5e98d9d7f849a4058265fbc4 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Mon, 19 Sep 2022 00:30:57 -0500 Subject: [PATCH 17/21] Set LC_NUMERIC=C on Linux The atof function is locale dependent. Specifically, it uses the locale-specific decimal separator to convert floating-point strings; that is, in a locale that uses commas as decimal separators, "0,5" will convert to 0.5, whereas "0.5" will fail, and convert as 0.0. Strings coming from Arma will always use a period as a decimal separator, this causes myriad failures. On Linux, on startup, we now set LC_NUMERIC to C, which has the behavior we want. I'm not certain why this isn't a problem on Win32. There may be a path in Qt/Mumble that sets locale one way on Linux and another on Windows. --- extensions/src/ACRE2Mumble/MumbleClient.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/extensions/src/ACRE2Mumble/MumbleClient.cpp b/extensions/src/ACRE2Mumble/MumbleClient.cpp index 81678e9b8..85bef7a64 100644 --- a/extensions/src/ACRE2Mumble/MumbleClient.cpp +++ b/extensions/src/ACRE2Mumble/MumbleClient.cpp @@ -13,6 +13,7 @@ #pragma comment(lib, "Shlwapi.lib") #else #include +#include #endif static constexpr std::int32_t invalid_mumble_channel = -1; @@ -60,6 +61,11 @@ acre::Result CMumbleClient::stop() { } acre::Result CMumbleClient::start(const acre::id_t id_) { + #ifdef __linux__ + // Make sure floats get serialized with period decimal separators + setlocale(LC_NUMERIC, "C"); + #endif + CEngine::getInstance()->start(id_); this->setInputActive(false); this->setDirectFirst(false); From 87d15c14495a3ac27f3244a15df1aa4700c8b70d Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Tue, 20 Sep 2022 07:57:15 -0500 Subject: [PATCH 18/21] Fix inconsistent indentation --- extensions/src/ACRE2Core/Engine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/src/ACRE2Core/Engine.cpp b/extensions/src/ACRE2Core/Engine.cpp index dc157b672..019148960 100644 --- a/extensions/src/ACRE2Core/Engine.cpp +++ b/extensions/src/ACRE2Core/Engine.cpp @@ -47,9 +47,9 @@ acre::Result CEngine::initialize(IClient *client, IServer *externalServer, std:: } #else if (getenv("XDG_DATA_HOME")) { - acrePluginLog = std::string(getenv("XDG_DATA_HOME")) + "/" + acrePluginLog; + acrePluginLog = std::string(getenv("XDG_DATA_HOME")) + "/" + acrePluginLog; } else { - acrePluginLog = std::string(getenv("HOME")) + "/.local/share/" + acrePluginLog; + acrePluginLog = std::string(getenv("HOME")) + "/.local/share/" + acrePluginLog; } #endif g_Log = (Log *) new Log(acrePluginLog.c_str()); From a8def6dc0b858d691bef93c0b11358073cfea3a5 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Tue, 20 Sep 2022 08:02:06 -0500 Subject: [PATCH 19/21] Remove hardcoded filenames from voip_plugin Instead of hardcoding the filenames of the destination files for plugins, VOIPPlugin::handle_update_plugin will now use the basenames of the x32 and x64 plugins paths passed into it. --- extensions/src/ACRE2Steam/voip_plugin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/src/ACRE2Steam/voip_plugin.cpp b/extensions/src/ACRE2Steam/voip_plugin.cpp index 7a279d560..971f51de6 100644 --- a/extensions/src/ACRE2Steam/voip_plugin.cpp +++ b/extensions/src/ACRE2Steam/voip_plugin.cpp @@ -194,10 +194,10 @@ idi::acre::UpdateCode VOIPPlugin::handle_update_plugin() noexcept { std::vector> plugin_paths_array; if (arch_to_install == Architecture::both || arch_to_install == Architecture::x32) { - plugin_paths_array.push_back(std::make_pair(plugin_folder / "acre2_win32.dll", x32_acre_plugin)); + plugin_paths_array.push_back(std::make_pair(plugin_folder / x32_acre_plugin.filename(), x32_acre_plugin)); } if (arch_to_install == Architecture::both || arch_to_install == Architecture::x64) { - plugin_paths_array.push_back(std::make_pair(plugin_folder / "acre2_win64.dll", x64_acre_plugin)); + plugin_paths_array.push_back(std::make_pair(plugin_folder / x64_acre_plugin.filename(), x64_acre_plugin)); } for (const auto &path : plugin_paths_array) { @@ -226,7 +226,7 @@ idi::acre::UpdateCode VOIPPlugin::handle_update_plugin() noexcept { continue; } - std::array plugin_paths_array = {plugin_folder / "acre2_win32.dll", plugin_folder / "acre2_win64.dll"}; + std::array plugin_paths_array = {plugin_folder / x32_acre_plugin.filename(), plugin_folder / x64_acre_plugin.filename()}; for (const auto &path : plugin_paths_array) { std::error_code err_code; From 659bffb655a06dee2772b3d355da43ac4ad6e290 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Tue, 20 Sep 2022 08:00:54 -0500 Subject: [PATCH 20/21] Auto-install plugin to Mumble on Linux If running under Wine, ACRE2Steam will now detect that and automatically install the Linux Mumble plugin to the Linux version of Mumble, if it is present. --- extensions/src/ACRE2Steam/CallExt_DllMain.cpp | 63 ++++++++++++++----- .../src/ACRE2Steam/mumble_linux_plugin.cpp | 42 +++++++++++++ .../src/ACRE2Steam/mumble_linux_plugin.hpp | 26 ++++++++ 3 files changed, 116 insertions(+), 15 deletions(-) create mode 100644 extensions/src/ACRE2Steam/mumble_linux_plugin.cpp create mode 100644 extensions/src/ACRE2Steam/mumble_linux_plugin.hpp diff --git a/extensions/src/ACRE2Steam/CallExt_DllMain.cpp b/extensions/src/ACRE2Steam/CallExt_DllMain.cpp index af0a6c6a7..75787ae66 100644 --- a/extensions/src/ACRE2Steam/CallExt_DllMain.cpp +++ b/extensions/src/ACRE2Steam/CallExt_DllMain.cpp @@ -14,6 +14,7 @@ #include "Shlwapi.h" #include "command_options.hpp" #include "mumble_plugin.hpp" +#include "mumble_linux_plugin.hpp" #include "shlobj.h" #include "ts3_plugin.hpp" @@ -74,6 +75,7 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) { idi::acre::TS3Plugin ts3_plugin(skip_ts_plugin); idi::acre::MumblePlugin mumble_plugin(skip_mumble_plugin, mumble_path); + idi::acre::MumbleLinuxPlugin mumble_linux_plugin(skip_mumble_plugin, mumble_path); switch (command) { case SteamCommand::check: { @@ -116,8 +118,9 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) { const bool ts3_locations_success = ts3_plugin.collect_plugin_locations(); const bool mumble_locations_success = mumble_plugin.collect_plugin_locations(); + const bool mumble_linux_locations_success = mumble_linux_plugin.collect_plugin_locations(); - if (!ts3_locations_success && !mumble_locations_success) { + if (!ts3_locations_success && !mumble_locations_success && !mumble_linux_locations_success) { const std::int32_t result = MessageBoxA(nullptr, "ACRE2 was unable to find a TeamSpeak 3 or a Mumble installation. If you do have an installation please copy the plugins " "yourself or reinstall TeamSpeak 3 or Mumble.\n\nIf you are sure you have TeamSpeak 3 and/or Mumble installed and wish to " @@ -140,9 +143,12 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) { std::async(std::launch::async, [&]() { return ts3_plugin.handle_update_plugin(); }); std::future update_mumble = std::async(std::launch::async, [&]() { return mumble_plugin.handle_update_plugin(); }); + std::future update_mumble_linux = + std::async(std::launch::async, [&]() { return mumble_linux_plugin.handle_update_plugin(); }); const idi::acre::UpdateCode ts3_update_result = update_ts3.get(); const idi::acre::UpdateCode mumble_update_result = update_mumble.get(); + const idi::acre::UpdateCode mumble_linux_update_result = update_mumble_linux.get(); std::string error_msg; const bool update_ts3_ok = @@ -157,7 +163,13 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) { error_msg = mumble_plugin.get_last_error_message(); } - if (!update_ts3_ok || !update_mumble_ok) { + const bool update_mumble_linux_ok = + (mumble_linux_update_result != idi::acre::UpdateCode::update_failed) && (mumble_linux_update_result != idi::acre::UpdateCode::other); + if (!update_mumble_linux_ok) { + error_msg = mumble_linux_plugin.get_last_error_message(); + } + + if (!update_ts3_ok || !update_mumble_ok || !update_mumble_linux_ok) { std::ostringstream oss; oss << "ACRE2 was unable to copy the Mumble/TeamSpeak 3 plugin. Please check if you have write access to the plugin " << "folder, close any instances of TeamSpeak 3 and/or Mumble and click \"Try Again\".\n\nIf you " @@ -179,7 +191,8 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) { // Update was not necessary. if ((ts3_update_result == idi::acre::UpdateCode::update_not_necessary) && - (mumble_update_result == idi::acre::UpdateCode::update_not_necessary)) { // No update was copied etc. + (mumble_update_result == idi::acre::UpdateCode::update_not_necessary) && + (mumble_linux_update_result == idi::acre::UpdateCode::update_not_necessary)) { // No update was copied etc. strncpy(output, "[0]", outputSize); return; } @@ -200,24 +213,35 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) { oss << "\n"; } - if (!mumble_plugin.get_updated_paths().empty()) { + if (!mumble_plugin.get_updated_paths().empty() || + !mumble_linux_plugin.get_updated_paths().empty()) { oss << "The Mumble plugins have been copied to the following location(s):\n"; - std::string arch_installed = ""; - if (mumble_plugin.get_arch_to_install() == idi::acre::Architecture::x32) { - arch_installed = " [32-bit only]"; - } else if (mumble_plugin.get_arch_to_install() == idi::acre::Architecture::x64) { - arch_installed = " [64-bit only]"; + if (!mumble_plugin.get_updated_paths().empty()) { + std::string arch_installed = ""; + if (mumble_plugin.get_arch_to_install() == idi::acre::Architecture::x32) { + arch_installed = " [32-bit only]"; + } else if (mumble_plugin.get_arch_to_install() == idi::acre::Architecture::x64) { + arch_installed = " [64-bit only]"; + } + + for (const auto &path : mumble_plugin.get_updated_paths()) { + oss << path << arch_installed << "\n"; + found_paths.append(path + "\n"); + } } - for (const auto &path : mumble_plugin.get_updated_paths()) { - oss << path << arch_installed << "\n"; - found_paths.append(path + "\n"); + if (!mumble_linux_plugin.get_updated_paths().empty()) { + for (const auto &path : mumble_linux_plugin.get_updated_paths()) { + oss << path << " [linux]" << "\n"; + found_paths.append(path + "\n"); + } } oss << "\n"; } + if (!ts3_plugin.get_removed_paths().empty()) { oss << "The TeamSpeak 3 plugin has been removed from the following location(s):\n"; for (const auto &path : ts3_plugin.get_removed_paths()) { @@ -227,10 +251,19 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function) { oss << "\n"; } - if (!mumble_plugin.get_removed_paths().empty()) { + if (!mumble_plugin.get_removed_paths().empty() || + !mumble_linux_plugin.get_removed_paths().empty()) { oss << "The Mumble plugin has been removed from the following location(s):\n"; - for (const auto &path : mumble_plugin.get_removed_paths()) { - oss << path << "\n"; + if (!mumble_plugin.get_removed_paths().empty()) { + for (const auto &path : mumble_plugin.get_removed_paths()) { + oss << path << "\n"; + } + } + + if (!mumble_linux_plugin.get_removed_paths().empty()) { + for (const auto &path : mumble_linux_plugin.get_removed_paths()) { + oss << path << "\n"; + } } oss << "\n"; diff --git a/extensions/src/ACRE2Steam/mumble_linux_plugin.cpp b/extensions/src/ACRE2Steam/mumble_linux_plugin.cpp new file mode 100644 index 000000000..02a31f576 --- /dev/null +++ b/extensions/src/ACRE2Steam/mumble_linux_plugin.cpp @@ -0,0 +1,42 @@ +#include "mumble_linux_plugin.hpp" +#include "wine.h" + +#include + +using ::idi::acre::MumbleLinuxPlugin; + +bool MumbleLinuxPlugin::collect_plugin_locations() noexcept { + if (get_skip_plugin()) { + return true; + } + + if (!detectWine()) { + return true; + } + + // No 32-bit Linux plugin + set_arch_to_install(Architecture::x64); + + if (!mumble_path.empty()) { + check_plugin_locations(mumble_path); + } else { + std::string mumble_data_path("Mumble\\Mumble"); + std::string check_path; + if (getenv("XDG_DATA_HOME")) { + check_path = (std::filesystem::path("Z:") / getenv("XDG_DATA_HOME") / mumble_data_path).string(); + } else if (char* winehome = getenv("WINEHOMEDIR")) { + if (strstr(winehome, "\\??\\")) { + winehome = winehome + 4; + } + check_path = (std::filesystem::path(winehome) / ".local\\share" / mumble_data_path).string(); + } else { + return false; + } + printf("%s\n", check_path.c_str()); + printf("%d\n", std::filesystem::exists(check_path)); + check_plugin_locations(check_path); + } + + // No locations to copy to. + return !get_plugin_locations().empty(); +} diff --git a/extensions/src/ACRE2Steam/mumble_linux_plugin.hpp b/extensions/src/ACRE2Steam/mumble_linux_plugin.hpp new file mode 100644 index 000000000..2f65d75ea --- /dev/null +++ b/extensions/src/ACRE2Steam/mumble_linux_plugin.hpp @@ -0,0 +1,26 @@ +/** + * Mumble auto-plugin copy functionality for running under Wine. + */ +#pragma once +#include "voip_plugin.hpp" + +#include +#include + +namespace idi::acre { + class MumbleLinuxPlugin final : public VOIPPlugin { + public: + explicit MumbleLinuxPlugin(bool skip_plugin_, std::string mumble_path_ = "") noexcept + : VOIPPlugin(skip_plugin_, + "", + "", + find_mod_file("plugin\\mumble\\acre2_x64.so")), + mumble_path(std::move(mumble_path_)) {} + ~MumbleLinuxPlugin() noexcept final = default; + + bool collect_plugin_locations() noexcept final; + + private: + std::string mumble_path; + }; +} // namespace idi::acre From 5d9af92bd7b0fc590940744a63d2857e1f282af0 Mon Sep 17 00:00:00 2001 From: Dylan Frese Date: Sun, 25 Sep 2022 06:02:18 -0500 Subject: [PATCH 21/21] Remove mistakenly committed debug statements --- extensions/src/ACRE2Steam/mumble_linux_plugin.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/extensions/src/ACRE2Steam/mumble_linux_plugin.cpp b/extensions/src/ACRE2Steam/mumble_linux_plugin.cpp index 02a31f576..7545ce39b 100644 --- a/extensions/src/ACRE2Steam/mumble_linux_plugin.cpp +++ b/extensions/src/ACRE2Steam/mumble_linux_plugin.cpp @@ -32,8 +32,6 @@ bool MumbleLinuxPlugin::collect_plugin_locations() noexcept { } else { return false; } - printf("%s\n", check_path.c_str()); - printf("%d\n", std::filesystem::exists(check_path)); check_plugin_locations(check_path); }