diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/ArenaMode.java b/FightSystem_Core/src/de/steamwar/fightsystem/ArenaMode.java index 94d3d2b..e291fd7 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/ArenaMode.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/ArenaMode.java @@ -25,7 +25,6 @@ import java.util.Set; public enum ArenaMode { NORMAL, - RANKED, EVENT, TEST, CHECK, @@ -38,7 +37,6 @@ public enum ArenaMode { public static final Set Check = Collections.unmodifiableSet(EnumSet.of(CHECK)); public static final Set Event = Collections.unmodifiableSet(EnumSet.of(EVENT)); public static final Set Test = Collections.unmodifiableSet(EnumSet.of(TEST, CHECK)); - public static final Set Ranked = Collections.unmodifiableSet(EnumSet.of(RANKED)); public static final Set Prepare = Collections.unmodifiableSet(EnumSet.of(PREPARE)); public static final Set Replay = Collections.unmodifiableSet(EnumSet.of(REPLAY, TEST)); @@ -46,9 +44,9 @@ public enum ArenaMode { public static final Set AntiTest = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(TEST, CHECK))); public static final Set AntiEvent = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(EVENT))); public static final Set AntiPrepare = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(PREPARE))); - public static final Set VariableTeams = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(RANKED, EVENT, REPLAY))); - public static final Set RankedEvent = Collections.unmodifiableSet(EnumSet.of(RANKED, EVENT, REPLAY)); - public static final Set Restartable = Collections.unmodifiableSet(EnumSet.of(NORMAL, RANKED)); + public static final Set VariableTeams = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(EVENT, REPLAY))); + public static final Set RankedEvent = Collections.unmodifiableSet(EnumSet.of(EVENT, REPLAY)); + public static final Set Restartable = Collections.unmodifiableSet(EnumSet.of(NORMAL)); public static final Set NotRestartable = Collections.unmodifiableSet(EnumSet.of(EVENT, REPLAY)); public static final Set SoloLeader = Collections.unmodifiableSet(EnumSet.of(TEST, CHECK, PREPARE)); public static final Set NotOnBau = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(TEST, CHECK, PREPARE, REPLAY))); diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/Config.java b/FightSystem_Core/src/de/steamwar/fightsystem/Config.java index 9e1dd53..6dab0a9 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/Config.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/Config.java @@ -92,7 +92,7 @@ public class Config { public static final String TeamChatDetection; public static final UUID BlueLeader; public static final UUID RedLeader; - public static final boolean Ranked; + public static final boolean RankedEnabled; //Active win conditions public static final Set ActiveWinconditions; @@ -150,6 +150,8 @@ public class Config { } FileConfiguration worldconfig = YamlConfiguration.loadConfiguration(worldConfigFile); + RankedEnabled = config.getBoolean("Server.Ranked", false); + NoPlayerOnlineDuration = config.getInt("Times.NoPlayersOnlineDuration", 30); PreSchemPasteDuration = config.getInt("Times.PreSchemPasteDuration", 120); SetupDuration = config.getInt("Times.SetupDuration", 300); @@ -370,12 +372,9 @@ public class Config { CheckSchemID = Integer.parseInt(System.getProperty("checkSchemID", "0")); PrepareSchemID = Integer.parseInt(System.getProperty("prepareSchemID", "0")); - Ranked = Boolean.parseBoolean(System.getProperty("ranked", "false")); ReplayID = Integer.parseInt(System.getProperty("replay", "0")); - if(Ranked){ - mode = ArenaMode.RANKED; - }else if(CheckSchemID != 0){ + if(CheckSchemID != 0){ mode = ArenaMode.CHECK; }else if(PrepareSchemID != 0){ mode = ArenaMode.PREPARE; diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java index 892edd1..5088d1c 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java @@ -87,7 +87,6 @@ public class FightSystem extends JavaPlugin { new PrepareSchem(); new TestJoin(); new NormalJoin(); - new RankedJoin(); new RunningWorldInteraction(); new PersonalKitCreator(); new ArrowStopper(); @@ -114,7 +113,6 @@ public class FightSystem extends JavaPlugin { new WinconditionHeartRatioTimeout(); new WinconditionTimeTechKO(); new EventTeamOffWincondition(); - new RankedPlayerLeftWincondition(); new WinconditionPercentTimeout(); new HellsBells(); diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties index cdd7e40..3ddde23 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties +++ b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties @@ -180,7 +180,7 @@ UI_PLAYER_LEAVES= UI_LEADER_JOINS=§a§l» {0}Leader {1} UI_PLAYER_DEATH={0}{1} §7ist gestorben UI_PLAYER_LEAVE={0}{1} §7hat den Kampf verlassen -UI_ELO=§7ELO von {0}{1}§8: §7{2}§8»§e{3} +UI_ELO_PLAYER=§7Elo§8: §7{0}§8»§7{1} UI_WIN={0}Sieg {1} UI_DRAW=§7Unentschieden @@ -232,7 +232,6 @@ WIN_FIGHTLEADER= WIN_PERCENT={0} §7zu beschädigt WIN_OFFLINE_BOTH=§7Beide Teams offline WIN_OFFLINE={0} §7offline -WIN_RANKED_LEFT={0} §7hat den Kampf verlassen WIN_ALL_DEAD={0}Alle Spieler kampfunfähig WIN_LEADER_DEAD={0} kampfunfähig WIN_TIME_OVER=§7Zeit abgelaufen diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/countdown/Countdown.java b/FightSystem_Core/src/de/steamwar/fightsystem/countdown/Countdown.java index 46c8ace..d575287 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/countdown/Countdown.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/countdown/Countdown.java @@ -45,6 +45,7 @@ public abstract class Countdown { private final boolean level; protected int time; + protected int timeElapsed; private BukkitTask task = null; public abstract void countdownFinished(); @@ -110,8 +111,13 @@ public abstract class Countdown { return time; } + public int getTimeElapsed(){ + return timeElapsed; + } + private void count() { time--; + timeElapsed++; show(); } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/listener/RankedJoin.java b/FightSystem_Core/src/de/steamwar/fightsystem/listener/RankedJoin.java deleted file mode 100644 index 49ec963..0000000 --- a/FightSystem_Core/src/de/steamwar/fightsystem/listener/RankedJoin.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - This file is a part of the SteamWar software. - - Copyright (C) 2020 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.fightsystem.listener; - -import de.steamwar.fightsystem.ArenaMode; -import de.steamwar.fightsystem.Config; -import de.steamwar.fightsystem.fight.Fight; -import de.steamwar.fightsystem.fight.FightTeam; -import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentListener; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; - -public class RankedJoin implements Listener { - - public RankedJoin() { - new StateDependentListener(ArenaMode.Ranked, FightState.PreLeaderSetup, this); - } - - @EventHandler - public void handlePlayerJoin(PlayerJoinEvent event) { - Player player = event.getPlayer(); - FightTeam fightTeam = Fight.getPlayerTeam(player); - - if (fightTeam == null) { - if(!player.getUniqueId().equals(Config.RedLeader) && Fight.getBlueTeam().canbeLeader(player)) { - Fight.getBlueTeam().addMember(player); - }else if(Fight.getRedTeam().canbeLeader(player)) { - Fight.getRedTeam().addMember(player); - } - } - } -} diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/FightStatistics.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/FightStatistics.java index 22c9891..1b245dc 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/FightStatistics.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/FightStatistics.java @@ -39,6 +39,9 @@ import java.io.FileInputStream; import java.sql.Timestamp; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import java.util.logging.Level; import static de.steamwar.sql.Fight.create; @@ -61,7 +64,7 @@ public class FightStatistics { new OneShotStateDependent(ArenaMode.SeriousFight, FightState.Spectate, () -> Bukkit.getScheduler().runTask(FightSystem.getPlugin(), this::disable)); } - private void enable(){ + private void enable() { starttime = Timestamp.from(Instant.now()); } @@ -84,33 +87,43 @@ public class FightStatistics { int win = 0; double blueResult; - if(winner == Fight.getBlueTeam()) { + if (winner == Fight.getBlueTeam()) { win = 1; blueResult = 1; - }else if(winner == Fight.getRedTeam()) { + } else if (winner == Fight.getRedTeam()) { win = 2; blueResult = 0; - }else{ + } else { blueResult = 0.5; } Integer blueSchem; + Integer blueSchemRank; Integer redSchem; - try{ - blueSchem = SchematicNode.getSchematicNode(Fight.getBlueTeam().getSchematic()).getId(); - }catch(SecurityException e){ + Integer redSchemRank; + try { + SchematicNode schematicNode = SchematicNode.getSchematicNode(Fight.getBlueTeam().getSchematic()); + blueSchem = schematicNode.getId(); + blueSchemRank = schematicNode.getRank(); + } catch (SecurityException e) { blueSchem = null; + blueSchemRank = null; } - try{ - redSchem = SchematicNode.getSchematicNode(Fight.getRedTeam().getSchematic()).getId(); - }catch(SecurityException e){ + try { + SchematicNode schematicNode = SchematicNode.getSchematicNode(Fight.getRedTeam().getSchematic()); + redSchem = schematicNode.getId(); + redSchemRank = schematicNode.getRank(); + } catch (SecurityException e) { redSchem = null; + redSchemRank = null; } int remainingTime = 0; + int timeElapsed = 0; Countdown timeOverCountdown = Wincondition.getTimeOverCountdown(); - if(timeOverCountdown != null){ + if (timeOverCountdown != null) { remainingTime = timeOverCountdown.getTimeLeft(); + timeElapsed = timeOverCountdown.getTimeElapsed(); } try { @@ -122,43 +135,88 @@ public class FightStatistics { for (FightPlayer fp : Fight.getRedTeam().getPlayers()) savePlayerStats(fp, fightId); - if(ArenaMode.Event.contains(Config.mode)) { + if (ArenaMode.Event.contains(Config.mode)) { FightSystem.getEventFight().setFight(fightId); } try { setReplay(fightId, new FileInputStream(FileRecorder.getFile())); - }catch(Exception e){ + } catch (Exception e) { Bukkit.getLogger().log(Level.INFO, "Failed to save replay", e); } - }catch(Exception e){ + } catch (Exception e) { Bukkit.getLogger().log(Level.SEVERE, "Failed to save statistics", e); } replayLock = false; - if(Config.Ranked){ - int blueElo = Elo.getElo(blueLeader, gameMode); - int redElo = Elo.getElo(redLeader, gameMode); - double redWinExpectation = 1 / (1 + Math.pow(10, (blueElo - redElo) / 400f)); - double blueWinExpectation = 1 / (1 + Math.pow(10, (redElo - blueElo) / 400f)); - int newBlueElo = (int) Math.round(blueElo + K * (blueResult - blueWinExpectation)); - int newRedElo = (int) Math.round(redElo + K * (1 - blueResult - redWinExpectation)); - Elo.setElo(blueLeader, gameMode, newBlueElo); - Elo.setElo(redLeader, gameMode, newRedElo); - FightSystem.broadcast("UI_ELO", Fight.getBlueTeam().getPrefix(), SteamwarUser.get(blueLeader).getUserName(), blueElo, newBlueElo); - FightSystem.broadcast("UI_ELO", Fight.getRedTeam().getPrefix(), SteamwarUser.get(redLeader).getUserName(), redElo, newRedElo); + calculateEloIfNeeded(timeElapsed, blueSchemRank, redSchemRank, blueResult, gameMode); + } + + private void calculateEloIfNeeded(int timeElapsed, Integer blueSchemRank, Integer redSchemRank, double blueResult, String gameMode) { + if (!Config.RankedEnabled) { + return; + } + + if (timeElapsed < 30) { // Too short fights are not worth elo change + return; + } + + if (blueSchemRank == null || redSchemRank == null) { // Schematics are not ranked + return; + } + + if (blueSchemRank != redSchemRank) { // Different schematics ranks are not worth elo change + return; + } + + Collection bluePlayers = Fight.getBlueTeam().getPlayers(); + Collection redPlayers = Fight.getRedTeam().getPlayers(); + double playerDiff = 1 - (Math.min(bluePlayers.size(), redPlayers.size()) / (double) Math.max(bluePlayers.size(), redPlayers.size())); + if (playerDiff >= 0.4) { // Too many players, not worth elo change + return; + } + + int blueElo = 0; + int redElo = 0; + Map blueElos = new HashMap<>(); + Map redElos = new HashMap<>(); + for (FightPlayer fp : bluePlayers) { + int elo = Elo.getElo(SteamwarUser.get(fp.getPlayer()).getId(), gameMode); + blueElo += elo; + blueElos.put(fp, elo); + } + for (FightPlayer fp : redPlayers) { + int elo = Elo.getElo(SteamwarUser.get(fp.getPlayer()).getId(), gameMode); + redElo += elo; + redElos.put(fp, elo); + } + + double redWinExpectation = 1 / (1 + Math.pow(10, (blueElo - redElo) / 600f)); + double blueWinExpectation = 1 / (1 + Math.pow(10, (redElo - blueElo) / 600f)); + double diffBlueElo = K * (blueResult - blueWinExpectation); + double diffRedElo = K * (1 - blueResult - redWinExpectation); + + for (FightPlayer fp : bluePlayers) { + int nElo = (int) Math.round(blueElos.get(fp) + diffBlueElo / bluePlayers.size()); + Elo.setElo(SteamwarUser.get(fp.getPlayer()).getId(), gameMode, nElo); + FightSystem.getMessage().send("UI_ELO_PLAYER", fp.getPlayer(), redElos.get(fp), nElo); + } + for (FightPlayer fp : redPlayers) { + int nElo = (int) Math.round(redElos.get(fp) + diffRedElo / redPlayers.size()); + Elo.setElo(SteamwarUser.get(fp.getPlayer()).getId(), gameMode, nElo); + FightSystem.getMessage().send("UI_ELO_PLAYER", fp.getPlayer(), redElos.get(fp), nElo); } } - private int getLeader(FightTeam team){ - if(team.getLeader() != null) + private int getLeader(FightTeam team) { + if (team.getLeader() != null) return SteamwarUser.get(team.getLeader().getPlayer().getUniqueId()).getId(); - else if(team.getDesignatedLeader() != null) + else if (team.getDesignatedLeader() != null) return SteamwarUser.get(team.getDesignatedLeader()).getId(); return 0; } - private void savePlayerStats(FightPlayer fp, int fightId){ + private void savePlayerStats(FightPlayer fp, int fightId) { SteamwarUser user = SteamwarUser.get(fp.getPlayer().getUniqueId()); de.steamwar.sql.FightPlayer.create(fightId, user.getId(), fp.getTeam().isBlue(), fp.getKit().getName(), fp.getKills(), !fp.isLiving()); } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/RankedPlayerLeftWincondition.java b/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/RankedPlayerLeftWincondition.java deleted file mode 100644 index 33f3045..0000000 --- a/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/RankedPlayerLeftWincondition.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - This file is a part of the SteamWar software. - - Copyright (C) 2020 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.fightsystem.winconditions; - -import de.steamwar.fightsystem.ArenaMode; -import de.steamwar.fightsystem.fight.Fight; -import de.steamwar.fightsystem.fight.FightTeam; -import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentListener; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerQuitEvent; - -public class RankedPlayerLeftWincondition extends Wincondition implements Listener { - - public RankedPlayerLeftWincondition(){ - super("LeaderQuit"); - new StateDependentListener(ArenaMode.Ranked, FightState.Setup, this); - } - - @EventHandler - public void handlePlayerQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); - FightTeam team = isTarget(player); - if(team == null) - return; - - if(team.isPlayerLeader(player)) { - win(Fight.getOpposite(team), "WIN_RANKED_LEFT", team.getPrefix() + team.getLeader().getPlayer().getName()); - } - } -}