Merge branch 'master' into CMDAPIStrings

# Conflicts:
#	src/de/steamwar/command/SWCommandUtils.java
Dieser Commit ist enthalten in:
yoyosource 2022-12-18 13:32:36 +01:00
Commit d38ddb54c7
32 geänderte Dateien mit 2766 neuen und 10 gelöschten Zeilen

Datei anzeigen

@ -81,6 +81,8 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.hamcrest:hamcrest:2.2'
compileOnly 'org.xerial:sqlite-jdbc:3.36.0'
}
task buildResources {

Datei anzeigen

@ -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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar;
import java.lang.reflect.InvocationTargetException;
public class ImplementationProvider {
private ImplementationProvider() {}
public static <T> 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);
}
}
}

Datei anzeigen

@ -58,10 +58,10 @@ public class SWCommandUtils {
if (s.equalsIgnoreCase("false")) return false;
return null;
}, s -> Arrays.asList("true", "false")));
addMapper(float.class, Float.class, createMapper(numberMapper(Float::parseFloat), numberCompleter(Float::parseFloat)));
addMapper(double.class, Double.class, createMapper(numberMapper(Double::parseDouble), numberCompleter(Double::parseDouble)));
addMapper(int.class, Integer.class, createMapper(numberMapper(Integer::parseInt), numberCompleter(Integer::parseInt)));
addMapper(long.class, Long.class, createMapper(numberMapper(Long::parseLong), numberCompleter(Long::parseLong)));
addMapper(float.class, Float.class, createMapper(numberMapper(Float::parseFloat), numberCompleter(Float::parseFloat, true)));
addMapper(double.class, Double.class, createMapper(numberMapper(Double::parseDouble), numberCompleter(Double::parseDouble, true)));
addMapper(int.class, Integer.class, createMapper(numberMapper(Integer::parseInt), numberCompleter(Integer::parseInt, false)));
addMapper(long.class, Long.class, createMapper(numberMapper(Long::parseLong), numberCompleter(Long::parseLong, false)));
MAPPER_FUNCTIONS.put(String.class.getTypeName(), createMapper(s -> {
if (s.startsWith("\"") && s.endsWith("\"")) {
return s.substring(1, s.length() - 1);
@ -103,12 +103,10 @@ public class SWCommandUtils {
Class<?> varArgType = parameter.isVarArgs() ? parameter.getType().getComponentType() : null;
AbstractSWCommand.OptionalValue optionalValue = parameter.getAnnotation(AbstractSWCommand.OptionalValue.class);
AbstractSWCommand.AllowNull allowNull = parameter.getAnnotation(AbstractSWCommand.AllowNull.class);
AbstractSWCommand.Quotable quotable = parameter.getAnnotation(AbstractSWCommand.Quotable.class);
CommandPart<T> commandPart = new CommandPart<>(command, typeMapper, validator, varArgType, optionalValue != null ? optionalValue.value() : null, parameter, i);
commandPart.setOnlyUseIfNoneIsGiven(optionalValue != null && optionalValue.onlyUINIG());
commandPart.setAllowNullValues(allowNull != null);
commandPart.setQuotable(quotable != null);
if (current != null) {
current.setNext(commandPart);
}
@ -265,10 +263,25 @@ public class SWCommandUtils {
};
}
private static Function<String, Collection<String>> numberCompleter(Function<String, ?> mapper) {
return s -> numberMapper(mapper).apply(s) != null
? Collections.singletonList(s)
: Collections.emptyList();
private static Function<String, Collection<String>> numberCompleter(Function<String, ?> mapper, boolean comma) {
return s -> {
if (numberMapper(mapper).apply(s) == null) {
return Collections.emptyList();
}
List<String> strings = new ArrayList<>();
if (s.length() == 0) {
strings.add("-");
} else {
strings.add(s);
}
for (int i = 0; i < 10; i++) {
strings.add(s + i);
}
if (comma && (!s.contains(".") || !s.contains(","))) {
strings.add(s + ".");
}
return strings;
};
}
static <T extends Annotation> T[] getAnnotation(Method method, Class<T> annotation) {

Datei anzeigen

@ -292,6 +292,7 @@ public class LinkageProcessor extends AbstractProcessor {
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();

Datei anzeigen

@ -0,0 +1,79 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
import de.steamwar.sql.internal.Field;
import de.steamwar.sql.internal.SelectStatement;
import de.steamwar.sql.internal.Table;
import lombok.Getter;
import java.util.*;
public class BauweltMember {
private static final Map<Integer, BauweltMember> memberCache = new HashMap<>();
public static void clear() {
memberCache.clear();
}
private static final Table<BauweltMember> table = new Table<>(BauweltMember.class);
private static final SelectStatement<BauweltMember> getMember = table.select(Table.PRIMARY);
private static final SelectStatement<BauweltMember> getMembers = table.selectFields("BauweltID");
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)
return member;
return getMember.select(ownerID, memberID);
}
public static List<BauweltMember> getMembers(UUID bauweltID){
return getMembers(SteamwarUser.get(bauweltID).getId());
}
public static List<BauweltMember> 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
private final boolean worldEdit;
@Getter
@Field
private final 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);
}
}

Datei anzeigen

@ -0,0 +1,71 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.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.util.List;
@AllArgsConstructor
public class CheckedSchematic {
private static final Table<CheckedSchematic> table = new Table<>(CheckedSchematic.class);
private static final SelectStatement<CheckedSchematic> statusOfNode = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != 'Prüfvorgang abgebrochen' ORDER BY EndTime DESC");
public static List<CheckedSchematic> getLastDeclinedOfNode(int node){
return statusOfNode.listSelect(node);
}
@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;
}
}

Datei anzeigen

@ -0,0 +1,75 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.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;
@AllArgsConstructor
public class Event {
private static final Table<Event> table = new Table<>(Event.class);
private static final SelectStatement<Event> byId = table.select(Table.PRIMARY);
public static Event get(int eventID){
return byId.select(eventID);
}
@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;
@Field
private final boolean spectateSystem;
public boolean publicSchemsOnly() {
return publicSchemsOnly;
}
public boolean spectateSystem(){
return spectateSystem;
}
public SchematicType getSchematicType() {
return schemType;
}
}

Datei anzeigen

@ -0,0 +1,72 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.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;
@AllArgsConstructor
public class EventFight {
private static final Table<EventFight> table = new Table<>(EventFight.class);
private static final SelectStatement<EventFight> byId = table.select(Table.PRIMARY);
private static final Statement setResult = table.update(Table.PRIMARY, "Ergebnis");
private static final Statement setFight = table.update(Table.PRIMARY, "Fight");
public static EventFight get(int fightID) {
return byId.select(fightID);
}
@Getter
@Field
private final int eventID;
@Getter
@Field(keys = {Table.PRIMARY}, autoincrement = true)
private final int fightID;
@Getter
@Field
private final int teamBlue;
@Getter
@Field
private final int teamRed;
@Getter
@Field
private final int kampfleiter;
@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);
}
}

