How to reference labels in script

Posts: 100
Hi everyone -

Relatively new to C# and I was really struggling to figure out how to do a live point system and structure for our graphics. The ATVO team has these nice inputs and a mostly done script to sort it out, but it was all over my head. I took a really simple, bare bones approach to calculating the number of points a driver has accumulated during a race - and to my amazement, it works! Still some minor things to sort out.

The only thing I have to do now is add this calculated value to the number of points the driver carried into the event. Out of curiosity and for simplicity's sake, instead of directly reading the excel sheet, can I pull a value contained in a label from elsewhere in the theme? I have a points excel sheet, and there's a column that contains the value of points from the season, and that is tied to a label on another widget. Can I access this value directly in the script and add that to my other calculation? What's the best way forward here? This is what I'm doing to calculate points:

The number of points for each position is stored in the Point Structure array (this particular example is Outsider Racing League's, 30 points to the winner, 29 for second etc.
It works by taking the current position of the driver in the race, using that position to reference the correct number of points in the array, and then adding the necessary bonus points.

using System; 
using ATVO.ThemesSDK;
using ATVO.ThemesSDK.Data.Entity;
using ATVO.ThemeEditor.ThemeModels;
using ATVO.ThemeEditor.Controls;
using ATVO.ThemeEditor.Scripting.DotNET;
using ATVO.ThemesSDK.Data.Enums;
using ATVO.ThemesSDK.Data.Results;


namespace Scripts
{
public class Script : IScript
{

int[] PointStructure = new int[] { 0, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};


public object Execute(ThemeContentItem item, object value, string parameter, ISimulation sim)
{
IEntitySessionResult result = (IEntitySessionResult) value;

var pos = result.LivePosition;
int CurrentPoints = PointStructure[pos];

if (result.LivePosition == 0)
{
return "0";
}

//Lap Led Point
if (result.LapsLed > 0)
{
CurrentPoints++;
}
//Pole Position Point
if (result.StartPosition == 1)
{
CurrentPoints++;
}
//Winner Point
if (result.LivePosition == 1)
{
CurrentPoints++;
}

return CurrentPoints;

}
}

}


And as I pasted this I realized I created a variable called pos so I don't have to call result.LivePosition every time... I told you I was new... :)
Posts: 785
Reading a value from a Label is easy if you have the reference to that Label, just grab the DisplayText property (and convert it to a number if you need it as a number):
var text = label.DisplayText;
var number = int.Parse(text);


The difficult part may be where to get the "label" object reference. If it's a static label in a static Widget in your theme, it's easy, just call it by name via its parents:
var theme = item.Theme;
var label = theme.Widgets.Find("MyWidget1").SubWidgets.Find("MySubWidget2").Labels.Find("TargetLabelName");


If it's a label in a Ticker it is more difficult. In that case it's probably easier to grab the reference to the Spreadsheet object (either the source file itself or if you've added it to the Theme you can get the Spreadsheet theme item).
Posts: 100
If it's a label in a Ticker it is more difficult. In that case it's probably easier to grab the reference to the Spreadsheet object (either the source file itself or if you've added it to the Theme you can get the Spreadsheet theme item).


Yes, as it stands, the label is in a ticker. Could you lay out the easiest way to pull data from a specific column? Thanks for the quick response.

I have one more question about how one could calculate if a driver has led the most laps. It's very easy to give a driver the bonus point for leading a lap, as I have done, but I guess I'd need to compare the number of laps they've led to other drivers. This seems pretty tricky to do, I had hoped their was a bool for MostLapsLed or something.


//Most Laps Led Point
if (result.LapsLed > (number.LapsTotal/2) || result.LapsLed > (number.LapsCompleted/2))
{
CurrentPoints++;
}

This code will work if the driver has led more than half the laps up to the current point or if they led more than half the laps in the race, but in theory someone could lead the most laps and not lead over half of the total laps. So this will work if someone is dominant but not if the lead is split among a bunch of drivers.


Thanks Nick!
Edited (1 time)
Posts: 785
This post shows how to read data from each row in a spreadsheet. You grab the Rows property, have to do something "fancy" to get them as DataRows, and then loop through them. Then in each row you can address each column by index via row[0], row[1], etc. Look near the bottom for example in LoadStandings.
https://atvo.appgineering.com/Forum/Thread/69?postId=451#451

For most laps led I think the easiest way is just to sort the results by LapsLed and grab the first one. It is probably not the most efficient but it's not gonna matter, sorting max 60 items should take a microsecond or less. Something like this perhaps:
var results = sim.Session.Current?.Results;
var sorted = results?.OrderBy(r => r.LapsLed)?.ToList();
if (sorted != null && sorted.Count > 0)
{
var most = sorted[0];
// Do what you want with this result
}
Posts: 100
Thank you! This will get me moving along nicely. I'll have to test, but does var most return the driver name or the number of laps led?

I assume with how it's written, it's the driver name or ID.
Edited (2 times)
Posts: 785
It is the result object, of type IEntitySessionResult
It has properties for almost all things related to current results of one entity (driver or team). It also links to the corresponding entity via the Entity property, so from that you can get the driver name, id, etc.
Posts: 100
Hi Nick - apologies for the messy formatting. I'm having trouble recognizing drivers off of the spreadsheet, it never seems to recognize when a driver is in the sheet and assigns them the default points value of zero. The script does correctly add the current points earned during the race, but not adding the points from Column9 (the points accumulated so far this season).

I didn't think DriverID was a necessary column, since the spreadsheet data binding works fine with just names, but I did try adding a column with IDs and have the same problem. Does anything stick out to you that would cause this?



using System; 
using ATVO.ThemesSDK;
using ATVO.ThemesSDK.Data.Entity;
using ATVO.ThemeEditor.ThemeModels;
using ATVO.ThemeEditor.Controls;
using ATVO.ThemeEditor.Scripting.DotNET;
using ATVO.ThemesSDK.Data.Enums;
using ATVO.ThemesSDK.Data.Results;
using System.Linq;
using System.Data;
using System.Collections.Generic;


namespace Scripts
{
public class Script : IScript
{

ChampDriver driver;


int[] PointStructure = new int[] { 0, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
private Dictionary<int, ChampDriver> _standings = new Dictionary<int, ChampDriver>();


public object Execute(ThemeContentItem item, object value, string parameter, ISimulation sim)
{
UpdateSessionStandings(sim);
LoadStandings(item.Theme);
IEntitySessionResult result = (IEntitySessionResult) value;

var pos = result.LivePosition;
int CurrentPoints = PointStructure[pos];

//Lap Led Point
if (result.LapsLed > 0)
{
CurrentPoints++;
}
//Pole Position Point
if (result.StartPosition == 1)
{
CurrentPoints++;
}
//Winner Point
if (result.LivePosition == 1)
{
CurrentPoints++;
}

int TotalPoints = CurrentPoints + driver.ChampPoints;

return TotalPoints;

}
/////////////////////////////////////////////////////////////////////////////////////////////////////////


private void LoadStandings(Theme theme)
{
if (_standings.Count == 0)
{
// Read current standings from embedded csv
// Columns: customer_id, position, carnumber, drivername, points
var sheet = theme.Spreadsheets.Find("Champ_Standings.csv");

foreach (var row in sheet.Table.Data.Rows.OfType<DataRow>())
{
var custid = row[1];
var position = row[0];
var carnum = row[11];
var name = row[2];
var points = row[9];

var driver = new ChampDriver();
driver.CustomerId = Convert.ToInt32(custid);
driver.ChampPosition = Convert.ToInt32(position);
driver.CarNumber = carnum.ToString();
driver.Name = name.ToString();
driver.ChampPoints = Convert.ToInt32(points);

_standings.Add(driver.CustomerId, driver);
}
}
}

private void UpdateSessionStandings(ISimulation sim)
{
// Loop through entity results in the session and update the standings
foreach (var result in sim.Session.Current.Results)
{

// Check if there is a driver in the session who was NOT in the standings csv
if (!_standings.ContainsKey(result.Entity.Id))
{
// This driver isn't in the standings yet, let's add him
driver = new ChampDriver();
driver.CustomerId = result.Entity.Id;
driver.Name = result.Entity.Name;
driver.CarNumber = result.Entity.Car.Number;
driver.ChampPoints = 0;
_standings.Add(driver.CustomerId, driver);
}
else
{
// Otherwise, grab him from memory
driver = _standings[result.Entity.Id];
}

// Link him to the session entity
driver.Entity = result.Entity;

}
}

public class ChampDriver
{
public IEntity Entity {get;set;}
public int CustomerId {get;set;}
public string CarNumber {get;set;}
public string Name {get;set;}

public int ChampPosition {get;set;}
public int ChampPoints {get;set;}
public int LiveChampPosition {get;set;}
public int LiveChampPoints {get;set;}
}
}
}