Timing of things in the plugin

JohnW63

The on going project....

At this point, I want to print out the session names at the pit stops. What I have done so far seems to work, but ... the print out is one digit off the actual session. For example, I learned that the sessions are numbered as follows:

1 is Practice 1
2 is Practice 2
3 is Practice 3
4 is Practice 4 ( if there is a P4 )
5 is Qualifying
6 is Warm-up
7 is Race.

So that I can print out more than numbers 1 -7 as the event moves on, I setup some code in the StartSession section:

Code:
if ( mSessionNumber == 1 ){
	  mSessionName = "Practice 1";
  }
  else if ( mSessionNumber == 2 ){
	mSessionName = "Practice 2";
  }
  else if ( mSessionNumber == 3 ){
	mSessionName = "Practice 3";
  }
  else if ( mSessionNumber == 4 ){
	mSessionName = "Practice 4";
  }
  else if ( mSessionNumber == 5 ){
	mSessionName = "Qualifying";
  }
  else if ( mSessionNumber == 6 ){
	mSessionName = "Warm-Up";
  }
  else if ( mSessionNumber == 7 ){
	  mSessionName = "Race";
	  mRaceTempRead = false;
  }

I'll probably change that all to a switch/case set of statements, when I get it working.

The variable mSessionNumber is one I created and I set it equal to the predefined variable mSession in the UpdateScoring section. This seems to work, because if I print out simply the session number in the Telemetry section, they are correct. However, in the same line of code, if I have it display the mSessionName , the first session shows as a blank, the next as Practice 1, when it is Qualifying, then Qualifying, when it is Warm-up ... etc.

My output code is like this:

Code:
fprintf( fo, " Session = %s , %d \n ", mSessionName.c_str(), mSessionNumber );

I had to include the string stuff in the Example.hpp file to do this as a string :

Code:
#include <string>
using std::string;


My question is why the assignment of the name seems to be one session behind the number.
 
I don't think I understand what the question is. Is your code not working? In my plugin I don't even bother testing for all sessions. Our server never runs all these practice sessions anyways. Here is what I test for:
Code:
switch(info.mSession)
{
case 0:
	fprintf( fo, "  <session>Test</session>\n");
	break;
case 1:
	fprintf( fo, "  <session>Practice</session>\n");
	break;
case 5:
	fprintf( fo, "  <session>Qualifying</session>\n");
	break;
case 6:
	fprintf( fo, "  <session>WarmUp</session>\n");
	break;
case 7:
	fprintf( fo, "  <session>Race</session>\n");
	break;
default:
	fprintf( fo, "  <session>%d</session>\n",info.mSession);
	break;
}

I threw in a catch all for the other session numbers that I don't really care about.
 
The issue is that while my variable mSessionNumber works properly and can display the proper session number at the right time, the other variable, mSessionName is off by 1. For instance, any session I am in, outputs the previous session name. I can use the same fprintf statement and the session number prints out properly, 1 - 7 or what I am in, but the name gets printed out improperly. When it prints out mSessionNumber as 1 , the SessionName prints out as nothing. When it prints out mSessionNumber as 5 ( which is Qualifying ), the mSessionName prints out as "Practice 1" , which was the session I was in prior to Qualifying.

Now that I think about it, it's not off by one, numerically, it's printing out the previous session that the game was in, regardless of the number pattern. It's like I'm getting the session before the scoring gets updated.
 
I came up with a fix. I put the part that assigns a value to the SessionNumber variable and the part that assigns the SessionName variable right after one another, in the UpdateTelemetry section. That way they would have to be in synch. What still puzzles me is why having the SessionName assignment in the StartSession() part made the two variables off timed.
 
To be honest I also don't understand. Give us some code proto.
What I know is, that StartSession method has no access to data like session number. Those data are passed to UpdateScoring method only. So in my opinion you cannot save SessionName in StartSession method.
 
"What I know is, that StartSession method has no access to data like session number. Those data are passed to UpdateScoring method only. So in my opinion you cannot save SessionName in StartSession method. "

True, with the default code, you can't. But I have added some variables to the Example.hpp file that I can assign the value of mSession to and then store a name with.

