From 39b8fbfb86e8092223f13def6aa4d78bdfc91d7b Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 4 Mar 2017 13:24:34 +0100 Subject: [PATCH] copydata communication fix, update loop tweaks --- EU07.cpp | 3 +- Ground.cpp | 24 ++++----- McZapkie/mctools.cpp | 4 +- Model3d.cpp | 3 +- World.cpp | 115 ++++++++++++++++++++++++++++--------------- World.h | 4 ++ maszyna.sln | 6 +-- maszyna.vcxproj | 2 +- 8 files changed, 97 insertions(+), 64 deletions(-) diff --git a/EU07.cpp b/EU07.cpp index 6e673d1a..11949bcf 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -27,6 +27,7 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others #include "PyInt.h" #include "World.h" #include "Mover.h" +#include "usefull.h" #pragma comment( lib, "glfw3dll.lib" ) #pragma comment( lib, "glew32.lib" ) @@ -143,7 +144,7 @@ LRESULT APIENTRY WndProc( HWND hWnd, // handle for this window case WM_COPYDATA: { // obsługa danych przesłanych przez program sterujący pDane = (PCOPYDATASTRUCT)lParam; - if( pDane->dwData == 'EU07' ) // sygnatura danych + if( pDane->dwData == MAKE_ID4( 'E', 'U', '0', '7' ) ) // sygnatura danych World.OnCommandGet( (DaneRozkaz *)( pDane->lpData ) ); break; } diff --git a/Ground.cpp b/Ground.cpp index 3fc43f6e..5d88e9d6 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -5052,7 +5052,7 @@ void TGround::Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LP void TGround::WyslijEvent(const std::string &e, const std::string &d) { // Ra: jeszcze do wyczyszczenia DaneRozkaz r; - r.iSygn = 'EU07'; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = 2; // 2 - event int i = e.length(), j = d.length(); r.cString[0] = char(i); @@ -5060,7 +5060,7 @@ void TGround::WyslijEvent(const std::string &e, const std::string &d) r.cString[i + 2] = char(j); // licznik po zerze kończącym strcpy(r.cString + 3 + i, d.c_str()); // zakończony zerem COPYDATASTRUCT cData; - cData.dwData = 'EU07'; // sygnatura + cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura cData.cbData = 12 + i + j; // 8+dwa liczniki i dwa zera kończące cData.lpData = &r; Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); @@ -5070,14 +5070,14 @@ void TGround::WyslijEvent(const std::string &e, const std::string &d) void TGround::WyslijUszkodzenia(const std::string &t, char fl) { // wysłanie informacji w postaci pojedynczego tekstu DaneRozkaz r; - r.iSygn = 'EU07'; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = 13; // numer komunikatu int i = t.length(); r.cString[0] = char(fl); r.cString[1] = char(i); strcpy(r.cString + 2, t.c_str()); // z zerem kończącym COPYDATASTRUCT cData; - cData.dwData = 'EU07'; // sygnatura + cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura cData.cbData = 11 + i; // 8+licznik i zero kończące cData.lpData = &r; Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); @@ -5087,13 +5087,13 @@ void TGround::WyslijUszkodzenia(const std::string &t, char fl) void TGround::WyslijString(const std::string &t, int n) { // wysłanie informacji w postaci pojedynczego tekstu DaneRozkaz r; - r.iSygn = 'EU07'; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = n; // numer komunikatu int i = t.length(); r.cString[0] = char(i); strcpy(r.cString + 1, t.c_str()); // z zerem kończącym COPYDATASTRUCT cData; - cData.dwData = 'EU07'; // sygnatura + cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura cData.cbData = 10 + i; // 8+licznik i zero kończące cData.lpData = &r; Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); @@ -5109,7 +5109,7 @@ void TGround::WyslijNamiary(TGroundNode *t) { // wysłanie informacji o pojeździe - (float), długość ramki będzie zwiększana w miarę potrzeby // WriteLog("Wysylam pojazd"); DaneRozkaz r; - r.iSygn = 'EU07'; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = 7; // 7 - dane pojazdu int i = 32, j = t->asName.length(); r.iPar[0] = i; // ilość danych liczbowych @@ -5171,7 +5171,7 @@ void TGround::WyslijNamiary(TGroundNode *t) r.cString[i] = char(j); // na końcu nazwa, żeby jakoś zidentyfikować strcpy(r.cString + i + 1, t->asName.c_str()); // zakończony zerem COPYDATASTRUCT cData; - cData.dwData = 'EU07'; // sygnatura + cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura cData.cbData = 10 + i + j; // 8+licznik i zero kończące cData.lpData = &r; // WriteLog("Ramka gotowa"); @@ -5183,7 +5183,7 @@ void TGround::WyslijNamiary(TGroundNode *t) void TGround::WyslijObsadzone() { // wysłanie informacji o pojeździe DaneRozkaz2 r; - r.iSygn = 'EU07'; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = 12; // kod 12 for (int i=0; i<1984; ++i) r.cString[i] = 0; @@ -5214,7 +5214,7 @@ void TGround::WyslijObsadzone() } COPYDATASTRUCT cData; - cData.dwData = 'EU07'; // sygnatura + cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura cData.cbData = 8 + 1984; // 8+licznik i zero kończące cData.lpData = &r; // WriteLog("Ramka gotowa"); @@ -5226,7 +5226,7 @@ void TGround::WyslijObsadzone() void TGround::WyslijParam(int nr, int fl) { // wysłanie parametrów symulacji w ramce (nr) z flagami (fl) DaneRozkaz r; - r.iSygn = 'EU07'; + r.iSygn = MAKE_ID4( 'E', 'U', '0', '7' ); r.iComm = nr; // zwykle 5 r.iPar[0] = fl; // flagi istotności kolejnych parametrów int i = 0; // domyślnie brak danych @@ -5239,7 +5239,7 @@ void TGround::WyslijParam(int nr, int fl) break; } COPYDATASTRUCT cData; - cData.dwData = 'EU07'; // sygnatura + cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura cData.cbData = 12 + i; // 12+rozmiar danych cData.lpData = &r; Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); diff --git a/McZapkie/mctools.cpp b/McZapkie/mctools.cpp index 2c751394..f91f7b9d 100644 --- a/McZapkie/mctools.cpp +++ b/McZapkie/mctools.cpp @@ -75,10 +75,8 @@ std::string Now() { std::time_t timenow = std::time( nullptr ); std::tm tm = *std::localtime( &timenow ); std::stringstream converter; - std::string output; converter << std::put_time( &tm, "%c" ); - converter >> output; - return output; + return converter.str(); /* char buffer[ 256 ]; sprintf( buffer, diff --git a/Model3d.cpp b/Model3d.cpp index 994862b5..ef1b0704 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -1812,8 +1812,7 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic) // wczytanie modelu z pliku std::string name = ToLower(FileName); // trim extension if needed - if( ( name.rfind( '.' ) != std::string::npos ) - && ( name.substr( name.rfind( '.' ) ) == ".t3d" ) ) + if( name.rfind( '.' ) != std::string::npos ) { name.erase(name.rfind('.')); } diff --git a/World.cpp b/World.cpp index bd325e09..6d2bc9c4 100644 --- a/World.cpp +++ b/World.cpp @@ -1081,13 +1081,15 @@ bool TWorld::Update() Update_Environment(); } // koniec działań niewykonywanych podczas pauzy // poprzednie jakoś tam działało - double dt = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu - fTime50Hz += - dt; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek - if (fTime50Hz >= 0.2) - Console::Update(); // to i tak trzeba wywoływać - dt = Timer::GetDeltaTime(); // 0.0 gdy pauza + + // fixed step, simulation time based updates + double dt = Timer::GetDeltaTime(); // 0.0 gdy pauza +/* fTimeBuffer += dt; //[s] dodanie czasu od poprzedniej ramki +*/ + m_primaryupdateaccumulator += dt; + m_secondaryupdateaccumulator += dt; +/* if (fTimeBuffer >= fMaxDt) // jest co najmniej jeden krok; normalnie 0.01s { // Ra: czas dla fizyki jest skwantowany - fizykę lepiej przeliczać stałym krokiem // tak można np. moc silników itp., ale ruch musi być przeliczany w każdej klatce, bo @@ -1101,28 +1103,31 @@ bool TWorld::Update() if (n > 20) n = 20; // Ra: jeżeli FPS jest zatrważająco niski, to fizyka nie może zająć całkowicie procesora } - // awaria PoKeys mogła włączyć pauzę - przekazać informację - if (Global::iMultiplayer) // dajemy znać do serwera o wykonaniu - if (iPause != Global::iPause) - { // przesłanie informacji o pauzie do programu nadzorującego - Ground.WyslijParam(5, 3); // ramka 5 z czasem i stanem zapauzowania - iPause = Global::iPause; - } - double iter; - int n = 1; - if (dt > fMaxDt) // normalnie 0.01s - { - iter = ceil(dt / fMaxDt); - n = iter; - dt = dt / iter; // Ra: fizykę lepiej by było przeliczać ze stałym krokiem - if (n > 20) - n = 20; // McZapkie-081103: przesuniecie granicy FPS z 10 na 5 +*/ +/* + // NOTE: until we have no physics state interpolation during render, we need to rely on the old code + // doing fixed step calculations but flexible step render results in ugly mini jitter + // core routines (physics) + int updatecount = 0; + while( ( m_primaryupdateaccumulator >= m_primaryupdaterate ) + &&( updatecount < 20 ) ) { + // no more than 20 updates per single pass, to keep physics from hogging up all run time + Ground.Update( m_primaryupdaterate, 1 ); + ++updatecount; + m_primaryupdateaccumulator -= m_primaryupdaterate; } - // else n=1; - // blablabla - // Ground.UpdatePhys(dt,n); //na razie tu //2014-12: yB przeniósł do Ground.Update() :( - Ground.Update(dt, n); // tu zrobić tylko coklatkową aktualizację przesunięć - +*/ + int updatecount = 1; + if( dt > m_primaryupdaterate ) // normalnie 0.01s + { + auto const iterations = std::ceil(dt / m_primaryupdaterate); + updatecount = std::min( 20, static_cast( iterations ) ); + dt = dt / iterations; // Ra: fizykę lepiej by było przeliczać ze stałym krokiem + } + // NOTE: updates are limited to 20, but dt is distributed over potentially many more iterations + // this means at count > 20 simulation and render are going to desync. is that right? + Ground.Update(dt, updatecount); // tu zrobić tylko coklatkową aktualizację przesunięć +/* if (DebugModeFlag) if (Global::bActive) // nie przyspieszać, gdy jedzie w tle :) if( Console::Pressed( GLFW_KEY_ESCAPE ) ) { @@ -1132,15 +1137,25 @@ bool TWorld::Update() Ground.Update(dt, n); Ground.Update(dt, n); // 5 razy } +*/ + // secondary fixed step simulation time routines + while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) { - dt = Timer::GetDeltaTime(); // czas niekwantowany + Global::tranTexts.Update(); // obiekt obsługujący stenogramy dźwięków na ekranie - Update_Camera( dt ); + // awaria PoKeys mogła włączyć pauzę - przekazać informację + if( Global::iMultiplayer ) // dajemy znać do serwera o wykonaniu + if( iPause != Global::iPause ) { // przesłanie informacji o pauzie do programu nadzorującego + Ground.WyslijParam( 5, 3 ); // ramka 5 z czasem i stanem zapauzowania + iPause = Global::iPause; + } - Ground.CheckQuery(); + // TODO: add fixed step part of the camera update here - Ground.Update_Lights(); + m_secondaryupdateaccumulator -= m_secondaryupdaterate; // these should be inexpensive enough we have no cap + } + // variable step simulation time routines if( Train != nullptr ) { TSubModel::iInstance = reinterpret_cast( Train->Dynamic() ); Train->Update( dt ); @@ -1149,6 +1164,23 @@ bool TWorld::Update() TSubModel::iInstance = 0; } + Ground.CheckQuery(); + + Ground.Update_Lights(); + + // render time routines follow: + dt = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu + + // fixed step render time routines + fTime50Hz += dt; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek + if( fTime50Hz >= 0.2 ) { + Console::Update(); // to i tak trzeba wywoływać + fTime50Hz -= 0.2; + } + + // variable step render time routines + Update_Camera( dt ); // TODO: move the fixed step cab camera updates to fixed step secondary routines section + // przy 0.25 smuga gaśnie o 6:37 w Quarku, a mogłaby już 5:40 // Ra 2014-12: przy 0.15 się skarżyli, że nie widać smug => zmieniłem na 0.25 // changed light activation threshold to 0.5, paired with strength reduction in daylight @@ -1164,6 +1196,7 @@ bool TWorld::Update() m_init = true; + // visualize state changes if (!Render()) return false; @@ -2578,7 +2611,7 @@ TWorld::Render_UI() { //--------------------------------------------------------------------------- void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) { // odebranie komunikatu z serwera - if (pRozkaz->iSygn == 'EU07') + if (pRozkaz->iSygn == MAKE_ID4('E','U','0','7') ) switch (pRozkaz->iComm) { case 0: // odesłanie identyfikatora wersji @@ -2609,7 +2642,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) int i = int(pRozkaz->cString[8]); // długość pierwszego łańcucha (z przodu dwa floaty) CommLog( - to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " " + + Now() + " " + to_string(pRozkaz->iComm) + " " + std::string(pRozkaz->cString + 11 + i, (unsigned)(pRozkaz->cString[10 + i])) + " rcvd"); TGroundNode *t = Ground.DynamicFind( @@ -2627,7 +2660,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) break; case 4: // badanie zajętości toru { - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " " + + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd"); TGroundNode *t = Ground.FindGroundNode( std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])), TP_TRACK); @@ -2638,7 +2671,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) break; case 5: // ustawienie parametrów { - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " params " + + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " params " + to_string(*pRozkaz->iPar) + " rcvd"); if (*pRozkaz->iPar == 0) // sprawdzenie czasu if (*pRozkaz->iPar & 1) // ustawienie czasu @@ -2663,7 +2696,7 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) case 6: // pobranie parametrów ruchu pojazdu if (Global::iMultiplayer) { // Ra 2014-12: to ma działać również dla pojazdów bez obsady - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " " + + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd"); if (pRozkaz->cString[0]) // jeśli długość nazwy jest niezerowa @@ -2686,15 +2719,15 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) } break; case 8: // ponowne wysłanie informacji o zajętych odcinkach toru - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " all busy track" + " rcvd"); + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " all busy track" + " rcvd"); Ground.TrackBusyList(); break; case 9: // ponowne wysłanie informacji o zajętych odcinkach izolowanych - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " all busy isolated" + " rcvd"); + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " all busy isolated" + " rcvd"); Ground.IsolatedBusyList(); break; case 10: // badanie zajętości jednego odcinka izolowanego - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " " + + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd"); Ground.IsolatedBusy(std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0]))); break; @@ -2702,14 +2735,14 @@ void TWorld::OnCommandGet(DaneRozkaz *pRozkaz) // Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0]))); break; case 12: // skrocona ramka parametrow pojazdow AI (wszystkich!!) - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " obsadzone" + " rcvd"); + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " obsadzone" + " rcvd"); Ground.WyslijObsadzone(); // Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0]))); break; case 13: // ramka uszkodzenia i innych stanow pojazdu, np. wylaczenie CA, wlaczenie recznego itd. // WriteLog("Przyszlo 13!"); // WriteLog(pRozkaz->cString); - CommLog(to_string(BorlandTime()) + " " + to_string(pRozkaz->iComm) + " " + + CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " + std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd"); if (pRozkaz->cString[1]) // jeśli długość nazwy jest niezerowa diff --git a/World.h b/World.h index bdc394b9..5def8d8a 100644 --- a/World.h +++ b/World.h @@ -79,6 +79,10 @@ class TWorld double fTime50Hz; // bufor czasu dla komunikacji z PoKeys double fTimeBuffer; // bufor czasu aktualizacji dla stałego kroku fizyki double fMaxDt; //[s] krok czasowy fizyki (0.01 dla normalnych warunków) + double m_primaryupdaterate{ 1.0 / 100.0 }; + double m_primaryupdateaccumulator{ 0.0 }; // keeps track of elapsed simulation time, for core fixed step routines + double m_secondaryupdaterate{ 1.0 / 50.0 }; + double m_secondaryupdateaccumulator{ 0.0 }; // keeps track of elapsed simulation time, for less important fixed step routines int iPause; // wykrywanie zmian w zapauzowaniu double VelPrev; // poprzednia prędkość int tprev; // poprzedni czas diff --git a/maszyna.sln b/maszyna.sln index 113432a9..4e726218 100644 --- a/maszyna.sln +++ b/maszyna.sln @@ -1,4 +1,5 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 @@ -18,7 +19,4 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection EndGlobal diff --git a/maszyna.vcxproj b/maszyna.vcxproj index 5b62a56d..dae5517e 100644 --- a/maszyna.vcxproj +++ b/maszyna.vcxproj @@ -67,7 +67,7 @@ WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreaded + MultiThreadedDLL Level3 ProgramDatabase $(SolutionDir);$(SolutionDir)console;$(SolutionDir)mczapkie;$(SolutionDir)ref/glfw/include;$(SolutionDir)ref/glew/include;$(SolutionDir)ref/python/include;%(AdditionalIncludeDirectories)