diff --git a/Plugins/Mineplex.Core/src/mineplex/core/elo/EloManager.java b/Plugins/Mineplex.Core/src/mineplex/core/elo/EloManager.java index 6b8febd48..16da4197c 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/elo/EloManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/elo/EloManager.java @@ -2,9 +2,11 @@ package mineplex.core.elo; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.HashSet; import mineplex.core.MiniDbClientPlugin; import mineplex.core.account.CoreClientManager; +import mineplex.core.common.util.NautHashMap; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; @@ -13,6 +15,7 @@ public class EloManager extends MiniDbClientPlugin { private EloRepository _repository; private EloRatingSystem _ratingSystem; + private NautHashMap _eloTeams = new NautHashMap<>(); public EloManager(JavaPlugin plugin, CoreClientManager clientManager) { @@ -53,7 +56,7 @@ public class EloManager extends MiniDbClientPlugin for (EloPlayer player : teamA.getPlayers()) { int newRating = (int)(player.getRating() + ((double)_ratingSystem.getKFactor(player.getRating()) / (double)kTotal) * (newTotal - teamA.TotalElo)); - EloPlayer newPlayer = new EloPlayer(player.getPlayer(), newRating); + EloPlayer newPlayer = new EloPlayer(player.getPlayer(), player.getAccountId(), newRating); newTeam.addPlayer(newPlayer); } @@ -61,7 +64,7 @@ public class EloManager extends MiniDbClientPlugin return newTeam; } - public void saveElo(final Player player, final int gameType, final int elo) + public void saveElo(final Player player, final int accountId, final int gameType, final int oldElo, final int elo) { runAsync(new Runnable() { @@ -71,7 +74,7 @@ public class EloManager extends MiniDbClientPlugin try { - success = _repository.saveElo(getClientManager().getAccountId(player), gameType, elo); + success = _repository.saveElo(accountId, gameType, oldElo, elo); } catch (SQLException e) { @@ -79,12 +82,24 @@ public class EloManager extends MiniDbClientPlugin } finally { - System.out.println("Saving " + player.getName() + "'s new elo rating of " + elo + " for gameType " + gameType + (success ? " SUCCEEDED." : " FAILED.")); + System.out.println("Saving " + accountId + "'s new elo rating of " + elo + " for gameType " + gameType + (success ? " SUCCEEDED." : " FAILED.")); } + + final boolean finalSuccess = success; + + runSync(new Runnable() + { + public void run() + { + if (finalSuccess) + { + if (player.isOnline()) + Get(player).Elos.put(gameType, elo); + } + } + }); } }); - - Get(player).Elos.put(gameType, elo); } public String getPlayerDivision(Player player, int gameType) @@ -145,4 +160,44 @@ public class EloManager extends MiniDbClientPlugin { return "SELECT gameType, elo FROM eloRating WHERE accountId = '" + accountId + "';"; } + + public void addTeam(String displayName, EloTeam eloTeam) + { + _eloTeams.put(displayName, eloTeam); + } + + public void setWinningTeam(String displayName) + { + _eloTeams.get(displayName).Winner = true; + } + + public void endMatch(int gameId) + { + EloTeam teamWinner = null; + EloTeam teamLoser = null; + + for (EloTeam team : _eloTeams.values()) + { + if (team.Winner) + teamWinner = team; + else + teamLoser = team; + } + + EloTeam teamWinnerNew = getNewRatings(teamWinner, teamLoser, GameResult.Win); + EloTeam teamLoserNew = getNewRatings(teamLoser, teamWinner, GameResult.Loss); + + // Use teams to calculate Elo + for (EloPlayer eloPlayer : teamWinnerNew.getPlayers()) + { + saveElo(eloPlayer.getPlayer(), eloPlayer.getAccountId(), gameId, teamWinner.getPlayer(eloPlayer.getPlayer().getUniqueId().toString()).getRating(), eloPlayer.getRating()); + } + + for (EloPlayer eloPlayer : teamLoserNew.getPlayers()) + { + saveElo(eloPlayer.getPlayer(), eloPlayer.getAccountId(), gameId, teamLoser.getPlayer(eloPlayer.getPlayer().getUniqueId().toString()).getRating(), eloPlayer.getRating()); + } + + _eloTeams.clear(); + } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/elo/EloPlayer.java b/Plugins/Mineplex.Core/src/mineplex/core/elo/EloPlayer.java index c99726989..58c56a888 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/elo/EloPlayer.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/elo/EloPlayer.java @@ -5,11 +5,13 @@ import org.bukkit.entity.Player; public class EloPlayer { private Player _player; - public int _rating; + private int _accountId; + private int _rating; - public EloPlayer(Player player, int rating) + public EloPlayer(Player player, int accountId, int rating) { _player = player; + _accountId = accountId; _rating = rating; } @@ -18,16 +20,16 @@ public class EloPlayer return _player; } - public void setRating(int rating) - { - _rating = rating; - } - public int getRating() { return _rating; } + public int getAccountId() + { + return _accountId; + } + public void printInfo() { System.out.println(_player.getName() + "'s elo is " + _rating); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/elo/EloRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/elo/EloRepository.java index 2bd9686e1..325c338ec 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/elo/EloRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/elo/EloRepository.java @@ -12,7 +12,8 @@ import org.bukkit.plugin.java.JavaPlugin; public class EloRepository extends MinecraftRepository { private static String INSERT_ELO = "INSERT INTO eloRating (accountId, gameType, elo) VALUES (?, ?, ?);"; - private static String UPDATE_ELO = "UPDATE eloRating SET elo=? WHERE accountId = ? AND gameType = ?;"; + private static String UPDATE_ELO = "UPDATE eloRating SET elo = elo + ? WHERE accountId = ? AND gameType = ?;"; + private static String UPDATE_ELO_ONLY_IF_MATCH = "UPDATE eloRating SET elo = elo + ? WHERE accountId = ? AND gameType = ? AND elo = ?;"; public EloRepository(JavaPlugin plugin) { @@ -23,14 +24,21 @@ public class EloRepository extends MinecraftRepository public void initialize() { } - public boolean saveElo(int accountId, int gameType, int elo) throws SQLException + public boolean saveElo(int accountId, int gameType, int oldElo, int elo) throws SQLException { - if (executeUpdate(UPDATE_ELO, new ColumnInt("elo", elo), new ColumnInt("accountId", accountId), new ColumnInt("gameType", gameType)) > 0) - return true; - else if (executeUpdate(INSERT_ELO, new ColumnInt("accountId", accountId), new ColumnInt("gameType", gameType), new ColumnInt("elo", elo)) > 0) - return true; + boolean updateSucceeded = false; - return false; + // If we're increasing in elo we verify the server version matches the database version (prevent d/c and double wins with concurrent matches) + // Otherwise we always take their elo down if they lose. + if (elo > oldElo) + updateSucceeded = executeUpdate(UPDATE_ELO_ONLY_IF_MATCH, new ColumnInt("elo", elo - oldElo), new ColumnInt("accountId", accountId), new ColumnInt("gameType", gameType), new ColumnInt("elo", oldElo)) > 0; + else + updateSucceeded = executeUpdate(UPDATE_ELO, new ColumnInt("elo", elo - oldElo), new ColumnInt("accountId", accountId), new ColumnInt("gameType", gameType)) > 0; + + if (!updateSucceeded && executeUpdate(INSERT_ELO, new ColumnInt("accountId", accountId), new ColumnInt("gameType", gameType), new ColumnInt("elo", elo)) > 0) + updateSucceeded = true; + + return updateSucceeded; } public EloClientData loadClientInformation(ResultSet resultSet) throws SQLException diff --git a/Plugins/Mineplex.Core/src/mineplex/core/elo/EloTeam.java b/Plugins/Mineplex.Core/src/mineplex/core/elo/EloTeam.java index 50996d227..538fd22da 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/elo/EloTeam.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/elo/EloTeam.java @@ -1,33 +1,29 @@ package mineplex.core.elo; -import java.util.ArrayList; -import java.util.List; +import java.util.Collection; + +import mineplex.core.common.util.NautHashMap; public class EloTeam { - private List _players = new ArrayList(); - + private NautHashMap _players = new NautHashMap<>(); public int TotalElo = 0; + public boolean Winner = false; public void addPlayer(EloPlayer player) { TotalElo += player.getRating(); - _players.add(player); + _players.put(player.getPlayer().getUniqueId().toString(), player); } - public List getPlayers() + public EloPlayer getPlayer(String uuid) { - return _players; + return _players.get(uuid); } - public void printTeamInfo() + public Collection getPlayers() { - System.out.println("TotalElo: " + TotalElo); - - for (EloPlayer player : _players) - { - System.out.println(player.getPlayer().getName() + "'s Elo: " + player.getRating()); - } + return _players.values(); } } diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/Game.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/Game.java index f590ef33a..4d55ecf34 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/Game.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/Game.java @@ -1568,55 +1568,38 @@ public abstract class Game implements Listener SetState(GameState.End); } + @EventHandler + public void onGameStart(GameStateChangeEvent event) + { + if (event.GetState() == GameState.Live) + { + if (EloRanking) + { + // Populate teams + for (GameTeam team : GetTeamList()) + { + EloTeam eloTeam = new EloTeam(); + + for (Player player : team.GetPlayers(false)) + { + eloTeam.addPlayer(new EloPlayer(player, Manager.GetClients().getAccountId(player), Manager.getEloManager().getElo(player, GetType().getGameId()))); + } + + Manager.getEloManager().addTeam(team.getDisplayName(), eloTeam); + } + } + } + } + // Handle Elo at end of game -- method can be overridden in different game modes to meet their individual needs protected void endElo() { if (EloRanking) { - // Make a list of all players to help find average Elo - EloTeam teamWinner = new EloTeam(); - EloTeam teamLoser = new EloTeam(); + if (WinnerTeam != null) + Manager.getEloManager().setWinningTeam(WinnerTeam.getDisplayName()); - // Populate teams - for (GameTeam team : GetTeamList()) - { - if (WinnerTeam != null && team.equals(WinnerTeam)) - { - for (Player player : WinnerTeam.GetPlayers(false)) - { - teamWinner.addPlayer(new EloPlayer(player, Manager.getEloManager().getElo(player, GetType().getGameId()))); - } - } - else - { - for (Player player : team.GetPlayers(false)) - { - teamLoser.addPlayer(new EloPlayer(player, Manager.getEloManager().getElo(player, GetType().getGameId()))); - } - } - } - - EloTeam teamWinnerNew = Manager.getEloManager().getNewRatings(teamWinner, teamLoser, GameResult.Win); - EloTeam teamLoserNew = Manager.getEloManager().getNewRatings(teamLoser, teamWinner, GameResult.Loss); - - System.out.println("Winning team:"); - teamWinner.printTeamInfo(); - teamWinnerNew.printTeamInfo(); - - System.out.println("Losing team:"); - teamLoser.printTeamInfo(); - teamLoserNew.printTeamInfo(); - - // Use teams to calculate Elo - for (EloPlayer eloPlayer : teamWinnerNew.getPlayers()) - { - Manager.getEloManager().saveElo(eloPlayer.getPlayer(), GetType().getGameId(), eloPlayer.getRating()); - } - - for (EloPlayer eloPlayer : teamLoserNew.getPlayers()) - { - Manager.getEloManager().saveElo(eloPlayer.getPlayer(), GetType().getGameId(), eloPlayer.getRating()); - } + Manager.getEloManager().endMatch(GetType().getGameId()); } }