Ranked #306
@ -24,11 +24,13 @@ import de.steamwar.bungeecore.ArenaMode;
|
||||
import de.steamwar.bungeecore.comms.SpigotHandler;
|
||||
import de.steamwar.bungeecore.comms.packets.FightEndsPacket;
|
||||
import de.steamwar.bungeecore.sql.SchemElo;
|
||||
import de.steamwar.bungeecore.sql.SchemNode;
|
||||
import de.steamwar.bungeecore.sql.SchematicNode;
|
||||
import de.steamwar.bungeecore.sql.SchematicType;
|
||||
import de.steamwar.bungeecore.sql.UserElo;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FightEndsHandler implements SpigotHandler {
|
||||
Lixfel markierte diese Unterhaltung als gelöst
Veraltet
|
||||
|
||||
private int K = 20;
|
||||
@ -41,15 +43,17 @@ public class FightEndsHandler implements SpigotHandler {
|
||||
return;
|
||||
}
|
||||
YoyoNow markierte diese Unterhaltung als gelöst
Lixfel
hat
Diese Ratio-Berechnung finde ich komplexer als nötig, sollte sich einfacher formulieren lassen Diese Ratio-Berechnung finde ich komplexer als nötig, sollte sich einfacher formulieren lassen
YoyoNow
hat
Hast du eine Idee, ich wüsste nicht wie außer das ich das 1- rausnehmen kann Hast du eine Idee, ich wüsste nicht wie außer das ich das 1- rausnehmen kann
Lixfel
hat
ratio = bluePlayerSize > redPlayerSize ? redPlayerSize / bluePlayerSize : bluePlayerSize / redPlayerSize if ratio < 0.6 return; ratio = bluePlayerSize > redPlayerSize ? redPlayerSize / bluePlayerSize : bluePlayerSize / redPlayerSize
if ratio < 0.6 return;
|
||||
|
||||
double playerRatio = 1 - (Math.min(fightEndsPacket.getBluePlayers().size(), fightEndsPacket.getRedPlayers().size()) / (double )Math.max(fightEndsPacket.getBluePlayers().size(), fightEndsPacket.getRedPlayers().size()));
|
||||
if (playerRatio >= 0.4) {
|
||||
int bluePlayerSize = fightEndsPacket.getBluePlayers().size();
|
||||
int redPlayerSize = fightEndsPacket.getRedPlayers().size();
|
||||
double playerRatio = bluePlayerSize > redPlayerSize ? (double) redPlayerSize / bluePlayerSize : (double) bluePlayerSize / redPlayerSize;
|
||||
if (playerRatio < 0.6) {
|
||||
YoyoNow markierte diese Unterhaltung als gelöst
Veraltet
Lixfel
hat
Statt schemOwner könntest du dir hier direkt bluePublic etc. speichern (weil das brauchst du dann ja mehrfach unten) Statt schemOwner könntest du dir hier direkt bluePublic etc. speichern (weil das brauchst du dann ja mehrfach unten)
|
||||
return;
|
||||
}
|
||||
|
||||
YoyoNow markierte diese Unterhaltung als gelöst
Veraltet
Lixfel
hat
Das müsste ein XOR ^ sein Das müsste ein XOR ^ sein
|
||||
int blueSchemOwner = SchemNode.getSchematicOwner(fightEndsPacket.getBlueSchem());
|
||||
int redSchemOwner = SchemNode.getSchematicOwner(fightEndsPacket.getRedSchem());
|
||||
boolean bluePublic = SchematicNode.getSchematicNode(fightEndsPacket.getBlueSchem()).getId() == 0;
|
||||
boolean redPublic = SchematicNode.getSchematicNode(fightEndsPacket.getRedSchem()).getId() == 0;
|
||||
|
||||
if ((blueSchemOwner == 0 && redSchemOwner != 0) || (blueSchemOwner != 0 && redSchemOwner == 0)) {
|
||||
if (bluePublic ^ redPublic) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -71,15 +75,16 @@ public class FightEndsHandler implements SpigotHandler {
|
||||
SchemElo.setElo(fightEndsPacket.getBlueSchem(), (int) Math.round(blueSchemElo + K * (blueResult - blueWinExpectation)));
|
||||
SchemElo.setElo(fightEndsPacket.getRedSchem(), (int) Math.round(redSchemElo + K * (1 - blueResult - redWinExpectation)));
|
||||
|
||||
if (blueSchemOwner != 0 && redSchemOwner != 0) {
|
||||
for (int bluePlayer : fightEndsPacket.getBluePlayers()) {
|
||||
int playerElo = UserElo.getElo(bluePlayer, fightEndsPacket.getGameMode()).orElse(1000);
|
||||
UserElo.setElo(bluePlayer, fightEndsPacket.getGameMode(), (int) Math.round(playerElo + K * (blueResult - blueWinExpectation)));
|
||||
}
|
||||
for (int redPlayer : fightEndsPacket.getRedPlayers()) {
|
||||
int playerElo = UserElo.getElo(redPlayer, fightEndsPacket.getGameMode()).orElse(1000);
|
||||
UserElo.setElo(redPlayer, fightEndsPacket.getGameMode(), (int) Math.round(playerElo + K * (1 - blueResult - redWinExpectation)));
|
||||
}
|
||||
if (!bluePublic) {
|
||||
calculateEloOfTeam(fightEndsPacket.getBluePlayers(), fightEndsPacket.getGameMode(), blueResult - blueWinExpectation);
|
||||
YoyoNow markierte diese Unterhaltung als gelöst
Veraltet
Lixfel
hat
Du hast hier sehr viel Codedopplung drin, würde mir eine teamunabhängige Abstrahierung wünschen. Du hast hier sehr viel Codedopplung drin, würde mir eine teamunabhängige Abstrahierung wünschen.
|
||||
calculateEloOfTeam(fightEndsPacket.getRedPlayers(), fightEndsPacket.getGameMode(), 1 - blueResult - blueWinExpectation);
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateEloOfTeam(List<Integer> team, String gameMode, double factor) {
|
||||
for (int player : team) {
|
||||
int playerElo = UserElo.getElo(player, gameMode).orElse(1000);
|
||||
UserElo.setElo(player, gameMode, (int) Math.round(playerElo + K * factor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ public class ChatListener extends BasicListener {
|
||||
}
|
||||
|
||||
private void publicChat(SteamwarUser user, ProxiedPlayer sender, String message){
|
||||
String name = getEmblem(user) + sender.getDisplayName();
|
||||
String name = UserElo.getEmblem(user) + sender.getDisplayName();
|
||||
String chatcolor = user.getUserGroup().getChatColorCode();
|
||||
|
||||
if(user.getUserGroup() != UserGroup.Member || user.getTeam() == 12 || user.getTeam() == 285 || user.getTeam() == 54)
|
||||
@ -227,35 +227,6 @@ public class ChatListener extends BasicListener {
|
||||
BungeeCore.log(sender.getServer().getInfo(), msg);
|
||||
}
|
||||
|
||||
private static String getEmblem(SteamwarUser user) {
|
||||
int maxEloOfPlayer = 0;
|
||||
ArenaMode arenaMode = null;
|
||||
for (ArenaMode mode : ArenaMode.getAllModes()) {
|
||||
if (!mode.isRanked()) continue;
|
||||
if (UserElo.getFightsOfSeason(user.getId(), mode.getSchemType()) < 10) continue;
|
||||
|
||||
Optional<Integer> currentElo = UserElo.getElo(user.getId(), mode.getSchemType());
|
||||
if (currentElo.isPresent() && currentElo.get() > maxEloOfPlayer) {
|
||||
maxEloOfPlayer = currentElo.get();
|
||||
arenaMode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
if (arenaMode == null) return "";
|
||||
int maxEloOfGameMode = UserElo.getMaxElo(arenaMode.getSchemType());
|
||||
return getEmblem(maxEloOfPlayer, maxEloOfGameMode);
|
||||
}
|
||||
|
||||
private static String getEmblem(int maxEloOfPlayer, int maxEloOfGameMode) {
|
||||
if (maxEloOfPlayer > maxEloOfGameMode * 0.99) return "§5❂ ";
|
||||
if (maxEloOfPlayer > maxEloOfGameMode * 0.94) return "§c✹ ";
|
||||
if (maxEloOfPlayer > maxEloOfGameMode * 0.84) return "§b✸ ";
|
||||
if (maxEloOfPlayer > maxEloOfGameMode * 0.69) return "§a✷ ";
|
||||
if (maxEloOfPlayer > maxEloOfGameMode * 0.49) return "§e✶ ";
|
||||
if (maxEloOfPlayer > maxEloOfGameMode * 0.26) return "§f✦ ";
|
||||
return "§7✧ ";
|
||||
}
|
||||
|
||||
private void localChat(ChatEvent e, String [] command){
|
||||
YoyoNow markierte diese Unterhaltung als gelöst
Veraltet
Lixfel
hat
Das hier bei jeder einzelnen Chatnachricht durchzuführen ist sehr wahrscheinlich performanceproblematisch. Besser wäre hier ein Cache und ich würde die Emblemberechnung eher ungerne hier im ChatListener drin haben wollen, eher in UserElo. Das hier bei jeder einzelnen Chatnachricht durchzuführen ist sehr wahrscheinlich performanceproblematisch. Besser wäre hier ein Cache und ich würde die Emblemberechnung eher ungerne hier im ChatListener drin haben wollen, eher in UserElo.
YoyoNow
hat
Ich muss aber alle gecached embleme killen, wenn es einen neuen max gibt und für dich wenn du eine neue elo erhälst richtig? Ich muss aber alle gecached embleme killen, wenn es einen neuen max gibt und für dich wenn du eine neue elo erhälst richtig?
Lixfel
hat
Es reicht auch, wenn es nach einer Stunde angepasst wird... Es reicht auch, wenn es nach einer Stunde angepasst wird...
YoyoNow
hat
Würde ich lieber nicht machen, ich würde gerne sie so schnell geupdated wie möglich haben. Würde ich lieber nicht machen, ich würde gerne sie so schnell geupdated wie möglich haben.
Lixfel
hat
Dann kannst du die Embleme dennoch cachen. Und ob sie so schnell geupdatet werden wie möglich oder nicht, dazwischen liegen bis zu 3 Kämpfe (in etwa).... Es ist also ziemlich egal und dafür ein heidenaufwand, das Echtzeit zu halten. Dann kannst du die Embleme dennoch cachen. Und ob sie so schnell geupdatet werden wie möglich oder nicht, dazwischen liegen bis zu 3 Kämpfe (in etwa).... Es ist also ziemlich egal und dafür ein heidenaufwand, das Echtzeit zu halten.
YoyoNow
hat
Ich sehe jetzt nicht unbedingt so viel aufwand darin, guck dir gleich einfach mal meine Lösung an und mecker dann gerne nochmal rum, dann schmeiße ich es gerne weiter raus. Ich sehe jetzt nicht unbedingt so viel aufwand darin, guck dir gleich einfach mal meine Lösung an und mecker dann gerne nochmal rum, dann schmeiße ich es gerne weiter raus.
|
||||
ProxiedPlayer sender = (ProxiedPlayer) e.getSender();
|
||||
BungeeCore.log(sender, e.getMessage());
|
||||
|
@ -24,7 +24,6 @@ public class SchemElo {
|
||||
|
||||
private static final Statement elo = new Statement("SELECT SchemElo FROM Elo WHERE SchemID = ? AND Season = ?");
|
||||
private static final Statement setElo = new Statement("UPDATE SchemElo SET Elo = ? WHERE Season = ? AND SchemID = ?");
|
||||
// private static final Statement place = new Statement("SELECT COUNT(*) AS Place FROM SchemElo WHERE Elo > ? AND Season = ?");
|
||||
|
||||
YoyoNow markierte diese Unterhaltung als gelöst
Veraltet
Lixfel
hat
Wird vorrausichtlich Ingame nie benötigt (MC Chat ist nicht unbedingt praktisch zum Anzeigen von Bestenlisten) Wird vorrausichtlich Ingame nie benötigt (MC Chat ist nicht unbedingt praktisch zum Anzeigen von Bestenlisten)
|
||||
public static int getElo(int schemID) {
|
||||
return getElo(Season.getSeason(), schemID);
|
||||
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 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.sql;
|
||||
|
||||
public class SchemNode {
|
||||
private SchemNode() {}
|
||||
|
||||
private static final Statement getSchemOwner = new Statement("SELECT NodeOwner FROM SchematicNode WHERE NodeId = ?");
|
||||
|
||||
public static int getSchematicOwner(int schemId) {
|
||||
return getSchemOwner.select(rs -> {
|
||||
return rs.getInt("NodeOwner");
|
||||
}, schemId);
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
|
||||
package de.steamwar.bungeecore.sql;
|
||||
|
||||
import de.steamwar.bungeecore.ArenaMode;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@ -30,9 +31,9 @@ public class UserElo {
|
||||
private UserElo() {
|
||||
}
|
||||
|
||||
private static Integer cachedSeason = null;
|
||||
private static final Map<Key, Optional<Integer>> userEloCache = new HashMap<>();
|
||||
YoyoNow markierte diese Unterhaltung als gelöst
Veraltet
Lixfel
hat
Da lieber eine Map<Map<>>, das bläst sich dann weniger auf. Da lieber eine Map<Map<>>, das bläst sich dann weniger auf.
YoyoNow
hat
Wie meinst du das genau? Wie meinst du das genau?
Lixfel
hat
HashMaps brauchen zur Kollisionsvermeidung immer Freiraum. Je kleiner die HashMaps bleiben, desto besser. HashMaps brauchen zur Kollisionsvermeidung immer Freiraum. Je kleiner die HashMaps bleiben, desto besser.
YoyoNow
hat
Würdest du dann GameMode UserId oder UserId GameMode als reihenfolge wählen? Würdest du dann GameMode UserId oder UserId GameMode als reihenfolge wählen?
Lixfel
hat
Definitiv Map<GameMode, Map<User, >> Definitiv Map<GameMode, Map<User, >>
|
||||
private static final Map<String, Integer> maxEloCache = new HashMap<>();
|
||||
private static final Map<Integer, String> emblemCache = new HashMap<>();
|
||||
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
@ -47,38 +48,15 @@ public class UserElo {
|
||||
private static final Statement maxElo = new Statement("SELECT MAX(Elo) AS MaxElo FROM UserElo WHERE Season = ? AND GameMode = ?");
|
||||
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(?)");
|
||||
|
||||
YoyoNow markierte diese Unterhaltung als gelöst
Veraltet
Lixfel
hat
Du clearst den Cache eh schon stündlich, das ist häufig genug auch für Seasonänderungen. Du clearst den Cache eh schon stündlich, das ist häufig genug auch für Seasonänderungen.
|
||||
private static void clearCacheIfNeeded(int season) {
|
||||
int currentSeason = Season.getSeason();
|
||||
if (currentSeason != season) {
|
||||
return;
|
||||
}
|
||||
if (cachedSeason != null && cachedSeason != currentSeason) {
|
||||
clearCache();
|
||||
cachedSeason = currentSeason;
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<Integer> getElo(int userID, String gameMode) {
|
||||
return getElo(Season.getSeason(), userID, gameMode);
|
||||
}
|
||||
|
||||
public static Optional<Integer> getElo(int season, int userID, String gameMode) {
|
||||
clearCacheIfNeeded(season);
|
||||
if (season == Season.getSeason()) {
|
||||
Key key = new Key(userID, gameMode);
|
||||
return userEloCache.computeIfAbsent(key, k -> {
|
||||
return elo.select(rs -> {
|
||||
if (rs.next())
|
||||
return Optional.of(rs.getInt("UserElo"));
|
||||
return Optional.empty();
|
||||
});
|
||||
});
|
||||
}
|
||||
return elo.select(rs -> {
|
||||
if (rs.next())
|
||||
return Optional.of(rs.getInt("Elo"));
|
||||
return Optional.empty();
|
||||
}, userID, gameMode, season);
|
||||
Key key = new Key(userID, gameMode);
|
||||
return userEloCache.computeIfAbsent(key, k -> {
|
||||
return elo.select(rs -> {
|
||||
if (rs.next())
|
||||
return Optional.of(rs.getInt("Elo"));
|
||||
return Optional.empty();
|
||||
}, userID, gameMode, Season.getSeason());
|
||||
});
|
||||
}
|
||||
|
||||
YoyoNow markierte diese Unterhaltung als gelöst
Veraltet
Lixfel
hat
Wenn hier eh schon mit Integer gearbeitet wird, kann man das Optional auch weglassen... Wenn hier eh schon mit Integer gearbeitet wird, kann man das Optional auch weglassen...
YoyoNow
hat
Würde ich ungern, weil so kann man darauf mit Würde ich ungern, weil so kann man darauf mit `.orElse()` ziemlich gut einen default direkt auswählen.
YoyoNow
hat
Und halt Optional.empty() als es gibt keinen wert in der db wählen, macht es für die emblem berechnung angenehmer, als mit einem spezial value zu arbeiten. Und halt Optional.empty() als es gibt keinen wert in der db wählen, macht es für die emblem berechnung angenehmer, als mit einem spezial value zu arbeiten.
|
||||
public static int getFightsOfSeason(int userID, String gameMode) {
|
||||
@ -90,59 +68,78 @@ public class UserElo {
|
||||
}
|
||||
|
||||
public static int getMaxElo(String gameMode) {
|
||||
return getMaxElo(Season.getSeason(), gameMode);
|
||||
}
|
||||
|
||||
public static int getMaxElo(int season, String gameMode) {
|
||||
clearCacheIfNeeded(season);
|
||||
if (season == Season.getSeason()) {
|
||||
return maxEloCache.computeIfAbsent(gameMode, gm -> {
|
||||
return maxElo.select(rs -> {
|
||||
if (rs.next())
|
||||
return rs.getInt("MaxElo");
|
||||
return -1;
|
||||
});
|
||||
});
|
||||
}
|
||||
return maxElo.select(rs -> {
|
||||
if (rs.next())
|
||||
return rs.getInt("MaxElo");
|
||||
return -1;
|
||||
}, season, gameMode);
|
||||
return maxEloCache.computeIfAbsent(gameMode, gm -> {
|
||||
return 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) {
|
||||
setElo(Season.getSeason(), userId, gameMode, elo);
|
||||
}
|
||||
|
||||
public static void setElo(int season, int userId, String gameMode, int elo) {
|
||||
clearCacheIfNeeded(season);
|
||||
if (season == Season.getSeason()) {
|
||||
Key key = new Key(userId, gameMode);
|
||||
userEloCache.put(key, Optional.of(elo));
|
||||
maxEloCache.compute(gameMode, (gm, max) -> {
|
||||
if (max == null || max < elo)
|
||||
return elo;
|
||||
return max;
|
||||
});
|
||||
}
|
||||
setElo.update(elo, season, userId, gameMode);
|
||||
emblemCache.remove(userId);
|
||||
Key key = new Key(userId, gameMode);
|
||||
userEloCache.put(key, Optional.of(elo));
|
||||
maxEloCache.compute(gameMode, (gm, max) -> {
|
||||
if (max == null || max < elo) {
|
||||
emblemCache.clear();
|
||||
return elo;
|
||||
}
|
||||
return max;
|
||||
});
|
||||
setElo.update(elo, Season.getSeason(), userId, gameMode);
|
||||
}
|
||||
|
||||
public static int getPlacement(int elo, String gameMode) {
|
||||
return getPlacement(Season.getSeason(), elo, gameMode);
|
||||
}
|
||||
|
||||
public static int getPlacement(int season, int elo, String gameMode) {
|
||||
return place.select(rs -> {
|
||||
if (rs.next())
|
||||
YoyoNow markierte diese Unterhaltung als gelöst
Veraltet
Lixfel
hat
Wann ist season hier != currentSeason? Wann ist season hier != currentSeason?
|
||||
return rs.getInt("Place");
|
||||
return -1;
|
||||
}, gameMode, elo, season);
|
||||
}, gameMode, elo, Season.getSeason());
|
||||
}
|
||||
|
||||
public static String getEmblem(SteamwarUser user) {
|
||||
if (emblemCache.containsKey(user.getId())) {
|
||||
return emblemCache.get(user.getId());
|
||||
}
|
||||
|
||||
int maxEloOfPlayer = 0;
|
||||
ArenaMode arenaMode = null;
|
||||
for (ArenaMode mode : ArenaMode.getAllModes()) {
|
||||
if (!mode.isRanked()) continue;
|
||||
if (UserElo.getFightsOfSeason(user.getId(), mode.getSchemType()) < 10) continue;
|
||||
|
||||
Optional<Integer> currentElo = UserElo.getElo(user.getId(), mode.getSchemType());
|
||||
if (currentElo.isPresent() && currentElo.get() > maxEloOfPlayer) {
|
||||
maxEloOfPlayer = currentElo.get();
|
||||
arenaMode = mode;
|
||||
}
|
||||
}
|
||||
YoyoNow markierte diese Unterhaltung als gelöst
Veraltet
Lixfel
hat
Selbe Frage Selbe Frage
|
||||
|
||||
if (arenaMode == null) {
|
||||
emblemCache.put(user.getId(), "");
|
||||
return "";
|
||||
}
|
||||
int maxEloOfGameMode = UserElo.getMaxElo(arenaMode.getSchemType());
|
||||
String emblem = getEmblem(maxEloOfPlayer, maxEloOfGameMode);
|
||||
emblemCache.put(user.getId(), emblem);
|
||||
return emblem;
|
||||
}
|
||||
|
||||
private static String getEmblem(int maxEloOfPlayer, int maxEloOfGameMode) {
|
||||
if (maxEloOfPlayer > maxEloOfGameMode * 0.99) return "§5❂";
|
||||
if (maxEloOfPlayer > maxEloOfGameMode * 0.94) return "§c✹";
|
||||
if (maxEloOfPlayer > maxEloOfGameMode * 0.84) return "§b✸";
|
||||
if (maxEloOfPlayer > maxEloOfGameMode * 0.69) return "§a✷";
|
||||
if (maxEloOfPlayer > maxEloOfGameMode * 0.49) return "§e✶";
|
||||
if (maxEloOfPlayer > maxEloOfGameMode * 0.26) return "§f✦";
|
||||
YoyoNow markierte diese Unterhaltung als gelöst
Veraltet
Lixfel
hat
. .
|
||||
return "§7✧";
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
userEloCache.clear();
|
||||
maxEloCache.clear();
|
||||
emblemCache.clear();
|
||||
}
|
||||
}
|
||||
|
Bitte überall mal deine Imports aufräumen! (Warum hast du das nicht autoaktiviert?)
Keine ahnung