Code:
  long mSessionNumber; // Variable to track the sessions
  string mSessionName; // Variable for the session name

mSessionNumber gets assigned the current value of mSession in the UpdateScoring() section:

Code:
mSessionNumber = info.mSession;

Then, under that, I assign the text values to mSessionName, based on the value of mSessionNumber.

Code:
if ( mSessionNumber == 1 ){
	  mSessionName = "Practice 1";
  }
  else if ( mSessionNumber == 2 ){
	mSessionName = "Practice 2";
  }
  else if ( mSessionNumber == 3 ){
	mSessionName = "Practice 3";
  }
  else if ( mSessionNumber == 4 ){
	mSessionName = "Practice 4";
  }
  else if ( mSessionNumber == 5 ){
	mSessionName = "Qualifying";
  }
  else if ( mSessionNumber == 6 ){
	mSessionName = "Warm-Up";
  }
  else if ( mSessionNumber == 7 ){
	  mSessionName = "Race";
  }

In my first attempt, I tried to make the name assignments in the StartSession() part. It worked, but was off by a session.
 
Stil given example clear enough because you didn't wrote in which methods you call all listed lines.
I suspect you perform mSession assigning in UpdateScoring method. So.. you cannot assign names in StartSession method, because it is called before the first call of ScoreUpdate.

You have to do all assigments in UpdateScoring method.
 
you didn't wrote in which methods you call all listed lines.

I believe I did. Check above.

The variables were declared in the Example.hpp file

They were assigned values in the UpdateScoring section of the Example.cpp file, in my current version.

The names were originally assigned, based on the session number, in the StartSession section and the session number assigned in the UpdateScoring section.

My assumption was that the StartSession output was done AFTER a session was started, so assigning the names in that part would be accurate. From what you are saying, the words "Start Session" are printed before the session is advanced. From my results, that would make sense, but it does still seem odd.
 
My assumption was that the StartSession output was done AFTER a session was started, so assigning the names in that part would be accurate. From what you are saying, the words "Start Session" are printed before the session is advanced. From my results, that would make sense, but it does still seem odd.

Well, first, MaXyM hasn't been reading properly, obviously.

That aside, you're looking at this whole thing too loosely. The game is doing one thing at a time, and it doesn't sit around waiting for a bit before it moves onto the next thing.

So, when the session changes (in the game) and it does its session-change code, at the end it calls StartSession in your plugin. There's no delay, there's no other thread calling your UpdateScoring in the meantime. So there's no way you can pick up the new session number before StartSession() is called - hence you still have the old one.

You have to picture rFactor going through doing its thing, and at specific times it comes and calls your code. Again, it doesn't 'start' your code and then continue doing whatever it's doing; your code becomes rFactor code. When it's calling StartSession that's all that rFactor is doing.