Datei anzeigen

@ -0,0 +1,61 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
import de.steamwar.sql.internal.Field;
import de.steamwar.sql.internal.Statement;
import de.steamwar.sql.internal.Table;
import lombok.AllArgsConstructor;
import java.sql.Timestamp;
@AllArgsConstructor
public class Fight {
private static final Table<Fight> table = new Table<>(Fight.class);
private static final Statement insert = table.insertFields(true, "GameMode", "Server", "StartTime", "Duration", "BlueLeader", "RedLeader", "BlueSchem", "RedSchem", "Win", "WinCondition");
@Field(keys = {Table.PRIMARY}, autoincrement = true)
private final int fightID;
@Field
private final String gameMode;
@Field
private final String server;
@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;
@Field
private final int win;
@Field
private final String wincondition;
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);
}
}

Datei anzeigen

@ -0,0 +1,49 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
import de.steamwar.sql.internal.Field;
import de.steamwar.sql.internal.Statement;
import de.steamwar.sql.internal.Table;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class FightPlayer {
private static final Table<FightPlayer> table = new Table<>(FightPlayer.class);
private static final Statement create = table.insertAll();
@Field(keys = {Table.PRIMARY})
private final int fightID;
@Field(keys = {Table.PRIMARY})
private final int userID;
@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);
}
}

Datei anzeigen

@ -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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
public class NoClipboardException extends RuntimeException {
}

Datei anzeigen

@ -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 <https://www.gnu.org/licenses/>.
*/
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.security.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<NodeDownload> 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();
}
}

Datei anzeigen

@ -0,0 +1,78 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.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.Set;
@AllArgsConstructor
public class NodeMember {
public static void init() {
// enforce class initialization
}
private static final Table<NodeMember> table = new Table<>(NodeMember.class);
private static final SelectStatement<NodeMember> getNodeMember = table.select(Table.PRIMARY);
private static final SelectStatement<NodeMember> getNodeMembers = table.selectFields("NodeId");
private static final SelectStatement<NodeMember> getSchematics = table.selectFields("UserId");
private static final Statement create = table.insertAll();
private static final Statement delete = table.delete(Table.PRIMARY);
@Field(keys = {Table.PRIMARY})
private final int nodeId;
@Field(keys = {Table.PRIMARY})
private final int userId;
public int getNode() {
return nodeId;
}
public int getMember() {
return userId;
}
public void delete() {
delete.update(nodeId, userId);
}
public static NodeMember createNodeMember(int node, int member) {
create.update(node, member);
return new NodeMember(node, member);
}
public static NodeMember getNodeMember(int node, int member) {
return getNodeMember.select(node, member);
}
public static Set<NodeMember> getNodeMembers(int node) {
return new HashSet<>(getNodeMembers.listSelect(node));
}
public static Set<NodeMember> getSchematics(int member) {
return new HashSet<>(getSchematics.listSelect(member));
}
}

Datei anzeigen

@ -0,0 +1,122 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
import de.steamwar.sql.internal.Field;
import de.steamwar.sql.internal.SelectStatement;
import de.steamwar.sql.internal.SqlTypeMapper;
import de.steamwar.sql.internal.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.sql.Timestamp;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@AllArgsConstructor
public class Punishment {
static {
SqlTypeMapper.nameEnumMapper(PunishmentType.class);
}
private static final Table<Punishment> table = new Table<>(Punishment.class, "Punishments");
private static final SelectStatement<Punishment> getPunishments = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE PunishmentId IN (SELECT MAX(PunishmentId) FROM Punishments WHERE UserId = ? GROUP BY Type)");
private static final SelectStatement<Punishment> getPunishment = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE UserId = ? AND Type = ? ORDER BY PunishmentId DESC LIMIT 1");
@Field(keys = {Table.PRIMARY}, autoincrement = true)
private final int punishmentId;
@Field
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;
public static Punishment getPunishmentOfPlayer(int user, PunishmentType type) {
return getPunishment.select(user, type);
}
public static Map<PunishmentType, Punishment> getPunishmentsOfPlayer(int user) {
return getPunishments.listSelect(user).stream().collect(Collectors.toMap(Punishment::getType, punishment -> punishment));
}
public static boolean isPunished(SteamwarUser user, Punishment.PunishmentType type, Consumer<Punishment> callback) {
Punishment punishment = Punishment.getPunishmentOfPlayer(user.getId(), type);
if(punishment == null || !punishment.isCurrent()) {
return false;
} else {
callback.accept(punishment);
return true;
}
}
@Deprecated // Not multiling, misleading title
public String getBantime(Timestamp endTime, boolean perma) {
if (perma) {
return "permanent";
} else {
return endTime.toLocalDateTime().format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"));
}
}
public int getUserId() {
return userId;
}
public boolean isCurrent() {
return isPerma() || getEndTime().after(new Date());
}
@AllArgsConstructor
@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");
private final boolean needsAdmin;
private final String teamMessage;
private final String playerMessagePerma;
private final String playerMessageUntil;
private final String usageNotPunished;
private final String unpunishmentMessage;
}
}

Datei anzeigen

@ -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 <https://www.gnu.org/licenses/>.
*/
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<Replay> table = new Table<>(Replay.class);
private static final SelectStatement<Replay> 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;
}

Datei anzeigen

@ -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 <https://www.gnu.org/licenses/>.
*/
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<SchematicType> tmpTypes, Map<String, SchematicType> tmpFromDB);
void additionalExceptionMetadata(StringBuilder builder);
}

Datei anzeigen

@ -0,0 +1,61 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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<SWException> table = new Table<>(SWException.class, "Exception");
private static final Statement insert = table.insertFields("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){
StringBuilder msgBuilder = new StringBuilder(message);
SQLWrapper.impl.additionalExceptionMetadata(msgBuilder);
msgBuilder.append("\nCWD: ").append(CWD);
insert.update(SERVER_NAME, msgBuilder.toString(), stacktrace);
}
}

Datei anzeigen

