diff --git a/CommonCore/build.gradle.kts b/CommonCore/build.gradle.kts
index 8e3456a7..a3343ba6 100644
--- a/CommonCore/build.gradle.kts
+++ b/CommonCore/build.gradle.kts
@@ -40,4 +40,18 @@ sourceSets {
exclude("**/*.java", "**/*.kt")
}
}
+ test {
+ java {
+ srcDirs("testsrc/")
+ }
+ resources {
+ srcDirs("testsrc/")
+ exclude("**/*.java", "**/*.kt")
+ }
+ }
+}
+
+dependencies {
+ compileOnly("org.projectlombok:lombok:1.18.32")
+ annotationProcessor("org.projectlombok:lombok:1.18.32")
}
diff --git a/CommonCore/src/de/steamwar/ImplementationProvider.java b/CommonCore/src/de/steamwar/ImplementationProvider.java
new file mode 100644
index 00000000..e5b795e4
--- /dev/null
+++ b/CommonCore/src/de/steamwar/ImplementationProvider.java
@@ -0,0 +1,34 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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;
+
+import java.lang.reflect.InvocationTargetException;
+
+public class ImplementationProvider {
+ private ImplementationProvider() {}
+
+ public static T getImpl(String className) {
+ try {
+ return (T) Class.forName(className).getDeclaredConstructor().newInstance();
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException e) {
+ throw new SecurityException("Could not load implementation", e);
+ }
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/AllowedContexts.java b/CommonCore/src/de/steamwar/linkage/AllowedContexts.java
new file mode 100644
index 00000000..175a7831
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/AllowedContexts.java
@@ -0,0 +1,36 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.ANNOTATION_TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface AllowedContexts {
+
+ /**
+ * The context in which this annotation is valid.
+ */
+ Context[] value();
+
+}
diff --git a/CommonCore/src/de/steamwar/linkage/Context.java b/CommonCore/src/de/steamwar/linkage/Context.java
new file mode 100644
index 00000000..7559bd0c
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/Context.java
@@ -0,0 +1,25 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage;
+
+public enum Context {
+ BUNGEE,
+ SPIGOT
+}
diff --git a/CommonCore/src/de/steamwar/linkage/EventMode.java b/CommonCore/src/de/steamwar/linkage/EventMode.java
new file mode 100644
index 00000000..cdff4665
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/EventMode.java
@@ -0,0 +1,44 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@AllowedContexts(Context.BUNGEE)
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.TYPE})
+public @interface EventMode {
+ Mode value();
+
+ @AllArgsConstructor
+ enum Mode {
+ EventOnly(""),
+ NonEvent("!");
+
+ @Getter
+ private String prefix;
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/LinkageProcessor.java b/CommonCore/src/de/steamwar/linkage/LinkageProcessor.java
new file mode 100644
index 00000000..29382a59
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/LinkageProcessor.java
@@ -0,0 +1,352 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage;
+
+import de.steamwar.linkage.plan.BuildPlan;
+import de.steamwar.linkage.plan.FieldBuilder;
+import de.steamwar.linkage.plan.MethodBuilder;
+import de.steamwar.linkage.types.Plain_GENERIC;
+import lombok.Cleanup;
+import lombok.Getter;
+import lombok.SneakyThrows;
+
+import javax.annotation.processing.*;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+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;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@SupportedAnnotationTypes("de.steamwar.linkage.Linked")
+public class LinkageProcessor extends AbstractProcessor {
+
+ private static Context context;
+
+ @Getter
+ private static String pluginMain;
+
+ private String name;
+ private String className;
+
+ private Set disabledFeatures = new HashSet<>();
+
+ private Messager messager;
+ private boolean processed = false;
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+ @SneakyThrows
+ @Override
+ public synchronized void init(ProcessingEnvironment processingEnv) {
+ super.init(processingEnv);
+
+ name = new File(System.getProperty("user.dir")).getName().replaceAll("[^a-zA-Z]", "").toLowerCase();
+
+ messager = processingEnv.getMessager();
+
+ className = "LinkageUtils";
+ mainClass();
+ disabledFeatures();
+ }
+
+ @SneakyThrows
+ private void mainClass() {
+ File file = new File(System.getProperty("user.dir"));
+ Optional pluginYMLFile = Files.walk(file.toPath())
+ .map(Path::toFile)
+ .filter(File::isFile)
+ .filter(f -> f.getName().equals("plugin.yml") || f.getName().equals("bungee.yml"))
+ .findFirst();
+ if (!pluginYMLFile.isPresent()) {
+ messager.printMessage(Diagnostic.Kind.ERROR, "Could not find plugin.yml or bungee.yml");
+ return;
+ }
+ context = pluginYMLFile.get().getName().equals("bungee.yml") ? Context.BUNGEE : Context.SPIGOT;
+ @Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(pluginYMLFile.get())));
+ Optional mainName = reader.lines()
+ .filter(line -> line.startsWith("main:"))
+ .map(line -> line.substring(line.indexOf(':') + 1).trim())
+ .findFirst();
+ if (mainName.isPresent()) {
+ pluginMain = mainName.get();
+ } else {
+ messager.printMessage(Diagnostic.Kind.ERROR, "Could not find main class in plugin.yml or bungee.yml");
+ }
+ }
+
+ @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 extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (processed) return false;
+ processed = true;
+
+ 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());
+
+ Map, List> groupedByChecks = elements.stream()
+ .collect(Collectors.groupingBy(element -> checks(element, buildPlan)));
+
+ Map neededFields = new HashMap<>();
+ Set fieldInjections = new HashSet<>();
+ for (TypeElement typeElement : elements) {
+ if (getLinkagesOfType(typeElement).size() > 1) {
+ neededFields.put(typeElement.getQualifiedName().toString(), typeElement);
+ }
+
+ List variableElements = typeElement.getEnclosedElements().stream()
+ .filter(e -> e.getKind() == ElementKind.FIELD)
+ .map(VariableElement.class::cast)
+ .filter(e -> e.getAnnotation(LinkedInstance.class) != null)
+ .collect(Collectors.toList());
+ if (variableElements.isEmpty()) continue;
+
+ for (VariableElement variableElement : variableElements) {
+ if (!variableElement.getModifiers().contains(Modifier.PUBLIC)) {
+ messager.printMessage(Diagnostic.Kind.ERROR, "Field " + variableElement.getSimpleName() + " must be public", variableElement);
+ continue;
+ }
+ if (variableElement.getModifiers().contains(Modifier.STATIC)) {
+ messager.printMessage(Diagnostic.Kind.ERROR, "Field " + variableElement.getSimpleName() + " must be non static", variableElement);
+ continue;
+ }
+ if (variableElement.getModifiers().contains(Modifier.FINAL)) {
+ messager.printMessage(Diagnostic.Kind.ERROR, "Field " + variableElement.getSimpleName() + " must be non final", variableElement);
+ continue;
+ }
+ 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(() -> {
+ specialElements(typeElement, buildPlan, buildPlan::addStaticLine, () -> {
+ buildPlan.addStaticLine(getElement(typeElement, neededFields) + "." + variableElement.getSimpleName().toString() + " = " + getElement((TypeElement) ((DeclaredType) variableElement.asType()).asElement(), neededFields) + ";");
+ });
+ });
+ }
+ }
+ 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);
+ buildPlan.addField(new FieldBuilder(typeElement.getSimpleName().toString(), t));
+
+ String finalT = t;
+ specialElements(typeElement, buildPlan, buildPlan::addStaticLine, () -> {
+ buildPlan.addStaticLine(finalT + " = new " + typeElement.getSimpleName().toString() + "();");
+ });
+ });
+ fieldInjections.forEach(Runnable::run);
+
+ Map methods = new HashMap<>();
+ for (Map.Entry, List> entry : groupedByChecks.entrySet()) {
+ Map>> groupedByMethod = new HashMap<>();
+ for (TypeElement typeElement : entry.getValue()) {
+ for (Map.Entry> linkages : getLinkagesOfType(typeElement).entrySet()) {
+ groupedByMethod.computeIfAbsent(linkages.getKey(), ignored -> new HashMap<>())
+ .put(typeElement, linkages.getValue());
+ }
+ }
+
+ for (Map.Entry>> group : groupedByMethod.entrySet()) {
+ MethodBuilder method = methods.computeIfAbsent(group.getKey(), s -> {
+ MethodBuilder methodBuilder = new MethodBuilder(s, "void");
+ buildPlan.addMethod(methodBuilder);
+ return methodBuilder;
+ });
+
+ 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 ")) {
+ method.addLine(typeElement.getSimpleName() + " local" + typeElement.getSimpleName().toString() + " = " + instance + ";");
+ instance = "local" + typeElement.getSimpleName().toString();
+ }
+ String finalInstance = instance;
+ toGenerate.getValue().forEach(linkageType -> {
+ buildPlan.addImport(typeElement.getQualifiedName().toString());
+ linkageType.generateCode(buildPlan, method, finalInstance, typeElement);
+ });
+ }
+ if (generated && !entry.getKey().isEmpty()) method.addLine("}");
+ }
+ }
+
+ BufferedWriter bufferedWriter = new BufferedWriter(writer);
+ buildPlan.write(bufferedWriter);
+ bufferedWriter.close();
+ return true;
+ }
+
+ private String getElement(TypeElement typeElement, Map neededFields) {
+ String s = typeElement.getSimpleName().toString();
+ if (neededFields.containsKey(typeElement.getQualifiedName().toString())) {
+ return s.substring(0, 1).toLowerCase() + s.substring(1);
+ }
+ return "new " + s + "()";
+ }
+
+ private Set checks(TypeElement typeElement, BuildPlan buildPlan) {
+ Set checks = new HashSet<>();
+ MinVersion minVersion = typeElement.getAnnotation(MinVersion.class);
+ MaxVersion maxVersion = typeElement.getAnnotation(MaxVersion.class);
+ EventMode eventMode = typeElement.getAnnotation(EventMode.class);
+ PluginCheck[] pluginChecks = typeElement.getAnnotationsByType(PluginCheck.class);
+ if (context == Context.SPIGOT) {
+ errorOnNonNull(typeElement, eventMode);
+ if (minVersion != null) {
+ buildPlan.addImport("de.steamwar.core.Core");
+ checks.add("Core.getVersion() >= " + minVersion.value());
+ }
+ if (maxVersion != null) {
+ buildPlan.addImport("de.steamwar.core.Core");
+ checks.add("Core.getVersion() <= " + maxVersion.value());
+ }
+ if (pluginChecks.length != 0) {
+ buildPlan.addImport("org.bukkit.Bukkit");
+ Arrays.stream(pluginChecks).map(pluginCheck -> {
+ return "Bukkit.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null";
+ }).forEach(checks::add);
+ }
+ } else {
+ errorOnNonNull(typeElement, minVersion, maxVersion);
+ if (eventMode != null) {
+ buildPlan.addImport("de.steamwar.bungeecore.BungeeCore");
+ checks.add(eventMode.value().getPrefix() + "BungeeCore.EVENT_MODE");
+ }
+ if (pluginChecks.length != 0) {
+ buildPlan.addImport("net.md_5.bungee.BungeeCord");
+ Arrays.stream(pluginChecks).map(pluginCheck -> {
+ return "BungeeCord.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null";
+ }).forEach(checks::add);
+ }
+ }
+ return checks;
+ }
+
+ private void specialElements(TypeElement typeElement, BuildPlan buildPlan, Consumer stringConsumer, Runnable inner) {
+ Set checks = checks(typeElement, buildPlan);
+ if (!checks.isEmpty()) stringConsumer.accept("if (" + String.join(" && ", checks) + ") {");
+ inner.run();
+ if (!checks.isEmpty()) stringConsumer.accept("}");
+ }
+
+ private void errorOnNonNull(TypeElement typeElement, Annotation... annotations) {
+ for (Annotation annotation : annotations) {
+ if (annotation != null) {
+ messager.printMessage(Diagnostic.Kind.ERROR, annotation.annotationType().getSimpleName() + " is not supported in " + context.name(), typeElement);
+ }
+ }
+ }
+
+ private Plain_GENERIC plain_GENERIC = new Plain_GENERIC();
+
+ private Map> getLinkagesOfType(TypeElement typeElement) {
+ Map> linkages = new HashMap<>();
+ Stream.concat(Stream.of(typeElement.getSuperclass()), typeElement.getInterfaces().stream())
+ .map(this::resolveSingle)
+ .filter(Objects::nonNull)
+ .forEach(linkageType -> linkages.computeIfAbsent(linkageType.method(), s -> new ArrayList<>()).add(linkageType));
+ if (linkages.size() == 1 && linkages.containsKey("unlink")) {
+ linkages.put(plain_GENERIC.method(), Collections.singletonList(plain_GENERIC));
+ }
+ return linkages;
+ }
+
+ private LinkageType resolveSingle(TypeMirror typeMirror) {
+ String qualifier = typeMirror.toString();
+ if (qualifier.contains("<")) qualifier = qualifier.substring(0, qualifier.indexOf('<'));
+ qualifier = qualifier.substring(qualifier.lastIndexOf('.') + 1);
+ try {
+ return (LinkageType) Class.forName("de.steamwar.linkage.types." + qualifier + "_" + context.name()).getDeclaredConstructor().newInstance();
+ } catch (Exception e) {
+ // Ignore
+ }
+ try {
+ return (LinkageType) Class.forName("de.steamwar.linkage.types." + qualifier + "_GENERIC").getDeclaredConstructor().newInstance();
+ } catch (Exception e) {
+ // Ignore
+ }
+ return null;
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/LinkageType.java b/CommonCore/src/de/steamwar/linkage/LinkageType.java
new file mode 100644
index 00000000..9291279b
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/LinkageType.java
@@ -0,0 +1,36 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage;
+
+import de.steamwar.linkage.plan.BuildPlan;
+import de.steamwar.linkage.plan.MethodBuilder;
+
+import javax.lang.model.element.TypeElement;
+
+public interface LinkageType {
+
+ default String getPluginMain() {
+ return LinkageProcessor.getPluginMain();
+ }
+
+ String method();
+
+ void generateCode(BuildPlan buildPlan, MethodBuilder method, String instance, TypeElement typeElement);
+}
diff --git a/CommonCore/src/de/steamwar/linkage/Linked.java b/CommonCore/src/de/steamwar/linkage/Linked.java
new file mode 100644
index 00000000..dbaf0eb7
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/Linked.java
@@ -0,0 +1,28 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.TYPE})
+public @interface Linked {
+ String feature() default "";
+}
diff --git a/CommonCore/src/de/steamwar/linkage/LinkedInstance.java b/CommonCore/src/de/steamwar/linkage/LinkedInstance.java
new file mode 100644
index 00000000..9636ba52
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/LinkedInstance.java
@@ -0,0 +1,30 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.FIELD})
+public @interface LinkedInstance {
+}
diff --git a/CommonCore/src/de/steamwar/linkage/MaxVersion.java b/CommonCore/src/de/steamwar/linkage/MaxVersion.java
new file mode 100644
index 00000000..e144b164
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/MaxVersion.java
@@ -0,0 +1,32 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@AllowedContexts(Context.SPIGOT)
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.TYPE})
+public @interface MaxVersion {
+ int value();
+}
diff --git a/CommonCore/src/de/steamwar/linkage/MinVersion.java b/CommonCore/src/de/steamwar/linkage/MinVersion.java
new file mode 100644
index 00000000..b6f5b997
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/MinVersion.java
@@ -0,0 +1,32 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@AllowedContexts(Context.SPIGOT)
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.TYPE})
+public @interface MinVersion {
+ int value();
+}
diff --git a/CommonCore/src/de/steamwar/linkage/PluginCheck.java b/CommonCore/src/de/steamwar/linkage/PluginCheck.java
new file mode 100644
index 00000000..241f19a1
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/PluginCheck.java
@@ -0,0 +1,42 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage;
+
+import java.lang.annotation.*;
+
+@AllowedContexts({Context.BUNGEE, Context.SPIGOT})
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.TYPE})
+@Repeatable(PluginCheck.PluginChecks.class)
+public @interface PluginCheck {
+ Has has() default Has.THIS;
+ String value();
+
+ enum Has {
+ THIS,
+ NOT
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.TYPE})
+ @interface PluginChecks {
+ @SuppressWarnings("unused") PluginCheck[] value() default {};
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/api/Disable.java b/CommonCore/src/de/steamwar/linkage/api/Disable.java
new file mode 100644
index 00000000..f09b8468
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/api/Disable.java
@@ -0,0 +1,24 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage.api;
+
+public interface Disable {
+ void disable();
+}
diff --git a/CommonCore/src/de/steamwar/linkage/api/Enable.java b/CommonCore/src/de/steamwar/linkage/api/Enable.java
new file mode 100644
index 00000000..5d516cd6
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/api/Enable.java
@@ -0,0 +1,24 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage.api;
+
+public interface Enable {
+ void enable();
+}
diff --git a/CommonCore/src/de/steamwar/linkage/api/Plain.java b/CommonCore/src/de/steamwar/linkage/api/Plain.java
new file mode 100644
index 00000000..23901ed2
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/api/Plain.java
@@ -0,0 +1,23 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage.api;
+
+public interface Plain {
+}
diff --git a/CommonCore/src/de/steamwar/linkage/plan/BuildPlan.java b/CommonCore/src/de/steamwar/linkage/plan/BuildPlan.java
new file mode 100644
index 00000000..2fc7b8b4
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/plan/BuildPlan.java
@@ -0,0 +1,89 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage.plan;
+
+import lombok.RequiredArgsConstructor;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.util.*;
+
+@RequiredArgsConstructor
+public class BuildPlan {
+
+ private final String packageName;
+ private Set imports = new HashSet<>();
+ private final String className;
+
+ private List fieldBuilders = new ArrayList<>();
+ private Map methodBuilderMap = new HashMap<>();
+ private List staticLines = new ArrayList<>();
+
+ public void addImport(String importName) {
+ imports.add(importName);
+ }
+
+ public void addField(FieldBuilder fieldBuilder) {
+ fieldBuilders.add(fieldBuilder);
+ }
+
+ public void addMethod(MethodBuilder methodBuilder) {
+ methodBuilderMap.put(methodBuilder.getMethodName(), methodBuilder);
+ }
+
+ public boolean hasMethod(String methodName) {
+ return methodBuilderMap.containsKey(methodName);
+ }
+
+ public void addStaticLine(String line) {
+ staticLines.add(line);
+ }
+
+ public void write(BufferedWriter writer) throws IOException {
+ writer.write("package " + packageName + ";\n");
+ if (!imports.isEmpty()) {
+ writer.write("\n");
+ for (String importName : imports) {
+ writer.write("import " + importName + ";\n");
+ }
+ }
+ writer.write("\n");
+ writer.write("public class " + className + " {\n");
+ if (!fieldBuilders.isEmpty()) {
+ for (FieldBuilder fieldBuilder : fieldBuilders) {
+ fieldBuilder.write(writer);
+ }
+ writer.write("\n");
+ }
+ if (!staticLines.isEmpty()) {
+ writer.write(" static {\n");
+ for (String line : staticLines) {
+ writer.write(" " + line + "\n");
+ }
+ writer.write(" }\n");
+ writer.write("\n");
+ }
+ for (MethodBuilder methodBuilder : methodBuilderMap.values()) {
+ methodBuilder.write(writer);
+ writer.write("\n");
+ }
+ writer.write("}\n");
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/plan/FieldBuilder.java b/CommonCore/src/de/steamwar/linkage/plan/FieldBuilder.java
new file mode 100644
index 00000000..12fa4408
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/plan/FieldBuilder.java
@@ -0,0 +1,44 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage.plan;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+
+@RequiredArgsConstructor
+@AllArgsConstructor
+public class FieldBuilder {
+ @Getter
+ private final String type;
+ private final String name;
+ private String initializer;
+
+ public String getFieldName() {
+ return name;
+ }
+
+ public void write(BufferedWriter writer) throws IOException {
+ writer.write(" private static " + type + " " + getFieldName() + (initializer == null ? "" : " = " + initializer) + ";\n");
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/plan/MethodBuilder.java b/CommonCore/src/de/steamwar/linkage/plan/MethodBuilder.java
new file mode 100644
index 00000000..6a31175a
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/plan/MethodBuilder.java
@@ -0,0 +1,70 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage.plan;
+
+import lombok.RequiredArgsConstructor;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+@RequiredArgsConstructor
+public class MethodBuilder {
+
+ private final String name;
+ private final String returnType;
+ private List parameters = new ArrayList<>();
+ private List lines = new ArrayList<>();
+ private boolean isPrivate = false;
+
+ public void addParameter(ParameterBuilder parameterBuilder) {
+ parameters.add(parameterBuilder);
+ }
+
+ public void addLine(String line) {
+ lines.add(line);
+ }
+
+ public String getMethodName() {
+ return name;
+ }
+
+ public void setPrivate(boolean isPrivate) {
+ this.isPrivate = isPrivate;
+ }
+
+ public void write(BufferedWriter writer) throws IOException {
+ writer.write(" " + (isPrivate ? "private" : "public") + " static " + returnType + " " + getMethodName() + "(");
+ for (int i = 0; i < parameters.size(); i++) {
+ parameters.get(i).write(writer);
+ if (i < parameters.size() - 1) {
+ writer.write(", ");
+ }
+ }
+ writer.write(") {");
+ for (String line : lines) {
+ writer.write("\n");
+ writer.write(" " + line);
+ }
+ writer.write("\n");
+ writer.write(" }\n");
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/plan/ParameterBuilder.java b/CommonCore/src/de/steamwar/linkage/plan/ParameterBuilder.java
new file mode 100644
index 00000000..d88364be
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/plan/ParameterBuilder.java
@@ -0,0 +1,35 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage.plan;
+
+import lombok.AllArgsConstructor;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+
+@AllArgsConstructor
+public class ParameterBuilder {
+ private String type;
+ private String name;
+
+ public void write(BufferedWriter writer) throws IOException {
+ writer.write(type + " " + name);
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/types/Disable_GENERIC.java b/CommonCore/src/de/steamwar/linkage/types/Disable_GENERIC.java
new file mode 100644
index 00000000..ea58c91b
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/types/Disable_GENERIC.java
@@ -0,0 +1,39 @@
+/*
+ * 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 .
+ */
+
+package de.steamwar.linkage.types;
+
+import de.steamwar.linkage.LinkageType;
+import de.steamwar.linkage.plan.BuildPlan;
+import de.steamwar.linkage.plan.MethodBuilder;
+
+import javax.lang.model.element.TypeElement;
+
+public class Disable_GENERIC implements LinkageType {
+
+ @Override
+ public String method() {
+ return "unlink";
+ }
+
+ @Override
+ public void generateCode(BuildPlan buildPlan, MethodBuilder method, String instance, TypeElement typeElement) {
+ method.addLine(instance + ".disable();");
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/types/Enable_GENERIC.java b/CommonCore/src/de/steamwar/linkage/types/Enable_GENERIC.java
new file mode 100644
index 00000000..03afd570
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/types/Enable_GENERIC.java
@@ -0,0 +1,39 @@
+/*
+ * 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 .
+ */
+
+package de.steamwar.linkage.types;
+
+import de.steamwar.linkage.LinkageType;
+import de.steamwar.linkage.plan.BuildPlan;
+import de.steamwar.linkage.plan.MethodBuilder;
+
+import javax.lang.model.element.TypeElement;
+
+public class Enable_GENERIC implements LinkageType {
+
+ @Override
+ public String method() {
+ return "link";
+ }
+
+ @Override
+ public void generateCode(BuildPlan buildPlan, MethodBuilder method, String instance, TypeElement typeElement) {
+ method.addLine(instance + ".enable();");
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/types/Listener_BUNGEE.java b/CommonCore/src/de/steamwar/linkage/types/Listener_BUNGEE.java
new file mode 100644
index 00000000..327b19ad
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/types/Listener_BUNGEE.java
@@ -0,0 +1,41 @@
+/*
+ * 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 .
+ */
+
+package de.steamwar.linkage.types;
+
+import de.steamwar.linkage.LinkageType;
+import de.steamwar.linkage.plan.BuildPlan;
+import de.steamwar.linkage.plan.MethodBuilder;
+
+import javax.lang.model.element.TypeElement;
+
+public class Listener_BUNGEE implements LinkageType {
+
+ @Override
+ public String method() {
+ return "link";
+ }
+
+ @Override
+ public void generateCode(BuildPlan buildPlan, MethodBuilder method, String instance, TypeElement typeElement) {
+ buildPlan.addImport("net.md_5.bungee.api.ProxyServer");
+ buildPlan.addImport("de.steamwar.bungeecore.BungeeCore");
+ method.addLine("ProxyServer.getInstance().getPluginManager().registerListener(BungeeCore.get(), " + instance + ");");
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/types/Listener_SPIGOT.java b/CommonCore/src/de/steamwar/linkage/types/Listener_SPIGOT.java
new file mode 100644
index 00000000..3491d6d2
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/types/Listener_SPIGOT.java
@@ -0,0 +1,105 @@
+/*
+ * 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 .
+ */
+
+package de.steamwar.linkage.types;
+
+import de.steamwar.linkage.LinkageType;
+import de.steamwar.linkage.plan.BuildPlan;
+import de.steamwar.linkage.plan.FieldBuilder;
+import de.steamwar.linkage.plan.MethodBuilder;
+import de.steamwar.linkage.plan.ParameterBuilder;
+
+import javax.lang.model.element.*;
+import javax.lang.model.type.DeclaredType;
+import java.util.HashMap;
+import java.util.Map;
+
+public class Listener_SPIGOT implements LinkageType {
+
+ @Override
+ public String method() {
+ return "link";
+ }
+
+ @Override
+ public void generateCode(BuildPlan buildPlan, MethodBuilder method, String instance, TypeElement typeElement) {
+ Map eventClasses = new HashMap<>();
+ Map eventMethods = new HashMap<>();
+
+ typeElement.getEnclosedElements().stream().filter(e -> e.getKind() == ElementKind.METHOD).map(ExecutableElement.class::cast).filter(e -> {
+ return e.getAnnotationMirrors().stream().anyMatch(annotationMirror -> {
+ return annotationMirror.getAnnotationType().asElement().getSimpleName().toString().equals("EventHandler");
+ });
+ }).forEach(e -> {
+ TypeElement current = ((TypeElement)((DeclaredType) e.getParameters().get(0).asType()).asElement());
+ eventClasses.put(current.getQualifiedName().toString(), current);
+ eventMethods.put(current, e);
+ });
+
+ eventClasses.forEach((s, eventType) -> {
+ if (buildPlan.hasMethod(eventType.getSimpleName().toString())) return;
+ buildPlan.addImport("org.bukkit.event.HandlerList");
+ buildPlan.addImport("org.bukkit.event.Listener");
+ buildPlan.addImport("java.util.function.Consumer");
+ buildPlan.addImport("org.bukkit.event.EventPriority");
+ buildPlan.addImport("org.bukkit.plugin.RegisteredListener");
+ buildPlan.addImport("org.bukkit.plugin.EventExecutor");
+ buildPlan.addImport(s);
+ buildPlan.addField(new FieldBuilder("HandlerList", "handlerList" + eventType.getSimpleName()));
+ MethodBuilder methodBuilder = new MethodBuilder(eventType.getSimpleName().toString(), "void");
+ methodBuilder.addParameter(new ParameterBuilder("Listener", "listener"));
+ methodBuilder.addParameter(new ParameterBuilder("Consumer<" + eventType.getSimpleName() + ">", "consumer"));
+ methodBuilder.addParameter(new ParameterBuilder("EventPriority", "eventPriority"));
+ methodBuilder.addParameter(new ParameterBuilder("boolean", "ignoreCancelled"));
+ methodBuilder.setPrivate(true);
+ methodBuilder.addLine("EventExecutor eventExecutor = (l, event) -> {");
+ methodBuilder.addLine(" if (event instanceof " + eventType.getSimpleName() + ") {");
+ methodBuilder.addLine(" consumer.accept((" + eventType.getSimpleName() + ") event);");
+ methodBuilder.addLine(" }");
+ methodBuilder.addLine("};");
+ methodBuilder.addLine("handlerList" + eventType.getSimpleName() + ".register(new RegisteredListener(listener, eventExecutor, eventPriority, " + getPluginMain() + ".getInstance(), ignoreCancelled));");
+ buildPlan.addMethod(methodBuilder);
+ method.addLine("handlerList" + eventType.getSimpleName() + " = " + eventType.getSimpleName() + ".getHandlerList();");
+ });
+
+ String localInstance = "local" + typeElement.getSimpleName().toString();
+ if (!instance.startsWith("new ")) {
+ localInstance = instance;
+ } else {
+ method.addLine(typeElement.getSimpleName() + " " + localInstance + " = " + instance + ";");
+ }
+ String finalLocalInstance = localInstance;
+ eventMethods.forEach((type, executableElement) -> {
+ AnnotationMirror eventHandler = executableElement.getAnnotationMirrors().stream().filter(annotationMirror -> annotationMirror.getAnnotationType().asElement().getSimpleName().toString().equals("EventHandler")).findFirst().orElse(null);
+ if (eventHandler == null) {
+ return;
+ }
+ String priority = "NORMAL";
+ String ignoreCancelled = "false";
+ for (Map.Entry extends ExecutableElement, ? extends AnnotationValue> entry : eventHandler.getElementValues().entrySet()) {
+ if (entry.getKey().getSimpleName().toString().equals("priority")) {
+ priority = entry.getValue().getValue().toString();
+ } else if (entry.getKey().getSimpleName().toString().equals("ignoreCancelled")) {
+ ignoreCancelled = entry.getValue().getValue().toString();
+ }
+ }
+ method.addLine(type.getSimpleName().toString() + "(" + finalLocalInstance + ", " + finalLocalInstance + "::" + executableElement.getSimpleName().toString() + ", EventPriority." + priority + ", " + ignoreCancelled + ");");
+ });
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/types/PacketHandler_GENERIC.java b/CommonCore/src/de/steamwar/linkage/types/PacketHandler_GENERIC.java
new file mode 100644
index 00000000..630f6f95
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/types/PacketHandler_GENERIC.java
@@ -0,0 +1,39 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.linkage.types;
+
+import de.steamwar.linkage.LinkageType;
+import de.steamwar.linkage.plan.BuildPlan;
+import de.steamwar.linkage.plan.MethodBuilder;
+
+import javax.lang.model.element.TypeElement;
+
+public class PacketHandler_GENERIC implements LinkageType {
+
+ @Override
+ public String method() {
+ return "link";
+ }
+
+ @Override
+ public void generateCode(BuildPlan buildPlan, MethodBuilder method, String instance, TypeElement typeElement) {
+ method.addLine(instance + ".register();");
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/types/Plain_GENERIC.java b/CommonCore/src/de/steamwar/linkage/types/Plain_GENERIC.java
new file mode 100644
index 00000000..f066d035
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/types/Plain_GENERIC.java
@@ -0,0 +1,39 @@
+/*
+ * 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 .
+ */
+
+package de.steamwar.linkage.types;
+
+import de.steamwar.linkage.LinkageType;
+import de.steamwar.linkage.plan.BuildPlan;
+import de.steamwar.linkage.plan.MethodBuilder;
+
+import javax.lang.model.element.TypeElement;
+
+public class Plain_GENERIC implements LinkageType {
+
+ @Override
+ public String method() {
+ return "link";
+ }
+
+ @Override
+ public void generateCode(BuildPlan buildPlan, MethodBuilder method, String instance, TypeElement typeElement) {
+ if (instance.startsWith("new ")) method.addLine(instance + ";");
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/types/SWCommand_BUNGEE.java b/CommonCore/src/de/steamwar/linkage/types/SWCommand_BUNGEE.java
new file mode 100644
index 00000000..5db62c4b
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/types/SWCommand_BUNGEE.java
@@ -0,0 +1,39 @@
+/*
+ * 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 .
+ */
+
+package de.steamwar.linkage.types;
+
+import de.steamwar.linkage.LinkageType;
+import de.steamwar.linkage.plan.BuildPlan;
+import de.steamwar.linkage.plan.MethodBuilder;
+
+import javax.lang.model.element.TypeElement;
+
+public class SWCommand_BUNGEE implements LinkageType {
+
+ @Override
+ public String method() {
+ return "link";
+ }
+
+ @Override
+ public void generateCode(BuildPlan buildPlan, MethodBuilder method, String instance, TypeElement typeElement) {
+ method.addLine(instance + ";");
+ }
+}
diff --git a/CommonCore/src/de/steamwar/linkage/types/SWCommand_SPIGOT.java b/CommonCore/src/de/steamwar/linkage/types/SWCommand_SPIGOT.java
new file mode 100644
index 00000000..96e3f770
--- /dev/null
+++ b/CommonCore/src/de/steamwar/linkage/types/SWCommand_SPIGOT.java
@@ -0,0 +1,39 @@
+/*
+ * 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 .
+ */
+
+package de.steamwar.linkage.types;
+
+import de.steamwar.linkage.LinkageType;
+import de.steamwar.linkage.plan.BuildPlan;
+import de.steamwar.linkage.plan.MethodBuilder;
+
+import javax.lang.model.element.TypeElement;
+
+public class SWCommand_SPIGOT implements LinkageType {
+
+ @Override
+ public String method() {
+ return "link";
+ }
+
+ @Override
+ public void generateCode(BuildPlan buildPlan, MethodBuilder method, String instance, TypeElement typeElement) {
+ method.addLine(instance + ".setMessage(" + getPluginMain() + ".MESSAGE);");
+ }
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/MetaInfos.java b/CommonCore/src/de/steamwar/network/packets/MetaInfos.java
new file mode 100644
index 00000000..61632d7c
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/MetaInfos.java
@@ -0,0 +1,23 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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;
+
+public interface MetaInfos {
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/NetworkPacket.java b/CommonCore/src/de/steamwar/network/packets/NetworkPacket.java
new file mode 100644
index 00000000..987e1ef1
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/NetworkPacket.java
@@ -0,0 +1,62 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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;
+
+import lombok.EqualsAndHashCode;
+import lombok.SneakyThrows;
+
+import java.io.*;
+
+@EqualsAndHashCode
+public abstract class NetworkPacket implements Serializable {
+
+ private static final long serialVersionUID = -3168992457669156473L;
+ private transient MetaInfos metaInfos;
+
+ public MetaInfos getMetaInfos() {
+ return metaInfos;
+ }
+
+ @SneakyThrows
+ public byte[] serialize() {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(this);
+ oos.flush();
+ return baos.toByteArray();
+ }
+
+ public static void handle(byte[] data) {
+ PacketHandler.handlePacket(deserialize(data));
+ }
+
+ public static void handle(MetaInfos metaInfos, byte[] data) {
+ NetworkPacket networkPacket = deserialize(data);
+ networkPacket.metaInfos = metaInfos;
+ PacketHandler.handlePacket(networkPacket);
+ }
+
+ @SneakyThrows
+ public static NetworkPacket deserialize(byte[] data) {
+ ByteArrayInputStream bais = new ByteArrayInputStream(data);
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ return (NetworkPacket) ois.readObject();
+ }
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/PacketHandler.java b/CommonCore/src/de/steamwar/network/packets/PacketHandler.java
new file mode 100644
index 00000000..671eb469
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/PacketHandler.java
@@ -0,0 +1,77 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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;
+
+import lombok.SneakyThrows;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public abstract class PacketHandler {
+
+ private static final List PACKET_HANDLERS = new ArrayList<>();
+
+ private final Map, Method> HANDLER_MAP = new HashMap<>();
+
+ public static void handlePacket(NetworkPacket packet) {
+ for (PacketHandler handler : PACKET_HANDLERS) {
+ handler.handle(packet);
+ }
+ }
+
+ protected PacketHandler() {
+ Method[] methods = getClass().getMethods();
+ for (Method method : methods) {
+ if(method.getParameterCount() != 1 || !NetworkPacket.class.isAssignableFrom(method.getParameterTypes()[0])) {
+ continue;
+ }
+
+ if (method.isAnnotationPresent(Handler.class)) {
+ Class extends NetworkPacket> packetClass = (Class extends NetworkPacket>) method.getParameterTypes()[0];
+ HANDLER_MAP.put(packetClass, method);
+ }
+ }
+ }
+
+ public void register() {
+ PACKET_HANDLERS.add(this);
+ }
+
+ public void unregister() {
+ PACKET_HANDLERS.remove(this);
+ }
+
+ @SneakyThrows
+ public void handle(NetworkPacket packet) {
+ Method method = HANDLER_MAP.get(packet.getClass());
+ if (method == null) {
+ return;
+ }
+ method.invoke(this, packet);
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ protected @interface Handler {}
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/client/ExecuteCommandPacket.java b/CommonCore/src/de/steamwar/network/packets/client/ExecuteCommandPacket.java
new file mode 100644
index 00000000..9f7d000f
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/client/ExecuteCommandPacket.java
@@ -0,0 +1,37 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@Getter
+public class ExecuteCommandPacket extends NetworkPacket {
+
+ private static final long serialVersionUID = 6283457297487602016L;
+ private int playerId;
+ private String command;
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/client/ImALobbyPacket.java b/CommonCore/src/de/steamwar/network/packets/client/ImALobbyPacket.java
new file mode 100644
index 00000000..dcd07ddf
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/client/ImALobbyPacket.java
@@ -0,0 +1,28 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+public class ImALobbyPacket extends NetworkPacket {
+ private static final long serialVersionUID = 8110246509205246654L;
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/client/InventoryCallbackPacket.java b/CommonCore/src/de/steamwar/network/packets/client/InventoryCallbackPacket.java
new file mode 100644
index 00000000..cfe9fbc6
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/client/InventoryCallbackPacket.java
@@ -0,0 +1,88 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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 InventoryCallbackPacket extends NetworkPacket {
+ private static final long serialVersionUID = -261823209186008718L;
+ @Builder.Default
+ private int position = -1;
+ private int owner;
+ private CallbackType type;
+ @Builder.Default
+ private ClickType clickType = ClickType.UNKNOWN;
+
+ public enum CallbackType {
+ CLICK,
+ CLOSE,
+ }
+
+ public enum ClickType {
+ LEFT,
+ SHIFT_LEFT,
+ RIGHT,
+ SHIFT_RIGHT,
+ WINDOW_BORDER_LEFT,
+ WINDOW_BORDER_RIGHT,
+ MIDDLE,
+ NUMBER_KEY,
+ DOUBLE_CLICK,
+ DROP,
+ CONTROL_DROP,
+ CREATIVE,
+ UNKNOWN;
+
+ public boolean isKeyboardClick() {
+ return this == NUMBER_KEY || this == DROP || this == CONTROL_DROP;
+ }
+
+ public boolean isCreativeAction() {
+ return this == MIDDLE || this == CREATIVE;
+ }
+
+ public boolean isRightClick() {
+ return this == RIGHT || this == SHIFT_RIGHT;
+ }
+
+ public boolean isLeftClick() {
+ return this == LEFT || this == SHIFT_LEFT || this == DOUBLE_CLICK || this == CREATIVE;
+ }
+
+ public boolean isShiftClick() {
+ return this == SHIFT_LEFT || this == SHIFT_RIGHT || this == CONTROL_DROP;
+ }
+
+ public static ClickType getByName(String name) {
+ for (ClickType type : values()) {
+ if (type.name().equalsIgnoreCase(name)) {
+ return type;
+ }
+ }
+ return UNKNOWN;
+ }
+ }
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/client/PrepareSchemPacket.java b/CommonCore/src/de/steamwar/network/packets/client/PrepareSchemPacket.java
new file mode 100644
index 00000000..8f607faf
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/client/PrepareSchemPacket.java
@@ -0,0 +1,38 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@Getter
+public class PrepareSchemPacket extends NetworkPacket {
+
+ private static final long serialVersionUID = -4798561188105813349L;
+ private int player;
+ private int schem;
+ private String schemType;
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/client/RequestSchematicSearchPacket.java b/CommonCore/src/de/steamwar/network/packets/client/RequestSchematicSearchPacket.java
new file mode 100644
index 00000000..ea8420ca
--- /dev/null
+++ b/CommonCore/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/CommonCore/src/de/steamwar/network/packets/common/FightEndsPacket.java b/CommonCore/src/de/steamwar/network/packets/common/FightEndsPacket.java
new file mode 100644
index 00000000..c1d86bb6
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/common/FightEndsPacket.java
@@ -0,0 +1,42 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.common;
+
+import de.steamwar.network.packets.NetworkPacket;
+import lombok.*;
+
+import java.util.List;
+
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@Getter
+public class FightEndsPacket extends NetworkPacket {
+
+ private static final long serialVersionUID = 1279352415549011332L;
+ private byte win;
+ private int blueSchem;
+ private int redSchem;
+ private List bluePlayers;
+ private List redPlayers;
+ private String gameMode;
+ private int duration;
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/common/FightInfoPacket.java b/CommonCore/src/de/steamwar/network/packets/common/FightInfoPacket.java
new file mode 100644
index 00000000..bbca8b09
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/common/FightInfoPacket.java
@@ -0,0 +1,49 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.common;
+
+import de.steamwar.network.packets.NetworkPacket;
+import lombok.*;
+
+import java.util.List;
+
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@Getter
+public class FightInfoPacket extends NetworkPacket {
+
+ private static final long serialVersionUID = 7448644597856605853L;
+ private @With String serverName;
+ private String gameMode;
+ private String arena;
+ private String blueName;
+ private String redName;
+ private String fightState;
+ private int countdown;
+ private int blueLeader;
+ private int redLeader;
+ private int blueSchem;
+ private int redSchem;
+ private List bluePlayers;
+ private List redPlayers;
+ private List spectators;
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/server/BaumemberUpdatePacket.java b/CommonCore/src/de/steamwar/network/packets/server/BaumemberUpdatePacket.java
new file mode 100644
index 00000000..5351473a
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/server/BaumemberUpdatePacket.java
@@ -0,0 +1,29 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.server;
+
+import de.steamwar.network.packets.NetworkPacket;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+public class BaumemberUpdatePacket extends NetworkPacket {
+ private static final long serialVersionUID = 6863118892424244051L;
+
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/server/CloseInventoryPacket.java b/CommonCore/src/de/steamwar/network/packets/server/CloseInventoryPacket.java
new file mode 100644
index 00000000..e30d927f
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/server/CloseInventoryPacket.java
@@ -0,0 +1,36 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.server;
+
+import de.steamwar.network.packets.NetworkPacket;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@Getter
+public class CloseInventoryPacket extends NetworkPacket {
+
+ private static final long serialVersionUID = -2191021190060504521L;
+ private int playerId;
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/server/InventoryPacket.java b/CommonCore/src/de/steamwar/network/packets/server/InventoryPacket.java
new file mode 100644
index 00000000..8e7f7b37
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/server/InventoryPacket.java
@@ -0,0 +1,41 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.server;
+
+import de.steamwar.network.packets.NetworkPacket;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.Map;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@Getter
+public class InventoryPacket extends NetworkPacket {
+
+ private static final long serialVersionUID = 8071052544654047316L;
+ private String title;
+ private int player;
+ private int size;
+ private Map items;
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/server/LocaleInvalidationPacket.java b/CommonCore/src/de/steamwar/network/packets/server/LocaleInvalidationPacket.java
new file mode 100644
index 00000000..1e24547d
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/server/LocaleInvalidationPacket.java
@@ -0,0 +1,35 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.server;
+
+import de.steamwar.network.packets.NetworkPacket;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@Getter
+public class LocaleInvalidationPacket extends NetworkPacket {
+ private static final long serialVersionUID = 1113963147008168582L;
+ private int playerId;
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/server/PingPacket.java b/CommonCore/src/de/steamwar/network/packets/server/PingPacket.java
new file mode 100644
index 00000000..88ac32a8
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/server/PingPacket.java
@@ -0,0 +1,35 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.server;
+
+import de.steamwar.network.packets.NetworkPacket;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@Getter
+public class PingPacket extends NetworkPacket {
+ private static final long serialVersionUID = 714647343959550378L;
+ private int id;
+}
diff --git a/CommonCore/src/de/steamwar/network/packets/server/StartingServerPacket.java b/CommonCore/src/de/steamwar/network/packets/server/StartingServerPacket.java
new file mode 100644
index 00000000..f536d8fe
--- /dev/null
+++ b/CommonCore/src/de/steamwar/network/packets/server/StartingServerPacket.java
@@ -0,0 +1,35 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.server;
+
+import de.steamwar.network.packets.NetworkPacket;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@Getter
+public class StartingServerPacket extends NetworkPacket {
+ private static final long serialVersionUID = 2808607245898121801L;
+ private int user;
+}
diff --git a/CommonCore/src/de/steamwar/sql/BannedUserIPs.java b/CommonCore/src/de/steamwar/sql/BannedUserIPs.java
new file mode 100644
index 00000000..f5828177
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/BannedUserIPs.java
@@ -0,0 +1,67 @@
+/*
+ * 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.time.Instant;
+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.insertAll();
+ 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, Timestamp.from(Instant.now()), ip);
+ }
+
+ public static void unbanIPs(int userID) {
+ unbanIPs.update(userID);
+ }
+}
diff --git a/CommonCore/src/de/steamwar/sql/BauweltMember.java b/CommonCore/src/de/steamwar/sql/BauweltMember.java
new file mode 100644
index 00000000..4efd9c38
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/BauweltMember.java
@@ -0,0 +1,123 @@
+/*
+ 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 .
+*/
+
+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;
+
+import java.util.*;
+
+public class BauweltMember {
+ private static final Map memberCache = new HashMap<>();
+
+ public static void clear() {
+ memberCache.clear();
+ }
+
+ 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());
+ }
+
+ public static BauweltMember getBauMember(int ownerID, int memberID){
+ BauweltMember member = memberCache.get(memberID);
+ if(member != null && member.bauweltID == ownerID)
+ return member;
+ return getMember.select(ownerID, memberID);
+ }
+
+ public static List getMembers(UUID bauweltID){
+ return getMembers(SteamwarUser.get(bauweltID).getId());
+ }
+
+ public static List getMembers(int bauweltID){
+ return getMembers.listSelect(bauweltID);
+ }
+
+ @Getter
+ @Field(keys = {Table.PRIMARY})
+ private final int bauweltID;
+ @Getter
+ @Field(keys = {Table.PRIMARY})
+ private final int memberID;
+ @Getter
+ @Field(def = "0")
+ private boolean worldEdit;
+ @Getter
+ @Field(def = "0")
+ private boolean world;
+
+ public BauweltMember(int bauweltID, int memberID, boolean worldEdit, boolean world) {
+ this.bauweltID = bauweltID;
+ this.memberID = memberID;
+ this.worldEdit = worldEdit;
+ 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);
+ memberCache.remove(memberID);
+ }
+
+ public boolean isBuild() {
+ return worldEdit;
+ }
+
+ public boolean isSupervisor() {
+ return world;
+ }
+
+ public void setBuild(boolean build) {
+ this.worldEdit = build;
+ updateDB();
+ }
+
+ public void setSupervisor(boolean supervisor) {
+ this.world = supervisor;
+ updateDB();
+ }
+}
diff --git a/CommonCore/src/de/steamwar/sql/CheckedSchematic.java b/CommonCore/src/de/steamwar/sql/CheckedSchematic.java
new file mode 100644
index 00000000..e173d413
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/CheckedSchematic.java
@@ -0,0 +1,86 @@
+/*
+ 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 .
+*/
+
+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 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
+ private final int nodeOwner;
+ @Field
+ private final String nodeName;
+ @Getter
+ @Field
+ private final int validator;
+ @Getter
+ @Field
+ private final Timestamp startTime;
+ @Getter
+ @Field
+ private final Timestamp endTime;
+ @Getter
+ @Field
+ private final String declineReason;
+
+ public int getNode() {
+ return nodeId;
+ }
+
+ public String getSchemName() {
+ return nodeName;
+ }
+
+ public int getSchemOwner() {
+ return nodeOwner;
+ }
+}
diff --git a/CommonCore/src/de/steamwar/sql/Event.java b/CommonCore/src/de/steamwar/sql/Event.java
new file mode 100644
index 00000000..31c220ac
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/Event.java
@@ -0,0 +1,109 @@
+/*
+ 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 .
+*/
+
+package de.steamwar.sql;
+
+import de.steamwar.sql.internal.Field;
+import de.steamwar.sql.internal.SelectStatement;
+import de.steamwar.sql.internal.Table;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.sql.Timestamp;
+import java.time.Instant;
+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()");
+ 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;
+ @Getter
+ @Field(keys = {"eventName"})
+ private final String eventName;
+ @Getter
+ @Field
+ private final Timestamp deadline;
+ @Getter
+ @Field
+ private final Timestamp start;
+ @Getter
+ @Field
+ private final Timestamp end;
+ @Getter
+ @Field
+ private final int maximumTeamMembers;
+ @Field(nullable = true)
+ private final SchematicType schemType;
+ @Field
+ private final boolean publicSchemsOnly;
+ @Deprecated
+ @Field
+ private final boolean spectateSystem;
+
+ public boolean publicSchemsOnly() {
+ return publicSchemsOnly;
+ }
+ public boolean spectateSystem(){
+ return spectateSystem;
+ }
+
+ public SchematicType getSchematicType() {
+ return schemType;
+ }
+
+ private boolean now() {
+ Instant now = Instant.now();
+ return now.isAfter(start.toInstant()) && now.isBefore(end.toInstant());
+ }
+}
diff --git a/CommonCore/src/de/steamwar/sql/EventFight.java b/CommonCore/src/de/steamwar/sql/EventFight.java
new file mode 100644
index 00000000..623e383a
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/EventFight.java
@@ -0,0 +1,136 @@
+/*
+ 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 .
+*/
+
+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.*;
+
+import static java.time.temporal.ChronoUnit.SECONDS;
+
+@AllArgsConstructor
+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;
+ @Getter
+ @Field(keys = {Table.PRIMARY}, autoincrement = true)
+ 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
+ private final int teamRed;
+ @Getter
+ @Field
+ @Deprecated
+ private final int kampfleiter;
+ @Getter
+ @Field
+ private final int spectatePort;
+ @Getter
+ @Field(def = "0")
+ private int ergebnis;
+ @Field(nullable = true)
+ private int fight;
+
+ public void setErgebnis(int winner) {
+ this.ergebnis = winner;
+ setResult.update(winner, fightID);
+ }
+
+ public void setFight(int fight) {
+ //Fight.FightID, not EventFight.FightID
+ this.fight = fight;
+ setFight.update(fight, fightID);
+ }
+
+ public boolean hasFinished() {
+ return fight != 0 || ergebnis != 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/CommonCore/src/de/steamwar/sql/Fight.java b/CommonCore/src/de/steamwar/sql/Fight.java
new file mode 100644
index 00000000..efa230d2
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/Fight.java
@@ -0,0 +1,124 @@
+/*
+ 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 .
+*/
+
+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
+ private final int duration;
+ @Field
+ private final int blueLeader;
+ @Field
+ private final int redLeader;
+ @Field(nullable = true)
+ 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;
+
+ @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/CommonCore/src/de/steamwar/sql/FightPlayer.java b/CommonCore/src/de/steamwar/sql/FightPlayer.java
new file mode 100644
index 00000000..57b977c6
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/FightPlayer.java
@@ -0,0 +1,65 @@
+/*
+ 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 .
+*/
+
+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
+ private final String kit;
+ @Field
+ private final int kills;
+ @Field
+ private final boolean isOut;
+
+ 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/CommonCore/src/de/steamwar/sql/IgnoreSystem.java b/CommonCore/src/de/steamwar/sql/IgnoreSystem.java
new file mode 100644
index 00000000..d6ce26aa
--- /dev/null
+++ b/CommonCore/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/CommonCore/src/de/steamwar/sql/Mod.java b/CommonCore/src/de/steamwar/sql/Mod.java
new file mode 100644
index 00000000..2a4e6981
--- /dev/null
+++ b/CommonCore/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/CommonCore/src/de/steamwar/sql/NoClipboardException.java b/CommonCore/src/de/steamwar/sql/NoClipboardException.java
new file mode 100644
index 00000000..97433485
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/NoClipboardException.java
@@ -0,0 +1,23 @@
+/*
+ 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 .
+*/
+
+package de.steamwar.sql;
+
+public class NoClipboardException extends RuntimeException {
+}
diff --git a/CommonCore/src/de/steamwar/sql/NodeData.java b/CommonCore/src/de/steamwar/sql/NodeData.java
new file mode 100644
index 00000000..52743811
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/NodeData.java
@@ -0,0 +1,92 @@
+/*
+ * 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.io.*;
+import java.sql.PreparedStatement;
+import java.util.zip.GZIPInputStream;
+
+@AllArgsConstructor
+public class NodeData {
+
+ static {
+ new SqlTypeMapper<>(PipedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("PipedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
+ new SqlTypeMapper<>(ByteArrayInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("ByteArrayInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
+ new SqlTypeMapper<>(BufferedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("BufferedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
+ }
+
+ private static final Table table = new Table<>(NodeData.class);
+
+ private static final Statement updateDatabase = new Statement("INSERT INTO NodeData(NodeId, NodeFormat, SchemData) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE NodeFormat = VALUES(NodeFormat), SchemData = VALUES(SchemData)");
+ private static final Statement selSchemData = new Statement("SELECT SchemData FROM NodeData WHERE NodeId = ?");
+
+ private static final SelectStatement get = table.select(Table.PRIMARY);
+
+ public static NodeData get(SchematicNode node) {
+ if(node.isDir())
+ throw new IllegalArgumentException("Node is a directory");
+ return get.select(rs -> {
+ if(rs.next()) {
+ return new NodeData(node.getId(), rs.getBoolean("NodeFormat"));
+ } else {
+ return new NodeData(node.getId(), false);
+ }
+ }, node);
+ }
+
+ @Getter
+ @Field(keys = {Table.PRIMARY})
+ private final int nodeId;
+
+ @Field
+ private boolean nodeFormat;
+
+ public InputStream schemData() throws IOException {
+ try {
+ return selSchemData.select(rs -> {
+ rs.next();
+ InputStream schemData = rs.getBinaryStream("SchemData");
+ try {
+ if(rs.wasNull() || schemData.available() == 0) {
+ throw new SecurityException("SchemData is null");
+ }
+ return new GZIPInputStream(schemData);
+ } catch (IOException e) {
+ throw new SecurityException("SchemData is wrong", e);
+ }
+ }, nodeId);
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+
+ public void saveFromStream(InputStream blob, boolean newFormat) {
+ updateDatabase.update(nodeId, newFormat, blob);
+ nodeFormat = newFormat;
+ }
+
+ public boolean getNodeFormat() {
+ return nodeFormat;
+ }
+}
diff --git a/CommonCore/src/de/steamwar/sql/NodeDownload.java b/CommonCore/src/de/steamwar/sql/NodeDownload.java
new file mode 100644
index 00000000..666cf681
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/NodeDownload.java
@@ -0,0 +1,69 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2021 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.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.sql.Timestamp;
+import java.time.Instant;
+
+@AllArgsConstructor
+public class NodeDownload {
+
+ private static final char[] HEX = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ private static final String LINK_BASE = "https://steamwar.de/download.php?schem=";
+
+ private static final Table table = new Table<>(NodeDownload.class);
+ private static final Statement insert = table.insertFields("NodeId", "Link");
+
+ @Field(keys = {Table.PRIMARY})
+ private final int nodeId;
+ @Field
+ private final String link;
+ @Field(def = "CURRENT_TIMESTAMP")
+ private final Timestamp timestamp;
+
+ public static String getLink(SchematicNode schem){
+ if(schem.isDir())
+ throw new SecurityException("Can not Download Directorys");
+ MessageDigest digest;
+ try {
+ digest = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ throw new SecurityException(e);
+ }
+ digest.reset();
+ digest.update((Instant.now().toString() + schem.getOwner() + schem.getId()).getBytes());
+ String hash = base16encode(digest.digest());
+ insert.update(schem.getId(), hash);
+ return LINK_BASE + hash;
+ }
+ public static String base16encode(byte[] byteArray) {
+ StringBuilder hexBuffer = new StringBuilder(byteArray.length * 2);
+ for (byte b : byteArray)
+ hexBuffer.append(HEX[(b >>> 4) & 0xF]).append(HEX[b & 0xF]);
+ return hexBuffer.toString();
+ }
+}
diff --git a/CommonCore/src/de/steamwar/sql/NodeMember.java b/CommonCore/src/de/steamwar/sql/NodeMember.java
new file mode 100644
index 00000000..e25764ec
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/NodeMember.java
@@ -0,0 +1,91 @@
+/*
+ * 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 .
+ */
+
+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.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+@AllArgsConstructor
+public class NodeMember {
+
+ public static void init() {
+ // enforce class initialization
+ }
+
+ private static final Table table = new Table<>(NodeMember.class);
+ private static final SelectStatement getNodeMember = table.select(Table.PRIMARY);
+ private static final SelectStatement getNodeMembers = table.selectFields("NodeId");
+ private static final SelectStatement getSchematics = table.selectFields("UserId");
+ private static final Statement create = table.insert(Table.PRIMARY);
+ private static final Statement delete = table.delete(Table.PRIMARY);
+ private static final Statement updateParent = table.update(Table.PRIMARY, "ParentId");
+
+ @Field(keys = {Table.PRIMARY})
+ private final int nodeId;
+ @Field(keys = {Table.PRIMARY})
+ private final int userId;
+ @Field(nullable = true, def = "null")
+ private Integer parentId;
+
+ public int getNode() {
+ return nodeId;
+ }
+
+ public int getMember() {
+ return userId;
+ }
+
+ public Optional getParent() {
+ return Optional.ofNullable(parentId);
+ }
+
+ public void delete() {
+ delete.update(nodeId, userId);
+ }
+
+ public static NodeMember createNodeMember(int node, int member) {
+ create.update(node, member);
+ return new NodeMember(node, member, null);
+ }
+
+ public static NodeMember getNodeMember(int node, int member) {
+ return getNodeMember.select(node, member);
+ }
+
+ public static Set getNodeMembers(int node) {
+ return new HashSet<>(getNodeMembers.listSelect(node));
+ }
+
+ public static Set getSchematics(int member) {
+ return new HashSet<>(getSchematics.listSelect(member));
+ }
+
+ public void setParentId(Integer parentId) {
+ this.parentId = parentId;
+ updateParent.update(this.parentId, nodeId, userId);
+ }
+}
diff --git a/CommonCore/src/de/steamwar/sql/PollAnswer.java b/CommonCore/src/de/steamwar/sql/PollAnswer.java
new file mode 100644
index 00000000..933f2536
--- /dev/null
+++ b/CommonCore/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/CommonCore/src/de/steamwar/sql/Punishment.java b/CommonCore/src/de/steamwar/sql/Punishment.java
new file mode 100644
index 00000000..5960dcef
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/Punishment.java
@@ -0,0 +1,140 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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 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;
+
+@AllArgsConstructor
+public class Punishment {
+
+ static {
+ 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
+ private final int punisher;
+ @Field
+ @Getter
+ private final PunishmentType type;
+ @Field
+ @Getter
+ private final Timestamp startTime;
+ @Field
+ @Getter
+ private final Timestamp endTime;
+ @Field
+ @Getter
+ private final boolean perma;
+ @Field
+ @Getter
+ private final String reason;
+
+ @Deprecated // Not multiling, misleading title
+ public String getBantime(Timestamp endTime, boolean perma) {
+ if (perma) {
+ return "permanent";
+ } else {
+ return endTime.toLocalDateTime().format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"));
+ }
+ }
+
+ 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"),
+ Mute( false, "MUTE_TEAM", "MUTE_PERMA", "MUTE_UNTIL", "UNMUTE_ERROR", "UNMUTE"),
+ 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"),
+ 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;
+ private final String playerMessagePerma;
+ private final String playerMessageUntil;
+ private final String usageNotPunished;
+ private final String unpunishmentMessage;
+ private boolean multi = false;
+ }
+}
diff --git a/CommonCore/src/de/steamwar/sql/Referee.java b/CommonCore/src/de/steamwar/sql/Referee.java
new file mode 100644
index 00000000..281ad302
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/Referee.java
@@ -0,0 +1,44 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 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.Table;
+import lombok.AllArgsConstructor;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@AllArgsConstructor
+public class Referee {
+
+ private static final Table table = new Table<>(Referee.class);
+ private static final SelectStatement byEvent = table.selectFields("eventID");
+
+ public static Set get(int eventID) {
+ return byEvent.listSelect(eventID).stream().map(referee -> referee.userID).collect(Collectors.toSet());
+ }
+
+ @Field(keys = {"eventReferee"})
+ private final int eventID;
+ @Field(keys = {"eventReferee"})
+ private final int userID;
+}
diff --git a/CommonCore/src/de/steamwar/sql/Replay.java b/CommonCore/src/de/steamwar/sql/Replay.java
new file mode 100644
index 00000000..a90e2392
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/Replay.java
@@ -0,0 +1,74 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.sql.SQLException;
+
+@AllArgsConstructor
+public class Replay {
+
+ static {
+ new SqlTypeMapper<>(File.class, "BLOB", (rs, identifier) -> {
+ try {
+ File file = File.createTempFile("replay", ".replay");
+ file.deleteOnExit();
+ Files.copy(rs.getBinaryStream(identifier), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ return file;
+ } catch (IOException e) {
+ throw new SQLException(e);
+ }
+ }, (st, index, value) -> {
+ try {
+ st.setBinaryStream(index, new FileInputStream(value));
+ } catch (FileNotFoundException e) {
+ throw new SQLException(e);
+ }
+ });
+ }
+
+ private static final Table table = new Table<>(Replay.class);
+ private static final SelectStatement get = table.select(Table.PRIMARY);
+
+ public static final Statement insert = table.insertAll();
+
+ public static Replay get(int fightID) {
+ return get.select(fightID);
+ }
+
+ public static void save(int fightID, File file) {
+ insert.update(fightID, file);
+ }
+
+ @Field(keys = {Table.PRIMARY})
+ private final int fightID;
+ @Getter
+ @Field
+ private final File replay;
+}
diff --git a/CommonCore/src/de/steamwar/sql/SQLWrapper.java b/CommonCore/src/de/steamwar/sql/SQLWrapper.java
new file mode 100644
index 00000000..cff7dec9
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/SQLWrapper.java
@@ -0,0 +1,33 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.ImplementationProvider;
+
+import java.util.List;
+import java.util.Map;
+
+public interface SQLWrapper {
+ SQLWrapper impl = ImplementationProvider.getImpl("de.steamwar.sql.SQLWrapperImpl");
+
+ void loadSchemTypes(List tmpTypes, Map tmpFromDB);
+
+ void additionalExceptionMetadata(StringBuilder builder);
+}
diff --git a/CommonCore/src/de/steamwar/sql/SWException.java b/CommonCore/src/de/steamwar/sql/SWException.java
new file mode 100644
index 00000000..4656804a
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/SWException.java
@@ -0,0 +1,68 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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.io.File;
+import java.sql.Timestamp;
+
+@AllArgsConstructor
+public class SWException {
+
+ public static void init() {
+ // force class initialialisation
+ }
+
+ private static final String CWD = System.getProperty("user.dir");
+ private static final String SERVER_NAME = new File(CWD).getName();
+
+ private static final Table table = new Table<>(SWException.class, "Exception");
+ private static final Statement insert = table.insertFields(true, "server", "message", "stacktrace");
+
+ @Field(keys = {Table.PRIMARY}, autoincrement = true)
+ private final int id;
+ @Field(def = "CURRENT_TIMESTAMP")
+ private final Timestamp time;
+ @Field
+ private final String server;
+ @Field
+ private final String message;
+ @Field
+ private final String stacktrace;
+
+ public static void log(String message, String stacktrace){
+ insert.update(SERVER_NAME, generateMessage(message), stacktrace);
+ }
+
+ public static int logGetId(String message, String stacktrace) {
+ return insert.insertGetKey(SERVER_NAME, generateMessage(message), stacktrace);
+ }
+
+ private static String generateMessage(String message) {
+ StringBuilder msgBuilder = new StringBuilder(message);
+ SQLWrapper.impl.additionalExceptionMetadata(msgBuilder);
+ msgBuilder.append("\nCWD: ").append(CWD);
+ return msgBuilder.toString();
+ }
+}
diff --git a/CommonCore/src/de/steamwar/sql/SchemElo.java b/CommonCore/src/de/steamwar/sql/SchemElo.java
new file mode 100644
index 00000000..0e92cfd5
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/SchemElo.java
@@ -0,0 +1,56 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 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;
+
+@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;
+ @Field
+ private final int elo;
+ @Field(keys = {Table.PRIMARY})
+ private final int season;
+}
diff --git a/CommonCore/src/de/steamwar/sql/SchematicNode.java b/CommonCore/src/de/steamwar/sql/SchematicNode.java
new file mode 100644
index 00000000..b432a709
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/SchematicNode.java
@@ -0,0 +1,559 @@
+/*
+ * 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 .
+ */
+
+package de.steamwar.sql;
+
+import de.steamwar.sql.internal.*;
+import lombok.Getter;
+
+import java.sql.Timestamp;
+import java.time.Instant;
+import java.util.*;
+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));
+ }
+
+ private static final Map>> TAB_CACHE = new HashMap<>();
+ public static void clear() {
+ TAB_CACHE.clear();
+ }
+
+ private static final String nodeSelector = "SELECT NodeId, NodeOwner, NodeOwner AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode ";
+
+ private static final Table table = new Table<>(SchematicNode.class);
+ private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem", "NodeType");
+ private static final Statement update = table.update(Table.PRIMARY, "NodeName", "ParentNode", "NodeItem", "NodeType", "NodeRank", "ReplaceColor", "AllowReplay");
+ private static final Statement delete = table.delete(Table.PRIMARY);
+
+ private static final SelectStatement byId = new SelectStatement<>(table, nodeSelector + "WHERE NodeId = ?");
+ private static final SelectStatement byOwnerNameParent = new SelectStatement<>(table, nodeSelector + "WHERE NodeOwner = ? AND NodeName = ? AND ParentNode " + Statement.NULL_SAFE_EQUALS + "?");
+ private static final SelectStatement byParent = new SelectStatement<>(table, nodeSelector + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName");
+ private static final SelectStatement dirsByParent = new SelectStatement<>(table, nodeSelector + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? AND NodeType is NULL ORDER BY NodeName");
+ private static final SelectStatement byOwnerType = new SelectStatement<>(table, nodeSelector + "WHERE NodeOwner = ? AND NodeType = ? ORDER BY NodeName");
+ private static final SelectStatement byType = new SelectStatement<>(table, nodeSelector + "WHERE NodeType = ? ORDER BY NodeName");
+ private static final SelectStatement all = new SelectStatement<>(table, "SELECT * FROM EffectiveSchematicNode WHERE EffectiveOwner = ? ORDER BY NodeName");
+ 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 RSASN AS(WITH RECURSIVE RSAN AS (WITH RSANH AS (WITH RECURSIVE RSA AS (SELECT SN.NodeId, NM.ParentId FROM SchematicNode SN LEFT JOIN NodeMember NM on SN.NodeId = NM.NodeId WHERE NM.UserId = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN INNER JOIN RSA ON RSA.NodeId = SN.ParentNode) SELECT * FROM RSA UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?) SELECT * FROM RSANH UNION SELECT SN.NodeId, SN.ParentNode FROM RSANH JOIN SchematicNode SN ON SN.ParentNode = RSANH.NodeId) SELECT RSAN.NodeId, RSAN.ParentId FROM RSAN JOIN SchematicNode SN ON SN.NodeId = RSAN.NodeId WHERE NodeType = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN JOIN RSASN ON SN.NodeId = RSASN.ParentId) SELECT SN.*, ? as EffectiveOwner, RSASN.ParentId AS ParentNode FROM RSASN JOIN SchematicNode SN ON SN.NodeId = RSASN.NodeId WHERE RSASN.ParentId" + Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName");
+ 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");
+
+ static {
+ NodeMember.init();
+ }
+
+ @Field(keys = {Table.PRIMARY}, autoincrement = true)
+ private final int nodeId;
+ @Field(keys = {"OwnerNameParent"})
+ private final int nodeOwner;
+ @Field(def = "0")
+ @Getter
+ private final int effectiveOwner;
+ @Field(keys = {"OwnerNameParent"})
+ private String nodeName;
+ @Field(keys = {"OwnerNameParent"}, nullable = true)
+ private Integer parentNode;
+ @Field(def = "CURRENT_TIMESTAMP")
+ private Timestamp lastUpdate;
+ @Field(def = "''")
+ private String nodeItem;
+ @Field(def = "'normal'", nullable = true)
+ private SchematicType nodeType;
+ @Field(def = "0")
+ private int nodeRank;
+ @Field(def = "1")
+ private boolean replaceColor;
+ @Field(def = "1")
+ private boolean allowReplay;
+
+ private String brCache;
+
+ public SchematicNode(
+ int nodeId,
+ int nodeOwner,
+ int effectiveOwner,
+ String nodeName,
+ Integer parentNode,
+ Timestamp lastUpdate,
+ String nodeItem,
+ SchematicType nodeType,
+ int nodeRank,
+ boolean replaceColor,
+ boolean allowReplay
+ ) {
+ this.nodeId = nodeId;
+ this.nodeOwner = nodeOwner;
+ this.effectiveOwner = effectiveOwner;
+ this.nodeName = nodeName;
+ this.parentNode = parentNode;
+ this.nodeItem = nodeItem;
+ this.nodeType = nodeType;
+ this.lastUpdate = lastUpdate;
+ this.nodeRank = nodeRank;
+ this.replaceColor = replaceColor;
+ this.allowReplay = allowReplay;
+ }
+
+ public static List getAll(SteamwarUser user) {
+ return all.listSelect(user);
+ }
+
+ public static Map> getAllMap(SteamwarUser user) {
+ return map(getAll(user));
+ }
+
+ public static List list(SteamwarUser user, Integer schematicId) {
+ return list.listSelect(user, schematicId, user, user, schematicId, user, schematicId, schematicId);
+ }
+
+ public static SchematicNode byParentName(SteamwarUser user, Integer schematicId, String name) {
+ return byParentName.select(user, schematicId, user, name, user, schematicId, user, schematicId, schematicId, name);
+ }
+
+ public static List accessibleByUserType(SteamwarUser user, SchematicType type) {
+ return accessibleByUserType.listSelect(user, user, user, type);
+ }
+
+ public static Map> accessibleByUserTypeMap(SteamwarUser user, SchematicType type) {
+ return map(accessibleByUserType(user, type));
+ }
+
+ public static boolean schematicAccessibleForUser(SteamwarUser user, Integer schematicId) {
+ return schematicAccessibleForUser.select(user, schematicId) != null;
+ }
+
+ public static List accessibleByUserTypeParent(SteamwarUser user, SchematicType type, Integer parentId) {
+ return accessibleByUserTypeInParent.listSelect(user, user, type, user, parentId);
+ }
+
+ public static SchematicNode byIdAndUser(SteamwarUser user, Integer id) {
+ return byIdAndUser.select(user, id);
+ }
+
+ public static List parentsOfNode(SteamwarUser user, Integer id) {
+ return allParentsOfNode.listSelect(id, user, user, user);
+ }
+
+ private static Map> map(List in) {
+ Map> map = new HashMap<>();
+ for (SchematicNode effectiveSchematicNode : in) {
+ map.computeIfAbsent(effectiveSchematicNode.getOptionalParent().orElse(0), k -> new ArrayList<>()).add(effectiveSchematicNode);
+ }
+ return map;
+ }
+
+ public static SchematicNode createSchematic(int owner, String name, Integer parent) {
+ return createSchematicNode(owner, name, parent, SchematicType.Normal.toDB(), "");
+ }
+
+ public static SchematicNode createSchematicDirectory(int owner, String name, Integer parent) {
+ return createSchematicNode(owner, name, parent, null, "");
+ }
+
+ public static SchematicNode createSchematicNode(int owner, String name, Integer parent, String type, String item) {
+ if (parent != null && parent == 0)
+ parent = null;
+ int nodeId = create.insertGetKey(owner, name, parent, item, type);
+ return getSchematicNode(nodeId);
+ }
+
+ public static SchematicNode getSchematicNode(int owner, String name, SchematicNode parent) {
+ return getSchematicNode(owner, name, parent.getId());
+ }
+
+ public static SchematicNode getSchematicNode(int owner, String name, Integer parent) {
+ return byOwnerNameParent.select(owner, name, parent);
+ }
+
+ public static List getSchematicNodeInNode(SchematicNode parent) {
+ return getSchematicNodeInNode(parent.getId());
+ }
+
+ public static List getSchematicNodeInNode(Integer parent) {
+ return byParent.listSelect(parent);
+ }
+
+ public static List getSchematicDirectoryInNode(Integer parent) {
+ return dirsByParent.listSelect(parent);
+ }
+
+ @Deprecated
+ public static SchematicNode getSchematicDirectory(String name, SchematicNode parent) {
+ return getSchematicNode(name, parent.getId());
+ }
+
+ @Deprecated
+ public static SchematicNode getSchematicDirectory(String name, Integer parent) {
+ return getSchematicNode(name, parent);
+ }
+
+ public static SchematicNode getSchematicNode(String name, Integer parent) {
+ return byParentName.select(name, parent);
+ }
+
+ public static SchematicNode getSchematicNode(int id) {
+ return byId.select(id);
+ }
+
+ public static List getAccessibleSchematicsOfTypeInParent(int owner, String schemType, Integer parent) {
+ return accessibleByUserTypeParent(SteamwarUser.get(owner), SchematicType.fromDB(schemType), parent);
+ }
+
+ public static List getAllAccessibleSchematicsOfType(int user, String schemType) {
+ return accessibleByUserType(SteamwarUser.get(user), SchematicType.fromDB(schemType));
+ }
+
+ public static List getAllSchematicsOfType(int owner, String schemType) {
+ return byOwnerType.listSelect(owner, schemType);
+ }
+
+ @Deprecated
+ public static List getAllSchematicsOfType(String schemType) {
+ return byType.listSelect(schemType);
+ }
+
+ public static List getAllSchematicsOfType(SchematicType schemType) {
+ return byType.listSelect(schemType);
+ }
+
+ public static List deepGet(Integer parent, Predicate filter) {
+ List finalList = new ArrayList<>();
+ List nodes = SchematicNode.getSchematicNodeInNode(parent);
+ nodes.forEach(node -> {
+ if (node.isDir()) {
+ finalList.addAll(deepGet(node.getId(), filter));
+ } else {
+ if (filter.test(node))
+ finalList.add(node);
+ }
+ });
+ return finalList;
+ }
+
+ @Deprecated
+ public static List getSchematicsAccessibleByUser(int user, Integer parent) {
+ return list(SteamwarUser.get(user), parent);
+ }
+
+ @Deprecated
+ public static List getAllSchematicsAccessibleByUser(int user) {
+ return getAll(SteamwarUser.get(user));
+ }
+
+ public static List getAllParentsOfNode(SchematicNode node) {
+ return getAllParentsOfNode(node.getId());
+ }
+
+ public static List getAllParentsOfNode(int node) {
+ return allParentsOfNode.listSelect(node);
+ }
+
+ public static SchematicNode getNodeFromPath(SteamwarUser user, String s) {
+ if (s.startsWith("/")) {
+ s = s.substring(1);
+ }
+ if (s.endsWith("/")) {
+ s = s.substring(0, s.length() - 1);
+ }
+ if (s.isEmpty()) {
+ return null;
+ }
+ if (s.contains("/")) {
+ String[] layers = s.split("/");
+ Optional currentNode = Optional.ofNullable(SchematicNode.byParentName(user, null, layers[0]));
+ for (int i = 1; i < layers.length; i++) {
+ int finalI = i;
+ Optional node = currentNode.map(effectiveSchematicNode -> SchematicNode.byParentName(user, effectiveSchematicNode.getId(), layers[finalI]));
+ if (!node.isPresent()) {
+ return null;
+ } else {
+ currentNode = node;
+ if (!currentNode.map(SchematicNode::isDir).orElse(false) && i != layers.length - 1) {
+ return null;
+ }
+ }
+ }
+ return currentNode.orElse(null);
+ } else {
+ return SchematicNode.byParentName(user, null, s);
+ }
+ }
+
+ public static List filterSchems(int user, Predicate filter) {
+ List finalList = new ArrayList<>();
+ List nodes = getSchematicsAccessibleByUser(user, null);
+ nodes.forEach(node -> {
+ if (node.isDir()) {
+ finalList.addAll(deepGet(node.getId(), filter));
+ } else {
+ if (filter.test(node))
+ finalList.add(node);
+ }
+ });
+ return finalList;
+ }
+
+ public int getId() {
+ return nodeId;
+ }
+
+ public int getOwner() {
+ return nodeOwner;
+ }
+
+ public String getName() {
+ return nodeName;
+ }
+
+ public void setName(String name) {
+ this.nodeName = name;
+ updateDB();
+ }
+
+ public Integer getParent() {
+ return parentNode;
+ }
+
+ public Optional getOptionalParent() {
+ return Optional.ofNullable(parentNode);
+ }
+
+ public void setParent(Integer parent) {
+ this.parentNode = parent;
+ updateDB();
+ }
+
+ public String getItem() {
+ if (nodeItem.isEmpty()) {
+ return isDir() ? "CHEST" : "CAULDRON_ITEM";
+ }
+ return nodeItem;
+ }
+
+ public void setItem(String item) {
+ this.nodeItem = item;
+ updateDB();
+ }
+
+ @Deprecated
+ public String getType() {
+ return nodeType.name();
+ }
+
+ @Deprecated
+ public void setType(String type) {
+ if(isDir())
+ throw new SecurityException("Node is Directory");
+ this.nodeType = SchematicType.fromDB(type);
+ updateDB();
+ }
+
+ public boolean isDir() {
+ return nodeType == null;
+ }
+
+ @Deprecated
+ public boolean getSchemFormat() {
+ if(isDir())
+ throw new SecurityException("Node is Directory");
+ return NodeData.get(this).getNodeFormat();
+ }
+
+ public int getRank() {
+ if(isDir())
+ throw new SecurityException("Node is Directory");
+ return nodeRank;
+ }
+
+ @Deprecated
+ public int getRankUnsafe() {
+ return nodeRank;
+ }
+
+ public void setRank(int rank) {
+ if(isDir())
+ throw new SecurityException("Node is Directory");
+ this.nodeRank = rank;
+ }
+
+ public SchematicType getSchemtype() {
+ if(isDir())
+ throw new SecurityException("Is Directory");
+ return nodeType;
+ }
+
+ public void setSchemtype(SchematicType type) {
+ if(isDir())
+ throw new SecurityException("Is Directory");
+ this.nodeType = type;
+ updateDB();
+ }
+
+ public boolean replaceColor() {
+ return replaceColor;
+ }
+
+ public void setReplaceColor(boolean replaceColor) {
+ if(isDir())
+ throw new SecurityException("Is Directory");
+ this.replaceColor = replaceColor;
+ updateDB();
+ }
+
+ public boolean allowReplay() {
+ return allowReplay;
+ }
+
+ public void setAllowReplay(boolean allowReplay) {
+ if(isDir())
+ throw new SecurityException("Is Directory");
+ this.allowReplay = allowReplay;
+ updateDB();
+ }
+
+ public SchematicNode getParentNode() {
+ if(parentNode == null) return null;
+ return SchematicNode.getSchematicNode(parentNode);
+ }
+
+ public int getElo(int season) {
+ return SchemElo.getElo(this, season);
+ }
+
+ public boolean accessibleByUser(int user) {
+ return NodeMember.getNodeMember(nodeId, user) != null;
+ }
+
+ public Set getMembers() {
+ return NodeMember.getNodeMembers(nodeId);
+ }
+
+ public Timestamp getLastUpdate() {
+ return lastUpdate;
+ }
+
+ private void updateDB() {
+ this.lastUpdate = Timestamp.from(Instant.now());
+ update.update(nodeName, parentNode, nodeItem, nodeType, nodeRank, replaceColor, allowReplay, nodeId);
+ TAB_CACHE.clear();
+ }
+
+ public void delete() {
+ delete.update(nodeId);
+ }
+
+ @Override
+ public int hashCode() {
+ return nodeId;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof SchematicNode))
+ return false;
+
+ return ((SchematicNode) obj).getId() == nodeId;
+ }
+
+ public String generateBreadcrumbs(SteamwarUser user) {
+ return byIdAndUser(user, nodeId).generateBreadcrumbs();
+ }
+
+ public String generateBreadcrumbs(String split, SteamwarUser user) {
+ return byIdAndUser(user, nodeId).generateBreadcrumbs(split);
+ }
+
+ public String generateBreadcrumbs() {
+ if(brCache == null) {
+ brCache = generateBreadcrumbs("/");
+ }
+ return brCache;
+ }
+
+ public String generateBreadcrumbs(String split) {
+ StringBuilder builder = new StringBuilder(getName());
+ Optional currentNode = Optional.of(this);
+ if(currentNode.map(SchematicNode::isDir).orElse(false)) {
+ builder.append(split);
+ }
+ while (currentNode.isPresent()) {
+ currentNode = currentNode.flatMap(schematicNode -> Optional.ofNullable(NodeMember.getNodeMember(schematicNode.getId(), effectiveOwner)).map(NodeMember::getParent).orElse(schematicNode.getOptionalParent())).map(SchematicNode::getSchematicNode);
+ currentNode.ifPresent(node -> builder.insert(0, split).insert(0, node.getName()));
+ }
+ return builder.toString();
+ }
+
+ private static final List FORBIDDEN_NAMES = Collections.unmodifiableList(Arrays.asList("public"));
+ public static boolean invalidSchemName(String[] layers) {
+ for (String layer : layers) {
+ if (layer.isEmpty()) {
+ return true;
+ }
+ if (layer.contains("/") ||
+ layer.contains("\\") ||
+ layer.contains("<") ||
+ layer.contains(">") ||
+ layer.contains("^") ||
+ layer.contains("°") ||
+ layer.contains("'") ||
+ layer.contains("\"") ||
+ layer.contains(" ")) {
+ return true;
+ }
+ if(FORBIDDEN_NAMES.contains(layer.toLowerCase())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static List getNodeTabcomplete(SteamwarUser user, String s) {
+ boolean sws = s.startsWith("/");
+ if (sws) {
+ s = s.substring(1);
+ }
+ int index = s.lastIndexOf("/");
+ String cacheKey = index == -1 ? "" : s.substring(0, index);
+ if(TAB_CACHE.containsKey(user.getId()) && TAB_CACHE.get(user.getId()).containsKey(cacheKey)) {
+ return new ArrayList<>(TAB_CACHE.get(user.getId()).get(cacheKey));
+ }
+ List list = new ArrayList<>();
+ if (s.contains("/")) {
+ String preTab = s.substring(0, s.lastIndexOf("/") + 1);
+ SchematicNode pa = SchematicNode.getNodeFromPath(user, preTab);
+ if (pa == null) return new ArrayList<>();
+ List nodes = SchematicNode.list(user, pa.getId());
+ String br = pa.generateBreadcrumbs();
+ nodes.forEach(node -> list.add((sws ? "/" : "") + br + node.getName() + (node.isDir() ? "/" : "")));
+ } else {
+ List nodes = SchematicNode.list(user, null);
+ nodes.forEach(node -> list.add((sws ? "/" : "") + node.getName() + (node.isDir() ? "/" : "")));
+ }
+ list.remove("//copy");
+ TAB_CACHE.computeIfAbsent(user.getId(), integer -> new HashMap<>()).putIfAbsent(cacheKey, list);
+ return list;
+ }
+}
diff --git a/CommonCore/src/de/steamwar/sql/SchematicType.java b/CommonCore/src/de/steamwar/sql/SchematicType.java
new file mode 100644
index 00000000..0ee483a8
--- /dev/null
+++ b/CommonCore/src/de/steamwar/sql/SchematicType.java
@@ -0,0 +1,124 @@
+/*
+ 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 .
+*/
+
+package de.steamwar.sql;
+
+import de.steamwar.sql.internal.SqlTypeMapper;
+import lombok.Getter;
+
+import java.util.*;
+
+public class SchematicType {
+
+ public static final SchematicType Normal = new SchematicType("Normal", "", Type.NORMAL, null, "STONE_BUTTON", false);
+
+ private static final Map fromDB;
+ private static final List types;
+
+ static {
+ List tmpTypes = new LinkedList<>();
+ Map tmpFromDB = new HashMap<>();
+
+ tmpTypes.add(Normal);
+ tmpFromDB.put(Normal.name().toLowerCase(), Normal);
+
+ SQLWrapper.impl.loadSchemTypes(tmpTypes, tmpFromDB);
+
+ fromDB = Collections.unmodifiableMap(tmpFromDB);
+ types = Collections.unmodifiableList(tmpTypes);
+ }
+
+ static {
+ new SqlTypeMapper<>(SchematicType.class, "VARCHAR(16)", (rs, identifier) -> {
+ String t = rs.getString(identifier);
+ return t != null ? fromDB.get(t) : null;
+ }, (st, index, value) -> st.setString(index, value.toDB()));
+ }
+
+ 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;
+ @Getter
+ private final boolean manualCheck;
+
+ SchematicType(String name, String kuerzel, Type type, SchematicType checkType, String material, boolean manualCheck){
+ this(name, kuerzel, type, checkType, material, null, manualCheck);
+ }
+
+ SchematicType(String name, String kuerzel, Type type, SchematicType checkType, String material, Date deadline, boolean manualCheck){
+ this.name = name;
+ this.kuerzel = kuerzel;
+ this.type = type;
+ this.checkType = checkType;
+ this.material = material;
+ this.deadline = deadline;
+ this.manualCheck = manualCheck;
+ }
+
+ public boolean isAssignable(){
+ return type == Type.NORMAL || (type == Type.FIGHT_TYPE && checkType != null) || !manualCheck;
+ }
+
+ public SchematicType checkType(){
+ if (!manualCheck) {
+ return this;
+ }
+ return checkType;
+ }
+
+ public boolean check(){
+ return type == Type.CHECK_TYPE;
+ }
+
+ public boolean fightType(){
+ return type == Type.FIGHT_TYPE;
+ }
+
+ public boolean writeable(){
+ return type == Type.NORMAL;
+ }
+
+ public String name(){
+ return name;
+ }
+
+ public String toDB(){
+ return name.toLowerCase();
+ }
+
+ public static SchematicType fromDB(String input){
+ return fromDB.get(input.toLowerCase());
+ }
+
+ public static List values(){
+ return types;
+ }
+
+ enum Type{
+ NORMAL,
+ CHECK_TYPE,
+ FIGHT_TYPE
+ }
+}
diff --git a/CommonCore/src/de/steamwar/sql/Script.java b/CommonCore/src/de/steamwar/sql/Script.java
new file mode 100644
index 00000000..9691c439
--- /dev/null
+++ b/CommonCore/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