diff --git a/src/de/steamwar/sql/CheckedSchematic.java b/src/de/steamwar/sql/CheckedSchematic.java index 71fe24a..e173d41 100644 --- a/src/de/steamwar/sql/CheckedSchematic.java +++ b/src/de/steamwar/sql/CheckedSchematic.java @@ -21,6 +21,7 @@ package de.steamwar.sql; import de.steamwar.sql.internal.Field; import de.steamwar.sql.internal.SelectStatement; +import de.steamwar.sql.internal.Statement; import de.steamwar.sql.internal.Table; import lombok.AllArgsConstructor; import lombok.Getter; @@ -33,11 +34,25 @@ public class CheckedSchematic { private static final Table table = new Table<>(CheckedSchematic.class); private static final SelectStatement statusOfNode = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != 'Prüfvorgang abgebrochen' ORDER BY EndTime DESC"); + private static final SelectStatement nodeHistory = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != '' AND DeclineReason != 'Prüfvorgang abgebrochen' ORDER BY EndTime DESC"); + private static final Statement insert = table.insertAll(); + + public static void create(int nodeId, String name, int owner, int validator, Timestamp startTime, Timestamp endTime, String reason){ + insert.update(nodeId, owner, name, validator, startTime, endTime, reason); + } + + public static void create(SchematicNode node, int validator, Timestamp startTime, Timestamp endTime, String reason){ + create(node.getId(), node.getName(), node.getOwner(), validator, startTime, endTime, reason); + } public static List getLastDeclinedOfNode(int node){ return statusOfNode.listSelect(node); } + public static List previousChecks(SchematicNode node) { + return nodeHistory.listSelect(node.getId()); + } + @Field(nullable = true) private final Integer nodeId; @Field diff --git a/src/de/steamwar/sql/IgnoreSystem.java b/src/de/steamwar/sql/IgnoreSystem.java new file mode 100644 index 0000000..d6ce26a --- /dev/null +++ b/src/de/steamwar/sql/IgnoreSystem.java @@ -0,0 +1,59 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2023 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.Field; +import de.steamwar.sql.internal.SelectStatement; +import de.steamwar.sql.internal.Statement; +import de.steamwar.sql.internal.Table; +import lombok.AllArgsConstructor; + +import java.sql.ResultSet; +import java.util.UUID; + +@AllArgsConstructor +public class IgnoreSystem { + + private static final Table table = new Table<>(IgnoreSystem.class, "IgnoredPlayers"); + private static final SelectStatement select = table.select(Table.PRIMARY); + private static final Statement insert = table.insertAll(); + private static final Statement delete = table.delete(Table.PRIMARY); + + @Field(keys = {Table.PRIMARY}) + private final int ignorer; + @Field(keys = {Table.PRIMARY}) + private final int ignored; + + public static boolean isIgnored(UUID ignorer, UUID ignored){ + return isIgnored(SteamwarUser.get(ignorer), SteamwarUser.get(ignored)); + } + + public static boolean isIgnored(SteamwarUser ignorer, SteamwarUser ignored) { + return select.select(ResultSet::next, ignorer.getId(), ignored.getId()); + } + + public static void ignore(SteamwarUser ignorer, SteamwarUser ignored) { + insert.update(ignorer.getId(), ignored.getId()); + } + + public static void unIgnore(SteamwarUser ignorer, SteamwarUser ignored) { + delete.update(ignorer.getId(), ignored.getId()); + } +} diff --git a/src/de/steamwar/sql/SchemElo.java b/src/de/steamwar/sql/SchemElo.java index 1f795d6..0e92cfd 100644 --- a/src/de/steamwar/sql/SchemElo.java +++ b/src/de/steamwar/sql/SchemElo.java @@ -27,8 +27,7 @@ import lombok.AllArgsConstructor; @AllArgsConstructor public class SchemElo { - - public static final int ELO_DEFAULT = 1000; + private static final int ELO_DEFAULT = 1000; private static final Table table = new Table<>(SchemElo.class); private static final SelectStatement select = table.select(Table.PRIMARY); diff --git a/src/de/steamwar/sql/UserElo.java b/src/de/steamwar/sql/UserElo.java new file mode 100644 index 0000000..5de692c --- /dev/null +++ b/src/de/steamwar/sql/UserElo.java @@ -0,0 +1,178 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2023 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.Field; +import de.steamwar.sql.internal.SelectStatement; +import de.steamwar.sql.internal.Statement; +import de.steamwar.sql.internal.Table; +import lombok.AllArgsConstructor; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +@AllArgsConstructor +public class UserElo { + private static final int ELO_DEFAULT = 1000; + + private static final Map>> gameModeUserEloCache = new ConcurrentHashMap<>(); + private static final Map maxEloCache = new ConcurrentHashMap<>(); + private static final Map emblemCache = new ConcurrentHashMap<>(); + + public static void clear() { + gameModeUserEloCache.clear(); + maxEloCache.clear(); + emblemCache.clear(); + } + + private static final Table table = new Table<>(UserElo.class); + private static final SelectStatement getElo = table.select(Table.PRIMARY); + private static final Statement setElo = table.insertAll(); + private static final Statement maxElo = new Statement("SELECT MAX(Elo) AS MaxElo FROM UserElo WHERE Season = ? AND GameMode = ?"); + + private static final Statement place = new Statement("SELECT COUNT(*) AS Place FROM UserElo WHERE GameMode = ? AND Elo > ? AND Season = ?"); + private static final Statement fightsOfSeason = new Statement("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(?)"); + + @Field(keys = {Table.PRIMARY}) + private final int season; + @Field(keys = {Table.PRIMARY}) + private final String gameMode; + @Field(keys = {Table.PRIMARY}) + private final int userId; + @Field + private final int elo; + + public static int getEloOrDefault(int userID, String gameMode) { + return getElo(userID, gameMode).orElse(ELO_DEFAULT); + } + + public static Optional getElo(int userID, String gameMode) { + return gameModeUserEloCache.computeIfAbsent(gameMode, gm -> new HashMap<>()).computeIfAbsent(userID, uid -> Optional.ofNullable(getElo.select(Season.getSeason(), gameMode, userID)).map(userElo -> userElo.elo)); + } + + public static int getFightsOfSeason(int userID, String gameMode) { + return fightsOfSeason.select(rs -> { + if (rs.next()) + return rs.getInt("Fights"); + return 0; + }, userID, gameMode, Season.getSeasonStart()); + } + + private static int getMaxElo(String gameMode) { + return maxEloCache.computeIfAbsent(gameMode, gm -> maxElo.select(rs -> { + if (rs.next()) + return rs.getInt("MaxElo"); + return 0; + }, Season.getSeason(), gameMode)); + } + + public static void setElo(int userId, String gameMode, int elo) { + emblemCache.remove(userId); + + Optional oldElo = Optional.ofNullable(gameModeUserEloCache.computeIfAbsent(gameMode, gm -> new HashMap<>()).put(userId, Optional.of(elo))).orElse(Optional.empty()); + int maxElo = getMaxElo(gameMode); + if (elo > maxElo || (oldElo.isPresent() && oldElo.get() == maxElo)) { + maxEloCache.remove(gameMode); + emblemCache.clear(); + } + + setElo.update(Season.getSeason(), gameMode, userId, elo); + } + + public static int getPlacement(int elo, String gameMode) { + return place.select(rs -> { + if (rs.next()) + return rs.getInt("Place") + 1; + return -1; + }, gameMode, elo, Season.getSeason()); + } + + public static String getEmblem(SteamwarUser user, List rankedModes) { + return emblemCache.computeIfAbsent(user.getId(), userId -> { + switch( + rankedModes.stream().filter( + mode -> UserElo.getFightsOfSeason(user.getId(), mode) >= 10 + ).map( + mode -> getProgression(user.getId(), mode) + ).max(Integer::compareTo).orElse(0) + ) { + case 0: + return ""; + case 1: + return "§7✧ "; + case 2: + return "§f✦ "; + case 3: + return "§e✶ "; + case 4: + return "§a✷ "; + case 5: + return "§b✸ "; + case 6: + return "§c✹ "; + case 7: + return "§5❂ "; + default: + throw new SecurityException("Progression out of range"); + } + }); + } + + public static String getEmblemProgression(String gameMode, int userId) { + switch (getProgression(userId, gameMode)) { + case 0: + return "§8✧ ✦ ✶ ✷ ✸ ✹ ❂"; + case 1: + return "§7✧ §8✦ ✶ ✷ ✸ ✹ ❂"; + case 2: + return "§8✧ §f✦ §8✶ ✷ ✸ ✹ ❂"; + case 3: + return "§8✧ ✦ §e✶ §8✷ ✸ ✹ ❂"; + case 4: + return "§8✧ ✦ ✶ §a✷ §8✸ ✹ ❂"; + case 5: + return "§8✧ ✦ ✶ ✷ §b✸ §8✹ ❂"; + case 6: + return "§8✧ ✦ ✶ ✷ ✸ §c✹ §8❂"; + case 7: + return "§8✧ ✦ ✶ ✷ ✸ ✹ §5❂"; + default: + throw new SecurityException("Progression is not in range"); + } + } + + private static int getProgression(int userId, String gameMode) { + int elo = getElo(userId, gameMode).orElse(0); + if(elo == 0) + return 0; + int maxElo = getMaxElo(gameMode); + + if (elo > maxElo * 0.99) return 7; + if (elo > maxElo * 0.97) return 6; + if (elo > maxElo * 0.94) return 5; + if (elo > maxElo * 0.88) return 4; + if (elo > maxElo * 0.76) return 3; + if (elo > maxElo * 0.51) return 2; + return 1; + } +}