diff --git a/src/de/steamwar/bungeecore/comms/handlers/FightEndsHandler.java b/src/de/steamwar/bungeecore/comms/handlers/FightEndsHandler.java index 0dda622d..b9a7492c 100644 --- a/src/de/steamwar/bungeecore/comms/handlers/FightEndsHandler.java +++ b/src/de/steamwar/bungeecore/comms/handlers/FightEndsHandler.java @@ -23,18 +23,29 @@ import com.google.common.io.ByteArrayDataInput; import de.steamwar.bungeecore.ArenaMode; import de.steamwar.bungeecore.comms.SpigotHandler; import de.steamwar.bungeecore.comms.packets.FightEndsPacket; -import de.steamwar.bungeecore.sql.SchemElo; -import de.steamwar.bungeecore.sql.SchematicNode; -import de.steamwar.bungeecore.sql.SchematicType; -import de.steamwar.bungeecore.sql.UserElo; +import de.steamwar.bungeecore.sql.*; +import lombok.RequiredArgsConstructor; import net.md_5.bungee.api.config.ServerInfo; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; public class FightEndsHandler implements SpigotHandler { + private Map> gameModeGames = new HashMap<>(); + private int K = 20; + private long defaultFightRange = 1000 /* Milliseconds */ * 60 /* Seconds */ * 15L /* Minutes */; + private Map fightRanges = new HashMap<>(); + private long defaultFightCount = 1; + private Map fightCounts = new HashMap<>(); + + { + fightRanges.put("miniwargear", 1000 /* Milliseconds */ * 60 /* Seconds */ * 30L /* Minutes */); + fightCounts.put("miniwargear", 3L); + } + @Override public void handle(ByteArrayDataInput in, ServerInfo info) { FightEndsPacket fightEndsPacket = new FightEndsPacket(in); @@ -66,6 +77,23 @@ public class FightEndsHandler implements SpigotHandler { blueResult = 0; } + // 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()); + for (int redPlayer : fightEndsPacket.getRedPlayers()) { + if (teamsIds.contains(SteamwarUser.get(redPlayer).getTeam())) { + return; + } + } + + try { + if (teamComboExistedAlready(fightEndsPacket.getBluePlayers(), fightEndsPacket.getRedPlayers(), fightEndsPacket.getGameMode())) { + return; + } + } finally { + gameModeGames.computeIfAbsent(fightEndsPacket.getGameMode(), s -> new LinkedList<>()).add(new Game(fightEndsPacket.getBluePlayers(), fightEndsPacket.getRedPlayers())); + } + int blueSchemElo = SchemElo.getElo(fightEndsPacket.getBlueSchem()); int redSchemElo = SchemElo.getElo(fightEndsPacket.getRedSchem()); @@ -77,14 +105,55 @@ public class FightEndsHandler implements SpigotHandler { } private void calculateEloOfTeam(int schemId, int eloSchemOwn, int eloSchemEnemy, int eloTeamOwn, int eloTeamEnemy, double result, List players, String gameMode, boolean noPlayerRank) { - double winSchemExpectation = 1 / (1 + Math.pow(10, (eloSchemEnemy - eloSchemOwn) / 600f)); + double winSchemExpectation = calsWinExpectation(eloSchemOwn, eloSchemEnemy); SchemElo.setElo(schemId, (int) Math.round(eloSchemOwn + K * (result - winSchemExpectation))); if (noPlayerRank) return; - double winTeamExpectation = 1 / (1 + Math.pow(10, (eloTeamEnemy - eloTeamOwn) / 600f)); + double winTeamExpectation = calsWinExpectation(eloTeamOwn, eloTeamEnemy); for (int player : players) { int playerElo = UserElo.getEloOrDefault(player, gameMode); - UserElo.setElo(player, gameMode, (int) Math.round(playerElo + K * (result - winTeamExpectation))); + int fights = UserElo.getFightsOfSeason(player, gameMode); + UserElo.setElo(player, gameMode, (int) Math.round(playerElo + getK(fights) * (result - winTeamExpectation))); + } + } + + private double calsWinExpectation(int eloOwn, int eloEnemy) { + return 1 / (1 + Math.pow(10, (eloEnemy - eloOwn) / 600f)); + } + + private double getK(int fights) { + return K * Math.max(1.3 - (fights / 200.0), 0.8); + } + + private boolean teamComboExistedAlready(List bluePlayers, List redPlayers, String gameMode) { + if (!gameModeGames.containsKey(gameMode)) { + return false; + } + LinkedList games = gameModeGames.get(gameMode); + long lifetime = fightRanges.getOrDefault(gameMode, defaultFightRange); + while (!games.isEmpty()) { + Game game = games.getFirst(); + if (game.livedMillis() > lifetime) { + games.removeFirst(); + } else { + break; + } + } + return games.stream().filter(game -> game.isSame(bluePlayers, redPlayers)).count() > fightCounts.getOrDefault(gameMode, defaultFightCount); + } + + @RequiredArgsConstructor + private static class Game { + private long time = System.currentTimeMillis(); + private final List bluePlayers; + private final List redPlayers; + + public long livedMillis() { + return System.currentTimeMillis() - time; + } + + public boolean isSame(List bluePlayers, List redPlayers) { + return bluePlayers.containsAll(this.bluePlayers) && redPlayers.containsAll(this.redPlayers); } } } diff --git a/src/de/steamwar/bungeecore/sql/UserElo.java b/src/de/steamwar/bungeecore/sql/UserElo.java index 67409661..efa00782 100644 --- a/src/de/steamwar/bungeecore/sql/UserElo.java +++ b/src/de/steamwar/bungeecore/sql/UserElo.java @@ -56,7 +56,7 @@ public class UserElo { }, userID, gameMode, Season.getSeason())); } - private static int getFightsOfSeason(int userID, String gameMode) { + public static int getFightsOfSeason(int userID, String gameMode) { return fightsOfSeason.select(rs -> { if (rs.next()) return rs.getInt("Fights");