diff --git a/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/PlayerMovementWrapper21.java b/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/PlayerMovementWrapper21.java
new file mode 100644
index 00000000..e62e4591
--- /dev/null
+++ b/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/PlayerMovementWrapper21.java
@@ -0,0 +1,46 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.bausystem.utils;
+
+import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
+import net.minecraft.server.level.ServerPlayer;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+
+public class PlayerMovementWrapper21 implements PlayerMovementWrapper {
+
+ @Override
+ public void setPosition(Player player, Object object) {
+ ServerboundMovePlayerPacket packetPlayInFlying = ((ServerboundMovePlayerPacket) object);
+ ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
+ if (packetPlayInFlying.hasPos) {
+ serverPlayer.setPosRaw(packetPlayInFlying.x, packetPlayInFlying.y, packetPlayInFlying.z);
+ }
+ if (packetPlayInFlying.hasRot) {
+ serverPlayer.setXRot(packetPlayInFlying.xRot);
+ serverPlayer.setYRot(packetPlayInFlying.yRot);
+ }
+ }
+
+ @Override
+ public Object convertToOut(Player player, Object object) {
+ return object;
+ }
+}
diff --git a/BauSystem/BauSystem_Main/src/BauSystem.properties b/BauSystem/BauSystem_Main/src/BauSystem.properties
index b90933b6..e6c490d7 100644
--- a/BauSystem/BauSystem_Main/src/BauSystem.properties
+++ b/BauSystem/BauSystem_Main/src/BauSystem.properties
@@ -1030,6 +1030,7 @@ SCHEMATIC_GUI_ITEM=§eSchematics
# TNTListener
TLS_MESSAGE_79=§7TLS§8> §7Tick §e{0} §8- §7TNT §e{1}
TLS_MESSAGE_80=§7TLS§8> §7Tick §e{0} §8- §7TNT §e{1} §8(§e{2} §7with Fuse 80§8)
-TLS_START_HELP=§8/§etls start §8: §7Start the TNT Listener
-TLS_STOP_HELP=§8/§etls stop §8: §7Stop the TNT Listener
-TLS_SCOREBOARD_ELEMENT=§eTLS§8: §aon
\ No newline at end of file
+TLS_START_HELP=§8/§etls start §8- §7Start the TNT Listener
+TLS_STOP_HELP=§8/§etls stop §8- §7Stop the TNT Listener
+TLS_SCOREBOARD_ELEMENT=§eTLS§8: §aon
+TLS_TOGGLE_HELP=§8/§etls§8: §7Toggle the TNT Listener
\ No newline at end of file
diff --git a/BauSystem/BauSystem_Main/src/BauSystem_de.properties b/BauSystem/BauSystem_Main/src/BauSystem_de.properties
index 453b4079..f0d55c5c 100644
--- a/BauSystem/BauSystem_Main/src/BauSystem_de.properties
+++ b/BauSystem/BauSystem_Main/src/BauSystem_de.properties
@@ -961,6 +961,7 @@ TYPEREPLACE_HELP=§8//§etyreplace §8[§7type§8] §8[§7type§8] §8- §7Erset
# Schematics
SCHEMATIC_GUI_ITEM=§eSchematics
TLS_MESSAGE_80=§7TLS§8> §7Tick §e{0} §8- §7TNT §e{1} §8(§e{2} §7mit Fuse 80§8)
-TLS_START_HELP=§8/§etls start §8: §7Starte den TNT Listener
-TLS_STOP_HELP=§8/§etls stop §8: §7Stope den TNT Listener
-TLS_SCOREBOARD_ELEMENT=§eTLS§8: §aan
\ No newline at end of file
+TLS_START_HELP=§8/§etls start §8- §7Starte den TNT Listener
+TLS_STOP_HELP=§8/§etls stop §8- §7Stope den TNT Listener
+TLS_SCOREBOARD_ELEMENT=§eTLS§8: §aan
+TLS_TOGGLE_HELP=§8/§etls §8: §7Toggle den TNT Listener
\ No newline at end of file
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/Permission.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/Permission.java
index ecc1df44..1cbb5d9f 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/Permission.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/Permission.java
@@ -27,8 +27,6 @@ import de.steamwar.sql.SteamwarUser;
import lombok.AllArgsConstructor;
import org.bukkit.entity.Player;
-import java.util.HashSet;
-import java.util.Set;
import java.util.function.Predicate;
@AllArgsConstructor
@@ -39,13 +37,12 @@ public enum Permission {
return bauweltMember.isSupervisor();
}),
BUILD(bauweltMember -> {
- if (isTempOnlySpectator(bauweltMember)) return false;
return bauweltMember.isBuild() || SUPERVISOR.permissionPredicate.test(bauweltMember);
}),
/**
* Only used for {@link BauMemberUpdate}
*/
- REAL_SPECTATOR(bauweltMember -> {
+ SPECTATOR(bauweltMember -> {
return !bauweltMember.isBuild() && !bauweltMember.isSupervisor();
}),
/**
@@ -55,28 +52,6 @@ public enum Permission {
return true;
});
- private static final Set TEMP_ONLY_SPECTATOR = new HashSet<>();
-
- private static boolean isTempOnlySpectator(BauweltMember bauweltMember) {
- return TEMP_ONLY_SPECTATOR.contains(bauweltMember.getMemberID());
- }
-
- public static boolean isTempOnlySpectator(Player player) {
- return TEMP_ONLY_SPECTATOR.contains(SteamwarUser.get(player.getUniqueId()).getId());
- }
-
- public static void forceOnlySpectator(Player player) {
- TEMP_ONLY_SPECTATOR.add(SteamwarUser.get(player.getUniqueId()).getId());
- BauMemberUpdate.baumemberUpdate();
- }
-
- /**
- * Only used by {@link BauMemberUpdate}
- */
- public static void removeForceOnlySpectator(Player player) {
- TEMP_ONLY_SPECTATOR.remove(SteamwarUser.get(player.getUniqueId()).getId());
- }
-
private final Predicate permissionPredicate;
public boolean hasPermission(BauweltMember bauweltMember) {
@@ -86,10 +61,10 @@ public enum Permission {
public boolean hasPermission(Player member) {
if (SteamwarUser.get(member.getUniqueId()).getId() == BauServer.getInstance().getOwnerID()) {
- return this != REAL_SPECTATOR;
+ return this != SPECTATOR;
}
BauweltMember bauweltMember = BauweltMember.getBauMember(BauServer.getInstance().getOwner(), member.getUniqueId());
- if (bauweltMember == null) return this == REAL_SPECTATOR;
+ if (bauweltMember == null) return this == SPECTATOR;
return permissionPredicate.test(bauweltMember);
}
}
\ No newline at end of file
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/config/BauServer.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/config/BauServer.java
index fea634a2..67fd9e52 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/config/BauServer.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/config/BauServer.java
@@ -36,7 +36,7 @@ public class BauServer {
private Integer owner;
public UUID getOwner() {
- return SteamwarUser.get(getOwnerID()).getUUID();
+ return SteamwarUser.byId(getOwnerID()).getUUID();
}
public int getOwnerID() {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/autostart/AutostartListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/autostart/AutostartListener.java
index d45a7029..efa7f199 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/autostart/AutostartListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/autostart/AutostartListener.java
@@ -32,6 +32,7 @@ import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.data.type.Chest;
import org.bukkit.entity.Player;
+import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
@@ -120,6 +121,7 @@ public class AutostartListener implements Listener {
@EventHandler
public void onEntityExplode(EntityExplodeEvent event) {
+ if (!(event.getEntity() instanceof TNTPrimed)) return;
if (regionStartTime.isEmpty()) {
return;
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/bau/ForceSpectatorCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/bau/ForceSpectatorCommand.java
deleted file mode 100644
index a4e79c2f..00000000
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/bau/ForceSpectatorCommand.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.bausystem.features.bau;
-
-import de.steamwar.bausystem.Permission;
-import de.steamwar.command.PreviousArguments;
-import de.steamwar.command.SWCommand;
-import de.steamwar.command.TypeMapper;
-import de.steamwar.linkage.Linked;
-import org.bukkit.Bukkit;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-
-import java.util.Collection;
-import java.util.stream.Collectors;
-
-@Linked
-public class ForceSpectatorCommand extends SWCommand {
-
- public ForceSpectatorCommand() {
- super("forcespectator");
- }
-
- @Register
- public void forceSpectator(@Validator("supervisor") Player player, @Mapper("builder") Player other) {
- Permission.forceOnlySpectator(other);
- }
-
- @Mapper("builder")
- public TypeMapper spectatorMapper() {
- return new TypeMapper<>() {
- @Override
- public Player map(CommandSender commandSender, String[] previousArguments, String s) {
- Player player = Bukkit.getPlayer(s);
- if (player == null) {
- return null;
- }
- if (Permission.BUILD.hasPermission(player) && !Permission.SUPERVISOR.hasPermission(player)) {
- return player;
- }
- return null;
- }
-
- @Override
- public Collection tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
- return Bukkit.getOnlinePlayers().stream()
- .filter(Permission.BUILD::hasPermission)
- .filter(player -> !Permission.SUPERVISOR.hasPermission(player))
- .map(Player::getName)
- .collect(Collectors.toList());
- }
- };
- }
-}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/bau/InfoCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/bau/InfoCommand.java
index adeb4c45..e5bce542 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/bau/InfoCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/bau/InfoCommand.java
@@ -47,7 +47,7 @@ public class InfoCommand extends SWCommand {
@Register(description = "BAU_INFO_COMMAND_HELP")
public void genericCommand(Player p) {
- BauSystem.MESSAGE.send("BAU_INFO_COMMAND_OWNER", p, SteamwarUser.get(bauServer.getOwnerID()).getUserName());
+ BauSystem.MESSAGE.send("BAU_INFO_COMMAND_OWNER", p, SteamwarUser.byId(bauServer.getOwnerID()).getUserName());
Region region = Region.getRegion(p.getLocation());
for (Flag flag : Flag.getFlags()) {
if (!region.getFlags().has(flag).isApplicable()) continue;
@@ -97,7 +97,7 @@ public class InfoCommand extends SWCommand {
st.append("§8, ");
}
st.append("§7");
- st.append(SteamwarUser.get(bauweltMembers.get(i).getMemberID()).getUserName());
+ st.append(SteamwarUser.byId(bauweltMembers.get(i).getMemberID()).getUserName());
}
return st.toString();
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/countingwand/Countingwand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/countingwand/Countingwand.java
index bcd13a7f..0fbaf1b7 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/countingwand/Countingwand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/countingwand/Countingwand.java
@@ -21,9 +21,10 @@ package de.steamwar.bausystem.features.countingwand;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.region.Point;
-import de.steamwar.bausystem.shared.Pair;
import de.steamwar.bausystem.utils.ItemUtils;
+import de.steamwar.core.SWPlayer;
import de.steamwar.inventory.SWItem;
+import lombok.Data;
import lombok.experimental.UtilityClass;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@@ -31,13 +32,32 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-
@UtilityClass
public class Countingwand {
+ @Data
+ public class CountingWandComponent implements SWPlayer.Component {
+ private Point pos1;
+ private Point pos2;
+
+ public boolean setPosition(boolean pos1, Point point) {
+ if (this.pos1 == null || this.pos2 == null) {
+ this.pos1 = point;
+ this.pos2 = point;
+ return true;
+ }
+ Point current = pos1 ? this.pos1 : this.pos2;
+ if (current.equals(point)) return false;
+ if (pos1) {
+ this.pos1 = point;
+ } else {
+ this.pos2 = point;
+ }
+ return true;
+ }
+ }
+
public static ItemStack getWandItem(Player player) {
ItemStack itemStack = new SWItem(Material.STICK, BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_NAME", player), Arrays.asList(BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE1", player), BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE2", player)), false, null).getItemStack();
ItemUtils.setItem(itemStack, "countingwand");
@@ -47,61 +67,20 @@ public class Countingwand {
return itemStack;
}
- private final Map> selections = new HashMap<>();
+ public boolean isCountingwand(ItemStack itemStack) {
+ return ItemUtils.isItem(itemStack, "countingwand");
+ }
- public boolean isCountingwand(ItemStack itemStack) {
- return ItemUtils.isItem(itemStack, "countingwand");
- }
-
- public void checkSelection(final Point point, final boolean pos1, final Player p) {
- Pair selection = selections.get(p.getUniqueId().toString());
- final boolean newPos;
- if (selection != null) {
- if (pos1) {
- newPos = !point.equals(selection.setKey(point));
- } else {
- newPos = !point.equals(selection.setValue(point));
- }
- } else {
- if (pos1) {
- selection = new Pair<>(point, null);
- } else {
- selection = new Pair<>(null, point);
- }
- selections.put(p.getUniqueId().toString(), selection);
- newPos = true;
- }
-
- if (newPos) {
- String dimension = getDimensions(p, selection.getKey(), selection.getValue());
- String volume = getVolume(p, selection.getKey(), selection.getValue());
- if (pos1) {
- BauSystem.MESSAGE.send("COUNTINGWAND_MESSAGE_RCLICK", p, point.getX(), point.getY(), point.getZ(), dimension, volume);
- } else {
- BauSystem.MESSAGE.send("COUNTINGWAND_MESSAGE_LCLICK", p, point.getX(), point.getY(), point.getZ(), dimension, volume);
- }
- }
- }
-
- public void removePlayer(Player p) {
- selections.remove(p.getUniqueId().toString());
- }
-
- public String getVolume(Player player, final Point point1, final Point point2) {
- if (point1 == null || point2 == null) {
- return BauSystem.MESSAGE.parse("COUNTINGWAND_MESSAGE_VOLUME", player, 0);
- }
- return BauSystem.MESSAGE.parse("COUNTINGWAND_MESSAGE_VOLUME", player, getAmount(point1, point2));
- }
-
- public String getDimensions(Player player, final Point point1, final Point point2) {
- if (point1 == null || point2 == null) {
- return BauSystem.MESSAGE.parse("COUNTINGWAND_MESSAGE_DIMENSION", player, 0, 0, 0);
- }
- return BauSystem.MESSAGE.parse("COUNTINGWAND_MESSAGE_DIMENSION", player, Math.abs(point1.getX() - point2.getX()) + 1, Math.abs(point1.getY() - point2.getY()) + 1, Math.abs(point1.getZ() - point2.getZ()) + 1);
- }
-
- public int getAmount(final Point point1, final Point point2) {
- return (Math.abs(point1.getX() - point2.getX()) + 1) * (Math.abs(point1.getY() - point2.getY()) + 1) * (Math.abs(point1.getZ() - point2.getZ()) + 1);
- }
+ public void checkSelection(final Point point, final boolean pos1, final Player p) {
+ SWPlayer player = SWPlayer.of(p);
+ CountingWandComponent countingWandComponent = player.getComponentOrDefault(CountingWandComponent.class, CountingWandComponent::new);
+ if (countingWandComponent.setPosition(pos1, point)) {
+ Point point1 = countingWandComponent.pos1;
+ Point point2 = countingWandComponent.pos2;
+ int amount = (Math.abs(point1.getX() - point2.getX()) + 1) * (Math.abs(point1.getY() - point2.getY()) + 1) * (Math.abs(point1.getZ() - point2.getZ()) + 1);
+ String dimension = player.using(BauSystem.MESSAGE).parse("COUNTINGWAND_MESSAGE_VOLUME", amount);
+ String volume = player.parse("COUNTINGWAND_MESSAGE_DIMENSION", Math.abs(point1.getX() - point2.getX()) + 1, Math.abs(point1.getY() - point2.getY()) + 1, Math.abs(point1.getZ() - point2.getZ()) + 1);
+ player.sendMessage(pos1 ? "COUNTINGWAND_MESSAGE_RCLICK" : "COUNTINGWAND_MESSAGE_LCLICK", point.getX(), point.getY(), point.getZ(), dimension, volume);
+ }
+ }
}
\ No newline at end of file
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/countingwand/CountingwandListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/countingwand/CountingwandListener.java
index 127bb964..9daab3f0 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/countingwand/CountingwandListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/countingwand/CountingwandListener.java
@@ -27,7 +27,6 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.player.PlayerInteractEvent;
-import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.util.RayTraceResult;
import java.util.Objects;
@@ -67,9 +66,4 @@ public class CountingwandListener implements Listener {
event.setCancelled(true);
Countingwand.checkSelection(Point.fromLocation(Objects.requireNonNull(event.getClickedBlock()).getLocation()), false, event.getPlayer());
}
-
- @EventHandler
- public void onLeave(PlayerQuitEvent event) {
- Countingwand.removePlayer(event.getPlayer());
- }
}
\ No newline at end of file
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/detonator/Detonator.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/detonator/Detonator.java
index 5ba2bca8..51d5e4e5 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/detonator/Detonator.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/detonator/Detonator.java
@@ -25,8 +25,11 @@ import de.steamwar.bausystem.configplayer.Config;
import de.steamwar.bausystem.features.autostart.AutostartListener;
import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage;
import de.steamwar.bausystem.features.detonator.storage.ItemStorage;
+import de.steamwar.core.SWPlayer;
import de.steamwar.entity.REntityServer;
import de.steamwar.entity.RFallingBlockEntity;
+import lombok.Getter;
+import lombok.Setter;
import lombok.experimental.UtilityClass;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -45,7 +48,28 @@ import java.util.*;
@UtilityClass
public class Detonator {
- private static final Map ENTITIES_MAP = new HashMap<>();
+ public class DetonatorComponent implements SWPlayer.Component {
+ private final REntityServer entities = new REntityServer();
+
+ @Getter
+ @Setter
+ private boolean hasUpdated = false;
+
+ @Override
+ public void onMount(SWPlayer player) {
+ entities.addPlayer(player.getPlayer());
+ entities.setCallback((player1, entity, action) -> {
+ Vector vector = new Vector(entity.getX(), entity.getY(), entity.getZ());
+ DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player1);
+ });
+ }
+
+ @Override
+ public void onUnmount(SWPlayer player) {
+ entities.close();
+ }
+ }
+
private static final Vector HALF = new Vector(0.5, 0, 0.5);
public static boolean isDetonator(ItemStack itemStack) {
@@ -53,28 +77,19 @@ public class Detonator {
}
public static void showDetonator(Player p, List locs) {
- if (ENTITIES_MAP.containsKey(p)) return;
- REntityServer entities = new REntityServer();
- entities.setCallback((player, rEntity, entityAction) -> {
- Vector vector = new Vector(rEntity.getX(), rEntity.getY(), rEntity.getZ());
- DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player);
- DetonatorListener.HAS_UPDATED.add(player);
- });
- entities.addPlayer(p);
- ENTITIES_MAP.put(p, entities);
-
+ DetonatorComponent detonatorComponent = SWPlayer.of(p).getComponentOrDefault(DetonatorComponent.class, DetonatorComponent::new);
locs.forEach(location -> {
- RFallingBlockEntity entity = new RFallingBlockEntity(entities, location.clone().add(HALF), Material.RED_STAINED_GLASS);
+ RFallingBlockEntity entity = new RFallingBlockEntity(detonatorComponent.entities, location.clone().add(HALF), Material.RED_STAINED_GLASS);
entity.setNoGravity(true);
});
}
public static void hideDetonator(Player p) {
- ENTITIES_MAP.remove(p).close();
+ SWPlayer.of(p).removeComponent(DetonatorComponent.class);
}
public static boolean hasActiveDetonatorShow(Player p) {
- return ENTITIES_MAP.containsKey(p);
+ return SWPlayer.of(p).hasComponent(DetonatorComponent.class);
}
public static void activateDetonator(DetonatorStorage detonator) {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/detonator/DetonatorListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/detonator/DetonatorListener.java
index 9d70d11a..d8cd57e3 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/detonator/DetonatorListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/detonator/DetonatorListener.java
@@ -24,6 +24,7 @@ import de.steamwar.bausystem.Permission;
import de.steamwar.bausystem.SWUtils;
import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage;
import de.steamwar.bausystem.features.detonator.storage.ItemStorage;
+import de.steamwar.core.SWPlayer;
import de.steamwar.linkage.Linked;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@@ -36,15 +37,11 @@ import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
-import java.util.HashSet;
-import java.util.Set;
-
@Linked
public class DetonatorListener implements Listener {
- static final Set HAS_UPDATED = new HashSet<>();
-
static void addLocationToDetonator(Location location, Player p) {
+ SWPlayer.of(p).getComponent(Detonator.DetonatorComponent.class).ifPresent(detonatorComponent -> detonatorComponent.setHasUpdated(true));
Detoblock detoblock = Detonator.getBlock(location.getBlock());
if (detoblock == Detoblock.INVALID) {
SWUtils.sendToActionbar(p, BauSystem.MESSAGE.parse("DETONATOR_INVALID_BLOCK", p));
@@ -66,64 +63,59 @@ public class DetonatorListener implements Listener {
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
- if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
+ if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
Player p = event.getPlayer();
if (Detonator.isDetonator(p.getInventory().getItemInMainHand())) {
event.setCancelled(true);
addLocationToDetonator(event.getBlock().getLocation(), p);
- HAS_UPDATED.add(event.getPlayer());
}
}
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
- if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
- if (!Detonator.isDetonator(event.getItem())) {
- return;
- }
+ if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
+ if (!Detonator.isDetonator(event.getItem())) return;
if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
event.setCancelled(true);
DetonatorStorage detonator = new ItemStorage(event.getPlayer());
Detonator.activateDetonator(detonator);
- HAS_UPDATED.add(event.getPlayer());
+ SWPlayer.of(event.getPlayer()).getComponent(Detonator.DetonatorComponent.class).ifPresent(detonatorComponent -> detonatorComponent.setHasUpdated(true));
}
}
@EventHandler(ignoreCancelled = true)
public void onPlayerMove(PlayerMoveEvent event) {
- if (!Permission.BUILD.hasPermission(event.getPlayer()) ||!Detonator.isDetonator(event.getPlayer().getInventory().getItemInMainHand())) {
+ if (!Permission.BUILD.hasPermission(event.getPlayer()) || !Detonator.isDetonator(event.getPlayer().getInventory().getItemInMainHand())) {
if (Detonator.hasActiveDetonatorShow(event.getPlayer())) {
Detonator.hideDetonator(event.getPlayer());
}
- } else {
- if (!Detonator.hasActiveDetonatorShow(event.getPlayer())) {
- Detonator.showDetonator(event.getPlayer(), new ItemStorage(event.getPlayer()).getLocations());
- }
+ return;
}
-
- if (HAS_UPDATED.contains(event.getPlayer())) {
- HAS_UPDATED.remove(event.getPlayer());
- if (Detonator.hasActiveDetonatorShow(event.getPlayer())) {
- Detonator.hideDetonator(event.getPlayer());
- Detonator.showDetonator(event.getPlayer(), new ItemStorage(event.getPlayer()).getLocations());
- }
+ if (!Detonator.hasActiveDetonatorShow(event.getPlayer())) {
+ Detonator.showDetonator(event.getPlayer(), new ItemStorage(event.getPlayer()).getLocations());
+ return;
}
+ Detonator.DetonatorComponent component = SWPlayer.of(event.getPlayer())
+ .getComponentAndFilter(Detonator.DetonatorComponent.class, Detonator.DetonatorComponent::isHasUpdated)
+ .orElse(null);
+ if (component == null) return;
+ component.setHasUpdated(false);
+ Detonator.hideDetonator(event.getPlayer());
+ Detonator.showDetonator(event.getPlayer(), new ItemStorage(event.getPlayer()).getLocations());
}
@EventHandler
public void onPlayerItemHeld(PlayerItemHeldEvent event) {
- if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
- if (Detonator.isDetonator(event.getPlayer().getInventory().getItemInMainHand())) {
- HAS_UPDATED.add(event.getPlayer());
- }
+ if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
+ if (!Detonator.isDetonator(event.getPlayer().getInventory().getItemInMainHand())) return;
+ SWPlayer.of(event.getPlayer()).getComponent(Detonator.DetonatorComponent.class).ifPresent(detonatorComponent -> detonatorComponent.setHasUpdated(true));
}
@EventHandler
public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) {
- if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
- if (Detonator.isDetonator(event.getMainHandItem()) || Detonator.isDetonator(event.getOffHandItem())) {
- HAS_UPDATED.add(event.getPlayer());
- }
+ if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
+ if (!(Detonator.isDetonator(event.getMainHandItem()) || Detonator.isDetonator(event.getOffHandItem()))) return;
+ SWPlayer.of(event.getPlayer()).getComponent(Detonator.DetonatorComponent.class).ifPresent(detonatorComponent -> detonatorComponent.setHasUpdated(true));
}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loader/Loader.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loader/Loader.java
index 491f45aa..4f990052 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loader/Loader.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loader/Loader.java
@@ -26,6 +26,7 @@ import de.steamwar.bausystem.features.loader.elements.LoaderInteractionElement;
import de.steamwar.bausystem.features.loader.elements.impl.LoaderTNT;
import de.steamwar.bausystem.features.loader.elements.impl.LoaderWait;
import de.steamwar.bausystem.shared.EnumDisplay;
+import de.steamwar.core.SWPlayer;
import de.steamwar.inventory.SWAnvilInv;
import de.steamwar.inventory.SWItem;
import de.steamwar.inventory.SWListInv;
@@ -40,21 +41,17 @@ import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
-public class Loader implements Listener {
-
- private static final Map LOADER_MAP = new HashMap<>();
+public class Loader implements Listener, SWPlayer.Component {
public static Loader getLoader(Player player) {
- return LOADER_MAP.get(player);
+ return SWPlayer.of(player).getComponent(Loader.class).orElse(null);
}
public static void newLoader(Player player) {
- LOADER_MAP.put(player, new Loader(player));
+ SWPlayer.of(player).setComponent(new Loader(player));
}
private final Player p;
@@ -145,7 +142,7 @@ public class Loader implements Listener {
recorder = null;
}
elements.clear();
- LOADER_MAP.remove(p);
+ SWPlayer.of(p).removeComponent(Loader.class);
}
public boolean setTicksBetweenShots(int delay) {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loadtimer/Loadtimer.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loadtimer/Loadtimer.java
index f1a42e1a..a7d642fe 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loadtimer/Loadtimer.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loadtimer/Loadtimer.java
@@ -29,6 +29,7 @@ import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
import org.bukkit.boss.BossBar;
import org.bukkit.entity.Player;
+import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
@@ -156,6 +157,7 @@ public class Loadtimer implements Listener {
}
public void onTntExplode(EntityExplodeEvent event) {
+ if (!(event.getEntity() instanceof TNTPrimed)) return;
if (region.getBuildArea().inRegion(event.getLocation(), true) && stage == Stage.IGNITION) {
stage = Stage.END;
explode = TPSUtils.currentRealTick.get();
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/observer/ObserverTracer.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/observer/ObserverTracer.java
index ad0bca1b..6dad9e00 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/observer/ObserverTracer.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/observer/ObserverTracer.java
@@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.observer;
import de.steamwar.Reflection;
import de.steamwar.bausystem.region.Point;
+import de.steamwar.core.SWPlayer;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
@@ -34,7 +35,7 @@ import org.bukkit.entity.Player;
import java.util.*;
-public class ObserverTracer {
+public class ObserverTracer implements SWPlayer.Component {
private static final Set ALLOWED = EnumSet.of(BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST, BlockFace.UP, BlockFace.DOWN);
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/observer/ObserverTracerCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/observer/ObserverTracerCommand.java
index 7cfadf2c..e88e4ca0 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/observer/ObserverTracerCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/observer/ObserverTracerCommand.java
@@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.observer;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.command.SWCommand;
+import de.steamwar.core.SWPlayer;
import de.steamwar.linkage.Linked;
import org.bukkit.entity.Player;
@@ -41,23 +42,23 @@ public class ObserverTracerCommand extends SWCommand {
@Register(value = "disable", description = "OBSERVER_HELP_DISABLE")
public void disable(Player p) {
ObserverTracerListener.enabled.remove(p);
- ObserverTracerListener.observerTracerMap.remove(p);
+ SWPlayer.of(p).removeComponent(ObserverTracer.class);
BauSystem.MESSAGE.send("OBSERVER_DISABLE", p);
}
@Register(value = "delete", description = "OBSERVER_HELP_DELETE")
public void delete(@Validator Player p) {
- ObserverTracerListener.observerTracerMap.remove(p);
+ SWPlayer.of(p).removeComponent(ObserverTracer.class);
BauSystem.MESSAGE.send("OBSERVER_DELETE", p);
}
@Register(value = "retrace", description = "OBSERVER_HELP_RETRACE")
public void retrace(@Validator Player p) {
- if (ObserverTracerListener.observerTracerMap.containsKey(p)) {
+ if (SWPlayer.of(p).hasComponent(ObserverTracer.class)) {
BauSystem.MESSAGE.send("OBSERVER_RETRACE_NO_TRACE", p);
return;
}
- ObserverTracerListener.observerTracerMap.get(p).trace();
+ SWPlayer.of(p).getComponent(ObserverTracer.class).ifPresent(ObserverTracer::trace);
BauSystem.MESSAGE.send("OBSERVER_RETRACE_DONE", p);
}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/observer/ObserverTracerListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/observer/ObserverTracerListener.java
index 9ef56909..0528527e 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/observer/ObserverTracerListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/observer/ObserverTracerListener.java
@@ -22,6 +22,7 @@ package de.steamwar.bausystem.features.observer;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.Permission;
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
+import de.steamwar.core.SWPlayer;
import de.steamwar.linkage.Linked;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
@@ -34,23 +35,19 @@ import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
@Linked
public class ObserverTracerListener implements Listener {
static Set enabled = new HashSet<>();
- static Map observerTracerMap = new HashMap<>();
public ObserverTracerListener() {
Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), () -> {
- observerTracerMap.forEach((player, observerTracer) -> {
- if (player.getGameMode() == GameMode.SPECTATOR) {
- observerTracer.show();
- }
+ SWPlayer.allWithSingleComponent(ObserverTracer.class).forEach(pair -> {
+ if (pair.getKey().getGameMode() != GameMode.SPECTATOR) return;
+ pair.getValue().show();
});
}, 15L, 15L);
}
@@ -58,20 +55,16 @@ public class ObserverTracerListener implements Listener {
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
- if (!enabled.contains(event.getPlayer())) {
- return;
- }
- if (event.getClickedBlock() == null) {
- return;
- }
- if (observerTracerMap.containsKey(event.getPlayer())) {
- ObserverTracer observerTracer = observerTracerMap.get(event.getPlayer());
+ if (!enabled.contains(event.getPlayer())) return;
+ if (event.getClickedBlock() == null) return;
+ ObserverTracer observerTracer = SWPlayer.of(event.getPlayer()).getComponent(ObserverTracer.class).orElse(null);
+ if (observerTracer != null) {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
if (!observerTracer.trace()) {
createNew(event);
}
- observerTracerMap.forEach((player, o) -> {
- o.trace();
+ SWPlayer.allWithSingleComponent(ObserverTracer.class).forEach(pair -> {
+ pair.getValue().trace();
});
}, 1L);
} else {
@@ -86,13 +79,13 @@ public class ObserverTracerListener implements Listener {
if (event.getClickedBlock().getType() == Material.OBSERVER) {
ObserverTracer observerTracer = new ObserverTracer(event.getPlayer(), event.getClickedBlock());
observerTracer.trace();
- observerTracerMap.put(event.getPlayer(), observerTracer);
+ SWPlayer.of(event.getPlayer()).setComponent(observerTracer);
}
}
@EventHandler
public void onBauMemberUpdate(BauMemberUpdateEvent event) {
- event.getNewSpectator().forEach(observerTracerMap::remove);
+ event.getNewBuilder().forEach(player -> SWPlayer.of(player).removeComponent(ObserverTracer.class));
}
@EventHandler
@@ -103,6 +96,5 @@ public class ObserverTracerListener implements Listener {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
enabled.remove(event.getPlayer());
- observerTracerMap.remove(event.getPlayer());
}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/TNTListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/TNTListener.java
index a8676ae2..22eabcaa 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/TNTListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/TNTListener.java
@@ -26,8 +26,10 @@ import de.steamwar.bausystem.region.flags.Flag;
import de.steamwar.bausystem.region.flags.TNTMode;
import de.steamwar.bausystem.utils.ScoreboardElement;
import de.steamwar.linkage.Linked;
+import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
+import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@@ -39,11 +41,14 @@ import java.util.List;
@Linked
public class TNTListener implements Listener, ScoreboardElement {
- private void explode(List blockList) {
+ private void explode(List blockList, boolean destroy) {
blockList.removeIf(block -> {
Region region = Region.getRegion(block.getLocation());
TNTMode value = region.getFlags().get(Flag.TNT).getWithDefault();
if (value == TNTMode.ALLOW) {
+ if (destroy && block.getType() != Material.TNT) {
+ block.setType(Material.AIR);
+ }
return false;
} else if (value == TNTMode.ONLY_TB) {
if (region.getBuildArea().inRegion(block.getLocation(), true)) {
@@ -57,12 +62,16 @@ public class TNTListener implements Listener, ScoreboardElement {
@EventHandler
public void onBlockExplode(BlockExplodeEvent event) {
- explode(event.blockList());
+ explode(event.blockList(), false);
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onExplode(EntityExplodeEvent event) {
- explode(event.blockList());
+ if (!(event.getEntity() instanceof TNTPrimed)) {
+ event.blockList().clear();
+ return;
+ }
+ explode(event.blockList(), true);
}
@Override
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/TestblockCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/TestblockCommand.java
index d09c06a0..52c53a63 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/TestblockCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/TestblockCommand.java
@@ -31,7 +31,6 @@ import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.LinkedInstance;
-import de.steamwar.sql.BauweltMember;
import de.steamwar.sql.Punishment;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
@@ -73,6 +72,14 @@ public class TestblockCommand extends SWCommand {
resetRegion(p, node, isExtension ? RegionExtensionType.EXTENSION : RegionExtensionType.NORMAL, isIgnoreAir, isOnlyColor, replaceTNT, replaceWater);
}
+ @Register(value="default")
+ public void setTestblockDefault(Player p) {
+ Region region = regionCheck(p);
+ if (region == null) return;
+ region.getRegionData().setTestblockSchematic(null);
+ resetRegion(p, null, RegionExtensionType.EXTENSION, false, false, false, false);
+ }
+
private void resetRegion(Player p, SchematicNode node, RegionExtensionType regionExtensionType, boolean ignoreAir, boolean onlyColors, boolean removeTNT, boolean removeWater) {
Region region = regionCheck(p);
if (region == null) return;
@@ -93,29 +100,10 @@ public class TestblockCommand extends SWCommand {
}
}
- // Beta Tester enabled
- switch (BauServer.getInstance().getOwnerID()) {
- case 245:
- case 403:
- case 1898:
- case 3320:
- case 4603:
- case 5262:
- case 5399:
- case 6032:
- case 7862:
- case 11077:
- case 11888:
- case 12258:
- case 16009:
- if (node == null) {
- node = region.getRegionData().getTestblockSchematic();
- } else {
- region.getRegionData().setTestblockSchematic(node);
- }
- break;
- default:
- break;
+ if (node == null) {
+ node = region.getRegionData().getTestblockSchematic();
+ } else {
+ region.getRegionData().setTestblockSchematic(node);
}
PasteBuilder.ClipboardProvider clipboardProvider;
@@ -198,7 +186,7 @@ public class TestblockCommand extends SWCommand {
@Override
public List tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) {
List stringList = new ArrayList<>(SchematicNode.getNodeTabcomplete(SteamwarUser.get(((Player) commandSender).getUniqueId()), s));
- stringList.addAll(SchematicNode.getNodeTabcomplete(SteamwarUser.get(0), s));
+ stringList.addAll(SchematicNode.getNodeTabcomplete(SteamwarUser.byId(0), s));
return stringList;
}
@@ -206,7 +194,7 @@ public class TestblockCommand extends SWCommand {
public SchematicNode map(CommandSender commandSender, PreviousArguments previousArguments, String s) {
SchematicNode node = SchematicNode.getNodeFromPath(SteamwarUser.get(((Player) commandSender).getUniqueId()), s);
if (node == null) {
- node = SchematicNode.getNodeFromPath(SteamwarUser.get(0), s);
+ node = SchematicNode.getNodeFromPath(SteamwarUser.byId(0), s);
}
return node;
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/ScriptHelper.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/ScriptHelper.java
index fd4bc826..bb486680 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/ScriptHelper.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/ScriptHelper.java
@@ -38,7 +38,7 @@ public class ScriptHelper {
BookMeta meta = (BookMeta) itemStack.getItemMeta();
if(!writeable) {
meta.setTitle(script.getName());
- meta.setAuthor(SteamwarUser.get(script.getUserId()).getUserName());
+ meta.setAuthor(SteamwarUser.byId(script.getUserId()).getUserName());
}
meta.setPages(getScriptPages(script));
itemStack.setItemMeta(meta);
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/ScriptListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/ScriptListener.java
index 0eadc3ed..2f444561 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/ScriptListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/ScriptListener.java
@@ -67,7 +67,7 @@ public class ScriptListener implements Listener {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
- ScriptRunner.remove(event.getPlayer());
+ playerSet.remove(event.getPlayer());
}
@EventHandler
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/ScriptRunner.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/ScriptRunner.java
index 2a506e12..ee10536e 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/ScriptRunner.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/ScriptRunner.java
@@ -23,8 +23,11 @@ import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.script.lua.CommandRegister;
import de.steamwar.bausystem.features.script.lua.SteamWarGlobalLuaPlugin;
import de.steamwar.bausystem.features.script.lua.SteamWarPlatform;
+import de.steamwar.core.SWPlayer;
import de.steamwar.sql.Script;
import de.steamwar.sql.SteamwarUser;
+import lombok.Getter;
+import lombok.Setter;
import lombok.experimental.UtilityClass;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
@@ -44,12 +47,25 @@ public class ScriptRunner {
// Key -> bau-script-
// Value ->
- private static final Map>> EVENT_MAP = new HashMap<>();
- private static final Map>> HOTKEY_MAP = new HashMap<>();
- private static final Map> COMMAND_MAP = new HashMap<>();
+ public class ScriptData implements SWPlayer.Component {
+ private Map> events = new EnumMap<>(SteamWarGlobalLuaPlugin.EventType.class);
+ private Map> hotkeys = new HashMap<>();
+ private Map commands = new HashMap<>();
+
+ @Getter
+ private Set calledCommands = new HashSet<>();
+
+ @Getter
+ @Setter
+ private Long lastF = Long.MAX_VALUE;
+
+ @Getter
+ @Setter
+ private boolean ignore;
+ }
public Set getCommandsOfPlayer(Player player) {
- return COMMAND_MAP.getOrDefault(player, new HashMap<>()).keySet();
+ return SWPlayer.of(player).getComponentOrDefault(ScriptData.class, ScriptData::new).commands.keySet();
}
public static void runScript(String script, Player player) {
@@ -64,10 +80,12 @@ public class ScriptRunner {
public static void createGlobalScript(List scripts, Player player) {
remove(player);
+ SWPlayer swPlayer = SWPlayer.of(player);
+ ScriptData scriptData = swPlayer.getComponentOrDefault(ScriptData.class, ScriptData::new);
Globals globals = SteamWarPlatform.createGlobalGlobals(player,
- (s, luaFunction) -> EVENT_MAP.computeIfAbsent(player, player1 -> new EnumMap<>(SteamWarGlobalLuaPlugin.EventType.class)).computeIfAbsent(s, s1 -> new ArrayList<>()).add(luaFunction),
- (s, luaFunction) -> HOTKEY_MAP.computeIfAbsent(player, player1 -> new HashMap<>()).computeIfAbsent(Hotkey.fromString(s), s1 -> new ArrayList<>()).add(luaFunction),
- commandRegister -> COMMAND_MAP.computeIfAbsent(player, player1 -> new HashMap<>()).put(commandRegister.getName(), commandRegister));
+ (s, luaFunction) -> scriptData.events.computeIfAbsent(s, s1 -> new ArrayList<>()).add(luaFunction),
+ (s, luaFunction) -> scriptData.hotkeys.computeIfAbsent(Hotkey.fromString(s), s1 -> new ArrayList<>()).add(luaFunction),
+ commandRegister -> scriptData.commands.put(commandRegister.getName(), commandRegister));
for (String script : scripts) {
catchScript("SCRIPT_ERROR_GLOBAL", player, () -> globals.load(script).call());
@@ -75,13 +93,14 @@ public class ScriptRunner {
}
public static void remove(Player player) {
- EVENT_MAP.remove(player);
- COMMAND_MAP.remove(player);
- HOTKEY_MAP.remove(player);
+ SWPlayer.of(player).removeComponent(ScriptData.class);
}
public static void callEvent(Player player, SteamWarGlobalLuaPlugin.EventType event, LuaValue eventValue, Event wrappedEvent) {
- List luaFunctions = EVENT_MAP.getOrDefault(player, Collections.emptyMap()).getOrDefault(event, Collections.emptyList());
+ List luaFunctions = SWPlayer.of(player).getComponent(ScriptData.class)
+ .map(scriptData -> scriptData.events)
+ .orElse(Collections.emptyMap())
+ .getOrDefault(event, Collections.emptyList());
if (luaFunctions.isEmpty()) {
if(event == SteamWarGlobalLuaPlugin.EventType.DoubleSwap) {
player.performCommand("gui");
@@ -124,7 +143,10 @@ public class ScriptRunner {
}
public static boolean callCommand(Player player, String command, String[] argsArray) {
- CommandRegister commandRegister = COMMAND_MAP.getOrDefault(player, Collections.emptyMap()).get(command);
+ CommandRegister commandRegister = SWPlayer.of(player).getComponent(ScriptData.class)
+ .map(scriptData -> scriptData.commands)
+ .orElse(Collections.emptyMap())
+ .get(command);
if (commandRegister == null) {
return false;
}
@@ -188,7 +210,11 @@ public class ScriptRunner {
public static void callHotkey(int mods, int key, Player player, boolean pressed) {
Hotkey hotkey = Hotkey.fromChar(key, mods);
- catchScript("SCRIPT_ERROR_GLOBAL", player, () -> HOTKEY_MAP.getOrDefault(player, Collections.emptyMap()).getOrDefault(hotkey, Collections.emptyList()).forEach(luaFunction -> luaFunction.call(LuaValue.valueOf(pressed))));
+ List hotkeys = SWPlayer.of(player).getComponent(ScriptData.class)
+ .map(scriptData -> scriptData.hotkeys)
+ .orElse(Collections.emptyMap())
+ .getOrDefault(hotkey, Collections.emptyList());
+ catchScript("SCRIPT_ERROR_GLOBAL", player, () -> hotkeys.forEach(luaFunction -> luaFunction.call(LuaValue.valueOf(pressed))));
}
public static void catchScript(String errorMsg, Player player, Runnable run) {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/CommandListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/CommandListener.java
index d52e4d9b..f79d4ac3 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/CommandListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/CommandListener.java
@@ -21,44 +21,24 @@ package de.steamwar.bausystem.features.script.event;
import de.steamwar.bausystem.Permission;
import de.steamwar.bausystem.features.script.ScriptRunner;
+import de.steamwar.core.SWPlayer;
import de.steamwar.linkage.Linked;
-import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
-import org.bukkit.event.player.PlayerJoinEvent;
-import org.bukkit.event.player.PlayerQuitEvent;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
@Linked
public class CommandListener implements Listener {
- private Map> calledCommands = new HashMap<>();
-
@EventHandler
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
String[] split = event.getMessage().split(" ");
- if (calledCommands.getOrDefault(event.getPlayer(), new HashSet<>()).contains(split[0])) {
- return;
- }
+ ScriptRunner.ScriptData scriptData = SWPlayer.of(event.getPlayer()).getComponentOrDefault(ScriptRunner.ScriptData.class, ScriptRunner.ScriptData::new);
+ if (scriptData.getCalledCommands().contains(split[0])) return;
- calledCommands.getOrDefault(event.getPlayer(), new HashSet<>()).add(split[0]);
+ scriptData.getCalledCommands().add(split[0]);
event.setCancelled(ScriptRunner.callCommand(event.getPlayer(), split[0].substring(1), split));
- calledCommands.getOrDefault(event.getPlayer(), new HashSet<>()).remove(split[0]);
- }
-
- @EventHandler
- public void onPlayerJoin(PlayerJoinEvent event) {
- calledCommands.put(event.getPlayer(), new HashSet<>());
- }
-
- @EventHandler
- public void onPlayerQuit(PlayerQuitEvent event) {
- calledCommands.remove(event.getPlayer());
+ scriptData.getCalledCommands().remove(split[0]);
}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/EventListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/EventListener.java
index 8aade642..3490ea2e 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/EventListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/EventListener.java
@@ -25,6 +25,7 @@ import de.steamwar.bausystem.features.script.ScriptRunner;
import de.steamwar.bausystem.features.script.lua.SteamWarGlobalLuaPlugin;
import de.steamwar.bausystem.features.script.lua.libs.StorageLib;
import de.steamwar.bausystem.region.Region;
+import de.steamwar.core.SWPlayer;
import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.linkage.Linked;
import org.bukkit.Bukkit;
@@ -43,32 +44,27 @@ import org.bukkit.event.player.*;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
@Linked
public class EventListener implements Listener {
- private static final Map LAST_FS = new HashMap<>();
-
static {
Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), () -> {
long millis = System.currentTimeMillis();
- LAST_FS.entrySet().removeIf(entry -> millis - entry.getValue() > 200);
+ SWPlayer.allWithSingleComponent(ScriptRunner.ScriptData.class)
+ .filter(pair -> millis - pair.getValue().getLastF() > 200)
+ .forEach(pair -> pair.getValue().setLastF(Long.MAX_VALUE));
}, 1, 1);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerJoin(PlayerJoinEvent event) {
- if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
+ if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
ScriptRunner.callEvent(event.getPlayer(), SteamWarGlobalLuaPlugin.EventType.SelfJoin, LuaValue.NIL, event);
}
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerQuit(PlayerQuitEvent event) {
- if(Permission.BUILD.hasPermission(event.getPlayer())) {
+ if (Permission.BUILD.hasPermission(event.getPlayer())) {
ScriptRunner.callEvent(event.getPlayer(), SteamWarGlobalLuaPlugin.EventType.SelfLeave, LuaValue.NIL, event);
}
StorageLib.removePlayer(event.getPlayer());
@@ -76,19 +72,20 @@ public class EventListener implements Listener {
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) {
- if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
- if (LAST_FS.containsKey(event.getPlayer())) {
+ if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
+ ScriptRunner.ScriptData scriptData = SWPlayer.of(event.getPlayer()).getComponentOrDefault(ScriptRunner.ScriptData.class, ScriptRunner.ScriptData::new);
+ if (scriptData.getLastF() != Long.MAX_VALUE) {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
ScriptRunner.callEvent(event.getPlayer(), SteamWarGlobalLuaPlugin.EventType.DoubleSwap, LuaValue.NIL, event);
}, 1);
} else {
- LAST_FS.put(event.getPlayer(), System.currentTimeMillis());
+ scriptData.setLastF(System.currentTimeMillis());
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onBlockPlace(BlockPlaceEvent event) {
- if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
+ if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
LuaTable table = new LuaTable();
table.set("x", event.getBlock().getX());
table.set("y", event.getBlock().getY());
@@ -99,7 +96,7 @@ public class EventListener implements Listener {
@EventHandler(priority = EventPriority.HIGH)
public void onBlockBreak(BlockBreakEvent event) {
- if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
+ if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
LuaTable table = new LuaTable();
table.set("x", event.getBlock().getX());
table.set("y", event.getBlock().getY());
@@ -108,12 +105,12 @@ public class EventListener implements Listener {
ScriptRunner.callEvent(event.getPlayer(), SteamWarGlobalLuaPlugin.EventType.BreakBlock, table, event);
}
- private final Set ignore = new HashSet<>();
-
@EventHandler(priority = EventPriority.LOW)
public void onPlayerInteract(PlayerInteractEvent event) {
- if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
- if (ignore.remove(event.getPlayer())) {
+ if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
+ ScriptRunner.ScriptData scriptData = SWPlayer.of(event.getPlayer()).getComponentOrDefault(ScriptRunner.ScriptData.class, ScriptRunner.ScriptData::new);
+ if (scriptData.isIgnore()) {
+ scriptData.setIgnore(false);
return;
}
LuaTable table = new LuaTable();
@@ -124,7 +121,7 @@ public class EventListener implements Listener {
table.set("hand", event.getHand().name());
}
table.set("block", event.getItem() == null ? Material.AIR.name() : event.getItem().getType().name());
- if(event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_BLOCK) {
+ if (event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_BLOCK) {
table.set("hasBlock", LuaValue.valueOf(true));
table.set("blockX", event.getClickedBlock().getX());
table.set("blockY", event.getClickedBlock().getY());
@@ -150,7 +147,7 @@ public class EventListener implements Listener {
Region tntRegion = Region.getRegion(event.getLocation());
for (Player player : Bukkit.getOnlinePlayers()) {
- if(!Permission.BUILD.hasPermission(player)) continue;
+ if (!Permission.BUILD.hasPermission(player)) continue;
if (tntRegion.getArea().inRegion(player.getLocation(), false)) {
ScriptRunner.callEvent(player, SteamWarGlobalLuaPlugin.EventType.TNTSpawn, LuaValue.NIL, event);
}
@@ -172,7 +169,7 @@ public class EventListener implements Listener {
boolean inBuild = event.blockList().stream().anyMatch(block -> tntRegion.getBuildArea().inRegion(block.getLocation(), true));
for (Player player : Bukkit.getOnlinePlayers()) {
- if(!Permission.BUILD.hasPermission(player)) continue;
+ if (!Permission.BUILD.hasPermission(player)) continue;
if (tntRegion.getArea().inRegion(player.getLocation(), false)) {
ScriptRunner.callEvent(player, SteamWarGlobalLuaPlugin.EventType.TNTExplode, table, event);
if (inBuild) {
@@ -184,8 +181,9 @@ public class EventListener implements Listener {
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerDropItem(PlayerDropItemEvent event) {
- if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
- ignore.add(event.getPlayer());
+ if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
+ ScriptRunner.ScriptData scriptData = SWPlayer.of(event.getPlayer()).getComponentOrDefault(ScriptRunner.ScriptData.class, ScriptRunner.ScriptData::new);
+ scriptData.setIgnore(true);
LuaTable table = new LuaTable();
table.set("type", event.getItemDrop().getItemStack().getType().name());
ScriptRunner.callEvent(event.getPlayer(), SteamWarGlobalLuaPlugin.EventType.DropItem, table, event);
@@ -194,7 +192,7 @@ public class EventListener implements Listener {
@EventHandler(priority = EventPriority.HIGH)
public void onEntityDeath(EntityDeathEvent event) {
for (Player player : Bukkit.getOnlinePlayers()) {
- if(!Permission.BUILD.hasPermission(player)) continue;
+ if (!Permission.BUILD.hasPermission(player)) continue;
LuaTable table = new LuaTable();
table.set("type", event.getEntityType().name());
ScriptRunner.callEvent(player, SteamWarGlobalLuaPlugin.EventType.EntityDeath, table, event);
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/SteamWarLuaPlugin.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/SteamWarLuaPlugin.java
index df6fc706..74225e62 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/SteamWarLuaPlugin.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/SteamWarLuaPlugin.java
@@ -48,6 +48,7 @@ import java.util.logging.Level;
public class SteamWarLuaPlugin extends TwoArgFunction {
private static final boolean hasFAWE = Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit") != null;
+ private static final Set ignoreCommandFromWorldEdit = Set.of("select", "schem", "/schem", "schematic", "/schematic");
protected static final Map, List> LUA_LIBS = new HashMap<>();
@@ -116,7 +117,7 @@ public class SteamWarLuaPlugin extends TwoArgFunction {
command = preprocessEvent.getMessage().substring(1);
Bukkit.getLogger().log(Level.INFO, player.getName() + " dispatched command: " + command);
String[] commandSplit = command.split(" ");
- if (!commandSplit[0].equals("select") && hasFAWE && WorldEditListener.isWorldEditCommand("/" + commandSplit[0])) {
+ if (!ignoreCommandFromWorldEdit.contains(commandSplit[0]) && hasFAWE && WorldEditListener.isWorldEditCommand("/" + commandSplit[0])) {
EditSession editSession = WorldEditUtils.getEditSession(player);
Actor actor = BukkitAdapter.adapt(player);
WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().handleCommandOnCurrentThread(new CommandEvent(actor, command, editSession));
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/StorageLib.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/StorageLib.java
index c1646d41..04cde3f0 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/StorageLib.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/StorageLib.java
@@ -89,7 +89,7 @@ public class StorageLib implements LuaLib, Enable, Disable {
jsonObject.keySet().forEach(key -> {
map.put(key, fromJson(jsonObject.get(key)));
});
- SteamwarUser steamwarUser = SteamwarUser.get(Integer.parseInt(playerStorage.getName().substring(0, playerStorage.getName().length() - ".json".length())));
+ SteamwarUser steamwarUser = SteamwarUser.byId(Integer.parseInt(playerStorage.getName().substring(0, playerStorage.getName().length() - ".json".length())));
PLAYER_STORAGE.put(steamwarUser.getUUID(), map);
} catch (Exception e) {}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabGenerator.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabGenerator.java
index 809358b6..37d1a5f0 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabGenerator.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabGenerator.java
@@ -26,6 +26,7 @@ import de.steamwar.bausystem.utils.PasteBuilder;
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
import org.bukkit.Bukkit;
import org.bukkit.Location;
+import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
@@ -51,6 +52,7 @@ public class StabGenerator extends StabStep implements Listener {
@EventHandler
public void onEntityExplode(EntityExplodeEvent event) {
+ if (!(event.getEntity() instanceof TNTPrimed)) return;
if (Region.getRegion(event.getEntity().getLocation()) == data.region) {
event.blockList().forEach(block -> {
if (!data.region.getTestblockArea().inRegion(block.getLocation(), true))
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/YAPIONFormatSimulatorLoader.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/YAPIONFormatSimulatorLoader.java
index c138ecb1..6111eb32 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/YAPIONFormatSimulatorLoader.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/YAPIONFormatSimulatorLoader.java
@@ -54,7 +54,7 @@ public class YAPIONFormatSimulatorLoader implements SimulatorLoader {
}
String name = file.getName().substring(0, file.getName().length() - 7);
- SteamwarUser steamwarUser = SteamwarUser.get(Integer.parseInt(name));
+ SteamwarUser steamwarUser = SteamwarUser.byId(Integer.parseInt(name));
List simulators = new ArrayList<>();
for (String s : yapionObject.getKeys()) {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/laufbau/LaufbauUtils.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/laufbau/LaufbauUtils.java
index 4eb6c382..a642c22d 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/laufbau/LaufbauUtils.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/laufbau/LaufbauUtils.java
@@ -20,17 +20,14 @@
package de.steamwar.bausystem.features.slaves.laufbau;
import de.steamwar.bausystem.BauSystem;
+import de.steamwar.core.SWPlayer;
import de.steamwar.inventory.SWItem;
-import de.steamwar.linkage.Linked;
import de.steamwar.sql.UserConfig;
import lombok.Cleanup;
import lombok.SneakyThrows;
+import lombok.experimental.UtilityClass;
import org.bukkit.Material;
import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-import org.bukkit.event.player.PlayerJoinEvent;
-import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.meta.ItemMeta;
import yapion.hierarchy.output.StreamOutput;
import yapion.hierarchy.types.YAPIONObject;
@@ -39,44 +36,45 @@ import yapion.parser.options.StreamOptions;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
-@Linked
-public class LaufbauUtils implements Listener {
+@UtilityClass
+public class LaufbauUtils {
- private static Map yapionObjectMap = new HashMap<>();
+ public static class LaufbauComponent implements SWPlayer.Component {
- @EventHandler
- @SneakyThrows
- public void onPlayerJoin(PlayerJoinEvent event) {
- String config = UserConfig.getConfig(event.getPlayer().getUniqueId(), "bausystem-laufbau");
- if (config == null) {
- return;
- }
- byte[] bytes = Base64.getDecoder().decode(config);
- @Cleanup GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
- YAPIONObject yapionObject = new YAPIONParser(gzipInputStream, new StreamOptions().stopOnStreamEnd(true)).parse().result();
- yapionObjectMap.put(event.getPlayer(), yapionObject);
- }
+ private YAPIONObject yapionObject = new YAPIONObject();
- @EventHandler
- @SneakyThrows
- public void onPlayerQuit(PlayerQuitEvent event) {
- YAPIONObject yapionObject = yapionObjectMap.get(event.getPlayer());
- if (yapionObject == null) {
- return;
+ @Override
+ @SneakyThrows
+ public void onMount(SWPlayer player) {
+ String config = UserConfig.getConfig(player.getPlayer().getUniqueId(), "bausystem-laufbau");
+ if (config == null) {
+ return;
+ }
+ byte[] bytes = Base64.getDecoder().decode(config);
+ @Cleanup GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
+ yapionObject = new YAPIONParser(gzipInputStream, new StreamOptions().stopOnStreamEnd(true)).parse().result();
}
- if (yapionObject.isEmpty()) {
- UserConfig.removePlayerConfig(event.getPlayer().getUniqueId(), "bausystem-laufbau");
- return;
+
+ @Override
+ @SneakyThrows
+ public void onUnmount(SWPlayer player) {
+ if (yapionObject.isEmpty()) {
+ UserConfig.removePlayerConfig(player.getPlayer().getUniqueId(), "bausystem-laufbau");
+ return;
+ }
+ @Cleanup ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ @Cleanup GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
+ yapionObject.toYAPION(new StreamOutput(gzipOutputStream)).close();
+ UserConfig.updatePlayerConfig(player.getPlayer().getUniqueId(), "bausystem-laufbau", Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()));
}
- @Cleanup ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
- @Cleanup GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
- yapionObject.toYAPION(new StreamOutput(gzipOutputStream)).close();
- UserConfig.updatePlayerConfig(event.getPlayer().getUniqueId(), "bausystem-laufbau", Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()));
}
public static Cuboid pixelCuboid(double pixelX, double pixelY, double pixelZ, double pixelDX, double pixelDY, double pixelDZ) {
@@ -125,11 +123,7 @@ public class LaufbauUtils implements Listener {
return false;
}
String identifier = identifier(bb);
- YAPIONObject yapionObject = yapionObjectMap.get(p);
- if (yapionObject == null) {
- return false;
- }
- return yapionObject.containsKey(identifier);
+ return SWPlayer.of(p).getComponentOrDefault(LaufbauComponent.class, LaufbauComponent::new).yapionObject.containsKey(identifier);
}
@SneakyThrows
@@ -138,11 +132,7 @@ public class LaufbauUtils implements Listener {
return;
}
String identifier = identifier(bb);
- YAPIONObject yapionObject = yapionObjectMap.get(p);
- if (yapionObject == null) {
- yapionObject = new YAPIONObject();
- yapionObjectMap.put(p, yapionObject);
- }
+ YAPIONObject yapionObject = SWPlayer.of(p).getComponentOrDefault(LaufbauComponent.class, LaufbauComponent::new).yapionObject;
if (yapionObject.containsKey(identifier)) {
yapionObject.remove(identifier);
} else {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/TechHiderCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/TechHiderCommand.java
index 7cb18b50..74888bec 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/TechHiderCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/TechHiderCommand.java
@@ -107,7 +107,7 @@ public class TechHiderCommand extends SWCommand implements Listener, ScoreboardE
@Override
public Player map(CommandSender commandSender, String[] previousArguments, String s) {
Player player = Bukkit.getPlayer(s);
- if (player != null && Permission.REAL_SPECTATOR.hasPermission(player)) {
+ if (player != null && Permission.SPECTATOR.hasPermission(player)) {
return player;
}
return null;
@@ -116,7 +116,7 @@ public class TechHiderCommand extends SWCommand implements Listener, ScoreboardE
@Override
public Collection tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
return Bukkit.getOnlinePlayers().stream()
- .filter(Permission.REAL_SPECTATOR::hasPermission)
+ .filter(Permission.SPECTATOR::hasPermission)
.map(Player::getName)
.collect(Collectors.toList());
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/testblock/blockcounter/BlockCounterListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/testblock/blockcounter/BlockCounterListener.java
index c4f711d8..beb693eb 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/testblock/blockcounter/BlockCounterListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/testblock/blockcounter/BlockCounterListener.java
@@ -22,6 +22,7 @@ package de.steamwar.bausystem.features.testblock.blockcounter;
import de.steamwar.bausystem.region.Region;
import de.steamwar.linkage.Linked;
import org.bukkit.block.Block;
+import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
@@ -34,6 +35,7 @@ public class BlockCounterListener implements Listener {
@EventHandler
public void onEntityExplode(EntityExplodeEvent event) {
+ if (!(event.getEntity() instanceof TNTPrimed)) return;
Region region = Region.getRegion(event.getLocation());
if (region.getType().isGlobal()) {
return;
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tntlistener/TLSCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tls/TLSCommand.java
similarity index 82%
rename from BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tntlistener/TLSCommand.java
rename to BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tls/TLSCommand.java
index 355803dc..252482b6 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tntlistener/TLSCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tls/TLSCommand.java
@@ -17,7 +17,7 @@
* along with this program. If not, see .
*/
-package de.steamwar.bausystem.features.tntlistener;
+package de.steamwar.bausystem.features.tls;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
@@ -43,4 +43,13 @@ public class TLSCommand extends SWCommand {
public void stop(@Validator Player player) {
listener.stopListening(player);
}
+
+ @Register(description = "TLS_TOGGLE_HELP")
+ public void toggle(@Validator Player player) {
+ if (listener.isActiveFor(player)) {
+ listener.stopListening(player);
+ } else {
+ listener.startListening(player);
+ }
+ }
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tntlistener/TLSListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tls/TLSListener.java
similarity index 98%
rename from BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tntlistener/TLSListener.java
rename to BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tls/TLSListener.java
index 9b587d8f..20e7f161 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tntlistener/TLSListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tls/TLSListener.java
@@ -17,7 +17,7 @@
* along with this program. If not, see .
*/
-package de.steamwar.bausystem.features.tntlistener;
+package de.steamwar.bausystem.features.tls;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tntlistener/TLSScoreboardElement.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tls/TLSScoreboardElement.java
similarity index 96%
rename from BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tntlistener/TLSScoreboardElement.java
rename to BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tls/TLSScoreboardElement.java
index 0dec6609..8744e1f0 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tntlistener/TLSScoreboardElement.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tls/TLSScoreboardElement.java
@@ -17,7 +17,7 @@
* along with this program. If not, see .
*/
-package de.steamwar.bausystem.features.tntlistener;
+package de.steamwar.bausystem.features.tls;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.Permission;
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/GamemodeCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/GamemodeCommand.java
index 9e3da950..86ecf6ca 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/GamemodeCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/GamemodeCommand.java
@@ -20,6 +20,7 @@ package de.steamwar.bausystem.features.util;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.command.SWCommand;
+import de.steamwar.core.SWPlayer;
import de.steamwar.linkage.Linked;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
@@ -39,10 +40,11 @@ public class GamemodeCommand extends SWCommand {
@Register
public void genericCommand(final Player p) {
- if (NoClipCommand.getNOCLIPS().contains(p)) {
- p.performCommand("noclip");
- return;
- }
+ SWPlayer swPlayer = SWPlayer.of(p);
+ if (swPlayer.hasComponent(NoClipCommand.NoClipData.class)) {
+ swPlayer.removeComponent(NoClipCommand.NoClipData.class);
+ return;
+ }
if (p.getGameMode() == GameMode.CREATIVE) {
p.setGameMode(GameMode.SPECTATOR);
} else {
@@ -52,9 +54,7 @@ public class GamemodeCommand extends SWCommand {
@Register
public void gamemodeCommand(final Player p, final GameMode gameMode) {
- if (NoClipCommand.getNOCLIPS().contains(p)) {
- p.performCommand("noclip");
- }
+ SWPlayer.of(p).removeComponent(NoClipCommand.NoClipData.class);
p.setGameMode(gameMode);
}
}
\ No newline at end of file
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/MaterialCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/MaterialCommand.java
index 69b53897..52a588f9 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/MaterialCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/MaterialCommand.java
@@ -26,6 +26,7 @@ import de.steamwar.bausystem.shared.EnumDisplay;
import de.steamwar.command.PreviousArguments;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
+import de.steamwar.core.SWPlayer;
import de.steamwar.data.CMDs;
import de.steamwar.inventory.SWAnvilInv;
import de.steamwar.inventory.SWInventory;
@@ -56,11 +57,9 @@ public class MaterialCommand extends SWCommand implements Listener {
WorldEditListener.addCommandExclusion("material");
}
- private Map searchMap = new HashMap<>();
-
@Getter
@Setter
- static class Search {
+ public class SearchParameter implements SWPlayer.Component {
SearchType transparent = SearchType.IGNORE;
SearchType solid = SearchType.IGNORE;
SearchType gravity = SearchType.IGNORE;
@@ -104,10 +103,10 @@ public class MaterialCommand extends SWCommand implements Listener {
@Register
public void materialGUI(Player p) {
- materialGUI(p, searchMap.get(p));
+ materialGUI(p, SWPlayer.of(p).getComponentOrDefault(SearchParameter.class, SearchParameter::new));
}
- private static final Map> elements = new HashMap<>();
+ private static final Map> elements = new HashMap<>();
static {
elements.put("-transparent", (search, searchType) -> search.transparent = searchType);
elements.put("-solid", (search, searchType) -> search.solid = searchType);
@@ -122,15 +121,15 @@ public class MaterialCommand extends SWCommand implements Listener {
@Register
public void search(Player p, @Mapper("search") String... searches) {
- Search search = new Search();
+ SearchParameter searchParameter = SWPlayer.of(p).getComponentOrDefault(SearchParameter.class, SearchParameter::new);
for (String s : searches) {
boolean has = false;
- for (Map.Entry> element: elements.entrySet()) {
+ for (Map.Entry> element: elements.entrySet()) {
if (s.startsWith(element.getKey() + ":")) {
- element.getValue().accept(search, SearchType.valueOf(s.substring(element.getKey().length() + 1).toUpperCase()));
+ element.getValue().accept(searchParameter, SearchType.valueOf(s.substring(element.getKey().length() + 1).toUpperCase()));
has = true;
} else if (s.startsWith(element.getKey().substring(0, 2) + ":")) {
- element.getValue().accept(search, SearchType.valueOf(s.substring(element.getKey().substring(0, 2).length() + 1).toUpperCase()));
+ element.getValue().accept(searchParameter, SearchType.valueOf(s.substring(element.getKey().substring(0, 2).length() + 1).toUpperCase()));
has = true;
}
if (has) break;
@@ -141,15 +140,15 @@ public class MaterialCommand extends SWCommand implements Listener {
case "-blastresistance:":
s = s.substring(s.indexOf(':') + 1).replace('_', ' ');
if (s.isEmpty() || s.matches("((([><]=?)|!|=)\\d+(\\.|,\\d+)?)( ((([><]=?)|!|=)\\d+(\\.|,\\d+)?))*")) {
- search.blastResistance = s;
+ searchParameter.blastResistance = s;
}
break;
default:
- search.name = s;
+ searchParameter.name = s;
break;
}
}
- materialGUI(p, search);
+ materialGUI(p, searchParameter);
}
@Mapper(value = "search", local = true)
@@ -182,7 +181,7 @@ public class MaterialCommand extends SWCommand implements Listener {
};
}
- public void materialGUI(Player p, Search search) {
+ public void materialGUI(Player p, SearchParameter search) {
List> swListEntries = new ArrayList<>();
MaterialLazyInit.materialData.forEach(data -> {
if (data.is(search)) {
@@ -202,59 +201,59 @@ public class MaterialCommand extends SWCommand implements Listener {
private void searchGUI(Player p) {
SWInventory swInventory = new SWInventory(p, 54, BauSystem.MESSAGE.parse("MATERIAL_SEARCH", p));
- Search search = searchMap.get(p);
+ SearchParameter searchParameter = SWPlayer.of(p).getComponentOrDefault(SearchParameter.class, SearchParameter::new);
swInventory.setItem(0, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("MATERIAL_BACK", p), clickType -> {
materialGUI(p);
}).setCustomModelData(CMDs.BACK));
- swInventory.setItem(10, new SWItem(Material.NAME_TAG, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_NAME", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, search.name), clickType -> {
- SWAnvilInv swAnvilInv = new SWAnvilInv(p, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_NAME", p), search.name);
+ swInventory.setItem(10, new SWItem(Material.NAME_TAG, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_NAME", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, searchParameter.name), clickType -> {
+ SWAnvilInv swAnvilInv = new SWAnvilInv(p, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_NAME", p), searchParameter.name);
swAnvilInv.setCallback(s -> {
- search.name = s;
+ searchParameter.name = s;
searchGUI(p);
});
swAnvilInv.open();
}));
- swInventory.setItem(19, new SWItem(Material.GLASS, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_TRANSPARENT", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(search.transparent.getChatValue(), p)), clickType -> {
- search.transparent = search.transparent.next();
+ swInventory.setItem(19, new SWItem(Material.GLASS, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_TRANSPARENT", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(searchParameter.transparent.getChatValue(), p)), clickType -> {
+ searchParameter.transparent = searchParameter.transparent.next();
searchGUI(p);
}));
- swInventory.setItem(20, new SWItem(Material.BRICK, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_SOLID", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(search.solid.getChatValue(), p)), clickType -> {
- search.solid = search.solid.next();
+ swInventory.setItem(20, new SWItem(Material.BRICK, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_SOLID", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(searchParameter.solid.getChatValue(), p)), clickType -> {
+ searchParameter.solid = searchParameter.solid.next();
searchGUI(p);
}));
- swInventory.setItem(21, new SWItem(Material.BLACK_CONCRETE_POWDER, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_GRAVITY", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(search.gravity.getChatValue(), p)), clickType -> {
- search.gravity = search.gravity.next();
+ swInventory.setItem(21, new SWItem(Material.BLACK_CONCRETE_POWDER, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_GRAVITY", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(searchParameter.gravity.getChatValue(), p)), clickType -> {
+ searchParameter.gravity = searchParameter.gravity.next();
searchGUI(p);
}));
- swInventory.setItem(22, new SWItem(Material.BIRCH_LOG, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_OCCLUDING", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(search.occluding.getChatValue(), p)), clickType -> {
- search.occluding = search.occluding.next();
+ swInventory.setItem(22, new SWItem(Material.BIRCH_LOG, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_OCCLUDING", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(searchParameter.occluding.getChatValue(), p)), clickType -> {
+ searchParameter.occluding = searchParameter.occluding.next();
searchGUI(p);
}));
- swInventory.setItem(23, new SWItem(Material.OAK_BUTTON, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_INTERACTEABLE", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(search.interacteable.getChatValue(), p)), clickType -> {
- search.interacteable = search.interacteable.next();
+ swInventory.setItem(23, new SWItem(Material.OAK_BUTTON, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_INTERACTEABLE", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(searchParameter.interacteable.getChatValue(), p)), clickType -> {
+ searchParameter.interacteable = searchParameter.interacteable.next();
searchGUI(p);
}));
- swInventory.setItem(24, new SWItem(Material.FLINT_AND_STEEL, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_FLAMMABLE", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(search.flammable.getChatValue(), p)), clickType -> {
- search.flammable = search.flammable.next();
+ swInventory.setItem(24, new SWItem(Material.FLINT_AND_STEEL, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_FLAMMABLE", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(searchParameter.flammable.getChatValue(), p)), clickType -> {
+ searchParameter.flammable = searchParameter.flammable.next();
searchGUI(p);
}));
- swInventory.setItem(25, new SWItem(Material.LAVA_BUCKET, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_BURNABLE", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(search.burnable.getChatValue(), p)), clickType -> {
- search.burnable = search.burnable.next();
+ swInventory.setItem(25, new SWItem(Material.LAVA_BUCKET, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_BURNABLE", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(searchParameter.burnable.getChatValue(), p)), clickType -> {
+ searchParameter.burnable = searchParameter.burnable.next();
searchGUI(p);
}));
- swInventory.setItem(28, new SWItem(Material.WATER_BUCKET, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_WATERLOGGABLE", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(search.waterloggable.getChatValue(), p)), clickType -> {
- search.waterloggable = search.waterloggable.next();
+ swInventory.setItem(28, new SWItem(Material.WATER_BUCKET, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_WATERLOGGABLE", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(searchParameter.waterloggable.getChatValue(), p)), clickType -> {
+ searchParameter.waterloggable = searchParameter.waterloggable.next();
searchGUI(p);
}));
- swInventory.setItem(29, new SWItem(Material.PISTON, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_UNMOVEABLE", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(search.unmoveable.getChatValue(), p)), clickType -> {
- search.unmoveable = search.unmoveable.next();
+ swInventory.setItem(29, new SWItem(Material.PISTON, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_UNMOVEABLE", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, BauSystem.MESSAGE.parse(searchParameter.unmoveable.getChatValue(), p)), clickType -> {
+ searchParameter.unmoveable = searchParameter.unmoveable.next();
searchGUI(p);
}));
- swInventory.setItem(34, new SWItem(Material.NETHER_BRICK, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_BLASTRESISTANCE", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, search.blastResistance), clickType -> {
- SWAnvilInv swAnvilInv = new SWAnvilInv(p, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_BLASTRESISTANCE", p), search.blastResistance);
+ swInventory.setItem(34, new SWItem(Material.NETHER_BRICK, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_BLASTRESISTANCE", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, searchParameter.blastResistance), clickType -> {
+ SWAnvilInv swAnvilInv = new SWAnvilInv(p, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_BLASTRESISTANCE", p), searchParameter.blastResistance);
swAnvilInv.setCallback(s -> {
if (s.isEmpty() || s.matches("((([><]=?)|!|=)\\d+(\\.|,\\d+)?)( ((([><]=?)|!|=)\\d+(\\.|,\\d+)?))*")) {
- search.blastResistance = s;
+ searchParameter.blastResistance = s;
}
searchGUI(p);
});
@@ -262,14 +261,4 @@ public class MaterialCommand extends SWCommand implements Listener {
}));
swInventory.open();
}
-
- @EventHandler
- public void onPlayerJoin(PlayerJoinEvent event) {
- searchMap.put(event.getPlayer(), new Search());
- }
-
- @EventHandler
- public void onPlayerQuit(PlayerQuitEvent event) {
- searchMap.remove(event.getPlayer());
- }
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/MaterialLazyInit.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/MaterialLazyInit.java
index 4f174c12..02ffc609 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/MaterialLazyInit.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/MaterialLazyInit.java
@@ -133,7 +133,7 @@ public class MaterialLazyInit {
}), originalMaterial);
}
- public boolean is(MaterialCommand.Search search) {
+ public boolean is(MaterialCommand.SearchParameter search) {
boolean result = true;
result &= search.transparent.test(transparent);
result &= search.solid.test(solid);
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/NoClipCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/NoClipCommand.java
index ad97dac0..61fdecdc 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/NoClipCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/NoClipCommand.java
@@ -19,17 +19,17 @@
package de.steamwar.bausystem.features.util;
-import de.steamwar.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;
import com.mojang.authlib.GameProfile;
+import de.steamwar.Reflection;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
import de.steamwar.bausystem.utils.NMSWrapper;
import de.steamwar.command.SWCommand;
import de.steamwar.core.ProtocolWrapper;
+import de.steamwar.core.SWPlayer;
import de.steamwar.linkage.Linked;
-import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
@@ -40,10 +40,6 @@ import org.bukkit.event.player.PlayerGameModeChangeEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerToggleFlightEvent;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
import java.util.function.BiFunction;
@Linked
@@ -59,29 +55,34 @@ public class NoClipCommand extends SWCommand implements Listener {
private static final Class> windowClick = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundContainerClickPacket");
private static final Class> setSlotStack = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundSetCreativeModeSlotPacket");
- @Getter
- private static final List NOCLIPS = new ArrayList<>();
- private static final Map LAST_TICKS = new HashMap<>();
+ public static class NoClipData implements SWPlayer.Component {
+ private long lastTick = -1;
+
+ @Override
+ public void onUnmount(SWPlayer player) {
+ player.setGameMode(GameMode.CREATIVE);
+ }
+ }
public NoClipCommand() {
super("noclip", "nc");
BiFunction first = (player, o) -> {
- if (NOCLIPS.contains(player)) {
- if (LAST_TICKS.getOrDefault(player, -1L).equals(TPSUtils.currentTick.get())) return o;
- NMSWrapper.impl.setInternalGameMode(player, GameMode.SPECTATOR);
- LAST_TICKS.put(player, TPSUtils.currentTick.get());
- }
+ NoClipData noClipData = SWPlayer.of(player).getComponent(NoClipData.class).orElse(null);
+ if (noClipData == null) return o;
+ if (noClipData.lastTick == TPSUtils.currentTick.get()) return o;
+ NMSWrapper.impl.setInternalGameMode(player, GameMode.SPECTATOR);
+ noClipData.lastTick = TPSUtils.currentTick.get();
return o;
};
TinyProtocol.instance.addFilter(position, first);
TinyProtocol.instance.addFilter(positionLook, first);
BiFunction second = (player, o) -> {
- if (NOCLIPS.contains(player)) {
- NMSWrapper.impl.setInternalGameMode(player, GameMode.CREATIVE);
- LAST_TICKS.put(player, TPSUtils.currentTick.get());
- }
+ NoClipData noClipData = SWPlayer.of(player).getComponent(NoClipData.class).orElse(null);
+ if (noClipData == null) return o;
+ NMSWrapper.impl.setInternalGameMode(player, GameMode.CREATIVE);
+ noClipData.lastTick = TPSUtils.currentTick.get();
return o;
};
TinyProtocol.instance.addFilter(useItem, second);
@@ -89,7 +90,7 @@ public class NoClipCommand extends SWCommand implements Listener {
TinyProtocol.instance.addFilter(windowClick, second);
BiFunction third = (player, o) -> {
- if (NOCLIPS.contains(player)) {
+ if (SWPlayer.of(player).hasComponent(NoClipData.class)) {
NMSWrapper.impl.setSlotToItemStack(player, o);
}
return o;
@@ -99,9 +100,9 @@ public class NoClipCommand extends SWCommand implements Listener {
@Register(help = true)
public void genericCommand(@Validator Player player) {
- if (NOCLIPS.contains(player)) {
- NOCLIPS.remove(player);
- player.setGameMode(GameMode.CREATIVE);
+ SWPlayer swPlayer = SWPlayer.of(player);
+ if (swPlayer.hasComponent(NoClipData.class)) {
+ swPlayer.removeComponent(NoClipData.class);
} else {
player.setGameMode(GameMode.SPECTATOR);
NMSWrapper.impl.setPlayerBuildAbilities(player);
@@ -109,8 +110,8 @@ public class NoClipCommand extends SWCommand implements Listener {
Object gameStateChangeObject = Reflection.newInstance(gameStateChange);
NMSWrapper.impl.setGameStateChangeReason(gameStateChangeObject);
floatFieldAccessor.set(gameStateChangeObject, 1F);
-
- NOCLIPS.add(player);
+
+ swPlayer.setComponent(new NoClipData());
BauSystem.MESSAGE.send("OTHER_NOCLIP_SLOT_INFO", player);
TinyProtocol.instance.sendPacket(player, gameStateChangeObject);
pseudoGameMode(player, GameMode.SPECTATOR);
@@ -120,30 +121,27 @@ public class NoClipCommand extends SWCommand implements Listener {
@EventHandler
public void onBauMemberUpdate(BauMemberUpdateEvent event) {
event.getNewSpectator().forEach(player -> {
- if (NOCLIPS.contains(player)) {
- NOCLIPS.remove(player);
- player.setGameMode(GameMode.CREATIVE);
- }
+ SWPlayer.of(player).removeComponent(NoClipData.class);
});
}
@EventHandler(ignoreCancelled = true)
public void onPlayerGameModeChange(PlayerGameModeChangeEvent event) {
- if (NOCLIPS.contains(event.getPlayer())) {
+ if (SWPlayer.of(event.getPlayer()).hasComponent(NoClipData.class)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true)
public void onBlock(BlockCanBuildEvent event) {
- if (NOCLIPS.contains(event.getPlayer())) {
+ if (SWPlayer.of(event.getPlayer()).hasComponent(NoClipData.class)) {
event.setBuildable(true);
}
}
@EventHandler(ignoreCancelled = true)
public void onPlayerToggleFlight(PlayerToggleFlightEvent event) {
- if (NOCLIPS.contains(event.getPlayer())) {
+ if (SWPlayer.of(event.getPlayer()).hasComponent(NoClipData.class)) {
event.setCancelled(true);
event.getPlayer().setFlying(true);
}
@@ -154,7 +152,7 @@ public class NoClipCommand extends SWCommand implements Listener {
if (event.getCause() != PlayerTeleportEvent.TeleportCause.SPECTATE) {
return;
}
- if (NOCLIPS.contains(event.getPlayer())) {
+ if (SWPlayer.of(event.getPlayer()).hasComponent(NoClipData.class)) {
event.setCancelled(true);
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
event.getPlayer().setSpectatorTarget(null);
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/items/SelectBauGuiItem.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/items/SelectBauGuiItem.java
index 78669a8d..43b9cb85 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/items/SelectBauGuiItem.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/items/SelectBauGuiItem.java
@@ -24,6 +24,7 @@ import de.steamwar.bausystem.Permission;
import de.steamwar.bausystem.linkage.BauGuiItem;
import de.steamwar.bausystem.region.utils.RegionExtensionType;
import de.steamwar.bausystem.region.utils.RegionType;
+import de.steamwar.core.SWPlayer;
import de.steamwar.inventory.SWInventory;
import de.steamwar.inventory.SWItem;
import de.steamwar.linkage.Linked;
@@ -35,15 +36,11 @@ import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.Locale;
-import java.util.Map;
@Linked
public class SelectBauGuiItem extends BauGuiItem {
- private static final Map LAST_SELECT_MAP = new HashMap<>();
-
public SelectBauGuiItem() {
super(13);
}
@@ -58,13 +55,13 @@ public class SelectBauGuiItem extends BauGuiItem {
private static void selectFinish(Player p, RegionType type, RegionExtensionType extensionType) {
p.closeInventory();
- LAST_SELECT_MAP.put(p, new LastSelect(type, extensionType));
+ SWPlayer.of(p).setComponent(new LastSelect(type, extensionType));
p.performCommand("select " + type.name() + " " + extensionType.toString());
}
@Override
public ItemStack getItem(Player player) {
- LastSelect last = LAST_SELECT_MAP.getOrDefault(player, new LastSelect(RegionType.BUILD, RegionExtensionType.NORMAL));
+ LastSelect last = SWPlayer.of(player).getComponentOrDefault(LastSelect.class, () -> new LastSelect(RegionType.BUILD, RegionExtensionType.NORMAL));
return new SWItem(Material.SCAFFOLDING, BauSystem.MESSAGE.parse("SELECT_ITEM_SELECT", player), Arrays.asList(BauSystem.MESSAGE.parse("SELECT_ITEM_AUSWAHL", player, BauSystem.MESSAGE.parse(last.type.getChatValue(), player), last.extensionType.name()), BauSystem.MESSAGE.parse("SELECT_ITEM_RIGHT_CLICK", player)), false, clickType -> {
}).getItemStack();
}
@@ -80,7 +77,7 @@ public class SelectBauGuiItem extends BauGuiItem {
inv.open();
} else {
p.closeInventory();
- LastSelect last = LAST_SELECT_MAP.getOrDefault(p, new LastSelect(RegionType.BUILD, RegionExtensionType.NORMAL));
+ LastSelect last = SWPlayer.of(p).getComponentOrDefault(LastSelect.class, () -> new LastSelect(RegionType.BUILD, RegionExtensionType.NORMAL));
p.performCommand("select " + last.getType().name() + " " + last.getExtensionType().toString());
}
return false;
@@ -92,7 +89,7 @@ public class SelectBauGuiItem extends BauGuiItem {
}
@AllArgsConstructor
- private static class LastSelect {
+ private static class LastSelect implements SWPlayer.Component {
@Getter
private final RegionType type;
@Getter
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/warp/WarpListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/warp/WarpListener.java
index 60121c90..f57ff726 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/warp/WarpListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/warp/WarpListener.java
@@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.warp;
import de.steamwar.bausystem.region.Region;
import de.steamwar.core.Core;
+import de.steamwar.core.SWPlayer;
import de.steamwar.entity.RArmorStand;
import de.steamwar.entity.REntityServer;
import de.steamwar.linkage.Linked;
@@ -30,7 +31,10 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
-import org.bukkit.event.player.*;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerItemHeldEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.event.player.PlayerToggleSneakEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
@@ -42,8 +46,21 @@ import java.util.Map;
@Linked
public class WarpListener implements Listener {
- private Map warpEntityServer = new HashMap<>();
- private Map> selected = new HashMap<>();
+ public static class WarpComponent implements SWPlayer.Component {
+ private REntityServer server;
+ private List selected = new ArrayList<>();
+
+ @Override
+ public void onMount(SWPlayer player) {
+ server = new REntityServer();
+ server.addPlayer(player.getPlayer());
+ }
+
+ @Override
+ public void onUnmount(SWPlayer player) {
+ server.close();
+ }
+ }
@EventHandler
public void onPlayerItemHeld(PlayerItemHeldEvent e) {
@@ -65,20 +82,11 @@ public class WarpListener implements Listener {
}
private void reshow(Player p, Material material, boolean sneaking) {
- REntityServer entityServer = warpEntityServer.get(p);
- if (entityServer != null) {
- entityServer.close();
- }
- if (material != Material.COMPASS) {
- warpEntityServer.remove(p);
- return;
- }
-
- selected.remove(p);
- entityServer = new REntityServer();
- entityServer.addPlayer(p);
- warpEntityServer.put(p, entityServer);
+ SWPlayer swPlayer = SWPlayer.of(p);
+ swPlayer.removeComponent(WarpComponent.class);
+ if (material != Material.COMPASS) return;
+ WarpComponent warpComponent = swPlayer.getComponentOrDefault(WarpComponent.class, WarpComponent::new);
Vector current = p.getLocation().clone().add(p.getLocation().getDirection().multiply(5)).toVector();
Map locations = new HashMap<>();
@@ -99,12 +107,9 @@ public class WarpListener implements Listener {
}
}
- REntityServer finalEntityServer = entityServer;
locations.forEach((name, location) -> {
Vector vector = location.toVector().subtract(p.getLocation().toVector());
- if (vector.getX() * vector.getX() + vector.getZ() * vector.getZ() < 25) {
- return;
- }
+ if (vector.getX() * vector.getX() + vector.getZ() * vector.getZ() < 25) return;
vector.setY(0);
Vector position = p.getLocation().toVector().clone().add(vector.normalize().multiply(5));
@@ -112,9 +117,9 @@ public class WarpListener implements Listener {
if ((position.getX() - current.getX()) * (position.getX() - current.getX()) + (position.getZ() - current.getZ()) * (position.getZ() - current.getZ()) < 0.1) {
name = "§a§l" + name;
- selected.computeIfAbsent(p, player -> new ArrayList<>()).add(location);
+ warpComponent.selected.add(location);
}
- RArmorStand armorStand = new RArmorStand(finalEntityServer, position.toLocation(p.getWorld()), RArmorStand.Size.MARKER);
+ RArmorStand armorStand = new RArmorStand(warpComponent.server, position.toLocation(p.getWorld()), RArmorStand.Size.MARKER);
armorStand.setDisplayName(name);
armorStand.setNoGravity(true);
armorStand.setInvisible(true);
@@ -123,28 +128,13 @@ public class WarpListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerInteract(PlayerInteractEvent event) {
- if (event.getPlayer().getInventory().getItemInMainHand().getType() != Material.COMPASS) {
- return;
- }
- if (event.getAction() != Action.RIGHT_CLICK_AIR) {
- return;
- }
- List locations = selected.getOrDefault(event.getPlayer(), new ArrayList<>());
- if (locations.size() != 1) {
- return;
- }
- Location location = locations.get(0);
+ if (event.getPlayer().getInventory().getItemInMainHand().getType() != Material.COMPASS) return;
+ if (event.getAction() != Action.RIGHT_CLICK_AIR) return;
+ WarpComponent warpComponent = SWPlayer.of(event.getPlayer()).getComponent(WarpComponent.class).orElse(null);
+ if (warpComponent == null || warpComponent.selected.size() != 1) return;
+ Location location = warpComponent.selected.get(0);
event.getPlayer().teleport(location);
event.getPlayer().playSound(location, Sound.ENTITY_ENDERMAN_TELEPORT, SoundCategory.PLAYERS, 1, 1);
event.setCancelled(true);
}
-
- @EventHandler
- public void onPlayerQuit(PlayerQuitEvent event) {
- warpEntityServer.computeIfPresent(event.getPlayer(), (player, rEntityServer) -> {
- rEntityServer.close();
- return null;
- });
- selected.remove(event.getPlayer());
- }
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/AntiBauAddMemberFix.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/AntiBauAddMemberFix.java
index c8c40cba..da75fe7c 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/AntiBauAddMemberFix.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/AntiBauAddMemberFix.java
@@ -41,7 +41,7 @@ public class AntiBauAddMemberFix implements Listener {
}
if (BauweltMember.getBauMember(BauServer.getInstance().getOwner(), event.getPlayer().getUniqueId()) == null) {
event.getPlayer().kickPlayer("");
- throw new SecurityException("The player " + event.getPlayer().getName() + " joined on the server of " + SteamwarUser.get(BauServer.getInstance().getOwnerID()).getUserName() + " without being added!");
+ throw new SecurityException("The player " + event.getPlayer().getName() + " joined on the server of " + SteamwarUser.byId(BauServer.getInstance().getOwnerID()).getUserName() + " without being added!");
}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/BauMemberUpdate.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/BauMemberUpdate.java
index a60e2958..1568ba5f 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/BauMemberUpdate.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/BauMemberUpdate.java
@@ -59,18 +59,14 @@ public class BauMemberUpdate extends PacketHandler implements Listener {
Set newSpectator = new HashSet<>();
Set newBuilder = new HashSet<>();
Bukkit.getOnlinePlayers().forEach(player -> {
- if (Permission.REAL_SPECTATOR.hasPermission(player)) {
+ if (Permission.SPECTATOR.hasPermission(player)) {
if (!SPECTATORS.contains(player)) {
SPECTATORS.add(player);
- Permission.removeForceOnlySpectator(player);
newSpectator.add(player);
player.addPotionEffect(new PotionEffect(PotionEffectType.GLOWING, -1, 1, false,false, false));
showSpectatorNotice(player);
}
} else {
- if (Permission.SUPERVISOR.hasPermission(player)) {
- Permission.removeForceOnlySpectator(player);
- }
if (SPECTATORS.contains(player)) {
SPECTATORS.remove(player);
newBuilder.add(player);
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/OtherTNTListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/OtherTNTListener.java
deleted file mode 100644
index 4deb1e5d..00000000
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/OtherTNTListener.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.bausystem.features.world;
-
-import de.steamwar.linkage.Linked;
-import org.bukkit.Material;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.Listener;
-import org.bukkit.event.entity.EntityExplodeEvent;
-
-@Linked
-public class OtherTNTListener implements Listener {
-
- @EventHandler(priority = EventPriority.MONITOR)
- public void onExplosion(EntityExplodeEvent e) {
- e.blockList().removeIf(block -> {
- if(block.getType() == Material.TNT) {
- return false;
- } else {
- block.setType(Material.AIR);
- return true;
- }
- });
- }
-}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java
index 9874c1fd..cfdc6fe3 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java
@@ -49,6 +49,7 @@ import java.util.Set;
@Linked
public class SpectatorListener implements Listener {
+ private static final TechHider techHider;
private static final Set NO_TECHHIDER = new HashSet<>();
static {
@@ -100,10 +101,20 @@ public class SpectatorListener implements Listener {
materials.add(Material.WATER);
materials.remove(Material.BARRIER);
materials.remove(Material.STONE);
- TechHider techHider = new TechHider((TechHider.LocationEvaluator) (player, i, i1) -> {
- return Permission.BUILD.hasPermission(player) || Permission.isTempOnlySpectator(player) || NO_TECHHIDER.contains(player);
+ techHider = new TechHider((TechHider.LocationEvaluator) (player, i, i1) -> {
+ return Permission.BUILD.hasPermission(player) || NO_TECHHIDER.contains(player);
}, Material.END_STONE, materials, new HashSet<>());
- techHider.enable();
+ }
+
+ private static void enableOrDisableTechhider() {
+ boolean enable = Bukkit.getOnlinePlayers()
+ .stream()
+ .anyMatch(player -> !(Permission.BUILD.hasPermission(player) || NO_TECHHIDER.contains(player)));
+ if (enable) {
+ techHider.enable();
+ } else {
+ techHider.disable();
+ }
}
public static void toggleNoTechHider(Player player) {
@@ -113,6 +124,7 @@ public class SpectatorListener implements Listener {
NO_TECHHIDER.add(player);
}
resendChunks(player);
+ enableOrDisableTechhider();
}
private static void resendChunks(Player player) {
@@ -131,6 +143,7 @@ public class SpectatorListener implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
+ enableOrDisableTechhider();
if (BauSystem.DEV_SERVER) return;
if (event.getPlayer().getUniqueId().equals(BauServer.getInstance().getOwner())) {
return;
@@ -152,6 +165,7 @@ public class SpectatorListener implements Listener {
@EventHandler
public void onBauMemberUpdate(BauMemberUpdateEvent event) {
+ enableOrDisableTechhider();
if (!anySupervisorOnline(null) && !BauSystem.DEV_SERVER) {
Bukkit.getOnlinePlayers().forEach(player -> {
player.kickPlayer("");
@@ -161,7 +175,6 @@ public class SpectatorListener implements Listener {
event.getChanged().forEach(player -> {
NO_TECHHIDER.remove(player);
- if (Permission.isTempOnlySpectator(player)) return;
resendChunks(player);
});
}
@@ -169,6 +182,7 @@ public class SpectatorListener implements Listener {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
NO_TECHHIDER.remove(event.getPlayer());
+ Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), SpectatorListener::enableOrDisableTechhider, 1);
if (BauSystem.DEV_SERVER) return;
if (!anySupervisorOnline(event.getPlayer())) {
Bukkit.getOnlinePlayers().forEach(player -> {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/worldedit/SelectAdjacent.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/worldedit/SelectAdjacent.java
index 518ca00c..3f6ca8f2 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/worldedit/SelectAdjacent.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/worldedit/SelectAdjacent.java
@@ -23,6 +23,7 @@ import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.region.Point;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.utils.FlatteningWrapper;
+import de.steamwar.core.SWPlayer;
import de.steamwar.core.WorldEditRenderer;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.MinVersion;
@@ -35,13 +36,10 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
-import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.Vector;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
@@ -71,32 +69,23 @@ public class SelectAdjacent implements Listener {
new Vector(0, -1, -1),
};
- private Map selectors = new HashMap<>();
-
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if (!event.hasItem()) return;
if (event.getItem().getType() != Material.WOODEN_AXE) return;
- Selector selector = selectors.get(event.getPlayer());
- if (selector != null) selector.cancel();
if (!event.getPlayer().isSneaking()) return;
if (event.getAction() != Action.LEFT_CLICK_BLOCK) return;
Material material = event.getPlayer().getInventory().getItemInOffHand().getType();
+ Selector selector;
if (material.isAir()) {
selector = new Selector(event.getClickedBlock(), event.getPlayer(), __ -> true);
} else {
selector = new Selector(event.getClickedBlock(), event.getPlayer(), type -> type == material);
}
- selectors.put(event.getPlayer(), selector);
+ SWPlayer.of(event.getPlayer()).setComponent(selector);
}
- @EventHandler
- public void onPlayerQuit(PlayerQuitEvent event) {
- Selector selector = selectors.remove(event.getPlayer());
- if (selector != null) selector.cancel();
- }
-
- private class Selector {
+ private class Selector implements SWPlayer.Component {
private static final int MAX_BLOCKS = 500_000;
@@ -154,6 +143,7 @@ public class SelectAdjacent implements Listener {
if (toCalc.isEmpty() || seen.size() > MAX_BLOCKS) {
bukkitTask.cancel();
player.sendTitle("§aDone", "§e" + volume + " §7Blocks", 0, 20, 5);
+ SWPlayer.of(player).removeComponent(Selector.class);
}
}, 1, 1);
}
@@ -190,5 +180,10 @@ public class SelectAdjacent implements Listener {
}
}
}
+
+ @Override
+ public void onUnmount(SWPlayer player) {
+ cancel();
+ }
}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/xray/XrayCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/xray/XrayCommand.java
index babd0d88..b128e27a 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/xray/XrayCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/xray/XrayCommand.java
@@ -104,7 +104,7 @@ public class XrayCommand extends SWCommand implements Listener, ScoreboardElemen
if (hidden.containsKey(region) && hidden.get(region).contains(player)) {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
PlayerMovementWrapper.impl.setPosition(player, o);
- }, 1L);
+ }, 0);
return null;
}
return o;
diff --git a/BauSystem/build.gradle.kts b/BauSystem/build.gradle.kts
index aeade561..df33b12e 100644
--- a/BauSystem/build.gradle.kts
+++ b/BauSystem/build.gradle.kts
@@ -50,5 +50,6 @@ tasks.register("DevBau21") {
description = "Run a 1.21 Dev Bau"
dependsOn(":SpigotCore:shadowJar")
dependsOn(":BauSystem:shadowJar")
+ dependsOn(":SchematicSystem:shadowJar")
template = "Bau21"
}
diff --git a/CommonCore/SQL/build.gradle.kts b/CommonCore/SQL/build.gradle.kts
index dc171dde..09528759 100644
--- a/CommonCore/SQL/build.gradle.kts
+++ b/CommonCore/SQL/build.gradle.kts
@@ -18,11 +18,26 @@
*/
plugins {
- steamwar.java
+ steamwar.kotlin
+}
+
+kotlin {
+ jvmToolchain(8)
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
}
dependencies {
compileOnly(libs.sqlite)
implementation("org.yaml:snakeyaml:2.2")
-}
\ No newline at end of file
+
+ compileOnlyApi("org.jetbrains.kotlin:kotlin-stdlib:2.2.21")
+ compileOnlyApi(libs.exposedCore)
+ compileOnlyApi(libs.exposedDao)
+ compileOnlyApi(libs.exposedJdbc)
+ compileOnlyApi(libs.exposedTime)
+}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/AuditLog.java b/CommonCore/SQL/src/de/steamwar/sql/AuditLog.java
deleted file mode 100644
index 04f87d9d..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/AuditLog.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SqlTypeMapper;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NonNull;
-
-import java.sql.Timestamp;
-import java.time.Instant;
-
-@AllArgsConstructor
-public class AuditLog {
-
- static {
- SqlTypeMapper.nameEnumMapper(AuditLog.Type.class);
- }
-
- public static final String SERVER_NAME_VELOCITY = "Velocity";
-
- private static final Table table = new Table<>(AuditLog.class);
-
- private static final Statement create = table.insertFields(true, "time", "serverName", "serverOwner", "actor", "actionType", "actionText");
-
- @Getter
- @Field
- private final Timestamp time;
-
- @Getter
- @Field
- private final String serverName;
-
- @Field(nullable = true)
- private final int serverOwner;
-
- @Field
- private final int actor;
-
- @Getter
- @Field
- private final Type actionType;
-
- @Getter
- @Field
- private final String actionText;
-
- public enum Type {
- JOIN,
- LEAVE,
- COMMAND,
- SENSITIVE_COMMAND,
-
- CHAT,
- GUI_OPEN,
- GUI_CLOSE,
- GUI_CLICK,
- }
-
- private static void create(String serverName, SteamwarUser serverOwner, SteamwarUser actor, Type actionType, String text) {
- create.insertGetKey(Timestamp.from(Instant.now()), serverName, serverOwner, actor, actionType, text);
- }
-
- public static void createJoin(@NonNull String jointServerName, SteamwarUser serverOwner, @NonNull SteamwarUser joinedPlayer) {
- create(jointServerName, serverOwner, joinedPlayer, Type.JOIN, "");
- }
-
- public static void createLeave(@NonNull String leftServerName, SteamwarUser serverOwner, @NonNull SteamwarUser joinedPlayer) {
- create(leftServerName, serverOwner, joinedPlayer, Type.LEAVE, "");
- }
-
- public static void createCommand(@NonNull String serverName, SteamwarUser serverOwner, SteamwarUser player, @NonNull String command) {
- if (player == null) return;
- create(serverName, serverOwner, player, Type.COMMAND, command);
- }
-
- public static void createSensitiveCommand(@NonNull String serverName, SteamwarUser serverOwner, SteamwarUser player, @NonNull String command) {
- if (player == null) return;
- create(serverName, serverOwner, player, Type.SENSITIVE_COMMAND, command);
- }
-
- public static void createChat(@NonNull String serverName, SteamwarUser serverOwner, @NonNull SteamwarUser chatter, @NonNull String chat) {
- create(serverName, serverOwner, chatter, Type.CHAT, chat);
- }
-
- public static void createGuiOpen(@NonNull String serverName, SteamwarUser serverOwner, @NonNull SteamwarUser player, @NonNull String guiName) {
- create(serverName, serverOwner, player, Type.GUI_OPEN, guiName);
- }
-
- public static void createGuiClick(@NonNull String serverName, SteamwarUser serverOwner, @NonNull SteamwarUser player, @NonNull String guiName, @NonNull String clickType, int slot, @NonNull String itemName) {
- create(serverName, serverOwner, player, Type.GUI_CLICK, "Gui: " + guiName + "\nSlot: " + slot + "\nClickType: " + clickType + "\nItemName: " + itemName);
- }
-
- public static void createGuiClose(@NonNull String serverName, SteamwarUser serverOwner, @NonNull SteamwarUser player, @NonNull String guiName) {
- create(serverName, serverOwner, player, Type.GUI_CLOSE, guiName);
- }
-
- public SteamwarUser getServerOwner() {
- return SteamwarUser.get(serverOwner);
- }
-
- public SteamwarUser getActor() {
- return SteamwarUser.get(actor);
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/AuditLog.kt b/CommonCore/SQL/src/de/steamwar/sql/AuditLog.kt
new file mode 100644
index 00000000..7ab0c8c4
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/AuditLog.kt
@@ -0,0 +1,121 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
+import org.jetbrains.exposed.v1.dao.IntEntity
+import org.jetbrains.exposed.v1.dao.IntEntityClass
+import org.jetbrains.exposed.v1.javatime.timestamp
+import java.time.Instant
+
+object AuditLogTable: IntIdTable("AuditLog", "AuditLogId") {
+ val time = timestamp("Time")
+ val server = varchar("ServerName", 255)
+ val serverOwner = reference("ServerOwner", SteamwarUserTable).nullable()
+ val actor = reference("Actor", SteamwarUserTable)
+ val action = enumerationByName("ActionType", 255, AuditLog.Type::class)
+ val actionText = text("ActionText")
+}
+
+class AuditLog(id: EntityID): IntEntity(id) {
+ companion object: IntEntityClass(AuditLogTable) {
+ const val SERVER_NAME_VELOCITY: String = "Velocity"
+
+ private fun create(
+ serverName: String,
+ serverOwner: SteamwarUser?,
+ actor: SteamwarUser,
+ actionType: Type,
+ text: String = ""
+ ) = useDb {
+ new {
+ this.time = Instant.now()
+ this.server = serverName
+ this.serverOwner = serverOwner?.id
+ this.actor = actor.id
+ this.action = actionType
+ this.actionText = text
+ }
+ }
+
+ @JvmStatic
+ fun createJoin(jointServerName: String, serverOwner: SteamwarUser?, joinedPlayer: SteamwarUser) = create(jointServerName, serverOwner, joinedPlayer, Type.JOIN)
+
+ @JvmStatic
+ fun createLeave(leftServerName: String, serverOwner: SteamwarUser?, joinedPlayer: SteamwarUser) = create(leftServerName, serverOwner, joinedPlayer, Type.LEAVE)
+
+ @JvmStatic
+ fun createCommand(serverName: String, serverOwner: SteamwarUser?, player: SteamwarUser?, command: String) = player?.let { create(serverName, serverOwner, it, Type.COMMAND, command) }
+
+ @JvmStatic
+ fun createSensitiveCommand(
+ serverName: String,
+ serverOwner: SteamwarUser?,
+ player: SteamwarUser?,
+ command: String
+ ) = player?.let { create(serverName, serverOwner, it, Type.SENSITIVE_COMMAND, command) }
+
+ @JvmStatic
+ fun createChat(serverName: String, serverOwner: SteamwarUser?, chatter: SteamwarUser, chat: String) = create(serverName, serverOwner, chatter, Type.CHAT, chat)
+
+ @JvmStatic
+ fun createGuiOpen(serverName: String, serverOwner: SteamwarUser?, player: SteamwarUser, guiName: String) = create(serverName, serverOwner, player, Type.GUI_OPEN, guiName)
+
+ @JvmStatic
+ fun createGuiClick(
+ serverName: String,
+ serverOwner: SteamwarUser?,
+ player: SteamwarUser,
+ guiName: String,
+ clickType: String,
+ slot: Int,
+ itemName: String
+ ) = create(
+ serverName,
+ serverOwner,
+ player,
+ Type.GUI_CLICK,
+ "Gui: $guiName\nSlot: $slot\nClickType: $clickType\nItemName: $itemName"
+ )
+
+ @JvmStatic
+ fun createGuiClose(serverName: String, serverOwner: SteamwarUser?, player: SteamwarUser, guiName: String) = create(serverName, serverOwner, player, Type.GUI_CLOSE, guiName)
+ }
+
+ var time by AuditLogTable.time
+ var server by AuditLogTable.server
+ var serverOwner by AuditLogTable.serverOwner
+ var actor by AuditLogTable.actor
+ var action by AuditLogTable.action
+ var actionText by AuditLogTable.actionText
+
+ enum class Type {
+ JOIN,
+ LEAVE,
+ COMMAND,
+ SENSITIVE_COMMAND,
+ CHAT,
+ GUI_OPEN,
+ GUI_CLOSE,
+ GUI_CLICK,
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/BannedUserIPs.java b/CommonCore/SQL/src/de/steamwar/sql/BannedUserIPs.java
deleted file mode 100644
index f16e0343..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/BannedUserIPs.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.sql.Timestamp;
-import java.time.Instant;
-import java.util.List;
-
-@AllArgsConstructor
-public class BannedUserIPs {
-
- private static final Table table = new Table<>(BannedUserIPs.class);
-
- private static final SelectStatement getByID = table.selectFields("UserID");
- private static final SelectStatement getByIP = new SelectStatement<>(table, "SELECT * FROM BannedUserIPs WHERE IP = ? ORDER BY Timestamp DESC");
- private static final Statement banIP = table.insertAll();
- private static final Statement unbanIPs = table.deleteFields("UserID");
-
- @Getter
- @Field(keys = {Table.PRIMARY})
- private final int userID;
- @Getter
- @Field(def = "CURRENT_TIMESTAMP")
- private final Timestamp timestamp;
- @Field(keys = {Table.PRIMARY})
- private final String ip;
-
- public static List get(int userID) {
- return getByID.listSelect(userID);
- }
-
- public static List get(String ip) {
- return getByIP.listSelect(ip);
- }
-
- public static void banIP(int userID, String ip){
- banIP.update(userID, Timestamp.from(Instant.now()), ip);
- }
-
- public static void unbanIPs(int userID) {
- unbanIPs.update(userID);
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/BannedUserIPs.kt b/CommonCore/SQL/src/de/steamwar/sql/BannedUserIPs.kt
new file mode 100644
index 00000000..495238ad
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/BannedUserIPs.kt
@@ -0,0 +1,78 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.dao.id.CompositeID
+import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.dao.CompositeEntity
+import org.jetbrains.exposed.v1.dao.CompositeEntityClass
+import org.jetbrains.exposed.v1.javatime.timestamp
+import org.jetbrains.exposed.v1.jdbc.deleteWhere
+import org.jetbrains.exposed.v1.jdbc.insertIgnore
+import java.sql.Timestamp
+import java.time.Instant
+
+object BannedUserIPsTable: CompositeIdTable("BannedUserIPs") {
+ val userId = reference("UserID", SteamwarUserTable)
+ val timestamp = timestamp("Timestamp")
+ val ip = varchar("IP", 45)
+
+ override val primaryKey = PrimaryKey(userId, ip)
+}
+
+class BannedUserIPs(id: EntityID): CompositeEntity(id) {
+ companion object: CompositeEntityClass(BannedUserIPsTable) {
+
+ @JvmStatic
+ fun get(userId: Int) = useDb {
+ find { BannedUserIPsTable.userId eq userId }.toList()
+ }
+
+ @JvmStatic
+ fun get(ip: String) = useDb {
+ find { BannedUserIPsTable.ip eq ip }.toList()
+ }
+
+ @JvmStatic
+ fun banIP(userId: Int, ip: String) = useDb {
+ BannedUserIPsTable.insertIgnore {
+ it[BannedUserIPsTable.userId] = userId
+ it[BannedUserIPsTable.ip] = ip
+ it[BannedUserIPsTable.timestamp] = Instant.now()
+ }
+ }
+
+ @JvmStatic
+ fun unbanIPs(userId: Int) = useDb {
+ BannedUserIPsTable.deleteWhere { BannedUserIPsTable.userId eq userId }
+ }
+ }
+
+ val userID by BannedUserIPsTable.userId.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
+ val timestamp: Timestamp by BannedUserIPsTable.timestamp.transform({ it.toInstant() }, { Timestamp.from(it) })
+ val ip by BannedUserIPsTable.ip
+
+ fun remove() = useDb {
+ delete()
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/BauweltMember.java b/CommonCore/SQL/src/de/steamwar/sql/BauweltMember.java
deleted file mode 100644
index 71fa3a46..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/BauweltMember.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.Getter;
-
-import java.util.*;
-
-public class BauweltMember {
- private static final Map memberCache = new HashMap<>();
-
- public static void clear() {
- memberCache.clear();
- }
-
- private static final Table table = new Table<>(BauweltMember.class);
- private static final SelectStatement getMember = table.select(Table.PRIMARY);
- private static final SelectStatement getMembers = table.selectFields("BauweltID");
- private static final Statement update = table.insertAll();
- private static final Statement delete = table.delete(Table.PRIMARY);
-
- public static void addMember(UUID ownerID, UUID memberID) {
- new BauweltMember(SteamwarUser.get(ownerID).getId(), SteamwarUser.get(memberID).getId(), false, false).updateDB();
- }
-
- public static BauweltMember getBauMember(UUID ownerID, UUID memberID){
- return getBauMember(SteamwarUser.get(ownerID).getId(), SteamwarUser.get(memberID).getId());
- }
-
- public static BauweltMember getBauMember(int ownerID, int memberID){
- BauweltMember member = memberCache.get(memberID);
- if(member != null && member.bauweltID == ownerID)
- return member;
- return getMember.select(ownerID, memberID);
- }
-
- public static List getMembers(UUID bauweltID){
- return getMembers(SteamwarUser.get(bauweltID).getId());
- }
-
- public static List getMembers(int bauweltID){
- return getMembers.listSelect(bauweltID);
- }
-
- @Getter
- @Field(keys = {Table.PRIMARY})
- private final int bauweltID;
- @Getter
- @Field(keys = {Table.PRIMARY})
- private final int memberID;
- @Getter
- @Field(def = "0")
- private boolean worldEdit;
- @Getter
- @Field(def = "0")
- private boolean world;
-
- public BauweltMember(int bauweltID, int memberID, boolean worldEdit, boolean world) {
- this.bauweltID = bauweltID;
- this.memberID = memberID;
- this.worldEdit = worldEdit;
- this.world = world;
- memberCache.put(memberID, this);
- }
-
- public void setWorldEdit(boolean worldEdit) {
- this.worldEdit = worldEdit;
- updateDB();
- }
-
- public void setWorld(boolean world) {
- this.world = world;
- updateDB();
- }
-
- private void updateDB(){
- update.update(bauweltID, memberID, worldEdit, world);
- }
-
- public void remove(){
- delete.update(bauweltID, memberID);
- memberCache.remove(memberID);
- }
-
- public boolean isBuild() {
- return worldEdit;
- }
-
- public boolean isSupervisor() {
- return world;
- }
-
- public void setBuild(boolean build) {
- this.worldEdit = build;
- updateDB();
- }
-
- public void setSupervisor(boolean supervisor) {
- this.world = supervisor;
- updateDB();
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/BauweltMember.kt b/CommonCore/SQL/src/de/steamwar/sql/BauweltMember.kt
new file mode 100644
index 00000000..66e3bb8b
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/BauweltMember.kt
@@ -0,0 +1,130 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.BauweltMemberTable.bauweltId
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.and
+import org.jetbrains.exposed.v1.core.dao.id.CompositeID
+import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.dao.CompositeEntity
+import org.jetbrains.exposed.v1.dao.CompositeEntityClass
+import org.jetbrains.exposed.v1.jdbc.insertIgnore
+import java.util.*
+
+object BauweltMemberTable: CompositeIdTable("BauweltMember") {
+ val bauweltId = reference("BauweltID", SteamwarUserTable)
+ val memberId = reference("MemberID", SteamwarUserTable)
+ val build = bool("Build")
+ val worldEdit = bool("WorldEdit")
+ val world = bool("World")
+
+ override val primaryKey = PrimaryKey(bauweltId, memberId)
+
+ init {
+ addIdColumn(bauweltId)
+ addIdColumn(memberId)
+ }
+}
+
+class BauweltMember(id: EntityID): CompositeEntity(id) {
+ companion object: CompositeEntityClass(BauweltMemberTable) {
+ private val cache = mutableMapOf()
+
+ private fun cache(member: BauweltMember) = cache.put(member.memberID, member)
+
+ @JvmStatic
+ fun clear() = cache.clear()
+
+ @JvmStatic
+ @Deprecated("Use addMember(ownerId: Int, newMemberId: Int)")
+ fun addMember(ownerId: UUID, newMemberId: UUID) = addMember(SteamwarUser.get(ownerId)!!.id, SteamwarUser.get(newMemberId)!!.id)
+
+ @JvmStatic
+ fun addMember(ownerId: Int, newMemberId: Int) = addMember(EntityID(ownerId, SteamwarUserTable), EntityID(newMemberId, SteamwarUserTable))
+
+ fun addMember(ownerId: EntityID, newMemberId: EntityID) = useDb {
+ BauweltMemberTable.insertIgnore {
+ it[bauweltId] = ownerId
+ it[memberId] = newMemberId
+ it[build] = false
+ it[worldEdit] = false
+ it[world] = false
+ }
+ }
+
+ @JvmStatic
+ @Deprecated("Use getBauMember(bauwelt: Int, member: Int)")
+ fun getBauMember(bauwelt: UUID, member: UUID) = useDb {
+ find { (bauweltId eq SteamwarUser.get(bauwelt)!!.id) and (BauweltMemberTable.memberId eq SteamwarUser.get(member)!!.id) }.firstOrNull()?.also { cache(it) }
+ }
+
+ @JvmStatic
+ fun getBauMember(bauwelt: Int, member: Int) = useDb {
+ find { (bauweltId eq bauwelt) and (BauweltMemberTable.memberId eq member) }.firstOrNull()?.also { cache(it) }
+ }
+
+ @JvmStatic
+ @Deprecated("Use getMembers(bauwelt: Int)")
+ fun getMembers(bauwelt: UUID) = getMembers(SteamwarUser.get(bauwelt)!!.id.value)
+
+ @JvmStatic
+ fun getMembers(bauwelt: Int) = useDb {
+ find { bauweltId eq bauwelt }.toList().also { it.forEach { cache(it) } }
+ }
+ }
+
+ val bauweltID by BauweltMemberTable.bauweltId.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
+ val memberID by BauweltMemberTable.memberId.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
+ private var worldEditInternal by BauweltMemberTable.worldEdit
+ var worldEdit: Boolean
+ get() = worldEditInternal
+ set(value) = useDb {
+ worldEditInternal = value
+ }
+ private var buildInternal by BauweltMemberTable.build
+ var build: Boolean
+ get() = buildInternal
+ set(value) = useDb {
+ buildInternal = value
+ }
+ private var worldInternal by BauweltMemberTable.world
+ var world: Boolean
+ get() = worldInternal
+ set(value) = useDb {
+ worldInternal = value
+ }
+ var supervisor: Boolean
+ get() = world
+ set(value) = useDb {
+ world = value
+ }
+
+ fun isBuild() = build
+ fun isSupervisor() = world
+ fun isWorldEdit() = build
+ fun isWorld() = world
+
+ fun remove() = useDb {
+ delete()
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.java b/CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.java
deleted file mode 100644
index 5a0e553c..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.sql.Timestamp;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-
-@AllArgsConstructor
-public class CheckedSchematic {
-
- private static final Table table = new Table<>(CheckedSchematic.class);
- private static final SelectStatement statusOfNode = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != 'Prüfvorgang abgebrochen' ORDER BY EndTime DESC");
- private static final SelectStatement nodeHistory = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != '' AND DeclineReason != 'Prüfvorgang abgebrochen' ORDER BY EndTime DESC");
- private static final Statement insert = table.insertAll();
-
- private static final SelectStatement getUnseen = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE Seen = 0 AND NodeOwner = ? ORDER BY StartTime DESC");
- private static final Statement updateSeen = new Statement("UPDATE CheckedSchematic SET Seen = ? WHERE StartTime = ? AND EndTime = ? AND NodeName = ?");
-
- public static void create(SchematicNode node, int validator, Timestamp startTime, Timestamp endTime, String reason, boolean seen) {
- insert.update(node.getId(), node.getOwner(), node.getName(), validator, startTime, endTime, reason, seen, node.getSchemtype().toDB().substring(1));
- }
-
- public static List getLastDeclinedOfNode(int node) {
- return statusOfNode.listSelect(node);
- }
-
- public static List previousChecks(SchematicNode node) {
- return nodeHistory.listSelect(node.getId());
- }
-
- public static List getUnseen(SteamwarUser owner) {
- return getUnseen.listSelect(owner);
- }
-
- @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;
- @Getter
- @Field
- private boolean seen;
- @Getter
- @Field
- private final String nodeType;
-
- public int getNode() {
- return nodeId;
- }
-
- public String getSchemName() {
- return nodeName;
- }
-
- public int getSchemOwner() {
- return nodeOwner;
- }
-
- public void setSeen(boolean seen) {
- this.seen = seen;
- updateSeen.update(seen, startTime, endTime, nodeName);
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.kt b/CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.kt
new file mode 100644
index 00000000..3e51d24e
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.kt
@@ -0,0 +1,100 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.SortOrder
+import org.jetbrains.exposed.v1.core.and
+import org.jetbrains.exposed.v1.core.dao.id.CompositeID
+import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.core.neq
+import org.jetbrains.exposed.v1.dao.CompositeEntity
+import org.jetbrains.exposed.v1.dao.CompositeEntityClass
+import org.jetbrains.exposed.v1.javatime.timestamp
+import org.jetbrains.exposed.v1.jdbc.insertIgnore
+import java.sql.Timestamp
+
+object CheckedSchematicTable: CompositeIdTable("CheckedSchematic") {
+ val nodeId = optReference("NodeId", SchematicNodeTable)
+ val nodeOwner = reference("NodeOwner", SteamwarUserTable)
+ val nodeName = varchar("NodeName", 64).entityId()
+ val validator = reference("Validator", SteamwarUserTable)
+ val startTime = timestamp("StartTime").entityId()
+ val endTime = timestamp("EndTime")
+ val declineReason = text("DeclineReason")
+ val seen = bool("Seen")
+ val nodeType = varchar("NodeType", 16)
+
+ init {
+ addIdColumn(nodeOwner)
+ addIdColumn(nodeName)
+ }
+}
+
+class CheckedSchematic(id: EntityID): CompositeEntity(id) {
+ companion object: CompositeEntityClass(CheckedSchematicTable) {
+ @JvmStatic
+ fun create(node: SchematicNode, validator: Int, startTime: Timestamp, endTime: Timestamp, reason: String, seen: Boolean) = useDb {
+ CheckedSchematicTable.insertIgnore {
+ it[this.nodeId] = node.id
+ it[this.nodeOwner] = EntityID(node.owner, SteamwarUserTable)
+ it[this.nodeName] = node.name
+ it[this.validator] = EntityID(validator, SteamwarUserTable)
+ it[this.startTime] = startTime.toInstant()
+ it[this.endTime] = endTime.toInstant()
+ it[this.declineReason] = reason
+ it[this.seen] = seen
+ it[this.nodeType] = node.schemtype.toDB().substring(1)
+ }
+ }
+
+ @JvmStatic
+ fun getLastDeclinedOfNode(node: Int) = useDb {
+ find { (CheckedSchematicTable.nodeId eq node) and (CheckedSchematicTable.declineReason neq "Prüfvorgang abgebrochen") }.orderBy(CheckedSchematicTable.endTime to SortOrder.DESC).toList()
+ }
+
+ @JvmStatic
+ fun previousChecks(node: SchematicNode) = useDb {
+ find { (CheckedSchematicTable.nodeId eq node.id) and (CheckedSchematicTable.declineReason neq "") and (CheckedSchematicTable.declineReason neq "Prüfvorgang abgebrochen") }.orderBy(CheckedSchematicTable.endTime to SortOrder.DESC).toList()
+ }
+
+ @JvmStatic
+ fun getUnseen(owner: SteamwarUser) = useDb {
+ find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.seen eq false) }.orderBy(CheckedSchematicTable.endTime to SortOrder.DESC).toList()
+ }
+ }
+
+ val node by CheckedSchematicTable.nodeId.transform({ it?.let { EntityID(it, SchematicNodeTable) } }, { it?.value })
+ val schemOwner by CheckedSchematicTable.nodeOwner.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
+ val nodeName by CheckedSchematicTable.nodeName
+ val schemName get() = nodeName.value
+ val validator by CheckedSchematicTable.validator.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
+ val startTimeId by CheckedSchematicTable.startTime
+ val startTime get() = Timestamp.from(startTimeId.value)
+ val endTime by CheckedSchematicTable.endTime.transform({ it.toInstant() }, { Timestamp.from(it) })
+ val declineReason by CheckedSchematicTable.declineReason
+ private var wasSeen by CheckedSchematicTable.seen
+ var seen: Boolean
+ get() = wasSeen
+ set(value) = useDb { wasSeen = value }
+ val nodeType by CheckedSchematicTable.nodeType
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/Event.java b/CommonCore/SQL/src/de/steamwar/sql/Event.java
deleted file mode 100644
index e65a1533..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/Event.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.sql.Timestamp;
-import java.time.Instant;
-import java.util.List;
-
-@AllArgsConstructor
-public class Event {
-
- static {
- SchematicType.Normal.name(); // Ensure SchematicType is loaded.
- }
-
- private static final Table table = new Table<>(Event.class);
-
- private static final SelectStatement byCurrent = new SelectStatement<>(table, "SELECT * FROM Event WHERE Start < now() AND End > now()");
- private static final SelectStatement byId = table.select(Table.PRIMARY);
- private static final SelectStatement byName = table.select("eventName");
- private static final SelectStatement byComing = new SelectStatement<>(table, "SELECT * FROM Event WHERE Start > now()");
- private static final SelectStatement all = new SelectStatement<>(table, "SELECT * FROM Event");
-
- private static final Statement create = table.insertFields(true, "eventName", "deadline", "start", "end", "maximumTeamMembers", "publicSchemsOnly");
- private static final Statement update = table.update(Table.PRIMARY, "eventName", "deadline", "start", "end", "schemType", "maximumTeamMembers", "publicSchemsOnly");
- private static final Statement delete = table.delete(Table.PRIMARY);
-
- private static Event current = null;
-
- public static Event get(){
- if(current != null && current.now())
- return current;
-
- current = byCurrent.select();
- return current;
- }
-
- public static List getAll(){
- return all.listSelect();
- }
-
- public static Event create(String eventName, Timestamp start, Timestamp end){
- return get(create.insertGetKey(eventName, start, start, end, 5, false));
- }
-
- public static Event get(int eventID){
- return byId.select(eventID);
- }
-
- public static Event get(String eventName) {
- return byName.select(eventName);
- }
-
- public static List getComing() {
- return byComing.listSelect();
- }
-
- @Getter
- @Field(keys = {Table.PRIMARY}, autoincrement = true)
- private final int eventID;
- @Getter
- @Field(keys = {"eventName"})
- private final String eventName;
- @Getter
- @Field
- private final Timestamp deadline;
- @Getter
- @Field
- private final Timestamp start;
- @Getter
- @Field
- private final Timestamp end;
- @Getter
- @Field
- private final int maximumTeamMembers;
- @Field(nullable = true)
- private final SchematicType schemType;
- @Field
- private final boolean publicSchemsOnly;
-
- public boolean publicSchemsOnly() {
- return publicSchemsOnly;
- }
-
- public SchematicType getSchematicType() {
- return schemType;
- }
-
- private boolean now() {
- Instant now = Instant.now();
- return now.isAfter(start.toInstant()) && now.isBefore(end.toInstant());
- }
-
- public void update(String eventName, Timestamp deadline, Timestamp start, Timestamp end, SchematicType schemType, int maximumTeamMembers, boolean publicSchemsOnly) {
- update.update(eventName, deadline, start, end, schemType, maximumTeamMembers, publicSchemsOnly, eventID);
- }
-
- public void delete() {
- delete.update(eventID);
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/Event.kt b/CommonCore/SQL/src/de/steamwar/sql/Event.kt
new file mode 100644
index 00000000..ffc08b8d
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/Event.kt
@@ -0,0 +1,121 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.and
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.core.greater
+import org.jetbrains.exposed.v1.core.lessEq
+import org.jetbrains.exposed.v1.dao.IntEntity
+import org.jetbrains.exposed.v1.dao.IntEntityClass
+import org.jetbrains.exposed.v1.javatime.timestamp
+import org.jetbrains.exposed.v1.jdbc.insertAndGetId
+import java.sql.Timestamp
+import java.time.Instant
+
+object EventTable : IntIdTable("Event", "EventId") {
+ val name = varchar("EventName", 100).uniqueIndex()
+ val deadline = timestamp("Deadline")
+ val start = timestamp("Start")
+ val end = timestamp("End")
+ val maxPlayers = integer("MaximumTeamMembers")
+ val schemType = varchar("SchemType", 16).nullable()
+ val publicsOnly = bool("PublicSchemsOnly")
+}
+
+class Event(id: EntityID) : IntEntity(id) {
+ companion object : IntEntityClass(EventTable) {
+ private var current: Event? = null
+
+ @JvmStatic
+ fun get(): Event? = if (current?.now() == true) {
+ current
+ } else useDb {
+ find { EventTable.start.lessEq(Instant.now()) and EventTable.end.greater(Instant.now()) }.firstOrNull()
+ ?.also { current == it }
+ }
+
+ @JvmStatic
+ fun getAll() = useDb { all().toList() }
+
+ @JvmStatic
+ fun create(name: String, start: Timestamp, end: Timestamp) = useDb {
+ EventTable.insertAndGetId {
+ it[this.name] = name
+ it[this.deadline] = start.toInstant()
+ it[this.start] = start.toInstant()
+ it[this.end] = end.toInstant()
+ it[this.maxPlayers] = 5
+ it[this.publicsOnly] = false
+ }.let { get(it) }
+ }
+
+ @JvmStatic
+ fun byId(id: Int) = useDb { findById(id) }
+
+ @JvmStatic
+ fun get(name: String) = useDb { find { EventTable.name eq name }.firstOrNull() }
+
+ @JvmStatic
+ fun getComing() = useDb { find { EventTable.start greater Instant.now() }.toList() }
+ }
+
+ val eventID by EventTable.id.transform({ EntityID(it, EventTable) }, { it.value })
+ var eventName by EventTable.name
+ private set
+ var deadline: Timestamp by EventTable.deadline.transform({ it.toInstant() }, { Timestamp.from(it) })
+ private set
+ var start: Timestamp by EventTable.start.transform({ it.toInstant() }, { Timestamp.from(it) })
+ private set
+ var end: Timestamp by EventTable.end.transform({ it.toInstant() }, { Timestamp.from(it) })
+ private set
+ var maximumTeamMembers by EventTable.maxPlayers
+ private set
+ var schematicType by EventTable.schemType.transform({ it?.toDB() }, { it?.let { SchematicType.fromDB(it) } })
+ private set
+ var publicSchemsOnly by EventTable.publicsOnly
+ private set
+
+ fun publicSchemsOnly() = publicSchemsOnly
+ fun now() = Instant.now().let { it.isAfter(start.toInstant()) && it.isBefore(end.toInstant()) }
+
+ fun update(
+ name: String,
+ deadline: Timestamp,
+ start: Timestamp,
+ end: Timestamp,
+ schematicType: SchematicType?,
+ maxPlayers: Int,
+ publicSchemsOnly: Boolean
+ ) = useDb {
+ this@Event.eventName = name
+ this@Event.deadline = deadline
+ this@Event.start = start
+ this@Event.end = end
+ this@Event.maximumTeamMembers = maxPlayers
+ this@Event.schematicType = schematicType
+ this@Event.publicSchemsOnly = publicSchemsOnly
+ }
+
+ override fun delete() = useDb { super.delete() }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/EventFight.java b/CommonCore/SQL/src/de/steamwar/sql/EventFight.java
deleted file mode 100644
index a1472918..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/EventFight.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.sql.Timestamp;
-import java.util.*;
-
-import static java.time.temporal.ChronoUnit.SECONDS;
-
-@AllArgsConstructor
-public class EventFight implements Comparable {
-
- private static final Table table = new Table<>(EventFight.class);
- private static final SelectStatement byId = table.select(Table.PRIMARY);
- private static final SelectStatement byGroup = new SelectStatement(table, "SELECT * FROM EventFight WHERE GroupID = ? ORDER BY StartTime ASC");
- private static final SelectStatement byGroupLast = new SelectStatement(table, "SELECT * FROM EventFight WHERE GroupID = ? ORDER BY StartTime DESC LIMIT 1");
- private static final SelectStatement allComing = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE StartTime > now() ORDER BY StartTime ASC");
- private static final SelectStatement event = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE EventID = ? ORDER BY StartTime ASC");
- private static final SelectStatement activeFights = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE EventID IN (SELECT EventID FROM Event WHERE Start < now() and End > now()) AND Fight IS NULL AND StartTime < now()");
- private static final Statement reschedule = table.update(Table.PRIMARY, "StartTime");
- private static final Statement setResult = table.update(Table.PRIMARY, "Ergebnis");
- private static final Statement setFight = table.update(Table.PRIMARY, "Fight");
-
- private static final Statement create = table.insertFields(true, "eventID", "startTime", "spielmodus", "map", "teamBlue", "teamRed", "spectatePort");
- private static final Statement update = table.update(Table.PRIMARY, "startTime", "spielModus", "map", "teamBlue", "teamRed", "spectatePort");
- private static final Statement setGroup = table.update(Table.PRIMARY, "GroupID");
- private static final Statement delete = table.delete(Table.PRIMARY);
-
- @Getter
- private static final Queue fights = new PriorityQueue<>();
-
- public static EventFight get(int fightID) {
- return byId.select(fightID);
- }
-
- public static List get(EventGroup group) {
- return byGroup.listSelect(group.getId());
- }
-
- public static Optional getLast(EventGroup group) {
- return Optional.ofNullable(byGroupLast.select(group.getId()));
- }
-
- public static void loadAllComingFights() {
- fights.clear();
- fights.addAll(allComing.listSelect());
- }
-
- public static List getEvent(int eventID) {
- return event.listSelect(eventID);
- }
-
- private static List activeFightsCache = null;
-
- public static void clearActiveFightsCache() {
- activeFightsCache = null;
- }
-
- public static List getActiveFights() {
- if (activeFightsCache == null) {
- activeFightsCache = activeFights.listSelect();
- }
- return activeFightsCache;
- }
-
- public static EventFight create(int event, Timestamp from, String spielmodus, String map, int blueTeam, int redTeam, Integer spectatePort) {
- return get(create.insertGetKey(event, from, spielmodus, map, blueTeam, redTeam, spectatePort));
- }
-
- @Getter
- @Field
- private final int eventID;
- @Getter
- @Field(keys = {Table.PRIMARY}, autoincrement = true)
- private final int fightID;
- @Getter
- @Setter
- @Field(nullable = true, def = "null")
- private Integer groupId;
- @Getter
- @Setter
- @Field
- private Timestamp startTime;
- @Getter
- @Setter
- @Field
- private String spielmodus;
- @Getter
- @Setter
- @Field
- private String map;
- @Getter
- @Setter
- @Field
- private int teamBlue;
- @Getter
- @Setter
- @Field
- private int teamRed;
- @Getter
- @Setter
- @Field(nullable = true)
- private Integer spectatePort;
- @Getter
- @Setter
- @Field(def = "1")
- private int bestOf;
- @Getter
- @Field(def = "0")
- private int ergebnis;
- @Field(nullable = true)
- private int fight;
-
- public Optional getGroup() {
- return Optional.ofNullable(groupId).flatMap(EventGroup::get);
- }
-
- public Optional getWinner() {
- if(ergebnis == 0)
- return Optional.empty();
- return Optional.ofNullable(ergebnis == 1 ? Team.get(teamBlue) : Team.get(teamRed));
- }
-
- public Optional getLosser() {
- if(ergebnis == 0)
- return Optional.empty();
- return Optional.ofNullable(ergebnis == 1 ? Team.get(teamRed) : Team.get(teamBlue));
- }
-
- public List getDependents() {
- return EventRelation.getFightRelations(this);
- }
-
- public void setErgebnis(int winner) {
- this.ergebnis = winner;
- setResult.update(winner, fightID);
- }
-
- public void setFight(int fight) {
- //Fight.FightID, not EventFight.FightID
- this.fight = fight;
- setFight.update(fight, fightID);
- }
-
- public void setGroup(Integer group) {
- setGroup.update(group, fightID);
- this.groupId = group;
- }
-
- public boolean hasFinished() {
- return fight != 0 || ergebnis != 0;
- }
-
- public void reschedule() {
- startTime = Timestamp.from(new Date().toInstant().plus(30, SECONDS));
- reschedule.update(startTime, fightID);
- }
-
- @Override
- public int hashCode(){
- return fightID;
- }
-
- @Override
- public boolean equals(Object o){
- if(o == null)
- return false;
- if(!(o instanceof EventFight))
- return false;
- return fightID == ((EventFight) o).fightID;
- }
-
- @Override
- public int compareTo(EventFight o) {
- return startTime.compareTo(o.startTime);
- }
-
- public void update(Timestamp startTime, String spielmodus, String map, int teamBlue, int teamRed, Integer spectatePort) {
- update.update(startTime, spielmodus, map, teamBlue, teamRed, spectatePort, fightID);
- this.startTime = startTime;
- this.spielmodus = spielmodus;
- this.map = map;
- this.teamBlue = teamBlue;
- this.teamRed = teamRed;
- this.spectatePort = spectatePort;
- }
-
- public void delete() {
- delete.update(fightID);
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/EventFight.kt b/CommonCore/SQL/src/de/steamwar/sql/EventFight.kt
new file mode 100644
index 00000000..f4c60248
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/EventFight.kt
@@ -0,0 +1,188 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.*
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
+import org.jetbrains.exposed.v1.dao.IntEntity
+import org.jetbrains.exposed.v1.dao.IntEntityClass
+import org.jetbrains.exposed.v1.javatime.timestamp
+import org.jetbrains.exposed.v1.jdbc.insertAndGetId
+import org.jetbrains.exposed.v1.jdbc.select
+import java.sql.Timestamp
+import java.time.Instant
+import java.util.*
+
+object EventFightTable : IntIdTable("EventFight", "FightID") {
+ val eventId = reference("EventID", EventTable)
+ val startTime = timestamp("StartTime")
+ val gamemode = text("Spielmodus")
+ val map = text("Map")
+ val groupId = optReference("GroupId", EventGroupTable)
+ val teamBlue = reference("TeamBlue", TeamTable)
+ val teamRed = reference("TeamRed", TeamTable)
+ val spectatePort = integer("SpectatePort").nullable()
+ val bestOf = integer("BestOf")
+ val ergebnis = integer("Ergebnis")
+ val fight = optReference("Fight", FightTable)
+}
+
+class EventFight(id: EntityID) : IntEntity(id), Comparable {
+ companion object : IntEntityClass(EventFightTable) {
+ val fights: Queue = PriorityQueue()
+ @JvmStatic get
+
+ @JvmStatic
+ fun byId(fightId: Int) = useDb { findById(fightId) }
+
+ @JvmStatic
+ fun byId(group: EventGroup) = useDb {
+ find { EventFightTable.groupId eq group.id }.orderBy(EventFightTable.startTime to SortOrder.DESC).toList()
+ }
+
+ @JvmStatic
+ fun getLast(group: EventGroup) = useDb {
+ Optional.ofNullable(
+ find { EventFightTable.groupId eq group.id }.orderBy(EventFightTable.startTime to SortOrder.DESC)
+ .firstOrNull()
+ )
+ }
+
+ @JvmStatic
+ fun loadAllComingFights() = useDb {
+ fights.clear()
+ fights.addAll(find { EventFightTable.startTime greaterEq Instant.now() }.orderBy(EventFightTable.startTime to SortOrder.ASC))
+ }
+
+ @JvmStatic
+ fun getEvent(eventId: Int) = useDb {
+ find { EventFightTable.eventId eq eventId }.orderBy(EventFightTable.startTime to SortOrder.ASC).toList()
+ }
+
+ private var activeFightsCache: List? = null
+
+ @JvmStatic
+ fun clearActiveFightsCache() {
+ activeFightsCache = null
+ }
+
+ @JvmStatic
+ fun getActiveFights(): List {
+ if (activeFightsCache == null) {
+ activeFightsCache = useDb {
+ find {
+ EventFightTable.fight.isNull() and (EventFightTable.startTime less Instant.now()) and (EventFightTable.eventId.inSubQuery(
+ EventTable.select(
+ EventTable.id
+ )
+ .where { (EventTable.start less Instant.now()) and (EventTable.end greater Instant.now()) }))
+ }.orderBy(EventFightTable.startTime to SortOrder.ASC).toList()
+ }
+ }
+
+ return activeFightsCache!!
+ }
+
+ @JvmStatic
+ fun create(
+ event: Int,
+ from: Timestamp,
+ spielmodus: String,
+ map: String,
+ blueTeam: Int,
+ redTeam: Int,
+ spectatePort: Int?
+ ) = useDb {
+ get(
+ EventFightTable.insertAndGetId {
+ it[eventId] = EntityID(event, EventTable)
+ it[startTime] = from.toInstant()
+ it[gamemode] = spielmodus
+ it[EventFightTable.map] = map
+ it[teamBlue] = EntityID(blueTeam, TeamTable)
+ it[teamRed] = EntityID(redTeam, TeamTable)
+ it[EventFightTable.spectatePort] = spectatePort
+ }
+ )
+ }
+ }
+
+ val fightID by EventFightTable.id.transform({ EntityID(it, EventFightTable) }, { it.value })
+ var teamBlue by EventFightTable.teamBlue.transform({ EntityID(it, TeamTable) }, { it.value })
+ var teamRed by EventFightTable.teamRed.transform({ EntityID(it, TeamTable) }, { it.value })
+ private var fightErgebnis by EventFightTable.ergebnis
+ var ergebnis: Int
+ get() = fightErgebnis
+ set(value) = useDb {
+ fightErgebnis = value
+ }
+ var eventID by EventFightTable.eventId.transform({ EntityID(it, EventTable) }, { it.value })
+ var startTime by EventFightTable.startTime.transform({ it.toInstant() }, { Timestamp.from(it) })
+ var spielmodus by EventFightTable.gamemode
+ var map by EventFightTable.map
+ var groupId by EventFightTable.groupId
+ val group by lazy { useDb { Optional.ofNullable(groupId).map { EventGroup[it] } } }
+ var spectatePort by EventFightTable.spectatePort
+ private var fightStat by EventFightTable.fight.transform({ it?.let { EntityID(it, EventFightTable) } }, { it?.value })
+ var fight: Int?
+ get() = fightStat
+ set(value) = useDb {
+ fightStat = value
+ }
+ val dependents by lazy { useDb { EventRelation.getFightRelations(this@EventFight).toList() } }
+
+ val winner: Team?
+ get() = useDb { if (ergebnis == 1) Team[teamBlue] else if (ergebnis == 2) Team[teamRed] else null }
+ val losser: Team?
+ get() = useDb { if (ergebnis == 1) Team[teamRed] else if (ergebnis == 2) Team[teamBlue] else null }
+
+ fun setGroup(group: Int?) = useDb { groupId = group?.let { EntityID(it, EventGroupTable) } }
+ fun hasFinished() = fight != null || ergebnis != 0
+
+ fun reschedule() = useDb {
+ startTime = Timestamp.from(Instant.now().plusSeconds(30))
+ }
+
+ override fun hashCode() = fightID
+ override fun equals(other: Any?) = other is EventFight && other.fightID == fightID
+ override fun compareTo(other: EventFight): Int = startTime.compareTo(other.startTime)
+
+ fun update(
+ startTime: Timestamp,
+ spielmodus: String,
+ map: String,
+ teamBlue: Int,
+ teamRed: Int,
+ spectatePort: Int?
+ ) = useDb {
+ this@EventFight.startTime = startTime
+ this@EventFight.spielmodus = spielmodus
+ this@EventFight.map = map
+ this@EventFight.teamBlue = teamBlue
+ this@EventFight.teamRed = teamRed
+ this@EventFight.spectatePort = spectatePort
+ }
+
+ override fun delete() = useDb {
+ super.delete()
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/EventGroup.java b/CommonCore/SQL/src/de/steamwar/sql/EventGroup.java
deleted file mode 100644
index 68934765..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/EventGroup.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.*;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.util.*;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-@Getter
-@Setter
-public class EventGroup {
- static {
- SqlTypeMapper.ordinalEnumMapper(EventGroupType.class);
- }
-
- private static final Table table = new Table<>(EventGroup.class);
-
- private static final SelectStatement get = table.select(Table.PRIMARY);
- private static final SelectStatement byEvent = new SelectStatement<>(table, "SELECT * FROM EventGroup WHERE EventID = ?");
-
- private static final Statement insert = table.insertFields(true, "EventID", "Name", "Type");
- private static final Statement update = table.update(Table.PRIMARY, "Name", "Type", "PointsPerWin", "PointsPerLoss", "PointsPerDraw");
- private static final Statement delete = table.delete(Table.PRIMARY);
-
- public static List get(Event eventID) {
- return byEvent.listSelect(eventID.getEventID());
- }
-
- public static EventGroup create(Event event, String name, EventGroupType type) {
- int key = insert.insertGetKey(event.getEventID(), name, type);
- return EventGroup.get(key).get();
- }
-
- public static Optional get(int id) {
- return Optional.ofNullable(get.select(id));
- }
-
- @Field(keys = Table.PRIMARY)
- private final int id;
-
- @Field(keys = "EVENT_NAME")
- private int eventID;
-
- @Field(keys = "EVENT_NAME")
- private String name;
-
- @Field
- private EventGroupType type;
-
- @Field
- private int pointsPerWin;
-
- @Field
- private int pointsPerLoss;
-
- @Field
- private int pointsPerDraw;
-
- public EventGroup(int id, int eventID, String name, EventGroupType type, int pointsPerWin, int pointsPerLoss, int pointsPerDraw) {
- this.id = id;
- this.eventID = eventID;
- this.name = name;
- this.type = type;
- this.pointsPerWin = pointsPerWin;
- this.pointsPerLoss = pointsPerLoss;
- this.pointsPerDraw = pointsPerDraw;
- }
-
- private Map points;
-
- public List getFights() {
- return EventFight.get(this);
- }
-
- public Set getTeamsId() {
- return getFights().stream().flatMap(fight -> Stream.of(fight.getTeamBlue(), fight.getTeamRed()))
- .collect(Collectors.toSet());
- }
-
- public Set getTeams() {
- return getTeamsId().stream().map(Team::get).collect(Collectors.toSet());
- }
-
- public Optional getLastFight() {
- return EventFight.getLast(this);
- }
-
- public List getDependents() {
- return EventRelation.getGroupRelations(this);
- }
-
- public Map calculatePoints() {
- if (points == null) {
- Map p = getTeamsId().stream().collect(Collectors.toMap(team -> team, team -> 0));
-
- for (EventFight fight : getFights()) {
- int blueTeamAdd = 0;
- int redTeamAdd = 0;
-
- if (!fight.hasFinished()) {
- continue;
- }
-
- switch (fight.getErgebnis()) {
- case 1:
- blueTeamAdd += pointsPerWin;
- redTeamAdd += pointsPerLoss;
- break;
- case 2:
- blueTeamAdd += pointsPerLoss;
- redTeamAdd += pointsPerWin;
- break;
- case 0:
- if (fight.getFightID() != 0) {
- blueTeamAdd += pointsPerDraw;
- redTeamAdd += pointsPerDraw;
- }
- break;
- }
-
- p.put(fight.getTeamBlue(), p.get(fight.getTeamBlue()) + blueTeamAdd);
- p.put(fight.getTeamRed(), p.get(fight.getTeamRed()) + redTeamAdd);
- }
-
- points = p.entrySet().stream().collect(Collectors.toMap(integerIntegerEntry -> Team.get(integerIntegerEntry.getKey()), Map.Entry::getValue));
- }
-
- return points;
- }
-
- public void update(String name, EventGroupType type, int pointsPerWin, int pointsPerLoss, int pointsPerDraw) {
- update.update(name, type, pointsPerWin, pointsPerLoss, pointsPerDraw, id);
- this.name = name;
- this.type = type;
- this.pointsPerWin = pointsPerWin;
- this.pointsPerLoss = pointsPerLoss;
- this.pointsPerDraw = pointsPerDraw;
- }
-
- public boolean needsTieBreak() {
- return calculatePoints().values().stream().sorted().limit(2).distinct().count() < 2;
- }
-
- public void delete() {
- delete.update(id);
- }
-
- public static enum EventGroupType {
- GROUP_STAGE,
- ELIMINATION_STAGE
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/EventGroup.kt b/CommonCore/SQL/src/de/steamwar/sql/EventGroup.kt
new file mode 100644
index 00000000..5db01dbf
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/EventGroup.kt
@@ -0,0 +1,153 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.dao.IntEntity
+import org.jetbrains.exposed.v1.dao.IntEntityClass
+import java.util.*
+
+object EventGroupTable : IntIdTable("EventGroup", "Id") {
+ val event = reference("EventID", EventTable)
+ val name = varchar("Name", 64)
+ val type = enumeration("Type", EventGroup.EventGroupType::class)
+ val pointsPerWin = integer("PointsPerWin").default(3)
+ val pointsPerLoss = integer("PointsPerLoss").default(0)
+ val pointsPerDraw = integer("PointsPerDraw").default(1)
+}
+
+class EventGroup(id: EntityID) : IntEntity(id) {
+ companion object : IntEntityClass(EventGroupTable) {
+
+ @JvmStatic
+ fun get(event: Event) = useDb { find { EventGroupTable.event eq event.id }.toList() }
+
+ @JvmStatic
+ fun byId(groupId: Int) = useDb { Optional.ofNullable(findById(groupId)) }
+
+ @JvmStatic
+ fun create(event: Event, name: String, type: EventGroupType) = useDb {
+ new {
+ this.eventID = event.id.value
+ this.groupName = name
+ this.groupType = type
+ }
+ }
+ }
+
+ var eventID by EventGroupTable.event.transform({ EntityID(it, EventTable) }, { it.value })
+ private set
+ private var groupName by EventGroupTable.name
+ private var groupType by EventGroupTable.type
+ private var groupPointsPerWin by EventGroupTable.pointsPerWin
+ private var groupPointsPerLoss by EventGroupTable.pointsPerLoss
+ private var groupPointsPerDraw by EventGroupTable.pointsPerDraw
+ val fights by lazy { useDb { EventFight.find { EventFightTable.groupId eq id }.toList() } }
+ val teamsId by lazy { fights.flatMap { listOf(it.teamBlue, it.teamRed) }.toSet() }
+
+ var name: String
+ get() = groupName
+ set(value) {
+ groupName = value
+ }
+ var type: EventGroupType
+ get() = groupType
+ set(value) {
+ groupType = value
+ }
+ var pointsPerWin: Int
+ get() = groupPointsPerWin
+ set(value) {
+ groupPointsPerWin = value
+ }
+ var pointsPerLoss: Int
+ get() = groupPointsPerLoss
+ set(value) {
+ groupPointsPerLoss = value
+ }
+ var pointsPerDraw: Int
+ get() = groupPointsPerDraw
+ set(value) {
+ groupPointsPerDraw = value
+ }
+ val dependents by lazy { EventRelation.getGroupRelations(this).toList() }
+ val lastFight by lazy { Optional.ofNullable(fights.maxByOrNull { it.startTime }) }
+
+ fun getId() = id.value
+
+ private var points: Map? = null
+
+ fun calculatePoints(): Map {
+ if (points == null) {
+ val p: MutableMap = teamsId.associateWith { 0 }.toMutableMap()
+
+ for (fight in fights) {
+ var blueTeamAdd = 0
+ var redTeamAdd = 0
+
+ if (!fight.hasFinished()) {
+ continue
+ }
+
+ when (fight.ergebnis) {
+ 1 -> {
+ blueTeamAdd += pointsPerWin
+ redTeamAdd += pointsPerLoss
+ }
+ 2 -> {
+ blueTeamAdd += pointsPerLoss
+ redTeamAdd += pointsPerWin
+ }
+ 0 -> if (fight.fight != null) {
+ blueTeamAdd += pointsPerDraw
+ redTeamAdd += pointsPerDraw
+ }
+ }
+
+ p[fight.teamBlue] = p[fight.teamBlue]?.plus(blueTeamAdd) ?: blueTeamAdd
+ p[fight.teamRed] = p[fight.teamRed]?.plus(redTeamAdd) ?: redTeamAdd
+ }
+
+ return p.mapKeys { Team.byId(it.key) }.also { points = it }
+ } else {
+ return points!!
+ }
+ }
+
+ fun needsTieBreak() = calculatePoints().values.let { it.size == it.toSet().size }
+
+ fun update(name: String, type: EventGroupType, pointsPerWin: Int, pointsPerLoss: Int, pointsPerDraw: Int) = useDb {
+ this@EventGroup.name = name
+ this@EventGroup.type = type
+ this@EventGroup.pointsPerWin = pointsPerWin
+ this@EventGroup.pointsPerLoss = pointsPerLoss
+ this@EventGroup.pointsPerDraw = pointsPerDraw
+ }
+
+ override fun delete() = useDb { super.delete() }
+
+ enum class EventGroupType {
+ GROUP_STAGE,
+ ELIMINATION_STAGE
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/EventRelation.java b/CommonCore/SQL/src/de/steamwar/sql/EventRelation.java
deleted file mode 100644
index 539908de..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/EventRelation.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.*;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-@AllArgsConstructor
-@Getter
-@Setter
-public class EventRelation {
-
- static {
- SqlTypeMapper.ordinalEnumMapper(FightTeam.class);
- SqlTypeMapper.ordinalEnumMapper(FromType.class);
- }
-
- private static final Table table = new Table<>(EventRelation.class);
-
- private static final SelectStatement get = new SelectStatement<>(table, "SELECT * FROM EventRelation WHERE FromType = ? AND FromId = ?");
- private static final SelectStatement byId = new SelectStatement<>(table, "SELECT * FROM EventRelation WHERE id = ?");
- private static final SelectStatement byEvent = new SelectStatement<>(table, "SELECT ER.* FROM EventRelation ER JOIN EventFight EF ON EF.fightId = ER.fightId WHERE EF.EventID = ?");
- private static final Statement insert = table.insertFields(true, "fightId", "fightTeam", "fromType", "fromId", "fromPlace");
- private static final Statement update = table.update(Table.PRIMARY, "fromType", "fromId", "fromPlace");
- private static final Statement updateTeam = table.update(Table.PRIMARY, "fightTeam");
- private static final Statement delete = table.delete(Table.PRIMARY);
-
- public static List get(Event event) {
- return byEvent.listSelect(event.getEventID());
- }
-
- public static EventRelation get(int id) {
- return byId.select(id);
- }
-
- public static List getFightRelations(EventFight fight) {
- return get.listSelect(FromType.FIGHT, fight.getFightID());
- }
-
- public static List getGroupRelations(EventGroup group) {
- return get.listSelect(FromType.GROUP, group.getId());
- }
-
- public static EventRelation create(EventFight fight, FightTeam fightTeam, FromType fromType, int fromId, int fromPlace) {
- int id = insert.insertGetKey(fight.getFightID(), fightTeam, fromType, fromId, fromPlace);
- return get(id);
- }
-
- @Field(keys = Table.PRIMARY)
- private final int id;
-
- @Field
- private int fightId;
-
- @Field
- private FightTeam fightTeam;
-
- @Field
- private FromType fromType;
-
- @Field
- private int fromId;
-
- @Field
- private int fromPlace;
-
- public EventFight getFight() {
- return EventFight.get(fightId);
- }
-
- public Optional getFromFight() {
- if(fromType == FromType.FIGHT) {
- return Optional.of(EventFight.get(fromId));
- } else {
- return Optional.empty();
- }
- }
-
- public Optional getFromGroup() {
- if(fromType == FromType.GROUP) {
- return EventGroup.get(fromId);
- } else {
- return Optional.empty();
- }
- }
-
- public void delete() {
- delete.update(id);
- }
-
- public void setUpdateTeam(FightTeam team) {
- updateTeam.update(id, team);
- this.fightTeam = team;
- }
-
- public void setFromFight(EventFight fight, int place) {
- setFrom(fight.getFightID(), place, FromType.FIGHT);
- }
-
- public void setFromGroup(EventGroup group, int place) {
- setFrom(group.getId(), place, FromType.GROUP);
- }
-
- private void setFrom(int fightId, int place, FromType type) {
- update.update(type, fightId, place, id);
- this.fromType = type;
- this.fromId = fightId;
- this.fromPlace = place;
- }
-
- public Optional getAdvancingTeam() {
- if (fromType == FromType.FIGHT) {
- if (fromPlace == 0) {
- return getFromFight().flatMap(EventFight::getWinner);
- } else {
- return getFromFight().flatMap(EventFight::getLosser);
- }
- } else if (fromType == FromType.GROUP) {
- return getFromGroup().map(EventGroup::calculatePoints)
- .flatMap(points -> points.entrySet().stream()
- .sorted(Map.Entry.comparingByValue().reversed())
- .skip(fromPlace)
- .findFirst()
- .map(Map.Entry::getKey));
- } else {
- return Optional.empty();
- }
- }
-
- public boolean apply() {
- Optional team = getAdvancingTeam().map(Team::getTeamId);
- if(!team.isPresent())
- return false;
-
- EventFight fight = getFight();
- if(fightTeam == FightTeam.RED) {
- fight.update(
- fight.getStartTime(),
- fight.getSpielmodus(),
- fight.getMap(),
- fight.getTeamBlue(),
- team.get(),
- fight.getSpectatePort()
- );
- } else {
- fight.update(
- fight.getStartTime(),
- fight.getSpielmodus(),
- fight.getMap(),
- team.get(),
- fight.getTeamRed(),
- fight.getSpectatePort()
- );
- }
-
- return true;
- }
-
- public static enum FightTeam {
- BLUE,
- RED
- }
-
- public static enum FromType {
- FIGHT,
- GROUP
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/EventRelation.kt b/CommonCore/SQL/src/de/steamwar/sql/EventRelation.kt
new file mode 100644
index 00000000..0ca7be22
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/EventRelation.kt
@@ -0,0 +1,149 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.and
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.dao.IntEntity
+import org.jetbrains.exposed.v1.dao.IntEntityClass
+import org.jetbrains.exposed.v1.jdbc.select
+
+object EventRelationTable : IntIdTable("EventRelation") {
+ val fightId = reference("FightId", EventFightTable)
+ val fightTeam = enumeration("FightTeam", EventRelation.FightTeam::class)
+ val fromType = enumeration("FromType", EventRelation.FromType::class)
+ val fromId = integer("FromId")
+ val fromPlace = integer("FromPlace")
+}
+
+class EventRelation(id: EntityID) : IntEntity(id) {
+ companion object : IntEntityClass(EventRelationTable) {
+ @JvmStatic
+ fun get(event: Event) = useDb {
+ EventRelationTable.innerJoin(EventFightTable)
+ .select(EventRelationTable.columns)
+ .where { EventFightTable.eventId eq event.id }
+ .map { wrapRow(it) }
+ }
+
+ @JvmStatic
+ fun byId(id: Int) = useDb { findById(id) }
+
+ @JvmStatic
+ fun getFightRelations(fight: EventFight) =
+ useDb { find { (EventRelationTable.fromId eq fight.id.value) and (EventRelationTable.fromType eq FromType.FIGHT) } }
+
+ @JvmStatic
+ fun getGroupRelations(group: EventGroup) =
+ useDb { find { (EventRelationTable.fromId eq group.id.value) and (EventRelationTable.fromType eq FromType.GROUP) } }
+
+ @JvmStatic
+ fun create(fight: EventFight, fightTeam: FightTeam, fromType: FromType, fromId: Int, fromPlace: Int) = useDb {
+ new {
+ this.fightEntityId = fight.id
+ this.fightTeam = fightTeam
+ this.fromType = fromType
+ this.fromId = fromId
+ this.fromPlace = fromPlace
+ }
+ }
+ }
+
+ var fightEntityId by EventRelationTable.fightId
+ var fightId: Int
+ get() = fightEntityId.value
+ set(value) = useDb { fightEntityId = EntityID(value, EventFightTable) }
+ val fight by lazy { useDb { EventFight[fightEntityId] } }
+ var fightTeam by EventRelationTable.fightTeam
+ private set
+ var fromType by EventRelationTable.fromType
+ private set
+ var fromId by EventRelationTable.fromId
+ private set
+
+ var fromFightId: Int?
+ get() = if (fromType == FromType.FIGHT) fromId else null
+ set(value) = useDb {
+ fromType = FromType.FIGHT
+ fromId = value!!
+ }
+ val fromFight: EventFight?
+ get() = fromFightId?.let { useDb { EventFight[it] } }
+ var fromGroupId: Int?
+ get() = if (fromType == FromType.GROUP) fromId else null
+ set(value) = useDb {
+ fromType = FromType.GROUP
+ fromId = value!!
+ }
+ val fromGroup: EventGroup?
+ get() = fromGroupId?.let { useDb { EventGroup[it] } }
+ var fromPlace by EventRelationTable.fromPlace
+ private set
+
+ fun getId() = id.value
+ fun setUpdateTeam(team: FightTeam) = useDb {
+ fightTeam = team
+ }
+
+ fun setFromFight(fight: EventFight, place: Int) = useDb {
+ fromType = FromType.FIGHT
+ fromId = fight.id.value
+ fromPlace = place
+ }
+
+ fun setFromGroup(group: EventGroup, place: Int) = useDb {
+ fromType = FromType.GROUP
+ fromId = group.id.value
+ fromPlace = place
+ }
+
+ fun getAdvancingTeam(): Team? = useDb { when(fromType) {
+ FromType.FIGHT -> if (fromPlace == 0) fromFight?.winner else fromFight?.losser
+ FromType.GROUP -> fromGroup?.calculatePoints()?.toList()?.sortedBy { (_, v) -> v }?.reversed()?.elementAt(fromPlace)?.first
+ } }
+
+ fun apply(): Boolean {
+ val team = getAdvancingTeam() ?: return false
+
+ useDb {
+ when(fightTeam) {
+ FightTeam.BLUE -> fight.teamBlue = team.teamId
+ FightTeam.RED -> fight.teamRed = team.teamId
+ }
+ }
+
+ return true
+ }
+
+ override fun delete() = useDb {
+ super.delete()
+ }
+
+ enum class FightTeam {
+ BLUE, RED
+ }
+
+ enum class FromType {
+ FIGHT, GROUP
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/Fight.java b/CommonCore/SQL/src/de/steamwar/sql/Fight.java
deleted file mode 100644
index b1f122b2..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/Fight.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.sql.Timestamp;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-@AllArgsConstructor
-public class Fight {
-
- private static final Table table = new Table<>(Fight.class);
- private static final SelectStatement getPage = new SelectStatement<>(table, "SELECT f.*, (b.NodeId IS NULL OR b.Config & 2) AND (r.NodeId IS NULL OR r.Config & 2) AS ReplayAllowed FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId ORDER BY FightID DESC LIMIT ?, ?");
- private static final SelectStatement getById = new SelectStatement<>(table, "SELECT f.*, (b.NodeId IS NULL OR b.Config & 2) AND (r.NodeId IS NULL OR r.Config & 2) AS ReplayAllowed FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId WHERE FightId = ?");
- private static final Statement insert = table.insertFields(true, "GameMode", "Server", "StartTime", "Duration", "BlueLeader", "RedLeader", "BlueSchem", "RedSchem", "Win", "WinCondition");
- private static final Statement updateReplayAvailable = table.update(Table.PRIMARY, "ReplayAvailable");
-
- public static List getPage(int page, int elementsPerPage) {
- List fights = getPage.listSelect(page * elementsPerPage, elementsPerPage);
-
- List fightPlayers = FightPlayer.batchGet(fights.stream().map(f -> f.fightID));
- for(Fight fight : fights) {
- fight.initPlayers(fightPlayers);
- }
-
- SteamwarUser.batchCache(fightPlayers.stream().map(FightPlayer::getUserID).collect(Collectors.toSet()));
- return fights;
- }
-
- public static Fight getById(int fightID) {
- return getById.select(fightID);
- }
-
- 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);
- }
-
- public static void markReplayAvailable(int fightID) {
- updateReplayAvailable.update(true, fightID);
- }
-
- @Getter
- @Field(keys = {Table.PRIMARY}, autoincrement = true)
- private final int fightID;
- @Field
- private final String gameMode;
- @Getter
- @Field
- private final String server;
- @Getter
- @Field
- private final Timestamp startTime;
- @Field
- private final int duration;
- @Field
- private final int blueLeader;
- @Field
- private final int redLeader;
- @Field(nullable = true)
- private final Integer blueSchem;
- @Field(nullable = true)
- private final Integer redSchem;
- @Getter
- @Field
- private final int win;
- @Field
- private final String wincondition;
- @Field
- private final boolean replayAvailable;
- @Field // Virtual field for easy select
- private final boolean replayAllowed;
-
- @Getter
- private final List bluePlayers = new ArrayList<>();
- @Getter
- private final List redPlayers = new ArrayList<>();
-
- public SchematicType getSchemType() {
- return SchematicType.fromDB(gameMode);
- }
-
- public SteamwarUser getBlueLeader() {
- return SteamwarUser.get(blueLeader);
- }
-
- public SteamwarUser getRedLeader() {
- return SteamwarUser.get(redLeader);
- }
-
- public boolean replayAllowed() {
- return replayExists() && replayAllowed;
- }
-
- public boolean replayExists() {
- return getSchemType() != null && replayAvailable;
- }
-
- private void initPlayers(List fightPlayers) {
- for(FightPlayer fp : fightPlayers) {
- if(fp.getFightID() != fightID)
- continue;
-
- if(fp.getTeam() == 1)
- bluePlayers.add(fp);
- else
- redPlayers.add(fp);
- }
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/Fight.kt b/CommonCore/SQL/src/de/steamwar/sql/Fight.kt
new file mode 100644
index 00000000..d64d7583
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/Fight.kt
@@ -0,0 +1,162 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.IntegerColumnType
+import org.jetbrains.exposed.v1.core.ReferenceOption
+import org.jetbrains.exposed.v1.core.SortOrder
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.dao.IntEntity
+import org.jetbrains.exposed.v1.dao.IntEntityClass
+import org.jetbrains.exposed.v1.javatime.timestamp
+import org.jetbrains.exposed.v1.jdbc.insertAndGetId
+import org.jetbrains.exposed.v1.jdbc.update
+import java.sql.Timestamp
+
+object FightTable : IntIdTable("Fight", "FightId") {
+ val gamemode = varchar("Gamemode", 30)
+ val server = text("Server")
+ val startTime = timestamp("StartTime")
+ val duration = integer("Duration")
+ val blueLeader = reference("BlueLeader", SteamwarUserTable)
+ val redLeader = reference("RedLeader", SteamwarUserTable)
+ val blueSchem = optReference("BlueSchem", SchematicNodeTable, onDelete = ReferenceOption.SET_NULL)
+ val redSchem = optReference("RedSchem", SchematicNodeTable, onDelete = ReferenceOption.SET_NULL)
+ val win = enumeration("Win", Fight.WinningTeam::class)
+ val winCondition = varchar("WinCondition", 100)
+ val replayAvailable = bool("ReplayAvailable")
+}
+
+class Fight(id: EntityID) : IntEntity(id) {
+ companion object : IntEntityClass(FightTable) {
+ @JvmStatic
+ fun getById(id: Int) = useDb { get(id) }
+
+ @JvmStatic
+ fun create(
+ gamemode: String,
+ server: String,
+ starttime: Timestamp,
+ duration: Int,
+ blueleader: Int,
+ redleader: Int,
+ blueschem: Int?,
+ redschem: Int?,
+ win: Int,
+ wincondition: String
+ ): Int = useDb {
+ FightTable.insertAndGetId {
+ it[FightTable.gamemode] = gamemode
+ it[FightTable.server] = server
+ it[FightTable.startTime] = starttime.toInstant()
+ it[FightTable.duration] = duration
+ it[FightTable.blueLeader] = EntityID(blueleader, SteamwarUserTable)
+ it[FightTable.redLeader] = EntityID(redleader, SteamwarUserTable)
+ it[FightTable.blueSchem] = blueschem?.let { EntityID(it, SchematicNodeTable) }
+ it[FightTable.redSchem] = redschem?.let { EntityID(it, SchematicNodeTable) }
+ it[FightTable.win] = WinningTeam.entries[win]
+ it[FightTable.winCondition] = wincondition
+ }.value
+ }
+
+ @JvmStatic
+ fun getPage(page: Int, pageSize: Int): List = useDb {
+ val fights = all().orderBy(FightTable.startTime to SortOrder.DESC).limit(pageSize).offset((pageSize * page).toLong())
+
+ val fightPlayer = FightPlayer.batchGet(fights.map { it.id.value })
+ for (fight in fights) {
+ fight.initPlayers(fightPlayer)
+ }
+
+ SteamwarUser.batchCache(fightPlayer.map { it.userID }.toMutableSet())
+ fights.toList()
+ }
+
+ @JvmStatic
+ fun markReplayAvailable(id: Int) = useDb {
+ FightTable.update({ FightTable.id eq id }) {
+ it[replayAvailable] = true
+ }
+ }
+ }
+
+ val fightID by FightTable.id.transform({ EntityID(it, FightTable) }, { it.value })
+ val gameMode by FightTable.gamemode
+ val server by FightTable.server
+ val startTime by FightTable.startTime.transform({ it.toInstant() }, { Timestamp.from(it) })
+ val duration by FightTable.duration
+ val blueLeaderId by FightTable.blueLeader
+ val blueLeader by lazy { useDb { SteamwarUser[blueLeaderId] } }
+ val redLeaderId by FightTable.redLeader
+ val redLeader by lazy { useDb { SteamwarUser[redLeaderId] } }
+ val blueSchem by FightTable.blueSchem
+ val redSchem by FightTable.redSchem
+ val winner by FightTable.win
+ val win: Int
+ get() = winner.ordinal
+ val winCondition by FightTable.winCondition
+ val replayAvailable by FightTable.replayAvailable
+
+ val schemType: SchematicType?
+ get() = SchematicType.fromDB(gameMode)
+
+ val replayAllowed by lazy {
+ replayExists() && useDb {
+ exec(
+ "SELECT (b.NodeId IS NULL OR b.Config & 2) AND (r.NodeId IS NULL OR r.Config & 2) AS ReplayAllowed FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId WHERE FightId = ?",
+ args = listOf(IntegerColumnType() to this@Fight.id.value)
+ ) {
+ if (it.next()) {
+ it.getBoolean("ReplayAllowed")
+ } else {
+ false
+ }
+ } ?: false
+ }
+ }
+
+ fun replayExists() = schemType != null && replayAvailable
+ fun replayAllowed() = replayAllowed
+
+ lateinit var bluePlayers: List
+ lateinit var redPlayers: List
+
+ private fun initPlayers(fightPlayers: List) {
+ val blue = mutableListOf()
+ val red = mutableListOf()
+
+ for (player in fightPlayers.filter { it.fightID == id.value }) {
+ if (player.team == 1)
+ blue.add(player)
+ else
+ red.add(player)
+ }
+
+ bluePlayers = blue
+ redPlayers = red
+ }
+
+ enum class WinningTeam {
+ NONE, BLUE, RED;
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/FightPlayer.java b/CommonCore/SQL/src/de/steamwar/sql/FightPlayer.java
deleted file mode 100644
index c45ec806..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/FightPlayer.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-@AllArgsConstructor
-public class FightPlayer {
-
- private static final Table table = new Table<>(FightPlayer.class);
- private static final Statement create = table.insertAll();
- private static final SelectStatement batchGet = new SelectStatement<>(table, "SELECT * FROM FightPlayer WHERE FightID IN ?");
-
- @Getter
- @Field(keys = {Table.PRIMARY})
- private final int fightID;
- @Getter
- @Field(keys = {Table.PRIMARY})
- private final int userID;
- @Getter
- @Field
- private final int team;
- @Field
- private final String kit;
- @Field
- private final int kills;
- @Field
- private final boolean isOut;
-
- public static void create(int fightID, int userID, boolean blue, String kit, int kills, boolean isOut) {
- create.update(fightID, userID, blue ? 1 : 2, kit, kills, isOut);
- }
-
- public static List batchGet(Stream fightIds) {
- try (SelectStatement batch = new SelectStatement<>(table, "SELECT * FROM FightPlayer WHERE FightID IN (" + fightIds.map(Object::toString).collect(Collectors.joining(", ")) + ")")) {
- return batch.listSelect();
- }
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/FightPlayer.kt b/CommonCore/SQL/src/de/steamwar/sql/FightPlayer.kt
new file mode 100644
index 00000000..d0238c96
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/FightPlayer.kt
@@ -0,0 +1,80 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.dao.id.CompositeID
+import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.inList
+import org.jetbrains.exposed.v1.dao.CompositeEntity
+import org.jetbrains.exposed.v1.dao.CompositeEntityClass
+import org.jetbrains.exposed.v1.jdbc.insertIgnore
+
+object FightPlayerTable : CompositeIdTable("FightPlayer") {
+ val fightId = reference("FightId", FightTable)
+ val userId = reference("UserId", SteamwarUserTable)
+ val team = integer("Team")
+ val kit = varchar("Kit", 64)
+ val kills = integer("Kills")
+ val out = bool("IsOut")
+
+ init {
+ addIdColumn(fightId)
+ addIdColumn(userId)
+ }
+}
+
+class FightPlayer(id: EntityID) : CompositeEntity(id) {
+ companion object : CompositeEntityClass(FightPlayerTable) {
+ @JvmStatic
+ fun create(
+ fightId: Int,
+ userId: Int,
+ blue: Boolean,
+ kit: String,
+ kills: Int,
+ out: Boolean
+ ) = useDb {
+ FightPlayerTable.insertIgnore {
+ it[this.fightId] = fightId
+ it[this.userId] = userId
+ it[this.team] = if (blue) 1 else 2
+ it[this.kit] = kit
+ it[this.kills] = kills
+ it[this.out] = out
+ }
+ }
+
+ @JvmStatic
+ fun batchGet(fightIds: List) = useDb {
+ find { FightPlayerTable.fightId inList fightIds.toList() }.toList()
+ }
+ }
+
+ val fightID by FightPlayerTable.fightId.transform({ EntityID(it, FightTable) }, { it.value })
+ val userID by FightPlayerTable.userId.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
+ val team by FightPlayerTable.team
+ val kit by FightPlayerTable.kit
+ val kills by FightPlayerTable.kills
+ val out by FightPlayerTable.out
+
+ fun isOut() = out
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java b/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java
index c7e9ecf8..2a737508 100644
--- a/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java
+++ b/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java
@@ -35,11 +35,19 @@ import java.util.stream.Collectors;
public final class GameModeConfig {
public static final Function ToString = Function.identity();
- public static final Function ToStaticWarGear = __ -> "WarGear";
- public static final Function ToInternalName = file -> file != null ? file.getName().replace(".yml", "") : "WarGear";
+ public static final Function ToStaticWarGear = GameModeConfig::constWarGear;
+ public static final Function ToInternalName = GameModeConfig::internalName;
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy HH:mm");
private static final Random random = new Random();
+ private static String constWarGear(File f) {
+ return "WarGear";
+ }
+
+ private static String internalName(File f) {
+ return f != null ? f.getName().replace(".yml", "") : constWarGear(null);
+ }
+
private static final Map> byFileName;
private static final Map> byGameName;
private static final Map> bySchematicType;
@@ -63,11 +71,15 @@ public final class GameModeConfig {
}
private static final Field Schematic_TypeField;
+ private static final Field Schematic_SubTypesField;
static {
try {
Schematic_TypeField = SchematicConfig.class.getDeclaredField("Type");
Schematic_TypeField.setAccessible(true);
+
+ Schematic_SubTypesField = SchematicConfig.class.getDeclaredField("SubTypes");
+ Schematic_SubTypesField.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new SecurityException(e.getMessage(), e);
}
@@ -77,6 +89,18 @@ public final class GameModeConfig {
bySchematicType = new HashMap<>();
SchematicType.values();
DEFAULTS = SQLWrapper.impl.loadGameModeConfig(null);
+
+ byFileName.values().forEach(gameModeConfig -> {
+ List subTypes = Collections.unmodifiableList(gameModeConfig.Schematic.SubTypesStrings.stream()
+ .map(SchematicType::fromDB)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList()));
+ try {
+ Schematic_SubTypesField.set(gameModeConfig.Schematic, subTypes);
+ } catch (IllegalAccessException e) {
+ throw new SecurityException(e.getMessage(), e);
+ }
+ });
}
public final boolean loaded;
@@ -516,6 +540,8 @@ public final class GameModeConfig {
*/
public final SchematicType Type;
+ private final List SubTypesStrings;
+
/**
* The schematic types that are also allowed to be chosen in this arena
*/
@@ -605,6 +631,13 @@ public final class GameModeConfig {
*/
public final int MaxDispenserItems;
+ /**
+ * Maximal blast resistance for the blocks
+ *
+ * @implSpec {@code Double.MAX_VALUE} by default
+ */
+ public final double MaxBlastResistance;
+
/**
* Maximal blast resistance for the design blocks
*
@@ -623,6 +656,7 @@ public final class GameModeConfig {
Size = new SizeConfig(loader.with("Size"));
Inset = new InsetConfig(loader.with("Inset"));
Type = loader.getSchematicType("Type", "Normal");
+ SubTypesStrings = loader.getStringList("SubTypes");
SubTypes = loader.getSchematicTypeList("SubTypes");
Shortcut = loader.getString("Shortcut", "");
Material = loader.getMaterial("Material", "STONE_BUTTON");
@@ -636,6 +670,7 @@ public final class GameModeConfig {
UnlimitedPrepare = loader.getBoolean("UnlimitedPrepare", false);
MaxBlocks = loader.getInt("MaxBlocks", 0);
MaxDispenserItems = loader.getInt("MaxDispenserItems", 128);
+ MaxBlastResistance = loader.getDouble("MaxBlastResistance", Double.MAX_VALUE);
MaxDesignBlastResistance = loader.getDouble("MaxDesignBlastResistance", Double.MAX_VALUE);
Map, Integer> Limited = new HashMap<>();
@@ -650,6 +685,10 @@ public final class GameModeConfig {
Limited.put(Collections.unmodifiableSet(materials.stream().map(String::toUpperCase).map(loader.materialMapper).collect(Collectors.toSet())), amount);
}
}
+ SQLWrapper.impl.getMaterialWithGreaterBlastResistance(MaxBlastResistance).forEach(material -> {
+ if (Limited.entrySet().stream().anyMatch(entry -> entry.getKey().contains(material))) return;
+ Limited.put(Collections.singleton((M) material), 0);
+ });
this.Limited = Collections.unmodifiableMap(Limited);
}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/IgnoreSystem.java b/CommonCore/SQL/src/de/steamwar/sql/IgnoreSystem.java
deleted file mode 100644
index c0c38cc8..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/IgnoreSystem.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.AllArgsConstructor;
-
-import java.sql.ResultSet;
-import java.util.UUID;
-
-@AllArgsConstructor
-public class IgnoreSystem {
-
- private static final Table table = new Table<>(IgnoreSystem.class, "IgnoredPlayers");
- private static final SelectStatement select = table.select(Table.PRIMARY);
- private static final Statement insert = table.insertAll();
- private static final Statement delete = table.delete(Table.PRIMARY);
-
- @Field(keys = {Table.PRIMARY})
- private final int ignorer;
- @Field(keys = {Table.PRIMARY})
- private final int ignored;
-
- public static boolean isIgnored(UUID ignorer, UUID ignored){
- return isIgnored(SteamwarUser.get(ignorer), SteamwarUser.get(ignored));
- }
-
- public static boolean isIgnored(SteamwarUser ignorer, SteamwarUser ignored) {
- return select.select(ResultSet::next, ignorer.getId(), ignored.getId());
- }
-
- public static void ignore(SteamwarUser ignorer, SteamwarUser ignored) {
- insert.update(ignorer.getId(), ignored.getId());
- }
-
- public static void unIgnore(SteamwarUser ignorer, SteamwarUser ignored) {
- delete.update(ignorer.getId(), ignored.getId());
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/IgnoreSystem.kt b/CommonCore/SQL/src/de/steamwar/sql/IgnoreSystem.kt
new file mode 100644
index 00000000..9df3a8cf
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/IgnoreSystem.kt
@@ -0,0 +1,74 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.and
+import org.jetbrains.exposed.v1.core.dao.id.CompositeID
+import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.dao.CompositeEntity
+import org.jetbrains.exposed.v1.dao.CompositeEntityClass
+import java.util.*
+
+object IgnoreSystemTable: CompositeIdTable("IgnoredPlayers") {
+ val ignorer = reference("Ignorer", SteamwarUserTable)
+ val ignored = reference("Ignored", SteamwarUserTable)
+
+ override val primaryKey = PrimaryKey(ignorer, ignored)
+
+ init {
+ addIdColumn(ignorer)
+ addIdColumn(ignored)
+ }
+}
+
+class IgnoreSystem(id: EntityID) : CompositeEntity(id) {
+ var ignorer by IgnoreSystemTable.ignorer
+ var ignored by IgnoreSystemTable.ignored
+
+ companion object : CompositeEntityClass(IgnoreSystemTable) {
+ @JvmStatic
+ fun isIgnored(ignorer: UUID, ignored: UUID) = useDb { isIgnored(SteamwarUser.get(ignorer)!!, SteamwarUser.get(ignored)!!) }
+
+ @JvmStatic
+ fun isIgnored(ignorer: SteamwarUser, ignored: SteamwarUser) = useDb {
+ find {
+ (IgnoreSystemTable.ignorer eq ignorer.id) and (IgnoreSystemTable.ignored eq ignored.id)
+ }.firstOrNull() != null
+ }
+
+ @JvmStatic
+ fun ignore(ignorer: SteamwarUser, ignored: SteamwarUser) = useDb {
+ new {
+ this.ignorer = ignorer.id
+ this.ignored = ignored.id
+ }
+ }
+
+ @JvmStatic
+ fun unIgnore(ignorer: SteamwarUser, ignored: SteamwarUser) = useDb {
+ find {
+ (IgnoreSystemTable.ignorer eq ignorer.id) and (IgnoreSystemTable.ignored eq ignored.id)
+ }.firstOrNull()?.delete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/Leaderboard.kt b/CommonCore/SQL/src/de/steamwar/sql/Leaderboard.kt
new file mode 100644
index 00000000..8a6e3e47
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/Leaderboard.kt
@@ -0,0 +1,94 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.SortOrder
+import org.jetbrains.exposed.v1.core.and
+import org.jetbrains.exposed.v1.core.count
+import org.jetbrains.exposed.v1.core.dao.id.CompositeID
+import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.core.lessSubQuery
+import org.jetbrains.exposed.v1.dao.CompositeEntity
+import org.jetbrains.exposed.v1.dao.CompositeEntityClass
+import org.jetbrains.exposed.v1.dao.flushCache
+import org.jetbrains.exposed.v1.javatime.CurrentTimestamp
+import org.jetbrains.exposed.v1.javatime.timestamp
+import org.jetbrains.exposed.v1.jdbc.select
+import org.jetbrains.exposed.v1.jdbc.upsert
+
+object LeaderboardTable : CompositeIdTable("Leaderboard") {
+ val userId = reference("UserId", SteamwarUserTable)
+ val name = varchar("LeaderboardName", 64).entityId()
+ val time = long("Time")
+ val updatedAt = timestamp("UpdatedAt").defaultExpression(CurrentTimestamp)
+ val bestTime = bool("BestTime")
+
+ override val primaryKey = PrimaryKey(userId, name)
+
+ init {
+ addIdColumn(userId)
+ }
+}
+
+class Leaderboard(id: EntityID) : CompositeEntity(id) {
+ companion object : CompositeEntityClass(LeaderboardTable) {
+ @JvmStatic
+ fun getLeaderboard(name: String) = useDb {
+ find { LeaderboardTable.name eq name }.orderBy(LeaderboardTable.time to SortOrder.ASC).limit(5).toList()
+ }
+
+ @JvmStatic
+ fun getPlayerTime(user: SteamwarUser, name: String) = useDb {
+ find { (LeaderboardTable.userId eq user.id.value) and (LeaderboardTable.name eq name) }.firstOrNull()
+ }
+
+ @JvmStatic
+ fun getPlayerPlacement(user: SteamwarUser, name: String) = useDb {
+ LeaderboardTable.select(LeaderboardTable.time.count())
+ .where {
+ (LeaderboardTable.name eq name) and (LeaderboardTable.time lessSubQuery LeaderboardTable.select(
+ LeaderboardTable.time
+ ).where { (LeaderboardTable.userId eq user.id.value) and (LeaderboardTable.name eq name) })
+ }
+ .firstOrNull()?.get(LeaderboardTable.time.count())?.toInt() ?: Int.MAX_VALUE
+ }
+
+ @JvmStatic
+ fun upsert(userId: Int, name: String, time: Long, bestTime: Boolean) = useDb {
+ LeaderboardTable.upsert(
+ onUpdateExclude = listOf(LeaderboardTable.updatedAt, LeaderboardTable.userId, LeaderboardTable.name)
+ ) {
+ it[LeaderboardTable.userId] = userId
+ it[LeaderboardTable.name] = name
+ it[LeaderboardTable.time] = time
+ it[LeaderboardTable.bestTime] = bestTime
+ }
+ }
+ }
+
+ val user by LeaderboardTable.userId.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
+ val name by LeaderboardTable.name
+ var time by LeaderboardTable.time
+ var updatedAt by LeaderboardTable.updatedAt
+ var bestTime by LeaderboardTable.bestTime
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/Mod.java b/CommonCore/SQL/src/de/steamwar/sql/Mod.java
deleted file mode 100644
index 4d8fcd9d..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/Mod.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.*;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.List;
-
-@AllArgsConstructor
-public class Mod {
-
- static {
- SqlTypeMapper.ordinalEnumMapper(Platform.class);
- SqlTypeMapper.ordinalEnumMapper(ModType.class);
- }
-
- private static final Table table = new Table<>(Mod.class, "Mods");
- private static final SelectStatement get = table.select(Table.PRIMARY);
- private static final SelectStatement findFirst = new SelectStatement<>(table, "SELECT * FROM Mods WHERE ModType = 0 LIMIT 1");
- private static final SelectStatement getPageOfType = new SelectStatement<>(table, "SELECT * FROM Mods WHERE ModType = ? ORDER BY ModName DESC LIMIT ?, ?");
- private static final Statement insert = table.insert(Table.PRIMARY);
- private static final Statement set = table.update(Table.PRIMARY, "ModType");
-
- public static Mod get(String name, Platform platform) {
- return get.select(platform, name);
- }
-
- public static Mod getOrCreate(String name, Platform platform) {
- Mod mod = get(name, platform);
- if(mod != null)
- return mod;
-
- insert.update(platform, name);
- return new Mod(platform, name, ModType.UNKLASSIFIED);
- }
-
- public static List getAllModsFiltered(int page, int elementsPerPage, ModType filter) {
- return Mod.getPageOfType.listSelect(filter, page * elementsPerPage, elementsPerPage);
- }
-
- public static Mod findFirstMod() {
- return findFirst.select();
- }
-
- @Getter
- @Field(keys = {Table.PRIMARY})
- private final Platform platform;
- @Getter
- @Field(keys = {Table.PRIMARY})
- private final String modName;
- @Getter
- @Field(def = "0")
- private ModType modType;
-
- public void setModType(ModType modType) {
- set.update(modType, platform, modName);
- this.modType = modType;
- }
-
- public enum Platform {
- FORGE,
- LABYMOD,
- FABRIC
- }
-
- public enum ModType {
- UNKLASSIFIED("7"),
- GREEN("a"),
- YELLOW("e"),
- RED("c"),
- YOUTUBER_ONLY("6");
-
- ModType(String colorcode) {
- this.colorcode = colorcode;
- }
- private final String colorcode;
-
- public String getColorCode() {
- return colorcode;
- }
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/Mod.kt b/CommonCore/SQL/src/de/steamwar/sql/Mod.kt
new file mode 100644
index 00000000..9e3b4d50
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/Mod.kt
@@ -0,0 +1,88 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.SortOrder
+import org.jetbrains.exposed.v1.core.and
+import org.jetbrains.exposed.v1.core.dao.id.CompositeID
+import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.dao.CompositeEntity
+import org.jetbrains.exposed.v1.dao.CompositeEntityClass
+
+object ModTable : CompositeIdTable("Mods") {
+ val platform = enumeration("Platform", Mod.Platform::class)
+ val modName = varchar("ModName", 100)
+ val modeType = enumerationByName("ModType", 10, Mod.ModType::class)
+}
+
+class Mod(id: EntityID) : CompositeEntity(id) {
+ companion object : CompositeEntityClass(ModTable) {
+ @JvmStatic
+ fun get(modName: String, platform: Platform) = useDb {
+ find { ModTable.platform eq platform and (ModTable.modName eq modName) }.firstOrNull()
+ }
+
+ @JvmStatic
+ fun getOrCreate(modName: String, platform: Platform) = useDb {
+ get(modName, platform) ?: new {
+ this.platform = platform
+ this.modName = modName
+ this.type = ModType.UNKLASSIFIED
+ }
+ }
+
+ @JvmStatic
+ fun getAllModsFiltered(page: Int, elementsPerPage: Int, filter: ModType) = useDb {
+ find { ModTable.modeType eq filter }.limit(elementsPerPage).offset((elementsPerPage * page).toLong())
+ .orderBy(
+ ModTable.modName to SortOrder.DESC
+ ).toList()
+ }
+
+ @JvmStatic
+ fun findFirstMod() = useDb {
+ find { ModTable.modeType eq ModType.UNKLASSIFIED }.limit(1).firstOrNull()
+ }
+ }
+
+ var platform by ModTable.platform
+ var modName by ModTable.modName
+ private var type by ModTable.modeType
+ var modType: ModType
+ get() = type
+ set(value) = useDb { type = value }
+
+ enum class Platform {
+ FORGE,
+ LABYMOD,
+ FABRIC
+ }
+
+ enum class ModType(val colorCode: String) {
+ UNKLASSIFIED("7"),
+ GREEN("a"),
+ YELLOW("e"),
+ RED("c"),
+ YOUTUBER_ONLY("6");
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeData.java b/CommonCore/SQL/src/de/steamwar/sql/NodeData.java
deleted file mode 100644
index be0bbc95..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/NodeData.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.*;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import javax.swing.plaf.nimbus.State;
-import java.io.*;
-import java.sql.PreparedStatement;
-import java.sql.Timestamp;
-import java.time.Instant;
-import java.util.List;
-import java.util.Optional;
-import java.util.zip.GZIPInputStream;
-
-@AllArgsConstructor
-@Getter
-public class NodeData {
- static {
- new SqlTypeMapper<>(PipedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("PipedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
- new SqlTypeMapper<>(ByteArrayInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("ByteArrayInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
- new SqlTypeMapper<>(BufferedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("BufferedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
-
- SqlTypeMapper.ordinalEnumMapper(SchematicFormat.class);
- }
-
- private static final Table table = new Table<>(NodeData.class);
-
- private static final Statement updateDatabase = new Statement("INSERT INTO NodeData(NodeId, NodeFormat, SchemData) VALUES (?, ?, ?)", true);
- private static final Statement selSchemData = new Statement("SELECT SchemData FROM NodeData WHERE NodeId = ? AND CreatedAt = ?");
- private static final Statement delete = table.delete(Table.PRIMARY);
-
- private static final SelectStatement get = new SelectStatement<>(table, "SELECT NodeId, CreatedAt, NodeFormat FROM NodeData WHERE NodeId = ? ORDER BY CreatedAt ");
- private static final Statement getRevisions = new Statement("SELECT COUNT(DISTINCT CreatedAt) as CNT FROM NodeData WHERE NodeId = ?");
- private static final SelectStatement getLatest = new SelectStatement<>(table, "SELECT NodeId, CreatedAt, NodeFormat FROM NodeData WHERE NodeId = ? ORDER BY CreatedAt DESC LIMIT 1");
-
- public static NodeData getLatest(SchematicNode node) {
- if (node.isDir()) throw new IllegalArgumentException("Node is dir");
- return Optional.ofNullable(getLatest.select(node)).orElseGet(() -> new NodeData(node.getId(), Timestamp.from(Instant.now()), SchematicFormat.MCEDIT));
- }
-
- public static List get(SchematicNode node) {
- return get.listSelect(node);
- }
-
- public static NodeData get(SchematicNode node, int revision) {
- return get.listSelect(node).get(revision - 1);
- }
-
- public static int getRevisions(SchematicNode node) {
- return getRevisions.select(rs -> {
- if (rs.next()) {
- return rs.getInt("CNT");
- } else {
- return 0;
- }
- }, node);
- }
-
- public static void saveFromStream(SchematicNode node, InputStream blob, SchematicFormat format) {
- updateDatabase.update(node.getId(), format, blob);
- }
-
- @Field(keys = {Table.PRIMARY})
- private final int nodeId;
-
- @Field(keys = {Table.PRIMARY})
- private Timestamp createdAt;
-
- @Field
- private SchematicFormat nodeFormat;
-
- public InputStream schemData() throws IOException {
- return schemData(true);
- }
-
- public InputStream schemData(boolean decompress) throws IOException {
- try {
- return selSchemData.select(rs -> {
- rs.next();
- InputStream schemData = rs.getBinaryStream("SchemData");
- try {
- if(rs.wasNull() || schemData.available() == 0) {
- throw new SecurityException("SchemData is null");
- }
- if (decompress) {
- return new GZIPInputStream(schemData);
- } else {
- return schemData;
- }
- } catch (IOException e) {
- throw new SecurityException("SchemData is wrong", e);
- }
- }, nodeId, createdAt);
- } catch (Exception e) {
- throw new IOException(e);
- }
- }
-
- @Deprecated
- public void saveFromStream(InputStream blob, SchematicFormat newFormat) {
- saveFromStream(SchematicNode.getSchematicNode(nodeId), blob, newFormat);
- }
-
- public void delete() {
- delete.update(nodeId, createdAt);
- }
-
- @AllArgsConstructor
- @Getter
- public enum SchematicFormat {
- MCEDIT(".schematic"),
- SPONGE_V2(".schem"),
- SPONGE_V3(".schem");
-
- private final String fileEnding;
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeData.kt b/CommonCore/SQL/src/de/steamwar/sql/NodeData.kt
new file mode 100644
index 00000000..69552ac0
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/NodeData.kt
@@ -0,0 +1,100 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.SortOrder
+import org.jetbrains.exposed.v1.core.dao.id.CompositeID
+import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.core.statements.api.ExposedBlob
+import org.jetbrains.exposed.v1.dao.CompositeEntity
+import org.jetbrains.exposed.v1.dao.CompositeEntityClass
+import org.jetbrains.exposed.v1.javatime.CurrentTimestamp
+import org.jetbrains.exposed.v1.javatime.timestamp
+import org.jetbrains.exposed.v1.jdbc.insert
+import java.io.InputStream
+import java.util.zip.GZIPInputStream
+
+object NodeDataTable: CompositeIdTable("NodeData") {
+ val nodeId = reference("NodeId", SchematicNodeTable)
+ val createdAt = timestamp("CreatedAt").defaultExpression(CurrentTimestamp).entityId()
+ val nodeFormat = enumeration("NodeFormat", NodeData.SchematicFormat::class)
+ val schemData = blob("SchemData")
+
+ override val primaryKey = PrimaryKey(nodeId, createdAt)
+
+ init {
+ addIdColumn(nodeId)
+ }
+}
+
+class NodeData(id: EntityID): CompositeEntity(id) {
+ val nodeId by NodeDataTable.nodeId
+ val createdAt by NodeDataTable.createdAt
+ val nodeFormat by NodeDataTable.nodeFormat
+ val schemData by NodeDataTable.schemData
+
+ companion object: CompositeEntityClass(NodeDataTable) {
+ @JvmStatic
+ fun getLatest(node: SchematicNode) = useDb {
+ find { (NodeDataTable.nodeId eq node.nodeId) }.orderBy(NodeDataTable.createdAt to SortOrder.DESC).firstOrNull()
+ }
+
+ @JvmStatic
+ fun get(node: SchematicNode) = useDb {
+ find { (NodeDataTable.nodeId eq node.nodeId) }.orderBy(NodeDataTable.createdAt to SortOrder.ASC).toList()
+ }
+
+ @JvmStatic
+ fun get(node: SchematicNode, revision: Int) = useDb {
+ find { NodeDataTable.nodeId eq node.nodeId }.orderBy(NodeDataTable.createdAt to SortOrder.ASC).toList().get(revision - 1)
+ }
+
+ @JvmStatic
+ fun getRevisions(node: SchematicNode) = useDb {
+ count(NodeDataTable.nodeId eq node.nodeId).toInt()
+ }
+
+ @JvmStatic
+ fun saveFromStream(node: SchematicNode, blob: InputStream, format: SchematicFormat) = useDb {
+ NodeDataTable.insert {
+ it[NodeDataTable.nodeId] = EntityID(node.getId(), SchematicNodeTable)
+ it[NodeDataTable.nodeFormat] = format
+ it[NodeDataTable.schemData] = ExposedBlob(blob.readBytes())
+ }
+ }
+ }
+
+ fun schemData(decompress: Boolean) = useDb {
+ schemData.inputStream.let { if(decompress) GZIPInputStream(it) else it }
+ }
+
+ fun schemData() = schemData(true)
+
+ override fun delete() = useDb { super.delete() }
+
+ enum class SchematicFormat(val fileEnding: String) {
+ MCEDIT(".schematic"),
+ SPONGE_V2(".schem"),
+ SPONGE_V3(".schem");
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeDownload.java b/CommonCore/SQL/src/de/steamwar/sql/NodeDownload.java
deleted file mode 100644
index 6580b589..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/NodeDownload.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.sql.Timestamp;
-import java.time.Instant;
-
-@AllArgsConstructor
-public class NodeDownload {
-
- private static final char[] HEX = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
- private static final String LINK_BASE = "https://api.steamwar.de/download/";
-
- private static final Table table = new Table<>(NodeDownload.class);
- private static final Statement insert = table.insertFields("NodeId", "Link");
-
- private static final SelectStatement select = table.selectFields("link");
-
- private static final Statement delete = table.delete(Table.PRIMARY);
-
- public static NodeDownload get(String link) {
- return select.select(link);
- }
-
- @Getter
- @Field(keys = {Table.PRIMARY})
- private final int nodeId;
- @Field
- private final String link;
- @Field(def = "CURRENT_TIMESTAMP")
- @Getter
- 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();
- }
-
- public void delete() {
- delete.update(nodeId);
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeDownload.kt b/CommonCore/SQL/src/de/steamwar/sql/NodeDownload.kt
new file mode 100644
index 00000000..62de6038
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/NodeDownload.kt
@@ -0,0 +1,76 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.dao.id.IdTable
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.dao.IntEntity
+import org.jetbrains.exposed.v1.dao.IntEntityClass
+import org.jetbrains.exposed.v1.javatime.CurrentTimestamp
+import org.jetbrains.exposed.v1.javatime.timestamp
+import java.security.MessageDigest
+import java.sql.Timestamp
+import java.time.Instant
+
+object NodeDownloadTable: IdTable("NodeDownload") {
+ override val id = reference("NodeId", SchematicNodeTable).uniqueIndex()
+ val link = varchar("Link", 255)
+ val timestamp = timestamp("Timestamp").defaultExpression(CurrentTimestamp)
+}
+
+class NodeDownload(id: EntityID) : IntEntity(id) {
+ companion object : IntEntityClass(NodeDownloadTable) {
+ const val LINK_BASE = "https://api.steamwar.de/download/"
+
+ @JvmStatic
+ fun getLink(schem: SchematicNode): String {
+ if (schem.isDir())
+ throw IllegalArgumentException("Cannot get link for directory")
+
+ val digest = MessageDigest.getInstance("SHA-1")
+ digest.update("${Instant.now()}${schem.owner}${schem.nodeId}".toByteArray())
+ val hash = digest.digest().joinToString("") { "%02x".format(it) }
+ useDb {
+ findByIdAndUpdate(schem.id.value) {
+ it.link = hash
+ } ?: new {
+ nodeId = schem.id.value
+ link = hash
+ }
+ }
+ return "${LINK_BASE}${hash}"
+ }
+
+ @JvmStatic
+ fun get(link: String) = useDb {
+ find { NodeDownloadTable.link eq link }.firstOrNull()
+ }
+ }
+
+ var nodeId by NodeDownloadTable.id.transform({ EntityID(it, SchematicNodeTable) }, { it.value })
+ var link by NodeDownloadTable.link
+ var timestamp by NodeDownloadTable.timestamp.transform({ it.toInstant() }, { Timestamp.from(it) })
+
+ override fun delete() = useDb {
+ super.delete()
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeMember.java b/CommonCore/SQL/src/de/steamwar/sql/NodeMember.java
deleted file mode 100644
index 8b40b8be..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/NodeMember.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.AllArgsConstructor;
-
-import java.util.HashSet;
-import java.util.Optional;
-import java.util.Set;
-
-@AllArgsConstructor
-public class NodeMember {
-
- public static void init() {
- // enforce class initialization
- }
-
- private static final Table table = new Table<>(NodeMember.class);
- private static final SelectStatement getNodeMember = table.select(Table.PRIMARY);
- private static final SelectStatement getNodeMembers = table.selectFields("NodeId");
- private static final SelectStatement getSchematics = table.selectFields("UserId");
- private static final Statement create = table.insert(Table.PRIMARY);
- private static final Statement delete = table.delete(Table.PRIMARY);
- private static final Statement updateParent = table.update(Table.PRIMARY, "ParentId");
-
- @Field(keys = {Table.PRIMARY})
- private final int nodeId;
- @Field(keys = {Table.PRIMARY})
- private final int userId;
- @Field(nullable = true, def = "null")
- private Integer parentId;
-
- public int getNode() {
- return nodeId;
- }
-
- public int getMember() {
- return userId;
- }
-
- public Optional getParent() {
- return Optional.ofNullable(parentId);
- }
-
- public void delete() {
- delete.update(nodeId, userId);
- }
-
- public static NodeMember createNodeMember(int node, int member) {
- create.update(node, member);
- return new NodeMember(node, member, null);
- }
-
- public static NodeMember getNodeMember(int node, SteamwarUser member) {
- return getNodeMember(node, member.getId());
- }
-
- public static NodeMember getNodeMember(int node, int member) {
- return getNodeMember.select(node, member);
- }
-
- public static Set getNodeMembers(int node) {
- return new HashSet<>(getNodeMembers.listSelect(node));
- }
-
- public static Set getSchematics(int member) {
- return new HashSet<>(getSchematics.listSelect(member));
- }
-
- public void setParentId(Integer parentId) {
- this.parentId = parentId;
- updateParent.update(this.parentId, nodeId, userId);
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeMember.kt b/CommonCore/SQL/src/de/steamwar/sql/NodeMember.kt
new file mode 100644
index 00000000..cf6d951e
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/NodeMember.kt
@@ -0,0 +1,104 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.and
+import org.jetbrains.exposed.v1.core.dao.id.CompositeID
+import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.dao.CompositeEntity
+import org.jetbrains.exposed.v1.dao.CompositeEntityClass
+import org.jetbrains.exposed.v1.jdbc.insertIgnore
+import java.util.*
+import kotlin.jvm.optionals.getOrNull
+
+object NodeMemberTable : CompositeIdTable("NodeMember") {
+ val node = reference("NodeId", SchematicNodeTable)
+ val userId = reference("UserId", SteamwarUserTable)
+ val parentNode = optReference("ParentId", SchematicNodeTable)
+
+ override val primaryKey = PrimaryKey(node, userId)
+
+ init {
+ addIdColumn(node)
+ addIdColumn(userId)
+ }
+}
+
+class NodeMember(id: EntityID) : CompositeEntity(id) {
+ companion object : CompositeEntityClass(NodeMemberTable) {
+ @JvmStatic
+ fun createNodeMember(node: Int, member: Int): NodeMember = useDb {
+ NodeMemberTable.insertIgnore {
+ it[this.node] = EntityID(node, SchematicNodeTable)
+ it[this.userId] = EntityID(member, SteamwarUserTable)
+ }
+ getNodeMember(node, member) ?: throw IllegalStateException("NodeMember not created")
+ }
+
+ @JvmStatic
+ fun createNodeMember(node: Int, member: Int, parent: SchematicNode): NodeMember = useDb {
+ if (!parent.isDir()) throw IllegalStateException("Parent must be a directory")
+ NodeMemberTable.insertIgnore {
+ it[this.node] = EntityID(node, SchematicNodeTable)
+ it[this.userId] = EntityID(member, SteamwarUserTable)
+ it[NodeMemberTable.parentNode] = parent.getId()
+ }
+ getNodeMember(node, member) ?: throw IllegalStateException("NodeMember not created")
+ }
+
+ @JvmStatic
+ fun createNodeMember(node: Int, member: SteamwarUser) = createNodeMember(node, member.id.value)
+
+ @JvmStatic
+ fun getNodeMember(node: Int, member: Int) = useDb {
+ find { (NodeMemberTable.node eq node) and (NodeMemberTable.userId eq member) }.firstOrNull()
+ }
+
+ @JvmStatic
+ fun getNodeMember(node: Int, member: SteamwarUser) = getNodeMember(node, member.id.value)
+
+ @JvmStatic
+ fun getNodeMembers(node: Int) = useDb { find { NodeMemberTable.node eq node }.toSet() }
+
+ @JvmStatic
+ fun getSchematics(member: Int) = useDb { find { NodeMemberTable.userId eq member }.toSet() }
+
+ @JvmStatic
+ fun init() = Unit
+ }
+
+ val node by NodeMemberTable.node.transform({ EntityID(it, SchematicNodeTable) }, { it.value })
+ val member by NodeMemberTable.userId.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
+ var parent by NodeMemberTable.parentNode.transform(
+ { it.map { EntityID(it, SchematicNodeTable) }.getOrNull() },
+ { Optional.ofNullable(it?.value) })
+ private set
+
+ fun setParentId(id: Int?) {
+ parent = Optional.ofNullable(id)
+ }
+
+ override fun delete() = useDb {
+ super.delete()
+ }
+}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/PersonalKit.kt b/CommonCore/SQL/src/de/steamwar/sql/PersonalKit.kt
new file mode 100644
index 00000000..cd774d3c
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/PersonalKit.kt
@@ -0,0 +1,117 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.and
+import org.jetbrains.exposed.v1.core.dao.id.CompositeID
+import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.eq
+import org.jetbrains.exposed.v1.dao.CompositeEntity
+import org.jetbrains.exposed.v1.dao.CompositeEntityClass
+import org.jetbrains.exposed.v1.jdbc.insert
+
+object PersonalKitTable: CompositeIdTable("PersonalKit") {
+ val userId = reference("UserId", SteamwarUserTable)
+ val gamemode = varchar("Gamemode", 64).entityId()
+ val kitName = varchar("Name", 64).entityId()
+ val inventory = text("Inventory")
+ val armor = text("Armor")
+ val inUse = bool("InUse")
+
+ override val primaryKey = PrimaryKey(userId, gamemode, kitName)
+
+ init {
+ addIdColumn(userId)
+ }
+}
+
+class InternalKit(id: EntityID): CompositeEntity(id) {
+ companion object: CompositeEntityClass(PersonalKitTable) {
+ @JvmStatic
+ fun get(userId: Int, gamemode: String) = useDb {
+ find { PersonalKitTable.userId eq userId and (PersonalKitTable.gamemode eq gamemode) and (PersonalKitTable.inUse eq true) }
+ .toList()
+ }
+
+ @JvmStatic
+ fun get(userId: Int, gamemode: String, kitName: String) = useDb {
+ find { PersonalKitTable.userId eq userId and (PersonalKitTable.gamemode eq gamemode) and (PersonalKitTable.kitName eq kitName) and (PersonalKitTable.inUse eq true) }
+ .firstOrNull()
+ }
+
+ @JvmStatic
+ fun create(userId: Int, gamemode: String, kitName: String, rawInventory: String, rawArmor: String) = useDb {
+ new(
+ CompositeID {
+ it[PersonalKitTable.userId] = EntityID(userId, SteamwarUserTable)
+ it[PersonalKitTable.gamemode] = gamemode
+ it[PersonalKitTable.kitName] = kitName
+ }
+ ) {
+ this.inventory = rawInventory
+ this.armor = rawArmor
+ this.inUse = true
+ }
+ }
+
+ @JvmStatic
+ fun getKitInUse(userId: Int, gamemode: String) = useDb {
+ find { PersonalKitTable.userId eq userId and (PersonalKitTable.gamemode eq gamemode) and (PersonalKitTable.inUse eq true) }
+ .firstOrNull()
+ }
+ }
+
+ var userID by PersonalKitTable.userId.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
+ private set
+ private var gameMode by PersonalKitTable.gamemode
+ val gamemode: String
+ get() = gameMode.value
+
+ var kitName by PersonalKitTable.kitName
+ private set
+ val name: String
+ get() = kitName.value
+
+ var rawInventory by PersonalKitTable.inventory
+ private set
+ var rawArmor by PersonalKitTable.armor
+ private set
+ var inUse by PersonalKitTable.inUse
+ private set
+
+ var inventory: String
+ get() = rawInventory
+ set(value) = useDb { rawInventory = value }
+ var armor: String
+ get() = rawArmor
+ set(value) = useDb { rawArmor = value }
+
+ fun setDefault() = useDb {
+ find { PersonalKitTable.userId eq userID and (PersonalKitTable.gamemode eq gameMode) and (PersonalKitTable.inUse eq true) }
+ .forEach { it.inUse = false }
+ inUse = true
+ }
+
+ override fun delete() = useDb {
+ super.delete()
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/PollAnswer.java b/CommonCore/SQL/src/de/steamwar/sql/PollAnswer.java
deleted file mode 100644
index 9376ed18..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/PollAnswer.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.util.HashMap;
-import java.util.Map;
-
-@AllArgsConstructor
-public class PollAnswer {
-
- @Getter
- @Setter
- private static String currentPoll;
-
- private static final Table table = new Table<>(PollAnswer.class);
-
- private static final SelectStatement get = table.select(Table.PRIMARY);
- private static final Statement getResults = new Statement("SELECT Count(UserID) AS Times, Answer FROM PollAnswer WHERE Question = ? GROUP BY Answer ORDER BY Times ASC");
- private static final Statement insert = table.insertAll();
-
- @Field(keys = {Table.PRIMARY})
- private final int userID;
- @Field(keys = {Table.PRIMARY})
- private final String question;
- @Field(def = "0")
- private int answer;
-
- public static PollAnswer get(int userID) {
- PollAnswer answer = get.select(userID, currentPoll);
- if(answer == null)
- return new PollAnswer(userID, currentPoll, 0);
- return answer;
- }
-
- public static Map getCurrentResults() {
- return getResults.select(rs -> {
- Map retMap = new HashMap<>();
- while (rs.next())
- retMap.put(rs.getInt("Answer")-1, rs.getInt("Times"));
- return retMap;
- }, currentPoll);
- }
-
- public boolean hasAnswered(){
- return answer != 0;
- }
-
- public void setAnswer(int answer){
- this.answer = answer;
- insert.update(userID, question, answer);
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/Punishment.java b/CommonCore/SQL/src/de/steamwar/sql/Punishment.java
deleted file mode 100644
index 1cd61078..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/Punishment.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.*;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-import java.sql.Timestamp;
-import java.time.Instant;
-import java.time.format.DateTimeFormatter;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-
-@AllArgsConstructor
-public class Punishment {
-
- static {
- SqlTypeMapper.nameEnumMapper(PunishmentType.class);
- }
-
- public static final Timestamp PERMA_TIME = Timestamp.from(Instant.ofEpochSecond(946674800));
-
- private static final Table table = new Table<>(Punishment.class, "Punishments");
- private static final SelectStatement getPunishments = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE PunishmentId IN (SELECT MAX(PunishmentId) FROM Punishments WHERE UserId = ? GROUP BY Type)");
- private static final SelectStatement getPunishment = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE UserId = ? AND Type = ? ORDER BY PunishmentId DESC LIMIT 1");
- private static final SelectStatement getAllPunishments = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE UserId = ? ORDER BY `PunishmentId` DESC");
- private static final Statement insert = table.insertFields(true, "UserId", "Punisher", "Type", "EndTime", "Perma", "Reason");
-
- public static Punishment getPunishmentOfPlayer(int user, PunishmentType type) {
- return getPunishment.select(user, type);
- }
-
- public static Map getPunishmentsOfPlayer(int user) {
- return getPunishments.listSelect(user).stream().collect(Collectors.toMap(Punishment::getType, punishment -> punishment));
- }
-
- public static List getAllPunishmentsOfPlayer(int user) {
- return getAllPunishments.listSelect(user);
- }
-
- public static boolean isPunished(SteamwarUser user, PunishmentType type, Consumer callback) {
- Punishment punishment = Punishment.getPunishmentOfPlayer(user.getId(), type);
- if(punishment == null || !punishment.isCurrent()) {
- return false;
- } else {
- callback.accept(punishment);
- return true;
- }
- }
-
- public static Punishment createPunishment(int user, int executor, PunishmentType type, String reason, Timestamp endTime, boolean perma) {
- if(perma && !endTime.equals(PERMA_TIME)) {
- throw new IllegalArgumentException("Permanent punishments must have an end time of `Punishment.PERMA_TIME`");
- }
- int punishmentId = insert.insertGetKey(user, executor, type.name(), endTime, perma, reason);
- return new Punishment(punishmentId, user, executor, type, Timestamp.from(Instant.now()), endTime, perma, reason);
- }
-
- @Field(keys = {Table.PRIMARY}, autoincrement = true)
- private final int punishmentId;
- @Field
- @Getter
- private final int userId;
- @Field
- @Getter
- private final int punisher;
- @Field
- @Getter
- private final PunishmentType type;
- @Field
- @Getter
- private final Timestamp startTime;
- @Field
- @Getter
- private final Timestamp endTime;
- @Field
- @Getter
- private final boolean perma;
- @Field
- @Getter
- private final String reason;
-
- @Deprecated // Not multiling, misleading title
- public String getBantime(Timestamp endTime, boolean perma) {
- if (perma) {
- return "permanent";
- } else {
- return endTime.toLocalDateTime().format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"));
- }
- }
-
- public boolean isCurrent() {
- return isPerma() || getEndTime().after(new Date());
- }
-
- @AllArgsConstructor
- @RequiredArgsConstructor
- @Getter
- public enum PunishmentType {
- Ban(UserPerm.TEAM, "BAN_TEAM", "BAN_PERMA", "BAN_UNTIL", "UNBAN_ERROR", "UNBAN"),
- Mute( UserPerm.TEAM, "MUTE_TEAM", "MUTE_PERMA", "MUTE_UNTIL", "UNMUTE_ERROR", "UNMUTE"),
- NoSchemReceiving(UserPerm.MODERATION, "NOSCHEMRECEIVING_TEAM", "NOSCHEMRECEIVING_PERMA", "NOSCHEMRECEIVING_UNTIL", "UNNOSCHEMRECEIVING_ERROR", "UNNOSCHEMRECEIVING"),
- NoSchemSharing(UserPerm.MODERATION, "NOSCHEMSHARING_TEAM", "NOSCHEMSHARING_PERMA", "NOSCHEMSHARING_UNTIL", "UNNOSCHEMSHARING_ERROR", "UNNOSCHEMSHARING"),
- NoSchemSubmitting(UserPerm.TEAM, "NOSCHEMSUBMITTING_TEAM", "NOSCHEMSUBMITTING_PERMA", "NOSCHEMSUBMITTING_UNTIL", "UNNOSCHEMSUBMITTING_ERROR", "UNNOSCHEMSUBMITTING"),
- NoDevServer(UserPerm.PREFIX_DEVELOPER, "NODEVSERVER_TEAM", "NODEVSERVER_PERMA", "NODEVSERVER_UNTIL", "UNNODEVSERVER_ERROR", "UNNODEVSERVER"),
- NoFightServer(UserPerm.MODERATION, "NOFIGHTSERVER_TEAM", "NOFIGHTSERVER_PERMA", "NOFIGHTSERVER_UNTIL", "UNNOFIGHTSERVER_ERROR", "UNNOFIGHTSERVER"),
- NoTeamServer(UserPerm.MODERATION, "NOTEAMSERVER_TEAM", "NOTEAMSERVER_PERMA", "NOTEAMSERVER_UNTIL", "UNNOTEAMSERVER_ERROR", "UNNOTEAMSERVER"),
- Note(UserPerm.TEAM, "NOTE_TEAM", null, null, null, null, true);
-
- private final UserPerm userPerm;
- private final String teamMessage;
- private final String playerMessagePerma;
- private final String playerMessageUntil;
- private final String usageNotPunished;
- private final String unpunishmentMessage;
- private boolean multi = false;
- }
-}
diff --git a/CommonCore/SQL/src/de/steamwar/sql/Punishment.kt b/CommonCore/SQL/src/de/steamwar/sql/Punishment.kt
new file mode 100644
index 00000000..d2ad06ba
--- /dev/null
+++ b/CommonCore/SQL/src/de/steamwar/sql/Punishment.kt
@@ -0,0 +1,186 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.sql
+
+import de.steamwar.sql.internal.useDb
+import org.jetbrains.exposed.v1.core.*
+import org.jetbrains.exposed.v1.core.dao.id.EntityID
+import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
+import org.jetbrains.exposed.v1.dao.IntEntity
+import org.jetbrains.exposed.v1.dao.IntEntityClass
+import org.jetbrains.exposed.v1.javatime.timestamp
+import org.jetbrains.exposed.v1.jdbc.select
+import java.sql.Timestamp
+import java.time.Instant
+import java.util.*
+import java.util.function.Consumer
+
+object PunishmentTable : IntIdTable("Punishments", "PunishmentId") {
+ val userId = reference("UserId", SteamwarUserTable)
+ val punisher = reference("Punisher", SteamwarUserTable)
+ val type = enumerationByName("Type", 32, Punishment.PunishmentType::class)
+ val startTime = timestamp("StartTime")
+ val endTime = timestamp("EndTime")
+ val perma = bool("Perma")
+ val reason = text("Reason")
+}
+
+class Punishment(id: EntityID) : IntEntity(id) {
+ companion object : IntEntityClass(PunishmentTable) {
+ @JvmField
+ val PERMA_TIME: Timestamp = Timestamp.from(Instant.ofEpochSecond(946674800))
+
+ @JvmStatic
+ fun getPunsihmentOfPlayer(user: Int, type: PunishmentType) = useDb {
+ find { (PunishmentTable.userId eq user) and (PunishmentTable.type eq type) }.orderBy(PunishmentTable.id to SortOrder.DESC)
+ .firstOrNull()
+ }
+
+ @JvmStatic
+ fun getPunishmentsOfPlayer(user: Int) = useDb {
+ find {
+ PunishmentTable.id inSubQuery PunishmentTable.select(PunishmentTable.id.max())
+ .where { PunishmentTable.userId eq user }.groupBy(
+ PunishmentTable.type
+ )
+ }.associateBy { it.type }.toMutableMap()
+ }
+
+ @JvmStatic
+ fun getAllPunishmentsOfPlayer(user: Int) = useDb {
+ find { PunishmentTable.userId eq user }.orderBy(PunishmentTable.id to SortOrder.DESC).toList()
+ }
+
+ @JvmStatic
+ fun isPunished(user: SteamwarUser, type: PunishmentType, callback: Consumer): Boolean = useDb {
+ val punishment = getPunsihmentOfPlayer(user.id.value, type) ?: return@useDb false
+
+ if (punishment.isCurrent()) {
+ callback.accept(punishment)
+ return@useDb true
+ }
+
+ return@useDb false
+ }
+
+ @JvmStatic
+ fun createPunishment(
+ user: Int,
+ executor: Int,
+ type: PunishmentType,
+ reason: String,
+ endTime: Timestamp,
+ perma: Boolean
+ ) = useDb {
+ new {
+ this.userId = user
+ this.punisher = executor
+ this.type = type
+ this.startTime = Timestamp.from(Instant.now())
+ this.endTime = endTime
+ this.perma = perma
+ this.reason = reason
+ }
+ }
+ }
+
+ var userId by PunishmentTable.userId.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
+ private set
+ var punisher by PunishmentTable.punisher.transform({ EntityID(it, SteamwarUserTable) }, { it.value })
+ private set
+ var type by PunishmentTable.type
+ private set
+ var startTime by PunishmentTable.startTime.transform({ it.toInstant() }, { Timestamp.from(it) })
+ private set
+ var endTime by PunishmentTable.endTime.transform({ it.toInstant() }, { Timestamp.from(it) })
+ private set
+ var perma by PunishmentTable.perma
+ private set
+ var reason by PunishmentTable.reason
+ private set
+
+ fun isPerma() = perma
+
+ fun isCurrent() = perma || endTime.after(Date())
+
+ enum class PunishmentType(
+ val teamMessage: String?,
+ val playerMessagePerma: String?,
+ val playerMessageUntil: String?,
+ val usageNotPunished: String?,
+ val unpunishmentMessage: String?,
+ val userPerm: UserPerm,
+ val multi: Boolean = false
+ ) {
+ Ban("BAN_TEAM", "BAN_PERMA", "BAN_UNTIL", "UNBAN_ERROR", "UNBAN", UserPerm.PUNISHMENTS),
+ Mute("MUTE_TEAM", "MUTE_PERMA", "MUTE_UNTIL", "UNMUTE_ERROR", "UNMUTE", UserPerm.PUNISHMENTS),
+ NoSchemReceiving(
+ "NOSCHEMRECEIVING_TEAM",
+ "NOSCHEMRECEIVING_PERMA",
+ "NOSCHEMRECEIVING_UNTIL",
+ "UNNOSCHEMRECEIVING_ERROR",
+ "UNNOSCHEMRECEIVING",
+ UserPerm.MODERATION
+ ),
+ NoSchemSharing(
+ "NOSCHEMSHARING_TEAM",
+ "NOSCHEMSHARING_PERMA",
+ "NOSCHEMSHARING_UNTIL",
+ "UNNOSCHEMSHARING_ERROR",
+ "UNNOSCHEMSHARING",
+ UserPerm.MODERATION
+ ),
+ NoSchemSubmitting(
+ "NOSCHEMSUBMITTING_TEAM",
+ "NOSCHEMSUBMITTING_PERMA",
+ "NOSCHEMSUBMITTING_UNTIL",
+ "UNNOSCHEMSUBMITTING_ERROR",
+ "UNNOSCHEMSUBMITTING",
+ UserPerm.CHECK
+ ),
+ NoDevServer(
+ "NODEVSERVER_TEAM",
+ "NODEVSERVER_PERMA",
+ "NODEVSERVER_UNTIL",
+ "UNNODEVSERVER_ERROR",
+ "UNNODEVSERVER",
+ UserPerm.PREFIX_DEVELOPER
+ ),
+ NoFightServer(
+ "NOFIGHTSERVER_TEAM",
+ "NOFIGHTSERVER_PERMA",
+ "NOFIGHTSERVER_UNTIL",
+ "UNNOFIGHTSERVER_ERROR",
+ "UNNOFIGHTSERVER",
+ UserPerm.MODERATION
+ ),
+ NoTeamServer(
+ "NOTEAMSERVER_TEAM",
+ "NOTEAMSERVER_PERMA",
+ "NOTEAMSERVER_UNTIL",
+ "UNNOTEAMSERVER_ERROR",
+ "UNNOTEAMSERVER",
+ UserPerm.MODERATION
+ ),
+ Note("NOTE_TEAM", null, null, null, null, UserPerm.PUNISHMENTS, true);
+
+ fun isMulti() = multi
+ }
+}
\ No newline at end of file
diff --git a/CommonCore/SQL/src/de/steamwar/sql/Referee.java b/CommonCore/SQL/src/de/steamwar/sql/Referee.java
deleted file mode 100644
index 3f909643..00000000
--- a/CommonCore/SQL/src/de/steamwar/sql/Referee.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * This file is a part of the SteamWar software.
- *
- * Copyright (C) 2025 SteamWar.de-Serverteam
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package de.steamwar.sql;
-
-import de.steamwar.sql.internal.Field;
-import de.steamwar.sql.internal.SelectStatement;
-import de.steamwar.sql.internal.Statement;
-import de.steamwar.sql.internal.Table;
-import lombok.AllArgsConstructor;
-
-import java.util.Set;
-import java.util.stream.Collectors;
-
-@AllArgsConstructor
-public class Referee {
-
- private static final Table table = new Table<>(Referee.class);
- private static final SelectStatement