Doesnt crash when there's no data to put in the relative
This commit is contained in:
+49
-31
@@ -46,49 +46,63 @@ func (e *ESDI) lapData() {
|
||||
lapLastLapTime := e.irsdk.Vars.Vars["LapLastLapTime"].Value
|
||||
lapDeltaToBestLap := e.irsdk.Vars.Vars["LapDeltaToBestLap"].Value
|
||||
|
||||
e.data.LapDeltaFloat = lapDeltaToBestLap.(float32)
|
||||
e.data.LapCount = int32(currentLap.(int))
|
||||
e.data.LapDistPct = float32(lapDistPct.(float32)) * 100
|
||||
copy(e.data.CurrLapTime[:], string(lapTimeRepresentation(currentLapTime.(float32))))
|
||||
copy(e.data.LastLapTime[:], string(lapTimeRepresentation(lapLastLapTime.(float32))))
|
||||
copy(e.data.BestLapTime[:], string(lapTimeRepresentation(lapBestLapTime.(float32))))
|
||||
copy(e.data.LapDelta[:], string(lapTimeDeltaRepresentation(lapDeltaToBestLap.(float32))))
|
||||
|
||||
// Don't create the strings here, should be creating them later one only
|
||||
copy(e.data.CurrLapTime[:], string(lapTimeRepresentation(currentLapTime.(float32),
|
||||
LapTimeFormatStr)))
|
||||
copy(e.data.LastLapTime[:], string(lapTimeRepresentation(lapLastLapTime.(float32),
|
||||
LapTimeFormatStr)))
|
||||
copy(e.data.BestLapTime[:], string(lapTimeRepresentation(lapBestLapTime.(float32),
|
||||
LapTimeFormatStr)))
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
// This function doesnt feel very pretty - NEED TO REFACTOR IT
|
||||
func (e *ESDI) positionData() {
|
||||
// Only create a table with more people if we have more players
|
||||
mu.Lock()
|
||||
standings := createStandingsTable(e.irsdk)
|
||||
relativeStandings(e.irsdk, standings, e.irsdk.SessionInfo.DriverInfo.DriverCarIdx)
|
||||
p := findEntry(standings, func(l StandingsLine) bool {
|
||||
return l.CarIdx == int32(e.irsdk.SessionInfo.DriverInfo.DriverCarIdx)
|
||||
})
|
||||
|
||||
lowerLim := p - 2
|
||||
upperLim := p + 3
|
||||
|
||||
var lowerPadding []StandingsLine
|
||||
var upperPadding []StandingsLine
|
||||
|
||||
if lowerLim < 0 {
|
||||
lowerPadding = make([]StandingsLine, abs(lowerLim))
|
||||
for k := 0; k < abs(lowerLim); k++ {
|
||||
lowerPadding[k] = paddingStandingsLine
|
||||
if len(standings) <= 0 {
|
||||
for range 5 {
|
||||
standings = append(standings, paddingStandingsLine)
|
||||
}
|
||||
lowerLim = 0
|
||||
}
|
||||
if upperLim >= len(standings) {
|
||||
upperPadding = make([]StandingsLine, upperLim-len(standings))
|
||||
for k := 0; k < upperLim-len(standings); k++ {
|
||||
upperPadding[k] = paddingStandingsLine
|
||||
}
|
||||
upperLim = len(standings)
|
||||
}
|
||||
} else {
|
||||
relativeStandings(e.irsdk, standings, e.irsdk.SessionInfo.DriverInfo.DriverCarIdx)
|
||||
p := findEntry(standings, func(l StandingsLine) bool {
|
||||
return l.CarIdx == int32(e.irsdk.SessionInfo.DriverInfo.DriverCarIdx)
|
||||
})
|
||||
|
||||
standings = append(lowerPadding, standings[lowerLim:upperLim]...)
|
||||
standings = append(standings, upperPadding...)
|
||||
lowerLim := p - 2
|
||||
upperLim := p + 3
|
||||
|
||||
var lowerPadding []StandingsLine
|
||||
var upperPadding []StandingsLine
|
||||
|
||||
if lowerLim < 0 {
|
||||
lowerPadding = make([]StandingsLine, abs(lowerLim))
|
||||
for k := range abs(lowerLim) {
|
||||
lowerPadding[k] = paddingStandingsLine
|
||||
}
|
||||
lowerLim = 0
|
||||
}
|
||||
if upperLim >= len(standings) {
|
||||
upperPadding = make([]StandingsLine, upperLim-len(standings))
|
||||
for k := range upperLim - len(standings) {
|
||||
upperPadding[k] = paddingStandingsLine
|
||||
}
|
||||
upperLim = len(standings)
|
||||
}
|
||||
|
||||
standings = append(lowerPadding, standings[lowerLim:upperLim]...)
|
||||
standings = append(standings, upperPadding...)
|
||||
|
||||
e.data.Position = int32(p)
|
||||
}
|
||||
|
||||
copy(e.data.Standings[:], standings[0:5])
|
||||
e.data.Position = int32(p)
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
@@ -140,6 +154,10 @@ func readData(e *ESDI, done <-chan string) {
|
||||
e.dataPacket.Standings = packageStandingsLineDataPacket(e.data.Standings)
|
||||
|
||||
copyBytes(e.dataPacket.LapNumber[:], LapNumberLen, fmt.Sprintf("%-3d", e.data.LapCount))
|
||||
copyBytes(e.dataPacket.DeltaToBestLap[:], DeltaToBestLapLen,
|
||||
fmt.Sprintf("%s", lapTimeDeltaRepresentation(e.data.LapDeltaFloat)))
|
||||
copyBytes(e.dataPacket.BestLapTime[:], BestLapTimeLen,
|
||||
fmt.Sprintf("%s", e.data.BestLapTime[:8]))
|
||||
copyBytes(e.dataPacket.CurrLapTime[:], CurrLapTimeLen,
|
||||
fmt.Sprintf("%s", e.data.CurrLapTime[:8]))
|
||||
copyBytes(e.dataPacket.LastLapTime[:], LastLapTimeLen,
|
||||
|
||||
+37
-21
@@ -35,11 +35,16 @@ var (
|
||||
mu sync.Mutex
|
||||
)
|
||||
|
||||
const (
|
||||
LapTimeFormatStr = "04:05.000"
|
||||
RelativeDeltaFormatStr = "04:05.0"
|
||||
)
|
||||
|
||||
func msToKph(v float32) int {
|
||||
return int((3600 * v) / 1000)
|
||||
}
|
||||
|
||||
func lapTimeRepresentation(t float32) string {
|
||||
func lapTimeRepresentation(t float32, f string) string {
|
||||
if t < 0 {
|
||||
t = 0
|
||||
}
|
||||
@@ -47,23 +52,34 @@ func lapTimeRepresentation(t float32) string {
|
||||
wholeSeconds := int64(t)
|
||||
lapTime := time.Unix(wholeSeconds, int64((t-float32(wholeSeconds))*1e9))
|
||||
|
||||
return lapTime.Format("04:05.000")
|
||||
return lapTime.Format(f)
|
||||
}
|
||||
|
||||
func lapTimeDeltaRepresentation(t float32) string {
|
||||
sign := '-'
|
||||
if t < 0 {
|
||||
sign = '+'
|
||||
t = -1 * t
|
||||
t = -t
|
||||
}
|
||||
|
||||
// Cap to 99.9 max
|
||||
if t > 99.9 {
|
||||
t = 99.9
|
||||
}
|
||||
|
||||
if t >= 1 {
|
||||
wholeSeconds := int64(t)
|
||||
lapTime := time.Unix(wholeSeconds, int64((t-float32(wholeSeconds))*1e9))
|
||||
return fmt.Sprintf("%c%s", sign, lapTime.Format("5.00"))
|
||||
// Round to nearest tenth
|
||||
rounded := float32(int(t*10+0.5)) / 10
|
||||
return fmt.Sprintf("%c%.1f", sign, rounded)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%c.%02d", sign, int64(t*100))
|
||||
// t < 1: round to nearest tenth and remove leading zero (e.g., "0.1" → ".1")
|
||||
rounded := float32(int(t*10+0.5)) / 10
|
||||
s := fmt.Sprintf("%.1f", rounded)
|
||||
if strings.HasPrefix(s, "0") {
|
||||
s = s[1:]
|
||||
}
|
||||
return fmt.Sprintf("%c%s", sign, s)
|
||||
}
|
||||
|
||||
func resetTerminal() {
|
||||
@@ -133,16 +149,14 @@ func printData(e *ESDI, done <-chan string) {
|
||||
e.dataPacket.Gear, e.dataPacket.RPM, e.dataPacket.Speed))
|
||||
|
||||
buffer.WriteString("Fuel data:\n")
|
||||
// buffer.WriteString(fmt.Sprintf("Fuel Tank: %s\n", e.dataPacket.FuelTank))
|
||||
// buffer.WriteString(fmt.Sprintf("Fuel Est: %s\n", e.dataPacket.FuelEst))
|
||||
buffer.WriteString(fmt.Sprintf("Fuel Est: %s\n", e.dataPacket.FuelEst))
|
||||
|
||||
buffer.WriteString("Lap data:\n")
|
||||
// buffer.WriteString(fmt.Sprintf("LapTime: %s [%s]\n", e.dataPacket.CurrLapTime,
|
||||
// e.dataPacket.LapDelta))
|
||||
// buffer.WriteString(fmt.Sprintf("Best Lap Time: %s\n", e.dataPacket.BestLapTime))
|
||||
// buffer.WriteString(fmt.Sprintf("Last Lap Time: %s\n", e.dataPacket.LastLapTime))
|
||||
// buffer.WriteString(fmt.Sprintf("Lap: %d [%.2f%%]\n\n", e.dataPacket.LapCount,
|
||||
// e.data.LapDistPct))
|
||||
buffer.WriteString(fmt.Sprintf("Delta: [%s] [%f] [%s]\n", e.dataPacket.DeltaToBestLap,
|
||||
e.data.LapDeltaFloat, lapTimeDeltaRepresentation(e.data.LapDeltaFloat)))
|
||||
buffer.WriteString(fmt.Sprintf("LapTime: %s\n", e.dataPacket.CurrLapTime))
|
||||
buffer.WriteString(fmt.Sprintf("Best Lap Time: %s\n", e.dataPacket.BestLapTime))
|
||||
buffer.WriteString(fmt.Sprintf("Last Lap Time: %s\n", e.dataPacket.LastLapTime))
|
||||
|
||||
// buffer.WriteString("Position data:\n")
|
||||
// buffer.WriteString(fmt.Sprintf("Pos: %d\n", e.dataPacket.Position))
|
||||
@@ -153,7 +167,7 @@ func printData(e *ESDI, done <-chan string) {
|
||||
buffer.WriteString(s)
|
||||
}
|
||||
|
||||
buffer.WriteString(fmt.Sprintf("Size: %v\n", binary.Size(DataPacket{})))
|
||||
buffer.WriteString(fmt.Sprintf("Size: %v\n", binary.Size(DataPacket{})))
|
||||
buffer.WriteString(fmt.Sprintf("Recv: %d\n", e.data.Recv))
|
||||
buffer.WriteString(fmt.Sprintf("Recv Err: %v\n", e.data.ReadError))
|
||||
|
||||
@@ -174,9 +188,11 @@ func (e *ESDI) telemetry() {
|
||||
done := e.setupSignalHandlers()
|
||||
dataError := make(chan string)
|
||||
|
||||
// go sendData(e, e.SerialConn, done, dataError)
|
||||
// Display the data on the terminal periodically
|
||||
go printData(e, done)
|
||||
|
||||
// Maybe create a struct made to calculate the fuel levels
|
||||
// -> struct FuelLvlCalculator
|
||||
fuelLevels = make(map[int]float32, 256)
|
||||
|
||||
// We need to add another goroutine here that continuously updates
|
||||
@@ -208,15 +224,15 @@ func (e *ESDI) telemetry() {
|
||||
// Wait for the display to request some data
|
||||
var r DataReq
|
||||
err := binary.Read(e.SerialConn, binary.LittleEndian, &r)
|
||||
e.data.ReadError = err
|
||||
e.data.ReadError = err
|
||||
if err != nil && err != io.EOF {
|
||||
log.Println(err)
|
||||
fmt.Println("->", r)
|
||||
fmt.Println("->", r)
|
||||
}
|
||||
e.data.Recv = r.Req
|
||||
|
||||
if r.Req == 5 {
|
||||
e.SerialConn.Flush()
|
||||
e.SerialConn.Flush()
|
||||
currTime := time.Now()
|
||||
if nRequests != 0 {
|
||||
total += currTime.Sub(previousRequest)
|
||||
@@ -232,7 +248,7 @@ func (e *ESDI) telemetry() {
|
||||
log.Printf("Unable to write data: %v", err)
|
||||
break
|
||||
}
|
||||
e.SerialConn.Flush()
|
||||
e.SerialConn.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+65
-37
@@ -1,61 +1,89 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLapTimeDeltaRepresentationPositiveLT1(t *testing.T) {
|
||||
// Arrange
|
||||
var time float32 = 0.123
|
||||
expect := "-.12"
|
||||
// Arrange
|
||||
var time float32 = 0.123
|
||||
expect := "-.1"
|
||||
|
||||
// Act
|
||||
res := lapTimeDeltaRepresentation(time)
|
||||
// Act
|
||||
res := lapTimeDeltaRepresentation(time)
|
||||
|
||||
// Test
|
||||
if res != expect {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expect, res)
|
||||
}
|
||||
// Test
|
||||
if res != expect {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expect, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLapTimeDeltaRepresentationPositiveGE1(t *testing.T) {
|
||||
// Arrange
|
||||
var time float32 = 1.123
|
||||
expect := "-1.12"
|
||||
// Arrange
|
||||
var time float32 = 1.123
|
||||
expect := "-1.1"
|
||||
|
||||
// Act
|
||||
res := lapTimeDeltaRepresentation(time)
|
||||
// Act
|
||||
res := lapTimeDeltaRepresentation(time)
|
||||
|
||||
// Test
|
||||
if res != expect {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expect, res)
|
||||
}
|
||||
// Test
|
||||
if res != expect {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expect, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLapTimeDeltaRepresentationNegativeLT1(t *testing.T) {
|
||||
// Arrange
|
||||
var time float32 = -0.123
|
||||
expect := "+.12"
|
||||
// Arrange
|
||||
var time float32 = -0.123
|
||||
expect := "+.1"
|
||||
|
||||
// Act
|
||||
res := lapTimeDeltaRepresentation(time)
|
||||
// Act
|
||||
res := lapTimeDeltaRepresentation(time)
|
||||
|
||||
// Test
|
||||
if res != expect {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expect, res)
|
||||
}
|
||||
// Test
|
||||
if res != expect {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expect, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLapTimeDeltaRepresentationNegativeGE1(t *testing.T) {
|
||||
// Arrange
|
||||
var time float32 = -1.123
|
||||
expect := "+1.12"
|
||||
// Arrange
|
||||
var time float32 = -1.123
|
||||
expect := "+1.1"
|
||||
|
||||
// Act
|
||||
res := lapTimeDeltaRepresentation(time)
|
||||
// Act
|
||||
res := lapTimeDeltaRepresentation(time)
|
||||
|
||||
// Test
|
||||
if res != expect {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expect, res)
|
||||
}
|
||||
// Test
|
||||
if res != expect {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expect, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLapTimeDeltaRepresentationGreaterThan100(t *testing.T) {
|
||||
// Arrange
|
||||
var time float32 = -102.123
|
||||
expect := "+99.9"
|
||||
|
||||
// Act
|
||||
res := lapTimeDeltaRepresentation(time)
|
||||
|
||||
// Test
|
||||
if res != expect {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expect, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLapTimeDeltaRepresentationGreaterNew(t *testing.T) {
|
||||
// Arrange
|
||||
var time float32 = -0.012
|
||||
expect := "+.0"
|
||||
|
||||
// Act
|
||||
res := lapTimeDeltaRepresentation(time)
|
||||
|
||||
// Test
|
||||
if res != expect {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expect, res)
|
||||
}
|
||||
}
|
||||
|
||||
+10
-16
@@ -43,7 +43,8 @@ func generalStandings(i *goirsdk.IBT, s []StandingsLine, id int) {
|
||||
}
|
||||
|
||||
s[p].TimeBehind = theThing
|
||||
copy(s[p].TimeBehindString[:], string(lapTimeRepresentation(theThing)))
|
||||
copy(s[p].TimeBehindString[:], string(lapTimeRepresentation(theThing,
|
||||
RelativeDeltaFormatStr)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,27 +67,23 @@ func relativeStandings(i *goirsdk.IBT, s []StandingsLine, id int) {
|
||||
delta = abs(estTime[id] - curCarEstimate)
|
||||
|
||||
s[p].TimeBehind = delta
|
||||
copy(s[p].TimeBehindString[:], string(lapTimeRepresentation(delta)))
|
||||
copy(s[p].TimeBehindString[:], string(lapTimeRepresentation(delta,
|
||||
RelativeDeltaFormatStr)))
|
||||
}
|
||||
}
|
||||
|
||||
func bestLapTime(i *goirsdk.IBT, id int) float32 {
|
||||
best := i.Vars.Vars["LapBestLapTime"].Value.(float32)
|
||||
|
||||
if best > 0 {
|
||||
return best
|
||||
}
|
||||
|
||||
return float32(i.SessionInfo.DriverInfo.Drivers[id].CarClassEstLapTime)
|
||||
}
|
||||
|
||||
// createStandingsTable will create a table with the standings data
|
||||
// still working on this
|
||||
// If the filter applied is generalStandings, the carId has to be 0
|
||||
// We can do some dynamicProgramming on this thing I guess, I still haven't
|
||||
// though about it much yet tbh
|
||||
func createStandingsTable(i *goirsdk.IBT) []StandingsLine {
|
||||
driversLapDistPct := i.Vars.Vars["CarIdxLapDistPct"].Value.([]float32)
|
||||
driversLapDistPctRaw := i.Vars.Vars["CarIdxLapDistPct"].Value
|
||||
if driversLapDistPctRaw == nil {
|
||||
return []StandingsLine{}
|
||||
}
|
||||
|
||||
driversLapDistPct := driversLapDistPctRaw.([]float32)
|
||||
driversEstTime := i.Vars.Vars["CarIdxEstTime"].Value.([]float32)
|
||||
driversLap := i.Vars.Vars["CarIdxLap"].Value.([]int32)
|
||||
drivers := i.SessionInfo.DriverInfo.Drivers
|
||||
@@ -122,6 +119,3 @@ func abs[V int32 | float32 | int](value V) V {
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func getPlayerPosition(s []StandingsLine, p int) {
|
||||
}
|
||||
|
||||
@@ -2,21 +2,23 @@ package main
|
||||
|
||||
// DataPacket Lens
|
||||
const (
|
||||
SpeedLen = 5
|
||||
GearLen = 3
|
||||
RpmLen = 6
|
||||
LapNumberLen = 5
|
||||
CurrLapTimeLen = 10
|
||||
LastLapTimeLen = 10
|
||||
FuelTankLen = 15 // 101.6 / 123.4L
|
||||
FuelEstLen = 15
|
||||
SpeedLen = 5
|
||||
GearLen = 3
|
||||
RpmLen = 6
|
||||
LapNumberLen = 5
|
||||
DeltaToBestLapLen = 6
|
||||
BestLapTimeLen = 10
|
||||
CurrLapTimeLen = 10
|
||||
LastLapTimeLen = 10
|
||||
FuelTankLen = 15 // 101.6 / 123.4L
|
||||
FuelEstLen = 15
|
||||
)
|
||||
|
||||
// StandingsLineDataPacket Lens
|
||||
const (
|
||||
LapStringLen = 4
|
||||
DriverNameLen = 24
|
||||
TimeBehindStringLen = 16
|
||||
TimeBehindStringLen = 8
|
||||
)
|
||||
|
||||
type GameSource interface {
|
||||
@@ -44,7 +46,7 @@ type SimulationData struct {
|
||||
LapCount int32
|
||||
LapDistPct float32
|
||||
CurrLapTime [16]byte // Current lap time
|
||||
LapDelta [16]byte // Delta to selected reference lap
|
||||
LapDeltaFloat float32
|
||||
BestLapTime [16]byte // Best lap in session
|
||||
LastLapTime [16]byte // Last lap time
|
||||
FuelUsageCurLap float32
|
||||
@@ -63,14 +65,16 @@ type StandingsLineDataPacket struct {
|
||||
}
|
||||
|
||||
type DataPacket struct {
|
||||
StartMarker uint8 `binary:"little"`
|
||||
Speed [SpeedLen]byte `binary:"little"`
|
||||
Gear [GearLen]byte `binary:"little"`
|
||||
RPM [RpmLen]byte `binary:"little"`
|
||||
LapNumber [LapNumberLen]byte `binary:"little"`
|
||||
CurrLapTime [CurrLapTimeLen]byte `binary:"little"` // Current lap time
|
||||
LastLapTime [LastLapTimeLen]byte `binary:"little"` // Last lap time
|
||||
FuelEst [FuelEstLen]byte `binary:"little"`
|
||||
Standings [5]StandingsLineDataPacket `binary:"little"`
|
||||
EndMarker uint8 `binary:"little"`
|
||||
StartMarker uint8 `binary:"little"`
|
||||
Speed [SpeedLen]byte `binary:"little"`
|
||||
Gear [GearLen]byte `binary:"little"`
|
||||
RPM [RpmLen]byte `binary:"little"`
|
||||
LapNumber [LapNumberLen]byte `binary:"little"`
|
||||
DeltaToBestLap [DeltaToBestLapLen]byte `binary:"little"`
|
||||
BestLapTime [BestLapTimeLen]byte `binary:"little"`
|
||||
CurrLapTime [CurrLapTimeLen]byte `binary:"little"`
|
||||
LastLapTime [LastLapTimeLen]byte `binary:"little"`
|
||||
FuelEst [FuelEstLen]byte `binary:"little"`
|
||||
Standings [5]StandingsLineDataPacket `binary:"little"`
|
||||
EndMarker uint8 `binary:"little"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user