From ac5dda58a1818c982ebe1dce026d885c0076780c Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sat, 20 Dec 2025 21:19:20 +0100 Subject: [PATCH 1/3] Remove SchemElo and UserElo --- .../SQL/src/de/steamwar/sql/SchemElo.kt | 74 ----- .../SQL/src/de/steamwar/sql/SchematicNode.kt | 2 - CommonCore/SQL/src/de/steamwar/sql/UserElo.kt | 170 ------------ .../src/SchematicSystem.properties | 1 - .../SchematicCommandUtils.java | 1 - .../steamwar/velocitycore/VelocityCore.java | 2 - .../velocitycore/commands/RankCommand.java | 68 ----- .../velocitycore/listeners/ChatListener.java | 2 +- .../network/handlers/EloPlayerHandler.java | 261 ------------------ .../network/handlers/EloSchemHandler.java | 82 ------ 10 files changed, 1 insertion(+), 662 deletions(-) delete mode 100644 CommonCore/SQL/src/de/steamwar/sql/SchemElo.kt delete mode 100644 CommonCore/SQL/src/de/steamwar/sql/UserElo.kt delete mode 100644 VelocityCore/src/de/steamwar/velocitycore/commands/RankCommand.java delete mode 100644 VelocityCore/src/de/steamwar/velocitycore/network/handlers/EloPlayerHandler.java delete mode 100644 VelocityCore/src/de/steamwar/velocitycore/network/handlers/EloSchemHandler.java diff --git a/CommonCore/SQL/src/de/steamwar/sql/SchemElo.kt b/CommonCore/SQL/src/de/steamwar/sql/SchemElo.kt deleted file mode 100644 index b187186b..00000000 --- a/CommonCore/SQL/src/de/steamwar/sql/SchemElo.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 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.sql - -import de.steamwar.sql.internal.useDb -import org.jetbrains.exposed.v1.core.and -import org.jetbrains.exposed.v1.core.dao.id.CompositeID -import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable -import org.jetbrains.exposed.v1.core.dao.id.EntityID -import org.jetbrains.exposed.v1.core.eq -import org.jetbrains.exposed.v1.dao.CompositeEntity -import org.jetbrains.exposed.v1.dao.CompositeEntityClass -import org.jetbrains.exposed.v1.jdbc.insertIgnore - -object SchemEloTable: CompositeIdTable("SchemElo") { - val schemId = reference("SchemId", SchematicNodeTable) - val season = integer("Season").entityId() - val elo = integer("Elo") - - override val primaryKey = PrimaryKey(schemId, season) - - init { - addIdColumn(schemId) - } -} - -class SchemElo(id: EntityID): CompositeEntity(id) { - companion object: CompositeEntityClass(SchemEloTable) { - @JvmStatic - fun getElo(node: SchematicNode, season: Int, defaultElo: Int = 0) = useDb { - find { (SchemEloTable.schemId eq node.id) and (SchemEloTable.season eq season) }.firstOrNull()?.elo ?: defaultElo - } - - @JvmStatic - fun getCurrentElo(schemId: Int) = getElo(SchematicNode.byId(schemId)!!, Season.getSeason()) - - @JvmStatic - fun setElo(node: Int, elo: Int) = useDb { - findByIdAndUpdate(CompositeID { - it[SchemEloTable.schemId] = node - it[SchemEloTable.season] = Season.getSeason() - }) { - it.elo = elo - } ?: SchemEloTable.insertIgnore { - it[SchemEloTable.schemId] = node - it[SchemEloTable.season] = Season.getSeason() - it[SchemEloTable.elo] = elo - } - - return@useDb - } - } - - var node by SchemEloTable.schemId - var season by SchemEloTable.season - var elo by SchemEloTable.elo -} \ No newline at end of file diff --git a/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.kt b/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.kt index 96fd0901..8cc0363f 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.kt +++ b/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.kt @@ -365,8 +365,6 @@ class SchematicNode(id: EntityID) : IntEntity(id) { } } - fun getElo(season: Int) = SchemElo.getElo(this, season) - override fun delete() = useDb { super.delete() } diff --git a/CommonCore/SQL/src/de/steamwar/sql/UserElo.kt b/CommonCore/SQL/src/de/steamwar/sql/UserElo.kt deleted file mode 100644 index 84441f46..00000000 --- a/CommonCore/SQL/src/de/steamwar/sql/UserElo.kt +++ /dev/null @@ -1,170 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 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.sql - -import de.steamwar.sql.internal.useDb -import org.jetbrains.exposed.v1.core.* -import org.jetbrains.exposed.v1.core.dao.id.CompositeID -import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable -import org.jetbrains.exposed.v1.core.dao.id.EntityID -import org.jetbrains.exposed.v1.dao.CompositeEntity -import org.jetbrains.exposed.v1.dao.CompositeEntityClass -import org.jetbrains.exposed.v1.jdbc.insertIgnore -import org.jetbrains.exposed.v1.jdbc.select -import java.util.concurrent.ConcurrentHashMap - -object UserEloTable : CompositeIdTable("UserElo") { - val season = integer("Season").entityId() - val gameMode = varchar("GameMode", 16).entityId() - val userId = reference("UserID", SteamwarUserTable) - val elo = integer("Elo") - - override val primaryKey = PrimaryKey(season, gameMode, userId) - - init { - addIdColumn(season) - addIdColumn(gameMode) - } -} - -class UserElo(id: EntityID) : CompositeEntity(id) { - companion object : CompositeEntityClass(UserEloTable) { - private const val ELO_DEFAULT = 0 - - private val gameModeUserEloCache: MutableMap> = ConcurrentHashMap() - private val emblemCache: MutableMap = ConcurrentHashMap() - - @JvmStatic - fun clear() { - gameModeUserEloCache.clear() - emblemCache.clear() - } - - @JvmStatic - fun getEloOrDefault(userId: Int, gameMode: String) = - getElo(userId, gameMode) ?: ELO_DEFAULT - - @JvmStatic - fun getElo(userId: Int, gameMode: String) = - gameModeUserEloCache.getOrPut(gameMode) { mutableMapOf() } - .getOrPut(userId) { getEloFromDb(userId, gameMode)?.elo } - - private fun getEloFromDb(userId: Int, gameMode: String) = useDb { - find { (UserEloTable.userId eq userId) and (UserEloTable.gameMode eq gameMode) and (UserEloTable.season eq Season.getSeason()) }.firstOrNull() - } - - @JvmStatic - fun getFightsOfSeason(userId: Int, gamemode: String) = useDb { - exec( - "SELECT COUNT(*) AS Fights FROM FightPlayer INNER JOIN Fight F on FightPlayer.FightID = F.FightID WHERE UserID = ? AND GameMode = ? AND UNIX_TIMESTAMP(StartTime) + Duration >= UNIX_TIMESTAMP(?)", - args = listOf( - IntegerColumnType() to userId, - VarCharColumnType() to gamemode, - VarCharColumnType() to Season.getSeasonStart() - ) - ) { - return@exec if (it.next()) { - it.getInt("Fights") - } else { - 0 - } - } ?: 0 - } - - @JvmStatic - fun setElo(userId: Int, gameMode: String, elo: Int) { - emblemCache.remove(userId) - gameModeUserEloCache.getOrDefault(gameMode, mutableMapOf()).remove(userId) - useDb { - findByIdAndUpdate(CompositeID { - it[UserEloTable.userId] = userId - it[UserEloTable.gameMode] = gameMode - it[UserEloTable.season] = Season.getSeason() - }) { - it.elo = elo - } ?: UserEloTable.insertIgnore { - it[UserEloTable.userId] = userId - it[UserEloTable.gameMode] = gameMode - it[UserEloTable.season] = Season.getSeason() - it[UserEloTable.elo] = elo - } - } - } - - @JvmStatic - fun getPlacement(elo: Int, gamemode: String) = useDb { - UserEloTable.select(UserEloTable.userId.count()).where { - (UserEloTable.gameMode eq gamemode) and (UserEloTable.elo greater elo) and (UserEloTable.season eq Season.getSeason()) - }.firstOrNull()?.get(UserEloTable.userId.count())?.let { it + 1 }?.toInt() ?: -1 - } - - @JvmStatic - fun getEmblem(user: SteamwarUser, rankedModes: List) = - emblemCache.getOrPut(user.id.value) { - var emblemProgression = -1 - for (mode in rankedModes) { - if (getFightsOfSeason(user.id.value, mode) == 0) continue - val progression = getProgression(user.id.value, mode) - if (progression > emblemProgression) { - emblemProgression = progression - } - } - return toEmblem(emblemProgression) - } - - @JvmStatic - fun getEmblemProgression(gameMode: String, userId: Int): String = - when (getProgression(userId, gameMode)) { - -1 -> "§8❱❱❱❱ ❂" - 0 -> "§e❱§8❱❱❱ ❂" - 1 -> "§e❱❱§8❱❱ ❂" - 2 -> "§e❱❱❱§8❱ ❂" - 3 -> "§e❱❱❱❱§8 ❂" - 4 -> "§8❱❱❱❱ §5❂" - else -> throw SecurityException("Progression is not in range") - } - - - @JvmStatic - fun getProgression(userId: Int, gameMode: String) = useDb { getElo(userId, gameMode) ?: -1 }.let { - when { - it < 0 -> -1 - it < 150 -> 0 - it < 350 -> 1 - it < 600 -> 2 - it < 900 -> 3 - else -> 4 - } - } - - @JvmStatic - fun toEmblem(progression: Int) = when (progression) { - -1 -> "" - 0 -> "§e❱ " - 1 -> "§e❱❱ " - 2 -> "§e❱❱❱ " - 3 -> "§e❱❱❱❱ " - 4 -> "§5❂ " - else -> throw SecurityException("Progression out of range") - } - } - - var elo by UserEloTable.elo -} \ No newline at end of file diff --git a/SchematicSystem/SchematicSystem_Core/src/SchematicSystem.properties b/SchematicSystem/SchematicSystem_Core/src/SchematicSystem.properties index 6115198f..0ff05daa 100644 --- a/SchematicSystem/SchematicSystem_Core/src/SchematicSystem.properties +++ b/SchematicSystem/SchematicSystem_Core/src/SchematicSystem.properties @@ -59,7 +59,6 @@ UTIL_INFO_TYPE_DIR=§eDIR UTIL_INFO_RANK=§7Rank: §e{0} UTIL_INFO_COLOR=§7Color translation: {0} UTIL_INFO_REPLAY=§7Replay playback: {0} -UTIL_INFO_ELO=§7Elo: §e{0} UTIL_INFO_FORMAT=§7Format: §e{0} UTIL_INFO_STATUS=§cState: §c{0}: {1} UTIL_INFO_MEMBER=§7Members: §e{0} diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java index fa9ccb42..d52a5569 100644 --- a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java +++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java @@ -248,7 +248,6 @@ public class SchematicCommandUtils { if (node.getSchemtype().fightType()) { SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_COLOR", player, SchematicSystem.MESSAGE.parse(node.replaceColor() ? "ON" : "OFF", player)); SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_REPLAY", player, SchematicSystem.MESSAGE.parse(node.allowReplay() ? "ON" : "OFF", player)); - SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_ELO", player, node.getElo(Season.getSeason())); } SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_FORMAT", player, node.getFileEnding()); diff --git a/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java b/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java index ed3f9ade..b38ff66e 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java +++ b/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java @@ -38,7 +38,6 @@ import de.steamwar.persistent.ReloadablePlugin; import de.steamwar.sql.Punishment; import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.Team; -import de.steamwar.sql.UserElo; import de.steamwar.sql.internal.Statement; import de.steamwar.velocitycore.commands.PunishmentCommand; import de.steamwar.velocitycore.commands.ServerSwitchCommand; @@ -184,7 +183,6 @@ public class VelocityCore implements ReloadablePlugin { schedule(() -> { SteamwarUser.clear(); - UserElo.clear(); Team.clear(); }).repeat(1, TimeUnit.HOURS).schedule(); diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/RankCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/RankCommand.java deleted file mode 100644 index fc96c478..00000000 --- a/VelocityCore/src/de/steamwar/velocitycore/commands/RankCommand.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 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.velocitycore.commands; - -import de.steamwar.command.SWCommand; -import de.steamwar.linkage.Linked; -import de.steamwar.messages.Chatter; -import de.steamwar.messages.Message; -import de.steamwar.sql.GameModeConfig; -import de.steamwar.sql.Season; -import de.steamwar.sql.SteamwarUser; -import de.steamwar.sql.UserElo; -import de.steamwar.velocitycore.ArenaMode; - -@Linked -public class RankCommand extends SWCommand { - - public RankCommand() { - super("rank"); - } - - @Register - public void ownRank(Chatter sender) { - rank(sender, sender.user()); - } - - @Register - public void rank(Chatter sender, @ErrorMessage("RANK_PLAYER_NOT_FOUND") SteamwarUser user) { - if (!sender.user().equals(user)) { - sender.prefixless("RANK_PLAYER_FOUND", user, Season.convertSeasonToString(Season.getSeason())); - } else { - sender.prefixless("RANK_PLAYER_SELF", Season.convertSeasonToString(Season.getSeason())); - } - - for(GameModeConfig mode : ArenaMode.getAllModes()) { - if (!mode.Server.Ranked) - continue; - - Integer elo = UserElo.getElo(user.getId(), mode.getSchemTypeOrInternalName()); - Message eloMsg; - if (elo != null) { - int placement = UserElo.getPlacement(elo, mode.getSchemTypeOrInternalName()); - eloMsg = new Message("RANK_PLACED", placement, elo); - } else { - eloMsg = new Message("RANK_UNPLACED"); - } - - sender.prefixless("RANK_DATA", UserElo.getEmblemProgression(mode.getChatName(), user.getId()), mode.getChatName(), eloMsg); - } - } -} diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/ChatListener.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/ChatListener.java index 95a65761..93a376cf 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/listeners/ChatListener.java +++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/ChatListener.java @@ -248,7 +248,7 @@ public class ChatListener extends BasicListener { msgReceiver == null ? receiver : msgReceiver, highlightMentions(message, chatColorCode, receiver), sender.getTeam() == 0 ? "" : "§" + Team.byId(sender.getTeam()).getTeamColor() + Team.byId(sender.getTeam()).getTeamKuerzel() + " ", - UserElo.getEmblem(sender, rankedModes), + "", prefix.getColorCode(), prefix.getChatPrefix().length() == 0 ? "§f" : prefix.getChatPrefix() + " ", chatColorCode); diff --git a/VelocityCore/src/de/steamwar/velocitycore/network/handlers/EloPlayerHandler.java b/VelocityCore/src/de/steamwar/velocitycore/network/handlers/EloPlayerHandler.java deleted file mode 100644 index 2925ee34..00000000 --- a/VelocityCore/src/de/steamwar/velocitycore/network/handlers/EloPlayerHandler.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 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.velocitycore.network.handlers; - -import com.velocitypowered.api.proxy.Player; -import de.steamwar.sql.GameModeConfig; -import de.steamwar.linkage.Linked; -import de.steamwar.messages.Chatter; -import de.steamwar.network.packets.PacketHandler; -import de.steamwar.network.packets.common.FightEndsPacket; -import de.steamwar.sql.SchematicType; -import de.steamwar.sql.SteamwarUser; -import de.steamwar.sql.UserElo; -import de.steamwar.velocitycore.ArenaMode; -import de.steamwar.velocitycore.VelocityCore; -import lombok.RequiredArgsConstructor; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.title.Title; - -import java.time.Duration; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.function.IntFunction; -import java.util.stream.Collectors; - -@Linked -public class EloPlayerHandler extends PacketHandler { - - private static final int MEDIAN_ELO_GAIN = 40; - private static final int MEDIAN_ELO_LOSE = 20; - private static final long REMATCH_LIFETIME = (long) 60 * 60 * 1000; - - private final Map> gameModeGames = new HashMap<>(); - - /** - * {@link FightEndsPacket#getWin()} == 1 -> Blue won - * {@link FightEndsPacket#getWin()} == 2 -> Red won - */ - @Handler - public void handle(FightEndsPacket fightEndsPacket) { - SchematicType schematicType = SchematicType.fromDB(fightEndsPacket.getGameMode()); - GameModeConfig arenaMode; - if (schematicType == null) { - arenaMode = ArenaMode.getByInternal(fightEndsPacket.getGameMode()); - } else { - arenaMode = ArenaMode.getBySchemType(schematicType); - } - if (arenaMode == null) return; - if (!arenaMode.Server.Ranked) return; - - if (EloSchemHandler.publicVsPrivate(fightEndsPacket)) - return; - - // 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::byId).map(SteamwarUser::getTeam).collect(Collectors.toSet()); - for (int redPlayer : fightEndsPacket.getRedPlayers()) { - int team = SteamwarUser.byId(redPlayer).getTeam(); - if (team != 0 && teamsIds.contains(team)) { - return; - } - } - - // Get sizes of both teams - int blueTeamSize = fightEndsPacket.getBluePlayers().size(); - int redTeamSize = fightEndsPacket.getRedPlayers().size(); - - // Calculate the favored team - double bluePlayerFactor = 1 / (1 + Math.exp(0 - (fightEndsPacket.getWin() == 2 ? (double) redTeamSize / blueTeamSize : (double) blueTeamSize / redTeamSize) * 3 + 3)) * 2; - double redPlayerFactor = 1 / (1 + Math.exp(0 - (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 redTeamElo = fightEndsPacket.getRedPlayers().stream().mapToInt(player -> UserElo.getEloOrDefault(player, fightEndsPacket.getGameMode())).sum(); - - // Adaptive elo bonus - int blueTeamEloBonus = 0; - int redTeamEloBonus = 0; - if (Math.abs(blueTeamElo / (double) fightEndsPacket.getBluePlayers().size() - redTeamElo / (double) fightEndsPacket.getRedPlayers().size()) > 400) { - int outlivedDuration = Math.max(fightEndsPacket.getDuration() - 60, 0); - if (fightEndsPacket.getWin() == 1 && blueTeamElo < redTeamElo) { - blueTeamEloBonus = outlivedDuration / 20; - redTeamEloBonus = -(blueTeamEloBonus / 2); - } else if (fightEndsPacket.getWin() == 2 && redTeamElo < blueTeamElo) { - redTeamEloBonus = outlivedDuration / 20; - blueTeamEloBonus = -(redTeamEloBonus / 2); - } else if (fightEndsPacket.getWin() == 0) { - if (redTeamElo < blueTeamElo) { - blueTeamEloBonus = outlivedDuration / 20; - redTeamEloBonus = -(blueTeamEloBonus / 2); - } else if (blueTeamElo < redTeamElo) { - redTeamEloBonus = outlivedDuration / 20; - blueTeamEloBonus = -(redTeamEloBonus / 2); - } - } - } - - // Calculate the elo factor - 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.0))) * 4; - double redEloFactor = blueEloFactor * -1; - - // Calculate favoured team on draw - if (fightEndsPacket.getWin() == 0) { - if (bluePlayerFactor > 1) { - blueEloFactor = Math.abs(blueEloFactor) * -1; - redEloFactor = Math.abs(redEloFactor); - } else if (bluePlayerFactor < 1) { - blueEloFactor = Math.abs(blueEloFactor); - redEloFactor = Math.abs(redEloFactor) * -1; - } else { - if (Math.abs(blueEloFactor) > 1) { - // Do nothing - } else if (Math.abs(blueEloFactor) < 1) { - blueEloFactor = -blueEloFactor; - redEloFactor = -blueEloFactor; - } else { - blueEloFactor = 0; - redEloFactor = 0; - } - } - } - - // Calculate the rematch factor - double rematchFactor = getRematchFactor(fightEndsPacket); - - // Calculate the win factor - double blueWinFactor = (fightEndsPacket.getWin() == 1 ? 1 : 0.7); - double redWinFactor = (fightEndsPacket.getWin() == 2 ? 1 : 0.7); - - // Calculate division factor - double divisionFactor = 1D / Math.max(blueTeamSize, redTeamSize); - - double blueFactor = bluePlayerFactor * timeFactor * blueEloFactor * rematchFactor * blueWinFactor * divisionFactor; - double redFactor = redPlayerFactor * timeFactor * redEloFactor * rematchFactor * redWinFactor * divisionFactor; - - // Calculate the elo gain for each player - int blueEloGain = (int) Math.round((blueFactor < 0 ? MEDIAN_ELO_LOSE : MEDIAN_ELO_GAIN) * blueFactor) + blueTeamEloBonus; - int redEloGain = (int) Math.round((redFactor < 0 ? MEDIAN_ELO_LOSE : MEDIAN_ELO_GAIN) * redFactor) + redTeamEloBonus; - - // BungeeCore.get().getLogger().info("Blue: " + fightEndsPacket.getBluePlayers() + " " + blueTeamSize + " " + bluePlayerFactor + " " + timeFactor + " " + blueEloFactor + " " + rematchFactor + " " + blueWinFactor + " " + divisionFactor + " " + blueEloGain); - // BungeeCore.get().getLogger().info("Red: " + fightEndsPacket.getRedPlayers() + " " + redTeamSize + " " + redPlayerFactor + " " + timeFactor + " " + redEloFactor + " " + rematchFactor + " " + redWinFactor + " " + divisionFactor + " " + redEloGain); - - update(fightEndsPacket.getBluePlayers(), fightEndsPacket.getGameMode(), blueEloGain); - update(fightEndsPacket.getRedPlayers(), fightEndsPacket.getGameMode(), redEloGain); - } - - private void update(List players, String gameMode, int eloGain) { - for (int player : players) { - // BungeeCore.get().getLogger().log(Level.INFO, "Player: " + player + " Elo: " + UserElo.getEloOrDefault(player, gameMode) + " Factor: " + factor); - int playerElo = UserElo.getEloOrDefault(player, gameMode); - playerElo += eloGain; - if (playerElo < 0) playerElo = 0; - - int oldProgression = UserElo.getProgression(player, gameMode); - UserElo.setElo(player, gameMode, playerElo); - int newProgression = UserElo.getProgression(player, gameMode); - - animate(player(player), UserElo.toEmblem(oldProgression).trim(), UserElo.toEmblem(newProgression).trim(), (oldProgression < newProgression) ? "§a" : "§c", eloGain); - } - } - - private void animate(Player player, String oldEmblem, String newEmblem, String arrowColor, int eloGain) { - if (player == null) - return; - - IntFunction getRankup = getEmblemTransition(oldEmblem, newEmblem, arrowColor); - - String color = ((eloGain > 0) ? "§a+" : (eloGain == 0 ? "§7" : "§c")); - - double eloStep = eloGain / 40.0; - for (int i = 0; i < 40; i++) { - Component eloGainComponent = Chatter.SERIALIZER.deserialize(color + (int) (eloStep * (i + 1))); - int finalI = i; - VelocityCore.schedule(() -> player.showTitle(Title.title( - Chatter.SERIALIZER.deserialize(getRankup.apply(finalI)), - eloGainComponent, - Title.Times.times(Duration.ofMillis(finalI == 0 ? 250 : 0), Duration.ofSeconds(2), Duration.ofMillis(finalI == 39 ? 250 : 0)) - ))).delay(i * 50L, TimeUnit.MILLISECONDS).schedule(); - } - } - - private static IntFunction getEmblemTransition(String oldEmblem, String newEmblem, String arrowColor) { - String finalOldEmblem = (oldEmblem.isEmpty() ? "/" : oldEmblem).trim(); - String finalNewEmblem = (newEmblem.isEmpty() ? "/" : newEmblem).trim(); - - return i -> { - if (oldEmblem.equals(newEmblem)) return "§8" + finalOldEmblem; - if (i < 8) return "§8" + finalOldEmblem; - if (i < 16) return "§8" + finalOldEmblem + arrowColor + " >"; - if (i < 24) return "§8" + finalOldEmblem + arrowColor + " >>"; - if (i < 32) return "§8" + finalOldEmblem + arrowColor + " >>>"; - return "§8" + finalOldEmblem + arrowColor + " >>> §8" + finalNewEmblem; - }; - } - - private Player player(int userId) { - return VelocityCore.getProxy().getPlayer(SteamwarUser.byId(userId).getUUID()).orElse(null); - } - - private double getTimeFactor(int duration) { - if (duration <= 10) { - return 0.5; - } - if (duration <= 60) { - return 0.8; - } - return 1.0; - } - - private double getRematchFactor(FightEndsPacket fightEndsPacket) { - gameModeGames.computeIfAbsent(fightEndsPacket.getGameMode(), s -> new LinkedList<>()).add(new Game(fightEndsPacket.getBluePlayers(), fightEndsPacket.getRedPlayers())); - - LinkedList games = gameModeGames.get(fightEndsPacket.getGameMode()); - while (!games.isEmpty()) { - Game game = games.getFirst(); - if (game.livedMillis() > REMATCH_LIFETIME) { - games.removeFirst(); - } else { - break; - } - } - - long rematchCount = games.stream().filter(game -> game.isSame(fightEndsPacket.getBluePlayers(), fightEndsPacket.getRedPlayers())).count(); - return 1.0 / rematchCount; - } - - @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/VelocityCore/src/de/steamwar/velocitycore/network/handlers/EloSchemHandler.java b/VelocityCore/src/de/steamwar/velocitycore/network/handlers/EloSchemHandler.java deleted file mode 100644 index cd291de7..00000000 --- a/VelocityCore/src/de/steamwar/velocitycore/network/handlers/EloSchemHandler.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 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.velocitycore.network.handlers; - -import de.steamwar.sql.GameModeConfig; -import de.steamwar.linkage.Linked; -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; -import de.steamwar.velocitycore.ArenaMode; - -@Linked -public class EloSchemHandler extends PacketHandler { - - private static final int K = 20; - - public static boolean publicVsPrivate(FightEndsPacket packet) { - if (packet.getRedSchem() == -1 && packet.getBlueSchem() == -1) { - return false; - } - SchematicNode blueSchem = SchematicNode.getSchematicNode(packet.getBlueSchem()); - SchematicNode redSchem = SchematicNode.getSchematicNode(packet.getRedSchem()); - return (blueSchem.getOwner() == 0) != (redSchem.getOwner() == 0); - } - - @Handler - public void handle(FightEndsPacket fightEndsPacket) { - SchematicType type = SchematicType.fromDB(fightEndsPacket.getGameMode()); - if (type == null) return; - GameModeConfig arenaMode = ArenaMode.getBySchemType(type); - if (!arenaMode.Server.Ranked) return; - - if (publicVsPrivate(fightEndsPacket)) - 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(redSchemElo, blueSchemElo, fightEndsPacket.getRedSchem(), blueResult); - calcSchemElo(blueSchemElo, redSchemElo, fightEndsPacket.getBlueSchem(), 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)); - } -} From b517fe3ad0f48e380ce7364da2da7f9711575cb9 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sat, 20 Dec 2025 21:26:42 +0100 Subject: [PATCH 2/3] Remove SchemElo and UserElo --- .../SQL/src/de/steamwar/sql/Season.java | 61 ------------------- WebsiteBackend/src/de/steamwar/sql/Stats.kt | 11 +--- 2 files changed, 1 insertion(+), 71 deletions(-) delete mode 100644 CommonCore/SQL/src/de/steamwar/sql/Season.java diff --git a/CommonCore/SQL/src/de/steamwar/sql/Season.java b/CommonCore/SQL/src/de/steamwar/sql/Season.java deleted file mode 100644 index 588717a5..00000000 --- a/CommonCore/SQL/src/de/steamwar/sql/Season.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 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.sql; - -import java.util.Calendar; - -public class Season { - private Season() {} - - public static int getSeason() { - Calendar calendar = Calendar.getInstance(); - int yearIndex = calendar.get(Calendar.MONTH) / 4; - return (calendar.get(Calendar.YEAR) * 3 + yearIndex); - } - - public static String getSeasonStart() { - Calendar calendar = Calendar.getInstance(); - int month = calendar.get(Calendar.MONTH); - if (month <= 3) { - return calendar.get(Calendar.YEAR) + "-1-1"; - } else if (month <= 7) { - return calendar.get(Calendar.YEAR) + "-5-1"; - } else { - return calendar.get(Calendar.YEAR) + "-9-1"; - } - } - - public static String convertSeasonToString(int season){ - if (season == -1) return ""; - int yearSeason = season % 3; - int year = (season - yearSeason) / 3; - return String.format("%d-%d", year, yearSeason + 1); - } - - public static int convertSeasonToNumber(String season){ - if (season.isEmpty()) return -1; - String[] split = season.split("-"); - try { - return Integer.parseInt(split[0]) * 3 + Integer.parseInt(split[1]) - 1; - } catch (NumberFormatException e) { - return -1; - } - } -} diff --git a/WebsiteBackend/src/de/steamwar/sql/Stats.kt b/WebsiteBackend/src/de/steamwar/sql/Stats.kt index 9cb546dc..ea0a0fef 100644 --- a/WebsiteBackend/src/de/steamwar/sql/Stats.kt +++ b/WebsiteBackend/src/de/steamwar/sql/Stats.kt @@ -61,17 +61,8 @@ private val fightCount = "SELECT COUNT(*) AS num FROM FightPlayer WHERE UserID = fun getFightCount(user: SteamwarUser) = useDb { exec(fightCount, args = listOf(IntegerColumnType() to user.getId())) { getNum(it) } } -private const val rankedList = - "SELECT UserName, Elo FROM UserData, UserElo WHERE UserID = id AND GameMode = ? AND Season = ? ORDER BY Elo DESC" - fun getRankedList(gamemode: String): List> = useDb { - exec(rankedList, args = listOf(VarCharColumnType() to gamemode, IntegerColumnType() to Season.getSeason())) { - val list = mutableListOf>() - while (it.next()) { - list.add(it.getString("UserName") to it.getInt("Elo")) - } - list - } ?: emptyList() + emptyList() } private const val fightList = From a1add4f997dae87d68b331bc79f207c97b18df7a Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sat, 20 Dec 2025 21:27:41 +0100 Subject: [PATCH 3/3] Remove SchemElo and UserElo --- .../src/de/steamwar/messages/BungeeCore.properties | 8 -------- .../src/de/steamwar/messages/BungeeCore_de.properties | 8 -------- 2 files changed, 16 deletions(-) diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties index 898f313f..66d439df 100644 --- a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties +++ b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties @@ -656,14 +656,6 @@ HOURS_PLAYED=§7Your playtime is§8: §e{0}h #Arena command ARENA_NOT_FOUND=§cThe specified arena could not be found -#Rank -RANK_PLAYER_NOT_FOUND=§cPlayer not found -RANK_PLAYER_SELF=§eRank §7Season §e{0} -RANK_PLAYER_FOUND=§eRank §7of §e{0} §7Season §e{1} -RANK_DATA={0} §e{1} {2} -RANK_UNPLACED=§7unranked -RANK_PLACED=§e{0}§8. §7with §e{1} §7Elo§8. - #Fabric Mod Sender MODIFICATION_BAN_MESSAGE=You tried to bypass / modify the FabricModSender! MODIFICATION_BAN_LOG={0} has tried to edit / bypass the FabricModSender! Reason: {1} diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties index 969c9c64..71e55412 100644 --- a/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties +++ b/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties @@ -624,14 +624,6 @@ HOURS_PLAYED=§7Deine Spielzeit beträgt§8: §e{0}h #Arena command ARENA_NOT_FOUND=§cDie angegebene Arena konnte nicht gefunden werden -#Rank -RANK_PLAYER_NOT_FOUND=§cSpieler nicht gefunden -RANK_PLAYER_SELF=§eRang §7Saison §e{0} -RANK_PLAYER_FOUND=§eRang §7von §e{0} §7Saison §e{1} -RANK_DATA={0} §e{1} {2} -RANK_UNPLACED=§7unplatziert -RANK_PLACED=§e{0}§8. §7mit §e{1} §7Elo§8. - #Fabric Mod Sender MODIFICATION_BAN_MESSAGE=Du hast probiert den FabricModSender zu umgehen / zu modifizieren! MODIFICATION_BAN_LOG={0} hat probiert den Fabric Mod Sender zu editieren / umzugehen! Grund: {1}