Prevent farming elo up with multiple games by dc and joining new game.

This commit is contained in:
Jonathan Williams 2016-04-22 04:05:07 -05:00
parent ddd1c5af9b
commit 7b18efa7b0
5 changed files with 121 additions and 77 deletions

View File

@ -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<EloClientData>
{
private EloRepository _repository;
private EloRatingSystem _ratingSystem;
private NautHashMap<String, EloTeam> _eloTeams = new NautHashMap<>();
public EloManager(JavaPlugin plugin, CoreClientManager clientManager)
{
@ -53,7 +56,7 @@ public class EloManager extends MiniDbClientPlugin<EloClientData>
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<EloClientData>
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<EloClientData>
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<EloClientData>
}
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<EloClientData>
{
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();
}
}

View File

@ -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);

View File

@ -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

View File

@ -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<EloPlayer> _players = new ArrayList<EloPlayer>();
private NautHashMap<String, EloPlayer> _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<EloPlayer> getPlayers()
public EloPlayer getPlayer(String uuid)
{
return _players;
return _players.get(uuid);
}
public void printTeamInfo()
public Collection<EloPlayer> getPlayers()
{
System.out.println("TotalElo: " + TotalElo);
for (EloPlayer player : _players)
{
System.out.println(player.getPlayer().getName() + "'s Elo: " + player.getRating());
}
return _players.values();
}
}

View File

@ -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());
}
}