diff --git a/src/de/steamwar/sql/BannedUserIPs.java b/src/de/steamwar/sql/BannedUserIPs.java
new file mode 100644
index 0000000..9a31099
--- /dev/null
+++ b/src/de/steamwar/sql/BannedUserIPs.java
@@ -0,0 +1,66 @@
+/*
+ * 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 lombok.Getter;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+@AllArgsConstructor
+public class BannedUserIPs {
+
+ private static final Table table = new Table<>(BannedUserIPs.class);
+
+ private static final SelectStatement getByID = table.selectFields("UserID");
+ private static final SelectStatement getByIP = new SelectStatement<>(table, "SELECT * FROM BannedUserIPs WHERE IP = ? ORDER BY Timestamp DESC");
+ private static final Statement banIP = table.insert(Table.PRIMARY);
+ private static final Statement unbanIPs = table.deleteFields("UserID");
+
+ @Getter
+ @Field(keys = {Table.PRIMARY})
+ private final int userID;
+ @Getter
+ @Field(def = "CURRENT_TIMESTAMP")
+ private final Timestamp timestamp;
+ @Field(keys = {Table.PRIMARY})
+ private final String ip;
+
+ public static List get(int userID) {
+ return getByID.listSelect(userID);
+ }
+
+ public static List get(String ip) {
+ return getByIP.listSelect(ip);
+ }
+
+ public static void banIP(int userID, String ip){
+ banIP.update(userID, ip);
+ }
+
+ public static void unbanIPs(int userID) {
+ unbanIPs.update(userID);
+ }
+}
diff --git a/src/de/steamwar/sql/BauweltMember.java b/src/de/steamwar/sql/BauweltMember.java
index aa3ed93..87393e8 100644
--- a/src/de/steamwar/sql/BauweltMember.java
+++ b/src/de/steamwar/sql/BauweltMember.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.Getter;
@@ -36,6 +37,12 @@ public class BauweltMember {
private static final Table table = new Table<>(BauweltMember.class);
private static final SelectStatement getMember = table.select(Table.PRIMARY);
private static final SelectStatement getMembers = table.selectFields("BauweltID");
+ private static final Statement update = table.insertAll();
+ private static final Statement delete = table.delete(Table.PRIMARY);
+
+ public static void addMember(UUID ownerID, UUID memberID) {
+ new BauweltMember(SteamwarUser.get(ownerID).getId(), SteamwarUser.get(memberID).getId(), false, false).updateDB();
+ }
public static BauweltMember getBauMember(UUID ownerID, UUID memberID){
return getBauMember(SteamwarUser.get(ownerID).getId(), SteamwarUser.get(memberID).getId());
@@ -43,7 +50,7 @@ public class BauweltMember {
public static BauweltMember getBauMember(int ownerID, int memberID){
BauweltMember member = memberCache.get(memberID);
- if(member != null)
+ if(member != null && member.bauweltID == ownerID)
return member;
return getMember.select(ownerID, memberID);
}
@@ -63,11 +70,11 @@ public class BauweltMember {
@Field(keys = {Table.PRIMARY})
private final int memberID;
@Getter
- @Field
- private final boolean worldEdit;
+ @Field(def = "0")
+ private boolean worldEdit;
@Getter
- @Field
- private final boolean world;
+ @Field(def = "0")
+ private boolean world;
public BauweltMember(int bauweltID, int memberID, boolean worldEdit, boolean world) {
this.bauweltID = bauweltID;
@@ -76,4 +83,22 @@ public class BauweltMember {
this.world = world;
memberCache.put(memberID, this);
}
+
+ public void setWorldEdit(boolean worldEdit) {
+ this.worldEdit = worldEdit;
+ updateDB();
+ }
+
+ public void setWorld(boolean world) {
+ this.world = world;
+ updateDB();
+ }
+
+ private void updateDB(){
+ update.update(bauweltID, memberID, worldEdit, world);
+ }
+
+ public void remove(){
+ delete.update(bauweltID, memberID);
+ }
}
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/Event.java b/src/de/steamwar/sql/Event.java
index a4c30e6..7985232 100644
--- a/src/de/steamwar/sql/Event.java
+++ b/src/de/steamwar/sql/Event.java
@@ -26,17 +26,41 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import java.sql.Timestamp;
+import java.time.Instant;
+import java.util.List;
@AllArgsConstructor
public class Event {
private static final Table table = new Table<>(Event.class);
+
+ private static final SelectStatement byCurrent = new SelectStatement<>(table, "SELECT * FROM Event WHERE Start < now() AND End > now()");
private static final SelectStatement byId = table.select(Table.PRIMARY);
+ private static final SelectStatement byName = table.select("eventName");
+ private static final SelectStatement byComing = new SelectStatement<>(table, "SELECT * FROM Event WHERE Start > now()");
+
+ private static Event current = null;
+
+ public static Event get(){
+ if(current != null && current.now())
+ return current;
+
+ current = byCurrent.select();
+ return current;
+ }
public static Event get(int eventID){
return byId.select(eventID);
}
+ public static Event get(String eventName) {
+ return byName.select(eventName);
+ }
+
+ public static List getComing() {
+ return byComing.listSelect();
+ }
+
@Getter
@Field(keys = {Table.PRIMARY}, autoincrement = true)
private final int eventID;
@@ -72,4 +96,9 @@ public class Event {
public SchematicType getSchematicType() {
return schemType;
}
+
+ private boolean now() {
+ Instant now = Instant.now();
+ return now.isAfter(start.toInstant()) && now.isBefore(end.toInstant());
+ }
}
diff --git a/src/de/steamwar/sql/EventFight.java b/src/de/steamwar/sql/EventFight.java
index 60e4831..eed7f51 100644
--- a/src/de/steamwar/sql/EventFight.java
+++ b/src/de/steamwar/sql/EventFight.java
@@ -26,18 +26,41 @@ import de.steamwar.sql.internal.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
+import java.sql.Timestamp;
+import java.util.*;
+
+import static java.time.temporal.ChronoUnit.SECONDS;
+
@AllArgsConstructor
-public class EventFight {
+public class EventFight implements Comparable {
private static final Table table = new Table<>(EventFight.class);
private static final SelectStatement byId = table.select(Table.PRIMARY);
+ private static final SelectStatement allComing = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE StartTime > now() ORDER BY StartTime ASC");
+ private static final SelectStatement event = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE EventID = ? ORDER BY StartTime ASC");
+ private static final Statement reschedule = table.update(Table.PRIMARY, "StartTime");
private static final Statement setResult = table.update(Table.PRIMARY, "Ergebnis");
private static final Statement setFight = table.update(Table.PRIMARY, "Fight");
+ private static final Queue fights = new PriorityQueue<>();
+
public static EventFight get(int fightID) {
return byId.select(fightID);
}
+ public static void loadAllComingFights() {
+ fights.clear();
+ fights.addAll(allComing.listSelect());
+ }
+
+ public static List getEvent(int eventID) {
+ return event.listSelect(eventID);
+ }
+
+ public static Queue getFights() {
+ return fights;
+ }
+
@Getter
@Field
private final int eventID;
@@ -46,6 +69,15 @@ public class EventFight {
private final int fightID;
@Getter
@Field
+ private Timestamp startTime;
+ @Getter
+ @Field
+ private final String spielmodus;
+ @Getter
+ @Field
+ private final String map;
+ @Getter
+ @Field
private final int teamBlue;
@Getter
@Field
@@ -69,4 +101,32 @@ public class EventFight {
this.fight = fight;
setFight.update(fight, fightID);
}
+
+ public boolean hasFinished() {
+ return fight != 0;
+ }
+
+ public void reschedule() {
+ startTime = Timestamp.from(new Date().toInstant().plus(30, SECONDS));
+ reschedule.update(startTime, fightID);
+ }
+
+ @Override
+ public int hashCode(){
+ return fightID;
+ }
+
+ @Override
+ public boolean equals(Object o){
+ if(o == null)
+ return false;
+ if(!(o instanceof EventFight))
+ return false;
+ return fightID == ((EventFight) o).fightID;
+ }
+
+ @Override
+ public int compareTo(EventFight o) {
+ return startTime.compareTo(o.startTime);
+ }
}
diff --git a/src/de/steamwar/sql/Fight.java b/src/de/steamwar/sql/Fight.java
index 0f9eae6..efa230d 100644
--- a/src/de/steamwar/sql/Fight.java
+++ b/src/de/steamwar/sql/Fight.java
@@ -20,24 +20,49 @@
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;
import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
@AllArgsConstructor
public class Fight {
private static final Table table = new Table<>(Fight.class);
+ private static final SelectStatement getPage = new SelectStatement<>(table, "SELECT f.*, (b.NodeId IS NULL OR b.AllowReplay) AND (r.NodeId IS NULL OR r.AllowReplay) AS ReplayAllowed, (SELECT COUNT(1) FROM Replay WHERE Replay.FightID = f.FightID) as ReplayAvailable FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId ORDER BY FightID DESC LIMIT ?, ?");
private static final Statement insert = table.insertFields(true, "GameMode", "Server", "StartTime", "Duration", "BlueLeader", "RedLeader", "BlueSchem", "RedSchem", "Win", "WinCondition");
+ public static List getPage(int page, int elementsPerPage) {
+ List fights = getPage.listSelect(page * elementsPerPage, elementsPerPage);
+
+ List fightPlayers = FightPlayer.batchGet(fights.stream().map(f -> f.fightID));
+ for(Fight fight : fights) {
+ fight.initPlayers(fightPlayers);
+ }
+
+ SteamwarUser.batchCache(fightPlayers.stream().map(FightPlayer::getUserID).collect(Collectors.toSet()));
+ return fights;
+ }
+
+ public static int create(String gamemode, String server, Timestamp starttime, int duration, int blueleader, int redleader, Integer blueschem, Integer redschem, int win, String wincondition){
+ return insert.insertGetKey(gamemode, server, starttime, duration, blueleader, redleader, blueschem, redschem, win, wincondition);
+ }
+
+ @Getter
@Field(keys = {Table.PRIMARY}, autoincrement = true)
private final int fightID;
@Field
private final String gameMode;
+ @Getter
@Field
private final String server;
+ @Getter
@Field
private final Timestamp startTime;
@Field
@@ -50,12 +75,50 @@ public class Fight {
private final Integer blueSchem;
@Field(nullable = true)
private final Integer redSchem;
+ @Getter
@Field
private final int win;
@Field
private final String wincondition;
+ @Field // Virtual field for easy select
+ private final boolean replayAllowed;
+ @Field // Virtual field for easy select
+ private final boolean replayAvailable;
- public static int create(String gamemode, String server, Timestamp starttime, int duration, int blueleader, int redleader, Integer blueschem, Integer redschem, int win, String wincondition){
- return insert.insertGetKey(gamemode, server, starttime, duration, blueleader, redleader, blueschem, redschem, win, wincondition);
+ @Getter
+ private final List bluePlayers = new ArrayList<>();
+ @Getter
+ private final List redPlayers = new ArrayList<>();
+
+ public SchematicType getSchemType() {
+ return SchematicType.fromDB(gameMode);
+ }
+
+ public SteamwarUser getBlueLeader() {
+ return SteamwarUser.get(blueLeader);
+ }
+
+ public SteamwarUser getRedLeader() {
+ return SteamwarUser.get(redLeader);
+ }
+
+ public boolean replayAllowed() {
+ return replayExists() && replayAllowed;
+ }
+
+ public boolean replayExists() {
+ return getSchemType() != null && replayAvailable;
+ }
+
+ private void initPlayers(List fightPlayers) {
+ for(FightPlayer fp : fightPlayers) {
+ if(fp.getFightID() != fightID)
+ continue;
+
+ if(fp.getTeam() == 1)
+ bluePlayers.add(fp);
+ else
+ redPlayers.add(fp);
+ }
}
}
diff --git a/src/de/steamwar/sql/FightPlayer.java b/src/de/steamwar/sql/FightPlayer.java
index cc529b8..57b977c 100644
--- a/src/de/steamwar/sql/FightPlayer.java
+++ b/src/de/steamwar/sql/FightPlayer.java
@@ -20,20 +20,30 @@
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;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
@AllArgsConstructor
public class FightPlayer {
private static final Table table = new Table<>(FightPlayer.class);
private static final Statement create = table.insertAll();
+ private static final SelectStatement batchGet = new SelectStatement<>(table, "SELECT * FROM FightPlayer WHERE FightID IN ?");
+ @Getter
@Field(keys = {Table.PRIMARY})
private final int fightID;
+ @Getter
@Field(keys = {Table.PRIMARY})
private final int userID;
+ @Getter
@Field
private final int team;
@Field
@@ -46,4 +56,10 @@ public class FightPlayer {
public static void create(int fightID, int userID, boolean blue, String kit, int kills, boolean isOut) {
create.update(fightID, userID, blue ? 1 : 2, kit, kills, isOut);
}
+
+ public static List batchGet(Stream fightIds) {
+ try (SelectStatement batch = new SelectStatement<>(table, "SELECT * FROM FightPlayer WHERE FightID IN (" + fightIds.map(Object::toString).collect(Collectors.joining(", ")) + ")")) {
+ return batch.listSelect();
+ }
+ }
}
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/Mod.java b/src/de/steamwar/sql/Mod.java
new file mode 100644
index 0000000..2a4e698
--- /dev/null
+++ b/src/de/steamwar/sql/Mod.java
@@ -0,0 +1,101 @@
+/*
+ * 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.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+
+@AllArgsConstructor
+public class Mod {
+
+ static {
+ SqlTypeMapper.ordinalEnumMapper(Platform.class);
+ SqlTypeMapper.ordinalEnumMapper(ModType.class);
+ }
+
+ private static final Table table = new Table<>(Mod.class, "Mods");
+ private static final SelectStatement get = table.select(Table.PRIMARY);
+ private static final SelectStatement findFirst = new SelectStatement<>(table, "SELECT * FROM Mods WHERE ModType = 0 LIMIT 1");
+ private static final SelectStatement getPageOfType = new SelectStatement<>(table, "SELECT * FROM Mods WHERE ModType = ? ORDER BY ModName DESC LIMIT ?, ?");
+ private static final Statement insert = table.insert(Table.PRIMARY);
+ private static final Statement set = table.update(Table.PRIMARY, "ModType");
+
+ public static Mod get(String name, Platform platform) {
+ return get.select(platform, name);
+ }
+
+ public static Mod getOrCreate(String name, Platform platform) {
+ Mod mod = get(name, platform);
+ if(mod != null)
+ return mod;
+
+ insert.update(platform, name);
+ return new Mod(platform, name, ModType.UNKLASSIFIED);
+ }
+
+ public static List getAllModsFiltered(int page, int elementsPerPage, Mod.ModType filter) {
+ return Mod.getPageOfType.listSelect(filter, page * elementsPerPage, elementsPerPage);
+ }
+
+ public static Mod findFirstMod() {
+ return findFirst.select();
+ }
+
+ @Getter
+ @Field(keys = {Table.PRIMARY})
+ private final Platform platform;
+ @Getter
+ @Field(keys = {Table.PRIMARY})
+ private final String modName;
+ @Getter
+ @Field(def = "0")
+ private ModType modType;
+
+ public void setModType(Mod.ModType modType) {
+ set.update(modType, platform, modName);
+ this.modType = modType;
+ }
+
+ public enum Platform {
+ FORGE,
+ LABYMOD,
+ FABRIC
+ }
+
+ public enum ModType {
+ UNKLASSIFIED("7"),
+ GREEN("a"),
+ YELLOW("e"),
+ RED("c"),
+ YOUTUBER_ONLY("6");
+
+ ModType(String colorcode) {
+ this.colorcode = colorcode;
+ }
+ private final String colorcode;
+
+ public String getColorCode() {
+ return colorcode;
+ }
+ }
+}
diff --git a/src/de/steamwar/sql/PollAnswer.java b/src/de/steamwar/sql/PollAnswer.java
new file mode 100644
index 0000000..933f253
--- /dev/null
+++ b/src/de/steamwar/sql/PollAnswer.java
@@ -0,0 +1,77 @@
+/*
+ * 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 lombok.Getter;
+import lombok.Setter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@AllArgsConstructor
+public class PollAnswer {
+
+ @Getter
+ @Setter
+ private static String currentPoll;
+
+ private static final Table table = new Table<>(PollAnswer.class);
+
+ private static final SelectStatement get = table.select(Table.PRIMARY);
+ private static final Statement getResults = new Statement("SELECT Count(UserID) AS Times, Answer FROM PollAnswer WHERE Question = ? GROUP BY Answer ORDER BY Times ASC");
+ private static final Statement insert = table.insertAll();
+
+ @Field(keys = {Table.PRIMARY})
+ private final int userID;
+ @Field(keys = {Table.PRIMARY})
+ private final String question;
+ @Field(def = "0")
+ private int answer;
+
+ public static PollAnswer get(int userID) {
+ PollAnswer answer = get.select(userID, currentPoll);
+ if(answer == null)
+ return new PollAnswer(userID, currentPoll, 0);
+ return answer;
+ }
+
+ public static Map getCurrentResults() {
+ return getResults.select(rs -> {
+ Map retMap = new HashMap<>();
+ while (rs.next())
+ retMap.put(rs.getInt("Answer")-1, rs.getInt("Times"));
+ return retMap;
+ }, currentPoll);
+ }
+
+ public boolean hasAnswered(){
+ return answer != 0;
+ }
+
+ public void setAnswer(int answer){
+ this.answer = answer;
+ insert.update(userID, question, answer);
+ }
+}
diff --git a/src/de/steamwar/sql/Punishment.java b/src/de/steamwar/sql/Punishment.java
index 086f445..5960dce 100644
--- a/src/de/steamwar/sql/Punishment.java
+++ b/src/de/steamwar/sql/Punishment.java
@@ -19,16 +19,16 @@
package de.steamwar.sql;
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.SqlTypeMapper;
-import de.steamwar.sql.internal.Table;
+import de.steamwar.sql.internal.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
+import lombok.RequiredArgsConstructor;
import java.sql.Timestamp;
+import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Date;
+import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -40,13 +40,48 @@ public class Punishment {
SqlTypeMapper.nameEnumMapper(PunishmentType.class);
}
+ public static final Timestamp PERMA_TIME = Timestamp.from(Instant.ofEpochSecond(946674800));
+
private static final Table table = new Table<>(Punishment.class, "Punishments");
private static final SelectStatement getPunishments = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE PunishmentId IN (SELECT MAX(PunishmentId) FROM Punishments WHERE UserId = ? GROUP BY Type)");
private static final SelectStatement getPunishment = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE UserId = ? AND Type = ? ORDER BY PunishmentId DESC LIMIT 1");
+ private static final SelectStatement getAllPunishments = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE UserId = ? ORDER BY `PunishmentId` DESC");
+ private static final Statement insert = table.insertFields(true, "UserId", "Punisher", "Type", "EndTime", "Perma", "Reason");
+
+ public static Punishment getPunishmentOfPlayer(int user, PunishmentType type) {
+ return getPunishment.select(user, type);
+ }
+
+ public static Map getPunishmentsOfPlayer(int user) {
+ return getPunishments.listSelect(user).stream().collect(Collectors.toMap(Punishment::getType, punishment -> punishment));
+ }
+
+ public static List getAllPunishmentsOfPlayer(int user) {
+ return getAllPunishments.listSelect(user);
+ }
+
+ public static boolean isPunished(SteamwarUser user, Punishment.PunishmentType type, Consumer callback) {
+ Punishment punishment = Punishment.getPunishmentOfPlayer(user.getId(), type);
+ if(punishment == null || !punishment.isCurrent()) {
+ return false;
+ } else {
+ callback.accept(punishment);
+ return true;
+ }
+ }
+
+ public static Punishment createPunishment(int user, int executor, PunishmentType type, String reason, Timestamp endTime, boolean perma) {
+ if(perma && !endTime.equals(PERMA_TIME)) {
+ throw new IllegalArgumentException("Permanent punishments must have an end time of `Punishment.PERMA_TIME`");
+ }
+ int punishmentId = insert.insertGetKey(user, executor, type.name(), endTime, perma, reason);
+ return new Punishment(punishmentId, user, executor, type, Timestamp.from(Instant.now()), endTime, perma, reason);
+ }
@Field(keys = {Table.PRIMARY}, autoincrement = true)
private final int punishmentId;
@Field
+ @Getter
private final int userId;
@Field
@Getter
@@ -67,24 +102,6 @@ public class Punishment {
@Getter
private final String reason;
- public static Punishment getPunishmentOfPlayer(int user, PunishmentType type) {
- return getPunishment.select(user, type);
- }
-
- public static Map getPunishmentsOfPlayer(int user) {
- return getPunishments.listSelect(user).stream().collect(Collectors.toMap(Punishment::getType, punishment -> punishment));
- }
-
- public static boolean isPunished(SteamwarUser user, Punishment.PunishmentType type, Consumer callback) {
- Punishment punishment = Punishment.getPunishmentOfPlayer(user.getId(), type);
- if(punishment == null || !punishment.isCurrent()) {
- return false;
- } else {
- callback.accept(punishment);
- return true;
- }
- }
-
@Deprecated // Not multiling, misleading title
public String getBantime(Timestamp endTime, boolean perma) {
if (perma) {
@@ -94,15 +111,12 @@ public class Punishment {
}
}
- public int getUserId() {
- return userId;
- }
-
public boolean isCurrent() {
return isPerma() || getEndTime().after(new Date());
}
@AllArgsConstructor
+ @RequiredArgsConstructor
@Getter
public enum PunishmentType {
Ban(false, "BAN_TEAM", "BAN_PERMA", "BAN_UNTIL", "UNBAN_ERROR", "UNBAN"),
@@ -110,7 +124,10 @@ public class Punishment {
NoSchemReceiving(false, "NOSCHEMRECEIVING_TEAM", "NOSCHEMRECEIVING_PERMA", "NOSCHEMRECEIVING_UNTIL", "UNNOSCHEMRECEIVING_ERROR", "UNNOSCHEMRECEIVING"),
NoSchemSharing(false, "NOSCHEMSHARING_TEAM", "NOSCHEMSHARING_PERMA", "NOSCHEMSHARING_UNTIL", "UNNOSCHEMSHARING_ERROR", "UNNOSCHEMSHARING"),
NoSchemSubmitting(true, "NOSCHEMSUBMITTING_TEAM", "NOSCHEMSUBMITTING_PERMA", "NOSCHEMSUBMITTING_UNTIL", "UNNOSCHEMSUBMITTING_ERROR", "UNNOSCHEMSUBMITTING"),
- NoDevServer(true, "NODEVSERVER_TEAM", "NODEVSERVER_PERMA", "NODEVSERVER_UNTIL", "UNNODEVSERVER_ERROR", "UNNODEVSERVER");
+ NoDevServer(true, "NODEVSERVER_TEAM", "NODEVSERVER_PERMA", "NODEVSERVER_UNTIL", "UNNODEVSERVER_ERROR", "UNNODEVSERVER"),
+ NoFightServer(false, "NOFIGHTSERVER_TEAM", "NOFIGHTSERVER_PERMA", "NOFIGHTSERVER_UNTIL", "UNNOFIGHTSERVER_ERROR", "UNNOFIGHTSERVER"),
+ NoTeamServer(true, "NOTEAMSERVER_TEAM", "NOTEAMSERVER_PERMA", "NOTEAMSERVER_UNTIL", "UNNOTEAMSERVER_ERROR", "UNNOTEAMSERVER"),
+ Note(false, "NOTE_TEAM", null, null, null, null, true);
private final boolean needsAdmin;
private final String teamMessage;
@@ -118,5 +135,6 @@ public class Punishment {
private final String playerMessageUntil;
private final String usageNotPunished;
private final String unpunishmentMessage;
+ private boolean multi = false;
}
}
diff --git a/src/de/steamwar/sql/SchemElo.java b/src/de/steamwar/sql/SchemElo.java
index 64090ce..0e92cfd 100644
--- a/src/de/steamwar/sql/SchemElo.java
+++ b/src/de/steamwar/sql/SchemElo.java
@@ -21,14 +21,31 @@ 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;
@AllArgsConstructor
public class SchemElo {
+ 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);
+ private static final Statement setElo = table.insertAll();
+
+ public static int getElo(SchematicNode node, int season) {
+ SchemElo elo = select.select(node, season);
+ return elo != null ? elo.elo : 0;
+ }
+
+ public static int getCurrentElo(int schemID) {
+ SchemElo elo = select.select(schemID, Season.getSeason());
+ return elo != null ? elo.elo : ELO_DEFAULT;
+ }
+
+ public static void setElo(int schemID, int elo) {
+ setElo.update(schemID, elo, Season.getSeason());
+ }
@Field(keys = {Table.PRIMARY})
private final int schemId;
@@ -36,9 +53,4 @@ public class SchemElo {
private final int elo;
@Field(keys = {Table.PRIMARY})
private final int season;
-
- public static int getElo(SchematicNode node, int season) {
- SchemElo elo = select.select(node, season);
- return elo != null ? elo.elo : 0;
- }
}
diff --git a/src/de/steamwar/sql/SchematicType.java b/src/de/steamwar/sql/SchematicType.java
index d87065c..43cfb44 100644
--- a/src/de/steamwar/sql/SchematicType.java
+++ b/src/de/steamwar/sql/SchematicType.java
@@ -20,6 +20,7 @@
package de.steamwar.sql;
import de.steamwar.sql.internal.SqlTypeMapper;
+import lombok.Getter;
import java.util.*;
@@ -51,17 +52,26 @@ public class SchematicType {
}
private final String name;
+ @Getter
private final String kuerzel;
private final Type type;
private final SchematicType checkType;
+ @Getter
private final String material;
+ @Getter
+ private final Date deadline;
SchematicType(String name, String kuerzel, Type type, SchematicType checkType, String material){
+ this(name, kuerzel, type, checkType, material, null);
+ }
+
+ SchematicType(String name, String kuerzel, Type type, SchematicType checkType, String material, Date deadline){
this.name = name;
this.kuerzel = kuerzel;
this.type = type;
this.checkType = checkType;
this.material = material;
+ this.deadline = deadline;
}
public boolean isAssignable(){
@@ -88,14 +98,6 @@ public class SchematicType {
return name;
}
- public String getKuerzel() {
- return kuerzel;
- }
-
- public String getMaterial() {
- return material;
- }
-
public String toDB(){
return name.toLowerCase();
}
diff --git a/src/de/steamwar/sql/Session.java b/src/de/steamwar/sql/Session.java
new file mode 100644
index 0000000..18ad2c8
--- /dev/null
+++ b/src/de/steamwar/sql/Session.java
@@ -0,0 +1,45 @@
+/*
+ * 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.Statement;
+import de.steamwar.sql.internal.Table;
+import lombok.AllArgsConstructor;
+
+import java.sql.Timestamp;
+
+@AllArgsConstructor
+public class Session {
+
+ private static final Table table = new Table<>(Session.class);
+ private static final Statement insert = table.insert(Table.PRIMARY);
+
+ public static void insertSession(int userID, Timestamp startTime){
+ insert.update(userID, startTime);
+ }
+
+ @Field(keys = {Table.PRIMARY})
+ private int userId;
+ @Field(keys = {Table.PRIMARY})
+ private Timestamp startTime;
+ @Field(def = "CURRENT_TIMESTAMP")
+ private Timestamp endTime;
+}
diff --git a/src/de/steamwar/sql/SteamwarUser.java b/src/de/steamwar/sql/SteamwarUser.java
index 874643f..7ce882d 100644
--- a/src/de/steamwar/sql/SteamwarUser.java
+++ b/src/de/steamwar/sql/SteamwarUser.java
@@ -22,7 +22,11 @@ package de.steamwar.sql;
import de.steamwar.sql.internal.*;
import lombok.Getter;
+import java.sql.Timestamp;
import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
public class SteamwarUser {
@@ -44,12 +48,16 @@ public class SteamwarUser {
private static final SelectStatement byDiscord = table.selectFields("DiscordId");
private static final SelectStatement byTeam = table.selectFields("Team");
private static final SelectStatement getServerTeam = new SelectStatement<>(table, "SELECT * FROM UserData WHERE UserGroup != 'Member' AND UserGroup != 'YouTuber'");
+
private static final Statement updateName = table.update(Table.PRIMARY, "UserName");
private static final Statement updateLocale = table.update(Table.PRIMARY, "Locale", "ManualLocale");
private static final Statement updateTeam = table.update(Table.PRIMARY, "Team");
private static final Statement updateLeader = table.update(Table.PRIMARY, "Leader");
private static final Statement updateDiscord = table.update(Table.PRIMARY, "DiscordId");
+ private static final Statement getPlaytime = new Statement("SELECT SUM(UNIX_TIMESTAMP(EndTime) - UNIX_TIMESTAMP(StartTime)) as Playtime FROM Session WHERE UserID = ?");
+ private static final Statement getFirstjoin = new Statement("SELECT MIN(StartTime) AS FirstJoin FROM Session WHERE UserID = ?");
+
private static final Map usersById = new HashMap<>();
private static final Map usersByUUID = new HashMap<>();
private static final Map usersByName = new HashMap<>();
@@ -69,67 +77,6 @@ public class SteamwarUser {
usersByUUID.remove(user.getUUID());
}
- @Getter
- @Field(keys = {Table.PRIMARY}, autoincrement = true)
- private final int id;
- @Field(keys = {"uuid"})
- private final UUID uuid;
- @Getter
- @Field
- private String userName;
- @Getter
- @Field(def = "'Member'")
- private final UserGroup userGroup;
- @Getter
- @Field(def = "0")
- private int team;
- @Field(def = "0")
- private boolean leader;
- @Field(nullable = true)
- private Locale locale;
- @Field(def = "0")
- private boolean manualLocale;
- @Field(keys = {"discordId"}, nullable = true)
- private Long discordId;
-
- public SteamwarUser(int id, UUID uuid, String userName, UserGroup userGroup, int team, boolean leader, Locale locale, boolean manualLocale, Long discordId) {
- this.id = id;
- this.uuid = uuid;
- this.userName = userName;
- this.userGroup = userGroup;
- this.team = team;
- this.leader = leader;
- this.locale = locale;
- this.manualLocale = manualLocale;
- this.discordId = discordId != null && discordId != 0 ? discordId : null;
-
- usersById.put(id, this);
- usersByName.put(userName.toLowerCase(), this);
- usersByUUID.put(uuid, this);
- if (this.discordId != null) {
- usersByDiscord.put(discordId, this);
- }
- }
-
- public UUID getUUID() {
- return uuid;
- }
-
- public Locale getLocale() {
- if(locale != null)
- return locale;
- return Locale.getDefault();
- }
-
- public void setLocale(Locale locale, boolean manualLocale) {
- if (locale == null || (this.manualLocale && !manualLocale))
- return;
-
- this.locale = locale;
- this.manualLocale = manualLocale;
- updateLocale.update(locale.toLanguageTag(), manualLocale, id);
- }
-
public static SteamwarUser get(String userName){
SteamwarUser user = usersByName.get(userName.toLowerCase());
if(user != null)
@@ -157,8 +104,22 @@ public class SteamwarUser {
return byDiscord.select(discordId);
}
- public static void createOrUpdateUsername(UUID uuid, String userName) {
- insert.update(uuid, userName);
+ public static SteamwarUser getOrCreate(UUID uuid, String name, Consumer newPlayer, BiConsumer nameUpdate) {
+ SteamwarUser user = SteamwarUser.get(uuid);
+
+ if (user != null) {
+ if (!user.userName.equals(name)) {
+ updateName.update(name, user.id);
+ nameUpdate.accept(user.userName, name);
+ user.userName = name;
+ }
+ } else {
+ insert.update(uuid, name);
+ newPlayer.accept(uuid);
+ return get(uuid);
+ }
+
+ return user;
}
public static List getServerTeam() {
@@ -168,4 +129,139 @@ public class SteamwarUser {
public static List getTeam(int teamId) {
return byTeam.listSelect(teamId);
}
+
+ public static void batchCache(Set ids) {
+ ids.removeIf(usersById::containsKey);
+ if(ids.isEmpty())
+ return;
+
+ try (SelectStatement batch = new SelectStatement<>(table, "SELECT * FROM UserData WHERE id IN (" + ids.stream().map(Object::toString).collect(Collectors.joining(", ")) + ")")) {
+ batch.listSelect();
+ }
+ }
+
+ @Getter
+ @Field(keys = {Table.PRIMARY}, autoincrement = true)
+ private final int id;
+ @Field(keys = {"uuid"})
+ private final UUID uuid;
+ @Getter
+ @Field
+ private String userName;
+ @Getter
+ @Field(def = "'Member'")
+ private final UserGroup userGroup;
+ @Getter
+ @Field(def = "0")
+ private int team;
+ @Getter
+ @Field(def = "0")
+ private boolean leader;
+ @Field(nullable = true)
+ private Locale locale;
+ @Field(def = "0")
+ private boolean manualLocale;
+ @Getter
+ @Field(keys = {"discordId"}, nullable = true)
+ private Long discordId;
+
+ private final Map punishments;
+
+ public SteamwarUser(int id, UUID uuid, String userName, UserGroup userGroup, int team, boolean leader, Locale locale, boolean manualLocale, Long discordId) {
+ this.id = id;
+ this.uuid = uuid;
+ this.userName = userName;
+ this.userGroup = userGroup;
+ this.team = team;
+ this.leader = leader;
+ this.locale = locale;
+ this.manualLocale = manualLocale;
+ this.discordId = discordId != null && discordId != 0 ? discordId : null;
+
+ usersById.put(id, this);
+ usersByName.put(userName.toLowerCase(), this);
+ usersByUUID.put(uuid, this);
+ if (this.discordId != null) {
+ usersByDiscord.put(discordId, this);
+ }
+ punishments = Punishment.getPunishmentsOfPlayer(id); //TODO load always on Subservers?
+ }
+
+ public UUID getUUID() {
+ return uuid;
+ }
+
+ public Locale getLocale() {
+ if(locale != null)
+ return locale;
+ return Locale.getDefault();
+ }
+
+ public Punishment getPunishment(Punishment.PunishmentType type) {
+ return punishments.getOrDefault(type, null);
+ }
+
+ public boolean isPunished(Punishment.PunishmentType punishment) {
+ if (!punishments.containsKey(punishment)) {
+ return false;
+ }
+ if (!punishments.get(punishment).isCurrent()) {
+ if (punishment == Punishment.PunishmentType.Ban) {
+ BannedUserIPs.unbanIPs(id);
+ }
+ punishments.remove(punishment);
+ return false;
+ }
+ return true;
+ }
+
+ public double getOnlinetime() {
+ return getPlaytime.select(rs -> {
+ if (rs.next() && rs.getBigDecimal("Playtime") != null)
+ return rs.getBigDecimal("Playtime").doubleValue();
+ return 0.0;
+ }, id);
+ }
+
+ public Timestamp getFirstjoin() {
+ return getFirstjoin.select(rs -> {
+ if (rs.next())
+ return rs.getTimestamp("FirstJoin");
+ return null;
+ }, id);
+ }
+
+ public void punish(Punishment.PunishmentType punishment, Timestamp time, String banReason, int from, boolean perma) {
+ punishments.remove(punishment);
+ punishments.put(punishment, Punishment.createPunishment(id, from, punishment, banReason, time, perma));
+ }
+
+ public void setTeam(int team) {
+ this.team = team;
+ updateTeam.update(team, id);
+ setLeader(false);
+ }
+
+ public void setLeader(boolean leader) {
+ this.leader = leader;
+ updateLeader.update(leader, id);
+ }
+
+ public void setLocale(Locale locale, boolean manualLocale) {
+ if (locale == null || (this.manualLocale && !manualLocale))
+ return;
+
+ this.locale = locale;
+ this.manualLocale = manualLocale;
+ updateLocale.update(locale.toLanguageTag(), manualLocale, id);
+ }
+
+ public void setDiscordId(Long discordId) {
+ usersByDiscord.remove(this.discordId);
+ this.discordId = discordId;
+ updateDiscord.update(discordId, id);
+ if (discordId != null) {
+ usersByDiscord.put(discordId, this);
+ }
+ }
}
diff --git a/src/de/steamwar/sql/Team.java b/src/de/steamwar/sql/Team.java
index 10e6892..8765ad9 100644
--- a/src/de/steamwar/sql/Team.java
+++ b/src/de/steamwar/sql/Team.java
@@ -21,41 +21,119 @@ 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;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.stream.Collectors;
@AllArgsConstructor
public class Team {
- private static final Table table = new Table<>(Team.class);
- private static final SelectStatement select = table.select(Table.PRIMARY);
+ private static final Map teamCache = new HashMap<>();
- @Field(keys = {Table.PRIMARY})
+ public static void clear() {
+ teamCache.clear();
+ }
+
+ private static final Table table = new Table<>(Team.class);
+ private static final SelectStatement byId = table.select(Table.PRIMARY);
+ private static final SelectStatement byName = new SelectStatement<>(table, "SELECT * FROM Team WHERE (lower(TeamName) = ? OR lower(TeamKuerzel) = ?) AND NOT TeamDeleted");
+ private static final SelectStatement all = table.selectFields("TeamDeleted");
+ private static final Statement insert = table.insertFields("TeamKuerzel", "TeamName");
+ private static final Statement update = table.update(Table.PRIMARY, "TeamKuerzel", "TeamName", "TeamColor", "Address", "Port");
+ private static final Statement delete = table.update(Table.PRIMARY, "TeamDeleted");
+ private static final Statement getSize = new Statement("SELECT COUNT(id) FROM UserData WHERE Team = ?");
+
+ @Field(keys = {Table.PRIMARY}, autoincrement = true)
@Getter
private final int teamId;
@Field
@Getter
- private final String teamKuerzel;
+ private String teamKuerzel;
@Field
@Getter
- private final String teamName;
+ private String teamName;
@Field(def = "'8'")
@Getter
- private final String teamColor;
+ private String teamColor;
+ @Field(nullable = true)
+ @Getter
+ private String address;
+ @Field(def = "'25565'")
+ @Getter
+ private int port;
+ @Field(def = "0")
+ private boolean teamDeleted;
- private static final Team pub = new Team(0, "PUB", "Öffentlich", "8");
+ public static void create(String kuerzel, String name){
+ insert.update(kuerzel, name);
+ }
public static Team get(int id) {
- if(id == 0)
- return pub;
- return select.select(id);
+ return teamCache.computeIfAbsent(id, byId::select);
+ }
+
+ public static Team get(String name){
+ // No cache lookup due to low frequency use
+ return byName.select(name, name);
+ }
+
+ public static List getAll(){
+ clear();
+ List teams = all.listSelect(false);
+ teams.forEach(team -> teamCache.put(team.getTeamId(), team));
+ return teams;
}
public List getMembers(){
return SteamwarUser.getTeam(teamId).stream().map(SteamwarUser::getId).collect(Collectors.toList());
}
+
+ public int size(){
+ return getSize.select(rs -> {
+ rs.next();
+ return rs.getInt("COUNT(id)");
+ }, teamId);
+ }
+
+ public void disband(SteamwarUser user){
+ user.setLeader(false);
+ delete.update(true, teamId);
+ teamCache.remove(teamId);
+ TeamTeilnahme.deleteFuture(teamId);
+ }
+
+ public void setTeamKuerzel(String teamKuerzel) {
+ this.teamKuerzel = teamKuerzel;
+ updateDB();
+ }
+
+ public void setTeamName(String teamName) {
+ this.teamName = teamName;
+ updateDB();
+ }
+
+ public void setTeamColor(String teamColor) {
+ this.teamColor = teamColor;
+ updateDB();
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ updateDB();
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ updateDB();
+ }
+
+ private void updateDB(){
+ update.update(teamKuerzel, teamName, teamColor, address, port, teamId);
+ }
}
diff --git a/src/de/steamwar/sql/TeamTeilnahme.java b/src/de/steamwar/sql/TeamTeilnahme.java
index 533b830..f1484da 100644
--- a/src/de/steamwar/sql/TeamTeilnahme.java
+++ b/src/de/steamwar/sql/TeamTeilnahme.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;
@@ -34,6 +35,9 @@ public class TeamTeilnahme {
private static final SelectStatement select = table.select(Table.PRIMARY);
private static final SelectStatement selectTeams = table.selectFields("EventID");
private static final SelectStatement selectEvents = table.selectFields("TeamID");
+ private static final Statement insert = table.insert(Table.PRIMARY);
+ private static final Statement delete = table.delete(Table.PRIMARY);
+ private static final Statement deleteFuture = new Statement("DELETE t FROM TeamTeilnahme t INNER JOIN Event e ON t.EventID = e.EventID WHERE t.TeamID = ? AND e.Start > NOW()");
@Field(keys = {Table.PRIMARY})
private final int teamId;
@@ -44,6 +48,18 @@ public class TeamTeilnahme {
return select.select(teamID, eventID) != null;
}
+ public static void teilnehmen(int teamID, int eventID){
+ insert.update(teamID, eventID);
+ }
+
+ public static void notTeilnehmen(int teamID, int eventID){
+ delete.update(teamID, eventID);
+ }
+
+ public static void deleteFuture(int teamID) {
+ deleteFuture.update(teamID);
+ }
+
public static Set getTeams(int eventID){
return selectTeams.listSelect(eventID).stream().map(tt -> Team.get(tt.teamId)).collect(Collectors.toSet()); // suboptimal performance (O(n) database queries)
}
diff --git a/src/de/steamwar/sql/Tutorial.java b/src/de/steamwar/sql/Tutorial.java
new file mode 100644
index 0000000..9febcba
--- /dev/null
+++ b/src/de/steamwar/sql/Tutorial.java
@@ -0,0 +1,94 @@
+/*
+ * 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 lombok.Getter;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@AllArgsConstructor
+public class Tutorial {
+
+ private static final Table table = new Table<>(Tutorial.class);
+ private static final SelectStatement by_popularity = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Released = ? GROUP BY t.TutorialID ORDER BY SUM(r.Stars) DESC LIMIT ?, ?");
+ private static final SelectStatement own = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Creator = ? GROUP BY t.TutorialID ORDER BY t.TutorialID ASC LIMIT ?, ?");
+ private static final SelectStatement by_creator_name = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Creator = ? AND t.Name = ? GROUP BY t.TutorialID");
+ private static final SelectStatement by_id = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.TutorialID = ? GROUP BY t.TutorialID");
+ private static final Statement rate = new Statement("INSERT INTO TutorialRating (TutorialID, UserID, Stars) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Stars = VALUES(Stars)");
+ private static final Statement create = new Statement("INSERT INTO Tutorial (Creator, Name, Item) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Item = VALUES(Item), Released = 0");
+ private static final Statement release = table.update(Table.PRIMARY, "released");
+ private static final Statement delete = table.delete(Table.PRIMARY);
+
+ public static List getPage(int page, int elementsPerPage, boolean released) {
+ List tutorials = by_popularity.listSelect(released, page * elementsPerPage, elementsPerPage);
+ SteamwarUser.batchCache(tutorials.stream().map(tutorial -> tutorial.creator).collect(Collectors.toSet()));
+ return tutorials;
+ }
+
+ public static List getOwn(int user, int page, int elementsPerPage) {
+ return own.listSelect(user, page * elementsPerPage, elementsPerPage);
+ }
+
+ public static Tutorial create(int creator, String name, String item) {
+ create.update(creator, name, item);
+ return by_creator_name.select(creator, name);
+ }
+
+ public static Tutorial get(int id) {
+ return by_id.select(id);
+ }
+
+ @Getter
+ @Field(keys = {Table.PRIMARY}, autoincrement = true)
+ private final int tutorialId;
+ @Getter
+ @Field(keys = {"CreatorName"})
+ private final int creator;
+ @Getter
+ @Field(keys = {"CreatorName"})
+ private final String name;
+ @Getter
+ @Field(def = "'BOOK'")
+ private final String item;
+ @Getter
+ @Field(def = "0")
+ private final boolean released;
+ @Getter
+ @Field(def = "0") // Not really a field, but necessary for select generation
+ private final double stars;
+
+ public void release() {
+ release.update(1, tutorialId);
+ }
+
+ public void delete() {
+ delete.update(tutorialId);
+ }
+
+ public void rate(int user, int rating) {
+ rate.update(tutorialId, user, rating);
+ }
+}
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;
+ }
+}
diff --git a/src/de/steamwar/sql/UserGroup.java b/src/de/steamwar/sql/UserGroup.java
index cef4fee..aea2dba 100644
--- a/src/de/steamwar/sql/UserGroup.java
+++ b/src/de/steamwar/sql/UserGroup.java
@@ -1,21 +1,21 @@
-/*
- 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 .
-*/
+/*
+ * 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;
@@ -24,22 +24,35 @@ import lombok.Getter;
@AllArgsConstructor
public enum UserGroup {
- Admin("§4", "§e", true, true, true),
- Developer("§3", "§f", true, true, true),
- Moderator("§c", "§f", true, true, true),
- Supporter("§9", "§f", false, true, true),
- Builder("§2", "§f", false, true, false),
- YouTuber("§5", "§f", false, false, false),
- Member("§7", "§7", false, false, false);
+ Admin("§4", "§e", "Admin", true, true, true, true),
+ Developer("§3", "§f", "Dev", true, true, true, true),
+ Moderator("§c", "§f", "Mod", true, true, true, true),
+ Supporter("§9", "§f", "Sup", false, true, true, true),
+ Builder("§2", "§f", "Arch", false, true, false, true),
+ YouTuber("§5", "§f", "YT", false, false, false, true),
+ Member("§7", "§7", "", false, false, false, false);
- @Getter
- private final String colorCode;
- @Getter
- private final String chatColorCode;
- @Getter
- private final boolean adminGroup;
- @Getter
- private final boolean teamGroup;
- @Getter
- private final boolean checkSchematics;
+ @Getter
+ private final String colorCode;
+ @Getter
+ private final String chatColorCode;
+ @Getter
+ private final String chatPrefix;
+ @Getter
+ private final boolean adminGroup;
+ @Getter
+ private final boolean teamGroup;
+ @Getter
+ private final boolean checkSchematics;
+ @Getter
+ private final boolean privilegedMods;
+
+ public static UserGroup getUsergroup(String name) {
+ for(UserGroup group : values()) {
+ if(group.name().equalsIgnoreCase(name))
+ return group;
+ }
+
+ throw new IllegalArgumentException(name);
+ }
}
\ No newline at end of file
diff --git a/src/de/steamwar/sql/internal/Statement.java b/src/de/steamwar/sql/internal/Statement.java
index e842d5f..c29f711 100644
--- a/src/de/steamwar/sql/internal/Statement.java
+++ b/src/de/steamwar/sql/internal/Statement.java
@@ -95,7 +95,7 @@ public class Statement implements AutoCloseable {
}
}
- private static int connectionBudget = MAX_CONNECTIONS;
+ private static volatile int connectionBudget = MAX_CONNECTIONS;
public static void closeAll() {
synchronized (connections) {
@@ -234,7 +234,7 @@ public class Statement implements AutoCloseable {
private static Connection aquireConnection() {
synchronized (connections) {
- while(connections.isEmpty() && connectionBudget == 0)
+ while(connections.isEmpty() && connectionBudget <= 0)
waitOnConnections();
if(!connections.isEmpty()) {