diff --git a/.gitmodules b/.gitmodules index 1d7e30cc..beb00b27 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,7 @@ [submodule "ref/asio"] path = ref/asio url = https://github.com/chriskohlhoff/asio.git +[submodule "ref/discord-rpc"] + path = ref/discord-rpc + url = https://github.com/discord/discord-rpc.git + branch = v3.4.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 115423b9..e87ed77f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -429,6 +429,12 @@ target_link_libraries(${PROJECT_NAME} Threads::Threads) find_package(GLM REQUIRED) include_directories(${GLM_INCLUDE_DIR}) +# add ref/discord-rpc to the project in the same way other dependencies are added +add_subdirectory(ref/discord-rpc) +target_link_libraries(${PROJECT_NAME} discord-rpc) + + + find_package(OpenAL REQUIRED) if (TARGET OpenAL::OpenAL) target_link_libraries(${PROJECT_NAME} OpenAL::OpenAL) diff --git a/DynObj.cpp b/DynObj.cpp index 24d31fc6..ecd017cc 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -97,8 +97,110 @@ void TAnimPant::AKP_4E() fHeightExtra[3] = -0.07f; //+0.3048 fHeightExtra[4] = -0.15f; //+0.3810 }; +void TAnimPant::WBL85() +{ // ustawienie wymiarów dla pantografu WBL88 + vPos = Math3D::vector3(0, 0, 0); // przypisanie domyśnych współczynników do pantografów + + // mnozniki animacji ramion dla pantografu WBL88 + rd1rf = 1.f; + rd2rf = 1.2; + rg1rf = 0.875; + rg2rf = 1.0; + slizgrf = 1.f; + + fLenL1 = 1.98374; + fLenU1 = 2.14199; + fHoriz = 0.142; // 0.54555075 przesunięcie ślizgu w długości pojazdu względem + // osi obrotu dolnego ramienia + fHeight = 0.09353; // wysokość ślizgu ponad oś obrotu + fWidth = 0.4969; // połowa szerokości ślizgu + fAngleL0 = DegToRad(2.8547285515689267247882521833308); + fAngleL = fAngleL0; // początkowy kąt dolnego ramienia + // fAngleU0=acos((1.22*cos(fAngleL)+0.535)/1.755); //górne ramię + fAngleU0 = acos((fLenL1 * cos(fAngleL) + fHoriz) / fLenU1); // górne ramię + fAngleU = fAngleU0; // początkowy kąt + // PantWys=1.22*sin(fAngleL)+1.755*sin(fAngleU); //wysokość początkowa + PantWys = fLenL1 * sin(fAngleL) + fLenU1 * sin(fAngleU) + fHeight; // wysokość początkowa + PantTraction = PantWys; + hvPowerWire = NULL; + fWidthExtra = 0.381f; //(2.032m-1.027)/2 + // poza obszarem roboczym jest aproksymacja łamaną o 5 odcinkach + fHeightExtra[0] = 0.0f; //+0.0762 + fHeightExtra[1] = -0.01f; //+0.1524 + fHeightExtra[2] = -0.03f; //+0.2286 + fHeightExtra[3] = -0.07f; //+0.3048 + fHeightExtra[4] = -0.15f; //+0.3810 +}; +void TAnimPant::EC160_200() +{ // ustawienie wymiarów dla pantografow EC160 lub EC200 + vPos = Math3D::vector3(0, 0, 0); // przypisanie domyśnych współczynników do pantografów + + // mnozniki animacji ramion dla pantografow EC160 lub EC200 + rd1rf = 1.f; + rd2rf = 0.85; + rg1rf = 1.f; + rg2rf = 1.f; // 0.833 + slizgrf = 1.f; + + fLenL1 = 1.98374; + fLenU1 = 2.14199; + fHoriz = 0.142; // 0.54555075 przesunięcie ślizgu w długości pojazdu względem + // osi obrotu dolnego ramienia + fHeight = 0.09353; // wysokość ślizgu ponad oś obrotu + fWidth = 0.4969; // połowa szerokości ślizgu + fAngleL0 = DegToRad(2.8547285515689267247882521833308); + fAngleL = fAngleL0; // początkowy kąt dolnego ramienia + // fAngleU0=acos((1.22*cos(fAngleL)+0.535)/1.755); //górne ramię + fAngleU0 = acos((fLenL1 * cos(fAngleL) + fHoriz) / fLenU1); // górne ramię + fAngleU = fAngleU0; // początkowy kąt + // PantWys=1.22*sin(fAngleL)+1.755*sin(fAngleU); //wysokość początkowa + PantWys = fLenL1 * sin(fAngleL) + fLenU1 * sin(fAngleU) + fHeight; // wysokość początkowa + PantTraction = PantWys; + hvPowerWire = NULL; + fWidthExtra = 0.381f; //(2.032m-1.027)/2 + // poza obszarem roboczym jest aproksymacja łamaną o 5 odcinkach + fHeightExtra[0] = 0.0f; //+0.0762 + fHeightExtra[1] = -0.01f; //+0.1524 + fHeightExtra[2] = -0.03f; //+0.2286 + fHeightExtra[3] = -0.07f; //+0.3048 + fHeightExtra[4] = -0.15f; //+0.3810 +}; +void TAnimPant::DSAx() +{ // ustawienie wymiarów dla pantografow z rodziny DSA + vPos = Math3D::vector3(0, 0, 0); // przypisanie domyśnych współczynników do pantografów + + // mnozniki animacji ramion dla pantografow z rodziny DSA + rd1rf = 1.f; + rd2rf = 1.025; + rg1rf = 0.875; + rg2rf = 1.f; + slizgrf = 1.f; + + fLenL1 = 1.98374; + fLenU1 = 2.14199; + fHoriz = 0.142; // 0.54555075 przesunięcie ślizgu w długości pojazdu względem + // osi obrotu dolnego ramienia + fHeight = 0.09353; // wysokość ślizgu ponad oś obrotu + fWidth = 0.4969; // połowa szerokości ślizgu + fAngleL0 = DegToRad(2.8547285515689267247882521833308); + fAngleL = fAngleL0; // początkowy kąt dolnego ramienia + // fAngleU0=acos((1.22*cos(fAngleL)+0.535)/1.755); //górne ramię + fAngleU0 = acos((fLenL1 * cos(fAngleL) + fHoriz) / fLenU1); // górne ramię + fAngleU = fAngleU0; // początkowy kąt + // PantWys=1.22*sin(fAngleL)+1.755*sin(fAngleU); //wysokość początkowa + PantWys = fLenL1 * sin(fAngleL) + fLenU1 * sin(fAngleU) + fHeight; // wysokość początkowa + PantTraction = PantWys; + hvPowerWire = NULL; + fWidthExtra = 0.381f; //(2.032m-1.027)/2 + // poza obszarem roboczym jest aproksymacja łamaną o 5 odcinkach + fHeightExtra[0] = 0.0f; //+0.0762 + fHeightExtra[1] = -0.01f; //+0.1524 + fHeightExtra[2] = -0.03f; //+0.2286 + fHeightExtra[3] = -0.07f; //+0.3048 + fHeightExtra[4] = -0.15f; //+0.3810 +}; //--------------------------------------------------------------------------- -int TAnim::TypeSet(int i, int fl) +int TAnim::TypeSet(int i, TMoverParameters currentMover, int fl) { // ustawienie typu animacji i zależnej od niego ilości animowanych submodeli fMaxDist = -1.0; // normalnie nie pokazywać switch (i) @@ -127,7 +229,21 @@ int TAnim::TypeSet(int i, int fl) case 5: // 5-pantograf - 5 submodeli iFlags = 0x055; fParamPants = new TAnimPant(); - fParamPants->AKP_4E(); + switch (currentMover.EnginePowerSource.CollectorParameters.PantographType) { + case (TPantType::AKP_4E): + fParamPants->AKP_4E(); + break; + case(TPantType::DSAx): + fParamPants->DSAx(); + break; + case(TPantType::EC160_200): + fParamPants->EC160_200(); + break; + case(TPantType::WBL85): + fParamPants->WBL85(); + break; + } + break; case 6: iFlags = 0x068; @@ -576,20 +692,20 @@ void TDynamicObject::UpdateDoorPlug(TAnim *pAnim) { void TDynamicObject::UpdatePant(TAnim *pAnim) { // animacja pantografu - 4 obracane ramiona, ślizg piąty - float a, b, c; - a = RadToDeg(pAnim->fParamPants->fAngleL - pAnim->fParamPants->fAngleL0); - b = RadToDeg(pAnim->fParamPants->fAngleU - pAnim->fParamPants->fAngleU0); - c = a + b; - if (pAnim->smElement[0]) - pAnim->smElement[0]->SetRotate(float3(-1, 0, 0), a); // dolne ramię - if (pAnim->smElement[1]) - pAnim->smElement[1]->SetRotate(float3(1, 0, 0), a); - if (pAnim->smElement[2]) - pAnim->smElement[2]->SetRotate(float3(1, 0, 0), c); // górne ramię - if (pAnim->smElement[3]) - pAnim->smElement[3]->SetRotate(float3(-1, 0, 0), c); - if (pAnim->smElement[4]) - pAnim->smElement[4]->SetRotate(float3(-1, 0, 0), b); //ślizg + float a, b, c; + a = RadToDeg(pAnim->fParamPants->fAngleL - pAnim->fParamPants->fAngleL0); + b = RadToDeg(pAnim->fParamPants->fAngleU - pAnim->fParamPants->fAngleU0); + c = a + b; + if (pAnim->smElement[0]) + pAnim->smElement[0]->SetRotate(float3(-1, 0, 0), a); // dolne ramie 1 + if (pAnim->smElement[1]) + pAnim->smElement[1]->SetRotate(float3(1, 0, 0), a * pAnim->fParamPants->rd2rf); // dolne ramie 2 + if (pAnim->smElement[2]) + pAnim->smElement[2]->SetRotate(float3(1, 0, 0), c); // górne ramie 1 + if (pAnim->smElement[3]) + pAnim->smElement[3]->SetRotate(float3(-1, 0, 0), c * pAnim->fParamPants->rg2rf); // gorne ramie 2 + if (pAnim->smElement[4]) + pAnim->smElement[4]->SetRotate(float3(-1, 0, 0), b * pAnim->fParamPants->slizgrf); // ślizg } // doorstep animation, shift @@ -5041,7 +5157,8 @@ TDynamicObject::radius() const { // McZapkie-250202 // wczytywanie pliku z danymi multimedialnymi (dzwieki) void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string const &ReplacableSkin ) { - + rTypeName = TypeName; + rReplacableSkin = ReplacableSkin; Global.asCurrentDynamicPath = asBaseDir; std::string asFileName = asBaseDir + TypeName + ".mmd"; std::string asAnimName; @@ -5142,8 +5259,8 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co if (iAnimType[ANIM_PANTS]) // o ile jakieś pantografy są (a domyślnie są) pants = &pAnimations[k]; // zapamiętanie na potrzeby wyszukania submodeli pAnimations[k].iShift = sm; // przesunięcie do przydzielenia wskaźnika - sm += pAnimations[k++].TypeSet(j); // ustawienie typu animacji i zliczanie tablicowanych submodeli - } + sm += pAnimations[k++].TypeSet(j, *MoverParameters); // ustawienie typu animacji i zliczanie tablicowanych submodeli + } if (sm) // o ile są bardziej złożone animacje { pAnimated = new TSubModel *[sm]; // tabela na animowane submodele @@ -7740,9 +7857,9 @@ TDynamicObject::update_shake( double const Timedelta ) { if( iVel > 0.5 ) { // acceleration-driven base shake shakevector += Math3D::vector3( - -MoverParameters->AccN * Timedelta * 5.0, // highlight side sway - -MoverParameters->AccVert * Timedelta, - -MoverParameters->AccSVBased * Timedelta * 1.5); // accent acceleration/deceleration + -MoverParameters->AccN * Timedelta * 5.0 * Global.ShakingMultiplierRL, // highlight side sway + -MoverParameters->AccVert * Timedelta * Global.ShakingMultiplierUD, + -MoverParameters->AccSVBased * Timedelta * 1.5 * Global.ShakingMultiplierBF); // accent acceleration/deceleration } auto shake { 1.25 * ShakeSpring.ComputateForces( shakevector, ShakeState.offset ) }; diff --git a/DynObj.h b/DynObj.h index d97826c3..97ca1a90 100644 --- a/DynObj.h +++ b/DynObj.h @@ -103,7 +103,17 @@ class TAnimPant float fWidthExtra; // dodatkowy rozmiar poziomy poza część roboczą (fWidth) float fHeightExtra[5]; //łamana symulująca kształt nabieżnika // double fHorizontal; //Ra 2015-01: położenie drutu względem osi pantografu + + // factory ktore mozna nadpisac z fiza + float rd1rf{1.f}; // mnoznik obrotu ramienia dolnego 1 + float rd2rf{1.f}; // mnoznik obrotu ramienia dolnego 2 + float rg1rf{1.f}; // mnoznik obrotu ramienia gornego 1 + float rg2rf{1.f}; // mnoznik obrotu ramienia gornego 2 + float slizgrf{1.f}; // mnoznik obrotu slizgacza void AKP_4E(); + void WBL85(); + void DSAx(); + void EC160_200(); }; class TAnim @@ -115,8 +125,8 @@ public: // destructor ~TAnim(); // methods - int TypeSet( int i, int fl = 0 ); // ustawienie typu -// members + int TypeSet(int i, TMoverParameters currentMover, int fl = 0); // ustawienie typu + // members union { TSubModel *smAnimated; // animowany submodel (jeśli tylko jeden, np. oś) @@ -209,7 +219,11 @@ public: inline TDynamicObject *PrevConnected() const { return MoverParameters->Neighbours[ end::front ].vehicle; }; // pojazd podłączony od strony sprzęgu 0 (kabina 1) inline int NextConnectedNo() const { return MoverParameters->Neighbours[ end::rear ].vehicle_end; } inline int PrevConnectedNo() const { return MoverParameters->Neighbours[ end::front ].vehicle_end; } -// double fTrackBlock; // odległość do przeszkody do dalszego ruchu (wykrywanie kolizji z innym pojazdem) + + // Dev tools + void Reload(); + + // double fTrackBlock; // odległość do przeszkody do dalszego ruchu (wykrywanie kolizji z innym pojazdem) // modele składowe pojazdu TModel3d *mdModel; // model pudła @@ -573,6 +587,9 @@ private: TDynamicObject *ABuFindObject( int &Foundcoupler, double &Distance, TTrack const *Track, int const Direction, int const Mycoupler ) const; void ABuCheckMyTrack(); + std::string rTypeName; // nazwa typu pojazdu + std::string rReplacableSkin; // nazwa tekstury pojazdu + public: bool DimHeadlights{ false }; // status of the headlight dimming toggle. NOTE: single toggle for all lights is a simplification. TODO: separate per-light switches bool HighBeamLights { false }; // status of the highbeam toggle diff --git a/Globals.cpp b/Globals.cpp index 186aaac1..fa75cfe3 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -213,6 +213,15 @@ global_settings::ConfigParse(cParser &Parser) { { Parser.getTokens(); Parser >> MultipleLogs; + } + else if (token == "shakefactor") + { + Parser.getTokens(); + Parser >> ShakingMultiplierBF; + Parser.getTokens(); + Parser >> ShakingMultiplierRL; + Parser.getTokens(); + Parser >> ShakingMultiplierUD; } else if (token == "logs.filter") { diff --git a/Globals.h b/Globals.h index 82a1b3f9..d54b9f4a 100644 --- a/Globals.h +++ b/Globals.h @@ -16,6 +16,9 @@ http://mozilla.org/MPL/2.0/. #include "light.h" #include "utilities.h" #include "motiontelemetry.h" +#include "ref/discord-rpc/include/discord_rpc.h" +#include + #ifdef WITH_UART #include "uart.h" #endif @@ -27,6 +30,11 @@ struct global_settings { // members // data items // TODO: take these out of the settings + + /// + /// Mapa z watkami w formacie + /// + std::map threads = {}; bool shiftState{ false }; //m7todo: brzydko bool ctrlState{ false }; bool altState{ false }; @@ -118,7 +126,9 @@ struct global_settings { glm::ivec2 window_size; // main window size in platform-specific virtual pixels glm::ivec2 cursor_pos; // cursor position in platform-specific virtual pixels glm::ivec2 fb_size; // main window framebuffer size - + float ShakingMultiplierBF {1.f}; // mnożnik bujania kamera przod/tyl + float ShakingMultiplierRL {1.f}; // mnożnik bujania kamera lewo/prawo + float ShakingMultiplierUD {1.f}; // mnożnik bujania kamera gora/dol float fDistanceFactor{ 1.f }; // baza do przeliczania odległości dla LoD float targetfps{ 0.0f }; bool bFullScreen{ false }; diff --git a/Logs.cpp b/Logs.cpp index 61d1c5ad..c24610c6 100644 --- a/Logs.cpp +++ b/Logs.cpp @@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/. #include "winheaders.h" #include "utilities.h" #include "uilayer.h" +#include std::ofstream output; // standardowy "log.txt", można go wyłączyć std::ofstream errors; // lista błędów "errors.txt", zawsze działa @@ -68,61 +69,88 @@ std::string filename_scenery() { } } +// log service stacks +std::deque InfoStack; +std::deque ErrorStack; + + +void LogService() +{ + while (true) + { + // loop for logging + + // write logs and log.txt + while (!InfoStack.empty()) + { + char *msg = InfoStack.front(); // get first element of stack + InfoStack.pop_front(); + if (Global.iWriteLogEnabled & 1) + { + if (!output.is_open()) + { + + std::string const filename = (Global.MultipleLogs ? "logs/log (" + filename_scenery() + ") " + filename_date() + ".txt" : "log.txt"); + output.open(filename, std::ios::trunc); + } + output << msg << "\n"; + output.flush(); + } + + log_scrollback.emplace_back(std::string(msg)); + if (log_scrollback.size() > 200) + log_scrollback.pop_front(); + + if (Global.iWriteLogEnabled & 2) + { +#ifdef _WIN32 + // hunter-271211: pisanie do konsoli tylko, gdy nie jest ukrywana + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY); + DWORD wr = 0; + WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), msg, (DWORD)strlen(msg), &wr, NULL); + WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), endstring, (DWORD)strlen(endstring), &wr, NULL); +#else + printf("%s\n", msg); +#endif + } + } + + // write to errors.txt + while (!ErrorStack.empty()) + { + char *msg = ErrorStack.front(); + ErrorStack.pop_front(); + + if (!(Global.iWriteLogEnabled & 1)) + return; + + if (!errors.is_open()) + { + + std::string const filename = (Global.MultipleLogs ? "logs/errors (" + filename_scenery() + ") " + filename_date() + ".txt" : "errors.txt"); + errors.open(filename, std::ios::trunc); + errors << "EU07.EXE " + Global.asVersion << "\n"; + } + + errors << msg << "\n"; + errors.flush(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(5)); // dont burn cpu so much + } +} + void WriteLog( const char *str, logtype const Type ) { if( str == nullptr ) { return; } if( true == TestFlag( Global.DisabledLogTypes, static_cast( Type ) ) ) { return; } - - if (Global.iWriteLogEnabled & 1) { - if( !output.is_open() ) { - - std::string const filename = - ( Global.MultipleLogs ? - "logs/log (" + filename_scenery() + ") " + filename_date() + ".txt" : - "log.txt" ); - output.open( filename, std::ios::trunc ); - } - output << str << "\n"; - output.flush(); - } - - log_scrollback.emplace_back(std::string(str)); - if (log_scrollback.size() > 200) - log_scrollback.pop_front(); - - if( Global.iWriteLogEnabled & 2 ) { -#ifdef _WIN32 - // hunter-271211: pisanie do konsoli tylko, gdy nie jest ukrywana - SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), FOREGROUND_GREEN | FOREGROUND_INTENSITY ); - DWORD wr = 0; - WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), str, (DWORD)strlen( str ), &wr, NULL ); - WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), endstring, (DWORD)strlen( endstring ), &wr, NULL ); -#else - printf("%s\n", str); -#endif - } + InfoStack.emplace_back(strdup(str)); } void ErrorLog( const char *str, logtype const Type ) { if( str == nullptr ) { return; } if( true == TestFlag( Global.DisabledLogTypes, static_cast( Type ) ) ) { return; } - - if (!(Global.iWriteLogEnabled & 1)) - return; - - if (!errors.is_open()) { - - std::string const filename = - ( Global.MultipleLogs ? - "logs/errors (" + filename_scenery() + ") " + filename_date() + ".txt" : - "errors.txt" ); - errors.open( filename, std::ios::trunc ); - errors << "EU07.EXE " + Global.asVersion << "\n"; - } - - errors << str << "\n"; - errors.flush(); + ErrorStack.emplace_back(strdup(str)); }; void Error(const std::string &asMessage, bool box) diff --git a/Logs.h b/Logs.h index ebdb5719..f7bf5795 100644 --- a/Logs.h +++ b/Logs.h @@ -23,7 +23,7 @@ enum class logtype : unsigned int { traction = ( 1 << 9 ), powergrid = ( 1 << 10 ), }; - +void LogService(); void WriteLog( const char *str, logtype const Type = logtype::generic ); void Error( const std::string &asMessage, bool box = false ); void Error( const char* &asMessage, bool box = false ); diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index b45e49fc..10eae432 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -469,6 +469,13 @@ struct TBoilerType { //} }; /*rodzaj odbieraka pradu*/ +enum TPantType +{ + AKP_4E, + DSAx, + EC160_200, + WBL85 +}; struct TCurrentCollector { long CollectorsNo; //musi być tu, bo inaczej się kopie double MinH; double MaxH; //zakres ruchu pantografu, nigdzie nie używany @@ -480,6 +487,7 @@ struct TCurrentCollector { double MaxPress; //maksymalne ciśnienie za reduktorem bool FakePower; int PhysicalLayout; + TPantType PantographType; //inline TCurrentCollector() { // CollectorsNo = 0; // MinH, MaxH, CSW, MinV, MaxV = 0.0; @@ -1069,6 +1077,8 @@ class TMoverParameters }; public: + std::string chkPath; + bool reload_FIZ(); double dMoveLen = 0.0; /*---opis lokomotywy, wagonu itp*/ /*--opis serii--*/ @@ -1138,6 +1148,9 @@ class TMoverParameters int UniversalBrakeButtonFlag[3] = {0, 0, 0}; /* mozliwe działania przycisków hamulcowych */ int UniversalResetButtonFlag[3] = {0, 0, 0}; // customizable reset buttons assignments int TurboTest = 0; + bool isBatteryButtonImpulse = false; // czy przelacznik baterii traktowac jako pojedynczy przycisk + bool shouldHoldBatteryButton = false; // czy nalezy przytrzymac przycisk baterii aby wlaczyc/wylaczyc baterie + float BatteryButtonHoldTime = 1.f; // minimalny czas przytrzymania przycisku baterii double MaxBrakeForce = 0.0; /*maksymalna sila nacisku hamulca*/ double MaxBrakePress[5]; // pomocniczy, proz, sred, lad, pp double P2FTrans = 0.0; @@ -1213,6 +1226,8 @@ class TMoverParameters double SpringBrakeDriveEmergencyVel{-1}; bool HideDirStatusWhenMoving{false}; // Czy gasic lampki kierunku powyzej predkosci zdefiniowanej przez HideDirStatusSpeed int HideDirStatusSpeed{1}; // Predkosc od ktorej lampki kierunku sa wylaczane + bool isDoubleClickForMeasureNeeded = {false}; // czy rozpoczecie pomiaru odleglosci odbywa sie po podwojnym wcisnienciu przycisku? + float DistanceCounterDoublePressPeriod = {1.f}; // czas w jakim nalezy podwojnie wcisnac przycisk, aby rozpoczac pomiar odleglosci TSecuritySystem SecuritySystem; int EmergencyBrakeWarningSignal{0}; // combined with basic WarningSignal when manual emergency brake is active TUniversalCtrlTable UniCtrlList; /*lista pozycji uniwersalnego nastawnika*/ diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index f26544ed..deb8492e 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -9444,6 +9444,7 @@ void TMoverParameters::BrakeSubsystemDecode() // ************************************************************************************************* bool TMoverParameters::LoadFIZ(std::string chkpath) { + chkPath = chkpath; // assign class path for reloading const int param_ok = 1; const int wheels_ok = 2; const int dimensions_ok = 4; @@ -10625,6 +10626,12 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) { extract_value(HideDirStatusWhenMoving, "HideDirStatusWhenMoving", line, ""); extract_value(HideDirStatusSpeed, "HideDirStatusSpeed", line, ""); + extract_value(isDoubleClickForMeasureNeeded, "DCMB", line, ""); + extract_value(DistanceCounterDoublePressPeriod, "DCDPP", line, ""); + + extract_value(isBatteryButtonImpulse, "IBTB", line, ""); + extract_value(shouldHoldBatteryButton, "SBBBH", line, ""); + extract_value(BatteryButtonHoldTime, "BBHT", line, ""); std::map starts { { "Disabled", start_t::disabled }, @@ -11331,6 +11338,17 @@ void TMoverParameters::LoadFIZ_PowerParamsDecode( TPowerParameters &Powerparamet auto &collectorparameters = Powerparameters.CollectorParameters; collectorparameters = TCurrentCollector { 0, 0, 0, 0, 0, 0, false, 0, 0, 0, false, 0 }; + + std::string PantType = ""; + extract_value(PantType, "PantType", Line, ""); + if (PantType == "AKP_4E") + collectorparameters.PantographType = TPantType::AKP_4E; + if (PantType._Starts_with("DSA")) // zakladam ze wszystkie pantografy DSA sa takie same + collectorparameters.PantographType = TPantType::DSAx; + if (PantType == "EC160" || PantType == "EC200") + collectorparameters.PantographType = TPantType::EC160_200; + if (PantType == "WBL85") + collectorparameters.PantographType = TPantType::WBL85; extract_value( collectorparameters.CollectorsNo, "CollectorsNo", Line, "" ); extract_value( collectorparameters.MinH, "MinH", Line, "" ); @@ -12467,6 +12485,24 @@ double TMoverParameters::ShowCurrentP(int AmpN) const } } +bool TMoverParameters::reload_FIZ() { + WriteLog("[DEV] Reloading FIZ for " + Name); + // pause simulation + Global.iPause |= 0b1000; + bool result = LoadFIZ(chkPath); + if (result == true) + { + // jesli sie udalo przeladowac FIZ + Global.iPause &= 0b0111; + WriteLog("[DEV] FIZ reloaded for " + Name); + } + else { + // failed to reload - exit simulator + ErrorLog("[DEV] Failed to reload fiz for vehicle " + Name); + } + return true; +} + namespace simulation { weights_table Weights; diff --git a/Spring.cpp b/Spring.cpp index da955280..59e5c55d 100644 --- a/Spring.cpp +++ b/Spring.cpp @@ -40,7 +40,7 @@ Math3D::vector3 TSpring::ComputateForces( Math3D::vector3 const &pPosition1, Mat // ScaleVector(&deltaP,1.0f / dist, &springForce); // Normalize Distance Vector // ScaleVector(&springForce,-(Hterm + Dterm),&springForce); // Calc Force - springForce = deltaP / dist * ( -( Hterm + Dterm ) ); + springForce = deltaP / dist * ( -( Hterm + Dterm )); // VectorSum(&p1->f,&springForce,&p1->f); // Apply to Particle 1 // VectorDifference(&p2->f,&springForce,&p2->f); // - Force on Particle 2 } diff --git a/Train.cpp b/Train.cpp index 035ad6da..b2a76c05 100644 --- a/Train.cpp +++ b/Train.cpp @@ -1317,7 +1317,17 @@ void TTrain::OnCommand_distancecounteractivate( TTrain *Train, command_data cons // visual feedback Train->ggDistanceCounterButton.UpdateValue( 1.0, Train->dsbSwitch ); // activate or start anew - Train->m_distancecounter = 0.f; + if (Train->mvOccupied->isDoubleClickForMeasureNeeded) { + // handler tempomatu dla podwojnego kliku + if (Train->trainLenghtMeasureTimer >= 0.f) // jesli zdazylismy w czasie sekundy + Train->m_distancecounter = 0.f; // rozpoczynamy pomiar + else + Train->trainLenghtMeasureTimer = Train->mvOccupied->DistanceCounterDoublePressPeriod; // odpalamy zegarek od nowa + } + else { + // dla pojedynczego kliku + Train->m_distancecounter = 0.f; + } } else if( Command.action == GLFW_RELEASE ) { // visual feedback @@ -2388,7 +2398,8 @@ void TTrain::OnCommand_cabsignalacknowledge( TTrain *Train, command_data const & void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command ) { - if( Command.action != GLFW_REPEAT ) { + if (Train->allowBatteryToggle || Command.action != GLFW_REPEAT) + { // keep the switch from flipping back and forth if key is held down if( false == Train->mvOccupied->Power24vIsAvailable ) { // turn on @@ -2402,44 +2413,160 @@ void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command } void TTrain::OnCommand_batteryenable( TTrain *Train, command_data const &Command ) { + if (!Train->mvOccupied->isBatteryButtonImpulse) + { // regular button behavior + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); - if( Command.action == GLFW_PRESS ) { - // visual feedback - Train->ggBatteryButton.UpdateValue( 1.0f, Train->dsbSwitch ); - Train->ggBatteryOnButton.UpdateValue( 1.0f, Train->dsbSwitch ); - - Train->mvOccupied->BatterySwitch( true ); - - // side-effects - if( Train->mvOccupied->LightsPosNo > 0 ) { - Train->Dynamic()->SetLights(); - } + Train->mvOccupied->BatterySwitch(true); + Train->allowBatteryToggle = false; + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->ggBatteryButton.type() == TGaugeType::push) + { + // return the switch to neutral position + Train->ggBatteryButton.UpdateValue(0.5f); + } + Train->ggBatteryOnButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->allowBatteryToggle = true; + } } - else if( Command.action == GLFW_RELEASE ) { - if( Train->ggBatteryButton.type() == TGaugeType::push ) { - // return the switch to neutral position - Train->ggBatteryButton.UpdateValue( 0.5f ); + else // impulse button behavior + { + if (Command.action == GLFW_PRESS) + { + if (Train->mvOccupied->shouldHoldBatteryButton) + { + // jesli przycisk trzeba przytrzymac + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->fBatteryTimer = Train->mvOccupied->BatteryButtonHoldTime; // start timer + } + else + { + // jesli przycisk dziala od razu + Train->mvOccupied->BatterySwitch(true); + Train->allowBatteryToggle = false; + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + + // visual feedback + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); + } } - Train->ggBatteryOnButton.UpdateValue( 0.0f, Train->dsbSwitch ); + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->fBatteryTimer = -1.f; // + Train->allowBatteryToggle = true; + } + else if (Command.action == GLFW_REPEAT && Train->mvOccupied->shouldHoldBatteryButton) + { + // trzymamy przycisk + if (Train->fBatteryTimer <= 0.0 && Train->mvOccupied->Battery == false) { + Train->mvOccupied->BatterySwitch(true); + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + Train->allowBatteryToggle = false; + } + + } } } void TTrain::OnCommand_batterydisable( TTrain *Train, command_data const &Command ) { - // TBD, TODO: ewentualnie zablokować z FIZ, np. w samochodach się nie odłącza akumulatora - if( Command.action == GLFW_PRESS ) { - // visual feedback - Train->ggBatteryButton.UpdateValue( 0.0f, Train->dsbSwitch ); - Train->ggBatteryOffButton.UpdateValue( 1.0f, Train->dsbSwitch ); + if (!Train->mvOccupied->isBatteryButtonImpulse) + { // regular button behavior + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->mvOccupied->BatterySwitch( false ); - } - else if( Command.action == GLFW_RELEASE ) { - if( Train->ggBatteryButton.type() == TGaugeType::push ) { - // return the switch to neutral position - Train->ggBatteryButton.UpdateValue( 0.5f ); - } - Train->ggBatteryOffButton.UpdateValue( 0.0f, Train->dsbSwitch ); - } + Train->mvOccupied->BatterySwitch(false); + + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->ggBatteryButton.type() == TGaugeType::push) + { + // return the switch to neutral position + Train->ggBatteryButton.UpdateValue(0.5f); + } + Train->ggBatteryOffButton.UpdateValue(0.0f, Train->dsbSwitch); + } + } + else // impulse button behavior + { + if (Command.action == GLFW_PRESS) + { + if (Train->mvOccupied->shouldHoldBatteryButton) + { + // jesli przycisk trzeba przytrzymac + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->fBatteryTimer = Train->mvOccupied->BatteryButtonHoldTime; // start timer + } + else + { + // jesli przycisk dziala od razu + Train->mvOccupied->BatterySwitch(false); + Train->allowBatteryToggle = false; + + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + // visual feedback + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->allowBatteryToggle = true; + } + else if (Command.action == GLFW_REPEAT && Train->mvOccupied->shouldHoldBatteryButton) + { + // trzymamy przycisk + if (Train->fBatteryTimer <= 0.0 && Train->mvOccupied->Battery == true) { + Train->mvOccupied->BatterySwitch(false); + Train->allowBatteryToggle = false; + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + } + } + } } void TTrain::OnCommand_cabactivationtoggle(TTrain *Train, command_data const &Command) { @@ -2848,23 +2975,43 @@ void TTrain::change_pantograph_selection( int const Change ) { void TTrain::OnCommand_pantographvalvesupdate( TTrain *Train, command_data const &Command ) { + bool hasSeparateSwitches = Train->m_controlmapper.contains("pantvalvesupdate_bt:") && + Train->m_controlmapper.contains("pantvalvesoff_bt:"); + if( Command.action == GLFW_REPEAT ) { return; } if( Command.action == GLFW_PRESS ) { - // implement action - Train->update_pantograph_valves(); - // visual feedback - Train->ggPantValvesButton.UpdateValue( 1.0, Train->dsbSwitch ); + if (hasSeparateSwitches) + { + // implement action + Train->update_pantograph_valves(); + // visual feedback + Train->ggPantValvesUpdate.UpdateValue(1.0, Train->dsbSwitch); + } + + // Old logic to maintain compatibility + else + { + Train->update_pantograph_valves(); + Train->ggPantValvesButton.UpdateValue(1.0, Train->dsbSwitch); + } } else if( Command.action == GLFW_RELEASE ) { // visual feedback // NOTE: pantvalves_sw: is a specialized button, with no toggle behavior support - Train->ggPantValvesButton.UpdateValue( 0.5, Train->dsbSwitch ); + if (hasSeparateSwitches) + Train->ggPantValvesUpdate.UpdateValue(0.5, Train->dsbSwitch); + + // Old logic to maintain compatibility + else + Train->ggPantValvesButton.UpdateValue(0.5, Train->dsbSwitch); } } void TTrain::OnCommand_pantographvalvesoff( TTrain *Train, command_data const &Command ) { + bool hasSeparateSwitches = Train->m_controlmapper.contains("pantvalvesupdate_bt:") && Train->m_controlmapper.contains("pantvalvesoff_bt:"); + if( Command.action == GLFW_REPEAT ) { return; } if( Command.action == GLFW_PRESS ) { @@ -2872,12 +3019,18 @@ void TTrain::OnCommand_pantographvalvesoff( TTrain *Train, command_data const &C Train->mvOccupied->OperatePantographValve( end::front, operation_t::disable ); Train->mvOccupied->OperatePantographValve( end::rear, operation_t::disable ); // visual feedback - Train->ggPantValvesButton.UpdateValue( 0.0, Train->dsbSwitch ); + if (hasSeparateSwitches) + Train->ggPantValvesOff.UpdateValue(1.0, Train->dsbSwitch); + else + Train->ggPantValvesButton.UpdateValue( 0.0, Train->dsbSwitch ); } else if( Command.action == GLFW_RELEASE ) { // visual feedback - // NOTE: pantvalves_sw: is a specialized button, with no toggle behavior support - Train->ggPantValvesButton.UpdateValue( 0.5, Train->dsbSwitch ); + // NOTE: pantvalves_sw: is a speciali zed button, with no toggle behavior support + if (hasSeparateSwitches) + Train->ggPantValvesOff.UpdateValue(0.f, Train->dsbSwitch); + else + Train->ggPantValvesButton.UpdateValue( 0.5, Train->dsbSwitch ); } } @@ -6926,6 +7079,21 @@ bool TTrain::Update( double const Deltatime ) mvOccupied->OperateDoors( static_cast( idx ), true ); } } + + // train measurement timer + if (trainLenghtMeasureTimer >= 0.f) { + trainLenghtMeasureTimer -= Deltatime; + if (trainLenghtMeasureTimer < 0.f) + trainLenghtMeasureTimer = -1.f; + } + + // battery timer + if (fBatteryTimer >= 0.f) { + fBatteryTimer -= Deltatime; + if (fBatteryTimer < 0.f) + fBatteryTimer = -1.f; + } + // helper variables if( DynamicObject->Mechanik != nullptr ) { m_doors = ( @@ -7435,6 +7603,12 @@ bool TTrain::Update( double const Deltatime ) else btCompressors.Turn(false); + // Lampka zezwolenia na hamowanie ED + if (mvControlled->EpFuse) + btEDenabled.Turn(true); + else + btEDenabled.Turn(false); + // Lampka aktywowanej kabiny if (mvControlled->CabActive != 0) { btCabActived.Turn(true); @@ -7448,6 +7622,7 @@ bool TTrain::Update( double const Deltatime ) else btAKLVents.Turn(false); + if( true == lowvoltagepower ) { // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa if( mvOccupied->SecuritySystem.is_vigilance_blinking() ) { @@ -8079,6 +8254,9 @@ bool TTrain::Update( double const Deltatime ) ggPantCompressorButton.Update(); ggPantCompressorValve.Update(); + ggPantValvesOff.Update(); + ggPantValvesUpdate.Update(); + ggLightsButton.Update(); ggUpperLightButton.Update(); ggLeftLightButton.Update(); @@ -9572,6 +9750,10 @@ void TTrain::clear_cab_controls() ggPantValvesButton.Clear(); ggPantCompressorButton.Clear(); ggPantCompressorValve.Clear(); + + ggPantValvesOff.Clear(); + ggPantValvesUpdate.Clear(); + ggI1B.Clear(); ggI2B.Clear(); ggI3B.Clear(); @@ -9723,6 +9905,16 @@ void TTrain::set_cab_controls( int const Cab ) { ggModernLightDimSw.PutValue(mvOccupied->modernDimmerState - 1); } + // Init separate buttons + if (ggPantValvesUpdate.SubModel != nullptr) + { + ggPantValvesUpdate.PutValue(0.f); + } + if (ggPantValvesOff.SubModel != nullptr) + { + ggPantValvesOff.PutValue(0.f); + } + // motor connectors ggStLinOffButton.PutValue( ( mvControlled->StLinSwitchOff ? @@ -9781,6 +9973,7 @@ void TTrain::set_cab_controls( int const Cab ) { 0.f ) ); } ggPantValvesButton.PutValue( 0.5f ); + // auxiliary compressor ggPantCompressorValve.PutValue( mvControlled->bPantKurek3 ? @@ -10164,7 +10357,8 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co { "i-universal9:", btUniversals[ 9 ] }, { "i-cabactived:", btCabActived }, {"i-aklvents:", btAKLVents}, - {"i-compressorany:", btCompressors } + {"i-compressorany:", btCompressors }, + {"i-edenabled", btEDenabled }, }; { auto lookup = lights.find( Label ); @@ -10396,6 +10590,8 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "invertertoggle10_bt:", ggInverterToggleButtons[9] }, { "invertertoggle11_bt:", ggInverterToggleButtons[10] }, { "invertertoggle12_bt:", ggInverterToggleButtons[11] }, + {"pantvalvesupdate_bt:", ggPantValvesUpdate}, + {"pantvalvesoff_bt:", ggPantValvesOff} }; { auto const lookup { gauges.find( Label ) }; diff --git a/Train.h b/Train.h index ccfa21a5..a6267bb2 100644 --- a/Train.h +++ b/Train.h @@ -663,6 +663,8 @@ public: // reszta może by?publiczna TGauge ggPantValvesButton; TGauge ggPantCompressorButton; TGauge ggPantCompressorValve; + TGauge ggPantValvesUpdate; + TGauge ggPantValvesOff; // Winger 020304 - wlacznik ogrzewania TGauge ggTrainHeatingButton; TGauge ggSignallingButton; @@ -777,6 +779,7 @@ public: // reszta może by?publiczna TButton btCabActived; TButton btAKLVents; TButton btCompressors; // lampka pracy jakiejkolwiek sprezarki + TButton btEDenabled; // czy wlaczony jest hamulec ED (czy dostepny) // other TButton btLampkaMalfunction; TButton btLampkaMalfunctionB; @@ -840,6 +843,8 @@ private: float fHaslerTimer; float fConverterTimer; // hunter-261211: dla przekaznika float fMainRelayTimer; // hunter-141211: zalaczanie WSa z opoznieniem + float fBatteryTimer = {-1.f}; // Hirek: zalaczanie baterii z opoznieniem (tylko gdy zdefiniowano takie zachowanie w fiz) + bool allowBatteryToggle = true; // Hirek: zabezpieczenie przed przelaczaniem bateri on/off int ScreenUpdateRate { 0 }; // vehicle specific python screen update rate override // McZapkie-240302 - przyda sie do tachometru @@ -882,6 +887,7 @@ private: bool m_dirbackward{ false }; // helper, true if direction set to backward bool m_doorpermits{ false }; // helper, true if any door permit is active float m_doorpermittimers[2] = { -1.f, -1.f }; + float trainLenghtMeasureTimer = { -1.f }; // ld substitute bool m_couplingdisconnect { false }; bool m_couplingdisconnectback { false }; diff --git a/application.cpp b/application.cpp index ccd49af3..08c9bfb6 100644 --- a/application.cpp +++ b/application.cpp @@ -29,6 +29,9 @@ http://mozilla.org/MPL/2.0/. #include "Timer.h" #include "dictionary.h" #include "version_info.h" +#include "ref/discord-rpc/include/discord_rpc.h" +#include +#include "translation.h" #ifdef _WIN32 #pragma comment (lib, "dsound.lib") @@ -174,6 +177,83 @@ int eu07_application::run_crashgui() } return -1; } +void eu07_application::DiscordRPCService() +{ + // initialize discord-rpc + WriteLog("Initializing Discord Rich Presence..."); + static const char *discord_app_id = "1343662664504840222"; + DiscordEventHandlers handlers; + memset(&handlers, 0, sizeof(handlers)); + Discord_Initialize(discord_app_id, &handlers, 1, nullptr); + + std::string rpcScnName = Global.SceneryFile; + if (rpcScnName[0] == '$') + rpcScnName.erase(0, 1); + rpcScnName.erase(rpcScnName.size() - 4, 4); + if (rpcScnName.find('_') != std::string::npos) + { + std::replace(rpcScnName.begin(), rpcScnName.end(), '_', ' '); + } + + // calculate startup timestamp + auto now = std::chrono::system_clock::now(); + auto now_c = std::chrono::system_clock::to_time_t(now); + + // Init RPC object + static DiscordRichPresence discord_rpc; + memset(&discord_rpc, 0, sizeof(discord_rpc)); + // realworld timestamp from datetime + discord_rpc.startTimestamp = static_cast(now_c); + static std::string state = Translations.lookup_s("Scenery: ") + rpcScnName; + discord_rpc.state = state.c_str(); + discord_rpc.details = Translations.lookup_c("Loading scenery..."); + discord_rpc.largeImageKey = "logo"; + discord_rpc.largeImageText = "MaSzyna"; + + // First RPC upload + Discord_UpdatePresence(&discord_rpc); + + // run loop + while (!glfwWindowShouldClose(m_windows.front()) && !m_modestack.empty()) + { + // Discord RPC updater + if (simulation::is_ready) + { + std::string PlayerVehicle; + if (simulation::Train != nullptr) + { + PlayerVehicle = simulation::Train->name(); + // make to upper + for (auto &c : PlayerVehicle) + c = toupper(c); + + PlayerVehicle = Translations.lookup_s("Driving: ") + PlayerVehicle; + discord_rpc.details = PlayerVehicle.c_str(); + + uint16_t playerTrainVelocity = simulation::Train->Dynamic()->GetVelocity(); + if (playerTrainVelocity > 1) + { + // ikonka ze jedziemy i nie spimy + discord_rpc.smallImageKey = "driving"; + std::string smallText = Translations.lookup_s("Speed: ") + std::to_string(playerTrainVelocity) + " km/h"; + discord_rpc.smallImageText = smallText.c_str(); + } + else + { + // krecimy postoj + discord_rpc.smallImageKey = "halt"; + discord_rpc.smallImageText = Translations.lookup_c("Stopped"); + } + } + + + + + Discord_UpdatePresence(&discord_rpc); + } + std::this_thread::sleep_for(std::chrono::milliseconds(5000)); // update RPC every 5 secs + } +} int eu07_application::init( int Argc, char *Argv[] ) { @@ -186,6 +266,10 @@ eu07_application::init( int Argc, char *Argv[] ) { return result; } + // start logging service + std::thread sLoggingService(LogService); + Global.threads.emplace("LogService", std::move(sLoggingService)); + WriteLog( "Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")" ); WriteLog( "For online documentation and additional files refer to: http://eu07.pl" ); WriteLog( "Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, " @@ -239,9 +323,15 @@ eu07_application::init( int Argc, char *Argv[] ) { if (!init_network()) return -1; + // Run DiscordRPC service + std::thread sDiscordRPC(&eu07_application::DiscordRPCService, this); + Global.threads.emplace("DiscordRPC", std::move(sDiscordRPC)); + return result; } + + double eu07_application::generate_sync() { if (Timer::GetDeltaTime() == 0.0) return 0.0; @@ -433,7 +523,8 @@ eu07_application::run() { std::this_thread::sleep_for( Global.minframetime - frametime ); } } - + Global.threads["LogService"].~thread(); // kill log service + Global.threads["DiscordRPC"].~thread(); // kill DiscordRPC service return 0; } diff --git a/application.h b/application.h index 4d6b2955..3cc73ff0 100644 --- a/application.h +++ b/application.h @@ -37,6 +37,8 @@ public: int run(); // issues request for a worker thread to perform specified task. returns: true if task was scheduled + + void eu07_application::DiscordRPCService(); // discord rich presence service function (runs as separate thread) bool request( python_taskqueue::task_request const &Task ); // ensures the main thread holds the python gil and can safely execute python calls diff --git a/appveyor.yml b/appveyor.yml index d42cd5f6..6644ef1a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,10 +3,10 @@ image: Visual Studio 2017 clone_depth: 1 build_script: - ps: >- + git submodule update --init --recursive + cd ref - - git clone "https://github.com/chriskohlhoff/asio" --depth 1 --branch asio-1-16-1 -q - + curl -o crashpad86.zip "http://get.backtrace.io/crashpad/builds/release/x86/crashpad-2020-07-01-release-x86-558c9614e3819179f30b92541450f5ac643afce5.zip" 7z x crashpad86.zip diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index 12a13ffa..31da0943 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -854,6 +854,12 @@ drivermouse_input::default_bindings() { { "pantvalves_sw:", { user_command::pantographvalvesupdate, user_command::pantographvalvesoff } }, + { "pantvalvesupdate_bt:", { + user_command::pantographvalvesupdate, + user_command::none}}, + { "pantvalvesoff_bt:", { + user_command::pantographvalvesoff, + user_command::none}}, { "pantcompressor_sw:", { user_command::pantographcompressoractivate, user_command::none } }, diff --git a/driveruipanels.cpp b/driveruipanels.cpp index b4e8c70c..b48e57ab 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -620,8 +620,9 @@ debug_panel::render() { ImGui::Checkbox( "Debug Traction", &DebugTractionFlag ); } render_section( "Camera", m_cameralines ); - render_section( "Gfx Renderer", m_rendererlines ); + render_section( "Gfx Renderer / Statistics", m_rendererlines ); render_section_settings(); + render_section_developer(); // Developer tools #ifdef WITH_UART if(true == render_section( "UART", m_uartlines)) { int ports_num = UartStatus.available_ports.size(); @@ -1469,6 +1470,14 @@ debug_panel::update_section_renderer( std::vector &Output ) { // renderer stats Output.emplace_back( GfxRenderer->info_times(), Global.UITextColor ); Output.emplace_back( GfxRenderer->info_stats(), Global.UITextColor ); + + // CPU related + Output.emplace_back("CPU:", Global.UITextColor); + + // thread counter + textline = "Running threads: " + std::to_string(Global.threads.size() + 1); + Output.emplace_back(textline, Global.UITextColor); + } bool @@ -1492,6 +1501,19 @@ debug_panel::render_section( std::vector const &Lines ) { return true; } +bool debug_panel::render_section_developer() +{ + if (false == ImGui::CollapsingHeader("Developer tools")) + return false; + ImGui::PushStyleColor(ImGuiCol_Text, {Global.UITextColor.r, Global.UITextColor.g, Global.UITextColor.b, Global.UITextColor.a}); + ImGui::TextUnformatted("Warning! These tools are only for developers.\nDo not use them if you are NOT sure what they do!"); + ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "These settings may crash your simulator!"); + if (ImGui::Button("Reload current vehicle .fiz") == true) + { + m_input.vehicle->MoverParameters->reload_FIZ(); // reload fiz + } +} + bool debug_panel::render_section_settings() { diff --git a/driveruipanels.h b/driveruipanels.h index e1a9acbe..f34a601e 100644 --- a/driveruipanels.h +++ b/driveruipanels.h @@ -104,7 +104,8 @@ private: bool render_section_uart(); #endif bool render_section_settings(); -// members + bool render_section_developer(); + // members std::array m_buffer; std::array m_eventsearch; input_data m_input; diff --git a/editormode.cpp b/editormode.cpp index 11a61890..f2cd69bc 100644 --- a/editormode.cpp +++ b/editormode.cpp @@ -206,7 +206,7 @@ editor_mode::on_key( int const Key, int const Scancode, int const Action, int co m_node = nullptr; m_dragging = false; - Application.set_cursor( GLFW_CURSOR_NORMAL ); + //Application.set_cursor( GLFW_CURSOR_NORMAL ); static_cast( m_userinterface.get() )->set_node(nullptr); simulation::State.delete_model(model); @@ -318,10 +318,14 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods if( Action == GLFW_PRESS ) { // left button press auto const mode = static_cast( m_userinterface.get() )->mode(); + auto const rotation_mode = static_cast( m_userinterface.get() )->rot_mode(); + auto const fixed_rotation_value = + static_cast(m_userinterface.get())->rot_val(); m_node = nullptr; - GfxRenderer->Pick_Node_Callback([this, mode,Action,Button](scene::basic_node *node) { + GfxRenderer->Pick_Node_Callback([this, mode, rotation_mode, fixed_rotation_value, + Action, Button](scene::basic_node *node) { editor_ui *ui = static_cast(m_userinterface.get()); if (mode == nodebank_panel::MODIFY) { @@ -329,10 +333,10 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods return; m_node = node; - if( m_node ) - Application.set_cursor( GLFW_CURSOR_DISABLED ); - else - m_dragging = false; + //if( m_node ) + //Application.set_cursor( GLFW_CURSOR_DISABLED ); + //else + //m_dragging = false; ui->set_node(m_node); } else if (mode == nodebank_panel::COPY) { @@ -360,8 +364,24 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods if (!m_dragging) return; - m_node = cloned; - Application.set_cursor( GLFW_CURSOR_DISABLED ); + + m_node = cloned; + + if (rotation_mode == functions_panel::RANDOM) + { + auto const rotation{glm::vec3{0, LocalRandom(0.0, 360.0), 0}}; + + m_editor.rotate(m_node, rotation, 1); + } + else if (rotation_mode == functions_panel::FIXED) + { + + auto const rotation{glm::vec3{0, fixed_rotation_value, 0}}; + + m_editor.rotate(m_node, rotation, 0); + + } + //Application.set_cursor( GLFW_CURSOR_DISABLED ); ui->set_node( m_node ); } }); @@ -370,8 +390,8 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods } else { // left button release - if( m_node ) - Application.set_cursor( GLFW_CURSOR_NORMAL ); + //if( m_node ) + //Application.set_cursor( GLFW_CURSOR_NORMAL ); m_dragging = false; // prime history stack for another snapshot m_takesnapshot = true; diff --git a/editoruilayer.cpp b/editoruilayer.cpp index 9ea162bf..0af6d525 100644 --- a/editoruilayer.cpp +++ b/editoruilayer.cpp @@ -21,6 +21,7 @@ editor_ui::editor_ui() { add_external_panel( &m_itempropertiespanel ); add_external_panel( &m_nodebankpanel ); + add_external_panel( &m_functionspanel ); } // updates state of UI elements @@ -41,6 +42,7 @@ editor_ui::update() { ui_layer::update(); m_itempropertiespanel.update( m_node ); + m_functionspanel.update( m_node ); } void @@ -63,3 +65,17 @@ nodebank_panel::edit_mode editor_ui::mode() { return m_nodebankpanel.mode; } + +functions_panel::rotation_mode +editor_ui::rot_mode() { + return m_functionspanel.rot_mode; +} +float +editor_ui::rot_val() { + return m_functionspanel.rot_value; +} +bool +editor_ui::rot_from_last() +{ + return m_functionspanel.rot_from_last; +} \ No newline at end of file diff --git a/editoruilayer.h b/editoruilayer.h index 893a03e9..2330d533 100644 --- a/editoruilayer.h +++ b/editoruilayer.h @@ -31,6 +31,12 @@ public: set_node( scene::basic_node * Node ); void add_node_template(const std::string &desc); + float + rot_val(); + bool + rot_from_last(); + functions_panel::rotation_mode + rot_mode(); const std::string * get_active_node_template(); nodebank_panel::edit_mode @@ -39,6 +45,7 @@ public: private: // members itemproperties_panel m_itempropertiespanel { "Node Properties", true }; + functions_panel m_functionspanel { "Functions", true }; nodebank_panel m_nodebankpanel{ "Node Bank", true }; scene::basic_node * m_node { nullptr }; // currently bound scene node, if any }; diff --git a/editoruipanels.cpp b/editoruipanels.cpp index 8b15bef2..6b4d4759 100644 --- a/editoruipanels.cpp +++ b/editoruipanels.cpp @@ -420,8 +420,6 @@ nodebank_panel::render() { ImGui::SameLine(); ImGui::RadioButton("Insert from bank", (int*)&mode, ADD); ImGui::SameLine(); - ImGui::RadioButton("Brush", (int*)&mode, BRUSH); - ImGui::SameLine(); ImGui::RadioButton( "Copy to bank", (int*)&mode, COPY ); ImGui::SameLine(); if (ImGui::Button("Reload Nodebank")) @@ -493,3 +491,64 @@ nodebank_panel::generate_node_label( std::string Input ) const { model : model + " (" + texture + ")" ); } + +void functions_panel::update(scene::basic_node const *Node) +{ + m_node = Node; + + if (false == is_open) + { + return; + } + + text_lines.clear(); + m_grouplines.clear(); + + std::string textline; + + // scenario inspector + auto const *node{Node}; + auto const &camera{Global.pCamera}; + + + + +} + +void +functions_panel::render() { + + if( false == is_open ) { return; } + + auto flags = + ImGuiWindowFlags_NoFocusOnAppearing + | ImGuiWindowFlags_NoCollapse + | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + + if( size.x > 0 ) { + ImGui::SetNextWindowSize( ImVec2S( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2S( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + auto const panelname { ( + title.empty() ? + m_name : + title ) + + "###" + m_name }; + if( true == ImGui::Begin( panelname.c_str(), nullptr, flags ) ) { + // header section + + ImGui::RadioButton("Random rotation", (int *)&rot_mode, RANDOM); + ImGui::RadioButton("Fixed rotation", (int *)&rot_mode, FIXED); + if(rot_mode == FIXED){ + //ImGui::Checkbox("Get rotation from last object", &rot_from_last); + ImGui::SliderFloat("Rotation Value", &rot_value, 0.0f, 360.0f, "%.1f"); + }; + ImGui::RadioButton("Default rotation", (int *)&rot_mode, DEFAULT); + for( auto const &line : text_lines ) { + ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); + } + } + ImGui::End(); +} \ No newline at end of file diff --git a/editoruipanels.h b/editoruipanels.h index 22fc554e..5aed376f 100644 --- a/editoruipanels.h +++ b/editoruipanels.h @@ -73,3 +73,35 @@ private: char m_nodesearch[ 128 ]; std::shared_ptr m_selectedtemplate; }; + +class functions_panel : public ui_panel +{ + + public: + enum rotation_mode + { + RANDOM, + FIXED, + DEFAULT + }; + rotation_mode rot_mode = DEFAULT; + + float rot_value = 0.0f; + bool rot_from_last = false; + + functions_panel(std::string const &Name, bool const Isopen) : ui_panel(Name, Isopen) {} + + void update(scene::basic_node const *Node); + void render() override; + + + private: + // methods + + + // members + scene::basic_node const *m_node{nullptr}; // scene node bound to the panel + scene::group_handle m_grouphandle{null_handle}; // scene group bound to the panel + std::string m_groupprefix; + std::vector m_grouplines; +}; \ No newline at end of file diff --git a/ref/discord-rpc b/ref/discord-rpc new file mode 160000 index 00000000..963aa9f3 --- /dev/null +++ b/ref/discord-rpc @@ -0,0 +1 @@ +Subproject commit 963aa9f3e5ce81a4682c6ca3d136cddda614db33 diff --git a/thread_list.txt b/thread_list.txt new file mode 100644 index 00000000..71388293 --- /dev/null +++ b/thread_list.txt @@ -0,0 +1,2 @@ +- DiscordRPC - Thread for refreshing discord rich presence +- LogService - Service that logs data to files and console \ No newline at end of file diff --git a/translation.cpp b/translation.cpp index 74a4e35a..65638988 100644 --- a/translation.cpp +++ b/translation.cpp @@ -283,6 +283,8 @@ std::string locale::label_cab_control(std::string const &Label) { "pantselectedoff_sw:", STRN("selected pantograph") }, { "pantselect_sw:", STRN("selected pantograph") }, { "pantvalves_sw:", STRN("selected pantograph") }, + { "pantvalvesoff_bt:", STRN("all pantographs down") }, + { "pantvalvesupdate_bt:", STRN("selected pantographs up") }, { "pantcompressor_sw:", STRN("pantograph compressor") }, { "pantcompressorvalve_sw:", STRN("pantograph 3 way valve") }, { "trainheating_sw:", STRN("heating") },