From c5ff9f95c95cb003d9d46b18fa6caeddff069811 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 16 Jan 2025 20:18:05 +0000 Subject: [PATCH] Working on some standings --- README.md | 2 + irsdk_test.go | 27 ++++++++++-- variables.go | 111 +++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 126 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 3ae0013..3ebf26f 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ - [x] Read data from a stored `.ibt` file - [x] Allow to export the data to an `.ibt` file - [x] Allow to export the session info data to a `.yaml` file +- [ ] Make sure variables with multiple counts are correctly parsed and stored +- [ ] Correctly support and implement the bitFields data - [ ] Add the message broadcasting system - [ ] Explore a more convenient API for fetching the data for the SDK user - [ ] Change the pattern in which the data is fetched from the telemetry and diff --git a/irsdk_test.go b/irsdk_test.go index 344e0c3..ffbf576 100644 --- a/irsdk_test.go +++ b/irsdk_test.go @@ -1,13 +1,20 @@ package goirsdk import ( - "fmt" + "fmt" "log" "os" + "sort" "testing" "time" ) +type StandingsLine struct { + CarIdx int + LapPct float32 + DriverName string +} + func TestFunctionality(t *testing.T) { input, err := os.Open("../testTelemetry/supercars_race_watkins_glenn.ibt") if err != nil { @@ -35,17 +42,31 @@ func TestFunctionality(t *testing.T) { if _, ok := i.Vars.Vars["CarIdxPosition"]; !ok { log.Fatal("Field `CarIdxPosition` doesn't exist") } - driversPositions := i.Vars.Vars["CarIdxPosition"].Value.([]int) + driversPositions := i.Vars.Vars["CarIdxLapDistPct"].Value.([]float32) drivers := i.SessionInfo.DriverInfo.Drivers + standings := make([]StandingsLine, len(drivers)) + fmt.Printf("\033[?25l\033[2J\033[H") for k := range len(drivers) { if drivers[k].CarIsPaceCar == 1 || drivers[k].IsSpectator == 1 { continue } - fmt.Printf("[%d] [%d] %s\n", k, driversPositions[drivers[k].CarIdx], drivers[k].UserName) + standings[k] = StandingsLine{ + CarIdx: k, + LapPct: float32(driversPositions[k]), + DriverName: drivers[k].UserName, + } + } + + sort.Slice(standings, func(i int, j int) bool { + return standings[i].LapPct >= standings[j].LapPct + }) + + for p, v := range standings { + fmt.Printf("[%d] %s %f\n", p + 1, v.DriverName, v.LapPct) } <-mainLoopTicker.C diff --git a/variables.go b/variables.go index 12ec584..84dde33 100644 --- a/variables.go +++ b/variables.go @@ -71,6 +71,20 @@ type Var struct { Value interface{} } +func (v *Var) ToString() string { + return fmt.Sprintf( + "Type: %5d (0x%08x)\n"+ + "Offset: %5d (0x%08x)\n"+ + "Count: %5d (0x%08x)\n"+ + "CountAsTime: %5t\n"+ + "Name: %s\n"+ + "Description: %s\n"+ + "Unit: %s", + v.Type, v.Type, v.Offset, v.Offset, v.Count, v.Count, + v.CountAsTime, v.Name, v.Description, v.Unit, + ) +} + func (v *IBTVar) ToString() string { return fmt.Sprintf( "Type: %5d (0x%08x)\n"+ @@ -147,29 +161,103 @@ func (i *IBT) readData(buf []byte) error { // Read the value switch v.Type { case IRSDK_char: - v.Value = string(rbuf[0]) - case IRSDK_bool: - v.Value = int(rbuf[0]) > 0 - case IRSDK_int: if v.Count > 1 { - data := make([]int, v.Count) + // Array of data + data := make([]string, v.Count) for entry := 0; entry < int(v.Count); entry++ { entryOffset := v.Offset + int32(entry)*int32(VarTypes[int(v.Type)].Size) rbuf := buf[entryOffset : entryOffset+int32(VarTypes[int(v.Type)].Size)] - newValue := int(binary.LittleEndian.Uint32(rbuf)) + + newValue := string(rbuf[0]) data[entry] = newValue } v.Value = data } else { + // Single value + v.Value = string(rbuf[0]) + } + case IRSDK_bool: + if v.Count > 1 { + // Array of data + data := make([]bool, v.Count) + for entry := 0; entry < int(v.Count); entry++ { + entryOffset := v.Offset + int32(entry)*int32(VarTypes[int(v.Type)].Size) + rbuf := buf[entryOffset : entryOffset+int32(VarTypes[int(v.Type)].Size)] + + newValue := int(rbuf[0]) > 0 + data[entry] = newValue + } + + v.Value = data + } else { + // Single value + v.Value = int(rbuf[0]) > 0 + } + case IRSDK_int: + if v.Count > 1 { + // Array of data + data := make([]int32, v.Count) + for entry := 0; entry < int(v.Count); entry++ { + entryOffset := v.Offset + int32(entry)*int32(VarTypes[int(v.Type)].Size) + rbuf := buf[entryOffset : entryOffset+int32(VarTypes[int(v.Type)].Size)] + newValue := int32(binary.LittleEndian.Uint32(rbuf)) + data[entry] = newValue + } + + v.Value = data + } else { + // Single value v.Value = int(binary.LittleEndian.Uint32(rbuf)) } case IRSDK_bitField: - v.Value = fmt.Sprintf("0x%x", int(binary.LittleEndian.Uint32(rbuf))) + if v.Count > 1 { + // Array of data + data := make([]string, v.Count) + for entry := 0; entry < int(v.Count); entry++ { + entryOffset := v.Offset + int32(entry)*int32(VarTypes[int(v.Type)].Size) + rbuf := buf[entryOffset : entryOffset+int32(VarTypes[int(v.Type)].Size)] + newValue := fmt.Sprintf("0x%x", int(binary.LittleEndian.Uint32(rbuf))) + data[entry] = newValue + } + + v.Value = data + } else { + // Single value + v.Value = fmt.Sprintf("0x%x", int(binary.LittleEndian.Uint32(rbuf))) + } case IRSDK_float: - v.Value = math.Float32frombits(uint32(binary.LittleEndian.Uint32(rbuf))) + if v.Count > 1 { + // Array of data + data := make([]float32, v.Count) + for entry := 0; entry < int(v.Count); entry++ { + entryOffset := v.Offset + int32(entry)*int32(VarTypes[int(v.Type)].Size) + rbuf := buf[entryOffset : entryOffset+int32(VarTypes[int(v.Type)].Size)] + newValue := math.Float32frombits(uint32(binary.LittleEndian.Uint32(rbuf))) + data[entry] = newValue + } + + v.Value = data + } else { + // Single value + v.Value = math.Float32frombits(uint32(binary.LittleEndian.Uint32(rbuf))) + } case IRSDK_double: - v.Value = math.Float64frombits(uint64(binary.LittleEndian.Uint64(rbuf))) + if v.Count > 1 { + // Array of data + data := make([]float64, v.Count) + for entry := 0; entry < int(v.Count); entry++ { + entryOffset := v.Offset + int32(entry)*int32(VarTypes[int(v.Type)].Size) + rbuf := buf[entryOffset : entryOffset+int32(VarTypes[int(v.Type)].Size)] + newValue := math.Float64frombits(uint64(binary.LittleEndian.Uint64(rbuf))) + data[entry] = newValue + } + + v.Value = data + } else { + // Single value + v.Value = math.Float64frombits(uint64(binary.LittleEndian.Uint64(rbuf))) + } } // -------------- @@ -236,6 +324,7 @@ func (i *IBT) Update(timeout time.Duration) (IRacingState, error) { return Ended, nil } + // Document why this is here, I don't remember the exact words right now i.Vars.RecorderTick++ } else { // This will get the dataframe corresponding to a given tick @@ -245,12 +334,12 @@ func (i *IBT) Update(timeout time.Duration) (IRacingState, error) { // Make this happen in a different thread, or have this send to a queue that has a thread // writing to a file - if i.IBTExport != nil { + if i.IBTExport != nil { err = i.exportIBT(buf, int64(start)) if err != nil { log.Printf("Failed to export offline telemetry data: %v", err) } - } + } if err == io.EOF { return Ended, nil