diff --git a/Event.cpp b/Event.cpp index bcca997f..ee34478a 100644 --- a/Event.cpp +++ b/Event.cpp @@ -610,16 +610,32 @@ void TEvent::Load(cParser *parser, vector3 *org) } }; -void TEvent::AddToQuery(TEvent *e) -{ // dodanie eventu do kolejki - if( ( evNext != nullptr ) - && ( e->fStartTime > evNext->fStartTime ) ) { - evNext->AddToQuery( e ); // sortowanie wg czasu +void TEvent::AddToQuery( TEvent *Event, TEvent *&Start ) { + + TEvent *target( Start ); + TEvent *previous( nullptr ); + while( ( Event->fStartTime >= target->fStartTime ) + && ( target->evNext != nullptr ) ) { + previous = target; + target = target->evNext; } - else - { // dodanie z przodu - e->evNext = evNext; - evNext = e; + // the new event will be either before or after the one we located + if( Event->fStartTime >= target->fStartTime ) { + assert( target->evNext == nullptr ); + target->evNext = Event; + // if we have resurrected event land at the end of list, the link from previous run could potentially "add" unwanted events to the queue + Event->evNext = nullptr; + } + else { + if( previous != nullptr ) { + previous->evNext = Event; + Event->evNext = target; + } + else { + // special case, we're inserting our event before the provided start point + Event->evNext = Start; + Start = Event; + } } } diff --git a/Event.h b/Event.h index 110e3abc..7d020046 100644 --- a/Event.h +++ b/Event.h @@ -105,7 +105,7 @@ class TEvent // zmienne: ev* ~TEvent(); void Init(); void Load(cParser *parser, vector3 *org); - void AddToQuery(TEvent *e); + static void AddToQuery( TEvent *Event, TEvent *&Start ); std::string CommandGet(); TCommandType Command(); double ValueGet(int n); diff --git a/Ground.cpp b/Ground.cpp index 91ee13e3..54662956 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -3065,17 +3065,6 @@ TTrack * TGround::FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclud if ((tmp = sr->FindTrack(&Point, iConnection, Exclude->pTrack)) != NULL) return tmp; } -#if 0 - //wyszukiwanie czołgowe (po wszystkich jak leci) - nie ma chyba sensu - for (Current=nRootOfType[TP_TRACK];Current;Current=Current->Next) - { - if ((Current->iType==TP_TRACK) && (Current!=Exclude)) - { - iConnection=Current->pTrack->TestPoint(&Point); - if (iConnection>=0) return Current->pTrack; - } - } -#endif return NULL; } @@ -3174,22 +3163,21 @@ TTraction * TGround::TractionNearestFind(vector3 &p, int dir, TGroundNode *n) bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node) { - if (Event->bEnabled) // jeśli może być dodany do kolejki (nie używany w skanowaniu) - if (!Event->iQueued) // jeśli nie dodany jeszcze do kolejki + if( Event->bEnabled ) { + // jeśli może być dodany do kolejki (nie używany w skanowaniu) + if( !Event->iQueued ) // jeśli nie dodany jeszcze do kolejki { // kolejka eventów jest posortowana względem (fStartTime) Event->Activator = Node; if( ( Event->Type == tp_AddValues ) - && ( Event->fDelay == 0.0 ) ) { - // eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić jakieś dodawanie - // Ra: kopiowanie wykonania tu jest bez sensu, lepiej by było wydzielić funkcję - // wykonującą eventy i ją wywołać - if (EventConditon(Event)) - { // teraz mogą być warunki do tych eventów - Event->Params[5].asMemCell->UpdateValues( - Event->Params[0].asText, Event->Params[1].asdouble, - Event->Params[2].asdouble, Event->iFlags); - if (Event->Params[6].asTrack) - { // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla + && ( Event->fDelay == 0.0 ) ) { + // eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić jakieś dodawanie + // Ra: kopiowanie wykonania tu jest bez sensu, lepiej by było wydzielić funkcję + // wykonującą eventy i ją wywołać + if( EventConditon( Event ) ) { // teraz mogą być warunki do tych eventów + Event->Params[ 5 ].asMemCell->UpdateValues( + Event->Params[ 0 ].asText, Event->Params[ 1 ].asdouble, + Event->Params[ 2 ].asdouble, Event->iFlags ); + if( Event->Params[ 6 ].asTrack ) { // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla // wszystkich 'dynamic' na danym torze for( auto dynamic : Event->Params[ 6 ].asTrack->Dynamics ) { Event->Params[ 5 ].asMemCell->PutCommand( @@ -3197,41 +3185,47 @@ bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node) &Event->Params[ 4 ].nGroundNode->pCenter ); } //if (DebugModeFlag) - WriteLog("EVENT EXECUTED: AddValues & Track command - " + - std::string(Event->Params[0].asText) + " " + - std::to_string(Event->Params[1].asdouble) + " " + - std::to_string(Event->Params[2].asdouble)); + WriteLog( + "EVENT EXECUTED" + ( Node ? ( " by " + Node->asName ) : "" ) + ": AddValues & Track command ( " + + std::string( Event->Params[ 0 ].asText ) + " " + + std::to_string( Event->Params[ 1 ].asdouble ) + " " + + std::to_string( Event->Params[ 2 ].asdouble ) + " )" ); } //else if (DebugModeFlag) - WriteLog("EVENT EXECUTED: AddValues - " + - std::string(Event->Params[0].asText) + " " + - std::to_string(Event->Params[1].asdouble) + " " + - std::to_string(Event->Params[2].asdouble)); + WriteLog( + "EVENT EXECUTED" + ( Node ? ( " by " + Node->asName ) : "" ) + ": AddValues ( " + + std::string( Event->Params[ 0 ].asText ) + " " + + std::to_string( Event->Params[ 1 ].asdouble ) + " " + + std::to_string( Event->Params[ 2 ].asdouble ) + " )" ); } // jeśli jest kolejny o takiej samej nazwie, to idzie do kolejki (and if there's no joint event it'll be set to null and processing will end here) - Event = Event->evJoined; + do { + Event = Event->evJoined; + // NOTE: we could've received a new event from joint event above, so we need to check conditions just in case and discard the bad events + // TODO: refactor this arrangement, it's hardly optimal + } while( ( Event != nullptr ) + && ( ( false == Event->bEnabled ) + || ( Event->iQueued > 0 ) ) ); } - if( Event != nullptr ) - { // standardowe dodanie do kolejki - WriteLog("EVENT ADDED TO QUEUE: " + Event->asName + (Node ? (" by " + Node->asName) : "")); - Event->fStartTime = - fabs(Event->fDelay) + Timer::GetTime(); // czas od uruchomienia scenerii - if (Event->fRandomDelay > 0.0) - Event->fStartTime += Event->fRandomDelay * Random(10000) * - 0.0001; // doliczenie losowego czasu opóźnienia + if( Event != nullptr ) { + // standardowe dodanie do kolejki ++Event->iQueued; // zabezpieczenie przed podwójnym dodaniem do kolejki - if( ( QueryRootEvent != nullptr ) - && ( Event->fStartTime > QueryRootEvent->fStartTime ) ) { - // dodanie gdzieś w środku - QueryRootEvent->AddToQuery( Event ); + WriteLog( "EVENT ADDED TO QUEUE" + ( Node ? ( " by " + Node->asName ) : "" ) + ": " + Event->asName ); + Event->fStartTime = std::abs( Event->fDelay ) + Timer::GetTime(); // czas od uruchomienia scenerii + if( Event->fRandomDelay > 0.0 ) { + // doliczenie losowego czasu opóźnienia + Event->fStartTime += Event->fRandomDelay * Random( 10000 ) * 0.0001; + } + if( QueryRootEvent != nullptr ) { + TEvent::AddToQuery( Event, QueryRootEvent ); } else { - // dodanie z przodu: albo nic nie ma, albo ma być wykonany szybciej niż pierwszy - Event->evNext = QueryRootEvent; QueryRootEvent = Event; + QueryRootEvent->evNext = nullptr; } } } + } return true; } @@ -3308,49 +3302,8 @@ bool TGround::CheckQuery() { // sprawdzenie kolejki eventów oraz wykonanie tych, którym czas minął TLocation loc; int i; - /* //Ra: to w ogóle jakiś chory kod jest; wygląda jak wyszukanie eventu z najlepszym czasem - Double evtime,evlowesttime; //Ra: co to za typ? - //evlowesttime=1000000; - if (QueryRootEvent) - { - OldQRE=QueryRootEvent; - tmpEvent=QueryRootEvent; - } - if (QueryRootEvent) - { - for (i=0;i<90;++i) - { - evtime=((tmpEvent->fStartTime)-(Timer::GetTime())); //pobranie wartości zmiennej - if (evtimeNext) - tmpEvent=tmpEvent->Next; - else - i=100; - } - if (OldQRE!=tmp2Event) - { - QueryRootEvent->AddToQuery(QueryRootEvent); - QueryRootEvent=tmp2Event; - } - } - */ - /* - if (QueryRootEvent) - {//wypisanie kolejki - tmpEvent=QueryRootEvent; - WriteLog("--> Event queue:"); - while (tmpEvent) - { - WriteLog(tmpEvent->asName+" "+AnsiString(tmpEvent->fStartTime)); - tmpEvent=tmpEvent->Next; - } - } - */ - while (QueryRootEvent ? QueryRootEvent->fStartTime < Timer::GetTime() : false) + while( ( QueryRootEvent != nullptr ) + && ( QueryRootEvent->fStartTime < Timer::GetTime() ) ) { // eventy są posortowana wg czasu wykonania tmpEvent = QueryRootEvent; // wyjęcie eventu z kolejki if (QueryRootEvent->evJoined) // jeśli jest kolejny o takiej samej nazwie @@ -3359,16 +3312,15 @@ bool TGround::CheckQuery() QueryRootEvent->evNext = tmpEvent->evNext; // pamiętając o następnym z kolejki QueryRootEvent->fStartTime = tmpEvent->fStartTime; // czas musi być ten sam, bo nie jest aktualizowany QueryRootEvent->Activator = tmpEvent->Activator; // pojazd aktywujący + QueryRootEvent->iQueued = 1; // w sumie można by go dodać normalnie do kolejki, ale trzeba te połączone posortować wg czasu wykonania } else // a jak nazwa jest unikalna, to kolejka idzie dalej QueryRootEvent = QueryRootEvent->evNext; // NULL w skrajnym przypadku if (tmpEvent->bEnabled) { // w zasadzie te wyłączone są skanowane i nie powinny się nigdy w kolejce znaleźć - WriteLog("EVENT LAUNCHED: " + tmpEvent->asName + - (tmpEvent->Activator ? - std::string(" by " + tmpEvent->Activator->asName) : - "" )); + --tmpEvent->iQueued; // teraz moze być ponownie dodany do kolejki + WriteLog( "EVENT LAUNCHED" + ( tmpEvent->Activator ? ( " by " + tmpEvent->Activator->asName ) : "" ) + ": " + tmpEvent->asName ); switch (tmpEvent->Type) { case tp_CopyValues: // skopiowanie wartości z innej komórki @@ -3530,29 +3482,20 @@ bool TGround::CheckQuery() conditional_anyelse)) // warunek spelniony albo było użyte else { WriteLog("Multiple passed"); - for (i = 0; i < 8; ++i) - { // dodawane do kolejki w kolejności zapisania - if (tmpEvent->Params[i].asEvent) - if (bCondition != (((tmpEvent->iFlags & (conditional_else << i)) != 0))) - { - if (tmpEvent->Params[i].asEvent != tmpEvent) - AddToQuery(tmpEvent->Params[i].asEvent, - tmpEvent->Activator); // normalnie dodać - else // jeśli ma być rekurencja - if (tmpEvent->fDelay >= - 5.0) // to musi mieć sensowny okres powtarzania - if (tmpEvent->iQueued < 2) - { // trzeba zrobić wyjątek, aby event mógł się sam dodać do - // kolejki, raz już jest, ale będzie usunięty - // pętla eventowa może być uruchomiona wiele razy, ale tylko - // pierwsze uruchomienie zadziała - tmpEvent->iQueued = - 0; // tymczasowo, aby był ponownie dodany do kolejki - AddToQuery(tmpEvent, tmpEvent->Activator); - tmpEvent->iQueued = - 2; // kolejny raz już absolutnie nie dodawać + for (i = 0; i < 8; ++i) { + // dodawane do kolejki w kolejności zapisania + if( tmpEvent->Params[ i ].asEvent ) { + if( bCondition != ( ( ( tmpEvent->iFlags & ( conditional_else << i ) ) != 0 ) ) ) { + if( tmpEvent->Params[ i ].asEvent != tmpEvent ) + AddToQuery( tmpEvent->Params[ i ].asEvent, tmpEvent->Activator ); // normalnie dodać + else { + // jeśli ma być rekurencja to musi mieć sensowny okres powtarzania + if( tmpEvent->fDelay >= 5.0 ) { + AddToQuery( tmpEvent, tmpEvent->Activator ); } + } } + } } if (Global::iMultiplayer) // dajemy znać do serwera o wykonaniu if ((tmpEvent->iFlags & conditional_anyelse) == @@ -3635,22 +3578,6 @@ bool TGround::CheckQuery() break; } // switch (tmpEvent->Type) } // if (tmpEvent->bEnabled) - --tmpEvent->iQueued; // teraz moze być ponownie dodany do kolejki - /* - if (QueryRootEvent->eJoined) //jeśli jest kolejny o takiej samej nazwie - {//to teraz jego dajemy do wykonania - QueryRootEvent->eJoined->Next=QueryRootEvent->Next; //pamiętając o następnym z kolejki - QueryRootEvent->eJoined->fStartTime=QueryRootEvent->fStartTime; //czas musi być ten sam, - bo nie jest aktualizowany - //QueryRootEvent->fStartTime=0; - QueryRootEvent=QueryRootEvent->eJoined; //a wykonać ten doczepiony - } - else - {//a jak nazwa jest unikalna, to kolejka idzie dalej - //QueryRootEvent->fStartTime=0; - QueryRootEvent=QueryRootEvent->Next; //NULL w skrajnym przypadku - } - */ } // while return true; } diff --git a/Ground.h b/Ground.h index dd408880..d8d62ac5 100644 --- a/Ground.h +++ b/Ground.h @@ -274,9 +274,7 @@ class TGround TGroundRect Rects[iNumRects][iNumRects]; // mapa kwadratów kilometrowych TEvent *RootEvent = nullptr; // lista zdarzeń TEvent *QueryRootEvent = nullptr, - *tmpEvent = nullptr, - *tmp2Event = nullptr, - *OldQRE = nullptr; + *tmpEvent = nullptr; TSubRect *pRendered[1500]; // lista renderowanych sektorów int iNumNodes = 0; vector3 pOrigin; diff --git a/Train.cpp b/Train.cpp index 75bd2f53..61bc9138 100644 --- a/Train.cpp +++ b/Train.cpp @@ -2881,10 +2881,12 @@ void TTrain::OnCommand_hornlowactivate( TTrain *Train, command_data const &Comma if( false == TestFlag( Train->mvOccupied->WarningSignal, 1 ) ) { // turn on Train->mvOccupied->WarningSignal |= 1; +/* if( true == TestFlag( Train->mvOccupied->WarningSignal, 2 ) ) { // low and high horn are treated as mutually exclusive Train->mvControlled->WarningSignal &= ~2; } +*/ // audio feedback if( ( Train->ggHornButton.GetValue() > -0.5 ) || ( Train->ggHornLowButton.GetValue() < 0.5 ) ) { @@ -2897,8 +2899,11 @@ void TTrain::OnCommand_hornlowactivate( TTrain *Train, command_data const &Comma } else if( Command.action == GLFW_RELEASE ) { // turn off +/* // NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved Train->mvOccupied->WarningSignal &= ~( 1 | 2 ); +*/ + Train->mvOccupied->WarningSignal &= ~1; // audio feedback if( ( Train->ggHornButton.GetValue() < -0.5 ) || ( Train->ggHornLowButton.GetValue() > 0.5 ) ) { @@ -2925,10 +2930,12 @@ void TTrain::OnCommand_hornhighactivate( TTrain *Train, command_data const &Comm if( false == TestFlag( Train->mvOccupied->WarningSignal, 2 ) ) { // turn on Train->mvOccupied->WarningSignal |= 2; +/* if( true == TestFlag( Train->mvOccupied->WarningSignal, 1 ) ) { // low and high horn are treated as mutually exclusive Train->mvControlled->WarningSignal &= ~1; } +*/ // audio feedback if( Train->ggHornButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); @@ -2940,8 +2947,11 @@ void TTrain::OnCommand_hornhighactivate( TTrain *Train, command_data const &Comm } else if( Command.action == GLFW_RELEASE ) { // turn off +/* // NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved Train->mvOccupied->WarningSignal &= ~( 1 | 2 ); +*/ + Train->mvOccupied->WarningSignal &= ~2; // audio feedback if( Train->ggHornButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); diff --git a/version.h b/version.h index cbf2eb2e..005e6949 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 531 +#define VERSION_MINOR 602 #define VERSION_REVISION 0