@ -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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
import de.steamwar.sql.internal.Field;
import de.steamwar.sql.internal.SelectStatement;
import de.steamwar.sql.internal.Table;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class SchemElo {
private static final Table<SchemElo> table = new Table<>(SchemElo.class);
private static final SelectStatement<SchemElo> select = table.select(Table.PRIMARY);
@Field(keys = {Table.PRIMARY})
private final int schemId;
@Field
private final int elo;
@Field(keys = {Table.PRIMARY})
private final int season;
public static int getElo(SchematicNode node, int season) {
SchemElo elo = select.select(node, season);
return elo != null ? elo.elo : 0;
}
}

Datei anzeigen

@ -0,0 +1,547 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
import de.steamwar.sql.internal.*;
import lombok.AccessLevel;
import lombok.Setter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class SchematicNode {
static {
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<Integer, Map<String, List<String>>> TAB_CACHE = new HashMap<>();
public static void clear() {
TAB_CACHE.clear();
}
private static final String[] fields = {"NodeId", "NodeOwner", "NodeName", "ParentNode", "LastUpdate", "NodeItem", "NodeType", "NodeRank", "ReplaceColor", "AllowReplay", "NodeFormat"};
private static String nodeSelectCreator(String itemPrefix) {
return "SELECT " + Arrays.stream(fields).map(s -> itemPrefix + s).collect(Collectors.joining(", ")) + " FROM SchematicNode ";
}
private static final Table<SchematicNode> table = new Table<>(SchematicNode.class);
private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem", "NodeType");
private static final Statement update = table.insertAll();
private static final Statement delete = table.delete(Table.PRIMARY);
private static final SelectStatement<SchematicNode> byId = table.select(Table.PRIMARY);
private static final SelectStatement<SchematicNode> byOwnerNameParent = table.select("OwnerNameParent");
private static final SelectStatement<SchematicNode> byOwnerNameParent_null = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeOwner = ? AND NodeName = ? AND ParentNode is NULL");
private static final SelectStatement<SchematicNode> byParent = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byParent_null = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode is NULL ORDER BY NodeName");
private static final SelectStatement<SchematicNode> dirsByParent = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode = ? AND NodeType is NULL ORDER BY NodeName");
private static final SelectStatement<SchematicNode> dirsByParent_null = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode is NULL AND NodeType is NULL ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byParentName = table.selectFields("NodeName", "ParentNode");
private static final SelectStatement<SchematicNode> byParentName_null = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeName = ? AND ParentNode is NULL");
private static final SelectStatement<SchematicNode> accessibleByUserTypeParent = new SelectStatement<>(table, "WITH RECURSIVE RSNB AS (WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN WHERE NodeType = ? UNION " + nodeSelectCreator("SN.") + "AS SN, RSNB WHERE SN.NodeId = RSNB.ParentNode)SELECT * FROM RSNB WHERE ParentNode = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> accessibleByUserTypeParent_Null = new SelectStatement<>(table, "WITH RECURSIVE RSNB AS (WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN WHERE NodeType = ? UNION " + nodeSelectCreator("SN.") + "AS SN, RSNB WHERE SN.NodeId = RSNB.ParentNode)SELECT * FROM RSNB WHERE ParentNode is null ORDER BY NodeName");
private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table, "WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN WHERE NodeType = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byOwnerType = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeOwner = ? AND NodeType = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byType = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeType = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> accessibleByUser = new SelectStatement<>(table, nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) AND ((s.NodeOwner = ? AND s.ParentNode IS NULL) OR NOT s.NodeOwner = ?) GROUP BY s.NodeId ORDER BY s.NodeName");
private static final Statement schematicAccessibleForUser = new Statement("WITH RECURSIVE RSN AS (" + nodeSelectCreator("") + "WHERE NodeId = ? UNION " + nodeSelectCreator("SN.") + "SN, RSN WHERE RSN.ParentNode = SN.NodeId) SELECT COUNT(RSN.NodeId) AS `Accessible` FROM RSN LEFT Join NodeMember NM On NM.NodeId = RSN.NodeId WHERE NodeOwner = ? OR UserId = ? LIMIT 1");
private static final SelectStatement<SchematicNode> allAccessibleByUser = new SelectStatement<>(table, "WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN ORDER BY NodeName");
private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table, "WITH RECURSIVE RSN AS (" + nodeSelectCreator("") + "WHERE NodeId = ? UNION " + nodeSelectCreator("SN.") + "SN, RSN WHERE RSN.ParentNode = SN.NodeId) SELECT * FROM RSN ORDER BY NodeName");
static {
NodeMember.init();
}
@Field(keys = {Table.PRIMARY}, autoincrement = true)
private final int nodeId;
@Field(keys = {"OwnerNameParent"})
private final int nodeOwner;
@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;
@Setter(AccessLevel.PACKAGE)
@Field(def = "1")
private boolean nodeFormat;
private final Map<Integer, String> brCache = new HashMap<>();
public SchematicNode(
int nodeId,
int nodeOwner,
String nodeName,
Integer parentNode,
Timestamp lastUpdate,
String nodeItem,
SchematicType nodeType,
int nodeRank,
boolean replaceColor,
boolean allowReplay,
boolean nodeFormat
) {
this.nodeId = nodeId;
this.nodeOwner = nodeOwner;
this.nodeName = nodeName;
this.parentNode = parentNode;
this.nodeItem = nodeItem;
this.nodeType = nodeType;
this.lastUpdate = lastUpdate;
this.nodeRank = nodeRank;
this.replaceColor = replaceColor;
this.allowReplay = allowReplay;
this.nodeFormat = nodeFormat;
}
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) {
if (parent == null || parent == 0)
return byOwnerNameParent_null.select(owner, name);
return byOwnerNameParent.select(owner, name, parent);
}
public static List<SchematicNode> getSchematicNodeInNode(SchematicNode parent) {
return getSchematicNodeInNode(parent.getId());
}
public static List<SchematicNode> getSchematicNodeInNode(Integer parent) {
if(parent == null || parent == 0) {
rootWarning();
return byParent_null.listSelect();
}
return byParent.listSelect(parent);
}
public static List<SchematicNode> getSchematicDirectoryInNode(Integer parent) {
if(parent == null || parent == 0) {
rootWarning();
return dirsByParent_null.listSelect();
}
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) {
if(parent == null || parent == 0) {
rootWarning();
return byParentName_null.select(name);
}
return byParentName.select(name, parent);
}
public static SchematicNode getSchematicNode(int id) {
return byId.select(id);
}
public static List<SchematicNode> getAccessibleSchematicsOfTypeInParent(int owner, String schemType, Integer parent) {
if(parent == null || parent == 0)
return accessibleByUserTypeParent_Null.listSelect(owner, owner, schemType);
return accessibleByUserTypeParent.listSelect(owner, owner, schemType, parent);
}
public static List<SchematicNode> getAllAccessibleSchematicsOfType(int user, String schemType) {
return accessibleByUserType.listSelect(user, user, schemType);
}
public static List<SchematicNode> getAllSchematicsOfType(int owner, String schemType) {
return byOwnerType.listSelect(owner, schemType);
}
@Deprecated
public static List<SchematicNode> getAllSchematicsOfType(String schemType) {
return byType.listSelect(schemType);
}
public static List<SchematicNode> getAllSchematicsOfType(SchematicType schemType) {
return byType.listSelect(schemType);
}
public static List<SchematicNode> deepGet(Integer parent, Predicate<SchematicNode> filter) {
List<SchematicNode> finalList = new ArrayList<>();
List<SchematicNode> 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;
}
public static List<SchematicNode> getSchematicsAccessibleByUser(int user, Integer parent) {
if (parent == null || parent == 0)
return accessibleByUser.listSelect(user, user, user, user);
if(schematicAccessibleForUser.select(rs -> {
rs.next();
return rs.getInt("Accessible") > 0;
}, parent, user, user))
return getSchematicNodeInNode(parent);
return Collections.emptyList();
}
public static List<SchematicNode> getAllSchematicsAccessibleByUser(int user) {
return allAccessibleByUser.listSelect(user, user);
}
public static List<SchematicNode> getAllParentsOfNode(SchematicNode node) {
return getAllParentsOfNode(node.getId());
}
public static List<SchematicNode> getAllParentsOfNode(int node) {
return allParentsOfNode.listSelect(node);
}
public static SchematicNode getNodeFromPath(SteamwarUser user, String s) {
if (s.startsWith("/")) {
s = s.substring(1);
}
if (s.isEmpty()) {
return null;
}
if (s.contains("/")) {
String[] layers = s.split("/");
SchematicNode currentNode = null;
for (int i = 0; i < layers.length; i++) {
int finalI = i;
Optional<SchematicNode> node;
if (currentNode == null) {
node = SchematicNode.getSchematicsAccessibleByUser(user.getId(), 0).stream().filter(node1 -> node1.getName().equals(layers[finalI])).findAny();
} else {
node = Optional.ofNullable(SchematicNode.getSchematicNode(layers[i], currentNode.getId()));
}
if (!node.isPresent()) {
return null;
} else {
currentNode = node.get();
if (!currentNode.isDir() && i != layers.length - 1) {
return null;
}
}
}
return currentNode;
} else {
String finalS = s;
return SchematicNode.getSchematicsAccessibleByUser(user.getId(), 0).stream().filter(node1 -> node1.getName().equals(finalS)).findAny().orElse(null);
}
}
public static List<SchematicNode> filterSchems(int user, Predicate<SchematicNode> filter) {
List<SchematicNode> finalList = new ArrayList<>();
List<SchematicNode> 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;
}
@Deprecated
public static Integer countNodes() {
return -1;
}
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 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;
}
public boolean getSchemFormat() {
if(isDir())
throw new SecurityException("Node is Directory");
return nodeFormat;
}
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<NodeMember> getMembers() {
return NodeMember.getNodeMembers(nodeId);
}
public Timestamp getLastUpdate() {
return lastUpdate;
}
private void updateDB() {
this.lastUpdate = Timestamp.from(Instant.now());
update.update(nodeId, nodeOwner, nodeName, parentNode, lastUpdate, nodeItem, nodeType, nodeRank, replaceColor, allowReplay, nodeFormat);
this.brCache.clear();
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 brCache.computeIfAbsent(user.getId(), integer -> generateBreadcrumbs("/", user));
}
public String generateBreadcrumbs(String split, SteamwarUser user) {
StringBuilder builder = new StringBuilder(getName());
SchematicNode currentNode = this;
if (currentNode.isDir()) builder.append("/");
final Set<NodeMember> nodeMembers = NodeMember.getSchematics(user.getId());
AtomicInteger i = new AtomicInteger();
i.set(currentNode.getId());
while (currentNode.getParentNode() != null && nodeMembers.stream().noneMatch(nodeMember -> nodeMember.getNode() == i.get())) {
currentNode = currentNode.getParentNode();
i.set(currentNode.getId());
builder.insert(0, split)
.insert(0, currentNode.getName());
}
return builder.toString();
}
private static final List<String> 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<String> 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<String> list = new ArrayList<>();
if (s.contains("/")) {
String preTab = s.substring(0, s.lastIndexOf("/") + 1);
SchematicNode pa = SchematicNode.getNodeFromPath(user, preTab);
if (pa == null) return Collections.emptyList();
List<SchematicNode> nodes = SchematicNode.getSchematicNodeInNode(pa);
nodes.forEach(node -> list.add((sws ? "/" : "") + node.generateBreadcrumbs(user)));
} else {
List<SchematicNode> nodes = SchematicNode.getSchematicsAccessibleByUser(user.getId(), 0);
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;
}
private static void rootWarning() {
ByteArrayOutputStream stacktraceOutput = new ByteArrayOutputStream();
new Throwable().printStackTrace(new PrintStream(stacktraceOutput));
SWException.log("PERFORMANCE!!! Getting all/weird subset of schematic nodes with parent NULL", stacktraceOutput.toString());
}
}

