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/listeners/mods/Fabric.java b/src/de/steamwar/bungeecore/listeners/mods/Fabric.java index 252aac0e..4e0a8524 100644 --- a/src/de/steamwar/bungeecore/listeners/mods/Fabric.java +++ b/src/de/steamwar/bungeecore/listeners/mods/Fabric.java @@ -38,8 +38,6 @@ import net.md_5.bungee.event.EventHandler; import java.nio.charset.StandardCharsets; import java.nio.charset.UnsupportedCharsetException; -import java.sql.Timestamp; -import java.time.Instant; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -48,9 +46,6 @@ public class Fabric extends BasicListener { private final Set neededMods = new HashSet<>(); - public static final Map checkedPlayers = new HashMap<>(); - private static final Map expectPluginMessage = new HashMap<>(); - { neededMods.add("java"); neededMods.add("minecraft"); @@ -58,9 +53,9 @@ public class Fabric extends BasicListener { neededMods.add("steamwarmodsender"); BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), () -> { - synchronized (expectPluginMessage) { - for (Map.Entry entry : expectPluginMessage.entrySet()) { - if (!checkedPlayers.containsKey(entry.getKey())) { + synchronized (Storage.fabricExpectPluginMessage) { + for (Map.Entry entry : Storage.fabricExpectPluginMessage.entrySet()) { + if (!Storage.fabricCheckedPlayers.containsKey(entry.getKey())) { continue; } if (System.currentTimeMillis() - entry.getValue() > TimeUnit.SECONDS.toMillis(20)) { @@ -84,15 +79,15 @@ public class Fabric extends BasicListener { ProxiedPlayer player = (ProxiedPlayer) e.getSender(); SteamwarUser user = SteamwarUser.get(player.getUniqueId()); - if (!checkedPlayers.containsKey(player)) { - synchronized (expectPluginMessage) { - if (expectPluginMessage.containsKey(player)) { + if (!Storage.fabricCheckedPlayers.containsKey(player)) { + synchronized (Storage.fabricExpectPluginMessage) { + if (Storage.fabricExpectPluginMessage.containsKey(player)) { banPlayer(user, player); return; } } } - expectPluginMessage.remove(player); + Storage.fabricExpectPluginMessage.remove(player); List mods = new LinkedList<>(); @@ -141,15 +136,15 @@ public class Fabric extends BasicListener { } if(Utils.handleMods(player,mods)) { - if (checkedPlayers.containsKey(player)) { - long current = checkedPlayers.get(player); + if (Storage.fabricCheckedPlayers.containsKey(player)) { + long current = Storage.fabricCheckedPlayers.get(player); if (current != dataString.hashCode()) { banPlayer(user, player); return; } } else { Message.send("MODIFICATION_CHECK_SUCCESS", player); - checkedPlayers.put(player, dataString.hashCode()); + Storage.fabricCheckedPlayers.put(player, dataString.hashCode()); } Storage.fabricPlayers.remove(player); } @@ -158,8 +153,8 @@ public class Fabric extends BasicListener { @EventHandler public void onServerSwitchEvent(ServerSwitchEvent e) { if (e.getFrom() == null) return; - synchronized (expectPluginMessage) { - expectPluginMessage.put(e.getPlayer(), System.currentTimeMillis()); + synchronized (Storage.fabricExpectPluginMessage) { + Storage.fabricExpectPluginMessage.put(e.getPlayer(), System.currentTimeMillis()); } } @@ -189,9 +184,9 @@ public class Fabric extends BasicListener { } public static void remove(ProxiedPlayer player) { - checkedPlayers.remove(player); - synchronized (expectPluginMessage) { - expectPluginMessage.remove(player); + Storage.fabricCheckedPlayers.remove(player); + synchronized (Storage.fabricExpectPluginMessage) { + Storage.fabricExpectPluginMessage.remove(player); } } } diff --git a/src/de/steamwar/bungeecore/listeners/mods/ModLoaderBlocker.java b/src/de/steamwar/bungeecore/listeners/mods/ModLoaderBlocker.java index 9965c3e6..71f8220f 100644 --- a/src/de/steamwar/bungeecore/listeners/mods/ModLoaderBlocker.java +++ b/src/de/steamwar/bungeecore/listeners/mods/ModLoaderBlocker.java @@ -46,7 +46,7 @@ public class ModLoaderBlocker extends BasicListener { if(new String(e.getData()).contains("fabric")){ ProxiedPlayer p = (ProxiedPlayer) sender; - if (!Fabric.checkedPlayers.containsKey(p) && !Storage.fabricPlayers.contains(p)) { + if (!Storage.fabricCheckedPlayers.containsKey(p) && !Storage.fabricPlayers.contains(p)) { Storage.fabricPlayers.add(p); Message.send("MODLOADER_INSTALLED_FABRIC", p, "Fabric"); } diff --git a/src/de/steamwar/bungeecore/sql/Fight.java b/src/de/steamwar/bungeecore/sql/Fight.java index 514946d6..e13b7872 100644 --- a/src/de/steamwar/bungeecore/sql/Fight.java +++ b/src/de/steamwar/bungeecore/sql/Fight.java @@ -11,7 +11,7 @@ import java.util.stream.Collectors; public class Fight { - private static final Statement getPage = new Statement("SELECT f.FightID, f.GameMode, f.Server, f.StartTime, f.BlueLeader, f.RedLeader, (b.NodeId IS NULL OR b.AllowReplay) AND (r.NodeId IS NULL OR r.AllowReplay) AS ReplayAllowed, f.Win, f.Replay IS NOT NULL AS ReplayExists FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId ORDER BY FightID DESC LIMIT ?, ?"); + private static final Statement getPage = new Statement("SELECT f.FightID, f.GameMode, f.Server, f.StartTime, f.BlueLeader, f.RedLeader, (b.NodeId IS NULL OR b.AllowReplay) AND (r.NodeId IS NULL OR r.AllowReplay) AS ReplayAllowed, f.Win, (SELECT COUNT(1) FROM Replay WHERE Replay.FightID = f.FightID) as ReplayAvailable FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId ORDER BY FightID DESC LIMIT ?, ?"); private final int fightID; private final String gameMode; @@ -22,8 +22,8 @@ public class Fight { private final int redLeader; private final int win; - private final boolean replayExists; private final boolean replayAllowed; + private final boolean replayAvailable; private final List bluePlayers = new ArrayList<>(); private final List redPlayers = new ArrayList<>(); @@ -36,8 +36,8 @@ public class Fight { blueLeader = rs.getInt("BlueLeader"); redLeader = rs.getInt("RedLeader"); replayAllowed = rs.getBoolean("ReplayAllowed"); + replayAvailable = rs.getBoolean("ReplayAvailable"); win = rs.getInt("Win"); - replayExists = rs.getBoolean("ReplayExists"); } private void initPlayers(List fightPlayers) { @@ -118,6 +118,6 @@ public class Fight { } public boolean replayExists() { - return replayExists && getGameMode() != null; + return getGameMode() != null && replayAvailable; } } 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");