SteamWar/BungeeCore
Archiviert
13
2

Hotfix (the last one hopefully) for the Elo handling

Dieser Commit ist enthalten in:
yoyosource 2023-05-14 10:34:14 +02:00
Ursprung fbcb043d1c
Commit 618c4d24a2
3 geänderte Dateien mit 123 neuen und 81 gelöschten Zeilen

Datei anzeigen

@ -25,8 +25,9 @@ import lombok.experimental.UtilityClass;
@UtilityClass @UtilityClass
public class BungeeNetworkHandler { public class BungeeNetworkHandler {
public static void register() { public static void register() {
new EloPlayerHandler().register();
new EloSchemHandler().register();
new ExecuteCommandHandler().register(); new ExecuteCommandHandler().register();
new FightEndsHandler().register();
new FightInfoHandler().register(); new FightInfoHandler().register();
new ImALobbyHandler().register(); new ImALobbyHandler().register();
new InventoryCallbackHandler().register(); new InventoryCallbackHandler().register();

Datei anzeigen

@ -38,7 +38,7 @@ import java.util.concurrent.TimeUnit;
import java.util.function.IntFunction; import java.util.function.IntFunction;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class FightEndsHandler extends PacketHandler { public class EloPlayerHandler extends PacketHandler {
private static final int MEDIAN_ELO_GAIN = 20; private static final int MEDIAN_ELO_GAIN = 20;
private static final double WIN_FACTOR = 1.0; private static final double WIN_FACTOR = 1.0;
@ -47,8 +47,6 @@ public class FightEndsHandler extends PacketHandler {
private static final double DRAW_LOSE_FACTOR = -0.2; private static final double DRAW_LOSE_FACTOR = -0.2;
private static final long REMATCH_LIFETIME = 1L * 60 * 60 * 1000; private static final long REMATCH_LIFETIME = 1L * 60 * 60 * 1000;
private int K = 20;
private Map<String, LinkedList<Game>> gameModeGames = new HashMap<>(); private Map<String, LinkedList<Game>> gameModeGames = new HashMap<>();
@Handler @Handler
@ -56,7 +54,6 @@ public class FightEndsHandler extends PacketHandler {
if (!ArenaMode.getBySchemType(SchematicType.fromDB(fightEndsPacket.getGameMode())).isRanked()) { if (!ArenaMode.getBySchemType(SchematicType.fromDB(fightEndsPacket.getGameMode())).isRanked()) {
return; return;
} }
// BungeeCore.get().getLogger().log(Level.INFO, fightEndsPacket.getWin() + " " + fightEndsPacket.getBlueSchem() + " " + fightEndsPacket.getRedSchem() + " " + fightEndsPacket.getBluePlayers() + " " + fightEndsPacket.getRedPlayers() + " " + fightEndsPacket.getGameMode() + " " + fightEndsPacket.getDuration());
boolean bluePublic = SchematicNode.getSchematicNode(fightEndsPacket.getBlueSchem()).getOwner() == 0; boolean bluePublic = SchematicNode.getSchematicNode(fightEndsPacket.getBlueSchem()).getOwner() == 0;
boolean redPublic = SchematicNode.getSchematicNode(fightEndsPacket.getRedSchem()).getOwner() == 0; boolean redPublic = SchematicNode.getSchematicNode(fightEndsPacket.getRedSchem()).getOwner() == 0;
@ -65,8 +62,6 @@ public class FightEndsHandler extends PacketHandler {
return; return;
} }
// BungeeCore.get().getLogger().log(Level.INFO, "After schematic public check");
// Die nächsten Zeilen filtern ein Fight innerhalb eines Teams nicht gewertet wird, bzw auch wenn nur Teile beider Teams im // 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. // gleichen Team sind dieser ungewertet ist.
Set<Integer> teamsIds = fightEndsPacket.getBluePlayers().stream().map(SteamwarUser::get).map(SteamwarUser::getTeam).collect(Collectors.toSet()); Set<Integer> teamsIds = fightEndsPacket.getBluePlayers().stream().map(SteamwarUser::get).map(SteamwarUser::getTeam).collect(Collectors.toSet());
@ -76,50 +71,68 @@ public class FightEndsHandler extends PacketHandler {
} }
} }
// BungeeCore.get().getLogger().log(Level.INFO, "After Team check"); // Get sizes of both teams
calcSchemElo(fightEndsPacket);
calcUserElo(fightEndsPacket);
}
private void calcUserElo(FightEndsPacket fightEndsPacket) {
int blueTeamSize = fightEndsPacket.getBluePlayers().size(); int blueTeamSize = fightEndsPacket.getBluePlayers().size();
int redTeamSize = fightEndsPacket.getRedPlayers().size(); int redTeamSize = fightEndsPacket.getRedPlayers().size();
// Calculate the favored team
double bluePlayerFactor = 1 / (1 + Math.exp(-(fightEndsPacket.getWin() == 2 ? (double) redTeamSize / blueTeamSize : (double) blueTeamSize / redTeamSize) * 3 + 3)) * 2;
double redPlayerFactor = 1 / (1 + Math.exp(-(fightEndsPacket.getWin() == 1 ? (double) blueTeamSize / redTeamSize : (double) redTeamSize / blueTeamSize) * 3 + 3)) * 2;
// Calculate the time factor
double timeFactor = getTimeFactor(fightEndsPacket.getDuration());
// Get total elo of both teams
int blueTeamElo = fightEndsPacket.getBluePlayers().stream().mapToInt(player -> UserElo.getEloOrDefault(player, fightEndsPacket.getGameMode())).sum(); int blueTeamElo = fightEndsPacket.getBluePlayers().stream().mapToInt(player -> UserElo.getEloOrDefault(player, fightEndsPacket.getGameMode())).sum();
int redTeamElo = fightEndsPacket.getRedPlayers().stream().mapToInt(player -> UserElo.getEloOrDefault(player, fightEndsPacket.getGameMode())).sum(); int redTeamElo = fightEndsPacket.getRedPlayers().stream().mapToInt(player -> UserElo.getEloOrDefault(player, fightEndsPacket.getGameMode())).sum();
double blueFactor = getBluePlayerFactor(blueTeamSize, redTeamSize) * getTimeFactor(fightEndsPacket.getDuration()) * getBlueEloFactor(blueTeamElo, redTeamElo) * getRematchFactor(fightEndsPacket); // Calculate the elo factor
double redFactor = getRedPlayerFactor(blueTeamSize, redTeamSize) * getTimeFactor(fightEndsPacket.getDuration()) * getRedEloFactor(blueTeamElo, redTeamElo) * getRematchFactor(fightEndsPacket); double blueEloFactor = ((fightEndsPacket.getWin() == 1 ? 1 : 0) - 1 / (1 + Math.pow(10, (redTeamElo - blueTeamElo) / 600.0))) * (1 / (1 + Math.exp(-Math.abs(blueTeamElo - redTeamElo) / 1200))) * 4;
double redEloFactor = blueEloFactor * -1;
if (fightEndsPacket.getWin() == 1) { // Calculate favoured team on draw
blueFactor *= WIN_FACTOR; if (fightEndsPacket.getWin() == 0) {
redFactor *= LOSE_FACTOR; if (bluePlayerFactor > 1) {
} else if (fightEndsPacket.getWin() == 2) { blueEloFactor = Math.abs(blueEloFactor) * -1;
blueFactor *= LOSE_FACTOR; redEloFactor = Math.abs(redEloFactor);
redFactor *= WIN_FACTOR; } else if (bluePlayerFactor < 1) {
blueEloFactor = Math.abs(blueEloFactor);
redEloFactor = Math.abs(redEloFactor) * -1;
} else { } else {
if (redFactor == blueFactor) { if (Math.abs(blueEloFactor) > 1) {
blueFactor *= 0; // Do nothing
redFactor *= 0; } else if (Math.abs(blueEloFactor) < 1) {
} else if (blueFactor > redFactor) { blueEloFactor = ((fightEndsPacket.getWin() == 1 ? 1 : 0) - 1 / (1 + Math.pow(10, (blueTeamElo - redTeamElo) / 600.0))) * (1 / (1 + Math.exp(-Math.abs(redTeamElo - blueTeamElo) / 1200))) * -4;
blueFactor *= DRAW_WIN_FACTOR; redEloFactor = blueEloFactor * -1;
redFactor *= DRAW_LOSE_FACTOR;
} else { } else {
blueFactor *= DRAW_LOSE_FACTOR; blueEloFactor = 0;
redFactor *= DRAW_WIN_FACTOR; redEloFactor = 0;
}
} }
} }
update(fightEndsPacket.getBluePlayers(), fightEndsPacket.getGameMode(), blueFactor); // Calculate the rematch factor
update(fightEndsPacket.getRedPlayers(), fightEndsPacket.getGameMode(), redFactor); double rematchFactor = getRematchFactor(fightEndsPacket);
// Calculate the win factor
double blueWinFactor = (fightEndsPacket.getWin() == 1 ? 1 : 0.9);
double redWinFactor = (fightEndsPacket.getWin() == 2 ? 1 : 0.9);
// Calculate division factor
double divisionFactor = 1/(fightEndsPacket.getWin() == 1 ? Math.max(blueTeamSize, redTeamSize) : Math.min(blueTeamSize, redTeamSize));
// Calculate the elo gain for each player
int blueEloGain = (int) Math.round(MEDIAN_ELO_GAIN * bluePlayerFactor * timeFactor * blueEloFactor * rematchFactor * blueWinFactor * divisionFactor);
int redEloGain = (int) Math.round(MEDIAN_ELO_GAIN * redPlayerFactor * timeFactor * redEloFactor * rematchFactor * redWinFactor * divisionFactor);
update(fightEndsPacket.getBluePlayers(), fightEndsPacket.getGameMode(), blueEloGain);
update(fightEndsPacket.getBluePlayers(), fightEndsPacket.getGameMode(), redEloGain);
} }
private void update(List<Integer> players, String gameMode, double factor) { private void update(List<Integer> players, String gameMode, int eloGain) {
for (int player : players) { for (int player : players) {
// BungeeCore.get().getLogger().log(Level.INFO, "Player: " + player + " Elo: " + UserElo.getEloOrDefault(player, gameMode) + " Factor: " + factor); // BungeeCore.get().getLogger().log(Level.INFO, "Player: " + player + " Elo: " + UserElo.getEloOrDefault(player, gameMode) + " Factor: " + factor);
int playerElo = UserElo.getEloOrDefault(player, gameMode); int playerElo = UserElo.getEloOrDefault(player, gameMode);
int eloGain = (int) Math.round(MEDIAN_ELO_GAIN * factor);
playerElo += eloGain; playerElo += eloGain;
if (playerElo < 0) playerElo = 0; if (playerElo < 0) playerElo = 0;
@ -154,11 +167,7 @@ public class FightEndsHandler extends PacketHandler {
scheduler.schedule(BungeeCore.get(), () -> { scheduler.schedule(BungeeCore.get(), () -> {
if (player == null) return; if (player == null) return;
if (!player.isConnected()) return; if (!player.isConnected()) return;
Title title = new BungeeTitle().title(TextComponent.fromLegacyText(getRankup.apply(finalI))) Title title = new BungeeTitle().title(TextComponent.fromLegacyText(getRankup.apply(finalI))).subTitle(eloGainComponent).fadeIn(finalI == 0 ? 5 : 0).stay(40).fadeOut(finalI == 39 ? 5 : 0);
.subTitle(eloGainComponent)
.fadeIn(finalI == 0 ? 5 : 0)
.stay(40)
.fadeOut(finalI == 39 ? 5 : 0);
title.send(player); title.send(player);
}, i * 50L, TimeUnit.MILLISECONDS); }, i * 50L, TimeUnit.MILLISECONDS);
} }
@ -168,39 +177,6 @@ public class FightEndsHandler extends PacketHandler {
return ProxyServer.getInstance().getPlayer(SteamwarUser.get(userId).getUUID()); return ProxyServer.getInstance().getPlayer(SteamwarUser.get(userId).getUUID());
} }
private void calcSchemElo(FightEndsPacket fightEndsPacket) {
double blueResult;
if (fightEndsPacket.getWin() == 0) {
blueResult = 0.5;
} else if (fightEndsPacket.getWin() == 1) {
blueResult = 1;
} else {
blueResult = 0;
}
int blueSchemElo = SchemElo.getCurrentElo(fightEndsPacket.getBlueSchem());
int redSchemElo = SchemElo.getCurrentElo(fightEndsPacket.getRedSchem());
calcSchemElo(fightEndsPacket.getBlueSchem(), blueSchemElo, redSchemElo, blueResult);
calcSchemElo(fightEndsPacket.getRedSchem(), redSchemElo, blueSchemElo, 1 - blueResult);
}
private void calcSchemElo(int eloSchemOwn, int eloSchemEnemy, int schemId, double result) {
double winSchemExpectation = calcWinExpectation(eloSchemOwn, eloSchemEnemy);
SchemElo.setElo(schemId, (int) Math.round(eloSchemOwn + K * (result - winSchemExpectation)));
}
private double calcWinExpectation(int eloOwn, int eloEnemy) {
return 1 / (1 + Math.pow(10, (eloEnemy - eloOwn) / 600f));
}
private double getBluePlayerFactor(int blueTeam, int redTeam) {
return 2 - calcWinExpectation(blueTeam, redTeam) * 2;
}
private double getRedPlayerFactor(int blueTeam, int redTeam) {
return 2 - calcWinExpectation(redTeam, blueTeam) * 2;
}
private double getTimeFactor(int duration) { private double getTimeFactor(int duration) {
if (duration <= 10) { if (duration <= 10) {
return 0.5; return 0.5;
@ -211,14 +187,6 @@ public class FightEndsHandler extends PacketHandler {
return 1.0; return 1.0;
} }
private double getBlueEloFactor(int blueElo, int redElo) {
return 2 - calcWinExpectation(blueElo, redElo) * 2;
}
private double getRedEloFactor(int blueElo, int redElo) {
return 2 - calcWinExpectation(redElo, blueElo) * 2;
}
private double getRematchFactor(FightEndsPacket fightEndsPacket) { private double getRematchFactor(FightEndsPacket fightEndsPacket) {
gameModeGames.computeIfAbsent(fightEndsPacket.getGameMode(), s -> new LinkedList<>()).add(new Game(fightEndsPacket.getBluePlayers(), fightEndsPacket.getRedPlayers())); gameModeGames.computeIfAbsent(fightEndsPacket.getGameMode(), s -> new LinkedList<>()).add(new Game(fightEndsPacket.getBluePlayers(), fightEndsPacket.getRedPlayers()));

Datei anzeigen

@ -0,0 +1,73 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bungeecore.network.handlers;
import de.steamwar.bungeecore.ArenaMode;
import de.steamwar.network.packets.PacketHandler;
import de.steamwar.network.packets.common.FightEndsPacket;
import de.steamwar.sql.SchemElo;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SchematicType;
public class EloSchemHandler extends PacketHandler {
private final int K = 20;
@Handler
public void handle(FightEndsPacket fightEndsPacket) {
if (!ArenaMode.getBySchemType(SchematicType.fromDB(fightEndsPacket.getGameMode())).isRanked()) {
return;
}
boolean bluePublic = SchematicNode.getSchematicNode(fightEndsPacket.getBlueSchem()).getOwner() == 0;
boolean redPublic = SchematicNode.getSchematicNode(fightEndsPacket.getRedSchem()).getOwner() == 0;
if (bluePublic ^ redPublic) {
return;
}
calcSchemElo(fightEndsPacket);
}
private void calcSchemElo(FightEndsPacket fightEndsPacket) {
double blueResult;
if (fightEndsPacket.getWin() == 0) {
blueResult = 0.5;
} else if (fightEndsPacket.getWin() == 1) {
blueResult = 1;
} else {
blueResult = 0;
}
int blueSchemElo = SchemElo.getCurrentElo(fightEndsPacket.getBlueSchem());
int redSchemElo = SchemElo.getCurrentElo(fightEndsPacket.getRedSchem());
calcSchemElo(fightEndsPacket.getBlueSchem(), blueSchemElo, redSchemElo, blueResult);
calcSchemElo(fightEndsPacket.getRedSchem(), redSchemElo, blueSchemElo, 1 - blueResult);
}
private void calcSchemElo(int eloSchemOwn, int eloSchemEnemy, int schemId, double result) {
double winSchemExpectation = calcWinExpectation(eloSchemOwn, eloSchemEnemy);
SchemElo.setElo(schemId, (int) Math.round(eloSchemOwn + K * (result - winSchemExpectation)));
}
private double calcWinExpectation(int eloOwn, int eloEnemy) {
return 1 / (1 + Math.pow(10, (eloEnemy - eloOwn) / 600f));
}
}