Datei anzeigen

@ -0,0 +1,116 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
import de.steamwar.sql.internal.SqlTypeMapper;
import java.util.*;
public class SchematicType {
public static final SchematicType Normal = new SchematicType("Normal", "", Type.NORMAL, null, "STONE_BUTTON");
private static final Map<String, SchematicType> fromDB;
private static final List<SchematicType> types;
static {
List<SchematicType> tmpTypes = new LinkedList<>();
Map<String, SchematicType> 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;
private final String kuerzel;
private final Type type;
private final SchematicType checkType;
private final String material;
SchematicType(String name, String kuerzel, Type type, SchematicType checkType, String material){
this.name = name;
this.kuerzel = kuerzel;
this.type = type;
this.checkType = checkType;
this.material = material;
}
public boolean isAssignable(){
return type == Type.NORMAL || (type == Type.FIGHT_TYPE && checkType != null);
}
public SchematicType checkType(){
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 getKuerzel() {
return kuerzel;
}
public String getMaterial() {
return material;
}
public String toDB(){
return name.toLowerCase();
}
public static SchematicType fromDB(String input){
return fromDB.get(input.toLowerCase());
}
public static List<SchematicType> values(){
return types;
}
enum Type{
NORMAL,
CHECK_TYPE,
FIGHT_TYPE
}
}

Datei anzeigen

@ -0,0 +1,54 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
import java.util.Calendar;
public class Season {
private Season() {}
public static int getSeason() {
Calendar calendar = Calendar.getInstance();
int yearIndex = calendar.get(Calendar.MONTH) / 4;
return (calendar.get(Calendar.YEAR) * 3 + yearIndex);
}
public static String getSeasonStart() {
Calendar calendar = Calendar.getInstance();
return calendar.get(Calendar.YEAR) + "-" + (calendar.get(Calendar.MONTH) / 4 * 3 + 1) + "-1";
}
public static String convertSeasonToString(int season){
if (season == -1) return "";
int yearSeason = season % 3;
int year = (season - yearSeason) / 3;
return String.format("%d-%d", year, yearSeason);
}
public static int convertSeasonToNumber(String season){
if (season.isEmpty()) return -1;
String[] split = season.split("-");
try {
return Integer.parseInt(split[0]) * 3 + Integer.parseInt(split[1]);
} catch (NumberFormatException e) {
return -1;
}
}
}

Datei anzeigen

@ -0,0 +1,171 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
import de.steamwar.sql.internal.*;
import lombok.Getter;
import java.util.*;
public class SteamwarUser {
static {
new SqlTypeMapper<>(UUID.class, "CHAR(36)", (rs, identifier) -> UUID.fromString(rs.getString(identifier)), (st, index, value) -> st.setString(index, value.toString()));
new SqlTypeMapper<>(Locale.class, "VARCHAR(32)", (rs, identifier) -> {
String l = rs.getString(identifier);
return l != null ? Locale.forLanguageTag(l) : null;
}, (st, index, value) -> st.setString(index, value.toLanguageTag()));
SqlTypeMapper.nameEnumMapper(UserGroup.class);
new SqlTypeMapper<>(SteamwarUser.class, null, (rs, identifier) -> { throw new SecurityException("SteamwarUser cannot be used as type (recursive select)"); }, (st, index, value) -> st.setInt(index, value.id));
}
private static final Table<SteamwarUser> table = new Table<>(SteamwarUser.class, "UserData");
private static final Statement insert = table.insertFields("UUID", "UserName");
private static final SelectStatement<SteamwarUser> byID = table.selectFields("id");
private static final SelectStatement<SteamwarUser> byUUID = table.selectFields("UUID");
private static final SelectStatement<SteamwarUser> byName = table.selectFields("UserName");
private static final SelectStatement<SteamwarUser> byDiscord = table.selectFields("DiscordId");
private static final SelectStatement<SteamwarUser> byTeam = table.selectFields("Team");
private static final SelectStatement<SteamwarUser> getServerTeam = new SelectStatement<>(table, "SELECT * FROM UserData WHERE UserGroup != 'Member' AND UserGroup != 'YouTuber'");
private static final Statement updateName = table.update(Table.PRIMARY, "UserName");
private static final Statement updateLocale = table.update(Table.PRIMARY, "Locale", "ManualLocale");
private static final Statement updateTeam = table.update(Table.PRIMARY, "Team");
private static final Statement updateLeader = table.update(Table.PRIMARY, "Leader");
private static final Statement updateDiscord = table.update(Table.PRIMARY, "DiscordId");
private static final Map<Integer, SteamwarUser> usersById = new HashMap<>();
private static final Map<UUID, SteamwarUser> usersByUUID = new HashMap<>();
private static final Map<String, SteamwarUser> usersByName = new HashMap<>();
private static final Map<Long, SteamwarUser> usersByDiscord = new HashMap<>();
public static void clear() {
usersById.clear();
usersByName.clear();
usersByUUID.clear();
usersByDiscord.clear();
}
public static void invalidate(int userId) {
SteamwarUser user = usersById.remove(userId);
if (user == null)
return;
usersByName.remove(user.getUserName());
usersByUUID.remove(user.getUUID());
}
@Getter
@Field(keys = {Table.PRIMARY}, autoincrement = true)
private final int id;
@Field(keys = {"uuid"})
private final UUID uuid;
@Getter
@Field
private String userName;
@Getter
@Field(def = "'Member'")
private final UserGroup userGroup;
@Getter
@Field(def = "0")
private int team;
@Field(def = "0")
private boolean leader;
@Field(nullable = true)
private Locale locale;
@Field(def = "0")
private boolean manualLocale;
@Field(keys = {"discordId"}, nullable = true)
private Long discordId;
public SteamwarUser(int id, UUID uuid, String userName, UserGroup userGroup, int team, boolean leader, Locale locale, boolean manualLocale, Long discordId) {
this.id = id;
this.uuid = uuid;
this.userName = userName;
this.userGroup = userGroup;
this.team = team;
this.leader = leader;
this.locale = locale;
this.manualLocale = manualLocale;
this.discordId = discordId != null && discordId != 0 ? discordId : null;
usersById.put(id, this);
usersByName.put(userName.toLowerCase(), this);
usersByUUID.put(uuid, this);
if (this.discordId != null) {
usersByDiscord.put(discordId, this);
}
}
public UUID getUUID() {
return uuid;
}
public Locale getLocale() {
if(locale != null)
return locale;
return Locale.getDefault();
}
public void setLocale(Locale locale, boolean manualLocale) {
if (locale == null || (this.manualLocale && !manualLocale))
return;
this.locale = locale;
this.manualLocale = manualLocale;
updateLocale.update(locale.toLanguageTag(), manualLocale, id);
}
public static SteamwarUser get(String userName){
SteamwarUser user = usersByName.get(userName.toLowerCase());
if(user != null)
return user;
return byName.select(userName);
}
public static SteamwarUser get(UUID uuid){
SteamwarUser user = usersByUUID.get(uuid);
if(user != null)
return user;
return byUUID.select(uuid);
}
public static SteamwarUser get(int id) {
SteamwarUser user = usersById.get(id);
if(user != null)
return user;
return byID.select(id);
}
public static SteamwarUser get(Long discordId) {
if(usersByDiscord.containsKey(discordId))
return usersByDiscord.get(discordId);
return byDiscord.select(discordId);
}
public static void createOrUpdateUsername(UUID uuid, String userName) {
insert.update(uuid, userName);
}
public static List<SteamwarUser> getServerTeam() {
return getServerTeam.listSelect();
}
public static List<SteamwarUser> getTeam(int teamId) {
return byTeam.listSelect(teamId);
}
}

Datei anzeigen

@ -0,0 +1,61 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.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.util.List;
import java.util.stream.Collectors;
@AllArgsConstructor
public class Team {
private static final Table<Team> table = new Table<>(Team.class);
private static final SelectStatement<Team> select = table.select(Table.PRIMARY);
@Field(keys = {Table.PRIMARY})
@Getter
private final int teamId;
@Field
@Getter
private final String teamKuerzel;
@Field
@Getter
private final String teamName;
@Field(def = "'8'")
@Getter
private final String teamColor;
private static final Team pub = new Team(0, "PUB", "Öffentlich", "8");
public static Team get(int id) {
if(id == 0)
return pub;
return select.select(id);
}
public List<Integer> getMembers(){
return SteamwarUser.getTeam(teamId).stream().map(SteamwarUser::getId).collect(Collectors.toList());
}
}

Datei anzeigen

@ -0,0 +1,54 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.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 TeamTeilnahme {
private static final Table<TeamTeilnahme> table = new Table<>(TeamTeilnahme.class);
private static final SelectStatement<TeamTeilnahme> select = table.select(Table.PRIMARY);
private static final SelectStatement<TeamTeilnahme> selectTeams = table.selectFields("EventID");
private static final SelectStatement<TeamTeilnahme> selectEvents = table.selectFields("TeamID");
@Field(keys = {Table.PRIMARY})
private final int teamId;
@Field(keys = {Table.PRIMARY})
private final int eventId;
public static boolean nimmtTeil(int teamID, int eventID){
return select.select(teamID, eventID) != null;
}
public static Set<Team> getTeams(int eventID){
return selectTeams.listSelect(eventID).stream().map(tt -> Team.get(tt.teamId)).collect(Collectors.toSet()); // suboptimal performance (O(n) database queries)
}
public static Set<Event> getEvents(int teamID){
return selectEvents.listSelect(teamID).stream().map(tt -> Event.get(tt.eventId)).collect(Collectors.toSet()); // suboptimal performance (O(n) database queries)
}
}

Datei anzeigen

@ -0,0 +1,73 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.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.UUID;
@AllArgsConstructor
public class UserConfig {
private static final Table<UserConfig> table = new Table<>(UserConfig.class);
private static final SelectStatement<UserConfig> 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 user;
@Field(keys = {Table.PRIMARY})
private final String config;
@Field
private final String value;
public static String getConfig(UUID player, String config) {
return getConfig(SteamwarUser.get(player).getId(), config);
}
public static String getConfig(int player, String config) {
UserConfig value = select.select(player, config);
return value != null ? value.value : null;
}
public static void updatePlayerConfig(UUID uuid, String config, String value) {
updatePlayerConfig(SteamwarUser.get(uuid).getId(), config, value);
}
public static void updatePlayerConfig(int id, String config, String value) {
if (value == null) {
removePlayerConfig(id, config);
return;
}
insert.update(id, config, value);
}
public static void removePlayerConfig(UUID uuid, String config) {
removePlayerConfig(SteamwarUser.get(uuid).getId(), config);
}
public static void removePlayerConfig(int id, String config) {
delete.update(id, config);
}
}

Datei anzeigen

@ -0,0 +1,45 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
public enum UserGroup {
Admin("§4", "§e", true, true, true),
Developer("§3", "§f", true, true, true),
Moderator("§c", "§f", true, true, true),
Supporter("§9", "§f", false, true, true),
Builder("§2", "§f", false, true, false),
YouTuber("§5", "§f", false, false, false),
Member("§7", "§7", false, false, false);
@Getter
private final String colorCode;
@Getter
private final String chatColorCode;
@Getter
private final boolean adminGroup;
@Getter
private final boolean teamGroup;
@Getter
private final boolean checkSchematics;
}

Datei anzeigen

@ -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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql.internal;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Field {
String[] keys() default {};
String def() default "";
boolean nullable() default false;
boolean autoincrement() default false;
}

Datei anzeigen

@ -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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql.internal;
import de.steamwar.ImplementationProvider;
import java.util.logging.Logger;
public interface SQLConfig {
SQLConfig impl = ImplementationProvider.getImpl("de.steamwar.sql.SQLConfigImpl");
Logger getLogger();
int maxConnections();
}

Datei anzeigen

@ -0,0 +1,72 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql.internal;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class SelectStatement<T> extends Statement {
private final Table<T> table;
SelectStatement(Table<T> table, String... kfields) {
this(table, "SELECT " + Arrays.stream(table.fields).map(f -> f.identifier).collect(Collectors.joining(", ")) + " FROM " + table.name + " WHERE " + Arrays.stream(kfields).map(f -> f + " = ?").collect(Collectors.joining(" AND ")));
}
public SelectStatement(Table<T> table, String sql) {
super(sql);
this.table = table;
}
public T select(Object... values) {
return select(rs -> {
if (rs.next())
return read(rs);
return null;
}, values);
}
public List<T> listSelect(Object... values) {
return select(rs -> {
List<T> result = new ArrayList<>();
while (rs.next())
result.add(read(rs));
return result;
}, values);
}
private T read(ResultSet rs) throws SQLException {
Object[] params = new Object[table.fields.length];
for(int i = 0; i < params.length; i++) {
params[i] = table.fields[i].read(rs);
}
try {
return table.constructor.newInstance(params);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new SecurityException(e);
}
}
}

Datei anzeigen

@ -0,0 +1,110 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql.internal;
import java.io.InputStream;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.Map;
public final class SqlTypeMapper<T> {
private static final Map<Class<?>, SqlTypeMapper<?>> mappers = new IdentityHashMap<>();
public static <T> SqlTypeMapper<T> getMapper(Class<?> clazz) {
return (SqlTypeMapper<T>) mappers.get(clazz);
}
public static <T extends Enum<T>> void ordinalEnumMapper(Class<T> type) {
T[] enumConstants = type.getEnumConstants();
new SqlTypeMapper<>(
type,
"INTEGER(" + (int)Math.ceil(enumConstants.length/256.0) + ")",
(rs, identifier) -> enumConstants[rs.getInt(identifier)],
(st, index, value) -> st.setInt(index, value.ordinal())
);
}
public static <T extends Enum<T>> void nameEnumMapper(Class<T> type) {
new SqlTypeMapper<>(
type,
"VARCHAR(" + Arrays.stream(type.getEnumConstants()).map(e -> e.name().length()).max(Integer::compareTo).orElse(0) + ")",
(rs, identifier) -> Enum.valueOf(type, rs.getString(identifier)),
(st, index, value) -> st.setString(index, value.name())
);
}
static {
primitiveMapper(boolean.class, Boolean.class, "BOOLEAN", ResultSet::getBoolean, PreparedStatement::setBoolean);
primitiveMapper(byte.class, Byte.class, "INTEGER(1)", ResultSet::getByte, PreparedStatement::setByte);
primitiveMapper(short.class, Short.class, "INTEGER(2)", ResultSet::getShort, PreparedStatement::setShort);
primitiveMapper(int.class, Integer.class, "INTEGER", ResultSet::getInt, PreparedStatement::setInt);
primitiveMapper(long.class, Long.class, "INTEGER(8)", ResultSet::getLong, PreparedStatement::setLong);
primitiveMapper(float.class, Float.class, "REAL", ResultSet::getFloat, PreparedStatement::setFloat);
primitiveMapper(double.class, Double.class, "REAL", ResultSet::getDouble, PreparedStatement::setDouble);
new SqlTypeMapper<>(String.class, "TEXT", ResultSet::getString, PreparedStatement::setString);
new SqlTypeMapper<>(Timestamp.class, "TIMESTAMP", ResultSet::getTimestamp, PreparedStatement::setTimestamp);
new SqlTypeMapper<>(InputStream.class, "BLOB", ResultSet::getBinaryStream, PreparedStatement::setBinaryStream);
}
private static <T> void primitiveMapper(Class<T> primitive, Class<T> wrapped, String sqlType, SQLReader<T> reader, SQLWriter<T> writer) {
new SqlTypeMapper<>(primitive, sqlType, reader, writer);
new SqlTypeMapper<>(wrapped, sqlType, (rs, identifier) -> {
T value = reader.read(rs, identifier);
return rs.wasNull() ? null : value;
}, writer);
}
private final String sqlType;
private final SQLReader<T> reader;
private final SQLWriter<T> writer;
public SqlTypeMapper(Class<T> clazz, String sqlType, SQLReader<T> reader, SQLWriter<T> writer) {
this.sqlType = sqlType;
this.reader = reader;
this.writer = writer;
mappers.put(clazz, this);
}
public T read(ResultSet rs, String identifier) throws SQLException {
return reader.read(rs, identifier);
}
public void write(PreparedStatement st, int index, Object value) throws SQLException {
writer.write(st, index, (T) value);
}
public String sqlType() {
return sqlType;
}
@FunctionalInterface
public interface SQLReader<T> {
T read(ResultSet rs, String identifier) throws SQLException;
}
@FunctionalInterface
public interface SQLWriter<T> {
void write(PreparedStatement st, int index, T value) throws SQLException;
}
}

Datei anzeigen

@ -0,0 +1,287 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql.internal;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Statement implements AutoCloseable {
private static final Logger logger = SQLConfig.impl.getLogger();
private static final List<Statement> statements = new ArrayList<>();
private static final Deque<Connection> connections = new ArrayDeque<>();
private static final int MAX_CONNECTIONS;
private static final Supplier<Connection> conProvider;
static final Consumer<Table<?>> schemaCreator;
static final String ON_DUPLICATE_KEY;
static final UnaryOperator<String> upsertWrapper;
private static final boolean MYSQL_MODE;
private static final boolean PRODUCTION_DATABASE;
static {
File file = new File(System.getProperty("user.home"), "mysql.properties");
MYSQL_MODE = file.exists();
if(MYSQL_MODE) {
Properties properties = new Properties();
try {
properties.load(new FileReader(file));
} catch (IOException e) {
throw new SecurityException("Could not load SQL connection", e);
}
String url = "jdbc:mysql://" + properties.getProperty("host") + ":" + properties.getProperty("port") + "/" + properties.getProperty("database") + "?useServerPrepStmts=true";
String user = properties.getProperty("user");
String password = properties.getProperty("password");
PRODUCTION_DATABASE = "core".equals(properties.getProperty("database"));
MAX_CONNECTIONS = SQLConfig.impl.maxConnections();
conProvider = () -> {
try {
return DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
throw new SecurityException("Could not create MySQL connection", e);
}
};
schemaCreator = table -> {};
ON_DUPLICATE_KEY = " ON DUPLICATE KEY UPDATE ";
upsertWrapper = f -> f + " = VALUES(" + f + ")";
} else {
Connection connection;
try {
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite:" + System.getProperty("user.home") + "/standalone.db");
} catch (SQLException | ClassNotFoundException e) {
throw new SecurityException("Could not create sqlite connection", e);
}
PRODUCTION_DATABASE = false;
MAX_CONNECTIONS = 1;
conProvider = () -> connection;
schemaCreator = Table::ensureExistanceInSqlite;
ON_DUPLICATE_KEY = " ON CONFLICT DO UPDATE SET ";
upsertWrapper = f -> f + " = " + f;
}
}
private static int connectionBudget = MAX_CONNECTIONS;
public static void closeAll() {
synchronized (connections) {
while(connectionBudget < MAX_CONNECTIONS) {
if(connections.isEmpty())
waitOnConnections();
else
closeConnection(aquireConnection());
}
}
}
public static boolean mysqlMode() {
return MYSQL_MODE;
}
public static boolean productionDatabase() {
return PRODUCTION_DATABASE;
}
private final boolean returnGeneratedKeys;
private final String sql;
private final Map<Connection, PreparedStatement> cachedStatements = new HashMap<>();
public Statement(String sql) {
this(sql, false);
}
public Statement(String sql, boolean returnGeneratedKeys) {
this.sql = sql;
this.returnGeneratedKeys = returnGeneratedKeys;
synchronized (statements) {
statements.add(this);
}
}
public <T> T select(ResultSetUser<T> user, Object... objects) {
return withConnection(st -> {
ResultSet rs = st.executeQuery();
T result = user.use(rs);
rs.close();
return result;
}, objects);
}
public void update(Object... objects) {
withConnection(PreparedStatement::executeUpdate, objects);
}
public int insertGetKey(Object... objects) {
return withConnection(st -> {
st.executeUpdate();
ResultSet rs = st.getGeneratedKeys();
rs.next();
return rs.getInt(1);
}, objects);
}
public String getSql() {
return sql;
}
private <T> T withConnection(SQLRunnable<T> runnable, Object... objects) {
Connection connection = aquireConnection();
try {
try {
return tryWithConnection(connection, runnable, objects);
} finally {
if(connectionInvalid(connection)) {
closeConnection(connection);
} else {
synchronized (connections) {
connections.push(connection);
connections.notify();
}
}
}
} catch (SQLException e) {
if(connectionInvalid(connection)) {
return withConnection(runnable, objects);
} else {
throw new SecurityException("Failing sql statement", e);
}
}
}
private boolean connectionInvalid(Connection connection) {
try {
return connection.isClosed();
} catch (SQLException e) {
logger.log(Level.INFO, "Could not check SQL connection status", e); // No database logging possible at this state
return true;
}
}
private <T> T tryWithConnection(Connection connection, SQLRunnable<T> runnable, Object... objects) throws SQLException {
PreparedStatement st = cachedStatements.get(connection);
if(st == null) {
if(returnGeneratedKeys)
st = connection.prepareStatement(sql, java.sql.Statement.RETURN_GENERATED_KEYS);
else
st = connection.prepareStatement(sql);
cachedStatements.put(connection, st);
}
for (int i = 0; i < objects.length; i++) {
Object o = objects[i];
if(o != null)
SqlTypeMapper.getMapper(o.getClass()).write(st, i+1, o);
else
st.setNull(i+1, Types.NULL);
}
return runnable.run(st);
}
@Override
public void close() {
cachedStatements.values().forEach(st -> closeStatement(st, false));
cachedStatements.clear();
synchronized (statements) {
statements.remove(this);
}
}
private void close(Connection connection) {
PreparedStatement st = cachedStatements.remove(connection);
if(st != null)
closeStatement(st, true);
}
private static Connection aquireConnection() {
synchronized (connections) {
if(connections.isEmpty() && connectionBudget == 0)
waitOnConnections();
if(!connections.isEmpty()) {
return connections.pop();
} else {
Connection connection = conProvider.get();
connectionBudget--;
return connection;
}
}
}
private static void closeConnection(Connection connection) {
synchronized (statements) {
for (Statement statement : statements) {
statement.close(connection);
}
}
try {
connection.close();
} catch (SQLException e) {
logger.log(Level.INFO, "Could not close connection", e);
}
synchronized (connections) {
connectionBudget++;
connections.notify();
}
}
private static void waitOnConnections() {
synchronized (connections) {
try {
connections.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
private static void closeStatement(PreparedStatement st, boolean silent) {
try {
st.close();
} catch (SQLException e) {
if(!silent)
logger.log(Level.INFO, "Could not close statement", e);
}
}
public interface ResultSetUser<T> {
T use(ResultSet rs) throws SQLException;
}
private interface SQLRunnable<T> {
T run(PreparedStatement st) throws SQLException;
}
}

Datei anzeigen

@ -0,0 +1,137 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql.internal;
import java.lang.reflect.Constructor;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Table<T> {
public static final String PRIMARY = "primary";
final String name;
final TableField<?>[] fields;
private final Map<String, TableField<?>> fieldsByIdentifier = new HashMap<>();
final Constructor<T> constructor;
private final Map<String, Table.TableField<?>[]> keys;
public Table(Class<T> clazz) {
this(clazz, clazz.getSimpleName());
}
public Table(Class<T> clazz, String name) {
this.name = name;
this.fields = Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.isAnnotationPresent(Field.class)).map(TableField::new).toArray(TableField[]::new);
try {
this.constructor = clazz.getDeclaredConstructor(Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.isAnnotationPresent(Field.class)).map(java.lang.reflect.Field::getType).toArray(Class[]::new));
} catch (NoSuchMethodException e) {
throw new SecurityException(e);
}
keys = Arrays.stream(fields).flatMap(field -> Arrays.stream(field.field.keys())).distinct().collect(Collectors.toMap(Function.identity(), key -> Arrays.stream(fields).filter(field -> Arrays.asList(field.field.keys()).contains(key)).toArray(TableField[]::new)));
for (TableField<?> field : fields) {
fieldsByIdentifier.put(field.identifier.toLowerCase(), field);
}
Statement.schemaCreator.accept(this);
}
public SelectStatement<T> select(String name) {
return selectFields(keyFields(name));
}
public SelectStatement<T> selectFields(String... kfields) {
return new SelectStatement<>(this, kfields);
}
public Statement update(String name, String... fields) {
return updateFields(fields, keyFields(name));
}
public Statement updateField(String field, String... kfields) {
return updateFields(new String[]{field}, kfields);
}
public Statement updateFields(String[] fields, String... kfields) {
return new Statement("UPDATE " + name + " SET " + Arrays.stream(fields).map(f -> f + " = ?").collect(Collectors.joining(", ")) + " WHERE " + Arrays.stream(kfields).map(f -> f + " = ?").collect(Collectors.joining(" AND ")));
}
public Statement insert(String name) {
return insertFields(keyFields(name));
}
public Statement insertAll() {
return insertFields(false, Arrays.stream(fields).map(f -> f.identifier).toArray(String[]::new));
}
public Statement insertFields(String... fields) {
return insertFields(false, fields);
}
public Statement insertFields(boolean returnGeneratedKeys, String... fields) {
List<String> nonKeyFields = Arrays.stream(fields).filter(f -> fieldsByIdentifier.get(f.toLowerCase()).field.keys().length == 0).collect(Collectors.toList());
return new Statement("INSERT INTO " + name + " (" + String.join(", ", fields) + ") VALUES (" + Arrays.stream(fields).map(f -> "?").collect(Collectors.joining(", ")) + ")" + (nonKeyFields.isEmpty() ? "" : Statement.ON_DUPLICATE_KEY + nonKeyFields.stream().map(Statement.upsertWrapper).collect(Collectors.joining(", "))), returnGeneratedKeys);
}
public Statement delete(String name) {
return deleteFields(keyFields(name));
}
public Statement deleteFields(String... kfields) {
return new Statement("DELETE FROM " + name + " WHERE " + Arrays.stream(kfields).map(f -> f + " = ?").collect(Collectors.joining(" AND ")));
}
void ensureExistanceInSqlite() {
try (Statement statement = new Statement(
"CREATE TABLE IF NOT EXISTS " + name + "(" +
Arrays.stream(fields).map(field -> field.identifier + " " + field.mapper.sqlType() + (field.field.nullable() ? " DEFAULT NULL" : " NOT NULL") + (field.field.nullable() || field.field.def().equals("") ? "" : " DEFAULT " + field.field.def())).collect(Collectors.joining(", ")) +
keys.entrySet().stream().map(key -> (key.getKey().equals(PRIMARY) ? ", PRIMARY KEY(" : ", UNIQUE (") + Arrays.stream(key.getValue()).map(field -> field.identifier).collect(Collectors.joining(", ")) + ")").collect(Collectors.joining(" ")) +
")")) {
statement.update();
}
}
private String[] keyFields(String name) {
return Arrays.stream(keys.get(name)).map(f -> f.identifier).toArray(String[]::new);
}
static class TableField<T> {
final String identifier;
final SqlTypeMapper<T> mapper;
private final Field field;
private TableField(java.lang.reflect.Field field) {
this.identifier = field.getName();
this.mapper = SqlTypeMapper.getMapper(field.getType());
this.field = field.getAnnotation(Field.class);
}
T read(ResultSet rs) throws SQLException {
return mapper.read(rs, identifier);
}
}
}