16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-20 07:59:18 +02:00

merge (with bugs)

This commit is contained in:
VB
2017-04-24 19:08:08 +02:00
53 changed files with 2340 additions and 2233 deletions

299
Track.cpp
View File

@@ -77,8 +77,8 @@ TIsolated::TIsolated()
TIsolated("none", NULL);
};
TIsolated::TIsolated(const string &n, TIsolated *i) :
asName( n ), pNext( i )
TIsolated::TIsolated(std::string const &n, TIsolated *i) :
asName( n ), pNext( i )
{
// utworznie obwodu izolowanego. nothing to do here.
};
@@ -96,7 +96,7 @@ TIsolated::~TIsolated(){
*/
};
TIsolated * TIsolated::Find(const string &n)
TIsolated * TIsolated::Find(std::string const &n)
{ // znalezienie obiektu albo utworzenie nowego
TIsolated *p = pRoot;
while (p)
@@ -121,13 +121,8 @@ void TIsolated::Modify(int i, TDynamicObject *o)
if (Global::iMultiplayer) // jeśli multiplayer
Global::pGround->WyslijString(asName, 10); // wysłanie pakietu o zwolnieniu
if (pMemCell) // w powiązanej komórce
#ifdef EU07_USE_OLD_TMEMCELL_TEXT_ARRAY
pMemCell->UpdateValues( NULL, 0, int( pMemCell->Value2() ) & ~0xFF,
update_memval2); //"zerujemy" ostatnią wartość
#else
pMemCell->UpdateValues( "", 0, int( pMemCell->Value2() ) & ~0xFF,
update_memval2 ); //"zerujemy" ostatnią wartość
#endif
}
}
else
@@ -140,12 +135,7 @@ void TIsolated::Modify(int i, TDynamicObject *o)
if (Global::iMultiplayer) // jeśli multiplayer
Global::pGround->WyslijString(asName, 11); // wysłanie pakietu o zajęciu
if (pMemCell) // w powiązanej komórce
#ifdef EU07_USE_OLD_TMEMCELL_TEXT_ARRAY
pMemCell->UpdateValues( NULL, 0, int( pMemCell->Value2() ) | 1,
update_memval2); // zmieniamy ostatnią wartość na nieparzystą
#else
pMemCell->UpdateValues( "", 0, int( pMemCell->Value2() ) | 1, update_memval2 ); // zmieniamy ostatnią wartość na nieparzystą
#endif
}
}
};
@@ -154,9 +144,6 @@ void TIsolated::Modify(int i, TDynamicObject *o)
TTrack::TTrack(TGroundNode *g) :
pMyNode( g ) // Ra: proteza, żeby tor znał swoją nazwę TODO: odziedziczyć TTrack z TGroundNode
{
#ifdef EU07_USE_OLD_TTRACK_DYNAMICS_ARRAY
::SecureZeroMemory( Dynamics, sizeof( Dynamics ) );
#endif
fRadiusTable[ 0 ] = 0.0;
fRadiusTable[ 1 ] = 0.0;
nFouling[ 0 ] = nullptr;
@@ -199,7 +186,7 @@ void TTrack::Init()
break;
case tt_Table: // oba potrzebne
SwitchExtension = std::make_shared<TSwitchExtension>( this, 1 ); // kopia oryginalnego toru
Segment = make_shared<TSegment>(this);
Segment = std::make_shared<TSegment>(this);
break;
}
}
@@ -413,7 +400,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
{ // pobranie obiektu trajektorii ruchu
vector3 pt, vec, p1, p2, cp1, cp2, p3, p4, cp3, cp4; // dodatkowe punkty potrzebne do skrzyżowań
double a1, a2, r1, r2, r3, r4;
string str;
std::string str;
size_t i; //,state; //Ra: teraz już nie ma początkowego stanu zwrotnicy we wpisie
std::string token;
@@ -554,8 +541,10 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
p2.y += 0.18;
// na przechyłce doliczyć jeszcze pół przechyłki
}
if (fRadius != 0) // gdy podany promień
segsize = Min0R(5.0, 0.2 + fabs(fRadius) * 0.02); // do 250m - 5, potem 1 co 50m
if( fRadius != 0 ) // gdy podany promień
segsize = Min0R( 5.0, 0.2 + fabs( fRadius ) * 0.02 ); // do 250m - 5, potem 1 co 50m
else
segsize = 10.0; // for straights, 10m per segment works good enough
if ((((p1 + p1 + p2) / 3.0 - p1 - cp1).Length() < 0.02) ||
(((p1 + p2 + p2) / 3.0 - p2 + cp1).Length() < 0.02))
@@ -563,11 +552,9 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
if ((cp1 == vector3(0, 0, 0)) &&
(cp2 == vector3(0, 0, 0))) // Ra: hm, czasem dla prostego są podane...
Segment->Init(p1, p2, segsize, r1,
r2); // gdy prosty, kontrolne wyliczane przy zmiennej przechyłce
Segment->Init(p1, p2, segsize, r1, r2); // gdy prosty, kontrolne wyliczane przy zmiennej przechyłce
else
Segment->Init(p1, cp1 + p1, cp2 + p2, p2, segsize, r1,
r2); // gdy łuk (ustawia bCurve=true)
Segment->Init(p1, cp1 + p1, cp2 + p2, p2, segsize, r1, r2); // gdy łuk (ustawia bCurve=true)
if ((r1 != 0) || (r2 != 0))
iTrapezoid = 1; // są przechyłki do uwzględniania w rysowaniu
if (eType == tt_Table) // obrotnica ma doklejkę
@@ -808,7 +795,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
}
// alternatywny zapis nazwy odcinka izolowanego - po znaku "@" w nazwie toru
if (!pIsolated)
if ((i = name.find("@")) != string::npos)
if ((i = name.find("@")) != std::string::npos)
if (i < name.length()) // nie może być puste
{
pIsolated = TIsolated::Find(name.substr(i + 1, name.length()));
@@ -976,7 +963,7 @@ bool TTrack::AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus)
return false;
};
string TTrack::IsolatedName()
std::string TTrack::IsolatedName()
{ // podaje nazwę odcinka izolowanego, jesli nie ma on jeszcze przypisanych zdarzeń
if (pIsolated)
if (!pIsolated->evBusy && !pIsolated->evFree)
@@ -1007,27 +994,6 @@ bool TTrack::AddDynamicObject(TDynamicObject *Dynamic)
Dynamic->MyTrack = NULL; // trzeba by to uzależnić od kierunku ruchu...
return true;
}
#ifdef EU07_USE_OLD_TTRACK_DYNAMICS_ARRAY
if (Global::iMultiplayer) // jeśli multiplayer
if (!iNumDynamics) // pierwszy zajmujący
if (pMyNode->asName != "none")
Global::pGround->WyslijString(pMyNode->asName,
8); // przekazanie informacji o zajętości toru
if (iNumDynamics < iMaxNumDynamics)
{ // jeśli jest miejsce, dajemy na koniec
Dynamics[iNumDynamics++] = Dynamic;
Dynamic->MyTrack = this; // ABu: na ktorym torze jesteśmy
if (Dynamic->iOverheadMask) // jeśli ma pantografy
Dynamic->OverheadTrack(
fOverhead); // przekazanie informacji o jeździe bezprądowej na tym odcinku toru
return true;
}
else
{
Error("Too many dynamics on track " + pMyNode->asName);
return false;
}
#else
if( Global::iMultiplayer ) {
// jeśli multiplayer
if( true == Dynamics.empty() ) {
@@ -1045,7 +1011,6 @@ bool TTrack::AddDynamicObject(TDynamicObject *Dynamic)
Dynamic->OverheadTrack( fOverhead ); // przekazanie informacji o jeździe bezprądowej na tym odcinku toru
}
return true;
#endif
};
void TTrack::MoveMe(vector3 pPosition)
@@ -1863,42 +1828,16 @@ void TTrack::Render()
bool TTrack::CheckDynamicObject(TDynamicObject *Dynamic)
{ // sprawdzenie, czy pojazd jest przypisany do toru
#ifdef EU07_USE_OLD_TTRACK_DYNAMICS_ARRAY
for (int i = 0; i < iNumDynamics; i++)
if (Dynamic == Dynamics[i])
return true;
return false;
#else
for( auto dynamic : Dynamics ) {
if( dynamic == Dynamic ) {
return true;
}
}
return false;
#endif
};
bool TTrack::RemoveDynamicObject(TDynamicObject *Dynamic)
{ // usunięcie pojazdu z listy przypisanych do toru
#ifdef EU07_USE_OLD_TTRACK_DYNAMICS_ARRAY
for (int i = 0; i < iNumDynamics; i++)
{ // sprawdzanie wszystkich po kolei
if (Dynamic == Dynamics[i])
{ // znaleziony, przepisanie następnych, żeby dziur nie było
--iNumDynamics;
for (i; i < iNumDynamics; i++)
Dynamics[i] = Dynamics[i + 1];
if (Global::iMultiplayer) // jeśli multiplayer
if (!iNumDynamics) // jeśli już nie ma żadnego
if (pMyNode->asName != "none")
Global::pGround->WyslijString(
pMyNode->asName, 9); // przekazanie informacji o zwolnieniu toru
return true;
}
}
Error("Cannot remove dynamic from track");
return false;
#else
bool result = false;
if( *Dynamics.begin() == Dynamic ) {
// most likely the object getting removed is at the front...
@@ -1935,7 +1874,6 @@ bool TTrack::RemoveDynamicObject(TDynamicObject *Dynamic)
}
return result;
#endif
}
bool TTrack::InMovement()
@@ -2457,8 +2395,7 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
}
};
void TTrack::RaRenderVBO(int iPtr)
{ // renderowanie z użyciem VBO
void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO
// Ra 2014-07: trzeba wymienić GL_TRIANGLE_STRIP na GL_TRIANGLES i renderować trójkąty sektora
// dla kolejnych tekstur!
EnvironmentSet();
@@ -2598,7 +2535,7 @@ void TTrack::EnvironmentSet()
#else
switch( eEnvironment ) {
case e_canyon: {
Global::daylight.intensity = 0.5f;
Global::daylight.intensity = 0.4f;
break;
}
case e_tunnel: {
@@ -2640,14 +2577,6 @@ void TTrack::EnvironmentReset()
void TTrack::RenderDyn()
{ // renderowanie nieprzezroczystych fragmentów pojazdów
#ifdef EU07_USE_OLD_TTRACK_DYNAMICS_ARRAY
if (!iNumDynamics)
return; // po co kombinować, jeśli nie ma pojazdów?
// EnvironmentSet(); //Ra: pojazdy sobie same teraz liczą cienie
for (int i = 0; i < iNumDynamics; i++)
Dynamics[i]->Render(); // sam sprawdza, czy VBO; zmienia kontekst VBO!
// EnvironmentReset();
#else
for( auto dynamic : Dynamics ) {
// sam sprawdza, czy VBO; zmienia kontekst VBO!
#ifdef EU07_USE_OLD_RENDERCODE
@@ -2656,19 +2585,10 @@ void TTrack::RenderDyn()
GfxRenderer.Render( dynamic );
#endif
}
#endif
};
void TTrack::RenderDynAlpha()
{ // renderowanie przezroczystych fragmentów pojazdów
#ifdef EU07_USE_OLD_TTRACK_DYNAMICS_ARRAY
if (!iNumDynamics)
return; // po co kombinować, jeśli nie ma pojazdów?
// EnvironmentSet(); //Ra: pojazdy sobie same teraz liczą cienie
for (int i = 0; i < iNumDynamics; i++)
Dynamics[i]->RenderAlpha(); // sam sprawdza, czy VBO; zmienia kontekst VBO!
// EnvironmentReset();
#else
for( auto dynamic : Dynamics ) {
// sam sprawdza, czy VBO; zmienia kontekst VBO!
#ifdef EU07_USE_OLD_RENDERCODE
@@ -2677,19 +2597,13 @@ void TTrack::RenderDynAlpha()
GfxRenderer.Render_Alpha( dynamic );
#endif
}
#endif
};
void TTrack::RenderDynSounds()
{ // odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania
#ifdef EU07_USE_OLD_TTRACK_DYNAMICS_ARRAY
for( int i = 0; i < iNumDynamics; i++ )
Dynamics[i]->RenderSounds();
#else
for( auto dynamic : Dynamics ) {
dynamic->RenderSounds();
}
#endif
};
//---------------------------------------------------------------------------
bool TTrack::SetConnections(int i)
@@ -2923,77 +2837,73 @@ TTrack * TTrack::RaAnimate()
m = false; // koniec animacji
}
}
if (Global::bUseVBO)
{ // dla OpenGL 1.4 odświeży się cały sektor, w późniejszych poprawiamy fragment
if (GLEW_VERSION_1_5) // dla OpenGL 1.4 to się nie wykona poprawnie
if (TextureID1) // Ra: !!!! tu jest do poprawienia
{ // iglice liczone tylko dla zwrotnic
vector6 rpts3[24], rpts4[24];
double fHTW = 0.5 * fabs(fTrackWidth);
double fHTW2 = fHTW; // Ra: na razie niech tak będzie
double cos1 = 1.0, sin1 = 0.0, cos2 = 1.0, sin2 = 0.0; // Ra: ...
for (int i = 0; i < 12; ++i)
{
rpts3[i] =
vector6((fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1,
-(fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z);
rpts3[i + 12] =
vector6((fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2,
-(fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z);
rpts4[11 - i] = vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1,
-(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1,
iglica[i].z);
rpts4[23 - i] =
vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2,
-(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z);
}
CVertNormTex Vert[2 * 2 * 12]; // na razie 2 segmenty
CVertNormTex *v = Vert; // bo RaAnimate() modyfikuje wskaźnik
glGetBufferSubData(
GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
2 * 2 * 12 * sizeof(CVertNormTex), &Vert); // pobranie fragmentu bufora VBO
if (SwitchExtension->RightSwitch)
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
SwitchExtension->Segments[0]->RaAnimate(v, rpts3, -nnumPts, fTexLength, 0,
2, SwitchExtension->fOffset2);
glBufferSubData(GL_ARRAY_BUFFER,
SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
2 * 2 * 12 * sizeof(CVertNormTex),
&Vert); // wysłanie fragmentu bufora VBO
v = Vert;
glGetBufferSubData(GL_ARRAY_BUFFER,
SwitchExtension->iRightVBO * sizeof(CVertNormTex),
2 * 2 * 12 * sizeof(CVertNormTex),
&Vert); // pobranie fragmentu bufora VBO
SwitchExtension->Segments[1]->RaAnimate(v, rpts4, -nnumPts, fTexLength, 0,
2, -fMaxOffset +
SwitchExtension->fOffset1);
}
else
{ // oryginalnie lewa działała lepiej niż prawa
SwitchExtension->Segments[0]->RaAnimate(
v, rpts4, -nnumPts, fTexLength, 0, 2,
-SwitchExtension->fOffset2); // prawa iglica
glBufferSubData(GL_ARRAY_BUFFER,
SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
2 * 2 * 12 * sizeof(CVertNormTex),
&Vert); // wysłanie fragmentu bufora VBO
v = Vert;
glGetBufferSubData(GL_ARRAY_BUFFER,
SwitchExtension->iRightVBO * sizeof(CVertNormTex),
2 * 2 * 12 * sizeof(CVertNormTex),
&Vert); // pobranie fragmentu bufora VBO
SwitchExtension->Segments[1]->RaAnimate(
v, rpts3, -nnumPts, fTexLength, 0, 2,
fMaxOffset - SwitchExtension->fOffset1); // lewa iglica
}
glBufferSubData(
GL_ARRAY_BUFFER, SwitchExtension->iRightVBO * sizeof(CVertNormTex),
2 * 2 * 12 * sizeof(CVertNormTex), &Vert); // wysłanie fragmentu bufora VBO
if (GLEW_VERSION_1_5) // dla OpenGL 1.4 to się nie wykona poprawnie
if (TextureID1) // Ra: !!!! tu jest do poprawienia
{ // iglice liczone tylko dla zwrotnic
vector6 rpts3[24], rpts4[24];
double fHTW = 0.5 * fabs(fTrackWidth);
double fHTW2 = fHTW; // Ra: na razie niech tak będzie
double cos1 = 1.0, sin1 = 0.0, cos2 = 1.0, sin2 = 0.0; // Ra: ...
for (int i = 0; i < 12; ++i)
{
rpts3[i] =
vector6((fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1,
-(fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z);
rpts3[i + 12] =
vector6((fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2,
-(fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z);
rpts4[11 - i] = vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1,
-(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1,
iglica[i].z);
rpts4[23 - i] =
vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2,
-(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z);
}
}
else // gdy Display List
Release(); // niszczenie skompilowanej listy, aby się wygenerowała nowa
CVertNormTex Vert[2 * 2 * 12]; // na razie 2 segmenty
CVertNormTex *v = Vert; // bo RaAnimate() modyfikuje wskaźnik
glGetBufferSubData(
GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
2 * 2 * 12 * sizeof(CVertNormTex), &Vert); // pobranie fragmentu bufora VBO
if (SwitchExtension->RightSwitch)
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
SwitchExtension->Segments[0]->RaAnimate(v, rpts3, -nnumPts, fTexLength, 0,
2, SwitchExtension->fOffset2);
glBufferSubData(GL_ARRAY_BUFFER,
SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
2 * 2 * 12 * sizeof(CVertNormTex),
&Vert); // wysłanie fragmentu bufora VBO
v = Vert;
glGetBufferSubData(GL_ARRAY_BUFFER,
SwitchExtension->iRightVBO * sizeof(CVertNormTex),
2 * 2 * 12 * sizeof(CVertNormTex),
&Vert); // pobranie fragmentu bufora VBO
SwitchExtension->Segments[1]->RaAnimate(v, rpts4, -nnumPts, fTexLength, 0,
2, -fMaxOffset +
SwitchExtension->fOffset1);
}
else
{ // oryginalnie lewa działała lepiej niż prawa
SwitchExtension->Segments[0]->RaAnimate(
v, rpts4, -nnumPts, fTexLength, 0, 2,
-SwitchExtension->fOffset2); // prawa iglica
glBufferSubData(GL_ARRAY_BUFFER,
SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
2 * 2 * 12 * sizeof(CVertNormTex),
&Vert); // wysłanie fragmentu bufora VBO
v = Vert;
glGetBufferSubData(GL_ARRAY_BUFFER,
SwitchExtension->iRightVBO * sizeof(CVertNormTex),
2 * 2 * 12 * sizeof(CVertNormTex),
&Vert); // pobranie fragmentu bufora VBO
SwitchExtension->Segments[1]->RaAnimate(
v, rpts3, -nnumPts, fTexLength, 0, 2,
fMaxOffset - SwitchExtension->fOffset1); // lewa iglica
}
glBufferSubData(
GL_ARRAY_BUFFER, SwitchExtension->iRightVBO * sizeof(CVertNormTex),
2 * 2 * 12 * sizeof(CVertNormTex), &Vert); // wysłanie fragmentu bufora VBO
}
}
else if (eType == tt_Table) // dla obrotnicy - szyny i podsypka
{
@@ -3023,36 +2933,27 @@ TTrack * TTrack::RaAnimate()
SwitchExtension->vTrans; // SwitchExtension->Segments[0]->FastGetPoint(0.5);
Segment->Init(middle + vector3(sina, 0.0, cosa),
middle - vector3(sina, 0.0, cosa), 5.0); // nowy odcinek
#ifdef EU07_USE_OLD_TTRACK_DYNAMICS_ARRAY
for( int i = 0; i < iNumDynamics; i++ )
Dynamics[i]->Move(0.000001); // minimalny ruch, aby przeliczyć pozycję i
#else
for( auto dynamic : Dynamics ) {
// minimalny ruch, aby przeliczyć pozycję
dynamic->Move( 0.000001 );
}
#endif
// kąty
if (Global::bUseVBO)
{ // dla OpenGL 1.4 odświeży się cały sektor, w późniejszych poprawiamy fragment
// aktualizacja pojazdów na torze
if (GLEW_VERSION_1_5) // dla OpenGL 1.4 to się nie wykona poprawnie
{
int size =
RaArrayPrepare(); // wielkość tabeli potrzebna dla tej obrotnicy
CVertNormTex *Vert = new CVertNormTex[size]; // bufor roboczy
// CVertNormTex *v=Vert; //zmieniane przez
RaArrayFill(Vert,
Vert -
SwitchExtension
->iLeftVBO); // iLeftVBO powinno zostać niezmienione
glBufferSubData(
GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
size * sizeof(CVertNormTex), Vert); // wysłanie fragmentu bufora VBO
}
// aktualizacja pojazdów na torze
if (GLEW_VERSION_1_5) // dla OpenGL 1.4 to się nie wykona poprawnie
{
int size =
RaArrayPrepare(); // wielkość tabeli potrzebna dla tej obrotnicy
CVertNormTex *Vert = new CVertNormTex[size]; // bufor roboczy
// CVertNormTex *v=Vert; //zmieniane przez
RaArrayFill(Vert,
Vert -
SwitchExtension
->iLeftVBO); // iLeftVBO powinno zostać niezmienione
glBufferSubData(
GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
size * sizeof(CVertNormTex), Vert); // wysłanie fragmentu bufora VBO
}
else // gdy Display List
Release(); // niszczenie skompilowanej listy, aby się wygenerowała nowa
} // animacja trwa nadal
}
else
@@ -3063,15 +2964,9 @@ TTrack * TTrack::RaAnimate()
//---------------------------------------------------------------------------
void TTrack::RadioStop()
{ // przekazanie pojazdom rozkazu zatrzymania
#ifdef EU07_USE_OLD_TTRACK_DYNAMICS_ARRAY
for (int i = 0; i < iNumDynamics; i++)
Dynamics[i]->RadioStop();
#else
for( auto dynamic : Dynamics ) {
dynamic->RadioStop();
}
#endif
};
double TTrack::WidthTotal()
@@ -3180,7 +3075,7 @@ void TTrack::MovedUp1(double dh)
fTexHeight1 += dh;
};
string TTrack::NameGet()
std::string TTrack::NameGet()
{ // ustalenie nazwy toru
if (this)
if (pMyNode)