diff --git a/src/de/steamwar/linkage/LinkageProcessor.java b/src/de/steamwar/linkage/LinkageProcessor.java index 488f9bf..29382a5 100644 --- a/src/de/steamwar/linkage/LinkageProcessor.java +++ b/src/de/steamwar/linkage/LinkageProcessor.java @@ -36,6 +36,7 @@ import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; +import javax.tools.StandardLocation; import java.io.*; import java.lang.annotation.Annotation; import java.nio.file.Files; @@ -56,6 +57,8 @@ public class LinkageProcessor extends AbstractProcessor { private String name; private String className; + private Set disabledFeatures = new HashSet<>(); + private Messager messager; private boolean processed = false; @@ -75,6 +78,7 @@ public class LinkageProcessor extends AbstractProcessor { className = "LinkageUtils"; mainClass(); + disabledFeatures(); } @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 @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { @@ -111,9 +127,27 @@ public class LinkageProcessor extends AbstractProcessor { Writer writer = processingEnv.getFiler().createSourceFile("de.steamwar." + name + ".linkage.LinkageUtils").openWriter(); BuildPlan buildPlan = new BuildPlan("de.steamwar." + name + ".linkage", className); + Set disabledElements = new HashSet<>(); + Set elements = roundEnv.getElementsAnnotatedWith(Linked.class).stream() .filter(element -> element.getKind() == ElementKind.CLASS) .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())) .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); continue; } - neededFields.put(typeElement.getQualifiedName().toString(), typeElement); 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); fieldInjections.add(() -> { @@ -159,6 +199,7 @@ public class LinkageProcessor extends AbstractProcessor { } } neededFields.forEach((s, typeElement) -> { + if (disabledElements.contains(typeElement)) return; buildPlan.addImport(typeElement.getQualifiedName().toString()); String t = typeElement.getSimpleName().toString(); t = t.substring(0, 1).toLowerCase() + t.substring(1); @@ -188,8 +229,13 @@ public class LinkageProcessor extends AbstractProcessor { return methodBuilder; }); - if (!entry.getKey().isEmpty()) method.addLine("if (" + String.join(" && ", entry.getKey()) + ") {"); + boolean generated = false; for (Map.Entry> 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(); String instance = getElement(typeElement, neededFields); if (toGenerate.getValue().size() > 1 && instance.startsWith("new ")) { @@ -202,7 +248,7 @@ public class LinkageProcessor extends AbstractProcessor { linkageType.generateCode(buildPlan, method, finalInstance, typeElement); }); } - if (!entry.getKey().isEmpty()) method.addLine("}"); + if (generated && !entry.getKey().isEmpty()) method.addLine("}"); } } diff --git a/src/de/steamwar/linkage/Linked.java b/src/de/steamwar/linkage/Linked.java index f3836e0..dbaf0eb 100644 --- a/src/de/steamwar/linkage/Linked.java +++ b/src/de/steamwar/linkage/Linked.java @@ -24,4 +24,5 @@ import java.lang.annotation.*; @Retention(RetentionPolicy.SOURCE) @Target({ElementType.TYPE}) public @interface Linked { + String feature() default ""; } diff --git a/src/de/steamwar/network/packets/client/ImALobbyPacket.java b/src/de/steamwar/network/packets/client/ImALobbyPacket.java index d8e1ba4..dcd07dd 100644 --- a/src/de/steamwar/network/packets/client/ImALobbyPacket.java +++ b/src/de/steamwar/network/packets/client/ImALobbyPacket.java @@ -21,7 +21,6 @@ package de.steamwar.network.packets.client; import de.steamwar.network.packets.NetworkPacket; import lombok.EqualsAndHashCode; -import lombok.Getter; @EqualsAndHashCode(callSuper = true) public class ImALobbyPacket extends NetworkPacket { diff --git a/src/de/steamwar/network/packets/client/RequestSchematicSearchPacket.java b/src/de/steamwar/network/packets/client/RequestSchematicSearchPacket.java new file mode 100644 index 0000000..ea8420c --- /dev/null +++ b/src/de/steamwar/network/packets/client/RequestSchematicSearchPacket.java @@ -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 . + */ + +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; + +} diff --git a/src/de/steamwar/network/packets/common/FightEndsPacket.java b/src/de/steamwar/network/packets/common/FightEndsPacket.java index a970d7b..c1d86bb 100644 --- a/src/de/steamwar/network/packets/common/FightEndsPacket.java +++ b/src/de/steamwar/network/packets/common/FightEndsPacket.java @@ -38,4 +38,5 @@ public class FightEndsPacket extends NetworkPacket { private List bluePlayers; private List redPlayers; private String gameMode; + private int duration; } diff --git a/src/de/steamwar/sql/Event.java b/src/de/steamwar/sql/Event.java index 2df7e9b..c284903 100644 --- a/src/de/steamwar/sql/Event.java +++ b/src/de/steamwar/sql/Event.java @@ -32,6 +32,10 @@ import java.util.List; @AllArgsConstructor public class Event { + static { + SchematicType.Normal.name(); // Ensure SchematicType is loaded. + } + 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()"); diff --git a/src/de/steamwar/sql/NodeDownload.java b/src/de/steamwar/sql/NodeDownload.java index 585b3db..666cf68 100644 --- a/src/de/steamwar/sql/NodeDownload.java +++ b/src/de/steamwar/sql/NodeDownload.java @@ -26,7 +26,7 @@ import lombok.AllArgsConstructor; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.Timestamp; +import java.sql.Timestamp; import java.time.Instant; @AllArgsConstructor diff --git a/src/de/steamwar/sql/SchematicNode.java b/src/de/steamwar/sql/SchematicNode.java index 7bedbdc..6aa83e1 100644 --- a/src/de/steamwar/sql/SchematicNode.java +++ b/src/de/steamwar/sql/SchematicNode.java @@ -20,9 +20,7 @@ package de.steamwar.sql; import de.steamwar.sql.internal.*; -import lombok.AccessLevel; import lombok.Getter; -import lombok.Setter; import java.sql.Timestamp; import java.time.Instant; @@ -32,6 +30,7 @@ import java.util.function.Predicate; public class SchematicNode { 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)); } @@ -57,8 +56,8 @@ public class SchematicNode { private static final SelectStatement 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 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 schematicAccessibleForUser = new SelectStatement<>(table, "SELECT COUNT(DISTINCT NodeId) FROM EffectiveSchematicNode WHERE EffectiveOwner = ? AND NodeId = ?"); - private static final SelectStatement 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 accessibleByUserType = new SelectStatement<>(table, "SELECT * FROM EffectiveSchematicNode WHERE EffectiveOwner = ? AND NodeType = ?"); + private static final SelectStatement 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 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 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 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 accessibleByUserType(SteamwarUser user, SchematicType type) { - return accessibleByUserType.listSelect(user, type); + return accessibleByUserType.listSelect(user, user, user, type); } public static Map> accessibleByUserTypeMap(SteamwarUser user, SchematicType type) { @@ -147,7 +146,7 @@ public class SchematicNode { } public static List 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) { diff --git a/src/de/steamwar/sql/Script.java b/src/de/steamwar/sql/Script.java new file mode 100644 index 0000000..9691c43 --- /dev/null +++ b/src/de/steamwar/sql/Script.java @@ -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 . + */ + +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