Merge branch 'master' into multitool
Einige Prüfungen sind fehlgeschlagen
SteamWarCI Build failed

Dieser Commit ist enthalten in:
Chaoscaot 2023-08-29 17:58:50 +02:00
Commit e604991cfd
Signiert von: Chaoscaot
GPG-Schlüssel-ID: BDF8FADD7D5EDB7A
12 geänderte Dateien mit 273 neuen und 78 gelöschten Zeilen

Datei anzeigen

@ -36,6 +36,7 @@ import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType; import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic; import javax.tools.Diagnostic;
import javax.tools.StandardLocation;
import java.io.*; import java.io.*;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.nio.file.Files; import java.nio.file.Files;
@ -56,6 +57,8 @@ public class LinkageProcessor extends AbstractProcessor {
private String name; private String name;
private String className; private String className;
private Set<String> disabledFeatures = new HashSet<>();
private Messager messager; private Messager messager;
private boolean processed = false; private boolean processed = false;
@ -75,6 +78,7 @@ public class LinkageProcessor extends AbstractProcessor {
className = "LinkageUtils"; className = "LinkageUtils";
mainClass(); mainClass();
disabledFeatures();
} }
@SneakyThrows @SneakyThrows
@ -102,6 +106,18 @@ public class LinkageProcessor extends AbstractProcessor {
} }
} }
@SneakyThrows
private void disabledFeatures() {
File file = new File(System.getProperty("user.dir"), "disabled-features.txt");
if (!file.exists()) return;
@Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
reader.lines()
.map(String::trim)
.filter(line -> !line.isEmpty())
.filter(line -> !line.startsWith("#"))
.forEach(disabledFeatures::add);
}
@SneakyThrows @SneakyThrows
@Override @Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
@ -111,9 +127,27 @@ public class LinkageProcessor extends AbstractProcessor {
Writer writer = processingEnv.getFiler().createSourceFile("de.steamwar." + name + ".linkage.LinkageUtils").openWriter(); Writer writer = processingEnv.getFiler().createSourceFile("de.steamwar." + name + ".linkage.LinkageUtils").openWriter();
BuildPlan buildPlan = new BuildPlan("de.steamwar." + name + ".linkage", className); BuildPlan buildPlan = new BuildPlan("de.steamwar." + name + ".linkage", className);
Set<TypeElement> disabledElements = new HashSet<>();
Set<TypeElement> elements = roundEnv.getElementsAnnotatedWith(Linked.class).stream() Set<TypeElement> elements = roundEnv.getElementsAnnotatedWith(Linked.class).stream()
.filter(element -> element.getKind() == ElementKind.CLASS) .filter(element -> element.getKind() == ElementKind.CLASS)
.map(TypeElement.class::cast) .map(TypeElement.class::cast)
.peek(element -> {
String featureName = element.getAnnotation(Linked.class).feature();
if (featureName.isEmpty()) {
String tempName = element.getQualifiedName().toString();
if (tempName.contains(".features.")) {
tempName = tempName.substring(tempName.indexOf(".features.") + 10);
featureName = tempName.substring(0, tempName.indexOf('.'));
} else {
tempName = tempName.substring(0, tempName.lastIndexOf('.'));
featureName = tempName.substring(tempName.lastIndexOf('.') + 1);
}
}
if (disabledFeatures.contains(featureName) || disabledFeatures.contains("*")) {
disabledElements.add(element);
}
})
.peek(typeElement -> System.out.println("Found element: " + typeElement.getQualifiedName().toString())) .peek(typeElement -> System.out.println("Found element: " + typeElement.getQualifiedName().toString()))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
@ -147,8 +181,14 @@ public class LinkageProcessor extends AbstractProcessor {
messager.printMessage(Diagnostic.Kind.ERROR, "Field " + variableElement.getSimpleName() + " must be non final", variableElement); messager.printMessage(Diagnostic.Kind.ERROR, "Field " + variableElement.getSimpleName() + " must be non final", variableElement);
continue; continue;
} }
neededFields.put(typeElement.getQualifiedName().toString(), typeElement);
TypeElement fieldType = (TypeElement) ((DeclaredType) variableElement.asType()).asElement(); TypeElement fieldType = (TypeElement) ((DeclaredType) variableElement.asType()).asElement();
if (disabledElements.contains(fieldType)) {
continue;
}
if (disabledElements.contains(typeElement)) {
continue;
}
neededFields.put(typeElement.getQualifiedName().toString(), typeElement);
neededFields.put(fieldType.getQualifiedName().toString(), fieldType); neededFields.put(fieldType.getQualifiedName().toString(), fieldType);
fieldInjections.add(() -> { fieldInjections.add(() -> {
@ -159,6 +199,7 @@ public class LinkageProcessor extends AbstractProcessor {
} }
} }
neededFields.forEach((s, typeElement) -> { neededFields.forEach((s, typeElement) -> {
if (disabledElements.contains(typeElement)) return;
buildPlan.addImport(typeElement.getQualifiedName().toString()); buildPlan.addImport(typeElement.getQualifiedName().toString());
String t = typeElement.getSimpleName().toString(); String t = typeElement.getSimpleName().toString();
t = t.substring(0, 1).toLowerCase() + t.substring(1); t = t.substring(0, 1).toLowerCase() + t.substring(1);
@ -188,8 +229,13 @@ public class LinkageProcessor extends AbstractProcessor {
return methodBuilder; return methodBuilder;
}); });
if (!entry.getKey().isEmpty()) method.addLine("if (" + String.join(" && ", entry.getKey()) + ") {"); boolean generated = false;
for (Map.Entry<TypeElement, List<LinkageType>> toGenerate : group.getValue().entrySet()) { for (Map.Entry<TypeElement, List<LinkageType>> toGenerate : group.getValue().entrySet()) {
if (disabledElements.contains(toGenerate.getKey())) continue;
if (!generated && !entry.getKey().isEmpty()) {
method.addLine("if (" + String.join(" && ", entry.getKey()) + ") {");
generated = true;
}
TypeElement typeElement = toGenerate.getKey(); TypeElement typeElement = toGenerate.getKey();
String instance = getElement(typeElement, neededFields); String instance = getElement(typeElement, neededFields);
if (toGenerate.getValue().size() > 1 && instance.startsWith("new ")) { if (toGenerate.getValue().size() > 1 && instance.startsWith("new ")) {
@ -202,7 +248,7 @@ public class LinkageProcessor extends AbstractProcessor {
linkageType.generateCode(buildPlan, method, finalInstance, typeElement); linkageType.generateCode(buildPlan, method, finalInstance, typeElement);
}); });
} }
if (!entry.getKey().isEmpty()) method.addLine("}"); if (generated && !entry.getKey().isEmpty()) method.addLine("}");
} }
} }

