diff --git a/controllers/cache_controller.go b/controllers/cache_controller.go index f4e2c36..93894c5 100644 --- a/controllers/cache_controller.go +++ b/controllers/cache_controller.go @@ -112,7 +112,7 @@ func UpdateCacheAfterExpiry(key string) { } if player.Clan.KeepUpdated { - score, statusCode := GetPlayerScore(player.Name) + score, statusCode := GetPlayerScoreNew(player.Name) if score == score && score != -1 { // not NaN if err := models.PlayerCache.SetScore(player.ID, score); err != nil { utils.Logger.Warnf("[KeepUpdated] Failed to update cache for player %s! Error: %s", player.Name, err.Error()) diff --git a/controllers/tracker_controller.go b/controllers/tracker_controller.go index acbb16f..a9245b9 100644 --- a/controllers/tracker_controller.go +++ b/controllers/tracker_controller.go @@ -25,7 +25,7 @@ func GetScoreByPlayerID(c *gin.Context) { score, err := models.PlayerCache.GetScore(player.ID) var statusCode int = http.StatusOK if err != nil || score == -1 { - score, statusCode = GetPlayerScore(player.Name) + score, statusCode = GetPlayerScoreNew(player.Name) if score == score && score != -1 { // not NaN if err := models.PlayerCache.SetScore(player.ID, score); err != nil { utils.Logger.Errorf("[SCORE] Failed to cache player score: %s", err.Error()) @@ -50,7 +50,7 @@ func GetScoreByPlayerID(c *gin.Context) { // GetScoreByPlayerName POST /score/:player_name func GetScoreByPlayerName(c *gin.Context) { playerName := c.Param("player_name") - score, statusCode := GetPlayerScore(playerName) + score, statusCode := GetPlayerScoreNew(playerName) switch statusCode { case 200: @@ -73,7 +73,15 @@ func GetPlayerScore(playerName string) (float32, int) { return calcPlayerScore(playerData), statusCode } -func getPlayerData(playerName string) (*models.TrackerWeaponJSON, int) { +func GetPlayerScoreNew(playerName string) (float32, int) { + playerData, statusCode := getPlayerData(playerName) + if statusCode != 200 { + return -1, statusCode + } + return calcPlayerScoreNew(playerData), statusCode +} + +func getPlayerData(playerName string) (*models.TrackerDataJSON, int) { c := http.Client{} reqUri := "https://api.gametools.network/bf2042/stats/?raw=false&format_values=false&name=" + playerName + "&platform=pc" @@ -105,7 +113,7 @@ func getPlayerData(playerName string) (*models.TrackerWeaponJSON, int) { return nil, res.StatusCode } - var response models.TrackerWeaponJSON + var response models.TrackerDataJSON body, err := io.ReadAll(res.Body) if err != nil { utils.Logger.Errorf("[SCORE] Failed to read response body: %s", err.Error()) @@ -119,7 +127,26 @@ func getPlayerData(playerName string) (*models.TrackerWeaponJSON, int) { return &response, 200 } -func calcPlayerScore(playerData *models.TrackerWeaponJSON) float32 { +func calcPlayerScoreNew(playerData *models.TrackerDataJSON) float32 { + const KdFactor = 0.5 + const KpmFactor = 0.3 + const ObjectiveFactor = 0.15 + const SupportFactor = 0.05 + const NormalizeFactor = 1.3 + + cleanedKills := playerData.DivKills.ADS + playerData.DivKills.Hip - playerData.DivKills.AI + kd := float64(cleanedKills) / float64(playerData.Deaths) + kpm := float64(cleanedKills) / float64(playerData.SecondsPlayed/60.0) + objective := float64(playerData.XP[0].Ribbons.Objective) / float64(playerData.XP[0].Ribbons.Total) + support := float64(playerData.XP[0].Ribbons.Support+playerData.XP[0].Ribbons.Squad) / float64(playerData.XP[0].Ribbons.Total) + + score := (kd * KdFactor) + (kpm * KpmFactor) + (objective * ObjectiveFactor) + (support * SupportFactor) + score *= NormalizeFactor + + return float32(score) +} + +func calcPlayerScore(playerData *models.TrackerDataJSON) float32 { gameMetrics := GetGameMetric("BF2042") if gameMetrics == nil { utils.Logger.Errorf("[SCORE] No game metrics specified for '%s'", "BF2042") diff --git a/models/tracker_json.go b/models/tracker_json.go index 4e9ec9d..7325cf2 100644 --- a/models/tracker_json.go +++ b/models/tracker_json.go @@ -1,7 +1,28 @@ package models -type TrackerWeaponJSON struct { - Weapons []Weapon `json:"weapons"` +type TrackerDataJSON struct { + Weapons []Weapon `json:"weapons"` + DivKills DividedKills `json:"dividedKills"` + Deaths int `json:"deaths"` + SecondsPlayed int `json:"secondsPlayed"` + XP []XP `json:"XP"` +} + +type DividedKills struct { + ADS int `json:"ads"` + Hip int `json:"hip"` + AI int `json:"ai"` +} + +type XP struct { + Ribbons Ribbons `json:"ribbons"` +} + +type Ribbons struct { + Objective int `json:"objective"` + Squad int `json:"squad"` + Support int `json:"support"` + Total int `json:"total"` } type Weapon struct { diff --git a/templates/modals/full_calc.html b/templates/modals/full_calc.html index fd1820f..ae4df1b 100644 --- a/templates/modals/full_calc.html +++ b/templates/modals/full_calc.html @@ -23,20 +23,20 @@
- Avg - + +
- +
- Avg - + +
@@ -167,8 +167,14 @@ homeAvgScore.innerText = homeAvg.toFixed(2); if (!isNaN(oppAvg)) oppAvgScore.innerText = oppAvg.toFixed(2); - if (!isNaN(homeAvg) && !isNaN(oppAvg)) - diffScore.innerText = (homeAvg - oppAvg).toFixed(2); + if (!isNaN(homeAvg) && !isNaN(oppAvg)) { + const diff = (((homeAvg / oppAvg) - 1.0) * 100).toFixed(1); + if (diff > 0) + diffScore.classList.replace('text-warning', 'text-success'); + else if (diff < 0) + diffScore.classList.replace('text-warning', 'text-danger'); + diffScore.innerText = diff + "%"; + } calcMutex = false; }