Since UpdateScoring is called roughly twice a second (and you can't make any guarantees about its timing relative to UpdateTelemetry, or any other function) if you want to use that info you need to do some testing so you know when you can rely on the data you're picking up.

For example, when StartSession is called, you know your existing scoring data is out of date (at least the session number). So you tell yourself that with a variable. Then in UpdateScoring, you see that your data is out of date, update it, and then tell yourself (with the same variable, probably) that it's now up to date. Then in UpdateTelemetry you test that variable and when you know it's up to date you can rely on it.

There are lots of 'gaps' and it's up to you to fill them in with code - rFactor doesn't know what you're trying to do and can't help you do it.
 
Which is why I asked about the timing of all this. What is the order of operation ? When is each function called ? Without a flow chart from the developers, it is hard to know WHEN any of the stuff I can see in the plugin gets called. All I can see at this point is that the telemetry gets called 90 times per second, so it is probably the most up-to-date section to be working in.
 
Update telemetry is most-updated one, but no all data are passed to this method (for example scoring data isn't).
You have to do keying of events using Start/StopSession methods, set needed variables in other methods, and output it using most appropriate method you need.


Well, first, MaXyM hasn't been reading properly, obviously.

Go away Lazza with such comments. You wrote exactly what I did.
However, John should give us some complete proto (whole methods with at least code you ask for). he gave us a few lines without description in which method exactly are called and when.
 
Last edited:
Sorry MaXyM - I thought all the replies were yours. One of the dangers of reading on a mobile device :)
 
OK, you can have all the details you want.

In the :class ExampleInternalsPlugin : public InternalsPluginV3

section of the Exmaple.hpp file I added variables at the end:

Code:
 private:

  void WriteToAllExampleOutputFiles( const char * const openStr, const char * const msg );

  float mET;  // needed for the hardware example
  bool mEnabled; // needed for the hardware example
  bool mCarInPits; // Car in Pit lane
  bool mTireChanged; // New tires installed
  bool mTireChangeReported; // Has the tire temp been printed ?
  bool mRaceTempRead; // Variable for tire temp check on race grid
  float mRaceTime;   // Variable to keep track of time
  short mLapCount;  // Variable to get laps into telemetry section
  short mStopCount; // Variable to keep used to print # of stops
  long mSessionNumber; // Variable to track the sessions
  string mSessionName; // Variable for the session name

Of course the float mET is a stock variable. All of these get used to be able to determine variable values in sections that don't talk to each other, such as Telemetry and Scoring.

I then added some variable values in the StartUp() section of the ExamplePlugin.cpp file:

Code:
void ExampleInternalsPlugin::Startup()
{
  // Open ports, read configs, whatever you need to do.  For now, I'll just clear out the
  // example output data files.
  WriteToAllExampleOutputFiles( "w", "-STARTUP-" );

  // default HW control enabled to true
  mEnabled = true;
  // stuff to check for tire changes
  mCarInPits = false;
  mTireChanged = false;
  mTireChangeReported = false;
  mRaceTime = 0.00;
  mLapCount = 0;
  mStopCount = 0;

}

So that it would only be set once, at the start of the race, I made this change as well:

Code:
void ExampleInternalsPlugin::StartSession()
{
  WriteToAllExampleOutputFiles( "a", "--START SESSION--" );
 if ( mSessionNumber == 7 ){
	  mRaceTempRead = false;
  }
}

The bulk of the code edits are in the Telemetry section:

I commented out any and all output lines that I didn't need. I have removed those lines to save space, here:

Code:
void ExampleInternalsPlugin::UpdateTelemetry( const TelemInfoV2 &info )
{
  
  FILE *fo = fopen( "ExampleInternalsCombinedOutput.txt", "a" );
  if( fo != NULL )
  {
    // Delta time is variable, as we send out the info once per frame
   

    // Wheels
	  float NewTireTemp[4]={0.0, 0.0, 0.0, 0.0 };  // Set initial tire temps in array to 0
	  float NewTireLoad[4]={1.0, 1.0, 1.0, 1.0 };  // Set initial loads to something other than 0
	  float NewTireWear[4]={0.0, 0.0, 0.0, 0.0 };  // Set initial tire wear left to zero

    for( long i = 0; i < 4; ++i )   // Start 4 wheel scan 
    {
      const TelemWheelV2 &wheel = info.mWheel[i];
	  if (wheel.mTemperature[1] != 0.0 ) {
			NewTireTemp[i] = (wheel.mTemperature[1]-273.15);   // Start populating tire temp array and convert to Celcius 
			NewTireLoad[i] = wheel.mTireLoad;				// Start populating tire load array
			NewTireWear[i] = wheel.mWear;				// Start populating wear array
	  }
	 
	  }  // End 4 wheel scan

// The following is used to determine the start of the race and output the tire temps
		if ( ( mSessionNumber == 7 ) && ( mRaceTempRead == false ) ) {
			fprintf( fo, " Race Session = %s \n ", mSessionName.c_str() );
			fprintf( fo, " Left front : %.1f -- Right front : %.1f -- Left rear : %.1f -- Right rear : %.1f \n", NewTireTemp[0], NewTireTemp[1], NewTireTemp[2], NewTireTemp[3] );
			mRaceTempRead = true;
		}
		
		if ( ( mCarInPits == true ) && ( mRaceTime > 0.00) ) {	//--Is the car in the pits ?
			if ( NewTireTemp[0] != 0.0 ) {				//-- Are the tires warm ?  ( Not in the garage ) 
				if ( (NewTireLoad[0] == NewTireLoad[1]== NewTireLoad[2] == NewTireLoad[3]== 0.0) && (NewTireWear[0] == NewTireWear[1] == NewTireWear[2] == NewTireWear[3] == 1.00) ){	// On the jacks and new tires installed
					mTireChanged = true;
					if ( mTireChangeReported == false ) {		//-- We haven't printed out the tire temps, yet
						fprintf( fo, " Car in Pits. \n " );
						fprintf( fo, " Pit Stops = %d \n ", mStopCount );
						fprintf( fo, " Session = %s \n ", mSessionName.c_str() );
						fprintf( fo, " Race Time = %.2f \n ", mRaceTime );
						fprintf ( fo, " Lap = %d \n", mLapCount );
						fprintf( fo, " Left front : %.1f -- Right front : %.1f -- Left rear : %.1f -- Right rear : %.1f \n", NewTireTemp[0], NewTireTemp[1], NewTireTemp[2], NewTireTemp[3] );
						mTireChangeReported = true;		// We've printed out the temps
						}								// End Tire Change Reported
					}									// end on jacks
				}										// end Tire Temp not zero
			}											// end CarInPits

		else {
			mTireChanged = false;					//-- Set variable for next time the car is in pits
			mTireChangeReported = false;			//-- Set variable to print out temps for next pit stop
		}

    // Compute some auxiliary info based on the above
    TelemVect3 forwardVector = { -info.mOriX.z, -info.mOriY.z, -info.mOriZ.z };
    TelemVect3    leftVector = {  info.mOriX.x,  info.mOriY.x,  info.mOriZ.x };

    // These are normalized vectors, and remember that our world Y coordinate is up.  So you can
    // determine the current pitch and roll (w.r.t. the world x-z plane) as follows:
    const float pitch = atan2f( forwardVector.y, sqrtf( ( forwardVector.x * forwardVector.x ) + ( forwardVector.z * forwardVector.z ) ) );
    const float  roll = atan2f(    leftVector.y, sqrtf( (    leftVector.x *    leftVector.x ) + (    leftVector.z *    leftVector.z ) ) );
    const float radsToDeg = 57.296f;
    const float metersPerSec = sqrtf( ( info.mLocalVel.x * info.mLocalVel.x ) +
                                      ( info.mLocalVel.y * info.mLocalVel.y ) +
                                      ( info.mLocalVel.z * info.mLocalVel.z ) );
	
    fclose( fo );
  }
}

The following is my scoring section. Again, all the example output code has been commented out and not show here:

Code:
void ExampleInternalsPlugin::UpdateScoring( const ScoringInfoV2 &info )
{
  // Note: function is called twice per second now (instead of once per second in previous versions)
  FILE *fo = fopen( "ExampleInternalsCombinedOutput.txt", "a" );
  if( fo != NULL )
  {

	mSessionNumber = info.mSession;  // Set the session number from the Session variable

	if ( mSessionNumber == 1 ){
	  mSessionName = "Practice 1";
  }
  else if ( mSessionNumber == 2 ){
	mSessionName = "Practice 2";
  }
  else if ( mSessionNumber == 3 ){
	mSessionName = "Practice 3";
  }
  else if ( mSessionNumber == 4 ){
	mSessionName = "Practice 4";
  }
  else if ( mSessionNumber == 5 ){
	mSessionName = "Qualifying";
  }
  else if ( mSessionNumber == 6 ){
	mSessionName = "Warm-Up";
  }
  else if ( mSessionNumber == 7 ){
	  mSessionName = "Race";
  }

   
	mRaceTime = info.mCurrentET; 
	
    // Print vehicle info
    for( long i = 0; i < info.mNumVehicles; ++i )
    {
      VehicleScoringInfoV2 &vinfo = info.mVehicle[ i ];
	  if ( vinfo.mIsPlayer == true ) {
	  mCarInPits = vinfo.mInPits;   // assign the InPits value to my new variable
	  mLapCount = vinfo.mTotalLaps;  // assign mTotalLaps value to my variable
	  mStopCount = vinfo.mNumPitstops;  // assign the stock pit stop count to my variable
	  }

  
			}  // End for loop to scan vehicle

    // Close file
    fclose( fo );
	} // end if not null
}  // end update scoring


I hope that is enough , because that is all I have done.
 
IMO this logic is not correct. Testing mSessionNumber variable inside of StartSession method doesn't make sense to me because it is filled with value just inside UpdateScoring which is fired after StartSession (or at least it should).
However to gather data from various methods you should make sure data are serialized.
I did in my LiveView plugin as follows


Code:
void ExampleInternalsPlugin::StartSession()
{
         mStartSessionEvent = true;

}


void ExampleInternalsPlugin::UpdateScoring( const ScoringInfoV2 &info )
{
         if (mStartSessionEvent)
         {
                // here session init: name assignments and other stuff done on session start
                // for example creating file name based on session name etc

                mStartSessionEvent = false;
        }

       // here gathering other scoring data
}

It might be possible to add another key variable to be set in UpdateScoring to serialize getting telemetry data after session is initialized
 
Last edited:
John, it still looks like you are over complicating the tire change plugin. I think Lazza had a very simple and reliable way to do it in this post here:
https://community.racesimcentral.ne...-plugin-sections?p=21185&viewfull=1#post21185

You don't need to check the inpits status, tire load or anything like that. The only way tire wear will ever decrease is if you swap tires. Test the wear every time UpdateTelemetry is called and only report to your log file when the tire wear decreases. Very simple and efficient.
 
The only way tire wear will ever decrease is if you swap tires.

Let's say a driver gets hit at the start and limps around the track and changes tires while repairs are being made. They could have no wear, and change tires. I've watched the tire wear with a heads up display and you could very well have made a lap and not had wear show up. I want to make sure that a very slow lap with a change is not missed. The other issue I had with his suggestion is he only thought ONE tire needed to be checked. With the different track directions, I didn't think that was fool proof. You could have a flat tire, and the ONE wheel I was checking could be off the ground as well. I'll put some thought to simplifying the tire change logic. I just need to make sure it can't be fooled. I don't want to DQ a driver because my code missed a tire change.
 
MaXym,

I set the variable in the startsession method because it was only going to happen ONCE during the race. The update scoring happens 2 times per second. I only want the tire temps right as the cars hit the grid to compare with their Q session tires. ( Did they start the race on the same tires they qualified on ? ) From then on, I will track what tires they change to in the pit stops. So, that variable is set to false at the race start and set to true for the rest of the event. Basically, have a read the starting tire temps ? If I have, then don't print them out anymore.
 
The heads up displays don't show the decimal so yeah I guess a slow lap could be made and not put enough wear on the tire to show on the HUD but when you have the raw data in the plugin you have more accuracy than what is displayed in the HUD. Lazza's example only showed one tire because it was just an example. He just didn't go into full detail and explain that you would need to repeat his logic for each tire.

I understand your desire to make it full proof though. You definitely want to do a lot of testing.

Edit: I just did a little test and I literally "rolled" 50ft and all 4 dropped to 99.9998%. Sure some mods have tires that wear more than others but I really doubt you could limp a whole lap and not put some detectable dent in the wear. I believe in KISS when it comes to stuff like this. I feel like the more convoluted you make it the more room for mistakes you can have. But that is just my 0.02.
 
Last edited:
Noel,

I'm pretty sure he said I only needed to check one rear tire.

I'll try to find his suggestion, but I think the problem was I couldn't figure out HOW to do what he suggested. I may be able to now, since I've spent a lot more time learning how this works. In the mean time I found a way to make it work, by visualizing what happens in a real pit stop.
 
Last edited:
I found that after I posted. The jist of THAT post was to understand how to use variables between the sections of the plugin, and I think I glossed over that because I didn't know HOW to do what he said to do. The basics hadn't clicked , yet.
 
I figured that was the case. It is funny how you can go back and reread stuff after you learn more and see it in a different way. But that is what makes it so fun. Well I find it fun anyways.
 

Back
Top