diff --git a/src/de/steamwar/bungeecore/network/BungeeNetworkHandler.java b/src/de/steamwar/bungeecore/network/BungeeNetworkHandler.java index 1cc4854..220220b 100644 --- a/src/de/steamwar/bungeecore/network/BungeeNetworkHandler.java +++ b/src/de/steamwar/bungeecore/network/BungeeNetworkHandler.java @@ -25,8 +25,9 @@ import lombok.experimental.UtilityClass; @UtilityClass public class BungeeNetworkHandler { public static void register() { + new EloPlayerHandler().register(); + new EloSchemHandler().register(); new ExecuteCommandHandler().register(); - new FightEndsHandler().register(); new FightInfoHandler().register(); new ImALobbyHandler().register(); new InventoryCallbackHandler().register(); diff --git a/src/de/steamwar/bungeecore/network/handlers/FightEndsHandler.java b/src/de/steamwar/bungeecore/network/handlers/EloPlayerHandler.java similarity index 66% rename from src/de/steamwar/bungeecore/network/handlers/FightEndsHandler.java rename to src/de/steamwar/bungeecore/network/handlers/EloPlayerHandler.java index 959a66a..135a1bb 100644 --- a/src/de/steamwar/bungeecore/network/handlers/FightEndsHandler.java +++ b/src/de/steamwar/bungeecore/network/handlers/EloPlayerHandler.java @@ -38,7 +38,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.IntFunction; import java.util.stream.Collectors; -public class FightEndsHandler extends PacketHandler { +public class EloPlayerHandler extends PacketHandler { private static final int MEDIAN_ELO_GAIN = 20; private static final double WIN_FACTOR = 1.0; @@ -47,8 +47,6 @@ public class FightEndsHandler extends PacketHandler { private static final double DRAW_LOSE_FACTOR = -0.2; private static final long REMATCH_LIFETIME = 1L * 60 * 60 * 1000; - private int K = 20; - private Map> gameModeGames = new HashMap<>(); @Handler @@ -56,7 +54,6 @@ public class FightEndsHandler extends PacketHandler { if (!ArenaMode.getBySchemType(SchematicType.fromDB(fightEndsPacket.getGameMode())).isRanked()) { return; } - // BungeeCore.get().getLogger().log(Level.INFO, fightEndsPacket.getWin() + " " + fightEndsPacket.getBlueSchem() + " " + fightEndsPacket.getRedSchem() + " " + fightEndsPacket.getBluePlayers() + " " + fightEndsPacket.getRedPlayers() + " " + fightEndsPacket.getGameMode() + " " + fightEndsPacket.getDuration()); boolean bluePublic = SchematicNode.getSchematicNode(fightEndsPacket.getBlueSchem()).getOwner() == 0; boolean redPublic = SchematicNode.getSchematicNode(fightEndsPacket.getRedSchem()).getOwner() == 0; @@ -65,8 +62,6 @@ public class FightEndsHandler extends PacketHandler { return; } - // BungeeCore.get().getLogger().log(Level.INFO, "After schematic public check"); - // Die nächsten Zeilen filtern ein Fight innerhalb eines Teams nicht gewertet wird, bzw auch wenn nur Teile beider Teams im // gleichen Team sind dieser ungewertet ist. Set teamsIds = fightEndsPacket.getBluePlayers().stream().map(SteamwarUser::get).map(SteamwarUser::getTeam).collect(Collectors.toSet()); @@ -76,50 +71,68 @@ public class FightEndsHandler extends PacketHandler { } } - // BungeeCore.get().getLogger().log(Level.INFO, "After Team check"); - - calcSchemElo(fightEndsPacket); - calcUserElo(fightEndsPacket); - } - - private void calcUserElo(FightEndsPacket fightEndsPacket) { + // Get sizes of both teams int blueTeamSize = fightEndsPacket.getBluePlayers().size(); int redTeamSize = fightEndsPacket.getRedPlayers().size(); + // Calculate the favored team + double bluePlayerFactor = 1 / (1 + Math.exp(-(fightEndsPacket.getWin() == 2 ? (double) redTeamSize / blueTeamSize : (double) blueTeamSize / redTeamSize) * 3 + 3)) * 2; + double redPlayerFactor = 1 / (1 + Math.exp(-(fightEndsPacket.getWin() == 1 ? (double) blueTeamSize / redTeamSize : (double) redTeamSize / blueTeamSize) * 3 + 3)) * 2; + + // Calculate the time factor + double timeFactor = getTimeFactor(fightEndsPacket.getDuration()); + + // Get total elo of both teams int blueTeamElo = fightEndsPacket.getBluePlayers().stream().mapToInt(player -> UserElo.getEloOrDefault(player, fightEndsPacket.getGameMode())).sum(); int redTeamElo = fightEndsPacket.getRedPlayers().stream().mapToInt(player -> UserElo.getEloOrDefault(player, fightEndsPacket.getGameMode())).sum(); - double blueFactor = getBluePlayerFactor(blueTeamSize, redTeamSize) * getTimeFactor(fightEndsPacket.getDuration()) * getBlueEloFactor(blueTeamElo, redTeamElo) * getRematchFactor(fightEndsPacket); - double redFactor = getRedPlayerFactor(blueTeamSize, redTeamSize) * getTimeFactor(fightEndsPacket.getDuration()) * getRedEloFactor(blueTeamElo, redTeamElo) * getRematchFactor(fightEndsPacket); + // Calculate the elo factor + double blueEloFactor = ((fightEndsPacket.getWin() == 1 ? 1 : 0) - 1 / (1 + Math.pow(10, (redTeamElo - blueTeamElo) / 600.0))) * (1 / (1 + Math.exp(-Math.abs(blueTeamElo - redTeamElo) / 1200))) * 4; + double redEloFactor = blueEloFactor * -1; - if (fightEndsPacket.getWin() == 1) { - blueFactor *= WIN_FACTOR; - redFactor *= LOSE_FACTOR; - } else if (fightEndsPacket.getWin() == 2) { - blueFactor *= LOSE_FACTOR; - redFactor *= WIN_FACTOR; - } else { - if (redFactor == blueFactor) { - blueFactor *= 0; - redFactor *= 0; - } else if (blueFactor > redFactor) { - blueFactor *= DRAW_WIN_FACTOR; - redFactor *= DRAW_LOSE_FACTOR; + // Calculate favoured team on draw + if (fightEndsPacket.getWin() == 0) { + if (bluePlayerFactor > 1) { + blueEloFactor = Math.abs(blueEloFactor) * -1; + redEloFactor = Math.abs(redEloFactor); + } else if (bluePlayerFactor < 1) { + blueEloFactor = Math.abs(blueEloFactor); + redEloFactor = Math.abs(redEloFactor) * -1; } else { - blueFactor *= DRAW_LOSE_FACTOR; - redFactor *= DRAW_WIN_FACTOR; + if (Math.abs(blueEloFactor) > 1) { + // Do nothing + } else if (Math.abs(blueEloFactor) < 1) { + blueEloFactor = ((fightEndsPacket.getWin() == 1 ? 1 : 0) - 1 / (1 + Math.pow(10, (blueTeamElo - redTeamElo) / 600.0))) * (1 / (1 + Math.exp(-Math.abs(redTeamElo - blueTeamElo) / 1200))) * -4; + redEloFactor = blueEloFactor * -1; + } else { + blueEloFactor = 0; + redEloFactor = 0; + } } } - update(fightEndsPacket.getBluePlayers(), fightEndsPacket.getGameMode(), blueFactor); - update(fightEndsPacket.getRedPlayers(), fightEndsPacket.getGameMode(), redFactor); + // Calculate the rematch factor + double rematchFactor = getRematchFactor(fightEndsPacket); + + // Calculate the win factor + double blueWinFactor = (fightEndsPacket.getWin() == 1 ? 1 : 0.9); + double redWinFactor = (fightEndsPacket.getWin() == 2 ? 1 : 0.9); + + // Calculate division factor + double divisionFactor = 1/(fightEndsPacket.getWin() == 1 ? Math.max(blueTeamSize, redTeamSize) : Math.min(blueTeamSize, redTeamSize)); + + // Calculate the elo gain for each player + int blueEloGain = (int) Math.round(MEDIAN_ELO_GAIN * bluePlayerFactor * timeFactor * blueEloFactor * rematchFactor * blueWinFactor * divisionFactor); + int redEloGain = (int) Math.round(MEDIAN_ELO_GAIN * redPlayerFactor * timeFactor * redEloFactor * rematchFactor * redWinFactor * divisionFactor); + + update(fightEndsPacket.getBluePlayers(), fightEndsPacket.getGameMode(), blueEloGain); + update(fightEndsPacket.getBluePlayers(), fightEndsPacket.getGameMode(), redEloGain); } - private void update(List players, String gameMode, double factor) { + private void update(List players, String gameMode, int eloGain) { for (int player : players) { // BungeeCore.get().getLogger().log(Level.INFO, "Player: " + player + " Elo: " + UserElo.getEloOrDefault(player, gameMode) + " Factor: " + factor); int playerElo = UserElo.getEloOrDefault(player, gameMode); - int eloGain = (int) Math.round(MEDIAN_ELO_GAIN * factor); playerElo += eloGain; if (playerElo < 0) playerElo = 0; @@ -154,11 +167,7 @@ public class FightEndsHandler extends PacketHandler { scheduler.schedule(BungeeCore.get(), () -> { if (player == null) return; if (!player.isConnected()) return; - Title title = new BungeeTitle().title(TextComponent.fromLegacyText(getRankup.apply(finalI))) - .subTitle(eloGainComponent) - .fadeIn(finalI == 0 ? 5 : 0) - .stay(40) - .fadeOut(finalI == 39 ? 5 : 0); + Title title = new BungeeTitle().title(TextComponent.fromLegacyText(getRankup.apply(finalI))).subTitle(eloGainComponent).fadeIn(finalI == 0 ? 5 : 0).stay(40).fadeOut(finalI == 39 ? 5 : 0); title.send(player); }, i * 50L, TimeUnit.MILLISECONDS); } @@ -168,39 +177,6 @@ public class FightEndsHandler extends PacketHandler { return ProxyServer.getInstance().getPlayer(SteamwarUser.get(userId).getUUID()); } - private void calcSchemElo(FightEndsPacket fightEndsPacket) { - double blueResult; - if (fightEndsPacket.getWin() == 0) { - blueResult = 0.5; - } else if (fightEndsPacket.getWin() == 1) { - blueResult = 1; - } else { - blueResult = 0; - } - - int blueSchemElo = SchemElo.getCurrentElo(fightEndsPacket.getBlueSchem()); - int redSchemElo = SchemElo.getCurrentElo(fightEndsPacket.getRedSchem()); - calcSchemElo(fightEndsPacket.getBlueSchem(), blueSchemElo, redSchemElo, blueResult); - calcSchemElo(fightEndsPacket.getRedSchem(), redSchemElo, blueSchemElo, 1 - blueResult); - } - - private void calcSchemElo(int eloSchemOwn, int eloSchemEnemy, int schemId, double result) { - double winSchemExpectation = calcWinExpectation(eloSchemOwn, eloSchemEnemy); - SchemElo.setElo(schemId, (int) Math.round(eloSchemOwn + K * (result - winSchemExpectation))); - } - - private double calcWinExpectation(int eloOwn, int eloEnemy) { - return 1 / (1 + Math.pow(10, (eloEnemy - eloOwn) / 600f)); - } - - private double getBluePlayerFactor(int blueTeam, int redTeam) { - return 2 - calcWinExpectation(blueTeam, redTeam) * 2; - } - - private double getRedPlayerFactor(int blueTeam, int redTeam) { - return 2 - calcWinExpectation(redTeam, blueTeam) * 2; - } - private double getTimeFactor(int duration) { if (duration <= 10) { return 0.5; @@ -211,14 +187,6 @@ public class FightEndsHandler extends PacketHandler { return 1.0; } - private double getBlueEloFactor(int blueElo, int redElo) { - return 2 - calcWinExpectation(blueElo, redElo) * 2; - } - - private double getRedEloFactor(int blueElo, int redElo) { - return 2 - calcWinExpectation(redElo, blueElo) * 2; - } - private double getRematchFactor(FightEndsPacket fightEndsPacket) { gameModeGames.computeIfAbsent(fightEndsPacket.getGameMode(), s -> new LinkedList<>()).add(new Game(fightEndsPacket.getBluePlayers(), fightEndsPacket.getRedPlayers())); diff --git a/src/de/steamwar/bungeecore/network/handlers/EloSchemHandler.java b/src/de/steamwar/bungeecore/network/handlers/EloSchemHandler.java new file mode 100644 index 0000000..84d56af --- /dev/null +++ b/src/de/steamwar/bungeecore/network/handlers/EloSchemHandler.java @@ -0,0 +1,73 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.network.handlers; + +import de.steamwar.bungeecore.ArenaMode; +import de.steamwar.network.packets.PacketHandler; +import de.steamwar.network.packets.common.FightEndsPacket; +import de.steamwar.sql.SchemElo; +import de.steamwar.sql.SchematicNode; +import de.steamwar.sql.SchematicType; + +public class EloSchemHandler extends PacketHandler { + + private final int K = 20; + + @Handler + public void handle(FightEndsPacket fightEndsPacket) { + if (!ArenaMode.getBySchemType(SchematicType.fromDB(fightEndsPacket.getGameMode())).isRanked()) { + return; + } + + boolean bluePublic = SchematicNode.getSchematicNode(fightEndsPacket.getBlueSchem()).getOwner() == 0; + boolean redPublic = SchematicNode.getSchematicNode(fightEndsPacket.getRedSchem()).getOwner() == 0; + + if (bluePublic ^ redPublic) { + return; + } + + calcSchemElo(fightEndsPacket); + } + + private void calcSchemElo(FightEndsPacket fightEndsPacket) { + double blueResult; + if (fightEndsPacket.getWin() == 0) { + blueResult = 0.5; + } else if (fightEndsPacket.getWin() == 1) { + blueResult = 1; + } else { + blueResult = 0; + } + + int blueSchemElo = SchemElo.getCurrentElo(fightEndsPacket.getBlueSchem()); + int redSchemElo = SchemElo.getCurrentElo(fightEndsPacket.getRedSchem()); + calcSchemElo(fightEndsPacket.getBlueSchem(), blueSchemElo, redSchemElo, blueResult); + calcSchemElo(fightEndsPacket.getRedSchem(), redSchemElo, blueSchemElo, 1 - blueResult); + } + + private void calcSchemElo(int eloSchemOwn, int eloSchemEnemy, int schemId, double result) { + double winSchemExpectation = calcWinExpectation(eloSchemOwn, eloSchemEnemy); + SchemElo.setElo(schemId, (int) Math.round(eloSchemOwn + K * (result - winSchemExpectation))); + } + + private double calcWinExpectation(int eloOwn, int eloEnemy) { + return 1 / (1 + Math.pow(10, (eloEnemy - eloOwn) / 600f)); + } +}