Datei anzeigen

@ -24,4 +24,5 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE}) @Target({ElementType.TYPE})
public @interface Linked { public @interface Linked {
String feature() default "";
} }

Datei anzeigen

@ -21,7 +21,6 @@ package de.steamwar.network.packets.client;
import de.steamwar.network.packets.NetworkPacket; import de.steamwar.network.packets.NetworkPacket;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class ImALobbyPacket extends NetworkPacket { public class ImALobbyPacket extends NetworkPacket {

Datei anzeigen

@ -0,0 +1,39 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.network.packets.client;
import de.steamwar.network.packets.NetworkPacket;
import lombok.*;
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Getter
public class RequestSchematicSearchPacket extends NetworkPacket {
private static final long serialVersionUID = -6525229932332581648L;
private int playerId;
private int schematicId;
private boolean ignoreBlockData;
private boolean ignoreAir;
private boolean airAsAny;
}

Datei anzeigen

@ -38,4 +38,5 @@ public class FightEndsPacket extends NetworkPacket {
private List<Integer> bluePlayers; private List<Integer> bluePlayers;
private List<Integer> redPlayers; private List<Integer> redPlayers;
private String gameMode; private String gameMode;
private int duration;
} }

Datei anzeigen

@ -32,6 +32,10 @@ import java.util.List;
@AllArgsConstructor @AllArgsConstructor
public class Event { public class Event {
static {
SchematicType.Normal.name(); // Ensure SchematicType is loaded.
}
private static final Table<Event> table = new Table<>(Event.class); private static final Table<Event> table = new Table<>(Event.class);
private static final SelectStatement<Event> byCurrent = new SelectStatement<>(table, "SELECT * FROM Event WHERE Start < now() AND End > now()"); private static final SelectStatement<Event> byCurrent = new SelectStatement<>(table, "SELECT * FROM Event WHERE Start < now() AND End > now()");

Datei anzeigen

@ -26,7 +26,7 @@ import lombok.AllArgsConstructor;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.Timestamp; import java.sql.Timestamp;
import java.time.Instant; import java.time.Instant;
@AllArgsConstructor @AllArgsConstructor

Datei anzeigen

@ -20,9 +20,7 @@
package de.steamwar.sql; package de.steamwar.sql;
import de.steamwar.sql.internal.*; import de.steamwar.sql.internal.*;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.time.Instant; import java.time.Instant;
@ -32,6 +30,7 @@ import java.util.function.Predicate;
public class SchematicNode { public class SchematicNode {
static { static {
SchematicType.Normal.name(); // Ensure SchematicType is loaded.
new SqlTypeMapper<>(SchematicNode.class, null, (rs, identifier) -> { throw new SecurityException("SchematicNode cannot be used as type (recursive select)"); }, (st, index, value) -> st.setInt(index, value.nodeId)); new SqlTypeMapper<>(SchematicNode.class, null, (rs, identifier) -> { throw new SecurityException("SchematicNode cannot be used as type (recursive select)"); }, (st, index, value) -> st.setInt(index, value.nodeId));
} }
@ -57,8 +56,8 @@ public class SchematicNode {
private static final SelectStatement<SchematicNode> list = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName"); private static final SelectStatement<SchematicNode> list = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byParentName = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?"); private static final SelectStatement<SchematicNode> byParentName = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?");
private static final SelectStatement<SchematicNode> schematicAccessibleForUser = new SelectStatement<>(table, "SELECT COUNT(DISTINCT NodeId) FROM EffectiveSchematicNode WHERE EffectiveOwner = ? AND NodeId = ?"); private static final SelectStatement<SchematicNode> schematicAccessibleForUser = new SelectStatement<>(table, "SELECT COUNT(DISTINCT NodeId) FROM EffectiveSchematicNode WHERE EffectiveOwner = ? AND NodeId = ?");
private static final SelectStatement<SchematicNode> accessibleByUserTypeInParent = new SelectStatement<>(table, "WITH RECURSIVE RSN AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeType = ? AND EffectiveOwner = ? UNION SELECT SN.NodeId, SN.ParentNode FROM RSN, EffectiveSchematicNode SN WHERE SN.NodeId = RSN.ParentNode AND EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, RSN.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE RSN.ParentNode" + Statement.NULL_SAFE_EQUALS + "?"); private static final SelectStatement<SchematicNode> accessibleByUserTypeInParent = new SelectStatement<>(table, "WITH RECURSIVE RSASN AS (WITH RSAN AS (WITH RECURSIVE RSA AS (SELECT SN.NodeId, NM.ParentId FROM SchematicNode SN LEFT JOIN NodeMember NM on SN.NodeId = NM.NodeId WHERE UserId = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSA WHERE RSA.NodeId = SN.ParentNode) SELECT * FROM RSA UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?) SELECT RSAN.NodeId, RSAN.ParentId FROM RSAN INNER JOIN SchematicNode SN ON SN.NodeId = RSAN.NodeId WHERE NodeType = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSASN WHERE SN.NodeId = RSASN.ParentId) SELECT SN.*, ? as EffectiveOwner, RSASN.ParentId AS ParentNode FROM RSASN INNER JOIN SchematicNode SN ON SN.NodeId = RSASN.NodeId WHERE RSASN.ParentId" + Statement.NULL_SAFE_EQUALS + "?");
private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table, "SELECT * FROM EffectiveSchematicNode WHERE EffectiveOwner = ? AND NodeType = ?"); private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table, "WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeType = ?");
private static final SelectStatement<SchematicNode> byIdAndUser = new SelectStatement<>(table, "SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE NodeId = ?"); private static final SelectStatement<SchematicNode> byIdAndUser = new SelectStatement<>(table, "SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE NodeId = ?");
private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table, "WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? AND EffectiveOwner = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId"); private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table, "WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? AND EffectiveOwner = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId");
@ -135,7 +134,7 @@ public class SchematicNode {
} }
public static List<SchematicNode> accessibleByUserType(SteamwarUser user, SchematicType type) { public static List<SchematicNode> accessibleByUserType(SteamwarUser user, SchematicType type) {
return accessibleByUserType.listSelect(user, type); return accessibleByUserType.listSelect(user, user, user, type);
} }
public static Map<Integer, List<SchematicNode>> accessibleByUserTypeMap(SteamwarUser user, SchematicType type) { public static Map<Integer, List<SchematicNode>> accessibleByUserTypeMap(SteamwarUser user, SchematicType type) {
@ -147,7 +146,7 @@ public class SchematicNode {
} }
public static List<SchematicNode> accessibleByUserTypeParent(SteamwarUser user, SchematicType type, Integer parentId) { public static List<SchematicNode> accessibleByUserTypeParent(SteamwarUser user, SchematicType type, Integer parentId) {
return accessibleByUserTypeInParent.listSelect(type, user, user, user, parentId); return accessibleByUserTypeInParent.listSelect(user, user, type, user, parentId);
} }
public static SchematicNode byIdAndUser(SteamwarUser user, Integer id) { public static SchematicNode byIdAndUser(SteamwarUser user, Integer id) {

Datei anzeigen

@ -0,0 +1,84 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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;
@AllArgsConstructor
@Getter
public class Script {
private static final Table<Script> table = new Table<>(Script.class);
private static final SelectStatement<Script> byId = table.select(Table.PRIMARY);
private static final SelectStatement<Script> byUserName = table.select("nameUser");
private static final SelectStatement<Script> byUser = table.selectFields("userId");
private static final Statement insert = table.insertFields(true, "userId", "name", "code");
private static final Statement updateName = table.update(Table.PRIMARY, "name");
private static final Statement updateCode = table.update(Table.PRIMARY, "code");
private static final Statement delete = table.delete(Table.PRIMARY);
public static Script get(int id) {
return byId.select(id);
}
public static Script get(SteamwarUser user, String name) {
return byUserName.select(user, name);
}
public static Script create(SteamwarUser user, String name, String code) {
return new Script(insert.insertGetKey(user, name, code), user.getId(), name, code);
}
public static List<Script> list(SteamwarUser user) {
return byUser.listSelect(user);
}
@Field(keys = Table.PRIMARY, autoincrement = true)
private final int id;
@Field(keys = "nameUser")
private final int userId;
@Field(keys = "nameUser")
private String name;
@Field
private String code;
public void setName(String name) {
this.name = name;
updateName.update(name, id);
}
public void setCode(String code) {
this.code = code;
updateCode.update(code, id);
}
public void delete() {
delete.update(id);
}
}

Datei anzeigen

@ -32,7 +32,14 @@ public class Season {
public static String getSeasonStart() { public static String getSeasonStart() {
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
return calendar.get(Calendar.YEAR) + "-" + (calendar.get(Calendar.MONTH) / 4 * 3 + 1) + "-1"; int month = calendar.get(Calendar.MONTH);
if (month <= 3) {
return calendar.get(Calendar.YEAR) + "-1-1";
} else if (month <= 7) {
return calendar.get(Calendar.YEAR) + "-5-1";
} else {
return calendar.get(Calendar.YEAR) + "-9-1";
}
} }
public static String convertSeasonToString(int season){ public static String convertSeasonToString(int season){

Datei anzeigen

@ -25,30 +25,25 @@ import de.steamwar.sql.internal.Statement;
import de.steamwar.sql.internal.Table; import de.steamwar.sql.internal.Table;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@AllArgsConstructor @AllArgsConstructor
public class UserElo { public class UserElo {
private static final int ELO_DEFAULT = 1000;
private static final int ELO_DEFAULT = 0;
private static final Map<String, Map<Integer, Optional<Integer>>> gameModeUserEloCache = new ConcurrentHashMap<>(); private static final Map<String, Map<Integer, Optional<Integer>>> gameModeUserEloCache = new ConcurrentHashMap<>();
private static final Map<String, Integer> maxEloCache = new ConcurrentHashMap<>();
private static final Map<Integer, String> emblemCache = new ConcurrentHashMap<>(); private static final Map<Integer, String> emblemCache = new ConcurrentHashMap<>();
public static void clear() { public static void clear() {
gameModeUserEloCache.clear(); gameModeUserEloCache.clear();
maxEloCache.clear();
emblemCache.clear(); emblemCache.clear();
} }
private static final Table<UserElo> table = new Table<>(UserElo.class); private static final Table<UserElo> table = new Table<>(UserElo.class);
private static final SelectStatement<UserElo> getElo = table.select(Table.PRIMARY); private static final SelectStatement<UserElo> getElo = table.select(Table.PRIMARY);
private static final Statement setElo = table.insertAll(); 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 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(?)"); 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(?)");
@ -78,21 +73,14 @@ public class UserElo {
}, userID, gameMode, Season.getSeasonStart()); }, 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) { public static void setElo(int userId, String gameMode, int elo) {
emblemCache.remove(userId); emblemCache.remove(userId);
Optional<Integer> oldElo = Optional.ofNullable(gameModeUserEloCache.computeIfAbsent(gameMode, gm -> new HashMap<>()).put(userId, Optional.of(elo))).orElse(Optional.empty()); int oldPlacement = getPlacement(getElo(userId, gameMode).orElse(0), gameMode);
int maxElo = getMaxElo(gameMode); int newPlacement = getPlacement(elo, gameMode);
if (elo > maxElo || (oldElo.isPresent() && oldElo.get() == maxElo)) {
maxEloCache.remove(gameMode); gameModeUserEloCache.getOrDefault(gameMode, Collections.emptyMap()).remove(userId);
if (oldPlacement <= 3 || newPlacement <= 3) {
emblemCache.clear(); emblemCache.clear();
} }
@ -109,70 +97,92 @@ public class UserElo {
public static String getEmblem(SteamwarUser user, List<String> rankedModes) { public static String getEmblem(SteamwarUser user, List<String> rankedModes) {
return emblemCache.computeIfAbsent(user.getId(), userId -> { return emblemCache.computeIfAbsent(user.getId(), userId -> {
switch( int emblemProgression = -1;
rankedModes.stream().filter( for (String mode : rankedModes) {
mode -> UserElo.getFightsOfSeason(user.getId(), mode) >= 10 if (UserElo.getFightsOfSeason(userId, mode) == 0) continue;
).map( int progression = getProgression(userId, mode);
mode -> getProgression(user.getId(), mode) if (progression > emblemProgression) {
).max(Integer::compareTo).orElse(0) emblemProgression = progression;
) {
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");
} }
}
return toEmblem(emblemProgression);
}); });
} }
public static String getEmblemProgression(String gameMode, int userId) { public static String getEmblemProgression(String gameMode, int userId) {
switch (getProgression(userId, gameMode)) { switch (getProgression(userId, gameMode)) {
case -1:
return "§f/ §8 ∧ ❂ III II I";
case 0: case 0:
return "§8✧ ✦ ✶ ✷ ✸ ✹ ❂"; return "§8/ §6 §8∧ ∧ ❂ III II I";
case 1: case 1:
return "§7✧ §8✦ ✶ ✷ ✸ ✹ ❂"; return "§8/ §6∧ §8 ∧ ❂ III II I";
case 2: case 2:
return "§8✧ §f✦ §8✶ ✷ ✸ ✹ ❂"; return "§8/ ∧ §7 §8∧ ∧ ❂ III II I";
case 3: case 3:
return "§8✧ ✦ §e✶ §8✷ ✸ ✹ ❂"; return "§8/ §7∧ §8 ∧ ❂ III II I";
case 4: case 4:
return "§8✧ ✦ ✶ §a✷ §8✸ ✹ ❂"; return "§8/ ∧ §e §8∧ ❂ III II I";
case 5: case 5:
return "§8✧ ✦ ✶ ✷ §b✸ §8✹ ❂"; return "§8/ §e∧ §8❂ III II I";
case 6: case 6:
return "§8✧ ✦ ✶ ✷ ✸ §c✹ §8❂"; return "§8/ ∧ §5❂ §8III II I";
case 7: case 7:
return "§8✧ ✦ ✶ ✷ ✸ ✹ §5❂"; return "§8/ ∧ ❂ §5III §8II I";
case 8:
return "§8/ ∧ ❂ III §5II §8I";
case 9:
return "§8/ ∧ ❂ III II §5I";
default: default:
throw new SecurityException("Progression is not in range"); throw new SecurityException("Progression is not in range");
} }
} }
private static int getProgression(int userId, String gameMode) { public static int getProgression(int userId, String gameMode) {
int elo = getElo(userId, gameMode).orElse(0); int elo = getElo(userId, gameMode).orElse(-1);
if(elo == 0) if (elo < 0) return -1;
return 0;
int maxElo = getMaxElo(gameMode);
if (elo > maxElo * 0.99) return 7; if (elo <= 100) return 0;
if (elo > maxElo * 0.97) return 6; if (elo <= 200) return 1;
if (elo > maxElo * 0.94) return 5; if (elo <= 400) return 2;
if (elo > maxElo * 0.88) return 4; if (elo <= 600) return 3;
if (elo > maxElo * 0.76) return 3; if (elo <= 900) return 4;
if (elo > maxElo * 0.51) return 2; if (elo <= 1200) return 5;
return 1;
int placement = getPlacement(elo, gameMode);
if (placement == 1) return 9;
if (placement == 2) return 8;
if (placement == 3) return 7;
return 6;
}
public static String toEmblem(int progression) {
switch(progression) {
case -1:
return "";
case 0:
return "§6 ";
case 1:
return "§6∧ ";
case 2:
return "§7 ";
case 3:
return "§7∧ ";
case 4:
return "§e ";
case 5:
return "§e∧ ";
case 6:
return "§5❂ ";
case 7:
return "§5III ";
case 8:
return "§5II ";
case 9:
return "§5I ";
default:
throw new SecurityException("Progression out of range");
}
} }
} }

Datei anzeigen

@ -32,7 +32,12 @@ public final class SqlTypeMapper<T> {
private static final Map<Class<?>, SqlTypeMapper<?>> mappers = new IdentityHashMap<>(); private static final Map<Class<?>, SqlTypeMapper<?>> mappers = new IdentityHashMap<>();
public static <T> SqlTypeMapper<T> getMapper(Class<?> clazz) { public static <T> SqlTypeMapper<T> getMapper(Class<?> clazz) {
return (SqlTypeMapper<T>) mappers.get(clazz); SqlTypeMapper<T> result = (SqlTypeMapper<T>) mappers.get(clazz);
if(result == null)
throw new SecurityException("Unregistered mapper requested: " + clazz.getName());
return result;
} }
public static <T extends Enum<T>> void ordinalEnumMapper(Class<T> type) { public static <T extends Enum<T>> void ordinalEnumMapper(Class<T> type) {